Browse Source

Implement identicon representation for devices.

The first fifteen characters of device IDs are now used to procedurally
generate psuedo-unique avatars for their respective devices. The avatars
are represented using SVG elements that replace the icons previously
shown next to device names in the GUI.
Chris Joel 11 years ago
parent
commit
ac079f0f83
4 changed files with 105 additions and 4 deletions
  1. 65 0
      gui/app.js
  2. 2 3
      gui/index.html
  3. 37 0
      gui/overrides.css
  4. 1 1
      internal/auto/gui.files.go

+ 65 - 0
gui/app.js

@@ -1231,3 +1231,68 @@ syncthing.directive('modal', function () {
         },
     };
 });
+
+syncthing.directive('identicon', ['$window', function ($window) {
+  var svgNS = 'http://www.w3.org/2000/svg';
+
+  function Identicon (value, size) {
+    var svg = document.createElementNS(svgNS, 'svg');
+    var shouldFillRectAt = function (row, col) {
+      return !($window.parseInt(value.charCodeAt(row + col * size), 10) % 2);
+    };
+    var shouldMirrorRectAt = function (row, col) {
+      return !(size % 2 && col === middleCol)
+    };
+    var mirrorColFor = function (col) {
+      return size - col - 1;
+    };
+    var fillRectAt = function (row, col) {
+      var rect = document.createElementNS(svgNS, 'rect');
+
+      rect.setAttribute('x', (col * rectSize) + '%');
+      rect.setAttribute('y', (row * rectSize) + '%');
+      rect.setAttribute('width', rectSize + '%');
+      rect.setAttribute('height', rectSize + '%');
+
+      svg.appendChild(rect);
+    };
+    var rect;
+    var row;
+    var col;
+    var middleCol;
+    var rectSize;
+
+    svg.setAttribute('class', 'identicon');
+    size = size || 5;
+    rectSize = 100 / size;
+    middleCol = Math.ceil(size / 2) - 1;
+
+    if (value) {
+      value = value.toString().replace(/[\W_]/i, '');
+
+      for (row = 0; row < size; ++row) {
+        for (col = middleCol; col > -1; --col) {
+          if (shouldFillRectAt(row, col)) {
+            fillRectAt(row, col);
+
+            if (shouldMirrorRectAt(row, col)) {
+              fillRectAt(row, mirrorColFor(col));
+            }
+          }
+        }
+      }
+    }
+
+    return svg;
+  }
+
+  return {
+    restrict: 'E',
+    scope: {
+      value: '='
+    },
+    link: function (scope, element, attributes) {
+      element.append(new Identicon(scope.value));
+    }
+  }
+}]);

+ 2 - 3
gui/index.html

@@ -190,7 +190,7 @@
         <div class="panel panel-default" ng-repeat="deviceCfg in [thisDevice()]">
           <div class="panel-heading" data-toggle="collapse" href="#device-this" style="cursor: pointer">
             <h3 class="panel-title">
-              <span class="glyphicon glyphicon-home"></span>&emsp;{{deviceName(deviceCfg)}}
+              <identicon data-value="deviceCfg.DeviceID"></identicon>&emsp;{{deviceName(deviceCfg)}}
             </h3>
           </div>
           <div id="device-this" class="panel-collapse collapse in">
@@ -236,7 +236,7 @@
           <div class="panel panel-{{deviceClass(deviceCfg)}}" ng-repeat="deviceCfg in otherDevices()">
             <div class="panel-heading" data-toggle="collapse" data-parent="#devices" href="#device-{{$index}}" style="cursor: pointer">
               <h3 class="panel-title">
-                <span class="glyphicon glyphicon-retweet"></span>&emsp;{{deviceName(deviceCfg)}}
+                <identicon data-value="deviceCfg.DeviceID"></identicon>&emsp;{{deviceName(deviceCfg)}}
                 <span class="pull-right hidden-xs">
                   <span ng-if="connections[deviceCfg.DeviceID] && completion[deviceCfg.DeviceID]._total == 100">
                     <span translate>Up to Date</span> (100%)
@@ -822,7 +822,6 @@
     </ul>
   </modal>
 
-
   <script src="angular/angular.min.js"></script>
   <script src="angular/angular-translate.min.js"></script>
   <script src="angular/angular-translate-loader.min.js"></script>

+ 37 - 0
gui/overrides.css

@@ -28,6 +28,43 @@ ul+h5 {
     margin-top: 1.5em;
 }
 
+identicon {
+  display: inline-block;
+  position: relative;
+  width: 1em;
+  height: 1em;
+  line-height: 1em;
+  overflow: visible;
+}
+
+.identicon {
+    width: 30px;
+    height: 30px;
+}
+
+.identicon rect {
+    opacity: 0.5;
+    fill: #aaa;
+}
+
+.panel-heading .identicon {
+    display: block;
+    position: absolute;
+    top: -4px;
+    left: -9px;
+}
+
+.panel-heading {
+    position: relative;
+    overflow: hidden;
+}
+
+[class*="-info"] .identicon rect,
+[class*="-success"] .identicon rect,
+[class*="-primary"] .identicon rect {
+    fill: #fff;
+}
+
 .text-monospace {
     font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
 }

File diff suppressed because it is too large
+ 1 - 1
internal/auto/gui.files.go


Some files were not shown because too many files changed in this diff