screenshots_view.dart 9.6 KB

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