From 6e762cc7fffc5b42e999059792bc6072d62fe0d6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 8 Apr 2020 23:04:48 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/tangemtest/_arch/structure/Ids.kt | 2 + .../_arch/widget/abstraction/ViewWidget.kt | 7 + .../ucase/resources/MainResourceHolder.kt | 4 +- .../initializers/ResponseResources.kt | 53 +++++++ .../personalize/ui/widgets/BlockHeadWidget.kt | 4 +- .../ui/widgets/DescriptionWidget.kt | 15 +- .../personalize/ui/widgets/EditTextWidget.kt | 6 +- .../personalize/ui/widgets/NumberWidget.kt | 6 +- .../personalize/ui/widgets/SpinnerWidget.kt | 4 +- .../personalize/ui/widgets/SwitchWidget.kt | 6 +- .../ucase/variants/responses/Ids.kt | 44 ++++++ .../variants/responses/ResponseViewModel.kt | 41 ++++++ .../responses/converter/CardConverter.kt | 85 +++++++++++ .../responses/converter/ConvertersStore.kt | 17 +++ .../responses/converter/SimpleConverters.kt | 35 +++++ .../variants/responses/ui/ResponseFragment.kt | 56 +++++++ .../responses/ui/widget/CheckBoxWidget.kt | 25 ++++ .../ui/widget}/ResponseItemBuilder.kt | 5 +- .../ui/widget}/ResponseTextWidget.kt | 25 +++- .../variants/scan/ui/ScanActionFragment.kt | 4 +- .../src/main/res/layout/fg_card_response.xml | 8 +- .../src/main/res/layout/w_response_item.xml | 24 ++- .../res/layout/w_response_item_checkbox.xml | 41 ++++++ .../src/main/res/navigation/navigation.xml | 2 +- tangem-demo/src/main/res/values/colors.xml | 5 +- tangem-demo/src/main/res/values/strings.xml | 2 +- .../src/main/res/values/strings_response.xml | 138 ++++++++++++++++++ 27 files changed, 611 insertions(+), 53 deletions(-) create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/ucase/resources/initializers/ResponseResources.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/Ids.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ResponseViewModel.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/CardConverter.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/ConvertersStore.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/SimpleConverters.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/ResponseFragment.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/CheckBoxWidget.kt rename tangem-demo/src/main/java/com/tangem/tangemtest/ucase/{ui => variants/responses/ui/widget}/ResponseItemBuilder.kt (75%) rename tangem-demo/src/main/java/com/tangem/tangemtest/ucase/{ui/widgets => variants/responses/ui/widget}/ResponseTextWidget.kt (53%) create mode 100644 tangem-demo/src/main/res/layout/w_response_item_checkbox.xml create mode 100644 tangem-demo/src/main/res/values/strings_response.xml diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/Ids.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/Ids.kt index 3b40edcc77..ce27853356 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/Ids.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/Ids.kt @@ -5,6 +5,8 @@ package com.tangem.tangemtest._arch.structure */ interface Id +class StringId(val name: String) : Id + enum class Additional : Id { UNDEFINED, JSON_INCOMING, diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/widget/abstraction/ViewWidget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/widget/abstraction/ViewWidget.kt index b3ca53c3a0..7fa8fd5bbb 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/widget/abstraction/ViewWidget.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/widget/abstraction/ViewWidget.kt @@ -5,10 +5,12 @@ import android.view.View import android.view.ViewGroup import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.DataHolder +import com.tangem.tangemtest._arch.structure.StringId import com.tangem.tangemtest._arch.structure.abstraction.BaseItem import com.tangem.tangemtest._arch.structure.abstraction.ItemViewModel import com.tangem.tangemtest.ucase.resources.MainResourceHolder import com.tangem.tangemtest.ucase.resources.Resources +import ru.dev.gbixahue.eu4d.lib.android._android.views.stringFrom import ru.dev.gbixahue.eu4d.lib.kotlin.common.LayoutHolder /** @@ -46,6 +48,11 @@ fun DataWidget<*>.getResNameId(): Int = MainResourceHolder.safeGet(da fun DataWidget<*>.getResDescription(): Int? = MainResourceHolder.safeGet(dataItem.id).resDescription +fun DataWidget<*>.getName(): String { + val id = dataItem.id + return if (id is StringId) id.name else view.stringFrom(getResNameId()) +} + internal fun inflate(id: Int, parent: ViewGroup): View { val layoutId = if (id <= 0) R.layout.w_empty else id val inflatedView = LayoutInflater.from(parent.context).inflate(layoutId, parent, false) diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/resources/MainResourceHolder.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/resources/MainResourceHolder.kt index 90b908b742..44028d9018 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/resources/MainResourceHolder.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/resources/MainResourceHolder.kt @@ -4,6 +4,7 @@ import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.Id import com.tangem.tangemtest.ucase.resources.initializers.ActionResources import com.tangem.tangemtest.ucase.resources.initializers.PersonalizeResources +import com.tangem.tangemtest.ucase.resources.initializers.ResponseResources import com.tangem.tangemtest.ucase.resources.initializers.TlvResources import ru.dev.gbixahue.eu4d.lib.kotlin.common.BaseTypedHolder @@ -17,10 +18,11 @@ object MainResourceHolder : ResourceHolder() { PersonalizeResources().init(this) ActionResources().init(this) TlvResources().init(this) + ResponseResources().init(this) } inline fun safeGet(id: Id): Res { val result = super.get(id) ?: Resources(R.string.unknown, R.string.unknown) return result as Res } -} +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/resources/initializers/ResponseResources.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/resources/initializers/ResponseResources.kt new file mode 100644 index 0000000000..a9ad0a3d69 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/resources/initializers/ResponseResources.kt @@ -0,0 +1,53 @@ +package com.tangem.tangemtest.ucase.resources.initializers + +import com.tangem.tangemtest.R +import com.tangem.tangemtest.ucase.resources.MainResourceHolder +import com.tangem.tangemtest.ucase.resources.Resources +import com.tangem.tangemtest.ucase.variants.responses.CardDataId +import com.tangem.tangemtest.ucase.variants.responses.CardId + +/** +[REDACTED_AUTHOR] + */ +class ResponseResources { + fun init(holder: MainResourceHolder) { + initCard(holder) + initCardData(holder) + } + + private fun initCard(holder: MainResourceHolder) { + holder.register(CardId.cardId, Resources(R.string.response_card_cid, R.string.info_response_card_cid)) + holder.register(CardId.manufacturerName, Resources(R.string.response_card_manufacturer_name, R.string.info_response_card_manufacturer_name)) + holder.register(CardId.status, Resources(R.string.response_card_status, R.string.info_response_card_status)) + holder.register(CardId.firmwareVersion, Resources(R.string.response_card_firmware_version, R.string.info_response_card_firmware_version)) + holder.register(CardId.cardPublicKey, Resources(R.string.response_card_public_key, R.string.info_response_card_public_key)) + holder.register(CardId.settingsMask, Resources(R.string.response_card_settings_mask, R.string.info_response_card_settings_mask)) + holder.register(CardId.cardData, Resources(R.string.response_card_card_data, R.string.info_response_card_card_data)) + holder.register(CardId.issuerPublicKey, Resources(R.string.response_card_issuer_data_public_key, R.string.info_response_card_issuer_data_public_key)) + holder.register(CardId.curve, Resources(R.string.response_card_curve, R.string.info_response_card_curve)) + holder.register(CardId.maxSignatures, Resources(R.string.response_card_max_signatures, R.string.info_response_card_max_signatures)) + holder.register(CardId.signingMethod, Resources(R.string.response_card_signing_method, R.string.response_card_signing_method)) + holder.register(CardId.pauseBeforePin2, Resources(R.string.response_card_pause_before_pin2, R.string.info_response_card_allow_pin2)) + holder.register(CardId.walletPublicKey, Resources(R.string.response_card_wallet_public_key, R.string.info_response_card_wallet_public_key)) + holder.register(CardId.walletRemainingSignatures, Resources(R.string.response_card_wallet_remaining_signatures, R.string.info_response_card_wallet_remaining_signatures)) + holder.register(CardId.walletSignedHashes, Resources(R.string.response_card_wallet_signed_hashes, R.string.info_response_card_wallet_signed_hashes)) + holder.register(CardId.health, Resources(R.string.response_card_health, R.string.info_response_card_health)) + holder.register(CardId.isActivated, Resources(R.string.response_card_is_activated, R.string.info_response_card_is_activated)) + holder.register(CardId.activationSeed, Resources(R.string.response_card_activation_seed, R.string.info_response_card_activation_seed)) + holder.register(CardId.paymentFlowVersion, Resources(R.string.response_card_payment_flow_version, R.string.info_response_card_payment_flow_version)) + holder.register(CardId.userCounter, Resources(R.string.response_card_user_counter, R.string.info_response_card_user_counter)) + holder.register(CardId.userProtectedCounter, Resources(R.string.response_card_user_protected_counter, R.string.info_response_card_user_protected_counter)) + } + + private fun initCardData(holder: MainResourceHolder) { + holder.register(CardDataId.batchId, Resources(R.string.response_card_card_data_batch_id, R.string.info_response_card_card_data_batch_id)) + holder.register(CardDataId.manufactureDateTime, Resources(R.string.response_card_card_data_manufacture_date_time, R.string.info_response_card_card_data_manufacture_date_time)) + holder.register(CardDataId.issuerName, Resources(R.string.response_card_card_data_issuer_name, R.string.info_response_card_card_data_issuer_name)) + holder.register(CardDataId.blockchainName, Resources(R.string.response_card_card_data_blockchain_name, R.string.info_response_card_card_data_blockchain_name)) + holder.register(CardDataId.manufacturerSignature, Resources(R.string.response_card_card_data_manufacturer_signature, R.string.info_response_card_card_data_manufacturer_signature)) + holder.register(CardDataId.productMask, Resources(R.string.response_card_card_data_product_mask, R.string.info_response_card_card_data_product_mask)) + holder.register(CardDataId.tokenSymbol, Resources(R.string.response_card_card_data_token_symbol, R.string.info_response_card_card_data_token_symbol)) + holder.register(CardDataId.tokenContractAddress, Resources(R.string.response_card_card_data_token_contract_address, R.string.info_response_card_card_data_token_contract_address)) + holder.register(CardDataId.tokenDecimal, Resources(R.string.response_card_card_data_token_decimal, R.string.info_response_card_card_data_token_decimal)) + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/BlockHeadWidget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/BlockHeadWidget.kt index 2f2dde5d72..4b0837723b 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/BlockHeadWidget.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/BlockHeadWidget.kt @@ -4,7 +4,7 @@ import android.view.ViewGroup import android.widget.TextView import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.impl.TextItem -import com.tangem.tangemtest._arch.widget.abstraction.getResNameId +import com.tangem.tangemtest._arch.widget.abstraction.getName /** [REDACTED_AUTHOR] @@ -15,6 +15,6 @@ class BlockHeadWidget(parent: ViewGroup, data: TextItem) : DescriptionWidget(R.id.tv_name) init { - tvName?.setText(getResNameId()) + tvName.text = getName() } } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/DescriptionWidget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/DescriptionWidget.kt index 70107becdb..9dfff32c48 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/DescriptionWidget.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/DescriptionWidget.kt @@ -30,7 +30,7 @@ abstract class DescriptionWidget( dataItem.viewModel.viewState.onDescriptionVisibilityChanged = { changeDescriptionVisibility(it) } } - protected fun changeDescriptionVisibility(state: Int) { + protected open fun changeDescriptionVisibility(state: Int) { val tv = tvDescription ?: return val descriptionId = getResDescription() ?: return val description = tv.context.getString(descriptionId) @@ -40,15 +40,4 @@ abstract class DescriptionWidget( TransitionManager.beginDelayedTransition(view.parent as ViewGroup, AutoTransition()) descriptionContainer.visibility = state } -} - - - - - - - - - - - +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/EditTextWidget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/EditTextWidget.kt index 791e80b048..9cb1061414 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/EditTextWidget.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/EditTextWidget.kt @@ -7,7 +7,7 @@ import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.impl.EditTextItem -import com.tangem.tangemtest._arch.widget.abstraction.getResNameId +import com.tangem.tangemtest._arch.widget.abstraction.getName import ru.dev.gbixahue.eu4d.lib.android._android.views.moveCursorToEnd import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf @@ -30,8 +30,8 @@ class EditTextWidget(parent: ViewGroup, data: EditTextItem) : DescriptionWidget< } init { - tilItem.hint = tilItem.context.getString(getResNameId()) - etItem.setText(dataItem.viewModel.data) + tilItem.hint = getName() + etItem.setText(dataItem.getData()) etItem.addTextChangedListener(watcher) dataItem.viewModel.onDataUpdated = { silentUpdate(it) } } diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/NumberWidget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/NumberWidget.kt index 1b72f5f21d..e2702465a4 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/NumberWidget.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/NumberWidget.kt @@ -8,7 +8,7 @@ import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.impl.NumberItem -import com.tangem.tangemtest._arch.widget.abstraction.getResNameId +import com.tangem.tangemtest._arch.widget.abstraction.getName import com.tangem.tangemtest.ucase.variants.personalize.CardNumber import ru.dev.gbixahue.eu4d.lib.android._android.views.addInputFilter import ru.dev.gbixahue.eu4d.lib.android._android.views.moveCursorToEnd @@ -33,12 +33,12 @@ class NumberWidget(parent: ViewGroup, data: NumberItem) : DescriptionWidget(R.id.tv_name) - name.setText(getResNameId()) + name.text = getName() spItem.adapter = spAdapter spAdapter.getItemPosition(stringOf(data.selectedItem))?.let { spItem.setSelection(it) diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/SwitchWidget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/SwitchWidget.kt index 35a12ff069..015ea477b2 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/SwitchWidget.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/widgets/SwitchWidget.kt @@ -5,7 +5,7 @@ import android.widget.CompoundButton import androidx.appcompat.widget.SwitchCompat import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.impl.BoolItem -import com.tangem.tangemtest._arch.widget.abstraction.getResNameId +import com.tangem.tangemtest._arch.widget.abstraction.getName /** [REDACTED_AUTHOR] @@ -20,8 +20,8 @@ class SwitchWidget(parent: ViewGroup, data: BoolItem) : DescriptionWidget? = null + + fun createItemList(taskEvent: TaskEvent<*>): List { + Log.d(this, "createItemList: itemList size: ${itemList?.size ?: 0}") + + val event = taskEvent as? TaskEvent.Event ?: return emptyList() + val type = event.data::class.java + val converter = convertersHolder.get(type) as? ModelToItems ?: return emptyList() + itemList = converter.convert(event.data) + return itemList!! + } + + fun toggleDescriptionVisibility(state: Boolean) { + itemList?.iterate { + val baseItem = it as? BaseItem<*> ?: return@iterate + baseItem.viewModel.viewState.descriptionVisibility = if (state) View.VISIBLE else View.GONE + } + } +} + + + + diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/CardConverter.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/CardConverter.kt new file mode 100644 index 0000000000..492989ebe1 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/CardConverter.kt @@ -0,0 +1,85 @@ +package com.tangem.tangemtest.ucase.variants.responses.converter + +import com.tangem.commands.Card +import com.tangem.commands.Settings +import com.tangem.commands.SettingsMask +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.structure.abstraction.ListItemBlock +import com.tangem.tangemtest._arch.structure.abstraction.ModelToItems +import com.tangem.tangemtest._arch.structure.impl.BoolItem +import com.tangem.tangemtest._arch.structure.impl.TextItem +import com.tangem.tangemtest.ucase.variants.personalize.BlockId +import com.tangem.tangemtest.ucase.variants.responses.CardDataId +import com.tangem.tangemtest.ucase.variants.responses.CardId +import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf + +/** +[REDACTED_AUTHOR] + */ +class CardConverter : ModelToItems { + override fun convert(from: Card): List { + val itemList = mutableListOf() +// val holder = GsonInitializer() +// itemList.add(TextItem(Additional.JSON_INCOMING, holder.gson.toJson(from))) + + itemList.add(simpleFields(from)) + itemList.add(cardData(from)) + itemList.add(settingsMask(from.settingsMask)) + return itemList + } + + private fun simpleFields(from: Card): Item { + val block = createBlock(BlockId.Common) + block.addItem(TextItem(CardId.cardId, from.cardId)) + block.addItem(TextItem(CardId.manufacturerName, from.manufacturerName)) + block.addItem(TextItem(CardId.status, stringOf(from.status))) + block.addItem(TextItem(CardId.firmwareVersion, from.firmwareVersion)) + block.addItem(TextItem(CardId.cardPublicKey, stringOf(from.cardPublicKey))) + block.addItem(TextItem(CardId.issuerPublicKey, stringOf(from.issuerPublicKey))) + block.addItem(TextItem(CardId.curve, stringOf(from.curve))) + block.addItem(TextItem(CardId.maxSignatures, stringOf(from.maxSignatures))) + block.addItem(TextItem(CardId.signingMethod, stringOf(from.signingMethod))) + block.addItem(TextItem(CardId.pauseBeforePin2, stringOf(from.pauseBeforePin2))) + block.addItem(TextItem(CardId.walletPublicKey, stringOf(from.walletPublicKey))) + block.addItem(TextItem(CardId.walletRemainingSignatures, stringOf(from.walletRemainingSignatures))) + block.addItem(TextItem(CardId.walletSignedHashes, stringOf(from.walletSignedHashes))) + block.addItem(TextItem(CardId.health, stringOf(from.health))) + block.addItem(TextItem(CardId.isActivated, stringOf(from.isActivated))) + block.addItem(TextItem(CardId.activationSeed, stringOf(from.activationSeed))) + block.addItem(TextItem(CardId.paymentFlowVersion, stringOf(from.paymentFlowVersion))) + block.addItem(TextItem(CardId.userCounter, stringOf(from.userCounter))) +// block.addItem(TextItem(CardId.UserProtectedCounter, stringOf(from.userProtectedCounter))) + return block + } + + private fun cardData(from: Card): Item { + val block = createBlock(BlockId.Common) + val data = from.cardData ?: return block + + val itemList = block.itemList + itemList.add(TextItem(CardDataId.batchId, data.batchId)) +// Format: Year (2 bytes) | Month (1 byte) | Day (1 byte) + itemList.add(TextItem(CardDataId.manufactureDateTime, stringOf(data.manufactureDateTime))) + itemList.add(TextItem(CardDataId.issuerName, data.issuerName)) + itemList.add(TextItem(CardDataId.blockchainName, data.blockchainName)) + itemList.add(TextItem(CardDataId.manufacturerSignature, stringOf(data.manufacturerSignature))) + itemList.add(TextItem(CardDataId.productMask, stringOf(data.productMask))) + itemList.add(TextItem(CardDataId.tokenSymbol, data.tokenSymbol)) + itemList.add(TextItem(CardDataId.tokenContractAddress, data.tokenContractAddress)) + itemList.add(TextItem(CardDataId.tokenDecimal, data.tokenSymbol)) + + return block + } + + private fun settingsMask(from: SettingsMask?): Item { + val block = createBlock(CardId.settingsMask) + val data = from ?: return block + + Settings.values().forEach { block.addItem(BoolItem(StringId(it.name), data.contains(it))) } + return block + } + + private fun createBlock(id: Id): ListItemBlock = ListItemBlock(id).apply { addItem(TextItem(id)) } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/ConvertersStore.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/ConvertersStore.kt new file mode 100644 index 0000000000..9b1dc76a49 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/ConvertersStore.kt @@ -0,0 +1,17 @@ +package com.tangem.tangemtest.ucase.variants.responses.converter + +import com.tangem.commands.Card +import com.tangem.commands.SignResponse +import com.tangem.commands.personalization.DepersonalizeResponse +import com.tangem.tasks.ScanEvent +import ru.dev.gbixahue.eu4d.lib.kotlin.common.BaseTypedHolder +import java.lang.reflect.Type + +class ConvertersStore : BaseTypedHolder() { + init { + register(ScanEvent.OnReadEvent::class.java, ReadEventConverter()) + register(SignResponse::class.java, SignResponseConverter()) + register(Card::class.java, CardConverter()) + register(DepersonalizeResponse::class.java, DepersonalizeResponseConverter()) + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/SimpleConverters.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/SimpleConverters.kt new file mode 100644 index 0000000000..a1c997465b --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/SimpleConverters.kt @@ -0,0 +1,35 @@ +package com.tangem.tangemtest.ucase.variants.responses.converter + +import com.tangem.commands.SignResponse +import com.tangem.commands.personalization.DepersonalizeResponse +import com.tangem.tangemtest._arch.structure.StringId +import com.tangem.tangemtest._arch.structure.abstraction.Item +import com.tangem.tangemtest._arch.structure.abstraction.ModelToItems +import com.tangem.tangemtest._arch.structure.impl.TextItem +import com.tangem.tasks.ScanEvent +import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf + +/** +[REDACTED_AUTHOR] + */ +class ReadEventConverter : ModelToItems { + override fun convert(from: ScanEvent.OnReadEvent): List = CardConverter().convert(from.card) +} + +class SignResponseConverter : ModelToItems { + + override fun convert(from: SignResponse): List { + return listOf( + TextItem(StringId("CID"), from.cardId), + TextItem(StringId("Wallet signed hashes"), stringOf(from.walletSignedHashes)), + TextItem(StringId("Wallet remaining signatures"), stringOf(from.walletRemainingSignatures)), + TextItem(StringId("Signature"), stringOf(from.signature)) + ) + } +} + +class DepersonalizeResponseConverter : ModelToItems { + override fun convert(from: DepersonalizeResponse): List { + return listOf(TextItem(StringId("Is success"), stringOf(from.success))) + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/ResponseFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/ResponseFragment.kt new file mode 100644 index 0000000000..e3009a8787 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/ResponseFragment.kt @@ -0,0 +1,56 @@ +package com.tangem.tangemtest.ucase.variants.responses.ui + +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import com.tangem.tangemtest.R +import com.tangem.tangemtest._arch.widget.WidgetBuilder +import com.tangem.tangemtest._main.MainViewModel +import com.tangem.tangemtest.ucase.ui.BaseFragment +import com.tangem.tangemtest.ucase.variants.responses.ResponseViewModel +import com.tangem.tangemtest.ucase.variants.responses.ui.widget.ResponseItemBuilder +import ru.dev.gbixahue.eu4d.lib.android.global.log.Log + +/** +[REDACTED_AUTHOR] + */ +open class ResponseFragment : BaseFragment() { + + companion object Arg { + val response = "response" + } + + private val mainActivityVM: MainViewModel by activityViewModels() + private val selfVM: ResponseViewModel by viewModels() + + private val itemContainer: ViewGroup by lazy { mainView.findViewById(R.id.ll_container) } + + override fun getLayoutId(): Int = R.layout.fg_card_response + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mainActivityVM.ldResponseEvent.observe(viewLifecycleOwner, Observer { event -> + val builder = WidgetBuilder(ResponseItemBuilder()) + val itemList = selfVM.createItemList(event) + itemList.forEach { builder.build(it, itemContainer) } + }) + subscribeToViewModelChanges() + } + + private fun subscribeToViewModelChanges() { + Log.d(this, "subscribeToViewModelChanges") + listenDescriptionSwitchChanges() + } + + + private fun listenDescriptionSwitchChanges() { + mainActivityVM.ldDescriptionSwitch.observe(viewLifecycleOwner, Observer { + selfVM.toggleDescriptionVisibility(it) + }) + } +} diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/CheckBoxWidget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/CheckBoxWidget.kt new file mode 100644 index 0000000000..5350ab0135 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/CheckBoxWidget.kt @@ -0,0 +1,25 @@ +package com.tangem.tangemtest.ucase.variants.responses.ui.widget + +import android.view.ViewGroup +import com.google.android.material.checkbox.MaterialCheckBox +import com.tangem.tangemtest.R +import com.tangem.tangemtest._arch.structure.impl.BoolItem +import com.tangem.tangemtest._arch.widget.abstraction.getName +import com.tangem.tangemtest.ucase.variants.personalize.ui.widgets.DescriptionWidget +import ru.dev.gbixahue.eu4d.lib.android._android.views.colorFrom + +/** +[REDACTED_AUTHOR] + */ +class CheckBoxWidget(parent: ViewGroup, private val boolItem: BoolItem) : DescriptionWidget(parent, boolItem) { + override fun getLayoutId(): Int = R.layout.w_response_item_checkbox + + private val switchItem = view.findViewById(R.id.sw_item) + + init { + switchItem.text = getName() + switchItem.isChecked = dataItem.getData() ?: false + switchItem.isEnabled = false + switchItem.setTextColor(switchItem.colorFrom(R.color.action_name)) + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/ResponseItemBuilder.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/ResponseItemBuilder.kt similarity index 75% rename from tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/ResponseItemBuilder.kt rename to tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/ResponseItemBuilder.kt index dd80c57862..cde044dc2c 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/ResponseItemBuilder.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/ResponseItemBuilder.kt @@ -1,11 +1,11 @@ -package com.tangem.tangemtest.ucase.ui +package com.tangem.tangemtest.ucase.variants.responses.ui.widget import android.view.ViewGroup import com.tangem.tangemtest._arch.structure.abstraction.BaseItem +import com.tangem.tangemtest._arch.structure.impl.BoolItem import com.tangem.tangemtest._arch.structure.impl.TextItem import com.tangem.tangemtest._arch.widget.ItemWidgetBuilder import com.tangem.tangemtest._arch.widget.abstraction.ViewWidget -import com.tangem.tangemtest.ucase.ui.widgets.ResponseTextWidget /** [REDACTED_AUTHOR] @@ -14,6 +14,7 @@ class ResponseItemBuilder : ItemWidgetBuilder { override fun build(item: BaseItem<*>, parent: ViewGroup): ViewWidget? { return when (item) { is TextItem -> ResponseTextWidget(parent, item) + is BoolItem -> CheckBoxWidget(parent, item) else -> null } } diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/widgets/ResponseTextWidget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/ResponseTextWidget.kt similarity index 53% rename from tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/widgets/ResponseTextWidget.kt rename to tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/ResponseTextWidget.kt index fde72c3d54..468b9963e7 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/widgets/ResponseTextWidget.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/widget/ResponseTextWidget.kt @@ -1,27 +1,38 @@ -package com.tangem.tangemtest.ucase.ui.widgets +package com.tangem.tangemtest.ucase.variants.responses.ui.widget import android.content.ClipData import android.content.ClipboardManager import android.content.Context +import android.view.View import android.view.ViewGroup import android.widget.TextView import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.impl.TextItem -import com.tangem.tangemtest._arch.widget.abstraction.getResNameId +import com.tangem.tangemtest._arch.widget.abstraction.getName import com.tangem.tangemtest.ucase.variants.personalize.ui.widgets.DescriptionWidget /** [REDACTED_AUTHOR] */ -class ResponseTextWidget(parent: ViewGroup, textItem: TextItem) : DescriptionWidget(parent, textItem) { +class ResponseTextWidget(parent: ViewGroup, private val textItem: TextItem) : DescriptionWidget(parent, textItem) { override fun getLayoutId(): Int = R.layout.w_response_item - private val tvName: TextView by lazy { view.findViewById(R.id.tv_name) } - private val tvValue: TextView by lazy { view.findViewById(R.id.tv_value) } + private val tvName: TextView = view.findViewById(R.id.tv_name) + private val tvValue: TextView = view.findViewById(R.id.tv_value) init { - tvName.setText(getResNameId()) - tvValue.text = dataItem.getData() + initWidgets() + } + + private fun initWidgets() { + val data = textItem.getData() + if (data == null || data.isEmpty()) { + view.visibility = View.GONE + return + } + + tvName.text = getName() + tvValue.text = data view.setOnClickListener { val clipboard = view.context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/scan/ui/ScanActionFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/scan/ui/ScanActionFragment.kt index 1edc4c72de..3ec710a4b7 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/scan/ui/ScanActionFragment.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/scan/ui/ScanActionFragment.kt @@ -8,7 +8,7 @@ import com.tangem.tangemtest.R import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager import com.tangem.tangemtest.ucase.domain.paramsManager.managers.ScanItemsManager import com.tangem.tangemtest.ucase.ui.BaseCardActionFragment -import com.tangem.tangemtest.ucase.ui.response.BaseCardResponseFragment +import com.tangem.tangemtest.ucase.variants.responses.ui.ResponseFragment /** [REDACTED_AUTHOR] @@ -28,7 +28,7 @@ class ScanActionFragment : BaseCardActionFragment() { actionVM.seReadResponse.observe(viewLifecycleOwner, Observer { navigateTo( R.id.action_nav_card_action_to_response_screen, - bundleOf(Pair(BaseCardResponseFragment.response, it)) + bundleOf(Pair(ResponseFragment.response, it)) ) }) } diff --git a/tangem-demo/src/main/res/layout/fg_card_response.xml b/tangem-demo/src/main/res/layout/fg_card_response.xml index f9aeaa5923..357f9c82c6 100644 --- a/tangem-demo/src/main/res/layout/fg_card_response.xml +++ b/tangem-demo/src/main/res/layout/fg_card_response.xml @@ -1,8 +1,8 @@ - + android:layout_height="match_parent"> - \ No newline at end of file + \ No newline at end of file diff --git a/tangem-demo/src/main/res/layout/w_response_item.xml b/tangem-demo/src/main/res/layout/w_response_item.xml index c44aa9cd78..c0f3b1e887 100644 --- a/tangem-demo/src/main/res/layout/w_response_item.xml +++ b/tangem-demo/src/main/res/layout/w_response_item.xml @@ -3,23 +3,24 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/root" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingStart="@dimen/def_indent" - android:paddingTop="6dp" - android:paddingEnd="@dimen/def_indent" - android:paddingBottom="6dp"> + android:layout_height="wrap_content"> + android:orientation="vertical" + android:paddingStart="@dimen/def_indent" + android:paddingTop="6dp" + android:paddingEnd="@dimen/def_indent" + android:paddingBottom="8dp"> + + \ No newline at end of file diff --git a/tangem-demo/src/main/res/layout/w_response_item_checkbox.xml b/tangem-demo/src/main/res/layout/w_response_item_checkbox.xml new file mode 100644 index 0000000000..2102af0305 --- /dev/null +++ b/tangem-demo/src/main/res/layout/w_response_item_checkbox.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + diff --git a/tangem-demo/src/main/res/navigation/navigation.xml b/tangem-demo/src/main/res/navigation/navigation.xml index cd84c2a849..8107b48599 100644 --- a/tangem-demo/src/main/res/navigation/navigation.xml +++ b/tangem-demo/src/main/res/navigation/navigation.xml @@ -127,7 +127,7 @@ diff --git a/tangem-demo/src/main/res/values/colors.xml b/tangem-demo/src/main/res/values/colors.xml index 20e2693328..c72e37bcd8 100644 --- a/tangem-demo/src/main/res/values/colors.xml +++ b/tangem-demo/src/main/res/values/colors.xml @@ -8,7 +8,10 @@ #E6959595 #2B2B2B - #888888 + + #888888 + #303030 + @color/field_info #C6C6C6 #FFE391 diff --git a/tangem-demo/src/main/res/values/strings.xml b/tangem-demo/src/main/res/values/strings.xml index 5cb0f4053a..df8e87a708 100644 --- a/tangem-demo/src/main/res/values/strings.xml +++ b/tangem-demo/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - Tangem Demo + Tangem Development Kit @string/app_name "Current card ID: " diff --git a/tangem-demo/src/main/res/values/strings_response.xml b/tangem-demo/src/main/res/values/strings_response.xml new file mode 100644 index 0000000000..c0086d1186 --- /dev/null +++ b/tangem-demo/src/main/res/values/strings_response.xml @@ -0,0 +1,138 @@ + + + + + + CID + Manufacturer_Name + Status + Firmware_Version + Card_PublicKey + Settings_Mask + Is_Reusable + Use_Activation + Prohibit_Purge_Wallet + Use_Block + Allow_SET_PIN1 + Allow_SET_PIN2 + Use_CVC + Prohibit_Default_PIN1 + Use_One_CommandAtTime + Use_NDEF + Use_Dynamic_NDEF + Smart_Security_Delay + Allow_Unencrypted + Allow_Fast_Encryption + Protect_Issuer_Data_Against_Replay + Allow_Select_Blockchain + Disable_Precomputed_NDEF + Skip_Security_Delay_If_Validated_By_Issuer + Skip_Check_PIN2_and_CVC_If_Validated_By_Issuer + Skip_Security_Delay_If_Validated_By_Linked_Terminal + Restrict_Overwrite_Issuer_Extra_Data + 1 – prohibit overwriting Issuer_Extra_Data + Require_Term_Tx_Signature + Require_Term_Cert_Signature + Check_PIN3_on_Card + Card_Data + Issuer_Data_PublicKey + Curve_ID + Max_Signatures + Signing_Method + Pause_Before_PIN2 + Wallet_PublicKey + Wallet_Remaining_Signatures + Wallet_Signed_Hashes + Health + Is_Activated + Activation_Seed + Payment_Flow_Version + User_Counter + User_Protected_Counter + + + Unique Tangem card ID number + Name of Tangem card manufacturer + Current status of the card + Version of Tangem COS + Public key that is used to authenticate the card against manufacturer’s database. It is generated one time during card manufacturing. See Security section for more details. + Card settings defined by personalization (bit mask: 0 – Enabled, 1 – Disabled): + Defines what happens when user calls PURGE_WALLET command: + \n0 - Card will switch to Purged state + \n1 - Card will switch to Empty state and let create a new wallet again + + 0 – Card will accept PURGE_WALLET command + \n1 – Card will reject PURGE_WALLET command + + Is user allowed to change PIN1 with SET_PIN command + Is user allowed to change PIN2 with SET_PIN command + All commands requiring PIN2 will also require additional CVC code printed on the card + SET_PIN commands will not change PIN1 to default value (‘000000’). + Card will execute only one command during one communication session, thus requiring user to physically take the card away from the host after each action (all commands except for READ_CARD). + Whether the card should emulate NDEF. In default configuration, two NDEF records are loaded during personalization: (1) Tangem web site address, (2) name of Android App package in Google Play Store. + 0 – Disable dynamic generation of NDEF for iOS. See Dynamic NDEF section for more details. + /n1 – Enable dynamic NDEF for iOS. + Security delay Pause_Before_PIN2 will not be applied if PIN2 is not default. + Whether the card supports unencrypted NFC communication. See NFC communication section for more details. + Whether the card supports fast encrypted NFC communication. See NFC communication section for more details. + 0 – No replay protection on write issuer data + /n1 – Enable replay protection on write issuer data (card will require additional Issuer_Data_Counter incremented on each write) + 0 – Wallet elliptic curve and blockchain information stored during PERSONALIZE command and never change + /n1 – Wallet elliptic curve and blockchain information can be changed on CREATE_WALLET command + 0 – Enable precomputed dynamic NDEF to work around iPhone 7+ NFC bug. + /n1 – Disable precomputed dynamic NDEF. See Dynamic NDEF section for more details. + 0 – Enforce security delay in SIGN command if the issuer validates the transaction (for signing methods 2, 3, 4 and 5). + /n1 – Skip security delay in SIGN command if the issuer validates the transaction (for signing methods 2, 3, 4 and 5). + 0 – Require and check PIN2 and CVC in SIGN command if the issuer validates the transaction (for signing method 2, 3, 4 and 5). + /n1 – Skip checking PIN2 and CVC in SIGN command if the issuer validates the transaction (for signing method 2, 3, 4 and 5). + 1 - Store Terminal_PublicKey public key of linked terminal no each SIGN command, skip security delay if valid signature of transaction is made with Terminal_PrivateKey is provided in SIGN command + + + 0 – Skip checking terminal’s signature when signing POS transaction + /n1 – Check terminal’s signature when signing POS transaction + 0 – Skip checking acquirer’s signature of terminal certificate when signing POS transaction + /n1 – Check acquirer’s signature of terminal certificate when signing POS transaction + 0 – Additionally encrypt POS transaction signature with key derived from PIN3 when the transaction amount exceeds PIN3 floor limit + /n1 – Require terminal to send PIN3 to card when the POS transaction amount exceeds PIN3_Floor_Limit + Detailed information about card contents. Format is defined by the card issuer. Cards complaint with Tangem Wallet application should have TLV format described in Personalization section. + Public key that is used by the card issuer to sign Issuer_Data field. See Security section for more details. + Explicit text name of the elliptic curve used for all wallet key operations. + Total number of signatures allowed for the wallet when the card was personalized. + Defines what data should be submitted to SIGN command. + Delay in seconds before COS executes commands protected by PIN2. + Public key of the blockchain wallet. Value returned only if the wallet has already been created by CREATE_WALLET command. See Security section for more details. + Remaining number of SIGN operations before the wallet will stop signing transactions. Value returned only if the wallet has already been created by CREATE_WALLET command. + Total number of signed single hashes returned by the card in SIGN command responses since card personalization. Sums up array elements within all SIGN commands. + Any non-zero value indicates that the card experiences some hardware problems. User should withdraw the value to other blockchain wallet as soon as possible. Non-zero Health tag will also appear in responses of all other commands. + Whether the card requires issuer’s confirmation of activation. + /n0 – card will require issuer’s confirmation of activation, + /notherwise this field will not be returned (card is activated and operational). + A random challenge generated by PERSONALIZE command that should be signed and returned to COS by the issuer to confirm the card has been activated. See ACTIVATE_CARD command for more details. + /nThis field will not be returned if the card is activated. + Version of POS payment scheme supported by COS ([0x02,0x01] for version 2.30) + /nReturned only if SigningMethod ‘6’ enabling POS transactions is supported by card. + This value can be initialized by App and will be increased by COS with the execution of each SIGN command. For example, this field can store blockchain “nonce” for a quick one-touch transaction on POS terminals. Returned only if SigningMethod =6. + This value can be initialized by App (with PIN2 confirmation) and will be increased by COS with the execution of each SIGN command. For example, this field can store blockchain “nonce” for a quick one-touch transaction on POS terminals. Returned only if SigningMethod =6. + + + + Batch_ID + Manufacture_Date_Time + Issuer_Name + Blockchain_Name + Manufacturer_Signature + ProductMask + tokenSymbol + tokenContractAddress + tokenDecimal + + Tangem internal manufacturing batch ID, should correspond with the data in Tangem’s card list (see Card attestation and UID and CID sections) + Timestamp of manufacturing should correspond with the data in Tangem’s card list (see Card attestation section). + Name of the issuer + Name of the blockchain (once personalized, the target blockchain is fixed for the whole life cycle) + Signature of CID with the MANUFACTURER_PRIVATE_KEY + Mask of products enabled on card + + + + \ No newline at end of file