gallery_app_bar_widget.dart 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:logging/logging.dart';
  4. import 'package:photos/core/configuration.dart';
  5. import 'package:photos/core/event_bus.dart';
  6. import 'package:photos/events/subscription_purchased_event.dart';
  7. import 'package:photos/models/collection.dart';
  8. import 'package:photos/models/gallery_type.dart';
  9. import 'package:photos/models/magic_metadata.dart';
  10. import 'package:photos/models/selected_files.dart';
  11. import 'package:photos/services/collections_service.dart';
  12. import 'package:photos/ui/common/rename_dialog.dart';
  13. import 'package:photos/ui/sharing/share_collection_widget.dart';
  14. import 'package:photos/utils/dialog_util.dart';
  15. import 'package:photos/utils/magic_util.dart';
  16. class GalleryAppBarWidget extends StatefulWidget {
  17. final GalleryType type;
  18. final String title;
  19. final SelectedFiles selectedFiles;
  20. final String path;
  21. final Collection collection;
  22. const GalleryAppBarWidget(
  23. this.type,
  24. this.title,
  25. this.selectedFiles, {
  26. Key key,
  27. this.path,
  28. this.collection,
  29. }) : super(key: key);
  30. @override
  31. State<GalleryAppBarWidget> createState() => _GalleryAppBarWidgetState();
  32. }
  33. class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
  34. final _logger = Logger("GalleryAppBar");
  35. StreamSubscription _userAuthEventSubscription;
  36. Function() _selectedFilesListener;
  37. String _appBarTitle;
  38. final GlobalKey shareButtonKey = GlobalKey();
  39. @override
  40. void initState() {
  41. _selectedFilesListener = () {
  42. setState(() {});
  43. };
  44. widget.selectedFiles.addListener(_selectedFilesListener);
  45. _userAuthEventSubscription =
  46. Bus.instance.on<SubscriptionPurchasedEvent>().listen((event) {
  47. setState(() {});
  48. });
  49. _appBarTitle = widget.title;
  50. super.initState();
  51. }
  52. @override
  53. void dispose() {
  54. _userAuthEventSubscription.cancel();
  55. widget.selectedFiles.removeListener(_selectedFilesListener);
  56. super.dispose();
  57. }
  58. @override
  59. Widget build(BuildContext context) {
  60. // if (widget.selectedFiles.files.isEmpty) {
  61. return AppBar(
  62. backgroundColor:
  63. widget.type == GalleryType.homepage ? const Color(0x00000000) : null,
  64. elevation: 0,
  65. centerTitle: false,
  66. title: widget.type == GalleryType.homepage
  67. ? const SizedBox.shrink()
  68. : TextButton(
  69. child: Text(
  70. _appBarTitle,
  71. style: Theme.of(context)
  72. .textTheme
  73. .headline5
  74. .copyWith(fontSize: 16),
  75. ),
  76. onPressed: () => _renameAlbum(context),
  77. ),
  78. actions: _getDefaultActions(context),
  79. );
  80. }
  81. Future<dynamic> _renameAlbum(BuildContext context) async {
  82. if (widget.type != GalleryType.ownedCollection) {
  83. return;
  84. }
  85. final result = await showDialog<String>(
  86. context: context,
  87. builder: (BuildContext context) {
  88. return RenameDialog(_appBarTitle, 'Album');
  89. },
  90. barrierColor: Colors.black.withOpacity(0.85),
  91. );
  92. // indicates user cancelled the rename request
  93. if (result == null || result.trim() == _appBarTitle.trim()) {
  94. return;
  95. }
  96. final dialog = createProgressDialog(context, "Changing name...");
  97. await dialog.show();
  98. try {
  99. await CollectionsService.instance.rename(widget.collection, result);
  100. await dialog.hide();
  101. if (mounted) {
  102. _appBarTitle = result;
  103. setState(() {});
  104. }
  105. } catch (e) {
  106. await dialog.hide();
  107. showGenericErrorDialog(context);
  108. }
  109. }
  110. List<Widget> _getDefaultActions(BuildContext context) {
  111. final List<Widget> actions = <Widget>[];
  112. if (Configuration.instance.hasConfiguredAccount() &&
  113. widget.selectedFiles.files.isEmpty &&
  114. (widget.type == GalleryType.localFolder ||
  115. widget.type == GalleryType.ownedCollection)) {
  116. actions.add(
  117. Tooltip(
  118. message: "Share",
  119. child: IconButton(
  120. icon: Icon(Icons.adaptive.share),
  121. onPressed: () {
  122. _showShareCollectionDialog();
  123. },
  124. ),
  125. ),
  126. );
  127. }
  128. if (widget.type == GalleryType.ownedCollection) {
  129. actions.add(
  130. PopupMenuButton(
  131. itemBuilder: (context) {
  132. final List<PopupMenuItem> items = [];
  133. if (widget.collection.type == CollectionType.album) {
  134. items.add(
  135. PopupMenuItem(
  136. value: 1,
  137. child: Row(
  138. children: const [
  139. Icon(Icons.edit),
  140. Padding(
  141. padding: EdgeInsets.all(8),
  142. ),
  143. Text("Rename"),
  144. ],
  145. ),
  146. ),
  147. );
  148. }
  149. final bool isArchived = widget.collection.isArchived();
  150. items.add(
  151. PopupMenuItem(
  152. value: 2,
  153. child: Row(
  154. children: [
  155. Icon(isArchived ? Icons.visibility : Icons.visibility_off),
  156. const Padding(
  157. padding: EdgeInsets.all(8),
  158. ),
  159. Text(isArchived ? "Unhide" : "Hide"),
  160. ],
  161. ),
  162. ),
  163. );
  164. return items;
  165. },
  166. onSelected: (value) async {
  167. if (value == 1) {
  168. await _renameAlbum(context);
  169. }
  170. if (value == 2) {
  171. await changeCollectionVisibility(
  172. context,
  173. widget.collection,
  174. widget.collection.isArchived()
  175. ? kVisibilityVisible
  176. : kVisibilityArchive,
  177. );
  178. }
  179. },
  180. ),
  181. );
  182. }
  183. return actions;
  184. }
  185. Future<void> _showShareCollectionDialog() async {
  186. var collection = widget.collection;
  187. final dialog = createProgressDialog(context, "Please wait...");
  188. await dialog.show();
  189. try {
  190. if (collection == null) {
  191. if (widget.type == GalleryType.localFolder) {
  192. collection =
  193. await CollectionsService.instance.getOrCreateForPath(widget.path);
  194. } else {
  195. throw Exception(
  196. "Cannot create a collection of type" + widget.type.toString(),
  197. );
  198. }
  199. } else {
  200. final sharees =
  201. await CollectionsService.instance.getSharees(collection.id);
  202. collection = collection.copyWith(sharees: sharees);
  203. }
  204. await dialog.hide();
  205. return showDialog<void>(
  206. context: context,
  207. builder: (BuildContext context) {
  208. return SharingDialog(collection);
  209. },
  210. );
  211. } catch (e, s) {
  212. _logger.severe(e, s);
  213. await dialog.hide();
  214. showGenericErrorDialog(context);
  215. }
  216. }
  217. }