32
32
</ion-toolbar >
33
33
</ion-header >
34
34
<ion-content
35
+ ref =" browserContent"
35
36
class =" ion-padding"
36
- v-if =" (files.cwd || files.collection_id) && connectedState "
37
+ v-if =" (files.cwd || files.collection_id) && connectionState "
37
38
>
38
- <ion-item @click =" onPrevDirectoryClicked" v-if =" files.prevDir" >
39
- <ion-icon :icon =" folder" slot =" start" ></ion-icon >
40
- ...
41
- </ion-item >
42
- <ion-item
43
- v-for =" (entry, index) in files.content"
44
- :key =" index"
45
- @click =" onEntryClicked(entry)"
39
+ <ion-list >
40
+ <ion-item @click =" onPrevDirectoryClicked" v-if =" files.prevDir" >
41
+ <ion-icon :icon =" folder" slot =" start" ></ion-icon >
42
+ ...
43
+ </ion-item >
44
+ <ion-item
45
+ v-for =" (entry, index) in browsableFiles"
46
+ :key =" index"
47
+ @click =" onEntryClicked(entry)"
48
+ >
49
+ <ion-icon
50
+ slot =" start"
51
+ v-if =" entry.mediaStatus && entry.mediaStatus.finished === 0"
52
+ class =" mediaStatusProgress"
53
+ :icon =" decideIcon(entry)"
54
+ ></ion-icon >
55
+ <ion-icon
56
+ slot =" start"
57
+ v-else-if =" entry.mediaStatus && entry.mediaStatus.finished === 1"
58
+ class =" mediaStatusFinished"
59
+ :icon =" decideIcon(entry)"
60
+ ></ion-icon >
61
+ <ion-icon
62
+ v-else-if =" entry.type === 'subtitle'"
63
+ class =" fileformatSubtitle"
64
+ :icon =" journalOutline"
65
+ slot =" start"
66
+ ></ion-icon >
67
+ <ion-icon v-else :icon =" decideIcon(entry)" slot =" start" ></ion-icon >
68
+ {{ entry.name }}
69
+ </ion-item >
70
+ </ion-list >
71
+
72
+ <ion-infinite-scroll
73
+ @ionInfinite =" onInfiniteScroll($event)"
74
+ threshold =" 1000px"
75
+ id =" infinite-scroll"
76
+ :disabled =" !infiniteScrollEnabled"
46
77
>
47
- <ion-icon
48
- slot =" start"
49
- v-if =" entry.mediaStatus && entry.mediaStatus.finished === 0"
50
- class =" mediaStatusProgress"
51
- :icon =" decideIcon(entry)"
52
- ></ion-icon >
53
- <ion-icon
54
- slot =" start"
55
- v-else-if =" entry.mediaStatus && entry.mediaStatus.finished === 1"
56
- class =" mediaStatusFinished"
57
- :icon =" decideIcon(entry)"
58
- ></ion-icon >
59
- <ion-icon
60
- v-else-if =" entry.type === 'subtitle'"
61
- class =" fileformatSubtitle"
62
- :icon =" journalOutline"
63
- slot =" start"
64
- ></ion-icon >
65
- <ion-icon v-else :icon =" decideIcon(entry)" slot =" start" ></ion-icon >
66
- {{ entry.name }}
67
- </ion-item >
78
+ <ion-infinite-scroll-content
79
+ loading-spinner =" bubbles"
80
+ loading-text =" Loading more data..."
81
+ >
82
+ </ion-infinite-scroll-content >
83
+ </ion-infinite-scroll >
68
84
</ion-content >
69
- <ion-content v-else-if =" !connectedState " >
85
+ <ion-content v-else-if =" !connectionState " >
70
86
Lost connection to server.
71
87
</ion-content >
72
88
<ion-content v-else-if =" !loading" >
@@ -134,6 +150,8 @@ import {
134
150
IonListHeader ,
135
151
actionSheetController ,
136
152
alertController ,
153
+ IonInfiniteScroll ,
154
+ IonInfiniteScrollContent ,
137
155
} from " @ionic/vue" ;
138
156
import {
139
157
folder ,
@@ -157,21 +175,31 @@ export default {
157
175
props: [" modalController" , " action" ],
158
176
setup (props ) {
159
177
const store = useStore ();
160
- const connectedState = computed (() => store .state .simpleapi .connected );
161
178
const serverConfig = computed (
162
179
() => store .state .simpleapi .MPVInfo .mpvremoteConfig
163
180
);
164
181
const files = ref ({});
165
- const collections = ref ([]);
182
+
183
+ // Browasble files by ion-infinite scroll
184
+ const browsableFiles = ref ([]);
185
+ const INFINITE_SCROLL_STEP = 100 ;
186
+ const infiniteScrollEnabled = ref (false );
187
+
166
188
const filesBak = ref ([]);
189
+ const collections = ref ([]);
167
190
const search = ref (" " );
168
191
const loading = ref (true );
192
+ const browserContent = ref ();
193
+
169
194
const showOpenFolder = ref (props .action === FileBrowserActions .OPENFOLDER );
170
195
const drives = ref ([]);
171
- const filemanLastPath = store .state .settings .settings .filemanLastPath ;
196
+
197
+ const filemanLastPath = store .state .settings .filemanLastPath ;
172
198
const sortBy = ref (FileBrowserSortBy .NAME );
173
199
174
- let history = store .state .settings .settings .history || [];
200
+ // let history = store.state.settings.settings.history || [];
201
+ let history = store .getters [" settings/getServerHistory" ];
202
+
175
203
const titleText = computed (() => {
176
204
if (files .value .dirname ) return files .value .dirname ;
177
205
else if (files .value .collection_id ) {
@@ -212,30 +240,21 @@ export default {
212
240
filemanLastPath .collection_id = files .value .collection_id ;
213
241
}
214
242
// Also save history
215
- await store .dispatch (" settings/setSetting " , {
216
- key : " history" ,
217
- value : JSON . stringify (history) ,
243
+ await store .dispatch (" settings/updateFilemanHistory " , {
244
+ paths : history,
245
+ last_path : filemanLastPath ,
218
246
});
219
-
220
- if (
221
- filemanLastPath .cwd != null ||
222
- filemanLastPath .collection_id != null
223
- ) {
224
- return store .dispatch (" settings/setSetting" , {
225
- key: " filemanLastPath" ,
226
- value: JSON .stringify (filemanLastPath),
227
- });
228
- }
229
247
};
230
248
231
249
const getDirectoryContents = async (path = null , collectionId = null ) => {
232
- console .log (" Get directory contents" );
250
+ console .log (
251
+ ` Get directory contents: path: ${ path} collection:${ collectionId} `
252
+ );
233
253
let data = {};
234
254
if (path) data .path = path;
235
255
if (collectionId) data .collection_id = collectionId;
236
256
// Save to history
237
257
// Render spinner if loading takes more than 150 msec
238
-
239
258
let loadingTimeout = setTimeout (() => {
240
259
loading .value = true ;
241
260
}, 150 );
@@ -245,7 +264,13 @@ export default {
245
264
files .value = response .data ;
246
265
filesBak .value = response .data ;
247
266
search .value = " " ;
248
-
267
+ browsableFiles .value = files .value .content .slice (
268
+ 0 ,
269
+ INFINITE_SCROLL_STEP
270
+ );
271
+ // Enable infinite scroll if needed.
272
+ if (files .value .content .length > INFINITE_SCROLL_STEP )
273
+ infiniteScrollEnabled .value = true ;
249
274
// Render IO related errors
250
275
if (response .data .errors && response .data .errors .length > 0 ) {
251
276
openToast (response .data .errors , 3000 );
@@ -254,12 +279,32 @@ export default {
254
279
.finally (() => {
255
280
clearTimeout (loadingTimeout);
256
281
loading .value = false ;
282
+ browserContent .value .$el .scrollToTop ();
257
283
});
258
284
};
259
285
286
+ const onInfiniteScroll = (ev ) => {
287
+ // Load more items
288
+ if (browsableFiles .value .length !== files .value .content .length ) {
289
+ console .log (" Load more items" );
290
+ browsableFiles .value .push (
291
+ ... files .value .content .slice (
292
+ browsableFiles .value .length ,
293
+ browsableFiles .value .length + INFINITE_SCROLL_STEP
294
+ )
295
+ );
296
+ } else {
297
+ infiniteScrollEnabled .value = false ;
298
+ console .log (" Reached end" );
299
+ }
300
+ ev .target .complete ();
301
+ };
302
+
260
303
if (filemanLastPath) {
261
304
if (filemanLastPath .type == " collection" ) {
305
+ console .log (" Collection should be loaded" );
262
306
getDirectoryContents (null , filemanLastPath .collection_id ).catch (() => {
307
+ console .log (" Got error, loading basic" );
263
308
getDirectoryContents ();
264
309
});
265
310
} else if (filemanLastPath .type == " directory" ) {
@@ -300,7 +345,6 @@ export default {
300
345
const { role } = await actionSheet .onDidDismiss ();
301
346
302
347
if (role === " continue" ) {
303
- console .log (" Continue" );
304
348
saveLastPath ().then (() => {
305
349
props .modalController .dismiss ({
306
350
filename: entry .fullPath ,
@@ -374,7 +418,6 @@ export default {
374
418
await actionSheet .present ();
375
419
376
420
const { role } = await actionSheet .onDidDismiss ();
377
- console .log (` Value:${ role} ` );
378
421
379
422
if (role !== " backdrop" ) {
380
423
getDirectoryContents (role);
@@ -411,6 +454,11 @@ export default {
411
454
files .value .content = files .value .content .filter (
412
455
(el ) => el .name .toLowerCase ().indexOf (search .value .toLowerCase ()) > - 1
413
456
);
457
+ // Enable infinite scroll if needed.
458
+ if (files .value .content .length > INFINITE_SCROLL_STEP )
459
+ infiniteScrollEnabled .value = true ;
460
+
461
+ browsableFiles .value = files .value .content .slice (0 , INFINITE_SCROLL_STEP );
414
462
};
415
463
const onOpenDirectoryClicked = () => {
416
464
saveLastPath ().then (() => props .modalController .dismiss (files .value .cwd ));
@@ -501,6 +549,10 @@ export default {
501
549
decideIcon,
502
550
onCollectionsClicked,
503
551
getDirectoryContents,
552
+ browsableFiles,
553
+ connectionState: computed (
554
+ () => store .getters [" simpleapi/connectionState" ]
555
+ ),
504
556
showOpenFolder,
505
557
titleText,
506
558
loading,
@@ -516,10 +568,12 @@ export default {
516
568
film,
517
569
collections,
518
570
drives,
519
- connectedState,
520
571
serverConfig,
521
572
funnelOutline,
522
573
onSortByClicked,
574
+ onInfiniteScroll,
575
+ infiniteScrollEnabled,
576
+ browserContent,
523
577
};
524
578
},
525
579
components: {
@@ -537,6 +591,8 @@ export default {
537
591
IonLoading,
538
592
IonList,
539
593
IonListHeader,
594
+ IonInfiniteScroll,
595
+ IonInfiniteScrollContent,
540
596
},
541
597
};
542
598
</script >
0 commit comments