diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/Item.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/Item.kt index eaf3d7afa4..7800192199 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/Item.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/Item.kt @@ -5,7 +5,12 @@ import com.tangem.tangemtest._arch.structure.Id /** [REDACTED_AUTHOR] */ -interface Item { + +interface UpdateBy{ + fun update(value: B) +} + +interface Item: UpdateBy { val id: Id var parent: Item? var viewModel: ItemViewModel @@ -36,4 +41,7 @@ open class BaseItem( override var parent: Item? = null + override fun update(value: Item) { + viewModel.update(value.viewModel) + } } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/ItemGroup.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/ItemGroup.kt index 61a43a0d1c..20a8def0e6 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/ItemGroup.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/ItemGroup.kt @@ -49,4 +49,8 @@ open class SimpleItemGroup( ILog.d(this, "clear $id") itemList.clear() } + + override fun update(value: Item) { + // nothing to do + } } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/ItemViewModel.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/ItemViewModel.kt index a542a3be4d..b3fdf6c422 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/ItemViewModel.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_arch/structure/abstraction/ItemViewModel.kt @@ -16,7 +16,7 @@ class KeyValue(val key: String, val value: Any) class ViewState( isVisible: Boolean? = null, bgColor: Int? = -1 -) { +) : UpdateBy { class State( stateValue: T, @@ -41,9 +41,15 @@ class ViewState( val states = listOf(isVisibleState, backgroundColor, descriptionVisibility) states.forEach { it.preventSameChanges = isPrevented } } + + override fun update(value: ViewState) { + isVisibleState = value.isVisibleState + backgroundColor = value.backgroundColor + descriptionVisibility = value.descriptionVisibility + } } -interface ItemViewModel : PayloadHolder { +interface ItemViewModel : PayloadHolder, UpdateBy { val viewState: ViewState var data: Any? var defaultData: Any? @@ -92,6 +98,14 @@ open class BaseItemViewModel( this.data = data onDataUpdated = callback } + + override fun update(value: ItemViewModel) { + viewState.update(value.viewState) + defaultData = value.defaultData + data = value.data + payload.clear() + payload.putAll(value.payload) + } } class ListViewModel( 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 index 92e093d2c8..3b6c05f333 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainActivity.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainActivity.kt @@ -53,7 +53,7 @@ class MainActivity : AppCompatActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.main_menu, menu) - val switchMenu = menu.findItem(R.id.action_favorite) + val switchMenu = menu.findItem(R.id.action_toggle_description_visibility) (switchMenu.actionView as? SwitchCompat)?.let { it.setOnCheckedChangeListener { buttonView, isChecked -> vm.switchToggled(isChecked) } } diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/Abstractions.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/Abstractions.kt index f5f02c0ace..8699900359 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/Abstractions.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/Abstractions.kt @@ -4,6 +4,13 @@ package com.tangem.tangemtest.commons [REDACTED_AUTHOR] */ interface Store { - fun save(config: M) + fun save(value: M) fun restore(): M +} + +interface KeyedStore { + fun save(key: String, value: M) + fun restore(key: String): M + fun restoreAll(): Map + fun delete(key: String) } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/commons/DialogController.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/DialogController.kt new file mode 100644 index 0000000000..de7db7ae3e --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/commons/DialogController.kt @@ -0,0 +1,76 @@ +package com.tangem.tangemtest.commons + +import android.app.Activity +import android.app.Dialog +import android.view.LayoutInflater +import android.view.View +import androidx.appcompat.app.AlertDialog + +class DialogController { + var onDismissCallback: (() -> Unit)? = null + var onShowCallback: (() -> Unit)? = null + var view: View? = null + + private var rawDialog: Dialog? = null + + private var inShowingProcess = false + private var inDismissingProcess = false + private var autoReleaseOnDismiss = false + + fun createAlert(context: Activity, resLayout: Int): AlertDialog { + view = LayoutInflater.from(context).inflate(resLayout, null) + rawDialog = AlertDialog.Builder(context).setView(view).create().apply { + setOnShowListener { onShow() } + setOnDismissListener { onDismiss() } + } + return rawDialog as AlertDialog + } + + fun set(dialog: Dialog) { + rawDialog = dialog + dialog.setOnShowListener { onShow() } + dialog.setOnDismissListener { onDismiss() } + } + + private fun onShow() { + inShowingProcess = false + onShowCallback?.invoke() + } + + private fun onDismiss() { + inDismissingProcess = false + if (autoReleaseOnDismiss) release() + onDismissCallback?.invoke() + } + + fun show() { + val dialog = rawDialog ?: return + if (inShowingProcess) return + if (dialog.isShowing) return + + inShowingProcess = true + dialog.show() + } + + fun dismiss(autoRelease: Boolean = true) { + val dialog = rawDialog ?: return + if (inDismissingProcess) return + if (!dialog.isShowing) return + + autoReleaseOnDismiss = autoRelease + inDismissingProcess = true + dialog.dismiss() + } + + fun release() { + onDismissCallback = null + onShowCallback = null + + inShowingProcess = false + inDismissingProcess = false + autoReleaseOnDismiss = false + + view = null + rawDialog = null + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/PersonalizeAction.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/PersonalizeAction.kt index 612b728c24..457b4baac3 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/PersonalizeAction.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/PersonalizeAction.kt @@ -37,7 +37,7 @@ class PersonalizeAction : BaseAction() { val acquirer = DefaultPersonalizationParams.acquirer() val manufacturer = DefaultPersonalizationParams.manufacturer() - val personalizeConfig = PersonalizationConfigConverter().convert(itemList, PersonalizationConfig()) + val personalizeConfig = PersonalizationConfigConverter().convert(itemList, PersonalizationConfig.default()) val cardConfig = PersonalizationConfigToCardConfig().convert(personalizeConfig) attrs.tangemSdk.personalize(cardConfig, issuer, manufacturer, acquirer) { diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/ItemsManager.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/ItemsManager.kt index a43809684b..20d2ed3eb8 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/ItemsManager.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/ItemsManager.kt @@ -25,6 +25,7 @@ interface ItemsManager : PayloadHolder { fun invokeMainAction(tangemSdk: TangemSdk, callback: ActionCallback) fun getActionByTag(id: Id, tangemSdk: TangemSdk): ((ActionCallback) -> Unit)? fun attachPayload(payload: Payload) + fun updateByItemList(list: List) } interface PayloadKey { diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/BaseItemsManager.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/BaseItemsManager.kt index 6ddbc6a916..a3308d623d 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/BaseItemsManager.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/BaseItemsManager.kt @@ -6,6 +6,7 @@ import com.tangem.tangemtest._arch.structure.Id import com.tangem.tangemtest._arch.structure.Payload import com.tangem.tangemtest._arch.structure.abstraction.Item import com.tangem.tangemtest._arch.structure.abstraction.findItem +import com.tangem.tangemtest._arch.structure.abstraction.iterate import com.tangem.tangemtest.ucase.domain.actions.Action import com.tangem.tangemtest.ucase.domain.actions.AttrForAction import com.tangem.tangemtest.ucase.domain.paramsManager.ActionCallback @@ -47,6 +48,10 @@ open class BaseItemsManager(protected val action: Action) : ItemsManager, Lifecy this.changeConsequence = consequence } + override fun updateByItemList(list: List) { + list.iterate { itemList.findItem(it.id)?.update(it) } + } + override fun invokeMainAction(tangemSdk: TangemSdk, callback: ActionCallback) { action.executeMainAction(this, getAttrsForAction(tangemSdk), callback) } diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt index 1652cd2833..4a9c0b0572 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt @@ -29,7 +29,7 @@ class PersonalizationItemsManager( @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onDestroy() { - val config = converter.convert(itemList, PersonalizationConfig()) + val config = converter.convert(itemList, PersonalizationConfig.default()) store.save(config) } } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/BaseCardActionFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/BaseCardActionFragment.kt index 1449441016..e438ba167f 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/BaseCardActionFragment.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/BaseCardActionFragment.kt @@ -12,6 +12,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.google.android.material.floatingactionbutton.FloatingActionButton import com.tangem.TangemSdk import com.tangem.commands.Card +import com.tangem.commands.CommandResponse import com.tangem.tangem_sdk_new.extensions.init import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.Id @@ -87,39 +88,45 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView { protected open fun subscribeToViewModelChanges() { Log.d(this, "subscribeToViewModelChanges") - listenResponse() - listenResponseData() - listenResponseCardData() - listenError() - listenChangedItems() - listenDescriptionSwitchChanges() - } - - private fun listenResponse() { actionVM.seResponse.observe(viewLifecycleOwner, Observer { - Log.d(this, "listen response: $it") - mainActivityVM.changeResponseEvent(it) + Log.d(this, "handle response: $it") + handleResponse(it) }) - } - - protected open fun listenResponseData() { actionVM.seResponseData.observe(viewLifecycleOwner, Observer { - Log.d(this, "listen responseData: $it") - navigateTo(R.id.action_nav_card_action_to_response_screen) + Log.d(this, "handle responseData: $it") + handleResponseData(it) }) - } - - protected open fun listenResponseCardData() { actionVM.seResponseCardData.observe(viewLifecycleOwner, Observer { - Log.d(this, "listen responseCardData: $it") - responseCardDataHandled(it) + Log.d(this, "handle responseCardData: $it") + handleResponseCardData(it) }) + actionVM.seError.observe(viewLifecycleOwner, Observer { + Log.d(this, "handle error: $it") + handleError(it) + }) + mainActivityVM.ldDescriptionSwitch.observe(viewLifecycleOwner, Observer { + Log.d(this, "handle descriptionVisibilityState: $it") + handleDescriptionSwitchChanges(it) + }) + listenChangedItems() } - protected open fun responseCardDataHandled(card: Card?) {} + protected open fun handleResponse(response: CommandResponse) { + mainActivityVM.changeResponseEvent(response) + } - protected open fun listenError() { - actionVM.seError.observe(viewLifecycleOwner, Observer { showSnackbar(it) }) + protected open fun handleResponseData(response: CommandResponse) { + navigateTo(R.id.action_nav_card_action_to_response_screen) + } + + protected open fun handleResponseCardData(card: Card) {} + + protected open fun handleError(error: String) { + showSnackbar(error) + } + + protected open fun handleDescriptionSwitchChanges(descriptionVisibilityState: Boolean) { + actionVM.toggleDescriptionVisibility(descriptionVisibilityState) } @Deprecated("Start to use itemViewModel") @@ -132,12 +139,6 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView { }) } - protected open fun listenDescriptionSwitchChanges() { - mainActivityVM.ldDescriptionSwitch.observe(viewLifecycleOwner, Observer { - actionVM.toggleDescriptionVisibility(it) - }) - } - private fun inflateParamView(where: ViewGroup): ViewGroup { val inflater = LayoutInflater.from(where.context) val view = inflater.inflate(R.layout.w_card_incoming_param, where, false) diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/PersonalizationConfigStore.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/PersonalizationConfigStore.kt index 77a68278f8..cf39429e76 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/PersonalizationConfigStore.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/PersonalizationConfigStore.kt @@ -5,22 +5,46 @@ import android.content.SharedPreferences import androidx.core.content.edit import com.google.gson.Gson import com.tangem.tangemtest.AppTangemDemo +import com.tangem.tangemtest.commons.KeyedStore import com.tangem.tangemtest.commons.Store import com.tangem.tangemtest.ucase.variants.personalize.dto.PersonalizationConfig -class PersonalizationConfigStore(context: Context) : Store { +class PersonalizationConfigStore(context: Context) : Store, KeyedStore { - private val key = "personalization_config" + private val sharedPreferencesKey = "personalization_presets" + private val defaultKey = "default" - private val sp: SharedPreferences = (context.applicationContext as AppTangemDemo).sharedPreferences() + private val sp: SharedPreferences = (context.applicationContext as AppTangemDemo).sharedPreferences(sharedPreferencesKey) private val gson: Gson = Gson() - override fun save(config: PersonalizationConfig) { - sp.edit(true) { putString(key, gson.toJson(config)) } + override fun save(value: PersonalizationConfig) { + save(defaultKey, value) } - override fun restore(): PersonalizationConfig { - val json = sp.getString(key, gson.toJson(PersonalizationConfig())) - return gson.fromJson(json, PersonalizationConfig::class.java) + override fun restore(): PersonalizationConfig = restore(defaultKey) + + override fun save(key: String, value: PersonalizationConfig) { + sp.edit(true) { putString(key, toJson(value)) } } + + override fun restore(key: String): PersonalizationConfig { + val json = sp.getString(key, toJson(getDefaultConfig())) + return fromJson(json!!) + } + + override fun restoreAll(): Map { + val map = mutableMapOf() + sp.all.forEach { map[it.key] = fromJson(it.value as String) } + return map.toSortedMap() + } + + override fun delete(key: String) { + sp.edit(true) { remove(key) } + } + + private fun getDefaultConfig(): PersonalizationConfig = PersonalizationConfig.default() + + private fun toJson(value: PersonalizationConfig): String = gson.toJson(value) + + private fun fromJson(json: String): PersonalizationConfig = gson.fromJson(json, PersonalizationConfig::class.java) } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/dto/PersonalizationConfig.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/dto/PersonalizationConfig.kt index 2bfd50514c..ba97f5768d 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/dto/PersonalizationConfig.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/dto/PersonalizationConfig.kt @@ -6,20 +6,19 @@ package com.tangem.tangemtest.ucase.variants.personalize.dto class PersonalizationConfig { // Card number - var series = "BB" - var startNumber: Long = 300000000000 - var batchId = "ffff" - + var series = "" + var startNumber: Long = 0 + var batchId = "" // Common - var curveID = "ed25519" - var blockchain = "BTC/test" + var curveID = "" + var blockchain = "" var blockchainCustom = "" - var MaxSignatures: Long = 999999 - var createWallet = true + var MaxSignatures: Long = 0 + var createWallet = false // Signing method - var SigningMethod0 = true + var SigningMethod0 = false var SigningMethod1 = false var SigningMethod2 = false var SigningMethod3 = false @@ -27,19 +26,16 @@ class PersonalizationConfig { var SigningMethod5 = false var SigningMethod6 = false - // Sign hash external properties - var pinLessFloorLimit: Long = 100000 - var hexCrExKey = "00112233445566778899AABBCCDDEEFFFFEEDDCCBBAA998877665544332211000000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF" + var pinLessFloorLimit: Long = 0 + var hexCrExKey = "" var requireTerminalTxSignature = false var requireTerminalCertSignature = false - var checkPIN3onCard = true - + var checkPIN3onCard = false // Denomination var writeOnPersonalization = false - var denomination: Long = 1000000 - + var denomination: Long = 0 // Token var itsToken = false @@ -47,49 +43,125 @@ class PersonalizationConfig { var contractAddress = "" var decimal: Long = 0 - var cardData = CardData() - // Settings mask - var isReusable = true + var isReusable = false var useActivation = false var forbidPurgeWallet = false var allowSelectBlockchain = false var useBlock = false var oneApdu = false var useCVC = false - var allowSwapPIN = true - var allowSwapPIN2 = true + var allowSwapPIN = false + var allowSwapPIN2 = false var forbidDefaultPIN = false - var smartSecurityDelay = true - var protectIssuerDataAgainstReplay = true - var skipSecurityDelayIfValidatedByIssuer = true - var skipCheckPIN2andCVCIfValidatedByIssuer = true - var skipSecurityDelayIfValidatedByLinkedTerminal = true + var smartSecurityDelay = false + var protectIssuerDataAgainstReplay = false + var skipSecurityDelayIfValidatedByIssuer = false + var skipCheckPIN2andCVCIfValidatedByIssuer = false + var skipSecurityDelayIfValidatedByLinkedTerminal = false var restrictOverwriteIssuerDataEx = false - // Settings mask - protocol encryption - var protocolAllowUnencrypted = true - var protocolAllowStaticEncryption = true + var protocolAllowUnencrypted = false + var protocolAllowStaticEncryption = false - - var useNDEF = true - var useDynamicNDEF = true + var useNDEF = false + var useDynamicNDEF = false var disablePrecomputedNDEF = false - var aar = "com.tangem.wallet" + var aar = "" var aarCustom = "" - var uri = "https://tangem.com" - + var uri = "" // Pins - var PIN = "000000" - var PIN2 = "000" + var PIN = "" + var PIN2 = "" var PIN3 = "" - var CVC = "000" - var pauseBeforePIN2: Long = 5000L + var CVC = "" + var pauseBeforePIN2: Long = 0 + companion object { + fun default(): PersonalizationConfig { + return PersonalizationConfig().apply { + // Card number + series = "BB" + startNumber = 300000000000L + batchId = "ffff" + + // Common + curveID = "ed25519" + blockchain = "BTC/test" + blockchainCustom = "" + MaxSignatures = 999999L + createWallet = true + + // Signing method + SigningMethod0 = true + SigningMethod1 = false + SigningMethod2 = false + SigningMethod3 = false + SigningMethod4 = false + SigningMethod5 = false + SigningMethod6 = false + + // Sign hash external properties + pinLessFloorLimit = 100000L + hexCrExKey = "00112233445566778899AABBCCDDEEFFFFEEDDCCBBAA998877665544332211000000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF" + requireTerminalTxSignature = false + requireTerminalCertSignature = false + checkPIN3onCard = true + + // Denomination + writeOnPersonalization = false + denomination = 1000000L + + // Token + itsToken = false + symbol = "" + contractAddress = "" + decimal = 0L + + cardData = CardData() + + // Settings mask + isReusable = true + useActivation = false + forbidPurgeWallet = false + allowSelectBlockchain = false + useBlock = false + oneApdu = false + useCVC = false + allowSwapPIN = true + allowSwapPIN2 = true + forbidDefaultPIN = false + smartSecurityDelay = true + protectIssuerDataAgainstReplay = true + skipSecurityDelayIfValidatedByIssuer = true + skipCheckPIN2andCVCIfValidatedByIssuer = true + skipSecurityDelayIfValidatedByLinkedTerminal = true + restrictOverwriteIssuerDataEx = false + + // Settings mask - protocol encryption + protocolAllowUnencrypted = true + protocolAllowStaticEncryption = true + + useNDEF = true + useDynamicNDEF = true + disablePrecomputedNDEF = false + aar = "com.tangem.wallet" + aarCustom = "" + uri = "https://tangem.com" + + // Pins + PIN = "000000" + PIN2 = "000" + PIN3 = "" + CVC = "000" + pauseBeforePIN2 = 5000L + } + } + } } class CardData { diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/PersonalizationFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/PersonalizationFragment.kt index 313410115c..4d771cd24b 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/PersonalizationFragment.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/PersonalizationFragment.kt @@ -1,11 +1,14 @@ package com.tangem.tangemtest.ucase.variants.personalize.ui +import android.content.DialogInterface import android.os.Bundle -import android.view.View -import android.view.ViewGroup +import android.view.* import android.widget.Button +import android.widget.EditText import android.widget.LinearLayout import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import androidx.transition.Fade import androidx.transition.TransitionManager import com.tangem.commands.Card @@ -13,7 +16,9 @@ import com.tangem.tangemtest.R import com.tangem.tangemtest._arch.structure.Id import com.tangem.tangemtest._arch.structure.StringId import com.tangem.tangemtest._arch.structure.abstraction.Item +import com.tangem.tangemtest._arch.structure.abstraction.SafeValueChanged import com.tangem.tangemtest._arch.widget.WidgetBuilder +import com.tangem.tangemtest.commons.DialogController import com.tangem.tangemtest.commons.view.MultiActionView import com.tangem.tangemtest.commons.view.ViewAction import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager @@ -24,6 +29,9 @@ import com.tangem.tangemtest.ucase.tunnel.ActionView import com.tangem.tangemtest.ucase.tunnel.ItemError import com.tangem.tangemtest.ucase.ui.BaseCardActionFragment import com.tangem.tangemtest.ucase.variants.personalize.PersonalizationConfigStore +import com.tangem.tangemtest.ucase.variants.personalize.ui.presets.PersonalizationPresetManager +import com.tangem.tangemtest.ucase.variants.personalize.ui.presets.PersonalizationPresetView +import com.tangem.tangemtest.ucase.variants.personalize.ui.presets.RvPresetNamesAdapter import com.tangem.tangemtest.ucase.variants.personalize.ui.widgets.PersonalizationItemBuilder import ru.dev.gbixahue.eu4d.lib.android._android.views.inflate import ru.dev.gbixahue.eu4d.lib.android.global.log.Log @@ -33,12 +41,17 @@ import ru.dev.gbixahue.eu4d.lib.android.global.threading.postWork /** [REDACTED_AUTHOR] */ -class PersonalizationFragment : BaseCardActionFragment() { +class PersonalizationFragment : BaseCardActionFragment(), PersonalizationPresetView { override val itemsManager: ItemsManager by lazy { PersonalizationItemsManager(PersonalizationConfigStore(requireContext())) } override fun getLayoutId(): Int = R.layout.fg_base_action_layout + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + setHasOptionsMenu(true) + return super.onCreateView(inflater, container, savedInstanceState) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) lifecycle.addObserver(itemsManager as PersonalizationItemsManager) @@ -102,6 +115,28 @@ class PersonalizationFragment : BaseCardActionFragment() { contentContainer.addView(btnContainer) } + override fun handleResponseCardData(card: Card) { + super.handleResponseCardData(card) + navigateTo(R.id.action_nav_card_action_to_response_screen) + } + + override fun onPrepareOptionsMenu(menu: Menu) { + super.onPrepareOptionsMenu(menu) + menu.setGroupVisible(R.id.menu_group_personalization_preset, true) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + val store = PersonalizationConfigStore(requireContext()) + val presetManager = PersonalizationPresetManager(itemsManager, store, this) + when (item.itemId) { + R.id.action_reset -> presetManager.resetToDefault() + R.id.action_save -> presetManager.savePreset() + R.id.action_load -> presetManager.loadPreset() + else -> return super.onOptionsItemSelected(item) + } + return true + } + override fun showSnackbar(id: Id, additionalHandler: ((Id) -> Int)?) { super.showSnackbar(id) { when (id) { @@ -112,8 +147,31 @@ class PersonalizationFragment : BaseCardActionFragment() { } } - override fun responseCardDataHandled(card: Card?) { - super.responseCardDataHandled(card) - navigateTo(R.id.action_nav_card_action_to_response_screen) + override fun showSavePresetDialog(onOk: SafeValueChanged) { + val dlgController = DialogController() + val dlg = dlgController.createAlert(requireActivity(), R.layout.dlg_personalization_preset_save) + dlg.setTitle(R.string.menu_preset_save) + dlg.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.btn_cancel)) { dialog, which -> } + dlg.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.btn_ok)) { dialog, which -> + val tvName = dlgController.view?.findViewById(R.id.et_item) ?: return@setButton + val name = tvName.text.toString() + if (name.isEmpty()) showSnackbar("Not saved") + else onOk.invoke(name) + } + dlgController.show() + } + + override fun showLoadPresetDialog(namesList: List, onChoose: SafeValueChanged, onDelete: SafeValueChanged) { + val dlgController = DialogController() + val dlg = dlgController.createAlert(requireActivity(), R.layout.dlg_personalization_preset_load) + dlg.setTitle(R.string.menu_preset_load) + val rvPresetNames: RecyclerView = dlgController.view?.findViewById(R.id.recycler_view) ?: return + + rvPresetNames.layoutManager = LinearLayoutManager(context) + rvPresetNames.adapter = RvPresetNamesAdapter({ + onChoose(it) + dlgController.dismiss() + }, onDelete).apply { setItemList(namesList.toMutableList()) } + dlgController.show() } } \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PersonalizationPresetManager.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PersonalizationPresetManager.kt new file mode 100644 index 0000000000..b9f821902a --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PersonalizationPresetManager.kt @@ -0,0 +1,47 @@ +package com.tangem.tangemtest.ucase.variants.personalize.ui.presets + +import com.tangem.tangemtest.R +import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager +import com.tangem.tangemtest.ucase.variants.personalize.PersonalizationConfigStore +import com.tangem.tangemtest.ucase.variants.personalize.converter.PersonalizationConfigConverter +import com.tangem.tangemtest.ucase.variants.personalize.dto.PersonalizationConfig + +class PersonalizationPresetManager( + private val itemsManager: ItemsManager, + private val store: PersonalizationConfigStore, + private val view: PersonalizationPresetView +) { + + fun resetToDefault() { + val config = PersonalizationConfig.default() + val converter = PersonalizationConfigConverter() + itemsManager.updateByItemList(converter.convert(config)) + store.save(config) + } + + fun loadPreset() { + val presets = store.restoreAll() + val namesList = presets.map { it.key }.toMutableList() + if (namesList.size <= 1) { + view.showSnackbar(R.string.error_nothing_to_load) + return + } + + namesList.removeAt(0) + view.showLoadPresetDialog(namesList, { + val converter = PersonalizationConfigConverter() + val config = store.restore(it) + itemsManager.updateByItemList(converter.convert(config)) + }, { + store.delete(it) + }) + } + + fun savePreset() { + view.showSavePresetDialog { name -> + val converter = PersonalizationConfigConverter() + val config = converter.convert(itemsManager.getItems(), PersonalizationConfig.default()) + store.save(name, config) + } + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PersonalizationPresetView.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PersonalizationPresetView.kt new file mode 100644 index 0000000000..d4988973dc --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PersonalizationPresetView.kt @@ -0,0 +1,9 @@ +package com.tangem.tangemtest.ucase.variants.personalize.ui.presets + +import com.tangem.tangemtest._arch.structure.abstraction.SafeValueChanged +import com.tangem.tangemtest.ucase.tunnel.SnackbarHolder + +interface PersonalizationPresetView : SnackbarHolder { + fun showSavePresetDialog(onOk: SafeValueChanged) + fun showLoadPresetDialog(namesList: List, onChoose: SafeValueChanged, onDelete: SafeValueChanged) +} \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PresetRv.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PresetRv.kt new file mode 100644 index 0000000000..885fd24554 --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/presets/PresetRv.kt @@ -0,0 +1,47 @@ +package com.tangem.tangemtest.ucase.variants.personalize.ui.presets + +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.TextView +import com.tangem.tangemtest.R +import com.tangem.tangemtest._arch.structure.abstraction.SafeValueChanged +import ru.dev.gbixahue.eu4d.lib.android._android.views.inflate +import ru.dev.gbixahue.eu4d.lib.android._android.views.recycler_view.RvBaseAdapter +import ru.dev.gbixahue.eu4d.lib.android._android.views.recycler_view.RvVH + +/** +[REDACTED_AUTHOR] + */ +class RvPresetNamesAdapter( + private val onItemClicked: SafeValueChanged, + private val onDeleteClicked: SafeValueChanged +) : RvBaseAdapter() { + override fun onBindViewHolder(holder: PresetNameVH, position: Int) { + holder.bindData(itemList[position]) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PresetNameVH { + val view = parent.inflate(R.layout.vh_personalization_preset_name, false) + return PresetNameVH(view, onItemClicked, { position, value -> + onDeleteClicked(value) + itemList.removeAt(position) + this.notifyItemRemoved(position) + }) + } +} + +class PresetNameVH( + itemView: View, + private val onItemClicked: SafeValueChanged, + private val onDeleteClicked: (Int, String) -> Unit +) : RvVH(itemView) { + private val tvName = itemView.findViewById(R.id.tv_name) + private val btnDelete = itemView.findViewById