cluster_app_bar.dart 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import 'dart:async';
  2. import "package:flutter/foundation.dart";
  3. import 'package:flutter/material.dart';
  4. import 'package:logging/logging.dart';
  5. import 'package:photos/core/configuration.dart';
  6. import 'package:photos/core/event_bus.dart';
  7. import "package:photos/db/files_db.dart";
  8. // import "package:photos/events/people_changed_event.dart";
  9. import 'package:photos/events/subscription_purchased_event.dart';
  10. // import "package:photos/face/db.dart";
  11. import "package:photos/face/model/person.dart";
  12. import 'package:photos/models/gallery_type.dart';
  13. import 'package:photos/models/selected_files.dart';
  14. import 'package:photos/services/collections_service.dart';
  15. import "package:photos/services/machine_learning/face_ml/face_ml_result.dart";
  16. import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart";
  17. import 'package:photos/ui/actions/collection/collection_sharing_actions.dart';
  18. import "package:photos/ui/viewer/people/cluster_page.dart";
  19. // import "package:photos/utils/dialog_util.dart";
  20. class ClusterAppBar extends StatefulWidget {
  21. final GalleryType type;
  22. final String? title;
  23. final SelectedFiles selectedFiles;
  24. final int clusterID;
  25. final Person? person;
  26. const ClusterAppBar(
  27. this.type,
  28. this.title,
  29. this.selectedFiles,
  30. this.clusterID, {
  31. this.person,
  32. Key? key,
  33. }) : super(key: key);
  34. @override
  35. State<ClusterAppBar> createState() => _AppBarWidgetState();
  36. }
  37. enum ClusterPopupAction {
  38. setCover,
  39. breakupCluster,
  40. hide,
  41. }
  42. class _AppBarWidgetState extends State<ClusterAppBar> {
  43. final _logger = Logger("_AppBarWidgetState");
  44. late StreamSubscription _userAuthEventSubscription;
  45. late Function() _selectedFilesListener;
  46. String? _appBarTitle;
  47. late CollectionActions collectionActions;
  48. final GlobalKey shareButtonKey = GlobalKey();
  49. bool isQuickLink = false;
  50. late GalleryType galleryType;
  51. @override
  52. void initState() {
  53. super.initState();
  54. _selectedFilesListener = () {
  55. setState(() {});
  56. };
  57. collectionActions = CollectionActions(CollectionsService.instance);
  58. widget.selectedFiles.addListener(_selectedFilesListener);
  59. _userAuthEventSubscription =
  60. Bus.instance.on<SubscriptionPurchasedEvent>().listen((event) {
  61. setState(() {});
  62. });
  63. _appBarTitle = widget.title;
  64. galleryType = widget.type;
  65. }
  66. @override
  67. void dispose() {
  68. _userAuthEventSubscription.cancel();
  69. widget.selectedFiles.removeListener(_selectedFilesListener);
  70. super.dispose();
  71. }
  72. @override
  73. Widget build(BuildContext context) {
  74. return AppBar(
  75. elevation: 0,
  76. centerTitle: false,
  77. title: Text(
  78. _appBarTitle!,
  79. style:
  80. Theme.of(context).textTheme.headlineSmall!.copyWith(fontSize: 16),
  81. maxLines: 2,
  82. overflow: TextOverflow.ellipsis,
  83. ),
  84. actions: kDebugMode ? _getDefaultActions(context) : null,
  85. );
  86. }
  87. List<Widget> _getDefaultActions(BuildContext context) {
  88. final List<Widget> actions = <Widget>[];
  89. // If the user has selected files, don't show any actions
  90. if (widget.selectedFiles.files.isNotEmpty ||
  91. !Configuration.instance.hasConfiguredAccount()) {
  92. return actions;
  93. }
  94. final List<PopupMenuItem<ClusterPopupAction>> items = [];
  95. items.addAll(
  96. [
  97. // PopupMenuItem(
  98. // value: ClusterPopupAction.setCover,
  99. // child: Row(
  100. // children: [
  101. // const Icon(Icons.image_outlined),
  102. // const Padding(
  103. // padding: EdgeInsets.all(8),
  104. // ),
  105. // Text(S.of(context).setCover),
  106. // ],
  107. // ),
  108. // ),
  109. const PopupMenuItem(
  110. value: ClusterPopupAction.breakupCluster,
  111. child: Row(
  112. children: [
  113. Icon(Icons.analytics_outlined),
  114. Padding(
  115. padding: EdgeInsets.all(8),
  116. ),
  117. Text('Break up cluster'),
  118. ],
  119. ),
  120. ),
  121. // PopupMenuItem(
  122. // value: ClusterPopupAction.hide,
  123. // child: Row(
  124. // children: [
  125. // const Icon(Icons.visibility_off_outlined),
  126. // const Padding(
  127. // padding: EdgeInsets.all(8),
  128. // ),
  129. // Text(S.of(context).hide),
  130. // ],
  131. // ),
  132. // ),
  133. ],
  134. );
  135. if (items.isNotEmpty) {
  136. actions.add(
  137. PopupMenuButton(
  138. itemBuilder: (context) {
  139. return items;
  140. },
  141. onSelected: (ClusterPopupAction value) async {
  142. if (value == ClusterPopupAction.breakupCluster) {
  143. // ignore: unawaited_futures
  144. await _breakUpCluster(context);
  145. }
  146. // else if (value == ClusterPopupAction.setCover) {
  147. // await setCoverPhoto(context);
  148. // } else if (value == ClusterPopupAction.hide) {
  149. // // ignore: unawaited_futures
  150. // }
  151. },
  152. ),
  153. );
  154. }
  155. return actions;
  156. }
  157. Future<void> _breakUpCluster(BuildContext context) async {
  158. final newClusterIDToFaceIDs =
  159. await ClusterFeedbackService.instance.breakUpCluster(widget.clusterID);
  160. for (final cluster in newClusterIDToFaceIDs.entries) {
  161. // ignore: unawaited_futures
  162. final newClusterID = cluster.key;
  163. final faceIDs = cluster.value;
  164. final files = await FilesDB.instance
  165. .getFilesFromIDs(faceIDs.map((e) => getFileIdFromFaceId(e)).toList());
  166. unawaited(
  167. Navigator.of(context).push(
  168. MaterialPageRoute(
  169. builder: (context) => ClusterPage(
  170. files.values.toList(),
  171. appendTitle:
  172. (newClusterID == -1) ? "(Analysis noise)" : "(Analysis)",
  173. clusterID: newClusterID,
  174. ),
  175. ),
  176. ),
  177. );
  178. }
  179. }
  180. }