phtoto_selected_preview_view.dart 12 KB

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