Skip to content

Commit 0b5ae98

Browse files
authored
feat: 온도 그래프 수정 및 자녀 화면 사이드바/건강기록 구현 (#143)
* fix: 마음기록 입력 화면 뒤로가기 타화면과 통일 * fix: 온도그래프 수정 * fix: 온도그래프 수정 * fix: 약 사이드바 연결 지연 업그레이드 * fix: 온도그래프 오류 수정 * fix: 온도그래프 오류 수정 * fix: 오류 수정 * feat: 자녀화면 건강기록 세부 * feat: 자녀화면 사이드바 구현
1 parent 44c0648 commit 0b5ae98

File tree

7 files changed

+443
-123
lines changed

7 files changed

+443
-123
lines changed

frontend/ongi/lib/screens/health/add_pill_screen.dart

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,22 @@ class _AddPillScreenState extends State<AddPillScreen> {
260260
);
261261

262262
if (!mounted) return;
263-
Navigator.pushReplacement(
264-
context,
265-
MaterialPageRoute(builder: (context) => const PillUpdatePopup()),
266-
);
263+
264+
// 즉시 홈으로 돌아가면서 성공 결과 전달
265+
Navigator.pop(context, true);
266+
267+
// 성공 팝업을 약간 지연 후 표시 (홈 화면이 먼저 업데이트되도록)
268+
Future.delayed(const Duration(milliseconds: 100), () {
269+
if (!mounted) return;
270+
showDialog(
271+
context: context,
272+
barrierDismissible: true,
273+
builder: (BuildContext context) => Dialog(
274+
backgroundColor: Colors.transparent,
275+
child: const PillUpdatePopup(),
276+
),
277+
);
278+
});
267279
} catch (e) {
268280
if (!mounted) return;
269281
ScaffoldMessenger.of(

frontend/ongi/lib/screens/health/exercise_record_screen.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class _ExerciseRecordScreenState extends State<ExerciseRecordScreen> {
235235
_dateCarouselController.jumpToPage(targetPage);
236236
}
237237

238-
// 새로운 날짜의 서버 데이터 조회
238+
//새로운 날짜의 서버 데이터 조회
239239
_loadExerciseFromServer(normalizedDate);
240240

241241
Future.delayed(const Duration(milliseconds: 100), () {
@@ -642,9 +642,9 @@ class _ExerciseRecordScreenState extends State<ExerciseRecordScreen> {
642642
height: 1,
643643
),
644644
),
645-
const Text(
646-
'다 채우셨나요?',
647-
style: TextStyle(
645+
Text(
646+
_isChild ? '다 채우셨을까요?' : '다 채우셨나요?',
647+
style: const TextStyle(
648648
fontSize: 40,
649649
color: Colors.white,
650650
fontWeight: FontWeight.w600,

frontend/ongi/lib/screens/health/health_home_screen.dart

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ class _HealthHomeScreenState extends State<HealthHomeScreen> {
410410
),
411411
SizedBox(height: 3),
412412
Text(
413-
'입력되지 않았어요!',
413+
'입력되지 \n않았어요!',
414414
style: TextStyle(
415415
fontSize: 38,
416416
fontWeight: FontWeight.w600,
@@ -539,54 +539,65 @@ class _HealthHomeScreenState extends State<HealthHomeScreen> {
539539
if (_isChild && !_isLoadingParents) {
540540
// 자녀인 경우 드롭다운 표시
541541
return Row(
542+
crossAxisAlignment: CrossAxisAlignment.center,
542543
children: [
543-
Container(
544-
decoration: BoxDecoration(
545-
color: Colors.white,
546-
borderRadius: BorderRadius.circular(25),
547-
boxShadow: [
548-
BoxShadow(
549-
color: Colors.black38,
550-
blurRadius: 4,
551-
offset: const Offset(0, 4),
552-
),
553-
],
554-
),
555-
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
556-
child: DropdownButtonHideUnderline(
557-
child: DropdownButton<String>(
558-
value: _selectedParentId,
559-
icon: const SizedBox.shrink(),
560-
dropdownColor: Colors.white,
561-
isDense: false,
562-
itemHeight: 65,
563-
borderRadius: BorderRadius.circular(20),
564-
style: const TextStyle(
565-
fontSize: 60,
566-
fontWeight: FontWeight.w800,
567-
color: AppColors.ongiOrange,
568-
),
569-
items: _parentMembers.map((parent) {
570-
return DropdownMenuItem<String>(
571-
value: parent['uuid'],
572-
child: Text(
573-
_formatNameForDisplay(parent['name']),
574-
style: const TextStyle(
575-
fontSize: 60,
576-
fontWeight: FontWeight.w800,
577-
color: AppColors.ongiOrange,
544+
Flexible(
545+
child: Container(
546+
decoration: BoxDecoration(
547+
color: Colors.white,
548+
borderRadius: BorderRadius.circular(25),
549+
boxShadow: [
550+
BoxShadow(
551+
color: Colors.black38,
552+
blurRadius: 4,
553+
offset: const Offset(0, 4),
554+
),
555+
],
556+
),
557+
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
558+
child: DropdownButtonHideUnderline(
559+
child: DropdownButton<String>(
560+
value: _selectedParentId,
561+
icon: const SizedBox.shrink(),
562+
dropdownColor: Colors.white,
563+
isDense: false,
564+
itemHeight: 80, // 높이 증가로 폰트 클리핑 방지
565+
borderRadius: BorderRadius.circular(20),
566+
isExpanded: false, // 내용에 맞는 너비
567+
style: const TextStyle(
568+
fontSize: 60,
569+
fontWeight: FontWeight.w800,
570+
color: AppColors.ongiOrange,
571+
height: 1.1, // 줄 높이 조정으로 클리핑 방지
572+
),
573+
items: _parentMembers.map((parent) {
574+
return DropdownMenuItem<String>(
575+
value: parent['uuid'],
576+
child: Container(
577+
alignment: Alignment.centerLeft,
578+
child: Text(
579+
_formatNameForDisplay(parent['name']),
580+
style: const TextStyle(
581+
fontSize: 60,
582+
fontWeight: FontWeight.w800,
583+
color: AppColors.ongiOrange,
584+
height: 1.1, // 줄 높이 조정
585+
),
586+
overflow: TextOverflow.ellipsis,
587+
),
578588
),
579-
),
580-
);
581-
}).toList(),
582-
onChanged: (String? newValue) {
583-
if (newValue != null) {
584-
_onParentSelected(newValue);
585-
}
586-
},
589+
);
590+
}).toList(),
591+
onChanged: (String? newValue) {
592+
if (newValue != null) {
593+
_onParentSelected(newValue);
594+
}
595+
},
596+
),
587597
),
588598
),
589599
),
600+
const SizedBox(width: 8), // 간격 추가
590601
const Text(
591602
'님의',
592603
style: TextStyle(

frontend/ongi/lib/screens/health/pill_history_screen.dart

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
2828
// 자녀 사용자 관련 상태
2929
bool _isChild = false;
3030
String? _selectedParentId;
31+
32+
// 약 복용 상태 관련
33+
int _todayPillCount = 0;
3134

3235
@override
3336
void initState() {
@@ -83,16 +86,41 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
8386
taken.add('$pillId|$hhmm');
8487
}
8588
}
89+
// 약 복용 카운트 계산
90+
int totalIntakes = 0;
91+
int takenIntakes = 0;
92+
93+
for (var pill in schedule) {
94+
final List<dynamic> intakeTimes = pill['intakeTimes'] ?? [];
95+
final Map<String, dynamic> dayIntakeStatus = pill['dayIntakeStatus'] ?? {};
96+
97+
totalIntakes += intakeTimes.length;
98+
99+
// dayIntakeStatus에서 실제 복용한 시간들을 확인
100+
for (var intakeTime in intakeTimes) {
101+
final timeKey = intakeTime.toString().substring(0, 5); // "08:00:00" -> "08:00"
102+
if (dayIntakeStatus.containsKey(timeKey)) {
103+
takenIntakes++;
104+
}
105+
}
106+
}
107+
108+
// 남은 복용 횟수
109+
int remainingIntakes = totalIntakes - takenIntakes;
110+
if (remainingIntakes < 0) remainingIntakes = 0;
111+
86112
setState(() {
87113
_todaySchedule = schedule;
88114
_takenKeys
89115
..clear()
90116
..addAll(taken);
117+
_todayPillCount = remainingIntakes;
91118
_isLoading = false;
92119
});
93120
} catch (e) {
94121
setState(() {
95122
_todaySchedule = <Map<String, dynamic>>[];
123+
_todayPillCount = 0;
96124
_isLoading = false;
97125
});
98126
}
@@ -122,6 +150,54 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
122150
}
123151
}
124152

153+
Widget _buildPillStatusText() {
154+
if (_todayPillCount == 0) {
155+
return const Column(
156+
children: [
157+
Text(
158+
'오늘의 약을',
159+
style: TextStyle(
160+
fontSize: 25,
161+
color: Colors.white,
162+
fontWeight: FontWeight.w600,
163+
height: 1,
164+
),
165+
),
166+
Text(
167+
'모두 섭취하셨어요!',
168+
style: TextStyle(
169+
fontSize: 40,
170+
color: Colors.white,
171+
fontWeight: FontWeight.w600,
172+
),
173+
),
174+
],
175+
);
176+
} else {
177+
return Column(
178+
children: [
179+
Text(
180+
_isChild ? '오늘 ${_todayPillCount}개의 약을' : '오늘 복용해야 할 약,',
181+
style: const TextStyle(
182+
fontSize: 25,
183+
color: Colors.white,
184+
fontWeight: FontWeight.w600,
185+
height: 1,
186+
),
187+
),
188+
Text(
189+
_isChild ? '섭취하지 않으셨어요!' : '다 섭취 하셨나요?',
190+
style: const TextStyle(
191+
fontSize: 40,
192+
color: Colors.white,
193+
fontWeight: FontWeight.w600,
194+
),
195+
),
196+
],
197+
);
198+
}
199+
}
200+
125201
Future<void> _addRecord({
126202
required String pillId,
127203
required String intakeTime,
@@ -131,6 +207,7 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
131207
// 즉시 UI 업데이트 (서버 응답 전)
132208
setState(() {
133209
_takenKeys.add(key);
210+
if (_todayPillCount > 0) _todayPillCount--;
134211
});
135212

136213
try {
@@ -159,6 +236,7 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
159236
// 서버 요청 실패 시 UI 상태 롤백
160237
setState(() {
161238
_takenKeys.remove(key);
239+
_todayPillCount++;
162240
});
163241
ScaffoldMessenger.of(context).showSnackBar(
164242
SnackBar(
@@ -186,6 +264,7 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
186264
// 즉시 UI 업데이트 (서버 응답 전)
187265
setState(() {
188266
_takenKeys.remove(key);
267+
_todayPillCount++;
189268
});
190269

191270
try {
@@ -214,6 +293,7 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
214293
// 서버 요청 실패 시 UI 상태 롤백
215294
setState(() {
216295
_takenKeys.add(key);
296+
if (_todayPillCount > 0) _todayPillCount--;
217297
});
218298
ScaffoldMessenger.of(context).showSnackBar(
219299
SnackBar(
@@ -264,23 +344,7 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
264344
maxHeight: double.infinity,
265345
child: Column(
266346
children: [
267-
const Text(
268-
'오늘 복용해야 할 약,',
269-
style: TextStyle(
270-
fontSize: 25,
271-
color: Colors.white,
272-
fontWeight: FontWeight.w600,
273-
height: 1,
274-
),
275-
),
276-
const Text(
277-
'다 섭취 하셨나요?',
278-
style: TextStyle(
279-
fontSize: 40,
280-
color: Colors.white,
281-
fontWeight: FontWeight.w600,
282-
),
283-
),
347+
_buildPillStatusText(),
284348
Image.asset(
285349
'assets/images/pill_history_title_logo.png',
286350
width: circleSize * 0.26,
@@ -314,17 +378,22 @@ class _PillHistoryScreenState extends State<PillHistoryScreen> {
314378
itemBuilder: (context, index) {
315379
if (index == _todaySchedule.length) {
316380
return GestureDetector(
317-
onTap: () {
318-
Navigator.push(
381+
onTap: () async {
382+
final result = await Navigator.push(
319383
context,
320384
MaterialPageRoute(
321385
builder: (context) => AddPillScreen(
322386
targetParentId: _selectedParentId,
323387
),
324388
),
325-
).then((_) {
389+
);
390+
391+
// 약 추가 성공 시 즉시 새로고침
392+
if (result == true) {
393+
print('약 추가 성공 - 즉시 데이터 새로고침');
394+
// 즉시 새로고침
326395
_fetchTodaySchedule();
327-
});
396+
}
328397
},
329398
child: Container(
330399
margin: const EdgeInsets.symmetric(

0 commit comments

Comments
 (0)