phtoto_selected_preview_view.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. import 'package:clean/base/base_page.dart';
  2. import 'package:clean/data/bean/photos_type.dart';
  3. import 'package:clean/module/photo_preview/photo_selected_preview_controller.dart';
  4. import 'package:clean/resource/assets.gen.dart';
  5. import 'package:clean/router/app_pages.dart';
  6. import 'package:flutter/Material.dart';
  7. import 'package:flutter_screenutil/flutter_screenutil.dart';
  8. import 'package:get/get_core/src/get_main.dart';
  9. import 'package:lottie/lottie.dart';
  10. import 'package:wechat_assets_picker/wechat_assets_picker.dart';
  11. import 'package:get/get.dart';
  12. class PhotoSelectedPreviewPage
  13. extends BasePage<PhotoSelectedPreviewController> {
  14. const PhotoSelectedPreviewPage({super.key});
  15. static void start(PhotosType photosType, Set<String> selectedIds) {
  16. Get.toNamed(RoutePath.photoSelectedPreview, arguments: {
  17. "photosType": photosType,
  18. "selectedIds": selectedIds,
  19. });
  20. }
  21. @override
  22. bool statusBarDarkFont() {
  23. return false;
  24. }
  25. @override
  26. bool immersive() {
  27. return true;
  28. }
  29. @override
  30. Widget buildBody(BuildContext context) {
  31. return Stack(children: [
  32. PopScope(
  33. canPop: false,
  34. onPopInvokedWithResult: (didPop, result) {
  35. if (didPop) {
  36. return;
  37. }
  38. controller.clickBack();
  39. },
  40. child: Container(
  41. child: SafeArea(
  42. child: Obx(() {
  43. if (controller.photoGroups.isEmpty ||
  44. controller.photoGroups[0].images.isEmpty) {
  45. return _noNoPicturesCard();
  46. }else if (controller.isKeepAll.value) {
  47. return _finishCleanCard();
  48. }
  49. return Column(
  50. children: [
  51. _titleCard(),
  52. Flexible(
  53. child: Obx(() {
  54. return SizedBox(
  55. child: GridView.builder(
  56. padding: EdgeInsets.symmetric(horizontal: 16.w),
  57. scrollDirection: Axis.vertical,
  58. // 设置为垂直方向滚动
  59. physics: BouncingScrollPhysics(),
  60. gridDelegate:
  61. SliverGridDelegateWithFixedCrossAxisCount(
  62. crossAxisCount: 3, // 每行显示 2 个元素
  63. mainAxisSpacing: 8.w, // 垂直间距
  64. crossAxisSpacing: 8.h, // 水平间距
  65. ),
  66. itemCount:
  67. controller.photoGroups[0].images.length,
  68. itemBuilder: _buildPhotoItem(
  69. controller.photoGroups[0].images)),
  70. );
  71. }),
  72. ),
  73. Obx(() {
  74. if (controller.photoGroups.isNotEmpty ||
  75. controller.photoGroups[0].images.isNotEmpty) {
  76. return _bottomBarCard();
  77. } else {
  78. return SizedBox();
  79. }
  80. }),
  81. SizedBox(height: 8.h),
  82. ],
  83. );
  84. }),
  85. ),
  86. )),
  87. Obx(() {
  88. if (controller.isKeepAll.value) {
  89. return IgnorePointer(
  90. child: Assets.images.bgPhotoSelectedPreviewFinish.image(
  91. width: 360.w,
  92. height: 335.h,
  93. ),
  94. );
  95. } else {
  96. return IgnorePointer(
  97. child: Assets.images.bgHome.image(
  98. width: 360.w,
  99. height: 234.h,
  100. ),
  101. );
  102. }
  103. }),
  104. ]);
  105. }
  106. Widget _titleCard() {
  107. return Container(
  108. alignment: Alignment.centerLeft,
  109. padding:
  110. EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w, bottom: 20.h),
  111. child: Column(
  112. crossAxisAlignment: CrossAxisAlignment.start,
  113. children: [
  114. Obx(() {
  115. return Row(
  116. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  117. children: [
  118. GestureDetector(
  119. onTap: () => controller.clickBack(),
  120. child: Assets.images.iconBackArrow.image(
  121. width: 28.w,
  122. height: 28.h,
  123. ),
  124. ),
  125. // 如果photoGroup数据为空,不显示全选按钮
  126. controller.photoGroups.isEmpty ||
  127. controller.photoGroups[0].images.isEmpty
  128. ? Container()
  129. : GestureDetector(
  130. onTap: () => controller.toggleGroupSelection(
  131. controller.photoGroups[0].images),
  132. child: Obx(() => Text(
  133. controller
  134. .getGroupByImages(
  135. controller.photoGroups[0].images)
  136. .isSelected
  137. .value
  138. ? 'Deselect All'
  139. : 'Select All',
  140. style: TextStyle(
  141. color: Colors.white.withValues(alpha: 0.7),
  142. fontSize: 14.sp,
  143. fontWeight: FontWeight.w400,
  144. ),
  145. )),
  146. ),
  147. ],
  148. );
  149. }),
  150. ],
  151. ),
  152. );
  153. }
  154. Widget _bottomBarCard() {
  155. return GestureDetector(
  156. onTap: () {
  157. controller.clickDelete();
  158. },
  159. child: Container(
  160. width: 328.w,
  161. height: 48.h,
  162. decoration: ShapeDecoration(
  163. color: Color(0xFF0279FB),
  164. shape: RoundedRectangleBorder(
  165. borderRadius: BorderRadius.circular(10.r),
  166. ),
  167. ),
  168. padding: EdgeInsets.symmetric(horizontal: 16.w),
  169. child: Row(
  170. mainAxisAlignment: MainAxisAlignment.center,
  171. children: [
  172. Assets.images.iconDelete.image(
  173. width: 18.w,
  174. height: 18.h,
  175. ),
  176. SizedBox(width: 5.w),
  177. Obx(() {
  178. if (controller.selectedPhotosIds.isNotEmpty) {
  179. return Text(
  180. 'delete ${controller.selectedFilesSizeString}',
  181. textAlign: TextAlign.center,
  182. style: TextStyle(
  183. color: Colors.white,
  184. fontSize: 16.sp,
  185. fontWeight: FontWeight.w500,
  186. ),
  187. );
  188. } else {
  189. return Text(
  190. 'Keep All',
  191. textAlign: TextAlign.center,
  192. style: TextStyle(
  193. color: Colors.white,
  194. fontSize: 16.sp,
  195. fontWeight: FontWeight.w500,
  196. ),
  197. );
  198. }
  199. }),
  200. ],
  201. ),
  202. ));
  203. }
  204. Widget Function(BuildContext, int) _buildPhotoItem(
  205. List<AssetEntity> images) =>
  206. (context, index) {
  207. final group =
  208. controller.getGroupByImages(controller.photoGroups[0].images);
  209. return GestureDetector(
  210. onTap: () =>
  211. controller.clickImage(images, index, controller.photosType),
  212. child: Obx(() {
  213. var isSelected = group.selectedImages[index];
  214. return Stack(
  215. children: [
  216. Container(
  217. width: 104.w,
  218. height: 104.w,
  219. decoration: ShapeDecoration(
  220. color: Colors.white.withValues(alpha: 0.12),
  221. shape: RoundedRectangleBorder(
  222. borderRadius: BorderRadius.circular(9.27.sp),
  223. ),
  224. image: DecorationImage(
  225. image: AssetEntityImageProvider(
  226. group.images[index],
  227. thumbnailSize: const ThumbnailSize.square(300),
  228. isOriginal: false,
  229. ),
  230. fit: BoxFit.cover,
  231. ),
  232. ),
  233. ),
  234. Positioned(
  235. right: 8.w,
  236. bottom: 8.h,
  237. child: GestureDetector(
  238. onTap: () =>
  239. controller.toggleImageSelection(images, index),
  240. child: Container(
  241. child: isSelected
  242. ? Center(
  243. child: Assets.images.iconSelected.image(
  244. width: 20.w,
  245. height: 20.h,
  246. ),
  247. )
  248. : Center(
  249. child: Assets.images.iconUnselected.image(
  250. width: 20.w,
  251. height: 20.h,
  252. )),
  253. )),
  254. ),
  255. ],
  256. );
  257. }),
  258. );
  259. };
  260. Widget _noNoPicturesCard() {
  261. return Column(
  262. mainAxisAlignment: MainAxisAlignment.start,
  263. children: [
  264. _titleCard(),
  265. SizedBox(height: 170.h),
  266. Column(
  267. mainAxisAlignment: MainAxisAlignment.center,
  268. crossAxisAlignment: CrossAxisAlignment.center,
  269. children: [
  270. Container(
  271. width: 70.w,
  272. height: 70.h,
  273. clipBehavior: Clip.antiAlias,
  274. decoration: BoxDecoration(),
  275. child: Assets.images.iconNoPictures.image(),
  276. ),
  277. SizedBox(height: 22.h),
  278. Text(
  279. 'No pictures found',
  280. textAlign: TextAlign.center,
  281. style: TextStyle(
  282. color: Colors.white,
  283. fontSize: 20.sp,
  284. fontWeight: FontWeight.w700,
  285. ),
  286. ),
  287. SizedBox(height: 12.h),
  288. Text(
  289. 'No pictures available at the moment',
  290. textAlign: TextAlign.center,
  291. style: TextStyle(
  292. color: Colors.white.withValues(alpha: 0.6),
  293. fontSize: 14.sp,
  294. fontWeight: FontWeight.w400,
  295. ),
  296. ),
  297. ],
  298. ),
  299. ],
  300. );
  301. }
  302. Widget _finishCleanCard() {
  303. return Container(
  304. width: 360.w,
  305. child: Column(
  306. mainAxisAlignment: MainAxisAlignment.start,
  307. children: [
  308. Spacer(
  309. flex: 3,
  310. ),
  311. Text(
  312. 'Great!',
  313. textAlign: TextAlign.center,
  314. style: TextStyle(
  315. color: Colors.white,
  316. fontSize: 32.sp,
  317. fontWeight: FontWeight.w700,
  318. ),
  319. ),
  320. SizedBox(height: 14.h),
  321. Text(
  322. "You've completed 1 photo review",
  323. textAlign: TextAlign.center,
  324. style: TextStyle(
  325. color: Colors.white.withValues(alpha: 0.8),
  326. fontSize: 16.sp,
  327. fontWeight: FontWeight.w400,
  328. ),
  329. ),
  330. SizedBox(height: 47.h),
  331. // Assets.images.iconPhotoSelectedPreviewFireworks.image(
  332. // width: 158.w,
  333. // height: 158.h,
  334. // ),
  335. SizedBox(
  336. child: Lottie.asset(
  337. Assets.anim.animPhotoSelectedPreviewFireworks,
  338. width: 158.w,
  339. height: 158.w,
  340. repeat: false,
  341. )),
  342. Spacer(
  343. flex: 5,
  344. ),
  345. ],
  346. ),
  347. );
  348. }
  349. }