Parcourir la source

Merge pull request #265 from threema-ch/2-battery-level

Show battery status indicator
Danilo Bargen il y a 8 ans
Parent
commit
f3f2195569

+ 2 - 0
src/directives.ts

@@ -21,6 +21,7 @@ import autofocus from './directives/autofocus';
 import avatar from './directives/avatar';
 import avatarArea from './directives/avatar_area';
 import avatarEditor from './directives/avatar_editor';
+import batteryStatus from './directives/battery';
 import composeArea from './directives/compose_area';
 import contactBadge from './directives/contact_badge';
 import distributionListBadge from './directives/distribution_list_badge';
@@ -50,6 +51,7 @@ import verificationLevel from './directives/verification_level';
 angular.module('3ema.directives').directive('autofocus', autofocus);
 angular.module('3ema.directives').directive('avatarArea', avatarArea);
 angular.module('3ema.directives').directive('avatarEditor', avatarEditor);
+angular.module('3ema.directives').directive('batteryStatus', batteryStatus);
 angular.module('3ema.directives').directive('composeArea', composeArea);
 angular.module('3ema.directives').directive('eeeAvatar', avatar);
 angular.module('3ema.directives').directive('eeeContactBadge', contactBadge);

+ 56 - 0
src/directives/battery.ts

@@ -0,0 +1,56 @@
+/**
+ * This file is part of Threema Web.
+ *
+ * Threema Web is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Threema Web. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import {BatteryStatusService} from '../services/battery';
+
+export default [
+    '$rootScope',
+    'BatteryStatusService',
+    function($rootScope: ng.IRootScopeService,
+             batteryStatusService: BatteryStatusService) {
+        return {
+            restrict: 'E',
+            scope: {},
+            bindToController: {},
+            controllerAs: 'ctrl',
+            controller: [function() {
+                this.available = () => batteryStatusService.dataAvailable;
+                this.percent = () => batteryStatusService.percent;
+                this.isCharging = () => batteryStatusService.isCharging;
+                this.alert = () => batteryStatusService.percent < 20;
+                this.showPercent = () => !this.alert() && !this.isCharging();
+            }],
+            template: `
+                <div class="battery-status" ng-if="ctrl.available()" ng-class="{'with-percent': ctrl.showPercent()}">
+                    <md-icon ng-if="ctrl.isCharging()"
+                             aria-label="Battery status: Charging"
+                             title="Charging: {{ ctrl.percent() }}%"
+                             class="material-icons md-light md-24">battery_charging_full</md-icon>
+                    <md-icon ng-if="!ctrl.isCharging() && !ctrl.alert()"
+                             aria-label="Battery status: Discharging"
+                             title="Discharging: {{ ctrl.percent() }}%"
+                             class="material-icons md-light md-24">battery_std</md-icon>
+                    <span ng-if="ctrl.showPercent()" class="battery-percent">{{ ctrl.percent() }}%</span>
+                    <md-icon ng-if="!ctrl.isCharging() && ctrl.alert()"
+                             aria-label="Battery status: Alert"
+                             title="Discharging: {{ ctrl.percent() }}%"
+                             class="material-icons md-light md-24">battery_alert</md-icon>
+                </div>
+            `,
+        };
+    },
+];

+ 2 - 0
src/partials/messenger.navigation.html

@@ -3,6 +3,8 @@
     <div class="my-identity-content" eee-my-identity
             eee-identity="ctrl.getMyIdentity()"></div>
 
+    <battery-status></battery-status>
+
     <md-menu md-position-mode="target-right target" md-offset="0 45">
         <md-button aria-label="Open menu" class="md-icon-button" ng-click="$mdOpenMenu($event)">
             <i class="material-icons md-light md-24">more_vert</i>

+ 1 - 0
src/sass/app.scss

@@ -45,6 +45,7 @@
 @import "components/mediabox";
 @import "components/backbutton";
 @import "components/emoji";
+@import "components/battery";
 
 // Sections: Styles specific to individual pages or sections.
 @import "sections/header";

+ 24 - 0
src/sass/components/_battery.scss

@@ -0,0 +1,24 @@
+.battery-status {
+    position: relative;
+    top: -12px;
+    right: 24px;
+
+    &.with-percent {
+        top: -18px;
+    }
+
+    md-icon, span {
+        width: 24px;
+        height: 24px;
+        line-height: 24px;
+        position: absolute;
+    }
+
+    .battery-percent {
+        font-size: 0.8em;
+        font-family: monospace;
+        text-align: center;
+        top: 20px;
+        left: 1px;
+    }
+}

+ 2 - 0
src/services.ts

@@ -15,6 +15,7 @@
  * along with Threema Web. If not, see <http://www.gnu.org/licenses/>.
  */
 
+import {BatteryStatusService} from './services/battery';
 import {BrowserService} from './services/browser';
 import {ContactService} from './services/contact';
 import {ControllerService} from './services/controller';
@@ -40,6 +41,7 @@ import {WebClientService} from './services/webclient';
 angular.module('3ema.services', [])
 
 // Register services
+.service('BatteryStatusService', BatteryStatusService)
 .service('ContactService', ContactService)
 .service('ControllerModelService', ControllerModelService)
 .service('FingerPrintService', FingerPrintService)

+ 57 - 0
src/services/battery.ts

@@ -0,0 +1,57 @@
+/**
+ * This file is part of Threema Web.
+ *
+ * Threema Web is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Threema Web. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+export class BatteryStatusService {
+    // Attributes
+    private batteryStatus: threema.BatteryStatus = null;
+
+    /**
+     * Update the battery status.
+     */
+    public setStatus(batteryStatus: threema.BatteryStatus): void {
+        this.batteryStatus = batteryStatus;
+    }
+
+    /**
+     * Is battery status information available?
+     */
+    public get dataAvailable(): boolean {
+        return this.batteryStatus !== null;
+    }
+
+    /**
+     * Return the charge level in percent.
+     */
+    public get percent(): number {
+        return this.batteryStatus.percent;
+    }
+
+    /**
+     * Return whether the battery is currently charging.
+     */
+    public get isCharging(): boolean {
+        return this.batteryStatus.isCharging;
+    }
+
+    public toString(): string {
+        if (this.batteryStatus === null) {
+            return 'No data';
+        }
+        return this.percent + '%, ' + (this.isCharging ? 'charging' : 'discharging');
+    }
+
+}

+ 52 - 13
src/services/webclient.ts

@@ -17,6 +17,7 @@
 
 import * as msgpack from 'msgpack-lite';
 import {hexToU8a} from '../helpers';
+import {BatteryStatusService} from './battery';
 import {BrowserService} from './browser';
 import {FingerPrintService} from './fingerprint';
 import {TrustedKeyStoreService} from './keystore';
@@ -94,6 +95,7 @@ export class WebClientService {
     private static SUB_TYPE_DISTRIBUTION_LIST = 'distributionList';
     private static SUB_TYPE_ALERT = 'alert';
     private static SUB_TYPE_GROUP_SYNC = 'groupSync';
+    private static SUB_TYPE_BATTERY_STATUS = 'batteryStatus';
     private static ARGUMENT_MODE = 'mode';
     private static ARGUMENT_MODE_REFRESH = 'refresh';
     private static ARGUMENT_MODE_NEW = 'new';
@@ -135,15 +137,16 @@ export class WebClientService {
     private $timeout: ng.ITimeoutService;
 
     // Custom services
-    private notificationService: NotificationService;
-    private messageService: MessageService;
-    private pushService: PushService;
+    private batteryStatusService: BatteryStatusService;
     private browserService: BrowserService;
-    private titleService: TitleService;
     private fingerPrintService: FingerPrintService;
-    private qrCodeService: QrCodeService;
+    private messageService: MessageService;
     private mimeService: MimeService;
+    private notificationService: NotificationService;
+    private pushService: PushService;
+    private qrCodeService: QrCodeService;
     private receiverService: ReceiverService;
+    private titleService: TitleService;
     private versionService: VersionService;
 
     // State handling
@@ -196,7 +199,7 @@ export class WebClientService {
         'Container', 'TrustedKeyStore',
         'StateService', 'NotificationService', 'MessageService', 'PushService', 'BrowserService',
         'TitleService', 'FingerPrintService', 'QrCodeService', 'MimeService', 'ReceiverService',
-        'VersionService',
+        'VersionService', 'BatteryStatusService',
         'CONFIG',
     ];
     constructor($log: ng.ILogService,
@@ -219,7 +222,8 @@ export class WebClientService {
                 qrCodeService: QrCodeService,
                 mimeService: MimeService,
                 receiverService: ReceiverService,
-                VersionService: VersionService,
+                versionService: VersionService,
+                batteryStatusService: BatteryStatusService,
                 CONFIG: threema.Config) {
 
         // Angular services
@@ -233,16 +237,17 @@ export class WebClientService {
         this.$timeout = $timeout;
 
         // Own services
-        this.notificationService = notificationService;
-        this.messageService = messageService;
-        this.pushService = pushService;
+        this.batteryStatusService = batteryStatusService;
         this.browserService = browserService;
-        this.titleService = titleService;
         this.fingerPrintService = fingerPrintService;
-        this.qrCodeService = qrCodeService;
+        this.messageService = messageService;
         this.mimeService = mimeService;
+        this.notificationService = notificationService;
+        this.pushService = pushService;
+        this.qrCodeService = qrCodeService;
         this.receiverService = receiverService;
-        this.versionService = VersionService;
+        this.titleService = titleService;
+        this.versionService = versionService;
 
         // Configuration object
         this.config = CONFIG;
@@ -705,6 +710,14 @@ export class WebClientService {
         });
     }
 
+    /**
+     * Send a battery status request.
+     */
+    public requestBatteryStatus(): void {
+        this.$log.debug('Sending battery status request');
+        this._sendRequest(WebClientService.SUB_TYPE_BATTERY_STATUS);
+    }
+
     /**
      * Send a message request for the specified receiver.
      *
@@ -1322,6 +1335,7 @@ export class WebClientService {
         this.requestClientInfo();
         this.requestReceivers();
         this.requestConversations();
+        this.requestBatteryStatus();
     }
 
     private _receiveResponseReceivers(message: threema.WireMessage) {
@@ -1953,6 +1967,25 @@ export class WebClientService {
         }
     }
 
+    /**
+     * Process an incoming battery status message.
+     */
+    private _receiveUpdateBatteryStatus(message: threema.WireMessage): void {
+        this.$log.debug('Received battery status');
+
+        // Unpack data and arguments
+        const data = message.data as threema.BatteryStatus;
+        if (data === undefined) {
+            this.$log.warn('Invalid battery status message, data missing');
+            return;
+        }
+
+        // Set battery status
+        this.batteryStatusService.setStatus(data);
+
+        this.$log.debug('[BatteryStatusService]', this.batteryStatusService.toString());
+    }
+
     /**
      * The peer sends the device information string. This can be used to
      * identify the active session.
@@ -2282,6 +2315,9 @@ export class WebClientService {
             case WebClientService.SUB_TYPE_GROUP_SYNC:
                 receiveResult = this._receiveGroupSync(message);
                 break;
+            case WebClientService.SUB_TYPE_BATTERY_STATUS:
+                this._receiveUpdateBatteryStatus(message);
+                break;
             default:
                 this.$log.warn('Ignored response with type:', type);
                 return;
@@ -2303,6 +2339,9 @@ export class WebClientService {
             case WebClientService.SUB_TYPE_TYPING:
                 this._receiveUpdateTyping(message);
                 break;
+            case WebClientService.SUB_TYPE_BATTERY_STATUS:
+                this._receiveUpdateBatteryStatus(message);
+                break;
             case WebClientService.SUB_TYPE_CONTACT:
                 receiveResult = this._receiveResponseContact(message);
                 break;

+ 6 - 1
src/threema.d.ts

@@ -44,7 +44,7 @@ declare namespace threema {
 
     type MessageType = 'text' | 'image' | 'video' | 'audio' | 'location' | 'status' | 'ballot' | 'file';
     type MessageState = 'delivered' | 'read' | 'send-failed' | 'sent' | 'user-ack' | 'user-dec' | 'pending' | 'sending';
-    type InitializationStep = 'client info' | 'conversations' |  'receivers';
+    type InitializationStep = 'client info' | 'conversations' | 'receivers';
 
     interface InitializationStepRoutine {
         requiredSteps: InitializationStep[];
@@ -405,6 +405,11 @@ declare namespace threema {
         OPERA: number;
     }
 
+    interface BatteryStatus {
+        percent: number;
+        isCharging: boolean;
+    }
+
     namespace Container {
         interface ReceiverData {
             me: MeReceiver;