Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorChristopher Ng <chrng8@gmail.com>2022-07-30 03:32:16 +0300
committerChristopher Ng <chrng8@gmail.com>2022-09-02 05:22:57 +0300
commitf44d2586b174991002d210efa9568e0b96d92304 (patch)
tree66ad3d1781cf45fc5a04a3c6303c1d31905aeb1b /apps
parentf167fe0ceb7179ef8ae705bb47c44e596196b5d8 (diff)
Remake profile picture saving with Vueenh/27869/avatar
Signed-off-by: Christopher Ng <chrng8@gmail.com>
Diffstat (limited to 'apps')
-rw-r--r--apps/settings/css/settings.css63
-rw-r--r--apps/settings/css/settings.css.map2
-rw-r--r--apps/settings/css/settings.scss70
-rw-r--r--apps/settings/js/settings/personalInfo.js225
-rw-r--r--apps/settings/lib/Settings/Personal/PersonalInfo.php4
-rw-r--r--apps/settings/src/components/PersonalInfo/AvatarSection.vue333
-rw-r--r--apps/settings/src/components/PersonalInfo/DisplayNameSection.vue4
-rw-r--r--apps/settings/src/constants/AccountPropertyConstants.js2
-rw-r--r--apps/settings/src/main-personal-info.js3
-rw-r--r--apps/settings/templates/settings/personal/personal.info.php37
10 files changed, 345 insertions, 398 deletions
diff --git a/apps/settings/css/settings.css b/apps/settings/css/settings.css
index 735d8c0b1fb..ec677434700 100644
--- a/apps/settings/css/settings.css
+++ b/apps/settings/css/settings.css
@@ -93,69 +93,6 @@ input#openid, input#webdav {
background-image: var(--icon-password-dark);
}
-#avatarform .avatardiv {
- margin: 10px auto;
-}
-#avatarform .warning {
- width: 100%;
-}
-#avatarform .jcrop-keymgr {
- display: none !important;
-}
-
-#displayavatar {
- text-align: center;
-}
-
-#uploadavatarbutton, #selectavatar, #removeavatar {
- padding: 21px;
-}
-
-#selectavatar, #removeavatar {
- vertical-align: top;
-}
-
-.jcrop-holder {
- z-index: 500;
-}
-
-#cropper {
- float: left;
- z-index: 500;
- /* float cropper above settings page to prevent unexpected flowing from dynamically sized element */
- position: fixed;
- background-color: rgba(0, 0, 0, 0.2);
- box-sizing: border-box;
- top: 45px;
- left: 0;
- width: 100%;
- height: calc(100% - 45px);
-}
-#cropper .inner-container {
- z-index: 2001;
- /* above the top bar if needed */
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: #fff;
- color: #333;
- border-radius: var(--border-radius-large);
- box-shadow: 0 0 10px var(--color-box-shadow);
- padding: 15px;
-}
-#cropper .inner-container .jcrop-holder,
-#cropper .inner-container .jcrop-holder img,
-#cropper .inner-container img.jcrop-preview {
- border-radius: var(--border-radius);
-}
-#cropper .inner-container .button {
- margin-top: 15px;
-}
-#cropper .inner-container .primary {
- float: right;
-}
-
#personal-settings-avatar-container {
display: inline-grid;
grid-template-columns: 1fr;
diff --git a/apps/settings/css/settings.css.map b/apps/settings/css/settings.css.map
index bdeacb4f959..20327a4557f 100644
--- a/apps/settings/css/settings.css.map
+++ b/apps/settings/css/settings.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../../core/css/variables.scss","settings.scss","../../../core/css/functions.scss"],"names":[],"mappings":";AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA;AAAA;AAAA;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA;AAAA;AAAA;AA4BA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AD3CC;EACC;;;AAIF;AACA;EACC;;;AAGD;AACA;AC6CC;EAEA;;;AD3CD;ACyCC;EAEA;;;ADvCD;ACqCC;EAEA;;;ADnCD;ACiCC;EAEA;;;AD/BD;AC6BC;EAEA;;;AD1BA;EACC;;AAGD;EACC;;AAGD;EACC;;;AAIF;EACC;;;AAGD;EACC;;;AAED;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;AACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;AACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EAGC;;AAGD;EACC;;AAGD;EACC;;;AAKH;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;AAGC;EACC;EACA;EACA;;;AAKH;EACC;;;AAIA;EACC;;AAEA;EACC;;AAIA;EACC;;;AAOH;EAGC;;;AAIF;EACC;EACA;EACA;EACA;;AAEA;EACC;EACA;;AAEA;EACC;;AAIF;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;;;AAMF;EACC;;AACA;EACC;;AACA;EACC;;;AAKH;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAGC;EACA;EACA;;AAGD;EACC;EACA;;;AAMF;EACC;IACC;IACA;;EAEA;IACC;IACA;;EAGD;IACC;IACA;;EAGD;IACC;IACA;IACA;;;AAKH;EACC;IACC;IACA;;EAEA;IACC;;EAGD;IACC;IACA;;EAGD;IACC;IACA;;;AAKH;EACC;IACC;IACA;;EAEA;IACC;;EAGD;IACC;IACA;;EAGD;IACC;IACA;;;AAKH;EACC;EACA;EACA;;AAEA;EACC;;AAIA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAKD;EACC;EACA;EACA;EACA;EACA;;AAKH;EACC;EACA;EACA;EACA;;AAEA;EACC;;AAIF;EACC;;AAGD;EACC;EACA;EACA;EACA;;;AAKF;EACC;EACA;;AAEA;EACC;;AAEA;EACC;;AAGD;EACC;;AAIF;EACC;EACA;;;AAKF;AACA;AACA;EACC;EACA;EACA;EACA;;AAEA;EACC;;AAGD;EACC;EACA;EACA;;;AAIF;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEC;EACA;;AAEA;EACC;;AAIF;EACC;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAIF;EACC;;AAGC;EAEC;EACA;;AAEA;EACC;;AAGD;EACC;;AAEA;EACC;;AAIF;EACC;EAEA;;AAEA;EACC;;;AAQN;EACC;;;AAGD;EACC;;;AAIA;EACC;;AAGD;EACC;;;AAIF;AAAA;EAEC;;;AAGD;EACC;;;AAGD;EACC;;;AAIA;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;;;AAMD;EACC;;AAGD;EACC;;;AAKD;EACC;EACA;EACA;EACA;;AACA;EACC;EACA;EACA;;AACA;EACC;;AAIF;EACC;EACA;EACA;;AAKA;EACC;EACA;;AAED;EACC;EACA;EACA;EACA;;AAIF;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;;AAKH;AAGC;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;;;AAIF;AAGC;EACC;EACA;EACA;EACA;;AAGD;EACC;;;AAKD;AAAA;EAEC;;;AAKD;AAAA;EAEC;;;AAIF;EACC;EACA;EACA;;AAEA;EACC;;AAGD;EACC;;;AAIF;AACA;EACC;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAKD;EACC;EACA;EACA;EACA;EACA;;AAGD;EACC;;AAEA;EACC;;AAIF;EACC;;AAGD;EAEC;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;;AAIF;EACC;;AAGD;EACC;EACA;;;AAIF;EACC;;;AAGD;AACA;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AACC;;AACA;EACC;EACA;EACA;;AAGD;EACC;;AAIA;EACC;;AAIF;EACC;;AAGD;EACC;;AAGD;EACC;;;AAIF;EACC;EACA;EACA;;;AAGD;EACC;;;AAIA;EACC;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAIF;EACC;EACA;EACA;;;AAIA;EACC;;;AAMD;EACC;;AAGD;EACC;EACA;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;EACA;;AAGD;EACC;;AAGD;EACC;;;AAMA;AAAA;EAEC;EACA;EACA;EACA;EACA;;AAIF;EACC;EACA;;AAEA;AAAA;EAEC;;AAGD;EACC;;AAIF;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;;AAEA;EACC;;AAIF;EACC;EACA;;AAGD;AAAA;AAAA;AAAA;AAAA;EAKC;;;AAIF;EACC;IACC;;;EAED;IACC;;;AAIF;EACC;IACC;;;EAED;IACC;;;AAIF;EACC;IACC;;;EAED;IACC;;;AAIF;EACC;IACC;;;EAED;IACC;;;AAIF;EACC;IACC;;;AAIF;EACC;IACC;;;AAIF;AACA;EAEE;IACC;;;AAKH;EACC;IACC;;;AAIF;EACC;;;AAGD;EACC;AACA;AAKA;;AAJA;EACC;;AAID;EACC;;AAEA;EACC;EACA;EACA;;;AAKH;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AAEA;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EAyGC;EACA;EACA;AAkDA;;AAzJA;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC,QAfgB;EAgBhB,SAjBiB;EAmBjB,cAlBgB;EAmBhB;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EAQC;;AAPA;EACC;EACA;EACA;EACA,YAjCe;;AAsChB;EACC;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;;AAKF;EACC;;AAEA;EACC;;AAIF;EACC;EACA;EACA;;AAGD;AAAA;EAEC;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;;AAEA;EACC;EACA;EACA;;AAKH;EACC;EACA;AACA;EACA;EACA;EACA;;AAOD;EACC;;AAGD;EACC;EACA;;AAEA;EACC;EACA;;AAGD;EACC;;AAKD;EACC;;AAGD;EACC;;AAGD;EACC;;AAEA;EACC;;AAKD;EACC;;AAKD;EACC;;AAMH;EACC;EACA;;AAEA;EACC;EACA;;AAGD;EACC;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAGD;EACC;;;AAQF;EACC;;;AAKH;AACA;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAOA;AAAA;AAAA;AAAA;EACC;;AAEA;AAAA;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;AAAA;EACC;EACA;EACA;EACA;EACA;;AAGD;AAAA;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;AAAA;EACC;;;AAMF;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;;AAIF;EACC;;;AAGD;EACC;;;AAGD;EACC;AACA;EACA;EACA;EACA;EACA;;;AAGD;AAEA;EACC;EACA;EACA;;;AAGD;AAAA;AAAA;EAGC;;;AAIA;EACC;EACA;EACA;;AAGD;AAAA;EAEC;;;AAIF;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;;AAEA;EACC;;;AAIF;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAIA;EACC;EACA;;AAGD;EACC;;AAGD;EACC;EACA;;;AAKF;AACA;EACC;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAIA;EACC;EACA;;AAEA;EACC;;AAGD;EACC;;AAIF;EACC;EACA;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;;AAKD;EACC;;AAGD;EACC;;;AAIF;EACC;;AAEA;EACC;EACA;;;AAIF;EACC;;;AAGD;EACC;EACA;EACA;;;AAID;AAKC;EACC;EACA;EACA;;AAEA;EAGC;EACA;EACA,YAbgB;EAchB;EACA;EACA;AACA;AAAA;EAEA,uBACE;EAOF;AAMA;AA0DA;;AA9DA;EACC;;AAID;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAOC,WAxCkB;;AA0ClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACC;EACA;EACA;;AAID;EAMC;;AAIF;AAAA;AAAA;EAGC,WA9DkB;;AAgElB;AAAA;AAAA;EACC;EACA;EACA;;AAIF;EACC;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;;AAID;EACC;EACA;EACA;EACA;AAAc;EACd;;AAEA;EACC;;AAIF;EACC;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUC;EACA;EACA;EACA;EACA;;AAKD;EACC;;AAGD;EACC;;AAIF;EACC;;AAGD;AAAA;AAAA;EAGC;EACA;EACA;EACA;AAaA;AA2GA;;AAtHA;AAAA;AAAA;EACC;EACA;;AAIA;AAAA;AAAA;AAAA;AAAA;EACC;;AAKF;AAAA;AAAA;EACC;EACA;;AAGD;AAAA;AAAA;EACC;;AAKA;AAAA;AAAA;AAAA;AAAA;EACC;EACA;;AAIF;AAAA;AAAA;AAAA;AAAA;AAEC;EACA;EACA;EACA;AACA;AAAA;AAAA;EAGA;EACA;EACA;EACA;;AAGD;AAAA;AAAA;EACC;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACC;EACA;EACA;;AAIF;AAAA;AAAA;EACC;EACA;;AAEA;AAAA;AAAA;EACC;;AAIF;AAAA;AAAA;EACC;EACA;EACA;;AAEA;AAAA;AAAA;EACC;;AAIF;AAAA;AAAA;EACC;EACA;;AAEA;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;EACC;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACC;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGC;EACA;;AAKH;AAAA;AAAA;EACC;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACC;EACA;;AAMH;AAAA;AAAA;EACC;;AAKH;EACC;EACA;EACA;EACA;;AAGD;EACC;EACA;;;AAKH;EACI;;;AAGJ;EACE;IACE;;;AAGJ;EACE;IACE","file":"settings.css"} \ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../../core/css/variables.scss","settings.scss","../../../core/css/functions.scss"],"names":[],"mappings":";AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA;AAAA;AAAA;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA;AAAA;AAAA;AA4BA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AD3CC;EACC;;;AAIF;AACA;EACC;;;AAGD;AACA;AC6CC;EAEA;;;AD3CD;ACyCC;EAEA;;;ADvCD;ACqCC;EAEA;;;ADnCD;ACiCC;EAEA;;;AD/BD;AC6BC;EAEA;;;AD3BD;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;AAGC;EACC;EACA;EACA;;;AAKH;EACC;;;AAIA;EACC;;AAEA;EACC;;AAIA;EACC;;;AAOH;EAGC;;;AAIF;EACC;EACA;EACA;EACA;;AAEA;EACC;EACA;;AAEA;EACC;;AAIF;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;;;AAMF;EACC;;AACA;EACC;;AACA;EACC;;;AAKH;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAGC;EACA;EACA;;AAGD;EACC;EACA;;;AAMF;EACC;IACC;IACA;;EAEA;IACC;IACA;;EAGD;IACC;IACA;;EAGD;IACC;IACA;IACA;;;AAKH;EACC;IACC;IACA;;EAEA;IACC;;EAGD;IACC;IACA;;EAGD;IACC;IACA;;;AAKH;EACC;IACC;IACA;;EAEA;IACC;;EAGD;IACC;IACA;;EAGD;IACC;IACA;;;AAKH;EACC;EACA;EACA;;AAEA;EACC;;AAIA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAKD;EACC;EACA;EACA;EACA;EACA;;AAKH;EACC;EACA;EACA;EACA;;AAEA;EACC;;AAIF;EACC;;AAGD;EACC;EACA;EACA;EACA;;;AAKF;EACC;EACA;;AAEA;EACC;;AAEA;EACC;;AAGD;EACC;;AAIF;EACC;EACA;;;AAKF;AACA;AACA;EACC;EACA;EACA;EACA;;AAEA;EACC;;AAGD;EACC;EACA;EACA;;;AAIF;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEC;EACA;;AAEA;EACC;;AAIF;EACC;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAIF;EACC;;AAGC;EAEC;EACA;;AAEA;EACC;;AAGD;EACC;;AAEA;EACC;;AAIF;EACC;EAEA;;AAEA;EACC;;;AAQN;EACC;;;AAGD;EACC;;;AAIA;EACC;;AAGD;EACC;;;AAIF;AAAA;EAEC;;;AAGD;EACC;;;AAGD;EACC;;;AAIA;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;;;AAMD;EACC;;AAGD;EACC;;;AAKD;EACC;EACA;EACA;EACA;;AACA;EACC;EACA;EACA;;AACA;EACC;;AAIF;EACC;EACA;EACA;;AAKA;EACC;EACA;;AAED;EACC;EACA;EACA;EACA;;AAIF;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;;AAKH;AAGC;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;;;AAIF;AAGC;EACC;EACA;EACA;EACA;;AAGD;EACC;;;AAKD;AAAA;EAEC;;;AAKD;AAAA;EAEC;;;AAIF;EACC;EACA;EACA;;AAEA;EACC;;AAGD;EACC;;;AAIF;AACA;EACC;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAKD;EACC;EACA;EACA;EACA;EACA;;AAGD;EACC;;AAEA;EACC;;AAIF;EACC;;AAGD;EAEC;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;;AAIF;EACC;;AAGD;EACC;EACA;;;AAIF;EACC;;;AAGD;AACA;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AACC;;AACA;EACC;EACA;EACA;;AAGD;EACC;;AAIA;EACC;;AAIF;EACC;;AAGD;EACC;;AAGD;EACC;;;AAIF;EACC;EACA;EACA;;;AAGD;EACC;;;AAIA;EACC;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAIF;EACC;EACA;EACA;;;AAIA;EACC;;;AAMD;EACC;;AAGD;EACC;EACA;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;EACA;;AAGD;EACC;;AAGD;EACC;;;AAMA;AAAA;EAEC;EACA;EACA;EACA;EACA;;AAIF;EACC;EACA;;AAEA;AAAA;EAEC;;AAGD;EACC;;AAIF;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;;AAEA;EACC;;AAIF;EACC;EACA;;AAGD;AAAA;AAAA;AAAA;AAAA;EAKC;;;AAIF;EACC;IACC;;;EAED;IACC;;;AAIF;EACC;IACC;;;EAED;IACC;;;AAIF;EACC;IACC;;;EAED;IACC;;;AAIF;EACC;IACC;;;EAED;IACC;;;AAIF;EACC;IACC;;;AAIF;EACC;IACC;;;AAIF;AACA;EAEE;IACC;;;AAKH;EACC;IACC;;;AAIF;EACC;;;AAGD;EACC;AACA;AAKA;;AAJA;EACC;;AAID;EACC;;AAEA;EACC;EACA;EACA;;;AAKH;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AAEA;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EAyGC;EACA;EACA;AAkDA;;AAzJA;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC,QAfgB;EAgBhB,SAjBiB;EAmBjB,cAlBgB;EAmBhB;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EAQC;;AAPA;EACC;EACA;EACA;EACA,YAjCe;;AAsChB;EACC;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;;AAKF;EACC;;AAEA;EACC;;AAIF;EACC;EACA;EACA;;AAGD;AAAA;EAEC;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;;AAEA;EACC;EACA;EACA;;AAKH;EACC;EACA;AACA;EACA;EACA;EACA;;AAOD;EACC;;AAGD;EACC;EACA;;AAEA;EACC;EACA;;AAGD;EACC;;AAKD;EACC;;AAGD;EACC;;AAGD;EACC;;AAEA;EACC;;AAKD;EACC;;AAKD;EACC;;AAMH;EACC;EACA;;AAEA;EACC;EACA;;AAGD;EACC;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAGD;EACC;;;AAQF;EACC;;;AAKH;AACA;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAOA;AAAA;AAAA;AAAA;EACC;;AAEA;AAAA;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;AAAA;EACC;EACA;EACA;EACA;EACA;;AAGD;AAAA;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;AAAA;EACC;;;AAMF;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;;AAIF;EACC;;;AAGD;EACC;;;AAGD;EACC;AACA;EACA;EACA;EACA;EACA;;;AAGD;AAEA;EACC;EACA;EACA;;;AAGD;AAAA;AAAA;EAGC;;;AAIA;EACC;EACA;EACA;;AAGD;AAAA;EAEC;;;AAIF;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;;AAEA;EACC;;;AAIF;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAIA;EACC;EACA;;AAGD;EACC;;AAGD;EACC;EACA;;;AAKF;AACA;EACC;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAIA;EACC;EACA;;AAEA;EACC;;AAGD;EACC;;AAIF;EACC;EACA;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;;AAKD;EACC;;AAGD;EACC;;;AAIF;EACC;;AAEA;EACC;EACA;;;AAIF;EACC;;;AAGD;EACC;EACA;EACA;;;AAID;AAKC;EACC;EACA;EACA;;AAEA;EAGC;EACA;EACA,YAbgB;EAchB;EACA;EACA;AACA;AAAA;EAEA,uBACE;EAOF;AAMA;AA0DA;;AA9DA;EACC;;AAID;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAOC,WAxCkB;;AA0ClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACC;EACA;EACA;;AAID;EAMC;;AAIF;AAAA;AAAA;EAGC,WA9DkB;;AAgElB;AAAA;AAAA;EACC;EACA;EACA;;AAIF;EACC;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;;AAID;EACC;EACA;EACA;EACA;AAAc;EACd;;AAEA;EACC;;AAIF;EACC;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUC;EACA;EACA;EACA;EACA;;AAKD;EACC;;AAGD;EACC;;AAIF;EACC;;AAGD;AAAA;AAAA;EAGC;EACA;EACA;EACA;AAaA;AA2GA;;AAtHA;AAAA;AAAA;EACC;EACA;;AAIA;AAAA;AAAA;AAAA;AAAA;EACC;;AAKF;AAAA;AAAA;EACC;EACA;;AAGD;AAAA;AAAA;EACC;;AAKA;AAAA;AAAA;AAAA;AAAA;EACC;EACA;;AAIF;AAAA;AAAA;AAAA;AAAA;AAEC;EACA;EACA;EACA;AACA;AAAA;AAAA;EAGA;EACA;EACA;EACA;;AAGD;AAAA;AAAA;EACC;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACC;EACA;EACA;;AAIF;AAAA;AAAA;EACC;EACA;;AAEA;AAAA;AAAA;EACC;;AAIF;AAAA;AAAA;EACC;EACA;EACA;;AAEA;AAAA;AAAA;EACC;;AAIF;AAAA;AAAA;EACC;EACA;;AAEA;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;EACC;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACC;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGC;EACA;;AAKH;AAAA;AAAA;EACC;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACC;EACA;;AAMH;AAAA;AAAA;EACC;;AAKH;EACC;EACA;EACA;EACA;;AAGD;EACC;EACA;;;AAKH;EACI;;;AAGJ;EACE;IACE;;;AAGJ;EACE;IACE","file":"settings.css"} \ No newline at end of file
diff --git a/apps/settings/css/settings.scss b/apps/settings/css/settings.scss
index 2343ac7de34..53f6644adfc 100644
--- a/apps/settings/css/settings.scss
+++ b/apps/settings/css/settings.scss
@@ -36,76 +36,6 @@ input {
@include icon-color('password', 'settings', variables.$color-black);
}
-#avatarform {
- .avatardiv {
- margin: 10px auto;
- }
-
- .warning {
- width: 100%;
- }
-
- .jcrop-keymgr {
- display: none !important;
- }
-}
-
-#displayavatar {
- text-align: center;
-}
-
-#uploadavatarbutton, #selectavatar, #removeavatar {
- padding: 21px;
-}
-#selectavatar, #removeavatar {
- vertical-align: top;
-}
-
-.jcrop-holder {
- z-index: 500;
-}
-
-#cropper {
- float: left;
- z-index: 500;
- /* float cropper above settings page to prevent unexpected flowing from dynamically sized element */
- position: fixed;
- background-color: rgba(0, 0, 0, 0.2);
- box-sizing: border-box;
- top: 45px;
- left: 0;
- width: 100%;
- height: calc(100% - 45px);
-
- .inner-container {
- z-index: 2001;
- /* above the top bar if needed */
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: #fff;
- color: #333;
- border-radius: var(--border-radius-large);
- box-shadow: 0 0 10px var(--color-box-shadow);
- padding: 15px;
-
- .jcrop-holder,
- .jcrop-holder img,
- img.jcrop-preview {
- border-radius: var(--border-radius);
- }
-
- .button {
- margin-top: 15px;
- }
-
- .primary {
- float: right;
- }
- }
-}
-
#personal-settings-avatar-container {
display: inline-grid;
grid-template-columns: 1fr;
diff --git a/apps/settings/js/settings/personalInfo.js b/apps/settings/js/settings/personalInfo.js
index 98a2dfe8d48..4309b462e47 100644
--- a/apps/settings/js/settings/personalInfo.js
+++ b/apps/settings/js/settings/personalInfo.js
@@ -41,107 +41,6 @@ jQuery.fn.keyUpDelayedOrEnter = function (callback, allowEmptyValue) {
});
};
-function updateAvatar (hidedefault) {
- var $headerdiv = $('#header .avatardiv'),
- $displaydiv = $('#displayavatar .avatardiv'),
- user = OC.getCurrentUser();
-
- //Bump avatar avatarversion
- oc_userconfig.avatar.version = -(Math.floor(Math.random() * 1000));
-
- if (hidedefault) {
- $headerdiv.hide();
- $('#header .avatardiv').removeClass('avatardiv-shown');
- } else {
- $headerdiv.css({'background-color': ''});
- $headerdiv.avatar(user.uid, 32, true, false, undefined, user.displayName);
- $('#header .avatardiv').addClass('avatardiv-shown');
- }
- $displaydiv.css({'background-color': ''});
- $displaydiv.avatar(user.uid, 145, true, null, function() {
- $displaydiv.removeClass('loading');
- $('#displayavatar img').show();
- if($('#displayavatar img').length === 0 || oc_userconfig.avatar.generated) {
- $('#removeavatar').removeClass('inlineblock').addClass('hidden');
- } else {
- $('#removeavatar').removeClass('hidden').addClass('inlineblock');
- }
- }, user.displayName);
- $('#uploadavatar').prop('disabled', false);
-}
-
-function showAvatarCropper () {
- var $cropper = $('#cropper');
- var $cropperImage = $('<img/>');
- $cropperImage.css('opacity', 0); // prevent showing the unresized image
- $cropper.children('.inner-container').prepend($cropperImage);
-
- $cropperImage.attr('src',
- OC.generateUrl('/avatar/tmp') + '?requesttoken=' + encodeURIComponent(OC.requestToken) + '#' + Math.floor(Math.random() * 1000));
-
- $cropperImage.load(function () {
- var img = $cropperImage.get()[0];
- var selectSize = Math.min(img.width, img.height);
- var offsetX = (img.width - selectSize) / 2;
- var offsetY = (img.height - selectSize) / 2;
- $cropperImage.Jcrop({
- onChange: saveCoords,
- onSelect: saveCoords,
- aspectRatio: 1,
- boxHeight: Math.min(500, $('#app-content').height() -100),
- boxWidth: Math.min(500, $('#app-content').width()),
- setSelect: [offsetX, offsetY, selectSize, selectSize]
- }, function() {
- $cropper.show();
- });
- });
-}
-
-function sendCropData () {
- cleanCropper();
-
- var cropperData = $('#cropper').data();
- var data = {
- x: cropperData.x,
- y: cropperData.y,
- w: cropperData.w,
- h: cropperData.h
- };
- $.post(OC.generateUrl('/avatar/cropped'), {crop: data}, avatarResponseHandler);
-}
-
-function saveCoords (c) {
- $('#cropper').data(c);
-}
-
-function cleanCropper () {
- var $cropper = $('#cropper');
- $('#displayavatar').show();
- $cropper.hide();
- $('.jcrop-holder').remove();
- $('#cropper img').removeData('Jcrop').removeAttr('style').removeAttr('src');
- $('#cropper img').remove();
-}
-
-function avatarResponseHandler (data) {
- if (typeof data === 'string') {
- data = JSON.parse(data);
- }
- var $warning = $('#avatarform .warning');
- $warning.hide();
- if (data.status === "success") {
- $('#displayavatar .avatardiv').removeClass('icon-loading');
- oc_userconfig.avatar.generated = false;
- updateAvatar();
- } else if (data.data === "notsquare") {
- cleanCropper();
- showAvatarCropper();
- } else {
- $warning.show();
- $warning.text(data.data.message);
- }
-}
-
window.addEventListener('DOMContentLoaded', function () {
if($('#pass2').length) {
$('#pass2').showPassword().keyup();
@@ -208,9 +107,6 @@ window.addEventListener('DOMContentLoaded', function () {
showPublishedScope: !!settingsEl.data('lookup-server-upload-enabled'),
});
- userSettings.on("sync", function() {
- updateAvatar(false);
- });
federationSettingsView.render();
var updateLanguage = function () {
@@ -264,125 +160,6 @@ window.addEventListener('DOMContentLoaded', function () {
});
};
$("#localeinput").change(updateLocale);
-
- var uploadparms = {
- pasteZone: null,
- done: function (e, data) {
- var response = data;
- if (typeof data.result === 'string') {
- response = JSON.parse(data.result);
- } else if (data.result && data.result.length) {
- // fetch response from iframe
- response = JSON.parse(data.result[0].body.innerText);
- } else {
- response = data.result;
- }
- avatarResponseHandler(response);
- },
- submit: function(e, data) {
- $('#displayavatar img').hide();
- $('#displayavatar .avatardiv').addClass('icon-loading');
- $('#uploadavatar').prop('disabled', true)
- data.formData = _.extend(data.formData || {}, {
- requesttoken: OC.requestToken
- });
- },
- fail: function (e, data) {
- $('#displayavatar .avatardiv').removeClass('icon-loading');
- $('#uploadavatar').prop('disabled', false)
- var msg = data.jqXHR.statusText + ' (' + data.jqXHR.status + ')';
- if (!_.isUndefined(data.jqXHR.responseJSON) &&
- !_.isUndefined(data.jqXHR.responseJSON.data) &&
- !_.isUndefined(data.jqXHR.responseJSON.data.message)
- ) {
- msg = data.jqXHR.responseJSON.data.message;
- }
- avatarResponseHandler({
- data: {
- message: msg
- }
- });
- }
- };
-
- $('#uploadavatar').fileupload(uploadparms);
-
- // Trigger upload action also with keyboard navigation on enter
- $('#uploadavatarbutton').on('keyup', function(event) {
- if (event.key === ' ' || event.key === 'Enter') {
- $('#uploadavatar').trigger('click');
- }
- });
-
- $('#selectavatar').click(function (event) {
- event.stopPropagation();
- event.preventDefault();
-
- OC.dialogs.filepicker(
- t('settings', "Select a profile picture"),
- function (path) {
- $('#displayavatar img').hide();
- $('#displayavatar .avatardiv').addClass('icon-loading');
- $('#uploadavatar').prop('disabled', true);
- $.ajax({
- type: "POST",
- url: OC.generateUrl('/avatar/'),
- data: { path: path }
- }).done(avatarResponseHandler)
- .fail(function(jqXHR) {
- var msg = jqXHR.statusText + ' (' + jqXHR.status + ')';
- if (!_.isUndefined(jqXHR.responseJSON) &&
- !_.isUndefined(jqXHR.responseJSON.data) &&
- !_.isUndefined(jqXHR.responseJSON.data.message)
- ) {
- msg = jqXHR.responseJSON.data.message;
- }
- avatarResponseHandler({
- data: {
- message: msg
- }
- });
- });
- },
- false,
- ["image/png", "image/jpeg"]
- );
- });
-
- $('#removeavatar').click(function (event) {
- event.stopPropagation();
- event.preventDefault();
-
- $.ajax({
- type: 'DELETE',
- url: OC.generateUrl('/avatar/'),
- success: function () {
- oc_userconfig.avatar.generated = true;
- updateAvatar(true);
- }
- });
- });
-
- $('#abortcropperbutton').click(function () {
- $('#displayavatar .avatardiv').removeClass('icon-loading');
- $('#displayavatar img').show();
- $('#uploadavatar').prop('disabled', false);
- cleanCropper();
- });
-
- $('#sendcropperbutton').click(function () {
- sendCropData();
- });
-
- // Load the big avatar
- var user = OC.getCurrentUser();
- $('#avatarform .avatardiv').avatar(user.uid, 145, true, null, function() {
- if($('#displayavatar img').length === 0 || oc_userconfig.avatar.generated) {
- $('#removeavatar').removeClass('inlineblock').addClass('hidden');
- } else {
- $('#removeavatar').removeClass('hidden').addClass('inlineblock');
- }
- }, user.displayName);
});
window.setInterval(function() {
@@ -390,5 +167,3 @@ window.setInterval(function() {
$('#localeexample-date').text(moment().format('L'))
$('#localeexample-fdow').text(t('settings', 'Week starts on {fdow}', { fdow: dayNames[firstDay] }))
}, 1000)
-
-OC.Settings.updateAvatar = updateAvatar;
diff --git a/apps/settings/lib/Settings/Personal/PersonalInfo.php b/apps/settings/lib/Settings/Personal/PersonalInfo.php
index 11d3f8b1e09..104989d2c61 100644
--- a/apps/settings/lib/Settings/Personal/PersonalInfo.php
+++ b/apps/settings/lib/Settings/Personal/PersonalInfo.php
@@ -143,10 +143,8 @@ class PersonalInfo implements ISettings {
'usage' => \OC_Helper::humanFileSize($storageInfo['used']),
'usage_relative' => round($storageInfo['relative']),
'quota' => $storageInfo['quota'],
- 'avatarChangeSupported' => $user->canChangeAvatar(),
'federationEnabled' => $federationEnabled,
'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
- 'avatarScope' => $account->getProperty(IAccountManager::PROPERTY_AVATAR)->getScope(),
'groups' => $this->getGroups($user),
'isFairUseOfFreePushService' => $this->isFairUseOfFreePushService(),
'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
@@ -154,6 +152,7 @@ class PersonalInfo implements ISettings {
$personalInfoParameters = [
'userId' => $uid,
+ 'avatar' => $this->getProperty($account, IAccountManager::PROPERTY_AVATAR),
'displayName' => $this->getProperty($account, IAccountManager::PROPERTY_DISPLAYNAME),
'emailMap' => $this->getEmailMap($account),
'phone' => $this->getProperty($account, IAccountManager::PROPERTY_PHONE),
@@ -170,6 +169,7 @@ class PersonalInfo implements ISettings {
];
$accountParameters = [
+ 'avatarChangeSupported' => $user->canChangeAvatar(),
'displayNameChangeSupported' => $user->canChangeDisplayName(),
'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
];
diff --git a/apps/settings/src/components/PersonalInfo/AvatarSection.vue b/apps/settings/src/components/PersonalInfo/AvatarSection.vue
new file mode 100644
index 00000000000..f0ad1b68d3b
--- /dev/null
+++ b/apps/settings/src/components/PersonalInfo/AvatarSection.vue
@@ -0,0 +1,333 @@
+<!--
+ - @copyright 2022 Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license AGPL-3.0-or-later
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+-->
+
+<template>
+ <section>
+ <HeaderBar :input-id="avatarChangeSupported ? inputId : null"
+ :readable="avatar.readable"
+ :scope.sync="avatar.scope" />
+
+ <div v-if="!showCropper" class="avatar__container">
+ <div class="avatar__preview">
+ <NcAvatar v-if="!loading"
+ :user="userId"
+ :aria-label="t('settings', 'Your profile picture')"
+ :disabled-menu="true"
+ :disabled-tooltip="true"
+ :show-user-status="false"
+ :size="180"
+ :key="version" />
+ <div v-else class="icon-loading" />
+ </div>
+ <template v-if="avatarChangeSupported">
+ <div class="avatar__buttons">
+ <NcButton :aria-label="t('settings', 'Upload profile picture')"
+ @click="activateLocalFilePicker">
+ <template #icon>
+ <Upload :size="20" />
+ </template>
+ </NcButton>
+ <NcButton :aria-label="t('settings', 'Choose profile picture from files')"
+ @click="openFilePicker">
+ <template #icon>
+ <Folder :size="20" />
+ </template>
+ </NcButton>
+ <NcButton v-if="!isGenerated"
+ :aria-label="t('settings', 'Remove profile picture')"
+ @click="removeAvatar">
+ <template #icon>
+ <Delete :size="20" />
+ </template>
+ </NcButton>
+ </div>
+ <span>{{ t('settings', 'png or jpg, max. 20 MB') }}</span>
+ <input ref="input"
+ :id="inputId"
+ type="file"
+ :accept="validMimeTypes.join(',')"
+ @change="onChange">
+ </template>
+ <span v-else>
+ {{ t('settings', 'Picture provided by original account') }}
+ </span>
+ </div>
+
+ <!-- Use v-show to ensure early cropper ref availability -->
+ <div v-show="showCropper" class="avatar__container">
+ <VueCropper ref="cropper"
+ class="avatar__cropper"
+ v-bind="cropperOptions" />
+ <div class="avatar__cropper-buttons">
+ <NcButton @click="cancel">
+ {{ t('settings', 'Cancel') }}
+ </NcButton>
+ <NcButton type="primary"
+ @click="saveAvatar">
+ {{ t('settings', 'Set as profile picture') }}
+ </NcButton>
+ </div>
+ <span>{{ t('settings', 'Please note that it can take up to 24 hours for your profile picture to be updated everywhere.') }}</span>
+ </div>
+ </section>
+</template>
+
+<script>
+import axios from '@nextcloud/axios'
+import { loadState } from '@nextcloud/initial-state'
+import { generateUrl } from '@nextcloud/router'
+import { getCurrentUser } from '@nextcloud/auth'
+import { getFilePickerBuilder, showError } from '@nextcloud/dialogs'
+import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
+
+import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar'
+import NcButton from '@nextcloud/vue/dist/Components/NcButton'
+import VueCropper from 'vue-cropperjs'
+// eslint-disable-next-line node/no-extraneous-import
+import 'cropperjs/dist/cropper.css'
+
+import Upload from 'vue-material-design-icons/Upload'
+import Folder from 'vue-material-design-icons/Folder'
+import Delete from 'vue-material-design-icons/Delete'
+
+import HeaderBar from './shared/HeaderBar.vue'
+import { NAME_READABLE_ENUM } from '../../constants/AccountPropertyConstants.js'
+
+const { avatar } = loadState('settings', 'personalInfoParameters', {})
+const { avatarChangeSupported } = loadState('settings', 'accountParameters', {})
+
+const VALID_MIME_TYPES = ['image/png', 'image/jpeg']
+
+const picker = getFilePickerBuilder(t('settings', 'Choose your profile picture'))
+ .setMultiSelect(false)
+ .setMimeTypeFilter(VALID_MIME_TYPES)
+ .setModal(true)
+ .setType(1)
+ .allowDirectories(false)
+ .build()
+
+export default {
+ name: 'AvatarSection',
+
+ components: {
+ Delete,
+ Folder,
+ HeaderBar,
+ NcAvatar,
+ NcButton,
+ Upload,
+ VueCropper,
+ },
+
+ data() {
+ return {
+ avatar: { ...avatar, readable: NAME_READABLE_ENUM[avatar.name] },
+ avatarChangeSupported,
+ showCropper: false,
+ loading: false,
+ userId: getCurrentUser().uid,
+ displayName: getCurrentUser().displayName,
+ version: oc_userconfig.avatar.version,
+ isGenerated: oc_userconfig.avatar.generated,
+ validMimeTypes: VALID_MIME_TYPES,
+ cropperOptions: {
+ aspectRatio: 1 / 1,
+ viewMode: 1,
+ guides: false,
+ center: false,
+ highlight: false,
+ autoCropArea: 1,
+ minContainerWidth: 300,
+ minContainerHeight: 300,
+ },
+ }
+ },
+
+ created() {
+ subscribe('settings:display-name:updated', this.handleDisplayNameUpdate)
+ },
+
+ beforeDestroy() {
+ unsubscribe('settings:display-name:updated', this.handleDisplayNameUpdate)
+ },
+
+ computed: {
+ inputId() {
+ return `account-property-${this.avatar.name}`
+ },
+ },
+
+ methods: {
+ activateLocalFilePicker() {
+ // Set to null so that selecting the same file will trigger the change event
+ this.$refs.input.value = null
+ this.$refs.input.click()
+ },
+
+ onChange(e) {
+ this.loading = true
+ const file = e.target.files[0]
+ if (!this.validMimeTypes.includes(file.type)) {
+ showError(t('settings', 'Please select a valid png or jpg file'))
+ this.cancel()
+ return
+ }
+
+ const reader = new FileReader()
+ reader.onload = (e) => {
+ this.$refs.cropper.replace(e.target.result)
+ this.showCropper = true
+ }
+ reader.readAsDataURL(file)
+ },
+
+ async openFilePicker() {
+ const path = await picker.pick()
+ this.loading = true
+ try {
+ const { data } = await axios.post(generateUrl('/avatar'), { path })
+ if (data.status === 'success') {
+ this.handleAvatarUpdate(false)
+ } else if (data.data === 'notsquare') {
+ const tempAvatar = generateUrl('/avatar/tmp') + '?requesttoken=' + encodeURIComponent(OC.requestToken) + '#' + Math.floor(Math.random() * 1000)
+ this.$refs.cropper.replace(tempAvatar)
+ this.showCropper = true
+ } else {
+ showError(data.data.message)
+ this.cancel()
+ }
+ } catch (e) {
+ showError(t('settings', 'Error setting profile picture'))
+ this.cancel()
+ }
+ },
+
+ saveAvatar() {
+ this.showCropper = false
+ this.loading = true
+
+ this.$refs.cropper.getCroppedCanvas().toBlob(async (blob) => {
+ if (blob === null) {
+ showError(t('settings', 'Error cropping profile picture'))
+ this.cancel()
+ return
+ }
+
+ const formData = new FormData()
+ formData.append('files[]', blob)
+ try {
+ await axios.post(generateUrl('/avatar'), formData)
+ this.handleAvatarUpdate(false)
+ } catch (e) {
+ showError(t('settings', 'Error saving profile picture'))
+ this.handleAvatarUpdate(this.isGenerated)
+ }
+ })
+ },
+
+ async removeAvatar() {
+ this.loading = true
+ try {
+ await axios.delete(generateUrl('/avatar'))
+ this.handleAvatarUpdate(true)
+ } catch (e) {
+ showError(t('settings', 'Error removing profile picture'))
+ this.handleAvatarUpdate(this.isGenerated)
+ }
+ },
+
+ cancel() {
+ this.showCropper = false
+ this.loading = false
+ },
+
+ handleAvatarUpdate(isGenerated) {
+ // Update the avatar version so that avatar update handlers refresh correctly
+ this.version = oc_userconfig.avatar.version = Date.now()
+ this.isGenerated = oc_userconfig.avatar.generated = isGenerated
+ this.loading = false
+ emit('settings:avatar:updated', oc_userconfig.avatar.version)
+ /**
+ * FIXME refresh all other avatars on the page when updated,
+ * the NcAvatar component itself should listen to the
+ * global events and optionally live refresh with a prop toggle
+ * https://github.com/nextcloud/nextcloud-vue/issues/2975
+ */
+ },
+
+ handleDisplayNameUpdate() {
+ this.version = oc_userconfig.avatar.version
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.avatar {
+ &__container {
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 16px 0;
+ width: 300px;
+
+ span {
+ color: var(--color-text-lighter);
+ }
+ }
+
+ &__preview {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 180px;
+ height: 180px;
+ }
+
+ &__buttons {
+ display: flex;
+ gap: 0 10px;
+ }
+
+ &__cropper {
+ width: 300px;
+ height: 300px;
+ overflow: hidden;
+
+ &-buttons {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ }
+
+ &::v-deep .cropper-view-box {
+ border-radius: 50%;
+ }
+ }
+}
+
+input[type="file"] {
+ display: none;
+}
+</style>
diff --git a/apps/settings/src/components/PersonalInfo/DisplayNameSection.vue b/apps/settings/src/components/PersonalInfo/DisplayNameSection.vue
index dd5f97966ac..c5517140cd2 100644
--- a/apps/settings/src/components/PersonalInfo/DisplayNameSection.vue
+++ b/apps/settings/src/components/PersonalInfo/DisplayNameSection.vue
@@ -59,6 +59,10 @@ export default {
},
onSave(value) {
+ if (oc_userconfig.avatar.generated) {
+ // Update the avatar version so that avatar update handlers refresh correctly
+ oc_userconfig.avatar.version = Date.now()
+ }
emit('settings:display-name:updated', value)
},
}
diff --git a/apps/settings/src/constants/AccountPropertyConstants.js b/apps/settings/src/constants/AccountPropertyConstants.js
index 2f3a84b4908..41dd7e023bd 100644
--- a/apps/settings/src/constants/AccountPropertyConstants.js
+++ b/apps/settings/src/constants/AccountPropertyConstants.js
@@ -47,7 +47,7 @@ export const ACCOUNT_PROPERTY_ENUM = Object.freeze({
/** Enum of account properties to human readable account property names */
export const ACCOUNT_PROPERTY_READABLE_ENUM = Object.freeze({
ADDRESS: t('settings', 'Location'),
- AVATAR: t('settings', 'Avatar'),
+ AVATAR: t('settings', 'Profile picture'),
BIOGRAPHY: t('settings', 'About'),
DISPLAYNAME: t('settings', 'Full name'),
EMAIL_COLLECTION: t('settings', 'Additional email'),
diff --git a/apps/settings/src/main-personal-info.js b/apps/settings/src/main-personal-info.js
index 32d8bfc8b45..47af5af8487 100644
--- a/apps/settings/src/main-personal-info.js
+++ b/apps/settings/src/main-personal-info.js
@@ -26,6 +26,7 @@ import { loadState } from '@nextcloud/initial-state'
import { translate as t } from '@nextcloud/l10n'
import '@nextcloud/dialogs/styles/toast.scss'
+import AvatarSection from './components/PersonalInfo/AvatarSection.vue'
import DisplayNameSection from './components/PersonalInfo/DisplayNameSection.vue'
import EmailSection from './components/PersonalInfo/EmailSection/EmailSection.vue'
import PhoneSection from './components/PersonalInfo/PhoneSection.vue'
@@ -50,6 +51,7 @@ Vue.mixin({
},
})
+const AvatarView = Vue.extend(AvatarSection)
const DisplayNameView = Vue.extend(DisplayNameSection)
const EmailView = Vue.extend(EmailSection)
const PhoneView = Vue.extend(PhoneSection)
@@ -58,6 +60,7 @@ const WebsiteView = Vue.extend(WebsiteSection)
const TwitterView = Vue.extend(TwitterSection)
const LanguageView = Vue.extend(LanguageSection)
+new AvatarView().$mount('#vue-avatar-section')
new DisplayNameView().$mount('#vue-displayname-section')
new EmailView().$mount('#vue-email-section')
new PhoneView().$mount('#vue-phone-section')
diff --git a/apps/settings/templates/settings/personal/personal.info.php b/apps/settings/templates/settings/personal/personal.info.php
index 9c18ec71d4a..551a781736b 100644
--- a/apps/settings/templates/settings/personal/personal.info.php
+++ b/apps/settings/templates/settings/personal/personal.info.php
@@ -47,42 +47,7 @@ script('settings', [
data-lookup-server-upload-enabled="<?php p($_['lookupServerUploadEnabled'] ? 'true' : 'false') ?>">
<h2 class="hidden-visually"><?php p($l->t('Personal info')); ?></h2>
<div id="personal-settings-avatar-container" class="personal-settings-container">
- <div>
- <form id="avatarform" class="section" method="post" action="<?php p(\OC::$server->getURLGenerator()->linkToRoute('core.avatar.postAvatar')); ?>">
- <h3>
- <?php p($l->t('Profile picture')); ?>
- <a href="#" class="federation-menu" aria-label="<?php p($l->t('Change privacy level of profile picture')); ?>">
- <span class="icon-federation-menu icon-password">
- <span class="icon-triangle-s"></span>
- </span>
- </a>
- </h3>
- <div id="displayavatar">
- <div class="avatardiv"></div>
- <div class="warning hidden"></div>
- <?php if ($_['avatarChangeSupported']) : ?>
- <label for="uploadavatar" class="inlineblock button icon-upload svg" id="uploadavatarbutton" title="<?php p($l->t('Upload new')); ?>" tabindex="0"></label>
- <button class="inlineblock button icon-folder svg" id="selectavatar" title="<?php p($l->t('Select from Files')); ?>"></button>
- <button class="hidden button icon-delete svg" id="removeavatar" title="<?php p($l->t('Remove image')); ?>"></button>
- <input type="file" name="files[]" id="uploadavatar" class="hiddenuploadfield" accept="image/*">
- <p><em><?php p($l->t('png or jpg, max. 20 MB')); ?></em></p>
- <?php else : ?>
- <?php p($l->t('Picture provided by original account')); ?>
- <?php endif; ?>
- </div>
-
- <div id="cropper" class="hidden">
- <div class="inner-container">
- <p style="width: 300px; margin-top: 0.5rem"><?php p($l->t('Please note that it can take up to 24 hours for the avatar to get updated everywhere.')); ?></p>
- <div class="inlineblock button" id="abortcropperbutton"><?php p($l->t('Cancel')); ?></div>
- <div class="inlineblock button primary" id="sendcropperbutton"><?php p($l->t('Choose as profile picture')); ?></div>
- </div>
- </div>
- <span class="icon-checkmark hidden"></span>
- <span class="icon-error hidden"></span>
- <input type="hidden" id="avatarscope" value="<?php p($_['avatarScope']) ?>">
- </form>
- </div>
+ <div id="vue-avatar-section"></div>
<div class="personal-settings-setting-box personal-settings-group-box section">
<h3><?php p($l->t('Details')); ?></h3>
<div id="groups" class="personal-info icon-user">