Ver Fonte

Merge pull request #310 from threema-ch/mark-work-contacts

Mark Threema Work users with a suitcase icon

It is displayed for all contacts that use the Threema Work app. This
helps to differentiate private and work-related contacts.

App support is required, so this may not be displayed yet for people
that use an older app version.
Danilo Bargen há 8 anos atrás
pai
commit
c1030c7d49

+ 2 - 1
public/i18n/de.json

@@ -148,7 +148,8 @@
         "MESSAGE_TOO_LONG_SPLIT_SUBJECT": "Nachricht aufteilen.",
         "MESSAGE_TOO_LONG_SPLIT_BODY": "Es werden maximal {max} Zeichen pro Nachricht unterstützt, wollen Sie die Nachricht in {count} separate Nachrichten aufteilen?",
         "BALLOT_MESSAGES_NOT_SUPPORTED": "Umfragen werden in Threema Web derzeit nicht untersützt.",
-        "NICKNAME": "Nickname"
+        "NICKNAME": "Nickname",
+        "THREEMA_WORK_CONTACT": "Threema Work Nutzer"
     },
     "messageTypes": {
         "AUDIO_MESSAGE": "Sprachnachricht",

+ 2 - 1
public/i18n/en.json

@@ -149,7 +149,8 @@
         "MESSAGE_TOO_LONG_SPLIT_SUBJECT": "Split Message",
         "MESSAGE_TOO_LONG_SPLIT_BODY": "No more than {max} characters can be sent per message, do you want to split it into {count} separate messages?",
         "BALLOT_MESSAGES_NOT_SUPPORTED": "Ballot messages are not yet supported in Threema Web.",
-        "NICKNAME": "Nickname"
+        "NICKNAME": "Nickname",
+        "THREEMA_WORK_CONTACT": "Threema Work user"
     },
     "messageTypes": {
         "AUDIO_MESSAGE": "Audio Message",

+ 37 - 0
public/img/ic_work_round.svg

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+    xmlns:dc="http://purl.org/dc/elements/1.1/"
+    xmlns:cc="http://creativecommons.org/ns#"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns:svg="http://www.w3.org/2000/svg"
+    xmlns="http://www.w3.org/2000/svg"
+    id="svg8"
+    version="1.1"
+    viewBox="0 0 16.933334 16.933334"
+    height="16.933334mm"
+    width="16.933334mm">
+    <g
+        transform="translate(30.994049,-246.80477)"
+        id="layer1">
+        <g
+            transform="matrix(0.06666667,0,0,0.06666667,-28.927779,246.15556)"
+            id="g4703">
+            <circle
+                style="fill:#ffffff;stroke-width:0.29123756"
+                id="path3889"
+                cx="96.005951"
+                cy="136.7381"
+                r="127" />
+            <circle
+                style="fill:#2196f3;fill-opacity:1;stroke-width:0.28050515"
+                id="path3893"
+                cx="96.005951"
+                cy="136.7381"
+                r="113.20387" />
+            <path
+                id="path3876"
+                d="M 141.10752,102.87344 H 118.54037 V 91.589898 c 0,-6.234187 -5.0494,-11.283652 -11.28359,-11.283652 H 84.689614 c -6.23418,0 -11.283578,5.049465 -11.283578,11.283652 V 102.87344 H 50.838871 c -6.234177,0 -11.227166,5.04936 -11.227166,11.28355 l -0.05651,62.05976 c 0,6.23419 5.049411,11.28355 11.283588,11.28355 h 90.268657 c 6.23418,0 11.28359,-5.04936 11.28359,-11.28355 v -62.05976 c -2e-5,-6.23419 -5.04944,-11.28355 -11.28361,-11.28355 z m -33.85074,0 H 84.689614 V 91.589898 h 22.567166 z"
+                style="fill:#ffffff;stroke-width:2.82089496" />
+        </g>
+    </g>
+</svg>

+ 11 - 0
src/directives/avatar.ts

@@ -96,12 +96,23 @@ export default [
                         loadingPromise = null;
                     }
                 };
+
+                this.showWorkIndicator = () => {
+                    return this.type === 'contact'
+                        && !this.highResolution
+                        && (this.receiver as threema.ContactReceiver).identityType === threema.IdentityType.Work;
+                };
             }],
             template: `
                 <div class="avatar" ng-class="ctrl.avatarClass()">
                     <div class="avatar-loading" ng-if="ctrl.isLoading">
                         <span></span>
                     </div>
+                    <div class="work-indicator" ng-if="ctrl.showWorkIndicator()"
+                        translate-attr="{'aria-label': 'messenger.THREEMA_WORK_CONTACT',
+                            'title': 'messenger.THREEMA_WORK_CONTACT'}">
+                        <img src="img/ic_work_round.svg" alt="Threema Work user">
+                    </div>
                     <img
                          ng-class="ctrl.avatarClass()"
                          ng-style="{ 'background-color': ctrl.backgroundColor }"

+ 0 - 1
src/directives/member_list_editor.ts

@@ -86,7 +86,6 @@ export default [
             template: `
                 <ul class="member-list">
                     <li>
-
                         <md-autocomplete
                                 md-no-cache="false"
                                 md-delay="200"

+ 11 - 4
src/partials/messenger.receiver/contact.html

@@ -9,10 +9,17 @@
 		<md-card-content>
 			<dl class="key-values">
 				<dt>Threema ID</dt>
-				<dd>{{ctrl.receiver.id}}
-					<eee-verification-level
-							contact="ctrl.receiver">
-					</eee-verification-level></dd>
+				<dd>
+					<span class="complex-values">
+						<span>{{ctrl.receiver.id}}</span>
+						<span class="indicator-icon" ng-if="ctrl.isWorkReceiver"
+							  translate-attr="{'aria-label': 'messenger.THREEMA_WORK_CONTACT',
+								'title': 'messenger.THREEMA_WORK_CONTACT'}">
+								<img src="img/ic_work_round.svg" alt="Threema Work user">
+						</span>
+						<eee-verification-level contact="ctrl.receiver"></eee-verification-level>
+					</span>
+				</dd>
 
 				<dt><span translate>messenger.KEY_FINGERPRINT</span></dt>
 				<dd>{{ ctrl.fingerPrint }}</dd>

+ 2 - 0
src/partials/messenger.ts

@@ -937,6 +937,7 @@ class ReceiverDetailController {
     private inDistributionLists: threema.DistributionListReceiver[] = [];
     private hasSystemEmails = false;
     private hasSystemPhones = false;
+    private isWorkReceiver = false;
 
     private controllerModel: threema.ControllerModel;
 
@@ -969,6 +970,7 @@ class ReceiverDetailController {
                     // do nothing
                 });
 
+            this.isWorkReceiver = contactReceiver.identityType === threema.IdentityType.Work;
             this.fingerPrint = this.fingerPrintService.generate(contactReceiver.publicKey);
             webClientService.groups.forEach((groupReceiver: threema.GroupReceiver) => {
                 // check if my identity is a member

+ 18 - 4
src/sass/components/_avatar.scss

@@ -1,4 +1,10 @@
 .avatar {
+    position: relative;
+    > img {
+        width: 100%;
+    }
+
+    // Different resolutions
     &.avatar-low {
         > img {
             width: 48px;
@@ -11,9 +17,10 @@
         max-height: 540px;
     }
 
+    // Loading indicator
     &.is-loading {
-        //show default blured
         &.avatar-high {
+            // Show default blured
             > img {
                 filter: blur(40px);
                 border-radius: 0;
@@ -36,9 +43,16 @@
             top: calc(50% - #{$circle-diameter / 2});
         }
     }
-    > img {
-        width: 100%;
-    }
 
+    // Indicators depending on identity type (e.g. Work suitcase)
+    .work-indicator {
+        $indicator-size: 18px;
+        position: absolute;
+        top: 48px - $indicator-size;
+        img {
+            width: $indicator-size;
+            height: $indicator-size;
+        }
+    }
 
 }

+ 18 - 8
src/sass/components/_receiver_badge.scss

@@ -1,14 +1,24 @@
 .md-autocomplete-suggestions{
     $avatar-size-in-autocomplete: 30px;
-  .receiver-badge {
-    .avatar-box {
-      max-height: $avatar-size-in-autocomplete;
-      img {
-        max-height: $avatar-size-in-autocomplete;
-        width: auto;
-      }
+    .receiver-badge {
+        .avatar-box {
+            height: $avatar-size-in-autocomplete;
+            img {
+                height: $avatar-size-in-autocomplete;
+                width: auto;
+            }
+            .work-indicator {
+                // Override configuration.
+                // This is a bit of a hack
+                $indicator-size: 12px;
+                top: $avatar-size-in-autocomplete - $indicator-size - 18px;
+                img {
+                    width: $indicator-size;
+                    height: $indicator-size;
+                }
+            }
+        }
     }
-  }
 }
 .receiver-badge {
   display: flex;

+ 20 - 1
src/sass/layout/_main.scss

@@ -293,8 +293,27 @@ a.threema-action {
 
     dd {
         word-break: normal;
-        display: block;
         margin-bottom: $main-padding*2;
+        display: block;
+
+        > .complex-values {
+            display: flex;
+            justify-items: center;
+            align-items: center;
+            flex-direction: row;
+
+            > *:not(:last-child) {
+                margin-right: $main-padding;
+            }
+            .indicator-icon {
+                $indicator-size: 18px;
+                top: 48px - $indicator-size;
+                img {
+                    width: $indicator-size;
+                    height: $indicator-size;
+                }
+            }
+        }
     }
 }
 

+ 45 - 2
src/threema.d.ts

@@ -139,6 +139,11 @@ declare namespace threema {
         canChangeMembers?: boolean;
     }
 
+    const enum IdentityType {
+        Regular = 0,
+        Work
+    }
+
     /**
      * The base class for a receiver. Only type and id.
      */
@@ -154,11 +159,22 @@ declare namespace threema {
      * of a certain type. The primary key for a receiver is the tuple (type, id).
      */
     interface Receiver extends BaseReceiver {
+        // The display name
         displayName: string;
+
+        // The color used for the avatar
         color: string;
-        avatar?: Avatar; // May be set if already fetched
+
+        // The avatar, may be set if already fetched
+        avatar?: Avatar;
+
+        // Permissions towards this receiver
         access: ReceiverAccess;
+
+        // Whether the chat with this receiver is locked.
         locked?: boolean;
+
+        // Whether the chat with this receiver is visible.
         visible?: boolean;
     }
 
@@ -166,17 +182,44 @@ declare namespace threema {
      * A contact.
      */
     interface ContactReceiver extends Receiver {
+        // Flag indicating whether this is the own profile or another contact
         type: 'contact' | 'me';
+
+        // Public nickname, if set
         publicNickname?: string;
+
+        // First name, if set
         firstName?: string;
+
+        // Last name, if set
         lastName?: string;
+
+        // Verification level integer (1-3)
         verificationLevel?: number;
-        state: string;
+
+        // Feature level (0-3)
         featureLevel: number | null;
+
+        // The identity state
+        state: 'ACTIVE' | 'INACTIVE';
+
+        // The Threema public key
         publicKey: ArrayBuffer;
+
+        // System confact information
         systemContact?: SystemContact;
+
+        // Permissions towards this contact
         access: ContactReceiverAccess;
+
+        // Whether this is a contact from the same Threema Work package.
+        // Only relevant for Threema Work users.
         isWork?: boolean;
+
+        // The identity type.
+        // 0 - Regular Threema user.
+        // 1 - Threema Work user.
+        identityType?: IdentityType;
     }
 
     /**