Commit Graph

6577 Commits

Author SHA1 Message Date
James Rich
e8d6647d44 Add unit tests for SdkPacketHandler, SdkRadioInterfaceService, and SdkRadioController edge cases
- SdkPacketHandlerTest: 10 tests covering sendToRadio (MeshPacket and
  ToRadio variants), sendRaw path for MQTT/XModem, disconnected client
  handling, and no-op queue methods
- SdkRadioInterfaceServiceTest: 14 tests covering device address
  management, mock transport detection, interface address composition,
  and connect/disconnect delegation
- SdkRadioControllerTest: 3 new tests for sendMessage routing,
  disconnected sendMessage drop, and requireClient exception

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 19:30:57 -05:00
James Rich
7875088f91 style: fix spotless and detekt violations
- Rename _metadataCache backing property (no public counterpart)
- Break long log lines to satisfy MaxLineLength
- Suppress intentional TooGenericExceptionCaught in error boundaries
- Suppress LongMethod on dispatchAction (when-block, not complex)
- Apply spotless formatting across all modules

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 19:01:43 -05:00
James Rich
d35dc5da04 fix: update MqttManagerImplTest for nodeRepository constructor param
After rebase, MqttManagerImpl gained a nodeRepository parameter.
Updated test to mock and pass the new dependency.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 18:02:00 -05:00
James Rich
813316110e chore: KDoc cleanup, stale comments, and cruft removal
- Add KDoc to 3 JSON datasource interfaces and 7 repository implementations
- Remove IndoorAirQuality stub comments
- Remove commented-out WRITE_EXTERNAL_STORAGE permission from manifest
- Update foreground service comment to architecture note (Android 14+)
- Remove redundant inline comments in PacketDao.kt

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
aacd789550 Add integration tests for SDK→Bridge→Repository chain
12 integration tests covering:
- T4a: SDK packets/events propagate through bridges to repositories
- T4b: Connection lifecycle state transitions (connect/disconnect/reconnect)
- T4c: Error resilience (malformed protos, unknown ports, rapid fire, empty payloads)

Tests verify the full chain from FakeRadioTransport through RadioClient,
SdkStateBridge orchestration, and into service/node/topology repositories.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
2d299f7e21 test: SdkRadioController and PacketRepository coverage
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
37be51bed9 test: MeshTopologyService and MessageDeliveryTracker tests
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
6490fc30e8 test: comprehensive bridge unit tests
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
6450c69820 Add distance-based node filter
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
839d43ddf1 Refactor SdkStateBridge bridges
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
4340fc5045 feat: handle NODE_STATUS_APP packets to populate node status string
Parse UTF-8 payload from NODE_STATUS_APP (PortNum=36) and update
the node's nodeStatus field. Already displayed in NodeItem and
NodeDetailsSection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
604ce68415 feat: set_ignored_node side effects mirror firmware behavior
When ignoring a node, wipe position, deviceMetrics, and publicKey locally
to match what firmware does on the device side. Un-ignoring just clears
the isIgnored flag (device will re-populate on next heard packet).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
fa6d625d90 perf: Phase 4 Android performance optimizations
- frequentEmojis: computed List → cached StateFlow (avoids parse+sort on every recomposition)
- SdkNodeRepositoryImpl: SharingStarted.Eagerly → WhileSubscribed(5_000) for ourNodeInfo, myId, localStats
- PacketRepositoryImpl: deduplicate flatMapLatest chains via shared combine(myNodeNumFlow, currentDb)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
52aaa4d926 feat: handle AdminResult.RateLimited from SDK, update MeshTopology API
- Add AdminException.RateLimited to domain exception hierarchy
- Handle AdminResult.RateLimited in SdkRadioController.unwrap()
- Update MeshTopologyService for SDK's new suspend API:
  topology.nodes → topology.nodes(), topology.edgeCount → edgeCount()

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
046efd50dd refactor: replace string-based route with typed Enum in RadioConfigState
- Change RadioConfigState.route from String to Enum<*>?
- ChannelScreen resolves navigation target via typed cast instead of
  string lookup through getNavRouteFrom()
- Delete dead SettingsNavUtils.kt (getNavRouteFrom now unused)
- Eliminates fragile string→enum round-trip that could silently fail

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
44b2a8c98a refactor: extract MqttProbeCoordinator and ProfileCoordinator from RadioConfigViewModel
Extract self-contained logic into plain coordinator classes:
- MqttProbeCoordinator: MQTT broker probe state + cancellation
- ProfileCoordinator: import/export/install profile file I/O

RadioConfigViewModel delegates to coordinators while retaining
state ownership and config-loading orchestration (its core job).
Reduces VM body by ~60 lines of implementation detail.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
07214bd307 refactor: decouple feature/connections from feature/settings
- Move ResponseState<T> to core/model
- Move PacketResponseStateDialog to core/ui/component
- Create RadioConfigStateProvider interface in core/model
- RadioConfigViewModel implements RadioConfigStateProvider
- ConnectionsScreen accepts interface instead of concrete VM
- ConnectionsNavigation receives provider via lambda from app/desktop
- Remove projects.feature.settings dependency from connections build

This eliminates a feature→feature dependency, improving build
parallelism and enforcing proper module boundaries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
b3542c76aa fix: remove circular StateFlow observation in RadioConfigViewModel
The combine(serviceRepository.connectionState, radioConfigState) pattern
subscribed to the ViewModel's own output StateFlow, causing redundant
re-evaluations on every state change. Replace with direct observation
of the source connectionState flow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:06 -05:00
James Rich
5dd5ebc074 chore: remove more dead dependencies + stability annotations
- feature/map: remove unused core.data, core.database, core.datastore;
  add missing core.common, core.repository (actual dependencies)
- feature/node: remove unused core.datastore
- feature/connections: remove unused core.database
- Add @Immutable to NodesUiState, NodeFilterState

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
6487d1316d refactor: remove dead deps + add Compose stability annotations
- Remove unused feature/node → feature/map dependency (nothing imported)
- Add @Immutable to RadioConfigState, DiscoveredDevices, DeviceListEntry
  to prevent unnecessary Compose recompositions from unstable inference

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
0b6d8eca08 chore: remove unused core.service dependencies from 5 feature modules
Only feature/messaging actually imports from core.service (SendMessageWorker).
The other 5 feature modules (connections, firmware, map, node, settings)
had vestigial dependency declarations from pre-migration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
0b5791a61d refactor: remove getPacketId() from public interface
- Remove getPacketId() from MessageSender interface (SDK owns packet IDs)
- Remove requestId parameter from requestTraceroute/requestNeighborInfo
- Make getPacketId() private in SdkRadioController (still used internally
  for delivery tracking correlation)
- Replace radioController.getPacketId() in map with local Random.nextInt()
  for waypoint ID generation (only needs uniqueness, not SDK correlation)
- Remove messageSender dependency from CommonNodeRequestActions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
f4c6cee332 feat: typed telemetry dispatch + MeshTopology service
- Replace magic int dispatch in requestTelemetry with TelemetryType enum
- Update DataRequester interface: remove requestId param, use TelemetryType directly
- Add HEALTH and TRAFFIC_MANAGEMENT to TelemetryType, remove stale PAX variant
- Create MeshTopologyService wrapping SDK's MeshTopology with thread-safe Mutex
- Wire NeighborInfo packet ingestion in SdkStateBridge → topology graph
- Clear topology on node snapshot (reconnect)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
3fb45e05bd fix: architecture review P0/P1 fixes
- P0: setDeviceAddress now persists address to RadioPrefs before reconnect
- P0: Document nodedbReset firmware limitation (preserveFavorites is local-only)
- P1: Add writeAction helper for AdminException → sendError in RadioConfigViewModel
- P1: Wrap CommonNodeRequestActions scope.launch with runCatching for crash safety
- P1: Create CongestionLevel typealias in core/model to decouple feature modules from SDK
- P1: Cancel prior loadJob in setResponseStateLoading to prevent stale results

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
140e062eee refactor: eliminate ProcessRadioResponseUseCase and packet-ID correlation
Replace the manual packet-ID tracking and meshPacketFlow subscription in
RadioConfigViewModel with direct typed returns from the SDK via
RadioConfigUseCase. The ViewModel now awaits typed results (User, Config,
ModuleConfig, channels, etc.) from suspend calls and maps AdminException
to UI error states.

Key changes:
- Delete ProcessRadioResponseUseCase (130 lines of manual proto decode)
- Remove requestIds state, registerRequestId, processPacketResponse,
  sendAdminRequest, and meshPacketFlow subscription from ViewModel
- Rewrite setResponseStateLoading to use direct coroutine calls
- Admin actions (reboot/shutdown/etc.) fire directly without session key
  preflight (SDK handles retryOnSessionExpiry transparently)
- All setters (setConfig, setModuleConfig, setOwner, updateChannels)
  no longer return/track packetIds
- Remove messageSender dependency from NodeManagementActions
- Update InstallProfileUseCase to use editSettings {} receiver pattern
- Update all callers: CleanNodeDatabaseUseCase, Esp32OtaUpdateHandler,
  NodeManagementActions
- Rewrite RadioConfigViewModelTest for new direct-await semantics
- Update RadioConfigUseCaseTest and InstallProfileUseCaseTest

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
6e5b159014 refactor: eliminate MeshPacket/Data imports from radio layer
- sendMessage() now uses client.send(portnum, payload, to, channel, ...)
- requestUserInfo() now uses client.requestNodeInfo(NodeId)
- SdkStateBridge position publishing calls SDK directly (removes
  intermediate DataPacket + RadioController dependency)
- Remove unused imports: MeshPacket, Data, okio.toByteString
- Remove unused radioController dependency from SdkStateBridge

Net: SdkRadioController no longer imports MeshPacket or Data proto.
Only AdminMessage remains (for beginEditSettings/commitEditSettings).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
35f03735ab refactor: use SDK remote admin API, eliminate sendRemoteAdmin
- Replace all isLocalNode/sendRemoteAdmin patterns with
  client.admin.forNode(NodeId(destNum)).method()
- Use client.sendReaction() instead of manual MeshPacket construction
- Use client.admin.forNode(dest).getDeviceMetadata() for remote metadata
- Delete sendRemoteAdmin() and isLocalNode() helpers
- Remove unused imports (AdminMessage, Data, MeshPacket from SdkStateBridge)

Net: -131 lines, all admin ops now go through SDK's typed API with
proper ACK tracking and session-key retry.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
b874873f10 refactor: delete 6 dead packet handlers post-SDK cutover (-1420 lines)
Remove handler interfaces, implementations, and tests that have zero production
callers after the SDK became authoritative for protocol handling:

- TelemetryPacketHandler/Impl — SDK owns telemetry via NodeChange.Updated
- StoreForwardPacketHandler/Impl — SDK owns S&F lifecycle + SFPP
- NeighborInfoHandler/Impl — SDK owns NeighborInfo model
- TracerouteHandler/Impl — SDK owns traceroute via AdminResult flow
- MeshDataHandler/MessagePersistenceHandler — handleReceivedData was no-op
- HistoryManager/Impl — only caller was deleted StoreForwardPacketHandlerImpl

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
31f792c71e fix: remove SFPP vestige, resource-back badge strings, add bridge tests
- Remove handleStoreForwardPlusPlus() from interface + impl (dead code post-SDK cutover)
- Move StoreForwardBadge/CongestionBadge hardcoded strings to string resources (i18n)
- Add SdkStateBridge tests: congestion warning → ServiceRepository, S&F server propagation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
c712d7ef68 chore: remove dead SfppHasher + unused NodeRepository injection
- Delete SfppHasher wrapper (SDK SfppHash handles SFPP hashing)
- Remove unused NodeRepository from StoreForwardPacketHandlerImpl
- Update tests to match constructor change

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
64464196b0 feat: SFPP delegation to SDK, NeighborInfo SDK model, congestion + S&F badges
- SdkStateBridge: handle SfppLinkProvided/SfppCanonAnnounced events from SDK
- StoreForwardPacketHandlerImpl: SFPP parsing removed (SDK-owned)
- NeighborInfoHandlerImpl: delegate formatting to SDK NeighborInfo.fromProto()
- NodeStatusIcons: CongestionBadge (yellow/orange/red for MEDIUM/HIGH/CRITICAL)
- NodeStatusIcons: StoreForwardBadge (blue cloud icon for S&F servers)
- NodeListViewModel: expose congestionLevel + storeForwardServers flows
- Tests updated for SFPP bridge coverage

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
7683db0c57 feat: deep SDK integration — retry delivery, Store-and-Forward API, congestion surfacing
I1 — RetryPolicy in MessageDeliveryTracker:
- track() now accepts optional RetryPolicy (default: ExponentialBackoff 3 attempts)
- Failed sends automatically retry before marking ERROR
- UI sees ENROUTE during retry attempts

I2 — Store-and-Forward SDK consumption:
- SdkStateBridge observes storeForward.events and servers
- ServiceRepository exposes storeForwardServers StateFlow
- SdkRadioController.requestStoreForwardHistory() delegates to SDK
- HistoryManagerImpl uses SDK path instead of manual packet construction

I3 — Congestion level surfacing:
- SdkStateBridge handles MeshEvent.CongestionWarning
- ServiceRepository.congestionLevel StateFlow exposed to UI
- Cleared on disconnect

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
27b2c19e69 refactor: narrow ViewModel injections, add ConnectionAware, delete dead code, integration tests
ViewModel Narrowing:
- V1: Created ConnectionAware interface; MessageSender, DeviceAdmin, DeviceControl extend it
- V2: Narrowed 6 ViewModels/actions to focused sub-interfaces (DeviceAdmin, MessageSender, DataRequester, DeviceControl)

Cleanup:
- C1: Deleted dead MeshDataMapper and its DI registration

Integration Tests:
- T2: SdkStateBridgeTest verifying WentOffline/CameOnline presence handling
- Verified Koin resolution, full test suite passes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
e9cb439849 feat: rearchitect around SDK — decompose RadioController, simplify DataPacket, integrate SDK utilities
Android rearchitecture consuming meshtastic-sdk improvements:

A1 — ConnectionState Enrichment:
- Rich sealed interface with Connecting(attempt), Configuring(phase, progress), Reconnecting(attempt)
- SdkStateBridge maps SDK states preserving metadata

A2 — MessageHandle Integration:
- MessageDeliveryTracker: tracks delivery via SDK MessageHandle
- SdkRadioController captures handles on send

A3 — RadioController Decomposition:
- Split into 5 focused interfaces: MessageSender, DeviceAdmin, RemoteAdmin, DeviceControl, DataRequester
- RadioController extends all; SdkRadioController binds all via Koin

A4 — DataPacket Simplification:
- to/from fields changed from String? to Int (node numbers directly)
- Removed string ID parsing layer; added BROADCAST/LOCAL constants
- Updated ~40 consumer files across feature modules

A5 — SDK Utility Consumption:
- DeviceVersion, Capabilities, SfppHasher, LocationUtils delegate to SDK
- Removed duplicated protocol logic

A6 — Presence Events:
- SdkStateBridge handles NodeChange.WentOffline/CameOnline
- Updates node online status via repository

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
43ecd2eb73 chore: rename stale files and update migration doc
- NodeInfo.kt → MeshModels.kt (no longer contains NodeInfo class)
- NodeManagerImplTest.kt → SdkNodeRepositoryImplTest.kt (tests SdkNodeRepositoryImpl)
- Update MIGRATION-REMAINING.md with dead code removal, error handling,
  and NodeManager merge status

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
2db6db5ed9 fix: add error handling to SDK bridge and radio controller
SdkStateBridge:
- Wrap handleServiceAction in try/catch to prevent bridge death
- Favorite/Ignore/Mute: only apply local state update on admin
  success (eliminates optimistic state inconsistency)
- ImportContact: guard with runCatching, log failures
- Extract dispatchAction for clean separation of concerns

SdkRadioController:
- Wrap sendMessage with try/catch + logging before re-throw
- Wrap sendRemoteAdmin with try/catch + logging before re-throw
- Ensures BLE disconnect errors are visible in logs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
296f27dc73 refactor: merge NodeManager into NodeRepository
Eliminate the vestigial NodeManager/NodeRepository interface split.
All runtime node state management methods (handleReceivedUser,
handleReceivedPosition, handleReceivedTelemetry, updateNode, etc.)
now live directly on NodeRepository alongside the query surface.

- Delete NodeManager.kt (82 LOC)
- Extend NodeRepository with NodeIdLookup and add all manager methods
- Update 8 consumers to inject NodeRepository instead of NodeManager
- Remove dead nodeManager param from MeshServiceOrchestrator
- Add NodeManager methods to FakeNodeRepository test double
- Update all tests (mocks, constructor params, verifications)
- SdkNodeRepositoryImpl now binds [NodeRepository, NodeIdLookup]

Build: assembleDebug , desktop:compileKotlin , all jvmTests 

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
e7d1767527 chore: remove ~220 LOC dead code from node layer
Delete dead methods from NodeManager/NodeRepository interfaces:
- allowNodeDbWrites, setAllowNodeDbWrites (never read)
- loadCachedNodeDB (no-op, zero-value call in orchestrator)
- getNodes(): List<NodeInfo> (deprecated, unused)
- handleReceivedPaxcounter (zero callers)
- handleReceivedNodeStatus, updateNodeStatus (zero callers)
- insertMetadata (zero production callers)

Delete NodeInfo data class (85 LOC):
- All consumers now use Node domain model directly
- Retained MeshUser, Position, DeviceMetrics, EnvironmentMetrics
  which have active consumers across feature modules

Remove corresponding implementations from SdkNodeRepositoryImpl,
FakeNodeRepository, and test verifications.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
a12aa2691e docs: update MIGRATION-REMAINING to ~100% complete
NodeManager merge and MeshActivity restoration are done.
Only optional VM param slimming and test coverage remain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
551d4419a4 refactor: merge NodeManager into SdkNodeRepositoryImpl + restore MeshActivity
- Merge NodeManagerImpl logic into SdkNodeRepositoryImpl (single source
  of truth for all node state — eliminates duplicate in-memory maps)
- SdkNodeRepositoryImpl now binds NodeRepository, NodeManager, NodeIdLookup
- Delete NodeManagerImpl.kt (377 LOC)
- Add meshActivityFlow to ServiceRepository for nav-bar icon animation
- Emit MeshActivity.Send from SdkPacketHandler and SdkRadioController
- Emit MeshActivity.Receive from ServiceRepositoryImpl.emitMeshPacket()
- Wire UIViewModel.meshActivity to serviceRepository.meshActivityFlow
- Align insertMetadata signature (remove unnecessary suspend)
- Adapt NodeManagerImplTest to test SdkNodeRepositoryImpl directly
- Update FakeServiceRepository with meshActivityFlow stub

All targets compile clean (Android + Desktop), all tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
352cce6603 docs: update MIGRATION-REMAINING.md — Room cleanup complete (97%)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
19eba729f7 chore(database): Room migration 39→40 — drop legacy node tables
- Remove my_node, nodes, metadata tables via AutoMigration with @DeleteTable
- Parameterize all 34 PacketDao queries to accept myNodeNum directly
- Delete NodeInfoDao, NodeEntity, MyNodeEntity, MetadataEntity
- Delete CommonNodeInfoDaoTest (dead)
- Rewrite PacketRepositoryImpl to inject NodeRepository for myNodeNum
- Rewrite CommonPacketDaoTest and CommonPacketRepositoryTest
- Update MigrationTest to remove nodeInfoDao usage
- Update core/database README to reflect current schema

SDK is now sole source of truth for all node data.
Room only stores messages, logs, and user annotations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
1dd3637b50 refactor: eliminate NodeInfoReadDataSource, use NodeRepository directly
MeshLogRepositoryImpl was the sole external consumer of
NodeInfoReadDataSource — it only needed myNodeNum to identify the
local node in logs. Replace with NodeRepository.myNodeInfo (already
SDK-backed via SdkNodeRepositoryImpl).

PacketRepositoryImpl referenced NodeInfoDao.MAX_BIND_PARAMS — inlined
as a private constant since it's just the SQLite bind-param limit.

With zero external consumers remaining, delete:
- NodeInfoReadDataSource interface
- SwitchingNodeInfoReadDataSource implementation

The Room NodeInfoDao/NodeEntity/MyNodeEntity remain in the database
module for now (internal tests + migration history) but have no
external dependents — ready for a future Room migration 40 to DROP.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
a0ee9e8399 docs: update MIGRATION-REMAINING.md with latest cleanup status
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
10425e8c4e refactor: delete dead broadcast Constants.kt and unused actionReceived
Constants.kt re-exported MeshtasticIntent constants for the deleted
ServiceBroadcasts system. No consumers remain after broadcast removal.
Also remove MeshService.actionReceived() companion method (no callers).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
f0aa99eaff refactor: delete POC ViewModels and stale references
- Delete SdkConfigViewModel, SdkMessagingViewModel, SdkTelemetryViewModel (unused POC)
- Delete RadioClientViewModel, SdkNodeListViewModel (POC logging only)
- Remove POC VM instantiation from Main.kt
- Delete NoopRadioInterfaceService (superseded by SdkRadioInterfaceService)
- Delete dead app/test/Fakes.kt (both classes unused)
- Fix stale KDoc references to MeshConnectionManager, RadioInterfaceService.connectionState

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
3cdad0da28 refactor: delete transport layer and dead intermediaries, slim RadioInterfaceService
- Delete entire transport layer: BleRadioTransport, TcpRadioTransport,
  SerialRadioTransport, StreamTransport, HeartbeatSender, StreamFrameCodec,
  AndroidRadioTransportFactory, BaseRadioTransportFactory, MockRadioTransport,
  NopRadioTransport, BleReconnectPolicy, TcpTransport, SerialTransport
- Delete MeshConfigHandler interface + impl (replaced by RadioConfigRepository)
- Delete RadioTransportCallback, RadioTransport, RadioTransportFactory interfaces
- Delete FakeRadioTransport, RadioTransportTest, MeshConfigHandlerImplTest
- Delete UseCase tests (impls restored, tests for deleted patterns removed)
- Slim RadioInterfaceService interface: remove transport internals, keep only
  device-address/connection surface needed by Scanner and connections UIs
- Create SdkRadioInterfaceService: thin SDK-backed impl delegating to
  RadioPrefs + RadioClientAccessor
- Update NoopRadioInterfaceService to match slimmed interface
- Update JvmUsbScanner to use SDK's JvmSerialPorts.list() instead of
  deleted SerialTransport.getAvailablePorts()
- Remove DesktopRadioTransportFactory from desktop DI module
- Fix NodeListViewModel: replace RadioInterfaceService with RadioPrefs
- Fix MeshServiceOrchestratorTest: align with updated constructor params
- Fix UIViewModel: use emptyFlow() for meshActivity (SDK doesn't emit
  raw transport-level activity events)

All targets compile clean, all JVM + Android unit tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
74ba959b24 feat: DRY SDK integration — shared bridge, Desktop cutover, dead infra deletion
Major architectural changes:

1. SHARED KMP BRIDGE (core/data/radio/):
   - RadioClientAccessor: Platform-agnostic interface for SDK RadioClient
   - SdkRadioController: Shared RadioController impl (replaces per-platform copies)
   - SdkStateBridge: Shared SDK→repository bridge (event dispatch, node sync)
   - SdkPacketHandler: Thin SDK-backed PacketHandler for MQTT/XModem/History

2. DESKTOP SDK CUTOVER:
   - DesktopRadioClientProvider: TCP + Serial transport support
   - Removed DirectRadioControllerImpl (old desktop radio path)
   - Desktop now shares the same SDK bridge code as Android

3. DEAD INFRASTRUCTURE DELETION (~5,100 LOC removed):
   - PacketHandlerImpl, MeshDataHandlerImpl, MeshRouterImpl
   - CommandSenderImpl, MeshActionHandlerImpl, MeshConfigFlowManagerImpl
   - MeshConnectionManagerImpl, AdminPacketHandlerImpl
   - ServiceBroadcasts (Android intent-based pub/sub)
   - NodeRepositoryImpl (Room-backed, replaced by SdkNodeRepositoryImpl)
   - 8 trivial UseCases (SetLocale, SetTheme, ToggleAnalytics, etc.)
   - All associated test files for deleted impls
   - Deleted interfaces: AdminPacketHandler, CommandSender, MeshActionHandler,
     MeshConfigFlowManager, MeshConnectionManager, MeshRouter, ServiceBroadcasts

4. NEW FEATURES:
   - NodeMetadataEntity + Room migration 38→39 (persistent favorites/notes)
   - AppMetadataRepository (clean access to node metadata)
   - MessagePersistenceHandler (focused rememberDataPacket for StoreForward)

All three targets compile clean: :app:compileGoogleDebugKotlin,
:desktop:compileKotlin, :core:data:jvmTest passes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
2c438b9a3f docs: add MIGRATION-REMAINING.md tracking clean-break progress
Documents completed phases (A-G partial), remaining blockers,
and recommended execution order for full SDK migration.

Key remaining items:
- Desktop SDK migration (unblocks ~2,000 LOC deletion)
- Module restructuring (unblocks VM direct-binding)
- 22 VM migrations to RadioClient
- 4 deferred UseCase deletions
- Phase C completion (packet flow cleanup)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00
James Rich
2162e0a340 feat: full SDK integration — drop AIDL, eliminate pipeline, SDK-backed nodes
Phase 1: Drop AIDL
- Delete all 6 .aidl files (core/api/src/main/aidl/)
- Strip binder object from MeshService (onBind returns null)
- Simplify MeshServiceClient to lifecycle observer (no AIDL binding)
- Remove meshService field from AndroidServiceRepository
- Delete ServiceClient, AndroidRadioControllerImpl, FakeIMeshService,
  IMeshServiceContractTest

Phase 2: Migrate TAK to RadioController
- GenericCoTHandler: RadioController replaces CommandSender
- TAKMeshIntegration: RadioController replaces CommandSender
- CoreTakServerModule: DI updated

Phase 3: Port remaining consumers
- MeshConnectionManagerImpl: RadioController, remove time sync/passkey
  (SDK handles internally), wrap telemetry in coroutine
- MeshConfigFlowManagerImpl: remove CommandSender dependency, use 0L
  for currentPacketId
- RefreshLocalStatsAction: RadioController for widget telemetry
- EnsureRemoteAdminSessionUseCase: serviceRepository.onServiceAction()
  replaces meshActionHandler

Phase 4: Delete dead pipeline
- Delete FromRadioPacketHandler interface + FromRadioPacketHandlerImpl
- Delete MeshMessageProcessor interface + MeshMessageProcessorImpl
- Delete related tests
- Remove MeshMessageProcessor dep from MeshActionHandlerImpl
- Keep CommandSender/MeshRouter/MeshActionHandler for
  DirectRadioControllerImpl (desktop target)

Phase 5: SDK-backed NodeRepository
- New SdkNodeRepositoryImpl: in-memory StateFlow backed by NodeManager
- SDK handles persistence via its own SqlDelight storage
- Deactivate Room-backed NodeRepositoryImpl (@Single removed)
- NodeManagerImpl propagates myNodeNum to SdkNodeRepositoryImpl
- Cold start: brief empty state until SDK emits snapshot (<1s)
- Node notes: in-memory for POC (does not survive process death)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:52:05 -05:00