home_controller.dart 13 KB

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