screenshots_view.dart 9.2 KB

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