Merge lp:~mardy/webbrowser-app/multi-account-no-ui into lp:webbrowser-app
- multi-account-no-ui
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~mardy/webbrowser-app/multi-account-no-ui |
Merge into: | lp:webbrowser-app |
Diff against target: |
1344 lines (+809/-244) 16 files modified
src/app/webcontainer/AccountChooserDialog.qml (+129/-0) src/app/webcontainer/AccountItem.qml (+4/-6) src/app/webcontainer/AccountsLoginPage.qml (+54/-137) src/app/webcontainer/AccountsModel.qml (+0/-51) src/app/webcontainer/AccountsPage.qml (+173/-10) src/app/webcontainer/CMakeLists.txt (+1/-1) src/app/webcontainer/LoggingInSheet.qml (+39/-0) src/app/webcontainer/LogoutDetector.qml (+78/-0) src/app/webcontainer/LogoutErrorSheet.qml (+64/-0) src/app/webcontainer/SplashScreen.qml (+105/-0) src/app/webcontainer/WebApp.qml (+2/-0) src/app/webcontainer/cookie-store.cpp (+1/-0) src/app/webcontainer/logout-detector.js (+41/-0) src/app/webcontainer/webapp-container.cpp (+24/-0) src/app/webcontainer/webapp-container.h (+3/-0) src/app/webcontainer/webapp-container.qml (+91/-39) |
To merge this branch: | bzr merge lp:~mardy/webbrowser-app/multi-account-no-ui |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
system-apps-ci-bot | continuous-integration | Needs Fixing | |
PS Jenkins bot | continuous-integration | Needs Fixing | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+255946@code.launchpad.net |
Commit message
Detection of logout events
Description of the change
Detection of logout events
This can be tested with Twitter: its .desktop file needs to be modified so that the Exec line becomes (remove any newlines!):
Exec=webapp-
--name=Twitter --icon=
PS Jenkins bot (ps-jenkins) wrote : | # |
- 974. By Alberto Mardegan
-
Remove multi-account leftovers
- 975. By Alberto Mardegan
-
From trunk
[ Alexandre Abreu ]
* remove qtwebkit deps (LP: #1362640) (LP: #1362640)
[ CI Train Bot ]
* New rebuild forced.
[ Justin McPherson ]
* Command line options for media-hub use through Oxide.
[ Olivier Tilloy ]
* Update translation template.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:975
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 976. By Alberto Mardegan
-
Add missing import
- 977. By Alberto Mardegan
-
Remove count of login attempts
We cannot count it reliably anyway.
- 978. By Alberto Mardegan
-
Reset the webview on logout detected
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:976
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:978
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 979. By Alberto Mardegan
-
UI changes
- 980. By Alberto Mardegan
-
Fixes
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:979
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 981. By Alberto Mardegan
-
UI updates
- 982. By Alberto Mardegan
-
alignment
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:981
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:982
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:982
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unmerged revisions
- 982. By Alberto Mardegan
-
alignment
- 981. By Alberto Mardegan
-
UI updates
- 980. By Alberto Mardegan
-
Fixes
- 979. By Alberto Mardegan
-
UI changes
- 978. By Alberto Mardegan
-
Reset the webview on logout detected
- 977. By Alberto Mardegan
-
Remove count of login attempts
We cannot count it reliably anyway.
- 976. By Alberto Mardegan
-
Add missing import
- 975. By Alberto Mardegan
-
From trunk
[ Alexandre Abreu ]
* remove qtwebkit deps (LP: #1362640) (LP: #1362640)
[ CI Train Bot ]
* New rebuild forced.
[ Justin McPherson ]
* Command line options for media-hub use through Oxide.
[ Olivier Tilloy ]
* Update translation template. - 974. By Alberto Mardegan
-
Remove multi-account leftovers
- 973. By Alberto Mardegan
-
Automatic re-login
Preview Diff
1 | === added file 'src/app/webcontainer/AccountChooserDialog.qml' |
2 | --- src/app/webcontainer/AccountChooserDialog.qml 1970-01-01 00:00:00 +0000 |
3 | +++ src/app/webcontainer/AccountChooserDialog.qml 2015-04-16 14:53:15 +0000 |
4 | @@ -0,0 +1,129 @@ |
5 | +/* |
6 | + * Copyright 2013-2014 Canonical Ltd. |
7 | + * |
8 | + * This file is part of webbrowser-app. |
9 | + * |
10 | + * webbrowser-app is free software; you can redistribute it and/or modify |
11 | + * it under the terms of the GNU General Public License as published by |
12 | + * the Free Software Foundation; version 3. |
13 | + * |
14 | + * webbrowser-app is distributed in the hope that it will be useful, |
15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | + * GNU General Public License for more details. |
18 | + * |
19 | + * You should have received a copy of the GNU General Public License |
20 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | + */ |
22 | + |
23 | +import QtQuick 2.0 |
24 | +import Qt.labs.settings 1.0 |
25 | +import Ubuntu.Components 1.1 |
26 | +import Ubuntu.Components.ListItems 1.0 as ListItem |
27 | +import Ubuntu.Components.Popups 1.0 |
28 | +import Ubuntu.OnlineAccounts 0.1 |
29 | +import Ubuntu.OnlineAccounts.Client 0.1 |
30 | + |
31 | +Dialog { |
32 | + id: root |
33 | + |
34 | + property string providerId: "" |
35 | + property string applicationId: "" |
36 | + property bool accountMandatory: true |
37 | + property var accountsModel: null |
38 | + |
39 | + signal accountSelected(int accountId) |
40 | + signal cancel() |
41 | + |
42 | + property var __selectedAccount: settings.selectedAccount |
43 | + |
44 | + Settings { |
45 | + id: settings |
46 | + property int selectedAccount |
47 | + } |
48 | + |
49 | + Setup { |
50 | + id: setup |
51 | + applicationId: root.applicationId |
52 | + providerId: root.providerId |
53 | + onFinished: { |
54 | + if ("accountId" in reply) { |
55 | + root.chooseAccount(reply.accountId) |
56 | + } else { |
57 | + root.cancel() |
58 | + } |
59 | + } |
60 | + } |
61 | + |
62 | + Repeater { |
63 | + model: accountsModel |
64 | + AccountItem { |
65 | + providerName: model.providerName |
66 | + accountName: model.displayName |
67 | + selected: model.accountId === root.__selectedAccount |
68 | + onClicked: root.__selectedAccount = model.accountId |
69 | + } |
70 | + } |
71 | + |
72 | + ListItem.Standard { |
73 | + id: addAccountButton |
74 | + text: i18n.tr("Add account") |
75 | + iconName: "add" |
76 | + selected: root.__selectedAccount === -1 |
77 | + onClicked: root.__selectedAccount = -1 |
78 | + } |
79 | + |
80 | + ListItem.Standard { |
81 | + id: skipButton |
82 | + visible: !root.accountMandatory |
83 | + text: i18n.tr("Don't use an account") |
84 | + selected: root.__selectedAccount === -2 |
85 | + onClicked: root.__selectedAccount = -2 |
86 | + } |
87 | + |
88 | + Item { |
89 | + anchors.left: parent.left |
90 | + anchors.right: parent.right |
91 | + anchors.margins: units.gu(1) |
92 | + height: childrenRect.height + units.gu(1) |
93 | + |
94 | + Button { |
95 | + id: cancelButton |
96 | + anchors.left: parent.left |
97 | + width: parent.width / 2 - units.gu(1) |
98 | + text: i18n.tr("Cancel") |
99 | + onClicked: root.cancel() |
100 | + } |
101 | + |
102 | + Button { |
103 | + anchors.right: parent.right |
104 | + width: cancelButton.width |
105 | + text: i18n.tr("OK") |
106 | + onClicked: root.onConfirmed() |
107 | + } |
108 | + } |
109 | + |
110 | + function chooseAccount(accountId) { |
111 | + for (var i = 0; i < accountsModel.count; i++) { |
112 | + if (accountsModel.get(i, "accountId") === accountId) { |
113 | + settings.selectedAccount = accountId |
114 | + root.accountSelected(accountId) |
115 | + return |
116 | + } |
117 | + } |
118 | + |
119 | + // The selected account was not found |
120 | + settings.selectedAccount = -1 |
121 | + root.cancel() |
122 | + } |
123 | + |
124 | + function onConfirmed() { |
125 | + if (__selectedAccount === -2) { |
126 | + root.selectedAccount(0) |
127 | + } else if (__selectedAccount === -1) { |
128 | + setup.exec() |
129 | + } else { |
130 | + chooseAccount(__selectedAccount) |
131 | + } |
132 | + } |
133 | +} |
134 | |
135 | === renamed file 'src/app/webcontainer/AccountItemView.qml' => 'src/app/webcontainer/AccountItem.qml' |
136 | --- src/app/webcontainer/AccountItemView.qml 2014-07-29 21:51:07 +0000 |
137 | +++ src/app/webcontainer/AccountItem.qml 2015-04-16 14:53:15 +0000 |
138 | @@ -20,14 +20,12 @@ |
139 | import Ubuntu.Components 1.1 |
140 | import Ubuntu.Components.ListItems 1.0 as ListItem |
141 | |
142 | -ListItem.Standard { |
143 | +ListItem.Subtitled { |
144 | id: root |
145 | |
146 | + property string providerName |
147 | property string accountName |
148 | |
149 | - text: accountName |
150 | - |
151 | - iconSource: Qt.resolvedUrl("/usr/share/icons/ubuntu-mobile/actions/scalable/contact.svg") |
152 | + text: providerName |
153 | + subText: accountName |
154 | } |
155 | - |
156 | - |
157 | |
158 | === modified file 'src/app/webcontainer/AccountsLoginPage.qml' |
159 | --- src/app/webcontainer/AccountsLoginPage.qml 2014-10-06 12:52:34 +0000 |
160 | +++ src/app/webcontainer/AccountsLoginPage.qml 2015-04-16 14:53:15 +0000 |
161 | @@ -17,18 +17,19 @@ |
162 | */ |
163 | |
164 | import QtQuick 2.0 |
165 | +import Qt.labs.settings 1.0 |
166 | import Ubuntu.Components 1.1 |
167 | import Ubuntu.Components.ListItems 1.0 as ListItem |
168 | import Ubuntu.OnlineAccounts 0.1 |
169 | - |
170 | +import Ubuntu.OnlineAccounts.Client 0.1 |
171 | |
172 | Item { |
173 | id: root |
174 | |
175 | - property string accountProvider: "" |
176 | - property string applicationName: "" |
177 | + property var accountsModel |
178 | |
179 | - signal done(variant credentialsId) |
180 | + signal accountSelected(int accountId) |
181 | + signal done(bool successful) |
182 | |
183 | Timer { |
184 | id: checkTimer |
185 | @@ -38,14 +39,21 @@ |
186 | interval: 100 |
187 | } |
188 | |
189 | - AccountsModel { |
190 | - id: accountsModel |
191 | - accountProvider: root.accountProvider |
192 | - applicationName: root.applicationName |
193 | - onCountChanged: checkAccounts() |
194 | + Settings { |
195 | + id: settings |
196 | + property int selectedAccount: -1 |
197 | + } |
198 | + |
199 | + Setup { |
200 | + id: setup |
201 | + applicationId: accountsModel.applicationId |
202 | + providerId: accountsModel.provider |
203 | onFinished: { |
204 | - if (count === 0) { |
205 | - Qt.quit(); |
206 | + if ("accountId" in reply) { |
207 | + settings.selectedAccount = reply.accountId |
208 | + root.accountSelected(reply.accountId) |
209 | + } else { |
210 | + Qt.quit() |
211 | } |
212 | } |
213 | } |
214 | @@ -64,137 +72,46 @@ |
215 | checkTimer.stop() |
216 | console.log("Accounts: " + accountsModel.count) |
217 | if (accountsModel.count === 0) { |
218 | - accountsModel.createNewAccount() |
219 | - } else { |
220 | - doLogin(accountsModel.model.get(0, "accountServiceHandle")) |
221 | - } |
222 | - |
223 | - // Note: Disable the account selection for now until we have a clearer view of |
224 | - // the design and behavior related to the feature. Keep the code for reference. |
225 | - /* |
226 | - if (accountsModel.count === 1) { |
227 | - doLogin(accountsModel.model.get(0, "accountServiceHandle")) |
228 | - } else { |
229 | - accountsViewLoader.sourceComponent = accountsSelectionViewComponent |
230 | - } |
231 | - */ |
232 | - } |
233 | - |
234 | - Component { |
235 | - id: accountsAdditionToolbarViewComponent |
236 | - Item { |
237 | - id: addAccountView |
238 | - |
239 | - Label { |
240 | - id: label |
241 | - anchors.centerIn: parent |
242 | - text: i18n.tr("No local account found for ") + root.accountProvider + "." |
243 | - } |
244 | - |
245 | - Label { |
246 | - id: skipLabel |
247 | - text: i18n.tr("Skip account creation step") |
248 | - color: UbuntuColors.orange |
249 | - fontSize: "small" |
250 | - |
251 | - anchors.top: label.bottom |
252 | - anchors.horizontalCenter: parent.horizontalCenter |
253 | - |
254 | - Icon { |
255 | - anchors.left: parent.right |
256 | - anchors.verticalCenter: parent.verticalCenter |
257 | - height: units.dp(12) |
258 | - width: units.dp(12) |
259 | - name: "chevron" |
260 | - color: UbuntuColors.orange |
261 | - } |
262 | - |
263 | - MouseArea { |
264 | - anchors.fill: parent |
265 | - anchors.margins: -units.gu(5) |
266 | - onClicked: root.done(null) |
267 | - } |
268 | - } |
269 | - |
270 | - Panel { |
271 | - id: panel |
272 | - anchors { |
273 | - right: parent.right |
274 | - left: parent.left |
275 | - bottom: parent.bottom |
276 | - } |
277 | - |
278 | - locked: true |
279 | - |
280 | - height: units.gu(8) |
281 | - |
282 | - Rectangle { |
283 | - color: Theme.palette.normal.overlay |
284 | - anchors.fill: parent |
285 | - Item { |
286 | - height: units.gu(8) |
287 | - width: units.gu(8) |
288 | - |
289 | - anchors { |
290 | - right: parent.right |
291 | - bottom: parent.bottom |
292 | - } |
293 | - |
294 | - ToolbarButton { |
295 | - action: Action { |
296 | - text: i18n.tr("Add account") |
297 | - iconSource: Qt.resolvedUrl("/usr/share/icons/ubuntu-mobile/actions/scalable/add.svg") |
298 | - onTriggered: { |
299 | - accountsModel.createNewAccount(); |
300 | - } |
301 | - } |
302 | - } |
303 | - |
304 | - signal clicked() |
305 | - onClicked: { |
306 | - accountsModel.createNewAccount(); |
307 | - } |
308 | - } |
309 | - } |
310 | - |
311 | - Component.onCompleted: panel.open() |
312 | - } |
313 | - |
314 | - } |
315 | - } |
316 | - |
317 | - Component { |
318 | - id: accountsSelectionViewComponent |
319 | - AccountsView { |
320 | - id: accountsView |
321 | - |
322 | - model: accountsModel.model |
323 | - |
324 | - onAccountSelected: doLogin(accountServiceHandle) |
325 | - } |
326 | - } |
327 | - |
328 | - function doLogin(accountHandle) { |
329 | - var account = accountComponent.createObject(root, {objectHandle: accountHandle}); |
330 | + setup.exec(); |
331 | + } else if (settings.selectedAccount > 0) { |
332 | + // check that the account exists |
333 | + for (var i = 0; i < accountsModel.count; i++) { |
334 | + if (accountsModel.get(i, "accountId") === settings.selectedAccount) { |
335 | + break; |
336 | + } |
337 | + } |
338 | + if (i >= accountsModel.count) { |
339 | + // The selected account was not found, pick the first account |
340 | + settings.selectedAccount = accountsModel.get(0, "accountId") |
341 | + } |
342 | + } |
343 | + |
344 | + root.accountSelected(settings.selectedAccount) |
345 | + } |
346 | + |
347 | + function login(account, forceCookieRefresh) { |
348 | + console.log("Preparing for login, forced = " + forceCookieRefresh) |
349 | |
350 | function authenticatedCallback() { |
351 | - account.authenticated.disconnect(authenticatedCallback); |
352 | - done(account.authData.credentialsId); |
353 | + console.log("Authenticated!") |
354 | + account.authenticated.disconnect(authenticatedCallback) |
355 | + root.done(true) |
356 | } |
357 | - account.authenticated.connect(authenticatedCallback); |
358 | + account.authenticated.connect(authenticatedCallback) |
359 | |
360 | function errorCallback() { |
361 | - account.authenticationError.disconnect(errorCallback); |
362 | - done(null); |
363 | - } |
364 | - account.authenticationError.connect(errorCallback); |
365 | - |
366 | - account.authenticate(null); |
367 | - } |
368 | - |
369 | - Component { |
370 | - id: accountComponent |
371 | - AccountService { } |
372 | + console.log("Authentication error!") |
373 | + account.authenticationError.disconnect(errorCallback) |
374 | + root.done(false) |
375 | + } |
376 | + account.authenticationError.connect(errorCallback) |
377 | + |
378 | + var params = {} |
379 | + if (forceCookieRefresh) { |
380 | + params["UiPolicy"] = 1 // RequestPasswordPolicy |
381 | + } |
382 | + |
383 | + account.authenticate(params) |
384 | } |
385 | } |
386 | |
387 | |
388 | === removed file 'src/app/webcontainer/AccountsModel.qml' |
389 | --- src/app/webcontainer/AccountsModel.qml 2014-10-02 07:30:06 +0000 |
390 | +++ src/app/webcontainer/AccountsModel.qml 1970-01-01 00:00:00 +0000 |
391 | @@ -1,51 +0,0 @@ |
392 | -/* |
393 | - * Copyright 2013 Canonical Ltd. |
394 | - * |
395 | - * This file is part of webbrowser-app. |
396 | - * |
397 | - * webbrowser-app is free software; you can redistribute it and/or modify |
398 | - * it under the terms of the GNU General Public License as published by |
399 | - * the Free Software Foundation; version 3. |
400 | - * |
401 | - * webbrowser-app is distributed in the hope that it will be useful, |
402 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
403 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
404 | - * GNU General Public License for more details. |
405 | - * |
406 | - * You should have received a copy of the GNU General Public License |
407 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
408 | - */ |
409 | - |
410 | -import QtQuick 2.0 |
411 | -import Ubuntu.OnlineAccounts 0.1 |
412 | -import Ubuntu.OnlineAccounts.Client 0.1 |
413 | - |
414 | -Item { |
415 | - id: root |
416 | - property string accountProvider: "" |
417 | - property string applicationName: "" |
418 | - property alias count: accountsModel.count |
419 | - |
420 | - signal finished |
421 | - |
422 | - function createNewAccount() { |
423 | - setup.exec(); |
424 | - } |
425 | - |
426 | - readonly property alias model: accountsModel |
427 | - |
428 | - AccountServiceModel { |
429 | - id: accountsModel |
430 | - includeDisabled: false |
431 | - serviceType: "webapps" |
432 | - applicationId: root.applicationName |
433 | - provider: root.accountProvider |
434 | - } |
435 | - |
436 | - Setup { |
437 | - id: setup |
438 | - applicationId: root.applicationName |
439 | - providerId: root.accountProvider |
440 | - onFinished: root.finished() |
441 | - } |
442 | -} |
443 | |
444 | === modified file 'src/app/webcontainer/AccountsPage.qml' |
445 | --- src/app/webcontainer/AccountsPage.qml 2014-10-02 18:03:46 +0000 |
446 | +++ src/app/webcontainer/AccountsPage.qml 2015-04-16 14:53:15 +0000 |
447 | @@ -18,15 +18,33 @@ |
448 | |
449 | import QtQuick 2.0 |
450 | import Ubuntu.Components 1.1 |
451 | +import Ubuntu.Components.Popups 1.0 |
452 | +import Ubuntu.OnlineAccounts 0.1 |
453 | import webcontainer.private 0.1 |
454 | |
455 | Page { |
456 | - id: accountsPage |
457 | - |
458 | - property alias accountProvider: accountsLogin.accountProvider |
459 | - property alias applicationName: accountsLogin.applicationName |
460 | - |
461 | - signal done(bool successful, var credentialsId) |
462 | + id: root |
463 | + |
464 | + property string providerId: "" |
465 | + property string applicationId: "" |
466 | + property string webappName: "" |
467 | + property url webappIcon |
468 | + property int credentialsId: -1 |
469 | + property alias webview: detector.webview |
470 | + property alias logoutUrlPattern: detector.logoutUrlPattern |
471 | + property alias logoutSelectors: detector.logoutSelectors |
472 | + |
473 | + signal accountSelected(var credentialsId) |
474 | + signal done(bool successful) |
475 | + |
476 | + property string __applicationName: webappName |
477 | + property url __applicationIcon: webappIcon |
478 | + property string __providerName: providerId |
479 | + property var __account: null |
480 | + property var __loggedOutAccounts: [] |
481 | + property var __accountsModel: accountsModel |
482 | + property bool __loggingIn: false |
483 | + property bool __ignoreLogout: false |
484 | |
485 | visible: true |
486 | anchors.fill: parent |
487 | @@ -35,11 +53,156 @@ |
488 | id: accountsLogin |
489 | |
490 | anchors.fill: parent |
491 | + accountsModel: root.__accountsModel |
492 | |
493 | + onAccountSelected: { |
494 | + if (accountId < 0) { |
495 | + showErrorSheet() |
496 | + } else { |
497 | + root.__setupAccount(accountId) |
498 | + } |
499 | + } |
500 | onDone: { |
501 | - if (!accountsPage.visible) |
502 | - return |
503 | - accountsPage.done(credentialsId != null, credentialsId) |
504 | - } |
505 | + __loggingIn = false |
506 | + if (successful && __account) { |
507 | + root.credentialsId = root.__account.authData.credentialsId |
508 | + } |
509 | + root.done(successful) |
510 | + } |
511 | + } |
512 | + |
513 | + LogoutErrorSheet { |
514 | + id: errorSheet |
515 | + |
516 | + visible: false |
517 | + |
518 | + onAccountLoginClicked: { |
519 | + root.credentialsId = -1 |
520 | + __loggedOutAccounts.push(__account.accountId) |
521 | + root.login() |
522 | + } |
523 | + |
524 | + onManualLoginClicked: { |
525 | + root.__ignoreLogout = true |
526 | + root.visible = false |
527 | + visible = false |
528 | + } |
529 | + } |
530 | + |
531 | + LoggingInSheet { |
532 | + visible: root.__loggingIn |
533 | + } |
534 | + |
535 | + Component { |
536 | + id: accountChooserComponent |
537 | + AccountChooserDialog { |
538 | + id: accountChooser |
539 | + providerId: root.providerId |
540 | + applicationId: root.applicationId |
541 | + accountsModel: root.__accountsModel |
542 | + onCancel: PopupUtils.close(accountChooser) |
543 | + onAccountSelected: { |
544 | + PopupUtils.close(accountChooser) |
545 | + root.__setupAccount(accountId) |
546 | + } |
547 | + } |
548 | + } |
549 | + |
550 | + LogoutDetector { |
551 | + id: detector |
552 | + onLogoutDetected: { |
553 | + console.log("Logout detected") |
554 | + if (!__ignoreLogout) { |
555 | + root.visible = true |
556 | + root.showErrorSheet() |
557 | + } |
558 | + } |
559 | + } |
560 | + |
561 | + ApplicationModel { |
562 | + id: applicationModel |
563 | + service: root.applicationId |
564 | + } |
565 | + |
566 | + ProviderModel { |
567 | + id: providerModel |
568 | + applicationId: root.applicationId |
569 | + } |
570 | + |
571 | + AccountServiceModel { |
572 | + id: accountsModel |
573 | + provider: root.providerId |
574 | + applicationId: root.applicationId |
575 | + } |
576 | + |
577 | + Component { |
578 | + id: accountComponent |
579 | + AccountService { } |
580 | + } |
581 | + |
582 | + function __setupApplicationData() { |
583 | + for (var i = 0; i < applicationModel.count; i++) { |
584 | + if (applicationModel.get(i, "applicationId") === root.applicationId) { |
585 | + var name = applicationModel.get(i, "displayName") |
586 | + if (name) root.__applicationName = name |
587 | + var icon = applicationModel.get(i, "iconName") |
588 | + if (icon) root.__applicationIcon = icon |
589 | + break |
590 | + } |
591 | + } |
592 | + } |
593 | + |
594 | + function __setupProviderData() { |
595 | + for (var i = 0; i < providerModel.count; i++) { |
596 | + if (providerModel.get(i, "providerId") === root.providerId) { |
597 | + root.__providerName = providerModel.get(i, "displayName") |
598 | + break |
599 | + } |
600 | + } |
601 | + } |
602 | + |
603 | + Component.onCompleted: { |
604 | + __setupApplicationData() |
605 | + __setupProviderData() |
606 | + } |
607 | + |
608 | + function __setupAccount(accountId) { |
609 | + console.log("Setup account " + accountId) |
610 | + if (__account && accountId === __account.accountId) { |
611 | + console.log("Same as current account") |
612 | + return |
613 | + } |
614 | + __account = null |
615 | + for (var i = 0; i < accountsModel.count; i++) { |
616 | + if (accountsModel.get(i, "accountId") === accountId) { |
617 | + var accountHandle = accountsModel.get(i, "accountServiceHandle") |
618 | + __account = accountComponent.createObject(root, { |
619 | + objectHandle: accountHandle |
620 | + }) |
621 | + break; |
622 | + } |
623 | + } |
624 | + credentialsId = __account ? __account.authData.credentialsId : 0 |
625 | + console.log("Credentials ID: " + credentialsId) |
626 | + } |
627 | + |
628 | + function login() { |
629 | + console.log("Logging in to " + __account) |
630 | + __loggingIn = true |
631 | + var forceCookieRefresh = false |
632 | + var index = __loggedOutAccounts.indexOf(__account.accountId) |
633 | + if (index >= 0) { |
634 | + forceCookieRefresh = true |
635 | + __loggedOutAccounts.splice(index, 1) |
636 | + } |
637 | + accountsLogin.login(__account, forceCookieRefresh) |
638 | + } |
639 | + |
640 | + function showErrorSheet() { |
641 | + errorSheet.visible = true |
642 | + } |
643 | + |
644 | + function chooseAccount() { |
645 | + PopupUtils.open(accountChooserComponent) |
646 | } |
647 | } |
648 | |
649 | === modified file 'src/app/webcontainer/CMakeLists.txt' |
650 | --- src/app/webcontainer/CMakeLists.txt 2015-01-26 14:53:18 +0000 |
651 | +++ src/app/webcontainer/CMakeLists.txt 2015-04-16 14:53:15 +0000 |
652 | @@ -30,7 +30,7 @@ |
653 | install(TARGETS ${WEBAPP_CONTAINER} |
654 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) |
655 | |
656 | -file(GLOB QML_FILES *.qml) |
657 | +file(GLOB QML_FILES *.qml *.js) |
658 | install(FILES ${QML_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app/webcontainer) |
659 | install(DIRECTORY actions DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app/webcontainer |
660 | FILES_MATCHING PATTERN *.qml) |
661 | |
662 | === added file 'src/app/webcontainer/LoggingInSheet.qml' |
663 | --- src/app/webcontainer/LoggingInSheet.qml 1970-01-01 00:00:00 +0000 |
664 | +++ src/app/webcontainer/LoggingInSheet.qml 2015-04-16 14:53:15 +0000 |
665 | @@ -0,0 +1,39 @@ |
666 | +/* |
667 | + * Copyright 2015 Canonical Ltd. |
668 | + * |
669 | + * This file is part of webbrowser-app. |
670 | + * |
671 | + * webbrowser-app is free software; you can redistribute it and/or modify |
672 | + * it under the terms of the GNU General Public License as published by |
673 | + * the Free Software Foundation; version 3. |
674 | + * |
675 | + * webbrowser-app is distributed in the hope that it will be useful, |
676 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
677 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
678 | + * GNU General Public License for more details. |
679 | + * |
680 | + * You should have received a copy of the GNU General Public License |
681 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
682 | + */ |
683 | + |
684 | +import QtQuick 2.0 |
685 | +import Ubuntu.Components 1.1 |
686 | + |
687 | +Rectangle { |
688 | + anchors.fill: parent |
689 | + |
690 | + ActivityIndicator { |
691 | + id: spinner |
692 | + anchors.centerIn: parent |
693 | + running: true |
694 | + } |
695 | + |
696 | + Label { |
697 | + anchors.left: parent.left |
698 | + anchors.right: parent.right |
699 | + anchors.top: spinner.bottom |
700 | + anchors.margins: units.gu(3) |
701 | + text: i18n.tr("Automatic login with Ubuntu in progress…").arg(url) |
702 | + wrapMode: Text.Wrap |
703 | + } |
704 | +} |
705 | |
706 | === added file 'src/app/webcontainer/LogoutDetector.qml' |
707 | --- src/app/webcontainer/LogoutDetector.qml 1970-01-01 00:00:00 +0000 |
708 | +++ src/app/webcontainer/LogoutDetector.qml 2015-04-16 14:53:15 +0000 |
709 | @@ -0,0 +1,78 @@ |
710 | +/* |
711 | + * Copyright 2015 Canonical Ltd. |
712 | + * |
713 | + * This file is part of webbrowser-app. |
714 | + * |
715 | + * webbrowser-app is free software; you can redistribute it and/or modify |
716 | + * it under the terms of the GNU General Public License as published by |
717 | + * the Free Software Foundation; version 3. |
718 | + * |
719 | + * webbrowser-app is distributed in the hope that it will be useful, |
720 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
721 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
722 | + * GNU General Public License for more details. |
723 | + * |
724 | + * You should have received a copy of the GNU General Public License |
725 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
726 | + */ |
727 | + |
728 | +import QtQuick 2.0 |
729 | +import com.canonical.Oxide 1.0 |
730 | + |
731 | +QtObject { |
732 | + id: root |
733 | + |
734 | + property var webview: null |
735 | + property string logoutUrlPattern: "" |
736 | + property string logoutSelectors: "" |
737 | + |
738 | + signal logoutDetected() |
739 | + |
740 | + property var __scriptMessageHandlerComponent: Component { |
741 | + ScriptMessageHandler { |
742 | + msgId: "domChanged" |
743 | + contexts: ["oxide://logoutDetector/"] |
744 | + callback: function(msg, frame) { |
745 | + console.log('Got a DOM changed message: ' + msg.args) |
746 | + var request = webview.rootFrame.sendMessage( |
747 | + "oxide://logoutDetector/", |
748 | + "evaluateSelectors", |
749 | + { selectors: root.logoutSelectors } |
750 | + ) |
751 | + |
752 | + // NOTE: does not handle error |
753 | + request.onreply = function(response) { |
754 | + console.log('Selector result: ' + response.result) |
755 | + if (response.result) { |
756 | + root.logoutDetected() |
757 | + } |
758 | + } |
759 | + } |
760 | + } |
761 | + } |
762 | + |
763 | + property var __connections: Connections { |
764 | + target: webview |
765 | + onLoadEvent: { |
766 | + console.log("Load event: " + event.url) |
767 | + if (logoutUrlPattern.length !== 0 && event.url.toString().match(logoutUrlPattern)) { |
768 | + root.logoutDetected() |
769 | + } |
770 | + } |
771 | + } |
772 | + |
773 | + property var __userScript: UserScript { |
774 | + context: "oxide://logoutDetector/" |
775 | + url: Qt.resolvedUrl("logout-detector.js") |
776 | + incognitoEnabled: true |
777 | + matchAllFrames: true |
778 | + } |
779 | + |
780 | + onWebviewChanged: { |
781 | + if (!webview) return |
782 | + console.log("Webview changed, adding script") |
783 | + var handler = __scriptMessageHandlerComponent.createObject(null, {}) |
784 | + webview.addMessageHandler(handler) |
785 | + webview.context.addUserScript(__userScript) |
786 | + } |
787 | +} |
788 | |
789 | === added file 'src/app/webcontainer/LogoutErrorSheet.qml' |
790 | --- src/app/webcontainer/LogoutErrorSheet.qml 1970-01-01 00:00:00 +0000 |
791 | +++ src/app/webcontainer/LogoutErrorSheet.qml 2015-04-16 14:53:15 +0000 |
792 | @@ -0,0 +1,64 @@ |
793 | +/* |
794 | + * Copyright 2015 Canonical Ltd. |
795 | + * |
796 | + * This file is part of webbrowser-app. |
797 | + * |
798 | + * webbrowser-app is free software; you can redistribute it and/or modify |
799 | + * it under the terms of the GNU General Public License as published by |
800 | + * the Free Software Foundation; version 3. |
801 | + * |
802 | + * webbrowser-app is distributed in the hope that it will be useful, |
803 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
804 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
805 | + * GNU General Public License for more details. |
806 | + * |
807 | + * You should have received a copy of the GNU General Public License |
808 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
809 | + */ |
810 | + |
811 | +import QtQuick 2.0 |
812 | +import Ubuntu.Components 1.1 |
813 | + |
814 | +Rectangle { |
815 | + signal accountLoginClicked() |
816 | + signal manualLoginClicked() |
817 | + |
818 | + anchors.fill: parent |
819 | + |
820 | + Column { |
821 | + anchors.fill: parent |
822 | + anchors.margins: units.gu(4) |
823 | + |
824 | + spacing: units.gu(3) |
825 | + |
826 | + Label { |
827 | + width: parent.width |
828 | + fontSize: "x-large" |
829 | + text: i18n.tr("Logged out") |
830 | + } |
831 | + |
832 | + Label { |
833 | + width: parent.width |
834 | + text: i18n.tr("It appears that you have been logged out.").arg(url) |
835 | + wrapMode: Text.Wrap |
836 | + } |
837 | + |
838 | + Label { |
839 | + width: parent.width |
840 | + text: i18n.tr("Press the <b>Login</b> button to automatically login via Ubuntu, or <b>Continue</b> to go back to the website.") |
841 | + wrapMode: Text.Wrap |
842 | + } |
843 | + |
844 | + Button { |
845 | + anchors.horizontalCenter: parent.horizontalCenter |
846 | + text: i18n.tr("Login with Ubuntu") |
847 | + onClicked: accountLoginClicked() |
848 | + } |
849 | + |
850 | + Button { |
851 | + anchors.horizontalCenter: parent.horizontalCenter |
852 | + text: i18n.tr("Continue anyway") |
853 | + onClicked: manualLoginClicked() |
854 | + } |
855 | + } |
856 | +} |
857 | |
858 | === added file 'src/app/webcontainer/SplashScreen.qml' |
859 | --- src/app/webcontainer/SplashScreen.qml 1970-01-01 00:00:00 +0000 |
860 | +++ src/app/webcontainer/SplashScreen.qml 2015-04-16 14:53:15 +0000 |
861 | @@ -0,0 +1,105 @@ |
862 | +/* |
863 | + * Copyright 2013-2014 Canonical Ltd. |
864 | + * |
865 | + * This file is part of webbrowser-app. |
866 | + * |
867 | + * webbrowser-app is free software; you can redistribute it and/or modify |
868 | + * it under the terms of the GNU General Public License as published by |
869 | + * the Free Software Foundation; version 3. |
870 | + * |
871 | + * webbrowser-app is distributed in the hope that it will be useful, |
872 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
873 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
874 | + * GNU General Public License for more details. |
875 | + * |
876 | + * You should have received a copy of the GNU General Public License |
877 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
878 | + */ |
879 | + |
880 | +import QtQuick 2.0 |
881 | +import Ubuntu.Components 1.1 |
882 | +import Ubuntu.OnlineAccounts 0.1 |
883 | + |
884 | +Item { |
885 | + id: root |
886 | + |
887 | + property string providerName |
888 | + property string applicationName |
889 | + property alias iconSource: icon.source |
890 | + property bool accountMandatory: true |
891 | + |
892 | + signal chooseAccount() |
893 | + signal skip() |
894 | + |
895 | + anchors.fill: parent |
896 | + |
897 | + Column { |
898 | + anchors { |
899 | + left: parent.left |
900 | + right: parent.right |
901 | + verticalCenter: parent.verticalCenter |
902 | + } |
903 | + spacing: units.gu(2) |
904 | + |
905 | + Icon { |
906 | + id: icon |
907 | + anchors.horizontalCenter: parent.horizontalCenter |
908 | + width: units.gu(10) |
909 | + height: width |
910 | + } |
911 | + |
912 | + Label { |
913 | + anchors.horizontalCenter: parent.horizontalCenter |
914 | + fontSize: "x-large" |
915 | + text: root.applicationName |
916 | + } |
917 | + |
918 | + Label { |
919 | + anchors.left: parent.left |
920 | + anchors.right: parent.right |
921 | + horizontalAlignment: Text.AlignHCenter |
922 | + wrapMode: Text.WordWrap |
923 | + text: i18n.tr("<b>%1</b> needs to access your %2 online account.").arg(root.applicationName).arg(root.providerName) |
924 | + visible: root.accountMandatory |
925 | + } |
926 | + |
927 | + Label { |
928 | + anchors.left: parent.left |
929 | + anchors.right: parent.right |
930 | + horizontalAlignment: Text.AlignHCenter |
931 | + wrapMode: Text.WordWrap |
932 | + text: i18n.tr("<b>%1</b> would like to access your %2 online account.").arg(root.applicationName).arg(root.providerName) |
933 | + visible: !root.accountMandatory |
934 | + } |
935 | + |
936 | + Label { |
937 | + anchors.left: parent.left |
938 | + anchors.right: parent.right |
939 | + horizontalAlignment: Text.AlignHCenter |
940 | + wrapMode: Text.WordWrap |
941 | + text: i18n.tr("Choose an account now, or skip this step and choose an online account later.") |
942 | + visible: !root.accountMandatory |
943 | + } |
944 | + |
945 | + Item { |
946 | + anchors.left: parent.left |
947 | + anchors.right: parent.right |
948 | + anchors.margins: units.gu(1) |
949 | + height: units.gu(6) |
950 | + |
951 | + Button { |
952 | + anchors.left: parent.left |
953 | + width: parent.width / 2 - units.gu(1) |
954 | + text: root.accountMandatory ? i18n.tr("Close the app") : i18n.tr("Skip") |
955 | + onClicked: root.accountMandatory ? Qt.quit() : root.skip() |
956 | + } |
957 | + |
958 | + Button { |
959 | + anchors.right: parent.right |
960 | + width: parent.width / 2 - units.gu(1) |
961 | + text: i18n.tr("Choose account") |
962 | + onClicked: root.chooseAccount() |
963 | + } |
964 | + } |
965 | + } |
966 | +} |
967 | |
968 | === modified file 'src/app/webcontainer/WebApp.qml' |
969 | --- src/app/webcontainer/WebApp.qml 2015-04-08 13:20:57 +0000 |
970 | +++ src/app/webcontainer/WebApp.qml 2015-04-16 14:53:15 +0000 |
971 | @@ -46,6 +46,8 @@ |
972 | property bool chromeVisible: false |
973 | readonly property bool chromeless: !chromeVisible && !backForwardButtonsVisible |
974 | |
975 | + signal chooseAccount() |
976 | + |
977 | actions: [ |
978 | Actions.Back { |
979 | enabled: webapp.backForwardButtonsVisible && webview.currentWebview && webview.currentWebview.canGoBack |
980 | |
981 | === modified file 'src/app/webcontainer/cookie-store.cpp' |
982 | --- src/app/webcontainer/cookie-store.cpp 2014-10-08 14:16:14 +0000 |
983 | +++ src/app/webcontainer/cookie-store.cpp 2015-04-16 14:53:15 +0000 |
984 | @@ -51,6 +51,7 @@ |
985 | QObject(parent) |
986 | { |
987 | qRegisterMetaType<QNetworkCookie>(); |
988 | + qRegisterMetaType<QList<QNetworkCookie> >("QList<QNetworkCookie>"); |
989 | qRegisterMetaType<Cookies>("Cookies"); |
990 | } |
991 | |
992 | |
993 | === added file 'src/app/webcontainer/logout-detector.js' |
994 | --- src/app/webcontainer/logout-detector.js 1970-01-01 00:00:00 +0000 |
995 | +++ src/app/webcontainer/logout-detector.js 2015-04-16 14:53:15 +0000 |
996 | @@ -0,0 +1,41 @@ |
997 | +/* |
998 | + * Copyright 2015 Canonical Ltd. |
999 | + * |
1000 | + * This file is part of webbrowser-app. |
1001 | + * |
1002 | + * webbrowser-app is free software; you can redistribute it and/or modify |
1003 | + * it under the terms of the GNU General Public License as published by |
1004 | + * the Free Software Foundation; version 3. |
1005 | + * |
1006 | + * webbrowser-app is distributed in the hope that it will be useful, |
1007 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1008 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1009 | + * GNU General Public License for more details. |
1010 | + * |
1011 | + * You should have received a copy of the GNU General Public License |
1012 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1013 | + */ |
1014 | + |
1015 | +oxide.sendMessage('domChanged', 'Some message'); |
1016 | + |
1017 | +var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; |
1018 | + |
1019 | +var observer = new MutationObserver(function(mutations) { |
1020 | + var addnodes = [] |
1021 | + mutations.forEach(function(mutation) { |
1022 | + for (var i in mutation.addedNodes) { |
1023 | + addnodes.push(mutation.addedNodes[i].className) |
1024 | + } |
1025 | + }); |
1026 | + |
1027 | + oxide.sendMessage('domChanged', JSON.stringify(addnodes)) |
1028 | +}); |
1029 | +observer.observe(document.body, {childList: true, subtree: true }); |
1030 | + |
1031 | + |
1032 | +oxide.addMessageHandler("evaluateSelectors", function(msg) { |
1033 | + var selectors = msg.args.selectors; |
1034 | + console.log("Evaluating selectors: " + selectors); |
1035 | + var match = document.querySelector(selectors); |
1036 | + msg.reply({result: (match !== null)}); |
1037 | +}); |
1038 | |
1039 | === modified file 'src/app/webcontainer/webapp-container.cpp' |
1040 | --- src/app/webcontainer/webapp-container.cpp 2015-04-10 13:33:19 +0000 |
1041 | +++ src/app/webcontainer/webapp-container.cpp 2015-04-16 14:53:15 +0000 |
1042 | @@ -116,9 +116,17 @@ |
1043 | } |
1044 | |
1045 | m_window->setProperty("webappName", m_webappName); |
1046 | + QFileInfo iconInfo(m_webappIcon); |
1047 | + QUrl iconUrl; |
1048 | + if (iconInfo.isReadable()) { |
1049 | + iconUrl = QUrl::fromLocalFile(iconInfo.absoluteFilePath()); |
1050 | + } |
1051 | + m_window->setProperty("webappIcon", iconUrl); |
1052 | m_window->setProperty("backForwardButtonsVisible", m_backForwardButtonsVisible); |
1053 | m_window->setProperty("chromeVisible", m_addressBarVisible); |
1054 | m_window->setProperty("accountProvider", m_accountProvider); |
1055 | + m_window->setProperty("logoutUrlPattern", m_logoutUrlPattern); |
1056 | + m_window->setProperty("logoutSelectors", m_logoutSelectors); |
1057 | |
1058 | m_window->setProperty("webappUrlPatterns", m_webappUrlPatterns); |
1059 | QQmlContext* context = m_engine->rootContext(); |
1060 | @@ -251,9 +259,13 @@ |
1061 | " [--app-id=APP_ID]" |
1062 | " [--homepage=URL]" |
1063 | " [--webapp=name]" |
1064 | + " [--name=NAME]" |
1065 | + " [--icon=PATH]" |
1066 | " [--webappModelSearchPath=PATH]" |
1067 | " [--webappUrlPatterns=URL_PATTERNS]" |
1068 | " [--accountProvider=PROVIDER_NAME]" |
1069 | + " [--logoutUrlPattern=URL_PATTERN]" |
1070 | + " [--logoutSelectors=selector1,selector2,...]" |
1071 | " [--enable-back-forward]" |
1072 | " [--enable-addressbar]" |
1073 | " [--store-session-cookies]" |
1074 | @@ -268,9 +280,13 @@ |
1075 | out << " --app-id=APP_ID run the application with a specific APP_ID" << endl; |
1076 | out << " --homepage=URL override any URL passed as an argument" << endl; |
1077 | out << " --webapp=name try to match the webapp by name with an installed integration script" << endl; |
1078 | + out << " --name=NAME display name of the webapp, shown in the splash screen" << endl; |
1079 | + out << " --icon=PATH Icon to be shown in the splash screen. PATH can be an absolute or path relative to CWD" << endl; |
1080 | out << " --webappModelSearchPath=PATH alter the search path for installed webapps and set it to PATH. PATH can be an absolute or path relative to CWD" << endl; |
1081 | out << " --webappUrlPatterns=URL_PATTERNS list of comma-separated url patterns (wildcard based) that the webapp is allowed to navigate to" << endl; |
1082 | out << " --accountProvider=PROVIDER_NAME Online account provider for the application if the application is to reuse a local account." << endl; |
1083 | + out << " --logoutUrlPattern=PATTERN Regexp pattern for detecting logout URLs." << endl; |
1084 | + out << " --logoutSelectors=SELECTORS Comma separated list of CSS selectors to detect the logout situation." << endl; |
1085 | out << " --store-session-cookies store session cookies on disk" << endl; |
1086 | out << " --enable-media-hub-audio enable media-hub for audio playback" << endl; |
1087 | out << " --user-agent-string=USER_AGENT overrides the default User Agent with the provided one." << endl; |
1088 | @@ -298,6 +314,10 @@ |
1089 | // TODO: validate that it is fine in all cases (country dependent, etc…). |
1090 | QString name = argument.split("--webapp=")[1]; |
1091 | m_webappName = QByteArray::fromBase64(name.toUtf8()).trimmed(); |
1092 | + } else if (argument.startsWith("--name=")) { |
1093 | + m_webappName = argument.split("--name=")[1]; |
1094 | + } else if (argument.startsWith("--icon=")) { |
1095 | + m_webappIcon = argument.split("--icon=")[1]; |
1096 | } else if (argument.startsWith("--webappUrlPatterns=")) { |
1097 | QString tail = argument.split("--webappUrlPatterns=")[1]; |
1098 | if (!tail.isEmpty()) { |
1099 | @@ -306,6 +326,10 @@ |
1100 | } |
1101 | } else if (argument.startsWith("--accountProvider=")) { |
1102 | m_accountProvider = argument.split("--accountProvider=")[1]; |
1103 | + } else if (argument.startsWith("--logoutUrlPattern=")) { |
1104 | + m_logoutUrlPattern = argument.split("--logoutUrlPattern=")[1]; |
1105 | + } else if (argument.startsWith("--logoutSelectors=")) { |
1106 | + m_logoutSelectors = argument.split("--logoutSelectors=")[1]; |
1107 | } else if (argument == "--clear-cookies") { |
1108 | qWarning() << argument << " is an unsupported option: it can be removed without notice..." << endl; |
1109 | clearCookiesHack(m_accountProvider); |
1110 | |
1111 | === modified file 'src/app/webcontainer/webapp-container.h' |
1112 | --- src/app/webcontainer/webapp-container.h 2015-04-10 13:33:19 +0000 |
1113 | +++ src/app/webcontainer/webapp-container.h 2015-04-16 14:53:15 +0000 |
1114 | @@ -58,9 +58,12 @@ |
1115 | |
1116 | private: |
1117 | QString m_webappName; |
1118 | + QString m_webappIcon; |
1119 | QString m_webappModelSearchPath; |
1120 | QStringList m_webappUrlPatterns; |
1121 | QString m_accountProvider; |
1122 | + QString m_logoutUrlPattern; |
1123 | + QString m_logoutSelectors; |
1124 | bool m_storeSessionCookies; |
1125 | bool m_backForwardButtonsVisible; |
1126 | bool m_addressBarVisible; |
1127 | |
1128 | === modified file 'src/app/webcontainer/webapp-container.qml' |
1129 | --- src/app/webcontainer/webapp-container.qml 2015-04-07 14:30:52 +0000 |
1130 | +++ src/app/webcontainer/webapp-container.qml 2015-04-16 14:53:15 +0000 |
1131 | @@ -34,10 +34,13 @@ |
1132 | |
1133 | property var intentFilterHandler |
1134 | property string url: "" |
1135 | + property string webappIcon: "" |
1136 | property string webappName: "" |
1137 | property string webappModelSearchPath: "" |
1138 | property var webappUrlPatterns |
1139 | property string accountProvider: "" |
1140 | + property string logoutUrlPattern: "" |
1141 | + property string logoutSelectors: "" |
1142 | property string popupRedirectionUrlPrefixPattern: "" |
1143 | property url webviewOverrideFile: "" |
1144 | property var __webappCookieStore: null |
1145 | @@ -50,6 +53,10 @@ |
1146 | |
1147 | title: getWindowTitle() |
1148 | |
1149 | + onCurrentWebviewChanged: if (accountsPageComponentLoader.item) { |
1150 | + accountsPageComponentLoader.item.webview = currentWebview |
1151 | + } |
1152 | + |
1153 | // Used for testing |
1154 | signal intentUriHandleResult(string uri) |
1155 | |
1156 | @@ -102,6 +109,8 @@ |
1157 | root.title = getWindowTitle(); |
1158 | } |
1159 | } |
1160 | + |
1161 | + onChooseAccount: accountsPageComponentLoader.item.chooseAccount() |
1162 | } |
1163 | } |
1164 | |
1165 | @@ -158,13 +167,15 @@ |
1166 | Loader { |
1167 | id: accountsPageComponentLoader |
1168 | anchors.fill: parent |
1169 | + z: -1 // This is needed to have the dialogs shown; see above comment about bug 1398046 |
1170 | onStatusChanged: { |
1171 | if (status == Loader.Error) { |
1172 | // Happens on the desktop, if Ubuntu.OnlineAccounts.Client |
1173 | // can't be imported |
1174 | - loadWebAppView() |
1175 | + loadWebAppView(true) |
1176 | } else if (status == Loader.Ready) { |
1177 | item.visible = true |
1178 | + initializeForAccount(item.credentialsId) |
1179 | } |
1180 | } |
1181 | } |
1182 | @@ -175,48 +186,82 @@ |
1183 | } |
1184 | if (!result) { |
1185 | console.log("Cookies were not moved") |
1186 | + } else { |
1187 | + console.log("cookies moved") |
1188 | } |
1189 | webappViewLoader.item.url = root.url |
1190 | } |
1191 | |
1192 | function moveCookies(credentialsId) { |
1193 | + console.log("moving cookies for id " + credentialsId) |
1194 | + var storeComponent = localCookieStoreDbPath.length !== 0 ? |
1195 | + localCookieStoreComponent : onlineAccountStoreComponent |
1196 | + |
1197 | + var instance = storeComponent.createObject(root, { "accountId": credentialsId }) |
1198 | + __webappCookieStore.moved.connect(onCookiesMoved) |
1199 | + __webappCookieStore.moveFrom(instance) |
1200 | + } |
1201 | + |
1202 | + function doLogin() { |
1203 | if (!__webappCookieStore) { |
1204 | var context = webappViewLoader.item.currentWebview.context |
1205 | - __webappCookieStore = oxideCookieStoreComponent.createObject(this, { |
1206 | + __webappCookieStore = oxideCookieStoreComponent.createObject(webappViewLoader.item, { |
1207 | "oxideStoreBackend": context.cookieManager, |
1208 | "dbPath": context.dataPath + "/cookies.sqlite" |
1209 | }) |
1210 | } |
1211 | |
1212 | - var storeComponent = localCookieStoreDbPath.length !== 0 ? |
1213 | - localCookieStoreComponent : onlineAccountStoreComponent |
1214 | - |
1215 | - var instance = storeComponent.createObject(root, { "accountId": credentialsId }) |
1216 | - __webappCookieStore.moved.connect(onCookiesMoved) |
1217 | - __webappCookieStore.moveFrom(instance) |
1218 | + accountsPageComponentLoader.item.login() |
1219 | + } |
1220 | + |
1221 | + function initializeForAccount(credentialsId) { |
1222 | + console.log("Account selected, creds: " + credentialsId) |
1223 | + if (credentialsId < 0) { |
1224 | + webappViewLoader.sourceComponent = null |
1225 | + __webappCookieStore = null |
1226 | + webappViewLoader.credentialsId = credentialsId |
1227 | + return |
1228 | + } |
1229 | + |
1230 | + if (credentialsId > 0) { |
1231 | + if (credentialsId == webappViewLoader.credentialsId) { |
1232 | + doLogin() |
1233 | + return |
1234 | + } |
1235 | + |
1236 | + webappViewLoader.sourceComponent = null |
1237 | + __webappCookieStore = null |
1238 | + webappViewLoader.loaded.connect(function onLoaded() { |
1239 | + if (webappViewLoader.status == Loader.Ready) { |
1240 | + webappViewLoader.loaded.disconnect(onLoaded) |
1241 | + doLogin() |
1242 | + } |
1243 | + }); |
1244 | + webappViewLoader.credentialsId = credentialsId |
1245 | + // If we need to preserve session cookies, make sure that the |
1246 | + // mode is "restored" and not "persistent", or the cookies |
1247 | + // transferred from OA would be lost. |
1248 | + // We check if the webContextSessionCookieMode is defined and, if so, |
1249 | + // we override it in the webapp loader. |
1250 | + if (typeof webContextSessionCookieMode === "string") { |
1251 | + webappViewLoader.webContextSessionCookieMode = "restored" |
1252 | + } |
1253 | + } |
1254 | + |
1255 | + loadWebAppView(credentialsId == 0) |
1256 | } |
1257 | |
1258 | Connections { |
1259 | target: accountsPageComponentLoader.item |
1260 | + onCredentialsIdChanged: initializeForAccount(accountsPageComponentLoader.item.credentialsId) |
1261 | + onVisibleChanged: webappViewLoader.item.visible = !accountsPageComponentLoader.item.visible |
1262 | onDone: { |
1263 | + console.log("Authentication done, successful = " + successful) |
1264 | if (successful) { |
1265 | - webappViewLoader.loaded.connect(function () { |
1266 | - if (webappViewLoader.status == Loader.Ready) { |
1267 | - moveCookies(webappViewLoader.credentialsId) |
1268 | - } |
1269 | - }); |
1270 | - webappViewLoader.credentialsId = credentialsId |
1271 | - // If we need to preserve session cookies, make sure that the |
1272 | - // mode is "restored" and not "persistent", or the cookies |
1273 | - // transferred from OA would be lost. |
1274 | - // We check if the webContextSessionCookieMode is defined and, if so, |
1275 | - // we override it in the webapp loader. |
1276 | - if (typeof webContextSessionCookieMode === "string") { |
1277 | - webappViewLoader.webContextSessionCookieMode = "restored" |
1278 | - } |
1279 | + moveCookies(webappViewLoader.credentialsId) |
1280 | + } else { |
1281 | + loadWebAppView(true) |
1282 | } |
1283 | - |
1284 | - loadWebAppView() |
1285 | } |
1286 | } |
1287 | |
1288 | @@ -241,7 +286,7 @@ |
1289 | if (accountProvider.length !== 0) { |
1290 | loadLoginView(); |
1291 | } else { |
1292 | - loadWebAppView(); |
1293 | + loadWebAppView(true); |
1294 | } |
1295 | } |
1296 | |
1297 | @@ -252,27 +297,34 @@ |
1298 | |
1299 | function loadLoginView() { |
1300 | accountsPageComponentLoader.setSource("AccountsPage.qml", { |
1301 | - "accountProvider": accountProvider, |
1302 | - "applicationName": unversionedAppId, |
1303 | + "providerId": accountProvider, |
1304 | + "applicationId": unversionedAppId, |
1305 | + "webappName": getWebappName(), |
1306 | + "webappIcon": webappIcon, |
1307 | + "logoutUrlPattern": logoutUrlPattern, |
1308 | + "logoutSelectors": logoutSelectors, |
1309 | }) |
1310 | } |
1311 | |
1312 | - function loadWebAppView() { |
1313 | + function loadWebAppView(startBrowsing) { |
1314 | if (accountsPageComponentLoader.item) |
1315 | accountsPageComponentLoader.item.visible = false |
1316 | |
1317 | - webappViewLoader.loaded.connect(function () { |
1318 | - if (webappViewLoader.status === Loader.Ready) { |
1319 | - // As we use StateSaver to restore the URL, we need to check first if |
1320 | - // it has not been set previously before setting the URL to the default property |
1321 | - // homepage. |
1322 | - var webView = webappViewLoader.item.currentWebview |
1323 | - var current_url = webView.url.toString(); |
1324 | - if (!current_url || current_url.length === 0) { |
1325 | - webView.url = root.url |
1326 | + if (startBrowsing) { |
1327 | + webappViewLoader.loaded.connect(function onLoaded() { |
1328 | + if (webappViewLoader.status === Loader.Ready) { |
1329 | + webappViewLoader.loaded.disconnect(onLoaded) |
1330 | + // As we use StateSaver to restore the URL, we need to check first if |
1331 | + // it has not been set previously before setting the URL to the default property |
1332 | + // homepage. |
1333 | + var webView = webappViewLoader.item.currentWebview |
1334 | + var current_url = webView.url.toString(); |
1335 | + if (!current_url || current_url.length === 0) { |
1336 | + webView.url = root.url |
1337 | + } |
1338 | } |
1339 | - } |
1340 | - }); |
1341 | + }); |
1342 | + } |
1343 | webappViewLoader.sourceComponent = webappViewComponent |
1344 | } |
1345 |
FAILED: Continuous integration, rev:973 jenkins. qa.ubuntu. com/job/ webbrowser- app-ci/ 1632/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 2195 jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- amd64-ci/ 390 jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- armhf-ci/ 390 jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- armhf-ci/ 390/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- i386-ci/ 390 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- vivid-mako/ 1928 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 2193 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 2193/artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 19567
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/webbrowser- app-ci/ 1632/rebuild
http://