gallery_app_bar_widget.dart 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import 'dart:async';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:photos/core/event_bus.dart';
  5. import 'package:photos/db/photo_db.dart';
  6. import 'package:photos/events/remote_sync_event.dart';
  7. import 'package:photos/models/photo.dart';
  8. import 'package:photos/photo_repository.dart';
  9. import 'package:photos/ui/setup_page.dart';
  10. import 'package:photo_manager/photo_manager.dart';
  11. import 'package:photos/ui/share_folder_widget.dart';
  12. import 'package:photos/utils/share_util.dart';
  13. enum GalleryAppBarType { homepage, folder }
  14. class GalleryAppBarWidget extends StatefulWidget
  15. implements PreferredSizeWidget {
  16. final GalleryAppBarType type;
  17. final String title;
  18. final String path;
  19. final Set<Photo> selectedPhotos;
  20. final Function() onSelectionClear;
  21. GalleryAppBarWidget(this.type, this.title, this.path, this.selectedPhotos,
  22. {this.onSelectionClear});
  23. @override
  24. _GalleryAppBarWidgetState createState() => _GalleryAppBarWidgetState();
  25. @override
  26. Size get preferredSize => Size.fromHeight(60.0);
  27. }
  28. class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
  29. bool _hasSyncErrors = false;
  30. StreamSubscription<RemoteSyncEvent> _subscription;
  31. @override
  32. void initState() {
  33. _subscription = Bus.instance.on<RemoteSyncEvent>().listen((event) {
  34. setState(() {
  35. _hasSyncErrors = !event.success;
  36. });
  37. });
  38. super.initState();
  39. }
  40. @override
  41. Widget build(BuildContext context) {
  42. if (widget.selectedPhotos.isEmpty) {
  43. return AppBar(
  44. title: Text(widget.title),
  45. actions: _getDefaultActions(context),
  46. );
  47. }
  48. return AppBar(
  49. leading: IconButton(
  50. icon: Icon(Icons.close),
  51. onPressed: () {
  52. _clearSelectedPhotos();
  53. },
  54. ),
  55. title: Text(widget.selectedPhotos.length.toString()),
  56. actions: _getPhotoActions(context),
  57. );
  58. }
  59. List<Widget> _getDefaultActions(BuildContext context) {
  60. List<Widget> actions = List<Widget>();
  61. if (_hasSyncErrors) {
  62. actions.add(IconButton(
  63. icon: Icon(Icons.sync_problem),
  64. onPressed: () {
  65. _openSyncConfiguration(context);
  66. },
  67. ));
  68. } else if (widget.type == GalleryAppBarType.folder) {
  69. actions.add(IconButton(
  70. icon: Icon(Icons.person_add),
  71. onPressed: () {
  72. _showShareCollectionDialog();
  73. },
  74. ));
  75. }
  76. return actions;
  77. }
  78. Future<void> _showShareCollectionDialog() async {
  79. return showDialog<void>(
  80. context: context,
  81. builder: (BuildContext context) {
  82. return ShareFolderWidget(widget.title, widget.path);
  83. },
  84. );
  85. }
  86. List<Widget> _getPhotoActions(BuildContext context) {
  87. List<Widget> actions = List<Widget>();
  88. if (widget.selectedPhotos.isNotEmpty) {
  89. actions.add(IconButton(
  90. icon: Icon(Icons.delete),
  91. onPressed: () {
  92. _showDeletePhotosSheet(context);
  93. },
  94. ));
  95. actions.add(IconButton(
  96. icon: Icon(Icons.share),
  97. onPressed: () {
  98. _shareSelectedPhotos(context);
  99. },
  100. ));
  101. }
  102. return actions;
  103. }
  104. void _shareSelectedPhotos(BuildContext context) {
  105. shareMultiple(widget.selectedPhotos.toList());
  106. }
  107. void _showDeletePhotosSheet(BuildContext context) {
  108. final action = CupertinoActionSheet(
  109. actions: <Widget>[
  110. CupertinoActionSheetAction(
  111. child: Text("Delete on device"),
  112. isDestructiveAction: true,
  113. onPressed: () async {
  114. await _deleteSelectedPhotos(context, false);
  115. },
  116. ),
  117. CupertinoActionSheetAction(
  118. child: Text("Delete everywhere [WiP]"),
  119. isDestructiveAction: true,
  120. onPressed: () async {
  121. await _deleteSelectedPhotos(context, true);
  122. },
  123. )
  124. ],
  125. cancelButton: CupertinoActionSheetAction(
  126. child: Text("Cancel"),
  127. onPressed: () {
  128. Navigator.of(context, rootNavigator: true).pop();
  129. },
  130. ),
  131. );
  132. showCupertinoModalPopup(context: context, builder: (_) => action);
  133. }
  134. Future _deleteSelectedPhotos(
  135. BuildContext context, bool deleteEverywhere) async {
  136. await PhotoManager.editor
  137. .deleteWithIds(widget.selectedPhotos.map((p) => p.localId).toList());
  138. for (Photo photo in widget.selectedPhotos) {
  139. deleteEverywhere
  140. ? await PhotoDB.instance.markPhotoForDeletion(photo)
  141. : await PhotoDB.instance.deletePhoto(photo);
  142. }
  143. Navigator.of(context, rootNavigator: true).pop();
  144. PhotoRepository.instance.reloadPhotos();
  145. _clearSelectedPhotos();
  146. }
  147. void _clearSelectedPhotos() {
  148. setState(() {
  149. widget.selectedPhotos.clear();
  150. });
  151. if (widget.onSelectionClear != null) {
  152. widget.onSelectionClear();
  153. }
  154. }
  155. void _openSyncConfiguration(BuildContext context) {
  156. final page = SetupPage();
  157. Navigator.of(context).push(
  158. MaterialPageRoute(
  159. settings: RouteSettings(name: "/setup"),
  160. builder: (BuildContext context) {
  161. return page;
  162. },
  163. ),
  164. );
  165. }
  166. void dispose() {
  167. _subscription.cancel();
  168. super.dispose();
  169. }
  170. }