calendar_selected_preview_view.dart 11 KB

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