From 398f62806f7af28ef6b52e6216d00191bf176527 Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Tue, 16 Aug 2022 11:19:15 +0200 Subject: [PATCH] feat(@desktop/keycard): initial UI for the keycard settings This is just a wireframe implementation, without any special functionalities. Fixes: #7023 --- src/app/boot/app_controller.nim | 3 +- src/app/modules/main/module.nim | 6 +- .../main/profile_section/io_interface.nim | 3 + .../profile_section/keycard/controller.nim | 26 +++ .../profile_section/keycard/io_interface.nim | 23 +++ .../main/profile_section/keycard/module.nim | 58 ++++++ .../main/profile_section/keycard/view.nim | 20 +++ .../modules/main/profile_section/module.nim | 16 +- src/app/modules/main/profile_section/view.nim | 5 + ui/app/AppLayouts/Profile/ProfileLayout.qml | 9 + .../Profile/stores/KeycardStore.qml | 9 + .../Profile/stores/ProfileSectionStore.qml | 7 + .../AppLayouts/Profile/views/KeycardView.qml | 167 ++++++++++++++++++ .../icons/keycard/security-keycard@2x.svg | 9 + .../png/keycard/security-keycard@2x.png | Bin 0 -> 16782 bytes ui/imports/utils/Constants.qml | 6 +- 16 files changed, 360 insertions(+), 7 deletions(-) create mode 100644 src/app/modules/main/profile_section/keycard/controller.nim create mode 100644 src/app/modules/main/profile_section/keycard/io_interface.nim create mode 100644 src/app/modules/main/profile_section/keycard/module.nim create mode 100644 src/app/modules/main/profile_section/keycard/view.nim create mode 100644 ui/app/AppLayouts/Profile/stores/KeycardStore.qml create mode 100644 ui/app/AppLayouts/Profile/views/KeycardView.qml create mode 100644 ui/imports/assets/icons/keycard/security-keycard@2x.svg create mode 100644 ui/imports/assets/png/keycard/security-keycard@2x.png diff --git a/src/app/boot/app_controller.nim b/src/app/boot/app_controller.nim index 373c6fa948..3efead1894 100644 --- a/src/app/boot/app_controller.nim +++ b/src/app/boot/app_controller.nim @@ -227,7 +227,8 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController = result.gifService, result.ensService, result.networkService, - result.generalService + result.generalService, + result.keycardService ) # Do connections diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 46e1fd44de..894740ae58 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -52,6 +52,7 @@ import ../../../app_service/service/gif/service as gif_service import ../../../app_service/service/ens/service as ens_service import ../../../app_service/service/network/service as network_service import ../../../app_service/service/general/service as general_service +import ../../../app_service/service/keycard/service as keycard_service from ../../../app_service/common/types import StatusType import ../../../app_service/common/social_links @@ -120,7 +121,8 @@ proc newModule*[T]( gifService: gif_service.Service, ensService: ens_service.Service, networkService: network_service.Service, - generalService: general_service.Service + generalService: general_service.Service, + keycardService: keycard_service.Service ): Module[T] = result = Module[T]() result.delegate = delegate @@ -158,7 +160,7 @@ proc newModule*[T]( result, events, accountsService, settingsService, stickersService, profileService, contactsService, aboutService, languageService, privacyService, nodeConfigurationService, devicesService, mailserversService, chatService, ensService, walletAccountService, generalService, communityService, - networkService, + networkService, keycardService ) result.stickersModule = stickers_module.newModule(result, events, stickersService, settingsService, walletAccountService, networkService) result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService, diff --git a/src/app/modules/main/profile_section/io_interface.nim b/src/app/modules/main/profile_section/io_interface.nim index 2f0d19e182..657669601c 100644 --- a/src/app/modules/main/profile_section/io_interface.nim +++ b/src/app/modules/main/profile_section/io_interface.nim @@ -85,3 +85,6 @@ method getCommunitiesModule*(self: AccessInterface): QVariant {.base.} = method communitiesModuleDidLoad*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") + +method getKeycardModule*(self: AccessInterface): QVariant {.base.} = + raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/profile_section/keycard/controller.nim b/src/app/modules/main/profile_section/keycard/controller.nim new file mode 100644 index 0000000000..7997120b68 --- /dev/null +++ b/src/app/modules/main/profile_section/keycard/controller.nim @@ -0,0 +1,26 @@ +import chronicles + +import io_interface + +import ../../../../core/eventemitter + +logScope: + topics = "profile-section-keycard-module-controller" + +type + Controller* = ref object of RootObj + delegate: io_interface.AccessInterface + events: EventEmitter + +proc newController*(delegate: io_interface.AccessInterface, + events: EventEmitter): + Controller = + result = Controller() + result.delegate = delegate + result.events = events + +proc delete*(self: Controller) = + discard + +proc init*(self: Controller) = + discard \ No newline at end of file diff --git a/src/app/modules/main/profile_section/keycard/io_interface.nim b/src/app/modules/main/profile_section/keycard/io_interface.nim new file mode 100644 index 0000000000..86445bc6f8 --- /dev/null +++ b/src/app/modules/main/profile_section/keycard/io_interface.nim @@ -0,0 +1,23 @@ +import NimQml + +type + AccessInterface* {.pure inheritable.} = ref object of RootObj + ## Abstract class for any input/interaction with this module. + +method delete*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method load*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method isLoaded*(self: AccessInterface): bool {.base.} = + raise newException(ValueError, "No implementation available") + +method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} = + raise newException(ValueError, "No implementation available") + +# View Delegate Interface +# Delegate for the view must be declared here due to use of QtObject and multi +# inheritance, which is not well supported in Nim. +method viewDidLoad*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/profile_section/keycard/module.nim b/src/app/modules/main/profile_section/keycard/module.nim new file mode 100644 index 0000000000..23f95ce2e8 --- /dev/null +++ b/src/app/modules/main/profile_section/keycard/module.nim @@ -0,0 +1,58 @@ +import NimQml, chronicles + +import ./io_interface, ./view, ./controller +import ../io_interface as delegate_interface + +import ../../../../core/eventemitter + +import ../../../../../app_service/service/keycard/service as keycard_service +import ../../../../../app_service/service/wallet_account/service as wallet_account_service + +export io_interface + +logScope: + topics = "profile-section-profile-module" + +type + Module* = ref object of io_interface.AccessInterface + delegate: delegate_interface.AccessInterface + controller: Controller + view: View + viewVariant: QVariant + moduleLoaded: bool + events: EventEmitter + keycardService: keycard_service.Service + walletAccountService: wallet_account_service.Service + +proc newModule*(delegate: delegate_interface.AccessInterface, + events: EventEmitter, + keycardService: keycard_service.Service, + walletAccountService: wallet_account_service.Service): Module = + result = Module() + result.delegate = delegate + result.events = events + result.keycardService = keycardService + result.walletAccountService = walletAccountService + result.view = view.newView(result) + result.viewVariant = newQVariant(result.view) + result.controller = controller.newController(result, events) + result.moduleLoaded = false + +method delete*(self: Module) = + self.view.delete + self.viewVariant.delete + self.controller.delete + +method load*(self: Module) = + self.controller.init() + self.view.load() + +method isLoaded*(self: Module): bool = + return self.moduleLoaded + +method viewDidLoad*(self: Module) = + self.moduleLoaded = true + self.delegate.profileModuleDidLoad() + +method getModuleAsVariant*(self: Module): QVariant = + return self.viewVariant \ No newline at end of file diff --git a/src/app/modules/main/profile_section/keycard/view.nim b/src/app/modules/main/profile_section/keycard/view.nim new file mode 100644 index 0000000000..abc3a3e685 --- /dev/null +++ b/src/app/modules/main/profile_section/keycard/view.nim @@ -0,0 +1,20 @@ +import NimQml + +import ./io_interface + +QtObject: + type + View* = ref object of QObject + delegate: io_interface.AccessInterface + + proc delete*(self: View) = + self.QObject.delete + + proc newView*(delegate: io_interface.AccessInterface): View = + new(result, delete) + result.QObject.setup + result.delegate = delegate + + proc load*(self: View) = + self.delegate.viewDidLoad() + \ No newline at end of file diff --git a/src/app/modules/main/profile_section/module.nim b/src/app/modules/main/profile_section/module.nim index 9da3833c14..c131dc366e 100644 --- a/src/app/modules/main/profile_section/module.nim +++ b/src/app/modules/main/profile_section/module.nim @@ -20,7 +20,7 @@ import ../../../../app_service/service/network/service as network_service import ../../../../app_service/service/wallet_account/service as wallet_account_service import ../../../../app_service/service/general/service as general_service import ../../../../app_service/service/community/service as community_service - +import ../../../../app_service/service/keycard/service as keycard_service import ./profile/module as profile_module import ./contacts/module as contacts_module @@ -33,6 +33,7 @@ import ./sync/module as sync_module import ./notifications/module as notifications_module import ./ens_usernames/module as ens_usernames_module import ./communities/module as communities_module +import ./keycard/module as keycard_module export io_interface @@ -55,6 +56,7 @@ type notificationsModule: notifications_module.AccessInterface ensUsernamesModule: ens_usernames_module.AccessInterface communitiesModule: communities_module.AccessInterface + keycardModule: keycard_module.AccessInterface proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, @@ -75,6 +77,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface, generalService: general_service.Service, communityService: community_service.Service, networkService: network_service.Service, + keycardService: keycard_service.Service ): Module = result = Module() result.delegate = delegate @@ -96,6 +99,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface, result, events, settingsService, ensService, walletAccountService, networkService ) result.communitiesModule = communities_module.newModule(result, communityService) + result.keycardModule = keycard_module.newModule(result, events, keycardService, walletAccountService) singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant) @@ -109,6 +113,7 @@ method delete*(self: Module) = self.devicesModule.delete self.syncModule.delete self.communitiesModule.delete + self.keycardModule.delete self.view.delete self.viewVariant.delete @@ -127,6 +132,7 @@ method load*(self: Module) = self.notificationsModule.load() self.ensUsernamesModule.load() self.communitiesModule.load() + self.keycardModule.load() method isLoaded*(self: Module): bool = return self.moduleLoaded @@ -165,6 +171,9 @@ proc checkIfModuleDidLoad(self: Module) = if(not self.communitiesModule.isLoaded()): return + if(not self.keycardModule.isLoaded()): + return + self.moduleLoaded = true self.delegate.profileSectionDidLoad() @@ -232,4 +241,7 @@ method getCommunitiesModule*(self: Module): QVariant = self.communitiesModule.getModuleAsVariant() method communitiesModuleDidLoad*(self: Module) = - self.checkIfModuleDidLoad() \ No newline at end of file + self.checkIfModuleDidLoad() + +method getKeycardModule*(self: Module): QVariant = + self.keycardModule.getModuleAsVariant() \ No newline at end of file diff --git a/src/app/modules/main/profile_section/view.nim b/src/app/modules/main/profile_section/view.nim index 99c6966d0a..bfcdfb6519 100644 --- a/src/app/modules/main/profile_section/view.nim +++ b/src/app/modules/main/profile_section/view.nim @@ -70,3 +70,8 @@ QtObject: return self.delegate.getCommunitiesModule() QtProperty[QVariant] communitiesModule: read = getCommunitiesModule + + proc getKeycardModule(self: View): QVariant {.slot.} = + return self.delegate.getKeycardModule() + QtProperty[QVariant] keycardModule: + read = getKeycardModule diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml index daf79b63ab..bbd3c386a5 100644 --- a/ui/app/AppLayouts/Profile/ProfileLayout.qml +++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml @@ -222,6 +222,15 @@ StatusAppTwoPanelLayout { sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.communitiesSettings) contentWidth: d.contentWidth } + + KeycardView { + implicitWidth: parent.width + implicitHeight: parent.height + + keycardStore: profileView.store.keycardStore + sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.keycard) + contentWidth: d.contentWidth + } } } // Item ModuleWarning { diff --git a/ui/app/AppLayouts/Profile/stores/KeycardStore.qml b/ui/app/AppLayouts/Profile/stores/KeycardStore.qml new file mode 100644 index 0000000000..e4edaec603 --- /dev/null +++ b/ui/app/AppLayouts/Profile/stores/KeycardStore.qml @@ -0,0 +1,9 @@ +import QtQuick 2.13 +import utils 1.0 + +QtObject { + id: root + + property var keycardModule + +} diff --git a/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml index c7ad17c3e5..3c67f3ed18 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml @@ -55,6 +55,10 @@ QtObject { property WalletStore walletStore: WalletStore { } + property KeycardStore keycardStore: KeycardStore { + keycardModule: profileSectionModuleInst.keycardModule + } + property var stickersModuleInst: stickersModule property var stickersStore: StickersStore { stickersModule: stickersModuleInst @@ -75,6 +79,9 @@ QtObject { append({subsection: Constants.settingsSubsection.profile, text: qsTr("Profile"), icon: "profile"}) + append({subsection: Constants.settingsSubsection.keycard, + text: qsTr("Keycard"), + icon: "keycard"}) append({subsection: Constants.settingsSubsection.ensUsernames, text: qsTr("ENS usernames"), icon: "username"}) diff --git a/ui/app/AppLayouts/Profile/views/KeycardView.qml b/ui/app/AppLayouts/Profile/views/KeycardView.qml new file mode 100644 index 0000000000..c8225126e4 --- /dev/null +++ b/ui/app/AppLayouts/Profile/views/KeycardView.qml @@ -0,0 +1,167 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtQuick.Layouts 1.13 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Components 0.1 +import StatusQ.Popups 0.1 + +import utils 1.0 +import shared.panels 1.0 +import shared.controls 1.0 +import shared.status 1.0 + +import "../stores" +import "../controls" +import "../panels" + +SettingsContentBase { + id: root + + property KeycardStore keycardStore + + titleRowComponentLoader.sourceComponent: StatusButton { + text: qsTr("Get Keycard") + onClicked: { + console.warn("TODO: Go to purchase page...") + } + } + + ColumnLayout { + id: contentColumn + spacing: Constants.settingsSection.itemSpacing + + Image { + Layout.alignment: Qt.AlignCenter + Layout.preferredHeight: sourceSize.height + Layout.preferredWidth: sourceSize.width + fillMode: Image.PreserveAspectFit + antialiasing: true + source: Style.png("keycard/security-keycard@2x") + mipmap: true + } + + Item { + Layout.fillWidth: true + Layout.preferredHeight: Style.current.halfPadding + } + + StyledText { + Layout.alignment: Qt.AlignCenter + font.pixelSize: Constants.settingsSection.importantInfoFontSize + color: Style.current.directColor1 + text: qsTr("Secure your funds. Keep your profile safe.") + } + + Item { + Layout.fillWidth: true + Layout.preferredHeight: Style.current.halfPadding + } + + StatusListItem { + Layout.preferredWidth: root.contentWidth + title: qsTr("Setup a new Keycard with an existing account") + components: [ + StatusIcon { + icon: "chevron-down" + rotation: 270 + color: Theme.palette.baseColor1 + } + ] + sensor.onClicked: { + console.warn("TODO: Run Set up Keycard flow...") + } + } + + StatusSectionHeadline { + Layout.preferredWidth: root.contentWidth + Layout.leftMargin: Style.current.padding + Layout.rightMargin: Style.current.padding + text: qsTr("Create, import or restore a Keycard account") + } + + StatusListItem { + Layout.preferredWidth: root.contentWidth + title: qsTr("Generate a seed phrase") + components: [ + StatusIcon { + icon: "chevron-down" + rotation: 270 + color: Theme.palette.baseColor1 + } + ] + sensor.onClicked: { + console.warn("TODO: Generate a seed phrase...") + } + } + + StatusListItem { + Layout.preferredWidth: root.contentWidth + title: qsTr("Import or restore via a seed phrase") + components: [ + StatusIcon { + icon: "chevron-down" + rotation: 270 + color: Theme.palette.baseColor1 + } + ] + sensor.onClicked: { + console.warn("TODO: Import or restore via a seed phrase...") + } + } + + StatusListItem { + Layout.preferredWidth: root.contentWidth + title: qsTr("Import from Keycard to Status Desktop") + components: [ + StatusIcon { + icon: "chevron-down" + rotation: 270 + color: Theme.palette.baseColor1 + } + ] + sensor.onClicked: { + console.warn("TODO: Import from Keycard to Status Desktop...") + } + } + + StatusSectionHeadline { + Layout.preferredWidth: root.contentWidth + Layout.leftMargin: Style.current.padding + Layout.rightMargin: Style.current.padding + text: qsTr("Other") + } + + StatusListItem { + Layout.preferredWidth: root.contentWidth + title: qsTr("Check what’s on a Keycard") + components: [ + StatusIcon { + icon: "chevron-down" + rotation: 270 + color: Theme.palette.baseColor1 + } + ] + sensor.onClicked: { + console.warn("TODO: Check what’s on a Keycard...") + } + } + + StatusListItem { + Layout.preferredWidth: root.contentWidth + title: qsTr("Factory reset a Keycard") + components: [ + StatusIcon { + icon: "chevron-down" + rotation: 270 + color: Theme.palette.baseColor1 + } + ] + sensor.onClicked: { + console.warn("TODO: Factory reset a Keycard...") + } + } + } +} diff --git a/ui/imports/assets/icons/keycard/security-keycard@2x.svg b/ui/imports/assets/icons/keycard/security-keycard@2x.svg new file mode 100644 index 0000000000..4b3cf90831 --- /dev/null +++ b/ui/imports/assets/icons/keycard/security-keycard@2x.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/ui/imports/assets/png/keycard/security-keycard@2x.png b/ui/imports/assets/png/keycard/security-keycard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..51ad127df59103f9e3f41624db6134490bb95e47 GIT binary patch literal 16782 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 literal 0 HcmV?d00001 diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 1ffaffa4d8..c2872e82bc 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -132,8 +132,9 @@ QtObject { property int advanced: 10 property int about: 11 property int communitiesSettings: 12 - property int signout: 13 - property int backUpSeed: 14 + property int keycard: 13 + property int signout: 14 + property int backUpSeed: 15 } readonly property QtObject currentUserStatus: QtObject{ @@ -273,6 +274,7 @@ QtObject { readonly property int radius: 8 readonly property int mainHeaderFontSize: 28 readonly property int subHeaderFontSize: 15 + readonly property int importantInfoFontSize: 18 readonly property int infoFontSize: 15 readonly property int infoLineHeight: 22 readonly property int infoSpacing: 5