diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim index a7f0dacba0..64ef04b788 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -44,10 +44,16 @@ proc mainProc() = status.tasks.marathon.registerWorker(mailserverWorker) status.initNode() + defer: + info "Status app is shutting down..." + status.tasks.teardown() + enableHDPI() initializeOpenGL() let app = newQGuiApplication() + defer: app.delete() + let resources = if defined(windows) and defined(production): "/../resources/resources.rcc" @@ -85,6 +91,7 @@ proc mainProc() = let networkAccessFactory = newQNetworkAccessManagerFactory(TMPDIR & "netcache") let engine = newQQmlApplicationEngine() + defer: engine.delete() engine.addImportPath("qrc:/./StatusQ/src") engine.setNetworkAccessManagerFactory(networkAccessFactory) app.installEventFilter(engine) @@ -103,46 +110,56 @@ proc mainProc() = netAccMgr.setNetworkAccessible(NetworkAccessibility.Accessible) let signalController = signals.newController(status) + defer: signalController.delete() # We need this global variable in order to be able to access the application # from the non-closure callback passed to `libstatus.setSignalEventCallback` signalsQObjPointer = cast[pointer](signalController.vptr) var wallet = wallet.newController(status) + defer: wallet.delete() engine.setRootContextProperty("walletModel", wallet.variant) var chat = chat.newController(status) + defer: chat.delete() engine.setRootContextProperty("chatsModel", chat.variant) var node = node.newController(status, netAccMgr) + defer: node.delete() engine.setRootContextProperty("nodeModel", node.variant) var utilsController = utilsView.newController(status) + defer: utilsController.delete() engine.setRootContextProperty("utilsModel", utilsController.variant) var browserController = browserView.newController(status) + defer: browserController.delete() engine.setRootContextProperty("browserModel", browserController.variant) proc changeLanguage(locale: string) = engine.setTranslationPackage(joinPath(i18nPath, fmt"qml_{locale}.qm")) var profile = profile.newController(status, changeLanguage) + defer: profile.delete() engine.setRootContextProperty("profileModel", profile.variant) var provider = provider.newController(status) + defer: provider.delete() engine.setRootContextProperty("web3Provider", provider.variant) var login = login.newController(status) + defer: login.delete() var onboarding = onboarding.newController(status) + defer: onboarding.delete() status.events.once("login") do(a: Args): var args = AccountArgs(a) status.tasks.marathon.onLoggedIn() - # Delete login and onboarding from memory to remove any mnemonic that would have been saved in the accounts list - login.delete() - onboarding.delete() + # Reset login and onboarding to remove any mnemonic that would have been saved in the accounts list + login.reset() + onboarding.reset() status.startMessenger() profile.init(args.account) @@ -161,23 +178,7 @@ proc mainProc() = let isExperimental = if getEnv("EXPERIMENTAL") == "1": "1" else: "0" # value explicity passed to avoid trusting input let experimentalFlag = newQVariant(isExperimental) engine.setRootContextProperty("isExperimental", experimentalFlag) - - defer: - error "TODO: if user is logged in, logout" - provider.delete() - engine.delete() - app.delete() - signalController.delete() - login.delete() - onboarding.delete() - wallet.delete() - chat.delete() - profile.delete() - utilsController.delete() - browserController.delete() - status.tasks.teardown() - - + # Initialize only controllers whose init functions # do not need a running node proc initControllers() = diff --git a/ui/main.qml b/ui/main.qml index bc8223f9da..2cbf57c45e 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -93,15 +93,15 @@ StatusWindow { target: applicationWindow onClosing: { if (loader.sourceComponent == login) { - applicationWindow.visible = false; - close.accepted = false; + applicationWindow.visible = false + close.accepted = false } else if (loader.sourceComponent == app) { if (loader.item.appSettings.quitOnClose) { - Qt.quit(); + close.accepted = true } else { - applicationWindow.visible = false; - close.accepted = false; + applicationWindow.visible = false + close.accepted = false } } } diff --git a/ui/onboarding/Login.qml b/ui/onboarding/Login.qml index 5435663296..4e10fb1d63 100644 --- a/ui/onboarding/Login.qml +++ b/ui/onboarding/Login.qml @@ -128,8 +128,9 @@ Item { id: txtPassword anchors.top: addressText.bottom anchors.topMargin: Style.current.padding * 2 + enabled: !loading //% "Enter password" - placeholderText: qsTrId("enter-password") + placeholderText: loading ? qsTr("Connecting...") : qsTrId("enter-password") textField.echoMode: TextInput.Password textField.focus: true Keys.onReturnPressed: { @@ -140,6 +141,7 @@ Item { loading = false } } + StatusRoundButton { id: submitBtn size: "medium" @@ -147,9 +149,9 @@ Item { icon.name: "arrow-right" icon.width: 18 icon.height: 14 - visible: txtPassword.text.length > 0 + opacity: (loading || txtPassword.text.length > 0) ? 1 : 0 anchors.left: txtPassword.right - anchors.leftMargin: Style.current.padding + anchors.leftMargin: (loading || txtPassword.text.length > 0) ? Style.current.padding : Style.current.smallPadding anchors.verticalCenter: txtPassword.verticalCenter state: loading ? "pending" : "default" onClicked: { @@ -159,6 +161,20 @@ Item { setCurrentFlow(true); loading = true loginModel.login(txtPassword.textField.text) + txtPassword.textField.clear() + } + + // https://www.figma.com/file/BTS422M9AkvWjfRrXED3WC/%F0%9F%91%8B-Onboarding%E2%8E%9CDesktop?node-id=6%3A0 + Behavior on opacity { + OpacityAnimator { + from: 0.5 + duration: 200 + } + } + Behavior on anchors.leftMargin { + NumberAnimation { + duration: 200 + } } } @@ -167,9 +183,15 @@ Item { ignoreUnknownSignals: true onLoginResponseChanged: { if (error) { - errMsg.visible = true; - loading = false; - + // SQLITE_NOTADB: "file is not a database" + if (error === "file is not a database") { + errMsg.text = errMsg.incorrectPasswordMsg + } else { + errMsg.text = qsTr("Login failed: %1").arg(error.toUpperCase()) + } + errMsg.visible = true + loading = false + txtPassword.textField.forceActiveFocus() } } } @@ -191,12 +213,13 @@ Item { StyledText { id: errMsg + //% "Login failed. Please re-enter your password and try again." + readonly property string incorrectPasswordMsg: qsTrId("login-failed--please-re-enter-your-password-and-try-again-") anchors.top: generateKeysLinkText.bottom anchors.topMargin: Style.current.smallPadding anchors.horizontalCenter: parent.horizontalCenter visible: false - //% "Login failed. Please re-enter your password and try again." - text: qsTrId("login-failed--please-re-enter-your-password-and-try-again-") + text: incorrectPasswordMsg font.pixelSize: 13 color: Style.current.danger }