Updated on 2026-08-14

This commit is contained in:
Tangem 2020-04-10 20:19:53 +03:00
parent 25d005a9b9
commit 94a04d8280
13 changed files with 303 additions and 32 deletions

View file

@ -8,30 +8,46 @@ import com.tangem.tangemtest._arch.structure.PayloadHolder
/**
[REDACTED_AUTHOR]
*/
typealias ValueChange<V> = (V?) -> Unit
typealias SafeValueChange<V> = (V) -> Unit
typealias ValueChanged<V> = (V?) -> Unit
typealias SafeValueChanged<V> = (V) -> Unit
class KeyValue(val key: String, val value: Any)
class ViewState(
var isHidden: Boolean = false,
var backgroundColor: Int? = -1
isVisible: Boolean? = null,
bgColor: Int? = -1
) {
var descriptionVisibility: Int = 0x00000008
set(value) {
field = value
onDescriptionVisibilityChanged?.invoke(value)
}
class State<T>(
stateValue: T,
var onValueChanged: SafeValueChanged<T>? = null
) {
var value = stateValue
set(value) {
if (preventSameChanges && field == value) return
var onDescriptionVisibilityChanged: SafeValueChange<Int>? = null
field = value
onValueChanged?.invoke(value)
}
internal var preventSameChanges = true
}
var isVisibleState = State(isVisible)
var backgroundColor = State(bgColor)
var descriptionVisibility = State(0x00000008)
internal fun preventSameChanges(isPrevented: Boolean) {
val states = listOf(isVisibleState, backgroundColor, descriptionVisibility)
states.forEach { it.preventSameChanges = isPrevented }
}
}
interface ItemViewModel : PayloadHolder {
val viewState: ViewState
var data: Any?
var defaultData: Any?
var onDataUpdated: ValueChange<Any?>?
var onDataUpdated: ValueChanged<Any?>?
fun updateDataByView(data: Any?)
}
@ -57,7 +73,7 @@ open class BaseItemViewModel(
}
// Use it for handling data updates in View
override var onDataUpdated: ValueChange<Any?>? = null
override var onDataUpdated: ValueChanged<Any?>? = null
// When data updates directly it invokes onDataUpdated
// return true = data will update

View file

@ -10,6 +10,7 @@ import com.tangem.tangemtest.R
import com.tangem.tangemtest._arch.structure.StringId
import com.tangem.tangemtest._arch.structure.StringResId
import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest._arch.structure.abstraction.ViewState
import ru.dev.gbixahue.eu4d.lib.android._android.views.colorFrom
import ru.dev.gbixahue.eu4d.lib.kotlin.common.LayoutHolder
@ -34,11 +35,22 @@ abstract class BaseViewWidget(
private var defaultBackground: Drawable? = view.background
init {
if (item.viewModel.viewState.isHidden) {
view.visibility = View.GONE
} else {
setBackgroundColor(item.viewModel.viewState.backgroundColor)
subscribeToViewStateChanges(item.viewModel.viewState)
initViewState(item.viewModel.viewState)
}
protected open fun subscribeToViewStateChanges(viewState: ViewState) {
viewState.isVisibleState.onValueChanged = { state ->
state?.let { view.visibility = if (it) View.VISIBLE else View.GONE }
}
viewState.backgroundColor.onValueChanged = { setBackgroundColor(it) }
}
protected open fun initViewState(viewState: ViewState) {
viewState.preventSameChanges(false)
viewState.isVisibleState.value = viewState.isVisibleState.value
if (viewState.backgroundColor.value != -1) setBackgroundColor(viewState.backgroundColor.value)
viewState.preventSameChanges(true)
}
override fun getName(): String {

View file

@ -0,0 +1,85 @@
package com.tangem.tangemtest.commons.view
import android.widget.TextView
import androidx.annotation.StringRes
import com.tangem.tangemtest._arch.structure.Id
import com.tangem.tangemtest._arch.structure.StringId
import com.tangem.tangemtest._arch.structure.abstraction.SafeValueChanged
import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
/**
[REDACTED_AUTHOR]
*/
open class MultiActionView<V : TextView>(
stateList: MutableList<ButtonState>,
val child: V
) {
interface State {
val id: Id
fun getAction(): StateButtonAction
fun getResNameId(): Int
}
var afterAction: SafeValueChanged<Id>? = null
var state: Id = DefaultId.default
set(value) {
if (field == value) return
field = value
Log.d(this, "state changed to: ${getKey(value)}")
btnState = stateHolder[getKey(value)]
}
init {
child.setOnClickListener {
val state = btnState ?: return@setOnClickListener
Log.d(this, "child handled OnClick for: ${getKey(state.id)}")
state.getAction().invoke()
afterAction?.invoke(state.id)
}
}
protected var btnState: State? = null
set(value) {
if (value == null) return
field = value
Log.d(this, "btnState changed to: ${getKey(value.id)}")
child.setText(value.getResNameId())
}
protected val stateHolder: MutableMap<String, State> = stateList.associateBy { getKey(it.id) }.toMutableMap()
fun performAction(id: Id) {
Log.d(this, "performAction ${getKey(id)}")
state = id
child.performClick()
}
protected open fun getKey(id: Id): String {
return when (id) {
is StringId -> id.value
else -> stringOf(id)
}
}
}
enum class DefaultId : Id { default }
typealias StateButtonAction = () -> Unit
class ButtonState(
override val id: Id,
@StringRes val name: Int,
private val action: StateButtonAction
) : MultiActionView.State {
override fun getAction(): StateButtonAction = action
override fun getResNameId(): Int = name
}

View file

@ -13,7 +13,9 @@ import com.tangem.tangemtest._arch.structure.abstraction.iterate
import com.tangem.tangemtest.commons.performAction
import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager
import com.tangem.tangemtest.ucase.domain.responses.ResponseJsonConverter
import com.tangem.tangemtest.ucase.resources.ActionType
import com.tangem.tangemtest.ucase.tunnel.ViewScreen
import com.tangem.tangemtest.ucase.variants.personalize.converter.ItemTypes
import com.tangem.tasks.ScanEvent
import com.tangem.tasks.TaskError
import com.tangem.tasks.TaskEvent
@ -73,7 +75,7 @@ class ActionViewModel(private val itemsManager: ItemsManager) : ViewModel(), Lif
fun toggleDescriptionVisibility(state: Boolean) {
ldItemList.value?.iterate {
it.viewModel.viewState.descriptionVisibility = if (state) View.VISIBLE else View.GONE
it.viewModel.viewState.descriptionVisibility.value = if (state) View.VISIBLE else View.GONE
}
}
@ -87,6 +89,41 @@ class ActionViewModel(private val itemsManager: ItemsManager) : ViewModel(), Lif
itemsManager.payload.filterValues { it is ViewScreen }.forEach { keyList.add(it.key) }
keyList.forEach { itemsManager.payload.remove(it) }
}
fun showFields(type: ActionType) {
toggleFieldsVisibility(type, true)
}
fun hideFields(type: ActionType) {
toggleFieldsVisibility(type, false)
}
private fun toggleFieldsVisibility(type: ActionType, show: Boolean) {
val oftenUsed = getItemsForTogglingVisibilityState(type)
val hidden = getItemIdsWhichWontShows(type)
itemsManager.getItems().iterate {
if (!hidden.contains(it.id)) {
if (!oftenUsed.contains(it.id)) {
it.viewModel.viewState.isVisibleState.value = show
}
}
}
}
private fun getItemsForTogglingVisibilityState(type: ActionType): List<Id> {
return when (type) {
ActionType.Personalize -> ItemTypes().oftenUsedList
else -> emptyList()
}
}
private fun getItemIdsWhichWontShows(type: ActionType): List<Id> {
return when (type) {
ActionType.Personalize -> ItemTypes().hiddenList
else -> emptyList()
}
}
}
internal class Notifier(private val vm: ActionViewModel) {

View file

@ -47,9 +47,14 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView {
actionVM.attachToPayload(mutableMapOf(PayloadKey.actionView to this as ActionView))
initFab()
createWidgets { subscribeToViewModelChanges() }
createWidgets {
widgetsWasCreated()
subscribeToViewModelChanges()
}
}
protected open fun widgetsWasCreated() {}
protected open fun bindViews() {
itemContainer = mainView.findViewById(R.id.ll_container)
actionFab = mainView.findViewById(R.id.fab_action)

View file

@ -1,5 +1,6 @@
package com.tangem.tangemtest.ucase.variants.personalize.converter
import com.tangem.tangemtest._arch.structure.Id
import com.tangem.tangemtest.ucase.variants.personalize.*
class ItemTypes {
@ -36,11 +37,81 @@ class ItemTypes {
CardNumber.Number, Common.MaxSignatures, SignHashExProp.PinLessFloorLimit, Denomination.Denomination, Token.Decimal
)
val hiddenList = mutableListOf(
val hiddenList = mutableListOf<Id>(
CardNumber.Series, CardNumber.BatchId, Pins.Pin3, SigningMethod.SignExternal,
SignHashExProp.CryptoExKey, SignHashExProp.CheckPin3, SettingsMask.OneApdu,
SettingsMask.UseBlock, SettingsMask.ProtectIssuerDataAgainstReplay,
SignHashExProp.RequireTerminalCertSig, SignHashExProp.RequireTerminalTxSig
)
}
val oftenUsedList = listOf<Id>(
// BlockId.CardNumber,
BlockId.Common,
// BlockId.SigningMethod,
// BlockId.SignHashExProp,
// BlockId.Denomination,
// BlockId.Token,
BlockId.ProdMask,
// BlockId.SettingsMask,
// BlockId.SettingsMaskProtocolEnc,
BlockId.SettingsMaskNdef,
// BlockId.Pins,
Common.Curve,
Common.Blockchain,
Common.BlockchainCustom,
// Common.MaxSignatures,
Common.CreateWallet,
// SigningMethod.SignTx,
// SigningMethod.SignTxRaw,
// SigningMethod.SignValidatedTx,
// SigningMethod.SignValidatedTxRaw,
// SigningMethod.SignValidatedTxIssuer,
// SigningMethod.SignValidatedTxRawIssuer,
// SigningMethod.SignExternal,
// SignHashExProp.PinLessFloorLimit,
// SignHashExProp.CryptoExKey,
// SignHashExProp.RequireTerminalCertSig,
// SignHashExProp.RequireTerminalTxSig,
// SignHashExProp.CheckPin3,
// Denomination.WriteOnPersonalize,
// Denomination.Denomination,
// Token.ItsToken,
// Token.Symbol,
// Token.ContractAddress,
// Token.Decimal,
ProductMask.Note,
ProductMask.Tag,
ProductMask.IdCard,
ProductMask.IdIssuerCard,
// SettingsMask.IsReusable,
// SettingsMask.NeedActivation,
// SettingsMask.ForbidPurge,
// SettingsMask.AllowSelectBlockchain,
// SettingsMask.UseBlock,
// SettingsMask.OneApdu,
// SettingsMask.UseCvc,
// SettingsMask.AllowSwapPin,
// SettingsMask.AllowSwapPin2,
// SettingsMask.ForbidDefaultPin,
// SettingsMask.SmartSecurityDelay,
// SettingsMask.ProtectIssuerDataAgainstReplay,
// SettingsMask.SkipSecurityDelayIfValidated,
// SettingsMask.SkipPin2CvcIfValidated,
// SettingsMask.SkipSecurityDelayOnLinkedTerminal,
// SettingsMask.RestrictOverwriteExtraIssuerData,
// SettingsMaskProtocolEnc.AllowUnencrypted,
// SettingsMaskProtocolEnc.AllowStaticEncryption,
// SettingsMaskNdef.UseNdef,
// SettingsMaskNdef.DynamicNdef,
// SettingsMaskNdef.DisablePrecomputedNdef,
SettingsMaskNdef.Aar,
SettingsMaskNdef.AarCustom,
SettingsMaskNdef.Uri,
// Pins.Pin,
// Pins.Pin2,
// Pins.Pin3,
// Pins.Cvc,
Pins.PauseBeforePin2
)
}

View file

@ -147,7 +147,7 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
blocList.add(pins())
blocList.iterate {
if (itemTypes.hiddenList.contains(it.id)) {
it.viewModel.viewState.isHidden = true
it.viewModel.viewState.isVisibleState.value = false
}
}
return blocList

View file

@ -2,19 +2,26 @@ package com.tangem.tangemtest.ucase.variants.personalize.ui
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.lifecycle.Observer
import com.tangem.tangemtest.R
import com.tangem.tangemtest._arch.structure.Id
import com.tangem.tangemtest._arch.structure.StringId
import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest._arch.widget.WidgetBuilder
import com.tangem.tangemtest.commons.view.ButtonState
import com.tangem.tangemtest.commons.view.MultiActionView
import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager
import com.tangem.tangemtest.ucase.domain.paramsManager.PayloadKey
import com.tangem.tangemtest.ucase.domain.paramsManager.managers.PersonalizationItemsManager
import com.tangem.tangemtest.ucase.resources.ActionType
import com.tangem.tangemtest.ucase.tunnel.ActionView
import com.tangem.tangemtest.ucase.tunnel.ItemError
import com.tangem.tangemtest.ucase.ui.BaseCardActionFragment
import com.tangem.tangemtest.ucase.variants.personalize.PersonalizationConfigStore
import com.tangem.tangemtest.ucase.variants.personalize.ui.widgets.PersonalizationItemBuilder
import ru.dev.gbixahue.eu4d.lib.android._android.views.inflate
import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
/**
@ -31,6 +38,25 @@ class PersonalizationFragment : BaseCardActionFragment() {
lifecycle.addObserver(itemsManager as PersonalizationItemsManager)
}
override fun widgetsWasCreated() {
super.widgetsWasCreated()
val btnContainer = itemContainer.inflate<ViewGroup>(R.layout.view_simple_button)
val btn = btnContainer.findViewById<Button>(R.id.button)
val show = StringId("show")
val hide = StringId("hide")
val multiAction = MultiActionView(mutableListOf(
ButtonState(show, R.string.show_rare_fields) { actionVM.showFields(ActionType.Personalize) },
ButtonState(hide, R.string.hide_rare_fields) { actionVM.hideFields(ActionType.Personalize) }
), btn)
multiAction.afterAction = {
multiAction.state = if (it == show) hide else show
}
multiAction.performAction(hide)
itemContainer.addView(btnContainer)
}
override fun initFab() {
actionFab.setOnClickListener { actionVM.invokeMainAction() }
}

View file

@ -6,7 +6,7 @@ import androidx.transition.AutoTransition
import androidx.transition.TransitionManager
import com.tangem.tangemtest.R
import com.tangem.tangemtest._arch.structure.abstraction.Item
import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
import com.tangem.tangemtest._arch.structure.abstraction.ViewState
/**
[REDACTED_AUTHOR]
@ -19,13 +19,9 @@ abstract class DescriptionWidget(
private val descriptionContainer: ViewGroup by lazy { view.findViewById<ViewGroup>(R.id.container_description) }
private val tvDescription: TextView? by lazy { descriptionContainer.findViewById<TextView>(R.id.tv_description) }
init {
Log.d(this, "init id: ${item.id}")
initDescriptionWidget()
}
private fun initDescriptionWidget() {
item.viewModel.viewState.onDescriptionVisibilityChanged = { changeDescriptionVisibility(it) }
override fun subscribeToViewStateChanges(viewState: ViewState) {
super.subscribeToViewStateChanges(viewState)
viewState.descriptionVisibility.onValueChanged = { changeDescriptionVisibility(it) }
}
protected open fun changeDescriptionVisibility(state: Int) {

View file

@ -34,7 +34,7 @@ class ResponseViewModel : ViewModel() {
fun toggleDescriptionVisibility(state: Boolean) {
itemList?.iterate {
it.viewModel.viewState.descriptionVisibility = if (state) View.VISIBLE else View.GONE
it.viewModel.viewState.descriptionVisibility.value = if (state) View.VISIBLE else View.GONE
}
}

View file

@ -42,7 +42,7 @@ class CardConverter : ModelToItems<Card> {
else -> false
}
if (isHidden) it.viewModel.viewState.isHidden = true
if (isHidden) it.viewModel.viewState.isVisibleState.value = false
}
}
@ -100,6 +100,6 @@ class CardConverter : ModelToItems<Card> {
private fun createGroup(id: Id, colorId: Int? = null): ItemGroup {
return if (colorId == null) SimpleItemGroup(id)
else SimpleItemGroup(id, BaseItemViewModel(viewState = ViewState(backgroundColor = colorId)))
else SimpleItemGroup(id, BaseItemViewModel(viewState = ViewState(bgColor = colorId)))
}
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -18,4 +18,7 @@
<string name="stub">Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit</string>
<!-- <string name="stub">Sed ut perspiciatis unde omnis iste natus</string>-->
<string name="show_rare_fields">Show rarely used fields</string>
<string name="hide_rare_fields">Hide</string>
</resources>