[gnome-shell/eos3.8: 173/255] js/ui/payg.js: PayGo UI utilities
- From: Matthew Leeds <mwleeds src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/eos3.8: 173/255] js/ui/payg.js: PayGo UI utilities
- Date: Wed, 10 Jun 2020 19:12:31 +0000 (UTC)
commit b1e871703e6d69d71b3ccc93aa768a71c7b8ae13
Author: Travis Reitter <travis reitter endlessm com>
Date: Thu Nov 29 10:22:50 2018 -0800
js/ui/payg.js: PayGo UI utilities
This factors out some PayGo UI code so it can be re-used for the
upcoming PayGo status applet and its notifications.
https://phabricator.endlessm.com/T24125
* 2020-04-02: Squash with 1358d284d
* 2019-10-21:
- Replace Tweener by ClutterActor.ease()
- Replace Mainloop by GLib
- Squash with "ed6d7c628 payg: make widgets insensitive […]"
js/js-resources.gresource.xml | 1 +
js/ui/payg.js | 214 ++++++++++++++++++++++++++++++++++++++++++
js/ui/paygUnlockDialog.js | 149 +++++++----------------------
po/POTFILES.in | 1 +
4 files changed, 251 insertions(+), 114 deletions(-)
---
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index 4fca81d025..9e09648234 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -154,6 +154,7 @@
<file>ui/hotCorner.js</file>
<file>ui/iconGridLayout.js</file>
<file>ui/internetSearch.js</file>
+ <file>ui/payg.js</file>
<file>ui/paygUnlockDialog.js</file>
<file>ui/sideComponent.js</file>
<file>ui/status/automaticUpdates.js</file>
diff --git a/js/ui/payg.js b/js/ui/payg.js
new file mode 100644
index 0000000000..04b1efb2cf
--- /dev/null
+++ b/js/ui/payg.js
@@ -0,0 +1,214 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+//
+// Copyright (C) 2018 Endless Mobile, Inc.
+//
+// Licensed under the GNU General Public License Version 2
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+/* exported PaygUnlockUi, SPINNER_ICON_SIZE_PIXELS, SUCCESS_DELAY_SECONDS */
+
+const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
+
+const PaygManager = imports.misc.paygManager;
+
+const Gettext = imports.gettext;
+const Main = imports.ui.main;
+
+var SUCCESS_DELAY_SECONDS = 3;
+
+var SPINNER_ICON_SIZE_PIXELS = 16;
+var SPINNER_ANIMATION_DELAY_MSECS = 1000;
+var SPINNER_ANIMATION_TIME_MSECS = 300;
+
+var UnlockStatus = {
+ NOT_VERIFYING: 0,
+ VERIFYING: 1,
+ FAILED: 2,
+ TOO_MANY_ATTEMPTS: 3,
+ SUCCEEDED: 4,
+};
+
+var PaygUnlockUi = GObject.registerClass(
+class PaygUnlockUi extends St.Widget {
+
+ // the following properties and functions are required for any subclasses of
+ // this class
+
+ // properties
+ // -----------
+ // applyButton
+ // entryCode
+ // spinner
+ // verificationStatus
+
+ // functions
+ // ----------
+ // entryReset
+ // entrySetEnabled
+ // onCodeAdded
+ // reset
+
+ _init(params = {}) {
+ super._init(params);
+ this._clearTooManyAttemptsId = 0;
+ this.connect('destroy', this._onDestroy.bind(this));
+ }
+
+ updateApplyButtonSensitivity() {
+ let sensitive = this.validateCurrentCode() &&
+ this.verificationStatus !== UnlockStatus.VERIFYING &&
+ this.verificationStatus !== UnlockStatus.SUCCEEDED &&
+ this.verificationStatus !== UnlockStatus.TOO_MANY_ATTEMPTS;
+
+ this.applyButton.reactive = sensitive;
+ this.applyButton.can_focus = sensitive;
+ }
+
+ updateSensitivity() {
+ let shouldEnableEntry =
+ this.verificationStatus !== UnlockStatus.VERIFYING &&
+ this.verificationStatus !== UnlockStatus.SUCCEEDED &&
+ this.verificationStatus !== UnlockStatus.TOO_MANY_ATTEMPTS;
+
+ this.updateApplyButtonSensitivity();
+ this.entrySetEnabled(shouldEnableEntry);
+ }
+
+ processError(error) {
+ logError(error, 'Error adding PAYG code');
+
+ // The 'too many errors' case is a bit special, and sets a different state.
+ if (error.matches(PaygManager.PaygErrorDomain, PaygManager.PaygError.TOO_MANY_ATTEMPTS)) {
+ let currentTime = Shell.util_get_boottime() / GLib.USEC_PER_SEC;
+ let secondsLeft = Main.paygManager.rateLimitEndTime - currentTime;
+ if (secondsLeft > 30) {
+ let minutesLeft = Math.max(0, Math.ceil(secondsLeft / 60));
+ this.setErrorMessage(
+ Gettext.ngettext(
+ 'Too many attempts. Try again in %s minute.',
+ 'Too many attempts. Try again in %s minutes.', minutesLeft)
+ .format(minutesLeft));
+ } else {
+ this.setErrorMessage(_('Too many attempts. Try again in a few seconds.'));
+ }
+
+ // Make sure to clean the status once the time is up (if this dialog is still alive)
+ // and make sure that we install this callback at some point in the future (+1 sec).
+ this._clearTooManyAttemptsId = GLib.timeout_add_seconds(
+ GLib.PRIORITY_DEFAULT,
+ Math.max(1, secondsLeft),
+ () => {
+ this._verificationStatus = UnlockStatus.NOT_VERIFYING;
+ this._clearError();
+ this._updateSensitivity();
+ return GLib.SOURCE_REMOVE;
+ });
+
+ this.verificationStatus = UnlockStatus.TOO_MANY_ATTEMPTS;
+ return;
+ }
+
+ // Common errors after this point.
+ if (error.matches(PaygManager.PaygErrorDomain, PaygManager.PaygError.INVALID_CODE)) {
+ this.setErrorMessage(_('Invalid code. Please try again.'));
+ } else if (error.matches(PaygManager.PaygErrorDomain, PaygManager.PaygError.CODE_ALREADY_USED)) {
+ this.setErrorMessage(_('Code already used. Please enter a new code.'));
+ } else if (error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.TIMED_OUT)) {
+ this.setErrorMessage(_('Time exceeded while verifying the code'));
+ } else {
+ // We don't consider any other error here (and we don't consider DISABLED explicitly,
+ // since that should not happen), but still we need to show something to the user.
+ this.setErrorMessage(_('Unknown error'));
+ }
+
+ this.verificationStatus = UnlockStatus.FAILED;
+ }
+
+ _onDestroy() {
+ if (this._clearTooManyAttemptsId > 0) {
+ GLib.source_remove(this._clearTooManyAttemptsId);
+ this._clearTooManyAttemptsId = 0;
+ }
+ }
+
+ setErrorMessage(message) {
+ if (message) {
+ this.errorLabel.text = message;
+ this.errorLabel.opacity = 255;
+ } else {
+ this.errorLabel.text = '';
+ this.errorLabel.opacity = 0;
+ }
+ }
+
+ clearError() {
+ this.setErrorMessage(null);
+ }
+
+ startSpinning() {
+ this.spinner.play();
+ this.spinner.actor.show();
+ this.spinner.actor.ease({
+ opacity: 255,
+ delay: SPINNER_ANIMATION_DELAY_MSECS,
+ duration: SPINNER_ANIMATION_TIME_MSECS,
+ mode: Clutter.AnimationMode.LINEAR,
+ });
+ }
+
+ stopSpinning() {
+ this.spinner.actor.hide();
+ this.spinner.actor.opacity = 0;
+ this.spinner.stop();
+ }
+
+ reset() {
+ this.stopSpinning();
+ this.entryReset();
+ this.updateSensitivity();
+ }
+
+ validateCurrentCode() {
+ return Main.paygManager.validateCode(this.entryCode);
+ }
+
+ startVerifyingCode() {
+ if (!this.validateCurrentCode())
+ return;
+
+ this.verificationStatus = UnlockStatus.VERIFYING;
+ this.startSpinning();
+ this.updateSensitivity();
+ this.cancelled = false;
+
+ Main.paygManager.addCode(this.entryCode, error => {
+ // We don't care about the result if we're closing the dialog.
+ if (this.cancelled) {
+ this.verificationStatus = UnlockStatus.NOT_VERIFYING;
+ return;
+ }
+
+ if (error) {
+ this.processError(error);
+ } else {
+ this.verificationStatus = UnlockStatus.SUCCEEDED;
+ this.onCodeAdded();
+ }
+
+ this.reset();
+ });
+ }
+});
diff --git a/js/ui/paygUnlockDialog.js b/js/ui/paygUnlockDialog.js
index 5c52db8153..70e3a8da22 100644
--- a/js/ui/paygUnlockDialog.js
+++ b/js/ui/paygUnlockDialog.js
@@ -25,6 +25,7 @@ const { Atk, Clutter, Gio, GLib,
const Gettext = imports.gettext;
const PaygManager = imports.misc.paygManager;
+const Payg = imports.ui.payg;
const Animation = imports.ui.animation;
const Main = imports.ui.main;
@@ -181,7 +182,7 @@ var PaygUnlockDialog = GObject.registerClass({
'failed': {},
'wake-up-screen': {},
},
-}, class PaygUnlockDialog extends St.Widget {
+}, class PaygUnlockDialog extends Payg.PaygUnlockUi {
_init(parentActor) {
super._init({
@@ -192,7 +193,6 @@ var PaygUnlockDialog = GObject.registerClass({
});
this._parentActor = parentActor;
-
this._entry = null;
this._errorMessage = null;
this._cancelButton = null;
@@ -200,7 +200,7 @@ var PaygUnlockDialog = GObject.registerClass({
this._spinner = null;
this._cancelled = false;
- this._verificationStatus = UnlockStatus.NOT_VERIFYING;
+ this._verificationStatus = Payg.UnlockStatus.NOT_VERIFYING;
// Clear the clipboard to make sure nothing can be copied into the entry.
St.Clipboard.get_default().set_text(St.ClipboardType.CLIPBOARD, '');
@@ -312,24 +312,21 @@ var PaygUnlockDialog = GObject.registerClass({
this._onCancelled();
});
this._nextButton.connect('clicked', () => {
- this._startVerifyingCode();
+ this.startVerifyingCode();
});
this._entry.connect('code-changed', () => {
- this._updateNextButtonSensitivity();
+ this.updateApplyButtonSensitivity();
});
this._entry.clutter_text.connect('activate', () => {
- this._startVerifyingCode();
+ this.startVerifyingCode();
});
- this._clearTooManyAttemptsId = 0;
- this.connect('destroy', this._onDestroy.bind(this));
-
this._idleMonitor = Meta.IdleMonitor.get_core();
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT_SECS * MSEC_PER_SEC,
this._onCancelled.bind(this));
- this._updateSensitivity();
+ this.updateSensitivity();
this._entry.grab_key_focus();
}
@@ -376,7 +373,7 @@ var PaygUnlockDialog = GObject.registerClass({
buttonsBox.add_child(buttonSpacer);
// We make the most of the spacer to show the spinner while verifying the code.
- this._spinner = new Animation.Spinner(SPINNER_ICON_SIZE_PIXELS, {
+ this._spinner = new Animation.Spinner(Payg.SPINNER_ICON_SIZE_PIXELS, {
animate: true,
hideOnStop: true,
});
@@ -399,132 +396,56 @@ var PaygUnlockDialog = GObject.registerClass({
_onCancelled() {
this._cancelled = true;
- this._reset();
+ this.reset();
// The ScreenShield will connect to the 'failed' signal
// to know when to cancel the unlock dialog.
- if (this._verificationStatus !== UnlockStatus.SUCCEEDED)
+ if (this._verificationStatus !== Payg.UnlockStatus.SUCCEEDED)
this.emit('failed');
}
- _validateCurrentCode() {
- return Main.paygManager.validateCode(this._entry.code);
+ entrySetEnabled(enabled) {
+ this._entry.setEnabled(enabled);
}
- _updateNextButtonSensitivity() {
- let sensitive = this._validateCurrentCode() &&
- this._verificationStatus !== UnlockStatus.VERIFYING &&
- this._verificationStatus !== UnlockStatus.TOO_MANY_ATTEMPTS;
-
- this._nextButton.reactive = sensitive;
- this._nextButton.can_focus = sensitive;
+ entryReset() {
+ this._entry.reset();
}
- _updateSensitivity() {
- let shouldEnableEntry = this._verificationStatus !== UnlockStatus.VERIFYING &&
- this._verificationStatus !== UnlockStatus.TOO_MANY_ATTEMPTS;
-
- this._updateNextButtonSensitivity();
- this._entry.setEnabled(shouldEnableEntry);
+ onCodeAdded() {
+ this.clearError();
}
- _setErrorMessage(message) {
- if (message) {
- this._errorMessage.text = message;
- this._errorMessage.opacity = 255;
- } else {
- this._errorMessage.text = '';
- this._errorMessage.opacity = 0;
- }
+ get entryCode() {
+ return this._entry.code;
}
- _reset() {
- this._spinner.stop();
- this._entry.reset();
- this._updateSensitivity();
+ get verificationStatus() {
+ return this._verificationStatus;
}
- _processError(error) {
- logError(error, 'Error adding PAYG code');
-
- // The 'too many errors' case is a bit special, and sets a different state.
- if (error.matches(PaygManager.PaygErrorDomain, PaygManager.PaygError.TOO_MANY_ATTEMPTS)) {
- let currentTime = GLib.get_real_time() / GLib.USEC_PER_SEC;
- let secondsLeft = Main.paygManager.rateLimitEndTime - currentTime;
- if (secondsLeft > 30) {
- let minutesLeft = Math.max(0, Math.ceil(secondsLeft / 60));
- this._setErrorMessage(
- Gettext.ngettext(
- 'Too many attempts. Try again in %s minute.',
- 'Too many attempts. Try again in %s minutes.', minutesLeft).format(minutesLeft));
- } else {
- this._setErrorMessage(_('Too many attempts. Try again in a few seconds.'));
- }
-
- // Make sure to clean the status once the time is up (if this dialog is still alive)
- // and make sure that we install this callback at some point in the future (+1 sec).
- this._clearTooManyAttemptsId = GLib.timeout_add_seconds(
- GLib.PRIORITY_DEFAULT,
- Math.max(1, secondsLeft),
- () => {
- this._verificationStatus = UnlockStatus.NOT_VERIFYING;
- this._clearError();
- this._updateSensitivity();
- this._entry.grab_key_focus();
- return GLib.SOURCE_REMOVE;
- });
-
- this._verificationStatus = UnlockStatus.TOO_MANY_ATTEMPTS;
- return;
- }
-
- // Common errors after this point.
- if (error.matches(PaygManager.PaygErrorDomain, PaygManager.PaygError.INVALID_CODE)) {
- this._setErrorMessage(_('Invalid code. Please try again.'));
- } else if (error.matches(PaygManager.PaygErrorDomain, PaygManager.PaygError.CODE_ALREADY_USED)) {
- this._setErrorMessage(_('Code already used. Please enter a new code.'));
- } else if (error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.TIMED_OUT)) {
- this._setErrorMessage(_('Time exceeded while verifying the code'));
- } else {
- // We don't consider any other error here (and we don't consider DISABLED explicitly,
- // since that should not happen), but still we need to show something to the user.
- this._setErrorMessage(_('Unknown error'));
- }
-
- this._verificationStatus = UnlockStatus.FAILED;
+ set verificationStatus(value) {
+ this._verificationStatus = value;
}
- _clearError() {
- this._setErrorMessage(null);
+ get cancelled() {
+ return this._cancelled;
}
- _addCodeCallback(error) {
- // We don't care about the result if we're closing the dialog.
- if (this._cancelled) {
- this._verificationStatus = UnlockStatus.NOT_VERIFYING;
- return;
- }
-
- if (error) {
- this._processError(error);
- } else {
- this._verificationStatus = UnlockStatus.SUCCEEDED;
- this._clearError();
- }
-
- this._reset();
+ set cancelled(value) {
+ this._cancelled = value;
}
- _startVerifyingCode() {
- if (!this._validateCurrentCode())
- return;
+ get errorLabel() {
+ return this._errorMessage;
+ }
- this._verificationStatus = UnlockStatus.VERIFYING;
- this._spinner.play();
- this._updateSensitivity();
- this._cancelled = false;
+ get spinner() {
+ return this._spinner;
+ }
- Main.paygManager.addCode(this._entry.code, this._addCodeCallback.bind(this));
+ get applyButton() {
+ return this._nextButton;
}
addCharacter(unichar) {
@@ -532,7 +453,7 @@ var PaygUnlockDialog = GObject.registerClass({
}
cancel() {
- this._reset();
+ this.entryReset();
this.destroy();
}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 05cffc4611..d8e6e52348 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -51,6 +51,7 @@ js/ui/overview.js
js/ui/padOsd.js
js/ui/panel.js
js/ui/paygUnlockDialog.js
+js/ui/payg.js
js/ui/popupMenu.js
js/ui/runDialog.js
js/ui/screenShield.js
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]