mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-24 23:01:22 -04:00
feat(nav): rename tab labels to canonical order (#5551)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
8
.github/copilot-instructions.md
vendored
8
.github/copilot-instructions.md
vendored
@@ -57,6 +57,14 @@ KMP modules have different task names than pure-Android modules. Using the wrong
|
||||
- **Protos**: `core/proto/` is a read-only git submodule. Never modify proto files.
|
||||
- **Branches**: Must start with `feat/`, `fix/`, `chore/`, `docs/`, `build/`, `ci/`, `refactor/`, `test/`, `deps/`, or a numeric spec prefix. Always branch off `origin/main`.
|
||||
|
||||
<!-- SPECKIT START -->
|
||||
## Active Plan
|
||||
|
||||
- **Feature**: Reorder Bottom Navigation Tab Labels
|
||||
- **Plan**: `specs/20260520-153412-nav-tab-labels/plan.md`
|
||||
- **Branch**: `jamesarich/issue-5543-alignment-reorder-bottom-navigation-tab-91d55d`
|
||||
<!-- SPECKIT END -->
|
||||
|
||||
## Deeper Guidance
|
||||
|
||||
Consult `.skills/` for detailed playbooks:
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"feature_directory":"specs/20260520-153449-node-list-context-menu"}
|
||||
{"feature_directory":"specs/20260520-153412-nav-tab-labels"}
|
||||
|
||||
@@ -59,7 +59,7 @@ fun MainScreen() {
|
||||
// from the StateFlow (seeded from persisted prefs) so the initial tab is set in one shot.
|
||||
val initialTab =
|
||||
if (viewModel.currentDeviceAddressFlow.value.isNullOrSelectedNone()) {
|
||||
TopLevelDestination.Connections.route
|
||||
TopLevelDestination.Connect.route
|
||||
} else {
|
||||
NodesRoute.Nodes
|
||||
}
|
||||
@@ -82,7 +82,7 @@ fun MainScreen() {
|
||||
scrollToTopEvents = viewModel.scrollToTopEventFlow,
|
||||
onHandleDeepLink = viewModel::handleDeepLink,
|
||||
onNavigateToConnections = {
|
||||
multiBackstack.navigateTopLevel(TopLevelDestination.Connections.route)
|
||||
multiBackstack.navigateTopLevel(TopLevelDestination.Connect.route)
|
||||
},
|
||||
)
|
||||
mapGraph(backStack)
|
||||
|
||||
@@ -83,15 +83,13 @@ private val CurrentTabSaver =
|
||||
TopLevelDestination.entries.indexOfFirst { it.route::class == state.value::class }.takeIf { it >= 0 }
|
||||
},
|
||||
restore = { ordinal ->
|
||||
mutableStateOf(
|
||||
TopLevelDestination.entries.getOrNull(ordinal)?.route ?: TopLevelDestination.Connections.route,
|
||||
)
|
||||
mutableStateOf(TopLevelDestination.entries.getOrNull(ordinal)?.route ?: TopLevelDestination.Connect.route)
|
||||
},
|
||||
)
|
||||
|
||||
/** Remembers a [MultiBackstack] for managing independent tab navigation histories with Navigation 3. */
|
||||
@Composable
|
||||
fun rememberMultiBackstack(initialTab: NavKey = TopLevelDestination.Connections.route): MultiBackstack {
|
||||
fun rememberMultiBackstack(initialTab: NavKey = TopLevelDestination.Connect.route): MultiBackstack {
|
||||
val stacks = mutableMapOf<NavKey, NavBackStack<NavKey>>()
|
||||
|
||||
TopLevelDestination.entries.forEach { dest ->
|
||||
|
||||
@@ -20,9 +20,9 @@ import androidx.navigation3.runtime.NavKey
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.bottom_nav_settings
|
||||
import org.meshtastic.core.resources.connections
|
||||
import org.meshtastic.core.resources.conversations
|
||||
import org.meshtastic.core.resources.connect
|
||||
import org.meshtastic.core.resources.map
|
||||
import org.meshtastic.core.resources.messages
|
||||
import org.meshtastic.core.resources.nodes
|
||||
|
||||
/**
|
||||
@@ -32,11 +32,11 @@ import org.meshtastic.core.resources.nodes
|
||||
* and Desktop navigation shells.
|
||||
*/
|
||||
enum class TopLevelDestination(val label: StringResource, val route: Route) {
|
||||
Conversations(Res.string.conversations, ContactsRoute.Contacts),
|
||||
Messages(Res.string.messages, ContactsRoute.Contacts),
|
||||
Nodes(Res.string.nodes, NodesRoute.Nodes),
|
||||
Map(Res.string.map, MapRoute.Map()),
|
||||
Settings(Res.string.bottom_nav_settings, SettingsRoute.Settings()),
|
||||
Connections(Res.string.connections, ConnectionsRoute.Connections),
|
||||
Connect(Res.string.connect, ConnectionsRoute.Connections),
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -85,21 +85,21 @@ class MultiBackstackTest {
|
||||
|
||||
@Test
|
||||
fun `goBack on root of non-start tab returns to start tab`() {
|
||||
val startTab = TopLevelDestination.Connections.route
|
||||
val startTab = TopLevelDestination.Connect.route
|
||||
val multiBackstack = createMultiBackstack(startTab)
|
||||
|
||||
val mapStack = NavBackStack<NavKey>().apply { addAll(listOf(TopLevelDestination.Map.route)) }
|
||||
val connectionsStack = NavBackStack<NavKey>().apply { addAll(listOf(TopLevelDestination.Connections.route)) }
|
||||
val connectStack = NavBackStack<NavKey>().apply { addAll(listOf(TopLevelDestination.Connect.route)) }
|
||||
|
||||
multiBackstack.backStacks =
|
||||
mapOf(TopLevelDestination.Map.route to mapStack, TopLevelDestination.Connections.route to connectionsStack)
|
||||
mapOf(TopLevelDestination.Map.route to mapStack, TopLevelDestination.Connect.route to connectStack)
|
||||
|
||||
multiBackstack.navigateTopLevel(TopLevelDestination.Map.route)
|
||||
assertEquals(TopLevelDestination.Map.route, multiBackstack.currentTabRoute)
|
||||
|
||||
multiBackstack.goBack()
|
||||
|
||||
assertEquals(TopLevelDestination.Connections.route, multiBackstack.currentTabRoute)
|
||||
assertEquals(TopLevelDestination.Connect.route, multiBackstack.currentTabRoute)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -120,21 +120,18 @@ class MultiBackstackTest {
|
||||
|
||||
@Test
|
||||
fun `handleDeepLink from different tab switches tab and sets stack`() {
|
||||
// Start on Connections tab
|
||||
val startTab = TopLevelDestination.Connections.route
|
||||
// Start on Connect tab
|
||||
val startTab = TopLevelDestination.Connect.route
|
||||
val multiBackstack = createMultiBackstack(startTab)
|
||||
|
||||
val connectionsStack = NavBackStack<NavKey>().apply { addAll(listOf(TopLevelDestination.Connections.route)) }
|
||||
val connectStack = NavBackStack<NavKey>().apply { addAll(listOf(TopLevelDestination.Connect.route)) }
|
||||
val nodesStack = NavBackStack<NavKey>().apply { addAll(listOf(TopLevelDestination.Nodes.route)) }
|
||||
|
||||
multiBackstack.backStacks =
|
||||
mapOf(
|
||||
TopLevelDestination.Connections.route to connectionsStack,
|
||||
TopLevelDestination.Nodes.route to nodesStack,
|
||||
)
|
||||
mapOf(TopLevelDestination.Connect.route to connectStack, TopLevelDestination.Nodes.route to nodesStack)
|
||||
|
||||
// Verify we start on Connections
|
||||
assertEquals(TopLevelDestination.Connections.route, multiBackstack.currentTabRoute)
|
||||
// Verify we start on Connect
|
||||
assertEquals(TopLevelDestination.Connect.route, multiBackstack.currentTabRoute)
|
||||
|
||||
// Deep-link to a TracerouteMap on the Nodes tab (this is the exact pattern
|
||||
// MeshtasticAppShell uses for traceroute alert "View on Map")
|
||||
|
||||
@@ -150,7 +150,7 @@ private fun handleNavigation(
|
||||
}
|
||||
}
|
||||
|
||||
TopLevelDestination.Conversations -> {
|
||||
TopLevelDestination.Messages -> {
|
||||
val onConversationsList = currentKey is ContactsRoute.Contacts
|
||||
if (!onConversationsList) {
|
||||
multiBackstack.navigateTopLevel(destination.route)
|
||||
@@ -180,7 +180,7 @@ private fun NavigationIconContent(
|
||||
selectedDevice: String?,
|
||||
uiViewModel: UIViewModel,
|
||||
) {
|
||||
val isConnectionsRoute = destination == TopLevelDestination.Connections
|
||||
val isConnectionsRoute = destination == TopLevelDestination.Connect
|
||||
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
|
||||
@@ -211,7 +211,7 @@ private fun NavigationIconContent(
|
||||
} else {
|
||||
BadgedBox(
|
||||
badge = {
|
||||
if (destination == TopLevelDestination.Conversations) {
|
||||
if (destination == TopLevelDestination.Messages) {
|
||||
var lastNonZeroCount by remember { mutableIntStateOf(unreadMessageCount) }
|
||||
if (unreadMessageCount > 0) {
|
||||
lastNonZeroCount = unreadMessageCount
|
||||
|
||||
@@ -29,9 +29,9 @@ import org.meshtastic.core.resources.ic_wifi
|
||||
val TopLevelDestination.icon: DrawableResource
|
||||
get() =
|
||||
when (this) {
|
||||
TopLevelDestination.Conversations -> Res.drawable.ic_forum
|
||||
TopLevelDestination.Messages -> Res.drawable.ic_forum
|
||||
TopLevelDestination.Nodes -> Res.drawable.ic_nodes
|
||||
TopLevelDestination.Map -> Res.drawable.ic_map
|
||||
TopLevelDestination.Settings -> Res.drawable.ic_settings
|
||||
TopLevelDestination.Connections -> Res.drawable.ic_wifi
|
||||
TopLevelDestination.Connect -> Res.drawable.ic_wifi
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ private fun ApplicationScope.MeshtasticWindow(
|
||||
rememberMultiBackstack(
|
||||
// Land on Connections for first-run / no-device-selected; otherwise on Nodes.
|
||||
if (uiViewModel.currentDeviceAddressFlow.value.let { it.isNullOrBlank() || it == "n" }) {
|
||||
TopLevelDestination.Connections.route
|
||||
TopLevelDestination.Connect.route
|
||||
} else {
|
||||
TopLevelDestination.Nodes.route
|
||||
},
|
||||
@@ -360,7 +360,7 @@ private fun handleKeyboardShortcut(
|
||||
}
|
||||
|
||||
Key.One -> {
|
||||
multiBackstack.navigateTopLevel(TopLevelDestination.Conversations.route)
|
||||
multiBackstack.navigateTopLevel(TopLevelDestination.Messages.route)
|
||||
true
|
||||
}
|
||||
|
||||
@@ -375,7 +375,7 @@ private fun handleKeyboardShortcut(
|
||||
}
|
||||
|
||||
Key.Four -> {
|
||||
multiBackstack.navigateTopLevel(TopLevelDestination.Connections.route)
|
||||
multiBackstack.navigateTopLevel(TopLevelDestination.Connect.route)
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ fun EntryProviderScope<NavKey>.desktopNavGraph(
|
||||
backStack = backStack,
|
||||
scrollToTopEvents = uiViewModel.scrollToTopEventFlow,
|
||||
onHandleDeepLink = uiViewModel::handleDeepLink,
|
||||
onNavigateToConnections = { multiBackstack.navigateTopLevel(TopLevelDestination.Connections.route) },
|
||||
onNavigateToConnections = { multiBackstack.navigateTopLevel(TopLevelDestination.Connect.route) },
|
||||
)
|
||||
contactsGraph(backStack, uiViewModel.scrollToTopEventFlow)
|
||||
mapGraph(backStack)
|
||||
|
||||
@@ -30,8 +30,8 @@ import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
/**
|
||||
* Keeps Desktop top-level destinations aligned with Android top-level navigation (Conversations, Nodes, Map, Settings,
|
||||
* Connections).
|
||||
* Keeps Desktop top-level destinations aligned with Android top-level navigation (Messages, Nodes, Map, Settings,
|
||||
* Connect).
|
||||
*/
|
||||
class DesktopTopLevelDestinationParityTest {
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# Specification Quality Checklist: Reorder Bottom Navigation Tab Labels
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2025-05-20
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- All items pass. Specification is ready for `/speckit.clarify` or `/speckit.plan`.
|
||||
- This is a straightforward label rename with well-defined scope and clear acceptance criteria.
|
||||
- No [NEEDS CLARIFICATION] markers were needed — the issue description fully specifies the required changes.
|
||||
60
specs/20260520-153412-nav-tab-labels/data-model.md
Normal file
60
specs/20260520-153412-nav-tab-labels/data-model.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Data Model: Nav Tab Labels Rename
|
||||
|
||||
**Feature**: Reorder Bottom Navigation Tab Labels
|
||||
**Date**: 2026-05-20
|
||||
|
||||
## Entities
|
||||
|
||||
### TopLevelDestination (Enum)
|
||||
|
||||
The shared enum defining the canonical set of top-level navigation destinations.
|
||||
|
||||
| Entry | Label Resource | Route | Position |
|
||||
|-------|---------------|-------|----------|
|
||||
| `Messages` | `Res.string.messages` | `ContactsRoute.Contacts` | 1 |
|
||||
| `Nodes` | `Res.string.nodes` | `NodesRoute.Nodes` | 2 |
|
||||
| `Map` | `Res.string.map` | `MapRoute.Map()` | 3 |
|
||||
| `Settings` | `Res.string.bottom_nav_settings` | `SettingsRoute.Settings()` | 4 |
|
||||
| `Connect` | `Res.string.connect` | `ConnectionsRoute.Connections` | 5 |
|
||||
|
||||
**Changes from current**:
|
||||
- `Conversations` → `Messages` (entry rename, label resource changes)
|
||||
- `Connections` → `Connect` (entry rename, label resource changes)
|
||||
|
||||
### String Resources (New Keys)
|
||||
|
||||
| Key | Value (English) | Usage |
|
||||
|-----|----------------|-------|
|
||||
| `messages` | `Messages` | Tab label for Messages destination |
|
||||
| `connect` | `Connect` | Tab label for Connect destination |
|
||||
|
||||
### String Resources (Retained — No Changes)
|
||||
|
||||
| Key | Value (English) | Usage |
|
||||
|-----|----------------|-------|
|
||||
| `conversations` | `Conversations` | Screen title in Contacts.kt |
|
||||
| `connections` | `Connection` | Screen title in ConnectionsScreen.kt |
|
||||
|
||||
## Relationships
|
||||
|
||||
```
|
||||
TopLevelDestination.Messages
|
||||
├── label → Res.string.messages (NEW)
|
||||
├── route → ContactsRoute.Contacts (UNCHANGED)
|
||||
└── icon → Res.drawable.ic_forum (UNCHANGED, via TopLevelDestinationExt)
|
||||
|
||||
TopLevelDestination.Connect
|
||||
├── label → Res.string.connect (NEW)
|
||||
├── route → ConnectionsRoute.Connections (UNCHANGED)
|
||||
└── icon → Res.drawable.ic_wifi (UNCHANGED, via TopLevelDestinationExt)
|
||||
```
|
||||
|
||||
## State Transitions
|
||||
|
||||
N/A — No state machines affected. The enum is purely declarative.
|
||||
|
||||
## Validation Rules
|
||||
|
||||
- Tab order MUST remain: Messages (0), Nodes (1), Map (2), Settings (3), Connect (4)
|
||||
- Enum ordinal positions MUST NOT change (preserves `MultiBackstack` ordinal-based fallback)
|
||||
- Route objects MUST NOT change (preserves navigation, deep links, state restoration)
|
||||
79
specs/20260520-153412-nav-tab-labels/plan.md
Normal file
79
specs/20260520-153412-nav-tab-labels/plan.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Implementation Plan: Reorder Bottom Navigation Tab Labels
|
||||
|
||||
**Branch**: `jamesarich/issue-5543-alignment-reorder-bottom-navigation-tab-91d55d` | **Date**: 2026-05-20 | **Spec**: [spec.md](./spec.md)
|
||||
**Input**: Feature specification from `specs/20260520-153412-nav-tab-labels/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Rename two bottom navigation tab labels from "Conversations" → "Messages" and "Connections" → "Connect" to match the cross-platform canonical naming convention from the Menu Alignment Audit. Implementation involves: renaming the `TopLevelDestination` enum entries, adding new string resource keys for tab labels, and updating all references across the KMP codebase. Existing string keys are retained for screen titles.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Kotlin 2.3+ / JDK 21
|
||||
**Primary Dependencies**: Compose Multiplatform, Navigation 3, Koin 4.2+
|
||||
**Storage**: N/A (string resource change only)
|
||||
**Testing**: `./gradlew allTests` (KMP commonTest), `./gradlew test` (Android-only)
|
||||
**Target Platform**: Android (mobile), Desktop (JVM) — KMP shared code
|
||||
**Project Type**: Mobile app (KMP multiplatform)
|
||||
**Performance Goals**: N/A (label change only, no runtime impact)
|
||||
**Constraints**: Must not break navigation routing, deep links, or state restoration
|
||||
**Scale/Scope**: 7 files modified across 3 modules (`core:navigation`, `core:ui`, `core:resources`) + test updates
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- **I. Kotlin Multiplatform Core**: ✅ All changes are in `commonMain` source sets (`core/navigation`, `core/ui`, `core/resources`). No platform-specific (`androidMain`/`desktopMain`) code is modified. Enum rename and string resources are shared across all targets.
|
||||
- **II. Zero Lint Tolerance**: ✅ Will run: `./gradlew spotlessApply spotlessCheck detekt` for all touched modules. After adding string resources: `python3 scripts/sort-strings.py`.
|
||||
- **III. Compose Multiplatform UI**: ✅ No new UI composables introduced. The `MeshtasticNavigationSuite` already uses `TopLevelDestination.label` via `stringResource()`; the label change is purely data-driven. No float formatting involved.
|
||||
- **IV. Privacy First**: ✅ No PII, location data, or cryptographic keys involved. `core/proto` submodule is not touched.
|
||||
- **V. Design Standards Compliance**: ✅ This change directly implements the [Menu Alignment Audit](https://github.com/meshtastic/design/blob/master/standards/audits/menu-alignment-audit.md) from `meshtastic/design`. Cross-platform behavior spec is the audit itself.
|
||||
- **VI. Documentation Freshness**: ✅ No doc pages require updates — this is a label rename with no feature behavior change. Existing docs reference screen functionality, not tab label text.
|
||||
- **VII. Verify Before Push**: Will run:
|
||||
```bash
|
||||
./gradlew spotlessApply spotlessCheck detekt assembleDebug test allTests
|
||||
python3 scripts/sort-strings.py
|
||||
```
|
||||
Post-push: `gh pr checks <PR>` or `gh run list --branch jamesarich/issue-5543-alignment-reorder-bottom-navigation-tab-91d55d --limit 5`
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/20260520-153412-nav-tab-labels/
|
||||
├── plan.md # This file
|
||||
├── research.md # Phase 0 output
|
||||
├── data-model.md # Phase 1 output
|
||||
├── quickstart.md # Phase 1 output
|
||||
└── tasks.md # Phase 2 output (via /speckit.tasks)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
core/
|
||||
├── navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/
|
||||
│ ├── TopLevelDestination.kt # Enum entries renamed
|
||||
│ └── MultiBackstack.kt # References updated
|
||||
├── navigation/src/commonTest/kotlin/org/meshtastic/core/navigation/
|
||||
│ └── MultiBackstackTest.kt # Test references updated
|
||||
├── ui/src/commonMain/kotlin/org/meshtastic/core/ui/
|
||||
│ ├── navigation/TopLevelDestinationExt.kt # Icon mapping updated
|
||||
│ └── component/MeshtasticNavigationSuite.kt # References updated
|
||||
├── resources/src/commonMain/composeResources/values/
|
||||
│ └── strings.xml # New keys: messages, connect
|
||||
androidApp/src/main/kotlin/org/meshtastic/app/ui/
|
||||
│ └── Main.kt # References updated
|
||||
desktopApp/src/main/kotlin/org/meshtastic/desktop/
|
||||
│ ├── Main.kt # References updated
|
||||
│ └── navigation/DesktopNavigation.kt # References updated
|
||||
desktopApp/src/test/kotlin/org/meshtastic/desktop/ui/
|
||||
│ └── DesktopTopLevelDestinationParityTest.kt # May need update
|
||||
```
|
||||
|
||||
**Structure Decision**: Kotlin Multiplatform with shared `commonMain` source sets. All changes are in existing files; no new modules or directories created.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> No constitution violations. All gates pass.
|
||||
63
specs/20260520-153412-nav-tab-labels/quickstart.md
Normal file
63
specs/20260520-153412-nav-tab-labels/quickstart.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Quickstart: Nav Tab Labels Rename
|
||||
|
||||
**Feature**: Reorder Bottom Navigation Tab Labels
|
||||
**Date**: 2026-05-20
|
||||
|
||||
## Overview
|
||||
|
||||
This feature renames two `TopLevelDestination` enum entries and their associated string resources to align with the Meshtastic cross-platform Menu Alignment Audit.
|
||||
|
||||
## Implementation Steps (High-Level)
|
||||
|
||||
### Step 1: Add String Resources
|
||||
|
||||
Add two new keys to `core/resources/src/commonMain/composeResources/values/strings.xml`:
|
||||
```xml
|
||||
<string name="connect">Connect</string>
|
||||
<string name="messages">Messages</string>
|
||||
```
|
||||
|
||||
Then run: `python3 scripts/sort-strings.py`
|
||||
|
||||
### Step 2: Rename Enum Entries
|
||||
|
||||
In `core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/TopLevelDestination.kt`:
|
||||
- `Conversations(Res.string.conversations, ...)` → `Messages(Res.string.messages, ...)`
|
||||
- `Connections(Res.string.connections, ...)` → `Connect(Res.string.connect, ...)`
|
||||
|
||||
Update imports accordingly.
|
||||
|
||||
### Step 3: Update All References
|
||||
|
||||
Files requiring mechanical rename of `TopLevelDestination.Conversations` → `.Messages` and `.Connections` → `.Connect`:
|
||||
|
||||
1. `core/ui/.../TopLevelDestinationExt.kt` — icon `when` branches
|
||||
2. `core/ui/.../MeshtasticNavigationSuite.kt` — any explicit references
|
||||
3. `core/navigation/.../MultiBackstack.kt` — default tab reference
|
||||
4. `core/navigation/src/commonTest/.../MultiBackstackTest.kt` — test setup
|
||||
5. `androidApp/.../Main.kt` — Android entry point
|
||||
6. `desktopApp/.../Main.kt` — Desktop entry point
|
||||
7. `desktopApp/.../DesktopNavigation.kt` — Desktop nav shell
|
||||
|
||||
### Step 4: Verify
|
||||
|
||||
```bash
|
||||
./gradlew spotlessApply spotlessCheck detekt assembleDebug test allTests
|
||||
```
|
||||
|
||||
## Key Decisions
|
||||
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| New string keys (not reusing old) | Old keys used as screen titles elsewhere |
|
||||
| Enum entry rename (not just label) | Code clarity + spec requirement |
|
||||
| No route changes | Preserves deep links & state restoration |
|
||||
| No localization changes | Deferred to Crowdin sync cycle |
|
||||
|
||||
## Risks & Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|-----------|
|
||||
| Missed reference causes compile error | IDE rename refactoring + full `allTests` build |
|
||||
| Ordinal shift breaks MultiBackstack | Entries stay in same position — order unchanged |
|
||||
| Localized users see English fallback | Expected behavior for new keys until Crowdin sync |
|
||||
78
specs/20260520-153412-nav-tab-labels/research.md
Normal file
78
specs/20260520-153412-nav-tab-labels/research.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Research: Nav Tab Labels Rename
|
||||
|
||||
**Feature**: Reorder Bottom Navigation Tab Labels
|
||||
**Date**: 2026-05-20
|
||||
|
||||
## Research Tasks
|
||||
|
||||
### 1. Enum Rename Impact on Serialization / State Restoration
|
||||
|
||||
**Decision**: Renaming `TopLevelDestination.Conversations` → `Messages` and `TopLevelDestination.Connections` → `Connect` is safe for navigation state.
|
||||
|
||||
**Rationale**:
|
||||
- Navigation state is keyed by `NavKey` route objects (e.g., `ContactsRoute.Contacts`, `ConnectionsRoute.Connections`), NOT by enum entry names.
|
||||
- The `TopLevelDestination.route` property maps to typed route objects — the enum name is never serialized.
|
||||
- `MultiBackstack` stores `NavKey` instances in its back stack maps, keyed by route class identity (`it::class == dest.route::class`).
|
||||
- Process death restoration uses `SavedStateHandle` with route objects, not enum string names.
|
||||
|
||||
**Alternatives Considered**:
|
||||
- Keep old enum names and only change labels: Rejected because the spec explicitly requires renaming entries for code clarity and alignment with the canonical naming.
|
||||
|
||||
### 2. String Resource Key Strategy
|
||||
|
||||
**Decision**: Add new keys `messages` and `connect` for tab labels. Retain existing keys `conversations` and `connections` for screen titles.
|
||||
|
||||
**Rationale**:
|
||||
- `conversations` is used in `Contacts.kt` for the screen title (confirmed from spec clarification session).
|
||||
- `connections` is used in `ConnectionsScreen.kt` for the screen/section title.
|
||||
- Separating tab label keys from screen title keys allows independent localization and prevents unintended label changes elsewhere.
|
||||
- The `connections` key currently has value "Connection" (singular) — this is a screen title, not a tab label.
|
||||
|
||||
**Alternatives Considered**:
|
||||
- Reuse existing keys and rename their values: Rejected because it would change screen titles in feature modules that are out of scope.
|
||||
- Use `tab_messages` / `tab_connect` prefixed keys: Rejected in favor of simpler `messages` / `connect` per clarification decision.
|
||||
|
||||
### 3. Compose Resource Import Changes
|
||||
|
||||
**Decision**: After adding `messages` and `connect` to `strings.xml`, the generated `Res.string.messages` and `Res.string.connect` accessors will be available after a build.
|
||||
|
||||
**Rationale**:
|
||||
- Compose Multiplatform generates accessor objects from resource keys at compile time.
|
||||
- Import statements in `TopLevelDestination.kt` will change from `org.meshtastic.core.resources.conversations` / `org.meshtastic.core.resources.connections` to `org.meshtastic.core.resources.messages` / `org.meshtastic.core.resources.connect`.
|
||||
- Old imports (`conversations`, `connections`) remain valid since those keys are retained — they just won't be used in `TopLevelDestination.kt` anymore.
|
||||
|
||||
**Alternatives Considered**: None — this is the standard Compose Resources workflow.
|
||||
|
||||
### 4. Test Impact Assessment
|
||||
|
||||
**Decision**: Update `MultiBackstackTest.kt` references from `TopLevelDestination.Connections` to `TopLevelDestination.Connect`. The `DesktopTopLevelDestinationParityTest.kt` tests enum parity generically (iterates `entries`) and requires no changes.
|
||||
|
||||
**Rationale**:
|
||||
- `MultiBackstackTest.kt` explicitly references `TopLevelDestination.Connections` in 8 locations for default tab setup.
|
||||
- The parity test uses `TopLevelDestination.entries` enumeration, so it adapts automatically to renamed entries.
|
||||
- No test logic changes needed — only identifier renames.
|
||||
|
||||
**Alternatives Considered**: None — mechanical rename with no behavioral changes.
|
||||
|
||||
### 5. Sort Script for String Resources
|
||||
|
||||
**Decision**: Run `python3 scripts/sort-strings.py` after adding new keys to maintain alphabetical ordering.
|
||||
|
||||
**Rationale**:
|
||||
- Constitution (Development Workflow) mandates running this script after any string resource addition.
|
||||
- Keys `connect` and `messages` will be inserted alphabetically by the script.
|
||||
- `strings-index.txt` will be regenerated automatically.
|
||||
|
||||
**Alternatives Considered**: None — this is a mandatory workflow step.
|
||||
|
||||
## Summary of Resolved Items
|
||||
|
||||
| Item | Resolution |
|
||||
|------|-----------|
|
||||
| Enum rename breaks state? | No — routes use typed objects, not enum names |
|
||||
| String key strategy | New keys `messages`/`connect`; old keys retained |
|
||||
| Import changes | Mechanical — generated accessors update on build |
|
||||
| Test updates needed | `MultiBackstackTest.kt` identifier renames only |
|
||||
| Post-change workflow | `python3 scripts/sort-strings.py` required |
|
||||
|
||||
All NEEDS CLARIFICATION items resolved. No open questions remain.
|
||||
157
specs/20260520-153412-nav-tab-labels/spec.md
Normal file
157
specs/20260520-153412-nav-tab-labels/spec.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# Feature Specification: Reorder Bottom Navigation Tab Labels
|
||||
|
||||
**Feature Branch**: `jamesarich/issue-5543-alignment-reorder-bottom-navigation-tab-91d55d`
|
||||
**Created**: 2025-05-20
|
||||
**Status**: Draft
|
||||
**Input**: User description: "Issue #5543 - Reorder bottom navigation tabs to canonical order per Menu Alignment Audit"
|
||||
**Cross-Platform Spec**: [Menu Alignment Audit](https://github.com/meshtastic/design/blob/master/standards/audits/menu-alignment-audit.md)
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2026-05-20
|
||||
|
||||
- Q: Should string resource keys be renamed (not just display values)? → A: Yes — create new keys `messages` and `connect` for nav tab labels. Old keys (`conversations`, `connections`) remain for screen titles in Contacts.kt and ConnectionsScreen.kt.
|
||||
- Q: Should localized strings.xml files be updated in this PR? → A: No — defer to Crowdin. Only update English `values/strings.xml`; localized files pick up new keys in next translation sync.
|
||||
|
||||
## Summary
|
||||
|
||||
Rename two bottom navigation tab labels to match the cross-platform canonical naming convention defined in the Meshtastic Menu Alignment Audit. "Conversations" becomes "Messages" and "Connections" becomes "Connect". Tab order already matches the canonical order and requires no positional changes.
|
||||
|
||||
## Goals
|
||||
|
||||
1. Achieve cross-platform label consistency by aligning Android tab names with the canonical standard
|
||||
2. Improve user familiarity by using industry-standard terminology ("Messages" for messaging)
|
||||
3. Reduce cognitive friction for users switching between Meshtastic clients on different platforms
|
||||
4. Maintain existing navigation behavior and tab ordering without regressions
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Changing the tab order (already matches canonical: Messages, Nodes, Map, Settings, Connect)
|
||||
- Redesigning tab icons or visual styling
|
||||
- Adding, removing, or merging navigation tabs
|
||||
- Changing functionality behind any tab
|
||||
- Modifying navigation deep link route identifiers (only user-visible labels change)
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - See Updated Tab Labels (Priority: P1)
|
||||
|
||||
As a Meshtastic Android user, I see "Messages" and "Connect" as tab labels so that the interface matches documentation and other platform clients.
|
||||
|
||||
**Why this priority**: This is the core deliverable — the visual label change that achieves cross-platform alignment.
|
||||
|
||||
**Independent Test**: Open the app after update; visually confirm bottom navigation bar shows "Messages" (position 1) and "Connect" (position 5).
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the app is launched, **When** the bottom navigation bar is visible, **Then** the first tab reads "Messages" (not "Conversations")
|
||||
2. **Given** the app is launched, **When** the bottom navigation bar is visible, **Then** the fifth tab reads "Connect" (not "Connections")
|
||||
3. **Given** the app is launched, **When** the bottom navigation bar is visible, **Then** tab order is: Messages, Nodes, Map, Settings, Connect
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Navigation Still Functions After Rename (Priority: P1)
|
||||
|
||||
As a user, I can tap the renamed tabs and navigate to the correct screens without any change in behavior.
|
||||
|
||||
**Why this priority**: Equal to P1 because broken navigation would be a blocking regression.
|
||||
|
||||
**Independent Test**: Tap "Messages" tab → messaging screen loads; tap "Connect" tab → connection/pairing screen loads.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the user is on any screen, **When** they tap "Messages", **Then** the messaging/conversations screen appears
|
||||
2. **Given** the user is on any screen, **When** they tap "Connect", **Then** the device connection/pairing screen appears
|
||||
3. **Given** the user taps between all five tabs in rapid succession, **When** each tab is selected, **Then** the correct corresponding screen displays without delay or error
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Deep Links and State Restoration Work (Priority: P2)
|
||||
|
||||
As a user who receives a notification or restores the app from background, deep links and saved navigation state continue to route correctly.
|
||||
|
||||
**Why this priority**: Ensures no regression in system-level navigation behavior that relies on route identifiers.
|
||||
|
||||
**Independent Test**: Trigger a message notification → tap it → app opens to the messaging screen. Kill and restore the app → previously selected tab is restored.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the app is in the background and a message notification arrives, **When** the user taps the notification, **Then** the app navigates to the messaging screen (now labeled "Messages")
|
||||
2. **Given** the user is on the "Connect" tab and the system kills the app, **When** the app is restored, **Then** the "Connect" tab is selected and the connection screen is displayed
|
||||
3. **Given** a deep link targets the messaging section, **When** the link is activated, **Then** the app navigates to the messaging screen under the "Messages" tab
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens if a user has the old version cached and updates? Label change takes effect immediately as it is a string resource change.
|
||||
- How does the app behave with localized strings? Localized translations for these labels should also be updated for all supported languages.
|
||||
- What about accessibility services (TalkBack)? The new labels ("Messages", "Connect") are announced correctly by screen readers since they derive from the same string resources.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Key Components
|
||||
|
||||
| Component | Module / File | Purpose |
|
||||
|-----------|---------------|---------|
|
||||
| Navigation bar strings | `core/resources/src/commonMain/composeResources/values/strings.xml` | New keys `messages` and `connect` for tab labels; old keys retained for screen titles |
|
||||
| Localized strings | `core/resources/src/commonMain/composeResources/values-*/strings.xml` | Deferred — new keys picked up in next Crowdin sync |
|
||||
| Bottom navigation composable | Navigation component referencing string resources | Displays tab labels in bottom bar |
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The bottom navigation tab currently labeled "Conversations" MUST display "Messages" in English locale
|
||||
- **FR-002**: The bottom navigation tab currently labeled "Connections" (or "Connection") MUST display "Connect" in English locale
|
||||
- **FR-003**: Tab order MUST remain: Messages, Nodes, Map, Settings, Connect (positions 1–5)
|
||||
- **FR-004**: Tapping any renamed tab MUST navigate to the same destination screen as before the rename
|
||||
- **FR-005**: Deep links that previously routed to the Conversations or Connections screens MUST continue to function
|
||||
- **FR-006**: State restoration MUST correctly restore the selected tab after process death
|
||||
|
||||
### Non-Functional Requirements
|
||||
|
||||
- **NFR-001**: Accessibility — screen readers MUST announce the updated labels ("Messages", "Connect") when tabs receive focus
|
||||
- **NFR-002**: Localization — translated string values are deferred to next Crowdin sync; only English `values/strings.xml` is updated in this change
|
||||
- **NFR-003**: No user-perceivable performance impact from the label change
|
||||
|
||||
## Source-Set Impact
|
||||
|
||||
| Source Set | Impact | Justification |
|
||||
|-----------|--------|---------------|
|
||||
| `commonMain` | Modified string resources | Tab labels are defined in shared compose resources |
|
||||
| `androidMain` | None | No platform-specific changes needed |
|
||||
| `jvmMain` | None | No desktop-specific changes needed |
|
||||
|
||||
## Design Standards Compliance
|
||||
|
||||
- [x] New screens reviewed against design standards — No new screens; existing screens unchanged
|
||||
- [x] M3 component selection verified — No component changes
|
||||
- [ ] Accessibility: TalkBack semantics, touch targets, color-independent info — Verify renamed labels are announced correctly
|
||||
- [x] Typography: No typography changes
|
||||
|
||||
## Privacy Assessment
|
||||
|
||||
- [x] No PII, location data, or cryptographic keys logged or exposed
|
||||
- [x] No new network calls that transmit user data
|
||||
- [x] Proto submodule (`core/proto`) not modified (read-only upstream)
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: 100% of users see "Messages" as the first tab label after updating the app
|
||||
- **SC-002**: 100% of users see "Connect" as the fifth tab label after updating the app
|
||||
- **SC-003**: Tab order matches canonical sequence (Messages, Nodes, Map, Settings, Connect) across all locales
|
||||
- **SC-004**: Zero navigation regressions — all existing deep links and state restoration paths continue to function
|
||||
- **SC-005**: Cross-platform label parity achieved — Android tab names match the Menu Alignment Audit specification
|
||||
|
||||
## Assumptions
|
||||
|
||||
- All business logic and UI composables reside in `commonMain` source set
|
||||
- String resources are defined in `core/resources/src/commonMain/composeResources/values/strings.xml`
|
||||
- New string resource keys (`messages`, `connect`) will be created for bottom navigation tab labels; existing keys (`conversations`, `connections`) are retained for screen titles in feature modules (Contacts.kt, ConnectionsScreen.kt)
|
||||
- Tab order is already correct (positions 1–5 match canonical) and no reordering logic changes are needed
|
||||
- Navigation route identifiers are independent of user-visible label strings (routes use programmatic keys, not display text)
|
||||
- Localized translations are deferred to the next Crowdin translation sync cycle (not in-scope for this PR)
|
||||
- The `doc_title_connections` string resource (used elsewhere, e.g., documentation titles) may need separate evaluation but is out of scope for this tab label change
|
||||
164
specs/20260520-153412-nav-tab-labels/tasks.md
Normal file
164
specs/20260520-153412-nav-tab-labels/tasks.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# Tasks: Reorder Bottom Navigation Tab Labels
|
||||
|
||||
**Input**: Design documents from `specs/20260520-153412-nav-tab-labels/`
|
||||
**Prerequisites**: plan.md ✅, spec.md ✅, research.md ✅, data-model.md ✅, quickstart.md ✅
|
||||
|
||||
**Tests**: No new automated tests requested in the feature specification. Existing tests will be updated to reflect the rename but no new test coverage is added.
|
||||
|
||||
**Verification**: Constitution-required validation tasks are included for formatting, static analysis, and compile/test commands.
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no dependencies)
|
||||
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
||||
- Include exact file paths in descriptions
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup (String Resources)
|
||||
|
||||
**Purpose**: Add new string resource keys required by all subsequent tasks
|
||||
|
||||
- [X] T001 Add `messages` and `connect` string keys to `core/resources/src/commonMain/composeResources/values/strings.xml`
|
||||
- [X] T002 Run `python3 scripts/sort-strings.py` to maintain alphabetical ordering and regenerate strings-index.txt
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Enum Rename)
|
||||
|
||||
**Purpose**: Rename the `TopLevelDestination` enum entries — this BLOCKS all reference updates
|
||||
|
||||
**⚠️ CRITICAL**: No reference update tasks can begin until this phase is complete
|
||||
|
||||
- [X] T003 Rename `Conversations` → `Messages` and `Connections` → `Connect` in `core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/TopLevelDestination.kt` — update label resource references from `Res.string.conversations` → `Res.string.messages` and `Res.string.connections` → `Res.string.connect`
|
||||
|
||||
**Checkpoint**: Enum entries renamed — reference updates can now proceed in parallel
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — See Updated Tab Labels (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: Bottom navigation bar displays "Messages" (position 1) and "Connect" (position 5) as tab labels
|
||||
|
||||
**Independent Test**: Launch the app → visually confirm bottom navigation shows "Messages" and "Connect" in correct positions
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [X] T004 [P] [US1] Update icon `when` branches for `Messages` and `Connect` in `core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/navigation/TopLevelDestinationExt.kt`
|
||||
- [X] T005 [P] [US1] Update any explicit references from `Conversations`/`Connections` to `Messages`/`Connect` in `core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MeshtasticNavigationSuite.kt`
|
||||
- [X] T006 [P] [US1] Update default tab reference from `Connections` to `Connect` in `core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/MultiBackstack.kt`
|
||||
- [X] T007 [P] [US1] Update references in `androidApp/src/main/kotlin/org/meshtastic/app/ui/Main.kt`
|
||||
- [X] T008 [P] [US1] Update references in `desktopApp/src/main/kotlin/org/meshtastic/desktop/Main.kt`
|
||||
- [X] T009 [P] [US1] Update references in `desktopApp/src/main/kotlin/org/meshtastic/desktop/navigation/DesktopNavigation.kt`
|
||||
|
||||
**Checkpoint**: Tab labels display correctly — User Story 1 is visually complete
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 — Navigation Still Functions After Rename (Priority: P1)
|
||||
|
||||
**Goal**: Tapping "Messages" and "Connect" tabs navigates to the correct screens without behavior change
|
||||
|
||||
**Independent Test**: Tap "Messages" tab → messaging screen loads; tap "Connect" tab → connection/pairing screen loads; rapid tab switching works without errors
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [X] T010 [US2] Update test references from `TopLevelDestination.Connections` to `TopLevelDestination.Connect` (8 locations) in `core/navigation/src/commonTest/kotlin/org/meshtastic/core/navigation/MultiBackstackTest.kt`
|
||||
|
||||
**Checkpoint**: Navigation functions correctly with renamed enum entries — no behavioral regression
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 — Deep Links and State Restoration Work (Priority: P2)
|
||||
|
||||
**Goal**: Deep links and saved navigation state continue to route correctly after the rename
|
||||
|
||||
**Independent Test**: Trigger a message notification → tap it → app opens to messaging screen. Kill and restore app → previously selected tab is restored.
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
No additional implementation tasks required. Deep links and state restoration use typed route objects (`ContactsRoute.Contacts`, `ConnectionsRoute.Connections`) which are NOT affected by the enum entry rename. This was confirmed in research.md (Research Task 1).
|
||||
|
||||
**Checkpoint**: Verified by existing tests — no code changes needed for this story
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: Verification and constitution-required validation
|
||||
|
||||
- [X] T011 [P] Run `./gradlew spotlessApply` to auto-format all touched files
|
||||
- [X] T012 [P] Run `./gradlew spotlessCheck detekt` to confirm zero lint violations
|
||||
- [X] T013 Run `./gradlew assembleDebug` to verify project compiles successfully
|
||||
- [X] T014 Run `./gradlew test allTests` to verify all existing tests pass with renamed references
|
||||
- [X] T015 Confirm no logs, telemetry, or config changes expose PII, location data, secrets, or modify `core/proto`
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Setup (Phase 1)**: No dependencies — can start immediately
|
||||
- **Foundational (Phase 2)**: Depends on Phase 1 (string resources must exist before enum references them)
|
||||
- **User Story 1 (Phase 3)**: Depends on Phase 2 (enum must be renamed before updating references)
|
||||
- **User Story 2 (Phase 4)**: Depends on Phase 2 (enum must be renamed before updating test references)
|
||||
- **User Story 3 (Phase 5)**: No implementation needed — verified by Phase 4 tests passing
|
||||
- **Polish (Phase 6)**: Depends on Phases 3 and 4 completion
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- **User Story 1 (P1)**: Can start after Foundational (Phase 2) — No dependencies on other stories
|
||||
- **User Story 2 (P1)**: Can start after Foundational (Phase 2) — Independent of US1 (different files)
|
||||
- **User Story 3 (P2)**: Zero implementation — verified by existing route-based navigation tests
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
- **Phase 3**: ALL tasks T004–T009 can run in parallel (each touches a different file)
|
||||
- **Phase 4**: T010 can run in parallel with Phase 3 tasks (different file: test vs production)
|
||||
- **Phase 6**: T011 and T012 can run in parallel with T015
|
||||
|
||||
---
|
||||
|
||||
## Parallel Example: User Stories 1 & 2
|
||||
|
||||
```bash
|
||||
# After Phase 2 completes, launch ALL of these in parallel:
|
||||
Task T004: "Update TopLevelDestinationExt.kt icon branches"
|
||||
Task T005: "Update MeshtasticNavigationSuite.kt references"
|
||||
Task T006: "Update MultiBackstack.kt default tab reference"
|
||||
Task T007: "Update androidApp Main.kt references"
|
||||
Task T008: "Update desktopApp Main.kt references"
|
||||
Task T009: "Update DesktopNavigation.kt references"
|
||||
Task T010: "Update MultiBackstackTest.kt test references"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Stories 1 & 2)
|
||||
|
||||
1. Complete Phase 1: Add string resources (T001–T002)
|
||||
2. Complete Phase 2: Rename enum entries (T003)
|
||||
3. Complete Phase 3: Update all production references (T004–T009) — **in parallel**
|
||||
4. Complete Phase 4: Update test references (T010) — **parallel with Phase 3**
|
||||
5. **STOP and VALIDATE**: Run `./gradlew assembleDebug test allTests`
|
||||
6. Complete Phase 6: Polish and verification (T011–T015)
|
||||
|
||||
### Total Effort Estimate
|
||||
|
||||
- **Sequential execution**: 15 tasks, ~30 minutes (mechanical renames)
|
||||
- **Parallel execution**: Critical path is 6 steps (T001 → T002 → T003 → T004‖T010 → T013 → T014)
|
||||
- **Risk**: Low — all changes are mechanical identifier renames with no logic changes
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- [P] tasks = different files, no dependencies
|
||||
- [Story] label maps task to specific user story for traceability
|
||||
- User Story 3 requires zero implementation — validated by passing tests from US2
|
||||
- All Phase 3 tasks are mechanical `Conversations` → `Messages` and `Connections` → `Connect` identifier replacements
|
||||
- Commit after Phase 2 and after Phase 3+4 combined for clean git history
|
||||
- Old string keys (`conversations`, `connections`) are deliberately RETAINED — they serve as screen titles in other modules
|
||||
Reference in New Issue
Block a user