Square every corner, enlarge the main surfaces and add a to-do list
Rounded rectangles and round controls are now square across the app; only status dots, glows, the sun, rings and the breathing circle stay round. Cards, rows, thumbnails, featured cards, category tiles, the standing card and the nav are larger. Home gets a quick To-do list kept on the device (TodoItem in InternalMemory), seeded with sample items in mock mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KhQh614DMeYoQEH9SoMRUw
This commit is contained in:
@@ -13,6 +13,7 @@ import '../../about/internal/application/NotificationType.dart';
|
||||
import '../../about/internal/application/RoutineKind.dart';
|
||||
import '../../about/internal/application/Standing.dart';
|
||||
import '../../about/internal/application/TextType.dart';
|
||||
import '../../about/internal/application/TodoItem.dart';
|
||||
import '../../about/internal/application/UserDetails.dart';
|
||||
import '../../configs/Navigator.dart';
|
||||
import '../../designs/AmbientBackground.dart';
|
||||
@@ -24,6 +25,7 @@ import '../../designs/ProgressRing.dart';
|
||||
import '../../designs/Responsive.dart';
|
||||
import '../../designs/Shell.dart';
|
||||
import '../../designs/buttons/Buttons.dart';
|
||||
import '../../designs/input/InputFields.dart';
|
||||
import '../../designs/scene/SceneArt.dart';
|
||||
import '../../designs/text/Text.dart';
|
||||
import '../../utils/Colors.dart';
|
||||
@@ -55,6 +57,10 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
|
||||
List<RoutineChain> _routines = <RoutineChain>[];
|
||||
|
||||
List<TodoItem> _todos = <TodoItem>[];
|
||||
|
||||
final TextEditingController _todoInput = TextEditingController();
|
||||
|
||||
Standing _standing = Standing.Good;
|
||||
|
||||
double _debt = 0;
|
||||
@@ -92,6 +98,12 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
_model?.initialise();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_todoInput.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// ── Derived ───────────────────────────────────────────────────────────────
|
||||
|
||||
bool _isDone(Commitment item) {
|
||||
@@ -206,6 +218,48 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
|
||||
void _onNavToday() {}
|
||||
|
||||
void _onAddTodo(String value) {
|
||||
final String title = value.trim();
|
||||
if (title.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_todos.insert(
|
||||
0,
|
||||
TodoItem(
|
||||
id: DateTime.now().microsecondsSinceEpoch.toString(),
|
||||
title: title));
|
||||
});
|
||||
_todoInput.clear();
|
||||
_model?.saveTodos(_todos);
|
||||
}
|
||||
|
||||
void _onAddTodoPressed() {
|
||||
_onAddTodo(_todoInput.text);
|
||||
}
|
||||
|
||||
void _onToggleTodo(TodoItem item) {
|
||||
setState(() {
|
||||
item.done = !item.done;
|
||||
});
|
||||
_model?.saveTodos(_todos);
|
||||
}
|
||||
|
||||
void _onRemoveTodo(TodoItem item) {
|
||||
setState(() {
|
||||
_todos.remove(item);
|
||||
});
|
||||
_model?.saveTodos(_todos);
|
||||
}
|
||||
|
||||
void _onClearDoneTodos() {
|
||||
setState(() {
|
||||
_todos.removeWhere((item) => item.done);
|
||||
});
|
||||
_model?.saveTodos(_todos);
|
||||
}
|
||||
|
||||
// ── Views ─────────────────────────────────────────────────────────────────
|
||||
|
||||
Widget _mobileView(BoxConstraints constraints) {
|
||||
@@ -291,7 +345,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
Widget _topBar() {
|
||||
return Row(
|
||||
children: [
|
||||
_avatar(46),
|
||||
_avatar(54),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -337,7 +391,6 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: colorWhite, width: 2),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
@@ -347,7 +400,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipOval(
|
||||
child: ClipRect(
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
@@ -417,7 +470,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
onTap: _overdue.isEmpty ? _onOpenReportCard : _onOpenOverdue,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
borderRadius: BorderRadius.zero,
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x142A3A30),
|
||||
@@ -427,21 +480,21 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
],
|
||||
),
|
||||
child: GlassSurface(
|
||||
radius: BorderRadius.circular(28),
|
||||
radius: BorderRadius.zero,
|
||||
tint: colorGlassStrong,
|
||||
padding: const EdgeInsets.all(18),
|
||||
padding: const EdgeInsets.all(22),
|
||||
child: Row(
|
||||
children: [
|
||||
ProgressRing(
|
||||
fraction: fraction,
|
||||
size: 84,
|
||||
stroke: 8,
|
||||
size: 104,
|
||||
stroke: 9,
|
||||
fill: colorPrimary,
|
||||
track: colorPrimary.withValues(alpha: 0.12),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
text("$_doneCount/${_plan.length}", 19, TextType.Medium,
|
||||
text("$_doneCount/${_plan.length}", 23, TextType.Medium,
|
||||
color: colorInk),
|
||||
text("done", 10, TextType.Regular, color: colorInkSoft),
|
||||
],
|
||||
@@ -477,7 +530,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
const SizedBox(height: 6),
|
||||
text(
|
||||
ToneEngine.standingHeadline(_standing, _user.tone),
|
||||
15,
|
||||
17,
|
||||
TextType.Medium,
|
||||
color: colorInk,
|
||||
maxLines: 2,
|
||||
@@ -515,7 +568,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
text(value, 19, TextType.Light,
|
||||
text(value, 23, TextType.Light,
|
||||
color: alert ? colorStandingGrounded : colorInk),
|
||||
const SizedBox(height: 2),
|
||||
text(label, 10, TextType.Regular, color: colorInkSoft),
|
||||
@@ -530,7 +583,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
padding: const EdgeInsets.fromLTRB(20, 24, 20, 24),
|
||||
decoration: BoxDecoration(
|
||||
color: colorFrost,
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
borderRadius: BorderRadius.zero,
|
||||
border: Border.all(color: colorGlassBorder),
|
||||
),
|
||||
child: child,
|
||||
@@ -552,7 +605,9 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
sectionBreak("Your day",
|
||||
trailing: _viewAll("View all", _onOpenRoutines)),
|
||||
_categoryRail(),
|
||||
const SizedBox(height: 26),
|
||||
const SizedBox(height: 28),
|
||||
_todoSection(),
|
||||
const SizedBox(height: 28),
|
||||
if (_upNext.isNotEmpty) ...[
|
||||
sectionBreak("Up next",
|
||||
caption: "${_upNext.length} routines",
|
||||
@@ -647,10 +702,9 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
width: 74,
|
||||
height: 74,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: colorWhite, width: 2.5),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
@@ -660,7 +714,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipOval(
|
||||
child: ClipRect(
|
||||
child: SceneArt(
|
||||
palette: palette,
|
||||
seed: seed,
|
||||
@@ -671,7 +725,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
text(label, 11, TextType.Regular, color: colorInk),
|
||||
text(label, 12, TextType.Regular, color: colorInk),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -681,7 +735,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
final List<RoutineChain> items = _upNext;
|
||||
|
||||
return SizedBox(
|
||||
height: 236,
|
||||
height: 290,
|
||||
child: ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
clipBehavior: Clip.none,
|
||||
@@ -701,9 +755,9 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
return GestureDetector(
|
||||
onTap: () => _onStartRoutine(routine),
|
||||
child: Container(
|
||||
width: 196,
|
||||
width: 244,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
borderRadius: BorderRadius.zero,
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x262A3A30),
|
||||
@@ -713,7 +767,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
borderRadius: BorderRadius.zero,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
@@ -726,7 +780,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
shade: true,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -734,7 +788,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
children: [
|
||||
GlassSurface(
|
||||
onDark: true,
|
||||
radius: BorderRadius.circular(99),
|
||||
radius: BorderRadius.zero,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10, vertical: 5),
|
||||
child: text(
|
||||
@@ -749,11 +803,11 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
const Spacer(),
|
||||
glassCircle(CupertinoIcons.play_fill,
|
||||
() => _onStartRoutine(routine),
|
||||
size: 32, onDark: true),
|
||||
size: 40, onDark: true),
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
text(routine.title, 16, TextType.Medium,
|
||||
text(routine.title, 20, TextType.Medium,
|
||||
color: colorWhite,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis),
|
||||
@@ -799,7 +853,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
text(value, 20, TextType.Light, color: colorWhite),
|
||||
text(value, 24, TextType.Light, color: colorWhite),
|
||||
const SizedBox(height: 2),
|
||||
Row(
|
||||
children: [
|
||||
@@ -812,6 +866,135 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
);
|
||||
}
|
||||
|
||||
/// The quick to-do list: things to remember that are not promises. No
|
||||
/// window, no debt. Open items first, done ones struck through below.
|
||||
Widget _todoSection() {
|
||||
final List<TodoItem> open = _todos.where((item) => !item.done).toList();
|
||||
final List<TodoItem> done = _todos.where((item) => item.done).toList();
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
sectionBreak(
|
||||
"To-do",
|
||||
caption: "${open.length} open, no debt",
|
||||
trailing: done.isEmpty
|
||||
? null
|
||||
: _viewAll("Clear done", _onClearDoneTodos),
|
||||
),
|
||||
GlassSurface(
|
||||
tint: colorGlassStrong,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 6, 6, 6),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.pencil, size: 20, color: colorInkSoft),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: quickAddField(
|
||||
_todoInput, "Add a to-do", _onAddTodo),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: _onAddTodoPressed,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
color: colorNight,
|
||||
alignment: Alignment.center,
|
||||
child: Icon(CupertinoIcons.add,
|
||||
size: 22, color: colorLime),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
for (TodoItem item in <TodoItem>[...open, ...done])
|
||||
_todoRow(item),
|
||||
if (_todos.isEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 4, 20, 20),
|
||||
child: text(
|
||||
"Nothing to remember. Jot anything here; it stays on this phone.",
|
||||
13,
|
||||
TextType.Regular,
|
||||
color: colorInkSoft,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _todoRow(TodoItem item) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(top: BorderSide(color: colorGlassBorder)),
|
||||
),
|
||||
padding: const EdgeInsets.fromLTRB(14, 4, 4, 4),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => _onToggleTodo(item),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: item.done ? colorPrimary : colorWhite,
|
||||
border: Border.all(
|
||||
color: item.done
|
||||
? colorPrimary
|
||||
: colorInk.withValues(alpha: 0.25),
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: item.done
|
||||
? Icon(Icons.check_rounded, size: 20, color: colorWhite)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => _onToggleTodo(item),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
child: text(
|
||||
item.title,
|
||||
16,
|
||||
TextType.Regular,
|
||||
color: item.done ? colorInkSoft : colorInk,
|
||||
decoration: item.done ? TextDecoration.lineThrough : null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => _onRemoveTodo(item),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: Icon(CupertinoIcons.xmark, size: 16, color: colorInkSoft),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Grounded: the plan is hidden entirely and only the mess is shown.
|
||||
Widget _groundedBody() {
|
||||
return Column(
|
||||
@@ -948,7 +1131,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
onTap: _onOpenOverdue,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
borderRadius: BorderRadius.zero,
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
@@ -963,15 +1146,14 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.all(14),
|
||||
padding: const EdgeInsets.all(18),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
width: 58,
|
||||
height: 58,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: const RadialGradient(
|
||||
center: Alignment(-0.3, -0.4),
|
||||
colors: <Color>[colorOverdueGlow, colorStandingGrounded],
|
||||
@@ -1006,7 +1188,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
],
|
||||
),
|
||||
),
|
||||
glassCircle(CupertinoIcons.arrow_right, _onOpenOverdue, size: 36),
|
||||
glassCircle(CupertinoIcons.arrow_right, _onOpenOverdue, size: 44),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -1019,9 +1201,9 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
return GestureDetector(
|
||||
onTap: _onOpenExcuses,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.fromLTRB(20, 18, 20, 20),
|
||||
padding: const EdgeInsets.fromLTRB(22, 22, 22, 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
borderRadius: BorderRadius.zero,
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
@@ -1051,7 +1233,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
text(cluster.insight, 16, TextType.Regular,
|
||||
text(cluster.insight, 18, TextType.Regular,
|
||||
color: colorWhite, height: 1.5),
|
||||
],
|
||||
),
|
||||
@@ -1085,17 +1267,17 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
: classColor(item.commitmentClass);
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 10),
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
child: card(
|
||||
padding: const EdgeInsets.fromLTRB(8, 8, 12, 8),
|
||||
padding: const EdgeInsets.fromLTRB(10, 10, 14, 10),
|
||||
onTap: _onOpenOverdue,
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 64,
|
||||
height: 64,
|
||||
width: 88,
|
||||
height: 88,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderRadius: BorderRadius.zero,
|
||||
child: Opacity(
|
||||
opacity: ticked ? 0.45 : 1,
|
||||
child: SceneArt(
|
||||
@@ -1127,7 +1309,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
const SizedBox(height: 3),
|
||||
text(
|
||||
item.title,
|
||||
15,
|
||||
17,
|
||||
TextType.Medium,
|
||||
color: ticked ? colorInkSoft : colorInk,
|
||||
maxLines: 2,
|
||||
@@ -1176,10 +1358,9 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 220),
|
||||
curve: Curves.easeOutBack,
|
||||
width: 38,
|
||||
height: 38,
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: checked ? colorPrimary : colorWhite,
|
||||
border: Border.all(
|
||||
color: checked ? colorPrimary : accent.withValues(alpha: 0.35),
|
||||
@@ -1196,7 +1377,7 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
: const [],
|
||||
),
|
||||
child: checked
|
||||
? Icon(Icons.check_rounded, size: 20, color: colorWhite)
|
||||
? Icon(Icons.check_rounded, size: 24, color: colorWhite)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
@@ -1228,6 +1409,13 @@ class HomeState extends State<Home> implements ConnectHome {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onTodosLoaded(List<TodoItem> todos) {
|
||||
setState(() {
|
||||
_todos = todos;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onPlanLoaded(List<Commitment> plan) {
|
||||
setState(() {
|
||||
|
||||
Reference in New Issue
Block a user