2020-06-17 19:18:31 +00:00
import QtQuick 2.13
import QtQuick . Controls 2.13
import QtQuick . Layouts 1.13
2020-05-11 21:24:08 +00:00
import Qt . labs . platform 1.1
2020-06-23 20:49:04 +00:00
import Qt . labs . settings 1.0
2020-07-10 21:47:31 +00:00
import QtQuick . Window 2.12
2020-06-23 20:49:04 +00:00
import QtQml 2.13
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.
2020-09-29 06:18:00 +00:00
import QtQuick . Controls . Universal 2.12
2020-07-12 16:47:46 +00:00
2021-10-27 21:27:49 +00:00
import utils 1.0
import shared 1.0
import shared . panels 1.0
import shared . popups 1.0
2022-03-03 22:50:53 +00:00
import mainui 1.0
2022-03-08 18:49:33 +00:00
import AppLayouts . Onboarding 1.0
2020-05-11 21:24:08 +00:00
2023-04-14 08:18:56 +00:00
import StatusQ 0.1 // Force import StatusQ plugin to load all StatusQ resources
2022-12-12 10:11:10 +00:00
import StatusQ . Core . Theme 0.1
2021-05-19 14:03:14 +00:00
StatusWindow {
2022-01-27 15:29:17 +00:00
property bool appIsReady: false
2020-06-23 20:49:04 +00:00
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.
2020-09-29 06:18:00 +00:00
Universal.theme: Universal . System
2020-05-11 21:24:08 +00:00
id: applicationWindow
2021-08-12 11:52:04 +00:00
objectName: "mainWindow"
2023-03-14 10:59:51 +00:00
minimumWidth: 1200
2022-07-13 22:13:37 +00:00
minimumHeight: 680
2020-07-13 18:45:54 +00:00
color: Style . current . background
2020-06-23 20:49:04 +00:00
title: {
// Set application settings
2022-07-19 12:12:29 +00:00
Qt . application . name = "Status Desktop"
Qt . application . displayName = qsTr ( "Status Desktop" )
2020-06-23 20:49:04 +00:00
Qt . application . organization = "Status"
Qt . application . domain = "status.im"
2022-10-27 11:17:08 +00:00
Qt . application . version = aboutModule . getCurrentVersion ( )
2022-07-19 12:12:29 +00:00
return Qt . application . displayName
2020-06-23 20:49:04 +00:00
}
2020-05-11 21:24:08 +00:00
visible: true
2020-05-18 15:07:30 +00:00
2022-05-16 06:57:51 +00:00
function restoreAppState ( ) {
let geometry = localAppSettings . geometry ;
let visibility = localAppSettings . visibility ;
if ( visibility !== Window . Windowed &&
visibility !== Window . Maximized &&
visibility !== Window . FullScreen ) {
visibility = Window . Windowed ;
}
2022-12-20 19:17:07 +00:00
if ( geometry === undefined ||
// If the monitor setup of the user changed, it's possible that the old geometry now falls out of the monitor range
// In this case, we reset to the basic geometry
geometry . x > Screen . desktopAvailableWidth ||
geometry . y > Screen . desktopAvailableHeight ||
geometry . width > Screen . desktopAvailableWidth ||
geometry . height > Screen . desktopAvailableHeight )
{
2022-05-16 06:57:51 +00:00
let screen = Qt . application . screens [ 0 ] ;
geometry = Qt . rect ( 0 ,
0 ,
Math . min ( Screen . desktopAvailableWidth - 125 , 1400 ) ,
Math . min ( Screen . desktopAvailableHeight - 125 , 840 ) ) ;
geometry . x = ( screen . width - geometry . width ) / 2 ;
geometry . y = ( screen . height - geometry . height ) / 2 ;
}
applicationWindow . visibility = visibility ;
2022-07-19 12:15:00 +00:00
if ( visibility === Window . Windowed ) {
2022-05-16 06:57:51 +00:00
applicationWindow . x = geometry . x ;
applicationWindow . y = geometry . y ;
2023-03-14 10:59:51 +00:00
applicationWindow . width = Math . max ( geometry . width , applicationWindow . minimumWidth )
applicationWindow . height = Math . max ( geometry . height , applicationWindow . minimumHeight )
2022-05-16 06:57:51 +00:00
}
2021-11-26 12:58:15 +00:00
}
2022-05-16 06:57:51 +00:00
function storeAppState ( ) {
if ( ! applicationWindow . appIsReady )
return ;
localAppSettings . visibility = applicationWindow . visibility ;
2022-07-19 12:15:00 +00:00
if ( applicationWindow . visibility === Window . Windowed ) {
2022-05-16 06:57:51 +00:00
localAppSettings . geometry = Qt . rect ( applicationWindow . x , applicationWindow . y ,
applicationWindow . width , applicationWindow . height ) ;
}
2021-11-26 12:58:15 +00:00
}
2022-05-16 06:57:51 +00:00
onXChanged: Qt . callLater ( storeAppState )
onYChanged: Qt . callLater ( storeAppState )
onWidthChanged: Qt . callLater ( storeAppState )
onHeightChanged: Qt . callLater ( storeAppState )
2021-11-26 12:58:15 +00:00
2023-08-02 13:49:28 +00:00
QtObject {
id: d
property int previousApplicationState: - 1
2023-09-25 11:23:25 +00:00
property var mockedKeycardControllerWindow
function runMockedKeycardControllerWindow ( ) {
if ( localAppSettings . testEnvironment ) {
if ( ! ! d . mockedKeycardControllerWindow ) {
d . mockedKeycardControllerWindow . close ( )
}
console . info ( "running mocked keycard lib controller window" )
var c = Qt . createComponent ( "qrc:/imports/shared/panels/MockedKeycardLibControllerWindow.qml" ) ;
if ( c . status === Component . Ready ) {
d . mockedKeycardControllerWindow = c . createObject ( applicationWindow , {
"relatedModule" : startupOnboarding . visible ?
startupModule :
mainModule
} )
if ( d . mockedKeycardControllerWindow ) {
d . mockedKeycardControllerWindow . show ( )
d . mockedKeycardControllerWindow . requestActivate ( )
}
}
}
}
2023-08-02 13:49:28 +00:00
}
2020-11-17 03:07:01 +00:00
Action {
shortcut: StandardKey . FullScreen
onTriggered: {
2022-07-19 12:15:00 +00:00
if ( applicationWindow . visibility === Window . FullScreen ) {
2020-11-17 03:07:01 +00:00
showNormal ( )
} else {
showFullScreen ( )
}
}
}
Action {
shortcut: "Ctrl+M"
onTriggered: {
2022-07-19 12:15:00 +00:00
if ( applicationWindow . visibility === Window . Minimized ) {
2020-11-17 03:07:01 +00:00
showNormal ( )
} else {
showMinimized ( )
}
}
}
2021-09-21 15:29:33 +00:00
2021-01-29 03:00:33 +00:00
Action {
shortcut: "Ctrl+W"
2022-12-09 11:35:29 +00:00
enabled: loader . item && ! ! loader . item . appLayout && loader . item . appLayout . appView ? loader . item . appLayout . appView . currentIndex === Constants . appViewStackIndex . browser
2021-04-20 20:15:16 +00:00
: true
2021-02-22 17:26:24 +00:00
onTriggered: {
applicationWindow . visible = false ;
}
}
Action {
shortcut: "Ctrl+Q"
2021-01-29 03:00:33 +00:00
onTriggered: {
Qt . quit ( )
}
}
2022-12-14 14:40:50 +00:00
//TODO remove direct backend access
2022-11-29 19:18:39 +00:00
Connections {
id: windowsOsNotificationsConnection
2022-12-09 10:17:40 +00:00
enabled: Qt . platform . os === Constants . windows
2022-12-19 21:33:48 +00:00
target: Qt . platform . os === Constants . windows && typeof mainModule !== "undefined" ? mainModule : null
2022-11-29 19:18:39 +00:00
function onDisplayWindowsOsNotification ( title , message ) {
systemTray . showMessage ( title , message )
}
}
2022-12-14 14:40:50 +00:00
//TODO remove direct backend access
2021-10-16 19:03:01 +00:00
Connections {
2021-10-20 09:58:39 +00:00
target: startupModule
2022-01-27 15:29:17 +00:00
2022-07-19 12:15:00 +00:00
function onStartUpUIRaised ( ) {
2022-05-16 06:57:51 +00:00
applicationWindow . appIsReady = true ;
applicationWindow . storeAppState ( ) ;
2023-09-25 11:23:25 +00:00
d . runMockedKeycardControllerWindow ( )
2022-01-27 15:29:17 +00:00
}
2022-07-19 12:15:00 +00:00
function onAppStateChanged ( state ) {
2022-08-05 08:52:29 +00:00
if ( state === Constants . appState . startup ) {
// we're here only in case of error when we're returning from the app loading state
loader . sourceComponent = undefined
2023-05-04 16:18:19 +00:00
appLoadingAnimation . active = false
2022-08-05 08:52:29 +00:00
startupOnboarding . visible = true
}
else if ( state === Constants . appState . appLoading ) {
2023-02-15 08:27:18 +00:00
loader . sourceComponent = undefined
2023-06-13 20:26:55 +00:00
appLoadingAnimation . active = false
2023-02-15 08:27:18 +00:00
appLoadingAnimation . active = true
2022-08-05 08:52:29 +00:00
startupOnboarding . visible = false
2022-08-01 14:39:05 +00:00
}
else if ( state === Constants . appState . main ) {
2022-01-11 23:16:17 +00:00
// We set main module to the Global singleton once user is logged in and we move to the main app.
2023-02-15 08:27:18 +00:00
appLoadingAnimation . active = localAppSettings && localAppSettings . fakeLoadingScreenEnabled
appLoadingAnimation . runningProgressAnimation = localAppSettings && localAppSettings . fakeLoadingScreenEnabled
2022-12-09 19:43:36 +00:00
Global . userProfile = userProfile
2023-02-14 09:20:53 +00:00
Global . appIsReady = true
2022-11-29 19:18:39 +00:00
2022-07-20 12:34:44 +00:00
loader . sourceComponent = app
2022-01-11 23:16:17 +00:00
if ( localAccountSensitiveSettings . recentEmojis === "" ) {
localAccountSensitiveSettings . recentEmojis = [ ] ;
}
if ( localAccountSensitiveSettings . hiddenCommunityWelcomeBanners === "" ) {
localAccountSensitiveSettings . hiddenCommunityWelcomeBanners = [ ] ;
}
if ( localAccountSensitiveSettings . hiddenCommunityBackUpBanners === "" ) {
localAccountSensitiveSettings . hiddenCommunityBackUpBanners = [ ] ;
}
2022-08-05 08:52:29 +00:00
startupOnboarding . unload ( )
startupOnboarding . visible = false
2022-08-30 15:23:21 +00:00
Style . changeTheme ( localAppSettings . theme , systemPalette . isCurrentSystemThemeDark ( ) )
2022-12-12 10:11:10 +00:00
Style . changeFontSize ( localAccountSensitiveSettings . fontSize )
Theme . updateFontSize ( localAccountSensitiveSettings . fontSize )
2023-09-25 11:23:25 +00:00
d . runMockedKeycardControllerWindow ( )
2023-04-02 11:19:38 +00:00
} else if ( state === Constants . appState . appEncryptionProcess ) {
2023-03-29 13:26:11 +00:00
loader . sourceComponent = undefined
appLoadingAnimation . active = true
appLoadingAnimation . item . splashScreenText = qsTr ( "Database re-encryption in progress. Please do NOT close the app.\nThis may take up to 30 minutes. Sorry for the inconvenience.\n\n This process is a one time thing and is necessary for the proper functioning of the application." )
startupOnboarding . visible = false
2021-11-24 13:30:00 +00:00
}
2021-10-16 19:03:01 +00:00
}
}
2021-05-19 14:03:14 +00:00
//! Workaround for custom QQuickWindow
Connections {
2021-06-03 08:29:14 +00:00
target: applicationWindow
2022-07-19 12:15:00 +00:00
function onClosing ( close ) {
2023-03-01 21:36:47 +00:00
if ( Qt . platform . os === Constants . mac ) {
2021-11-17 20:27:19 +00:00
loader . sourceComponent = undefined
close . accepted = true
} else {
2022-03-25 09:54:27 +00:00
if ( loader . sourceComponent != app ) {
2021-11-17 20:27:19 +00:00
Qt . quit ( ) ;
}
else if ( loader . sourceComponent == app ) {
if ( localAccountSensitiveSettings . quitOnClose ) {
Qt . quit ( ) ;
} else {
applicationWindow . visible = false ;
}
}
}
2021-05-19 14:03:14 +00:00
}
2021-01-29 03:00:33 +00:00
}
2021-09-21 15:29:33 +00:00
2023-08-02 13:49:28 +00:00
// On MacOS, explicitely restore the window on activating
Connections {
target: Qt . application
enabled: Qt . platform . os === Constants . mac
function onStateChanged ( ) {
if ( Qt . application . state == d . previousApplicationState
&& Qt . application . state == Qt . ApplicationActive ) {
applicationWindow . visible = true
applicationWindow . showNormal ( )
}
d . previousApplicationState = Qt . application . state
}
}
2022-12-14 14:40:50 +00:00
//TODO remove direct backend access
2021-09-06 13:37:00 +00:00
Connections {
2022-07-04 21:14:13 +00:00
target: singleInstance
2021-09-06 13:37:00 +00:00
2022-07-19 12:15:00 +00:00
function onSecondInstanceDetected ( ) {
2021-09-06 13:37:00 +00:00
console . log ( "User attempted to run the second instance of the application" )
// activating this instance to give user visual feedback
applicationWindow . show ( )
applicationWindow . raise ( )
applicationWindow . requestActivate ( )
}
}
2021-01-29 03:00:33 +00:00
2021-08-12 11:52:04 +00:00
// The easiest way to get current system theme (is it light or dark) without using
// OS native methods is to check lightness (0 - 1.0) of the window color.
// If it's too high (0.85+) means light theme is an active.
SystemPalette {
id: systemPalette
function isCurrentSystemThemeDark ( ) {
return window . hslLightness < 0.85
}
}
function changeThemeFromOutside ( ) {
2022-08-30 15:23:21 +00:00
Style . changeTheme ( startupOnboarding . visible ? Universal.System : localAppSettings . theme ,
systemPalette . isCurrentSystemThemeDark ( ) )
2021-08-12 11:52:04 +00:00
}
2020-07-12 16:47:46 +00:00
Component.onCompleted: {
2021-12-08 21:20:43 +00:00
Global . applicationWindow = this ;
2022-08-30 15:23:21 +00:00
Style . changeTheme ( Universal . System , systemPalette . isCurrentSystemThemeDark ( ) ) ;
2022-02-03 20:42:22 +00:00
2022-05-16 06:57:51 +00:00
restoreAppState ( ) ;
2020-07-12 16:47:46 +00:00
}
2020-06-04 07:38:24 +00:00
signal navigateTo ( string path )
2021-09-21 15:29:33 +00:00
2021-08-18 14:43:59 +00:00
function makeStatusAppActive ( ) {
applicationWindow . show ( )
applicationWindow . raise ( )
applicationWindow . requestActivate ( )
}
2020-05-18 15:07:30 +00:00
SystemTrayIcon {
2020-12-07 17:37:39 +00:00
id: systemTray
2020-05-18 15:07:30 +00:00
visible: true
2021-07-19 16:00:05 +00:00
icon.source: {
2021-07-20 04:12:11 +00:00
if ( production ) {
2023-03-01 21:36:47 +00:00
if ( Qt . platform . os == Constants . mac )
2022-07-13 18:26:59 +00:00
return "imports/assets/icons/status-logo-round-rect.svg"
2021-07-19 16:00:05 +00:00
else
2022-07-13 18:26:59 +00:00
return "imports/assets/icons/status-logo-circle.svg"
2021-07-20 04:12:11 +00:00
} else {
2023-03-01 21:36:47 +00:00
if ( Qt . platform . os == Constants . mac )
2022-07-13 18:26:59 +00:00
return "imports/assets/icons/status-logo-dev-round-rect.svg"
2021-07-19 16:00:05 +00:00
else
2022-07-13 18:26:59 +00:00
return "imports/assets/icons/status-logo-dev-circle.svg"
2021-07-19 16:00:05 +00:00
}
}
2022-11-29 19:18:39 +00:00
onMessageClicked: {
if ( Qt . platform . os === Constants . windows ) {
applicationWindow . makeStatusAppActive ( )
}
}
2021-07-19 12:14:10 +00:00
2020-05-18 15:07:30 +00:00
menu: Menu {
2021-01-29 03:00:33 +00:00
MenuItem {
2022-04-04 11:26:30 +00:00
text: qsTr ( "Open Status" )
2021-01-29 03:00:33 +00:00
onTriggered: {
2021-08-18 14:43:59 +00:00
applicationWindow . makeStatusAppActive ( )
2021-01-29 03:00:33 +00:00
}
}
2021-09-21 15:29:33 +00:00
2021-05-19 14:03:14 +00:00
MenuSeparator {
2021-01-29 03:00:33 +00:00
}
2020-05-18 15:07:30 +00:00
MenuItem {
2022-04-04 11:26:30 +00:00
text: qsTr ( "Quit" )
2020-05-18 15:07:30 +00:00
onTriggered: Qt . quit ( )
}
}
onActivated: {
2021-07-19 12:14:10 +00:00
if ( reason !== SystemTrayIcon . Context ) {
2021-08-18 14:43:59 +00:00
applicationWindow . makeStatusAppActive ( )
2021-04-07 18:33:23 +00:00
}
2020-05-18 15:07:30 +00:00
}
}
2020-06-04 07:38:24 +00:00
Loader {
id: loader
2020-05-18 15:07:30 +00:00
anchors.fill: parent
2022-10-18 09:06:18 +00:00
asynchronous: true
2022-03-03 22:50:53 +00:00
opacity: active ? 1.0 : 0.0
visible: ( opacity > 0.0001 )
Behavior on opacity { NumberAnimation { duration: 120 } }
2020-05-19 13:22:38 +00:00
}
2020-05-18 15:07:30 +00:00
2020-06-04 07:38:24 +00:00
Component {
2020-05-19 13:22:38 +00:00
id: app
2021-12-09 13:28:02 +00:00
AppMain {
sysPalette: systemPalette
2023-06-14 19:06:13 +00:00
visible: ! appLoadingAnimation . active
2021-12-09 13:28:02 +00:00
}
2020-06-04 07:38:24 +00:00
}
2023-02-15 08:27:18 +00:00
Loader {
2022-08-01 14:39:05 +00:00
id: appLoadingAnimation
2023-11-14 08:19:58 +00:00
objectName: "loadingAnimationLoader"
2023-02-15 08:27:18 +00:00
property bool runningProgressAnimation: false
anchors.fill: parent
active: false
sourceComponent: DidYouKnowSplashScreen {
2022-09-29 14:30:25 +00:00
objectName: "splashScreen"
2023-02-15 08:27:18 +00:00
NumberAnimation on progress { from: 0.0 ; to: 1 ; duration: 30000 ; running: runningProgressAnimation }
onProgressChanged: {
if ( progress === 1 ) {
appLoadingAnimation . active = false
}
}
2022-08-01 14:39:05 +00:00
}
}
2022-03-03 22:50:53 +00:00
OnboardingLayout {
2022-07-20 12:34:44 +00:00
id: startupOnboarding
2022-08-22 11:35:58 +00:00
objectName: "startupOnboardingLayout"
2022-07-20 12:34:44 +00:00
anchors.fill: parent
2020-05-11 21:24:08 +00:00
}
2020-07-10 21:47:31 +00:00
2023-03-01 21:36:47 +00:00
MacTrafficLights { // FIXME should be a direct part of StatusAppNavBar
2021-05-19 18:31:18 +00:00
anchors.left: parent . left
anchors.top: parent . top
anchors.margins: 13
2023-03-01 21:36:47 +00:00
visible: Qt . platform . os === Constants . mac && ! applicationWindow . isFullScreen
2021-06-03 08:29:14 +00:00
onClose: {
2022-03-25 09:54:27 +00:00
if ( loader . sourceComponent != app ) {
2023-08-02 13:49:28 +00:00
Qt . quit ( )
return
2021-06-03 08:29:14 +00:00
}
2023-09-25 11:23:25 +00:00
2023-08-02 13:49:28 +00:00
if ( localAccountSensitiveSettings . quitOnClose ) {
Qt . quit ( ) ;
return
2023-09-25 11:23:25 +00:00
}
2023-08-02 13:49:28 +00:00
applicationWindow . visible = false ;
2021-06-03 08:29:14 +00:00
}
onMinimised: {
applicationWindow . showMinimized ( )
}
onMaximized: {
applicationWindow . toggleFullScreen ( )
}
2021-05-19 18:31:18 +00:00
}
2020-05-11 21:24:08 +00:00
}