timeline: revert loading icon move
Signed-off-by: Varun Patil <radialapps@gmail.com>pull/653/merge
parent
a7e7f80745
commit
90003614b7
|
@ -6,7 +6,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineComponent, type PropType } from 'vue';
|
||||
|
||||
const SWIPE_PX = 250;
|
||||
|
||||
|
@ -14,37 +14,56 @@ export default defineComponent({
|
|||
name: 'SwipeRefresh',
|
||||
|
||||
props: {
|
||||
refresh: {
|
||||
type: Function as PropType<() => Promise<any>>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
allowSwipe: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
state: {
|
||||
type: Number,
|
||||
default: Math.random(),
|
||||
},
|
||||
},
|
||||
|
||||
emits: {
|
||||
refresh: () => true,
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
/** Is active interaction */
|
||||
on: false,
|
||||
/** Start touch Y coordinate */
|
||||
start: 0,
|
||||
/** End touch Y coordinate */
|
||||
end: 0,
|
||||
updateFrame: 0,
|
||||
/** Percentage progress to show in swiping */
|
||||
progress: 0,
|
||||
/** Next update frame reference */
|
||||
updateFrame: 0,
|
||||
|
||||
// Loading animation state
|
||||
loading: false,
|
||||
animate: false,
|
||||
wasSwiped: true,
|
||||
firstcycle: 0,
|
||||
}),
|
||||
|
||||
emits: [],
|
||||
|
||||
mounted() {
|
||||
this.animate = this.loading; // start if needed
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.reset();
|
||||
},
|
||||
|
||||
watch: {
|
||||
state() {
|
||||
this.reset();
|
||||
},
|
||||
|
||||
loading() {
|
||||
this.wasSwiped = this.progress >= 100;
|
||||
if (!this.wasSwiped) {
|
||||
|
@ -93,6 +112,21 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
methods: {
|
||||
reset() {
|
||||
// Clear events
|
||||
window.cancelAnimationFrame(this.updateFrame);
|
||||
window.clearTimeout(this.firstcycle);
|
||||
|
||||
// Reset state
|
||||
this.on = false;
|
||||
this.progress = 0;
|
||||
this.updateFrame = 0;
|
||||
this.loading = false;
|
||||
this.animate = false;
|
||||
this.wasSwiped = true;
|
||||
this.firstcycle = 0;
|
||||
},
|
||||
|
||||
/** Start gesture on container (passive) */
|
||||
touchstart(event: TouchEvent) {
|
||||
if (!this.allowSwipe) return;
|
||||
|
@ -104,12 +138,12 @@ export default defineComponent({
|
|||
|
||||
/** Execute gesture on container (passive) */
|
||||
touchmove(event: TouchEvent) {
|
||||
if (!this.allowSwipe) return;
|
||||
if (!this.allowSwipe || !this.on) return;
|
||||
const touch = event.touches[0];
|
||||
this.end = touch.clientY;
|
||||
|
||||
// Update progress only once per frame
|
||||
this.updateFrame ||= requestAnimationFrame(() => {
|
||||
this.updateFrame ||= window.requestAnimationFrame(async () => {
|
||||
this.updateFrame = 0;
|
||||
|
||||
// Compute percentage of swipe
|
||||
|
@ -118,8 +152,16 @@ export default defineComponent({
|
|||
|
||||
// Execute action on threshold
|
||||
if (this.progress >= 100) {
|
||||
this.$emit('refresh');
|
||||
this.on = false;
|
||||
const state = this.state;
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.refresh();
|
||||
} finally {
|
||||
if (this.state === state) {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -170,7 +212,7 @@ export default defineComponent({
|
|||
}
|
||||
49.99% {
|
||||
background-image: $progress-outside;
|
||||
background-size: 12000% 12000%;
|
||||
background-size: 11000% 11000%;
|
||||
}
|
||||
50% {
|
||||
background-image: $progress-inside;
|
||||
|
@ -178,7 +220,7 @@ export default defineComponent({
|
|||
}
|
||||
100% {
|
||||
background-image: $progress-inside;
|
||||
background-size: 12000% 12000%;
|
||||
background-size: 11000% 11000%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
<SwipeRefresh
|
||||
class="container no-user-select"
|
||||
ref="container"
|
||||
:refresh="softRefreshSync"
|
||||
:allowSwipe="allowSwipe"
|
||||
@refresh="softRefresh"
|
||||
:loading="loading > 0"
|
||||
:state="state"
|
||||
>
|
||||
<!-- Loading indicator -->
|
||||
<XLoadingIcon class="loading-icon centered" v-if="loading" />
|
||||
|
||||
<!-- Static top matter -->
|
||||
<TopMatter ref="topmatter" />
|
||||
|
||||
|
@ -275,7 +278,7 @@ export default defineComponent({
|
|||
|
||||
// Do a soft refresh if the query changes
|
||||
else if (JSON.stringify(from.query) !== JSON.stringify(to.query)) {
|
||||
await this.softRefreshInternal(true);
|
||||
await this.softRefreshSync();
|
||||
}
|
||||
|
||||
// Check if viewer is supposed to be open
|
||||
|
@ -370,14 +373,19 @@ export default defineComponent({
|
|||
* when changing the configuration
|
||||
*/
|
||||
softRefresh() {
|
||||
this.softRefreshInternal(false);
|
||||
this._softRefreshInternal(false);
|
||||
},
|
||||
|
||||
/** Fetch and re-process days (sync can be awaited) */
|
||||
async softRefreshSync() {
|
||||
await this._softRefreshInternal(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch and re-process days (can be awaited if sync).
|
||||
* Do not pass this function as a callback directly.
|
||||
*/
|
||||
async softRefreshInternal(sync: boolean) {
|
||||
async _softRefreshInternal(sync: boolean) {
|
||||
this.refs.selectionManager.clear();
|
||||
this.fetchDayQueue = []; // reset queue
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ export default defineComponent({
|
|||
|
||||
.loading-icon {
|
||||
z-index: 100000; // above everything
|
||||
pointer-events: none;
|
||||
|
||||
.higher {
|
||||
position: relative;
|
||||
|
|
Loading…
Reference in New Issue