Files
trainhub-flutter/lib/presentation/calendar/widgets/program_week_view.dart
Kazimierz Ciołek 782986a632 Initial commit
2026-02-19 02:49:29 +01:00

245 lines
9.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:trainhub_flutter/core/utils/id_generator.dart';
import 'package:trainhub_flutter/domain/entities/program_week.dart';
import 'package:trainhub_flutter/domain/entities/program_workout.dart';
import 'package:trainhub_flutter/domain/entities/training_plan.dart';
class ProgramWeekView extends StatelessWidget {
final ProgramWeekEntity week;
final List<ProgramWorkoutEntity> workouts;
final List<TrainingPlanEntity> availablePlans;
final Function(ProgramWorkoutEntity) onAddWorkout;
final Function(String) onDeleteWorkout;
const ProgramWeekView({
super.key,
required this.week,
required this.workouts,
required this.availablePlans,
required this.onAddWorkout,
required this.onDeleteWorkout,
});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 24),
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Week ${week.position}",
style: Theme.of(context).textTheme.headlineSmall,
),
const Divider(),
SizedBox(
height: 500, // Fixed height for the week grid, or make it dynamic
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: List.generate(7, (dayIndex) {
final dayNum = dayIndex + 1;
final dayWorkouts = workouts
.where((w) => w.day == dayNum.toString())
.toList();
return Expanded(
child: Container(
decoration: BoxDecoration(
border: dayIndex < 6
? const Border(
right: BorderSide(
color: Colors.grey,
width: 0.5,
),
)
: null,
color: dayIndex % 2 == 0
? Theme.of(context).colorScheme.surfaceContainerLow
: null,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Theme.of(
context,
).colorScheme.surfaceContainerHigh,
border: const Border(
bottom: BorderSide(
color: Colors.grey,
width: 0.5,
),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
_getDayName(dayNum),
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
InkWell(
onTap: () =>
_showAddWorkoutSheet(context, dayNum),
borderRadius: BorderRadius.circular(16),
child: const Icon(
Icons.add_circle_outline,
size: 20,
),
),
],
),
),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(4),
child: Column(
children: [
if (dayWorkouts.isEmpty)
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Center(
child: Text(
"Rest",
style: TextStyle(
color: Theme.of(
context,
).colorScheme.onSurfaceVariant,
fontSize: 12,
),
),
),
)
else
...dayWorkouts.map(
(w) => Card(
margin: const EdgeInsets.only(
bottom: 4,
),
child: ListTile(
contentPadding:
const EdgeInsets.symmetric(
horizontal: 8,
vertical: 0,
),
visualDensity: VisualDensity.compact,
title: Text(
w.name ?? 'Untitled',
style: const TextStyle(
fontSize: 12,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
trailing: InkWell(
onTap: () => onDeleteWorkout(w.id),
borderRadius: BorderRadius.circular(
12,
),
child: const Icon(
Icons.close,
size: 14,
),
),
onTap: () {
// Optional: Edit on tap
},
),
),
),
],
),
),
),
],
),
),
);
}),
),
),
],
),
),
);
}
String _getDayName(int day) {
const days = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
if (day >= 1 && day <= 7) return days[day - 1];
return 'Day $day';
}
void _showAddWorkoutSheet(BuildContext context, int dayNum) {
showModalBottomSheet(
context: context,
builder: (context) => Container(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
child: Text(
"Select Training Plan",
style: Theme.of(context).textTheme.titleMedium,
),
),
const Divider(),
if (availablePlans.isEmpty)
const Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: Text("No training plans available. Create one first!"),
),
),
...availablePlans
.map(
(plan) => ListTile(
leading: const Icon(Icons.fitness_center),
title: Text(plan.name),
subtitle: Text("${plan.totalExercises} exercises"),
onTap: () {
final newWorkout = ProgramWorkoutEntity(
id: IdGenerator.generate(),
programId: week.programId,
weekId: week.id,
day: dayNum.toString(),
type: 'workout',
name: plan.name,
refId: plan.id,
description: "${plan.sections.length} sections",
completed: false,
);
onAddWorkout(newWorkout);
Navigator.pop(context);
},
),
)
.toList(),
],
),
),
);
}
}