@christianriedl/media 1.0.90 → 1.0.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/iMedia.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/FileUpload.vue +14 -9
- package/src/views/MusicPage.vue +1 -1
- package/src/views/PhotoAlbumPage.vue +38 -5
- package/src/views/PhotosPage.vue +3 -3
- package/src/views/PhotosPageDataTable.vue +286 -0
- package/src/views/VideosPage.vue +1 -1
package/dist/iMedia.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -3,31 +3,34 @@
|
|
|
3
3
|
import { IRest, IRestResult, IValueResult, Rest } from '@christianriedl/rest';
|
|
4
4
|
import { MediaService, getMediaSymbol } from '@christianriedl/media';
|
|
5
5
|
|
|
6
|
+
const props = defineProps<{ accept: string }>();
|
|
7
|
+
|
|
6
8
|
const getMediaService = inject(getMediaSymbol)!;
|
|
7
9
|
const mediaService = getMediaService();
|
|
8
10
|
const feedBack = ref("");
|
|
9
11
|
const name = ref("");
|
|
12
|
+
const files = ref<File[]>([]);
|
|
10
13
|
|
|
11
|
-
async function
|
|
12
|
-
const files = event.target.files as File[];
|
|
14
|
+
async function onUpload() {
|
|
13
15
|
feedBack.value = "Start Upload";
|
|
14
16
|
let count = 0;
|
|
15
17
|
let rc = false;
|
|
16
|
-
for (let i = 0; i < files.length; i++) {
|
|
17
|
-
|
|
18
|
+
for (let i = 0; i < files.value.length; i++) {
|
|
19
|
+
var file = files.value[i];
|
|
20
|
+
if (file.size > 20000000) {
|
|
18
21
|
// Big file
|
|
19
|
-
rc = await mediaService.uploadBigFile(
|
|
22
|
+
rc = await mediaService.uploadBigFile(file, name.value, (progress) => feedBack.value = progress);
|
|
20
23
|
}
|
|
21
24
|
else {
|
|
22
25
|
const formData = new FormData()
|
|
23
|
-
formData.append(name.value,
|
|
26
|
+
formData.append(name.value, file);
|
|
24
27
|
rc = await mediaService.upload(formData);
|
|
25
28
|
}
|
|
26
29
|
if (rc)
|
|
27
30
|
count++;
|
|
28
|
-
feedBack.value = `${
|
|
31
|
+
feedBack.value = `${file.name} : ${rc ? " - OK" : "- FAILED"}`;
|
|
29
32
|
}
|
|
30
|
-
feedBack.value = `${count} von ${files.length} erfolgreich hochgeladen ! (Close : Upload Icon)`;
|
|
33
|
+
feedBack.value = `${count} von ${files.value.length} erfolgreich hochgeladen ! (Close : Upload Icon)`;
|
|
31
34
|
}
|
|
32
35
|
</script>
|
|
33
36
|
|
|
@@ -37,7 +40,9 @@
|
|
|
37
40
|
<v-text-field name="directory" label="Name (Directory)" type="text" v-model="name" density="compact" hide-details></v-text-field>
|
|
38
41
|
</v-col>
|
|
39
42
|
<v-col cols="4">
|
|
40
|
-
<input
|
|
43
|
+
<v-file-input show-size clearable multiple hide-details v-model="files" :accept="props.accept" label="Select File"
|
|
44
|
+
prepend-icon="" append-icon="$upload" @click:append="onUpload">
|
|
45
|
+
</v-file-input>
|
|
41
46
|
</v-col>
|
|
42
47
|
<v-col cols="6">{{feedBack}}
|
|
43
48
|
</v-col>
|
package/src/views/MusicPage.vue
CHANGED
|
@@ -361,7 +361,7 @@
|
|
|
361
361
|
</v-card-actions>
|
|
362
362
|
<v-progress-linear v-if="playingTrack" v-model="positionLength" color="blue" height="25"><strong>{{positionText}}</strong></v-progress-linear>
|
|
363
363
|
</v-card>
|
|
364
|
-
<file-upload v-if="uploadVisible"></file-upload>
|
|
364
|
+
<file-upload v-if="uploadVisible" accept="audio/mpeg, audio/flac"></file-upload>
|
|
365
365
|
<v-card :height="listHeight" class="overflow-y-auto bg-media">
|
|
366
366
|
<v-list lines="two" class="bg-media">
|
|
367
367
|
<v-list-item-group v-model="itemIndex">
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
let gpsLat: number[];
|
|
34
34
|
let mouseDownTime: number = 0;
|
|
35
35
|
let mouseTimer: number = -1;
|
|
36
|
+
let nameTimer: number = -1;
|
|
37
|
+
const showName = ref(false);
|
|
36
38
|
|
|
37
39
|
watch([appState.bodyHeight, appState.pageWidth], () => {
|
|
38
40
|
width.value = appState.pageWidth.value;
|
|
@@ -68,6 +70,7 @@
|
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
72
|
url.value = photos.Url;
|
|
73
|
+
onUpdate();
|
|
71
74
|
}
|
|
72
75
|
else {
|
|
73
76
|
nextTick(() => router.back());
|
|
@@ -194,12 +197,12 @@
|
|
|
194
197
|
case "ArrowLeft":
|
|
195
198
|
if (index.value > 0)
|
|
196
199
|
index.value--;
|
|
197
|
-
|
|
200
|
+
onUpdate();
|
|
198
201
|
break;
|
|
199
202
|
case "ArrowRight":
|
|
200
203
|
if (index.value < items.length - 1)
|
|
201
204
|
index.value++;
|
|
202
|
-
|
|
205
|
+
onUpdate();
|
|
203
206
|
break;
|
|
204
207
|
case "KeyI": // Info
|
|
205
208
|
if (infoDialog.value) {
|
|
@@ -364,15 +367,38 @@
|
|
|
364
367
|
document.body.removeChild(anchor);
|
|
365
368
|
infoDialog.value = false;
|
|
366
369
|
}
|
|
370
|
+
function clearName() { // also called by VImg::loadstart
|
|
371
|
+
showName.value = false;
|
|
372
|
+
if (nameTimer >= 0) {
|
|
373
|
+
window.clearTimeout(nameTimer);
|
|
374
|
+
nameTimer = -1;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function onUpdate() { // Carousel updated
|
|
378
|
+
infoDialog.value = false;
|
|
379
|
+
clearName();
|
|
380
|
+
const item = items[index.value];
|
|
381
|
+
nameTimer = window.setTimeout(() => { onLoad(item); }, 200);
|
|
382
|
+
}
|
|
383
|
+
function onLoad(item: IPictureFile) { // img loaded or cached
|
|
384
|
+
clearName();
|
|
385
|
+
const idx = item.Url.lastIndexOf('.');
|
|
386
|
+
const name = item.Url.substr(0, idx);
|
|
387
|
+
if (!name.includes(item.Name)) {
|
|
388
|
+
showName.value = true;
|
|
389
|
+
nameTimer = window.setTimeout(() => { clearName(); }, mediaAppConfig.nameDurationMS);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
367
392
|
</script>
|
|
368
393
|
|
|
369
394
|
<template>
|
|
370
395
|
<v-container fluid :style="heightStyle" class="bg-grey-darken-3 pa-0">
|
|
371
396
|
<v-carousel ref="carousel" hide-delimiters :show-arrows="false" v-model="index"
|
|
372
397
|
:width="width" :height="height" :cycle="cycle" :interval="interval"
|
|
373
|
-
@click="onClick" @mousedown="onMouseDown" @update:modelValue="
|
|
374
|
-
<v-carousel-item v-for="item in items" :key="item.DLNAID"
|
|
375
|
-
|
|
398
|
+
@click="onClick" @mousedown="onMouseDown" @update:modelValue="onUpdate">
|
|
399
|
+
<v-carousel-item v-for="item in items" :key="item.DLNAID" :src="getUrl(item)" :alt="item.Name" :width="getWidth(item)" :height="getHeight(item)"
|
|
400
|
+
@load="onLoad(item)" @loadstart="clearName()">
|
|
401
|
+
<h2 v-if="showName" class="imgtext">{{item.Name}}</h2>
|
|
376
402
|
</v-carousel-item>
|
|
377
403
|
</v-carousel>
|
|
378
404
|
<v-dialog v-model="infoDialog" :fullscreen="isMobile" >
|
|
@@ -441,4 +467,11 @@
|
|
|
441
467
|
margin-left: auto;
|
|
442
468
|
margin-right: auto;
|
|
443
469
|
}
|
|
470
|
+
.imgtext {
|
|
471
|
+
position:absolute;
|
|
472
|
+
top:0px;
|
|
473
|
+
width:100%;
|
|
474
|
+
text-align:center;
|
|
475
|
+
color:magenta;
|
|
476
|
+
}
|
|
444
477
|
</style>
|
package/src/views/PhotosPage.vue
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
const router = useRouter();
|
|
18
18
|
const open = ref<string[]>([]);
|
|
19
19
|
|
|
20
|
-
const items
|
|
20
|
+
const items = ref<IMediaFolder[]>([]);
|
|
21
21
|
const selected = reactive<IPhotoSelection>(mediaService.photoSelection);
|
|
22
22
|
const listHeight = ref(0);
|
|
23
23
|
const listhead = ref<ComponentPublicInstance|null>(null);
|
|
@@ -181,7 +181,7 @@
|
|
|
181
181
|
itemIndex.value = i;
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
|
-
items.
|
|
184
|
+
items.value = folders;
|
|
185
185
|
}
|
|
186
186
|
function onScroll(ev: Event) {
|
|
187
187
|
const scrollTop = (ev.target as Element).scrollTop;
|
|
@@ -208,7 +208,7 @@
|
|
|
208
208
|
</v-btn>
|
|
209
209
|
</v-card-actions>
|
|
210
210
|
</v-card>
|
|
211
|
-
<file-upload v-if="uploadVisible"></file-upload>
|
|
211
|
+
<file-upload v-if="uploadVisible" accept="image/jpeg"></file-upload>
|
|
212
212
|
<v-card :max-height="listHeight" class="overflow-y-auto bg-media" ref="scrollElement" v-scroll.self="onScroll">
|
|
213
213
|
<v-list v-if="!grouped">
|
|
214
214
|
<v-list-item v-for="item in items" :key="item.DLNAID" :title="item.info" density="compact" @click.stop="showFolder(item)">
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { inject, ref, reactive, computed, onMounted, onUnmounted, nextTick, watch, StyleValue } from 'vue';
|
|
3
|
+
import { VDataTableVirtual } from 'vuetify/labs/VDataTable';
|
|
4
|
+
import type { ComponentPublicInstance } from 'vue';
|
|
5
|
+
import { useRouter } from 'vue-router';
|
|
6
|
+
import { IAppState, IAppConfig, EDevice, EBrowser, appStateSymbol, appConfigSymbol, Helper } from '@christianriedl/utils';
|
|
7
|
+
import { EItemType, EMediaType, IMediaFolder, IMediaItem, IPhotoSelection, MediaService, getMediaSymbol, IMediaAppConfig } from '@christianriedl/media';
|
|
8
|
+
import FileUpload from '../components/FileUpload.vue';
|
|
9
|
+
import PhotoDownload from '../components/PhotoDownload.vue';
|
|
10
|
+
|
|
11
|
+
const appState = inject(appStateSymbol)!;
|
|
12
|
+
const appConfig = inject(appConfigSymbol)!;
|
|
13
|
+
const mediaAppConfig = appConfig as unknown as IMediaAppConfig;
|
|
14
|
+
const getMediaService = inject(getMediaSymbol)!;
|
|
15
|
+
const mediaService = getMediaService();
|
|
16
|
+
const heightStyle = computed<StyleValue>(() => { return { height: appState.bodyHeight.value + 'px', overflowY: 'auto' } });
|
|
17
|
+
const isMobile = appState.isMobile && (appState.device != EDevice.iPad);
|
|
18
|
+
const router = useRouter();
|
|
19
|
+
const open = ref<string[]>([]);
|
|
20
|
+
|
|
21
|
+
const items = ref<IMediaFolder[]>([]);
|
|
22
|
+
const selected = reactive<IPhotoSelection>(mediaService.photoSelection);
|
|
23
|
+
const listHeight = ref(appState.bodyHeight.value);
|
|
24
|
+
const listhead = ref<ComponentPublicInstance|null>(null);
|
|
25
|
+
const table = ref<InstanceType<typeof VDataTableVirtual> | null>(null);
|
|
26
|
+
const uploadVisible = ref(false);
|
|
27
|
+
|
|
28
|
+
const roots: string[] = ['Jahr', 'Orte', 'Ereignisse', 'Personen'];
|
|
29
|
+
const criterias: string[] = ['ye', 'lo', 'ev', 'pe'];
|
|
30
|
+
const groupBy = ref<any>([{key: 'info', order: 'asc'}]);
|
|
31
|
+
const sortBy = ref<any>([{key: 'title', order: 'asc'}]);
|
|
32
|
+
const headers= [
|
|
33
|
+
{ title: 'Title', key: 'title', align: 'start', sortable: false },
|
|
34
|
+
{ title: 'Actions', key: 'actions', sortable: false }
|
|
35
|
+
];
|
|
36
|
+
const grouped = ref(false);
|
|
37
|
+
const backVisible = ref(false);
|
|
38
|
+
const showDownload = ref(false);
|
|
39
|
+
const downloadFolder = ref<IMediaFolder | null>(null);
|
|
40
|
+
const selectedYear = ref<number | undefined>(undefined);
|
|
41
|
+
const selectedName = ref<string | undefined>(undefined);
|
|
42
|
+
|
|
43
|
+
window.addEventListener('popstate', onPopState);
|
|
44
|
+
function onPopState(event: any) {
|
|
45
|
+
if (event.state && event.state.noBackExitsApp && backVisible.value) {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
listBack();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
onUnmounted(() => {
|
|
51
|
+
window.removeEventListener('popstate', onPopState);
|
|
52
|
+
while (window.history.state && window.history.state.noBackExitsApp)
|
|
53
|
+
window.history.back();
|
|
54
|
+
});
|
|
55
|
+
onMounted(async () => {
|
|
56
|
+
mediaService.log.trace('Photos created');
|
|
57
|
+
const rc = await mediaService.getLists(EMediaType.Picture);
|
|
58
|
+
let root;
|
|
59
|
+
if (!selected.selected.DLNAID) {
|
|
60
|
+
root = await mediaService.initializePhotos(stars(), selected.criteria);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
root = mediaService.folders[selected.selected.DLNAID];
|
|
64
|
+
}
|
|
65
|
+
const folders = setSelected(root);
|
|
66
|
+
if (selected.selectedAlbum)
|
|
67
|
+
selectedYear.value = selected.selectedAlbum.Year;
|
|
68
|
+
const expanded = selected.criteria == 'ye' || root.ItemType == EItemType.PictureCategory;
|
|
69
|
+
setGrouped(folders, expanded, selectedYear.value);
|
|
70
|
+
const scrollTop = appState.scrollPosition.value;
|
|
71
|
+
if (scrollTop > 0 && table.value) {
|
|
72
|
+
nextTick(() => {
|
|
73
|
+
// Scoll to this position
|
|
74
|
+
const el = table.value?._?.vnode?.el;
|
|
75
|
+
el?.scrollTo(0, scrollTop);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
mediaService.log.trace(`Photos start with ${selected.selected.DLNAID} scrollTop: ${scrollTop}`);
|
|
79
|
+
})
|
|
80
|
+
watch(appState.bodyHeight, () => computeListHeight());
|
|
81
|
+
function computeListHeight() {
|
|
82
|
+
nextTick(() => {
|
|
83
|
+
let height = appState.bodyHeight.value;
|
|
84
|
+
if (listhead.value) {
|
|
85
|
+
height = height - (listhead.value.$el as HTMLElement).clientHeight;
|
|
86
|
+
}
|
|
87
|
+
listHeight.value = height;
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
function stars() {
|
|
91
|
+
return selected.rating ? (selected.rating == 1 ? '*' : '**') : 'all';
|
|
92
|
+
}
|
|
93
|
+
function showFolder(folder: IMediaFolder) {
|
|
94
|
+
const folders = setSelected(folder);
|
|
95
|
+
setGrouped(folders, true);
|
|
96
|
+
computeListHeight();
|
|
97
|
+
}
|
|
98
|
+
function listExpand(folder: IMediaFolder) {
|
|
99
|
+
if (folder.Year && folder.Year > 0)
|
|
100
|
+
selectedYear.value = folder.Year;
|
|
101
|
+
}
|
|
102
|
+
function showPictures(folder: IMediaFolder) {
|
|
103
|
+
selected.selectedAlbum = folder;
|
|
104
|
+
router.push({ path: 'photoalbum', query: { id: folder.DLNAID } });
|
|
105
|
+
}
|
|
106
|
+
function onClick(ev: Event, row: any) {
|
|
107
|
+
const folder = row.item.raw as IMediaFolder;
|
|
108
|
+
if (folder.info)
|
|
109
|
+
showPictures(folder);
|
|
110
|
+
else
|
|
111
|
+
showFolder(folder);
|
|
112
|
+
}
|
|
113
|
+
function listBack() {
|
|
114
|
+
const parent = mediaService.folders[selected.selected.DLNAParentID];
|
|
115
|
+
const index = parent.Folders.indexOf(selected.selected);
|
|
116
|
+
const folders = setSelected(parent);
|
|
117
|
+
setGrouped(folders, false);
|
|
118
|
+
}
|
|
119
|
+
function onLightbox(folder: IMediaFolder) {
|
|
120
|
+
selected.selectedAlbum = folder;
|
|
121
|
+
router.push({ path: 'photothumbnails', query: { id: folder.DLNAID } });
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
function onDownload(folder: IMediaFolder) {
|
|
125
|
+
downloadFolder.value = folder;
|
|
126
|
+
showDownload.value = true;
|
|
127
|
+
}
|
|
128
|
+
async function onShare(folder: IMediaFolder) {
|
|
129
|
+
const guid = Helper.generateUUID();
|
|
130
|
+
const url = `https://www.christian-riedl.com/photos?id=${guid}`;
|
|
131
|
+
try {
|
|
132
|
+
await window.navigator.clipboard.writeText(url);
|
|
133
|
+
const id = await mediaService.addPhotoService(guid, appConfig.user, folder.DLNAID, mediaAppConfig.linkDaysValid);
|
|
134
|
+
if (id)
|
|
135
|
+
window.alert(`Created and Pasted - id : ${id} !`);
|
|
136
|
+
else
|
|
137
|
+
window.alert(`Creation failed, please repeat !`);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
window.alert(`Not Pasted : ${err} !`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function onCloseDownload() {
|
|
144
|
+
downloadFolder.value = null;
|
|
145
|
+
showDownload.value = false;
|
|
146
|
+
}
|
|
147
|
+
function onRootChange(root: string) {
|
|
148
|
+
const idx = roots.indexOf(selected.root);
|
|
149
|
+
selected.criteria = criterias[idx];
|
|
150
|
+
selectedName.value = undefined;
|
|
151
|
+
initialize().then((v) => { });;
|
|
152
|
+
}
|
|
153
|
+
function onRating(value: number | string) {
|
|
154
|
+
selected.rating = Number(value);
|
|
155
|
+
initialize().then((v) => { });;
|
|
156
|
+
}
|
|
157
|
+
async function initialize(): Promise<boolean> {
|
|
158
|
+
let root = await mediaService.initializePhotos(stars(), selected.criteria);
|
|
159
|
+
let expanded = selected.criteria == 'ye';
|
|
160
|
+
if (selected.criteria != 'ye' && selectedName.value) {
|
|
161
|
+
for (let i = 0; i < root.Folders.length; i++) {
|
|
162
|
+
if (root.Folders[i].Name == selectedName.value) {
|
|
163
|
+
root = root.Folders[i];
|
|
164
|
+
expanded = true;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const folders = setSelected(root);
|
|
170
|
+
setGrouped(folders, expanded, selectedYear.value);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
function setSelected(folder: IMediaFolder) : IMediaFolder[] {
|
|
174
|
+
selected.selected = folder;
|
|
175
|
+
if (folder.Year && folder.Year > 0)
|
|
176
|
+
selectedYear.value = folder.Year;
|
|
177
|
+
selectedName.value = folder.Name;
|
|
178
|
+
backVisible.value = selected.selected.ItemType != EItemType.PictureGenreType;
|
|
179
|
+
|
|
180
|
+
// calculate list height
|
|
181
|
+
computeListHeight();
|
|
182
|
+
return folder.Folders;
|
|
183
|
+
}
|
|
184
|
+
function setGrouped(folders: IMediaFolder[], expand: boolean, year?: number) {
|
|
185
|
+
grouped.value = expand;
|
|
186
|
+
groupBy.value = expand ? [{key: 'info', order: 'asc'}] : [];
|
|
187
|
+
const expanded = (expand && folders.length <= 6) ? true : false;
|
|
188
|
+
const list: IMediaFolder[] = [];
|
|
189
|
+
for (let i = 0; i < folders.length; i++) {
|
|
190
|
+
let folder = folders[i];
|
|
191
|
+
if (expand) {
|
|
192
|
+
if (year && year == folder.Year) {
|
|
193
|
+
open.value.push(year.toString());
|
|
194
|
+
}
|
|
195
|
+
for (let j = 0; j < folder.Folders.length; j++) {
|
|
196
|
+
const item = folder.Folders[j];
|
|
197
|
+
item.info = folder.title;
|
|
198
|
+
list.push(item);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
folder.info = undefined;
|
|
203
|
+
list.push(folder);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
items.value = list;
|
|
207
|
+
}
|
|
208
|
+
function onScroll(ev: Event) {
|
|
209
|
+
const scrollTop = (ev.target as Element).scrollTop;
|
|
210
|
+
appState.scrollPosition.value = scrollTop;
|
|
211
|
+
}
|
|
212
|
+
function setGroupFunc(toggle:any) : string {
|
|
213
|
+
return "";
|
|
214
|
+
}
|
|
215
|
+
</script>
|
|
216
|
+
<template>
|
|
217
|
+
<v-card ref="listhead" class="bg-media_head">
|
|
218
|
+
<v-card-title>{{selected.selected.Name}}</v-card-title>
|
|
219
|
+
<v-card-actions>
|
|
220
|
+
<v-btn v-if="backVisible" @click="listBack">
|
|
221
|
+
<v-icon size="large" icon="$back" />
|
|
222
|
+
</v-btn>
|
|
223
|
+
<v-rating clearable length="2" v-model="selected.rating" @update:modelValue="onRating" />
|
|
224
|
+
<v-select v-model="selected.root"
|
|
225
|
+
:items="roots"
|
|
226
|
+
persistent-hint
|
|
227
|
+
@update:modelValue="onRootChange"
|
|
228
|
+
hide-details single-line>
|
|
229
|
+
</v-select>
|
|
230
|
+
<v-btn v-if="!isMobile" @click="uploadVisible = !uploadVisible">
|
|
231
|
+
UPLOAD
|
|
232
|
+
<v-icon icon="$upload" />
|
|
233
|
+
</v-btn>
|
|
234
|
+
</v-card-actions>
|
|
235
|
+
</v-card>
|
|
236
|
+
<file-upload v-if="uploadVisible" accept="image/jpeg"></file-upload>
|
|
237
|
+
<v-data-table-virtual ref="table" :group-by="groupBy" :sort-by="sortBy" :items="items" :headers="headers" class="elevation-1" item-value="title" :height="listHeight"
|
|
238
|
+
@click:row="onClick" v-scroll.self="onScroll">
|
|
239
|
+
<template v-slot:top="{ toggleGroup, isGroupOpen }">
|
|
240
|
+
<p style="display:none">{{setGroupFunc(toggleGroup)}}</p>
|
|
241
|
+
</template>
|
|
242
|
+
<template v-slot:item.actions="{ item }">
|
|
243
|
+
<div v-if="item.raw.info">
|
|
244
|
+
<v-icon size="small" icon="$share" @click="onShare(item.raw)"></v-icon>
|
|
245
|
+
<v-icon size="small" icon="$download" @click="onDownload(item.raw)"></v-icon>
|
|
246
|
+
<v-icon size="small" icon="$grid" @click="onLightbox(item.raw)"></v-icon>
|
|
247
|
+
</div>
|
|
248
|
+
</template>
|
|
249
|
+
</v-data-table-virtual>
|
|
250
|
+
<!--
|
|
251
|
+
<v-card :max-height="listHeight" class="overflow-y-auto bg-media" ref="scrollElement" v-scroll.self="onScroll">
|
|
252
|
+
<v-data-table-virtual ref="table" :group-by="groupBy" :items="items" :headers="headers" class="elevation-1" item-value="title" :height="listHeight" @click:row="onClick">
|
|
253
|
+
<template v-slot:item.actions="{ item }">
|
|
254
|
+
<v-icon size="small" icon="$share" @click="onShare(item.raw)"></v-icon>
|
|
255
|
+
<v-icon size="small" icon="$download" @click="onDownload(item.raw)"></v-icon>
|
|
256
|
+
<v-icon size="small" icon="$grid" @click="onLightbox(item.raw)"></v-icon>
|
|
257
|
+
</template>
|
|
258
|
+
</v-data-table-virtual>
|
|
259
|
+
<!-
|
|
260
|
+
<v-list v-if="!grouped">
|
|
261
|
+
<v-list-item v-for="item in items" :key="item.DLNAID" :title="item.info" density="compact" @click.stop="showFolder(item)">
|
|
262
|
+
</v-list-item>
|
|
263
|
+
</v-list>
|
|
264
|
+
<v-list v-else v-model:opened="open">
|
|
265
|
+
<v-list-group v-for="item in items" :key="item.DLNAID" :value="item.Name" @click.stop="listExpand(item)">
|
|
266
|
+
<template v-slot:activator="{ props }">
|
|
267
|
+
<v-list-item v-bind="props" :title="item.info" :value="item.info" density="compact"></v-list-item>
|
|
268
|
+
</template>
|
|
269
|
+
<v-list-item v-for="subItem in item.Folders" :key="subItem.DLNAID" :title="subItem.info" density="compact" @click.stop="showPictures(subItem)">
|
|
270
|
+
<template v-slot:append>
|
|
271
|
+
<v-btn color="grey" variant="tonal" icon="$share" @click.stop.prevent="onShare(subItem)"></v-btn>
|
|
272
|
+
<v-btn color="grey" variant="tonal" icon="$download" @click.stop.prevent="onDownload(subItem)"></v-btn>
|
|
273
|
+
<v-btn color="grey" variant="tonal" icon="$grid" @click.stop.prevent="onLightbox(subItem)"></v-btn>
|
|
274
|
+
</template>
|
|
275
|
+
</v-list-item>
|
|
276
|
+
</v-list-group>
|
|
277
|
+
</v-list>
|
|
278
|
+
->
|
|
279
|
+
</v-card>
|
|
280
|
+
-->
|
|
281
|
+
|
|
282
|
+
<v-dialog v-model="showDownload">
|
|
283
|
+
<photo-download :folder="downloadFolder!" v-click-outside="onCloseDownload" @close="onCloseDownload"></photo-download>
|
|
284
|
+
</v-dialog>
|
|
285
|
+
</template>
|
|
286
|
+
|
package/src/views/VideosPage.vue
CHANGED
|
@@ -248,7 +248,7 @@
|
|
|
248
248
|
</v-btn>
|
|
249
249
|
</v-card-actions>
|
|
250
250
|
</v-card>
|
|
251
|
-
<file-upload v-if="uploadVisible"></file-upload>
|
|
251
|
+
<file-upload v-if="uploadVisible" accept="video/mp4"></file-upload>
|
|
252
252
|
<v-card :max-height="listHeight" class="overflow-y-auto bg-media">
|
|
253
253
|
<v-list lines="two" class="bg-media">
|
|
254
254
|
<v-list-item-group v-model="itemIndex">
|