phtoto_selected_preview_view.dart 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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:wechat_assets_picker/wechat_assets_picker.dart';
  10. import 'package:get/get.dart';
  11. class PhotoSelectedPreviewPage
  12. extends BasePage<PhotoSelectedPreviewController> {
  13. const PhotoSelectedPreviewPage({super.key});
  14. static void start(PhotosType photosType, Set<String> selectedIds) {
  15. Get.toNamed(RoutePath.photoSelectedPreview, arguments: {
  16. "photosType": photosType,
  17. "selectedIds": selectedIds,
  18. });
  19. }
  20. @override
  21. bool statusBarDarkFont() {
  22. return false;
  23. }
  24. @override
  25. bool immersive() {
  26. return true;
  27. }
  28. @override
  29. Widget buildBody(BuildContext context) {
  30. return Stack(children: [
  31. Container(
  32. child: SafeArea(
  33. child: Obx(() {
  34. if (controller.photoGroups.isEmpty ||
  35. controller.photoGroups[0].images.isEmpty) {
  36. return _noNoPicturesCard();
  37. }
  38. return Column(
  39. children: [
  40. _titleCard(),
  41. Flexible(
  42. child: Obx(() {
  43. return SizedBox(
  44. child: GridView.builder(
  45. padding: EdgeInsets.symmetric(horizontal: 16.w),
  46. scrollDirection: Axis.vertical,
  47. // 设置为垂直方向滚动
  48. physics: BouncingScrollPhysics(),
  49. gridDelegate:
  50. SliverGridDelegateWithFixedCrossAxisCount(
  51. crossAxisCount: 3, // 每行显示 2 个元素
  52. mainAxisSpacing: 8.w, // 垂直间距
  53. crossAxisSpacing: 8.h, // 水平间距
  54. ),
  55. itemCount: controller.photoGroups[0].images.length,
  56. itemBuilder: _buildPhotoItem(
  57. controller.photoGroups[0].images)),
  58. );
  59. }),
  60. ),
  61. Obx(() {
  62. if (controller.selectedPhotosIds.isNotEmpty) {
  63. return _bottomBarCard();
  64. } else {
  65. return SizedBox();
  66. }
  67. }),
  68. SizedBox(height: 8.h),
  69. ],
  70. );
  71. }),
  72. ),
  73. ),
  74. IgnorePointer(
  75. child: Assets.images.bgHome.image(
  76. width: 360.w,
  77. height: 234.h,
  78. ),
  79. ),
  80. ]);
  81. }
  82. Widget _titleCard() {
  83. return Container(
  84. alignment: Alignment.centerLeft,
  85. padding: EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w,bottom: 20.h),
  86. child: Column(
  87. crossAxisAlignment: CrossAxisAlignment.start,
  88. children: [
  89. Obx(() {
  90. return Row(
  91. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  92. children: [
  93. GestureDetector(
  94. onTap: () => Get.back(),
  95. child: Assets.images.iconBackArrow.image(
  96. width: 28.w,
  97. height: 28.h,
  98. ),
  99. ),
  100. // 如果photoGroup数据为空,不显示全选按钮
  101. controller.photoGroups.isEmpty ||
  102. controller.photoGroups[0].images.isEmpty
  103. ? Container()
  104. : GestureDetector(
  105. onTap: () => controller.toggleGroupSelection(
  106. controller.photoGroups[0].images),
  107. child: Obx(() => Text(
  108. controller
  109. .getGroupByImages(
  110. controller.photoGroups[0].images)
  111. .isSelected
  112. .value
  113. ? 'Deselect All'
  114. : 'Select All',
  115. style: TextStyle(
  116. color: Colors.white.withValues(alpha: 0.7),
  117. fontSize: 14.sp,
  118. fontWeight: FontWeight.w400,
  119. ),
  120. )),
  121. ),
  122. ],
  123. );
  124. }),
  125. ],
  126. ),
  127. );
  128. }
  129. Widget _bottomBarCard() {
  130. return GestureDetector(
  131. onTap: () {
  132. controller.clickDelete();
  133. },
  134. child: Container(
  135. width: 328.w,
  136. height: 48.h,
  137. decoration: ShapeDecoration(
  138. color: Color(0xFF0279FB),
  139. shape: RoundedRectangleBorder(
  140. borderRadius: BorderRadius.circular(10.r),
  141. ),
  142. ),
  143. padding: EdgeInsets.symmetric(horizontal: 16.w),
  144. child: Row(
  145. mainAxisAlignment: MainAxisAlignment.center,
  146. children: [
  147. Assets.images.iconDelete.image(
  148. width: 18.w,
  149. height: 18.h,
  150. ),
  151. SizedBox(width: 5.w),
  152. Obx(() {
  153. return Text(
  154. 'delete ${controller.selectedFilesSize.value.toStringAsFixed(1)} KB',
  155. textAlign: TextAlign.center,
  156. style: TextStyle(
  157. color: Colors.white,
  158. fontSize: 16.sp,
  159. fontWeight: FontWeight.w500,
  160. ),
  161. );
  162. }),
  163. ],
  164. ),
  165. ));
  166. }
  167. Widget Function(BuildContext, int) _buildPhotoItem(
  168. List<AssetEntity> images) =>
  169. (context, index) {
  170. final group =
  171. controller.getGroupByImages(controller.photoGroups[0].images);
  172. return GestureDetector(
  173. onTap: () => controller.clickImage(images, index),
  174. child: Obx(() {
  175. var isSelected = group.selectedImages[index];
  176. return Stack(
  177. children: [
  178. Container(
  179. width: 104.w,
  180. height: 104.w,
  181. decoration: ShapeDecoration(
  182. color: Colors.white.withValues(alpha: 0.12),
  183. shape: RoundedRectangleBorder(
  184. borderRadius: BorderRadius.circular(9.27.sp),
  185. ),
  186. image: DecorationImage(
  187. image: AssetEntityImageProvider(
  188. group.images[index],
  189. thumbnailSize: const ThumbnailSize.square(300),
  190. isOriginal: false,
  191. ),
  192. fit: BoxFit.cover,
  193. ),
  194. ),
  195. ),
  196. Positioned(
  197. right: 8.w,
  198. bottom: 8.h,
  199. child: GestureDetector(
  200. onTap: () =>
  201. controller.toggleImageSelection(images, index),
  202. child: Container(
  203. child: isSelected
  204. ? Center(
  205. child: Assets.images.iconSelected.image(
  206. width: 20.w,
  207. height: 20.h,
  208. ),
  209. )
  210. : Center(
  211. child: Assets.images.iconUnselected.image(
  212. width: 20.w,
  213. height: 20.h,
  214. )),
  215. )),
  216. ),
  217. ],
  218. );
  219. }),
  220. );
  221. };
  222. Widget _noNoPicturesCard() {
  223. return Column(
  224. mainAxisAlignment: MainAxisAlignment.start,
  225. children: [
  226. _titleCard(),
  227. SizedBox(height: 170.h),
  228. Column(
  229. mainAxisAlignment: MainAxisAlignment.center,
  230. crossAxisAlignment: CrossAxisAlignment.center,
  231. children: [
  232. Container(
  233. width: 70.w,
  234. height: 70.h,
  235. clipBehavior: Clip.antiAlias,
  236. decoration: BoxDecoration(),
  237. child: Assets.images.iconNoPictures.image(),
  238. ),
  239. SizedBox(height: 22.h),
  240. Text(
  241. 'No pictures found',
  242. textAlign: TextAlign.center,
  243. style: TextStyle(
  244. color: Colors.white,
  245. fontSize: 20.sp,
  246. fontWeight: FontWeight.w700,
  247. ),
  248. ),
  249. SizedBox(height: 12.h),
  250. Text(
  251. 'No pictures available at the moment',
  252. textAlign: TextAlign.center,
  253. style: TextStyle(
  254. color: Colors.white.withValues(alpha: 0.6),
  255. fontSize: 14.sp,
  256. fontWeight: FontWeight.w400,
  257. ),
  258. ),
  259. ],
  260. ),
  261. ],
  262. );
  263. }
  264. }