people_photo_view.dart 12 KB

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