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.
This commit is contained in:
emizzle 2020-09-29 16:18:00 +10:00 committed by Iuri Matias
parent 7f0720608e
commit c236e01fc8
4 changed files with 67 additions and 14 deletions

View File

@ -42,6 +42,8 @@ QtObject:
proc appearance*(self: ProfileInfoView): int {.slot.} = result = self.appearance proc appearance*(self: ProfileInfoView): int {.slot.} = result = self.appearance
proc setAppearance*(self: ProfileInfoView, appearance: int) {.slot.} = proc setAppearance*(self: ProfileInfoView, appearance: int) {.slot.} =
if self.appearance == appearance:
return
self.appearance = appearance self.appearance = appearance
self.profileChanged() self.profileChanged()
QtProperty[int] appearance: QtProperty[int] appearance:

View File

@ -1,14 +1,33 @@
import QtQuick 2.13 import QtQuick 2.13
import QtQuick.Controls 2.13 import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13 import QtQuick.Layouts 1.13
import QtQuick.Controls.Universal 2.12
import "../../../../imports" import "../../../../imports"
import "../../../../shared" import "../../../../shared"
import "../../../../shared/status"
Item { Item {
id: appearanceContainer id: root
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: 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 { StyledText {
id: title id: title
//% "Appearance setting" //% "Appearance setting"
@ -22,15 +41,6 @@ Item {
} }
RowLayout { RowLayout {
property bool isDarkTheme: {
const isDarkTheme = profileModel.profile.appearance === 1
if (isDarkTheme) {
Style.changeTheme('dark')
} else {
Style.changeTheme('light')
}
return isDarkTheme
}
id: themeSetting id: themeSetting
anchors.top: title.bottom anchors.top: title.bottom
anchors.topMargin: 20 anchors.topMargin: 20
@ -40,10 +50,44 @@ Item {
//% "Theme (Light - Dark)" //% "Theme (Light - Dark)"
text: qsTrId("theme-(light---dark)") text: qsTrId("theme-(light---dark)")
} }
Switch { ButtonGroup { id: appearance }
checked: themeSetting.isDarkTheme
onToggled: function() { StatusRadioButton {
profileModel.changeTheme(themeSetting.isDarkTheme ? 0 : 1) 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)
} }
} }
} }

View File

@ -8,6 +8,7 @@ import Qt.labs.settings 1.0
import QtQuick.Window 2.12 import QtQuick.Window 2.12
import QtQml 2.13 import QtQml 2.13
import QtQuick.Window 2.0 import QtQuick.Window 2.0
import QtQuick.Controls.Universal 2.12
import "./onboarding" import "./onboarding"
import "./app" import "./app"
@ -18,6 +19,8 @@ import "./imports"
ApplicationWindow { ApplicationWindow {
property bool hasAccounts: !!loginModel.rowCount() property bool hasAccounts: !!loginModel.rowCount()
Universal.theme: Universal.System
id: applicationWindow id: applicationWindow
width: 1232 width: 1232
height: 770 height: 770
@ -33,6 +36,9 @@ ApplicationWindow {
visible: true visible: true
Component.onCompleted: { 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); setX(Qt.application.screens[0].width / 2 - width / 2);
setY(Qt.application.screens[0].height / 2 - height / 2); setY(Qt.application.screens[0].height / 2 - height / 2);
} }

View File

@ -30,5 +30,6 @@ RadioButton {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
leftPadding: !!control.text ? control.indicator.width + control.spacing : control.indicator.width leftPadding: !!control.text ? control.indicator.width + control.spacing : control.indicator.width
font.pixelSize: 15 font.pixelSize: 15
font.family: Style.current.fontRegular.name
} }
} }