diff --git a/tangem-demo/build.gradle b/tangem-demo/build.gradle
index b1de1a90fd..116ffff7cd 100644
--- a/tangem-demo/build.gradle
+++ b/tangem-demo/build.gradle
@@ -3,8 +3,7 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
- buildToolsVersion "29.0.2"
-
+ buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.tangem.tangemtest"
@@ -34,13 +33,22 @@ android {
dependencies {
implementation project(':tangem-core')
implementation project(':tangem-sdk')
-
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin"
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.core:core-ktx:1.1.0'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin"
+
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.core:core-ktx:1.2.0'
+ implementation "androidx.constraintlayout:constraintlayout:2.0.0-beta4"
+ implementation "androidx.navigation:navigation-fragment-ktx:2.2.1"
+ implementation "androidx.navigation:navigation-ui-ktx:2.2.1"
+ implementation "androidx.recyclerview:recyclerview:1.2.0-alpha01"
+
+ implementation "com.google.android.material:material:1.2.0-alpha05"
+
+ implementation 'com.google.code.gson:gson:2.8.6'
}
diff --git a/tangem-demo/src/main/AndroidManifest.xml b/tangem-demo/src/main/AndroidManifest.xml
index 600bca8f4e..cf184dcfe2 100644
--- a/tangem-demo/src/main/AndroidManifest.xml
+++ b/tangem-demo/src/main/AndroidManifest.xml
@@ -8,8 +8,8 @@
-
-
+
-
+
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/AppTangemDemo.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/AppTangemDemo.kt
new file mode 100644
index 0000000000..cd3f9ace12
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/AppTangemDemo.kt
@@ -0,0 +1,14 @@
+package com.tangem.tangemtest
+
+import android.app.Application
+import com.tangem.tangemtest.card_use_cases.CardContext
+import com.tangem.tangemtest.commons.DiManager
+
+/**
+[REDACTED_AUTHOR]
+ */
+class AppTangemDemo : Application(), DiManager {
+ private val cardContext: CardContext = CardContext()
+
+ override fun getCardContext(): CardContext = cardContext
+}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/MainActivity.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/MainActivity.kt
deleted file mode 100644
index 01207d703d..0000000000
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/MainActivity.kt
+++ /dev/null
@@ -1,161 +0,0 @@
-package com.tangem.tangemtest
-
-import android.content.Intent
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import com.tangem.CardManager
-import com.tangem.tangem_sdk_new.extensions.init
-import com.tangem.tasks.ScanEvent
-import com.tangem.tasks.TaskError
-import com.tangem.tasks.TaskEvent
-import kotlinx.android.synthetic.main.activity_main.*
-
-class MainActivity : AppCompatActivity() {
-
- private lateinit var cardManager: CardManager
- private lateinit var cardId: String
- private lateinit var issuerData: ByteArray
- private lateinit var issuerDataSignature: ByteArray
- private var issuerDataCounter: Int = 1
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
-
- 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
- cardId = (taskEvent.data as ScanEvent.OnReadEvent).card.cardId
- runOnUiThread {
- tv_card_cid?.text = cardId
- btn_create_wallet.isEnabled = true
- }
- }
- is ScanEvent.OnVerifyEvent -> {
- //Handle card verification
- runOnUiThread {
- tv_card_cid?.text = cardId
- btn_sign.isEnabled = true
- btn_read_issuer_data.isEnabled = true
- btn_read_issuer_extra_data.isEnabled = true
- btn_write_issuer_data.isEnabled = true
- btn_purge_wallet.isEnabled = true
- btn_create_wallet.isEnabled = true
- }
- }
- }
- }
- 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_sign?.setOnClickListener { _ ->
- cardManager.sign(
- createSampleHashes(),
- cardId) {
- when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
- }
- is TaskEvent.Event -> runOnUiThread { tv_card_cid?.text = cardId + "was used to sign sample hashes." }
- }
- }
- }
- btn_read_issuer_data?.setOnClickListener { _ ->
- cardManager.readIssuerData(cardId) {
- when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
- }
- is TaskEvent.Event -> runOnUiThread {
- btn_write_issuer_data.isEnabled = true
- tv_card_cid?.text = it.data.issuerData.contentToString()
- issuerData = it.data.issuerData
- issuerDataSignature = it.data.issuerDataSignature
- }
- }
- }
- }
- btn_write_issuer_data?.setOnClickListener { _ ->
- cardManager.writeIssuerData(
- cardId,
- issuerData,
- issuerDataSignature) {
- when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
- }
- is TaskEvent.Event -> runOnUiThread {
- tv_card_cid?.text = it.data.cardId
- }
- }
- }
- }
- btn_read_issuer_extra_data?.setOnClickListener { _ ->
- cardManager.readIssuerExtraData(cardId) {
- when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
- }
- is TaskEvent.Event -> runOnUiThread {
- issuerDataCounter = (it.data.issuerDataCounter ?: 0) + 1
- btn_write_issuer_data.isEnabled = true
- tv_card_cid?.text = "Read ${it.data.issuerData.size} bytes of data."
- }
- }
- }
- }
- btn_purge_wallet?.setOnClickListener { _ ->
- cardManager.purgeWallet(
- cardId) {
- when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
- }
- is TaskEvent.Event -> runOnUiThread {
- tv_card_cid?.text = it.data.status.name
- }
- }
- }
- }
- btn_create_wallet?.setOnClickListener { _ ->
- cardManager.createWallet(
- cardId) {
- when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
- }
- is TaskEvent.Event -> runOnUiThread {
- tv_card_cid?.text = it.data.status.name
- btn_sign.isEnabled = true
- btn_read_issuer_data.isEnabled = true
- btn_purge_wallet.isEnabled = true
- btn_create_wallet.isEnabled = false
-
- }
- }
- }
- }
- btn_read_write_user_data?.setOnClickListener { startActivity(Intent(this, TestUserDataActivity::class.java)) }
- }
-
- private fun createSampleHashes(): Array {
- val hash1 = ByteArray(32) { 1 }
- val hash2 = ByteArray(32) { 2 }
- return arrayOf(hash1, hash2)
- }
-}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainActivity.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainActivity.kt
new file mode 100644
index 0000000000..7be9b29f37
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainActivity.kt
@@ -0,0 +1,48 @@
+package com.tangem.tangemtest._main
+
+import android.content.res.Resources
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.Toolbar
+import androidx.navigation.findNavController
+import androidx.navigation.fragment.NavHostFragment
+import androidx.navigation.ui.AppBarConfiguration
+import androidx.navigation.ui.navigateUp
+import androidx.navigation.ui.setupActionBarWithNavController
+import com.tangem.tangemtest.R
+
+/**
+ * A simple activity demonstrating use of a NavHostFragment with a navigation drawer.
+ */
+class MainActivity : AppCompatActivity() {
+ private lateinit var appBarConfiguration: AppBarConfiguration
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.a_main)
+
+ val toolbar = findViewById(R.id.toolbar)
+ setSupportActionBar(toolbar)
+
+ val host: NavHostFragment = supportFragmentManager
+ .findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: return
+
+ val navController = host.navController
+ appBarConfiguration = AppBarConfiguration(setOf(R.id.nav_entry_point))
+ setupActionBarWithNavController(navController, appBarConfiguration)
+
+ navController.addOnDestinationChangedListener { _, destination, _ ->
+ val dest: String = try {
+ resources.getResourceName(destination.id)
+ } catch (e: Resources.NotFoundException) {
+ destination.id.toString()
+ }
+ Log.d("NavigationActivity", "Navigated to $dest")
+ }
+ }
+
+ override fun onSupportNavigateUp(): Boolean {
+ return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration)
+ }
+}
\ 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
new file mode 100644
index 0000000000..1537c2bd2c
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/entry_point/EntryPointFragment.kt
@@ -0,0 +1,62 @@
+package com.tangem.tangemtest._main.entry_point
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.navigation.NavController
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.tangem.tangemtest.R
+import com.tangem.tangemtest.card_use_cases.CardContext
+import com.tangem.tangemtest.card_use_cases.actions.Action
+import com.tangem.tangemtest.commons.NavigateAction
+import com.tangem.tangemtest.commons.getDefaultNavigationOptions
+import com.tangem.tangemtest.commons.getDiManager
+import kotlinx.android.synthetic.main.fg_entry_point.*
+
+/**
+[REDACTED_AUTHOR]
+ */
+class EntryPointFragment : Fragment() {
+
+ private val navController: NavController by lazy { findNavController() }
+ private lateinit var rvActions: RecyclerView
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.fg_entry_point, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val activity = activity ?: throw Exception("Fragment isn't associated with activity ")
+
+ val cardContext = getDiManager().getCardContext().init(activity)
+ initRecyclerView(cardContext)
+ }
+
+ private fun initRecyclerView(cardContext: CardContext) {
+ rvActions = rv_actions
+ rvActions.layoutManager = LinearLayoutManager(activity)
+
+ val adapter = RvActionsAdapter(cardContext) { position, destinationId -> navigate(destinationId as Int) }
+ adapter.setItems(mutableListOf(
+ NavigateAction(Action.Scan(), R.id.nav_scan),
+ NavigateAction(Action.Sign(), R.id.nav_sign)
+ ))
+ rvActions.adapter = adapter
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ rvActions.adapter?.notifyDataSetChanged()
+ }
+
+ private fun navigate(destinationId: Int) {
+ navController.navigate(destinationId, null, getDefaultNavigationOptions())
+ }
+}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_main/entry_point/rv.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/entry_point/rv.kt
new file mode 100644
index 0000000000..6035bebb85
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/entry_point/rv.kt
@@ -0,0 +1,69 @@
+package com.tangem.tangemtest._main.entry_point
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.tangem.tangemtest.R
+import com.tangem.tangemtest.card_use_cases.CardContext
+import com.tangem.tangemtest.card_use_cases.actions.Action
+import com.tangem.tangemtest.commons.Bindable
+import com.tangem.tangemtest.commons.NavigateAction
+
+/**
+[REDACTED_AUTHOR]
+ */
+typealias RvCallback = (Int, Any?) -> Unit
+
+class RvActionsAdapter(
+ private val cardContext: CardContext,
+ private val callback: RvCallback
+) : RecyclerView.Adapter() {
+
+ private val actionList = mutableListOf()
+
+ fun setItems(list: MutableList) {
+ actionList.clear()
+ actionList.addAll(list)
+ }
+
+ fun addToItems(list: MutableList) {
+ actionList.addAll(list)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RvActionsVH {
+ val view = LayoutInflater.from(parent.context).inflate(R.layout.vh_actions, parent, false)
+ return RvActionsVH(view, cardContext.isVerified, callback)
+ }
+
+ override fun getItemCount(): Int = actionList.size
+
+ override fun onBindViewHolder(holder: RvActionsVH, position: Int) {
+ holder.bind(actionList[position])
+ }
+}
+
+class RvActionsVH(
+ view: View,
+ private val cardIsVerified: Boolean,
+ private val callback: RvCallback
+) : RecyclerView.ViewHolder(view), Bindable {
+
+ private val tvAction = itemView.findViewById(R.id.tv_title)
+ private val navigateRight = itemView.findViewById(R.id.tv_navigate_right)
+
+ override fun bind(data: NavigateAction) {
+ tvAction.text = tvAction.context.getString(data.action.resId)
+ itemView.setOnClickListener { callback(adapterPosition, data.destinationId) }
+ switchItemBackground(data.action)
+ }
+
+ private fun switchItemBackground(action: Action) {
+ when (action) {
+ is Action.Scan -> {
+ }
+ else -> itemView.visibility = if (cardIsVerified) View.VISIBLE else View.GONE
+ }
+ }
+}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/CardContext.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/CardContext.kt
new file mode 100644
index 0000000000..2f37449a27
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/CardContext.kt
@@ -0,0 +1,31 @@
+package com.tangem.tangemtest.card_use_cases
+
+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/actions/ScanActionFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/actions/ScanActionFragment.kt
new file mode 100644
index 0000000000..f6a24b91ed
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/actions/ScanActionFragment.kt
@@ -0,0 +1,41 @@
+package com.tangem.tangemtest.card_use_cases.actions
+
+import android.os.Bundle
+import android.view.View
+import com.google.gson.Gson
+import com.tangem.tangemtest.R
+import com.tangem.tangemtest.card_use_cases.base.BaseCardActionFragment
+import com.tangem.tangemtest.commons.postUI
+import com.tangem.tasks.ScanEvent
+import com.tangem.tasks.TaskEvent
+import kotlinx.android.synthetic.main.fg_card_scan.*
+
+/**
+[REDACTED_AUTHOR]
+ */
+class ScanActionFragment : BaseCardActionFragment() {
+
+ override fun getLayoutId(): Int = R.layout.fg_card_scan
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ cardContext.reset()
+ cardContext.cardManager.scanCard { taskEvent ->
+ when (taskEvent) {
+ is TaskEvent.Event -> handleDataEvent(taskEvent.data)
+ is TaskEvent.Completion -> handleCompletionEvent(taskEvent)
+ }
+ }
+ }
+
+ private fun handleDataEvent(event: ScanEvent) {
+ when (event) {
+ is ScanEvent.OnReadEvent -> {
+ cardContext.card = event.card
+ postUI { tv_card_cid.text = Gson().toJson(cardContext.card) }
+ }
+ is ScanEvent.OnVerifyEvent -> cardContext.isVerified = true
+ }
+ }
+}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/actions/SignActionFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/actions/SignActionFragment.kt
new file mode 100644
index 0000000000..51513df71f
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/actions/SignActionFragment.kt
@@ -0,0 +1,40 @@
+package com.tangem.tangemtest.card_use_cases.actions
+
+import android.os.Bundle
+import android.view.View
+import com.tangem.commands.SignResponse
+import com.tangem.tangemtest.R
+import com.tangem.tangemtest.card_use_cases.base.BaseCardActionFragment
+import com.tangem.tangemtest.commons.postUI
+import com.tangem.tasks.TaskEvent
+import kotlinx.android.synthetic.main.fg_card_sign.*
+
+/**
+[REDACTED_AUTHOR]
+ */
+class SignActionFragment : BaseCardActionFragment() {
+
+ override fun getLayoutId(): Int = R.layout.fg_card_sign
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val cardId = cardContext.requireCard().cardId
+ cardContext.cardManager.sign(createSampleHashes(), cardId) { taskEvent ->
+ when (taskEvent) {
+ is TaskEvent.Event -> handleDataEvent(taskEvent.data)
+ is TaskEvent.Completion -> handleCompletionEvent(taskEvent)
+ }
+ }
+ }
+
+ private fun handleDataEvent(event: SignResponse) {
+ postUI { tv_sign_result.text = toJson(event) }
+ }
+
+ private fun createSampleHashes(): Array {
+ val hash1 = ByteArray(32) { 1 }
+ val hash2 = ByteArray(32) { 2 }
+ return arrayOf(hash1, hash2)
+ }
+}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/actions/actions.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/actions/actions.kt
new file mode 100644
index 0000000000..69fecafb54
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/actions/actions.kt
@@ -0,0 +1,12 @@
+package com.tangem.tangemtest.card_use_cases.actions
+
+import androidx.annotation.StringRes
+import com.tangem.tangemtest.R
+
+/**
+[REDACTED_AUTHOR]
+ */
+sealed class Action(@StringRes val resId: Int) {
+ class Scan: Action(R.string.action_card_scan)
+ class Sign: Action(R.string.action_card_sign)
+}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/base/BaseCardActionFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/base/BaseCardActionFragment.kt
new file mode 100644
index 0000000000..aacbf2d2d7
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/card_use_cases/base/BaseCardActionFragment.kt
@@ -0,0 +1,53 @@
+package com.tangem.tangemtest.card_use_cases.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.UiThread
+import androidx.fragment.app.Fragment
+import com.google.android.material.snackbar.BaseTransientBottomBar
+import com.google.android.material.snackbar.Snackbar
+import com.google.gson.Gson
+import com.tangem.tangemtest.card_use_cases.CardContext
+import com.tangem.tangemtest.commons.LayoutHolder
+import com.tangem.tangemtest.commons.getDiManager
+import com.tangem.tasks.TaskError
+import com.tangem.tasks.TaskEvent
+
+/**
+[REDACTED_AUTHOR]
+ */
+abstract class BaseCardActionFragment : Fragment(), LayoutHolder {
+
+ protected lateinit var cardContext: CardContext
+ protected lateinit var mainView: View
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ mainView = inflater.inflate(getLayoutId(), container, false)
+ return mainView
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ cardContext = getDiManager().getCardContext()
+ }
+
+ @UiThread
+ protected fun handleCompletionEvent(taskEvent: TaskEvent.Completion<*>) {
+ val error: TaskError = taskEvent.error ?: return
+
+ when (error) {
+ is TaskError.UserCancelled -> showSnackbarMessage("Error: User was canceled")
+ else -> showSnackbarMessage("Description not implemented. code: ${error.code}")
+ }
+
+ }
+
+ protected fun showSnackbarMessage(message: String) {
+ Snackbar.make(mainView, message, BaseTransientBottomBar.LENGTH_SHORT).show()
+ }
+
+ protected fun toJson(obj: Any): String = Gson().toJson(obj)
+
+}
\ 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
new file mode 100644
index 0000000000..3ca51329f8
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/abstracts.kt
@@ -0,0 +1,12 @@
+package com.tangem.tangemtest.commons
+
+/**
+[REDACTED_AUTHOR]
+ */
+interface LayoutHolder {
+ fun getLayoutId(): Int
+}
+
+interface Bindable {
+ fun bind(data: T)
+}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/di.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/di.kt
new file mode 100644
index 0000000000..fdea2ad5af
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/di.kt
@@ -0,0 +1,17 @@
+package com.tangem.tangemtest.commons
+
+import android.content.Context
+import androidx.fragment.app.Fragment
+import com.tangem.tangemtest.card_use_cases.CardContext
+
+/**
+[REDACTED_AUTHOR]
+ */
+
+interface DiManager {
+ fun getCardContext(): CardContext
+}
+
+fun Context.getDiManager(): DiManager = applicationContext as DiManager
+
+fun Fragment.getDiManager(): DiManager = activity?.applicationContext as DiManager
\ 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
new file mode 100644
index 0000000000..0ad3b205ff
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/navigation.kt
@@ -0,0 +1,23 @@
+package com.tangem.tangemtest.commons
+
+import androidx.navigation.NavOptions
+import androidx.navigation.navOptions
+import com.tangem.tangemtest.R
+import com.tangem.tangemtest.card_use_cases.actions.Action
+
+/**
+[REDACTED_AUTHOR]
+ */
+
+fun getDefaultNavigationOptions(): NavOptions {
+ return navOptions {
+ anim {
+ enter = R.anim.slide_in_right
+ exit = R.anim.slide_out_left
+ popEnter = R.anim.slide_in_left
+ popExit = R.anim.slide_out_right
+ }
+ }
+}
+
+data class NavigateAction(val action: Action, val destinationId: Int)
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/threading.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/threading.kt
new file mode 100644
index 0000000000..0e7a797614
--- /dev/null
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/threading.kt
@@ -0,0 +1,30 @@
+package com.tangem.tangemtest.commons
+
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.Looper
+
+/**
+[REDACTED_AUTHOR]
+ */
+object Threading {
+ val uiHandler: Handler = Handler(Looper.getMainLooper())
+ val workHandler: Handler = Handler(HandlerThread("Application worker thread").apply { start() }.looper)
+
+ fun postInCurrentThread(msTime: Long, func: () -> Unit) {
+ Handler().postDelayed({ func() }, msTime)
+ }
+}
+
+
+fun post(msTime: Long, func: () -> Unit) {
+ Threading.postInCurrentThread(msTime, func)
+}
+
+fun postUI(msTime: Long = 0, func: () -> Unit) {
+ if (msTime > 0) Threading.uiHandler.postDelayed({ func() }, msTime) else Threading.uiHandler.post(func)
+}
+
+fun postWork(msTime: Long = 0, func: () -> Unit) {
+ if (msTime > 0) Threading.workHandler.postDelayed({ func() }, msTime) else Threading.workHandler.post(func)
+}
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/anim/fade_in.xml b/tangem-demo/src/main/res/anim/fade_in.xml
new file mode 100644
index 0000000000..1052d2aa22
--- /dev/null
+++ b/tangem-demo/src/main/res/anim/fade_in.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/anim/fade_out.xml b/tangem-demo/src/main/res/anim/fade_out.xml
new file mode 100644
index 0000000000..cfe4193dc3
--- /dev/null
+++ b/tangem-demo/src/main/res/anim/fade_out.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/anim/slide_in_left.xml b/tangem-demo/src/main/res/anim/slide_in_left.xml
new file mode 100644
index 0000000000..3ab232f97f
--- /dev/null
+++ b/tangem-demo/src/main/res/anim/slide_in_left.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/anim/slide_in_right.xml b/tangem-demo/src/main/res/anim/slide_in_right.xml
new file mode 100644
index 0000000000..5c18975a6f
--- /dev/null
+++ b/tangem-demo/src/main/res/anim/slide_in_right.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/tangem-demo/src/main/res/anim/slide_out_left.xml b/tangem-demo/src/main/res/anim/slide_out_left.xml
new file mode 100644
index 0000000000..3e5db825b6
--- /dev/null
+++ b/tangem-demo/src/main/res/anim/slide_out_left.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/tangem-demo/src/main/res/anim/slide_out_right.xml b/tangem-demo/src/main/res/anim/slide_out_right.xml
new file mode 100644
index 0000000000..486d3ae08c
--- /dev/null
+++ b/tangem-demo/src/main/res/anim/slide_out_right.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/layout/a_main.xml b/tangem-demo/src/main/res/layout/a_main.xml
new file mode 100644
index 0000000000..a3736051f4
--- /dev/null
+++ b/tangem-demo/src/main/res/layout/a_main.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/tangem-demo/src/main/res/layout/fg_card_scan.xml b/tangem-demo/src/main/res/layout/fg_card_scan.xml
new file mode 100644
index 0000000000..e8efc318bc
--- /dev/null
+++ b/tangem-demo/src/main/res/layout/fg_card_scan.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/layout/fg_card_sign.xml b/tangem-demo/src/main/res/layout/fg_card_sign.xml
new file mode 100644
index 0000000000..ea78e82cdb
--- /dev/null
+++ b/tangem-demo/src/main/res/layout/fg_card_sign.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/layout/fg_entry_point.xml b/tangem-demo/src/main/res/layout/fg_entry_point.xml
new file mode 100644
index 0000000000..8a589c5489
--- /dev/null
+++ b/tangem-demo/src/main/res/layout/fg_entry_point.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/layout/vh_actions.xml b/tangem-demo/src/main/res/layout/vh_actions.xml
new file mode 100644
index 0000000000..e1ebc1d1a6
--- /dev/null
+++ b/tangem-demo/src/main/res/layout/vh_actions.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tangem-demo/src/main/res/navigation/navigation.xml b/tangem-demo/src/main/res/navigation/navigation.xml
new file mode 100644
index 0000000000..7ca8a58e7b
--- /dev/null
+++ b/tangem-demo/src/main/res/navigation/navigation.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tangem-demo/src/main/res/values/strings.xml b/tangem-demo/src/main/res/values/strings.xml
index 821087e07e..c480d46cdf 100644
--- a/tangem-demo/src/main/res/values/strings.xml
+++ b/tangem-demo/src/main/res/values/strings.xml
@@ -1,3 +1,7 @@
- TangemTest
+ Tangem Demo
+
+ @string/app_name
+ Read card
+ Sign card
diff --git a/tangem-demo/src/main/res/values/styles.xml b/tangem-demo/src/main/res/values/styles.xml
index 5885930df6..0eb88fe335 100644
--- a/tangem-demo/src/main/res/values/styles.xml
+++ b/tangem-demo/src/main/res/values/styles.xml
@@ -1,7 +1,7 @@
-