Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
259 changes: 200 additions & 59 deletions frontend/ongi/lib/screens/health/exercise_record_detail_screen.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import '../../core/app_colors.dart';
import 'package:ongi/core/app_colors.dart';
import 'package:ongi/widgets/date_carousel.dart';
import 'package:ongi/widgets/time_grid.dart';

class ExerciseRecordDetailScreen extends StatelessWidget {
class ExerciseRecordDetailScreen extends StatefulWidget {
final DateTime date;
final int hours;
final int minutes;
Expand All @@ -13,90 +15,229 @@ class ExerciseRecordDetailScreen extends StatelessWidget {
required this.minutes,
});

@override
State<ExerciseRecordDetailScreen> createState() =>
_ExerciseRecordDetailScreenState();
}

class _ExerciseRecordDetailScreenState
extends State<ExerciseRecordDetailScreen> {
List<int> selected = [];

String _calExTime(List<int> selectedCells) {
final totalMinutes = selectedCells.length * 10;
final hours = totalMinutes ~/ 60;
final minutes = totalMinutes % 60;

String result = '';
if (hours > 0) {
result += '$hours시간';
if (minutes > 0) {
result += ' $minutes분';
}
} else if (minutes > 0) {
result += '$minutes분';
} else {
result = '0분';
}

return result;
}

// Calculate hours and minutes from selected cells
Map<String, int> _calculateHoursAndMinutes(List<int> selectedCells) {
final totalMinutes = selectedCells.length * 10;
final hours = totalMinutes ~/ 60;
final minutes = totalMinutes % 60;
return {'hours': hours, 'minutes': minutes};
}

// Handle back navigation with exercise time data
void _handleBack() {
final timeData = _calculateHoursAndMinutes(selected);
Navigator.pop(context, timeData);
}

@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
final circleSize = screenWidth * 1.56;

return Scaffold(
backgroundColor: AppColors.ongiLigntgrey,
body: SafeArea(
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.topCenter,
child: Transform.translate(
offset: Offset(0, -circleSize * 0.76),
child: OverflowBox(
maxWidth: double.infinity,
maxHeight: double.infinity,
return PopScope(
canPop: false,
onPopInvoked: (didPop) {
if (!didPop) {
_handleBack();
}
},
child: Scaffold(
backgroundColor: AppColors.ongiLigntgrey,
body: SafeArea(
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.topCenter,
child: Transform.translate(
offset: Offset(0, -circleSize * 0.76),
child: OverflowBox(
maxWidth: double.infinity,
maxHeight: double.infinity,
child: Container(
width: circleSize,
height: circleSize,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.ongiOrange,
),
child: Center(
child: Padding(
padding: EdgeInsets.only(top: circleSize * 0.62),
child: OverflowBox(
maxHeight: double.infinity,
child: Column(
children: [
const Text(
'오늘 목표 운동 시간,',
style: TextStyle(
fontSize: 25,
color: Colors.white,
fontWeight: FontWeight.w600,
height: 1,
),
),
const Text(
'다 채우셨나요?',
style: TextStyle(
fontSize: 40,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
),
),
),
),
),

Positioned(
top: circleSize * 0.5,
left: 0,
right: 0,
bottom: 0,
child: Padding(
padding: const EdgeInsets.only(
left: 15,
right: 15,
bottom: 20,
),
child: Container(
width: circleSize,
height: circleSize,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.ongiOrange,
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: Center(
child: Padding(
padding: EdgeInsets.only(top: circleSize),
child: OverflowBox(
maxHeight: double.infinity,
child: Stack(
children: [
Positioned(
top: 20,
right: 0,
child: SizedBox(
width: 200,
height: 100,
child: DateCarousel(
initialDate: widget.date,
onDateChanged: (selectedDate) {},
),
),
),
Padding(
padding: EdgeInsets.only(left: 25, top: 75),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'오늘 목표 운동 시간,',
'오늘은',
style: TextStyle(
fontSize: 25,
color: Colors.white,
fontSize: 20,
color: AppColors.ongiOrange,
fontWeight: FontWeight.w600,
height: 1,
),
),
const Text(
'다 채우셨나요?',
style: TextStyle(
fontSize: 40,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 6),
child: Image.asset(
'assets/images/exercise_record_title_logo.png',
width: circleSize * 0.3,
RichText(
text: TextSpan(
text: '${_calExTime(selected)} ',
style: TextStyle(
fontSize: 35,
color: AppColors.ongiOrange,
fontWeight: FontWeight.w600,
),
children: [
TextSpan(
text: '운동했어요!',
style: TextStyle(
fontSize: 20,
color: AppColors.ongiOrange,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
),
),
Positioned(
top: 160,
left: 7,
right: 7,
bottom: 20,
child: Center(
child: TimeGrid(
initialSelected: selected,
cellColor: Colors.white,
cellSelectedColor: AppColors.ongiOrange,
borderColor: AppColors.ongiOrange,
onValueChanged: (newList) {
setState(() => selected = newList);
},
),
),
),
],
),
),
),
),
),
Positioned(
top: circleSize * 0.5,
left: 0,
right: 0,
child: Center(
Positioned(
top: circleSize * 0.23,
left: 0,
right: 0,
child: Center(
child: Container(
margin: const EdgeInsets.symmetric(vertical: 6),
child: Image.asset(
'assets/images/exercise_record_title_logo.png',
width: circleSize * 0.23,
),
),
),
),
),
// Back button
Positioned(
top: 16,
left: 16,
child: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context),
Positioned(
top: 16,
left: 16,
child: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: _handleBack,
),
),
),
],
],
),
),
),
);
}
}
}
28 changes: 23 additions & 5 deletions frontend/ongi/lib/screens/health/exercise_record_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@ class _ExerciseRecordScreenState extends State<ExerciseRecordScreen> {
bool _isSwipeTriggered =
false; // Prevent button callback when triggered by swipe

// Get exercise time for a specific date (placeholder: returns 0)
// Store exercise times for different dates
Map<String, Map<String, int>> exerciseTimes = {};

// Get exercise time for a specific date
Map<String, int> getExerciseTime(DateTime date) {
// TODO: Replace with real backend call
return {'hours': 1, 'minutes': 30};
final dateKey = "${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}";
return exerciseTimes[dateKey] ?? {'hours': 0, 'minutes': 0};
}

// Save exercise time for a specific date
void saveExerciseTime(DateTime date, int hours, int minutes) {
final dateKey = "${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}";
setState(() {
exerciseTimes[dateKey] = {'hours': hours, 'minutes': minutes};
});
}

// Convert page index to date for exercise PageView
Expand Down Expand Up @@ -149,8 +160,8 @@ class _ExerciseRecordScreenState extends State<ExerciseRecordScreen> {
getExerciseTime(date);

return GestureDetector(
onTap: () {
Navigator.push(
onTap: () async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
Expand All @@ -165,6 +176,13 @@ class _ExerciseRecordScreenState extends State<ExerciseRecordScreen> {
),
),
);

// Handle returned exercise time data
if (result != null && result is Map<String, dynamic>) {
final returnedHours = result['hours'] as int;
final returnedMinutes = result['minutes'] as int;
saveExerciseTime(date, returnedHours, returnedMinutes);
}
},
child: Padding(
padding:
Expand Down
Loading
Loading