locations_single_photo_view.dart 8.1 KB

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