people_photo_view.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import 'dart:io';
  2. import 'package:clean/base/base_page.dart';
  3. import 'package:clean/data/bean/photos_type.dart';
  4. import 'package:clean/module/image_picker/image_picker_util.dart';
  5. import 'package:clean/module/people_photo/people_photo_controller.dart';
  6. import 'package:clean/resource/assets.gen.dart';
  7. import 'package:clean/router/app_pages.dart';
  8. import 'package:flutter/Material.dart';
  9. import 'package:flutter/cupertino.dart';
  10. import 'package:flutter_screenutil/flutter_screenutil.dart';
  11. import 'package:get/get.dart';
  12. import 'package:wechat_assets_picker/wechat_assets_picker.dart';
  13. import '../../utils/styles.dart';
  14. class PeoplePhotoPage extends BasePage<PeoplePhotoController> {
  15. const PeoplePhotoPage({super.key});
  16. static start() {
  17. Get.toNamed(RoutePath.peoplePhoto, arguments: {});
  18. }
  19. @override
  20. bool statusBarDarkFont() {
  21. // TODO: implement statusBarDarkFont
  22. return false;
  23. }
  24. @override
  25. bool immersive() {
  26. // TODO: implement immersive
  27. return true;
  28. }
  29. @override
  30. Widget buildBody(BuildContext context) {
  31. return Stack(children: [
  32. PopScope(
  33. canPop: false,
  34. onPopInvokedWithResult: (didPop, result) {
  35. if (didPop) {
  36. return;
  37. }
  38. controller.clickBack();
  39. },
  40. child: Container(
  41. child: SafeArea(
  42. child: Obx(() {
  43. if (controller.photoGroups.isEmpty ||
  44. controller.photoGroups[0].images.isEmpty) {
  45. return _noNoPicturesCard();
  46. }
  47. return Column(
  48. children: [
  49. _titleCard(),
  50. // Photo groups
  51. Flexible(
  52. child: Obx(() {
  53. return ListView(
  54. padding: EdgeInsets.symmetric(horizontal: 16.w),
  55. children: [
  56. ...controller.photoGroups.map((group) => Column(
  57. children: [
  58. _buildPhotoGroup(
  59. images: group.images,
  60. title: "photo: ${group.images.length}",
  61. imageCount: group.images.length,
  62. ),
  63. SizedBox(height: 15.h),
  64. ],
  65. ))
  66. ],
  67. );
  68. }),
  69. ),
  70. _bottomBarCard(),
  71. ],
  72. );
  73. }),
  74. ),
  75. ),
  76. ),
  77. IgnorePointer(
  78. child: Assets.images.bgHome.image(
  79. width: 360.w,
  80. ),
  81. ),
  82. ]);
  83. }
  84. Widget _titleCard() {
  85. return Container(
  86. alignment: Alignment.centerLeft,
  87. padding: EdgeInsets.only(left: 16.w, top: 14.h),
  88. child: Column(
  89. crossAxisAlignment: CrossAxisAlignment.start,
  90. children: [
  91. GestureDetector(
  92. onTap: controller.clickBack,
  93. child: Assets.images.iconBackArrow.image(
  94. width: 28.w,
  95. height: 28.h,
  96. ),
  97. ),
  98. (controller.photoGroups.isEmpty ||
  99. controller.photoGroups[0].images.isEmpty)
  100. ? SizedBox()
  101. : Column(
  102. children: [
  103. SizedBox(height: 12.h),
  104. Text(
  105. 'People Photos',
  106. style: TextStyle(
  107. color: Colors.white,
  108. fontSize: 24.sp,
  109. fontWeight: FontWeight.w700,
  110. ),
  111. ),
  112. SizedBox(height: 20.h),
  113. ],
  114. )
  115. ],
  116. ),
  117. );
  118. }
  119. Widget _bottomBarCard() {
  120. return GestureDetector(
  121. onTap: () {
  122. controller.clickJumpSelect();
  123. },
  124. child: Container(
  125. width: 360.w,
  126. height: 81.h,
  127. padding: EdgeInsets.symmetric(horizontal: 16.w),
  128. decoration: ShapeDecoration(
  129. color: Color(0xFF23232A),
  130. shape: RoundedRectangleBorder(
  131. side: BorderSide(
  132. width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
  133. borderRadius: BorderRadius.only(
  134. topLeft: Radius.circular(14.r),
  135. topRight: Radius.circular(14.r),
  136. ),
  137. ),
  138. ),
  139. child: Row(
  140. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  141. children: [
  142. Obx(() {
  143. return Text(
  144. '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString})',
  145. textAlign: TextAlign.center,
  146. style: TextStyle(
  147. color: Colors.white.withOpacity(0.9),
  148. fontSize: 13.sp,
  149. fontWeight: FontWeight.w500,
  150. ),
  151. );
  152. }),
  153. GestureDetector(
  154. onTap: () {
  155. controller.clickDelete();
  156. },
  157. child: Container(
  158. width: 108.w,
  159. height: 38.h,
  160. decoration: ShapeDecoration(
  161. color: Color(0xFF0279FB),
  162. shape: RoundedRectangleBorder(
  163. borderRadius: BorderRadius.circular(10.r),
  164. ),
  165. ),
  166. child: Row(
  167. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  168. children: [
  169. Text(
  170. 'Delete',
  171. textAlign: TextAlign.center,
  172. style: TextStyle(
  173. color: Colors.white,
  174. fontSize: 16.sp,
  175. fontWeight: FontWeight.w500,
  176. ),
  177. ),
  178. Assets.images.iconDelete.image(
  179. width: 18.w,
  180. height: 18.h,
  181. ),
  182. ],
  183. ),
  184. ),
  185. ),
  186. ],
  187. ),
  188. ));
  189. }
  190. Widget _buildPhotoGroup({
  191. required List<AssetEntity> images,
  192. required String title,
  193. required int imageCount,
  194. }) {
  195. return Container(
  196. padding: EdgeInsets.symmetric(horizontal: 12.w),
  197. margin: EdgeInsets.only(top: 14.h),
  198. width: 328.w,
  199. height: imageCount < 5 ? 160.h : 230.h,
  200. decoration: ShapeDecoration(
  201. color: Colors.white.withValues(alpha: 0.12),
  202. shape: RoundedRectangleBorder(
  203. borderRadius: BorderRadius.circular(14.sp),
  204. ),
  205. ),
  206. child: Column(
  207. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  208. children: [
  209. Row(
  210. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  211. children: [
  212. Text(
  213. title,
  214. textAlign: TextAlign.center,
  215. style: TextStyle(
  216. color: Colors.white,
  217. fontSize: 14.sp,
  218. fontWeight: FontWeight.w500,
  219. ),
  220. ),
  221. GestureDetector(
  222. onTap: () => controller.toggleGroupSelection(images),
  223. child: Obx(() => Text(
  224. controller.getGroupByImages(images).isSelected.value
  225. ? 'Deselect All'
  226. : 'Select All',
  227. style: TextStyle(
  228. color: Colors.white.withValues(alpha: 0.7),
  229. fontSize: 14.sp,
  230. fontWeight: FontWeight.w400,
  231. ),
  232. )),
  233. ),
  234. ],
  235. ),
  236. SizedBox(
  237. height: imageCount < 3
  238. ? 70.h
  239. : imageCount <= 8
  240. ? null
  241. : 148.h,
  242. child: imageCount <= 8
  243. ? GridView.builder(
  244. shrinkWrap: true,
  245. physics: NeverScrollableScrollPhysics(),
  246. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  247. crossAxisCount: 4,
  248. mainAxisSpacing: 8.w,
  249. crossAxisSpacing: 8.h,
  250. ),
  251. itemCount: imageCount,
  252. itemBuilder: _buildPhotoItem(images),
  253. )
  254. : GridView.builder(
  255. scrollDirection: Axis.horizontal,
  256. physics: BouncingScrollPhysics(),
  257. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  258. crossAxisCount: 2,
  259. mainAxisSpacing: 8.w,
  260. crossAxisSpacing: 8.h,
  261. childAspectRatio: 1,
  262. ),
  263. itemCount: imageCount,
  264. itemBuilder: _buildPhotoItem(images),
  265. ),
  266. ),
  267. ],
  268. ),
  269. );
  270. }
  271. Widget Function(BuildContext, int) _buildPhotoItem(
  272. List<AssetEntity> images) =>
  273. (context, index) {
  274. final group = controller.getGroupByImages(images);
  275. final assetEntity = group.images[index];
  276. return GestureDetector(
  277. onTap: () {
  278. controller.clickImage(images, index, PhotosType.peoplePhotos);
  279. print("点击图片");
  280. },
  281. child: Obx(() {
  282. final isSelected = group.selectedImages[index];
  283. return Stack(
  284. children: [
  285. Container(
  286. width: 70.w,
  287. height: 70.w,
  288. decoration: ShapeDecoration(
  289. color: Colors.white.withValues(alpha: 0.12),
  290. shape: RoundedRectangleBorder(
  291. borderRadius: BorderRadius.circular(9.27.sp),
  292. ),
  293. ),
  294. child: ClipRRect(
  295. borderRadius: BorderRadius.circular(9.27.sp),
  296. child: AssetEntityImage(assetEntity,
  297. thumbnailSize: const ThumbnailSize.square(300),
  298. isOriginal: false,
  299. fit: BoxFit.cover,
  300. frameBuilder: Styles.customFrameBuilder(
  301. opacity: 0.22,
  302. width: 80.w,
  303. height: 80.w,
  304. ))),
  305. ),
  306. Positioned(
  307. right: 6.w,
  308. bottom: 6.h,
  309. child: GestureDetector(
  310. onTap: () {
  311. controller.toggleImageSelection(images, index);
  312. },
  313. child: Container(
  314. child: isSelected
  315. ? Center(
  316. child: Assets.images.iconSelected.image(
  317. width: 20.w,
  318. height: 20.h,
  319. ),
  320. )
  321. : Center(
  322. child: Assets.images.iconUnselected.image(
  323. width: 20.w,
  324. height: 20.h,
  325. )),
  326. ),
  327. )),
  328. ],
  329. );
  330. }),
  331. );
  332. };
  333. Widget _noNoPicturesCard() {
  334. return Column(
  335. // mainAxisAlignment: MainAxisAlignment.start,
  336. children: [
  337. _titleCard(),
  338. Spacer(flex: 1),
  339. Column(
  340. crossAxisAlignment: CrossAxisAlignment.center,
  341. children: [
  342. Container(
  343. width: 70.w,
  344. height: 70.h,
  345. clipBehavior: Clip.antiAlias,
  346. decoration: BoxDecoration(),
  347. child: Assets.images.iconNoPictures.image(),
  348. ),
  349. SizedBox(height: 22.h),
  350. Text(
  351. 'No pictures found',
  352. textAlign: TextAlign.center,
  353. style: TextStyle(
  354. color: Colors.white,
  355. fontSize: 20.sp,
  356. fontWeight: FontWeight.w700,
  357. ),
  358. ),
  359. SizedBox(height: 12.h),
  360. Text(
  361. 'No pictures available at the moment',
  362. textAlign: TextAlign.center,
  363. style: TextStyle(
  364. color: Colors.white.withValues(alpha: 0.6),
  365. fontSize: 14.sp,
  366. fontWeight: FontWeight.w400,
  367. ),
  368. ),
  369. ],
  370. ),
  371. Spacer(
  372. flex: 3,
  373. ),
  374. ],
  375. );
  376. }
  377. }