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
+93
View File
@@ -0,0 +1,93 @@
import 'focus_session.dart';
import 'habit.dart';
import 'reflection_entry.dart';
class AppState {
const AppState({
required this.anchor,
required this.habits,
required this.sessions,
required this.reflections,
});
final String anchor;
final List<Habit> habits;
final List<FocusSession> sessions;
final List<ReflectionEntry> reflections;
bool get isFreshStart => habits.isEmpty && sessions.isEmpty && anchor.isEmpty;
AppState copyWith({
String? anchor,
List<Habit>? habits,
List<FocusSession>? sessions,
List<ReflectionEntry>? reflections,
}) {
return AppState(
anchor: anchor ?? this.anchor,
habits: habits ?? this.habits,
sessions: sessions ?? this.sessions,
reflections: reflections ?? this.reflections,
);
}
Map<String, dynamic> toJson() {
return {
'version': 1,
'anchor': anchor,
'habits': habits.map((habit) => habit.toJson()).toList(),
'sessions': sessions.map((session) => session.toJson()).toList(),
'reflections':
reflections.map((reflection) => reflection.toJson()).toList(),
};
}
static AppState fromJson(Map<String, dynamic> json) {
return AppState(
anchor: (json['anchor'] as String?) ?? '',
habits: _jsonObjects(json['habits']).map(Habit.fromJson).toList(),
sessions:
_jsonObjects(json['sessions']).map(FocusSession.fromJson).toList(),
reflections:
_jsonObjects(
json['reflections'],
).map(ReflectionEntry.fromJson).toList(),
);
}
static Iterable<Map<String, dynamic>> _jsonObjects(Object? value) {
if (value is! List<Object?>) {
return const Iterable<Map<String, dynamic>>.empty();
}
return value.whereType<Map<String, dynamic>>();
}
static AppState starter() {
final now = DateTime.now();
return AppState(
anchor: '',
habits: [
Habit(
id: 'habit-${now.microsecondsSinceEpoch}-1',
title: 'Plan one clear task',
createdAt: now,
completedDates: {},
),
Habit(
id: 'habit-${now.microsecondsSinceEpoch}-2',
title: 'Focus for 25 minutes',
createdAt: now,
completedDates: {},
),
Habit(
id: 'habit-${now.microsecondsSinceEpoch}-3',
title: 'Write a one-line reflection',
createdAt: now,
completedDates: {},
),
],
sessions: const [],
reflections: const [],
);
}
}
+27
View File
@@ -0,0 +1,27 @@
class FocusSession {
const FocusSession({
required this.id,
required this.minutes,
required this.completedAt,
});
final String id;
final int minutes;
final DateTime completedAt;
Map<String, dynamic> toJson() {
return {
'id': id,
'minutes': minutes,
'completedAt': completedAt.toIso8601String(),
};
}
static FocusSession fromJson(Map<String, dynamic> json) {
return FocusSession(
id: json['id'] as String,
minutes: json['minutes'] as int,
completedAt: DateTime.parse(json['completedAt'] as String),
);
}
}
+43
View File
@@ -0,0 +1,43 @@
class Habit {
const Habit({
required this.id,
required this.title,
required this.createdAt,
required this.completedDates,
});
final String id;
final String title;
final DateTime createdAt;
final Set<String> completedDates;
Habit copyWith({String? title, Set<String>? completedDates}) {
return Habit(
id: id,
title: title ?? this.title,
createdAt: createdAt,
completedDates: completedDates ?? this.completedDates,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'createdAt': createdAt.toIso8601String(),
'completedDates': completedDates.toList()..sort(),
};
}
static Habit fromJson(Map<String, dynamic> json) {
return Habit(
id: json['id'] as String,
title: json['title'] as String,
createdAt: DateTime.parse(json['createdAt'] as String),
completedDates:
((json['completedDates'] as List?) ?? const [])
.map((value) => value.toString())
.toSet(),
);
}
}
+13
View File
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
enum Mood {
calm('Calm', Icons.spa_outlined),
clear('Clear', Icons.wb_sunny_outlined),
proud('Proud', Icons.emoji_events_outlined),
tired('Tired', Icons.bedtime_outlined);
const Mood(this.label, this.icon);
final String label;
final IconData icon;
}
+40
View File
@@ -0,0 +1,40 @@
import 'mood.dart';
class ReflectionEntry {
const ReflectionEntry({
required this.id,
required this.dateKey,
required this.note,
required this.mood,
required this.createdAt,
});
final String id;
final String dateKey;
final String note;
final Mood mood;
final DateTime createdAt;
Map<String, dynamic> toJson() {
return {
'id': id,
'dateKey': dateKey,
'note': note,
'mood': mood.name,
'createdAt': createdAt.toIso8601String(),
};
}
static ReflectionEntry fromJson(Map<String, dynamic> json) {
return ReflectionEntry(
id: json['id'] as String,
dateKey: json['dateKey'] as String,
note: json['note'] as String,
mood: Mood.values.firstWhere(
(mood) => mood.name == json['mood'],
orElse: () => Mood.clear,
),
createdAt: DateTime.parse(json['createdAt'] as String),
);
}
}