photo_preview_view.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. import 'package:clean/base/base_page.dart';
  2. import 'package:clean/data/bean/photos_type.dart';
  3. import 'package:clean/module/photo_preview/photo_preview_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/src/widgets/framework.dart';
  8. import 'package:flutter_card_swiper/flutter_card_swiper.dart';
  9. import 'package:flutter_screenutil/flutter_screenutil.dart';
  10. import 'package:get/get.dart';
  11. import 'package:lottie/lottie.dart';
  12. import 'package:wechat_assets_picker/wechat_assets_picker.dart';
  13. class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
  14. PhotoPreviewPage({Key? key}) : super(key: key);
  15. static void start(PhotosType photosType, String currentImageId) {
  16. print(' PhotoPreviewPage start $photosType $currentImageId');
  17. Get.toNamed(RoutePath.photoPreview, arguments: {
  18. "photosType": photosType,
  19. "currentImageId": currentImageId,
  20. });
  21. }
  22. @override
  23. bool immersive() {
  24. // TODO: implement immersive
  25. return true;
  26. }
  27. @override
  28. bool statusBarDarkFont() {
  29. // TODO: implement statusBarDarkFont
  30. return false;
  31. }
  32. @override
  33. Widget buildBody(BuildContext context) {
  34. return Stack(children: [
  35. Container(
  36. child: PopScope(
  37. canPop: false,
  38. onPopInvokedWithResult: (didPop, result) {
  39. if (didPop) {
  40. return;
  41. }
  42. controller.clickBack();
  43. },
  44. child: SafeArea(
  45. child: Container(
  46. child: Obx(() {
  47. if (controller.isSwiperEnd.value ||
  48. controller.listAssetEntity.isEmpty) {
  49. return onSwiperEndCard();
  50. } else {
  51. return Column(
  52. children: [
  53. _titleCard(),
  54. Spacer(),
  55. Container(
  56. width: 314.w,
  57. height: 392.h,
  58. child: CardSwiper(
  59. scale: 0.8,
  60. allowedSwipeDirection: AllowedSwipeDirection.only(
  61. right: true,
  62. left: true,
  63. ),
  64. isLoop: false,
  65. backCardOffset: Offset(0.w, -20.h),
  66. controller: controller.cardSwiperController.value,
  67. cardsCount: controller.listAssetEntity.length,
  68. onSwipe: controller.onSwipe,
  69. onUndo: controller.onSwiperUndo,
  70. numberOfCardsDisplayed:
  71. (controller.listAssetEntity.length == 1) ? 1 : 2,
  72. onEnd: controller.onSwiperEnd,
  73. cardBuilder: (context,
  74. index,
  75. horizontalOffsetPercentage,
  76. verticalOffsetPercentage) {
  77. final assetEntity = controller.listAssetEntity[index];
  78. return ClipRRect(
  79. borderRadius: BorderRadius.circular(20.r),
  80. child: AssetEntityImage(
  81. assetEntity,
  82. width: 314.w,
  83. height: 392.h,
  84. fit: BoxFit.cover,
  85. ),
  86. );
  87. },
  88. ),
  89. ),
  90. Spacer(),
  91. bottomButtonCard(),
  92. _bottomBarCard(),
  93. ],
  94. );
  95. }
  96. }),
  97. ),
  98. ),
  99. )),
  100. Obx(() {
  101. if (controller.isSwiperEnd.value ||
  102. controller.listAssetEntity.isEmpty) {
  103. return IgnorePointer(
  104. child: Assets.images.bgPhotoSelectedPreviewFinish.image(
  105. width: 360.w,
  106. ),
  107. );
  108. } else {
  109. return IgnorePointer(
  110. child: Assets.images.bgHome.image(
  111. width: 360.w,
  112. ),
  113. );
  114. }
  115. }),
  116. ]);
  117. }
  118. Widget _titleCard() {
  119. return Container(
  120. alignment: Alignment.centerLeft,
  121. padding: EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w),
  122. child: Column(
  123. crossAxisAlignment: CrossAxisAlignment.start,
  124. children: [
  125. Row(
  126. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  127. children: [
  128. GestureDetector(
  129. onTap: controller.clickBack,
  130. child: Assets.images.iconBackArrow.image(
  131. width: 28.w,
  132. height: 28.h,
  133. ),
  134. ),
  135. Obx(() => Row(
  136. mainAxisAlignment: MainAxisAlignment.center,
  137. children: [
  138. Text(
  139. '${controller.groupIndex.value + 1}',
  140. textAlign: TextAlign.center,
  141. style: TextStyle(
  142. color: Colors.white,
  143. fontSize: 16.sp,
  144. fontWeight: FontWeight.w700,
  145. ),
  146. ),
  147. Text(
  148. ' / ${controller.listAssetEntity.length}',
  149. textAlign: TextAlign.center,
  150. style: TextStyle(
  151. color: Colors.white.withValues(alpha: 0.6),
  152. fontSize: 16.sp,
  153. fontWeight: FontWeight.w500,
  154. ),
  155. ),
  156. ],
  157. )),
  158. GestureDetector(
  159. onTap: controller.recoverSelectPhoto,
  160. child: Assets.images.iconPreviewRecover.image(
  161. width: 30.w,
  162. height: 30.h,
  163. ),
  164. ),
  165. ],
  166. ),
  167. SizedBox(height: 12.h),
  168. ],
  169. ),
  170. );
  171. }
  172. Widget _bottomBarCard() {
  173. return Container(
  174. width: 360.w,
  175. height: 81.h,
  176. padding: EdgeInsets.symmetric(horizontal: 16.w),
  177. decoration: ShapeDecoration(
  178. color: Color(0xFF23232A),
  179. shape: RoundedRectangleBorder(
  180. side: BorderSide(
  181. width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
  182. borderRadius: BorderRadius.only(
  183. topLeft: Radius.circular(14.r),
  184. topRight: Radius.circular(14.r),
  185. ),
  186. ),
  187. ),
  188. child: Row(
  189. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  190. children: [
  191. Obx(() {
  192. return Text(
  193. '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString} )',
  194. textAlign: TextAlign.center,
  195. style: TextStyle(
  196. color: Colors.white.withValues(alpha: 0.9),
  197. fontSize: 13.sp,
  198. fontWeight: FontWeight.w500,
  199. ),
  200. );
  201. }),
  202. GestureDetector(
  203. onTap: controller.clickDelete,
  204. child: Container(
  205. width: 108.w,
  206. height: 38.h,
  207. decoration: ShapeDecoration(
  208. color: Color(0xFF0279FB),
  209. shape: RoundedRectangleBorder(
  210. borderRadius: BorderRadius.circular(10.r),
  211. ),
  212. ),
  213. child: Row(
  214. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  215. children: [
  216. Text(
  217. 'Delete',
  218. textAlign: TextAlign.center,
  219. style: TextStyle(
  220. color: Colors.white,
  221. fontSize: 16.sp,
  222. fontWeight: FontWeight.w500,
  223. ),
  224. ),
  225. Assets.images.iconDelete.image(
  226. width: 18.w,
  227. height: 18.h,
  228. ),
  229. ],
  230. ),
  231. )),
  232. ],
  233. ),
  234. );
  235. }
  236. Widget bottomButtonCard() {
  237. return Container(
  238. margin: EdgeInsets.only(bottom: 54.h),
  239. child: Row(
  240. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  241. children: [
  242. GestureDetector(
  243. onTap: () => controller.clickSelect(),
  244. child: Assets.images.iconPreviewSelect.image(
  245. width: 62.w,
  246. height: 62.h,
  247. ),
  248. ),
  249. GestureDetector(
  250. onTap: () => controller.clickUnselect(),
  251. child: Assets.images.iconPreviewNoSelect.image(
  252. width: 62.w,
  253. height: 62.h,
  254. ),
  255. ),
  256. ],
  257. ),
  258. );
  259. }
  260. Widget onSwiperEndCard() {
  261. return Column(
  262. children: [
  263. Container(
  264. child: Lottie.asset(
  265. Assets.anim.animFireworks,
  266. controller: controller.animationController,
  267. height: 351.h,
  268. repeat: false,
  269. ),
  270. ),
  271. Visibility(
  272. visible: controller.animationIsComplete.value,
  273. child: Center(
  274. child: Column(
  275. crossAxisAlignment: CrossAxisAlignment.center,
  276. mainAxisAlignment: MainAxisAlignment.center,
  277. children: [
  278. Text(
  279. 'Perfect!',
  280. textAlign: TextAlign.center,
  281. style: TextStyle(
  282. color: Colors.white,
  283. fontSize: 32.sp,
  284. fontWeight: FontWeight.w700,
  285. ),
  286. ),
  287. SizedBox(height: 16.h),
  288. SizedBox(
  289. child: Row(
  290. mainAxisAlignment: MainAxisAlignment.center,
  291. children: [
  292. Container(
  293. clipBehavior: Clip.antiAlias,
  294. decoration: BoxDecoration(),
  295. child:
  296. Assets.images.iconPreviewSwiperEndFirework.image(
  297. width: 40.w,
  298. height: 40.w,
  299. ),
  300. ),
  301. SizedBox(width: 4.w),
  302. Text(
  303. 'All Similar and Redundant\nPhotos Cleared',
  304. textAlign: TextAlign.center,
  305. style: TextStyle(
  306. color: Colors.white.withValues(alpha: 0.9),
  307. fontSize: 16.sp,
  308. fontWeight: FontWeight.w400,
  309. ),
  310. ),
  311. SizedBox(width: 4.w),
  312. Container(
  313. clipBehavior: Clip.antiAlias,
  314. decoration: BoxDecoration(),
  315. child:
  316. Assets.images.iconPreviewSwiperEndFirework.image(
  317. width: 40.w,
  318. height: 40.w,
  319. ),
  320. ),
  321. ],
  322. ),
  323. ),
  324. ],
  325. ),
  326. )),
  327. Spacer(
  328. flex: 5,
  329. ),
  330. controller.listAssetEntity.isEmpty ? SizedBox() : _bottomBarCard(),
  331. ],
  332. );
  333. }
  334. }