phtoto_selected_preview_view.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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: (context, index) => _buildPhotoItem(
  70. context,
  71. index,
  72. controller.photoGroups[0].images)),
  73. );
  74. }),
  75. ),
  76. Obx(() {
  77. if (controller.photoGroups.isNotEmpty ||
  78. controller.photoGroups[0].images.isNotEmpty) {
  79. return _bottomBarCard();
  80. } else {
  81. return SizedBox();
  82. }
  83. }),
  84. SizedBox(height: 8.h),
  85. ],
  86. );
  87. }),
  88. ),
  89. )),
  90. Obx(() {
  91. if (controller.isKeepAll.value) {
  92. return IgnorePointer(
  93. child: Assets.images.bgPhotoSelectedPreviewFinish.image(
  94. width: 360.w,
  95. ),
  96. );
  97. } else {
  98. return IgnorePointer(
  99. child: Assets.images.bgHome.image(
  100. width: 360.w,
  101. ),
  102. );
  103. }
  104. }),
  105. ]);
  106. }
  107. Widget _titleCard() {
  108. return Container(
  109. alignment: Alignment.centerLeft,
  110. padding:
  111. EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w, bottom: 20.h),
  112. child: Column(
  113. crossAxisAlignment: CrossAxisAlignment.start,
  114. children: [
  115. Obx(() {
  116. return Row(
  117. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  118. children: [
  119. GestureDetector(
  120. onTap: () => controller.clickBack(),
  121. child: Assets.images.iconBackArrow.image(
  122. width: 28.w,
  123. height: 28.h,
  124. ),
  125. ),
  126. // 如果photoGroup数据为空,不显示全选按钮
  127. controller.photoGroups.isEmpty ||
  128. controller.photoGroups[0].images.isEmpty
  129. ? Container()
  130. : GestureDetector(
  131. onTap: () => controller.toggleGroupSelection(
  132. controller.photoGroups[0].images),
  133. child: Obx(() => Text(
  134. controller
  135. .getGroupByImages(
  136. controller.photoGroups[0].images)
  137. .isSelected
  138. .value
  139. ? 'Deselect All'
  140. : 'Select All',
  141. style: TextStyle(
  142. color: Colors.white.withValues(alpha: 0.7),
  143. fontSize: 14.sp,
  144. fontWeight: FontWeight.w400,
  145. ),
  146. )),
  147. ),
  148. ],
  149. );
  150. }),
  151. ],
  152. ),
  153. );
  154. }
  155. Widget _bottomBarCard() {
  156. return GestureDetector(
  157. onTap: () {
  158. controller.clickDelete();
  159. },
  160. child: Container(
  161. width: 328.w,
  162. height: 48.h,
  163. decoration: ShapeDecoration(
  164. color: Color(0xFF0279FB),
  165. shape: RoundedRectangleBorder(
  166. borderRadius: BorderRadius.circular(10.r),
  167. ),
  168. ),
  169. padding: EdgeInsets.symmetric(horizontal: 16.w),
  170. child: Row(
  171. mainAxisAlignment: MainAxisAlignment.center,
  172. children: [
  173. Assets.images.iconDelete.image(
  174. width: 18.w,
  175. height: 18.h,
  176. ),
  177. SizedBox(width: 5.w),
  178. Obx(() {
  179. if (controller.selectedPhotosIds.isNotEmpty) {
  180. return Text(
  181. 'delete ${controller.selectedFilesSizeString}',
  182. textAlign: TextAlign.center,
  183. style: TextStyle(
  184. color: Colors.white,
  185. fontSize: 16.sp,
  186. fontWeight: FontWeight.w500,
  187. ),
  188. );
  189. } else {
  190. return Text(
  191. 'Keep All',
  192. textAlign: TextAlign.center,
  193. style: TextStyle(
  194. color: Colors.white,
  195. fontSize: 16.sp,
  196. fontWeight: FontWeight.w500,
  197. ),
  198. );
  199. }
  200. }),
  201. ],
  202. ),
  203. ));
  204. }
  205. Widget _buildPhotoItem(context, index, List<AssetEntity> images) {
  206. final group = controller.getGroupByImages(controller.photoGroups[0].images);
  207. return GestureDetector(
  208. onTap: () => controller.clickImage(images, index, controller.photosType),
  209. child: Obx(() {
  210. var isSelected = group.isImageSelected(images[index]);
  211. return Stack(
  212. children: [
  213. Container(
  214. width: 104.w,
  215. height: 104.w,
  216. decoration: ShapeDecoration(
  217. color: Colors.white.withValues(alpha: 0.12),
  218. shape: RoundedRectangleBorder(
  219. borderRadius: BorderRadius.circular(9.27.sp),
  220. ),
  221. ),
  222. child: ClipRRect(
  223. borderRadius: BorderRadius.circular(9.27.sp),
  224. child: AssetEntityImage(
  225. group.images[index],
  226. width: 104.w,
  227. isOriginal: false,
  228. thumbnailSize: const ThumbnailSize.square(300),
  229. height: 104.w,
  230. fit: BoxFit.cover,
  231. frameBuilder: Styles.customFrameBuilder(
  232. width: 104.w,
  233. height: 104.w,
  234. ),
  235. ),
  236. ),
  237. ),
  238. Positioned(
  239. right: 8.w,
  240. bottom: 8.h,
  241. child: GestureDetector(
  242. onTap: () => controller.toggleImageSelection(images, index),
  243. child: Container(
  244. child: isSelected
  245. ? Center(
  246. child: Assets.images.iconSelected.image(
  247. width: 20.w,
  248. height: 20.h,
  249. ),
  250. )
  251. : Center(
  252. child: Assets.images.iconUnselected.image(
  253. width: 20.w,
  254. height: 20.h,
  255. )),
  256. )),
  257. ),
  258. ],
  259. );
  260. }),
  261. );
  262. }
  263. Widget _noNoPicturesCard() {
  264. return Column(
  265. mainAxisAlignment: MainAxisAlignment.start,
  266. children: [
  267. _titleCard(),
  268. SizedBox(height: 170.h),
  269. Column(
  270. mainAxisAlignment: MainAxisAlignment.center,
  271. crossAxisAlignment: CrossAxisAlignment.center,
  272. children: [
  273. Container(
  274. width: 70.w,
  275. height: 70.h,
  276. clipBehavior: Clip.antiAlias,
  277. decoration: BoxDecoration(),
  278. child: Assets.images.iconNoPictures.image(),
  279. ),
  280. SizedBox(height: 22.h),
  281. Text(
  282. 'No pictures found',
  283. textAlign: TextAlign.center,
  284. style: TextStyle(
  285. color: Colors.white,
  286. fontSize: 20.sp,
  287. fontWeight: FontWeight.w700,
  288. ),
  289. ),
  290. SizedBox(height: 12.h),
  291. Text(
  292. 'No pictures available at the moment',
  293. textAlign: TextAlign.center,
  294. style: TextStyle(
  295. color: Colors.white.withValues(alpha: 0.6),
  296. fontSize: 14.sp,
  297. fontWeight: FontWeight.w400,
  298. ),
  299. ),
  300. ],
  301. ),
  302. ],
  303. );
  304. }
  305. Widget _finishCleanCard() {
  306. return Container(
  307. width: 360.w,
  308. child: Column(
  309. mainAxisAlignment: MainAxisAlignment.start,
  310. children: [
  311. Spacer(
  312. flex: 3,
  313. ),
  314. Text(
  315. 'Great!',
  316. textAlign: TextAlign.center,
  317. style: TextStyle(
  318. color: Colors.white,
  319. fontSize: 32.sp,
  320. fontWeight: FontWeight.w700,
  321. ),
  322. ),
  323. SizedBox(height: 14.h),
  324. Text(
  325. "You've completed 1 photo review",
  326. textAlign: TextAlign.center,
  327. style: TextStyle(
  328. color: Colors.white.withValues(alpha: 0.8),
  329. fontSize: 16.sp,
  330. fontWeight: FontWeight.w400,
  331. ),
  332. ),
  333. SizedBox(height: 47.h),
  334. // Assets.images.iconPhotoSelectedPreviewFireworks.image(
  335. // width: 158.w,
  336. // height: 158.h,
  337. // ),
  338. SizedBox(
  339. child: Lottie.asset(
  340. Assets.anim.animPhotoSelectedPreviewFireworks,
  341. width: 158.w,
  342. height: 158.w,
  343. repeat: false,
  344. )),
  345. Spacer(
  346. flex: 5,
  347. ),
  348. ],
  349. ),
  350. );
  351. }
  352. }