home_view.dart 25 KB

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