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-04 07:38:24 +00:00
|
|
|
import QtQml.StateMachine 1.14 as DSM
|
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
|
2020-07-12 16:47:46 +00:00
|
|
|
import QtQuick.Window 2.0
|
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
|
|
|
|
2020-05-13 02:51:26 +00:00
|
|
|
import "./onboarding"
|
|
|
|
import "./app"
|
2020-07-09 17:02:58 +00:00
|
|
|
import "./sounds"
|
2020-07-10 21:47:31 +00:00
|
|
|
import "./shared"
|
2020-06-19 18:06:58 +00:00
|
|
|
import "./imports"
|
2020-05-11 21:24:08 +00:00
|
|
|
|
|
|
|
ApplicationWindow {
|
2020-07-01 15:37:36 +00:00
|
|
|
property bool hasAccounts: !!loginModel.rowCount()
|
2021-02-18 19:14:31 +00:00
|
|
|
property bool removeMnemonicAfterLogin: false
|
2021-03-10 04:59:01 +00:00
|
|
|
property alias dragAndDrop: dragTarget
|
2021-04-07 13:59:42 +00:00
|
|
|
property bool popupOpened: 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
|
|
|
|
|
2021-04-16 10:37:53 +00:00
|
|
|
Settings {
|
|
|
|
id: globalSettings
|
|
|
|
category: "global"
|
|
|
|
fileName: profileModel.globalSettingsFile
|
|
|
|
property string locale: "en"
|
|
|
|
property int theme: 2
|
|
|
|
}
|
|
|
|
|
2020-05-11 21:24:08 +00:00
|
|
|
id: applicationWindow
|
2021-04-08 15:44:58 +00:00
|
|
|
minimumWidth: 900
|
2020-11-18 14:01:09 +00:00
|
|
|
minimumHeight: 600
|
|
|
|
width: 1232
|
|
|
|
height: 770
|
2020-07-13 18:45:54 +00:00
|
|
|
color: Style.current.background
|
2020-06-23 20:49:04 +00:00
|
|
|
title: {
|
|
|
|
// Set application settings
|
2020-09-04 16:07:11 +00:00
|
|
|
//% "Status Desktop"
|
|
|
|
Qt.application.name = qsTrId("status-desktop")
|
2020-06-23 20:49:04 +00:00
|
|
|
Qt.application.organization = "Status"
|
|
|
|
Qt.application.domain = "status.im"
|
|
|
|
return Qt.application.name
|
|
|
|
}
|
2020-05-11 21:24:08 +00:00
|
|
|
visible: true
|
2020-05-18 15:07:30 +00:00
|
|
|
|
2020-11-17 03:07:01 +00:00
|
|
|
Action {
|
|
|
|
shortcut: StandardKey.FullScreen
|
|
|
|
onTriggered: {
|
|
|
|
if (visibility === Window.FullScreen) {
|
|
|
|
showNormal()
|
|
|
|
} else {
|
|
|
|
showFullScreen()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Action {
|
|
|
|
shortcut: "Ctrl+M"
|
|
|
|
onTriggered: {
|
|
|
|
if (visibility === Window.Minimized) {
|
|
|
|
showNormal()
|
|
|
|
} else {
|
|
|
|
showMinimized()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-22 17:26:24 +00:00
|
|
|
|
2021-01-29 03:00:33 +00:00
|
|
|
Action {
|
|
|
|
shortcut: "Ctrl+W"
|
2021-04-20 20:15:16 +00:00
|
|
|
enabled: loader.item ? loader.item.currentView !== Utils.getAppSectionIndex(Constants.browser)
|
|
|
|
: 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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onClosing: {
|
2021-02-22 22:10:47 +00:00
|
|
|
if(loader.sourceComponent == app){
|
|
|
|
if(loader.item.appSettings.quitOnClose){
|
|
|
|
Qt.quit();
|
|
|
|
} else {
|
|
|
|
applicationWindow.visible = false;
|
|
|
|
close.accepted = false;
|
|
|
|
}
|
|
|
|
}
|
2021-01-29 03:00:33 +00:00
|
|
|
}
|
|
|
|
|
2020-07-12 16:47:46 +00:00
|
|
|
Component.onCompleted: {
|
2021-04-16 10:37:53 +00:00
|
|
|
Style.changeTheme(globalSettings.theme)
|
2020-07-14 16:20:08 +00:00
|
|
|
setX(Qt.application.screens[0].width / 2 - width / 2);
|
|
|
|
setY(Qt.application.screens[0].height / 2 - height / 2);
|
2020-07-12 16:47:46 +00:00
|
|
|
}
|
|
|
|
|
2020-06-04 07:38:24 +00:00
|
|
|
signal navigateTo(string path)
|
2021-02-18 19:14:31 +00:00
|
|
|
|
2021-02-15 16:29:16 +00:00
|
|
|
property bool currentlyHasANotification: false
|
|
|
|
|
|
|
|
onActiveChanged: {
|
|
|
|
if (active && currentlyHasANotification) {
|
|
|
|
currentlyHasANotification = false
|
|
|
|
// QML doesn't have a function to hide notifications, but this does the trick
|
|
|
|
systemTray.hide()
|
|
|
|
systemTray.show()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-02-10 10:55:57 +00:00
|
|
|
icon.source: applicationWindow.Universal.theme === Universal.Dark ?
|
|
|
|
"shared/img/status-logo.svg" :
|
|
|
|
"shared/img/status-logo-light-theme.svg";
|
2020-05-18 15:07:30 +00:00
|
|
|
menu: Menu {
|
2021-01-29 03:00:33 +00:00
|
|
|
MenuItem {
|
|
|
|
visible: !applicationWindow.visible
|
|
|
|
text: qsTr("Open Status")
|
|
|
|
onTriggered: {
|
|
|
|
applicationWindow.visible = true;
|
|
|
|
applicationWindow.requestActivate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MenuSeparator {
|
|
|
|
visible: !applicationWindow.visible
|
|
|
|
}
|
|
|
|
|
2020-05-18 15:07:30 +00:00
|
|
|
MenuItem {
|
2020-07-06 20:39:55 +00:00
|
|
|
//% "Quit"
|
|
|
|
text: qsTrId("quit")
|
2020-05-18 15:07:30 +00:00
|
|
|
onTriggered: Qt.quit()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onActivated: {
|
2021-04-07 18:33:23 +00:00
|
|
|
if (reason === SystemTrayIcon.Context) {
|
|
|
|
return
|
|
|
|
}
|
2020-05-18 15:07:30 +00:00
|
|
|
applicationWindow.show()
|
|
|
|
applicationWindow.raise()
|
|
|
|
applicationWindow.requestActivate()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-04 07:38:24 +00:00
|
|
|
DSM.StateMachine {
|
|
|
|
id: stateMachine
|
|
|
|
initialState: onboardingState
|
|
|
|
running: true
|
|
|
|
|
|
|
|
DSM.State {
|
|
|
|
id: onboardingState
|
2021-01-06 13:11:26 +00:00
|
|
|
initialState: hasAccounts ? stateLogin : keysMainState
|
2020-06-04 07:38:24 +00:00
|
|
|
|
|
|
|
DSM.State {
|
|
|
|
id: stateIntro
|
|
|
|
onEntered: loader.sourceComponent = intro
|
|
|
|
}
|
|
|
|
|
|
|
|
DSM.State {
|
|
|
|
id: keysMainState
|
|
|
|
onEntered: loader.sourceComponent = keysMain
|
|
|
|
|
|
|
|
DSM.SignalTransition {
|
|
|
|
targetState: genKeyState
|
|
|
|
signal: applicationWindow.navigateTo
|
|
|
|
guard: path === "GenKey"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DSM.State {
|
|
|
|
id: existingKeyState
|
|
|
|
onEntered: loader.sourceComponent = existingKey
|
|
|
|
|
|
|
|
DSM.SignalTransition {
|
|
|
|
targetState: appState
|
|
|
|
signal: onboardingModel.loginResponseChanged
|
|
|
|
guard: !error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DSM.State {
|
|
|
|
id: genKeyState
|
|
|
|
onEntered: loader.sourceComponent = genKey
|
|
|
|
|
|
|
|
DSM.SignalTransition {
|
|
|
|
targetState: appState
|
|
|
|
signal: onboardingModel.loginResponseChanged
|
|
|
|
guard: !error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DSM.State {
|
|
|
|
id: stateLogin
|
|
|
|
onEntered: loader.sourceComponent = login
|
|
|
|
|
|
|
|
DSM.SignalTransition {
|
|
|
|
targetState: appState
|
|
|
|
signal: loginModel.loginResponseChanged
|
|
|
|
guard: !error
|
|
|
|
}
|
|
|
|
|
|
|
|
DSM.SignalTransition {
|
|
|
|
targetState: genKeyState
|
|
|
|
signal: applicationWindow.navigateTo
|
|
|
|
guard: path === "GenKey"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-12 20:47:44 +00:00
|
|
|
DSM.SignalTransition {
|
2020-07-01 15:37:36 +00:00
|
|
|
targetState: hasAccounts ? stateLogin : stateIntro
|
2020-06-12 20:47:44 +00:00
|
|
|
signal: applicationWindow.navigateTo
|
|
|
|
guard: path === "InitialState"
|
|
|
|
}
|
|
|
|
|
|
|
|
DSM.SignalTransition {
|
|
|
|
targetState: existingKeyState
|
|
|
|
signal: applicationWindow.navigateTo
|
|
|
|
guard: path === "ExistingKey"
|
|
|
|
}
|
|
|
|
|
2020-07-01 15:37:36 +00:00
|
|
|
DSM.SignalTransition {
|
|
|
|
targetState: keysMainState
|
|
|
|
signal: applicationWindow.navigateTo
|
|
|
|
guard: path === "KeysMain"
|
|
|
|
}
|
|
|
|
|
2020-06-04 07:38:24 +00:00
|
|
|
DSM.FinalState {
|
|
|
|
id: onboardingDoneState
|
|
|
|
}
|
|
|
|
}
|
2020-09-22 15:12:48 +00:00
|
|
|
|
2020-06-04 07:38:24 +00:00
|
|
|
DSM.State {
|
|
|
|
id: appState
|
|
|
|
onEntered: loader.sourceComponent = app
|
|
|
|
|
|
|
|
DSM.SignalTransition {
|
|
|
|
targetState: stateLogin
|
|
|
|
signal: loginModel.onLoggedOut
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Loader {
|
|
|
|
id: loader
|
2020-05-18 15:07:30 +00:00
|
|
|
anchors.fill: parent
|
2021-02-22 22:10:47 +00:00
|
|
|
property var appSettings
|
2020-05-19 13:22:38 +00:00
|
|
|
}
|
2020-05-18 15:07:30 +00:00
|
|
|
|
2021-03-10 04:59:01 +00:00
|
|
|
DropArea {
|
|
|
|
id: dragTarget
|
|
|
|
|
|
|
|
signal droppedOnValidScreen(var drop)
|
|
|
|
property alias droppedUrls: rptDraggedPreviews.model
|
|
|
|
readonly property int chatView: Utils.getAppSectionIndex(Constants.chat)
|
|
|
|
readonly property int timelineView: Utils.getAppSectionIndex(Constants.timeline)
|
|
|
|
property bool enabled: containsDrag && loader.item &&
|
|
|
|
(
|
|
|
|
// in chat view
|
|
|
|
(loader.item.currentView === chatView &&
|
|
|
|
(
|
|
|
|
// in a one-to-one chat
|
|
|
|
chatsModel.activeChannel.chatType === Constants.chatTypeOneToOne ||
|
|
|
|
// in a private group chat
|
|
|
|
chatsModel.activeChannel.chatType === Constants.chatTypePrivateGroupChat
|
|
|
|
)
|
|
|
|
) ||
|
|
|
|
// in timeline view
|
|
|
|
loader.item.currentView === timelineView
|
|
|
|
)
|
|
|
|
|
|
|
|
width: applicationWindow.width
|
|
|
|
height: applicationWindow.height
|
|
|
|
|
|
|
|
function cleanup() {
|
|
|
|
rptDraggedPreviews.model = []
|
|
|
|
}
|
|
|
|
|
|
|
|
onDropped: (drop) => {
|
|
|
|
if (enabled) {
|
|
|
|
droppedOnValidScreen(drop)
|
|
|
|
}
|
|
|
|
cleanup()
|
|
|
|
}
|
|
|
|
onEntered: {
|
|
|
|
// needed because drag.urls is not a normal js array
|
|
|
|
rptDraggedPreviews.model = drag.urls.filter(img => Utils.hasDragNDropImageExtension(img))
|
|
|
|
}
|
|
|
|
onPositionChanged: {
|
|
|
|
rptDraggedPreviews.x = drag.x
|
|
|
|
rptDraggedPreviews.y = drag.y
|
|
|
|
}
|
|
|
|
onExited: cleanup()
|
|
|
|
Rectangle {
|
|
|
|
id: dropRectangle
|
|
|
|
|
|
|
|
width: parent.width
|
|
|
|
height: parent.height
|
|
|
|
color: Style.current.transparent
|
|
|
|
opacity: 0.8
|
|
|
|
|
|
|
|
states: [
|
|
|
|
State {
|
|
|
|
when: dragTarget.enabled
|
|
|
|
PropertyChanges {
|
|
|
|
target: dropRectangle
|
|
|
|
color: Style.current.background
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
Repeater {
|
|
|
|
id: rptDraggedPreviews
|
|
|
|
|
|
|
|
Image {
|
|
|
|
source: modelData
|
|
|
|
width: 80
|
|
|
|
height: 80
|
|
|
|
sourceSize.width: 160
|
|
|
|
sourceSize.height: 160
|
|
|
|
fillMode: Image.PreserveAspectFit
|
|
|
|
x: index * 10 + rptDraggedPreviews.x
|
|
|
|
y: index * 10 + rptDraggedPreviews.y
|
|
|
|
z: 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-04 07:38:24 +00:00
|
|
|
Component {
|
2020-05-19 13:22:38 +00:00
|
|
|
id: app
|
2020-09-15 19:47:13 +00:00
|
|
|
AppMain {}
|
2020-06-04 07:38:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: intro
|
|
|
|
Intro {
|
|
|
|
btnGetStarted.onClicked: applicationWindow.navigateTo("KeysMain")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: keysMain
|
|
|
|
KeysMain {
|
|
|
|
btnGenKey.onClicked: applicationWindow.navigateTo("GenKey")
|
|
|
|
btnExistingKey.onClicked: applicationWindow.navigateTo("ExistingKey")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: existingKey
|
2020-06-12 20:47:44 +00:00
|
|
|
ExistingKey {
|
|
|
|
onClosed: function () {
|
2021-02-18 19:14:31 +00:00
|
|
|
removeMnemonicAfterLogin = false
|
2020-07-01 15:37:36 +00:00
|
|
|
if (hasAccounts) {
|
|
|
|
applicationWindow.navigateTo("InitialState")
|
|
|
|
} else {
|
|
|
|
applicationWindow.navigateTo("KeysMain")
|
|
|
|
}
|
2020-06-12 20:47:44 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-04 07:38:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: genKey
|
|
|
|
GenKey {
|
2020-06-13 15:17:54 +00:00
|
|
|
onClosed: function () {
|
2020-07-01 15:37:36 +00:00
|
|
|
if (hasAccounts) {
|
|
|
|
applicationWindow.navigateTo("InitialState")
|
|
|
|
} else {
|
|
|
|
applicationWindow.navigateTo("KeysMain")
|
|
|
|
}
|
2020-06-13 15:17:54 +00:00
|
|
|
}
|
2020-06-04 07:38:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: login
|
|
|
|
Login {
|
2020-06-12 20:47:44 +00:00
|
|
|
onGenKeyClicked: function () {
|
|
|
|
applicationWindow.navigateTo("GenKey")
|
|
|
|
}
|
|
|
|
onExistingKeyClicked: function () {
|
|
|
|
applicationWindow.navigateTo("ExistingKey")
|
|
|
|
}
|
2020-06-04 07:38:24 +00:00
|
|
|
}
|
2020-05-11 21:24:08 +00:00
|
|
|
}
|
2020-07-10 21:47:31 +00:00
|
|
|
|
|
|
|
NotificationWindow {
|
|
|
|
id: notificationWindow
|
|
|
|
}
|
2020-05-11 21:24:08 +00:00
|
|
|
}
|
2020-07-01 17:35:57 +00:00
|
|
|
|
|
|
|
/*##^##
|
|
|
|
Designer {
|
|
|
|
D{i:0;formeditorZoom:0.5}
|
|
|
|
}
|
|
|
|
##^##*/
|