From 81fa0636e59a8c0a4850d1f7e9f1704fa7543a36 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Mon, 30 Sep 2024 12:21:19 +0200 Subject: [PATCH 001/122] new progress bars logic --- src/img/icon/progress/close.svg | 3 +- src/json/text.json | 14 ++--- src/scss/component/progress.scss | 61 ++++++++++++++------- src/ts/app.tsx | 18 +++---- src/ts/component/util/progress.tsx | 86 +++++++++++++++++------------- src/ts/interface/progress.ts | 27 +++++----- src/ts/lib/api/dispatcher.ts | 55 +++++++++---------- src/ts/lib/api/mapper.ts | 18 ++++++- src/ts/store/common.ts | 18 +------ src/ts/store/index.ts | 2 + src/ts/store/progress.ts | 46 ++++++++++++++++ 11 files changed, 213 insertions(+), 135 deletions(-) create mode 100644 src/ts/store/progress.ts diff --git a/src/img/icon/progress/close.svg b/src/img/icon/progress/close.svg index 9cd240df95..1bcde89ec1 100644 --- a/src/img/icon/progress/close.svg +++ b/src/img/icon/progress/close.svg @@ -1,4 +1,3 @@ - - + \ No newline at end of file diff --git a/src/json/text.json b/src/json/text.json index 2b883087f1..027cd09baa 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -163,6 +163,7 @@ "commonNothingFound": "Nothing found", "commonEntrySpace": "My First Space", "commonSystem": "System", + "commonProgress": "Progress", "pluralDay": "day|days", "pluralObject": "Object|Objects", @@ -315,12 +316,13 @@ "viewName4": "Calendar", "viewName5": "Graph", - "progress0": "Copying files %s\/%s", - "progress1": "Import in progress", - "progress2": "Export in progress", - "progress3": "Download in progress", - "progress4": "Recovering vault", - "progress5": "Migration in progress", + + "progressDropFiles": "Copying files...", + "progressImport": "Import in progress...", + "progressExport": "Export in progress...", + "progressSaveFile": "Download in progress...", + "progressMigration": "Recovering vault...", + "progressRecoverAccount": "Migration in progress...", "progressUpdateCheck": "Checking for update...", "spellcheckAdd": "Add to dictionary", diff --git a/src/scss/component/progress.scss b/src/scss/component/progress.scss index 354ba6a526..9932151429 100644 --- a/src/scss/component/progress.scss +++ b/src/scss/component/progress.scss @@ -1,32 +1,53 @@ @import "~scss/_mixins"; -.progress { - position: fixed; left: 0px; top: 0px; z-index: 110; width: 100%; height: 100%; background: rgba(0,0,0,0.4); - transition: background 0.05s ease-in-out; user-select: none; -} - -.progress.isUnlocked { background: none; pointer-events: none; } -.progress.isUnlocked { - .inner { top: auto; left: 10px; top: 40px; margin: 0px; } -} +.progress { position: fixed; left: 0px; top: 0px; z-index: 110; width: 100%; height: 100%; pointer-events: none; user-select: none; } .progress { .inner { - position: absolute; left: 50%; top: 50%; box-shadow: 0px 6px 24px rgba(0, 0, 0, 0.2); height: 72px; width: 384px; cursor: grab; - border-radius: 12px; text-align: center; background: var(--color-bg-primary); overflow: hidden; margin: -36px 0px 0px -192px; padding: 12px 16px; + position: absolute; left: 50%; top: 50%; box-shadow: 0px 6px 24px rgba(0, 0, 0, 0.2); cursor: grab; width: 384px; + border-radius: 12px; text-align: center; background: var(--color-bg-primary); overflow: hidden; margin: -36px 0px 0px -192px; transition-property: opacity, transform; transition-duration: 0.05s; transition-timing-function: ease-in-out; pointer-events: all; + display: flex; flex-direction: column; } - .inner { - .label { position: absolute; left: 16px; top: 12px; z-index: 1; color: var(--color-text-primary); white-space: nowrap; @include text-paragraph; } - .bar { width: calc(100% - 32px); height: 8px; background: var(--color-shape-tertiary); overflow: hidden; border-radius: 8px; position: absolute; bottom: 16px; left: 16px; } - .fill { position: absolute; left: 0px; top: 0px; height: 100%; background: var(--color-control-accent); transition: width 0.2s linear; } + + .titleWrap { font-weight: 600; display: flex; gap: 0px 6px; padding: 11px 16px 3px 16px; } + .titleWrap { + .label.percent { font-weight: 400; color: var(--color-text-secondary); } } - - .icon.close { - width: 24px; height: 24px; position: absolute; top: 14px; right: 14px; background-image: url('~img/icon/progress/close.svg'); - cursor: default; background-size: 20px; border-radius: 4px; + + .item { + padding: 8px 16px; position: relative; border-bottom: 1px solid var(--color-shape-secondary); gap: 4px 0px; display: flex; + flex-direction: column; } - .icon.close:hover { background-color: var(--color-shape-highlight-medium); } + .item { + .nameWrap { display: flex; flex-direction: row; gap: 0px 6px; justify-content: space-between; align-items: center; } + .nameWrap { + .label { color: var(--color-text-primary); @include text-overflow-nw; @include text-common; line-height: 28px; } + .icon.close { width: 20px; height: 20px; background-image: url('~img/icon/progress/close.svg'); cursor: default; flex-shrink: 0; opacity: 0; } + } + + .bar { width: 100%; height: 4px; background: var(--color-shape-secondary); overflow: hidden; border-radius: 8px; position: relative; } + + .fill { position: absolute; left: 0px; top: 0px; height: 100%; background: var(--color-system-accent-25); transition: width 0.2s linear; } + .fill::after { + content: ''; width: 100%; height: 100%; position: absolute; left: 0px; top: 0px; + background-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, var(--color-system-accent-50) 50%, rgba(0,0,0,0) 100%); + animation: animateGradient 2s linear infinite; + } + + @keyframes animateGradient { + 0% { opacity: 1; transform: translateX(-100%); } + 50% { transform: translateX(100%); } + 50.01% { opacity: 0; } + 100% { opacity: 0; } + } + } + .item:hover { + .nameWrap { + .icon.close { opacity: 1; } + } + } + .item:last-child { border-bottom: 0px; } } .progress.hide { background: rgba(0,0,0,0); } diff --git a/src/ts/app.tsx b/src/ts/app.tsx index f462e396ee..2ba65ea60d 100644 --- a/src/ts/app.tsx +++ b/src/ts/app.tsx @@ -255,7 +255,7 @@ class App extends React.Component { Renderer.on('update-available', this.onUpdateAvailable); Renderer.on('update-confirm', this.onUpdateConfirm); Renderer.on('update-not-available', this.onUpdateUnavailable); - Renderer.on('update-downloaded', () => S.Common.progressClear()); + Renderer.on('update-downloaded', () => S.Progress.delete('update')); Renderer.on('update-error', this.onUpdateError); Renderer.on('download-progress', this.onUpdateProgress); Renderer.on('spellcheck', this.onSpellcheck); @@ -410,12 +410,12 @@ class App extends React.Component { onUpdateCheck (e: any, auto: boolean) { if (!auto) { - S.Common.progressSet({ status: translate('progressUpdateCheck'), current: 0, total: 1, isUnlocked: true }); + S.Progress.add({ id: I.ProgressType.UpdateCheck, type: I.ProgressType.UpdateCheck, current: 0, total: 1 }); }; }; onUpdateConfirm (e: any, auto: boolean) { - S.Common.progressClear(); + S.Progress.delete(I.ProgressType.UpdateCheck); Storage.setHighlight('whatsNew', true); if (auto) { @@ -441,7 +441,7 @@ class App extends React.Component { }; onUpdateAvailable (e: any, auto: boolean) { - S.Common.progressClear(); + S.Progress.delete(I.ProgressType.UpdateCheck); if (auto) { return; @@ -466,7 +466,7 @@ class App extends React.Component { }; onUpdateUnavailable (e: any, auto: boolean) { - S.Common.progressClear(); + S.Progress.delete(I.ProgressType.UpdateCheck); if (auto) { return; @@ -487,7 +487,7 @@ class App extends React.Component { onUpdateError (e: any, err: string, auto: boolean) { console.error(err); - S.Common.progressClear(); + S.Progress.delete(I.ProgressType.UpdateCheck); if (auto) { return; @@ -512,11 +512,11 @@ class App extends React.Component { }; onUpdateProgress (e: any, progress: any) { - S.Common.progressSet({ - status: U.Common.sprintf(translate('commonUpdateProgress'), U.File.size(progress.transferred), U.File.size(progress.total)), + S.Progress.update({ + id: I.ProgressType.Update, + type: I.ProgressType.Update, current: progress.transferred, total: progress.total, - isUnlocked: true, }); }; diff --git a/src/ts/component/util/progress.tsx b/src/ts/component/util/progress.tsx index 03f222a16a..79516e8134 100644 --- a/src/ts/component/util/progress.tsx +++ b/src/ts/component/util/progress.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; -import { observer } from 'mobx-react'; import $ from 'jquery'; +import { observer } from 'mobx-react'; import { Icon, Label } from 'Component'; -import { S, U, C, J, Storage, keyboard } from 'Lib'; +import { S, U, C, J, Storage, keyboard, translate } from 'Lib'; const Progress = observer(class Progress extends React.Component { @@ -22,26 +22,50 @@ const Progress = observer(class Progress extends React.Component { }; render () { - const { progress } = S.Common; - const { status, current, total, isUnlocked, canCancel } = progress || {}; + const { list } = S.Progress; + const cn = [ 'progress' ]; - if (!status) { + if (!list.length) { return null; }; - - const text = U.Common.sprintf(status, current, total); - const cn = [ 'progress', (isUnlocked ? 'isUnlocked' : '') ]; - + + let current = 0; + let total = 0; + + list.forEach(item => { + current += item.current; + total += item.total; + }); + + const percent = total > 0 ? Math.ceil(current / total * 100) : 0; + + const Item = (item: any) => { + return ( +
+
+
+ +
+
+
+
+ ); + }; + return (
this.node = node} className={cn.join(' ')} >
-