2020-05-05 12:56:24 +00:00
|
|
|
import 'dart:async';
|
2020-04-18 18:46:38 +00:00
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
2020-10-30 19:57:14 +00:00
|
|
|
import 'package:logging/logging.dart';
|
2020-10-28 12:03:28 +00:00
|
|
|
import 'package:page_transition/page_transition.dart';
|
2020-05-30 21:15:21 +00:00
|
|
|
import 'package:photos/core/configuration.dart';
|
2020-11-15 07:19:44 +00:00
|
|
|
import 'package:photos/core/event_bus.dart';
|
|
|
|
import 'package:photos/events/user_authenticated_event.dart';
|
2020-10-29 12:56:30 +00:00
|
|
|
import 'package:photos/models/collection.dart';
|
2020-07-15 20:29:29 +00:00
|
|
|
import 'package:photos/models/selected_files.dart';
|
2020-10-13 05:22:20 +00:00
|
|
|
import 'package:photos/services/collections_service.dart';
|
2020-10-28 12:03:28 +00:00
|
|
|
import 'package:photos/ui/create_collection_page.dart';
|
2020-10-30 20:51:17 +00:00
|
|
|
import 'package:photos/ui/share_collection_widget.dart';
|
2020-07-15 19:14:37 +00:00
|
|
|
import 'package:photos/utils/dialog_util.dart';
|
2020-07-29 07:53:13 +00:00
|
|
|
import 'package:photos/utils/file_util.dart';
|
2020-05-01 18:20:12 +00:00
|
|
|
import 'package:photos/utils/share_util.dart';
|
2020-12-01 14:02:36 +00:00
|
|
|
import 'package:photos/utils/toast_util.dart';
|
2020-04-18 18:46:38 +00:00
|
|
|
|
2020-05-25 15:01:02 +00:00
|
|
|
enum GalleryAppBarType {
|
|
|
|
homepage,
|
|
|
|
local_folder,
|
2020-10-13 21:46:46 +00:00
|
|
|
shared_collection,
|
2020-10-24 23:10:37 +00:00
|
|
|
collection,
|
2020-07-15 17:27:41 +00:00
|
|
|
search_results,
|
2020-05-25 15:01:02 +00:00
|
|
|
}
|
2020-05-17 14:23:37 +00:00
|
|
|
|
2020-04-18 18:46:38 +00:00
|
|
|
class GalleryAppBarWidget extends StatefulWidget
|
|
|
|
implements PreferredSizeWidget {
|
2020-05-17 14:23:37 +00:00
|
|
|
final GalleryAppBarType type;
|
2020-04-18 18:46:38 +00:00
|
|
|
final String title;
|
2020-07-15 20:29:29 +00:00
|
|
|
final SelectedFiles selectedFiles;
|
2020-05-17 12:39:38 +00:00
|
|
|
final String path;
|
2020-10-29 12:56:30 +00:00
|
|
|
final Collection collection;
|
2020-04-18 18:46:38 +00:00
|
|
|
|
2020-07-15 17:17:53 +00:00
|
|
|
GalleryAppBarWidget(
|
|
|
|
this.type,
|
2020-07-15 20:29:29 +00:00
|
|
|
this.title,
|
2020-10-29 12:56:30 +00:00
|
|
|
this.selectedFiles, {
|
2020-07-15 17:17:53 +00:00
|
|
|
this.path,
|
2020-10-29 12:56:30 +00:00
|
|
|
this.collection,
|
|
|
|
});
|
2020-04-18 18:46:38 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
_GalleryAppBarWidgetState createState() => _GalleryAppBarWidgetState();
|
|
|
|
|
|
|
|
@override
|
|
|
|
Size get preferredSize => Size.fromHeight(60.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
2020-10-30 19:57:14 +00:00
|
|
|
final _logger = Logger("GalleryAppBar");
|
2020-11-15 07:19:44 +00:00
|
|
|
StreamSubscription _userAuthEventSubscription;
|
2020-10-30 19:57:14 +00:00
|
|
|
|
2020-04-30 15:09:41 +00:00
|
|
|
@override
|
|
|
|
void initState() {
|
2020-07-15 20:29:29 +00:00
|
|
|
widget.selectedFiles.addListener(() {
|
|
|
|
setState(() {});
|
|
|
|
});
|
2020-11-15 07:19:44 +00:00
|
|
|
_userAuthEventSubscription =
|
|
|
|
Bus.instance.on<UserAuthenticatedEvent>().listen((event) {
|
|
|
|
setState(() {});
|
|
|
|
});
|
2020-04-30 15:09:41 +00:00
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
2020-11-15 07:19:44 +00:00
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
_userAuthEventSubscription.cancel();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
2020-04-18 18:46:38 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2020-07-15 20:29:29 +00:00
|
|
|
if (widget.selectedFiles.files.isEmpty) {
|
2020-04-30 15:09:41 +00:00
|
|
|
return AppBar(
|
2020-12-12 00:31:06 +00:00
|
|
|
backgroundColor: Color(0x00000000),
|
|
|
|
elevation: 0,
|
2021-01-08 16:17:26 +00:00
|
|
|
title: widget.type == GalleryAppBarType.homepage
|
|
|
|
? Container()
|
|
|
|
: Text(
|
|
|
|
widget.title,
|
|
|
|
style: TextStyle(
|
|
|
|
color: Colors.white.withOpacity(0.60),
|
|
|
|
),
|
|
|
|
),
|
2020-04-30 15:09:41 +00:00
|
|
|
actions: _getDefaultActions(context),
|
|
|
|
);
|
2020-04-18 18:46:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return AppBar(
|
|
|
|
leading: IconButton(
|
|
|
|
icon: Icon(Icons.close),
|
|
|
|
onPressed: () {
|
2020-06-19 23:03:26 +00:00
|
|
|
_clearSelectedFiles();
|
2020-04-18 18:46:38 +00:00
|
|
|
},
|
|
|
|
),
|
2020-07-15 20:29:29 +00:00
|
|
|
title: Text(widget.selectedFiles.files.length.toString()),
|
2020-06-19 23:03:26 +00:00
|
|
|
actions: _getActions(context),
|
2020-04-18 18:46:38 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-04-30 15:09:41 +00:00
|
|
|
List<Widget> _getDefaultActions(BuildContext context) {
|
|
|
|
List<Widget> actions = List<Widget>();
|
2021-01-08 16:17:26 +00:00
|
|
|
if (Configuration.instance.hasConfiguredAccount() &&
|
|
|
|
(widget.type == GalleryAppBarType.local_folder ||
|
|
|
|
widget.type == GalleryAppBarType.collection)) {
|
|
|
|
actions.add(IconButton(
|
|
|
|
icon: Icon(Icons.person_add),
|
|
|
|
onPressed: () {
|
|
|
|
_showShareCollectionDialog();
|
|
|
|
},
|
|
|
|
));
|
2020-04-30 15:09:41 +00:00
|
|
|
}
|
|
|
|
return actions;
|
|
|
|
}
|
|
|
|
|
2020-05-17 14:23:37 +00:00
|
|
|
Future<void> _showShareCollectionDialog() async {
|
2020-10-29 12:56:30 +00:00
|
|
|
var collection = widget.collection;
|
|
|
|
if (collection == null) {
|
|
|
|
if (widget.type == GalleryAppBarType.local_folder) {
|
|
|
|
collection =
|
|
|
|
CollectionsService.instance.getCollectionForPath(widget.path);
|
|
|
|
if (collection == null) {
|
|
|
|
final dialog = createProgressDialog(context, "Please wait...");
|
|
|
|
await dialog.show();
|
2020-10-30 20:51:17 +00:00
|
|
|
try {
|
|
|
|
collection = await CollectionsService.instance
|
|
|
|
.getOrCreateForPath(widget.path);
|
|
|
|
await dialog.hide();
|
|
|
|
} catch (e, s) {
|
|
|
|
_logger.severe(e, s);
|
|
|
|
await dialog.hide();
|
|
|
|
showGenericErrorDialog(context);
|
|
|
|
}
|
2020-10-29 12:56:30 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw Exception(
|
|
|
|
"Cannot create a collection of type" + widget.type.toString());
|
|
|
|
}
|
|
|
|
}
|
2020-12-03 22:41:01 +00:00
|
|
|
return showDialog<void>(
|
|
|
|
context: context,
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
return SharingDialog(collection);
|
|
|
|
},
|
|
|
|
);
|
2020-05-17 12:39:38 +00:00
|
|
|
}
|
|
|
|
|
2020-10-28 12:03:28 +00:00
|
|
|
Future<void> _createAlbum() async {
|
|
|
|
Navigator.push(
|
|
|
|
context,
|
|
|
|
PageTransition(
|
|
|
|
type: PageTransitionType.bottomToTop,
|
|
|
|
child: CreateCollectionPage(
|
2020-10-29 00:30:02 +00:00
|
|
|
widget.selectedFiles,
|
2020-10-28 12:03:28 +00:00
|
|
|
)));
|
|
|
|
}
|
|
|
|
|
2020-06-19 23:03:26 +00:00
|
|
|
List<Widget> _getActions(BuildContext context) {
|
2020-04-18 18:46:38 +00:00
|
|
|
List<Widget> actions = List<Widget>();
|
2020-10-30 19:57:14 +00:00
|
|
|
actions.add(IconButton(
|
|
|
|
icon: Icon(Icons.add),
|
|
|
|
onPressed: () {
|
|
|
|
_createAlbum();
|
|
|
|
},
|
|
|
|
));
|
|
|
|
actions.add(IconButton(
|
|
|
|
icon: Icon(Icons.share),
|
|
|
|
onPressed: () {
|
|
|
|
_shareSelected(context);
|
|
|
|
},
|
|
|
|
));
|
|
|
|
if (widget.type == GalleryAppBarType.homepage ||
|
|
|
|
widget.type == GalleryAppBarType.local_folder) {
|
2020-10-28 12:03:28 +00:00
|
|
|
actions.add(IconButton(
|
2020-10-30 19:57:14 +00:00
|
|
|
icon: Icon(Icons.delete),
|
2020-10-28 12:03:28 +00:00
|
|
|
onPressed: () {
|
2020-10-30 19:57:14 +00:00
|
|
|
_showDeleteSheet(context);
|
2020-10-28 12:03:28 +00:00
|
|
|
},
|
|
|
|
));
|
2020-10-30 19:57:14 +00:00
|
|
|
} else if (widget.type == GalleryAppBarType.collection) {
|
|
|
|
actions.add(PopupMenuButton(
|
|
|
|
itemBuilder: (context) {
|
|
|
|
return [
|
|
|
|
PopupMenuItem(
|
|
|
|
value: 1,
|
|
|
|
child: Row(
|
|
|
|
children: [
|
|
|
|
Icon(Icons.remove_circle),
|
|
|
|
Padding(
|
|
|
|
padding: EdgeInsets.all(8),
|
|
|
|
),
|
|
|
|
Text("Remove"),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
PopupMenuItem(
|
|
|
|
value: 2,
|
|
|
|
child: Row(
|
|
|
|
children: [
|
|
|
|
Icon(Icons.delete),
|
|
|
|
Padding(
|
|
|
|
padding: EdgeInsets.all(8),
|
|
|
|
),
|
|
|
|
Text("Delete"),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
)
|
|
|
|
];
|
|
|
|
},
|
|
|
|
onSelected: (value) {
|
|
|
|
if (value == 1) {
|
|
|
|
_showRemoveFromCollectionSheet(context);
|
|
|
|
} else if (value == 2) {
|
|
|
|
_showDeleteSheet(context);
|
|
|
|
}
|
2020-04-18 18:46:38 +00:00
|
|
|
},
|
|
|
|
));
|
|
|
|
}
|
|
|
|
return actions;
|
|
|
|
}
|
|
|
|
|
2020-06-19 23:03:26 +00:00
|
|
|
void _shareSelected(BuildContext context) {
|
2020-07-15 20:29:29 +00:00
|
|
|
shareMultiple(context, widget.selectedFiles.files.toList());
|
2020-04-18 18:46:38 +00:00
|
|
|
}
|
|
|
|
|
2020-10-30 19:57:14 +00:00
|
|
|
void _showRemoveFromCollectionSheet(BuildContext context) {
|
2020-11-01 05:33:53 +00:00
|
|
|
final count = widget.selectedFiles.files.length;
|
2020-10-30 19:57:14 +00:00
|
|
|
final action = CupertinoActionSheet(
|
|
|
|
title: Text("Remove " +
|
2020-11-01 05:33:53 +00:00
|
|
|
count.toString() +
|
|
|
|
" file" +
|
|
|
|
(count == 1 ? "" : "s") +
|
|
|
|
" from " +
|
2020-10-30 19:57:14 +00:00
|
|
|
widget.collection.name +
|
|
|
|
"?"),
|
|
|
|
actions: <Widget>[
|
|
|
|
CupertinoActionSheetAction(
|
|
|
|
child: Text("Remove"),
|
|
|
|
isDestructiveAction: true,
|
|
|
|
onPressed: () async {
|
|
|
|
final dialog = createProgressDialog(context, "Removing files...");
|
|
|
|
await dialog.show();
|
|
|
|
try {
|
|
|
|
CollectionsService.instance.removeFromCollection(
|
|
|
|
widget.collection.id, widget.selectedFiles.files.toList());
|
|
|
|
await dialog.hide();
|
|
|
|
widget.selectedFiles.clearAll();
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
} catch (e, s) {
|
|
|
|
_logger.severe(e, s);
|
|
|
|
await dialog.hide();
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
showGenericErrorDialog(context);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
cancelButton: CupertinoActionSheetAction(
|
|
|
|
child: Text("Cancel"),
|
|
|
|
onPressed: () {
|
|
|
|
Navigator.of(context, rootNavigator: true).pop();
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
|
|
showCupertinoModalPopup(context: context, builder: (_) => action);
|
|
|
|
}
|
|
|
|
|
2020-06-19 23:03:26 +00:00
|
|
|
void _showDeleteSheet(BuildContext context) {
|
2020-11-01 05:33:53 +00:00
|
|
|
final count = widget.selectedFiles.files.length;
|
2020-12-01 14:02:36 +00:00
|
|
|
bool containsUploadedFile = false;
|
|
|
|
for (final file in widget.selectedFiles.files) {
|
|
|
|
if (file.uploadedFileID != null) {
|
|
|
|
containsUploadedFile = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
final actions = List<Widget>();
|
|
|
|
if (containsUploadedFile) {
|
|
|
|
actions.add(CupertinoActionSheetAction(
|
|
|
|
child: Text("This Device"),
|
|
|
|
isDestructiveAction: true,
|
|
|
|
onPressed: () async {
|
|
|
|
await deleteFilesOnDeviceOnly(
|
|
|
|
context, widget.selectedFiles.files.toList());
|
|
|
|
_clearSelectedFiles();
|
|
|
|
showToast("Files deleted from device");
|
|
|
|
Navigator.of(context, rootNavigator: true).pop();
|
|
|
|
},
|
|
|
|
));
|
|
|
|
actions.add(CupertinoActionSheetAction(
|
|
|
|
child: Text("Everywhere"),
|
|
|
|
isDestructiveAction: true,
|
|
|
|
onPressed: () async {
|
|
|
|
await deleteFilesFromEverywhere(
|
|
|
|
context, widget.selectedFiles.files.toList());
|
|
|
|
_clearSelectedFiles();
|
|
|
|
showToast("Files deleted from everywhere");
|
|
|
|
Navigator.of(context, rootNavigator: true).pop();
|
|
|
|
},
|
|
|
|
));
|
|
|
|
} else {
|
|
|
|
actions.add(CupertinoActionSheetAction(
|
|
|
|
child: Text("Delete forever"),
|
|
|
|
isDestructiveAction: true,
|
|
|
|
onPressed: () async {
|
|
|
|
await deleteFilesFromEverywhere(
|
|
|
|
context, widget.selectedFiles.files.toList());
|
|
|
|
_clearSelectedFiles();
|
|
|
|
showToast("Files deleted from everywhere");
|
|
|
|
Navigator.of(context, rootNavigator: true).pop();
|
|
|
|
},
|
|
|
|
));
|
|
|
|
}
|
2020-04-18 18:46:38 +00:00
|
|
|
final action = CupertinoActionSheet(
|
2020-12-01 14:02:36 +00:00
|
|
|
title: Text("Delete " +
|
2020-11-01 05:33:53 +00:00
|
|
|
count.toString() +
|
|
|
|
" file" +
|
2020-12-01 14:02:36 +00:00
|
|
|
(count == 1 ? "" : "s") +
|
|
|
|
(containsUploadedFile ? " from" : "?")),
|
|
|
|
actions: actions,
|
2020-04-18 18:46:38 +00:00
|
|
|
cancelButton: CupertinoActionSheetAction(
|
|
|
|
child: Text("Cancel"),
|
|
|
|
onPressed: () {
|
|
|
|
Navigator.of(context, rootNavigator: true).pop();
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
|
|
showCupertinoModalPopup(context: context, builder: (_) => action);
|
|
|
|
}
|
|
|
|
|
2020-06-19 23:03:26 +00:00
|
|
|
void _clearSelectedFiles() {
|
2020-07-15 20:29:29 +00:00
|
|
|
widget.selectedFiles.clearAll();
|
2020-04-18 18:46:38 +00:00
|
|
|
}
|
|
|
|
}
|