Reduce coupling between gallery and the app bar

This commit is contained in:
Vishnu Mohandas 2020-07-15 22:47:53 +05:30
parent 9829eb4792
commit c07a103450
6 changed files with 78 additions and 109 deletions

View file

@ -15,13 +15,13 @@ class FileRepository {
return _files;
}
Future<bool> loadFiles() async {
Future<List<File>> loadFiles() async {
var files = await FileDB.instance.getAllLocalFiles();
_files.clear();
_files.addAll(files);
return true;
return _files;
}
Future<void> reloadFiles() async {

View file

@ -1,5 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/local_photos_updated_event.dart';
@ -21,33 +19,22 @@ class DeviceFolderPage extends StatefulWidget {
class _DeviceFolderPageState extends State<DeviceFolderPage> {
final logger = Logger("DeviceFolderPageState");
Set<File> _selectedFiles = Set<File>();
@override
Widget build(Object context) {
var gallery = Gallery(
syncLoader: () => _getFilteredFiles(FileRepository.instance.files),
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
tagPrefix: "device_folder",
);
return Scaffold(
appBar: GalleryAppBarWidget(
gallery,
GalleryAppBarType.local_folder,
widget.folder.name,
widget.folder.thumbnail.deviceFolder,
_selectedFiles,
onSelectionClear: () {
setState(() {
_selectedFiles.clear();
});
},
),
body: Gallery(
syncLoader: () => _getFilteredFiles(FileRepository.instance.files),
selectedFiles: _selectedFiles,
onFileSelectionChange: (Set<File> selectedFiles) {
setState(() {
_selectedFiles = selectedFiles;
});
},
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
tagPrefix: "device_folder",
),
body: gallery,
);
}

View file

@ -21,8 +21,7 @@ class Gallery extends StatefulWidget {
// should have done the job.
final Stream<Event> reloadEvent;
final Future<void> Function() onRefresh;
final Set<File> selectedFiles;
final Function(Set<File>) onFileSelectionChange;
final fileSelectionChangeListeners = new List<Function(Set<File>)>();
final String tagPrefix;
Gallery({
@ -30,14 +29,19 @@ class Gallery extends StatefulWidget {
this.asyncLoader,
this.reloadEvent,
this.onRefresh,
this.selectedFiles,
this.onFileSelectionChange,
this.tagPrefix,
});
_GalleryState state;
@override
_GalleryState createState() {
return _GalleryState();
state = _GalleryState();
return state;
}
void clearSelection() {
state.clearSelection();
}
}
@ -52,7 +56,7 @@ class _GalleryState extends State<Gallery> {
bool _requiresLoad = false;
bool _hasLoadedAll = false;
double _scrollOffset = 0;
Set<File> _selectedFiles = HashSet<File>();
Set<File> _selectedFiles = Set<File>();
List<File> _files;
RefreshController _refreshController = RefreshController();
@ -69,6 +73,12 @@ class _GalleryState extends State<Gallery> {
super.initState();
}
void clearSelection() {
setState(() {
_selectedFiles = Set<File>();
});
}
@override
Widget build(BuildContext context) {
if (!_requiresLoad) {
@ -100,7 +110,6 @@ class _GalleryState extends State<Gallery> {
if (_files.isEmpty) {
return Center(child: Text("Nothing to see here! 👀"));
}
_selectedFiles = widget.selectedFiles ?? Set<File>();
_collateFiles();
_scrollController = ScrollController(
initialScrollOffset: _scrollOffset,
@ -227,7 +236,9 @@ class _GalleryState extends State<Gallery> {
} else {
_selectedFiles.add(file);
}
widget.onFileSelectionChange(_selectedFiles);
for (final listener in widget.fileSelectionChangeListeners) {
listener.call(_selectedFiles);
}
});
}

View file

@ -7,6 +7,7 @@ import 'package:photos/db/file_db.dart';
import 'package:photos/events/remote_sync_event.dart';
import 'package:photos/models/file.dart';
import 'package:photos/file_repository.dart';
import 'package:photos/ui/gallery.dart';
import 'package:photos/ui/setup_page.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:photos/ui/share_folder_widget.dart';
@ -20,14 +21,17 @@ enum GalleryAppBarType {
class GalleryAppBarWidget extends StatefulWidget
implements PreferredSizeWidget {
final Gallery gallery;
final GalleryAppBarType type;
final String title;
final String path;
final Set<File> selectedFiles;
final Function() onSelectionClear;
GalleryAppBarWidget(this.type, this.title, this.path, this.selectedFiles,
{this.onSelectionClear});
GalleryAppBarWidget(
this.gallery,
this.type,
this.title,
this.path,
);
@override
_GalleryAppBarWidgetState createState() => _GalleryAppBarWidgetState();
@ -39,6 +43,7 @@ class GalleryAppBarWidget extends StatefulWidget
class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
bool _hasSyncErrors = false;
StreamSubscription<RemoteSyncEvent> _subscription;
Set<File> _selectedFiles = Set<File>();
@override
void initState() {
@ -47,12 +52,18 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
_hasSyncErrors = !event.success;
});
});
if (widget.gallery != null)
widget.gallery.fileSelectionChangeListeners.add((selectedFiles) {
setState(() {
_selectedFiles = selectedFiles;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
if (widget.selectedFiles.isEmpty) {
if (_selectedFiles.isEmpty) {
return AppBar(
title: Text(widget.title),
actions: _getDefaultActions(context),
@ -66,7 +77,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
_clearSelectedFiles();
},
),
title: Text(widget.selectedFiles.length.toString()),
title: Text(_selectedFiles.length.toString()),
actions: _getActions(context),
);
}
@ -105,7 +116,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
List<Widget> _getActions(BuildContext context) {
List<Widget> actions = List<Widget>();
if (widget.selectedFiles.isNotEmpty) {
if (_selectedFiles.isNotEmpty) {
if (widget.type != GalleryAppBarType.remote_folder) {
actions.add(IconButton(
icon: Icon(Icons.delete),
@ -125,7 +136,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
}
void _shareSelected(BuildContext context) {
shareMultiple(context, widget.selectedFiles.toList());
shareMultiple(context, _selectedFiles.toList());
}
void _showDeleteSheet(BuildContext context) {
@ -158,9 +169,9 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
Future _deleteSelected(BuildContext context, bool deleteEverywhere) async {
await PhotoManager.editor
.deleteWithIds(widget.selectedFiles.map((p) => p.localId).toList());
.deleteWithIds(_selectedFiles.map((p) => p.localId).toList());
for (File file in widget.selectedFiles) {
for (File file in _selectedFiles) {
deleteEverywhere
? await FileDB.instance.markForDeletion(file)
: await FileDB.instance.delete(file);
@ -171,12 +182,10 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
}
void _clearSelectedFiles() {
widget.gallery.clearSelection();
setState(() {
widget.selectedFiles.clear();
_selectedFiles.clear();
});
if (widget.onSelectionClear != null) {
widget.onSelectionClear();
}
}
void _openSyncConfiguration(BuildContext context) {

View file

@ -14,7 +14,6 @@ import 'package:photos/ui/device_folders_gallery_widget.dart';
import 'package:photos/ui/gallery.dart';
import 'package:photos/ui/gallery_app_bar_widget.dart';
import 'package:photos/ui/loading_photos_widget.dart';
import 'package:photos/ui/loading_widget.dart';
import 'package:photos/ui/remote_folder_gallery_widget.dart';
import 'package:photos/ui/search_page.dart';
import 'package:photos/utils/logging_util.dart';
@ -59,33 +58,24 @@ class _HomeWidgetState extends State<HomeWidget> {
@override
Widget build(BuildContext context) {
var gallery = _getMainGalleryWidget();
return Scaffold(
appBar: GalleryAppBarWidget(
gallery,
GalleryAppBarType.homepage,
widget.title,
"/",
_selectedPhotos,
onSelectionClear: _clearSelectedPhotos,
),
bottomNavigationBar: _buildBottomNavigationBar(),
body: FutureBuilder<bool>(
future: PhotoSyncManager.instance.hasScannedDisk(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return IndexedStack(
children: <Widget>[
snapshot.data ? _getMainGalleryWidget() : LoadingPhotosWidget(),
_deviceFolderGalleryWidget,
_remoteFolderGalleryWidget,
],
index: _selectedNavBarItem,
);
} else if (snapshot.hasError) {
return Center(child: Text(snapshot.error.toString()));
} else {
return loadWidget;
}
},
body: IndexedStack(
children: <Widget>[
PhotoSyncManager.instance.hasScannedDisk()
? gallery
: LoadingPhotosWidget(),
_deviceFolderGalleryWidget,
_remoteFolderGalleryWidget,
],
index: _selectedNavBarItem,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
@ -109,28 +99,15 @@ class _HomeWidgetState extends State<HomeWidget> {
}
Widget _getMainGalleryWidget() {
return FutureBuilder<bool>(
future: FileRepository.instance.loadFiles(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Gallery(
syncLoader: () => _getFilteredPhotos(FileRepository.instance.files),
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
onRefresh: PhotoSyncManager.instance.sync,
selectedFiles: _selectedPhotos,
onFileSelectionChange: (Set<File> selectedPhotos) {
setState(() {
_selectedPhotos = selectedPhotos;
});
},
tagPrefix: "home_gallery",
);
} else if (snapshot.hasError) {
return Center(child: Text(snapshot.error.toString()));
} else {
return loadWidget;
}
return Gallery(
asyncLoader: (_, __) {
return FileRepository.instance.loadFiles().then((files) {
return _getFilteredPhotos(files);
});
},
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
onRefresh: PhotoSyncManager.instance.sync,
tagPrefix: "home_gallery",
);
}

View file

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:photos/db/file_db.dart';
import 'package:photos/folder_service.dart';
import 'package:photos/models/folder.dart';
import 'package:photos/models/file.dart';
import 'package:photos/ui/gallery.dart';
import 'package:photos/ui/gallery_app_bar_widget.dart';
@ -16,36 +15,22 @@ class RemoteFolderPage extends StatefulWidget {
}
class _RemoteFolderPageState extends State<RemoteFolderPage> {
Set<File> _selectedPhotos = Set<File>();
@override
Widget build(Object context) {
var gallery = Gallery(
asyncLoader: (offset, limit) =>
FileDB.instance.getAllInFolder(widget.folder.id, offset, limit),
onRefresh: () => FolderSharingService.instance.syncDiff(widget.folder),
tagPrefix: "remote_folder",
);
return Scaffold(
appBar: GalleryAppBarWidget(
gallery,
GalleryAppBarType.remote_folder,
widget.folder.name,
widget.folder.deviceFolder,
_selectedPhotos,
onSelectionClear: () {
setState(() {
_selectedPhotos.clear();
});
},
),
body: Gallery(
asyncLoader: (offset, limit) =>
FileDB.instance.getAllInFolder(widget.folder.id, offset, limit),
onRefresh: () => FolderSharingService.instance.syncDiff(widget.folder),
selectedFiles: _selectedPhotos,
onFileSelectionChange: (Set<File> selectedPhotos) {
setState(
() {
_selectedPhotos = selectedPhotos;
},
);
},
tagPrefix: "remote_folder",
),
body: gallery,
);
}
}