locations_single_photo_view.dart 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. import 'package:clean/base/base_page.dart';
  2. import 'package:clean/data/bean/photos_type.dart';
  3. import 'package:clean/module/locations_photo/locations_single_photo_controller.dart';
  4. import 'package:clean/module/people_photo/photo_group.dart';
  5. import 'package:clean/resource/assets.gen.dart';
  6. import 'package:clean/router/app_pages.dart';
  7. import 'package:flutter/Material.dart';
  8. import 'package:flutter_screenutil/flutter_screenutil.dart';
  9. import 'package:get/get.dart';
  10. import 'package:wechat_assets_picker/wechat_assets_picker.dart';
  11. import '../../utils/styles.dart';
  12. class LocationsSinglePhotoPage
  13. extends BasePage<LocationsSinglePhotoController> {
  14. const LocationsSinglePhotoPage({super.key});
  15. static void start({required PhotoGroup photoGroup}) {
  16. Get.toNamed(RoutePath.locationsSinglePhoto, arguments: {
  17. "PhotoGroup": photoGroup,
  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. PopScope(
  32. canPop: false,
  33. onPopInvokedWithResult: (didPop, result) {
  34. if (didPop) {
  35. return;
  36. }
  37. controller.clickBack();
  38. },
  39. child: Container(
  40. child: SafeArea(
  41. child: Obx(() {
  42. if (controller.photoGroups.isEmpty) {
  43. return _noNoPicturesCard();
  44. }
  45. return Column(
  46. children: [
  47. _titleCard(),
  48. Expanded(
  49. child: Obx(() {
  50. return SizedBox(
  51. child: GridView.builder(
  52. padding: EdgeInsets.symmetric(horizontal: 16.w),
  53. scrollDirection: Axis.vertical,
  54. // 设置为垂直方向滚动
  55. physics: BouncingScrollPhysics(),
  56. gridDelegate:
  57. SliverGridDelegateWithFixedCrossAxisCount(
  58. crossAxisCount: 3, // 每行显示 3 个元素
  59. mainAxisSpacing: 8.w, // 垂直间距
  60. crossAxisSpacing: 8.h, // 水平间距
  61. ),
  62. itemCount:
  63. controller.photoGroups.first.images.length,
  64. itemBuilder: _buildPhotoItem(
  65. controller.photoGroups.first.images)),
  66. );
  67. }),
  68. ),
  69. Obx(() {
  70. if (controller.selectedFileCount.value == 0) {
  71. return SizedBox();
  72. } else {
  73. return _bottomBarCard();
  74. }
  75. }),
  76. SizedBox(height: 8.h),
  77. ],
  78. );
  79. }),
  80. ),
  81. )),
  82. IgnorePointer(
  83. child: Assets.images.bgHome.image(
  84. width: 360.w,
  85. ),
  86. ),
  87. ]);
  88. }
  89. Widget _titleCard() {
  90. return Container(
  91. alignment: Alignment.centerLeft,
  92. padding: EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w),
  93. child: Column(
  94. crossAxisAlignment: CrossAxisAlignment.start,
  95. children: [
  96. Row(
  97. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  98. children: [
  99. GestureDetector(
  100. onTap: controller.clickBack,
  101. child: Assets.images.iconBackArrow.image(
  102. width: 28.w,
  103. height: 28.h,
  104. ),
  105. ),
  106. Obx(() {
  107. if (controller.photoGroups.isEmpty) return SizedBox();
  108. return Text(
  109. controller.photoGroups.first.location ?? "",
  110. textAlign: TextAlign.center,
  111. style: TextStyle(
  112. color: Colors.white,
  113. fontSize: 17.sp,
  114. fontWeight: FontWeight.w500,
  115. ),
  116. );
  117. }),
  118. Obx(() {
  119. if (controller.photoGroups.isEmpty) return SizedBox();
  120. return GestureDetector(
  121. onTap: () => controller.toggleGroupSelection(
  122. controller.photoGroups.first.images),
  123. child: Obx(() => Text(
  124. controller.photoGroups.first.isSelected.value
  125. ? 'Deselect All'
  126. : 'Select All',
  127. style: TextStyle(
  128. color: Colors.white.withValues(alpha: 0.7),
  129. fontSize: 14.sp,
  130. fontWeight: FontWeight.w400,
  131. ),
  132. )),
  133. );
  134. }),
  135. ],
  136. ),
  137. SizedBox(height: 30.h),
  138. ],
  139. ),
  140. );
  141. }
  142. Widget _bottomBarCard() {
  143. return GestureDetector(
  144. onTap: () => controller.clickDelete(),
  145. child: Container(
  146. width: 328.w,
  147. height: 48.h,
  148. decoration: ShapeDecoration(
  149. color: Color(0xFF0279FB),
  150. shape: RoundedRectangleBorder(
  151. borderRadius: BorderRadius.circular(10.r),
  152. ),
  153. ),
  154. padding: EdgeInsets.symmetric(horizontal: 16.w),
  155. child: Row(
  156. mainAxisAlignment: MainAxisAlignment.center,
  157. children: [
  158. Assets.images.iconDelete.image(
  159. width: 18.w,
  160. height: 18.h,
  161. ),
  162. SizedBox(width: 5.w),
  163. Obx(() {
  164. return Text(
  165. 'Delete ${controller.selectedFileCount.value} Photos (${controller.selectedFilesSizeString})',
  166. textAlign: TextAlign.center,
  167. style: TextStyle(
  168. color: Colors.white,
  169. fontSize: 16.sp,
  170. fontWeight: FontWeight.w500,
  171. ),
  172. );
  173. }),
  174. ],
  175. ),
  176. ),
  177. );
  178. }
  179. Widget Function(BuildContext, int) _buildPhotoItem(
  180. List<AssetEntity> images) =>
  181. (context, index) {
  182. final group = controller.getGroupByImages(images);
  183. return GestureDetector(
  184. onTap: () =>
  185. controller.clickImage(images, index, PhotosType.locationPhotos),
  186. child: Obx(() {
  187. final isSelected = group.selectedImages[index];
  188. return Stack(
  189. children: [
  190. Container(
  191. width: 104.w,
  192. height: 104.w,
  193. decoration: ShapeDecoration(
  194. color: Colors.white.withValues(alpha: 0.12),
  195. shape: RoundedRectangleBorder(
  196. borderRadius: BorderRadius.circular(9.27.sp),
  197. ),
  198. ),
  199. child: ClipRRect(
  200. borderRadius: BorderRadius.circular(9.27.sp),
  201. child: AssetEntityImage(
  202. group.images[index],
  203. width: 104.w,
  204. height: 104.w,
  205. fit: BoxFit.cover,
  206. frameBuilder: Styles.customFrameBuilder(
  207. opacity: 0.22,
  208. width: 80.w,
  209. height: 80.w,
  210. ),
  211. ),
  212. ),
  213. ),
  214. Positioned(
  215. right: 8.w,
  216. bottom: 8.h,
  217. child: GestureDetector(
  218. onTap: () =>
  219. controller.toggleImageSelection(images, index),
  220. child: Container(
  221. child: isSelected
  222. ? Center(
  223. child: Assets.images.iconSelected.image(
  224. width: 20.w,
  225. height: 20.h,
  226. ),
  227. )
  228. : Center(
  229. child: Assets.images.iconUnselected.image(
  230. width: 20.w,
  231. height: 20.h,
  232. )),
  233. )),
  234. ),
  235. ],
  236. );
  237. }),
  238. );
  239. };
  240. Widget _noNoPicturesCard() {
  241. return Column(
  242. children: [
  243. _titleCard(),
  244. SizedBox(
  245. height: 170.h,
  246. ),
  247. Container(
  248. child: Column(
  249. mainAxisAlignment: MainAxisAlignment.center,
  250. crossAxisAlignment: CrossAxisAlignment.center,
  251. children: [
  252. Container(
  253. width: 70.w,
  254. height: 70.h,
  255. clipBehavior: Clip.antiAlias,
  256. decoration: BoxDecoration(),
  257. child: Assets.images.iconNoPictures.image(),
  258. ),
  259. SizedBox(height: 22.h),
  260. Text(
  261. 'No pictures found',
  262. textAlign: TextAlign.center,
  263. style: TextStyle(
  264. color: Colors.white,
  265. fontSize: 20.sp,
  266. fontWeight: FontWeight.w700,
  267. ),
  268. ),
  269. SizedBox(height: 12.h),
  270. Text(
  271. 'No pictures available at the moment',
  272. textAlign: TextAlign.center,
  273. style: TextStyle(
  274. color: Colors.white.withValues(alpha: 0.6),
  275. fontSize: 14.sp,
  276. fontWeight: FontWeight.w400,
  277. ),
  278. ),
  279. ],
  280. ),
  281. ),
  282. ],
  283. );
  284. }
  285. }