UX: add pending changes indicator
This commit is contained in:
parent
09e50464b8
commit
d7d6c3142c
6 changed files with 56 additions and 16 deletions
|
@ -316,6 +316,7 @@
|
|||
},
|
||||
"skip": "Skip this question",
|
||||
"testing": "Testing - changes won't be saved",
|
||||
"uploadError": "Error while uploading changes: {error}",
|
||||
"uploadGpx": {
|
||||
"choosePermission": "Choose below if your track should be shared:",
|
||||
"confirm": "Confirm upload",
|
||||
|
@ -343,6 +344,9 @@
|
|||
"uploadFinished": "Your track has been uploaded!",
|
||||
"uploading": "Uploading your trace…"
|
||||
},
|
||||
"uploadPending": "{count} changes pending",
|
||||
"uploadPendingSingle": "One change pending",
|
||||
"uploadingChanges": "Uploading changes…",
|
||||
"useSearch": "Use the search above to see presets",
|
||||
"useSearchForMore": "Use the search function to search within {total} more values…",
|
||||
"waitingForGeopermission": "Waiting for your permission to use the geolocation…",
|
||||
|
|
|
@ -5,23 +5,11 @@ import { Utils } from "../../Utils"
|
|||
import { Feature } from "geojson"
|
||||
|
||||
export default class PendingChangesUploader {
|
||||
private lastChange: Date
|
||||
|
||||
constructor(changes: Changes, selectedFeature: UIEventSource<Feature>) {
|
||||
const self = this
|
||||
this.lastChange = new Date()
|
||||
changes.pendingChanges.addCallback(() => {
|
||||
self.lastChange = new Date()
|
||||
changes.pendingChanges.stabilized(Constants.updateTimeoutSec * 1000).addCallback(() => changes.flushChanges("Flushing changes due to timeout"))
|
||||
|
||||
window.setTimeout(() => {
|
||||
const diff = (new Date().getTime() - self.lastChange.getTime()) / 1000
|
||||
if (Constants.updateTimeoutSec >= diff - 1) {
|
||||
changes.flushChanges("Flushing changes due to timeout")
|
||||
}
|
||||
}, Constants.updateTimeoutSec * 1000)
|
||||
})
|
||||
|
||||
selectedFeature.stabilized(10000).addCallback((feature) => {
|
||||
selectedFeature.stabilized(1000).addCallback((feature) => {
|
||||
if (feature === undefined) {
|
||||
// The popup got closed - we flush
|
||||
changes.flushChanges("Flushing changes due to popup closed")
|
||||
|
|
|
@ -26,6 +26,7 @@ export class Changes {
|
|||
public readonly extraComment: UIEventSource<string> = new UIEventSource(undefined)
|
||||
public readonly backend: string
|
||||
public readonly isUploading = new UIEventSource(false)
|
||||
public readonly errors = new UIEventSource<string[]>([], "upload-errors")
|
||||
private readonly historicalUserLocations?: FeatureSource
|
||||
private _nextId: number = -1 // Newly assigned ID's are negative
|
||||
private readonly previouslyCreated: OsmObject[] = []
|
||||
|
@ -128,8 +129,11 @@ export class Changes {
|
|||
const csNumber = await this.flushChangesAsync()
|
||||
this.isUploading.setData(false)
|
||||
console.log("Changes flushed. Your changeset is " + csNumber)
|
||||
this.errors.setData([])
|
||||
} catch (e) {
|
||||
this.isUploading.setData(false)
|
||||
this.errors.data.push(e)
|
||||
this.errors.ping()
|
||||
console.error("Flushing changes failed due to", e)
|
||||
}
|
||||
}
|
||||
|
@ -415,6 +419,8 @@ export class Changes {
|
|||
id,
|
||||
" dropping it from the changes (" + e + ")"
|
||||
)
|
||||
this.errors.data.push(e)
|
||||
this.errors.ping()
|
||||
return undefined
|
||||
}
|
||||
})
|
||||
|
@ -572,9 +578,15 @@ export class Changes {
|
|||
openChangeset.data
|
||||
)
|
||||
|
||||
return await self.flushSelectChanges(pendingChanges, openChangeset)
|
||||
const result = await self.flushSelectChanges(pendingChanges, openChangeset)
|
||||
if(result){
|
||||
this.errors.setData([])
|
||||
}
|
||||
return result
|
||||
} catch (e) {
|
||||
console.error("Could not upload some changes:", e)
|
||||
this.errors.data.push(e)
|
||||
this.errors.ping()
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
@ -589,6 +601,8 @@ export class Changes {
|
|||
"Could not handle changes - probably an old, pending changeset in localstorage with an invalid format; erasing those",
|
||||
e
|
||||
)
|
||||
this.errors.data.push(e)
|
||||
this.errors.ping()
|
||||
self.pendingChanges.setData([])
|
||||
} finally {
|
||||
self.isUploading.setData(false)
|
||||
|
|
|
@ -63,7 +63,7 @@ export default class Constants {
|
|||
* Used by 'PendingChangesUploader', which waits this amount of seconds to upload changes.
|
||||
* (Note that pendingChanges might upload sooner if the popup is closed or similar)
|
||||
*/
|
||||
static updateTimeoutSec: number = 30
|
||||
static updateTimeoutSec: number = 15
|
||||
/**
|
||||
* If the contributor has their GPS location enabled and makes a change,
|
||||
* the points visited less then `nearbyVisitTime`-seconds ago will be inspected.
|
||||
|
|
32
src/UI/BigComponents/PendingChangesIndicator.svelte
Normal file
32
src/UI/BigComponents/PendingChangesIndicator.svelte
Normal file
|
@ -0,0 +1,32 @@
|
|||
<script lang="ts">
|
||||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
import { Changes } from "../../Logic/Osm/Changes"
|
||||
import Loading from "../Base/Loading.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
|
||||
export let state: SpecialVisualizationState
|
||||
|
||||
const changes: Changes = state.changes
|
||||
const isUploading: Store<boolean> = changes.isUploading
|
||||
const pendingChangesCount: Store<number> = changes.pendingChanges.map(ls => ls.length)
|
||||
const errors = changes.errors
|
||||
</script>
|
||||
|
||||
|
||||
<div class="flex flex-col pointer-events-auto" on:click={() => changes.flushChanges("Pending changes indicator clicked")}>
|
||||
{#if $isUploading}
|
||||
<Loading>
|
||||
<Tr cls="thx" t={Translations.t.general.uploadingChanges} />
|
||||
</Loading>
|
||||
{:else if $pendingChangesCount === 1}
|
||||
<Tr cls="alert" t={Translations.t.general.uploadPendingSingle} />
|
||||
{:else if $pendingChangesCount > 1}
|
||||
<Tr cls="alert" t={Translations.t.general.uploadPending.Subs({count: $pendingChangesCount})} />
|
||||
{/if}
|
||||
|
||||
{#each $errors as error}
|
||||
<Tr cls="alert" t={Translations.t.general.uploadError.Subs({error})} />
|
||||
{/each}
|
||||
</div>
|
|
@ -53,6 +53,7 @@
|
|||
import Locale from "./i18n/Locale";
|
||||
import ShareScreen from "./BigComponents/ShareScreen.svelte";
|
||||
import UploadingImageCounter from "./Image/UploadingImageCounter.svelte"
|
||||
import PendingChangesIndicator from "./BigComponents/PendingChangesIndicator.svelte"
|
||||
|
||||
export let state: ThemeViewState;
|
||||
let layout = state.layout;
|
||||
|
@ -156,6 +157,7 @@
|
|||
construct={() => new ExtraLinkButton(state, layout.extraLink).SetClass("pointer-events-auto")}
|
||||
/>
|
||||
<UploadingImageCounter {state} featureId="*" showThankYou={false}/>
|
||||
<PendingChangesIndicator {state}/>
|
||||
<If condition={state.featureSwitchIsTesting}>
|
||||
<div class="alert w-fit">Testmode</div>
|
||||
</If>
|
||||
|
|
Loading…
Reference in a new issue