mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-23 07:29:23 +01:00
Refactor slideshow to work with file ids
This also fixed files missing when starting slideshow from search result
This commit is contained in:
parent
94cb4e7d92
commit
58e6b6c238
11 changed files with 199 additions and 93 deletions
|
@ -1530,6 +1530,7 @@
|
||||||
"@albumAddMapTooltip": {
|
"@albumAddMapTooltip": {
|
||||||
"description": "Add a map that display between photos to an album"
|
"description": "Add a map that display between photos to an album"
|
||||||
},
|
},
|
||||||
|
"fileNotFound": "File not found",
|
||||||
|
|
||||||
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
|
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
|
||||||
"@errorUnauthenticated": {
|
"@errorUnauthenticated": {
|
||||||
|
|
|
@ -272,6 +272,7 @@
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip",
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound",
|
||||||
"errorUnauthenticated",
|
"errorUnauthenticated",
|
||||||
"errorDisconnected",
|
"errorDisconnected",
|
||||||
"errorLocked",
|
"errorLocked",
|
||||||
|
@ -295,7 +296,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"de": [
|
"de": [
|
||||||
|
@ -311,7 +313,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"el": [
|
"el": [
|
||||||
|
@ -472,7 +475,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"es": [
|
"es": [
|
||||||
|
@ -488,7 +492,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fi": [
|
"fi": [
|
||||||
|
@ -540,7 +545,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fr": [
|
"fr": [
|
||||||
|
@ -592,7 +598,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"it": [
|
"it": [
|
||||||
|
@ -649,7 +656,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"nl": [
|
"nl": [
|
||||||
|
@ -1041,6 +1049,7 @@
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip",
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound",
|
||||||
"errorUnauthenticated",
|
"errorUnauthenticated",
|
||||||
"errorDisconnected",
|
"errorDisconnected",
|
||||||
"errorLocked",
|
"errorLocked",
|
||||||
|
@ -1104,7 +1113,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"pt": [
|
"pt": [
|
||||||
|
@ -1176,7 +1186,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ru": [
|
"ru": [
|
||||||
|
@ -1228,7 +1239,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"tr": [
|
"tr": [
|
||||||
|
@ -1244,7 +1256,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"zh": [
|
"zh": [
|
||||||
|
@ -1327,7 +1340,8 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
],
|
],
|
||||||
|
|
||||||
"zh_Hant": [
|
"zh_Hant": [
|
||||||
|
@ -1504,6 +1518,7 @@
|
||||||
"customizeCollectionsNavBarDescription",
|
"customizeCollectionsNavBarDescription",
|
||||||
"customizeButtonsUnsupportedWarning",
|
"customizeButtonsUnsupportedWarning",
|
||||||
"placePickerTitle",
|
"placePickerTitle",
|
||||||
"albumAddMapTooltip"
|
"albumAddMapTooltip",
|
||||||
|
"fileNotFound"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
|
import 'package:nc_photos/app_localizations.dart';
|
||||||
import 'package:nc_photos/bloc_util.dart';
|
import 'package:nc_photos/bloc_util.dart';
|
||||||
import 'package:nc_photos/controller/account_controller.dart';
|
import 'package:nc_photos/controller/account_controller.dart';
|
||||||
|
import 'package:nc_photos/controller/files_controller.dart';
|
||||||
import 'package:nc_photos/entity/file_descriptor.dart';
|
import 'package:nc_photos/entity/file_descriptor.dart';
|
||||||
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||||
import 'package:nc_photos/k.dart' as k;
|
import 'package:nc_photos/k.dart' as k;
|
||||||
|
@ -23,6 +25,7 @@ import 'package:nc_photos/widget/video_viewer.dart';
|
||||||
import 'package:nc_photos/widget/viewer_mixin.dart';
|
import 'package:nc_photos/widget/viewer_mixin.dart';
|
||||||
import 'package:nc_photos/widget/wakelock_util.dart';
|
import 'package:nc_photos/widget/wakelock_util.dart';
|
||||||
import 'package:np_codegen/np_codegen.dart';
|
import 'package:np_codegen/np_codegen.dart';
|
||||||
|
import 'package:np_common/object_util.dart';
|
||||||
import 'package:np_ui/np_ui.dart';
|
import 'package:np_ui/np_ui.dart';
|
||||||
import 'package:to_string/to_string.dart';
|
import 'package:to_string/to_string.dart';
|
||||||
|
|
||||||
|
@ -35,13 +38,13 @@ part 'slideshow_viewer/view.dart';
|
||||||
class SlideshowViewerArguments {
|
class SlideshowViewerArguments {
|
||||||
const SlideshowViewerArguments(
|
const SlideshowViewerArguments(
|
||||||
this.account,
|
this.account,
|
||||||
this.files,
|
this.fileIds,
|
||||||
this.startIndex,
|
this.startIndex,
|
||||||
this.config,
|
this.config,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Account account;
|
final Account account;
|
||||||
final List<FileDescriptor> files;
|
final List<int> fileIds;
|
||||||
final int startIndex;
|
final int startIndex;
|
||||||
final SlideshowConfig config;
|
final SlideshowConfig config;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +62,7 @@ class SlideshowViewer extends StatelessWidget {
|
||||||
const SlideshowViewer({
|
const SlideshowViewer({
|
||||||
super.key,
|
super.key,
|
||||||
required this.account,
|
required this.account,
|
||||||
required this.files,
|
required this.fileIds,
|
||||||
required this.startIndex,
|
required this.startIndex,
|
||||||
required this.config,
|
required this.config,
|
||||||
});
|
});
|
||||||
|
@ -68,7 +71,7 @@ class SlideshowViewer extends StatelessWidget {
|
||||||
: this(
|
: this(
|
||||||
key: key,
|
key: key,
|
||||||
account: args.account,
|
account: args.account,
|
||||||
files: args.files,
|
fileIds: args.fileIds,
|
||||||
startIndex: args.startIndex,
|
startIndex: args.startIndex,
|
||||||
config: args.config,
|
config: args.config,
|
||||||
);
|
);
|
||||||
|
@ -77,8 +80,9 @@ class SlideshowViewer extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => _Bloc(
|
create: (context) => _Bloc(
|
||||||
|
filesController: context.read<AccountController>().filesController,
|
||||||
account: context.read<AccountController>().account,
|
account: context.read<AccountController>().account,
|
||||||
files: files,
|
fileIds: fileIds,
|
||||||
startIndex: startIndex,
|
startIndex: startIndex,
|
||||||
config: config,
|
config: config,
|
||||||
)..add(const _Init()),
|
)..add(const _Init()),
|
||||||
|
@ -87,7 +91,7 @@ class SlideshowViewer extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
final Account account;
|
final Account account;
|
||||||
final List<FileDescriptor> files;
|
final List<int> fileIds;
|
||||||
final int startIndex;
|
final int startIndex;
|
||||||
final SlideshowConfig config;
|
final SlideshowConfig config;
|
||||||
}
|
}
|
||||||
|
@ -145,7 +149,11 @@ class _WrappedSlideshowViewerState extends State<_WrappedSlideshowViewer>
|
||||||
onPopInvoked: (_) {
|
onPopInvoked: (_) {
|
||||||
context.addEvent(const _RequestExit());
|
context.addEvent(const _RequestExit());
|
||||||
},
|
},
|
||||||
child: const _Body(),
|
child: _BlocSelector<bool>(
|
||||||
|
selector: (state) => state.hasInit,
|
||||||
|
builder: (context, hasInit) =>
|
||||||
|
hasInit ? const _Body() : const _InitBody(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -18,6 +18,7 @@ abstract class $_StateCopyWithWorker {
|
||||||
int? page,
|
int? page,
|
||||||
int? nextPage,
|
int? nextPage,
|
||||||
bool? shouldAnimateNextPage,
|
bool? shouldAnimateNextPage,
|
||||||
|
List<FileDescriptor?>? files,
|
||||||
FileDescriptor? currentFile,
|
FileDescriptor? currentFile,
|
||||||
bool? isShowUi,
|
bool? isShowUi,
|
||||||
bool? isPlay,
|
bool? isPlay,
|
||||||
|
@ -38,7 +39,8 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
|
||||||
dynamic page,
|
dynamic page,
|
||||||
dynamic nextPage,
|
dynamic nextPage,
|
||||||
dynamic shouldAnimateNextPage,
|
dynamic shouldAnimateNextPage,
|
||||||
dynamic currentFile,
|
dynamic files,
|
||||||
|
dynamic currentFile = copyWithNull,
|
||||||
dynamic isShowUi,
|
dynamic isShowUi,
|
||||||
dynamic isPlay,
|
dynamic isPlay,
|
||||||
dynamic isVideoCompleted,
|
dynamic isVideoCompleted,
|
||||||
|
@ -53,7 +55,10 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
|
||||||
nextPage: nextPage as int? ?? that.nextPage,
|
nextPage: nextPage as int? ?? that.nextPage,
|
||||||
shouldAnimateNextPage:
|
shouldAnimateNextPage:
|
||||||
shouldAnimateNextPage as bool? ?? that.shouldAnimateNextPage,
|
shouldAnimateNextPage as bool? ?? that.shouldAnimateNextPage,
|
||||||
currentFile: currentFile as FileDescriptor? ?? that.currentFile,
|
files: files as List<FileDescriptor?>? ?? that.files,
|
||||||
|
currentFile: currentFile == copyWithNull
|
||||||
|
? that.currentFile
|
||||||
|
: currentFile as FileDescriptor?,
|
||||||
isShowUi: isShowUi as bool? ?? that.isShowUi,
|
isShowUi: isShowUi as bool? ?? that.isShowUi,
|
||||||
isPlay: isPlay as bool? ?? that.isPlay,
|
isPlay: isPlay as bool? ?? that.isPlay,
|
||||||
isVideoCompleted: isVideoCompleted as bool? ?? that.isVideoCompleted,
|
isVideoCompleted: isVideoCompleted as bool? ?? that.isVideoCompleted,
|
||||||
|
@ -104,7 +109,7 @@ extension _$_PageViewNpLog on _PageView {
|
||||||
extension _$_StateToString on _State {
|
extension _$_StateToString on _State {
|
||||||
String _$toString() {
|
String _$toString() {
|
||||||
// ignore: unnecessary_string_interpolations
|
// ignore: unnecessary_string_interpolations
|
||||||
return "_State {hasInit: $hasInit, page: $page, nextPage: $nextPage, shouldAnimateNextPage: $shouldAnimateNextPage, currentFile: ${currentFile.fdPath}, isShowUi: $isShowUi, isPlay: $isPlay, isVideoCompleted: $isVideoCompleted, hasPrev: $hasPrev, hasNext: $hasNext, isShowTimeline: $isShowTimeline, hasShownTimeline: $hasShownTimeline, hasRequestExit: $hasRequestExit}";
|
return "_State {hasInit: $hasInit, page: $page, nextPage: $nextPage, shouldAnimateNextPage: $shouldAnimateNextPage, files: [length: ${files.length}], currentFile: ${currentFile == null ? null : "${currentFile!.fdPath}"}, isShowUi: $isShowUi, isPlay: $isPlay, isVideoCompleted: $isVideoCompleted, hasPrev: $hasPrev, hasNext: $hasNext, isShowTimeline: $isShowTimeline, hasShownTimeline: $hasShownTimeline, hasRequestExit: $hasRequestExit}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +120,13 @@ extension _$_InitToString on _Init {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension _$_SetFilesToString on _SetFiles {
|
||||||
|
String _$toString() {
|
||||||
|
// ignore: unnecessary_string_interpolations
|
||||||
|
return "_SetFiles {dataMap: {length: ${dataMap.length}}}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension _$_ToggleShowUiToString on _ToggleShowUi {
|
extension _$_ToggleShowUiToString on _ToggleShowUi {
|
||||||
String _$toString() {
|
String _$toString() {
|
||||||
// ignore: unnecessary_string_interpolations
|
// ignore: unnecessary_string_interpolations
|
||||||
|
|
|
@ -3,14 +3,14 @@ part of '../slideshow_viewer.dart';
|
||||||
@npLog
|
@npLog
|
||||||
class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
_Bloc({
|
_Bloc({
|
||||||
|
required this.filesController,
|
||||||
required this.account,
|
required this.account,
|
||||||
required this.files,
|
required this.fileIds,
|
||||||
required this.startIndex,
|
required this.startIndex,
|
||||||
required this.config,
|
required this.config,
|
||||||
}) : super(_State.init(
|
}) : super(_State.init()) {
|
||||||
initialFile: files[startIndex],
|
|
||||||
)) {
|
|
||||||
on<_Init>(_onInit);
|
on<_Init>(_onInit);
|
||||||
|
on<_SetFiles>(_onSetFiles);
|
||||||
on<_ToggleShowUi>(_onToggleShowUi);
|
on<_ToggleShowUi>(_onToggleShowUi);
|
||||||
on<_PreloadSidePages>(_onPreloadSidePages);
|
on<_PreloadSidePages>(_onPreloadSidePages);
|
||||||
on<_VideoCompleted>(_onVideoCompleted);
|
on<_VideoCompleted>(_onVideoCompleted);
|
||||||
|
@ -23,6 +23,10 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
on<_ToggleTimeline>(_onToggleTimeline);
|
on<_ToggleTimeline>(_onToggleTimeline);
|
||||||
on<_RequestPage>(_onRequestPage);
|
on<_RequestPage>(_onRequestPage);
|
||||||
on<_RequestExit>(_onRequestExit);
|
on<_RequestExit>(_onRequestExit);
|
||||||
|
|
||||||
|
_subscriptions.add(filesController.stream.listen((event) {
|
||||||
|
add(_SetFiles(event.dataMap));
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -40,24 +44,27 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
/// Convert the page index to the corresponding item index
|
/// Convert the page index to the corresponding item index
|
||||||
int convertPageToFileIndex(int pageIndex) {
|
int convertPageToFileIndex(int pageIndex) {
|
||||||
if (config.isShuffle) {
|
if (config.isShuffle) {
|
||||||
final i = pageIndex ~/ files.length;
|
final i = pageIndex ~/ fileIds.length;
|
||||||
if (!_shuffledIndex.containsKey(i)) {
|
if (!_shuffledIndex.containsKey(i)) {
|
||||||
final index = [for (var i = 0; i < files.length; ++i) i];
|
final index = [for (var i = 0; i < fileIds.length; ++i) i];
|
||||||
_shuffledIndex[i] = index..shuffle();
|
_shuffledIndex[i] = index..shuffle();
|
||||||
}
|
}
|
||||||
return _shuffledIndex[i]![pageIndex % files.length];
|
return _shuffledIndex[i]![pageIndex % fileIds.length];
|
||||||
} else {
|
} else {
|
||||||
return _shuffledIndex[0]![pageIndex % files.length];
|
return _shuffledIndex[0]![pageIndex % fileIds.length];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor getFileByPageIndex(int pageIndex) =>
|
FileDescriptor? getFileByPageIndex(int pageIndex) =>
|
||||||
files[convertPageToFileIndex(pageIndex)];
|
state.files[convertPageToFileIndex(pageIndex)];
|
||||||
|
|
||||||
void _onInit(_Init ev, Emitter<_State> emit) {
|
Future<void> _onInit(_Init ev, Emitter<_State> emit) async {
|
||||||
_log.info(ev);
|
_log.info(ev);
|
||||||
|
// needed for now because some pages (e.g., search) haven't yet migrated
|
||||||
|
await filesController.queryByFileId(fileIds);
|
||||||
|
|
||||||
final parsedConfig = _parseConfig(
|
final parsedConfig = _parseConfig(
|
||||||
files: files,
|
fileIds: fileIds,
|
||||||
startIndex: startIndex,
|
startIndex: startIndex,
|
||||||
config: config,
|
config: config,
|
||||||
);
|
);
|
||||||
|
@ -71,7 +78,16 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
hasPrev: initialPage > 0,
|
hasPrev: initialPage > 0,
|
||||||
hasNext: pageCount == null || initialPage < (pageCount! - 1),
|
hasNext: pageCount == null || initialPage < (pageCount! - 1),
|
||||||
));
|
));
|
||||||
_prepareNextPage();
|
unawaited(_prepareNextPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onSetFiles(_SetFiles ev, Emitter<_State> emit) {
|
||||||
|
_log.info(ev);
|
||||||
|
final files = fileIds.map((e) => ev.dataMap[e]).toList();
|
||||||
|
emit(state.copyWith(
|
||||||
|
files: files,
|
||||||
|
currentFile: files[convertPageToFileIndex(state.page)],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onToggleShowUi(_ToggleShowUi ev, Emitter<_State> emit) {
|
void _onToggleShowUi(_ToggleShowUi ev, Emitter<_State> emit) {
|
||||||
|
@ -96,16 +112,14 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
}
|
}
|
||||||
_log.info("[_onPreloadSidePages] Pre-loading nearby images");
|
_log.info("[_onPreloadSidePages] Pre-loading nearby images");
|
||||||
if (ev.center > 0) {
|
if (ev.center > 0) {
|
||||||
final fileIndex = convertPageToFileIndex(ev.center - 1);
|
final prevFile = getFileByPageIndex(ev.center - 1);
|
||||||
final prevFile = files[fileIndex];
|
if (prevFile != null && file_util.isSupportedImageFormat(prevFile)) {
|
||||||
if (file_util.isSupportedImageFormat(prevFile)) {
|
|
||||||
RemoteImageViewer.preloadImage(account, prevFile);
|
RemoteImageViewer.preloadImage(account, prevFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pageCount == null || ev.center + 1 < pageCount!) {
|
if (pageCount == null || ev.center + 1 < pageCount!) {
|
||||||
final fileIndex = convertPageToFileIndex(ev.center + 1);
|
final nextFile = getFileByPageIndex(ev.center + 1);
|
||||||
final nextFile = files[fileIndex];
|
if (nextFile != null && file_util.isSupportedImageFormat(nextFile)) {
|
||||||
if (file_util.isSupportedImageFormat(nextFile)) {
|
|
||||||
RemoteImageViewer.preloadImage(account, nextFile);
|
RemoteImageViewer.preloadImage(account, nextFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +142,7 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
|
|
||||||
void _onSetPlay(_SetPlay ev, Emitter<_State> emit) {
|
void _onSetPlay(_SetPlay ev, Emitter<_State> emit) {
|
||||||
_log.info(ev);
|
_log.info(ev);
|
||||||
if (file_util.isSupportedVideoFormat(state.currentFile)) {
|
if (state.currentFile?.let(file_util.isSupportedVideoFormat) == true) {
|
||||||
// only start the countdown if the video completed
|
// only start the countdown if the video completed
|
||||||
if (state.isVideoCompleted) {
|
if (state.isVideoCompleted) {
|
||||||
_pageChangeTimer?.cancel();
|
_pageChangeTimer?.cancel();
|
||||||
|
@ -196,12 +210,12 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ({List<int> shuffled, int initial, int? count}) _parseConfig({
|
static ({List<int> shuffled, int initial, int? count}) _parseConfig({
|
||||||
required List<FileDescriptor> files,
|
required List<int> fileIds,
|
||||||
required int startIndex,
|
required int startIndex,
|
||||||
required SlideshowConfig config,
|
required SlideshowConfig config,
|
||||||
}) {
|
}) {
|
||||||
final index = [for (var i = 0; i < files.length; ++i) i];
|
final index = [for (var i = 0; i < fileIds.length; ++i) i];
|
||||||
final count = config.isRepeat ? null : files.length;
|
final count = config.isRepeat ? null : fileIds.length;
|
||||||
if (config.isShuffle) {
|
if (config.isShuffle) {
|
||||||
return (
|
return (
|
||||||
shuffled: index..shuffle(),
|
shuffled: index..shuffle(),
|
||||||
|
@ -211,7 +225,7 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
} else if (config.isReverse) {
|
} else if (config.isReverse) {
|
||||||
return (
|
return (
|
||||||
shuffled: index.reversed.toList(),
|
shuffled: index.reversed.toList(),
|
||||||
initial: files.length - 1 - startIndex,
|
initial: fileIds.length - 1 - startIndex,
|
||||||
count: count,
|
count: count,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -224,8 +238,7 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _prepareNextPage() async {
|
Future<void> _prepareNextPage() async {
|
||||||
final file = state.currentFile;
|
if (state.currentFile?.let(file_util.isSupportedVideoFormat) == true) {
|
||||||
if (file_util.isSupportedVideoFormat(file)) {
|
|
||||||
// for videos, we need to wait until it's ended
|
// for videos, we need to wait until it's ended
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -264,8 +277,9 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
add(_NextPage(nextPage));
|
add(_NextPage(nextPage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final FilesController filesController;
|
||||||
final Account account;
|
final Account account;
|
||||||
final List<FileDescriptor> files;
|
final List<int> fileIds;
|
||||||
final int startIndex;
|
final int startIndex;
|
||||||
final SlideshowConfig config;
|
final SlideshowConfig config;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ class _State {
|
||||||
required this.page,
|
required this.page,
|
||||||
required this.nextPage,
|
required this.nextPage,
|
||||||
required this.shouldAnimateNextPage,
|
required this.shouldAnimateNextPage,
|
||||||
required this.currentFile,
|
required this.files,
|
||||||
|
this.currentFile,
|
||||||
required this.isShowUi,
|
required this.isShowUi,
|
||||||
required this.isPlay,
|
required this.isPlay,
|
||||||
required this.isVideoCompleted,
|
required this.isVideoCompleted,
|
||||||
|
@ -19,15 +20,12 @@ class _State {
|
||||||
required this.hasRequestExit,
|
required this.hasRequestExit,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory _State.init({
|
factory _State.init() => const _State(
|
||||||
required FileDescriptor initialFile,
|
|
||||||
}) =>
|
|
||||||
_State(
|
|
||||||
hasInit: false,
|
hasInit: false,
|
||||||
page: 0,
|
page: 0,
|
||||||
nextPage: 0,
|
nextPage: 0,
|
||||||
shouldAnimateNextPage: true,
|
shouldAnimateNextPage: true,
|
||||||
currentFile: initialFile,
|
files: [],
|
||||||
isShowUi: false,
|
isShowUi: false,
|
||||||
isPlay: true,
|
isPlay: true,
|
||||||
isVideoCompleted: false,
|
isVideoCompleted: false,
|
||||||
|
@ -45,7 +43,8 @@ class _State {
|
||||||
final int page;
|
final int page;
|
||||||
final int nextPage;
|
final int nextPage;
|
||||||
final bool shouldAnimateNextPage;
|
final bool shouldAnimateNextPage;
|
||||||
final FileDescriptor currentFile;
|
final List<FileDescriptor?> files;
|
||||||
|
final FileDescriptor? currentFile;
|
||||||
final bool isShowUi;
|
final bool isShowUi;
|
||||||
final bool isPlay;
|
final bool isPlay;
|
||||||
final bool isVideoCompleted;
|
final bool isVideoCompleted;
|
||||||
|
@ -66,6 +65,16 @@ class _Init implements _Event {
|
||||||
String toString() => _$toString();
|
String toString() => _$toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@toString
|
||||||
|
class _SetFiles implements _Event {
|
||||||
|
const _SetFiles(this.dataMap);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => _$toString();
|
||||||
|
|
||||||
|
final Map<int, FileDescriptor> dataMap;
|
||||||
|
}
|
||||||
|
|
||||||
@toString
|
@toString
|
||||||
class _ToggleShowUi implements _Event {
|
class _ToggleShowUi implements _Event {
|
||||||
const _ToggleShowUi();
|
const _ToggleShowUi();
|
||||||
|
|
|
@ -87,11 +87,24 @@ class _TimelineItem extends StatelessWidget {
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? Theme.of(context).colorScheme.secondaryContainer
|
? Theme.of(context).colorScheme.secondaryContainer
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
child: PhotoListImage(
|
child: file != null
|
||||||
|
? PhotoListImage(
|
||||||
account: context.bloc.account,
|
account: context.bloc.account,
|
||||||
previewUrl: NetworkRectThumbnail.imageUrlForFile(
|
previewUrl: NetworkRectThumbnail.imageUrlForFile(
|
||||||
context.bloc.account,
|
context.bloc.account,
|
||||||
file,
|
file!,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
L10n.global().fileNotFound,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -111,6 +124,6 @@ class _TimelineItem extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
final int index;
|
final int index;
|
||||||
final FileDescriptor file;
|
final FileDescriptor? file;
|
||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,31 @@ class _ControlBar extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _InitBody extends StatelessWidget {
|
||||||
|
const _InitBody();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
const Center(child: CircularProgressIndicator()),
|
||||||
|
Positioned.directional(
|
||||||
|
textDirection: Directionality.of(context),
|
||||||
|
top: 0,
|
||||||
|
start: 0,
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@npLog
|
@npLog
|
||||||
class _Body extends StatelessWidget {
|
class _Body extends StatelessWidget {
|
||||||
const _Body();
|
const _Body();
|
||||||
|
@ -259,7 +284,17 @@ class _PageView extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final file = context.bloc.files[itemIndex];
|
return _BlocSelector<FileDescriptor?>(
|
||||||
|
selector: (state) => state.files[itemIndex],
|
||||||
|
builder: (context, file) {
|
||||||
|
if (file == null) {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
L10n.global().fileNotFound,
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
if (file_util.isSupportedImageFormat(file)) {
|
if (file_util.isSupportedImageFormat(file)) {
|
||||||
return _ImagePageView(
|
return _ImagePageView(
|
||||||
file: file,
|
file: file,
|
||||||
|
@ -278,6 +313,8 @@ class _PageView extends StatelessWidget {
|
||||||
_log.shout("[build] Unknown file format: ${file.fdMime}");
|
_log.shout("[build] Unknown file format: ${file.fdMime}");
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final int page;
|
final int page;
|
||||||
|
|
|
@ -254,7 +254,7 @@ class _WrappedViewerState extends State<_WrappedViewer>
|
||||||
SlideshowViewer.routeName,
|
SlideshowViewer.routeName,
|
||||||
arguments: SlideshowViewerArguments(
|
arguments: SlideshowViewerArguments(
|
||||||
slideshowRequest.value!.account,
|
slideshowRequest.value!.account,
|
||||||
slideshowRequest.value!.files,
|
slideshowRequest.value!.fileIds,
|
||||||
slideshowRequest.value!.startIndex,
|
slideshowRequest.value!.startIndex,
|
||||||
result,
|
result,
|
||||||
),
|
),
|
||||||
|
|
|
@ -343,14 +343,11 @@ class _Bloc extends Bloc<_Event, _State>
|
||||||
|
|
||||||
void _onStartSlideshow(_StartSlideshow ev, _Emitter emit) {
|
void _onStartSlideshow(_StartSlideshow ev, _Emitter emit) {
|
||||||
_log.info(ev);
|
_log.info(ev);
|
||||||
final files =
|
|
||||||
state.fileIdOrders.map((id) => state.files[id]).nonNulls.toList();
|
|
||||||
final req = _SlideshowRequest(
|
final req = _SlideshowRequest(
|
||||||
account: account,
|
account: account,
|
||||||
files: files,
|
fileIds: state.fileIdOrders,
|
||||||
startIndex: files
|
startIndex:
|
||||||
.indexWhere((e) => e.fdId == ev.fileId)
|
state.fileIdOrders.indexOf(ev.fileId).let((i) => i == -1 ? 0 : i),
|
||||||
.let((i) => i == -1 ? 0 : i),
|
|
||||||
);
|
);
|
||||||
emit(state.copyWith(slideshowRequest: Unique(req)));
|
emit(state.copyWith(slideshowRequest: Unique(req)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@ class _ShareRequest {
|
||||||
class _SlideshowRequest {
|
class _SlideshowRequest {
|
||||||
const _SlideshowRequest({
|
const _SlideshowRequest({
|
||||||
required this.account,
|
required this.account,
|
||||||
required this.files,
|
required this.fileIds,
|
||||||
required this.startIndex,
|
required this.startIndex,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Account account;
|
final Account account;
|
||||||
final List<FileDescriptor> files;
|
final List<int> fileIds;
|
||||||
final int startIndex;
|
final int startIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue