Skip to content

Commit 9fa8919

Browse files
skjnldsvnextcloud-command
authored andcommitted
Optimize saving performances and design papercut
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com> Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
1 parent aa718de commit 9fa8919

3 files changed

Lines changed: 76 additions & 53 deletions

File tree

js/viewer-main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/viewer-main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/ImageEditor.vue

Lines changed: 73 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<script>
55
import { basename, dirname, extname, join } from 'path'
66
import { emit } from '@nextcloud/event-bus'
7+
import { showError, showSuccess } from '@nextcloud/dialogs'
78
import axios from '@nextcloud/axios'
89
import FilerobotImageEditor from 'filerobot-image-editor'
910
@@ -143,39 +144,38 @@ export default {
143144
this.$emit('close')
144145
},
145146
146-
async onSave(imageData) {
147+
/**
148+
* User saved the image
149+
*
150+
* @see https://github.com/scaleflex/filerobot-image-editor#onsave
151+
* @param {object} props destructuring object
152+
* @param {string} props.fullName the file name
153+
* @param {HTMLCanvasElement} props.imageCanvas the image canvas
154+
* @param {string} props.mimeType the image mime type
155+
* @param {number} props.quality the image saving quality
156+
*/
157+
async onSave({ fullName, imageCanvas, mimeType, quality }) {
147158
const { origin, pathname } = new URL(this.src)
148-
const putUrl = origin + join(dirname(pathname), imageData.fullName)
149-
logger.debug('Saving image...', { putUrl, src: this.src, fullName: imageData.fullName })
159+
const putUrl = origin + join(dirname(pathname), fullName)
160+
logger.debug('Saving image...', { putUrl, src: this.src, fullName })
150161
151162
try {
152-
const file = this.dataURLtoFile(imageData.imageBase64, imageData.fullName)
153-
const response = await axios.put(putUrl, file)
163+
const blob = await new Promise(resolve => imageCanvas.toBlob(resolve, mimeType, quality))
164+
const response = await axios.put(putUrl, new File([blob], fullName))
154165
155166
logger.info('Edited image saved!', { response })
167+
showSuccess(t('viewer', 'Image saved'))
156168
if (putUrl !== this.src) {
157169
emit('files:file:created', { fileid: parseInt(response?.headers?.['oc-fileid']?.split('oc')[0]) || null })
158170
} else {
159171
emit('files:file:updated', { fileid: this.fileid })
160172
}
161173
} catch (error) {
162174
logger.error('Error saving image', { error })
175+
showError(t('viewer', 'Error saving image'))
163176
}
164177
},
165178
166-
dataURLtoFile(dataurl, filename) {
167-
const arr = dataurl.split(',')
168-
const mime = arr[0].match(/:(.*?);/)[1]
169-
const bstr = atob(arr[1])
170-
let n = bstr.length
171-
const u8arr = new Uint8Array(n)
172-
while (n) {
173-
u8arr[n - 1] = bstr.charCodeAt(n - 1)
174-
n -= 1
175-
}
176-
return new File([u8arr], filename, { type: mime })
177-
},
178-
179179
/**
180180
* Show warning if unsaved changes
181181
*/
@@ -240,14 +240,15 @@ export default {
240240
<style lang="scss" scoped>
241241
// Take full screen size ()
242242
.viewer__image-editor {
243-
width: 100%;
244-
height: 100vh;
243+
position: absolute;
244+
z-index: 10100;
245245
top: calc(var(--header-height) * -1);
246246
bottom: calc(var(--header-height) * -1);
247247
left: 0;
248-
position: absolute;
249-
z-index: 10100;
248+
width: 100%;
249+
height: 100vh;
250250
}
251+
251252
</style>
252253
253254
<style lang="scss">
@@ -279,12 +280,12 @@ export default {
279280
280281
// Fix button ratio and center content
281282
button {
282-
padding: 6px 12px;
283-
min-width: 44px;
284-
min-height: 44px;
285283
display: flex;
286-
justify-content: center;
287284
align-items: center;
285+
justify-content: center;
286+
min-width: 44px;
287+
min-height: 44px;
288+
padding: 6px 12px;
288289
}
289290
}
290291
@@ -304,21 +305,21 @@ export default {
304305
305306
// Global buttons
306307
.SfxButton-root {
307-
margin: 0 !important;
308308
min-height: 44px !important;
309+
margin: 0 !important;
309310
border: transparent !important;
310311
&[color='error'] {
311-
background-color: var(--color-error) !important;
312312
color: white !important;
313+
background-color: var(--color-error) !important;
313314
&:hover,
314315
&:focus {
315316
border-color: white !important;
316317
background-color: var(--color-error-hover) !important;
317318
}
318319
}
319320
&[color='primary'] {
320-
background-color: var(--color-primary-element) !important;
321321
color: var(--color-primary-text) !important;
322+
background-color: var(--color-primary-element) !important;
322323
&:hover,
323324
&:focus {
324325
background-color: var(--color-primary-element-hover) !important;
@@ -332,11 +333,11 @@ export default {
332333
padding-left: 8px !important;
333334
// Center the menu entry icon and fix width
334335
> div {
335-
cursor: pointer;
336336
margin-right: 0;
337337
padding: 14px;
338338
// Minus the parent padding-left
339339
padding: calc(14px - 8px);
340+
cursor: pointer;
340341
}
341342
342343
// Disable jpeg saving (jpg is already here)
@@ -347,8 +348,8 @@ export default {
347348
348349
// Modal
349350
.SfxModal-Container {
350-
padding: 22px;
351351
min-height: 300px;
352+
padding: 22px;
352353
353354
// Fill height
354355
.SfxModal-root,
@@ -358,14 +359,15 @@ export default {
358359
color: var(--color-main-text);
359360
}
360361
.SfxModalTitle-Icon {
361-
background: none !important;
362362
margin-bottom: 22px !important;
363+
background: none !important;
363364
// Fit EmptyContent styling
364365
svg {
365366
width: 64px;
366367
height: 64px;
367368
opacity: .4;
368369
// Override all coloured icons
370+
369371
--color-primary: var(--color-main-text);
370372
--color-error: var(--color-main-text);
371373
}
@@ -392,9 +394,9 @@ export default {
392394
}
393395
394396
.FIE_tab {
395-
padding: 8px;
396397
width: 80px !important;
397398
height: 80px !important;
399+
padding: 8px;
398400
border-radius: var(--border-radius-large) !important;
399401
svg {
400402
width: 16px;
@@ -425,24 +427,24 @@ export default {
425427
// Matching buttons tools
426428
& > div[class$='-tool-button'],
427429
& > div[class$='-tool'] {
428-
height: 44px;
429-
min-width: 44px;
430430
display: flex;
431-
justify-content: center;
432431
align-items: center;
433-
border-radius: var(--border-radius-pill);
432+
justify-content: center;
433+
min-width: 44px;
434+
height: 44px;
434435
padding: 6px 16px;
436+
border-radius: var(--border-radius-pill);
435437
}
436438
}
437439
438440
// Crop preset select button
439441
.FIE_crop-presets-opener-button {
440-
background-color: transparent !important;
441-
border: none !important;
442+
// override default button width
443+
min-width: 0 !important;
442444
padding: 5px !important;
443445
padding-left: 10px !important;
444-
// override default button width
445-
min-width: 0px !important;
446+
border: none !important;
447+
background-color: transparent !important;
446448
}
447449
448450
// Force icon-only style
@@ -478,18 +480,37 @@ export default {
478480
479481
// Save button fixes
480482
.FIE_topbar-save-button {
481-
background-color: var(--color-primary-element) !important;
482483
color: var(--color-primary-text) !important;
483484
border: none !important;
485+
background-color: var(--color-primary-element) !important;
484486
&:hover,
485487
&:focus {
486488
background-color: var(--color-primary-element-hover) !important;
487489
}
488490
}
489491
492+
// Save Modal fixes
493+
.FIE_resize-tool-options {
494+
.FIE_resize-width-option,
495+
.FIE_resize-height-option {
496+
flex: 1 1;
497+
min-width: 0;
498+
}
499+
}
500+
490501
// Resize lock
491502
.FIE_resize-ratio-locker {
492503
margin-right: 8px !important;
504+
// Icon is very thin
505+
svg {
506+
width: 20px;
507+
height: 20px;
508+
path {
509+
stroke-width: 1;
510+
stroke: var(--color-main-text);
511+
fill: var(--color-main-text);
512+
}
513+
}
493514
}
494515
495516
// Close editor button fixes
@@ -517,22 +538,24 @@ export default {
517538
}
518539
519540
.FIE_spinner::before {
520-
z-index: 2;
521-
content: '';
522-
height: 28px;
523-
width: 28px;
524-
margin: -16px 0 0 -16px;
525541
position: absolute;
542+
z-index: 2;
526543
top: 50%;
527544
left: 50%;
528-
border-radius: 100%;
529-
-webkit-animation: rotate .8s infinite linear;
530-
animation: rotate .8s infinite linear;
545+
width: 28px;
546+
height: 28px;
547+
margin: -16px 0 0 -16px;
548+
content: '';
531549
-webkit-transform-origin: center;
532550
-ms-transform-origin: center;
533551
transform-origin: center;
552+
-webkit-animation: rotate .8s infinite linear;
553+
animation: rotate .8s infinite linear;
534554
border: 2px solid var(--color-loading-light);
535555
border-top-color: var(--color-loading-dark);
556+
border-radius: 100%;
557+
536558
filter: var(--background-invert-if-dark);
537559
}
560+
538561
</style>

0 commit comments

Comments
 (0)