refactor: make scroller use rows
parent
48ba5d35ac
commit
ec4a11dae8
|
@ -22,7 +22,7 @@
|
||||||
<div v-for="tick of visibleTicks" :key="tick.dayId"
|
<div v-for="tick of visibleTicks" :key="tick.dayId"
|
||||||
class="tick"
|
class="tick"
|
||||||
:class="{ 'dash': !tick.text }"
|
:class="{ 'dash': !tick.text }"
|
||||||
:style="{ top: tick.topC + 'px' }">
|
:style="{ top: tick.top + 'px' }">
|
||||||
|
|
||||||
<span v-if="tick.text">{{ tick.text }}</span>
|
<span v-if="tick.text">{{ tick.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Mixins, Prop } from 'vue-property-decorator';
|
import { Component, Mixins, Prop } from 'vue-property-decorator';
|
||||||
import { IDay, IHeadRow, ITick } from '../types';
|
import { IDay, IHeadRow, IRow, IRowType, ITick } from '../types';
|
||||||
import GlobalMixin from '../mixins/GlobalMixin';
|
import GlobalMixin from '../mixins/GlobalMixin';
|
||||||
import ScrollIcon from 'vue-material-design-icons/UnfoldMoreHorizontal.vue';
|
import ScrollIcon from 'vue-material-design-icons/UnfoldMoreHorizontal.vue';
|
||||||
|
|
||||||
|
@ -43,14 +43,10 @@ import * as utils from "../services/Utils";
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class ScrollerManager extends Mixins(GlobalMixin) {
|
export default class ScrollerManager extends Mixins(GlobalMixin) {
|
||||||
/** Days from Timeline */
|
/** Rows from Timeline */
|
||||||
@Prop() days!: IDay[];
|
@Prop() rows!: IRow[];
|
||||||
/** Heads from Timeline */
|
|
||||||
@Prop() heads!: { [dayid: number]: IHeadRow };
|
|
||||||
/** Total height */
|
/** Total height */
|
||||||
@Prop() height!: number;
|
@Prop() height!: number;
|
||||||
/** Height of a row */
|
|
||||||
@Prop() rowHeight!: number;
|
|
||||||
/** Actual recycler component */
|
/** Actual recycler component */
|
||||||
@Prop() recycler!: any;
|
@Prop() recycler!: any;
|
||||||
/** Recycler before slot component */
|
/** Recycler before slot component */
|
||||||
|
@ -107,32 +103,31 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Re-create tick data in the next frame */
|
/** Re-create tick data in the next frame */
|
||||||
public async reflow(orderOnly = false) {
|
public async reflow() {
|
||||||
if (this.reflowRequest) {
|
if (this.reflowRequest) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reflowRequest = true;
|
this.reflowRequest = true;
|
||||||
await this.$nextTick();
|
await this.$nextTick();
|
||||||
this.reflowNow(orderOnly);
|
this.reflowNow();
|
||||||
this.reflowRequest = false;
|
this.reflowRequest = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Re-create tick data */
|
/** Re-create tick data */
|
||||||
private reflowNow(orderOnly = false) {
|
private reflowNow() {
|
||||||
if (!orderOnly) {
|
// Recreate ticks data
|
||||||
this.recreate();
|
this.recreate();
|
||||||
}
|
|
||||||
|
|
||||||
|
// Get height of recycler
|
||||||
this.recyclerHeight = this.recycler.$refs.wrapper.clientHeight;
|
this.recyclerHeight = this.recycler.$refs.wrapper.clientHeight;
|
||||||
|
|
||||||
// Static extra height at top
|
// Static extra height at top (before slot)
|
||||||
const rb = this.recyclerBefore as Element;
|
const extraY = this.recyclerBefore?.clientHeight || 0;
|
||||||
const extraHeight = rb?.clientHeight || 0;
|
|
||||||
|
|
||||||
// Compute tick positions
|
// Compute tick positions
|
||||||
for (const tick of this.ticks) {
|
for (const tick of this.ticks) {
|
||||||
tick.topC = (extraHeight + tick.topS + tick.top * this.rowHeight) * this.height / this.recyclerHeight;
|
tick.top = (extraY + tick.y) * (this.height / this.recyclerHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do another pass to figure out which points are visible
|
// Do another pass to figure out which points are visible
|
||||||
|
@ -143,13 +138,13 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
|
||||||
let prevShow = -9999;
|
let prevShow = -9999;
|
||||||
for (const [idx, tick] of this.ticks.entries()) {
|
for (const [idx, tick] of this.ticks.entries()) {
|
||||||
// You can't see these anyway, why bother?
|
// You can't see these anyway, why bother?
|
||||||
if (tick.topC < minGap || tick.topC > this.height - minGap) {
|
if (tick.top < minGap || tick.top > this.height - minGap) {
|
||||||
tick.s = false;
|
tick.s = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will overlap with the previous tick. Skip anyway.
|
// Will overlap with the previous tick. Skip anyway.
|
||||||
if (tick.topC - prevShow < minGap) {
|
if (tick.top - prevShow < minGap) {
|
||||||
tick.s = false;
|
tick.s = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -157,7 +152,7 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
|
||||||
// This is a labelled tick then show it anyway for the sake of best effort
|
// This is a labelled tick then show it anyway for the sake of best effort
|
||||||
if (tick.text) {
|
if (tick.text) {
|
||||||
tick.s = true;
|
tick.s = true;
|
||||||
prevShow = tick.topC;
|
prevShow = tick.top;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,8 +168,8 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
|
||||||
if (i < this.ticks.length) {
|
if (i < this.ticks.length) {
|
||||||
// A labelled tick was found
|
// A labelled tick was found
|
||||||
const nextLabelledTick = this.ticks[i];
|
const nextLabelledTick = this.ticks[i];
|
||||||
if (tick.topC + minGap > nextLabelledTick.topC &&
|
if (tick.top + minGap > nextLabelledTick.top &&
|
||||||
nextLabelledTick.topC < this.height - minGap) { // make sure this will be shown
|
nextLabelledTick.top < this.height - minGap) { // make sure this will be shown
|
||||||
tick.s = false;
|
tick.s = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -182,7 +177,7 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
|
||||||
|
|
||||||
// Show this tick
|
// Show this tick
|
||||||
tick.s = true;
|
tick.s = true;
|
||||||
prevShow = tick.topC;
|
prevShow = tick.top;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,48 +187,45 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
|
||||||
this.ticks = [];
|
this.ticks = [];
|
||||||
|
|
||||||
// Ticks
|
// Ticks
|
||||||
let currTopRow = 0;
|
let y = 0;
|
||||||
let currTopStatic = 0;
|
|
||||||
let prevYear = 9999;
|
let prevYear = 9999;
|
||||||
let prevMonth = 0;
|
let prevMonth = 0;
|
||||||
const thisYear = new Date().getFullYear();
|
const thisYear = new Date().getFullYear();
|
||||||
|
|
||||||
// Get a new tick
|
// Get a new tick
|
||||||
const getTick = (day: IDay, text?: string | number): ITick => {
|
const getTick = (dayId: number, text?: string | number): ITick => {
|
||||||
return {
|
return {
|
||||||
dayId: day.dayid,
|
dayId,
|
||||||
top: currTopRow,
|
y: y,
|
||||||
topS: currTopStatic,
|
text,
|
||||||
topC: 0,
|
top: 0,
|
||||||
text: text,
|
s: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Itearte over days
|
// Itearte over rows
|
||||||
for (const day of this.days) {
|
for (const row of this.rows) {
|
||||||
if (day.count === 0) {
|
if (row.type === IRowType.HEAD) {
|
||||||
continue;
|
if (Object.values(this.TagDayID).includes(row.dayId)) {
|
||||||
}
|
// Blank tick
|
||||||
|
this.ticks.push(getTick(row.dayId));
|
||||||
if (Object.values(this.TagDayID).includes(day.dayid)) {
|
|
||||||
// Blank dash ticks only
|
|
||||||
this.ticks.push(getTick(day));
|
|
||||||
} else {
|
} else {
|
||||||
// Make date string
|
// Make date string
|
||||||
const dateTaken = utils.dayIdToDate(day.dayid);
|
const dateTaken = utils.dayIdToDate(row.dayId);
|
||||||
|
|
||||||
// Create tick if month changed
|
// Create tick if month changed
|
||||||
const dtYear = dateTaken.getUTCFullYear();
|
const dtYear = dateTaken.getUTCFullYear();
|
||||||
const dtMonth = dateTaken.getUTCMonth()
|
const dtMonth = dateTaken.getUTCMonth()
|
||||||
if (Number.isInteger(day.dayid) && (dtMonth !== prevMonth || dtYear !== prevYear)) {
|
if (Number.isInteger(row.dayId) && (dtMonth !== prevMonth || dtYear !== prevYear)) {
|
||||||
this.ticks.push(getTick(day, (dtYear === prevYear || dtYear === thisYear) ? undefined : dtYear));
|
const text = (dtYear === prevYear || dtYear === thisYear) ? undefined : dtYear;
|
||||||
|
this.ticks.push(getTick(row.dayId, text));
|
||||||
}
|
}
|
||||||
prevMonth = dtMonth;
|
prevMonth = dtMonth;
|
||||||
prevYear = dtYear;
|
prevYear = dtYear;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
currTopStatic += this.heads[day.dayid].size;
|
y += row.size;
|
||||||
currTopRow += day.rows.size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,8 +234,10 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
|
||||||
this.hoverCursorY = y;
|
this.hoverCursorY = y;
|
||||||
|
|
||||||
// Get index of previous tick
|
// Get index of previous tick
|
||||||
let idx = this.ticks.findIndex(t => t.topC > y);
|
let idx = this.ticks.findIndex(t => t.top >= y);
|
||||||
if (idx >= 1) {
|
if (idx === 0) {
|
||||||
|
// use this tick
|
||||||
|
} else if (idx >= 1) {
|
||||||
idx = idx - 1;
|
idx = idx - 1;
|
||||||
} else if (idx === -1 && this.ticks.length > 0) {
|
} else if (idx === -1 && this.ticks.length > 0) {
|
||||||
idx = this.ticks.length - 1;
|
idx = this.ticks.length - 1;
|
||||||
|
|
|
@ -76,9 +76,8 @@
|
||||||
|
|
||||||
<!-- Managers -->
|
<!-- Managers -->
|
||||||
<ScrollerManager ref="scrollerManager"
|
<ScrollerManager ref="scrollerManager"
|
||||||
:days="days" :heads="heads"
|
:rows="list"
|
||||||
:height="scrollerHeight"
|
:height="scrollerHeight"
|
||||||
:rowHeight="rowHeight"
|
|
||||||
:recycler="$refs.recycler"
|
:recycler="$refs.recycler"
|
||||||
:recyclerBefore="$refs.recyclerBefore" />
|
:recyclerBefore="$refs.recyclerBefore" />
|
||||||
|
|
||||||
|
@ -92,7 +91,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Watch, Mixins } from 'vue-property-decorator';
|
import { Component, Watch, Mixins } from 'vue-property-decorator';
|
||||||
import { IDay, IFolder, IHeadRow, IPhoto, IRow, IRowType, ITick } from "../types";
|
import { IDay, IFolder, IHeadRow, IPhoto, IRow, IRowType } from "../types";
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '@nextcloud/dialogs'
|
import { showError } from '@nextcloud/dialogs'
|
||||||
import { getCanonicalLocale } from '@nextcloud/l10n';
|
import { getCanonicalLocale } from '@nextcloud/l10n';
|
||||||
|
@ -285,7 +284,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
|
||||||
this.list.filter(r => r.type !== IRowType.HEAD).forEach(row => {
|
this.list.filter(r => r.type !== IRowType.HEAD).forEach(row => {
|
||||||
row.size = this.rowHeight;
|
row.size = this.rowHeight;
|
||||||
});
|
});
|
||||||
this.scrollerManager.reflow(true);
|
this.scrollerManager.reflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -109,12 +109,10 @@ export enum IRowType {
|
||||||
export type ITick = {
|
export type ITick = {
|
||||||
/** Day ID */
|
/** Day ID */
|
||||||
dayId: number;
|
dayId: number;
|
||||||
/** Number of ROWS above this (dynamic) */
|
/** Display top position */
|
||||||
top: number;
|
top: number;
|
||||||
/** Extra static distance from top (for headers) */
|
/** Y coordinate on recycler */
|
||||||
topS: number;
|
y: number;
|
||||||
/** Actual Y position calculated (C) */
|
|
||||||
topC: number;
|
|
||||||
/** Text if any (e.g. year) */
|
/** Text if any (e.g. year) */
|
||||||
text?: string | number;
|
text?: string | number;
|
||||||
/** Whether this tick should be shown */
|
/** Whether this tick should be shown */
|
||||||
|
|
Loading…
Reference in New Issue