182 lines
5.5 KiB
Dart
182 lines
5.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../../app/app_theme.dart';
|
|
import '../../../l10n/l10n.dart';
|
|
import '../../../models/today_progress.dart';
|
|
import '../../../widgets/surface_panel.dart';
|
|
|
|
class JourneyTimeline extends StatelessWidget {
|
|
const JourneyTimeline({
|
|
required this.progress,
|
|
required this.onReflect,
|
|
super.key,
|
|
});
|
|
|
|
final TodayProgress progress;
|
|
final VoidCallback onReflect;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = context.l10n;
|
|
final items = [
|
|
_TimelineData(
|
|
title: l10n.progressIntention,
|
|
detail:
|
|
progress.hasIntention ? progress.intention : l10n.chooseOneOutcome,
|
|
icon: Icons.flag_outlined,
|
|
complete: progress.hasIntention,
|
|
),
|
|
_TimelineData(
|
|
title: l10n.progressFocus,
|
|
detail:
|
|
progress.hasFocus
|
|
? l10n.focusedMinutes(progress.focusMinutes)
|
|
: l10n.noFocusSessionYet,
|
|
icon: Icons.timer_outlined,
|
|
complete: progress.hasFocus,
|
|
),
|
|
_TimelineData(
|
|
title: l10n.progressHabits,
|
|
detail: l10n.habitsCompleted(
|
|
progress.completedHabits,
|
|
progress.totalHabits,
|
|
),
|
|
icon: Icons.eco_outlined,
|
|
complete: progress.hasHabits,
|
|
),
|
|
_TimelineData(
|
|
title: l10n.progressReflect,
|
|
detail:
|
|
progress.hasReflection
|
|
? l10n.reflectionCaptured
|
|
: l10n.reflectionAction,
|
|
icon: Icons.auto_awesome_outlined,
|
|
complete: progress.hasReflection,
|
|
action: progress.hasReflection ? null : onReflect,
|
|
),
|
|
_TimelineData(
|
|
title: l10n.growthTitle,
|
|
detail:
|
|
progress.hasReflection ? l10n.growthFlowerOpen : l10n.growthLocked,
|
|
icon: Icons.local_florist_outlined,
|
|
complete: progress.hasReflection,
|
|
),
|
|
];
|
|
return Column(
|
|
children: [
|
|
for (var index = 0; index < items.length; index++)
|
|
_TimelineItem(data: items[index], isLast: index == items.length - 1),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _TimelineItem extends StatelessWidget {
|
|
const _TimelineItem({required this.data, required this.isLast});
|
|
|
|
final _TimelineData data;
|
|
final bool isLast;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final visuals = FocusSeedVisuals.of(context);
|
|
final accent =
|
|
data.icon == Icons.auto_awesome_outlined
|
|
? visuals.reflection
|
|
: theme.colorScheme.primary;
|
|
return IntrinsicHeight(
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
SizedBox(
|
|
width: 38,
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
width: 30,
|
|
height: 30,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color:
|
|
data.complete
|
|
? accent
|
|
: theme.colorScheme.surfaceContainerLowest,
|
|
border: Border.all(color: accent),
|
|
),
|
|
child: Icon(
|
|
data.complete ? Icons.check_rounded : data.icon,
|
|
size: 16,
|
|
color: data.complete ? theme.colorScheme.onPrimary : accent,
|
|
),
|
|
),
|
|
if (!isLast)
|
|
Expanded(
|
|
child: Container(
|
|
width: 2,
|
|
color:
|
|
data.complete
|
|
? accent.withValues(alpha: 0.55)
|
|
: theme.colorScheme.outlineVariant,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Padding(
|
|
padding: const EdgeInsets.only(bottom: 10),
|
|
child: SurfacePanel(
|
|
padding: const EdgeInsets.all(14),
|
|
borderColor:
|
|
data.action == null ? null : accent.withValues(alpha: 0.5),
|
|
onTap: data.action,
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(data.title, style: theme.textTheme.labelLarge),
|
|
const SizedBox(height: 3),
|
|
Text(
|
|
data.detail,
|
|
maxLines: 3,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: theme.textTheme.bodyMedium?.copyWith(
|
|
color: theme.colorScheme.onSurfaceVariant,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (data.action != null)
|
|
Icon(Icons.arrow_forward_rounded, color: accent),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _TimelineData {
|
|
const _TimelineData({
|
|
required this.title,
|
|
required this.detail,
|
|
required this.icon,
|
|
required this.complete,
|
|
this.action,
|
|
});
|
|
|
|
final String title;
|
|
final String detail;
|
|
final IconData icon;
|
|
final bool complete;
|
|
final VoidCallback? action;
|
|
}
|