Updated on 2026-08-14

This commit is contained in:
Tangem 2020-04-08 23:04:48 +03:00
parent f9b627bd62
commit 6e762cc7ff
27 changed files with 611 additions and 53 deletions

View file

@ -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,

View file

@ -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<Resources>(da
fun DataWidget<*>.getResDescription(): Int? = MainResourceHolder.safeGet<Resources>(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)

View file

@ -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<Id>() {
PersonalizeResources().init(this)
ActionResources().init(this)
TlvResources().init(this)
ResponseResources().init(this)
}
inline fun <reified Res : Resources> safeGet(id: Id): Res {
val result = super.get(id) ?: Resources(R.string.unknown, R.string.unknown)
return result as Res
}
}
}

View file

@ -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))
}
}

View file

@ -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<Str
private val tvName = view.findViewById<TextView>(R.id.tv_name)
init {
tvName?.setText(getResNameId())
tvName.text = getName()
}
}

View file

@ -30,7 +30,7 @@ abstract class DescriptionWidget<D>(
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<D>(
TransitionManager.beginDelayedTransition(view.parent as ViewGroup, AutoTransition())
descriptionContainer.visibility = state
}
}
}

View file

@ -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) }
}

View file

@ -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<Numb
}
init {
tilItem.hint = tilItem.context.getString(getResNameId())
tilItem.hint = getName()
//TODO: remove from Widget
if (dataItem.id == CardNumber.Number) etItem.addInputFilter(InputFilter.LengthFilter(13))
etItem.setText(stringOf(dataItem.viewModel.data))
etItem.setText(stringOf(dataItem.getData()))
etItem.addTextChangedListener(watcher)
dataItem.viewModel.onDataUpdated = { silentUpdate(it) }
}

View file

@ -10,7 +10,7 @@ import com.tangem.tangemtest.R
import com.tangem.tangemtest._arch.structure.impl.KeyValue
import com.tangem.tangemtest._arch.structure.impl.ListItem
import com.tangem.tangemtest._arch.structure.impl.ListValueWrapper
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.inflate
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
@ -36,7 +36,7 @@ class SpinnerWidget(parent: ViewGroup, listItem: ListItem) : DescriptionWidget<L
init {
val name = view.findViewById<TextView>(R.id.tv_name)
name.setText(getResNameId())
name.text = getName()
spItem.adapter = spAdapter
spAdapter.getItemPosition(stringOf(data.selectedItem))?.let {
spItem.setSelection(it)

View file

@ -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<Boolea
}
init {
switchItem.setText(getResNameId())
switchItem.isChecked = dataItem.viewModel.data ?: false
switchItem.text = getName()
switchItem.isChecked = dataItem.getData() ?: false
switchItem.setOnCheckedChangeListener(changeListener)
dataItem.viewModel.onDataUpdated = {
switchItem.setOnCheckedChangeListener(null)

View file

@ -0,0 +1,44 @@
package com.tangem.tangemtest.ucase.variants.responses
import com.tangem.tangemtest._arch.structure.Id
/**
[REDACTED_AUTHOR]
*/
interface ResponseId : Id
enum class CardId : ResponseId {
cardId,
manufacturerName,
status,
firmwareVersion,
cardPublicKey,
settingsMask,
cardData,
issuerPublicKey,
curve,
maxSignatures,
signingMethod,
pauseBeforePin2,
walletPublicKey,
walletRemainingSignatures,
walletSignedHashes,
health,
isActivated,
activationSeed,
paymentFlowVersion,
userCounter,
userProtectedCounter,
}
enum class CardDataId : ResponseId {
batchId,
manufactureDateTime,
issuerName,
blockchainName,
manufacturerSignature,
productMask,
tokenSymbol,
tokenContractAddress,
tokenDecimal,
}

View file

@ -0,0 +1,41 @@
package com.tangem.tangemtest.ucase.variants.responses
import android.view.View
import androidx.lifecycle.ViewModel
import com.tangem.tangemtest._arch.structure.abstraction.BaseItem
import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest._arch.structure.abstraction.ModelToItems
import com.tangem.tangemtest._arch.structure.abstraction.iterate
import com.tangem.tangemtest.ucase.variants.responses.converter.ConvertersStore
import com.tangem.tasks.TaskEvent
import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
/**
[REDACTED_AUTHOR]
*/
class ResponseViewModel : ViewModel() {
private val convertersHolder = ConvertersStore()
private var itemList: List<Item>? = null
fun createItemList(taskEvent: TaskEvent<*>): List<Item> {
Log.d(this, "createItemList: itemList size: ${itemList?.size ?: 0}")
val event = taskEvent as? TaskEvent.Event<Any> ?: return emptyList()
val type = event.data::class.java
val converter = convertersHolder.get(type) as? ModelToItems<Any> ?: 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
}
}
}

View file

@ -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<Card> {
override fun convert(from: Card): List<Item> {
val itemList = mutableListOf<Item>()
// 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)) }
}

View file

@ -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<Type, Any>() {
init {
register(ScanEvent.OnReadEvent::class.java, ReadEventConverter())
register(SignResponse::class.java, SignResponseConverter())
register(Card::class.java, CardConverter())
register(DepersonalizeResponse::class.java, DepersonalizeResponseConverter())
}
}

View file

@ -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<ScanEvent.OnReadEvent> {
override fun convert(from: ScanEvent.OnReadEvent): List<Item> = CardConverter().convert(from.card)
}
class SignResponseConverter : ModelToItems<SignResponse> {
override fun convert(from: SignResponse): List<Item> {
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<DepersonalizeResponse> {
override fun convert(from: DepersonalizeResponse): List<Item> {
return listOf(TextItem(StringId("Is success"), stringOf(from.success)))
}
}

View file

@ -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<LinearLayout>(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)
})
}
}

View file

@ -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<Boolean>(parent, boolItem) {
override fun getLayoutId(): Int = R.layout.w_response_item_checkbox
private val switchItem = view.findViewById<MaterialCheckBox>(R.id.sw_item)
init {
switchItem.text = getName()
switchItem.isChecked = dataItem.getData() ?: false
switchItem.isEnabled = false
switchItem.setTextColor(switchItem.colorFrom(R.color.action_name))
}
}

View file

@ -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
}
}

View file

@ -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<String>(parent, textItem) {
class ResponseTextWidget(parent: ViewGroup, private val textItem: TextItem) : DescriptionWidget<String>(parent, textItem) {
override fun getLayoutId(): Int = R.layout.w_response_item
private val tvName: TextView by lazy { view.findViewById<TextView>(R.id.tv_name) }
private val tvValue: TextView by lazy { view.findViewById<TextView>(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

View file

@ -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))
)
})
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="match_parent">
<ScrollView
android:id="@+id/scroll_view"
@ -19,4 +19,4 @@
</ScrollView>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -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">
<LinearLayout
android:id="@+id/container_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:orientation="vertical"
android:paddingStart="@dimen/def_indent"
android:paddingTop="6dp"
android:paddingEnd="@dimen/def_indent"
android:paddingBottom="8dp">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="@color/field_content"
android:textSize="16sp"
tools:text="Custom blockchain" />
<TextView
@ -27,11 +28,18 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
android:textSize="14sp"
android:textColor="@color/field_info"
android:textSize="13sp"
tools:text="Not Defined" />
<include layout="@layout/w_field_description" />
</LinearLayout>
<include
layout="@layout/m_divider_h"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom" />
</FrameLayout>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
android:paddingStart="@dimen/def_indent"
android:paddingTop="14dp"
android:paddingEnd="@dimen/def_indent"
android:paddingBottom="14dp">
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/sw_item"
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_marginEnd="2dp"
android:button="@null"
android:drawableEnd="?android:attr/listChoiceIndicatorMultiple"
android:textColor="@color/field_content"
android:textSize="@dimen/iw_text_size"
tools:text="Some text field" />
<include
layout="@layout/w_field_description"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<include
layout="@layout/m_divider_h"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom" />
</FrameLayout>

View file

@ -127,7 +127,7 @@
<fragment
android:id="@+id/nav_card_response"
android:name="com.tangem.tangemtest.ucase.ui.response.BaseCardResponseFragment"
android:name="com.tangem.tangemtest.ucase.variants.responses.ui.ResponseFragment"
android:label="@string/unknown"
tools:layout="@layout/fg_card_response" />

View file

@ -8,7 +8,10 @@
<color name="edit_text_underline">#E6959595</color>
<color name="action_name">#2B2B2B</color>
<color name="field_description">#888888</color>
<color name="field_info">#888888</color>
<color name="field_content">#303030</color>
<color name="field_description">@color/field_info</color>
<color name="switchTrack">#C6C6C6</color>
<color name="switchTrackActive">#FFE391</color>

View file

@ -1,5 +1,5 @@
<resources>
<string name="app_name">Tangem Demo</string>
<string name="app_name">Tangem Development Kit</string>
<string name="fg_name_entry_point">@string/app_name</string>
<string name="current_card_id">"Current card ID: "</string>

View file

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Field names - Response: Card -->
<string name="response_card_cid">CID</string>
<string name="response_card_manufacturer_name">Manufacturer_Name</string>
<string name="response_card_status">Status</string>
<string name="response_card_firmware_version">Firmware_Version</string>
<string name="response_card_public_key">Card_PublicKey</string>
<string name="response_card_settings_mask">Settings_Mask</string>
<string name="response_card_is_reusable">Is_Reusable</string>
<string name="response_card_use_activation">Use_Activation</string>
<string name="response_card_purge_wallet">Prohibit_Purge_Wallet</string>
<string name="response_card_use_block">Use_Block</string>
<string name="response_card_allow_pin">Allow_SET_PIN1</string>
<string name="response_card_allow_pin2">Allow_SET_PIN2</string>
<string name="response_card_use_cvc">Use_CVC</string>
<string name="response_card_default_pin">Prohibit_Default_PIN1</string>
<string name="response_card_one_apdu_at_time">Use_One_CommandAtTime</string>
<string name="response_card_use_ndef">Use_NDEF</string>
<string name="response_card_use_dynamic_ndef">Use_Dynamic_NDEF</string>
<string name="response_card_smart_security_delay">Smart_Security_Delay</string>
<string name="response_card_allow_unencrypted">Allow_Unencrypted</string>
<string name="response_card_allow_fast_encryption">Allow_Fast_Encryption</string>
<string name="response_card_protect_issuer_data_against_replay">Protect_Issuer_Data_Against_Replay</string>
<string name="response_card_allow_select_blockchain">Allow_Select_Blockchain</string>
<string name="response_card_disable_precomputed_ndef">Disable_Precomputed_NDEF</string>
<string name="response_card_security_delay_if_validated">Skip_Security_Delay_If_Validated_By_Issuer</string>
<string name="response_card_skip_pin2_cvc_if_validated_by_issuer">Skip_Check_PIN2_and_CVC_If_Validated_By_Issuer</string>
<string name="response_card_skip_security_delay_if_validated_by_linked_terminal">Skip_Security_Delay_If_Validated_By_Linked_Terminal</string>
<string name="response_card_restrict_overwrite_issuer_ex_data">Restrict_Overwrite_Issuer_Extra_Data</string>
<string name="response_card_prohibit_overwriting_issuer_ex_data">1 prohibit overwriting Issuer_Extra_Data</string>
<string name="response_card_require_terminal_tx_sig">Require_Term_Tx_Signature</string>
<string name="response_card_require_terminal_cert_sig">Require_Term_Cert_Signature</string>
<string name="response_card_check_pin3">Check_PIN3_on_Card</string>
<string name="response_card_card_data">Card_Data</string>
<string name="response_card_issuer_data_public_key">Issuer_Data_PublicKey</string>
<string name="response_card_curve">Curve_ID</string>
<string name="response_card_max_signatures">Max_Signatures</string>
<string name="response_card_signing_method">Signing_Method</string>
<string name="response_card_pause_before_pin2">Pause_Before_PIN2</string>
<string name="response_card_wallet_public_key">Wallet_PublicKey</string>
<string name="response_card_wallet_remaining_signatures">Wallet_Remaining_Signatures</string>
<string name="response_card_wallet_signed_hashes">Wallet_Signed_Hashes</string>
<string name="response_card_health">Health</string>
<string name="response_card_is_activated">Is_Activated</string>
<string name="response_card_activation_seed">Activation_Seed</string>
<string name="response_card_payment_flow_version">Payment_Flow_Version</string>
<string name="response_card_user_counter">User_Counter</string>
<string name="response_card_user_protected_counter">User_Protected_Counter</string>
<string name="info_response_card_cid">Unique Tangem card ID number</string>
<string name="info_response_card_manufacturer_name">Name of Tangem card manufacturer</string>
<string name="info_response_card_status">Current status of the card</string>
<string name="info_response_card_firmware_version">Version of Tangem COS</string>
<string name="info_response_card_public_key">Public key that is used to authenticate the card against manufacturers database. It is generated one time during card manufacturing. See Security section for more details.</string>
<string name="info_response_card_settings_mask">Card settings defined by personalization (bit mask: 0 Enabled, 1 Disabled):</string>
<string name="info_response_card_is_reusable">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</string>
<string name="info_response_card_use_activation"></string>
<string name="info_response_card_purge_wallet">0 Card will accept PURGE_WALLET command
\n1 Card will reject PURGE_WALLET command</string>
<string name="info_response_card_use_block"></string>
<string name="info_response_card_allow_pin">Is user allowed to change PIN1 with SET_PIN command</string>
<string name="info_response_card_allow_pin2">Is user allowed to change PIN2 with SET_PIN command</string>
<string name="info_response_card_use_cvc">All commands requiring PIN2 will also require additional CVC code printed on the card</string>
<string name="info_response_card_default_pin">SET_PIN commands will not change PIN1 to default value (000000).</string>
<string name="info_response_card_one_apdu_at_time">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).</string>
<string name="info_response_card_use_ndef">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.</string>
<string name="info_response_card_use_dynamic_ndef">0 Disable dynamic generation of NDEF for iOS. See Dynamic NDEF section for more details.
/n1 Enable dynamic NDEF for iOS.</string>
<string name="info_response_card_smart_security_delay">Security delay Pause_Before_PIN2 will not be applied if PIN2 is not default.</string>
<string name="info_response_card_allow_unencrypted">Whether the card supports unencrypted NFC communication. See NFC communication section for more details.</string>
<string name="info_response_card_allow_fast_encryption">Whether the card supports fast encrypted NFC communication. See NFC communication section for more details.</string>
<string name="info_response_card_protect_issuer_data_against_replay">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)</string>
<string name="info_response_card_allow_select_blockchain">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</string>
<string name="info_response_card_disable_precomputed_ndef">0 Enable precomputed dynamic NDEF to work around iPhone 7+ NFC bug.
/n1 Disable precomputed dynamic NDEF. See Dynamic NDEF section for more details.</string>
<string name="info_response_card_security_delay_if_validated">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).</string>
<string name="info_response_card_skip_pin2_cvc_if_validated_by_issuer">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).</string>
<string name="info_response_card_skip_security_delay_if_validated_by_linked_terminal">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</string>
<string name="info_response_card_restrict_overwrite_issuer_ex_data"></string>
<string name="info_info_response_card_prohibit_overwriting_issuer_ex_data"></string>
<string name="info_response_card_require_terminal_tx_sig">0 Skip checking terminals signature when signing POS transaction
/n1 Check terminals signature when signing POS transaction</string>
<string name="info_response_card_require_terminal_cert_sig">0 Skip checking acquirers signature of terminal certificate when signing POS transaction
/n1 Check acquirers signature of terminal certificate when signing POS transaction</string>
<string name="info_response_card_check_pin3">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</string>
<string name="info_response_card_card_data">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.</string>
<string name="info_response_card_issuer_data_public_key">Public key that is used by the card issuer to sign Issuer_Data field. See Security section for more details.</string>
<string name="info_response_card_curve">Explicit text name of the elliptic curve used for all wallet key operations.</string>
<string name="info_response_card_max_signatures">Total number of signatures allowed for the wallet when the card was personalized.</string>
<string name="info_response_card_signing_method">Defines what data should be submitted to SIGN command.</string>
<string name="info_response_card_pause_before_pin2">Delay in seconds before COS executes commands protected by PIN2.</string>
<string name="info_response_card_wallet_public_key">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.</string>
<string name="info_response_card_wallet_remaining_signatures">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.</string>
<string name="info_response_card_wallet_signed_hashes">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.</string>
<string name="info_response_card_health">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.</string>
<string name="info_response_card_is_activated">Whether the card requires issuers confirmation of activation.
/n0 card will require issuers confirmation of activation,
/notherwise this field will not be returned (card is activated and operational).</string>
<string name="info_response_card_activation_seed">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.</string>
<string name="info_response_card_payment_flow_version">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.</string>
<string name="info_response_card_user_counter">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.</string>
<string name="info_response_card_user_protected_counter">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.</string>
<!-- Field names - Response: Card.cardData -->
<string name="response_card_card_data_batch_id">Batch_ID</string>
<string name="response_card_card_data_manufacture_date_time">Manufacture_Date_Time</string>
<string name="response_card_card_data_issuer_name">Issuer_Name</string>
<string name="response_card_card_data_blockchain_name">Blockchain_Name</string>
<string name="response_card_card_data_manufacturer_signature">Manufacturer_Signature</string>
<string name="response_card_card_data_product_mask">ProductMask</string>
<string name="response_card_card_data_token_symbol">tokenSymbol</string>
<string name="response_card_card_data_token_contract_address">tokenContractAddress</string>
<string name="response_card_card_data_token_decimal">tokenDecimal</string>
<string name="info_response_card_card_data_batch_id">Tangem internal manufacturing batch ID, should correspond with the data in Tangems card list (see Card attestation and UID and CID sections)</string>
<string name="info_response_card_card_data_manufacture_date_time">Timestamp of manufacturing should correspond with the data in Tangems card list (see Card attestation section).</string>
<string name="info_response_card_card_data_issuer_name">Name of the issuer</string>
<string name="info_response_card_card_data_blockchain_name">Name of the blockchain (once personalized, the target blockchain is fixed for the whole life cycle)</string>
<string name="info_response_card_card_data_manufacturer_signature">Signature of CID with the MANUFACTURER_PRIVATE_KEY</string>
<string name="info_response_card_card_data_product_mask">Mask of products enabled on card</string>
<string name="info_response_card_card_data_token_symbol"></string>
<string name="info_response_card_card_data_token_contract_address"></string>
<string name="info_response_card_card_data_token_decimal"></string>
</resources>