feat(@desktop/keycards): managing mocked keycards when running keycard flows

This commit is contained in:
Sale Djenic 2023-09-22 12:38:44 +02:00 committed by saledjenic
parent b97e1fc8da
commit d107a9f90b
21 changed files with 723 additions and 17 deletions

View File

@ -263,7 +263,7 @@ $(STATUSQ_CMAKE_CACHE): | deps
-Wno-dev \
$(HANDLE_OUTPUT)
statusq-configure: | $(STATUSQ_CMAKE_CACHE)
statusq-configure: | $(STATUSQ_CMAKE_CACHE)
statusq-build: | statusq-configure
echo -e "\033[92mBuilding:\033[39m StatusQ"
@ -328,7 +328,7 @@ run-statusq-tests: statusq-tests
ifneq ($(detected_OS),Windows)
DOTHERSIDE_CMAKE_CONFIG_PARAMS += -DENABLE_DYNAMIC_LIBS=OFF -DENABLE_STATIC_LIBS=ON
# NIM_PARAMS +=
# NIM_PARAMS +=
else
DOTHERSIDE_LIBFILE := vendor/DOtherSide/build/lib/$(COMMON_CMAKE_BUILD_TYPE)/DOtherSide.dll
DOTHERSIDE_CMAKE_CONFIG_PARAMS += -DENABLE_DYNAMIC_LIBS=ON -DENABLE_STATIC_LIBS=OFF
@ -354,7 +354,7 @@ $(DOTHERSIDE_CMAKE_CACHE): | deps
-Wno-dev \
$(HANDLE_OUTPUT)
dotherside-configure: | $(DOTHERSIDE_CMAKE_CACHE)
dotherside-configure: | $(DOTHERSIDE_CMAKE_CACHE)
dotherside-build: | dotherside-configure
echo -e "\033[92mBuilding:\033[39m DOtherSide"
@ -392,11 +392,16 @@ STATUSKEYCARDGO := vendor/status-keycard-go/build/libkeycard/libkeycard.$(LIBSTA
STATUSKEYCARDGO_LIBDIR := $(shell pwd)/$(shell dirname "$(STATUSKEYCARDGO)")
export STATUSKEYCARDGO_LIBDIR
STATUSKEYCARDGO_RULE := build-lib
ifeq ($(TEST_ENVIRONMENT),true)
STATUSKEYCARDGO_RULE := build-mocked-lib
endif
status-keycard-go: $(STATUSKEYCARDGO)
$(STATUSKEYCARDGO): | deps
echo -e $(BUILD_MSG) "status-keycard-go"
+ cd vendor/status-keycard-go && \
$(MAKE) build-lib $(STATUSKEYCARDGO_MAKE_PARAMS) $(HANDLE_OUTPUT)
$(MAKE) $(STATUSKEYCARDGO_RULE) $(STATUSKEYCARDGO_MAKE_PARAMS) $(HANDLE_OUTPUT)
QRCODEGEN := vendor/QR-Code-generator/c/libqrcodegen.a

View File

@ -1,4 +1,4 @@
import NimQml, os
import NimQml, strutils, os
import ../../constants
@ -142,7 +142,8 @@ QtObject:
proc getTestEnvironment*(self: LocalAppSettings): bool {.slot.} =
return existsEnv(TEST_ENVIRONMENT_VAR)
let value = getEnv(TEST_ENVIRONMENT_VAR)
return value.toUpperAscii() == "TRUE" or value == "1"
QtProperty[bool] testEnvironment:
read = getTestEnvironment
@ -150,7 +151,7 @@ QtObject:
proc fakeLoadingScreenEnabledChanged*(self: LocalAppSettings) {.signal.}
proc getFakeLoadingScreenEnabled*(self: LocalAppSettings): bool {.slot.} =
self.settings.value(LAS_KEY_FAKE_LOADING_SCREEN_ENABLED, newQVariant(DEFAULT_FAKE_LOADING_SCREEN_ENABLED)).boolVal
proc setFakeLoadingScreenEnabled*(self: LocalAppSettings, enabled: bool) {.slot.} =
self.settings.setValue(LAS_KEY_FAKE_LOADING_SCREEN_ENABLED, newQVariant(enabled))
self.fakeLoadingScreenEnabledChanged()

View File

@ -353,6 +353,23 @@ method windowDeactivated*(self: AccessInterface) {.base.} =
method communityMembersRevealedAccountsLoaded*(self: AccessInterface, communityId: string, membersRevealedAccounts: MembersRevealedAccounts) {.base.} =
raise newException(ValueError, "No implementation available")
## Used in test env only, for testing keycard flows
method registerMockedKeycard*(self: AccessInterface, cardIndex: int, readerState: int, keycardState: int,
mockedKeycard: string, mockedKeycardHelper: string) {.base.} =
raise newException(ValueError, "No implementation available")
method pluginMockedReaderAction*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method unplugMockedReaderAction*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method insertMockedKeycardAction*(self: AccessInterface, cardIndex: int) {.base.} =
raise newException(ValueError, "No implementation available")
method removeMockedKeycardAction*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c

View File

@ -1424,3 +1424,19 @@ method communityMembersRevealedAccountsLoaded*[T](self: Module[T], communityId:
self.view.model.setMembersAirdropAddress(communityId, communityMembersAirdropAddress)
## Used in test env only, for testing keycard flows
method registerMockedKeycard*[T](self: Module[T], cardIndex: int, readerState: int, keycardState: int,
mockedKeycard: string, mockedKeycardHelper: string) =
self.keycardService.registerMockedKeycard(cardIndex, readerState, keycardState, mockedKeycard, mockedKeycardHelper)
method pluginMockedReaderAction*[T](self: Module[T]) =
self.keycardService.pluginMockedReaderAction()
method unplugMockedReaderAction*[T](self: Module[T]) =
self.keycardService.unplugMockedReaderAction()
method insertMockedKeycardAction*[T](self: Module[T], cardIndex: int) =
self.keycardService.insertMockedKeycardAction(cardIndex)
method removeMockedKeycardAction*[T](self: Module[T]) =
self.keycardService.removeMockedKeycardAction()

View File

@ -295,4 +295,21 @@ QtObject:
proc showNetworkEndpointUpdated*(self: View, name: string, isTest: bool) {.signal.}
proc showIncludeWatchOnlyAccountUpdated*(self: View, includeWatchOnly: bool) {.signal.}
proc showToastKeypairRemoved*(self: View, keypairName: string) {.signal.}
proc showToastKeypairsImported*(self: View, keypairName: string, keypairsCount: int, error: string) {.signal.}
proc showToastKeypairsImported*(self: View, keypairName: string, keypairsCount: int, error: string) {.signal.}
## Used in test env only, for testing keycard flows
proc registerMockedKeycard*(self: View, cardIndex: int, readerState: int, keycardState: int,
mockedKeycard: string, mockedKeycardHelper: string) {.slot.} =
self.delegate.registerMockedKeycard(cardIndex, readerState, keycardState, mockedKeycard, mockedKeycardHelper)
proc pluginMockedReaderAction*(self: View) {.slot.} =
self.delegate.pluginMockedReaderAction()
proc unplugMockedReaderAction*(self: View) {.slot.} =
self.delegate.unplugMockedReaderAction()
proc insertMockedKeycardAction*(self: View, cardIndex: int) {.slot.} =
self.delegate.insertMockedKeycardAction(cardIndex)
proc removeMockedKeycardAction*(self: View) {.slot.} =
self.delegate.removeMockedKeycardAction()

View File

@ -195,6 +195,23 @@ method onReencryptionProcessStarted*(self: AccessInterface) {.base.} =
method onReencryptionProcessFinished*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
## Used in test env only, for testing keycard flows
method registerMockedKeycard*(self: AccessInterface, cardIndex: int, readerState: int, keycardState: int,
mockedKeycard: string, mockedKeycardHelper: string) {.base.} =
raise newException(ValueError, "No implementation available")
method pluginMockedReaderAction*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method unplugMockedReaderAction*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method insertMockedKeycardAction*(self: AccessInterface, cardIndex: int) {.base.} =
raise newException(ValueError, "No implementation available")
method removeMockedKeycardAction*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c

View File

@ -552,4 +552,21 @@ method onReencryptionProcessFinished*[T](self: Module[T]) =
currStateObj.stateType() == StateType.LoginKeycardConvertedToRegularAccount:
self.moveToStartupState()
return
self.moveToLoadingAppState()
self.moveToLoadingAppState()
## Used in test env only, for testing keycard flows
method registerMockedKeycard*[T](self: Module[T], cardIndex: int, readerState: int, keycardState: int,
mockedKeycard: string, mockedKeycardHelper: string) =
self.keycardService.registerMockedKeycard(cardIndex, readerState, keycardState, mockedKeycard, mockedKeycardHelper)
method pluginMockedReaderAction*[T](self: Module[T]) =
self.keycardService.pluginMockedReaderAction()
method unplugMockedReaderAction*[T](self: Module[T]) =
self.keycardService.unplugMockedReaderAction()
method insertMockedKeycardAction*[T](self: Module[T], cardIndex: int) =
self.keycardService.insertMockedKeycardAction(cardIndex)
method removeMockedKeycardAction*[T](self: Module[T]) =
self.keycardService.removeMockedKeycardAction()

View File

@ -373,3 +373,20 @@ QtObject:
proc validateLocalPairingConnectionString*(self: View, connectionString: string): string {.slot.} =
return self.delegate.validateLocalPairingConnectionString(connectionString)
## Used in test env only, for testing keycard flows
proc registerMockedKeycard*(self: View, cardIndex: int, readerState: int, keycardState: int,
mockedKeycard: string, mockedKeycardHelper: string) {.slot.} =
self.delegate.registerMockedKeycard(cardIndex, readerState, keycardState, mockedKeycard, mockedKeycardHelper)
proc pluginMockedReaderAction*(self: View) {.slot.} =
self.delegate.pluginMockedReaderAction()
proc unplugMockedReaderAction*(self: View) {.slot.} =
self.delegate.unplugMockedReaderAction()
proc insertMockedKeycardAction*(self: View, cardIndex: int) {.slot.} =
self.delegate.insertMockedKeycardAction(cardIndex)
proc removeMockedKeycardAction*(self: View) {.slot.} =
self.delegate.removeMockedKeycardAction()

View File

@ -1,7 +1,8 @@
import NimQml, json, os, chronicles, random, strutils
import keycard_go
import ../../../app/core/eventemitter
import ../../../app/core/tasks/[qt, threadpool]
import app/global/global_singleton
import app/core/eventemitter
import app/core/tasks/[qt, threadpool]
import ../../../constants as status_const
import constants
@ -148,6 +149,50 @@ QtObject:
if self.doLogging:
debug "keycardCancelFlow", kcServiceCurrFlow=($self.currentFlow), response=response
##########################################################
## Used in test env only, for testing keycard flows
proc registerMockedKeycard*(self: Service, cardIndex: int, readerState: int, keycardState: int,
mockedKeycard: string, mockedKeycardHelper: string) =
if not singletonInstance.localAppSettings.getTestEnvironment():
error "registerMockedKeycard can be used only in test env"
return
let response = keycard_go.mockedLibRegisterKeycard(cardIndex, readerState, keycardState, mockedKeycard, mockedKeycardHelper)
if self.doLogging:
debug "mockedLibRegisterKeycard", kcServiceCurrFlow=($self.currentFlow), cardIndex=cardIndex, readerState=readerState, keycardState=keycardState, mockedKeycard=mockedKeycard, mockedKeycardHelper=mockedKeycardHelper, response=response
proc pluginMockedReaderAction*(self: Service) =
if not singletonInstance.localAppSettings.getTestEnvironment():
error "pluginMockedReaderAction can be used only in test env"
return
let response = keycard_go.mockedLibReaderPluggedIn()
if self.doLogging:
debug "mockedLibReaderPluggedIn", kcServiceCurrFlow=($self.currentFlow), response=response
proc unplugMockedReaderAction*(self: Service) =
if not singletonInstance.localAppSettings.getTestEnvironment():
error "unplugMockedReaderAction can be used only in test env"
return
let response = keycard_go.mockedLibReaderUnplugged()
if self.doLogging:
debug "mockedLibReaderUnplugged", kcServiceCurrFlow=($self.currentFlow), response=response
proc insertMockedKeycardAction*(self: Service, cardIndex: int) =
if not singletonInstance.localAppSettings.getTestEnvironment():
error "insertMockedKeycardAction can be used only in test env"
return
let response = keycard_go.mockedLibKeycardInserted(cardIndex)
if self.doLogging:
debug "mockedLibKeycardInserted", kcServiceCurrFlow=($self.currentFlow), cardIndex=cardIndex, response=response
proc removeMockedKeycardAction*(self: Service) =
if not singletonInstance.localAppSettings.getTestEnvironment():
error "removeMockedKeycardAction can be used only in test env"
return
let response = keycard_go.mockedLibKeycardRemoved()
if self.doLogging:
debug "mockedLibKeycardRemoved", kcServiceCurrFlow=($self.currentFlow), response=response
##########################################################
proc generateRandomPUK*(self: Service): string =
randomize()
for i in 0 ..< PUKLengthForStatusApp:

View File

@ -8,6 +8,7 @@ import StatusQ.Core.Theme 0.1
import utils 1.0
import shared.popups.keycard 1.0
import shared.panels 1.0
import "controls"
import "views"
@ -30,6 +31,16 @@ OnboardingBasePage {
loader.sourceComponent = undefined
}
MockedKeycardLibFlowController {
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: Style.current.bigPadding
anchors.leftMargin: 4 * Style.current.bigPadding
visible: localAppSettings.testEnvironment
relatedModule: root.startupStore.startupModuleInst
}
Loader {
id: loader
anchors.fill: parent

View File

@ -1622,4 +1622,20 @@ Item {
onClosed: userAgreementLoader.active = false
}
}
Loader {
id: mockedKeycardLibInitialController
anchors.right: parent.right
anchors.bottom: parent.bottom
active: localAppSettings.testEnvironment
sourceComponent: MockedKeycardLibInitialController {
width: 450
height: 500
onClose: {
mockedKeycardLibInitialController.active = false
}
}
}
}

View File

@ -0,0 +1,85 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
ColumnLayout {
id: root
property string title
property int selectedState: MockedKeycardReaderStateSelector.State.NoReader
enum State {
NoReader,
NoKeycard,
KeycardInserted
}
QtObject {
id: d
readonly property string readerStateReaderUnplugged: qsTr("Reader Unplugged")
readonly property string readerStateKeycardNotInserted: qsTr("Keycard Not Inserted")
readonly property string readerStateKeycardInserted: qsTr("Keycard Inserted")
}
StatusBaseText {
text: root.title
}
StatusButton {
id: selectReaderStateButton
text: {
switch (root.selectedState) {
case MockedKeycardReaderStateSelector.State.NoReader:
return d.readerStateReaderUnplugged
case MockedKeycardReaderStateSelector.State.NoKeycard:
return d.readerStateKeycardNotInserted
case MockedKeycardReaderStateSelector.State.KeycardInserted:
return d.readerStateKeycardInserted
}
return ""
}
icon.name: "chevron-down"
onClicked: {
if (initialReaderState.opened) {
initialReaderState.close()
} else {
initialReaderState.popup(selectReaderStateButton.x, selectReaderStateButton.y + selectReaderStateButton.height + 8)
}
}
}
StatusMenu {
id: initialReaderState
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
StatusAction {
text: d.readerStateReaderUnplugged
onTriggered: {
root.selectedState = MockedKeycardReaderStateSelector.State.NoReader
}
}
StatusAction {
text: d.readerStateKeycardNotInserted
onTriggered: {
root.selectedState = MockedKeycardReaderStateSelector.State.NoKeycard
}
}
StatusAction {
text: d.readerStateKeycardInserted
onTriggered: {
root.selectedState = MockedKeycardReaderStateSelector.State.KeycardInserted
}
}
}
}

View File

@ -0,0 +1,140 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
ColumnLayout {
id: root
property string title
property int selectedState: MockedKeycardStateSelector.State.EmptyKeycard
enum State {
NotStatusKeycard,
EmptyKeycard,
MaxPairingSlotsReached,
MaxPINRetriesReached,
MaxPUKRetriesReached,
KeycardWithMnemonicOnly,
KeycardWithMnemonicAndMedatada,
CustomKeycard // should be always the last option
}
QtObject {
id: d
readonly property string kcStateNotStatusKeycard: qsTr("Not Status Keycard")
readonly property string kcStateEmptyKeycard: qsTr("Empty Keycard")
readonly property string kcStateMaxPairingSlotsReached: qsTr("Max Pairing Slots Reached")
readonly property string kcStateMaxPINRetriesReached: qsTr("Max PIN Retries Reached")
readonly property string kcStateMaxPUKRetriesReached: qsTr("Max PUK Retries Reached")
readonly property string kcStateKeycardWithMnemonicOnly: qsTr("Keycard With Mnemonic Only")
readonly property string kcStateKeycardWithMnemonicAndMedatada: qsTr("Keycard With Mnemonic & Metadata")
readonly property string kcStateCustomKeycard: qsTr("Custom Keycard")
}
StatusBaseText {
text: root.title
}
StatusButton {
id: selectKeycardsStateButton
text: {
switch (root.selectedState) {
case MockedKeycardStateSelector.State.NotStatusKeycard:
return d.kcStateNotStatusKeycard
case MockedKeycardStateSelector.State.EmptyKeycard:
return d.kcStateEmptyKeycard
case MockedKeycardStateSelector.State.MaxPairingSlotsReached:
return d.kcStateMaxPairingSlotsReached
case MockedKeycardStateSelector.State.MaxPINRetriesReached:
return d.kcStateMaxPINRetriesReached
case MockedKeycardStateSelector.State.MaxPUKRetriesReached:
return d.kcStateMaxPUKRetriesReached
case MockedKeycardStateSelector.State.KeycardWithMnemonicOnly:
return d.kcStateKeycardWithMnemonicOnly
case MockedKeycardStateSelector.State.KeycardWithMnemonicAndMedatada:
return d.kcStateKeycardWithMnemonicAndMedatada
case MockedKeycardStateSelector.State.CustomKeycard:
return d.kcStateCustomKeycard
}
return ""
}
icon.name: "chevron-down"
onClicked: {
if (initialKeycardState.opened) {
initialKeycardState.close()
} else {
initialKeycardState.popup(selectKeycardsStateButton.x, selectKeycardsStateButton.y + selectKeycardsStateButton.height + 8)
}
}
}
StatusMenu {
id: initialKeycardState
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
StatusAction {
text: d.kcStateNotStatusKeycard
onTriggered: {
root.selectedState = MockedKeycardStateSelector.State.NotStatusKeycard
}
}
StatusAction {
text: d.kcStateEmptyKeycard
onTriggered: {
root.selectedState = MockedKeycardStateSelector.State.EmptyKeycard
}
}
StatusAction {
text: d.kcStateMaxPairingSlotsReached
onTriggered: {
root.selectedState = MockedKeycardStateSelector.State.MaxPairingSlotsReached
}
}
StatusAction {
text: d.kcStateMaxPINRetriesReached
onTriggered: {
root.selectedState = MockedKeycardStateSelector.State.MaxPINRetriesReached
}
}
StatusAction {
text: d.kcStateMaxPUKRetriesReached
onTriggered: {
root.selectedState = MockedKeycardStateSelector.State.MaxPUKRetriesReached
}
}
StatusAction {
text: d.kcStateKeycardWithMnemonicOnly
onTriggered: {
root.selectedState = MockedKeycardStateSelector.State.KeycardWithMnemonicOnly
}
}
StatusAction {
text: d.kcStateKeycardWithMnemonicAndMedatada
onTriggered: {
root.selectedState = MockedKeycardStateSelector.State.KeycardWithMnemonicAndMedatada
}
}
StatusAction {
text: d.kcStateCustomKeycard
onTriggered: {
root.selectedState = MockedKeycardStateSelector.State.CustomKeycard
}
}
}
}

View File

@ -41,3 +41,5 @@ TransactionAddressTile 1.0 TransactionAddressTile.qml
TransactionDataTile 1.0 TransactionDataTile.qml
TransactionDelegate 1.0 TransactionDelegate.qml
TransactionDetailsHeader.qml 1.0 TransactionDetailsHeader.qml
MockedKeycardReaderStateSelector 1.0 MockedKeycardReaderStateSelector.qml
MockedKeycardStateSelector 1.0 MockedKeycardStateSelector.qml

View File

@ -0,0 +1,65 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Controls 0.1
RowLayout {
id: root
property var relatedModule
StatusButton {
text: qsTr("Plugin R")
onClicked: {
if (!!root.relatedModule) {
root.relatedModule.pluginMockedReaderAction()
}
}
}
StatusButton {
text: qsTr("Unplug R")
onClicked: {
if (!!root.relatedModule) {
root.relatedModule.unplugMockedReaderAction()
}
}
}
StatusButton {
text: qsTr("Ins Kc 1")
onClicked: {
if (!!root.relatedModule) {
root.relatedModule.insertMockedKeycardAction(1)
}
}
}
StatusButton {
text: qsTr("Ins Kc 2")
onClicked: {
if (!!root.relatedModule) {
root.relatedModule.insertMockedKeycardAction(2)
}
}
}
StatusButton {
text: qsTr("Remove Kc")
onClicked: {
if (!!root.relatedModule) {
root.relatedModule.removeMockedKeycardAction()
}
}
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: 1
}
}

View File

@ -0,0 +1,213 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
import shared.controls 1.0
import utils 1.0
Rectangle {
id: root
color: Style.current.modalBackground
radius: Style.current.radius
border.color: Style.current.grey3
border.width: 2
signal close()
QtObject {
id: d
property int btnWidth: 30
property int btnHeight: 30
property int margin: 8
property bool minimized: false
property int maxWidth
property int maxHeight
onMinimizedChanged: {
if (minimized) {
d.maxWidth = root.width
d.maxHeight = root.height
root.width = header.implicitWidth + 2 * d.margin
root.height = header.implicitHeight + 2 * d.margin
return
}
root.width = d.maxWidth
root.height = d.maxHeight
}
}
Row {
id: header
anchors.right: parent.right
anchors.rightMargin: d.margin
anchors.top: parent.top
anchors.topMargin: d.margin
spacing: d.margin
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
icon.name: d.minimized? "chevron-up" : "chevron-down"
icon.color: Theme.palette.directColor1
implicitWidth: d.btnWidth
implicitHeight: d.btnHeight
onClicked: {
d.minimized = !d.minimized
}
}
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
icon.name: "close"
icon.color: Theme.palette.directColor1
implicitWidth: d.btnWidth
implicitHeight: d.btnHeight
onClicked: {
root.close()
}
}
}
MockedKeycardReaderStateSelector {
id: readerState
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: Style.current.bigPadding
anchors.leftMargin: Style.current.bigPadding
visible: !d.minimized
title: qsTr("Initial reader state")
}
StatusTabBar {
id: tabBar
anchors.top: readerState.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Style.current.bigPadding
visible: !d.minimized
StatusTabButton {
width: implicitWidth
leftPadding: 0
text: qsTr("Keycard-1")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Keycard-2")
}
}
StackLayout {
anchors.top: tabBar.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Style.current.halfPadding
visible: !d.minimized
currentIndex: tabBar.currentIndex
KeycardSettingsTab {
cardIndex: 1
onRegisterKeycard: {
mainModule.registerMockedKeycard(cardIndex, readerState.selectedState, kcState, kc, kcHelper)
}
}
KeycardSettingsTab {
cardIndex: 2
onRegisterKeycard: {
mainModule.registerMockedKeycard(cardIndex, MockedKeycardReaderStateSelector.NoKeycard, kcState, kc, kcHelper)
}
}
}
component KeycardSettingsTab: StatusScrollView {
id: keycardSettingsTabRoot
property int cardIndex
signal registerKeycard(int kcState, string kc, string kcHelper)
ColumnLayout {
spacing: 16
MockedKeycardStateSelector {
id: keycardState
title: qsTr("Keycard %1 - initial keycard state").arg(keycardSettingsTabRoot.cardIndex)
}
Column {
id: customSection
visible: keycardState.selectedState === MockedKeycardStateSelector.CustomKeycard
spacing: 16
StatusInput {
id: mockedKeycard
label: qsTr("Mocked Keycard")
implicitWidth: 400
minimumHeight: 200
maximumHeight: 200
input.multiline: true
input.verticalAlignment: TextEdit.AlignTop
placeholderText: qsTr("Enter json form of status-go MockedKeycard")
errorMessageCmp.text: qsTr("Invalid json format")
}
StatusInput {
id: mockedKeycardHelper
label: qsTr("Specific keycard details")
implicitWidth: 400
minimumHeight: 200
maximumHeight: 200
input.multiline: true
input.verticalAlignment: TextEdit.AlignTop
placeholderText: qsTr("Enter json form of status-go MockedKeycard")
errorMessageCmp.text: qsTr("Invalid json format")
}
}
StatusButton {
text: qsTr("Register Keycard")
onClicked: {
if (customSection.visible) {
mockedKeycard.input.valid = true
mockedKeycardHelper.input.valid = true
if (mockedKeycard.text != "") {
try {
JSON.parse(mockedKeycard.text)
}
catch(e) {
mockedKeycard.input.valid = false
}
}
if (mockedKeycardHelper.text != "") {
try {
JSON.parse(mockedKeycardHelper.text)
}
catch(e) {
mockedKeycardHelper.input.valid = false
}
}
if (!mockedKeycard.input.valid || !mockedKeycardHelper.input.valid) {
return
}
}
keycardSettingsTabRoot.registerKeycard(keycardState.selectedState,
mockedKeycard.text,
mockedKeycardHelper.text)
}
}
}
}
}

View File

@ -25,3 +25,5 @@ StatusAssetSelector 1.0 StatusAssetSelector.qml
StyledText 1.0 StyledText.qml
TextWithLabel 1.0 TextWithLabel.qml
DropAndEditImagePanel 1.0 DropAndEditImagePanel.qml
MockedKeycardLibFlowController 1.0 MockedKeycardLibFlowController.qml
MockedKeycardLibInitialController 1.0 MockedKeycardLibInitialController.qml

View File

@ -83,21 +83,23 @@ StatusModal {
id: content
width: scrollView.availableWidth
implicitHeight: {
let additionalHeight = localAppSettings.testEnvironment? 60 : 0
// for all flows
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
if (!root.sharedKeycardModule.keyPairStoredOnKeycardIsKnown) {
return Constants.keycard.general.popupBiggerHeight
return Constants.keycard.general.popupBiggerHeight + additionalHeight
}
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.importFromKeycard &&
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.manageKeycardAccounts &&
root.sharedKeycardModule.keyPairHelper.accounts.count > 1) {
return Constants.keycard.general.popupBiggerHeight
return Constants.keycard.general.popupBiggerHeight + additionalHeight
}
return Constants.keycard.general.popupHeight
return Constants.keycard.general.popupHeight + additionalHeight
}
sharedKeycardModule: root.sharedKeycardModule

View File

@ -1,6 +1,7 @@
import QtQuick 2.14
import utils 1.0
import shared.panels 1.0
import "./states"
@ -18,9 +19,26 @@ Item {
property bool primaryButtonEnabled: false
}
MockedKeycardLibFlowController {
id: mockedLibFlowController
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
visible: localAppSettings.testEnvironment
relatedModule: mainModule
}
Loader {
id: loader
anchors.fill: parent
anchors.top: mockedLibFlowController.visible? mockedLibFlowController.bottom : parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
sourceComponent: {
switch (root.sharedKeycardModule.currentState.stateType) {
case Constants.keycardSharedState.biometrics:

@ -1 +1 @@
Subproject commit 6a4bed51d53f3ef8d1eaff038e08449c288c8334
Subproject commit a1724bad72e83ca83df2632d83a631cd8d8ff0f6

@ -1 +1 @@
Subproject commit c6b7095a85f04fe798e4847406967beb0d3566d3
Subproject commit 1a86f57a96932ff248f767487ce41575ee1c4b7c