refactor: improve typing
Signed-off-by: Varun Patil <radialapps@gmail.com>pull/803/head
parent
fbcec52de4
commit
65cd1952ff
|
@ -40,8 +40,10 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import config from '../services/static-config';
|
||||
import type { Component } from 'vue';
|
||||
|
||||
import axios from '@nextcloud/axios';
|
||||
import { translate as t } from '@nextcloud/l10n';
|
||||
|
||||
import ClusterHList from './ClusterHList.vue';
|
||||
|
||||
|
@ -55,9 +57,10 @@ import CalendarIcon from 'vue-material-design-icons/Calendar.vue';
|
|||
import MapIcon from 'vue-material-design-icons/Map.vue';
|
||||
import CogIcon from 'vue-material-design-icons/Cog.vue';
|
||||
|
||||
import type { ICluster, IConfig } from '../types';
|
||||
import config from '../services/static-config';
|
||||
import { API } from '../services/API';
|
||||
import { translate as t } from '@nextcloud/l10n';
|
||||
|
||||
import type { ICluster, IConfig } from '../types';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Explore',
|
||||
|
@ -110,7 +113,7 @@ export default defineComponent({
|
|||
},
|
||||
] as {
|
||||
name: string;
|
||||
icon: any;
|
||||
icon: Component;
|
||||
link?: string;
|
||||
click?: () => void;
|
||||
}[],
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
|
||||
import NcActions from '@nextcloud/vue/dist/Components/NcActions';
|
||||
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton';
|
||||
|
@ -97,7 +98,7 @@ interface TopField {
|
|||
id?: string;
|
||||
title: string;
|
||||
subtitle: string[];
|
||||
icon: any;
|
||||
icon: Component;
|
||||
href?: string;
|
||||
edit?: () => void;
|
||||
}
|
||||
|
@ -117,7 +118,7 @@ export default defineComponent({
|
|||
data: () => ({
|
||||
fileid: null as number | null,
|
||||
filename: '',
|
||||
exif: {} as { [prop: string]: any },
|
||||
exif: {} as NonNullable<IImageInfo['exif']>,
|
||||
baseInfo: {} as IImageInfo,
|
||||
|
||||
loading: 0,
|
||||
|
@ -210,8 +211,8 @@ export default defineComponent({
|
|||
// The fallback to datetaken can be eventually removed
|
||||
// and then this can be discarded
|
||||
if (this.exif.DateTimeEpoch) {
|
||||
const tzOffset: string = this.exif.OffsetTimeOriginal || this.exif.OffsetTime; // e.g. -05:00
|
||||
const tzId: string = this.exif.LocationTZID; // e.g. America/New_York
|
||||
const tzOffset = this.exif.OffsetTimeOriginal || this.exif.OffsetTime; // e.g. -05:00
|
||||
const tzId = this.exif.LocationTZID; // e.g. America/New_York
|
||||
|
||||
let dateWithTz: DateTime | undefined = undefined;
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import type { Route } from 'vue-router';
|
||||
|
||||
import axios from '@nextcloud/axios';
|
||||
import { showError } from '@nextcloud/dialogs';
|
||||
|
@ -182,7 +183,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
watch: {
|
||||
async $route(to: any, from?: any) {
|
||||
async $route(to: Route, from?: Route) {
|
||||
await this.routeChange(to, from);
|
||||
},
|
||||
},
|
||||
|
@ -228,7 +229,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
methods: {
|
||||
async routeChange(to: any, from?: any) {
|
||||
async routeChange(to: Route, from?: Route) {
|
||||
// Always do a hard refresh if the path changes
|
||||
if (from?.path !== to.path) {
|
||||
await this.refresh();
|
||||
|
@ -444,7 +445,7 @@ export default defineComponent({
|
|||
* This does NOT indicate the items have changed, only that
|
||||
* the pixel position of the recycler has changed.
|
||||
*/
|
||||
scrollPositionChange(event?: any) {
|
||||
scrollPositionChange(event?: Event) {
|
||||
this.scrollerManager().recyclerScrolled(event);
|
||||
},
|
||||
|
||||
|
@ -549,40 +550,41 @@ export default defineComponent({
|
|||
|
||||
/** Get query string for API calls */
|
||||
getQuery() {
|
||||
const query: { [key: string]: string } = {};
|
||||
const query: { [key in DaysFilterType]?: string } = {};
|
||||
const set = (filter: DaysFilterType, value: string = '1') => (query[filter] = value);
|
||||
|
||||
// Favorites
|
||||
if (this.$route.name === 'favorites') {
|
||||
API.DAYS_FILTER(query, DaysFilterType.FAVORITES);
|
||||
if (this.routeIsFavorites) {
|
||||
set(DaysFilterType.FAVORITES);
|
||||
}
|
||||
|
||||
// Videos
|
||||
if (this.$route.name === 'videos') {
|
||||
API.DAYS_FILTER(query, DaysFilterType.VIDEOS);
|
||||
if (this.routeIsVideos) {
|
||||
set(DaysFilterType.VIDEOS);
|
||||
}
|
||||
|
||||
// Folder
|
||||
if (this.$route.name === 'folders') {
|
||||
if (this.routeIsFolders) {
|
||||
const path = utils.getFolderRoutePath(this.config.folders_path);
|
||||
API.DAYS_FILTER(query, DaysFilterType.FOLDER, path);
|
||||
set(DaysFilterType.FOLDER, path);
|
||||
if (this.$route.query.recursive) {
|
||||
API.DAYS_FILTER(query, DaysFilterType.RECURSIVE);
|
||||
set(DaysFilterType.RECURSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
// Archive
|
||||
if (this.$route.name === 'archive') {
|
||||
API.DAYS_FILTER(query, DaysFilterType.ARCHIVE);
|
||||
if (this.routeIsArchive) {
|
||||
set(DaysFilterType.ARCHIVE);
|
||||
}
|
||||
|
||||
// Albums
|
||||
const user = <string>this.$route.params.user;
|
||||
const name = <string>this.$route.params.name;
|
||||
if (this.$route.name === 'albums') {
|
||||
if (this.routeIsAlbums) {
|
||||
if (!user || !name) {
|
||||
throw new Error('Invalid album route');
|
||||
}
|
||||
API.DAYS_FILTER(query, DaysFilterType.ALBUM, `${user}/${name}`);
|
||||
set(DaysFilterType.ALBUM, `${user}/${name}`);
|
||||
}
|
||||
|
||||
// People
|
||||
|
@ -591,47 +593,48 @@ export default defineComponent({
|
|||
throw new Error('Invalid album route');
|
||||
}
|
||||
|
||||
// name is "recognize" or "facerecognition"
|
||||
const filter = <DaysFilterType>this.$route.name;
|
||||
API.DAYS_FILTER(query, filter, `${user}/${name}`);
|
||||
set(filter, `${user}/${name}`);
|
||||
|
||||
// Face rect
|
||||
if (this.config.show_face_rect || this.routeIsRecognizeUnassigned) {
|
||||
API.DAYS_FILTER(query, DaysFilterType.FACE_RECT);
|
||||
set(DaysFilterType.FACE_RECT);
|
||||
}
|
||||
}
|
||||
|
||||
// Places
|
||||
if (this.$route.name === 'places') {
|
||||
if (this.routeIsPlaces) {
|
||||
if (!name || !name.includes('-')) {
|
||||
throw new Error('Invalid place route');
|
||||
}
|
||||
|
||||
const id = <string>name.split('-', 1)[0];
|
||||
API.DAYS_FILTER(query, DaysFilterType.PLACE, id);
|
||||
set(DaysFilterType.PLACE, id);
|
||||
}
|
||||
|
||||
// Tags
|
||||
if (this.$route.name === 'tags') {
|
||||
if (this.routeIsTags) {
|
||||
if (!name) {
|
||||
throw new Error('Invalid tag route');
|
||||
}
|
||||
API.DAYS_FILTER(query, DaysFilterType.TAG, name);
|
||||
set(DaysFilterType.TAG, name);
|
||||
}
|
||||
|
||||
// Map Bounds
|
||||
if (this.$route.name === 'map') {
|
||||
if (this.routeIsMap) {
|
||||
const bounds = <string>this.$route.query.b;
|
||||
if (!bounds) {
|
||||
throw new Error('Missing map bounds');
|
||||
}
|
||||
|
||||
API.DAYS_FILTER(query, DaysFilterType.MAP_BOUNDS, bounds);
|
||||
set(DaysFilterType.MAP_BOUNDS, bounds);
|
||||
}
|
||||
|
||||
// Month view
|
||||
if (this.isMonthView) {
|
||||
API.DAYS_FILTER(query, DaysFilterType.MONTH_VIEW);
|
||||
API.DAYS_FILTER(query, DaysFilterType.REVERSE);
|
||||
set(DaysFilterType.MONTH_VIEW);
|
||||
set(DaysFilterType.REVERSE);
|
||||
}
|
||||
|
||||
return query;
|
||||
|
|
|
@ -226,7 +226,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
/** Error in loading image */
|
||||
error(e: any) {
|
||||
error(e: Event) {
|
||||
this.data.flag |= this.c.FLAG_LOAD_FAIL;
|
||||
},
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ const expirationManager = new CacheExpiration(cacheName, {
|
|||
});
|
||||
|
||||
// Start fetching with multipreview
|
||||
let fetchPreviewTimer: any;
|
||||
let fetchPreviewTimer: number;
|
||||
|
||||
/** Flushes the queue of preview image requests */
|
||||
async function flushPreviewQueue() {
|
||||
|
|
|
@ -62,7 +62,7 @@ export default defineComponent({
|
|||
this.$emit('close');
|
||||
},
|
||||
|
||||
done({ album }: any) {
|
||||
done({ album }: { album: { basename: string; filename: string } }) {
|
||||
if (!this.album || album.basename !== this.album.basename) {
|
||||
const user = album.filename.split('/')[2];
|
||||
const name = album.basename;
|
||||
|
|
|
@ -41,7 +41,7 @@ export default defineComponent({
|
|||
}),
|
||||
|
||||
watch: {
|
||||
$route: async function (from: any, to: any) {
|
||||
$route() {
|
||||
this.refreshParams();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -163,7 +163,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
methods: {
|
||||
submit(collaborators: any = []) {
|
||||
submit(collaborators: any[] = []) {
|
||||
if (this.albumName === '' || this.loading) {
|
||||
return;
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
|
||||
async handleCreateAlbum(collaborators = []) {
|
||||
async handleCreateAlbum(collaborators: any[] = []) {
|
||||
try {
|
||||
this.loading = true;
|
||||
let album = {
|
||||
|
|
|
@ -64,7 +64,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
methods: {
|
||||
click($event: any, album: IAlbum) {
|
||||
click($event: Event, album: IAlbum) {
|
||||
if (!this.link) {
|
||||
$event.preventDefault();
|
||||
}
|
||||
|
|
|
@ -28,6 +28,11 @@ const NcTextField = () => import('@nextcloud/vue/dist/Components/NcTextField');
|
|||
|
||||
import { translate as t } from '@nextcloud/l10n';
|
||||
|
||||
interface IField {
|
||||
field: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
NcTextField,
|
||||
|
@ -41,8 +46,8 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
data: () => ({
|
||||
exif: null as any,
|
||||
dirty: {},
|
||||
exif: null! as Record<string, string>,
|
||||
dirty: {} as Record<string, boolean>,
|
||||
|
||||
fields: [
|
||||
{
|
||||
|
@ -73,7 +78,7 @@ export default defineComponent({
|
|||
field: 'Copyright',
|
||||
label: t('memories', 'Copyright'),
|
||||
},
|
||||
],
|
||||
] as IField[],
|
||||
}),
|
||||
|
||||
mounted() {
|
||||
|
@ -95,7 +100,7 @@ export default defineComponent({
|
|||
if (ePhoto && (eCurr === null || ePhoto === eCurr)) {
|
||||
exif[field.field] = String(ePhoto);
|
||||
} else {
|
||||
exif[field.field] = '';
|
||||
exif[field.field] = String();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,15 +119,15 @@ export default defineComponent({
|
|||
return diff;
|
||||
},
|
||||
|
||||
label(field: any) {
|
||||
label(field: IField) {
|
||||
return field.label + (this.dirty[field.field] ? '*' : '');
|
||||
},
|
||||
|
||||
placeholder(field: any) {
|
||||
placeholder(field: IField) {
|
||||
return this.dirty[field.field] ? t('memories', 'Empty') : t('memories', 'Unchanged');
|
||||
},
|
||||
|
||||
reset(field: any) {
|
||||
reset(field: IField) {
|
||||
this.exif[field.field] = '';
|
||||
this.dirty[field.field] = false;
|
||||
},
|
||||
|
|
|
@ -44,7 +44,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
watch: {
|
||||
$route: async function (from: any, to: any) {
|
||||
$route() {
|
||||
this.refreshParams();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -55,7 +55,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
watch: {
|
||||
$route: async function (from: any, to: any) {
|
||||
$route() {
|
||||
this.refreshParams();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -63,7 +63,7 @@ export default defineComponent({
|
|||
}),
|
||||
|
||||
watch: {
|
||||
$route: async function (from: any, to: any) {
|
||||
$route() {
|
||||
this.refreshParams();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -135,7 +135,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
isLocal(): boolean {
|
||||
return utils.isLocalPhoto(this.photo);
|
||||
return utils.isLocalPhoto(this.photo!);
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Component } from 'vue';
|
||||
|
||||
import UserMixin from '../../mixins/UserConfig';
|
||||
|
||||
|
@ -23,7 +24,7 @@ export default defineComponent({
|
|||
mixins: [UserMixin],
|
||||
|
||||
computed: {
|
||||
currentmatter(): any {
|
||||
currentmatter(): Component | null {
|
||||
if (this.routeIsFolders) {
|
||||
return FolderDynamicTopMatter;
|
||||
} else if (this.routeIsPlaces) {
|
||||
|
|
|
@ -340,7 +340,7 @@ export default defineComponent({
|
|||
|
||||
/** Is the current slide a local photo */
|
||||
isLocal(): boolean {
|
||||
return utils.isLocalPhoto(this.currentPhoto);
|
||||
return utils.isLocalPhoto(this.currentPhoto!);
|
||||
},
|
||||
|
||||
/** Show bottom bar info such as date taken */
|
||||
|
@ -418,16 +418,16 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
/** User interacted with the page with mouse */
|
||||
setUiVisible(evt: any) {
|
||||
setUiVisible(event: PointerEvent | false) {
|
||||
clearTimeout(this.activityTimer);
|
||||
if (evt) {
|
||||
if (event) {
|
||||
// If directly triggered, always update ui visibility
|
||||
// If triggered through a pointer event, only update if this is not
|
||||
// a touch event (i.e. a mouse move).
|
||||
// On touch devices, tapAction directly handles the ui visibility
|
||||
// through Photoswipe.
|
||||
const isPointer = evt instanceof PointerEvent;
|
||||
const isMouse = isPointer && evt.pointerType !== 'touch';
|
||||
const isPointer = event instanceof PointerEvent;
|
||||
const isMouse = isPointer && event.pointerType !== 'touch';
|
||||
if (this.isOpen && (!isPointer || isMouse)) {
|
||||
this.photoswipe?.template?.classList.add('pswp--ui-visible');
|
||||
|
||||
|
|
|
@ -16,6 +16,12 @@ export default defineComponent({
|
|||
routeIsBase(): boolean {
|
||||
return this.$route.name === 'timeline';
|
||||
},
|
||||
routeIsFavorites(): boolean {
|
||||
return this.$route.name === 'favorites';
|
||||
},
|
||||
routeIsVideos(): boolean {
|
||||
return this.$route.name === 'videos';
|
||||
},
|
||||
routeIsFolders(): boolean {
|
||||
return this.$route.name === 'folders';
|
||||
},
|
||||
|
|
|
@ -76,10 +76,6 @@ export class API {
|
|||
return tok(gen(`${BASE}/days/{id}`, { id }));
|
||||
}
|
||||
|
||||
static DAYS_FILTER(query: any, filter: DaysFilterType, value: string = '1') {
|
||||
query[filter] = value;
|
||||
}
|
||||
|
||||
static FOLDERS_SUB() {
|
||||
return tok(gen(`${BASE}/folders/sub`));
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* @param elem Element to search for
|
||||
* @param key Key to use for comparison
|
||||
*/
|
||||
export function binarySearch(arr: any, elem: any, key?: string) {
|
||||
export function binarySearch<T, K extends keyof T>(arr: T[], elem: T | T[K], key?: K): number {
|
||||
if (arr.length === 0) return 0;
|
||||
|
||||
const desc = key ? arr[0][key] > arr[arr.length - 1][key] : arr[0] > arr[arr.length - 1];
|
||||
|
@ -56,7 +56,7 @@ export function roundHalf(num: number) {
|
|||
}
|
||||
|
||||
/** Choose a random element from an array */
|
||||
export function randomChoice(arr: any[]) {
|
||||
export function randomChoice<T>(arr: T[]): T {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ export function randomChoice(arr: any[]) {
|
|||
* Choose a random sub array from an array
|
||||
* https://stackoverflow.com/a/11935263/4745239
|
||||
*/
|
||||
export function randomSubarray(arr: any[], size: number) {
|
||||
export function randomSubarray<T>(arr: T[], size: number): T[] {
|
||||
if (arr.length <= size) return arr;
|
||||
var shuffled = arr.slice(0),
|
||||
i = arr.length,
|
||||
|
@ -81,7 +81,7 @@ export function randomSubarray(arr: any[], size: number) {
|
|||
}
|
||||
|
||||
/** Set a timer that renews if existing */
|
||||
export function setRenewingTimeout(ctx: any, name: string, callback: (() => void) | null, delay: number) {
|
||||
export function setRenewingTimeout<T>(ctx: T, name: string, callback: (() => void) | null, delay: number): void {
|
||||
if (ctx[name]) window.clearTimeout(ctx[name]);
|
||||
ctx[name] = window.setTimeout(() => {
|
||||
ctx[name] = 0;
|
||||
|
@ -90,7 +90,7 @@ export function setRenewingTimeout(ctx: any, name: string, callback: (() => void
|
|||
}
|
||||
|
||||
/** Checks if a object is numeric */
|
||||
export function isNumber(num: any): boolean {
|
||||
export function isNumber<T>(num: T): boolean {
|
||||
const cast = Number(num);
|
||||
return !isNaN(cast) && isFinite(cast);
|
||||
}
|
||||
|
|
|
@ -90,8 +90,8 @@ export function getPreviewUrl(opts: PreviewOptsSize | PreviewOptsMsize | Preview
|
|||
* Check if the object is a local photo
|
||||
* @param photo Photo object
|
||||
*/
|
||||
export function isLocalPhoto(photo: any): boolean {
|
||||
return typeof photo === 'object' && photo?.fileid && Boolean((photo?.flag ?? 0) & constants.c.FLAG_IS_LOCAL);
|
||||
export function isLocalPhoto(photo: IPhoto): boolean {
|
||||
return Boolean(photo?.fileid) && Boolean((photo?.flag ?? 0) & constants.c.FLAG_IS_LOCAL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,7 +102,7 @@ export function isLocalPhoto(photo: any): boolean {
|
|||
export function getImageInfoUrl(photo: IPhoto | number): string {
|
||||
const fileid = typeof photo === 'number' ? photo : photo.fileid;
|
||||
|
||||
if (isLocalPhoto(photo)) {
|
||||
if (typeof photo === 'object' && isLocalPhoto(photo)) {
|
||||
return nativex.API.IMAGE_INFO(fileid);
|
||||
}
|
||||
|
||||
|
|
|
@ -111,8 +111,17 @@ export interface IImageInfo {
|
|||
Orientation?: number;
|
||||
ImageWidth?: number;
|
||||
ImageHeight?: number;
|
||||
|
||||
Title?: string;
|
||||
Description?: string;
|
||||
Make?: string;
|
||||
Model?: string;
|
||||
|
||||
DateTimeEpoch?: number;
|
||||
OffsetTimeOriginal?: string;
|
||||
OffsetTime?: string;
|
||||
LocationTZID?: string;
|
||||
|
||||
[other: string]: unknown;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ declare module 'vue' {
|
|||
state_noDownload: boolean;
|
||||
|
||||
routeIsBase: boolean;
|
||||
routeIsFavorites: boolean;
|
||||
routeIsVideos: boolean;
|
||||
routeIsFolders: boolean;
|
||||
routeIsAlbums: boolean;
|
||||
routeIsPeople: boolean;
|
||||
|
|
Loading…
Reference in New Issue