home_view.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. import 'dart:ui';
  2. import 'package:clean/base/base_view.dart';
  3. import 'package:clean/module/home/home_controller.dart';
  4. import 'package:clean/resource/assets.gen.dart';
  5. import 'package:clean/resource/string.gen.dart';
  6. import 'package:get/get.dart';
  7. import 'package:flutter/Material.dart';
  8. import 'package:flutter_screenutil/flutter_screenutil.dart';
  9. import 'package:syncfusion_flutter_charts/charts.dart';
  10. class HomePage extends BaseView<HomeController> {
  11. const HomePage({super.key});
  12. @override
  13. backgroundColor() {
  14. return Color(0xFF05050D);
  15. }
  16. @override
  17. viewHeight() {
  18. return double.infinity;
  19. }
  20. @override
  21. Widget buildBody(BuildContext context) {
  22. // TODO: implement buildBody
  23. return Stack(
  24. children: [
  25. SafeArea(
  26. child: SingleChildScrollView(
  27. child: Column(
  28. children: [
  29. titleCard(),
  30. storageCard(),
  31. similarCard(),
  32. quickPhotoCard(),
  33. peopleCard(),
  34. locationsCard(),
  35. screenshotsAndBlurryCard(),
  36. SizedBox(height: 40.h),
  37. ],
  38. )),
  39. ),
  40. IgnorePointer(
  41. child: Assets.images.bgHome.image(
  42. width: 360.w,
  43. height: 234.h,
  44. ),
  45. ),
  46. ],
  47. );
  48. }
  49. Widget titleCard() {
  50. return Padding(
  51. padding: EdgeInsets.only(top: 29.h, left: 16.w, right: 16.w),
  52. child: Row(
  53. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  54. children: [
  55. Text(
  56. StringName.cleanPro,
  57. style: TextStyle(
  58. color: Colors.white,
  59. fontSize: 24.sp,
  60. fontWeight: FontWeight.w900,
  61. ),
  62. ),
  63. GestureDetector(
  64. onTap: () {
  65. print("home vip");
  66. controller.usedSpace.value = controller.usedSpace.value + 60;
  67. controller.freeSpace.value = controller.freeSpace.value - 60;
  68. },
  69. child: Assets.images.iconHomeTitleVip
  70. .image(width: 60.8.w, height: 20.h),
  71. ),
  72. ],
  73. ),
  74. );
  75. }
  76. Widget storageCard() {
  77. return Container(
  78. margin: EdgeInsets.only(top: 20.h),
  79. padding: EdgeInsets.symmetric(horizontal: 16.w),
  80. width: 328.w,
  81. height: 146.h,
  82. decoration: ShapeDecoration(
  83. color: Colors.white.withValues(alpha: 0.10000000149011612),
  84. shape: RoundedRectangleBorder(
  85. borderRadius: BorderRadius.circular(14.r),
  86. ),
  87. ),
  88. child: Row(
  89. children: [
  90. circularChartCard(),
  91. SizedBox(
  92. width: 14.w,
  93. ),
  94. storageInfoCard(),
  95. ],
  96. ));
  97. }
  98. Widget circularChartCard() {
  99. return SizedBox(
  100. width: 120.00.w,
  101. child: Obx(() {
  102. return SfCircularChart(
  103. series: <CircularSeries>[
  104. DoughnutSeries<PieData, String>(
  105. dataSource: [
  106. PieData('photo Space', controller.photoSpacePercentage,
  107. Colors.blue),
  108. PieData(
  109. 'Used Space',
  110. controller.usedSpacePercentage -
  111. controller.photoSpacePercentage,
  112. Colors.red),
  113. PieData(
  114. 'Unused Space',
  115. controller.freeSpacePercentage,
  116. Colors.white.withValues(alpha: 0.10000000149011612),
  117. ),
  118. ],
  119. xValueMapper: (PieData data, _) => data.label,
  120. yValueMapper: (PieData data, _) => data.value,
  121. pointColorMapper: (PieData data, _) => data.color,
  122. cornerStyle: CornerStyle.bothCurve,
  123. radius: '100%',
  124. // 设置饼图的半径
  125. innerRadius: '80%',
  126. // 设置饼图的内半径
  127. startAngle: 0,
  128. // 设置开始角度
  129. endAngle: 360, // 设置结束角度
  130. ),
  131. ],
  132. annotations: <CircularChartAnnotation>[
  133. CircularChartAnnotation(
  134. widget: Container(
  135. child: Column(
  136. mainAxisSize: MainAxisSize.min,
  137. crossAxisAlignment: CrossAxisAlignment.center,
  138. children: [
  139. Row(
  140. mainAxisAlignment: MainAxisAlignment.center,
  141. crossAxisAlignment: CrossAxisAlignment.end,
  142. children: [
  143. Obx(() {
  144. return Text(
  145. controller.usedSpacePercentage.toStringAsFixed(0),
  146. textAlign: TextAlign.end,
  147. style: TextStyle(
  148. color: Colors.white
  149. .withValues(alpha: 0.8999999761581421),
  150. fontSize: 30.sp,
  151. height: 1,
  152. fontWeight: FontWeight.w400,
  153. ),
  154. );
  155. }),
  156. Text(
  157. '%',
  158. textAlign: TextAlign.end,
  159. style: TextStyle(
  160. color: Colors.white
  161. .withValues(alpha: 0.8999999761581421),
  162. fontSize: 14.87.r,
  163. fontWeight: FontWeight.w500,
  164. ),
  165. ),
  166. ],
  167. ),
  168. Text(
  169. 'used',
  170. textAlign: TextAlign.center,
  171. style: TextStyle(
  172. color: Colors.white.withValues(
  173. alpha: 0.6000000238418579),
  174. fontSize: 14.87.r,
  175. height: 1,
  176. fontWeight: FontWeight.w500,
  177. ),
  178. )
  179. ],
  180. )),
  181. horizontalAlignment: ChartAlignment.center,
  182. verticalAlignment: ChartAlignment.center,
  183. radius: '0%',
  184. ),
  185. ],
  186. );
  187. }),
  188. );
  189. }
  190. Widget storageInfoCard() {
  191. return Column(
  192. crossAxisAlignment: CrossAxisAlignment.start,
  193. children: [
  194. SizedBox(
  195. height: 24.h,
  196. ),
  197. Text(
  198. 'Storage Used',
  199. style: TextStyle(
  200. color: Colors.white,
  201. fontSize: 16.sp,
  202. fontWeight: FontWeight.w500,
  203. ),
  204. ),
  205. Row(
  206. children: [
  207. Obx(() {
  208. return Text.rich(
  209. TextSpan(
  210. children: [
  211. TextSpan(
  212. text: controller.usedSpace.toStringAsFixed(1),
  213. style: TextStyle(
  214. color: Color(0xFFFC4C4F),
  215. fontSize: 13.sp,
  216. fontWeight: FontWeight.w400,
  217. ),
  218. ),
  219. TextSpan(
  220. text: 'GB',
  221. style: TextStyle(
  222. color: Color(0xFFFC4C4F),
  223. fontSize: 13.sp,
  224. fontWeight: FontWeight.w500,
  225. ),
  226. ),
  227. ],
  228. ),
  229. textAlign: TextAlign.center,
  230. );
  231. }),
  232. Text(
  233. ' / ',
  234. style: TextStyle(
  235. color: Colors.white.withValues(alpha: 0.6000000238418579),
  236. fontSize: 13.sp,
  237. fontWeight: FontWeight.w500,
  238. ),
  239. ),
  240. Obx(() {
  241. return Text.rich(
  242. TextSpan(
  243. children: [
  244. TextSpan(
  245. text: controller.totalSpace.toStringAsFixed(1),
  246. style: TextStyle(
  247. color:
  248. Colors.white.withValues(alpha: 0.6000000238418579),
  249. fontSize: 13.sp,
  250. fontWeight: FontWeight.w400,
  251. ),
  252. ),
  253. TextSpan(
  254. text: 'GB',
  255. style: TextStyle(
  256. color:
  257. Colors.white.withValues(alpha: 0.6000000238418579),
  258. fontSize: 13.sp,
  259. fontWeight: FontWeight.w500,
  260. ),
  261. ),
  262. ],
  263. ),
  264. textAlign: TextAlign.center,
  265. );
  266. }),
  267. ],
  268. ),
  269. SizedBox(
  270. height: 10.h,
  271. ),
  272. Row(
  273. crossAxisAlignment: CrossAxisAlignment.start,
  274. children: [
  275. Container(
  276. margin: EdgeInsets.only(top: 7.h),
  277. width: 6.w,
  278. height: 6.h,
  279. decoration: ShapeDecoration(
  280. color: Color(0xFF0279FB),
  281. shape: OvalBorder(),
  282. ),
  283. ),
  284. SizedBox(
  285. width: 3.5.w,
  286. ),
  287. Column(
  288. crossAxisAlignment: CrossAxisAlignment.start,
  289. children: [
  290. Text(
  291. 'Photos',
  292. textAlign: TextAlign.start,
  293. style: TextStyle(
  294. color: Colors.white,
  295. fontSize: 14.sp,
  296. fontWeight: FontWeight.w500,
  297. ),
  298. ),
  299. Obx(() {
  300. return Text(
  301. '${controller.photoSpace.toStringAsFixed(1)} GB',
  302. textAlign: TextAlign.start,
  303. style: TextStyle(
  304. color: Colors.white.withValues(alpha: 0.6499999761581421),
  305. fontSize: 13.sp,
  306. fontWeight: FontWeight.w400,
  307. ),
  308. );
  309. }),
  310. ],
  311. ),
  312. SizedBox(
  313. width: 10.w,
  314. ),
  315. Container(
  316. margin: EdgeInsets.only(top: 7.h),
  317. width: 6.w,
  318. height: 6.h,
  319. decoration: ShapeDecoration(
  320. color: Color(0xFFEE4933),
  321. shape: OvalBorder(),
  322. ),
  323. ),
  324. SizedBox(
  325. width: 3.5.w,
  326. ),
  327. Column(
  328. crossAxisAlignment: CrossAxisAlignment.start,
  329. children: [
  330. Text(
  331. 'iphone',
  332. textAlign: TextAlign.start,
  333. style: TextStyle(
  334. color: Colors.white,
  335. fontSize: 14.sp,
  336. fontWeight: FontWeight.w500,
  337. ),
  338. ),
  339. Obx(() {
  340. return Text(
  341. '${controller.usedSpace.toStringAsFixed(1)} GB',
  342. textAlign: TextAlign.start,
  343. style: TextStyle(
  344. color: Colors.white.withValues(alpha: 0.6499999761581421),
  345. fontSize: 13.sp,
  346. fontWeight: FontWeight.w400,
  347. ),
  348. );
  349. }),
  350. ],
  351. ),
  352. ],
  353. ),
  354. ],
  355. );
  356. }
  357. Widget similarCard() {
  358. return Container(
  359. width: 328.w,
  360. height: 155.h,
  361. margin: EdgeInsets.only(top: 20.h),
  362. padding: EdgeInsets.symmetric(horizontal: 16.w),
  363. decoration: ShapeDecoration(
  364. color: Colors.white.withValues(alpha: 0.11999999731779099),
  365. shape: RoundedRectangleBorder(
  366. borderRadius: BorderRadius.circular(16.r),
  367. ),
  368. ),
  369. child: Column(
  370. crossAxisAlignment: CrossAxisAlignment.start,
  371. children: [
  372. SizedBox(height: 12.h),
  373. Row(
  374. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  375. children: [
  376. Column(
  377. crossAxisAlignment: CrossAxisAlignment.start,
  378. children: [
  379. Text(
  380. 'Similar',
  381. style: TextStyle(
  382. color: Colors.white,
  383. fontSize: 16.sp,
  384. fontWeight: FontWeight.w700,
  385. ),
  386. ),
  387. Text.rich(
  388. TextSpan(
  389. children: [
  390. TextSpan(
  391. text: '800',
  392. style: TextStyle(
  393. color: Colors.white,
  394. fontSize: 12.sp,
  395. fontWeight: FontWeight.w400,
  396. ),
  397. ),
  398. TextSpan(
  399. text: ' duplicate photos detected',
  400. style: TextStyle(
  401. color: Colors.white
  402. .withValues(alpha: 0.800000011920929),
  403. fontSize: 12.sp,
  404. fontWeight: FontWeight.w400,
  405. ),
  406. ),
  407. ],
  408. ),
  409. ),
  410. ],
  411. ),
  412. CleanUpButton(
  413. label: 'Clean up',
  414. size: '0 GB',
  415. onTap: () {
  416. controller.similarCleanClick();
  417. },
  418. ),
  419. ],
  420. ),
  421. // SizedBox(height: 19.h),
  422. Spacer(),
  423. Obx(() {
  424. return Row(
  425. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  426. children: List.generate(4, (index) {
  427. return ImageContainer(
  428. imagePath: controller.similarImages[index], // 可以传入不同的路径
  429. size: 70.w,
  430. );
  431. }),
  432. );
  433. }),
  434. Spacer(),
  435. ],
  436. ),
  437. );
  438. }
  439. Widget quickPhotoCard() {
  440. return Container(
  441. padding: EdgeInsets.symmetric(horizontal: 16.w),
  442. margin: EdgeInsets.only(top: 30.h),
  443. alignment: Alignment.centerLeft,
  444. child: Text(
  445. 'Quick Photo Clean',
  446. style: TextStyle(
  447. color: Colors.white,
  448. fontSize: 18.sp,
  449. fontWeight: FontWeight.w700,
  450. ),
  451. ),
  452. );
  453. }
  454. Widget peopleCard() {
  455. return Container(
  456. margin: EdgeInsets.only(top: 12.h),
  457. width: 328.w,
  458. height: 205.h,
  459. decoration: ShapeDecoration(
  460. color: Colors.white.withValues(alpha: 0.12),
  461. shape: RoundedRectangleBorder(
  462. borderRadius: BorderRadius.circular(14.sp),
  463. ),
  464. ),
  465. child: Stack(
  466. children: [
  467. Column(
  468. crossAxisAlignment: CrossAxisAlignment.start,
  469. children: [
  470. Spacer(),
  471. Padding(
  472. padding: EdgeInsets.only(left: 14.0.w),
  473. child: Text(
  474. 'People',
  475. style: TextStyle(
  476. color: Colors.white,
  477. fontSize: 16.sp,
  478. fontWeight: FontWeight.w700,
  479. ),
  480. ),
  481. ),
  482. Spacer(),
  483. Row(
  484. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  485. children: List.generate(2, (index) {
  486. return ImageContainer(
  487. imagePath: 'iconHomeNoPhoto',
  488. size: 146.w,
  489. );
  490. }),
  491. ),
  492. Spacer(),
  493. ],
  494. ),
  495. Positioned(
  496. bottom: 20.h,
  497. right: 20.w,
  498. child: CleanUpButton(
  499. label: 'Clean up',
  500. size: '0 GB',
  501. onTap: () {
  502. controller.peopleCleanClick();
  503. },
  504. ),
  505. ),
  506. ],
  507. ),
  508. );
  509. }
  510. Widget locationsCard() {
  511. return Container(
  512. padding: EdgeInsets.symmetric(horizontal: 12.w),
  513. margin: EdgeInsets.only(top: 14.h),
  514. width: 328.w,
  515. height: 230.h,
  516. decoration: ShapeDecoration(
  517. color: Colors.white.withValues(alpha: 0.12),
  518. shape: RoundedRectangleBorder(
  519. borderRadius: BorderRadius.circular(14.sp),
  520. ),
  521. ),
  522. child: Stack(
  523. children: [
  524. Column(
  525. crossAxisAlignment: CrossAxisAlignment.start,
  526. children: [
  527. Spacer(),
  528. Text(
  529. 'Locations',
  530. style: TextStyle(
  531. color: Colors.white,
  532. fontSize: 16.sp,
  533. fontWeight: FontWeight.w700,
  534. ),
  535. ),
  536. Spacer(),
  537. Container(
  538. width: 304.w,
  539. height: 171.h,
  540. decoration: ShapeDecoration(
  541. color: Color(0xFF272C33),
  542. shape: RoundedRectangleBorder(
  543. borderRadius: BorderRadius.circular(12.r),
  544. ),
  545. ),
  546. child: Center(
  547. child: Assets.images.iconHomeNoPhoto.image(
  548. width: 60.w,
  549. height: 60.h,
  550. ),
  551. ),
  552. ),
  553. Spacer(),
  554. ],
  555. ),
  556. Positioned(
  557. bottom: 20.h,
  558. right: 8.w,
  559. child: CleanUpButton(
  560. label: 'Clean up',
  561. size: '0 GB',
  562. onTap: () {
  563. controller.locationCleanClick();
  564. },
  565. ),
  566. ),
  567. ],
  568. ),
  569. );
  570. }
  571. Widget screenshotsAndBlurryCard() {
  572. return Container(
  573. padding: EdgeInsets.symmetric(horizontal: 16.w),
  574. margin: EdgeInsets.only(top: 14.h),
  575. child: Row(
  576. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  577. children: [
  578. _buildCard('Screenshots', 'Clean up', '0 GB', onTap: () {
  579. controller.screenshotCleanClick();
  580. }),
  581. _buildCard('Blurry', 'Clean up', '0 GB', onTap: () {
  582. controller.blurryCleanClick();
  583. }),
  584. ],
  585. ),
  586. );
  587. }
  588. Widget _buildCard(String title, String buttonLabel, String size,
  589. {required Function() onTap}) {
  590. return Stack(
  591. children: [
  592. Container(
  593. width: 160.w,
  594. height: 189.h,
  595. decoration: ShapeDecoration(
  596. color: Colors.white.withValues(alpha: 0.12),
  597. shape: RoundedRectangleBorder(
  598. borderRadius: BorderRadius.circular(14.r),
  599. ),
  600. ),
  601. child: Column(
  602. crossAxisAlignment: CrossAxisAlignment.center,
  603. children: [
  604. Spacer(),
  605. Container(
  606. alignment: Alignment.centerLeft,
  607. padding: EdgeInsets.only(left: 9.w),
  608. child: Text(
  609. title,
  610. style: TextStyle(
  611. color: Colors.white,
  612. fontSize: 16.sp,
  613. fontWeight: FontWeight.w700,
  614. ),
  615. ),
  616. ),
  617. Spacer(),
  618. Container(
  619. width: 144.w,
  620. height: 142.h,
  621. decoration: ShapeDecoration(
  622. color: Color(0xFF272C33),
  623. shape: RoundedRectangleBorder(
  624. borderRadius: BorderRadius.circular(12.r),
  625. ),
  626. ),
  627. child: Center(
  628. child: Assets.images.iconHomeNoPhoto.image(
  629. width: 60.w,
  630. height: 60.h,
  631. ),
  632. ),
  633. ),
  634. Spacer(),
  635. ],
  636. ),
  637. ),
  638. Positioned(
  639. bottom: 16.h,
  640. right: 16.w,
  641. child: CleanUpButton(
  642. label: buttonLabel,
  643. size: size,
  644. onTap: onTap,
  645. ),
  646. ),
  647. ],
  648. );
  649. }
  650. }
  651. class CleanUpButton extends StatelessWidget {
  652. final String label;
  653. final String size;
  654. final Function() onTap;
  655. const CleanUpButton({
  656. super.key,
  657. required this.label,
  658. required this.size,
  659. required this.onTap,
  660. });
  661. @override
  662. Widget build(BuildContext context) {
  663. return Container(
  664. width: 94.w,
  665. height: 44.h,
  666. decoration: ShapeDecoration(
  667. color: Color(0xFF0279FB),
  668. shape: RoundedRectangleBorder(
  669. borderRadius: BorderRadius.circular(10.r),
  670. ),
  671. ),
  672. child: GestureDetector(
  673. onTap: onTap,
  674. child: Row(
  675. mainAxisAlignment: MainAxisAlignment.spaceAround,
  676. children: [
  677. Column(
  678. crossAxisAlignment: CrossAxisAlignment.start,
  679. children: [
  680. Spacer(),
  681. Text(
  682. label,
  683. style: TextStyle(
  684. color: Colors.white,
  685. fontSize: 12.sp,
  686. fontWeight: FontWeight.w400,
  687. ),
  688. ),
  689. Text(
  690. size,
  691. style: TextStyle(
  692. color: Colors.white,
  693. fontSize: 16.sp,
  694. height: 1,
  695. fontWeight: FontWeight.w700,
  696. ),
  697. ),
  698. Spacer(),
  699. ],
  700. ),
  701. Assets.images.iconHomeRightArrow.image(
  702. width: 6.52.w,
  703. height: 6.52.h,
  704. ),
  705. ],
  706. ),
  707. ));
  708. }
  709. }
  710. class ImageContainer extends StatelessWidget {
  711. final String imagePath;
  712. final double size;
  713. const ImageContainer({
  714. super.key,
  715. required this.imagePath,
  716. required this.size,
  717. });
  718. @override
  719. Widget build(BuildContext context) {
  720. return Container(
  721. width: size,
  722. height: size,
  723. decoration: ShapeDecoration(
  724. color: Color(0xFF272C33),
  725. shape: RoundedRectangleBorder(
  726. borderRadius: BorderRadius.circular(12.r),
  727. ),
  728. ),
  729. child: Center(
  730. child: Assets.images.iconHomeNoPhoto.image(
  731. width: size * 0.45, // 图片的大小相对容器
  732. height: size * 0.45,
  733. ),
  734. ),
  735. );
  736. }
  737. }
  738. class PieData {
  739. final String label;
  740. final double value;
  741. final Color color;
  742. PieData(this.label, this.value, this.color);
  743. }