Refactor slideshow to work with file ids

This also fixed files missing when starting slideshow from search result
This commit is contained in:
Ming Ming 2024-11-27 00:44:57 +08:00
parent 94cb4e7d92
commit 58e6b6c238
11 changed files with 199 additions and 93 deletions

View file

@ -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": {

View file

@ -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"
] ]
} }

View file

@ -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(),
),
), ),
), ),
), ),

View file

@ -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

View file

@ -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;

View file

@ -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();

View file

@ -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;
} }

View file

@ -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;

View file

@ -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,
), ),

View file

@ -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)));
} }

View file

@ -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;
} }