Просмотр исходного кода

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 лет назад
Родитель
Сommit
ac079f0f83
4 измененных файлов с 105 добавлено и 4 удалено
  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;
 }

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
internal/auto/gui.files.go


Некоторые файлы не были показаны из-за большого количества измененных файлов