summaryrefslogtreecommitdiffstats
path: root/components/kube/qml/Kube.qml
diff options
context:
space:
mode:
Diffstat (limited to 'components/kube/qml/Kube.qml')
-rw-r--r--components/kube/qml/Kube.qml413
1 files changed, 413 insertions, 0 deletions
diff --git a/components/kube/qml/Kube.qml b/components/kube/qml/Kube.qml
new file mode 100644
index 00000000..79b18a2f
--- /dev/null
+++ b/components/kube/qml/Kube.qml
@@ -0,0 +1,413 @@
1/*
2 * Copyright (C) 2017 Michael Bohlender, <michael.bohlender@kdemail.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19
20import QtQuick 2.7
21import QtQuick.Layouts 1.3
22import QtQuick.Window 2.0
23
24import QtQuick.Controls 2.0 as Controls2
25import org.kube.framework 1.0 as Kube
26
27Controls2.ApplicationWindow {
28 id: app
29
30 property int sidebarWidth: Kube.Units.gridUnit + Kube.Units.largeSpacing
31
32 height: Screen.desktopAvailableHeight * 0.8
33 width: Screen.desktopAvailableWidth * 0.8
34 visible: true
35
36 //Application default font
37 font.family: Kube.Font.fontFamily
38
39 //Application context
40 property variant currentFolder
41 onCurrentFolderChanged: {
42 if (!!currentFolder) {
43 Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": currentFolder})
44 }
45 }
46 property variant currentAccount
47 onCurrentAccountChanged: {
48 if (!!currentAccount) {
49 Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": currentAccount})
50 }
51 }
52
53 //accountId -> requiresKeyring
54 Kube.AccountFactory {
55 id: accountFactory
56 accountId: !!app.currentAccount ? app.currentAccount : ""
57 }
58
59 //Interval sync
60 Timer {
61 id: intervalSync
62 //5min
63 interval: 300000
64 running: !!app.currentFolder
65 repeat: true
66 onTriggered: Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": app.currentFolder})
67 }
68
69 Kube.StartupCheck {
70 id: startupCheck
71 }
72
73 //Listener
74 Kube.Listener {
75 filter: Kube.Messages.accountSelection
76 onMessageReceived: app.currentAccount = message.account
77 }
78
79 Kube.Listener {
80 filter: Kube.Messages.folderSelection
81 onMessageReceived: app.currentFolder = message.folder
82 }
83
84 Kube.Listener {
85 filter: Kube.Messages.notification
86 onMessageReceived: {
87 notificationPopup.notify(message.message);
88 }
89 }
90
91 Kube.Listener {
92 filter: Kube.Messages.reply
93 onMessageReceived: {
94 kubeViews.openComposerWithMail(message.mail, false)
95 }
96 }
97
98 Kube.Listener {
99 filter: Kube.Messages.edit
100 onMessageReceived: {
101 kubeViews.openComposerWithMail(message.mail, true)
102 }
103 }
104
105 Kube.Listener {
106 filter: Kube.Messages.compose
107 onMessageReceived: kubeViews.openComposer(true, message.recipients)
108 }
109
110 Kube.Listener {
111 filter: Kube.Messages.requestLogin
112 onMessageReceived: kubeViews.setLoginView()
113 }
114
115 Kube.Listener {
116 filter: Kube.Messages.requestAccountsConfiguration
117 onMessageReceived: kubeViews.setAccountsView()
118 }
119
120 //BEGIN Shortcuts
121 Shortcut {
122 sequence: StandardKey.Quit
123 onActivated: Qt.quit()
124 }
125 Shortcut {
126 onActivated: Kube.Fabric.postMessage(Kube.Messages.search, {})
127 sequence: StandardKey.Find
128 }
129 Shortcut {
130 onActivated: {
131 Kube.Fabric.postMessage(Kube.Messages.unlockKeyring, {accountId: app.currentAccount})
132 }
133 sequence: "Ctrl+l"
134 }
135 Shortcut {
136 id: syncShortcut
137 sequence: StandardKey.Refresh
138 onActivated: !!app.currentFolder ? Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": app.currentFolder}) : Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": app.currentAccount})
139 }
140 //END Shortcuts
141
142 //BEGIN background
143 Rectangle {
144 anchors.fill: parent
145
146 color: Kube.Colors.backgroundColor
147 }
148 //END background
149
150 //BEGIN Main content
151 RowLayout {
152 id: mainContent
153 spacing: 0
154 anchors.fill: parent
155
156 Rectangle {
157 id: sideBar
158
159 anchors {
160 top: mainContent.top
161 bottom: mainContent.bottom
162 }
163 width: app.sidebarWidth
164 color: Kube.Colors.textColor
165
166 Rectangle {
167 anchors.right: parent.right
168 width: 1
169 height: parent.height
170 color: Kube.Colors.viewBackgroundColor
171 opacity: 0.3
172 }
173
174 Controls2.ButtonGroup { id: viewButtonGroup }
175
176 Column {
177 anchors {
178 top: parent.top
179 topMargin: Kube.Units.smallSpacing
180 horizontalCenter: parent.horizontalCenter
181 }
182
183 spacing: Kube.Units.largeSpacing - Kube.Units.smallSpacing
184
185 Kube.IconButton {
186 id: composerButton
187 iconName: Kube.Icons.edit_inverted
188 onClicked: kubeViews.openComposer(false, [])
189 activeFocusOnTab: true
190 checkable: true
191 Controls2.ButtonGroup.group: viewButtonGroup
192 tooltip: qsTr("composer")
193 }
194
195 Kube.IconButton {
196 id: mailButton
197 iconName: Kube.Icons.mail_inverted
198 onClicked: kubeViews.setMailView()
199 activeFocusOnTab: true
200 checkable: true
201 checked: true
202 Controls2.ButtonGroup.group: viewButtonGroup
203 tooltip: qsTr("mails")
204 }
205
206 Kube.IconButton {
207 id: peopleButton
208 iconName: Kube.Icons.user_inverted
209 onClicked: kubeViews.setPeopleView()
210 activeFocusOnTab: true
211 checkable: true
212 Controls2.ButtonGroup.group: viewButtonGroup
213 tooltip: qsTr("people")
214 }
215 }
216 Column {
217 anchors {
218 bottom: parent.bottom
219 bottomMargin: Kube.Units.smallSpacing
220 horizontalCenter: parent.horizontalCenter
221 }
222
223 spacing: Kube.Units.largeSpacing - Kube.Units.smallSpacing
224 Kube.Outbox {
225 height: Kube.Units.gridUnit * 1.5
226 width: height
227
228 Kube.ToolTip {
229 text: qsTr("outbox")
230 visible: parent.hovered
231 }
232 }
233
234 Kube.IconButton {
235 id: logButton
236 iconName: Kube.Icons.info_inverted
237 onClicked: kubeViews.setLogView()
238 activeFocusOnTab: true
239 checkable: true
240 alert: logView.pendingError
241 Controls2.ButtonGroup.group: viewButtonGroup
242 tooltip: qsTr("logview")
243 }
244
245 Kube.IconButton {
246 id: accountsButton
247 iconName: Kube.Icons.menu_inverted
248 onClicked: kubeViews.setAccountsView()
249 activeFocusOnTab: true
250 checkable: true
251 Controls2.ButtonGroup.group: viewButtonGroup
252 tooltip: qsTr("settings")
253 }
254 }
255 }
256 Controls2.StackView {
257 id: kubeViews
258
259 anchors {
260 top: mainContent.top
261 bottom: mainContent.bottom
262 }
263 Layout.fillWidth: true
264
265 function loginIfNecessary()
266 {
267 if (!!app.currentAccount && !Kube.Keyring.isUnlocked(app.currentAccount)) {
268 if (accountFactory.requiresKeyring) {
269 setLoginView()
270 } else {
271 Kube.Keyring.unlock(app.currentAccount)
272 }
273 }
274 }
275
276 Kube.Listener {
277 filter: Kube.Messages.componentDone
278 onMessageReceived: {
279 //Return to the mailview if we try to pop everything off
280 if (kubeViews.depth == 1) {
281 kubeViews.setMailView()
282 } else {
283 kubeViews.pop(Controls2.StackView.Immediate)
284 }
285 kubeViews.loginIfNecessary()
286 }
287 }
288
289 onCurrentItemChanged: {
290 if (currentItem) {
291 currentItem.forceActiveFocus()
292 }
293 }
294
295 Component.onCompleted: {
296 //Setup the initial item stack
297 if (!currentItem) {
298 setMailView()
299 if (startupCheck.noAccount) {
300 setAccountsView()
301 } else {
302 loginIfNecessary()
303 }
304 }
305 }
306
307 ///Replace the current view (we can't go back to the old view, and we destroy the old view)
308 function replaceView(view) {
309 if (currentItem != view) {
310 kubeViews.replace(null, view, {}, Controls2.StackView.Immediate)
311 }
312 }
313
314 ///Push a new view on the stack (the old view remains, and we can go back once done)
315 function pushView(view, properties) {
316 kubeViews.push(view, properties, Controls2.StackView.Immediate)
317 }
318
319 //TODO replacing here while a composer is open is destructive
320 function setPeopleView() {
321 replaceView(peopleView)
322 }
323
324 function setMailView() {
325 replaceView(mailView)
326 }
327
328 function setAccountsView() {
329 pushView(accountsView, {})
330 }
331
332 function setLogView() {
333 replaceView(logView)
334 }
335
336 function setLoginView() {
337 if (currentItem != loginView) {
338 pushView(loginView, {accountId: currentAccount})
339 }
340 }
341
342 function openComposer(newMessage, recipients) {
343 pushView(composerView, {newMessage: newMessage, recipients: recipients})
344 }
345
346 function openComposerWithMail(mail, openAsDraft) {
347 pushView(composerView, {message: mail, loadAsDraft: openAsDraft})
348 }
349
350
351 //These items are not visible until pushed onto the stack, so we keep them in resources instead of items
352 resources: [
353 //Not components so we maintain state
354 MailView {
355 id: mailView
356 anchors.fill: parent
357 Controls2.StackView.onActivated: mailButton.checked = true
358 Controls2.StackView.onDeactivated: mailButton.checked = false
359 },
360 PeopleView {
361 id: peopleView
362 anchors.fill: parent
363 Controls2.StackView.onActivated: peopleButton.checked = true
364 Controls2.StackView.onDeactivated: peopleButton.checked = false
365 },
366 //Not a component because otherwise we can't log stuff
367 LogView {
368 id: logView
369 anchors.fill: parent
370 Controls2.StackView.onActivated: logButton.checked = true
371 Controls2.StackView.onDeactivated: logButton.checked = false
372 }
373 ]
374 //A component so it's always destroyed when we're done
375 Component {
376 id: composerView
377 ComposerView {
378 anchors.fill: parent
379 Controls2.StackView.onActivated: composerButton.checked = true
380 Controls2.StackView.onDeactivated: composerButton.checked = false
381 }
382 }
383 Component {
384 id: accountsView
385 AccountsView {
386 anchors.fill: parent
387 Controls2.StackView.onActivated: accountsButton.checked = true
388 Controls2.StackView.onDeactivated: accountsButton.checked = false
389 }
390 }
391 Component {
392 id: loginView
393 LoginView {
394 anchors.fill: parent
395 }
396 }
397 }
398 }
399 //END Main content
400
401 //BEGIN Notification
402 Kube.NotificationPopup {
403 id: notificationPopup
404
405 anchors {
406 left: parent.left
407 leftMargin: app.sidebarWidth - 3 // so it does not align with the border
408 bottom: parent.bottom
409 bottomMargin: Kube.Units.gridUnit * 4
410 }
411 }
412 //END Notification
413}