phtoto_selected_preview_view.dart 11 KB

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