locations_single_photo_view.dart 9.2 KB

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