store_view.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. import 'package:clean/base/base_page.dart';
  2. import 'package:clean/data/bean/store_item.dart';
  3. import 'package:clean/module/store/store_controller.dart';
  4. import 'package:clean/utils/expand.dart';
  5. import 'package:flutter/Material.dart';
  6. import 'package:flutter_screenutil/flutter_screenutil.dart';
  7. import 'package:get/get.dart';
  8. import '../../resource/assets.gen.dart';
  9. class StorePage extends BasePage<StoreController> {
  10. const StorePage({super.key});
  11. @override
  12. bool immersive() {
  13. return true;
  14. }
  15. @override
  16. bool statusBarDarkFont() => false;
  17. @override
  18. Widget buildBody(BuildContext context) {
  19. return Scaffold(
  20. backgroundColor: Colors.black,
  21. body: Stack(
  22. children: [
  23. IgnorePointer(
  24. child: Assets.images.bgStore.image(
  25. width: 360.w,
  26. ),
  27. ),
  28. SafeArea(
  29. child: Column(
  30. crossAxisAlignment: CrossAxisAlignment.start,
  31. children: [
  32. Row(
  33. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  34. crossAxisAlignment: CrossAxisAlignment.center,
  35. children: [
  36. Container(
  37. margin: EdgeInsets.only(left: 16.w, top: 14.h),
  38. child: GestureDetector(
  39. onTap: () {
  40. Get.back();
  41. },
  42. child: Assets.images.iconCommonBack
  43. .image(width: 28.w, height: 28.w),
  44. ),
  45. ),
  46. Container(
  47. margin: EdgeInsets.only(right: 16.w, top: 17.h),
  48. child: GestureDetector(
  49. onTap: () {
  50. Get.back();
  51. },
  52. child: Text(
  53. 'Restore',
  54. style: TextStyle(
  55. color: Colors.white70,
  56. fontSize: 14.sp,
  57. ),
  58. ),
  59. ),
  60. ),
  61. ],
  62. ),
  63. SizedBox(
  64. height: 30.h,
  65. ),
  66. // 标题
  67. Center(
  68. child: RichText(
  69. text: TextSpan(
  70. children: [
  71. TextSpan(
  72. text: 'CLEAN ',
  73. style: TextStyle(
  74. color: "#FFDD55".color,
  75. fontSize: 20.sp,
  76. fontWeight: FontWeight.bold,
  77. ),
  78. ),
  79. TextSpan(
  80. text: 'PRO ',
  81. style: TextStyle(
  82. color: Colors.white,
  83. fontSize: 20.sp,
  84. fontWeight: FontWeight.bold,
  85. ),
  86. ),
  87. TextSpan(
  88. text: 'FREE ',
  89. style: TextStyle(
  90. color: "#FFDD55".color,
  91. fontSize: 20.sp,
  92. fontWeight: FontWeight.bold,
  93. ),
  94. ),
  95. TextSpan(
  96. text: 'UP STORAGE',
  97. style: TextStyle(
  98. color: Colors.white,
  99. fontSize: 20.sp,
  100. fontWeight: FontWeight.bold,
  101. ),
  102. ),
  103. ],
  104. ),
  105. ),
  106. ),
  107. SizedBox(
  108. height: 20.h,
  109. ),
  110. Center(
  111. child: Container(
  112. width: 328.w,
  113. height: 203.h,
  114. decoration: BoxDecoration(
  115. image: DecorationImage(
  116. image: Assets.images.bgStoreFunc.provider(),
  117. fit: BoxFit.fill,
  118. ),
  119. ),
  120. child: Column(
  121. mainAxisAlignment: MainAxisAlignment.spaceAround,
  122. children: [
  123. _buildFeatureItem(
  124. icon: Assets.images.iconStoreSimilar
  125. .image(width: 30.w, height: 30.w),
  126. title: 'One-click Remove Similar Photos',
  127. ),
  128. _buildFeatureItem(
  129. icon: Assets.images.iconStoreAi
  130. .image(width: 30.w, height: 30.w),
  131. title: 'Detect Blurry and Junk Photos',
  132. ),
  133. _buildFeatureItem(
  134. icon: Assets.images.iconStoreContacts
  135. .image(width: 30.w, height: 30.w),
  136. title: 'Merge Duplicate Contacts',
  137. ),
  138. _buildFeatureItem(
  139. icon: Assets.images.iconStorePremium
  140. .image(width: 30.w, height: 30.w),
  141. title: 'Premium Unlimited',
  142. ),
  143. ],
  144. ),
  145. ),
  146. ),
  147. SizedBox(height: 14.h),
  148. Expanded(
  149. child: Obx(() {
  150. return ListView.builder(
  151. itemCount: controller.storeItems.length,
  152. itemBuilder: (context, index) {
  153. var item = controller.storeItems[index];
  154. return _buildSubscriptionOption(
  155. item: item,
  156. );
  157. },
  158. );
  159. }),
  160. ),
  161. Center(
  162. child: Text(
  163. 'Auto-renewable.Cancel anytime.',
  164. style: TextStyle(
  165. color: Colors.white.withOpacity(0.8),
  166. fontSize: 12.sp,
  167. ),
  168. ),
  169. ),
  170. SizedBox(
  171. height: 5.h,
  172. ),
  173. Center(
  174. child: Container(
  175. width: 312.w,
  176. height: 48.h,
  177. decoration: BoxDecoration(
  178. color: "#0279FB".color,
  179. borderRadius: BorderRadius.all(
  180. Radius.circular(24.r),
  181. ),
  182. ),
  183. child: GestureDetector(
  184. child: Center(
  185. child: Text(
  186. "CONTINUE",
  187. style: TextStyle(
  188. color: Colors.white,
  189. fontWeight: FontWeight.w700,
  190. fontSize: 16.sp,
  191. ),
  192. ),
  193. ),
  194. ),
  195. ),
  196. ),
  197. // // 底部链接
  198. SizedBox(
  199. height: 8.h,
  200. ),
  201. Row(
  202. mainAxisAlignment: MainAxisAlignment.center,
  203. children: [
  204. GestureDetector(
  205. child: Text(
  206. 'Privacy Policy',
  207. style: TextStyle(
  208. color: Colors.white.withOpacity(0.8),
  209. fontSize: 12.sp,
  210. ),
  211. ),
  212. onTap: () {},
  213. ),
  214. Text(
  215. ' | ',
  216. style: TextStyle(
  217. color: Colors.white.withOpacity(0.8),
  218. fontSize: 12.sp,
  219. ),
  220. ),
  221. GestureDetector(
  222. child: Text(
  223. 'User Agreement',
  224. style: TextStyle(
  225. color: Colors.white.withOpacity(0.8),
  226. fontSize: 12.sp,
  227. ),
  228. ),
  229. onTap: () {},
  230. ),
  231. ],
  232. ),
  233. ],
  234. ),
  235. ),
  236. ],
  237. ),
  238. );
  239. }
  240. Widget _buildFeatureItem({
  241. required Image icon,
  242. required String title,
  243. }) {
  244. return Row(
  245. children: [
  246. SizedBox(width: 15.w),
  247. icon,
  248. SizedBox(width: 8.w),
  249. Text(
  250. title,
  251. style: TextStyle(
  252. color: Colors.white,
  253. fontSize: 15.sp,
  254. fontWeight: FontWeight.w500,
  255. ),
  256. ),
  257. ],
  258. );
  259. }
  260. Widget _buildSubscriptionOption({
  261. required StoreItem item,
  262. }) {
  263. bool isSelected = controller.currentSelectedStoreItem.value?.id == item.id;
  264. return Obx(() {
  265. return Container(
  266. height: 80.h,
  267. margin: EdgeInsets.symmetric(horizontal: 20.w),
  268. child: Stack(
  269. children: [
  270. GestureDetector(
  271. onTap: () {
  272. controller.currentSelectedStoreItem.value = item;
  273. },
  274. child: Container(
  275. margin: EdgeInsets.only(top: 12.h),
  276. height: 74.h,
  277. decoration: BoxDecoration(
  278. borderRadius: BorderRadius.circular(14.r),
  279. gradient:
  280. controller.currentSelectedStoreItem.value?.id == item.id
  281. ? LinearGradient(
  282. begin: Alignment.centerRight,
  283. end: Alignment.centerLeft,
  284. colors: [
  285. '#63CEFF'.color,
  286. '#0279FB'.color,
  287. "#047AFB".color
  288. ],
  289. )
  290. : null,
  291. border:
  292. controller.currentSelectedStoreItem.value?.id == item.id
  293. ? Border.all(color: Colors.transparent, width: 0.w)
  294. : Border.all(
  295. color: Colors.white.withOpacity(0.2),
  296. width: 2.w,
  297. ),
  298. ),
  299. child: Container(
  300. margin:
  301. controller.currentSelectedStoreItem.value?.id == item.id
  302. ? EdgeInsets.all(2.w)
  303. : null,
  304. decoration: BoxDecoration(
  305. color: "#05050D".color,
  306. borderRadius: BorderRadius.circular(13.r),
  307. ),
  308. child: Container(
  309. color: Colors.white.withOpacity(0.06),
  310. child: Stack(
  311. children: [
  312. Padding(
  313. padding: EdgeInsets.only(
  314. left: 12.w, top: 10.h, bottom: 12.h, right: 20.w),
  315. child: Row(
  316. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  317. children: [
  318. Column(
  319. mainAxisAlignment:
  320. MainAxisAlignment.spaceBetween,
  321. crossAxisAlignment: CrossAxisAlignment.start,
  322. children: [
  323. Text(
  324. item.name,
  325. style: TextStyle(
  326. color: Colors.white,
  327. fontSize: 16.sp,
  328. fontWeight: FontWeight.bold,
  329. ),
  330. ),
  331. Text(
  332. item.name,
  333. style: TextStyle(
  334. color: Colors.white60,
  335. fontSize: 12.sp,
  336. ),
  337. ),
  338. ],
  339. ),
  340. Text(
  341. item.priceDesc,
  342. style: TextStyle(
  343. color: Colors.white,
  344. fontSize: 16.sp,
  345. fontWeight: FontWeight.bold,
  346. ),
  347. ),
  348. ],
  349. ),
  350. ),
  351. if (isSelected)
  352. Positioned(
  353. right: 0,
  354. top: 0,
  355. child: Container(
  356. padding: EdgeInsets.only(
  357. left: 8.w,
  358. right: 8.w,
  359. top: 2.h,
  360. bottom: 5.h,
  361. ),
  362. decoration: BoxDecoration(
  363. gradient: LinearGradient(
  364. begin: Alignment.centerRight,
  365. end: Alignment.centerLeft,
  366. colors: ['#63CEFF'.color, '#0279FB'.color],
  367. ),
  368. borderRadius: BorderRadius.only(
  369. topRight: Radius.circular(14.r),
  370. bottomLeft: Radius.circular(14.r),
  371. ),
  372. // border: Border.all(color: Colors.transparent, width: 2.w),
  373. ),
  374. child: Text(
  375. 'No payment now!',
  376. style: TextStyle(
  377. color: Colors.white,
  378. fontSize: 11.sp,
  379. fontWeight: FontWeight.bold,
  380. ),
  381. ),
  382. ),
  383. ),
  384. ],
  385. ),
  386. ),
  387. ),
  388. ),
  389. ),
  390. if (false)
  391. Positioned(
  392. right: 120.w,
  393. top: 0.h,
  394. child: Assets.images.iconStoreFree
  395. .image(width: 30.w, height: 28.h),
  396. ),
  397. ],
  398. ),
  399. );
  400. });
  401. }
  402. }