avatar_area.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * This file is part of Threema Web.
  3. *
  4. * Threema Web is free software: you can redistribute it and/or modify it
  5. * under the terms of the GNU Affero General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or (at
  7. * your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Affero General Public License
  15. * along with Threema Web. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. // tslint:disable:max-line-length
  18. import {bufferToUrl, logAdapter} from '../helpers';
  19. import {WebClientService} from '../services/webclient';
  20. /**
  21. * Support uploading and resizing avatar
  22. */
  23. export default [
  24. '$rootScope',
  25. '$log',
  26. '$mdDialog',
  27. 'WebClientService',
  28. function($rootScope: ng.IRootScopeService,
  29. $log: ng.ILogService,
  30. $mdDialog: ng.material.IDialogService,
  31. webClientService: WebClientService) {
  32. return {
  33. restrict: 'EA',
  34. scope: true,
  35. bindToController: {
  36. onChange: '=',
  37. loadAvatar: '=',
  38. enableClear: '=?',
  39. color: '=?',
  40. },
  41. controllerAs: 'ctrl',
  42. controller: [function() {
  43. const logTag = '[AvatarAreaDirective]';
  44. this.isLoading = false;
  45. this.avatar = null; // String
  46. const avatarFormat = webClientService.appCapabilities.imageFormat.avatar;
  47. this.$onInit = function() {
  48. this.setAvatar = (avatarBytes: ArrayBuffer) => {
  49. this.avatar = (avatarBytes === null)
  50. ? null
  51. : bufferToUrl(avatarBytes, avatarFormat, logAdapter($log.warn, logTag));
  52. };
  53. this.imageChanged = (image: ArrayBuffer, notify = true) => {
  54. this.isLoading = true;
  55. if (notify === true && this.onChange !== undefined) {
  56. this.onChange(image);
  57. }
  58. this.setAvatar(image);
  59. this.isLoading = false;
  60. };
  61. if (this.loadAvatar !== undefined) {
  62. this.isLoading = true;
  63. (this.loadAvatar as Promise<ArrayBuffer>)
  64. .then((image: ArrayBuffer) => {
  65. $rootScope.$apply(() => {
  66. this.setAvatar(image);
  67. this.isLoading = false;
  68. });
  69. })
  70. .catch(() => {
  71. $rootScope.$apply(() => {
  72. this.isLoading = false;
  73. });
  74. });
  75. }
  76. this.delete = () => {
  77. this.imageChanged(null, true);
  78. };
  79. // show editor in a dialog
  80. this.modify = (ev) => {
  81. $mdDialog.show({
  82. controllerAs: 'ctrl',
  83. controller: function() {
  84. this.avatar = null;
  85. this.apply = () => $mdDialog.hide(this.avatar);
  86. this.cancel = () => $mdDialog.cancel();
  87. this.changeAvatar = (image: ArrayBuffer) => this.avatar = image;
  88. },
  89. template: `
  90. <md-dialog translate-attr="{'aria-label': 'messenger.UPLOAD_AVATAR'}">
  91. <form ng-cloak>
  92. <md-toolbar>
  93. <div class="md-toolbar-tools">
  94. <h2 translate>messenger.UPLOAD_AVATAR</h2>
  95. </div>
  96. </md-toolbar>
  97. <md-dialog-content>
  98. <div class="md-dialog-content avatar-area editor">
  99. <avatar-editor on-change="ctrl.changeAvatar"></avatar-editor>
  100. </div>
  101. </md-dialog-content>
  102. <md-dialog-actions layout="row" >
  103. <md-button ng-click="ctrl.cancel()">
  104. <span translate>common.CANCEL</span>
  105. </md-button>
  106. <md-button ng-click="ctrl.apply()">
  107. <span translate>common.OK</span>
  108. </md-button>
  109. </md-dialog-actions>
  110. </form>
  111. </md-dialog>
  112. `,
  113. parent: angular.element(document.body),
  114. targetEvent: ev,
  115. clickOutsideToClose: true,
  116. })
  117. .then((newImage: ArrayBuffer) => {
  118. // update image only if a image was set or if enable clear is true
  119. if (this.enableClear === true || newImage !== null) {
  120. this.imageChanged(newImage, true);
  121. }
  122. }, () => null);
  123. };
  124. };
  125. }],
  126. template: `
  127. <div class="avatar-area overview">
  128. <div class="avatar-image" ng-style="{ 'background-color': ctrl.color }">
  129. <div class="loading-element" ng-class="{'active': ctrl.isLoading}">
  130. <md-progress-circular
  131. class="md-primary"
  132. md-diameter="96"></md-progress-circular>
  133. </div>
  134. <img ng-src="{{ ctrl.avatar }}" ng-if="ctrl.avatar !== null">
  135. </div>
  136. <div class="avatar-area-navigation" layout="row" layout-wrap layout-margin layout-align="center">
  137. <md-button type="submit" class="md-raised" ng-click="ctrl.delete()" ng-if="ctrl.enableClear === true">
  138. <span translate>common.DELETE</span>
  139. </md-button>
  140. <md-button type="submit" class="md-raised md-primary" ng-click="ctrl.modify()">
  141. <span translate>messenger.UPLOAD_AVATAR</span>
  142. </md-button>
  143. </div>
  144. </div>
  145. </div>
  146. `,
  147. };
  148. },
  149. ];