Quellcode durchsuchen

Contact sorting: Make it locale aware

On supported platforms, this will sort with proper handling of casing
and accented characters.
Danilo Bargen vor 7 Jahren
Ursprung
Commit
73fc848162
3 geänderte Dateien mit 54 neuen und 10 gelöschten Zeilen
  1. 28 1
      src/services/browser.ts
  2. 26 0
      src/services/webclient.ts
  3. 0 9
      src/threema/container.ts

+ 28 - 1
src/services/browser.ts

@@ -18,13 +18,15 @@
 import BrowserName = threema.BrowserName;
 
 export class BrowserService {
+    private logTag: string = '[BrowserService]';
+
     private browser: threema.BrowserInfo;
     private $log: ng.ILogService;
     private $window: ng.IWindowService;
     private isPageVisible = true;
+    private supportsExtendedLocaleCompareCache: boolean;
 
     public static $inject = ['$log', '$window'];
-
     constructor($log: ng.ILogService, $window: ng.IWindowService) {
         // Angular services
         this.$log = $log;
@@ -184,4 +186,29 @@ export class BrowserService {
         }
         return true;
     }
+
+    /**
+     * Return whether the browser supports extended `string.localeCompare` options.
+     */
+    public supportsExtendedLocaleCompare() {
+        if (this.supportsExtendedLocaleCompareCache !== undefined) {
+            return this.supportsExtendedLocaleCompareCache;
+        }
+
+        function getSupport(): boolean {
+            try {
+                'foo'.localeCompare('bar', 'i');
+            } catch (e) {
+                return e.name === 'RangeError';
+            }
+            return false;
+        }
+
+        const support = getSupport();
+        this.supportsExtendedLocaleCompareCache = support;
+        this.$log.debug(this.logTag, 'Browser',
+            support ? 'supports' : 'does not support',
+            'extended locale compare options');
+        return support;
+    }
 }

+ 26 - 0
src/services/webclient.ts

@@ -1698,6 +1698,7 @@ export class WebClientService {
         }
 
         // Store receivers
+        this.sortContacts(data.contact);
         this.receivers.set(data);
         this.registerInitializationStep(InitializationStep.Receivers);
     }
@@ -2171,6 +2172,7 @@ export class WebClientService {
         // Refresh lists of receivers
         switch (type) {
             case 'contact':
+                this.sortContacts(data);
                 this.receivers.setContacts(data);
                 break;
             case 'group':
@@ -3132,4 +3134,28 @@ export class WebClientService {
     public get appCapabilities(): threema.AppCapabilities {
         return this.clientInfo.capabilities;
     }
+
+    /**
+     * Sort a list of contacts in-place.
+     */
+    private sortContacts(contacts: threema.ContactReceiver[]): void {
+        const getSortableName = (name: string) => name.startsWith('~') ? name.substr(1) : name;
+
+        let options;
+        if (this.browserService.supportsExtendedLocaleCompare()) {
+            options = {
+                usage: 'sort',
+                sensitivity: 'variant',
+            };
+        }
+
+        const compareFunc = (a: threema.Receiver, b: threema.Receiver) => {
+            if (a.id.startsWith('*') && !b.id.startsWith('*')) { return 1; }
+            if (!a.id.startsWith('*') && b.id.startsWith('*')) { return -1; }
+            const left = getSortableName(a.displayName);
+            const right = getSortableName(b.displayName);
+            return left.localeCompare(right, undefined, options);
+        };
+        contacts.sort(compareFunc);
+    }
 }

+ 0 - 9
src/threema/container.ts

@@ -120,15 +120,6 @@ class Receivers implements threema.Container.Receivers {
      * Set contacts.
      */
     public setContacts(data: threema.ContactReceiver[]): void {
-        data.sort((a: threema.Receiver, b: threema.Receiver) => {
-            if (a.id.startsWith('*') && !b.id.startsWith('*')) { return 1; }
-            if (!a.id.startsWith('*') && b.id.startsWith('*')) { return -1; }
-            const left = a.displayName.startsWith('~') ? a.displayName.substr(1) : a.displayName;
-            const right = b.displayName.startsWith('~') ? b.displayName.substr(1) : b.displayName;
-            if (left < right) { return -1; }
-            if (left > right) { return 1; }
-            return 0;
-        });
         this.contacts = new Map(data.map((c) => {
             c.type = 'contact';
             return [c.id, c];