people_photo_view.dart 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import 'dart:io';
  2. import 'package:clean/base/base_page.dart';
  3. import 'package:clean/module/people_photo/people_photo_controller.dart';
  4. import 'package:clean/resource/assets.gen.dart';
  5. import 'package:clean/router/app_pages.dart';
  6. import 'package:flutter/Material.dart';
  7. import 'package:flutter/cupertino.dart';
  8. import 'package:flutter_screenutil/flutter_screenutil.dart';
  9. import 'package:get/get.dart';
  10. class PeoplePhotoPage extends BasePage<PeoplePhotoController> {
  11. const PeoplePhotoPage({super.key});
  12. static start() {
  13. Get.put((PeoplePhotoController()));
  14. Get.toNamed(RoutePath.peoplePhoto, arguments: {});
  15. }
  16. @override
  17. bool statusBarDarkFont() {
  18. // TODO: implement statusBarDarkFont
  19. return false;
  20. }
  21. @override
  22. bool immersive() {
  23. // TODO: implement immersive
  24. return true;
  25. }
  26. @override
  27. Widget buildBody(BuildContext context) {
  28. return Stack(children: [
  29. Container(
  30. child: SafeArea(
  31. child: Column(
  32. children: [
  33. _titleCard(),
  34. // Photo groups
  35. Expanded(
  36. child: Obx(() {
  37. return ListView(
  38. padding: EdgeInsets.symmetric(horizontal: 16.w),
  39. children: [
  40. ...controller.photoGroups.map((group) => Column(
  41. children: [
  42. _buildPhotoGroup(
  43. title: group.title,
  44. imageCount: group.imageCount,
  45. ),
  46. SizedBox(height: 15.h),
  47. ],
  48. ))
  49. ],
  50. );
  51. }),
  52. ),
  53. _bottomBarCard(),
  54. ],
  55. ),
  56. ),
  57. ),
  58. IgnorePointer(
  59. child: Assets.images.bgHome.image(
  60. width: 360.w,
  61. height: 234.h,
  62. ),
  63. ),
  64. ]);
  65. }
  66. Widget _titleCard() {
  67. return Container(
  68. alignment: Alignment.centerLeft,
  69. padding: EdgeInsets.only(left: 16.w, top: 14.h),
  70. child: Column(
  71. crossAxisAlignment: CrossAxisAlignment.start,
  72. children: [
  73. GestureDetector(
  74. onTap: () => Get.back(),
  75. child: Assets.images.iconBackArrow.image(
  76. width: 28.w,
  77. height: 28.h,
  78. ),
  79. ),
  80. SizedBox(height: 12.h),
  81. Text(
  82. 'People Photos',
  83. style: TextStyle(
  84. color: Colors.white,
  85. fontSize: 24.sp,
  86. fontWeight: FontWeight.w700,
  87. ),
  88. ),
  89. SizedBox(height: 20.h),
  90. ],
  91. ),
  92. );
  93. }
  94. Widget _bottomBarCard() {
  95. return Container(
  96. width: 360.w,
  97. height: 81.h,
  98. padding: EdgeInsets.symmetric(horizontal: 16.w),
  99. decoration: ShapeDecoration(
  100. color: Color(0xFF23232A),
  101. shape: RoundedRectangleBorder(
  102. side: BorderSide(
  103. width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
  104. borderRadius: BorderRadius.only(
  105. topLeft: Radius.circular(14.r),
  106. topRight: Radius.circular(14.r),
  107. ),
  108. ),
  109. ),
  110. child: Row(
  111. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  112. children: [
  113. Obx(() => Text(
  114. '${controller.selectedFileCount} files selected (${controller.selectedFilesSize.toStringAsFixed(1)} KB)',
  115. textAlign: TextAlign.center,
  116. style: TextStyle(
  117. color: Colors.white.withValues(alpha: 0.9),
  118. fontSize: 13.sp,
  119. fontWeight: FontWeight.w500,
  120. ),
  121. )),
  122. Container(
  123. width: 108.w,
  124. height: 38.h,
  125. decoration: ShapeDecoration(
  126. color: Color(0xFF0279FB),
  127. shape: RoundedRectangleBorder(
  128. borderRadius: BorderRadius.circular(10.r),
  129. ),
  130. ),
  131. child: Row(
  132. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  133. children: [
  134. Text(
  135. 'Delete',
  136. textAlign: TextAlign.center,
  137. style: TextStyle(
  138. color: Colors.white,
  139. fontSize: 16.sp,
  140. fontWeight: FontWeight.w500,
  141. ),
  142. ),
  143. Assets.images.iconDelete.image(
  144. width: 18.w,
  145. height: 18.h,
  146. ),
  147. ],
  148. ),
  149. ),
  150. ],
  151. ),
  152. );
  153. }
  154. Widget _buildPhotoGroup({
  155. required String title,
  156. required int imageCount,
  157. }) {
  158. return Container(
  159. padding: EdgeInsets.symmetric(horizontal: 12.w),
  160. margin: EdgeInsets.only(top: 14.h),
  161. width: 328.w,
  162. height: 230.h,
  163. decoration: ShapeDecoration(
  164. color: Colors.white.withValues(alpha: 0.12),
  165. shape: RoundedRectangleBorder(
  166. borderRadius: BorderRadius.circular(14.sp),
  167. ),
  168. ),
  169. child: Column(
  170. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  171. children: [
  172. Row(
  173. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  174. children: [
  175. Text(
  176. title,
  177. textAlign: TextAlign.center,
  178. style: TextStyle(
  179. color: Colors.white,
  180. fontSize: 14.sp,
  181. fontWeight: FontWeight.w500,
  182. ),
  183. ),
  184. GestureDetector(
  185. onTap: () => controller.toggleGroupSelection(title),
  186. child: Obx(() => Text(
  187. controller.photoGroups
  188. .firstWhere((g) => g.title == title)
  189. .isSelected
  190. .value
  191. ? 'Deselect All'
  192. : 'Select All',
  193. style: TextStyle(
  194. color: Colors.white.withValues(alpha: 0.7),
  195. fontSize: 14.sp,
  196. fontWeight: FontWeight.w400,
  197. ),
  198. )),
  199. ),
  200. ],
  201. ),
  202. SizedBox(
  203. height: imageCount <= 8 ? null : 148.w,
  204. child: imageCount <= 8
  205. ? GridView.builder(
  206. shrinkWrap: true,
  207. physics: NeverScrollableScrollPhysics(),
  208. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  209. crossAxisCount: 4,
  210. mainAxisSpacing: 8.w,
  211. crossAxisSpacing: 8.h,
  212. ),
  213. itemCount: imageCount,
  214. itemBuilder: _buildPhotoItem(title),
  215. )
  216. : GridView.builder(
  217. scrollDirection: Axis.horizontal,
  218. physics: BouncingScrollPhysics(),
  219. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  220. crossAxisCount: 2,
  221. mainAxisSpacing: 8.w,
  222. crossAxisSpacing: 8.h,
  223. childAspectRatio: 1,
  224. ),
  225. itemCount: imageCount,
  226. itemBuilder: _buildPhotoItem(title),
  227. ),
  228. ),
  229. ],
  230. ),
  231. );
  232. }
  233. Widget Function(BuildContext, int) _buildPhotoItem(String title) =>
  234. (context, index) {
  235. final group =
  236. controller.photoGroups.firstWhere((group) => group.title == title);
  237. final imagePath = group.images[index];
  238. return GestureDetector(
  239. onTap: () => controller.toggleImageSelection(title, index),
  240. child: Obx(() {
  241. final isSelected = group.selectedImages[index];
  242. return Stack(
  243. children: [
  244. Container(
  245. width: 70.w,
  246. height: 70.w,
  247. decoration: ShapeDecoration(
  248. color: Colors.white.withValues(alpha: 0.12),
  249. shape: RoundedRectangleBorder(
  250. borderRadius: BorderRadius.circular(9.27.sp),
  251. ),
  252. image: DecorationImage(
  253. image: FileImage(File(imagePath)),
  254. fit: BoxFit.cover,
  255. ),
  256. ),
  257. ),
  258. Positioned(
  259. right: 6.w,
  260. bottom: 6.h,
  261. child: Container(
  262. child: isSelected
  263. ? Center(
  264. child: Assets.images.iconSelected.image(
  265. width: 20.w,
  266. height: 20.h,
  267. ),
  268. )
  269. : Center(
  270. child: Assets.images.iconUnselected.image(
  271. width: 20.w,
  272. height: 20.h,
  273. )),
  274. ),
  275. ),
  276. ],
  277. );
  278. }),
  279. );
  280. };
  281. }