app_storage_viewer.dart 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import 'dart:io';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_cache_manager/flutter_cache_manager.dart';
  4. import 'package:path_provider/path_provider.dart';
  5. import 'package:photos/core/cache/video_cache_manager.dart';
  6. import 'package:photos/core/configuration.dart';
  7. import 'package:photos/services/feature_flag_service.dart';
  8. import 'package:photos/theme/ente_theme.dart';
  9. import 'package:photos/ui/components/captioned_text_widget.dart';
  10. import 'package:photos/ui/components/icon_button_widget.dart';
  11. import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart';
  12. import 'package:photos/ui/components/menu_section_title.dart';
  13. import 'package:photos/ui/components/title_bar_title_widget.dart';
  14. import 'package:photos/ui/components/title_bar_widget.dart';
  15. import 'package:photos/ui/tools/debug/path_storage_viewer.dart';
  16. import 'package:photos/utils/directory_content.dart';
  17. class AppStorageViewer extends StatefulWidget {
  18. const AppStorageViewer({Key? key}) : super(key: key);
  19. @override
  20. State<AppStorageViewer> createState() => _AppStorageViewerState();
  21. }
  22. class _AppStorageViewerState extends State<AppStorageViewer> {
  23. final List<PathStorageItem> paths = [];
  24. late String iosTempDirectoryPath;
  25. late bool internalUser;
  26. int _refreshCounterKey = 0;
  27. @override
  28. void initState() {
  29. internalUser = FeatureFlagService.instance.isInternalUserOrDebugBuild();
  30. addPath();
  31. super.initState();
  32. }
  33. void addPath() async {
  34. final appDocumentsDirectory = (await getApplicationDocumentsDirectory());
  35. final appSupportDirectory = (await getApplicationSupportDirectory());
  36. final appTemporaryDirectory = (await getTemporaryDirectory());
  37. iosTempDirectoryPath = "${appDocumentsDirectory.parent.path}/tmp/";
  38. final iOSPhotoManagerInAppCacheDirectory =
  39. iosTempDirectoryPath + "flutter-images";
  40. final androidGlideCacheDirectory =
  41. "${appTemporaryDirectory.path}/image_manager_disk_cache/";
  42. final String tempDownload = Configuration.instance.getTempDirectory();
  43. final String cacheDirectory =
  44. Configuration.instance.getThumbnailCacheDirectory();
  45. final imageCachePath =
  46. appTemporaryDirectory.path + "/" + DefaultCacheManager.key;
  47. final videoCachePath =
  48. appTemporaryDirectory.path + "/" + VideoCacheManager.key;
  49. paths.addAll([
  50. PathStorageItem.name(
  51. imageCachePath,
  52. "Remote images",
  53. allowCacheClear: true,
  54. ),
  55. PathStorageItem.name(
  56. videoCachePath,
  57. "Remote videos",
  58. allowCacheClear: true,
  59. ),
  60. PathStorageItem.name(
  61. cacheDirectory,
  62. "Remote thumbnails",
  63. allowCacheClear: true,
  64. ),
  65. PathStorageItem.name(tempDownload, "Pending sync"),
  66. PathStorageItem.name(
  67. Platform.isAndroid
  68. ? androidGlideCacheDirectory
  69. : iOSPhotoManagerInAppCacheDirectory,
  70. "Local gallery",
  71. allowCacheClear: true,
  72. ),
  73. ]);
  74. if (internalUser) {
  75. paths.addAll([
  76. PathStorageItem.name(appDocumentsDirectory.path, "App Documents Dir"),
  77. PathStorageItem.name(appSupportDirectory.path, "App Support Dir"),
  78. PathStorageItem.name(appTemporaryDirectory.path, "App Temp Dir"),
  79. ]);
  80. if (!Platform.isAndroid) {
  81. paths.add(PathStorageItem.name(iosTempDirectoryPath, "/tmp directory"));
  82. }
  83. }
  84. if (mounted) {
  85. setState(() => {});
  86. }
  87. }
  88. @override
  89. Widget build(BuildContext context) {
  90. debugPrint("$runtimeType building");
  91. return Scaffold(
  92. body: CustomScrollView(
  93. primary: false,
  94. slivers: <Widget>[
  95. TitleBarWidget(
  96. flexibleSpaceTitle: const TitleBarTitleWidget(
  97. title: "Manage device storage",
  98. ),
  99. actionIcons: [
  100. IconButtonWidget(
  101. icon: Icons.close_outlined,
  102. iconButtonType: IconButtonType.secondary,
  103. onTap: () {
  104. Navigator.pop(context);
  105. if (Navigator.canPop(context)) {
  106. Navigator.pop(context);
  107. }
  108. if (Navigator.canPop(context)) {
  109. Navigator.pop(context);
  110. }
  111. },
  112. ),
  113. ],
  114. ),
  115. SliverList(
  116. delegate: SliverChildBuilderDelegate(
  117. (context, index) {
  118. return Padding(
  119. padding: const EdgeInsets.symmetric(horizontal: 16),
  120. child: Column(
  121. mainAxisSize: MainAxisSize.min,
  122. children: [
  123. Column(
  124. children: [
  125. const MenuSectionTitle(
  126. title: 'Cached data',
  127. ),
  128. ListView.builder(
  129. shrinkWrap: true,
  130. padding: const EdgeInsets.all(0),
  131. physics: const ScrollPhysics(),
  132. // to disable GridView's scrolling
  133. itemBuilder: (context, index) {
  134. final path = paths[index];
  135. return PathStorageViewer(
  136. path,
  137. removeTopRadius: index > 0,
  138. removeBottomRadius: index < paths.length - 1,
  139. enableDoubleTapClear: internalUser,
  140. key: ValueKey("$index-$_refreshCounterKey"),
  141. );
  142. },
  143. itemCount: paths.length,
  144. ),
  145. const SizedBox(
  146. height: 24,
  147. ),
  148. MenuItemWidget(
  149. leadingIcon: Icons.delete_sweep_outlined,
  150. captionedTextWidget: const CaptionedTextWidget(
  151. title: "Clear caches",
  152. ),
  153. menuItemColor:
  154. getEnteColorScheme(context).fillFaint,
  155. singleBorderRadius: 8,
  156. alwaysShowSuccessState: true,
  157. onTap: () async {
  158. for (var pathItem in paths) {
  159. if (pathItem.allowCacheClear) {
  160. await deleteDirectoryContents(
  161. pathItem.path,
  162. );
  163. }
  164. }
  165. if (!Platform.isAndroid) {
  166. await deleteDirectoryContents(
  167. iosTempDirectoryPath,
  168. );
  169. }
  170. _refreshCounterKey++;
  171. if (mounted) {
  172. setState(() => {});
  173. }
  174. },
  175. ),
  176. const SizedBox(
  177. height: 24,
  178. ),
  179. ],
  180. ),
  181. ],
  182. ),
  183. );
  184. },
  185. childCount: 1,
  186. ),
  187. ),
  188. ],
  189. ),
  190. );
  191. }
  192. }