Show real photos for people instead of scene art

Your avatar is your photo, picked from the device by tapping it on Home or
from a new Profile photo row in Settings, shrunk to 256 px and kept on the
phone (there is no upload endpoint yet). Group members show the photo the
server sends in a new `photo` field, everywhere avatars appear. Without a
photo, an initial on a neutral disc. Mock mode bundles free Unsplash
portraits for the sample people.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhQh614DMeYoQEH9SoMRUw
This commit is contained in:
alvocool
2026-11-09 08:22:41 +03:00
parent 72786701a9
commit 1b5d105400
33 changed files with 406 additions and 168 deletions

View File

@@ -43,7 +43,8 @@ class MockStore {
{
'id': 'goal-strong',
'title': 'Get strong',
'description': 'Deadlift my bodyweight by spring, without getting hurt.',
'description':
'Deadlift my bodyweight by spring, without getting hurt.',
'category': 'Health',
'defaultClass': 'Standard',
'startDate': at(-30, 0).toIso8601String(),
@@ -145,10 +146,7 @@ class MockStore {
minutes: 60,
category: 'Deep work'),
task('c-meal', 'Meal prep for the week',
goal: 'goal-strong',
start: at(1, 17),
end: at(1, 20),
minutes: 90),
goal: 'goal-strong', start: at(1, 17), end: at(1, 20), minutes: 90),
// Two things already past their window, so the overdue queue and debt
// have something to show.
task('c-email', 'Email supervisor the outline',
@@ -159,10 +157,7 @@ class MockStore {
status: 'Overdue',
deferrals: 1),
task('c-kitchen', 'Deep clean the kitchen',
start: at(-1, 18),
end: at(-1, 21),
minutes: 45,
status: 'Overdue'),
start: at(-1, 18), end: at(-1, 21), minutes: 45, status: 'Overdue'),
]);
// ── Routines ───────────────────────────────────────────────────────────
@@ -175,7 +170,10 @@ class MockStore {
final RoutineChain push = RoutineTemplates.upperPush()
..id = 'routine-push'
..goalId = 'goal-strong'
..days = <int>[1, 2, 3, 4, 5, 6, 7].where((day) => day != weekday).take(2).toList();
..days = <int>[1, 2, 3, 4, 5, 6, 7]
.where((day) => day != weekday)
.take(2)
.toList();
final RoutineChain breathing = RoutineTemplates.boxBreathing()
..id = 'routine-breathing'
@@ -262,12 +260,14 @@ class MockStore {
final List<Map<String, dynamic>> tasks = goalTasks(goal['id']);
final int completed = tasks
.where((item) =>
item['status'] == 'Completed' || item['status'] == 'LateCompleted')
item['status'] == 'Completed' ||
item['status'] == 'LateCompleted')
.length;
final int late =
tasks.where((item) => !_settled(item) && _windowClosed(item)).length;
return Map<String, dynamic>.from(goal)
..['totalTasks'] = tasks.where((item) => item['status'] != 'Abandoned').length
..['totalTasks'] =
tasks.where((item) => item['status'] != 'Abandoned').length
..['completedTasks'] = completed
..['overdueTasks'] = late
..['debtContribution'] = late * 2.0;