fading_bottom_bar.dart 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import 'dart:io';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:photos/core/configuration.dart';
  5. import 'package:photos/models/file.dart';
  6. import 'package:photos/models/file_type.dart';
  7. import 'package:photos/models/magic_metadata.dart';
  8. import 'package:photos/models/selected_files.dart';
  9. import 'package:photos/models/trash_file.dart';
  10. import 'package:photos/services/collections_service.dart';
  11. import 'package:photos/theme/colors.dart';
  12. import 'package:photos/theme/ente_theme.dart';
  13. import "package:photos/ui/actions/file/file_actions.dart";
  14. import 'package:photos/ui/create_collection_sheet.dart';
  15. import 'package:photos/utils/delete_file_util.dart';
  16. import 'package:photos/utils/magic_util.dart';
  17. import 'package:photos/utils/share_util.dart';
  18. class FadingBottomBar extends StatefulWidget {
  19. final File file;
  20. final Function(File) onEditRequested;
  21. final bool showOnlyInfoButton;
  22. const FadingBottomBar(
  23. this.file,
  24. this.onEditRequested,
  25. this.showOnlyInfoButton, {
  26. Key? key,
  27. }) : super(key: key);
  28. @override
  29. FadingBottomBarState createState() => FadingBottomBarState();
  30. }
  31. class FadingBottomBarState extends State<FadingBottomBar> {
  32. bool _shouldHide = false;
  33. final GlobalKey shareButtonKey = GlobalKey();
  34. @override
  35. Widget build(BuildContext context) {
  36. return _getBottomBar();
  37. }
  38. void hide() {
  39. setState(() {
  40. _shouldHide = true;
  41. });
  42. }
  43. void show() {
  44. setState(() {
  45. _shouldHide = false;
  46. });
  47. }
  48. void safeRefresh() {
  49. if (mounted) {
  50. setState(() {});
  51. }
  52. }
  53. Widget _getBottomBar() {
  54. final List<Widget> children = [];
  55. children.add(
  56. Tooltip(
  57. message: "Info",
  58. child: Padding(
  59. padding: const EdgeInsets.only(top: 12, bottom: 12),
  60. child: IconButton(
  61. icon: Icon(
  62. Platform.isAndroid ? Icons.info_outline : CupertinoIcons.info,
  63. color: Colors.white,
  64. ),
  65. onPressed: () async {
  66. await _displayInfo(widget.file);
  67. safeRefresh(); //to instantly show the new caption if keypad is closed after pressing 'done' - here the caption will be updated before the bottom sheet is closed
  68. await Future.delayed(
  69. const Duration(milliseconds: 500),
  70. ); //Waiting for some time till the caption gets updated in db if the user closes the bottom sheet without pressing 'done'
  71. safeRefresh();
  72. },
  73. ),
  74. ),
  75. ),
  76. );
  77. if (widget.file is TrashFile) {
  78. _addTrashOptions(children);
  79. }
  80. final bool isUploadedByUser = widget.file.uploadedFileID != null &&
  81. widget.file.ownerID == Configuration.instance.getUserID();
  82. bool isFileHidden = false;
  83. if (isUploadedByUser) {
  84. isFileHidden = CollectionsService.instance
  85. .getCollectionByID(widget.file.collectionID!)
  86. ?.isHidden() ??
  87. false;
  88. }
  89. if (!widget.showOnlyInfoButton && widget.file is! TrashFile) {
  90. if (widget.file.fileType == FileType.image ||
  91. widget.file.fileType == FileType.livePhoto) {
  92. children.add(
  93. Tooltip(
  94. message: "Edit",
  95. child: Padding(
  96. padding: const EdgeInsets.only(top: 12, bottom: 12),
  97. child: IconButton(
  98. icon: const Icon(
  99. Icons.tune_outlined,
  100. color: Colors.white,
  101. ),
  102. onPressed: () {
  103. widget.onEditRequested(widget.file);
  104. },
  105. ),
  106. ),
  107. ),
  108. );
  109. }
  110. if (isUploadedByUser && !isFileHidden) {
  111. final bool isArchived =
  112. widget.file.magicMetadata.visibility == visibilityArchive;
  113. children.add(
  114. Tooltip(
  115. message: isArchived ? "Unarchive" : "Archive",
  116. child: Padding(
  117. padding: const EdgeInsets.only(top: 12, bottom: 12),
  118. child: IconButton(
  119. icon: Icon(
  120. isArchived ? Icons.unarchive : Icons.archive_outlined,
  121. color: Colors.white,
  122. ),
  123. onPressed: () async {
  124. await changeVisibility(
  125. context,
  126. [widget.file],
  127. isArchived ? visibilityVisible : visibilityArchive,
  128. );
  129. safeRefresh();
  130. },
  131. ),
  132. ),
  133. ),
  134. );
  135. }
  136. children.add(
  137. Tooltip(
  138. message: "Share",
  139. child: Padding(
  140. padding: const EdgeInsets.only(top: 12, bottom: 12),
  141. child: IconButton(
  142. key: shareButtonKey,
  143. icon: Icon(
  144. Platform.isAndroid
  145. ? Icons.share_outlined
  146. : CupertinoIcons.share,
  147. color: Colors.white,
  148. ),
  149. onPressed: () {
  150. share(context, [widget.file], shareButtonKey: shareButtonKey);
  151. },
  152. ),
  153. ),
  154. ),
  155. );
  156. }
  157. final safeAreaBottomPadding = MediaQuery.of(context).padding.bottom * .5;
  158. return IgnorePointer(
  159. ignoring: _shouldHide,
  160. child: AnimatedOpacity(
  161. opacity: _shouldHide ? 0 : 1,
  162. duration: const Duration(milliseconds: 150),
  163. child: Align(
  164. alignment: Alignment.bottomCenter,
  165. child: Container(
  166. decoration: BoxDecoration(
  167. gradient: LinearGradient(
  168. begin: Alignment.topCenter,
  169. end: Alignment.bottomCenter,
  170. colors: [
  171. Colors.transparent,
  172. Colors.black.withOpacity(0.6),
  173. Colors.black.withOpacity(0.72),
  174. ],
  175. stops: const [0, 0.8, 1],
  176. ),
  177. ),
  178. child: Padding(
  179. padding: EdgeInsets.only(bottom: safeAreaBottomPadding),
  180. child: Column(
  181. mainAxisSize: MainAxisSize.min,
  182. children: [
  183. widget.file.caption?.isNotEmpty ?? false
  184. ? Padding(
  185. padding: const EdgeInsets.fromLTRB(
  186. 16,
  187. 28,
  188. 16,
  189. 12,
  190. ),
  191. child: Text(
  192. widget.file.caption!,
  193. overflow: TextOverflow.ellipsis,
  194. maxLines: 4,
  195. style: getEnteTextTheme(context)
  196. .small
  197. .copyWith(color: textBaseDark),
  198. textAlign: TextAlign.center,
  199. ),
  200. )
  201. : const SizedBox.shrink(),
  202. Row(
  203. mainAxisAlignment: MainAxisAlignment.spaceAround,
  204. children: children,
  205. ),
  206. ],
  207. ),
  208. ),
  209. ),
  210. ),
  211. ),
  212. );
  213. }
  214. void _addTrashOptions(List<Widget> children) {
  215. children.add(
  216. Tooltip(
  217. message: "Restore",
  218. child: Padding(
  219. padding: const EdgeInsets.only(top: 12, bottom: 12),
  220. child: IconButton(
  221. icon: const Icon(
  222. Icons.restore_outlined,
  223. color: Colors.white,
  224. ),
  225. onPressed: () {
  226. final selectedFiles = SelectedFiles();
  227. selectedFiles.toggleSelection(widget.file);
  228. createCollectionSheet(
  229. selectedFiles,
  230. null,
  231. context,
  232. actionType: CollectionActionType.restoreFiles,
  233. );
  234. },
  235. ),
  236. ),
  237. ),
  238. );
  239. children.add(
  240. Tooltip(
  241. message: "Delete",
  242. child: Padding(
  243. padding: const EdgeInsets.only(top: 12, bottom: 12),
  244. child: IconButton(
  245. icon: const Icon(
  246. Icons.delete_forever_outlined,
  247. color: Colors.white,
  248. ),
  249. onPressed: () async {
  250. final trashedFile = <TrashFile>[];
  251. trashedFile.add(widget.file as TrashFile);
  252. if (await deleteFromTrash(context, trashedFile) == true) {
  253. Navigator.pop(context);
  254. }
  255. },
  256. ),
  257. ),
  258. ),
  259. );
  260. }
  261. Future<void> _displayInfo(File file) async {
  262. await showInfoSheet(context, file);
  263. }
  264. }