Skip to content

[#617][Part 2/3] Migrate to navigation 3 - Sample compose project#619

Draft
eeeeaa wants to merge 8 commits intochore/#617-migrate-to-navigation-3-template-composefrom
chore/#617-migrate-to-navigation-3
Draft

[#617][Part 2/3] Migrate to navigation 3 - Sample compose project#619
eeeeaa wants to merge 8 commits intochore/#617-migrate-to-navigation-3-template-composefrom
chore/#617-migrate-to-navigation-3

Conversation

@eeeeaa
Copy link
Copy Markdown

@eeeeaa eeeeaa commented Dec 2, 2025

#617

What happened 👀

Note

Split migration into 3 Parts
Part 1 - migrate template compose
Part 2 - migrate sample compose
Part 3 - refactor sample compose examples

  • Add navigation 3 dependencies
  • Update navigation route to use NavKeys
  • Create Navigator class to hold and handle navigation state to replace NavController
  • Migrate from hilt-navigation-compose to hilt-lifecycle-viewmodel-compose for nav3
  • Add custom slide transitions for navigation in MainActivity
  • Remove nav2 destinations and related classes/dependencies
  • For deepLink in part 2, add custom deep link implementation based on POC
  • Update tests and add FakeNavigator

Insight 📝

  • Aim to keep flow and screen the same as before migration, will refactor to add more example like POC in part 2

Reference:

Proof Of Work 📹

Sample project work the same as before migration

Screen.Recording.2569-02-11.at.12.04.04.mov

Summary by CodeRabbit

  • New Features

    • Deep link handling for direct navigation
    • Result event system for screen-to-screen communication
    • Edge-to-edge UI support
  • Refactor

    • Redesigned navigation architecture with observable back stack
    • Switched model serialization to Kotlinx Serialization
  • Tests

    • Added a test navigation helper to simplify navigation-related tests
  • Chores

    • Updated toolchain and dependency versions (Gradle, Compose BOM, Hilt, Lifecycle, navigation libraries, Kotlinx Serialization)

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 2, 2025

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors navigation from a BaseDestination/NavHost system to a retained-scope Navigator with backStack, adds deep-link parsing/matching, introduces ResultEventBus and ResultEffect for inter-screen results, migrates UiModel to Kotlinx Serialization, updates DI and MainActivity wiring, and bumps dependency versions.

Changes

Cohort / File(s) Summary
Navigation Core
sample-compose/app/src/main/java/co/nimblehq/sample/compose/navigation/Navigator.kt, .../NavigatorImpl.kt
Adds new Navigator interface and ActivityRetainedScoped NavigatorImpl managing observable backStack with goTo/goBack/goBackToLast.
Main Activity & DI
sample-compose/app/src/main/java/.../ui/screens/MainActivity.kt, sample-compose/app/src/main/java/.../di/modules/main/MainActivityModule.kt
MainActivity updated to use NavDisplay, deep-link handling, ResultEventBus provisioning; DI module changed to object and bound to ActivityRetainedComponent with provideNavigator and entry provider installer.
Deep-link Utilities
sample-compose/app/src/main/java/.../util/DeepLinkRequest.kt, DeepLinkPattern.kt, DeepLinkMatcher.kt
New internal types to parse URIs, represent pattern segments, and match requests to pattern keyBuilders and extracted args.
Result Bus & Effects
sample-compose/app/src/main/java/.../util/ResultEventBus.kt, .../ResultEffect.kt
Introduces ResultEventBus (channel-based keyed flows), LocalResultEventBus composition local, and ResultEffect composable to collect results.
Screens & Models
sample-compose/app/src/main/java/.../ui/screens/main/*, sample-compose/app/src/main/java/.../ui/models/UiModel.kt
Replaces BaseDestination-based API with concrete data objects (Home, Second, Third), screens accept Navigator, UiModel switched to @Serializable (kotlinx).
Removed Nav Abstractions
sample-compose/app/src/main/java/.../ui/base/BaseDestination.kt, AppDestination.kt, AppNavGraph.kt, MainDestination.kt, MainNavGraph.kt, .../SavedStateHandleExt.kt
Removes previous BaseDestination hierarchy, AppNavGraph, and related nav-graph utilities and savedState helper.
Utilities & Small API Changes
sample-compose/app/src/main/java/.../extensions/ComponentActivityExt.kt, .../util/ComposableUtil.kt, .../ui/base/BaseScreen.kt, .../ui/base/BaseViewModel.kt, .../ui/common/Constants.kt
Adds setEdgeToEdgeConfig extension; renames setStatusBarColor→StatusBarColor; BaseViewModel navigator flow type changed to Any; adds URL_SECOND_SCREEN constant.
Tests & Test Doubles
sample-compose/app/src/androidTest/.../FakeNavigator.kt, sample-compose/app/src/test/.../FakeNavigator.kt, .../HomeScreenTest.kt, .../HomeViewModelTest.kt
Adds FakeNavigator test doubles and updates tests to use them (assert by currentScreen/currentScreenClass), plus toast reset in setup.
Build & Versions
sample-compose/app/build.gradle.kts, sample-compose/gradle/libs.versions.toml, sample-compose/gradle/wrapper/gradle-wrapper.properties, sample-compose/domain/build.gradle.kts
Adds Kotlin Serialization plugin and kotlinx-serialization-json dep; updates version catalog (SDK→36, Compose BOM, Gradle, Hilt, lifecycle, adds navigation3 and kotlinxSerialization); Gradle wrapper bumped to 8.11.1; JVM toolchain set to 17.

Sequence Diagram(s)

sequenceDiagram
    participant Activity as MainActivity
    participant Nav as Navigator
    participant DLM as DeepLinkMatcher
    participant REB as ResultEventBus
    participant Entry as EntryProvider

    Activity->>Nav: injected via DI
    Activity->>REB: create & provide LocalResultEventBus
    Activity->>Activity: handleNewIntent(intent)
    Activity->>DLM: DeepLinkMatcher(DeepLinkRequest, pattern).match()
    alt match found
        DLM-->>Activity: keyBuilder + args
        Activity->>Nav: goTo(keyBuilder(args))
    end
    Entry->>Nav: compose screen for current destination
    Entry->>REB: use LocalResultEventBus for sending/getting results
Loading
sequenceDiagram
    participant Source as CallingScreen
    participant Nav as Navigator
    participant Second as SecondScreen
    participant REB as ResultEventBus

    Source->>Nav: goTo(Second(id))
    Nav->>Second: display SecondScreen(id)
    Second->>REB: sendResult(key, value)
    Second->>Nav: goBack()
    Source->>REB: collect ResultEffect(key)
    REB-->>Source: result received
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • hoangnguyen92dn
  • AVI5HEK
  • luongvo
  • ryan-conway
  • kaungkhantsoe
  • sleepylee
  • toby-thanathip

Poem

"🐇 I hopped from NavHost to a neat backStack,
Deep links decoded each curious track,
Results bounced in a bus with a ping,
Screens leap and the navigator sings—
A tiny rabbit cheers this refactor's knack!"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: migrating the sample compose project to Navigation 3 (Part 2/3), and is specific and clear.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/#617-migrate-to-navigation-3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Dec 2, 2025

17 Warnings
⚠️ Big PR
⚠️ Uh oh! BaseViewModel.kt is under 95% coverage!
⚠️ Uh oh! HomeScreen.kt is under 95% coverage!
⚠️ Uh oh! Your project is under 80% coverage!
⚠️ template-compose/gradle/libs.versions.toml#L10 - A newer version of androidx.compose:compose-bom than 2025.02.00 is available: 2026.02.00
⚠️ template-compose/gradle/libs.versions.toml#L12 - A newer version of androidx.navigation:navigation-compose than 2.5.3 is available: 2.9.7
⚠️ template-compose/gradle/libs.versions.toml#L13 - A newer version of androidx.core:core-ktx than 1.15.0 is available: 1.17.0
⚠️ template-compose/gradle/libs.versions.toml#L14 - A newer version of androidx.datastore:datastore-preferences than 1.1.3 is available: 1.2.0
⚠️ template-compose/gradle/libs.versions.toml#L17 - A newer version of com.android.application than 8.8.2 is available: 9.0.1
⚠️ template-compose/gradle/libs.versions.toml#L17 - A newer version of com.android.library than 8.8.2 is available: 9.0.1
⚠️ template-compose/gradle/libs.versions.toml#L19 - A newer version of androidx.hilt:hilt-navigation-compose than 1.2.0 is available: 1.3.0
⚠️ template-compose/gradle/libs.versions.toml#L25 - A newer version of org.jetbrains.kotlinx:kotlinx-coroutines-core than 1.7.3 is available: 1.10.2
⚠️ template-compose/gradle/libs.versions.toml#L25 - A newer version of org.jetbrains.kotlinx:kotlinx-coroutines-test than 1.7.3 is available: 1.10.2
⚠️ template-compose/gradle/libs.versions.toml#L28 - A newer version of androidx.lifecycle:lifecycle-runtime-compose than 2.8.7 is available: 2.10.0
⚠️ template-compose/gradle/libs.versions.toml#L28 - A newer version of androidx.lifecycle:lifecycle-runtime-ktx than 2.8.7 is available: 2.10.0
⚠️ template-compose/gradle/libs.versions.toml#L35 - A newer version of androidx.security:security-crypto than 1.0.0 is available: 1.1.0
⚠️ template-compose/gradle/libs.versions.toml#L36 - A newer version of androidx.test:core-ktx than 1.6.1 is available: 1.7.0

Kover report for template-compose:

🧛 Template - Compose Unit Tests Code Coverage: 73.20%

Coverage of Modified Files:

File Coverage
BaseScreen.kt 100.00%
BaseViewModel.kt 85.71%
HomeScreen.kt 92.00%
HomeViewModel.kt 100.00%
UiModel.kt 100.00%

Modified Files Not Found In Coverage Report:

ComponentActivityExt.kt
ComposableUtil.kt
Constants.kt
DeepLinkMatcher.kt
DeepLinkPattern.kt
DeepLinkRequest.kt
FakeNavigator.kt
FakeNavigator.kt
HomeScreenTest.kt
HomeScreenTest.kt
HomeViewModelTest.kt
KeyDecoder.kt
MainActivity.kt
MainActivityModule.kt
Navigator.kt
NavigatorImpl.kt
ResultEffect.kt
ResultEventBus.kt
SecondScreen.kt
ThirdScreen.kt
build.gradle.kts
build.gradle.kts
gradle-wrapper.properties
libs.versions.toml

Codebase cunningly covered by count Shroud 🧛

Generated by 🚫 Danger

@eeeeaa eeeeaa temporarily deployed to template-compose December 2, 2025 02:25 — with GitHub Actions Inactive
@eeeeaa eeeeaa changed the title [#617] Migrate to navigation 3 [#617][Part 1] Migrate to navigation 3 Dec 2, 2025
@eeeeaa eeeeaa changed the base branch from develop to chore/610-part-2-update-navigation-library-and-refactor-to-follow-unidirectional-data-flow December 2, 2025 02:35
@eeeeaa eeeeaa changed the base branch from chore/610-part-2-update-navigation-library-and-refactor-to-follow-unidirectional-data-flow to develop December 2, 2025 02:39
@eeeeaa eeeeaa temporarily deployed to template-compose December 2, 2025 02:39 — with GitHub Actions Inactive
@eeeeaa eeeeaa force-pushed the chore/#617-migrate-to-navigation-3 branch from 5d653e5 to b44c618 Compare December 2, 2025 02:56
@eeeeaa eeeeaa temporarily deployed to template-compose December 2, 2025 02:56 — with GitHub Actions Inactive
@eeeeaa eeeeaa temporarily deployed to template-compose January 7, 2026 02:25 — with GitHub Actions Inactive
@eeeeaa eeeeaa changed the title [#617][Part 1] Migrate to navigation 3 [#617][Part 1] Migrate to navigation 3 - Sample compose project Feb 11, 2026
@eeeeaa eeeeaa force-pushed the chore/#617-migrate-to-navigation-3 branch from b44c618 to 33c4f7b Compare February 11, 2026 04:37
@eeeeaa eeeeaa temporarily deployed to template-compose February 11, 2026 04:39 — with GitHub Actions Inactive
@eeeeaa eeeeaa force-pushed the chore/#617-migrate-to-navigation-3 branch from 33c4f7b to 1491c46 Compare February 11, 2026 05:03
@eeeeaa eeeeaa temporarily deployed to template-compose February 11, 2026 05:05 — with GitHub Actions Inactive
@eeeeaa eeeeaa temporarily deployed to template-compose February 11, 2026 05:16 — with GitHub Actions Inactive
@eeeeaa eeeeaa temporarily deployed to template-compose February 11, 2026 05:21 — with GitHub Actions Inactive
@eeeeaa eeeeaa temporarily deployed to template-compose February 11, 2026 07:08 — with GitHub Actions Inactive
@eeeeaa eeeeaa temporarily deployed to template-compose February 11, 2026 07:13 — with GitHub Actions Inactive
@kaungkhantsoe
Copy link
Copy Markdown
Contributor

Also, shouldn't we work on Template Compose first, then Sample Compose? Or may be work on both at the same time. Because when we merge this PR, we will have different library versions in Template and Sample compose and different ways of navigation. 🤔

@eeeeaa
Copy link
Copy Markdown
Author

eeeeaa commented Feb 26, 2026

@kaungkhantsoe I aim to migrate to nav3 step by step else the PR size will be too big, so I will work on template-compose on a separate PR, we could determine the order later when we merge, wdyt?

@kaungkhantsoe
Copy link
Copy Markdown
Contributor

@eeeeaa I am good with merging the template first 🤝

@eeeeaa eeeeaa force-pushed the chore/#617-migrate-to-navigation-3 branch from 26dbd65 to d19f547 Compare February 26, 2026 07:36
@eeeeaa eeeeaa temporarily deployed to template-compose February 26, 2026 07:36 — with GitHub Actions Inactive
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt (1)

79-96: Consider extracting duplicated pop transition specs.

The blocks on Line 79-87 and Line 88-96 are identical. A shared helper would reduce drift risk.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt`
around lines 79 - 96, The two identical lambda blocks assigned to
popTransitionSpec and predictivePopTransitionSpec should be extracted into a
single helper to avoid duplication: create a reusable function or val (e.g.,
createPopTransitionSpec or popTransitionSpecHelper) that returns the combined
slideInHorizontally togetherWith slideOutHorizontally using
TWEEN_DURATION_IN_MILLIS, then replace both popTransitionSpec and
predictivePopTransitionSpec usages with that helper; reference the existing
symbols popTransitionSpec, predictivePopTransitionSpec, slideInHorizontally,
slideOutHorizontally and TWEEN_DURATION_IN_MILLIS when implementing the change.
sample-compose/app/src/main/java/co/nimblehq/sample/compose/di/modules/main/MainActivityModule.kt (1)

41-46: Use an explicit result key for this update event.

On Line 41/45/62, the default Boolean-typed key is used. This can cause cross-screen collisions when another Boolean result channel is introduced.

♻️ Proposed refactor
 object MainActivityModule {
+    private const val RESULT_KEY_SECOND_UPDATED = "result_second_updated"

     `@Provides`
     `@ActivityRetainedScoped`
     fun provideNavigator(): Navigator = NavigatorImpl(startDestination = Home)

@@
-                ResultEffect<Boolean> { isUpdated ->
+                ResultEffect<Boolean>(resultKey = RESULT_KEY_SECOND_UPDATED) { isUpdated ->
                     if (isUpdated) {
                         context.showToast(context.getString(R.string.message_updated))
                     }
-                    eventBus.removeResult<Boolean>()
+                    eventBus.removeResult<Boolean>(resultKey = RESULT_KEY_SECOND_UPDATED)
                 }
@@
                     onUpdateClick = {
-                        eventBus.sendResult<Boolean>(result = true)
+                        eventBus.sendResult<Boolean>(
+                            resultKey = RESULT_KEY_SECOND_UPDATED,
+                            result = true
+                        )
                         navigator.goBack()
                     }
                 )
             }

Also applies to: 61-63

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/di/modules/main/MainActivityModule.kt`
around lines 41 - 46, The ResultEffect<Boolean> block uses the implicit
Boolean-typed default key which can collide across screens; change it to use an
explicit result key constant (e.g., val UPDATE_RESULT_KEY = "update_result") and
pass that key into ResultEffect<Boolean>(key = UPDATE_RESULT_KEY) and into
eventBus.removeResult<Boolean>(UPDATE_RESULT_KEY); update both occurrences (the
ResultEffect<Boolean> where
context.showToast(context.getString(R.string.message_updated)) is called and the
matching eventBus.removeResult<Boolean> calls) so the result channel is uniquely
namespaced.
sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt (1)

22-23: Align ThirdScreen nullability with Third key contract.

Line 22 defines Third.model as non-null, but Line 27/38 accept nullable values. Tightening this keeps the API consistent and avoids accidental "null" rendering.

♻️ Proposed refactor
 data class Third(val model: UiModel)

 `@Suppress`("UnusedPrivateMember")
 `@Composable`
 fun ThirdScreen(
-    model: UiModel?,
+    model: UiModel,
     navigator: Navigator,
     viewModel: ThirdViewModel = hiltViewModel(),
 ) = BaseScreen(
@@
 private fun ThirdScreenContent(
-    data: UiModel?,
+    data: UiModel,
     modifier: Modifier = Modifier,
 ) {

Also applies to: 27-39

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt`
around lines 22 - 23, ThirdScreen currently accepts nullable models while the
Third data class declares model as non-null (data class Third(val model:
UiModel)); update the API to be consistent by changing ThirdScreen’s parameters
and any call sites to require a non-null Third (or non-null UiModel) instead of
nullable types—locate the ThirdScreen composable/function that takes a nullable
Third or UiModel and make its parameter non-null, remove null checks or default
"null" rendering, and ensure callers always pass a Third (or Third.model) that
is non-null to match data class Third(val model: UiModel).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt`:
- Around line 44-47: The deep-link key construction currently force-unwraps
args["id"] in the DeepLinkPattern keyBuilder (and keyBuilder is invoked
unguarded elsewhere), which can crash on malformed links; update the
DeepLinkPattern entries in deepLinkPatterns so keyBuilder safely handles a
missing or non-numeric "id" (e.g., parse/validate args["id"] and return a
nullable key or a Result) and then update the place that executes keyBuilder
(the code that calls keyBuilder around lines 110-115) to check the returned
value for null/failure before using it (skip navigation or show an error)
instead of assuming a non-null Second(id = ...); reference DeepLinkPattern,
keyBuilder, Second, and deepLinkPatterns when making the changes.

In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkMatcher.kt`:
- Around line 13-16: Validate the incoming URI's scheme and authority/host
before comparing path segments: in DeepLinkMatcher.kt, before the existing
pathSegments.size check and before the argument-matching block (the blocks
around request.pathSegments vs deepLinkPattern.pathSegments and the later 20-35
logic), first compare request.scheme (or request.uri.scheme) and
request.authority/host with deepLinkPattern's expected scheme/authority; if they
differ return null. Apply the same scheme/authority check in both the
exact-match branch that returns DeepLinkMatchResult(deepLinkPattern.keyBuilder,
mapOf()) and in the argument-extraction branch so URIs from other hosts/schemes
with identical path shapes are rejected.

---

Nitpick comments:
In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/di/modules/main/MainActivityModule.kt`:
- Around line 41-46: The ResultEffect<Boolean> block uses the implicit
Boolean-typed default key which can collide across screens; change it to use an
explicit result key constant (e.g., val UPDATE_RESULT_KEY = "update_result") and
pass that key into ResultEffect<Boolean>(key = UPDATE_RESULT_KEY) and into
eventBus.removeResult<Boolean>(UPDATE_RESULT_KEY); update both occurrences (the
ResultEffect<Boolean> where
context.showToast(context.getString(R.string.message_updated)) is called and the
matching eventBus.removeResult<Boolean> calls) so the result channel is uniquely
namespaced.

In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt`:
- Around line 22-23: ThirdScreen currently accepts nullable models while the
Third data class declares model as non-null (data class Third(val model:
UiModel)); update the API to be consistent by changing ThirdScreen’s parameters
and any call sites to require a non-null Third (or non-null UiModel) instead of
nullable types—locate the ThirdScreen composable/function that takes a nullable
Third or UiModel and make its parameter non-null, remove null checks or default
"null" rendering, and ensure callers always pass a Third (or Third.model) that
is non-null to match data class Third(val model: UiModel).

In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt`:
- Around line 79-96: The two identical lambda blocks assigned to
popTransitionSpec and predictivePopTransitionSpec should be extracted into a
single helper to avoid duplication: create a reusable function or val (e.g.,
createPopTransitionSpec or popTransitionSpecHelper) that returns the combined
slideInHorizontally togetherWith slideOutHorizontally using
TWEEN_DURATION_IN_MILLIS, then replace both popTransitionSpec and
predictivePopTransitionSpec usages with that helper; reference the existing
symbols popTransitionSpec, predictivePopTransitionSpec, slideInHorizontally,
slideOutHorizontally and TWEEN_DURATION_IN_MILLIS when implementing the change.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e995ee4 and 26dbd65.

📒 Files selected for processing (12)
  • sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/di/modules/main/MainActivityModule.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainDestination.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreen.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModel.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondScreen.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkMatcher.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkPattern.kt
  • sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt
  • sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModelTest.kt
💤 Files with no reviewable changes (1)
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainDestination.kt
🚧 Files skipped from review as they are similar to previous changes (4)
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondScreen.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModel.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkPattern.kt
  • sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModelTest.kt

@coderabbitai coderabbitai Bot temporarily deployed to template-compose February 26, 2026 07:42 Inactive
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkMatcher.kt (1)

13-16: ⚠️ Potential issue | 🟠 Major

Reject cross-host/cross-scheme URIs before path matching.

At Line 13, matching starts with path shape only. A URI from a different scheme/authority but same path pattern can still match and build a key.

🛡️ Proposed fix
 fun match(): DeepLinkMatchResult<T>? {
+    if (request.uri.scheme != deepLinkPattern.uriPattern.scheme) return null
+    if (request.uri.authority != deepLinkPattern.uriPattern.authority) return null
     if (request.pathSegments.size != deepLinkPattern.pathSegments.size) return null
     // exact match (url does not contain any arguments)
     if (request.uri == deepLinkPattern.uriPattern)
         return DeepLinkMatchResult(deepLinkPattern.keyBuilder, mapOf())

Also applies to: 20-35

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkMatcher.kt`
around lines 13 - 16, The matcher currently compares only path shape
(request.pathSegments vs deepLinkPattern.pathSegments) before constructing a
key, allowing URIs with different schemes/hosts to match; update the matching
logic in DeepLinkMatcher (the block using request.pathSegments, request.uri and
deepLinkPattern.uriPattern and the later matching logic around lines ~20-35) to
first compare scheme and authority/host between the incoming request and the
deepLinkPattern (reject if scheme or host differ), and only then proceed to
path-segment or exact uriPattern comparisons and return
DeepLinkMatchResult(keyBuilder, ...).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkMatcher.kt`:
- Around line 13-16: The matcher currently compares only path shape
(request.pathSegments vs deepLinkPattern.pathSegments) before constructing a
key, allowing URIs with different schemes/hosts to match; update the matching
logic in DeepLinkMatcher (the block using request.pathSegments, request.uri and
deepLinkPattern.uriPattern and the later matching logic around lines ~20-35) to
first compare scheme and authority/host between the incoming request and the
deepLinkPattern (reject if scheme or host differ), and only then proceed to
path-segment or exact uriPattern comparisons and return
DeepLinkMatchResult(keyBuilder, ...).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26dbd65 and d19f547.

📒 Files selected for processing (12)
  • sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/di/modules/main/MainActivityModule.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainDestination.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreen.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModel.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondScreen.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkMatcher.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/util/DeepLinkPattern.kt
  • sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt
  • sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModelTest.kt
💤 Files with no reviewable changes (1)
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainDestination.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt
  • sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModel.kt

@eeeeaa eeeeaa force-pushed the chore/#617-migrate-to-navigation-3 branch from d19f547 to aba7ac7 Compare February 26, 2026 07:48
@eeeeaa eeeeaa force-pushed the chore/#617-migrate-to-navigation-3 branch from aba7ac7 to 7492383 Compare February 26, 2026 07:52
@eeeeaa eeeeaa temporarily deployed to template-compose February 26, 2026 07:52 — with GitHub Actions Inactive
@eeeeaa eeeeaa temporarily deployed to template-compose February 26, 2026 08:00 — with GitHub Actions Inactive
@eeeeaa eeeeaa force-pushed the chore/#617-migrate-to-navigation-3 branch from ac0c62b to 2d22049 Compare February 26, 2026 08:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants