screenshots_view.dart 9.5 KB

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