Updated on 2026-08-14
This commit is contained in:
commit
0b7d4ecdae
71 changed files with 1219 additions and 446 deletions
|
|
@ -46,10 +46,11 @@ dependencies {
|
|||
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 "androidx.recyclerview:recyclerview:1.2.0-alpha02"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
||||
implementation "com.google.android.material:material:1.2.0-alpha05"
|
||||
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.github.gbIxaHue:eu4d:0.3.7'
|
||||
implementation 'com.github.gbIxaHue:eu4d:0.3.8'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ fun List<Item>.iterate(func: (Item) -> Unit) {
|
|||
forEach {
|
||||
when (it) {
|
||||
is BaseItem -> func(it)
|
||||
is ItemGroup -> it.itemList.iterate(func)
|
||||
is ItemGroup -> {
|
||||
func(it)
|
||||
it.itemList.iterate(func)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,12 @@ import com.tangem.tangemtest._arch.structure.Id
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface Item {
|
||||
|
||||
interface UpdateBy<B>{
|
||||
fun update(value: B)
|
||||
}
|
||||
|
||||
interface Item: UpdateBy<Item> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -49,4 +49,8 @@ open class SimpleItemGroup(
|
|||
ILog.d(this, "clear $id")
|
||||
itemList.clear()
|
||||
}
|
||||
|
||||
override fun update(value: Item) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ class KeyValue(val key: String, val value: Any)
|
|||
class ViewState(
|
||||
isVisible: Boolean? = null,
|
||||
bgColor: Int? = -1
|
||||
) {
|
||||
) : UpdateBy<ViewState> {
|
||||
|
||||
class State<T>(
|
||||
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.update(value.isVisibleState)
|
||||
// backgroundColor.update(value.backgroundColor)
|
||||
// descriptionVisibility.update(value.descriptionVisibility)
|
||||
}
|
||||
}
|
||||
|
||||
interface ItemViewModel : PayloadHolder {
|
||||
interface ItemViewModel : PayloadHolder, UpdateBy<ItemViewModel> {
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -11,29 +11,29 @@ open class TypedItem<D>(id: Id, viewModel: ItemViewModel) : BaseItem(id, viewMod
|
|||
open fun getTypedData(): D? = viewModel.data as? D
|
||||
}
|
||||
|
||||
class TextItem(id: Id, viewModel: ItemViewModel) : TypedItem<String>(id, viewModel) {
|
||||
open class TextItem(id: Id, viewModel: ItemViewModel) : TypedItem<String>(id, viewModel) {
|
||||
constructor(id: Id, value: String? = null, viewState: ViewState = ViewState())
|
||||
: this(id, BaseItemViewModel(value, viewState))
|
||||
}
|
||||
|
||||
class NumberItem(id: Id, viewModel: ItemViewModel) : TypedItem<Number>(id, viewModel) {
|
||||
open class NumberItem(id: Id, viewModel: ItemViewModel) : TypedItem<Number>(id, viewModel) {
|
||||
constructor(id: Id, value: Number? = null, viewState: ViewState = ViewState())
|
||||
: this(id, BaseItemViewModel(value, viewState))
|
||||
}
|
||||
|
||||
class BoolItem(id: Id, viewModel: ItemViewModel) : TypedItem<Boolean>(id, viewModel) {
|
||||
open class BoolItem(id: Id, viewModel: ItemViewModel) : TypedItem<Boolean>(id, viewModel) {
|
||||
constructor(id: Id, value: Boolean? = null, viewState: ViewState = ViewState())
|
||||
: this(id, BaseItemViewModel(value, viewState))
|
||||
}
|
||||
|
||||
|
||||
class EditTextItem(id: Id, viewModel: ItemViewModel) : TypedItem<String>(id, viewModel) {
|
||||
open class EditTextItem(id: Id, viewModel: ItemViewModel) : TypedItem<String>(id, viewModel) {
|
||||
constructor(id: Id, value: String? = null, viewState: ViewState = ViewState())
|
||||
: this(id, BaseItemViewModel(value, viewState))
|
||||
}
|
||||
|
||||
|
||||
class SpinnerItem(id: Id, viewModel: ListViewModel) : TypedItem<ListViewModel>(id, viewModel) {
|
||||
open class SpinnerItem(id: Id, viewModel: ListViewModel) : TypedItem<ListViewModel>(id, viewModel) {
|
||||
constructor(id: Id, list: List<KeyValue>, selectedValue: Any?, viewState: ViewState = ViewState())
|
||||
: this(id, ListViewModel(list, selectedValue, viewState))
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@ package com.tangem.tangemtest._main
|
|||
import android.content.res.Resources
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
|
|
@ -20,7 +20,7 @@ import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
|
|||
*/
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private val vm: MainViewModel by viewModels<MainViewModel>()
|
||||
private val mainVM: MainViewModel by viewModels<MainViewModel>()
|
||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -52,11 +52,24 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.main_menu, menu)
|
||||
val switchMenu = menu.findItem(R.id.action_favorite)
|
||||
(switchMenu.actionView as? SwitchCompat)?.let {
|
||||
it.setOnCheckedChangeListener { buttonView, isChecked -> vm.switchToggled(isChecked) }
|
||||
menuInflater.inflate(R.menu.menu_activity_main, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||
val switchItem = menu.findItem(R.id.action_toggle_description_visibility)
|
||||
switchItem.isChecked = mainVM.descriptionSwitchState
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val result = when (item.itemId) {
|
||||
R.id.action_toggle_description_visibility -> {
|
||||
item.isChecked = !item.isChecked
|
||||
mainVM.switchToggled(item.isChecked)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
return if (result == null) super.onOptionsItemSelected(item) else true
|
||||
}
|
||||
}
|
||||
|
|
@ -10,10 +10,12 @@ import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
|
|||
*/
|
||||
class MainViewModel : ViewModel() {
|
||||
val ldDescriptionSwitch = MutableLiveData<Boolean>(false)
|
||||
var descriptionSwitchState = false
|
||||
|
||||
var commandResponse: CommandResponse? = null
|
||||
|
||||
fun switchToggled(state: Boolean) {
|
||||
descriptionSwitchState = state
|
||||
ldDescriptionSwitch.postValue(state)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,16 +2,14 @@ package com.tangem.tangemtest._main.entryPoint
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.AutoTransition
|
||||
import androidx.transition.TransitionManager
|
||||
import com.tangem.tangemtest.R
|
||||
import com.tangem.tangemtest._main.MainViewModel
|
||||
import com.tangem.tangemtest.extensions.view.beginDelayedTransition
|
||||
import com.tangem.tangemtest.ucase.getDefaultNavigationOptions
|
||||
import com.tangem.tangemtest.ucase.resources.ActionType
|
||||
import com.tangem.tangemtest.ucase.resources.MainResourceHolder
|
||||
|
|
@ -47,7 +45,7 @@ class ActionListFragment : BaseFragment() {
|
|||
}
|
||||
mainActivityVM.ldDescriptionSwitch.observe(viewLifecycleOwner, Observer {
|
||||
vhDataWrapper.descriptionIsVisible = it
|
||||
TransitionManager.beginDelayedTransition(rvActions as ViewGroup, AutoTransition())
|
||||
rvActions.beginDelayedTransition()
|
||||
rvActions.adapter?.notifyDataSetChanged()
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ class RvActionsVH(
|
|||
|
||||
containerDescription.visibility = if (wrapper.descriptionIsVisible) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun onDataBound(data: ActionType) {}
|
||||
}
|
||||
|
||||
fun RecyclerView.ViewHolder.getString(@StringRes id: Int?, ifNull: String = ""): String {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@ package com.tangem.tangemtest.commons
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface Store<M> {
|
||||
fun save(config: M)
|
||||
fun save(value: M)
|
||||
fun restore(): M
|
||||
}
|
||||
|
||||
interface KeyedStore<M> {
|
||||
fun save(key: String, value: M)
|
||||
fun restore(key: String): M
|
||||
fun restoreAll(): MutableMap<String, M>
|
||||
fun delete(key: String)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.tangemtest.extensions.view
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.transition.AutoTransition
|
||||
import androidx.transition.Transition
|
||||
import androidx.transition.TransitionManager
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun ViewGroup.beginDelayedTransition(transition: Transition = AutoTransition()) {
|
||||
TransitionManager.beginDelayedTransition(this, transition)
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
|||
class SignAction : BaseAction() {
|
||||
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
|
||||
val dataForHashing = attrs.itemList.findItem(TlvId.TransactionOutHash) ?: return
|
||||
val hash = dataForHashing.getData() as? ByteArray ?: return
|
||||
val hash = dataForHashing.getData() as? String ?: return
|
||||
val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return
|
||||
|
||||
attrs.tangemSdk.sign(arrayOf(hash), stringOf(cardId)) { handleResult(payload, it, null, attrs, callback) }
|
||||
attrs.tangemSdk.sign(arrayOf(hash.toByteArray()), stringOf(cardId)) { handleResult(payload, it, null, attrs, callback) }
|
||||
}
|
||||
|
||||
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
|
||||
|
|
|
|||
|
|
@ -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<Item>)
|
||||
}
|
||||
|
||||
interface PayloadKey {
|
||||
|
|
|
|||
|
|
@ -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<Item>) {
|
||||
list.iterate { itemList.findItem(it.id)?.update(it) }
|
||||
}
|
||||
|
||||
override fun invokeMainAction(tangemSdk: TangemSdk, callback: ActionCallback) {
|
||||
action.executeMainAction(this, getAttrsForAction(tangemSdk), callback)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import com.tangem.commands.Card
|
|||
import com.tangem.commands.EllipticCurve
|
||||
import com.tangem.common.extensions.calculateSha256
|
||||
import com.tangem.common.extensions.calculateSha512
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.tangemtest._arch.structure.PayloadHolder
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.Item
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.findItem
|
||||
|
|
@ -40,7 +41,7 @@ class SignScanConsequence : ItemsChangeConsequence {
|
|||
EllipticCurve.Ed25519 -> dataForHashing.calculateSha512()
|
||||
else -> return null
|
||||
}
|
||||
hashItem.setData(hashedData)
|
||||
hashItem.setData(hashedData.toHexString())
|
||||
}
|
||||
return affectedItems.toList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tangemtest.ucase.domain.responses
|
|||
import com.google.gson.*
|
||||
import com.tangem.commands.*
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.tangemtest.extensions.print
|
||||
import java.lang.reflect.Type
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
|
@ -11,14 +12,17 @@ import java.util.*
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class ResponseJsonConverter {
|
||||
|
||||
val gson: Gson by lazy { init() }
|
||||
|
||||
private val fieldConverter = ResponseFieldConverter()
|
||||
|
||||
private fun init(): Gson {
|
||||
val builder = GsonBuilder().apply {
|
||||
registerTypeAdapter(ByteArray::class.java, ByteTypeAdapter())
|
||||
registerTypeAdapter(SigningMethodMask::class.java, SigningMethodTypeAdapter())
|
||||
registerTypeAdapter(SettingsMask::class.java, SettingsMaskTypeAdapter())
|
||||
registerTypeAdapter(ProductMask::class.java, ProductMaskTypeAdapter())
|
||||
registerTypeAdapter(ByteArray::class.java, ByteTypeAdapter(fieldConverter))
|
||||
registerTypeAdapter(SigningMethodMask::class.java, SigningMethodTypeAdapter(fieldConverter))
|
||||
registerTypeAdapter(SettingsMask::class.java, SettingsMaskTypeAdapter(fieldConverter))
|
||||
registerTypeAdapter(ProductMask::class.java, ProductMaskTypeAdapter(fieldConverter))
|
||||
registerTypeAdapter(Date::class.java, DateTypeAdapter())
|
||||
}
|
||||
builder.setPrettyPrinting()
|
||||
|
|
@ -28,31 +32,41 @@ class ResponseJsonConverter {
|
|||
fun convertResponse(response: CommandResponse?): String = gson.toJson(response)
|
||||
}
|
||||
|
||||
class ByteTypeAdapter : JsonSerializer<ByteArray> {
|
||||
class ByteTypeAdapter(
|
||||
private val fieldConverter: ResponseFieldConverter
|
||||
) : JsonSerializer<ByteArray> {
|
||||
override fun serialize(src: ByteArray, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
return JsonPrimitive(src.toHexString())
|
||||
return JsonPrimitive(fieldConverter.byteArray(src))
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsMaskTypeAdapter : JsonSerializer<SettingsMask> {
|
||||
class SettingsMaskTypeAdapter(
|
||||
private val fieldConverter: ResponseFieldConverter
|
||||
) : JsonSerializer<SettingsMask> {
|
||||
override fun serialize(src: SettingsMask, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
val arrayElement = JsonArray()
|
||||
Settings.values()
|
||||
.filter { src.contains(it) }
|
||||
.forEach { arrayElement.add(it.name) }
|
||||
return arrayElement
|
||||
return JsonArray().apply {
|
||||
fieldConverter.settingsMaskList(src).forEach { add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ProductMaskTypeAdapter : JsonSerializer<ProductMask> {
|
||||
class ProductMaskTypeAdapter(
|
||||
private val fieldConverter: ResponseFieldConverter
|
||||
) : JsonSerializer<ProductMask> {
|
||||
override fun serialize(src: ProductMask, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
return JsonPrimitive(src.rawValue.toString())
|
||||
return JsonArray().apply {
|
||||
fieldConverter.productMaskList(src).forEach { add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SigningMethodTypeAdapter : JsonSerializer<SigningMethodMask> {
|
||||
class SigningMethodTypeAdapter(
|
||||
private val fieldConverter: ResponseFieldConverter
|
||||
) : JsonSerializer<SigningMethodMask> {
|
||||
override fun serialize(src: SigningMethodMask, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
return JsonPrimitive(src.rawValue.toString())
|
||||
return JsonArray().apply {
|
||||
fieldConverter.signingMethodList(src).forEach { add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,4 +75,41 @@ class DateTypeAdapter : JsonSerializer<Date> {
|
|||
val formatter = DateFormat.getDateInstance(DateFormat.DEFAULT, Locale("en_US"))
|
||||
return JsonPrimitive(formatter.format(src).toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseFieldConverter {
|
||||
|
||||
fun productMask(productMask: ProductMask?): String {
|
||||
return productMaskList(productMask).print(wrap = false)
|
||||
}
|
||||
|
||||
fun productMaskList(productMask: ProductMask?): List<String> {
|
||||
val mask = productMask ?: return emptyList()
|
||||
|
||||
return Product.values().filter { mask.contains(it) }.map { it.name }
|
||||
}
|
||||
|
||||
fun signingMethod(signingMask: SigningMethodMask?): String {
|
||||
return signingMethodList(signingMask).print(wrap = false)
|
||||
}
|
||||
|
||||
fun signingMethodList(signingMask: SigningMethodMask?): List<String> {
|
||||
val mask = signingMask ?: return emptyList()
|
||||
|
||||
return SigningMethod.values().filter { mask.contains(it) }.map { it.name }
|
||||
}
|
||||
|
||||
fun settingsMask(settingsMask: SettingsMask?): String {
|
||||
return settingsMaskList(settingsMask).print(wrap = false)
|
||||
}
|
||||
|
||||
fun settingsMaskList(settingsMask: SettingsMask?): List<String> {
|
||||
val masks = settingsMask ?: return emptyList()
|
||||
|
||||
return Settings.values().filter { masks.contains(it) }.map { it.name }
|
||||
}
|
||||
|
||||
fun byteArray(byteArray: ByteArray?): String? {
|
||||
return byteArray?.toHexString()
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ import com.tangem.tangemtest.ucase.resources.MainResourceHolder
|
|||
import com.tangem.tangemtest.ucase.resources.Resources
|
||||
import com.tangem.tangemtest.ucase.variants.responses.CardDataId
|
||||
import com.tangem.tangemtest.ucase.variants.responses.CardId
|
||||
import com.tangem.tangemtest.ucase.variants.responses.DepersonalizeId
|
||||
import com.tangem.tangemtest.ucase.variants.responses.SignId
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -13,6 +15,8 @@ class ResponseResources {
|
|||
fun init(holder: MainResourceHolder) {
|
||||
initCard(holder)
|
||||
initCardData(holder)
|
||||
initSignResponse(holder)
|
||||
initDepersonalizeResponse(holder)
|
||||
}
|
||||
|
||||
private fun initCard(holder: MainResourceHolder) {
|
||||
|
|
@ -26,7 +30,7 @@ class ResponseResources {
|
|||
holder.register(CardId.issuerPublicKey, Resources(R.string.response_card_issuer_data_public_key, R.string.info_response_card_issuer_data_public_key))
|
||||
holder.register(CardId.curve, Resources(R.string.response_card_curve, R.string.info_response_card_curve))
|
||||
holder.register(CardId.maxSignatures, Resources(R.string.response_card_max_signatures, R.string.info_response_card_max_signatures))
|
||||
holder.register(CardId.signingMethod, Resources(R.string.response_card_signing_method, R.string.response_card_signing_method))
|
||||
holder.register(CardId.signingMethod, Resources(R.string.response_card_signing_method, R.string.info_response_card_signing_method))
|
||||
holder.register(CardId.pauseBeforePin2, Resources(R.string.response_card_pause_before_pin2, R.string.info_response_card_allow_pin2))
|
||||
holder.register(CardId.walletPublicKey, Resources(R.string.response_card_wallet_public_key, R.string.info_response_card_wallet_public_key))
|
||||
holder.register(CardId.walletRemainingSignatures, Resources(R.string.response_card_wallet_remaining_signatures, R.string.info_response_card_wallet_remaining_signatures))
|
||||
|
|
@ -50,4 +54,15 @@ class ResponseResources {
|
|||
holder.register(CardDataId.tokenContractAddress, Resources(R.string.response_card_card_data_token_contract_address, R.string.info_response_card_card_data_token_contract_address))
|
||||
holder.register(CardDataId.tokenDecimal, Resources(R.string.response_card_card_data_token_decimal, R.string.info_response_card_card_data_token_decimal))
|
||||
}
|
||||
|
||||
private fun initSignResponse(holder: MainResourceHolder) {
|
||||
holder.register(SignId.cid, Resources(R.string.response_sign_cid, R.string.info_response_sign_cid))
|
||||
holder.register(SignId.walletSignedHashes, Resources(R.string.response_sign_wallet_signed_hashes, R.string.info_response_sign_wallet_signed_hashes))
|
||||
holder.register(SignId.walletRemainingSignatures, Resources(R.string.response_sign_wallet_remaining_signatures, R.string.info_response_sign_wallet_remaining_signatures))
|
||||
holder.register(SignId.signature, Resources(R.string.response_sign_signature, R.string.info_response_sign_signature))
|
||||
}
|
||||
|
||||
private fun initDepersonalizeResponse(holder: MainResourceHolder) {
|
||||
holder.register(DepersonalizeId.isSuccess, Resources(R.string.response_depersonalize_is_success, R.string.info_response_depersonalize_is_success))
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,11 @@ import androidx.core.view.plusAssign
|
|||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
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
|
||||
|
|
@ -28,7 +30,8 @@ import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
|
|||
*/
|
||||
abstract class BaseCardActionFragment : BaseFragment(), ActionView {
|
||||
|
||||
protected lateinit var itemContainer: ViewGroup
|
||||
protected lateinit var swrLayout: SwipeRefreshLayout
|
||||
protected lateinit var contentContainer: ViewGroup
|
||||
protected lateinit var actionFab: FloatingActionButton
|
||||
|
||||
protected abstract val itemsManager: ItemsManager
|
||||
|
|
@ -38,6 +41,8 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView {
|
|||
|
||||
private val paramsWidgetList = mutableListOf<ParameterWidget>()
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.fg_base_action_layout
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
Log.d(this, "onViewCreated")
|
||||
|
|
@ -47,7 +52,7 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView {
|
|||
actionVM.setCardManager(TangemSdk.init(requireActivity()))
|
||||
actionVM.attachToPayload(mutableMapOf(PayloadKey.actionView to this as ActionView))
|
||||
|
||||
initFab()
|
||||
initViews()
|
||||
createWidgets {
|
||||
widgetsWasCreated()
|
||||
subscribeToViewModelChanges()
|
||||
|
|
@ -57,11 +62,13 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView {
|
|||
protected open fun widgetsWasCreated() {}
|
||||
|
||||
protected open fun bindViews() {
|
||||
itemContainer = mainView.findViewById(R.id.ll_container)
|
||||
swrLayout = mainView.findViewById(R.id.swr_layout)
|
||||
contentContainer = mainView.findViewById(R.id.ll_content_container)
|
||||
actionFab = mainView.findViewById(R.id.fab_action)
|
||||
}
|
||||
|
||||
protected open fun initFab() {
|
||||
protected open fun initViews() {
|
||||
swrLayout.isEnabled = false
|
||||
enableActionFab(false)
|
||||
actionFab.setOnClickListener { actionVM.invokeMainAction() }
|
||||
}
|
||||
|
|
@ -70,7 +77,7 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView {
|
|||
Log.d(this, "createWidgets")
|
||||
actionVM.ldItemList.observe(viewLifecycleOwner, Observer { itemList ->
|
||||
itemList.forEach { param ->
|
||||
val widget = ParameterWidget(inflateParamView(itemContainer), param)
|
||||
val widget = ParameterWidget(inflateParamView(contentContainer), param)
|
||||
widget.onValueChanged = { id, value -> actionVM.userChangedItem(id, value) }
|
||||
widget.onActionBtnClickListener = actionVM.getItemAction(param.id)
|
||||
paramsWidgetList.add(widget)
|
||||
|
|
@ -81,39 +88,46 @@ 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, options = null)
|
||||
}
|
||||
|
||||
protected open fun handleResponseCardData(card: Card) {}
|
||||
|
||||
protected open fun handleError(error: String) {
|
||||
showSnackbar(error)
|
||||
}
|
||||
|
||||
protected open fun handleDescriptionSwitchChanges(descriptionVisibilityState: Boolean) {
|
||||
actionVM.toggleDescriptionVisibility(descriptionVisibilityState)
|
||||
paramsWidgetList.forEach { it.toggleDescriptionVisibility(descriptionVisibilityState) }
|
||||
}
|
||||
|
||||
@Deprecated("Start to use itemViewModel")
|
||||
|
|
@ -126,12 +140,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)
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.transition.AutoTransition
|
||||
import androidx.transition.TransitionManager
|
||||
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.Id
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.Item
|
||||
import com.tangem.tangemtest._arch.structure.impl.EditTextItem
|
||||
import com.tangem.tangemtest.extensions.view.beginDelayedTransition
|
||||
import com.tangem.tangemtest.ucase.resources.ActionType
|
||||
import com.tangem.tangemtest.ucase.resources.MainResourceHolder
|
||||
import com.tangem.tangemtest.ucase.resources.Resources
|
||||
|
|
@ -73,7 +72,7 @@ class ParameterWidget(
|
|||
}
|
||||
|
||||
fun toggleDescriptionVisibility(state: Boolean) {
|
||||
TransitionManager.beginDelayedTransition(parent.parent as ViewGroup, AutoTransition())
|
||||
(parent.parent as ViewGroup).beginDelayedTransition()
|
||||
descriptionContainer.visibility = if (state) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +94,7 @@ class ParameterWidget(
|
|||
private fun toggleActionBtnVisibility() {
|
||||
fun switchVisibilityState(newState: Int) {
|
||||
actionBtnVisibilityState = newState
|
||||
TransitionManager.beginDelayedTransition(parent, AutoTransition())
|
||||
parent.beginDelayedTransition()
|
||||
btnAction.visibility = actionBtnVisibilityState
|
||||
}
|
||||
when {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tangemtest.ucase.variants.depersonalize.ui
|
||||
|
||||
import com.tangem.tangemtest.R
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.managers.DepersonalizeItemsManager
|
||||
import com.tangem.tangemtest.ucase.ui.BaseCardActionFragment
|
||||
|
|
@ -11,6 +10,4 @@ import com.tangem.tangemtest.ucase.ui.BaseCardActionFragment
|
|||
class DepersonalizeActionFragment : BaseCardActionFragment() {
|
||||
|
||||
override val itemsManager: ItemsManager by lazy { DepersonalizeItemsManager() }
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.fg_depersonalize
|
||||
}
|
||||
|
|
@ -5,22 +5,49 @@ 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<PersonalizationConfig> {
|
||||
class PersonalizationConfigStore(context: Context) : Store<PersonalizationConfig>, KeyedStore<PersonalizationConfig> {
|
||||
|
||||
private val key = "personalization_config"
|
||||
companion object {
|
||||
val defaultKey = "default"
|
||||
}
|
||||
|
||||
private val sp: SharedPreferences = (context.applicationContext as AppTangemDemo).sharedPreferences()
|
||||
private val sharedPreferencesKey = "personalization_presets"
|
||||
|
||||
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(): MutableMap<String, PersonalizationConfig> {
|
||||
val map = mutableMapOf<String, PersonalizationConfig>()
|
||||
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)
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ class ConfigValuesHolder : BaseTypedHolder<Id, Value>() {
|
|||
register(CardNumber.BatchId, Value(default.batchId))
|
||||
register(Common.Curve, Value(default.curveID, Helper.listOfCurves()))
|
||||
register(Common.Blockchain, Value(default.blockchain, Helper.listOfBlockchain()))
|
||||
register(Common.BlockchainCustom, Value(""))
|
||||
register(Common.BlockchainCustom, Value(default.blockchainCustom))
|
||||
register(Common.MaxSignatures, Value(default.MaxSignatures))
|
||||
register(Common.CreateWallet, Value(default.createWallet))
|
||||
register(SigningMethod.SignTx, Value(default.SigningMethod0))
|
||||
|
|
@ -66,7 +66,7 @@ class ConfigValuesHolder : BaseTypedHolder<Id, Value>() {
|
|||
register(SettingsMaskNdef.DynamicNdef, Value(default.useDynamicNDEF))
|
||||
register(SettingsMaskNdef.DisablePrecomputedNdef, Value(default.disablePrecomputedNDEF))
|
||||
register(SettingsMaskNdef.Aar, Value(default.aar, Helper.aarList()))
|
||||
register(SettingsMaskNdef.AarCustom, Value(default.aar))
|
||||
register(SettingsMaskNdef.AarCustom, Value(default.aarCustom))
|
||||
register(SettingsMaskNdef.Uri, Value(default.uri))
|
||||
register(Pins.Pin, Value(default.PIN))
|
||||
register(Pins.Pin2, Value(default.PIN2))
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class ItemsToPersonalizationConfig : ItemsToModel<PersonalizationConfig> {
|
|||
val export = PersonalizationConfig()
|
||||
export.series = getTyped(CardNumber.Series)
|
||||
export.startNumber = getTyped(CardNumber.Number)
|
||||
export.batchId = getTyped(CardNumber.BatchId)
|
||||
export.curveID = getTyped(Common.Curve)
|
||||
export.blockchain = getTyped(Common.Blockchain)
|
||||
export.blockchainCustom = getTyped(Common.BlockchainCustom)
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
package com.tangem.tangemtest.ucase.variants.personalize.dto
|
||||
|
||||
import com.tangem.commands.EllipticCurve
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
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 +28,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 +45,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 = EllipticCurve.Secp256k1.curve
|
||||
blockchain = "ETH"
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,30 @@
|
|||
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.view.inputmethod.InputMethodManager
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.Fade
|
||||
import com.tangem.commands.Card
|
||||
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.extensions.view.beginDelayedTransition
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.PayloadKey
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.managers.PersonalizationItemsManager
|
||||
|
|
@ -21,28 +33,80 @@ 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 com.tangem.tangemtest.ucase.variants.responses.ui.ResponseFragment
|
||||
import ru.dev.gbixahue.eu4d.lib.android._android.views.inflate
|
||||
import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
|
||||
import ru.dev.gbixahue.eu4d.lib.android.global.threading.post
|
||||
import ru.dev.gbixahue.eu4d.lib.android.global.threading.postUI
|
||||
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_personalization
|
||||
override fun getLayoutId(): Int = R.layout.fg_base_action_layout
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
lifecycle.addObserver(itemsManager as PersonalizationItemsManager)
|
||||
}
|
||||
|
||||
override fun bindViews() {
|
||||
super.bindViews()
|
||||
swrLayout.isRefreshing = true
|
||||
}
|
||||
|
||||
override fun initViews() {
|
||||
actionFab.setOnClickListener { actionVM.invokeMainAction() }
|
||||
}
|
||||
|
||||
override fun createWidgets(widgetCreatedCallback: () -> Unit) {
|
||||
Log.d(this, "createWidgets")
|
||||
val itemList = mutableListOf<Item>()
|
||||
|
||||
val maxDelay = 500
|
||||
val timeStart = System.currentTimeMillis()
|
||||
actionVM.ldItemList.observe(viewLifecycleOwner, Observer { list ->
|
||||
Log.d(this, "ldBlockList size: ${list.size}")
|
||||
itemList.addAll(list)
|
||||
val llContainer = LinearLayout(requireContext()).apply { orientation = LinearLayout.VERTICAL }
|
||||
postWork {
|
||||
val builder = WidgetBuilder(PersonalizationItemBuilder())
|
||||
itemList.forEach { builder.build(it, llContainer) }
|
||||
actionVM.attachToPayload(mutableMapOf(
|
||||
PayloadKey.actionView to this as ActionView,
|
||||
PayloadKey.itemList to itemList
|
||||
))
|
||||
val timeEnd = System.currentTimeMillis()
|
||||
val diff = timeEnd - timeStart
|
||||
postUI(maxDelay - diff) {
|
||||
contentContainer.beginDelayedTransition(Fade())
|
||||
contentContainer.addView(llContainer)
|
||||
widgetCreatedCallback()
|
||||
swrLayout.isRefreshing = false
|
||||
swrLayout.isEnabled = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun widgetsWasCreated() {
|
||||
super.widgetsWasCreated()
|
||||
|
||||
val btnContainer = itemContainer.inflate<ViewGroup>(R.layout.view_simple_button)
|
||||
val btnContainer = contentContainer.inflate<ViewGroup>(R.layout.view_simple_button)
|
||||
val btn = btnContainer.findViewById<Button>(R.id.button)
|
||||
|
||||
val show = StringId("show")
|
||||
|
|
@ -55,28 +119,30 @@ class PersonalizationFragment : BaseCardActionFragment() {
|
|||
multiAction.state = if (it == show) hide else show
|
||||
}
|
||||
multiAction.performAction(hide)
|
||||
itemContainer.addView(btnContainer)
|
||||
contentContainer.addView(btnContainer)
|
||||
}
|
||||
|
||||
override fun initFab() {
|
||||
actionFab.setOnClickListener { actionVM.invokeMainAction() }
|
||||
override fun handleResponseCardData(card: Card) {
|
||||
super.handleResponseCardData(card)
|
||||
val bundle = ResponseFragment.setTittle(R.string.fg_name_response_personalization)
|
||||
navigateTo(R.id.action_nav_card_action_to_response_screen, bundle, null)
|
||||
}
|
||||
|
||||
override fun createWidgets(widgetCreatedCallback: () -> Unit) {
|
||||
Log.d(this, "createWidgets")
|
||||
val itemList = mutableListOf<Item>()
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.menu_fg_peronalization, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
actionVM.ldItemList.observe(viewLifecycleOwner, Observer { list ->
|
||||
Log.d(this, "ldBlockList size: ${list.size}")
|
||||
itemList.clear()
|
||||
itemList.addAll(list)
|
||||
itemList.forEach { WidgetBuilder(PersonalizationItemBuilder()).build(it, itemContainer) }
|
||||
actionVM.attachToPayload(mutableMapOf(
|
||||
PayloadKey.actionView to this as ActionView,
|
||||
PayloadKey.itemList to itemList
|
||||
))
|
||||
widgetCreatedCallback()
|
||||
})
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val store = PersonalizationConfigStore(requireContext())
|
||||
val presetManager = PersonalizationPresetManager(itemsManager, store, this)
|
||||
val result = when (item.itemId) {
|
||||
R.id.action_reset -> presetManager.resetToDefault()
|
||||
R.id.action_save -> presetManager.savePreset()
|
||||
R.id.action_load -> presetManager.loadPreset()
|
||||
else -> null
|
||||
}
|
||||
return if (result == null) super.onOptionsItemSelected(item) else true
|
||||
}
|
||||
|
||||
override fun showSnackbar(id: Id, additionalHandler: ((Id) -> Int)?) {
|
||||
|
|
@ -89,8 +155,51 @@ 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<String>) {
|
||||
val dlgController = DialogController()
|
||||
val dlg = dlgController.createAlert(requireActivity(), R.layout.dlg_personalization_preset_save)
|
||||
dlg.setTitle(R.string.menu_personalization_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<EditText>(R.id.et_item)
|
||||
?: return@setButton
|
||||
val name = tvName.text.toString()
|
||||
if (name.isEmpty()) showSnackbar("Not saved")
|
||||
else onOk.invoke(name)
|
||||
}
|
||||
dlgController.onShowCallback = {
|
||||
dlgController.view?.findViewById<TextView>(R.id.et_item)?.let {
|
||||
post(150) {
|
||||
it.requestFocus()
|
||||
val imm = getSystemService(requireContext(), InputMethodManager::class.java)
|
||||
imm?.showSoftInput(it, InputMethodManager.SHOW_IMPLICIT)
|
||||
}
|
||||
}
|
||||
}
|
||||
dlgController.show()
|
||||
}
|
||||
|
||||
override fun showLoadPresetDialog(namesList: List<String>, onChoose: SafeValueChanged<String>, onDelete: SafeValueChanged<String>) {
|
||||
val dlgController = DialogController()
|
||||
dlgController.createAlert(requireActivity(), R.layout.dlg_personalization_preset_load)
|
||||
.setTitle(R.string.menu_personalization_preset_load)
|
||||
|
||||
val rvPresetNames: RecyclerView = dlgController.view?.findViewById(R.id.recycler_view) ?: return
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
rvPresetNames.layoutManager = layoutManager
|
||||
rvPresetNames.addItemDecoration(DividerItemDecoration(activity, layoutManager.orientation))
|
||||
|
||||
val adapter = RvPresetNamesAdapter({
|
||||
onChoose(it)
|
||||
dlgController.dismiss()
|
||||
}, {
|
||||
onDelete(it)
|
||||
if (rvPresetNames.adapter?.itemCount == 0)
|
||||
dlgController.dismiss()
|
||||
})
|
||||
adapter.setItemList(namesList.toMutableList())
|
||||
|
||||
rvPresetNames.adapter = adapter
|
||||
dlgController.show()
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
presets.remove(PersonalizationConfigStore.defaultKey)
|
||||
val namesList = presets.map { it.key }.toMutableList()
|
||||
if (namesList.isEmpty()) {
|
||||
view.showSnackbar(R.string.error_nothing_to_load)
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String>)
|
||||
fun showLoadPresetDialog(namesList: List<String>, onChoose: SafeValueChanged<String>, onDelete: SafeValueChanged<String>)
|
||||
}
|
||||
|
|
@ -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<String>,
|
||||
private val onDeleteClicked: SafeValueChanged<String>
|
||||
) : RvBaseAdapter<PresetNameVH, String>() {
|
||||
override fun onBindViewHolder(holder: PresetNameVH, position: Int) {
|
||||
holder.bindData(itemList[position])
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PresetNameVH {
|
||||
val view = parent.inflate<View>(R.layout.vh_personalization_preset_name, false)
|
||||
return PresetNameVH(view, onItemClicked, { position, value ->
|
||||
itemList.removeAt(position)
|
||||
this.notifyItemRemoved(position)
|
||||
onDeleteClicked(value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class PresetNameVH(
|
||||
itemView: View,
|
||||
private val onItemClicked: SafeValueChanged<String>,
|
||||
private val onDeleteClicked: (Int, String) -> Unit
|
||||
) : RvVH<String>(itemView) {
|
||||
private val tvName = itemView.findViewById<TextView>(R.id.tv_name)
|
||||
private val btnDelete = itemView.findViewById<View>(R.id.btn_delete)
|
||||
override fun onDataBound(data: String) {
|
||||
tvName.text = data
|
||||
tvName.isClickable = false
|
||||
itemView.setOnClickListener { onItemClicked(data) }
|
||||
btnDelete.setOnClickListener { onDeleteClicked(absoluteAdapterPosition, data) }
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,10 @@ package com.tangem.tangemtest.ucase.variants.personalize.ui.widgets
|
|||
|
||||
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.abstraction.Item
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.ViewState
|
||||
import com.tangem.tangemtest.extensions.view.beginDelayedTransition
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -31,7 +30,7 @@ abstract class DescriptionWidget(
|
|||
if (description.isEmpty()) return
|
||||
|
||||
tv.text = description
|
||||
TransitionManager.beginDelayedTransition(view.parent as ViewGroup, AutoTransition())
|
||||
(view.parent as ViewGroup).beginDelayedTransition()
|
||||
descriptionContainer.visibility = state
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ import com.tangem.tangemtest._arch.widget.abstraction.ViewWidget
|
|||
class PersonalizationItemBuilder : ItemWidgetBuilder {
|
||||
override fun build(item: BaseItem, parent: ViewGroup): ViewWidget? {
|
||||
return when (item) {
|
||||
is TextItem -> GroupTitleWidget(parent, item)
|
||||
is TextItem -> TextHeaderWidget(parent, item)
|
||||
is EditTextItem -> EditTextWidget(parent, item)
|
||||
is NumberItem -> NumberWidget(parent, item)
|
||||
is BoolItem -> SwitchWidget(parent, item)
|
||||
|
|
|
|||
|
|
@ -46,9 +46,8 @@ class SpinnerWidget(
|
|||
}
|
||||
spinner.onItemSelectedListener = onItemSelectedListener
|
||||
item.viewModel.onDataUpdated = {
|
||||
val selectedItem = it as? String
|
||||
spinner.onItemSelectedListener = null
|
||||
viewModel.itemList.firstOrNull { item -> item.value == selectedItem }?.let { keyValue ->
|
||||
viewModel.itemList.firstOrNull { item -> item.value == it }?.let { keyValue ->
|
||||
val position = viewModel.itemList.indexOf(keyValue)
|
||||
spinner.setSelection(position)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import com.tangem.tangemtest._arch.structure.impl.TextItem
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class GroupTitleWidget(parent: ViewGroup, data: TextItem) : DescriptionWidget(parent, data) {
|
||||
override fun getLayoutId(): Int = R.layout.w_personalize_item_text
|
||||
class TextHeaderWidget(parent: ViewGroup, data: TextItem) : DescriptionWidget(parent, data) {
|
||||
override fun getLayoutId(): Int = R.layout.w_personalize_item_header
|
||||
|
||||
private val tvName = view.findViewById<TextView>(R.id.tv_name)
|
||||
|
||||
|
|
@ -29,6 +29,7 @@ enum class CardId : ResponseId {
|
|||
paymentFlowVersion,
|
||||
userCounter,
|
||||
userProtectedCounter,
|
||||
empty
|
||||
}
|
||||
|
||||
enum class CardDataId : ResponseId {
|
||||
|
|
@ -41,4 +42,15 @@ enum class CardDataId : ResponseId {
|
|||
tokenSymbol,
|
||||
tokenContractAddress,
|
||||
tokenDecimal,
|
||||
}
|
||||
|
||||
enum class SignId : ResponseId {
|
||||
cid,
|
||||
walletSignedHashes,
|
||||
walletRemainingSignatures,
|
||||
signature,
|
||||
}
|
||||
|
||||
enum class DepersonalizeId: ResponseId {
|
||||
isSuccess
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.tangemtest.ucase.variants.responses.converter
|
||||
|
||||
import com.tangem.tangemtest._arch.structure.Id
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.*
|
||||
import com.tangem.tangemtest.ucase.domain.responses.ResponseFieldConverter
|
||||
import com.tangem.tangemtest.ucase.variants.responses.item.TextHeaderItem
|
||||
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
abstract class BaseResponseConverter<M> : ModelToItems<M> {
|
||||
protected val fieldConverter = ResponseFieldConverter()
|
||||
|
||||
protected open fun createGroup(id: Id, colorId: Int? = null, addHeaderItem: Boolean = true): ItemGroup {
|
||||
val group = if (colorId == null) SimpleItemGroup(id)
|
||||
else SimpleItemGroup(id, BaseItemViewModel(viewState = ViewState(bgColor = colorId)))
|
||||
|
||||
if (addHeaderItem) group.addItem(TextHeaderItem(id, ""))
|
||||
return group
|
||||
}
|
||||
|
||||
protected open fun valueToString(value: Any?): String? {
|
||||
if (value == null) return null
|
||||
return stringOf(value)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +1,27 @@
|
|||
package com.tangem.tangemtest.ucase.variants.responses.converter
|
||||
|
||||
import com.tangem.commands.Card
|
||||
import com.tangem.commands.CardData
|
||||
import com.tangem.commands.Settings
|
||||
import com.tangem.commands.SettingsMask
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.commands.*
|
||||
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.*
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.Item
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.ItemGroup
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.iterate
|
||||
import com.tangem.tangemtest._arch.structure.impl.BoolItem
|
||||
import com.tangem.tangemtest._arch.structure.impl.TextItem
|
||||
import com.tangem.tangemtest.ucase.variants.personalize.BlockId
|
||||
import com.tangem.tangemtest.ucase.variants.responses.CardDataId
|
||||
import com.tangem.tangemtest.ucase.variants.responses.CardId
|
||||
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
||||
import com.tangem.tangemtest.ucase.variants.responses.item.TextHeaderItem
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class CardConverter : ModelToItems<Card> {
|
||||
class CardConverter : BaseResponseConverter<Card>() {
|
||||
|
||||
override fun convert(from: Card): List<Item> {
|
||||
val itemList = mutableListOf<Item>()
|
||||
// val holder = GsonInitializer()
|
||||
// itemList.add(TextItem(Additional.JSON_INCOMING, holder.gson.toJson(from)))
|
||||
|
||||
itemList.add(simpleFields(from))
|
||||
itemList.add(cardData(from.cardData))
|
||||
itemList.add(settingsMask(from.settingsMask))
|
||||
commonGroup(itemList, from)
|
||||
cardDataGroup(itemList, from.cardData)
|
||||
settingsMaskGroup(itemList, from.settingsMask)
|
||||
hideEmptyNullFields(itemList)
|
||||
|
||||
return itemList
|
||||
|
|
@ -35,71 +29,66 @@ class CardConverter : ModelToItems<Card> {
|
|||
|
||||
private fun hideEmptyNullFields(itemList: MutableList<Item>) {
|
||||
itemList.iterate {
|
||||
val data = it.getData<Any?>()
|
||||
val isHidden = if (data == null) true
|
||||
else when (data) {
|
||||
is String -> data.isEmpty()
|
||||
else -> false
|
||||
}
|
||||
if (it is ItemGroup) return@iterate
|
||||
|
||||
if (isHidden) it.viewModel.viewState.isVisibleState.value = false
|
||||
if (it.getData<Any?>() == null) it.viewModel.viewState.isVisibleState.value = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun simpleFields(from: Card): Item {
|
||||
val group = createGroup(BlockId.Common)
|
||||
private fun commonGroup(itemList: MutableList<Item>, from: Card) {
|
||||
val group = createGroup(CardId.empty, addHeaderItem = false)
|
||||
itemList.add(group)
|
||||
|
||||
group.addItem(TextItem(CardId.cardId, from.cardId))
|
||||
group.addItem(TextItem(CardId.manufacturerName, from.manufacturerName))
|
||||
group.addItem(TextItem(CardId.status, stringOf(from.status)))
|
||||
group.addItem(TextItem(CardId.status, valueToString(from.status)))
|
||||
group.addItem(TextItem(CardId.firmwareVersion, from.firmwareVersion))
|
||||
group.addItem(TextItem(CardId.cardPublicKey, from.cardPublicKey?.toHexString()))
|
||||
group.addItem(TextItem(CardId.issuerPublicKey, from.issuerPublicKey?.toHexString()))
|
||||
group.addItem(TextItem(CardId.curve, stringOf(from.curve)))
|
||||
group.addItem(TextItem(CardId.maxSignatures, stringOf(from.maxSignatures)))
|
||||
group.addItem(TextItem(CardId.signingMethod, stringOf(from.signingMethods?.rawValue)))
|
||||
group.addItem(TextItem(CardId.pauseBeforePin2, stringOf(from.pauseBeforePin2)))
|
||||
group.addItem(TextItem(CardId.walletPublicKey, stringOf(from.walletPublicKey)))
|
||||
group.addItem(TextItem(CardId.walletRemainingSignatures, stringOf(from.walletRemainingSignatures)))
|
||||
group.addItem(TextItem(CardId.walletSignedHashes, stringOf(from.walletSignedHashes)))
|
||||
group.addItem(TextItem(CardId.health, stringOf(from.health)))
|
||||
group.addItem(TextItem(CardId.isActivated, stringOf(from.isActivated)))
|
||||
group.addItem(TextItem(CardId.activationSeed, stringOf(from.activationSeed)))
|
||||
group.addItem(TextItem(CardId.paymentFlowVersion, stringOf(from.paymentFlowVersion)))
|
||||
group.addItem(TextItem(CardId.userCounter, stringOf(from.userCounter)))
|
||||
// block.addItem(TextItem(CardId.UserProtectedCounter, stringOf(from.userProtectedCounter)))
|
||||
return group
|
||||
group.addItem(TextItem(CardId.cardPublicKey, fieldConverter.byteArray(from.cardPublicKey)))
|
||||
group.addItem(TextItem(CardId.issuerPublicKey, fieldConverter.byteArray(from.issuerPublicKey)))
|
||||
group.addItem(TextItem(CardId.curve, valueToString(from.curve)))
|
||||
group.addItem(TextItem(CardId.maxSignatures, valueToString(from.maxSignatures)))
|
||||
group.addItem(TextItem(CardId.pauseBeforePin2, valueToString(from.pauseBeforePin2)))
|
||||
group.addItem(TextItem(CardId.walletPublicKey, fieldConverter.byteArray(from.walletPublicKey)))
|
||||
group.addItem(TextItem(CardId.walletRemainingSignatures, valueToString(from.walletRemainingSignatures)))
|
||||
group.addItem(TextItem(CardId.walletSignedHashes, valueToString(from.walletSignedHashes)))
|
||||
group.addItem(TextItem(CardId.health, valueToString(from.health)))
|
||||
group.addItem(TextItem(CardId.isActivated, valueToString(from.isActivated)))
|
||||
group.addItem(TextItem(CardId.activationSeed, valueToString(from.activationSeed)))
|
||||
group.addItem(TextItem(CardId.paymentFlowVersion, valueToString(from.paymentFlowVersion)))
|
||||
group.addItem(TextItem(CardId.userCounter, valueToString(from.userCounter)))
|
||||
|
||||
val signingMethodMask = from.signingMethods ?: return
|
||||
|
||||
group.addItem(TextHeaderItem(CardId.signingMethod, ""))
|
||||
SigningMethod.values().forEach { group.addItem(BoolItem(StringId(it.name), signingMethodMask.contains(it))) }
|
||||
}
|
||||
|
||||
private fun cardData(from: CardData?): Item {
|
||||
val group = createGroup(BlockId.Common, R.color.group_card_data)
|
||||
val data = from ?: return group
|
||||
private fun cardDataGroup(itemList: MutableList<Item>, cardData: CardData?) {
|
||||
val data = cardData ?: return
|
||||
|
||||
// group.addItem(TextItem(StringResId(R.string.response_card_card_data)))
|
||||
val group = createGroup(CardId.cardData, R.color.group_card_data)
|
||||
itemList.add(group)
|
||||
group.addItem(TextItem(CardDataId.batchId, data.batchId))
|
||||
// Format: Year (2 bytes) | Month (1 byte) | Day (1 byte)
|
||||
group.addItem(TextItem(CardDataId.manufactureDateTime, stringOf(data.manufactureDateTime)))
|
||||
group.addItem(TextItem(CardDataId.manufactureDateTime, valueToString(data.manufactureDateTime)))
|
||||
group.addItem(TextItem(CardDataId.issuerName, data.issuerName))
|
||||
group.addItem(TextItem(CardDataId.blockchainName, data.blockchainName))
|
||||
group.addItem(TextItem(CardDataId.manufacturerSignature, data.manufacturerSignature?.toHexString()))
|
||||
group.addItem(TextItem(CardDataId.productMask, stringOf(data.productMask?.rawValue)))
|
||||
group.addItem(TextItem(CardDataId.manufacturerSignature, fieldConverter.byteArray(data.manufacturerSignature)))
|
||||
group.addItem(TextItem(CardDataId.tokenSymbol, data.tokenSymbol))
|
||||
group.addItem(TextItem(CardDataId.tokenContractAddress, data.tokenContractAddress))
|
||||
group.addItem(TextItem(CardDataId.tokenDecimal, data.tokenSymbol))
|
||||
|
||||
return group
|
||||
val productMask = data.productMask ?: return
|
||||
|
||||
group.addItem(TextHeaderItem(CardDataId.productMask, ""))
|
||||
Product.values().forEach { group.addItem(BoolItem(StringId(it.name), productMask.contains(it))) }
|
||||
}
|
||||
|
||||
private fun settingsMask(from: SettingsMask?): Item {
|
||||
val group = createGroup(CardId.settingsMask, R.color.group_signing_method)
|
||||
val data = from ?: return group
|
||||
private fun settingsMaskGroup(itemList: MutableList<Item>, from: SettingsMask?) {
|
||||
val data = from ?: return
|
||||
|
||||
val group = createGroup(CardId.settingsMask, R.color.group_settings_mask)
|
||||
itemList.add(group)
|
||||
|
||||
// group.addItem(TextItem(StringResId(R.string.response_card_settings_mask)))
|
||||
Settings.values().forEach { group.addItem(BoolItem(StringId(it.name), data.contains(it))) }
|
||||
return group
|
||||
}
|
||||
|
||||
private fun createGroup(id: Id, colorId: Int? = null): ItemGroup {
|
||||
return if (colorId == null) SimpleItemGroup(id)
|
||||
else SimpleItemGroup(id, BaseItemViewModel(viewState = ViewState(bgColor = colorId)))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +1,30 @@
|
|||
package com.tangem.tangemtest.ucase.variants.responses.converter
|
||||
|
||||
import com.tangem.commands.Card
|
||||
import com.tangem.commands.SignResponse
|
||||
import com.tangem.commands.personalization.DepersonalizeResponse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tangemtest._arch.structure.StringId
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.Item
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.ModelToItems
|
||||
import com.tangem.tangemtest._arch.structure.impl.TextItem
|
||||
import com.tangem.tangemtest.ucase.variants.responses.DepersonalizeId
|
||||
import com.tangem.tangemtest.ucase.variants.responses.SignId
|
||||
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class ReadEventConverter : ModelToItems<CompletionResult.Success<Card>> {
|
||||
override fun convert(from: CompletionResult.Success<Card>): List<Item> = CardConverter().convert(from.data)
|
||||
}
|
||||
|
||||
class SignResponseConverter : ModelToItems<SignResponse> {
|
||||
class SignResponseConverter : BaseResponseConverter<SignResponse>() {
|
||||
|
||||
override fun convert(from: SignResponse): List<Item> {
|
||||
return listOf(
|
||||
TextItem(StringId("CID"), from.cardId),
|
||||
TextItem(StringId("Wallet signed hashes"), stringOf(from.walletSignedHashes)),
|
||||
TextItem(StringId("Wallet remaining signatures"), stringOf(from.walletRemainingSignatures)),
|
||||
TextItem(StringId("Signature"), stringOf(from.signature))
|
||||
TextItem(SignId.cid, from.cardId),
|
||||
TextItem(SignId.walletSignedHashes, valueToString(from.walletSignedHashes)),
|
||||
TextItem(SignId.walletRemainingSignatures, valueToString(from.walletRemainingSignatures)),
|
||||
TextItem(SignId.signature, fieldConverter.byteArray(from.signature))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class DepersonalizeResponseConverter : ModelToItems<DepersonalizeResponse> {
|
||||
class DepersonalizeResponseConverter : BaseResponseConverter<DepersonalizeResponse>() {
|
||||
override fun convert(from: DepersonalizeResponse): List<Item> {
|
||||
return listOf(TextItem(StringId("Is success"), stringOf(from.success)))
|
||||
return listOf(TextItem(DepersonalizeId.isSuccess, stringOf(from.success)))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tangemtest.ucase.variants.responses.item
|
||||
|
||||
import com.tangem.tangemtest._arch.structure.Id
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.BaseItemViewModel
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.ItemViewModel
|
||||
import com.tangem.tangemtest._arch.structure.abstraction.ViewState
|
||||
import com.tangem.tangemtest._arch.structure.impl.TypedItem
|
||||
|
||||
open class TextHeaderItem(id: Id, viewModel: ItemViewModel) : TypedItem<String>(id, viewModel) {
|
||||
constructor(id: Id, value: String? = null, viewState: ViewState = ViewState())
|
||||
: this(id, BaseItemViewModel(value, viewState))
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ package com.tangem.tangemtest.ucase.variants.responses.ui
|
|||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
|
|
@ -23,24 +25,25 @@ open class ResponseFragment : BaseFragment() {
|
|||
private val mainActivityVM: MainViewModel by activityViewModels()
|
||||
private val selfVM: ResponseViewModel by viewModels()
|
||||
|
||||
private val itemContainer: ViewGroup by lazy { mainView.findViewById<LinearLayout>(R.id.ll_container) }
|
||||
private val itemContainer: ViewGroup by lazy { mainView.findViewById<LinearLayout>(R.id.ll_content_container) }
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.fg_card_response
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setHasOptionsMenu(true)
|
||||
setTittle()
|
||||
}
|
||||
|
||||
private fun setTittle() {
|
||||
val titleId = selfVM.determineTitleId(mainActivityVM.commandResponse)
|
||||
val titleId = getTittleId(arguments) ?: selfVM.determineTitleId(mainActivityVM.commandResponse)
|
||||
activity?.setTitle(titleId)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setHasOptionsMenu(true)
|
||||
buildWidgets()
|
||||
listenDescriptionSwitchChanges()
|
||||
}
|
||||
|
|
@ -58,10 +61,8 @@ open class ResponseFragment : BaseFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.menu_fg_response, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
|
||||
val menuItem = menu.findItem(R.id.action_share)
|
||||
menuItem.isVisible = true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
|
@ -72,4 +73,12 @@ open class ResponseFragment : BaseFragment() {
|
|||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val argTittle = "tittle"
|
||||
|
||||
fun setTittle(@StringRes id: Int): Bundle = bundleOf(Pair(argTittle, id))
|
||||
|
||||
private fun getTittleId(args: Bundle?): Int? = args?.getInt(argTittle)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.tangemtest._arch.structure.impl.BoolItem
|
|||
import com.tangem.tangemtest._arch.structure.impl.TextItem
|
||||
import com.tangem.tangemtest._arch.widget.ItemWidgetBuilder
|
||||
import com.tangem.tangemtest._arch.widget.abstraction.ViewWidget
|
||||
import com.tangem.tangemtest.ucase.variants.responses.item.TextHeaderItem
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -13,6 +14,7 @@ import com.tangem.tangemtest._arch.widget.abstraction.ViewWidget
|
|||
class ResponseItemBuilder : ItemWidgetBuilder {
|
||||
override fun build(item: BaseItem, parent: ViewGroup): ViewWidget? {
|
||||
return when (item) {
|
||||
is TextHeaderItem -> ResponseHeaderWidget(parent, item)
|
||||
is TextItem -> ResponseTextWidget(parent, item)
|
||||
is BoolItem -> CheckBoxWidget(parent, item)
|
||||
else -> null
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.view.ViewGroup
|
|||
import android.widget.TextView
|
||||
import com.tangem.tangemtest.R
|
||||
import com.tangem.tangemtest._arch.structure.impl.TextItem
|
||||
import com.tangem.tangemtest.ucase.variants.responses.item.TextHeaderItem
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -27,4 +28,18 @@ class ResponseTextWidget(
|
|||
tvName.text = getName()
|
||||
tvValue.text = data
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseHeaderWidget(
|
||||
parent: ViewGroup,
|
||||
private val typedItem: TextHeaderItem
|
||||
) : ResponseWidget(parent, typedItem) {
|
||||
override fun getLayoutId(): Int = R.layout.w_response_item_header
|
||||
|
||||
private val tvName: TextView = view.findViewById(R.id.tv_name)
|
||||
|
||||
init {
|
||||
tvName.text = getName()
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
abstract class ResponseWidget(parent: ViewGroup, item: Item): DescriptionWidget(parent, item) {
|
||||
abstract class ResponseWidget(parent: ViewGroup, item: Item) : DescriptionWidget(parent, item) {
|
||||
|
||||
init {
|
||||
view.setOnClickListener {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
package com.tangem.tangemtest.ucase.variants.scan.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import com.tangem.commands.Card
|
||||
import com.tangem.tangemtest.R
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.managers.ScanItemsManager
|
||||
import com.tangem.tangemtest.ucase.ui.BaseCardActionFragment
|
||||
import com.tangem.tangemtest.ucase.variants.responses.ui.ResponseFragment
|
||||
import ru.dev.gbixahue.eu4d.lib.android._android.views.dpToPx
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -13,14 +21,36 @@ class ScanActionFragment : BaseCardActionFragment() {
|
|||
|
||||
override val itemsManager: ItemsManager by lazy { ScanItemsManager() }
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.fg_action_card_scan
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
override fun initFab() {
|
||||
val howToUseView = createHowToUse()
|
||||
contentContainer.layoutParams = FrameLayout.LayoutParams(-1, -1, Gravity.CENTER)
|
||||
contentContainer.addView(howToUseView)
|
||||
}
|
||||
|
||||
private fun createHowToUse(): View {
|
||||
val fl = FrameLayout(requireContext())
|
||||
fl.layoutParams = FrameLayout.LayoutParams(-1, -1, Gravity.CENTER)
|
||||
val tv = TextView(requireContext()).apply {
|
||||
val padding = dpToPx(16f).toInt()
|
||||
setPadding(padding, 0, padding, 0)
|
||||
gravity = Gravity.CENTER
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f)
|
||||
setText(R.string.htu_scan_action)
|
||||
}
|
||||
fl.addView(tv)
|
||||
return fl
|
||||
}
|
||||
|
||||
override fun initViews() {
|
||||
swrLayout.isEnabled = false
|
||||
actionFab.setOnClickListener { actionVM.invokeMainAction() }
|
||||
}
|
||||
|
||||
override fun responseCardDataHandled(card: Card?) {
|
||||
super.responseCardDataHandled(card)
|
||||
navigateTo(R.id.action_nav_card_action_to_response_screen)
|
||||
override fun handleResponseCardData(card: Card) {
|
||||
super.handleResponseCardData(card)
|
||||
val bundle = ResponseFragment.setTittle(R.string.fg_name_response_scan)
|
||||
navigateTo(R.id.action_nav_card_action_to_response_screen, bundle, null)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tangemtest.ucase.variants.sign.ui
|
||||
|
||||
import com.tangem.tangemtest.R
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager
|
||||
import com.tangem.tangemtest.ucase.domain.paramsManager.managers.SignItemsManager
|
||||
import com.tangem.tangemtest.ucase.ui.BaseCardActionFragment
|
||||
|
|
@ -11,6 +10,4 @@ import com.tangem.tangemtest.ucase.ui.BaseCardActionFragment
|
|||
class SignActionFragment : BaseCardActionFragment() {
|
||||
|
||||
override val itemsManager: ItemsManager by lazy { SignItemsManager() }
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.fg_action_card_sign
|
||||
}
|
||||
|
|
@ -10,7 +10,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" />
|
||||
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
|
||||
app:popupTheme="@style/ThemeOverlay.MaterialComponents.Light"/>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_host_fragment"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/def_indent"
|
||||
android:paddingBottom="@dimen/def_half_indent">
|
||||
|
||||
<include
|
||||
layout="@layout/m_divider_h"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="@dimen/def_indent"
|
||||
android:layout_marginEnd="@dimen/def_indent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/til_item"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
app:boxBackgroundColor="@android:color/transparent"
|
||||
android:hint="Enter a preset name"
|
||||
tools:hint="Field name">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Some text field" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/coordinator_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/w_action_response_json" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_screen_stub"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="@dimen/def_double_indent"
|
||||
android:text="@string/empty_screen_stub" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_action"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="@dimen/def_indent"
|
||||
android:layout_marginBottom="@dimen/def_double_indent"
|
||||
android:src="@drawable/ic_nfc" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/coordinator_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/w_action_response_json" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_action"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="@dimen/def_indent"
|
||||
android:layout_marginBottom="@dimen/def_double_indent"
|
||||
android:src="@drawable/ic_nfc" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -5,29 +5,17 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
<include layout="@layout/v_content_container" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_action"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="@dimen/def_indent"
|
||||
android:layout_marginBottom="@dimen/def_double_indent"
|
||||
android:src="@drawable/ic_nfc"
|
||||
app:layout_anchor="@id/scroll_view"
|
||||
app:layout_anchor="@id/swr_layout"
|
||||
app:layout_anchorGravity="bottom|end" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_container"
|
||||
android:id="@+id/ll_content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/coordinator_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/w_action_response_json" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_action"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="@dimen/def_indent"
|
||||
android:layout_marginBottom="@dimen/def_double_indent"
|
||||
android:src="@drawable/ic_nfc" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
20
tangem-demo/src/main/res/layout/v_content_container.xml
Normal file
20
tangem-demo/src/main/res/layout/v_content_container.xml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/swr_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
26
tangem-demo/src/main/res/layout/v_item_list_container.xml
Normal file
26
tangem-demo/src/main/res/layout/v_item_list_container.xml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/root_items"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/item_header_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/item_list_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/item_footer_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_delete"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:hint="Field name" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_delete"
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@android:drawable/ic_menu_delete" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/delimiter"
|
||||
android:background="@color/field_header_background"
|
||||
android:minHeight="@dimen/iw_layout_frame_header_min_height"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp">
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/w_personalize_item_text" />
|
||||
<include layout="@layout/w_personalize_item_header" />
|
||||
|
||||
<include layout="@layout/w_personalize_item_edit_text" />
|
||||
|
||||
|
|
|
|||
35
tangem-demo/src/main/res/layout/w_response_item_header.xml
Normal file
35
tangem-demo/src/main/res/layout/w_response_item_header.xml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/field_header_background">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/def_indent"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/field_content"
|
||||
android:textSize="16sp"
|
||||
tools:text="Custom blockchain" />
|
||||
|
||||
<include layout="@layout/w_field_description" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
layout="@layout/m_divider_h"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="bottom" />
|
||||
|
||||
</FrameLayout>
|
||||
11
tangem-demo/src/main/res/menu/menu_activity_main.xml
Normal file
11
tangem-demo/src/main/res/menu/menu_activity_main.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_toggle_description_visibility"
|
||||
android:checkable="true"
|
||||
android:title="@string/menu_main_description"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
18
tangem-demo/src/main/res/menu/menu_fg_peronalization.xml
Normal file
18
tangem-demo/src/main/res/menu/menu_fg_peronalization.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<group android:id="@+id/menu_group_personalization_preset">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_reset"
|
||||
android:title="@string/menu_personalization_preset_reset" />
|
||||
<item
|
||||
android:id="@+id/action_save"
|
||||
android:title="@string/menu_personalization_preset_save" />
|
||||
<item
|
||||
android:id="@+id/action_load"
|
||||
android:title="@string/menu_personalization_preset_load" />
|
||||
|
||||
</group>
|
||||
|
||||
</menu>
|
||||
|
|
@ -5,14 +5,7 @@
|
|||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:icon="@drawable/ic_share_white_18dp"
|
||||
android:title="Share"
|
||||
android:visible="false"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_favorite"
|
||||
android:title=""
|
||||
app:actionLayout="@layout/menu_item_switch"
|
||||
app:showAsAction="always" />
|
||||
android:title="@string/menu_response_share"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
</menu>
|
||||
|
|
@ -6,7 +6,13 @@
|
|||
|
||||
<action
|
||||
android:id="@+id/action_nav_card_action_to_response_screen"
|
||||
app:destination="@+id/nav_card_response" />
|
||||
app:destination="@+id/nav_card_response"
|
||||
app:enterAnim="@anim/slide_in_right"
|
||||
app:exitAnim="@anim/slide_out_left"
|
||||
app:popEnterAnim="@anim/slide_in_left"
|
||||
app:popExitAnim="@anim/slide_out_right"
|
||||
app:popUpTo="@id/nav_entry_point"
|
||||
app:popUpToInclusive="false" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_entry_point"
|
||||
|
|
@ -57,25 +63,25 @@
|
|||
android:id="@+id/nav_scan"
|
||||
android:name="com.tangem.tangemtest.ucase.variants.scan.ui.ScanActionFragment"
|
||||
android:label="@string/action_card_scan"
|
||||
tools:layout="@layout/fg_action_card_scan" />
|
||||
tools:layout="@layout/fg_base_action_layout" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_sign"
|
||||
android:name="com.tangem.tangemtest.ucase.variants.sign.ui.SignActionFragment"
|
||||
android:label="@string/action_card_sign"
|
||||
tools:layout="@layout/fg_action_card_sign" />
|
||||
tools:layout="@layout/fg_base_action_layout" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_personalize"
|
||||
android:name="com.tangem.tangemtest.ucase.variants.personalize.ui.PersonalizationFragment"
|
||||
android:label="@string/action_personalize"
|
||||
tools:layout="@layout/fg_personalization" />
|
||||
tools:layout="@layout/fg_base_action_layout" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_depersonalize"
|
||||
android:name="com.tangem.tangemtest.ucase.variants.depersonalize.ui.DepersonalizeActionFragment"
|
||||
android:label="@string/action_depersonalize"
|
||||
tools:layout="@layout/fg_depersonalize" />
|
||||
tools:layout="@layout/fg_base_action_layout" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_issuer_read_data"
|
||||
|
|
|
|||
|
|
@ -9,12 +9,13 @@
|
|||
|
||||
<color name="action_name">#2B2B2B</color>
|
||||
|
||||
<color name="field_header_background">#C3C3C3</color>
|
||||
<color name="field_info">#888888</color>
|
||||
<color name="field_content">#303030</color>
|
||||
<color name="field_description">@color/field_info</color>
|
||||
|
||||
<color name="group_card_data">#D7E4F3</color>
|
||||
<color name="group_signing_method">#D7F3E6</color>
|
||||
<color name="group_settings_mask">#D7F3E6</color>
|
||||
|
||||
|
||||
<color name="switchTrack">#C6C6C6</color>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,25 @@
|
|||
<resources>
|
||||
<string name="app_name">Tangem Development Kit</string>
|
||||
|
||||
<string name="menu_main_description">Description</string>
|
||||
|
||||
<string name="copy_to_clipboard">Copy to clipboard</string>
|
||||
<string name="btn_delete">Delete</string>
|
||||
<string name="btn_ok">OK</string>
|
||||
<string name="btn_cancel">Cancel</string>
|
||||
<string name="btn_save">Save</string>
|
||||
<string name="btn_load">Load</string>
|
||||
|
||||
<string name="unknown">unknown</string>
|
||||
<string name="error_nothing_to_load">Nothing to load</string>
|
||||
|
||||
<string name="fg_name_entry_point">@string/app_name</string>
|
||||
<string name="fg_name_response_scan">Scan response</string>
|
||||
<string name="fg_name_response_scan">Read response</string>
|
||||
<string name="fg_name_response_sign">Sign response</string>
|
||||
<string name="fg_name_response_personalization">Personalization response</string>
|
||||
<string name="fg_name_response_depersonalization">Depersonalization response</string>
|
||||
|
||||
<string name="unknown">unknown</string>
|
||||
<string name="copy_to_clipboard">Copy to clipboard</string>
|
||||
|
||||
<string name="switch_description">Docs</string>
|
||||
|
||||
<string name="card_error_not_personalized">Your card hasn\'t been personalized yet. You need to run personalize command first.</string>
|
||||
|
|
@ -18,7 +29,7 @@
|
|||
<string name="stub">Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit</string>
|
||||
<!-- <string name="stub">Sed ut perspiciatis unde omnis iste natus</string>-->
|
||||
|
||||
<string name="show_rare_fields">Show rarely used fields</string>
|
||||
<string name="hide_rare_fields">Hide</string>
|
||||
<string name="show_rare_fields">Show all fields</string>
|
||||
<string name="hide_rare_fields">Hide fields</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="menu_personalization_preset_reset">Reset to default</string>
|
||||
<string name="menu_personalization_preset_save">Save configuration</string>
|
||||
<string name="menu_personalization_preset_load">Load configuration</string>
|
||||
|
||||
<string name="personalize">Personalize</string>
|
||||
<string name="depersonalize">Depersonalize</string>
|
||||
<string name="pers_block_card_number">Card number</string>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="menu_response_share">Share</string>
|
||||
|
||||
<!-- Field names - Response: Card -->
|
||||
<string name="response_card_cid">CID</string>
|
||||
|
|
@ -56,7 +57,7 @@
|
|||
<string name="info_response_card_status">Current status of the card</string>
|
||||
<string name="info_response_card_firmware_version">Version of Tangem COS</string>
|
||||
<string name="info_response_card_public_key">Public key that is used to authenticate the card against manufacturer’s database. It is generated one time during card manufacturing. See Security section for more details.</string>
|
||||
<string name="info_response_card_settings_mask">Card settings defined by personalization (bit mask: 0 – Enabled, 1 – Disabled):</string>
|
||||
<string name="info_response_card_settings_mask">Card settings defined by personalization.</string>
|
||||
<string name="info_response_card_is_reusable">Defines what happens when user calls PURGE_WALLET command:
|
||||
\n0 - Card will switch to Purged state
|
||||
\n1 - Card will switch to Empty state and let create a new wallet again</string>
|
||||
|
|
@ -71,29 +72,29 @@
|
|||
<string name="info_response_card_one_apdu_at_time">Card will execute only one command during one communication session, thus requiring user to physically take the card away from the host after each action (all commands except for READ_CARD).</string>
|
||||
<string name="info_response_card_use_ndef">Whether the card should emulate NDEF. In default configuration, two NDEF records are loaded during personalization: (1) Tangem web site address, (2) name of Android App package in Google Play Store.</string>
|
||||
<string name="info_response_card_use_dynamic_ndef">0 – Disable dynamic generation of NDEF for iOS. See Dynamic NDEF section for more details.
|
||||
/n1 – Enable dynamic NDEF for iOS.</string>
|
||||
\n1 – Enable dynamic NDEF for iOS.</string>
|
||||
<string name="info_response_card_smart_security_delay">Security delay Pause_Before_PIN2 will not be applied if PIN2 is not default.</string>
|
||||
<string name="info_response_card_allow_unencrypted">Whether the card supports unencrypted NFC communication. See NFC communication section for more details.</string>
|
||||
<string name="info_response_card_allow_fast_encryption">Whether the card supports fast encrypted NFC communication. See NFC communication section for more details.</string>
|
||||
<string name="info_response_card_protect_issuer_data_against_replay">0 – No replay protection on write issuer data
|
||||
/n1 – Enable replay protection on write issuer data (card will require additional Issuer_Data_Counter incremented on each write)</string>
|
||||
\n1 – Enable replay protection on write issuer data (card will require additional Issuer_Data_Counter incremented on each write)</string>
|
||||
<string name="info_response_card_allow_select_blockchain">0 – Wallet elliptic curve and blockchain information stored during PERSONALIZE command and never change
|
||||
/n1 – Wallet elliptic curve and blockchain information can be changed on CREATE_WALLET command</string>
|
||||
\n1 – Wallet elliptic curve and blockchain information can be changed on CREATE_WALLET command</string>
|
||||
<string name="info_response_card_disable_precomputed_ndef">0 – Enable precomputed dynamic NDEF to work around iPhone 7+ NFC bug.
|
||||
/n1 – Disable precomputed dynamic NDEF. See Dynamic NDEF section for more details.</string>
|
||||
\n1 – Disable precomputed dynamic NDEF. See Dynamic NDEF section for more details.</string>
|
||||
<string name="info_response_card_security_delay_if_validated">0 – Enforce security delay in SIGN command if the issuer validates the transaction (for signing methods 2, 3, 4 and 5).
|
||||
/n1 – Skip security delay in SIGN command if the issuer validates the transaction (for signing methods 2, 3, 4 and 5).</string>
|
||||
\n1 – Skip security delay in SIGN command if the issuer validates the transaction (for signing methods 2, 3, 4 and 5).</string>
|
||||
<string name="info_response_card_skip_pin2_cvc_if_validated_by_issuer">0 – Require and check PIN2 and CVC in SIGN command if the issuer validates the transaction (for signing method 2, 3, 4 and 5).
|
||||
/n1 – Skip checking PIN2 and CVC in SIGN command if the issuer validates the transaction (for signing method 2, 3, 4 and 5).</string>
|
||||
\n1 – Skip checking PIN2 and CVC in SIGN command if the issuer validates the transaction (for signing method 2, 3, 4 and 5).</string>
|
||||
<string name="info_response_card_skip_security_delay_if_validated_by_linked_terminal">1 - Store Terminal_PublicKey public key of linked terminal no each SIGN command, skip security delay if valid signature of transaction is made with Terminal_PrivateKey is provided in SIGN command</string>
|
||||
<string name="info_response_card_restrict_overwrite_issuer_ex_data"></string>
|
||||
<string name="info_info_response_card_prohibit_overwriting_issuer_ex_data"></string>
|
||||
<string name="info_response_card_require_terminal_tx_sig">0 – Skip checking terminal’s signature when signing POS transaction
|
||||
/n1 – Check terminal’s signature when signing POS transaction</string>
|
||||
\n1 – Check terminal’s signature when signing POS transaction</string>
|
||||
<string name="info_response_card_require_terminal_cert_sig">0 – Skip checking acquirer’s signature of terminal certificate when signing POS transaction
|
||||
/n1 – Check acquirer’s signature of terminal certificate when signing POS transaction</string>
|
||||
\n1 – Check acquirer’s signature of terminal certificate when signing POS transaction</string>
|
||||
<string name="info_response_card_check_pin3">0 – Additionally encrypt POS transaction signature with key derived from PIN3 when the transaction amount exceeds PIN3 floor limit
|
||||
/n1 – Require terminal to send PIN3 to card when the POS transaction amount exceeds PIN3_Floor_Limit</string>
|
||||
\n1 – Require terminal to send PIN3 to card when the POS transaction amount exceeds PIN3_Floor_Limit</string>
|
||||
<string name="info_response_card_card_data">Detailed information about card contents. Format is defined by the card issuer. Cards complaint with Tangem Wallet application should have TLV format described in Personalization section.</string>
|
||||
<string name="info_response_card_issuer_data_public_key">Public key that is used by the card issuer to sign Issuer_Data field. See Security section for more details.</string>
|
||||
<string name="info_response_card_curve">Explicit text name of the elliptic curve used for all wallet key operations.</string>
|
||||
|
|
@ -105,12 +106,12 @@
|
|||
<string name="info_response_card_wallet_signed_hashes">Total number of signed single hashes returned by the card in SIGN command responses since card personalization. Sums up array elements within all SIGN commands.</string>
|
||||
<string name="info_response_card_health">Any non-zero value indicates that the card experiences some hardware problems. User should withdraw the value to other blockchain wallet as soon as possible. Non-zero Health tag will also appear in responses of all other commands.</string>
|
||||
<string name="info_response_card_is_activated">Whether the card requires issuer’s confirmation of activation.
|
||||
/n0 – card will require issuer’s confirmation of activation,
|
||||
/notherwise this field will not be returned (card is activated and operational).</string>
|
||||
\n0 – card will require issuer’s confirmation of activation,
|
||||
\notherwise this field will not be returned (card is activated and operational).</string>
|
||||
<string name="info_response_card_activation_seed">A random challenge generated by PERSONALIZE command that should be signed and returned to COS by the issuer to confirm the card has been activated. See ACTIVATE_CARD command for more details.
|
||||
/nThis field will not be returned if the card is activated.</string>
|
||||
\nThis field will not be returned if the card is activated.</string>
|
||||
<string name="info_response_card_payment_flow_version">Version of POS payment scheme supported by COS ([0x02,0x01] for version 2.30)
|
||||
/nReturned only if SigningMethod ‘6’ enabling POS transactions is supported by card.</string>
|
||||
\nReturned only if SigningMethod ‘6’ enabling POS transactions is supported by card.</string>
|
||||
<string name="info_response_card_user_counter">This value can be initialized by App and will be increased by COS with the execution of each SIGN command. For example, this field can store blockchain “nonce” for a quick one-touch transaction on POS terminals. Returned only if SigningMethod =6.</string>
|
||||
<string name="info_response_card_user_protected_counter">This value can be initialized by App (with PIN2 confirmation) and will be increased by COS with the execution of each SIGN command. For example, this field can store blockchain “nonce” for a quick one-touch transaction on POS terminals. Returned only if SigningMethod =6.</string>
|
||||
|
||||
|
|
@ -135,4 +136,23 @@
|
|||
<string name="info_response_card_card_data_token_symbol"></string>
|
||||
<string name="info_response_card_card_data_token_contract_address"></string>
|
||||
<string name="info_response_card_card_data_token_decimal"></string>
|
||||
|
||||
|
||||
<!-- Field names - Response: Sign -->
|
||||
<string name="response_sign_cid">CID</string>
|
||||
<string name="response_sign_wallet_signed_hashes">Wallet signed hashes</string>
|
||||
<string name="response_sign_wallet_remaining_signatures">Wallet remaining signatures</string>
|
||||
<string name="response_sign_signature">Signature</string>
|
||||
|
||||
<string name="info_response_sign_cid">@string/info_response_card_cid</string>
|
||||
<string name="info_response_sign_wallet_signed_hashes">Total number of signed single hashes returned by the card in SIGN command responses since card personalization. Sums up array elements within all SIGN commands.</string>
|
||||
<string name="info_response_sign_wallet_remaining_signatures">Remaining number of SIGN operations before the wallet will stop signing transactions.</string>
|
||||
<string name="info_response_sign_signature">Array of resulting signatures that App should embed into a raw transaction according to a transaction format of an appropriate blockchain.</string>
|
||||
|
||||
|
||||
<!-- Field names - Response: Depersonalize -->
|
||||
<string name="response_depersonalize_is_success">Is success</string>
|
||||
|
||||
<string name="info_response_depersonalize_is_success">Is success</string>
|
||||
|
||||
</resources>
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="empty_screen_stub">To read the card, press the button at the right bottom corner of the screen</string>
|
||||
<!-- How to use -->
|
||||
<string name="htu_scan_action">To read the card, press the button at the right bottom corner of the screen</string>
|
||||
|
||||
</resources>
|
||||
73
tangem-demo/src/main/res/values/theme_debug.xml
Normal file
73
tangem-demo/src/main/res/values/theme_debug.xml
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- You can change the parent around to whatever you normally use -->
|
||||
<style name="DebugColors" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
|
||||
<!-- System colors -->
|
||||
<item name="android:windowBackground">@color/__debugWindowBackground</item>
|
||||
|
||||
<item name="android:colorPressedHighlight">#FF4400</item>
|
||||
<item name="android:colorLongPressedHighlight">#FF0044</item>
|
||||
<item name="android:colorFocusedHighlight">#44FF00</item>
|
||||
<item name="android:colorActivatedHighlight">#00FF44</item>
|
||||
<item name="android:colorMultiSelectHighlight">#4400FF</item>
|
||||
|
||||
<item name="android:statusBarColor">#FFF000</item>
|
||||
<item name="android:navigationBarColor">#000FFF</item>
|
||||
|
||||
<item name="android:colorForeground">#440000</item>
|
||||
<item name="android:colorForegroundInverse">#004400</item>
|
||||
<item name="android:colorBackground">#444400</item>
|
||||
<item name="android:colorBackgroundCacheHint">#440044</item>
|
||||
|
||||
//Only for >21
|
||||
<item name="android:textColorPrimary">#FFFF00</item>
|
||||
<item name="android:textColorSecondary">#FF00FF</item>
|
||||
<item name="android:textColorTertiary">#00FFFF</item> <!-- Overrides a TextView textColor-->
|
||||
|
||||
<item name="android:textColorPrimaryInverse">#CCCC00</item>
|
||||
<item name="android:textColorSecondaryInverse">#CC00CC</item>
|
||||
<item name="android:textColorTertiaryInverse">#00CCCC</item>
|
||||
|
||||
<item name="android:textColorPrimaryDisableOnly">#FFCC00</item>
|
||||
<item name="android:textColorPrimaryInverseDisableOnly">#FF00CC</item>
|
||||
|
||||
<item name="android:textColorPrimaryNoDisable">#CCFF00</item>
|
||||
<item name="android:textColorSecondaryNoDisable">#00FFCC</item>
|
||||
|
||||
<item name="android:textColorPrimaryInverseNoDisable">#CC00FF</item>
|
||||
<item name="android:textColorSecondaryInverseNoDisable">#00CCFF</item>
|
||||
|
||||
<item name="android:textColorHint">#FF8800</item>
|
||||
<item name="android:textColorHintInverse">#FF0088</item>
|
||||
|
||||
<item name="android:textColorHighlight">#88FF00</item>
|
||||
<item name="android:textColorHighlightInverse">#00FF88</item>
|
||||
|
||||
<item name="android:textColorLink">#8800FF</item>
|
||||
<item name="android:textColorLinkInverse">#0088FF</item>
|
||||
|
||||
<item name="android:textColorAlertDialogListItem">#444444</item>
|
||||
|
||||
<!-- Color palette (via app-compat) -->
|
||||
<item name="colorPrimary">#FF0000</item>
|
||||
<item name="colorPrimaryDark">#00FF00</item>
|
||||
<item name="colorAccent">#0000FF</item>
|
||||
|
||||
<item name="colorControlNormal">#CC0000</item>
|
||||
<item name="colorControlActivated">#00CC00</item>
|
||||
<item name="colorControlHighlight">#0000CC</item>
|
||||
|
||||
<item name="colorButtonNormal">#880000</item>
|
||||
<item name="colorSwitchThumbNormal">#008800</item>
|
||||
|
||||
<!-- Random other things found in app-compat -->
|
||||
<item name="actionMenuTextColor">#440000</item>
|
||||
<item name="editTextColor">#FF4400</item> <!-- Overrides textColorPrimary-->
|
||||
<item name="textColorSearchUrl">#000044</item>
|
||||
|
||||
</style>
|
||||
|
||||
<!-- Also needed, since windowBackground is a reference, not a color -->
|
||||
<color name="__debugWindowBackground">#888888</color>
|
||||
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue