From c236e01fc8a7c0440910a172689e1b81e64785ea Mon Sep 17 00:00:00 2001 From: emizzle Date: Tue, 29 Sep 2020 16:18:00 +1000 Subject: [PATCH] feat: Support system dark mode theme Supports system dark mode. Changes the user appearance setting to a 3-way setting of System, Light, Dark. New accounts will have their appearance setting set to "System", which uses the system setting to determine if dark mode should be applied. Breaking change: Users who had their settings on Light Theme, will now get the system theme (light or dark). Users who had their theme set to Dark, will now get the Light theme. At startup, the onboarding screens will have the system-level setting of dark mode applied or not. Once, logged in, the user settings will be applied. ## Note An appearance setting of "System" is not dynamic to the system-level setting. This means that if a user has "System" set for their appearance (and ie, the user has light mode set), and then user then changes their system setting from light to dark, the app will not respond until it is restarted. This is due to a limitation of Qt not having a reliable way to propagate these changes to QML. --- src/app/profile/views/profile_info.nim | 2 + .../Profile/Sections/AppearanceContainer.qml | 72 +++++++++++++++---- ui/main.qml | 6 ++ ui/shared/status/StatusRadioButton.qml | 1 + 4 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/app/profile/views/profile_info.nim b/src/app/profile/views/profile_info.nim index 1234cc0184..eda7011fe6 100644 --- a/src/app/profile/views/profile_info.nim +++ b/src/app/profile/views/profile_info.nim @@ -42,6 +42,8 @@ QtObject: proc appearance*(self: ProfileInfoView): int {.slot.} = result = self.appearance proc setAppearance*(self: ProfileInfoView, appearance: int) {.slot.} = + if self.appearance == appearance: + return self.appearance = appearance self.profileChanged() QtProperty[int] appearance: diff --git a/ui/app/AppLayouts/Profile/Sections/AppearanceContainer.qml b/ui/app/AppLayouts/Profile/Sections/AppearanceContainer.qml index 5c736e3862..f3706dcf3d 100644 --- a/ui/app/AppLayouts/Profile/Sections/AppearanceContainer.qml +++ b/ui/app/AppLayouts/Profile/Sections/AppearanceContainer.qml @@ -1,14 +1,33 @@ import QtQuick 2.13 import QtQuick.Controls 2.13 import QtQuick.Layouts 1.13 +import QtQuick.Controls.Universal 2.12 import "../../../../imports" import "../../../../shared" +import "../../../../shared/status" Item { - id: appearanceContainer + id: root Layout.fillHeight: true Layout.fillWidth: true + enum Theme { + System, // 0 + Light, // 1 + Dark // 2 + } + + function updateTheme(theme) { + let themeStr = Universal.theme === Universal.Dark ? "dark" : "light" + if (theme === AppearanceContainer.Theme.Light) { + themeStr = "light" + } else if (theme === AppearanceContainer.Theme.Dark) { + themeStr = "dark" + } + profileModel.changeTheme(theme) + Style.changeTheme(themeStr) + } + StyledText { id: title //% "Appearance setting" @@ -22,15 +41,6 @@ Item { } RowLayout { - property bool isDarkTheme: { - const isDarkTheme = profileModel.profile.appearance === 1 - if (isDarkTheme) { - Style.changeTheme('dark') - } else { - Style.changeTheme('light') - } - return isDarkTheme - } id: themeSetting anchors.top: title.bottom anchors.topMargin: 20 @@ -40,10 +50,44 @@ Item { //% "Theme (Light - Dark)" text: qsTrId("theme-(light---dark)") } - Switch { - checked: themeSetting.isDarkTheme - onToggled: function() { - profileModel.changeTheme(themeSetting.isDarkTheme ? 0 : 1) + ButtonGroup { id: appearance } + + StatusRadioButton { + checked: profileModel.profile.appearance === AppearanceContainer.Theme.System + Layout.alignment: Qt.AlignRight + ButtonGroup.group: appearance + rightPadding: 15 + text: qsTr("System") + onClicked: { + root.updateTheme(AppearanceContainer.Theme.System) + } + } + StatusRadioButton { + checked: profileModel.profile.appearance === AppearanceContainer.Theme.Light + Layout.alignment: Qt.AlignRight + ButtonGroup.group: appearance + rightPadding: 15 + text: qsTr("Light") + onClicked: { + root.updateTheme(AppearanceContainer.Theme.Light) + } + } + StatusRadioButton { + checked: profileModel.profile.appearance === AppearanceContainer.Theme.Dark + Layout.alignment: Qt.AlignRight + ButtonGroup.group: appearance + rightPadding: 0 + text: qsTr("Dark") + onClicked: { + root.updateTheme(AppearanceContainer.Theme.Dark) + } + } + // For the case where the theme was finally loaded by status-go in init(), + // update the theme in qml + Connections { + target: profileModel + onProfileChanged: { + root.updateTheme(profileModel.profile.appearance) } } } diff --git a/ui/main.qml b/ui/main.qml index fa42804620..8b75b329ac 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -8,6 +8,7 @@ import Qt.labs.settings 1.0 import QtQuick.Window 2.12 import QtQml 2.13 import QtQuick.Window 2.0 +import QtQuick.Controls.Universal 2.12 import "./onboarding" import "./app" @@ -18,6 +19,8 @@ import "./imports" ApplicationWindow { property bool hasAccounts: !!loginModel.rowCount() + Universal.theme: Universal.System + id: applicationWindow width: 1232 height: 770 @@ -33,6 +36,9 @@ ApplicationWindow { visible: true Component.onCompleted: { + // Change the theme to the system theme (dark/light) until we get the + // user's saved setting from status-go (after login) + Style.changeTheme(Universal.theme === Universal.Dark ? "dark" : "light") setX(Qt.application.screens[0].width / 2 - width / 2); setY(Qt.application.screens[0].height / 2 - height / 2); } diff --git a/ui/shared/status/StatusRadioButton.qml b/ui/shared/status/StatusRadioButton.qml index 5bb34e69b1..f827870bef 100644 --- a/ui/shared/status/StatusRadioButton.qml +++ b/ui/shared/status/StatusRadioButton.qml @@ -30,5 +30,6 @@ RadioButton { verticalAlignment: Text.AlignVCenter leftPadding: !!control.text ? control.indicator.width + control.spacing : control.indicator.width font.pixelSize: 15 + font.family: Style.current.fontRegular.name } }