diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 6c5a917..7e9c400 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -111,7 +111,7 @@ status field. That's what makes honest history and excuse analysis possible. See `design.md`. In short: sage-to-cream ambient backdrop, frosted glass controls, painted `SceneArt` instead of photos, image-led cards, two-tone -greetings, night pills with a lime spark. +greetings, square night buttons with a lime spark, no rounded corners. - Screens are built from `Sheet` (`designs/Shell.dart`); Home, Routines and the routine player compose `AmbientBackground` + glass directly. diff --git a/frontend/design.md b/frontend/design.md index 4536059..a536e17 100644 --- a/frontend/design.md +++ b/frontend/design.md @@ -4,7 +4,7 @@ Reference: an airy fitness-app look. Sage mist drifting into cream behind everything (`AmbientBackground`), frosted glass for controls and floating chrome (`GlassSurface`, `glassCircle`), ink type with a soft grey second tone, painted landscapes instead of photography (`SceneArt`), a floating -glass tab bar with a dark round action button (`FloatingNav`), and one lime +glass tab bar with a dark square action button (`FloatingNav`), and one lime spark on night-green for the primary control. ## Building blocks (`designs/`) @@ -12,7 +12,7 @@ spark on night-green for the primary control. | Piece | Use | |---|---| | `AmbientBackground` | The backdrop for every light screen. | -| `GlassSurface` / `glassCircle` | Frosted panels and round controls; `onDark` over a scene or tinted stage. | +| `GlassSurface` / `glassCircle` | Frosted panels and square controls; `onDark` over a scene or tinted stage. | | `SceneArt` | Painted sky, sun and ridges with an optional figure glyph. Palettes come from `scenePalette(kind)`, `goalScene(accent)`, `classScene(class)`; seed with `sceneSeed(title)` so an item always wears the same picture. | | `DotDigits` | The dotted clock in the routine player. | | `FloatingNav` | Home's tab bar and action button. | @@ -21,7 +21,7 @@ spark on night-green for the primary control. Cards are image-led where an item has a kind (routines, goals, tasks): scene on top or as a thumbnail, white type over the shaded lower half, three light numbers along the bottom. Greetings are two-tone: Medium ink, then Regular -`colorInkSoft`. Primary buttons are night pills with a lime icon. +`colorInkSoft`. Primary buttons are square night bars with a lime icon. `Sheet` is light (ambient) by default; passing `chrome`, `banner` or `scene` gives a tinted stage with white type. Home, Routines and the player @@ -45,7 +45,7 @@ directly above a large dark value. Used everywhere numbers appear. ## Geometry -- Sheet radius `28`, card radius `16`, chip radius `999`, control radius `12`. +- No rounded corners anywhere: sheets, cards, chips, buttons, fields, tiles and portraits are all square (`BorderRadius.zero`). Only small status dots, glows, the sun, progress rings and the breathing circle stay round. - Screen padding `20` horizontal. Card padding `16`. Section gap `28`. - Hairlines at `colorDivider` (black 7%), borders at `colorBorder` (black 8%). - One soft shadow only: `0 4 18 rgba(0,0,0,0.03)`. No coloured glows. @@ -69,7 +69,7 @@ the standing is legible without reading the word. ## Structure Every screen is: black `headerBar` (back, title, action) → white sheet with a -`28` top radius → `sectionHeader` (label + light display title) → content. +square top edge → `sectionHeader` (label + light display title) → content. ## Rules diff --git a/frontend/lib/Grounded/about/internal/application/TodoItem.dart b/frontend/lib/Grounded/about/internal/application/TodoItem.dart new file mode 100644 index 0000000..566715d --- /dev/null +++ b/frontend/lib/Grounded/about/internal/application/TodoItem.dart @@ -0,0 +1,27 @@ +/// A quick to-do: no window, no class, no debt. Kept on the device so jotting +/// something down never waits on the network. +class TodoItem { + String id; + + String title; + + bool done; + + TodoItem({required this.id, required this.title, this.done = false}); + + factory TodoItem.fromJson(Map json) { + return TodoItem( + id: json['id'] ?? '', + title: json['title'] ?? '', + done: json['done'] ?? false, + ); + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['title'] = title; + data['done'] = done; + return data; + } +} diff --git a/frontend/lib/Grounded/designs/Checkbox.dart b/frontend/lib/Grounded/designs/Checkbox.dart index 231f472..f1d93e4 100644 --- a/frontend/lib/Grounded/designs/Checkbox.dart +++ b/frontend/lib/Grounded/designs/Checkbox.dart @@ -48,7 +48,7 @@ class TickBox extends StatelessWidget { height: size, decoration: BoxDecoration( color: checked ? tone : Colors.transparent, - borderRadius: BorderRadius.circular(7), + borderRadius: BorderRadius.zero, border: Border.all( color: checked ? tone : colorGrey.withValues(alpha: 0.55), width: 1.6, @@ -202,7 +202,7 @@ Widget addTaskAffordance( alignment: Alignment.center, decoration: BoxDecoration( color: tone.withValues(alpha: 0.12), - borderRadius: BorderRadius.circular(14), + borderRadius: BorderRadius.zero, border: Border.all(color: tone.withValues(alpha: 0.25), width: 1), ), child: Icon(Icons.add_rounded, size: 22, color: tone), diff --git a/frontend/lib/Grounded/designs/Component.dart b/frontend/lib/Grounded/designs/Component.dart index 11b9b43..a5dbcf1 100644 --- a/frontend/lib/Grounded/designs/Component.dart +++ b/frontend/lib/Grounded/designs/Component.dart @@ -32,7 +32,7 @@ Widget pill( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), decoration: BoxDecoration( color: background, - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, border: Border.all(color: foreground.withValues(alpha: 0.20), width: 1), ), child: Row( @@ -57,7 +57,7 @@ Widget pill( /// The standard card surface. Widget card({ required Widget child, - EdgeInsets padding = const EdgeInsets.all(16), + EdgeInsets padding = const EdgeInsets.all(20), EdgeInsets margin = EdgeInsets.zero, Color? background, Color? borderColor, @@ -70,7 +70,7 @@ Widget card({ margin: margin, decoration: BoxDecoration( color: background ?? colorCard, - borderRadius: BorderRadius.circular(radius), + borderRadius: BorderRadius.zero, border: Border.all(color: borderColor ?? colorGlassBorder, width: 1), boxShadow: const [ BoxShadow( @@ -159,7 +159,6 @@ Widget emptyState( height: 76, decoration: BoxDecoration( color: tone.withValues(alpha: 0.08), - shape: BoxShape.circle, ), child: Icon(icon, size: 32, color: tone), ), @@ -191,7 +190,7 @@ Widget meter( : fraction; return ClipRRect( - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, child: LinearProgressIndicator( value: clamped, minHeight: height, diff --git a/frontend/lib/Grounded/designs/FloatingNav.dart b/frontend/lib/Grounded/designs/FloatingNav.dart index 33ea526..0b47ed3 100644 --- a/frontend/lib/Grounded/designs/FloatingNav.dart +++ b/frontend/lib/Grounded/designs/FloatingNav.dart @@ -36,7 +36,7 @@ class FloatingNav extends StatelessWidget { Expanded( child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(34), + borderRadius: BorderRadius.zero, boxShadow: const [ BoxShadow( color: Color(0x1A1A1F1C), @@ -46,7 +46,7 @@ class FloatingNav extends StatelessWidget { ], ), child: GlassSurface( - radius: BorderRadius.circular(34), + radius: BorderRadius.zero, tint: colorGlassStrong, padding: const EdgeInsets.all(6), child: Row( @@ -62,10 +62,9 @@ class FloatingNav extends StatelessWidget { GestureDetector( onTap: onAction, child: Container( - width: 64, - height: 64, + width: 72, + height: 72, decoration: BoxDecoration( - shape: BoxShape.circle, gradient: const RadialGradient( center: Alignment(-0.3, -0.4), colors: [colorNightGlow, colorNight], @@ -98,7 +97,7 @@ class FloatingNav extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 9), decoration: BoxDecoration( color: active ? colorWhite : colorWhite.withValues(alpha: 0.0), - borderRadius: BorderRadius.circular(28), + borderRadius: BorderRadius.zero, boxShadow: active ? const [ BoxShadow( @@ -113,7 +112,7 @@ class FloatingNav extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Icon(entry.icon, - size: 19, color: active ? colorInk : colorInkSoft), + size: 23, color: active ? colorInk : colorInkSoft), const SizedBox(height: 4), text(entry.label, 10, active ? TextType.Medium : TextType.Regular, color: active ? colorInk : colorInkSoft, maxLines: 1), diff --git a/frontend/lib/Grounded/designs/GlassSurface.dart b/frontend/lib/Grounded/designs/GlassSurface.dart index 11fa1cb..376e3c5 100644 --- a/frontend/lib/Grounded/designs/GlassSurface.dart +++ b/frontend/lib/Grounded/designs/GlassSurface.dart @@ -23,7 +23,7 @@ class GlassSurface extends StatelessWidget { const GlassSurface({ super.key, required this.child, - this.radius = const BorderRadius.all(Radius.circular(20)), + this.radius = const BorderRadius.all(Radius.zero), this.padding = EdgeInsets.zero, this.tint, this.onDark = false, @@ -60,7 +60,7 @@ class GlassSurface extends StatelessWidget { Widget glassCircle( IconData icon, VoidCallback onTap, { - double size = 42, + double size = 50, bool onDark = false, bool dotted = false, Color? dotColor, @@ -73,7 +73,7 @@ Widget glassCircle( children: [ GlassSurface( onDark: onDark, - radius: BorderRadius.circular(size), + radius: BorderRadius.zero, child: SizedBox( width: size, height: size, diff --git a/frontend/lib/Grounded/designs/GoalPicker.dart b/frontend/lib/Grounded/designs/GoalPicker.dart index 552125c..16a33c6 100644 --- a/frontend/lib/Grounded/designs/GoalPicker.dart +++ b/frontend/lib/Grounded/designs/GoalPicker.dart @@ -32,8 +32,8 @@ Future showGoalPicker( decoration: const BoxDecoration( color: colorSheetBackground, borderRadius: BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: ListView( @@ -93,7 +93,7 @@ Widget _goalOption( padding: const EdgeInsets.fromLTRB(14, 13, 14, 13), decoration: BoxDecoration( color: colorWhite, - borderRadius: BorderRadius.circular(14), + borderRadius: BorderRadius.zero, border: Border.all( color: selected ? accent.withValues(alpha: 0.5) : colorBorder, width: selected ? 1.5 : 1, diff --git a/frontend/lib/Grounded/designs/Shell.dart b/frontend/lib/Grounded/designs/Shell.dart index 2dc6a56..eb404cc 100644 --- a/frontend/lib/Grounded/designs/Shell.dart +++ b/frontend/lib/Grounded/designs/Shell.dart @@ -136,8 +136,8 @@ class Sheet extends StatelessWidget { decoration: BoxDecoration( color: light ? colorFrost : colorPrimaryLight, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), clipBehavior: Clip.antiAlias, diff --git a/frontend/lib/Grounded/designs/buttons/Buttons.dart b/frontend/lib/Grounded/designs/buttons/Buttons.dart index b38a5da..3c656e3 100644 --- a/frontend/lib/Grounded/designs/buttons/Buttons.dart +++ b/frontend/lib/Grounded/designs/buttons/Buttons.dart @@ -27,7 +27,7 @@ Widget roundedCornerButton( disabledBackgroundColor: colorGrey.withValues(alpha: 0.4), padding: EdgeInsets.symmetric(vertical: verticalPadding), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(radius), + borderRadius: BorderRadius.zero, ), ), child: Row( @@ -65,7 +65,7 @@ Widget outlinedActionButton( side: BorderSide(color: fg.withValues(alpha: 0.35), width: 1), padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(radius), + borderRadius: BorderRadius.zero, ), ), child: Row( @@ -112,7 +112,7 @@ Widget iconButton( alignment: Alignment.center, decoration: BoxDecoration( color: background ?? Colors.transparent, - borderRadius: BorderRadius.circular(radius), + borderRadius: BorderRadius.zero, border: bordered ? Border.all(color: borderColor ?? colorBorder, width: 1) : null, @@ -161,7 +161,7 @@ Widget segmentedSelector({ padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), decoration: BoxDecoration( color: isSelected ? active : colorWhite, - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.zero, border: Border.all( color: isSelected ? active : colorBorder, width: 1, diff --git a/frontend/lib/Grounded/designs/input/CountStepper.dart b/frontend/lib/Grounded/designs/input/CountStepper.dart index b9ae504..6c7b82b 100644 --- a/frontend/lib/Grounded/designs/input/CountStepper.dart +++ b/frontend/lib/Grounded/designs/input/CountStepper.dart @@ -17,7 +17,7 @@ Widget countStepper( padding: const EdgeInsets.fromLTRB(14, 10, 8, 10), decoration: BoxDecoration( color: colorWhite, - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, border: Border.all(color: colorBorder, width: 1), ), child: Row( @@ -54,7 +54,7 @@ Widget _stepButton(IconData icon, VoidCallback? onTap) { alignment: Alignment.center, decoration: BoxDecoration( color: enabled ? colorSecondary : colorInset, - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.zero, ), child: Icon(icon, size: 14, color: enabled ? colorPrimaryDark : colorGrey), diff --git a/frontend/lib/Grounded/designs/input/InputFields.dart b/frontend/lib/Grounded/designs/input/InputFields.dart index 3602f7e..df901ca 100644 --- a/frontend/lib/Grounded/designs/input/InputFields.dart +++ b/frontend/lib/Grounded/designs/input/InputFields.dart @@ -54,19 +54,19 @@ Widget inputField( contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14), enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, borderSide: BorderSide(color: colorBorder, width: 1), ), focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, borderSide: BorderSide(color: colorPrimaryDark, width: 1.4), ), errorBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, borderSide: BorderSide(color: colorNegative, width: 1), ), focusedErrorBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, borderSide: BorderSide(color: colorNegative, width: 1.4), ), errorStyle: TextStyle( @@ -80,6 +80,36 @@ Widget inputField( ); } +/// The bare add-a-line field used inside a card: no label, no box of its +/// own; return or the trailing button submits. +Widget quickAddField( + TextEditingController controller, + String hint, + ValueChanged onSubmitted, +) { + return TextField( + controller: controller, + onSubmitted: onSubmitted, + textInputAction: TextInputAction.done, + style: TextStyle( + fontFamily: getTextType(TextType.Regular), + fontSize: 16, + color: colorInk, + ), + decoration: InputDecoration( + hintText: hint, + hintStyle: TextStyle( + fontFamily: getTextType(TextType.Regular), + fontSize: 16, + color: colorInkSoft, + ), + isDense: true, + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric(vertical: 14), + ), + ); +} + /// The excuse field. Deliberately unadorned — no templates, no quick-picks, a /// live character count that shows the minimum, because the friction is the /// feature rather than an obstacle to route around. @@ -131,19 +161,19 @@ Widget excuseField( fillColor: colorWhite, contentPadding: const EdgeInsets.all(14), enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, borderSide: BorderSide(color: colorBorder, width: 1), ), focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, borderSide: BorderSide(color: colorPrimaryDark, width: 1.4), ), errorBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, borderSide: BorderSide(color: colorNegative, width: 1), ), focusedErrorBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, borderSide: BorderSide(color: colorNegative, width: 1.4), ), errorStyle: TextStyle( @@ -180,7 +210,7 @@ Widget selectField( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 16), decoration: BoxDecoration( color: colorWhite, - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, border: Border.all(color: colorBorder, width: 1), ), child: Row( diff --git a/frontend/lib/Grounded/informatics/AppDataManager.dart b/frontend/lib/Grounded/informatics/AppDataManager.dart index d8bc551..47d31c9 100644 --- a/frontend/lib/Grounded/informatics/AppDataManager.dart +++ b/frontend/lib/Grounded/informatics/AppDataManager.dart @@ -21,6 +21,7 @@ import '../about/external/initial/SessionLogRequest.dart'; import '../about/external/initial/SickModeRequest.dart'; import '../about/external/initial/ToneRequest.dart'; import '../about/internal/application/CapacityProfile.dart'; +import '../about/internal/application/TodoItem.dart'; import '../about/internal/application/MeDescription.dart'; import '../about/internal/application/Token.dart'; import '../about/internal/application/UserDetails.dart'; @@ -119,6 +120,12 @@ class AppDataManager implements DataManager { @override Future setAmnestySpent(int spent) => memory.setAmnestySpent(spent); + @override + Future> getTodos() => memory.getTodos(); + + @override + Future setTodos(List todos) => memory.setTodos(todos); + @override Future showOnboarding() => memory.showOnboarding(); diff --git a/frontend/lib/Grounded/memory/ConnectInternalMemory.dart b/frontend/lib/Grounded/memory/ConnectInternalMemory.dart index 6428e4d..5b891fc 100644 --- a/frontend/lib/Grounded/memory/ConnectInternalMemory.dart +++ b/frontend/lib/Grounded/memory/ConnectInternalMemory.dart @@ -3,6 +3,7 @@ import '../about/external/data/Program.dart'; import '../about/external/data/SystemResponse.dart'; import '../about/internal/application/CapacityProfile.dart'; import '../about/internal/application/MeDescription.dart'; +import '../about/internal/application/TodoItem.dart'; import '../about/internal/application/Token.dart'; import '../about/internal/application/UserDetails.dart'; @@ -59,6 +60,11 @@ abstract class ConnectInternalMemory { Future setAmnestySpent(int spent); + /// The quick to-do list on Home. + Future> getTodos(); + + Future setTodos(List todos); + Future showOnboarding(); Future setOnboardingOption(bool value); diff --git a/frontend/lib/Grounded/memory/InternalMemory.dart b/frontend/lib/Grounded/memory/InternalMemory.dart index 67d3d39..38c45e1 100644 --- a/frontend/lib/Grounded/memory/InternalMemory.dart +++ b/frontend/lib/Grounded/memory/InternalMemory.dart @@ -8,6 +8,7 @@ import '../about/external/data/ResponseState.dart'; import '../about/external/data/SystemResponse.dart'; import '../about/internal/application/CapacityProfile.dart'; import '../about/internal/application/MeDescription.dart'; +import '../about/internal/application/TodoItem.dart'; import '../about/internal/application/Token.dart'; import '../about/internal/application/UserDetails.dart'; import 'ConnectInternalMemory.dart'; @@ -40,6 +41,8 @@ class InternalMemory implements ConnectInternalMemory { static const String AMNESTY_SPENT = "AMNESTY_SPENT_Jr4xVh9KmT3gLc6B"; + static const String TODOS = "TODOS_Wm3kRb8TqZ5nHc2F"; + static const String SHOW_ONBOARDING = "SHOW_ONBOARDING_Nz6qGf2SdX7wPb4M"; final groundedStorage = const FlutterSecureStorage(); @@ -252,6 +255,26 @@ class InternalMemory implements ConnectInternalMemory { await groundedStorage.write(key: AMNESTY_SPENT, value: spent.toString()); } + @override + Future> getTodos() async { + String? value = await groundedStorage.read(key: TODOS); + + if (value != null) { + return (jsonDecode(value) as List) + .map((item) => TodoItem.fromJson(item as Map)) + .toList(); + } + + return []; + } + + @override + Future setTodos(List todos) async { + await groundedStorage.write( + key: TODOS, + value: jsonEncode(todos.map((item) => item.toJson()).toList())); + } + @override Future showOnboarding() async { String? value = await groundedStorage.read(key: SHOW_ONBOARDING); diff --git a/frontend/lib/Grounded/mock/MockMemory.dart b/frontend/lib/Grounded/mock/MockMemory.dart index c48369c..c8e650d 100644 --- a/frontend/lib/Grounded/mock/MockMemory.dart +++ b/frontend/lib/Grounded/mock/MockMemory.dart @@ -3,6 +3,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import '../about/internal/application/MeDescription.dart'; +import '../about/internal/application/TodoItem.dart'; import '../about/internal/application/UserDetails.dart'; import '../memory/InternalMemory.dart'; import 'MockStorage.dart'; @@ -18,6 +19,11 @@ class MockMemory extends InternalMemory { setMyDescription( MeDescription(id: "mock-user", name: "Alex", token: "mock-token")); setUserDetails(UserDetails(pic: "", name: "Alex")); + setTodos([ + TodoItem(id: "t1", title: "Refill water bottle"), + TodoItem(id: "t2", title: "Book physio for Thursday"), + TodoItem(id: "t3", title: "Reply to Sam about Saturday", done: true), + ]); } } diff --git a/frontend/lib/Grounded/see/commitment/NewCommitmentState.dart b/frontend/lib/Grounded/see/commitment/NewCommitmentState.dart index 963c75e..2f0f7c8 100644 --- a/frontend/lib/Grounded/see/commitment/NewCommitmentState.dart +++ b/frontend/lib/Grounded/see/commitment/NewCommitmentState.dart @@ -443,8 +443,8 @@ class NewCommitmentState extends State decoration: BoxDecoration( color: colorSheetBackground, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: SingleChildScrollView( @@ -460,7 +460,7 @@ class NewCommitmentState extends State margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: colorGrey.withValues(alpha: 0.35), - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, ), ), ), diff --git a/frontend/lib/Grounded/see/excuse/ExcuseReportState.dart b/frontend/lib/Grounded/see/excuse/ExcuseReportState.dart index 5e54cd1..b353f36 100644 --- a/frontend/lib/Grounded/see/excuse/ExcuseReportState.dart +++ b/frontend/lib/Grounded/see/excuse/ExcuseReportState.dart @@ -142,7 +142,7 @@ class ExcuseReportState extends State padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: colorInset, - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, border: Border.all(color: colorBorder, width: 1), ), child: Row( diff --git a/frontend/lib/Grounded/see/goal/GoalDetailState.dart b/frontend/lib/Grounded/see/goal/GoalDetailState.dart index 4c848cd..3e60a15 100644 --- a/frontend/lib/Grounded/see/goal/GoalDetailState.dart +++ b/frontend/lib/Grounded/see/goal/GoalDetailState.dart @@ -242,7 +242,7 @@ class GoalDetailState extends State padding: const EdgeInsets.fromLTRB(16, 14, 16, 14), decoration: BoxDecoration( color: colorWhite.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.zero, ), child: Column( mainAxisSize: MainAxisSize.min, @@ -405,7 +405,7 @@ class GoalDetailState extends State width: 58, height: 58, child: ClipRRect( - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.zero, child: SceneArt( palette: scenePalette(routine.kind), seed: sceneSeed(routine.title), @@ -454,7 +454,6 @@ class GoalDetailState extends State color: routine.kind == RoutineKind.MustDo ? colorPrimaryDark : tone, - shape: BoxShape.circle, ), child: Icon(CupertinoIcons.play_fill, size: 15, color: colorWhite), diff --git a/frontend/lib/Grounded/see/goal/GoalEditorState.dart b/frontend/lib/Grounded/see/goal/GoalEditorState.dart index 5418b7a..4b48408 100644 --- a/frontend/lib/Grounded/see/goal/GoalEditorState.dart +++ b/frontend/lib/Grounded/see/goal/GoalEditorState.dart @@ -282,7 +282,7 @@ class GoalEditorState extends State implements ConnectGoalEditor { return Container( padding: const EdgeInsets.all(18), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), + borderRadius: BorderRadius.zero, gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -338,7 +338,6 @@ class GoalEditorState extends State implements ConnectGoalEditor { alignment: Alignment.center, decoration: BoxDecoration( color: colour, - shape: BoxShape.circle, border: Border.all( color: selected ? colorWhite : Colors.transparent, width: 3, diff --git a/frontend/lib/Grounded/see/goal/GoalsState.dart b/frontend/lib/Grounded/see/goal/GoalsState.dart index 0a2dfe4..bbdd247 100644 --- a/frontend/lib/Grounded/see/goal/GoalsState.dart +++ b/frontend/lib/Grounded/see/goal/GoalsState.dart @@ -117,10 +117,10 @@ class GoalsState extends State implements ConnectGoals { return GestureDetector( onTap: () => _onOpenGoal(goal), child: Container( - height: 214, + height: 260, margin: const EdgeInsets.only(bottom: 14), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(26), + borderRadius: BorderRadius.zero, boxShadow: const [ BoxShadow( color: Color(0x262A3A30), @@ -130,7 +130,7 @@ class GoalsState extends State implements ConnectGoals { ], ), child: ClipRRect( - borderRadius: BorderRadius.circular(26), + borderRadius: BorderRadius.zero, child: Stack( fit: StackFit.expand, children: [ @@ -151,7 +151,7 @@ class GoalsState extends State implements ConnectGoals { children: [ GlassSurface( onDark: true, - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 5), child: text( diff --git a/frontend/lib/Grounded/see/home/ConnectHome.dart b/frontend/lib/Grounded/see/home/ConnectHome.dart index b680d65..916cfe2 100644 --- a/frontend/lib/Grounded/see/home/ConnectHome.dart +++ b/frontend/lib/Grounded/see/home/ConnectHome.dart @@ -2,6 +2,7 @@ import '../../about/external/data/Commitment.dart'; import '../../about/external/data/ExcuseCluster.dart'; import '../../about/external/data/RoutineChain.dart'; import '../../about/internal/application/Standing.dart'; +import '../../about/internal/application/TodoItem.dart'; import '../../about/internal/application/UserDetails.dart'; abstract class ConnectHome { @@ -14,6 +15,9 @@ abstract class ConnectHome { /// The routine library, for the up-next rail. void onRoutinesLoaded(List routines); + /// The quick to-do list, read from the device. + void onTodosLoaded(List todos); + /// Standing arrives derived, with the debt it was derived from. void onStandingResolved(Standing standing, double debtScore); diff --git a/frontend/lib/Grounded/see/home/HomeState.dart b/frontend/lib/Grounded/see/home/HomeState.dart index c7e9327..fe2e668 100644 --- a/frontend/lib/Grounded/see/home/HomeState.dart +++ b/frontend/lib/Grounded/see/home/HomeState.dart @@ -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 implements ConnectHome { List _routines = []; + List _todos = []; + + final TextEditingController _todoInput = TextEditingController(); + Standing _standing = Standing.Good; double _debt = 0; @@ -92,6 +98,12 @@ class HomeState extends State implements ConnectHome { _model?.initialise(); } + @override + void dispose() { + _todoInput.dispose(); + super.dispose(); + } + // ── Derived ─────────────────────────────────────────────────────────────── bool _isDone(Commitment item) { @@ -206,6 +218,48 @@ class HomeState extends State 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 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 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 implements ConnectHome { ), ], ), - child: ClipOval( + child: ClipRect( child: Stack( fit: StackFit.expand, children: [ @@ -417,7 +470,7 @@ class HomeState extends State 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 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 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 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 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 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 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 implements ConnectHome { ), ], ), - child: ClipOval( + child: ClipRect( child: SceneArt( palette: palette, seed: seed, @@ -671,7 +725,7 @@ class HomeState extends State 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 implements ConnectHome { final List 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 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 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 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 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 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 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 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 open = _todos.where((item) => !item.done).toList(); + final List 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 [...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 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 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: [colorOverdueGlow, colorStandingGrounded], @@ -1006,7 +1188,7 @@ class HomeState extends State implements ConnectHome { ], ), ), - glassCircle(CupertinoIcons.arrow_right, _onOpenOverdue, size: 36), + glassCircle(CupertinoIcons.arrow_right, _onOpenOverdue, size: 44), ], ), ), @@ -1019,9 +1201,9 @@ class HomeState extends State 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 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 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 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 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 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 implements ConnectHome { }); } + @override + void onTodosLoaded(List todos) { + setState(() { + _todos = todos; + }); + } + @override void onPlanLoaded(List plan) { setState(() { diff --git a/frontend/lib/Grounded/see/home/ViewHome.dart b/frontend/lib/Grounded/see/home/ViewHome.dart index dea0c40..31c3e8a 100644 --- a/frontend/lib/Grounded/see/home/ViewHome.dart +++ b/frontend/lib/Grounded/see/home/ViewHome.dart @@ -11,6 +11,7 @@ import '../../about/external/initial/CompletionRequest.dart'; import '../../about/external/initial/ReportCardRequest.dart'; import '../../about/internal/application/CommitmentClass.dart'; import '../../about/internal/application/Standing.dart'; +import '../../about/internal/application/TodoItem.dart'; import '../../about/internal/application/UserDetails.dart'; import '../../utils/DebtEngine.dart'; import '../../utils/GuardrailEngine.dart'; @@ -31,9 +32,20 @@ class ViewHome extends ParentViewModel { final UserDetails cached = await getDataManager().getUserDetails(); connection.onUserLoaded(cached); + loadTodos(); + loadPlan(); } + void loadTodos() async { + connection.onTodosLoaded(await getDataManager().getTodos()); + } + + /// Saves the whole list; it is small and only ever lives on the device. + void saveTodos(List todos) async { + await getDataManager().setTodos(todos); + } + void loadPlan() async { if (!await hasNetwork(() => loadPlan())) return; diff --git a/frontend/lib/Grounded/see/live/LiveTaskState.dart b/frontend/lib/Grounded/see/live/LiveTaskState.dart index 199d970..6c3033c 100644 --- a/frontend/lib/Grounded/see/live/LiveTaskState.dart +++ b/frontend/lib/Grounded/see/live/LiveTaskState.dart @@ -184,8 +184,8 @@ class LiveTaskState extends State decoration: BoxDecoration( color: colorSheetBackground, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: SingleChildScrollView( diff --git a/frontend/lib/Grounded/see/login/LoginState.dart b/frontend/lib/Grounded/see/login/LoginState.dart index edb6fdf..217f675 100644 --- a/frontend/lib/Grounded/see/login/LoginState.dart +++ b/frontend/lib/Grounded/see/login/LoginState.dart @@ -107,8 +107,8 @@ class LoginState extends State implements ConnectLogin { decoration: BoxDecoration( color: colorPrimaryLight, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), clipBehavior: Clip.antiAlias, diff --git a/frontend/lib/Grounded/see/overdue/OverdueQueueState.dart b/frontend/lib/Grounded/see/overdue/OverdueQueueState.dart index a7589a0..e89b7fb 100644 --- a/frontend/lib/Grounded/see/overdue/OverdueQueueState.dart +++ b/frontend/lib/Grounded/see/overdue/OverdueQueueState.dart @@ -147,8 +147,8 @@ class OverdueQueueState extends State decoration: BoxDecoration( color: colorSheetBackground, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: SingleChildScrollView( @@ -166,7 +166,7 @@ class OverdueQueueState extends State margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: colorGrey.withValues(alpha: 0.35), - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, ), ), ), @@ -242,8 +242,8 @@ class OverdueQueueState extends State decoration: BoxDecoration( color: colorSheetBackground, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: SingleChildScrollView( @@ -261,7 +261,7 @@ class OverdueQueueState extends State margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: colorGrey.withValues(alpha: 0.35), - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, ), ), ), @@ -343,8 +343,8 @@ class OverdueQueueState extends State decoration: BoxDecoration( color: colorSheetBackground, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: SingleChildScrollView( @@ -360,7 +360,7 @@ class OverdueQueueState extends State margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: colorGrey.withValues(alpha: 0.35), - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, ), ), ), @@ -504,7 +504,7 @@ class OverdueQueueState extends State padding: const EdgeInsets.fromLTRB(16, 14, 16, 14), decoration: BoxDecoration( color: colorWhite.withValues(alpha: 0.10), - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.zero, ), child: Row( children: [ diff --git a/frontend/lib/Grounded/see/parent/ParentViewModel.dart b/frontend/lib/Grounded/see/parent/ParentViewModel.dart index 7c74a5a..c229681 100644 --- a/frontend/lib/Grounded/see/parent/ParentViewModel.dart +++ b/frontend/lib/Grounded/see/parent/ParentViewModel.dart @@ -152,7 +152,7 @@ class ParentViewModel extends ChangeNotifier { height: 64, decoration: BoxDecoration( color: colorPrimaryDark, - borderRadius: BorderRadius.circular(18), + borderRadius: BorderRadius.zero, ), child: Icon(CupertinoIcons.wifi_slash, size: 26, color: colorWhite), @@ -396,7 +396,7 @@ class ParentViewModel extends ChangeNotifier { alignment: Alignment.center, decoration: BoxDecoration( color: colorStandingGroundedBg, - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, ), child: Icon( CupertinoIcons.exclamationmark_triangle_fill, @@ -544,8 +544,8 @@ class ParentViewModel extends ChangeNotifier { decoration: BoxDecoration( color: colorSheetBackground, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: Column( @@ -559,7 +559,7 @@ class ParentViewModel extends ChangeNotifier { margin: const EdgeInsets.only(top: 12, bottom: 8), decoration: BoxDecoration( color: colorGrey.withValues(alpha: 0.35), - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, ), ), ), @@ -579,7 +579,7 @@ class ParentViewModel extends ChangeNotifier { alignment: Alignment.center, decoration: BoxDecoration( color: actionBgColor, - borderRadius: BorderRadius.circular(15), + borderRadius: BorderRadius.zero, ), child: Icon(actionIconData, size: 24, color: actionColor), diff --git a/frontend/lib/Grounded/see/reportcard/ReportCardScreenState.dart b/frontend/lib/Grounded/see/reportcard/ReportCardScreenState.dart index 0b82b0b..6f4b6df 100644 --- a/frontend/lib/Grounded/see/reportcard/ReportCardScreenState.dart +++ b/frontend/lib/Grounded/see/reportcard/ReportCardScreenState.dart @@ -99,7 +99,7 @@ class ReportCardScreenState extends State padding: const EdgeInsets.fromLTRB(16, 14, 16, 14), decoration: BoxDecoration( color: colorWhite.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.zero, ), child: Row( children: [ @@ -128,7 +128,7 @@ class ReportCardScreenState extends State alignment: Alignment.center, decoration: BoxDecoration( color: colorWhite, - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.zero, ), child: text(_report.grade, 26, TextType.Light, color: colorPrimaryDark), diff --git a/frontend/lib/Grounded/see/routine/RoutineBuilderState.dart b/frontend/lib/Grounded/see/routine/RoutineBuilderState.dart index d28ae45..8b8a510 100644 --- a/frontend/lib/Grounded/see/routine/RoutineBuilderState.dart +++ b/frontend/lib/Grounded/see/routine/RoutineBuilderState.dart @@ -402,7 +402,7 @@ class RoutineBuilderState extends State height: 124, padding: const EdgeInsets.all(12), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.zero, gradient: selected ? LinearGradient( begin: Alignment.topLeft, @@ -424,7 +424,6 @@ class RoutineBuilderState extends State color: selected ? colorWhite.withValues(alpha: 0.16) : kindBackground(kind), - shape: BoxShape.circle, ), child: Icon(kindIcon(kind), size: 17, color: selected ? colorWhite : tone), @@ -470,7 +469,7 @@ class RoutineBuilderState extends State padding: const EdgeInsets.fromLTRB(14, 12, 14, 12), decoration: BoxDecoration( color: applied ? kindBackground(_routine.kind) : colorWhite, - borderRadius: BorderRadius.circular(14), + borderRadius: BorderRadius.zero, border: Border.all( color: applied ? kindColor(_routine.kind).withValues(alpha: 0.4) @@ -515,7 +514,6 @@ class RoutineBuilderState extends State alignment: Alignment.center, decoration: BoxDecoration( color: on ? tone : colorWhite, - shape: BoxShape.circle, border: Border.all(color: on ? tone : colorBorder), ), child: text(weekdayInitial(day), 13, @@ -576,7 +574,7 @@ class RoutineBuilderState extends State alignment: Alignment.center, decoration: BoxDecoration( color: kindBackground(_routine.kind), - borderRadius: BorderRadius.circular(9), + borderRadius: BorderRadius.zero, ), child: text("${index + 1}", 12, TextType.Bold, color: tone), ), diff --git a/frontend/lib/Grounded/see/routine/RoutineRunnerState.dart b/frontend/lib/Grounded/see/routine/RoutineRunnerState.dart index 1f042a3..d623b30 100644 --- a/frontend/lib/Grounded/see/routine/RoutineRunnerState.dart +++ b/frontend/lib/Grounded/see/routine/RoutineRunnerState.dart @@ -457,7 +457,7 @@ class RoutineRunnerState extends State Widget _totalPill() { return GlassSurface( onDark: true, - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 11), child: Row( mainAxisSize: MainAxisSize.min, @@ -496,7 +496,7 @@ class RoutineRunnerState extends State track: colorWhite.withValues(alpha: 0.22), child: GlassSurface( onDark: true, - radius: BorderRadius.circular(100), + radius: BorderRadius.zero, child: SizedBox( width: 150, height: 150, @@ -552,7 +552,7 @@ class RoutineRunnerState extends State ), GlassSurface( onDark: true, - radius: BorderRadius.circular(200), + radius: BorderRadius.zero, child: SizedBox( width: 120 + 50 * t, height: 120 + 50 * t, @@ -588,7 +588,7 @@ class RoutineRunnerState extends State children: [ GlassSurface( onDark: true, - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), child: Row( mainAxisSize: MainAxisSize.min, @@ -610,7 +610,7 @@ class RoutineRunnerState extends State const SizedBox(width: 8), GlassSurface( onDark: true, - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), child: text("Left app ${_run.backgroundedCount}×", 11, TextType.Medium, @@ -727,7 +727,6 @@ class RoutineRunnerState extends State height: size, padding: const EdgeInsets.all(2.5), decoration: BoxDecoration( - shape: BoxShape.circle, color: isCurrent ? colorNight : colorWhite, boxShadow: const [ BoxShadow( @@ -737,7 +736,7 @@ class RoutineRunnerState extends State ), ], ), - child: ClipOval( + child: ClipRect( child: Stack( fit: StackFit.expand, children: [ @@ -794,7 +793,7 @@ class RoutineRunnerState extends State margin: const EdgeInsets.only(right: 4), decoration: BoxDecoration( color: filled || active ? tone : tone.withValues(alpha: 0.15), - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, ), ); }), @@ -894,7 +893,7 @@ class RoutineRunnerState extends State alignment: Alignment.center, decoration: BoxDecoration( color: colorNight, - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, boxShadow: const [ BoxShadow( color: Color(0x331A1F1C), @@ -956,8 +955,8 @@ class RoutineRunnerState extends State decoration: const BoxDecoration( color: colorSheetBackground, borderRadius: BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: ListView( @@ -985,7 +984,7 @@ class RoutineRunnerState extends State padding: const EdgeInsets.fromLTRB(12, 12, 14, 12), decoration: BoxDecoration( color: current ? kindBackground(_run.chain.kind) : colorWhite, - borderRadius: BorderRadius.circular(14), + borderRadius: BorderRadius.zero, border: Border.all( color: current ? tone.withValues(alpha: 0.35) : colorBorder, ), @@ -998,7 +997,6 @@ class RoutineRunnerState extends State alignment: Alignment.center, decoration: BoxDecoration( color: step.completed ? tone : colorSecondary, - shape: BoxShape.circle, ), child: step.completed ? Icon(Icons.check_rounded, @@ -1072,7 +1070,7 @@ class RoutineRunnerState extends State children: [ GlassSurface( onDark: true, - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 7), child: text( @@ -1096,7 +1094,7 @@ class RoutineRunnerState extends State track: colorWhite.withValues(alpha: 0.3), child: GlassSurface( onDark: true, - radius: BorderRadius.circular(100), + radius: BorderRadius.zero, child: SizedBox( width: 158, height: 158, @@ -1128,7 +1126,7 @@ class RoutineRunnerState extends State ), const SizedBox(height: 22), GlassSurface( - radius: BorderRadius.circular(24), + radius: BorderRadius.zero, tint: colorGlassStrong, padding: const EdgeInsets.fromLTRB(18, 16, 18, 16), child: Row( diff --git a/frontend/lib/Grounded/see/routine/RoutinesState.dart b/frontend/lib/Grounded/see/routine/RoutinesState.dart index aa98603..749ac0c 100644 --- a/frontend/lib/Grounded/see/routine/RoutinesState.dart +++ b/frontend/lib/Grounded/see/routine/RoutinesState.dart @@ -330,7 +330,7 @@ class RoutinesState extends State implements ConnectRoutines { ..sort((a, b) => a.startMinute.compareTo(b.startMinute)); return GlassSurface( - radius: BorderRadius.circular(24), + radius: BorderRadius.zero, tint: colorGlassStrong, padding: const EdgeInsets.fromLTRB(18, 16, 18, 16), child: Row( @@ -391,18 +391,17 @@ class RoutinesState extends State implements ConnectRoutines { onTap: () => _onSelectKind(kind), behavior: HitTestBehavior.opaque, child: SizedBox( - width: 74, + width: 88, child: Column( mainAxisSize: MainAxisSize.min, children: [ AnimatedContainer( duration: const Duration(milliseconds: 200), curve: Curves.easeOut, - width: 64, - height: 64, + width: 78, + height: 78, padding: const EdgeInsets.all(2.5), decoration: BoxDecoration( - shape: BoxShape.circle, color: selected ? colorNight : colorWhite, boxShadow: const [ BoxShadow( @@ -412,7 +411,7 @@ class RoutinesState extends State implements ConnectRoutines { ), ], ), - child: ClipOval( + child: ClipRect( child: kind == null ? Container( color: colorWhite, @@ -450,7 +449,7 @@ class RoutinesState extends State implements ConnectRoutines { final List items = _upNext; return SizedBox( - height: 240, + height: 290, child: ListView.separated( scrollDirection: Axis.horizontal, clipBehavior: Clip.none, @@ -470,9 +469,9 @@ class RoutinesState extends State implements ConnectRoutines { return GestureDetector( onTap: () => _onPreview(routine), child: Container( - width: 200, + width: 244, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(26), + borderRadius: BorderRadius.zero, boxShadow: const [ BoxShadow( color: Color(0x262A3A30), @@ -482,7 +481,7 @@ class RoutinesState extends State implements ConnectRoutines { ], ), child: ClipRRect( - borderRadius: BorderRadius.circular(26), + borderRadius: BorderRadius.zero, child: Stack( fit: StackFit.expand, children: [ @@ -503,7 +502,7 @@ class RoutinesState extends State implements ConnectRoutines { children: [ GlassSurface( onDark: true, - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 5), child: text( @@ -611,10 +610,10 @@ class RoutinesState extends State implements ConnectRoutines { child: Row( children: [ SizedBox( - width: 70, - height: 70, + width: 90, + height: 90, child: ClipRRect( - borderRadius: BorderRadius.circular(18), + borderRadius: BorderRadius.zero, child: SceneArt( palette: scenePalette(routine.kind), seed: sceneSeed(routine.title), @@ -665,7 +664,6 @@ class RoutinesState extends State implements ConnectRoutines { alignment: Alignment.center, decoration: BoxDecoration( color: tone, - shape: BoxShape.circle, ), child: Icon(Icons.check_rounded, size: 22, color: colorWhite), @@ -717,8 +715,8 @@ class RoutinesState extends State implements ConnectRoutines { decoration: const BoxDecoration( color: colorAmbientMid, borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), clipBehavior: Clip.antiAlias, @@ -755,7 +753,7 @@ class RoutinesState extends State implements ConnectRoutines { height: 4, decoration: BoxDecoration( color: colorWhite.withValues(alpha: 0.7), - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, ), ), ), @@ -772,7 +770,7 @@ class RoutinesState extends State implements ConnectRoutines { children: [ GlassSurface( onDark: true, - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 5), child: text(kindLabel(routine.kind), 10, @@ -782,7 +780,7 @@ class RoutinesState extends State implements ConnectRoutines { const SizedBox(width: 6), GlassSurface( onDark: true, - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 5), child: text( @@ -816,7 +814,7 @@ class RoutinesState extends State implements ConnectRoutines { const SizedBox(height: 16), ], GlassSurface( - radius: BorderRadius.circular(22), + radius: BorderRadius.zero, tint: colorGlassStrong, padding: const EdgeInsets.fromLTRB(16, 14, 16, 14), child: Row( @@ -895,7 +893,7 @@ class RoutinesState extends State implements ConnectRoutines { padding: const EdgeInsets.fromLTRB(10, 10, 14, 10), decoration: BoxDecoration( color: colorWhite, - borderRadius: BorderRadius.circular(18), + borderRadius: BorderRadius.zero, ), child: Row( children: [ @@ -905,7 +903,6 @@ class RoutinesState extends State implements ConnectRoutines { alignment: Alignment.center, decoration: BoxDecoration( color: tone.withValues(alpha: 0.10), - shape: BoxShape.circle, ), child: text("${index + 1}", 12, TextType.Medium, color: tone), ), diff --git a/frontend/lib/Grounded/see/routine/StepEditorState.dart b/frontend/lib/Grounded/see/routine/StepEditorState.dart index 5d4c4d1..d301186 100644 --- a/frontend/lib/Grounded/see/routine/StepEditorState.dart +++ b/frontend/lib/Grounded/see/routine/StepEditorState.dart @@ -67,8 +67,8 @@ class StepEditorState extends State { decoration: const BoxDecoration( color: colorSheetBackground, borderRadius: BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: SingleChildScrollView( @@ -234,7 +234,7 @@ class StepEditorState extends State { padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( color: kindBackground(widget.kind), - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.zero, ), child: Row( children: [ diff --git a/frontend/lib/Grounded/see/settings/SettingsState.dart b/frontend/lib/Grounded/see/settings/SettingsState.dart index 313d284..d965f6d 100644 --- a/frontend/lib/Grounded/see/settings/SettingsState.dart +++ b/frontend/lib/Grounded/see/settings/SettingsState.dart @@ -93,8 +93,8 @@ class SettingsState extends State implements ConnectSettings { decoration: BoxDecoration( color: colorSheetBackground, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), + topLeft: Radius.zero, + topRight: Radius.zero, ), ), child: SingleChildScrollView( @@ -112,7 +112,7 @@ class SettingsState extends State implements ConnectSettings { margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: colorGrey.withValues(alpha: 0.35), - borderRadius: BorderRadius.circular(999), + borderRadius: BorderRadius.zero, ), ), ), @@ -222,7 +222,7 @@ class SettingsState extends State implements ConnectSettings { color: _amnestyRemaining > 0 ? colorStandingGoodBg : colorMuted, - borderRadius: BorderRadius.circular(14), + borderRadius: BorderRadius.zero, ), child: Icon( CupertinoIcons.checkmark_shield_fill, diff --git a/frontend/lib/Grounded/see/splash/SplashState.dart b/frontend/lib/Grounded/see/splash/SplashState.dart index c8b5117..4e45032 100644 --- a/frontend/lib/Grounded/see/splash/SplashState.dart +++ b/frontend/lib/Grounded/see/splash/SplashState.dart @@ -239,7 +239,7 @@ class SplashState extends State implements ConnectSplash { ], ), GlassSurface( - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), child: Row( mainAxisSize: MainAxisSize.min, @@ -299,11 +299,11 @@ class SplashState extends State implements ConnectSplash { Widget _mark() { return GlassSurface( - radius: BorderRadius.circular(46), + radius: BorderRadius.zero, padding: const EdgeInsets.all(10), child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(34), + borderRadius: BorderRadius.zero, boxShadow: [ BoxShadow( color: colorPrimary.withValues(alpha: 0.4), @@ -342,7 +342,7 @@ class SplashState extends State implements ConnectSplash { alignment: alignment, child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(99), + borderRadius: BorderRadius.zero, boxShadow: const [ BoxShadow( color: Color(0x142A3A30), @@ -352,7 +352,7 @@ class SplashState extends State implements ConnectSplash { ], ), child: GlassSurface( - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, tint: colorGlassStrong, padding: const EdgeInsets.fromLTRB(4, 4, 12, 4), child: Row( @@ -424,7 +424,7 @@ class SplashState extends State implements ConnectSplash { /// The whole idea in three beats, on glass over the valley. Widget _howItWorks() { return GlassSurface( - radius: BorderRadius.circular(24), + radius: BorderRadius.zero, tint: colorGlassStrong, padding: const EdgeInsets.fromLTRB(14, 14, 14, 14), child: Row( @@ -499,7 +499,7 @@ class SplashState extends State implements ConnectSplash { return Column( children: [ GlassSurface( - radius: BorderRadius.circular(99), + radius: BorderRadius.zero, padding: const EdgeInsets.all(3), child: SizedBox( width: 150, @@ -510,7 +510,7 @@ class SplashState extends State implements ConnectSplash { width: 150, decoration: BoxDecoration( color: colorNight, - borderRadius: BorderRadius.circular(99), + borderRadius: BorderRadius.zero, ), ).animate().scaleX( begin: 0.04, diff --git a/frontend/lib/Grounded/see/system/sessionexpired/SessionExpiredState.dart b/frontend/lib/Grounded/see/system/sessionexpired/SessionExpiredState.dart index 7c9ef0b..f97d1af 100644 --- a/frontend/lib/Grounded/see/system/sessionexpired/SessionExpiredState.dart +++ b/frontend/lib/Grounded/see/system/sessionexpired/SessionExpiredState.dart @@ -71,7 +71,7 @@ class SessionExpiredState extends State alignment: Alignment.center, decoration: BoxDecoration( color: colorWhite.withValues(alpha: 0.10), - borderRadius: BorderRadius.circular(18), + borderRadius: BorderRadius.zero, ), child: Icon(CupertinoIcons.lock_fill, size: 24, color: colorWhite), diff --git a/frontend/lib/Grounded/see/system/updateme/UpdateMeState.dart b/frontend/lib/Grounded/see/system/updateme/UpdateMeState.dart index f7fa51f..4968a18 100644 --- a/frontend/lib/Grounded/see/system/updateme/UpdateMeState.dart +++ b/frontend/lib/Grounded/see/system/updateme/UpdateMeState.dart @@ -68,7 +68,7 @@ class UpdateMeState extends State implements ConnectUpdateMe { alignment: Alignment.center, decoration: BoxDecoration( color: colorWhite.withValues(alpha: 0.10), - borderRadius: BorderRadius.circular(18), + borderRadius: BorderRadius.zero, ), child: Icon(CupertinoIcons.arrow_up_circle_fill, size: 24, color: colorWhite), diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart index 4d98518..9561b33 100644 --- a/frontend/lib/main.dart +++ b/frontend/lib/main.dart @@ -48,7 +48,7 @@ class GroundedApp extends StatelessWidget { fontSize: 17, ), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20), + borderRadius: BorderRadius.zero, ), ), ),