From 39d9f7e0530e0e92a0581eb11d1790e9e64fe981 Mon Sep 17 00:00:00 2001 From: bvandeusen Date: Mon, 6 Apr 2026 06:35:31 -0400 Subject: [PATCH] docs: add Android nav restructure + projects staleness fix spec --- ...26-04-06-android-nav-restructure-design.md | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-06-android-nav-restructure-design.md diff --git a/docs/superpowers/specs/2026-04-06-android-nav-restructure-design.md b/docs/superpowers/specs/2026-04-06-android-nav-restructure-design.md new file mode 100644 index 0000000..d412df7 --- /dev/null +++ b/docs/superpowers/specs/2026-04-06-android-nav-restructure-design.md @@ -0,0 +1,136 @@ +# Android Nav Restructure & Projects Staleness Fix + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace the Projects bottom-nav tab with a "More" bottom sheet that houses Projects, News, and Calendar; fix stale task data on the project tasks screen. + +**Architecture:** The shell's 4th nav item becomes a non-routing action — tapping it shows a `showModalBottomSheet` with the three overflow destinations. `_tabIndex()` maps `/projects`, `/news`, `/calendar` prefixes to index 3 so the "More" tab highlights correctly. News and Calendar are added as stub push-routes now; their real screens are built in subsequent passes. The staleness fix is a single `await` + `ref.invalidate` after returning from task edit. + +**Tech Stack:** Flutter, GoRouter, Riverpod, Material 3 `NavigationBar` / `NavigationRail` + +--- + +## Scope + +Two independent changes in one pass: + +1. **Nav restructure** — `lib/app.dart` +2. **Staleness fix** — `lib/screens/library/project_tasks_screen.dart` + +--- + +## Design Details + +### 1. Nav Restructure (`lib/app.dart`) + +**Route changes:** +- Remove `/projects` from the `ShellRoute` routes list. +- Add three new top-level `GoRoute` entries (alongside the existing non-shell routes): + - `/projects` → `ProjectsScreen()` (moved from shell) + - `/news` → stub `Scaffold(body: Center(child: Text('News — coming soon')))` + - `/calendar` → stub `Scaffold(body: Center(child: Text('Calendar — coming soon')))` +- Add route constants to `lib/core/constants.dart`: `news = '/news'`, `calendar = '/calendar'` + +**Shell tab list:** +```dart +static const _tabs = [ + Routes.briefing, + Routes.knowledge, + Routes.conversations, +]; +``` +(3 entries — "More" is index 3 but handled specially, not a route) + +**`_tabIndex()` update:** +```dart +int _tabIndex(String location) { + for (var i = 0; i < _tabs.length; i++) { + if (location.startsWith(_tabs[i])) return i; + } + // Projects, News, Calendar all highlight "More" + if (location.startsWith(Routes.projects) || + location.startsWith(Routes.news) || + location.startsWith(Routes.calendar)) return 3; + return 0; +} +``` + +**`onDestinationSelected` update (both `NavigationBar` and `NavigationRail`):** +```dart +onDestinationSelected: (i) { + if (i == 3) { + _showMoreSheet(context); + } else { + context.go(_tabs[i]); + } +}, +``` + +**`_showMoreSheet` method on `_ShellState`:** +```dart +void _showMoreSheet(BuildContext context) { + showModalBottomSheet( + context: context, + builder: (_) => SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.folder_outlined), + title: const Text('Projects'), + onTap: () { + Navigator.pop(context); + context.push(Routes.projects); + }, + ), + ListTile( + leading: const Icon(Icons.newspaper_outlined), + title: const Text('News'), + onTap: () { + Navigator.pop(context); + context.push(Routes.news); + }, + ), + ListTile( + leading: const Icon(Icons.calendar_month_outlined), + title: const Text('Calendar'), + onTap: () { + Navigator.pop(context); + context.push(Routes.calendar); + }, + ), + ], + ), + ), + ); +} +``` + +**4th nav destination label:** "More" with `Icons.more_horiz_outlined` / `Icons.more_horiz`. + +**NavigationRail note:** The wide-layout rail also gets the same 4 destinations and the same intercept on `onDestinationSelected`. + +--- + +### 2. Projects Staleness Fix (`lib/screens/library/project_tasks_screen.dart`) + +**Current (line ~321):** +```dart +context.push(Routes.taskEdit.replaceFirst(':id', '${task.id}')); +``` + +**Fixed:** +```dart +await context.push(Routes.taskEdit.replaceFirst(':id', '${task.id}')); +ref.invalidate(projectTasksProvider(widget.projectId)); +``` + +This re-fetches tasks as soon as the user pops back from the task edit screen, eliminating stale data. + +--- + +## What This Does NOT Include + +- Real News screen implementation (separate spec/pass) +- Real Calendar screen implementation (separate spec/pass) +- Any changes to the web frontend