home_controller.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:airbridge_flutter_sdk/airbridge_flutter_sdk.dart';
  4. import 'package:classify_photo/classify_photo.dart';
  5. import 'package:clean/base/base_controller.dart';
  6. import 'package:clean/data/consts/constants.dart';
  7. import 'package:clean/data/repositories/event_repository.dart';
  8. import 'package:clean/data/repositories/user_repository.dart';
  9. import 'package:clean/module/image_picker/image_picker_util.dart';
  10. import 'package:clean/module/locations_photo/locations_photo_view.dart';
  11. import 'package:clean/module/people_photo/people_photo_view.dart';
  12. import 'package:clean/module/screenshots_blurry/screenshots_view.dart';
  13. import 'package:clean/module/similar_photo/similar_photo_view.dart';
  14. import 'package:clean/router/app_pages.dart';
  15. import 'package:clean/utils/toast_util.dart';
  16. import 'package:flutter/Material.dart';
  17. import 'package:get/get.dart';
  18. import 'package:permission_handler/permission_handler.dart';
  19. import 'package:wechat_assets_picker/wechat_assets_picker.dart';
  20. import '../../data/api/response/user_info_response.dart';
  21. import '../../data/consts/event_report_id.dart';
  22. import '../../data/repositories/config_repository.dart';
  23. import '../../handler/event_handler.dart';
  24. import '../../handler/photo_scan_handler.dart';
  25. import '../../widget/multi_segment_circle_indicator.dart';
  26. class HomeController extends BaseController {
  27. Rx<double> totalSpace = 0.0.obs;
  28. Rx<double> usedSpace = 0.0.obs;
  29. Rx<double> photoSpace = 0.0.obs;
  30. Rx<double> freeSpace = 0.0.obs;
  31. Rx<String> totalSpaceStr = "".obs;
  32. Rx<String> usedSpaceStr = "".obs;
  33. Rx<String> photoSpaceStr = "".obs;
  34. Rx<String> freeSpaceStr = "".obs;
  35. // 计算已用存储百分比
  36. double get usedSpacePercentage => (usedSpace.value / totalSpace.value) * 100;
  37. // 计算照片占用存储百分比
  38. double get photoSpacePercentage =>
  39. (photoSpace.value / totalSpace.value) * 100;
  40. // 计算可用存储百分比
  41. double get freeSpacePercentage => (freeSpace.value / totalSpace.value) * 100;
  42. RxList<String> similarImages =
  43. List.generate(4, (index) => 'iconHomeNoPhoto').obs;
  44. RxInt imageCount = 0.obs;
  45. // 相似图片
  46. RxList<AssetEntity> similarPhotos = PhotoScanHandler.similarPhotos;
  47. // 人物图片
  48. RxList<AssetEntity> peoplePhotos = PhotoScanHandler.peoplePhotos;
  49. // 地点图片
  50. Rx<AssetEntity?> locationPhoto = PhotoScanHandler.locationPhoto;
  51. // 截图照片
  52. Rx<AssetEntity?> screenshotPhoto = PhotoScanHandler.screenshotPhoto;
  53. // 模糊照片
  54. Rx<AssetEntity?> blurryPhoto = PhotoScanHandler.blurryPhoto;
  55. // 是否扫描完成
  56. RxBool isSimilarScanned = PhotoScanHandler.isSimilarScanned;
  57. // 是否扫描完成
  58. RxBool isPeopleScanned = PhotoScanHandler.isPeopleScanned;
  59. // 是否扫描完成
  60. RxBool isScreenShotScanned = PhotoScanHandler.isScreenShotScanned;
  61. // 是否扫描完成
  62. RxBool isBlurryScanned = PhotoScanHandler.isBlurryScanned;
  63. // 存储是否扫描完成
  64. RxBool isStorageScanned = false.obs;
  65. UserInfoResponse? get userInfo => userRepository.userInfo.value;
  66. List<PieData> get pieDataList => [
  67. PieData("PhotoSpace", photoSpacePercentage, Colors.blue),
  68. PieData("OtherUsed", usedSpacePercentage - photoSpacePercentage,
  69. Colors.red),
  70. PieData("totalSpace", totalSpace.value, Colors.grey.withOpacity(0.1)),
  71. ];
  72. @override
  73. Future<void> onInit() async {
  74. // TODO: implement onInit
  75. super.onInit();
  76. if (Platform.isAndroid) {
  77. // 延迟3秒
  78. Future.delayed(const Duration(seconds: 3), () {
  79. isStorageScanned.value = true;
  80. totalSpace.value = 200.0;
  81. usedSpace.value = 50.0;
  82. photoSpace.value = 30.0;
  83. freeSpace.value = 150.0;
  84. });
  85. }
  86. configRepository.refreshConfig();
  87. await userRepository.getUserInfo();
  88. if (userRepository.userInfo.value != null) {
  89. Airbridge.setUserID(userRepository.userInfo.value!.ssid);
  90. // 接收归因结果
  91. Airbridge.setOnAttributionReceived((result) {
  92. print(result);
  93. Map<String, String> attr = <String, String>{};
  94. attr["attributedChannel"] = "Appstore";
  95. Airbridge.fetchDeviceUUID(onSuccess: (uuid) {
  96. eventRepository.attrPush(uuid, "airbridge", jsonEncode(result));
  97. });
  98. });
  99. }
  100. EventHandler.pushInstall();
  101. if (!userRepository.isVip()) {
  102. Get.toNamed(RoutePath.discount);
  103. }
  104. setFirstIntoApp(false);
  105. var status = await Permission.photos.status;
  106. if (status.isGranted) {
  107. getStorageInfo();
  108. } else if (status.isPermanentlyDenied) {
  109. ToastUtil.show("Please enable the album permission");
  110. openAppSettings();
  111. } else {
  112. ToastUtil.show("Please enable the album permission");
  113. }
  114. }
  115. @override
  116. void onReady() {
  117. super.onReady();
  118. // EventHandler.report(EventId.event_03000);
  119. }
  120. Future<void> getStorageInfo() async {
  121. final classifyPhoto = ClassifyPhoto();
  122. try {
  123. final storageInfo = await classifyPhoto.getStorageInfo();
  124. // 转换为 GB
  125. final totalSpaceGB = storageInfo['totalSpace']! / (1000 * 1000 * 1000);
  126. final freeSpaceGB = storageInfo['freeSpace']! / (1024 * 1024 * 1024);
  127. final usedSpaceGB = storageInfo['usedSpace']! / (1024 * 1024 * 1024);
  128. final photoSpaceGB = storageInfo['photoSpace']! / (1024 * 1024 * 1024);
  129. totalSpaceStr.value = ImagePickerUtil.formatFileSize(
  130. storageInfo['totalSpace']!,
  131. decimals: 1);
  132. freeSpaceStr.value = ImagePickerUtil.formatFileSize(
  133. storageInfo['freeSpace']!,
  134. decimals: 1);
  135. usedSpaceStr.value = ImagePickerUtil.formatFileSize(
  136. storageInfo['usedSpace']!,
  137. decimals: 1);
  138. photoSpaceStr.value = ImagePickerUtil.formatFileSize(
  139. storageInfo['photoSpace']!,
  140. decimals: 1);
  141. totalSpace.value = totalSpaceGB.round().toDouble();
  142. freeSpace.value = freeSpaceGB;
  143. usedSpace.value = usedSpaceGB;
  144. photoSpace.value = photoSpaceGB;
  145. print('总容量: $totalSpaceStr');
  146. print('可用空间: $freeSpaceStr');
  147. print('已用空间: $usedSpaceStr');
  148. print('照片占用: $photoSpaceStr');
  149. isStorageScanned.value = true;
  150. } catch (e) {
  151. print('获取存储信息失败: $e');
  152. }
  153. }
  154. // Future<void> handleScreenPhotos() async {
  155. // final photoClassify = ClassifyPhoto();
  156. // try {
  157. // print('开始获取截图照片');
  158. // final photos = await photoClassify.getScreenshots();
  159. // print('获取截图照片完成: ${photos?.length ?? 0} 组照片');
  160. // isScreenShotScanned.value = true;
  161. // if (photos != null) {
  162. // await ImagePickerUtil.updatePhotos(photos);
  163. // if (ImagePickerUtil.screenshotPhotos.isNotEmpty) {
  164. // var asset = ImagePickerUtil.screenshotPhotos.first;
  165. // screenshotPhoto.value = asset;
  166. // }
  167. // }
  168. // } catch (e, stackTrace) {
  169. // print('获取照片失败: $e');
  170. // print('Stack trace: $stackTrace');
  171. // }
  172. // }
  173. //
  174. // Future<void> handleBlurryPhotos() async {
  175. // final photoClassify = ClassifyPhoto();
  176. // try {
  177. // print('开始获取模糊照片');
  178. // final photos = await photoClassify.getBlurryPhotos();
  179. // print('获取模糊照片完成: ${photos?.length ?? 0} 组照片');
  180. // isBlurryScanned.value = true;
  181. // if (photos != null) {
  182. // await ImagePickerUtil.updatePhotos(photos);
  183. // if (ImagePickerUtil.blurryPhotos.isNotEmpty) {
  184. // var asset = ImagePickerUtil.blurryPhotos.first;
  185. // blurryPhoto.value = asset;
  186. // }
  187. // }
  188. // } catch (e, stackTrace) {
  189. // print('获取照片失败: $e');
  190. // print('Stack trace: $stackTrace');
  191. // }
  192. // }
  193. //
  194. // Future<void> handlePeoplePhotos() async {
  195. // final photoClassify = ClassifyPhoto();
  196. // try {
  197. // print('开始获取人物照片');
  198. // final photos = await photoClassify.getPeoplePhotos();
  199. // print('获取人物照片完成: ${photos?.length ?? 0} 组照片');
  200. // isPeopleScanned.value = true;
  201. // if (photos != null) {
  202. // await ImagePickerUtil.updatePhotos(photos);
  203. //
  204. // // 处理人物照片
  205. // peoplePhotos.clear();
  206. // if (ImagePickerUtil.peoplePhotos.isNotEmpty) {
  207. // for (var personPhotos in ImagePickerUtil.peoplePhotos) {
  208. // peoplePhotos.add(personPhotos);
  209. // if (peoplePhotos.length == 2) {
  210. // break;
  211. // }
  212. // }
  213. // }
  214. // }
  215. // } catch (e, stackTrace) {
  216. // print('获取照片失败: $e');
  217. // print('Stack trace: $stackTrace');
  218. // }
  219. // }
  220. //
  221. // Future<void> handleSimilarPhotos() async {
  222. // final photoClassify = ClassifyPhoto();
  223. // try {
  224. // print('开始获取相似照片');
  225. // final photos = await photoClassify.getSimilarPhotos();
  226. // print('获取相似照片完成: ${photos?.length ?? 0} 组照片');
  227. // isSimilarScanned.value = true;
  228. // if (photos != null) {
  229. // await ImagePickerUtil.updatePhotos(photos);
  230. //
  231. // similarPhotos.clear();
  232. // if (ImagePickerUtil.similarPhotos.isNotEmpty) {
  233. // for (var group in ImagePickerUtil.similarPhotos) {
  234. // for (var asset in group) {
  235. // similarPhotos.add(asset);
  236. // if (similarPhotos.length == 4) {
  237. // break;
  238. // }
  239. // }
  240. // }
  241. // }
  242. // }
  243. // } catch (e, stackTrace) {
  244. // print('获取照片失败: $e');
  245. // print('Stack trace: $stackTrace');
  246. // }
  247. // }
  248. // Future<void> handlePhotos() async {
  249. // final photoClassify = ClassifyPhoto();
  250. // try {
  251. // print('开始获取照片');
  252. // final photos = await photoClassify.getPhoto();
  253. // print('获取照片完成: ${photos?.length ?? 0} 组照片');
  254. //
  255. // // 已完成扫描
  256. // // isScanned.value = true;
  257. //
  258. // if (photos != null) {
  259. // await ImagePickerUtil.updatePhotos(photos);
  260. //
  261. // similarPhotos.clear();
  262. // if (ImagePickerUtil.similarPhotos.isNotEmpty) {
  263. // for (var group in ImagePickerUtil.similarPhotos) {
  264. // for (var asset in group) {
  265. // similarPhotos.add(asset);
  266. // if (similarPhotos.length == 4) {
  267. // break;
  268. // }
  269. // }
  270. // }
  271. // }
  272. //
  273. // // 处理地点照片
  274. // locationPhoto.value = null;
  275. // if (ImagePickerUtil.locationPhotos.isNotEmpty) {
  276. // // 获取第一个地点的第一张照片
  277. // final firstLocationPhotos =
  278. // ImagePickerUtil.locationPhotos.values.first;
  279. // if (firstLocationPhotos.isNotEmpty) {
  280. // var asset = firstLocationPhotos.first;
  281. // locationPhoto.value = asset;
  282. // }
  283. // }
  284. //
  285. // // 处理人物照片
  286. // peoplePhotos.clear();
  287. // if (ImagePickerUtil.peoplePhotos.isNotEmpty) {
  288. // for (var personPhotos in ImagePickerUtil.peoplePhotos) {
  289. // peoplePhotos.add(personPhotos);
  290. // if (peoplePhotos.length == 2) {
  291. // break;
  292. // }
  293. // }
  294. // }
  295. //
  296. // if (ImagePickerUtil.screenshotPhotos.isNotEmpty) {
  297. // var asset = ImagePickerUtil.screenshotPhotos.first;
  298. // screenshotPhoto.value = asset;
  299. // }
  300. //
  301. // if (ImagePickerUtil.blurryPhotos.isNotEmpty) {
  302. // var asset = ImagePickerUtil.blurryPhotos.first;
  303. // blurryPhoto.value = asset;
  304. // }
  305. // }
  306. // } catch (e, stackTrace) {
  307. // print('获取照片失败: $e');
  308. // print('Stack trace: $stackTrace');
  309. // }
  310. // }
  311. void _navigateAndStartPage(Function pageStartFunction) {
  312. // if (isFirstClickHomeClean()) {
  313. // setFirstClickHomeClean(false);
  314. // Get.toNamed(RoutePath.discount)?.then((value) {
  315. // pageStartFunction();
  316. // });
  317. // } else {
  318. pageStartFunction();
  319. // }
  320. }
  321. similarCleanClick() {
  322. print('similarCleanClick');
  323. EventHandler.report(EventId.event_03001);
  324. _navigateAndStartPage(SimilarPhotoPage.start);
  325. }
  326. peopleCleanClick() {
  327. print('peopleCleanClick');
  328. EventHandler.report(EventId.event_03002);
  329. _navigateAndStartPage(PeoplePhotoPage.start);
  330. }
  331. locationCleanClick() {
  332. print('locationCleanClick');
  333. EventHandler.report(EventId.event_03003);
  334. _navigateAndStartPage(LocationsPhotoPage.start);
  335. }
  336. screenshotCleanClick() {
  337. print('screenshotCleanClick');
  338. EventHandler.report(EventId.event_03004);
  339. _navigateAndStartPage(() => ScreenshotsPage.start("Screenshots"));
  340. }
  341. blurryCleanClick() {
  342. print('blurCleanClick');
  343. EventHandler.report(EventId.event_03005);
  344. _navigateAndStartPage(() => ScreenshotsPage.start("Blurry"));
  345. }
  346. titleVipClick() {
  347. EventHandler.report(EventId.event_02000);
  348. Get.toNamed(RoutePath.store);
  349. }
  350. }