This file lives identically in both OmniTAK-iOS and OmniTAK-Android. It tracks visual and behavioral gaps between the two clients so they converge on a single OmniTAK design language.
These are the architectural calls made up front. Don't reopen them in PRs without raising it as an issue first.
| Decision | Choice | Reasoning |
|---|---|---|
| Primary navigation | Bottom tab bar | TAK users are often gloved / one-handed. Matches iTAK convention. Android already there. |
| Secondary actions | Long-press radial menu on the map | Already implemented on both platforms; keep it. |
| Color palette | Tactical dark by default | Both already lean dark. Extract shared tokens. |
| License | Apache-2.0 on both |
Tracked as a single checklist; tick off when both platforms match. Each item should land as paired commits — one PR per repo, referencing the same gap ID.
- GAP-001 iOS: replace hamburger drawer with bottom tab bar (Map / Chat / Servers / Mesh / Settings) — done in
RootTabView.swift - GAP-002 Android: bottom tab bar already in place — keep it
- GAP-003 Both: identical tab order, labels, icons (SF Symbols ↔ Material icons mapped 1:1)
- GAP-004 Android: replace flat NavigationBar with floating Liquid Glass capsule matching iOS 26 aesthetic —
LiquidGlassNavBar.kt. Per-tab brand colors, tinted halo on selection, drop shadow, translucent surface.
- GAP-010 (interim) iOS: default switched from
.satelliteto.standard(street map with labels) - GAP-010-android-dark Android basemap upgraded to CartoDB Dark Matter — pure tactical look, both clients now dark by default
- GAP-010 (final) iOS: optional swap MKMapView → MLNMapView to render the same MapLibre style natively. Lower priority now that both look tactical.
- GAP-011 Both: provide identical built-in basemap picker (OSM, OpenTopo, Satellite, Dark)
- GAP-012 Both: persist last-selected basemap
- GAP-020 Canonical metric set locked:
dot · server-name · ↓ · ↑ · ±accuracy · time · ☰ - GAP-021 iOS adopted text
↓/↑arrows (cyan / orange), matching Android ATAKStatusBar - GAP-022 iOS time formatter switched to 24h
HH:mm - GAP-023 Android
±Nmaccuracy badge wired through ATAKStatusBar (stubbed value pending GAP-030b)
- GAP-030 PPLI card visible on both — iOS already had it; Android added
SelfPositionCard.kt - GAP-030c Hide-from-Layers toggle on both. Long-press → Radial → Layers → Callsign Card switch. Mirrors operator complaints that the panel was covering map data.
- GAP-030b Wire real telemetry on Android: FusedLocationProviderClient flow + UserPrefsStore callsign (currently stubbed)
- GAP-031 Card position: iOS floats at user location, Android docks bottom-right above bottom nav. Pick one canonical position and align.
- GAP-032 Android: replaced MapLibre default blue pulse with tactical-accent ATAK bullseye drawable + bearing chevron —
ic_self_marker.xml/ic_self_marker_bearing.xml. iOS still uses MKMapView default blue dot; matching iOS to this style is filed as GAP-032b. - GAP-032b iOS: primary MapViewController delegate now returns a configured MKAnnotationView with
SelfPositionMarkerImage.bullseyefor MKUserLocation. Same hex / proportions as Androidic_self_marker.xml. Other map delegates (Map3D, RadialMenuMapOverlay, MeasurementService) still default — adopt later.
- GAP-040 Both: same overlay buttons in same positions
- GAP-041 Both: scale bar visible by default. iOS already has one; Android needs camera-change listener + meters/pixel calc — deferred.
- GAP-042 Android: stacked zoom +/− FABs added at BottomStart, paired with locator.
MapControlFabhelper. TacticalMap acceptszoomInTrigger/zoomOutTriggerInt counters. - GAP-043 Both: locator FAB returns to user position
- GAP-050 iOS: RadialMenuView already implemented
- GAP-051 Android: RadialMenu.kt already implemented
- GAP-052 Both: same set of radial actions, same icons, same color tokens
- GAP-060 Shared design-tokens spec lives at DESIGN_TOKENS.md — color palette (surface / brand / affiliation / status / nav-tab tints / text), typography scale, spacing scale, shape radii, elevation tiers. Identical file in both repos.
- GAP-061 iOS: extract to
Color+Tactical.swiftreferencing DESIGN_TOKENS.md hexes - GAP-062 Android: expand
ui/theme/Color.ktto cover every DESIGN_TOKENS token - GAP-063 Typography scale extracted into shared types referenced by both
- GAP-070 iOS has FirstTimeOnboarding flow — Android has none, decide if we add it
- GAP-071 If yes, identical copy and visuals
Features iOS has that Android doesn't yet. Triage which need parity vs which can wait.
- GAP-080 Data Package import (.zip) — iOS has, Android missing
- GAP-081 CSR enrollment (port 8446) — iOS has, Android missing
- GAP-082 Video feeds (HLS / RTSP / SRT) — iOS has, Android missing
- GAP-083 Photo attachments with EXIF — iOS has, Android missing
- GAP-084 Plugin system — iOS has, Android missing
- GAP-085 ADS-B traffic display — iOS has, Android has scaffolding (
AdsbService.kt)
Features Android has that iOS may benefit from. Same triage.
- GAP-090 None known yet — to be filled in as discovered
Real practitioner feedback from Android closed test. Some are bugs to fix, some are features to add. iOS may have the same issues — audit during port.
- [~] GAP-100 Callsign on main screen stuck at hardcoded
"OMNI-1"—MapScreen.ktwas passing a literal string instead ofuserPrefs.callsign. Code shipped — awaiting SxS verification on emulator before final tick. - [~] GAP-101 Map tile picker (Settings) didn't switch the basemap —
TacticalMapdefaulted to CARTO Dark andMapScreennever overrode it. Now wiresMapProviderenum to a per-provider style JSON (OSM standard / OpenTopoMap / Esri World Imagery / CARTO Dark) and re-applies viaDisposableEffect(styleJson). Settings copy updated. Code shipped — awaiting SxS. - [~] GAP-102 Top-left + top-right hamburger menus on main screen — were wired to empty
Slice 6:lambdas. Now route via existingonOpenTab: server icon → Servers tab; menu icon → Settings tab. Code shipped — awaiting SxS. - [~] GAP-103 Settings text fields jumpy — DataStore round-trip on every keystroke. Local
mutableStateOfdraft now insulates the field from re-emission; remember-key re-syncs on external changes. Fixed for Callsign (Team is now a dropdown — see GAP-104). Code shipped — awaiting SxS. - [~] GAP-104 Team field replaced with ATAK standard color dropdown — 14 canonical colors with swatches matching CoT spec (White, Yellow, Orange, Magenta, Red, Maroon, Purple, Dark Blue, Blue, Cyan, Teal, Green, Dark Green, Brown). Code shipped — awaiting SxS. iOS port pending.
- [~] GAP-105 Server auth menu — partial: server-icon tap on the status bar now opens the Servers tab (was dead, see GAP-102), and the Add Server form now has username + password fields. Still missing: QR-scan path for ATAK data package import. Code shipped — awaiting SxS.
- GAP-106 Add UTM to coordinate format toggle (currently Lat/Lon Decimal, DMS, MGRS). Same change on iOS.
- GAP-107 Custom WMTS basemap source — let operators paste a WMTS endpoint as an additional basemap option. Practitioners use private/agency WMTS tiles.
- GAP-108 Server-pushed app config / data package settings. Operator pushes settings (PLI intervals, default basemap, server URL, callsign rules) to clients via OpenTAKserver, config file, or
.zipdata package. Real differentiator vs ATAK / iTAK / TAKaware. Source of complaint: 80-node airsoft event needing centralised PLI intervals. - GAP-109 Meshtastic device settings UI — full control of connected node config (radio settings, channels, PLI cadence, role). Reference: github.com/cubeos-app/meshsat-android, github.com/torlando-tech/columba.
- Pick an unchecked GAP that's not blocked by a higher-priority one
- Open an issue in both repos titled
parity: GAP-NNN — short descriptionand cross-link - Implement on the platform that's behind. If both need work, decide source of truth first
- Open paired PRs. Reference the same GAP ID in both PR titles
- Both PRs merge together (or close together — within a week)
- Tick the box in this file in both repos
- Update PARITY.md in the other repo to match
- iOS lead: OmniTAK-iOS contributors
- Android lead: OmniTAK-Android contributors
- Design source of truth: this document. Conflicts? Open an issue, don't just diverge.