From 8a6f9f3ff61ed0386c2e2d8fa3ca8f33564e13b6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Mar 2020 22:55:21 +0300 Subject: [PATCH] Updated on 2026-08-14 --- tangem-demo/build.gradle | 2 +- .../src/main/assets/personalize_default.json | 55 +++ .../com/tangem/tangemtest/AppTangemDemo.kt | 7 +- .../tangem/tangemtest/TestUserDataActivity.kt | 270 +++++------ .../_arch/structure/base/abstracts.kt | 20 + .../tangemtest/_arch/structure/base/logger.kt | 36 ++ .../tangemtest/_arch/structure/base/unit.kt | 17 + .../_arch/structure/base/unit_block.kt | 53 +++ .../_arch/structure/base/unit_model.kt | 31 ++ .../_arch/structure/base/unit_plugin.kt | 10 + .../tangemtest/_arch/structure/impl/blocks.kt | 8 + .../tangemtest/_arch/structure/impl/items.kt | 18 + .../_arch/structure/impl/view_models.kt | 14 + .../_main/entry_point/EntryPointFragment.kt | 9 + .../card_use_cases/domain/CardContext.kt | 31 -- .../domain/card_action/card_actions.kt | 6 + .../domain/params_manager/factory.kt | 1 + .../domain/params_manager/params_managers.kt | 19 +- .../ui/personalize/PersonalizeFragment.kt | 70 +++ .../json_test/encode_decode.kt | 21 + .../json_test/json_dto.kt | 111 +++++ .../json_test/to_block.kt | 213 +++++++++ .../json_test/to_json.kt | 8 + .../view_model/PersonalizeViewModel.kt | 29 ++ .../ui/personalize/widgets/block_widget.kt | 62 +++ .../ui/personalize/widgets/unit_widget.kt | 64 +++ .../ui/personalize/widgets/widgets.kt | 128 ++++++ .../tangem/tangemtest/commons/abstracts.kt | 8 - .../com/tangem/tangemtest/commons/logs.kt | 4 +- .../tangem/tangemtest/commons/navigation.kt | 1 + .../res/layout/activity_test_user_data.xml | 428 +++++++++--------- .../src/main/res/layout/fg_entry_point.xml | 10 + .../src/main/res/layout/fg_personalize.xml | 13 + .../src/main/res/layout/old_activity_main.xml | 202 ++++----- .../src/main/res/layout/vh_actions.xml | 2 +- .../main/res/layout/vh_sp_dropdown_item.xml | 11 + .../src/main/res/layout/vh_sp_item.xml | 9 + tangem-demo/src/main/res/layout/w_empty.xml | 4 + .../main/res/layout/w_field_description.xml | 18 + .../layout/w_personalize_item_edit_text.xml | 34 ++ .../res/layout/w_personalize_item_number.xml | 35 ++ .../res/layout/w_personalize_item_spinner.xml | 28 ++ .../res/layout/w_personalize_item_switch.xml | 20 + .../res/layout/w_personalize_item_text.xml | 20 + .../main/res/layout/w_personilize_block.xml | 6 + .../src/main/res/navigation/navigation.xml | 13 +- tangem-demo/src/main/res/values/dimens.xml | 6 + tangem-demo/src/main/res/values/strings.xml | 70 +++ 48 files changed, 1752 insertions(+), 503 deletions(-) create mode 100644 tangem-demo/src/main/assets/personalize_default.json create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/abstracts.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/logger.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_block.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_model.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_plugin.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/blocks.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/items.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/view_models.kt delete mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/CardContext.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/PersonalizeFragment.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/encode_decode.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/json_dto.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/to_block.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/to_json.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/view_model/PersonalizeViewModel.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/block_widget.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/unit_widget.kt create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/widgets.kt delete mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/commons/abstracts.kt create mode 100644 tangem-demo/src/main/res/layout/fg_personalize.xml create mode 100644 tangem-demo/src/main/res/layout/vh_sp_dropdown_item.xml create mode 100644 tangem-demo/src/main/res/layout/vh_sp_item.xml create mode 100644 tangem-demo/src/main/res/layout/w_empty.xml create mode 100644 tangem-demo/src/main/res/layout/w_field_description.xml create mode 100644 tangem-demo/src/main/res/layout/w_personalize_item_edit_text.xml create mode 100644 tangem-demo/src/main/res/layout/w_personalize_item_number.xml create mode 100644 tangem-demo/src/main/res/layout/w_personalize_item_spinner.xml create mode 100644 tangem-demo/src/main/res/layout/w_personalize_item_switch.xml create mode 100644 tangem-demo/src/main/res/layout/w_personalize_item_text.xml create mode 100644 tangem-demo/src/main/res/layout/w_personilize_block.xml diff --git a/tangem-demo/build.gradle b/tangem-demo/build.gradle index 67f976cb93..405747555f 100644 --- a/tangem-demo/build.gradle +++ b/tangem-demo/build.gradle @@ -51,5 +51,5 @@ dependencies { implementation "androidx.viewpager2:viewpager2:1.0.0" implementation 'com.google.code.gson:gson:2.8.6' - implementation 'com.github.gbIxaHue:eu4d:0.3.4' + implementation 'com.github.gbIxaHue:eu4d:0.3.6' } diff --git a/tangem-demo/src/main/assets/personalize_default.json b/tangem-demo/src/main/assets/personalize_default.json new file mode 100644 index 0000000000..e18ecffeac --- /dev/null +++ b/tangem-demo/src/main/assets/personalize_default.json @@ -0,0 +1,55 @@ +{ + "releaseVersion": false, + "issuerName": "TANGEM SDK", + "series": "DB", + "startNumber": 300000000, + "count": 20, + "numberFormat": "", + "PIN": "000000", + "PIN2": "000", + "PIN3": "", + "hexCrExKey": "", + "CVC": "000", + "pauseBeforePIN2": 15000, + "smartSecurityDelay": true, + "curveID": "ed25519", + "SigningMethod": 0, + "MaxSignatures": 1000000, + "isReusable": true, + "allowSwapPIN": false, + "allowSwapPIN2": true, + "useActivation": false, + "useCVC": false, + "useNDEF": true, + "useDynamicNDEF": true, + "useOneCommandAtTime": false, + "useBlock": false, + "allowSelectBlockchain": false, + "forbidPurgeWallet": false, + "protocolAllowUnencrypted": true, + "protocolAllowStaticEncryption": true, + "protectIssuerDataAgainstReplay": true, + "forbidDefaultPIN": false, + "disablePrecomputedNDEF": false, + "skipSecurityDelayIfValidatedByIssuer": false, + "skipCheckPIN2andCVCIfValidatedByIssuer": false, + "skipSecurityDelayIfValidatedByLinkedTerminal": true, + "restrictOverwriteIssuerDataEx": false, + "requireTerminalTxSignature": false, + "requireTerminalCertSignature": false, + "checkPIN3onCard": false, + "ndef": { + "type": "AAR", + "value": "com.tangem.wallet" + }, + "cardData": { + "date": "2020-02-17", + "batch": "FF87", + "blockchain": "IROHA", + "product_note": true, + "product_tag": false, + "product_id_card": false + }, + "createWallet": 1, + "issuerData": null +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/AppTangemDemo.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/AppTangemDemo.kt index 199844f32f..fd90e38433 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/AppTangemDemo.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/AppTangemDemo.kt @@ -1,6 +1,8 @@ package com.tangem.tangemtest import android.app.Application +import com.tangem.tangemtest._arch.structure.base.ULog +import com.tangem.tangemtest._arch.structure.base.UnitLogger import com.tangem.tangemtest.commons.TangemLogger import ru.dev.gbixahue.eu4d.lib.android.global.log.Log @@ -12,10 +14,11 @@ class AppTangemDemo : Application() { override fun onCreate() { super.onCreate() - setLogger() + setupLoggers() } - private fun setLogger() { + private fun setupLoggers() { Log.setLogger(TangemLogger()) + ULog.setLogger(UnitLogger()) } } diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt index 5b187df946..9ffcba3103 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt @@ -19,162 +19,162 @@ import java.nio.charset.StandardCharsets /** [REDACTED_AUTHOR] */ -class TestUserDataActivity: AppCompatActivity() { +class TestUserDataActivity : AppCompatActivity() { - private lateinit var cardManager: CardManager - private lateinit var writeOptions: WriteOptions + private lateinit var cardManager: CardManager + private lateinit var writeOptions: WriteOptions - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_test_user_data) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_test_user_data) - init() - initWriteOptions() - } - - private fun init() { - cardManager = CardManager.init(this) - - btn_scan?.setOnClickListener { _ -> - cardManager.scanCard { taskEvent -> - when (taskEvent) { - is TaskEvent.Event -> { - when (taskEvent.data) { - is ScanEvent.OnReadEvent -> { - // Handle returned card data - writeOptions.cardId = (taskEvent.data as ScanEvent.OnReadEvent).card.cardId - runOnUiThread { showReadWriteSection(true) } - } - is ScanEvent.OnVerifyEvent -> { - //Handle card verification - } - } - } - is TaskEvent.Completion -> { - if (taskEvent.error != null) { - if (taskEvent.error is TaskError.UserCancelled) { - // Handle case when user cancelled manually - } - // Handle other errors - } - // Handle completion - } - } - } + init() + initWriteOptions() } - btn_write.setOnClickListener { - if (writeOptions.cardId == null) return@setOnClickListener + private fun init() { + cardManager = CardManager.init(this) - cardManager.writeUserData( - writeOptions.cardId !!, - writeOptions.userData, - writeOptions.userProtectedData, - writeOptions.userCounter, - writeOptions.userProtectedCounter - ) { - when (it) { - is TaskEvent.Completion -> handleError(tv_write_result, it.error) - is TaskEvent.Event -> { - runOnUiThread { - val data = it.data as? WriteUserDataResponse - if (data == null) { - tv_write_result.text = "Response doesn't match" - return@runOnUiThread - } - tv_write_result?.text = "Success" + btn_scan?.setOnClickListener { _ -> + cardManager.scanCard { taskEvent -> + when (taskEvent) { + is TaskEvent.Event -> { + when (taskEvent.data) { + is ScanEvent.OnReadEvent -> { + // Handle returned card data + writeOptions.cardId = (taskEvent.data as ScanEvent.OnReadEvent).card.cardId + runOnUiThread { showReadWriteSection(true) } + } + is ScanEvent.OnVerifyEvent -> { + //Handle card verification + } + } + } + is TaskEvent.Completion -> { + if (taskEvent.error != null) { + if (taskEvent.error is TaskError.UserCancelled) { + // Handle case when user cancelled manually + } + // Handle other errors + } + // Handle completion + } + } + } + } + + btn_write.setOnClickListener { + if (writeOptions.cardId == null) return@setOnClickListener + + cardManager.writeUserData( + writeOptions.cardId!!, + writeOptions.userData, + writeOptions.userProtectedData, + writeOptions.userCounter, + writeOptions.userProtectedCounter + ) { + when (it) { + is TaskEvent.Completion -> handleError(tv_write_result, it.error) + is TaskEvent.Event -> { + runOnUiThread { + val data = it.data as? WriteUserDataResponse + if (data == null) { + tv_write_result.text = "Response doesn't match" + return@runOnUiThread + } + tv_write_result?.text = "Success" + } + } + } + } + } + + btn_read.setOnClickListener { + if (writeOptions.cardId == null) return@setOnClickListener + + cardManager.readUserData(writeOptions.cardId!!) { + when (it) { + is TaskEvent.Completion -> handleError(tv_read_result, it.error) + is TaskEvent.Event -> { + runOnUiThread { + val data = it.data as? ReadUserDataResponse + if (data == null) { + tv_read_result.text = "Response doesn't match" + return@runOnUiThread + } + tv_read_result?.text = "Success" + + writeOptions.userData = data.userData + writeOptions.userProtectedData = data.userProtectedData + writeOptions.userCounter = data.userCounter + writeOptions.userProtectedCounter = data.userProtectedCounter + + tv_card_cid.text = data.cardId + tv_data.text = String(data.userData, StandardCharsets.US_ASCII) + tv_protected_data.text = String(data.userProtectedData, StandardCharsets.US_ASCII) + tv_counter.text = data.userCounter.toString() + tv_protected_counter.text = data.userProtectedCounter.toString() + } + + } + } } - } } - } } - btn_read.setOnClickListener { - if (writeOptions.cardId == null) return@setOnClickListener + private fun handleError(tv: TextView, error: TaskError?) { + val er = error ?: return + if (er is TaskError.UserCancelled) return - cardManager.readUserData(writeOptions.cardId !!) { - when (it) { - is TaskEvent.Completion -> handleError(tv_read_result, it.error) - is TaskEvent.Event -> { - runOnUiThread { - val data = it.data as? ReadUserDataResponse - if (data == null) { - tv_read_result.text = "Response doesn't match" - return@runOnUiThread - } - tv_read_result?.text = "Success" - - writeOptions.userData = data.userData - writeOptions.userProtectedData = data.userProtectedData - writeOptions.userCounter = data.userCounter - writeOptions.userProtectedCounter = data.userProtectedCounter - - tv_card_cid.text = data.cardId - tv_data.text = String(data.userData, StandardCharsets.US_ASCII) - tv_protected_data.text = String(data.userProtectedData, StandardCharsets.US_ASCII) - tv_counter.text = data.userCounter.toString() - tv_protected_counter.text = data.userProtectedCounter.toString() - } - - } - } - } + runOnUiThread { tv.text = er::class.simpleName } } - } - private fun handleError(tv: TextView, error: TaskError?) { - val er = error ?: return - if (er is TaskError.UserCancelled) return + private fun initWriteOptions() { + writeOptions = WriteOptions() - runOnUiThread { tv.text = er::class.simpleName } - } + chb_with_ud.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateData(buttonView) } + chb_with_ud_protected.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateProtectedData(buttonView) } + chb_with_counter.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateCounter(buttonView) } + chb_with_protected_counter.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateProtectedCounter(buttonView) } + chb_with_pin2.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updatePin2(buttonView) } + } - private fun initWriteOptions() { - writeOptions = WriteOptions() - - chb_with_ud.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateData(buttonView) } - chb_with_ud_protected.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateProtectedData(buttonView) } - chb_with_counter.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateCounter(buttonView) } - chb_with_protected_counter.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateProtectedCounter(buttonView) } - chb_with_pin2.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updatePin2(buttonView) } - } - - private fun showReadWriteSection(show: Boolean) { - val state = if (show) View.VISIBLE else View.GONE - cl_read_write.visibility = state - } + private fun showReadWriteSection(show: Boolean) { + val state = if (show) View.VISIBLE else View.GONE + cl_read_write.visibility = state + } } class WriteOptions { - var cardId: String? = null - var userData: ByteArray? = null - var userProtectedData: ByteArray? = null - var userCounter: Int? = null - var userProtectedCounter: Int? = null - var pin2: String? = null + var cardId: String? = null + var userData: ByteArray? = null + var userProtectedData: ByteArray? = null + var userCounter: Int? = null + var userProtectedCounter: Int? = null + var pin2: String? = null - fun updateData(chbx: CompoundButton) { - val value = "simple user data".toByteArray() - userData = if (chbx.isChecked) value else null - } + fun updateData(chbx: CompoundButton) { + val value = "simple user data".toByteArray() + userData = if (chbx.isChecked) value else null + } - fun updateProtectedData(chbx: CompoundButton) { - val value = "protected user data".toByteArray() - userProtectedData = if (chbx.isChecked) value else null - } + fun updateProtectedData(chbx: CompoundButton) { + val value = "protected user data".toByteArray() + userProtectedData = if (chbx.isChecked) value else null + } - fun updateCounter(chbx: CompoundButton) { - val value = if (userCounter == null) 0 else userCounter !! + 1 - userCounter = if (chbx.isChecked) value else null - } + fun updateCounter(chbx: CompoundButton) { + val value = if (userCounter == null) 0 else userCounter!! + 1 + userCounter = if (chbx.isChecked) value else null + } - fun updateProtectedCounter(chbx: CompoundButton) { - val value = if (userProtectedCounter == null) 0 else userProtectedCounter !! + 1 - userProtectedCounter = if (chbx.isChecked) value else null - } + fun updateProtectedCounter(chbx: CompoundButton) { + val value = if (userProtectedCounter == null) 0 else userProtectedCounter!! + 1 + userProtectedCounter = if (chbx.isChecked) value else null + } - fun updatePin2(chbx: CompoundButton) { - val value = CardEnvironment.DEFAULT_PIN2 - pin2 = if (chbx.isChecked) value else null - } + fun updatePin2(chbx: CompoundButton) { + val value = CardEnvironment.DEFAULT_PIN2 + pin2 = if (chbx.isChecked) value else null + } } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/abstracts.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/abstracts.kt new file mode 100644 index 0000000000..a6b60c5ac0 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/abstracts.kt @@ -0,0 +1,20 @@ +package com.tangem.tangemtest._arch.structure.base + +/** +[REDACTED_AUTHOR] + */ +interface DataHolder { + var viewModel: D? +} + +interface Payload { + val payload: MutableMap +} + +interface ItemListHolder { + fun setItems(list: MutableList) + fun getItems(): MutableList + fun addItem(item: I) + fun removeItem(item: I) + fun clear() +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/logger.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/logger.kt new file mode 100644 index 0000000000..55b650ecd7 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/logger.kt @@ -0,0 +1,36 @@ +package com.tangem.tangemtest._arch.structure.base + +import ru.dev.gbixahue.eu4d.lib.android.global.log.Logger +import ru.dev.gbixahue.eu4d.lib.android.global.log.TagLogger +import ru.dev.gbixahue.eu4d.lib.android.global.log.profiling.SimpleLogProfiler +import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf + +/** +[REDACTED_AUTHOR] + */ +object ULog { + + private var logger: Logger? = null + + fun setLogger(logger: Logger) { + ULog.logger = logger + } + + fun d(from: Any, msg: Any?, value: Any? = null) { + logger?.d(from, stringOf(msg), value) + } + + fun w(from: Any, msg: Any?, value: Any? = null) { + logger?.w(from, stringOf(msg), value) + } + + fun e(from: Any, msg: Any?, value: Any? = null) { + logger?.e(from, stringOf(msg), value) + } +} + +class UnitLogger : TagLogger("UNIT") { + init { + msProfiler = SimpleLogProfiler() + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit.kt new file mode 100644 index 0000000000..54d042a064 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit.kt @@ -0,0 +1,17 @@ +package com.tangem.tangemtest._arch.structure.base + +/** +[REDACTED_AUTHOR] + */ +interface Unit : Payload { + var parent: Unit? +} + +abstract class BaseUnit : Unit { + override var parent: Unit? = null + override val payload: MutableMap = mutableMapOf() +} + +open class DataUnit( + override var viewModel: UnitViewModel? +) : BaseUnit(), DataHolder> \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_block.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_block.kt new file mode 100644 index 0000000000..2ce9d6371a --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_block.kt @@ -0,0 +1,53 @@ +package com.tangem.tangemtest._arch.structure.base + +/** +[REDACTED_AUTHOR] + */ +typealias BlockModified = () -> Unit + +interface Block : Unit { + val unitList: MutableList + var blockModified: BlockModified? +} + +abstract class BaseBlock : Block { + override var parent: Unit? = null + override val unitList: MutableList = mutableListOf() + override val payload: MutableMap = mutableMapOf() + override var blockModified: BlockModified? = null +} + +open class ListUnitBlock : BaseBlock(), ItemListHolder { + + override fun setItems(list: MutableList) { + ULog.d(this, "setUnits: ${list.size}") + unitList.clear() + unitList.addAll(list) + unitList.forEach { it.parent = this } + blockModified?.invoke() + } + + override fun getItems(): MutableList { + ULog.d(this, "getUnits: ${unitList.size}") + return unitList + } + + override fun addItem(item: Unit) { + ULog.d(this, "addUnit: ${unitList.size}") + item.parent = this + unitList.add(item) + blockModified?.invoke() + } + + override fun removeItem(item: Unit) { + ULog.d(this, "removeUnit $item") + unitList.remove(item) + blockModified?.invoke() + } + + override fun clear() { + ULog.d(this, "clear") + unitList.clear() + blockModified?.invoke() + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_model.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_model.kt new file mode 100644 index 0000000000..94c7aa795c --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_model.kt @@ -0,0 +1,31 @@ +package com.tangem.tangemtest._arch.structure.base + + +/** +[REDACTED_AUTHOR] + */ +data class ViewState( + var isEnabled: Boolean = true, + var visibility: Int = 0x00000000, + var descriptionVisibility: Int = 0x00000008 +) + +interface UnitViewModel : Payload { + var viewState: ViewState? + var data: D? + + fun updateData(data: D?) +} + +open class BaseUnitViewModel( + override var data: D? = null +) : UnitViewModel { + + override var viewState: ViewState? = ViewState() + override val payload: MutableMap = mutableMapOf() + + override fun updateData(data: D?) { + ULog.d(this, "data changed: $data") + this.data = data + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_plugin.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_plugin.kt new file mode 100644 index 0000000000..9a308d69f1 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/base/unit_plugin.kt @@ -0,0 +1,10 @@ +package com.tangem.tangemtest._arch.structure.base + +/** +[REDACTED_AUTHOR] + */ +typealias PluginCallBackResult = (Any?) -> Unit + +interface Plugin : Unit { + fun invoke(data: Any?, asyncCallback: PluginCallBackResult? = null): Any? +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/blocks.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/blocks.kt new file mode 100644 index 0000000000..ee1ec1cf86 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/blocks.kt @@ -0,0 +1,8 @@ +package com.tangem.tangemtest._arch.structure.impl + +import com.tangem.tangemtest._arch.structure.base.ListUnitBlock + +/** +[REDACTED_AUTHOR] + */ +class LinearBlock : ListUnitBlock() \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/items.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/items.kt new file mode 100644 index 0000000000..a71fef0499 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/items.kt @@ -0,0 +1,18 @@ +package com.tangem.tangemtest._arch.structure.impl + +import com.tangem.tangemtest._arch.structure.base.DataUnit + + +class TextUnit(value: String? = null) : DataUnit(StringViewModel(value)) +class EditTextUnit(value: String? = null) : DataUnit(StringViewModel(value)) +class NumberUnit(value: Number? = null) : DataUnit(NumberViewModel(value)) +class BoolUnit(value: Boolean? = null) : DataUnit(BoolViewModel(value)) + +class ListUnit(value: List, selectedValue: Any) + : DataUnit(ListViewModel(ModelHelper(selectedValue, value)) +) + +fun DataUnit<*>.resName(resId: Int): DataUnit<*> { + payload["resName"] = resId + return this +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/view_models.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/view_models.kt new file mode 100644 index 0000000000..8c96338253 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/impl/view_models.kt @@ -0,0 +1,14 @@ +package com.tangem.tangemtest._arch.structure.impl + +import com.tangem.tangemtest._arch.structure.base.BaseUnitViewModel + +/** +[REDACTED_AUTHOR] + */ +class StringViewModel(value: String?) : BaseUnitViewModel(value) +class NumberViewModel(value: Number?) : BaseUnitViewModel(value) +class BoolViewModel(value: Boolean?) : BaseUnitViewModel(value) +class ListViewModel(value: ModelHelper?) : BaseUnitViewModel(value) + +class KeyValue(val key: String, val value: Any) +class ModelHelper(var selectedItem: Any, val itemList: List) \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_main/entry_point/EntryPointFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/entry_point/EntryPointFragment.kt index 8859a79897..31f7efc701 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/_main/entry_point/EntryPointFragment.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/entry_point/EntryPointFragment.kt @@ -10,11 +10,13 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.tangem.tangemtest.R import com.tangem.tangemtest.commons.ActionType import com.tangem.tangemtest.commons.NavigateOptions import com.tangem.tangemtest.commons.getDefaultNavigationOptions import kotlinx.android.synthetic.main.fg_entry_point.* +import ru.dev.gbixahue.eu4d.lib.android._android.views.find /** [REDACTED_AUTHOR] @@ -31,6 +33,13 @@ class EntryPointFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initRecyclerView() + initPersonalizeNagivation() + } + + private fun initPersonalizeNagivation() { + view?.find(R.id.fab_personalize)?.setOnClickListener { + navigate(R.id.action_nav_entry_point_to_nav_personalize) + } } private fun initRecyclerView() { diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/CardContext.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/CardContext.kt deleted file mode 100644 index f0137ce272..0000000000 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/CardContext.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.tangem.tangemtest.card_use_cases.domain - -import androidx.fragment.app.FragmentActivity -import com.tangem.CardManager -import com.tangem.commands.Card -import com.tangem.tangem_sdk_new.extensions.init - -/** -[REDACTED_AUTHOR] - */ -class CardContext { - lateinit var cardManager: CardManager - private set - - var card: Card? = null - var isVerified: Boolean = false - - fun reset() { - isVerified = false - card = null - } - - fun requireCard(): Card = card!! - - fun init(activity: FragmentActivity): CardContext { - if (::cardManager.isInitialized) return this - - cardManager = CardManager.init(activity) - return this - } -} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/card_action/card_actions.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/card_action/card_actions.kt index 51ed8731de..ae177a8eab 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/card_action/card_actions.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/card_action/card_actions.kt @@ -70,4 +70,10 @@ class SignAction : BaseCardAction() { private fun createHashes(value: String): Array { return arrayOf(value.toByteArray()) } +} + +class PersonalizeAction : BaseCardAction() { + override fun executeMainAction(attrs: AttrForAction, callback: ActionCallback) { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/params_manager/factory.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/params_manager/factory.kt index 54a3784a7c..9d95abb8b3 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/params_manager/factory.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/params_manager/factory.kt @@ -13,6 +13,7 @@ class ParamsManagerFactory : BaseTypedHolder() { return ParamsManagerFactory().apply { register(ActionType.Scan, ScanParamsManager()) register(ActionType.Sign, SignParamsManager()) + register(ActionType.Personalize, PersonalizeParamsManager()) } } } diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/params_manager/params_managers.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/params_manager/params_managers.kt index c22861de59..afc762c311 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/params_manager/params_managers.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/domain/params_manager/params_managers.kt @@ -2,10 +2,7 @@ package com.tangem.tangemtest.card_use_cases.domain.params_manager import com.tangem.CardManager import com.tangem.common.tlv.TlvTag -import com.tangem.tangemtest.card_use_cases.domain.card_action.AttrForAction -import com.tangem.tangemtest.card_use_cases.domain.card_action.CardAction -import com.tangem.tangemtest.card_use_cases.domain.card_action.ScanAction -import com.tangem.tangemtest.card_use_cases.domain.card_action.SignAction +import com.tangem.tangemtest.card_use_cases.domain.card_action.* import com.tangem.tangemtest.card_use_cases.domain.params_manager.modifiers.ParamsChangeConsequence import com.tangem.tasks.TaskEvent @@ -51,6 +48,8 @@ abstract class BaseParamsManager(protected val action: CardAction) : ParamsManag override fun getParams(): MutableList = paramsList.toMutableList() + override fun getActionByTag(tag: TlvTag, cardManager: CardManager): ((ActionCallback) -> Unit)? = null + // Use it if current parameter needs to be affect any other parameters protected open fun applyChangesByAffectedParams(param: IncomingParameter, callback: AffectedParamsCallback?) { getChangeConsequence()?.affectChanges(param, paramsList)?.let { callback?.invoke(it) } @@ -70,8 +69,6 @@ class ScanParamsManager : BaseParamsManager(ScanAction()) { override fun invokeMainAction(cardManager: CardManager, callback: ActionCallback) { action.executeMainAction(getAttrsForAction(cardManager), callback) } - - override fun getActionByTag(tag: TlvTag, cardManager: CardManager): ((ActionCallback) -> Unit)? = null } class SignParamsManager : BaseParamsManager(SignAction()) { @@ -89,4 +86,14 @@ class SignParamsManager : BaseParamsManager(SignAction()) { override fun getActionByTag(tag: TlvTag, cardManager: CardManager): ((ActionCallback) -> Unit)? { return action.getActionByTag(tag, getAttrsForAction(cardManager)) } +} + +class PersonalizeParamsManager : BaseParamsManager(PersonalizeAction()) { + override fun createParamsList(): List { + return listOf() + } + + override fun invokeMainAction(cardManager: CardManager, callback: ActionCallback) { + + } } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/PersonalizeFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/PersonalizeFragment.kt new file mode 100644 index 0000000000..f3d99a1fa4 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/PersonalizeFragment.kt @@ -0,0 +1,70 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import com.tangem.tangemtest.R +import com.tangem.tangemtest.card_use_cases.ui.personalize.view_model.PersonalizeViewModel +import com.tangem.tangemtest.card_use_cases.ui.personalize.view_model.PersonalizeViewModelFactory +import com.tangem.tangemtest.card_use_cases.ui.personalize.widgets.WidgetBuilder +import ru.dev.gbixahue.eu4d.lib.android.global.log.Log +import java.io.IOException +import java.io.InputStream +import java.nio.charset.Charset + +/** +[REDACTED_AUTHOR] + */ +class PersonalizeFragment : Fragment() { + + protected val blockContainer: ViewGroup by lazy { + mainView.findViewById(R.id.ll_container) + } + protected val viewModel: PersonalizeViewModel by viewModels { PersonalizeViewModelFactory(getPersonalizeJson()) } + protected lateinit var mainView: View + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + Log.d(this, "onCreateView") + mainView = inflater.inflate(R.layout.fg_personalize, container, false) + return mainView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewModel.ldBlockList.observe(viewLifecycleOwner, Observer { + WidgetBuilder().build(it, blockContainer) + }) + } + + private fun getPersonalizeJson(): String { + return getJsonFromAssets(requireContext(), "personalize_default.json") ?: "[]" + } + + private fun getJsonFromAssets(context: Context, fileName: String): String? { + return try { + val stream: InputStream = context.assets.open(fileName) + val size: Int = stream.available() + val buffer = ByteArray(size) + stream.read(buffer) + stream.close() + String(buffer, Charset.forName("UTF-8")) + } catch (e: IOException) { + e.printStackTrace() + null + } + } +} + + + + + + + diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/encode_decode.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/encode_decode.kt new file mode 100644 index 0000000000..46c121ba12 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/encode_decode.kt @@ -0,0 +1,21 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize.personalize_converter.json_test + +import com.tangem.tangemtest._arch.structure.base.Block + +/** +[REDACTED_AUTHOR] + */ +interface EncodeDecode { + fun decode(from: A): B + fun encode(from: B): A +} + +class JsonBlockEnDe( + private val jsonToBlock: JsonToBlockConverter, + private val blockToJson: BlockToJsonConverter +) : EncodeDecode { + + override fun encode(from: Block): TestJsonDto = blockToJson.convert(from) + + override fun decode(from: TestJsonDto): Block = jsonToBlock.convert(from) +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/json_dto.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/json_dto.kt new file mode 100644 index 0000000000..d8da4cb477 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/json_dto.kt @@ -0,0 +1,111 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize.personalize_converter.json_test + +class TestJsonDto { + + // Card number + val series = "DB" + val startNumber = 300000000000 + + + // Common + val curveID = "ed25519" + val blockchain = Blockchain() // новое поле + val MaxSignatures = 1000000 + val createWallet = 1 + val createWalletB = createWallet == 1 + + + // Signing method + val SigningMethod0 = false + val SigningMethod1 = false + val SigningMethod2 = false + val SigningMethod3 = false + val SigningMethod4 = false + val SigningMethod5 = false + val SigningMethod6 = false + + + // Sign hash external properties + val pinLessFloorLimit = 0 // новое поле + val hexCrExKey = "" + val requireTerminalTxSignature = false + val requireTerminalCertSignature = false + val checkPIN3onCard = false + + + // Denomination + val writeOnPersonalization = false // новое поле + val denomination = 0 // новое поле + + + // Token + val itsToken = true // новое поле + val symbol = "token symbol" // новое поле + val contractAddress = "contact adress" // новое поле + val decimal = 1 // новое поле + + + val cardData = CardData() + + + // Settings mask + val isReusable = true + val useActivation = false + val forbidPurgeWallet = false + val allowSelectBlockchain = false + val useBlock = false + val useOneCommandAtTime = false + val useCVC = false + val allowSwapPIN = false + val allowSwapPIN2 = true + val forbidDefaultPIN = false + val smartSecurityDelay = true + val protectIssuerDataAgainstReplay = true + val skipSecurityDelayIfValidatedByIssuer = false + val skipCheckPIN2andCVCIfValidatedByIssuer = false + val skipSecurityDelayIfValidatedByLinkedTerminal = true + val restrictOverwriteIssuerDataEx = false + + + // Settings mask - protocol encryption + val protocolAllowUnencrypted = true + val protocolAllowStaticEncryption = true + + + val useNDEF = true + val useDynamicNDEF = true + val disablePrecomputedNDEF = false + val NDEF: MutableList = mutableListOf(Ndef("AAR", "com.tangem.wallet")) // aar, customAAR package + + + // Pins + val PIN = "000000" + val PIN2 = "000" + val PIN3 = "" + val CVC = "000" + val pauseBeforePIN2 = 15000 + + + // not used + val count = 20 + val numberFormat = "" + val issuerData = null + val releaseVersion = false + val issuerName = "TANGEM SDK" +} + +class CardData { + val date = "2020-02-17" + val batch = "FF87" + val blockchain = "IROHA" + val product_note = true + val product_tag = false + val product_id_card = false +} + +class Blockchain { + val customName: String? = null + val name = "BTC" +} + +class Ndef(val type: String, val value: String) \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/to_block.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/to_block.kt new file mode 100644 index 0000000000..5c483384ab --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/to_block.kt @@ -0,0 +1,213 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize.personalize_converter.json_test + +import com.tangem.tangemtest.R +import com.tangem.tangemtest._arch.structure.base.Block +import com.tangem.tangemtest._arch.structure.impl.* +import ru.dev.gbixahue.eu4d.lib.kotlin.common.Converter + +class JsonToBlockConverter : Converter { + + override fun convert(from: TestJsonDto): Block { + val initialBlock = LinearBlock() + initialBlock.addItem(cardNumber(from)) + initialBlock.addItem(common(from)) + initialBlock.addItem(signingMethod(from)) + initialBlock.addItem(signHashExProperties(from)) + initialBlock.addItem(denomination(from)) + initialBlock.addItem(token(from)) + initialBlock.addItem(productMask(from)) + initialBlock.addItem(settingsMask(from)) + initialBlock.addItem(settingsMaskProtocolEnc(from)) + initialBlock.addItem(cardNumber(from)) + initialBlock.addItem(settingsMaskNdef(from)) + initialBlock.addItem(pins(from)) + addPayload(initialBlock, from) + return initialBlock + } + + private fun cardNumber(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_card_number)) + block.addItem(EditTextUnit(from.series).resName(R.string.pers_item_series)) + block.addItem(NumberUnit(from.startNumber).resName(R.string.pers_item_number)) + return block + } + + private fun common(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_common)) + block.addItem(ListUnit(Helper.listOfCurves(), from.curveID).resName(R.string.pers_item_curve)) + block.addItem(ListUnit(Helper.listOfBlockchain(), from.blockchain.name).resName(R.string.pers_item_blockchain)) + block.addItem(EditTextUnit(from.blockchain.customName).resName(R.string.pers_item_custom_blockchain)) + block.addItem(NumberUnit(from.MaxSignatures).resName(R.string.pers_item_max_signatures)) + block.addItem(BoolUnit(from.createWalletB).resName(R.string.action_wallet_create)) + return block + } + + private fun signingMethod(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_signing_method)) + block.addItem(BoolUnit(from.SigningMethod0).resName(R.string.pers_item_sign_tx_hashes)) + block.addItem(BoolUnit(from.SigningMethod1).resName(R.string.pers_item_sign_raw_tx)) + block.addItem(BoolUnit(from.SigningMethod2).resName(R.string.pers_item_sign_validated_tx_hashes)) + block.addItem(BoolUnit(from.SigningMethod3).resName(R.string.pers_item_sign_validated_raw_tx)) + block.addItem(BoolUnit(from.SigningMethod4).resName(R.string.pers_item_sign_validated_tx_hashes_with_iss_data)) + block.addItem(BoolUnit(from.SigningMethod5).resName(R.string.pers_item_sign_validated_raw_tx_with_iss_data)) + block.addItem(BoolUnit(from.SigningMethod6).resName(R.string.pers_item_sign_hash_ex)) + return block + } + + private fun signHashExProperties(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_sign_hash_ex_prop)) + block.addItem(NumberUnit(from.pinLessFloorLimit).resName(R.string.pers_item_pin_less_floor_limit)) + block.addItem(EditTextUnit(from.hexCrExKey).resName(R.string.pers_item_cr_ex_key)) + block.addItem(BoolUnit(from.requireTerminalCertSignature).resName(R.string.pers_item_require_terminal_cert_sig)) + block.addItem(BoolUnit(from.requireTerminalTxSignature).resName(R.string.pers_item_require_terminal_tx_sig)) + block.addItem(BoolUnit(from.checkPIN3onCard).resName(R.string.pers_item_check_pin3_on_card)) + return block + } + + private fun denomination(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_denomination)) + block.addItem(BoolUnit(from.writeOnPersonalization).resName(R.string.pers_item_write_on_personalize)) + block.addItem(NumberUnit(from.denomination).resName(R.string.pers_item_denomination)) + return block + } + + private fun token(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_token)) + block.addItem(BoolUnit(from.itsToken).resName(R.string.pers_item_its_token)) + block.addItem(EditTextUnit(from.symbol).resName(R.string.pers_item_symbol)) + block.addItem(EditTextUnit(from.contractAddress).resName(R.string.pers_item_contract_address)) + block.addItem(NumberUnit(from.decimal).resName(R.string.pers_item_decimal)) + return block + } + + private fun productMask(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_product_mask)) + block.addItem(BoolUnit(from.cardData.product_note).resName(R.string.pers_item_note)) + block.addItem(BoolUnit(from.cardData.product_tag).resName(R.string.pers_item_tag)) + block.addItem(BoolUnit(from.cardData.product_id_card).resName(R.string.pers_item_id_card)) + return block + } + + private fun settingsMask(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_settings_mask)) + block.addItem(BoolUnit(from.isReusable).resName(R.string.pers_item_is_reusable)) + block.addItem(BoolUnit(from.useActivation).resName(R.string.pers_item_need_activation)) + block.addItem(BoolUnit(from.forbidPurgeWallet).resName(R.string.pers_item_forbid_purge)) + block.addItem(BoolUnit(from.allowSelectBlockchain).resName(R.string.pers_item_allow_select_blockchain)) + block.addItem(BoolUnit(from.useBlock).resName(R.string.pers_item_use_block)) + block.addItem(BoolUnit(from.useOneCommandAtTime).resName(R.string.pers_item_one_apdu_at_once)) + block.addItem(BoolUnit(from.useCVC).resName(R.string.pers_item_use_cvc)) + block.addItem(BoolUnit(from.allowSwapPIN).resName(R.string.pers_item_allow_swap_pin)) + block.addItem(BoolUnit(from.allowSwapPIN2).resName(R.string.pers_item_allow_swap_pin2)) + block.addItem(BoolUnit(from.forbidDefaultPIN).resName(R.string.pers_item_forbid_default_pin)) + block.addItem(BoolUnit(from.smartSecurityDelay).resName(R.string.pers_item_smart_security_delay)) + block.addItem(BoolUnit(from.protectIssuerDataAgainstReplay).resName(R.string.pers_item_protect_issuer_data_against_replay)) + block.addItem(BoolUnit(from.skipSecurityDelayIfValidatedByIssuer).resName(R.string.pers_item_skip_security_delay_if_validated)) + block.addItem(BoolUnit(from.skipCheckPIN2andCVCIfValidatedByIssuer).resName(R.string.pers_item_skip_pin2_and_cvc_if_validated)) + block.addItem(BoolUnit(from.skipSecurityDelayIfValidatedByLinkedTerminal).resName(R.string.pers_item_skip_security_delay_on_linked_terminal)) + block.addItem(BoolUnit(from.restrictOverwriteIssuerDataEx).resName(R.string.pers_item_restrict_overwrite_ex_issuer_data)) + return block + } + + private fun settingsMaskProtocolEnc(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_settings_mask_protocol_enc)) + block.addItem(BoolUnit(from.protocolAllowUnencrypted).resName(R.string.pers_item_allow_unencrypted)) + block.addItem(BoolUnit(false).resName(R.string.pers_item_allow_fast_encryption)) + return block + } + + private fun settingsMaskNdef(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_settings_mask_ndef)) + block.addItem(BoolUnit(from.useNDEF).resName(R.string.pers_item_use_ndef)) + block.addItem(BoolUnit(from.useDynamicNDEF).resName(R.string.pers_item_dynamic_ndef)) + block.addItem(BoolUnit(from.disablePrecomputedNDEF).resName(R.string.pers_item_disable_precomputed_ndef)) + block.addItem(ListUnit(Helper.aarList(), from.NDEF[0].type).resName(R.string.pers_item_aar)) +// block.addItem(TextItem(R.string.pers_item_custom_aar_package_name, from.ndef[0].value)) + return block + } + + private fun pins(from: TestJsonDto): Block { + val block = LinearBlock() + block.addItem(TextUnit().resName(R.string.pers_block_pins)) + block.addItem(EditTextUnit(from.PIN).resName(R.string.pers_item_pin)) + block.addItem(EditTextUnit(from.PIN2).resName(R.string.pers_item_pin2)) + block.addItem(EditTextUnit(from.PIN3).resName(R.string.pers_item_pin3)) + block.addItem(EditTextUnit(from.CVC).resName(R.string.pers_item_cvc)) + block.addItem(ListUnit(Helper.pauseBeforePin(), from.pauseBeforePIN2).resName(R.string.pers_item_pause_before_pin2)) + return block + } + + private fun addPayload(block: Block, from: TestJsonDto) { + block.payload["count"] = from.count + block.payload["numberFormat"] = from.numberFormat + block.payload["issuerData"] = from.issuerData + block.payload["releaseVersion"] = from.releaseVersion + block.payload["issuerName"] = from.issuerName + } +} + +internal class Helper { + companion object { + fun listOfCurves(): List { + return mutableListOf( + KeyValue("secp256k1", "secp256k1"), + KeyValue("ed25519", "ed25519") + ) + } + + fun listOfBlockchain(): List { + return mutableListOf( + KeyValue("--- CUSTOM ---", "BTC/test"), + KeyValue("BTC", "BTC"), + KeyValue("BTC/test", "BTC/test"), + KeyValue("ETH", "ETH"), + KeyValue("ETH/test", "ETH/test"), + KeyValue("BCH", "BCH"), + KeyValue("BCH/test", "BCH/test"), + KeyValue("LTC", "LTC"), + KeyValue("XLM", "XLM"), + KeyValue("XLM/test", "XLM/test"), + KeyValue("RSK", "RSK"), + KeyValue("XPR", "XPR"), + KeyValue("CARDANO", "CARDANO") + ) + } + + fun aarList(): List { + return mutableListOf( + KeyValue("--- CUSTOM ---", ""), + KeyValue("Release APP", "com.some.release"), + KeyValue("Debug APP", "com.some.debug"), + KeyValue("None", "") + ) + } + + fun pauseBeforePin(): List { + return mutableListOf( + KeyValue("immediately", 0), + KeyValue("2 seconds", 2000), + KeyValue("5 seconds", 5000), + KeyValue("15 seconds", 15000), + KeyValue("30 seconds", 30000), + KeyValue("1 minute", 60000), + KeyValue("2 minute", 120000) + ) + } + + fun ndef(ndef: MutableList): Map { + val map = mutableMapOf() + ndef.forEach { map[it.type] = it.value } + return map + } + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/to_json.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/to_json.kt new file mode 100644 index 0000000000..5c1c61eed8 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/personalize_converter/json_test/to_json.kt @@ -0,0 +1,8 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize.personalize_converter.json_test + +import com.tangem.tangemtest._arch.structure.base.Block +import ru.dev.gbixahue.eu4d.lib.kotlin.common.Converter + +class BlockToJsonConverter : Converter { + override fun convert(from: Block): TestJsonDto = TestJsonDto() +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/view_model/PersonalizeViewModel.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/view_model/PersonalizeViewModel.kt new file mode 100644 index 0000000000..ed6726a9be --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/view_model/PersonalizeViewModel.kt @@ -0,0 +1,29 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize.view_model + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.google.gson.Gson +import com.tangem.tangemtest._arch.structure.base.Block +import com.tangem.tangemtest.card_use_cases.ui.personalize.personalize_converter.json_test.BlockToJsonConverter +import com.tangem.tangemtest.card_use_cases.ui.personalize.personalize_converter.json_test.JsonBlockEnDe +import com.tangem.tangemtest.card_use_cases.ui.personalize.personalize_converter.json_test.JsonToBlockConverter +import com.tangem.tangemtest.card_use_cases.ui.personalize.personalize_converter.json_test.TestJsonDto + +/** +[REDACTED_AUTHOR] + */ +class PersonalizeViewModelFactory(private val jsonPersonalizeString: String) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T = PersonalizeViewModel(jsonPersonalizeString) as T +} + +class PersonalizeViewModel(private val jsonPersonalizeString: String) : ViewModel() { + + val ldBlockList: MutableLiveData by lazy { MutableLiveData(readJson()) } + + private fun readJson(): Block { + val enDe = JsonBlockEnDe(JsonToBlockConverter(), BlockToJsonConverter()) + val jsonDto = Gson().fromJson(jsonPersonalizeString, TestJsonDto::class.java) + return enDe.decode(jsonDto) + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/block_widget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/block_widget.kt new file mode 100644 index 0000000000..b28527dd81 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/block_widget.kt @@ -0,0 +1,62 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize.widgets + +import android.view.View +import android.view.ViewGroup +import com.tangem.tangemtest.R +import com.tangem.tangemtest._arch.structure.base.Block +import com.tangem.tangemtest._arch.structure.base.DataUnit +import com.tangem.tangemtest._arch.structure.base.Unit +import com.tangem.tangemtest._arch.structure.impl.* +import ru.dev.gbixahue.eu4d.lib.android._android.views.inflate + +/** +[REDACTED_AUTHOR] + */ +interface BlockWidget : ViewWidget + +class EmptyWidget(parent: ViewGroup) : BlockWidget { + override val view: View = parent.inflate(getLayoutId(), parent, false) + override fun getLayoutId(): Int = R.layout.w_empty +} + +abstract class BaseBlockWidget(parent: ViewGroup) : BaseViewWidget(parent), BlockWidget + +class LinearBlockWidget( + private val linearBlock: LinearBlock, + parent: ViewGroup +) : BaseBlockWidget>>(parent) { + override fun getLayoutId(): Int = R.layout.w_personilize_block +} + +class WidgetBuilder { + + fun build(unit: Unit, parent: ViewGroup): ViewWidget? { + return when (unit) { + is Block -> buildBlock(unit, parent) + is DataUnit<*> -> buildUnitItem(unit, parent) + else -> EmptyWidget(parent) + } + } + + private fun buildBlock(block: Block, parent: ViewGroup): BlockWidget { + return when (block) { + is LinearBlock -> { + val linearBlock = LinearBlockWidget(block, parent) + block.getItems().forEach { build(it, linearBlock.view as ViewGroup) } + linearBlock + } + else -> EmptyWidget(parent) + } + } + + private fun buildUnitItem(unit: DataUnit<*>, parent: ViewGroup): UnitWidget<*>? { + return when (unit) { + is TextUnit -> TextWidget(parent, unit) + is EditTextUnit -> EditTextWidget(parent, unit) + is NumberUnit -> NumberWidget(parent, unit) + is BoolUnit -> SwitchWidget(parent, unit) + is ListUnit -> SpinnerWidget(parent, unit) + else -> null + } + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/unit_widget.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/unit_widget.kt new file mode 100644 index 0000000000..15a930abef --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/unit_widget.kt @@ -0,0 +1,64 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize.widgets + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.transition.AutoTransition +import androidx.transition.TransitionManager +import com.tangem.tangemtest.R +import com.tangem.tangemtest._arch.structure.base.DataUnit +import ru.dev.gbixahue.eu4d.lib.kotlin.common.LayoutHolder +import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf + +/** +[REDACTED_AUTHOR] + */ +interface ViewWidget : LayoutHolder { + val view: View +} + +interface UnitWidget : ViewWidget { + val unit: DataUnit +} + +abstract class BaseViewWidget(parent: ViewGroup) : ViewWidget { + override val view: View = inflateView(parent) + + private fun inflateView(parent: ViewGroup): View { + var id = getLayoutId() + if (id == -1) id = R.layout.w_empty + val inflatedView = LayoutInflater.from(parent.context).inflate(id, parent, false) + parent.addView(inflatedView) + return inflatedView + } +} + +interface DescriptionWidget { + fun toggleDescriptionVisibility() +} + +interface ParamWidget : UnitWidget, DescriptionWidget + +abstract class BaseParamWidget( + parent: ViewGroup, + override val unit: DataUnit +) : BaseViewWidget(parent), ParamWidget { + + override fun toggleDescriptionVisibility() { + val tvDescription = view.findViewById(R.id.tv_description) ?: return + + tvDescription.text = getDescription() + TransitionManager.beginDelayedTransition(tvDescription.parent as ViewGroup, AutoTransition()) + tvDescription.visibility = unit.viewModel?.viewState?.descriptionVisibility ?: View.GONE + } +} + +fun UnitWidget<*>.getResNameId(): Int { + val id = unit.payload["resName"] ?: R.string.unknown + return id as Int +} + +fun UnitWidget<*>.getDescription(): String { + return stringOf(unit.payload["description"], isNull = "not found") +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/widgets.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/widgets.kt new file mode 100644 index 0000000000..82fc3c1990 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/ui/personalize/widgets/widgets.kt @@ -0,0 +1,128 @@ +package com.tangem.tangemtest.card_use_cases.ui.personalize.widgets + +import android.view.View +import android.view.ViewGroup +import android.widget.* +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.* +import ru.dev.gbixahue.eu4d.lib.android._android.views.afterTextChanged +import ru.dev.gbixahue.eu4d.lib.android._android.views.inflate +import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf + +/** +[REDACTED_AUTHOR] + */ + +class TextWidget(parent: ViewGroup, private val textUnit: TextUnit) : BaseParamWidget(parent, textUnit) { + + private val tvName = view.findViewById(R.id.tv_name) + + init { + tvName.setText(getResNameId()) + } + + override fun getLayoutId(): Int = R.layout.w_personalize_item_text +} + +class EditTextWidget(parent: ViewGroup, private val editTextUnit: EditTextUnit) : BaseParamWidget(parent, editTextUnit) { + + private val tilItem = view.findViewById(R.id.til_item) + private val etItem = view.findViewById(R.id.et_item) + + init { + tilItem.hint = tilItem.context.getString(getResNameId()) + etItem.setText(editTextUnit.viewModel?.data) + etItem.afterTextChanged { editTextUnit.viewModel?.updateData(it) } + } + + override fun getLayoutId(): Int = R.layout.w_personalize_item_edit_text +} + +class NumberWidget(parent: ViewGroup, private val numberUnit: NumberUnit) : BaseParamWidget(parent, numberUnit) { + + private val tilItem = view.findViewById(R.id.til_item) + private val etItem = view.findViewById(R.id.et_item) + + init { + tilItem.hint = tilItem.context.getString(getResNameId()) + etItem.setText(stringOf(numberUnit.viewModel?.data)) + etItem.afterTextChanged { numberUnit.viewModel?.updateData(getIntValue(it)) } + } + + private fun getIntValue(value: String): Number? { + return if (value.isEmpty()) null else value.toInt() + } + + override fun getLayoutId(): Int = R.layout.w_personalize_item_number +} + +class SwitchWidget(parent: ViewGroup, private val boolUnit: BoolUnit) : BaseParamWidget(parent, boolUnit) { + + private val switchItem = view.findViewById(R.id.sw_item) + + init { + switchItem.setText(getResNameId()) + switchItem.isChecked = boolUnit.viewModel?.data ?: false + switchItem.setOnCheckedChangeListener { view, isChecked -> boolUnit.viewModel?.updateData(isChecked) } + } + + override fun getLayoutId(): Int = R.layout.w_personalize_item_switch + +} + +class SpinnerWidget(parent: ViewGroup, private val listUnit: ListUnit) : BaseParamWidget(parent, listUnit) { + + private val spItem = view.findViewById(R.id.sp_item) + private val spAdapter = SpItemAdapter(listUnit.viewModel?.data?.itemList) + + init { + val name = view.findViewById(R.id.tv_name) + name.setText(getResNameId()) + spItem.adapter = spAdapter + spItem.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onNothingSelected(parent: AdapterView<*>?) {} + + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + val data = listUnit.viewModel?.data ?: return + + data.selectedItem = data.itemList[position] + listUnit.viewModel?.updateData(data) + } + } + } + + override fun getLayoutId(): Int = R.layout.w_personalize_item_spinner +} + +class SpItemAdapter(list: List?) : BaseAdapter() { + + private val itemList: List = list ?: listOf() + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = convertView ?: parent.inflate(R.layout.vh_sp_item) + + val tv = view.findViewById(R.id.tv_sp_item) + tv.text = extractData(itemList[position]) + + return view + } + + override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = convertView ?: parent.inflate(R.layout.vh_sp_dropdown_item) + + val tv = view.findViewById(R.id.tv_sp_item) + tv.text = extractData(itemList[position]) + + return view + } + + private fun extractData(item: KeyValue): String? = item.key + + override fun getItem(position: Int): String = stringOf(itemList[position]) + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = itemList.size +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/abstracts.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/abstracts.kt deleted file mode 100644 index 14d7dca27f..0000000000 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/abstracts.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.tangemtest.commons - -/** -[REDACTED_AUTHOR] - */ -interface OnBackPressHandler { - fun onBackPressed(): Boolean -} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/logs.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/logs.kt index 0d903aa79a..795c23c726 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/logs.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/logs.kt @@ -1,8 +1,8 @@ package com.tangem.tangemtest.commons -import ru.dev.gbixahue.eu4d.lib.android.global.log.CLogger +import ru.dev.gbixahue.eu4d.lib.android.global.log.TagLogger /** [REDACTED_AUTHOR] */ -class TangemLogger : CLogger("TangemDemo") \ No newline at end of file +class TangemLogger : TagLogger("TangemDemo") \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/navigation.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/navigation.kt index 05cf3df94d..899776890c 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/navigation.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/navigation.kt @@ -33,5 +33,6 @@ enum class ActionType(@StringRes val resName: Int) { WriteIssuerExData(R.string.action_issuer_write_ex_data), ReadUserData(R.string.action_user_read_data), WriteUserData(R.string.action_user_write_data), + Personalize(R.string.personalize), Unknown(R.string.unknown), } \ No newline at end of file diff --git a/tangem-demo/src/main/res/layout/activity_test_user_data.xml b/tangem-demo/src/main/res/layout/activity_test_user_data.xml index 7b571ab9b6..c1874b434b 100644 --- a/tangem-demo/src/main/res/layout/activity_test_user_data.xml +++ b/tangem-demo/src/main/res/layout/activity_test_user_data.xml @@ -1,238 +1,238 @@ - -