release: seal Focus Seed 1.0.0

This commit is contained in:
2026-06-11 00:10:50 +08:00
commit 67ecb15c03
121 changed files with 5253 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
import 'package:flutter/material.dart';
import '../../app/app_theme.dart';
import '../../core/date_keys.dart';
import '../../models/app_state.dart';
import '../../models/habit.dart';
import '../../widgets/app_scaffold.dart';
import '../../widgets/dialogs.dart';
import '../../widgets/empty_state.dart';
import '../../widgets/habit_row.dart';
import '../../widgets/inline_editable_text.dart';
import '../../widgets/metric_tile.dart';
import '../../widgets/section_label.dart';
import '../../widgets/seed_card.dart';
import '../../widgets/weekly_progress.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({
required this.state,
required this.onAnchorChanged,
required this.onOpenTimer,
required this.onToggleHabit,
required this.onAddHabit,
super.key,
});
final AppState state;
final ValueChanged<String> onAnchorChanged;
final VoidCallback onOpenTimer;
final ValueChanged<Habit> onToggleHabit;
final ValueChanged<String> onAddHabit;
@override
Widget build(BuildContext context) {
final today = todayKey();
final completed =
state.habits
.where((habit) => habit.completedDates.contains(today))
.length;
final focusMinutes = minutesForDate(state.sessions, today);
final streak = currentStreak(
state.habits,
state.sessions,
state.reflections,
);
return AppScaffold(
title: 'Focus Seed',
subtitle: readableToday(),
child: ListView(
padding: const EdgeInsets.fromLTRB(20, 8, 20, 24),
children: [
SeedCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SectionLabel(
icon: Icons.flag_outlined,
text: 'Today anchor',
),
const SizedBox(height: 12),
InlineEditableText(
value: state.anchor,
emptyText: 'Choose one important task',
onSubmitted: onAnchorChanged,
),
const SizedBox(height: 16),
FilledButton.icon(
onPressed: onOpenTimer,
icon: const Icon(Icons.play_arrow_rounded),
label: const Text('Start focus'),
),
],
),
),
const SizedBox(height: 14),
Row(
children: [
Expanded(
child: MetricTile(
label: 'Focus',
value: '$focusMinutes',
suffix: 'min',
icon: Icons.timer_outlined,
),
),
const SizedBox(width: 10),
Expanded(
child: MetricTile(
label: 'Habits',
value: '$completed/${state.habits.length}',
suffix: '',
icon: Icons.check_circle_outline,
),
),
const SizedBox(width: 10),
Expanded(
child: MetricTile(
label: 'Streak',
value: '$streak',
suffix: 'days',
icon: Icons.local_fire_department_outlined,
accent: AppTheme.accent,
),
),
],
),
const SizedBox(height: 18),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Today habits',
style: Theme.of(context).textTheme.titleMedium,
),
IconButton.filledTonal(
tooltip: 'Add habit',
onPressed: () => showHabitDialog(context, onAddHabit),
icon: const Icon(Icons.add),
),
],
),
const SizedBox(height: 8),
if (state.habits.isEmpty)
EmptyState(
icon: Icons.checklist_rtl,
title: 'Add one tiny habit',
action: 'Add habit',
onAction: () => showHabitDialog(context, onAddHabit),
)
else
...state.habits
.take(5)
.map(
(habit) => HabitRow(
habit: habit,
dateKey: today,
onToggle: () => onToggleHabit(habit),
),
),
const SizedBox(height: 18),
WeeklyProgress(state: state),
],
),
);
}
}