[gnome-shell/eos3.8: 177/255] payg: Add success screen



commit bdf9069be7e496fd99e43d1b9c22cc47635e5a57
Author: Mazen Asef <mazen asefali gmail com>
Date:   Fri Dec 7 14:17:21 2018 -0200

    payg: Add success screen
    
    Add success screen to the code-expiry-change event.
    
    Also adding a code that does not add time for the users makes
    the paygManager to try and trigger the screenShield, and the
    signal is received, but does not make it pop since it's not
    unlocked, finishing the unlock process before adding a valid
    code. So we add a error handling using the time added from the
    daemon so we know how much time has been returned, and if it's
    zero, do nothing.
    
    https://phabricator.endlessm.com/T24128
    
     * 2019-10-21:
        - Remove Mainloop usage

 data/dbus-interfaces/com.endlessm.Payg1.xml        |   1 +
 data/theme/gnome-shell-sass/_endless.scss          |  10 ++
 .../gnome-shell-sass/_high-contrast-colors.scss    |   2 +
 js/misc/paygManager.js                             |   8 ++
 js/ui/payg.js                                      |  65 ++++++++++-
 js/ui/paygUnlockDialog.js                          | 122 +++++++++++++++++++++
 js/ui/screenShield.js                              |  47 ++++----
 7 files changed, 230 insertions(+), 25 deletions(-)
---
diff --git a/data/dbus-interfaces/com.endlessm.Payg1.xml b/data/dbus-interfaces/com.endlessm.Payg1.xml
index 7bd7d8d739..a003a69a77 100644
--- a/data/dbus-interfaces/com.endlessm.Payg1.xml
+++ b/data/dbus-interfaces/com.endlessm.Payg1.xml
@@ -2,6 +2,7 @@
   <interface name="com.endlessm.Payg1">
     <method name="AddCode">
       <arg type="s" direction="in" name="code"/>
+      <arg type="x" direction="out" name="time_added"/>
     </method>
     <method name="ClearCode" />
     <signal name="Expired" />
diff --git a/data/theme/gnome-shell-sass/_endless.scss b/data/theme/gnome-shell-sass/_endless.scss
index f487cde32e..2a9c95e2e0 100644
--- a/data/theme/gnome-shell-sass/_endless.scss
+++ b/data/theme/gnome-shell-sass/_endless.scss
@@ -673,6 +673,8 @@ popup-separator-menu-item {
 
 // Pay As You Go unlock screen (based on .login-dialog)
 
+$success_time_payg_color: #02b842;
+
 .unlock-dialog-payg {
   border: none;
   background-color: transparent;
@@ -746,6 +748,14 @@ popup-separator-menu-item {
           font-size: 100%;
           text-align: left;
       }
+
+      .unlock-dialog-payg-success {
+          color: $success_time_payg_color;
+          font-size: 24px;
+          font-weight: bold;
+          text-align: left;
+          margin: 24px;
+      }
   }
 }
 
diff --git a/data/theme/gnome-shell-sass/_high-contrast-colors.scss 
b/data/theme/gnome-shell-sass/_high-contrast-colors.scss
index 710179367e..0e78c0799d 100644
--- a/data/theme/gnome-shell-sass/_high-contrast-colors.scss
+++ b/data/theme/gnome-shell-sass/_high-contrast-colors.scss
@@ -27,6 +27,8 @@ $osd_outer_borders_color: rgba(255,255,255, 0.1);
 
 $shadow_color: rgba(0,0,0, 0.1);
 
+$success_time_payg_color: #02b842;
+
 //insensitive state derived colors
 $insensitive_fg_color: mix($fg_color, $bg_color, 50%);
 $insensitive_bg_color: mix($bg_color, $base_color, 60%);
diff --git a/js/misc/paygManager.js b/js/misc/paygManager.js
index b30521f27e..58fd0e0400 100644
--- a/js/misc/paygManager.js
+++ b/js/misc/paygManager.js
@@ -85,6 +85,7 @@ var PaygManager = GObject.registerClass({
 
         this._enabled = false;
         this._expiryTime = 0;
+        this._lastTimeAdded = 0;
         this._rateLimitEndTime = 0;
         this._codeFormat = '';
         this._codeFormatRegex = null;
@@ -280,6 +281,9 @@ var PaygManager = GObject.registerClass({
         }
 
         this._proxy.AddCodeRemote(code, (result, error) => {
+            if (!error)
+                this._lastTimeAdded = result;
+
             if (callback)
                 callback(error);
         });
@@ -316,6 +320,10 @@ var PaygManager = GObject.registerClass({
         return this._expiryTime;
     }
 
+    get lastTimeAdded() {
+        return this._lastTimeAdded;
+    }
+
     get rateLimitEndTime() {
         return this._rateLimitEndTime;
     }
diff --git a/js/ui/payg.js b/js/ui/payg.js
index d2a2c42159..0773306f29 100644
--- a/js/ui/payg.js
+++ b/js/ui/payg.js
@@ -48,8 +48,11 @@ var UnlockStatus = {
     SUCCEEDED: 4,
 };
 
-var PaygUnlockUi = GObject.registerClass(
-class PaygUnlockUi extends St.Widget {
+var PaygUnlockUi = GObject.registerClass({
+    Signals: {
+        'code-reset': {},
+    },
+}, class PaygUnlockUi extends St.Widget {
 
     // the following properties and functions are required for any subclasses of
     // this class
@@ -144,6 +147,13 @@ class PaygUnlockUi extends St.Widget {
         this.verificationStatus = UnlockStatus.FAILED;
     }
 
+    processReset() {
+        // If time has been removed entirely, we show the user the according message
+        // that the time has been reset to zero.
+        this.emit('code-reset');
+        this.verificationStatus = UnlockStatus.FAILED;
+    }
+
     _onDestroy() {
         if (this._clearTooManyAttemptsId > 0) {
             GLib.source_remove(this._clearTooManyAttemptsId);
@@ -210,6 +220,8 @@ class PaygUnlockUi extends St.Widget {
 
             if (error) {
                 this.processError(error);
+            } else if (Main.paygManager.lastTimeAdded <= 0) {
+                this.processReset();
             } else {
                 this.verificationStatus = UnlockStatus.SUCCEEDED;
                 this.onCodeAdded();
@@ -381,7 +393,7 @@ class ApplyCodeNotification extends MessageTray.Notification {
     }
 
     _onCodeAdded() {
-        this._setMessage(_('Code applied successfully!'));
+        this._setMessage(successMessage());
 
         GLib.timeout_add_seconds(
             GLib.PRIORITY_DEFAULT,
@@ -466,6 +478,53 @@ function timeToString(seconds) {
     return '%s %s'.format(daysStr, hoursStr);
 }
 
+// Similar to timeToStrings, but does not process partial time,
+// since it's meant to be used for expiration time changes, with
+// a wider range of periods
+function successMessage() {
+    let seconds = Main.paygManager.lastTimeAdded;
+    if (seconds < 60) {
+        return Gettext.ngettext("%s second has been added to your Pay As You Go credit.",
+                                "%s seconds have been added to your Pay As You Go credit.")
+                                .format(Math.floor(seconds));
+    }
+
+    let minutes = Math.floor(seconds / 60);
+    if (minutes < 120) {
+        return Gettext.ngettext("%s minute has been added to your Pay As You Go credit.",
+                                "%s minutes have been added to your Pay As You Go credit.")
+                                .format(Math.floor(minutes));
+    }
+
+    let hours = Math.floor(minutes / 60);
+    if (hours < 24) {
+        return Gettext.ngettext("%s hour has been added to your Pay As You Go credit.",
+                                "%s hours have been added to your Pay As You Go credit.")
+                                .format(Math.floor(hours));
+    }
+
+    let days = Math.floor(hours / 24);
+    if (days < 30) {
+        return Gettext.ngettext("%s day has been added to your Pay As You Go credit.",
+                                "%s days have been added to your Pay As You Go credit.")
+                                .format(Math.floor(days));
+    }
+
+    let months = Math.floor(days / 30);
+    if (months < 12) {
+        return Gettext.ngettext("%s month has been added to your Pay As You Go credit.",
+                                "%s months have been added to your Pay As You Go credit.")
+                                .format(Math.floor(months));
+    }
+
+    let year = Math.floor(months / 12);
+    if (year == 1)
+        return _("1 year has been added to your Pay As You Go credit.");
+
+    //Unlock permanently message
+    return _("You have successfully unlocked your Endless Machine");
+}
+
 var PaygNotifier = GObject.registerClass(
 class PaygNotifier extends GObject.Object {
     _init() {
diff --git a/js/ui/paygUnlockDialog.js b/js/ui/paygUnlockDialog.js
index dbe7a59fbf..85edf489fe 100644
--- a/js/ui/paygUnlockDialog.js
+++ b/js/ui/paygUnlockDialog.js
@@ -179,7 +179,9 @@ var PaygUnlockCodeEntry = GObject.registerClass({
 
 var PaygUnlockDialog = GObject.registerClass({
     Signals: {
+        'code-added': {},
         'failed': {},
+        'success-message-shown': {},
         'wake-up-screen': {},
     },
 }, class PaygUnlockDialog extends Payg.PaygUnlockUi {
@@ -323,6 +325,17 @@ var PaygUnlockDialog = GObject.registerClass({
             this.startVerifyingCode();
         });
 
+        this.connect('code-added', () => {
+            this.actor.remove_child(mainBox);
+            this._successScreen();
+        });
+
+        this.connect('code-reset', () => {
+            this._paygUnlockDialog = mainBox;
+            this.actor.remove_child(mainBox);
+            this._resetScreen();
+        });
+
         this._idleMonitor = Meta.IdleMonitor.get_core();
         this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT_SECS * MSEC_PER_SEC, 
this._onCancelled.bind(this));
 
@@ -394,6 +407,114 @@ var PaygUnlockDialog = GObject.registerClass({
         return buttonsBox;
     }
 
+    _createMessageBox() {
+        let messageBox = new St.BoxLayout({
+            vertical: true,
+            x_align: Clutter.ActorAlign.FILL,
+            y_align: Clutter.ActorAlign.CENTER,
+            x_expand: true,
+            y_expand: true,
+            style_class: 'unlock-dialog-payg-layout',
+        });
+
+        return messageBox;
+    }
+
+    _createMessageButtonArea(buttonLabel) {
+        let messageButtonBox = new St.BoxLayout({
+            style_class: 'unlock-dialog-payg-button-box',
+            vertical: false,
+            x_expand: true,
+            x_align: Clutter.ActorAlign.CENTER,
+            y_expand: true,
+            y_align: Clutter.ActorAlign.END,
+        });
+
+        this._messageButton = new St.Button({
+            style_class: 'modal-dialog-button button',
+            button_mask: St.ButtonMask.THREE,
+            reactive: true,
+            can_focus: true,
+            label: buttonLabel,
+            x_align: St.Align.MIDDLE,
+            y_align: St.Align.END,
+        });
+
+        this._messageButton.add_style_pseudo_class('default');
+        messageButtonBox.add_child(this._messageButton);
+
+        return messageButtonBox;
+    }
+
+    _createMessageString(string) {
+        let messageString = new St.Label({
+            style_class: 'unlock-dialog-payg-success',
+            text: string,
+            x_align: Clutter.ActorAlign.CENTER,
+        });
+
+        return messageString;
+    }
+
+    _successScreen() {
+        let messageBox = this._createMessageBox();
+        this.add_child(messageBox);
+
+        // successMessage will handle the formatting of the string
+        messageBox.add_child(this._createMessageString(Payg.successMessage()));
+        messageBox.add_child(this._createMessageButtonArea(_('Success!')));
+        this._messageButton.grab_key_focus();
+
+        this._timeoutId = GLib.timeout_add_seconds(
+            GLib.PRIORITY_DEFAULT,
+            3,
+            () => {
+                this.emit('success-message-shown');
+                return GLib.SOURCE_REMOVE;
+            });
+        this._messageButton.connect('button-press-event', () => {
+            GLib.source_remove(this._timeoutId);
+            this.emit('success-message-shown');
+        });
+        this._messageButton.connect('key-press-event', () => {
+            GLib.source_remove(this._timeoutId);
+            this.emit('success-message-shown');
+        });
+    }
+
+    _resetScreen() {
+        let messageBox = this._createMessageBox();
+        this.add_child(messageBox);
+
+        messageBox.add_child(this._createMessageString(_('Remaining time cleared!')));
+        messageBox.add_child(this._createMessageButtonArea(_('OK!')));
+        this._messageButton.grab_key_focus();
+
+        this._timeoutId = GLib.timeout_add_seconds(
+            GLib.PRIORITY_DEFAULT,
+            3,
+            () => {
+                this.add_child(this._paygUnlockDialog);
+                this.remove_child(messageBox);
+                return GLib.SOURCE_REMOVE;
+            });
+        this._messageButton.connect('button-press-event', () => {
+            this._restorePaygUnlockCodeEntry();
+            this.actor.remove_child(messageBox);
+        });
+        this._messageButton.connect('key-press-event', () => {
+            this._restorePaygUnlockCodeEntry();
+            this.actor.remove_child(messageBox);
+        });
+    }
+
+    _restorePaygUnlockCodeEntry() {
+        GLib.source_remove(this._timeoutId);
+        this.actor.add_child(this._paygUnlockDialog);
+        this.updateSensitivity();
+        this._entry.grab_key_focus();
+    }
+
     _onCancelled() {
         this._cancelled = true;
         this.reset();
@@ -413,6 +534,7 @@ var PaygUnlockDialog = GObject.registerClass({
     }
 
     onCodeAdded() {
+        this.emit('code-added');
         this.clearError();
     }
 
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
index bf943b5d88..61872e0c2f 100644
--- a/js/ui/screenShield.js
+++ b/js/ui/screenShield.js
@@ -8,9 +8,9 @@ const GnomeSession = imports.misc.gnomeSession;
 const OVirt = imports.gdm.oVirt;
 const LoginManager = imports.misc.loginManager;
 const Lightbox = imports.ui.lightbox;
+const MessageTray = imports.ui.messageTray;
 const Main = imports.ui.main;
 const Overview = imports.ui.overview;
-const MessageTray = imports.ui.messageTray;
 const ShellDBus = imports.ui.shellDBus;
 const SmartcardManager = imports.misc.smartcardManager;
 
@@ -155,27 +155,30 @@ var ScreenShield = class {
                 return;
             }
 
-            // A new valid code unlocked the machine and user has no
-            // password set -> Go straight to the user's session.
-            if (user.password_mode == AccountsService.UserPasswordMode.NONE) {
-                this.deactivate(false);
-                return;
-            }
-
-            let paygExpectedMode = this._isGreeter ? 'gdm-unlock-dialog-payg' : 'unlock-dialog-payg';
-            if (Main.sessionMode.currentMode === 'unlock-dialog-payg') {
-                // This is the most common case.
-                Main.sessionMode.popMode(paygExpectedMode);
-            }
-
-            // The machine is unlocked but we still need to unlock the
-            // user's session with the password, so don't deactivate yet.
-            if (this._dialog) {
-                this._dialog.destroy();
-                this._dialog = null;
-            }
-
-            this.showDialog();
+            // Take the dialog instance and wait for the success message to be shown
+            this._dialog.connect('success-message-shown', () => {
+                // A new valid code unlocked the machine and user has no
+                // password set -> Go straight to the user's session.
+                if (user.password_mode == AccountsService.UserPasswordMode.NONE) {
+                    this.deactivate(false);
+                    return;
+                }
+
+                let paygExpectedMode = this._isGreeter ? 'gdm-unlock-dialog-payg' : 'unlock-dialog-payg';
+                if (Main.sessionMode.currentMode === paygExpectedMode) {
+                    // This is the most common case.
+                    Main.sessionMode.popMode(paygExpectedMode);
+                }
+
+                // The machine is unlocked but we still need to unlock the
+                // user's session with the password, so don't deactivate yet.
+                if (this._dialog) {
+                    this._dialog.destroy();
+                    this._dialog = null;
+                }
+
+                this.showDialog();
+            });
         });
     }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]