11import 'package:flutter/material.dart' ;
22import 'package:ongi/core/app_colors.dart' ;
33import 'package:flutter_svg/flutter_svg.dart' ;
4+ import 'package:ongi/widgets/custom_chart_painter.dart' ;
45
56class HomeCapsuleSection extends StatelessWidget {
67 const HomeCapsuleSection ({super .key});
78
89 @override
910 Widget build (BuildContext context) {
1011 return Expanded (
11- child: Row (
12- crossAxisAlignment: CrossAxisAlignment .center,
12+ child: Stack (
1313 children: [
14- Expanded (
15- flex: 2 ,
16- child: Align (
17- alignment: Alignment .centerRight,
18- // 도넛 위치
14+ // 도넛 차트 영역
15+ Positioned (
16+ left: 0 ,
17+ bottom: MediaQuery .of (context).size.height * 0.05 ,
18+ width: MediaQuery .of (context).size.width * 0.95 ,
19+ height: MediaQuery .of (context).size.width * 0.95 ,
20+ child: Stack (
21+ clipBehavior: Clip .none,
22+ children: [
23+ Align (
24+ alignment: Alignment .centerLeft,
25+ child: Transform .translate (
26+ offset: Offset (- MediaQuery .of (context).size.width * 0.35 , 0 ), // 왼쪽으로 이동
27+ child: OverflowBox (
28+ maxWidth: double .infinity,
29+ maxHeight: double .infinity,
30+ child: CustomPaint (
31+ painter: CustomChartPainter (
32+ percentages: [15 , 10 , 20 , 20 ],
33+ ),
34+ size: Size (
35+ MediaQuery .of (context).size.width * 0.95 ,
36+ MediaQuery .of (context).size.width * 0.95 ,
37+ ),
38+ ),
39+ ),
40+ ),
41+ ),
42+ // 텍스트 (화면 안에 있음)
43+ Positioned (
44+ left: MediaQuery .of (context).size.width * 0.05 , // 도넛 차트 중심에 맞춰 조정
45+ top: 0 ,
46+ bottom: 0 ,
47+ child: Center (
48+ child: Row (
49+ crossAxisAlignment: CrossAxisAlignment .end,
50+ children: [
51+ Text (
52+ '36.5' ,
53+ style: TextStyle (
54+ fontSize: 43 ,
55+ fontWeight: FontWeight .w800,
56+ color: AppColors .ongiOrange,
57+ height: 1 ,
58+ ),
59+ ),
60+ Text (
61+ '℃' ,
62+ style: TextStyle (
63+ fontSize: 24 ,
64+ fontWeight: FontWeight .w800,
65+ color: AppColors .ongiOrange,
66+ ),
67+ ),
68+ ],
69+ ),
70+ ),
71+ ),
72+ ],
1973 ),
2074 ),
21- Expanded (
22- flex: 2 ,
23- child: Padding (
24- padding: EdgeInsets .only (
25- top: MediaQuery .of (context).size.height * 0.17
26- ),
27-
28- child: Transform .translate (
29-
30- offset: Offset (MediaQuery .of (context).size.width * 0.35 , 0 ),
31- child: ButtonColumn (),
32- ),
33- ),
75+ Positioned (
76+ right: 0 ,
77+ bottom: MediaQuery .of (context).size.height * 0.05 ,
78+ child: ButtonColumn (),
3479 ),
3580 ],
3681 ),
3782 );
3883 }
3984}
4085
41-
4286class CapsuleButton extends StatelessWidget {
4387 final String svgAsset;
4488 final bool selected;
@@ -57,56 +101,58 @@ class CapsuleButton extends StatelessWidget {
57101 Widget build (BuildContext context) {
58102 return GestureDetector (
59103 onTap: onTap,
60- child: FractionallySizedBox (
61- widthFactor: selected ? 2.9 : 1.0 , // 선택 시 2.8배, 아니면 1.0배
62- alignment: Alignment .centerRight,
63- child: AnimatedContainer (
64- duration: const Duration (milliseconds: 200 ),
65- height: 68 ,
66- margin: const EdgeInsets .symmetric (vertical: 2 ),
67- decoration: BoxDecoration (
68- color: selected ? AppColors .ongiOrange : Colors .white,
69- border: Border .all (
70- color: AppColors .ongiOrange,
71- width: 2 ,
72- ),
73- borderRadius: BorderRadius .circular (39 ),
74- boxShadow: selected
75- ? [
76- BoxShadow (
77- color: AppColors .ongiOrange,
78- offset: Offset (0 , 4 ),
79- ),
80- ]
81- : [],
104+ child: AnimatedContainer (
105+ duration: const Duration (milliseconds: 250 ),
106+ curve: Curves .easeInOut,
107+ height: MediaQuery .of (context).size.width * 0.18 ,
108+ width: selected ? MediaQuery .of (context).size.width * 0.9 : MediaQuery .of (context).size.width * 0.17 ,
109+ margin: const EdgeInsets .only (top: 2 , bottom: 2 , left: 0 , right: 0 ),
110+ decoration: BoxDecoration (
111+ color: selected ? AppColors .ongiOrange : AppColors .ongiLigntgrey,
112+ border: Border (
113+ top: BorderSide (color: AppColors .ongiOrange, width: 2 ),
114+ bottom: BorderSide (color: AppColors .ongiOrange, width: 2 ),
115+ left: BorderSide (color: AppColors .ongiOrange, width: 2 ),
116+ right: BorderSide .none, // 오른쪽 테두리 제거
82117 ),
83- child: Row (
84- children: [
85- const SizedBox (width: 20 ),
86- SvgPicture .asset (
87- svgAsset,
88- width: MediaQuery .of (context).size.width * 0.07 ,
89- height: MediaQuery .of (context).size.width * 0.07 ,
90- colorFilter: ColorFilter .mode (
91- selected ? Colors .white : AppColors .ongiOrange,
92- BlendMode .srcIn,
93- ),
118+ borderRadius: BorderRadius .only (
119+ topLeft: Radius .circular (39 ),
120+ bottomLeft: Radius .circular (39 ),
121+ topRight: Radius .circular (0 ),
122+ bottomRight: Radius .circular (0 ),
123+ ),
124+ boxShadow: selected
125+ ? [BoxShadow (color: AppColors .ongiOrange, offset: Offset (0 , 4 ))]
126+ : [],
127+ ),
128+ child: Row (
129+ children: [
130+ const SizedBox (width: 20 ),
131+ SvgPicture .asset (
132+ svgAsset,
133+ width: MediaQuery .of (context).size.width * 0.07 ,
134+ height: MediaQuery .of (context).size.width * 0.07 ,
135+ colorFilter: ColorFilter .mode (
136+ selected ? Colors .white : AppColors .ongiOrange,
137+ BlendMode .srcIn,
94138 ),
139+ ),
140+ if (selected && notificationText.isNotEmpty) ...[
95141 const SizedBox (width: 20 ),
96142 Expanded (
97143 child: Text (
98144 notificationText,
99145 overflow: TextOverflow .ellipsis,
100- // textAlign: TextAlign.center,
146+ textAlign: TextAlign .center, // 텍스트 중앙 정렬
101147 style: TextStyle (
102- color: selected ? Colors .white : AppColors .ongiOrange ,
148+ color: Colors .white,
103149 fontWeight: FontWeight .w600,
104- fontSize: 20 ,
150+ fontSize: 22 ,
105151 ),
106152 ),
107153 ),
108154 ],
109- ) ,
155+ ] ,
110156 ),
111157 ),
112158 );
@@ -115,42 +161,48 @@ class CapsuleButton extends StatelessWidget {
115161
116162class ButtonColumn extends StatefulWidget {
117163 const ButtonColumn ({super .key});
164+
118165 @override
119166 State <ButtonColumn > createState () => _ButtonColumnState ();
120167}
121168
122169class _ButtonColumnState extends State <ButtonColumn > {
123- int selectedIdx = 0 ;
170+ int selectedIdx = - 1 ; // 초기값을 -1로 변경 (아무것도 선택되지 않은 상태)
124171
125172 @override
126173 Widget build (BuildContext context) {
127174 return SizedBox (
128175 child: Column (
129176 mainAxisAlignment: MainAxisAlignment .end,
130177 mainAxisSize: MainAxisSize .min, // overflow 방지
178+ crossAxisAlignment: CrossAxisAlignment .end, // 오른쪽 정렬
131179 children: [
132180 CapsuleButton (
133181 svgAsset: 'assets/images/homebar_capsule.svg' ,
134182 selected: selectedIdx == 0 ,
135- onTap: () => setState (() => selectedIdx = 0 ),
136- notificationText: selectedIdx == 0 ? '23분 뒤, 이부프로펜 1알 섭취 예정' : '알림이 없어요' ,
183+ onTap: () => setState (() => selectedIdx = selectedIdx == 0 ? - 1 : 0 ),
184+ notificationText: selectedIdx == 0
185+ ? '23분 뒤, 이부프로펜 1알 섭취 예정'
186+ : '' ,
137187 ),
138188 const SizedBox (height: 8 ),
139189 CapsuleButton (
140190 svgAsset: 'assets/images/homebar_med.svg' ,
141191 selected: selectedIdx == 1 ,
142- onTap: () => setState (() => selectedIdx = 1 ),
143- notificationText: selectedIdx == 1 ? '오늘의 통증 부위: 허리, 오른쪽 무릎' : '알림이 없어요' ,
192+ onTap: () => setState (() => selectedIdx = selectedIdx == 1 ? - 1 : 1 ),
193+ notificationText: selectedIdx == 1
194+ ? '오늘의 통증 부위: 허리, 오른쪽 무릎'
195+ : '' ,
144196 ),
145197 const SizedBox (height: 8 ),
146198 CapsuleButton (
147199 svgAsset: 'assets/images/homebar_walk.svg' ,
148200 selected: selectedIdx == 2 ,
149- onTap: () => setState (() => selectedIdx = 2 ),
150- notificationText: selectedIdx == 2 ? '12,000 걸음' : '알림이 없어요 ' ,
201+ onTap: () => setState (() => selectedIdx = selectedIdx == 2 ? - 1 : 2 ),
202+ notificationText: selectedIdx == 2 ? '12,000 걸음' : '' ,
151203 ),
152204 ],
153205 ),
154206 );
155207 }
156- }
208+ }
0 commit comments