Skip to content

Commit 0e7421a

Browse files
Merge pull request #91 from Rikul/deeplink-test-fix
Fix deeplink test and update dependencies
2 parents 2a92d2d + 67b02bc commit 0e7421a

5 files changed

Lines changed: 62 additions & 18 deletions

File tree

android/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies {
1717
implementation(libs.koin.core)
1818
implementation(libs.koin.android)
1919
implementation(libs.koin.androidx.compose)
20+
implementation(libs.androidx.preference.ktx)
2021

2122
androidTestImplementation(libs.androidx.ui.test.junit4)
2223
debugImplementation(libs.androidx.ui.test.manifest)

android/src/androidTest/java/com/inspiredandroid/linuxcommandbibliotheca/ComposeDeeplinkTests.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ package com.inspiredandroid.linuxcommandbibliotheca
33
import android.content.Context
44
import android.content.Intent
55
import android.net.Uri
6-
import android.preference.PreferenceManager
76
import androidx.compose.ui.test.assertTextEquals
8-
import androidx.compose.ui.test.junit4.createEmptyComposeRule
7+
import androidx.compose.ui.test.junit4.createAndroidComposeRule
98
import androidx.compose.ui.test.onNodeWithContentDescription
109
import androidx.compose.ui.test.performClick
11-
import androidx.test.core.app.ActivityScenario
1210
import androidx.test.core.app.ApplicationProvider
1311
import androidx.test.ext.junit.runners.AndroidJUnit4
1412
import org.junit.Before
@@ -24,23 +22,27 @@ import org.junit.runner.RunWith
2422
@RunWith(AndroidJUnit4::class)
2523
class ComposeDeeplinkTests {
2624

27-
private lateinit var scenario: ActivityScenario<MainActivity>
28-
2925
@get:Rule
30-
val composeTestRule = createEmptyComposeRule()
26+
val composeTestRule = createAndroidComposeRule<MainActivity>()
3127

3228
@Before
3329
fun setUp() {
3430
val context: Context = ApplicationProvider.getApplicationContext()
3531

3632
// Clear bookmarks
37-
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
33+
val prefs = androidx.preference.PreferenceManager.getDefaultSharedPreferences(context)
3834
prefs.edit().putString("KEY_BOOKMARKS", "").apply()
3935
}
4036

4137
private fun openUrl(url: String) {
38+
val context = ApplicationProvider.getApplicationContext<Context>()
4239
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
43-
scenario = ActivityScenario.launch(intent)
40+
.setPackage(context.packageName)
41+
42+
composeTestRule.activityRule.scenario.onActivity { activity ->
43+
activity.startActivity(intent)
44+
}
45+
composeTestRule.waitForIdle()
4446
}
4547

4648
@Test
@@ -54,7 +56,7 @@ class ComposeDeeplinkTests {
5456
@Test
5557
fun testBasicCategory() {
5658
openUrl("https://linuxcommandlibrary.com/basic/usersgroups")
57-
59+
5860
composeTestRule.onNodeWithContentDescription("TopAppBarTitle")
5961
.assertTextEquals("Users & Groups")
6062
}
@@ -71,7 +73,6 @@ class ComposeDeeplinkTests {
7173
fun testCommandList() {
7274
openUrl("https://linuxcommandlibrary.com/")
7375

74-
composeTestRule.onNodeWithContentDescription("Back").performClick()
7576
composeTestRule.onNodeWithContentDescription("TopAppBarTitle")
7677
.assertTextEquals("Commands")
7778
}

android/src/main/java/com/inspiredandroid/linuxcommandbibliotheca/MainActivity.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class MainActivity : AppCompatActivity() {
3939
)
4040
super.onCreate(savedInstanceState)
4141

42+
val deeplink = intent?.data?.toString()
43+
4244
setContent {
4345
LinuxTheme {
4446
Box(
@@ -51,7 +53,7 @@ class MainActivity : AppCompatActivity() {
5153
.background(LocalCustomColors.current.navBarBackground)
5254
.systemBarsPadding(),
5355
) {
54-
App()
56+
App(initialDeeplink = deeplink)
5557
}
5658
}
5759
}

composeApp/src/commonMain/kotlin/com/linuxcommandlibrary/app/App.kt

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ import androidx.compose.ui.focus.focusRequester
5151
import androidx.compose.ui.graphics.Color
5252
import androidx.compose.ui.input.pointer.PointerIcon
5353
import androidx.compose.ui.input.pointer.pointerHoverIcon
54+
import androidx.compose.ui.semantics.contentDescription
55+
import androidx.compose.ui.semantics.semantics
5456
import androidx.compose.ui.text.TextRange
5557
import androidx.compose.ui.text.input.TextFieldValue
5658
import androidx.compose.ui.text.style.TextOverflow
@@ -88,7 +90,7 @@ sealed class NavDestination {
8890
}
8991

9092
@Composable
91-
fun App() {
93+
fun App(initialDeeplink: String? = null) {
9294
val reviewHandler: ReviewHandler = koinInject()
9395
LaunchedEffect(Unit) {
9496
reviewHandler.incrementAppStartCount()
@@ -106,7 +108,7 @@ fun App() {
106108
)
107109
// Main content
108110
Box(modifier = Modifier.weight(1f)) {
109-
LinuxApp()
111+
LinuxApp(initialDeeplink = initialDeeplink)
110112
}
111113
// Navigation bar area with white/surface color
112114
Spacer(
@@ -120,8 +122,11 @@ fun App() {
120122
}
121123

122124
@Composable
123-
fun LinuxApp() {
124-
var currentDestination by remember { mutableStateOf<NavDestination>(NavDestination.Basics) }
125+
fun LinuxApp(initialDeeplink: String? = null) {
126+
val initialDestination = remember(initialDeeplink) {
127+
parseDeeplink(initialDeeplink) ?: NavDestination.Basics
128+
}
129+
var currentDestination by remember { mutableStateOf<NavDestination>(initialDestination) }
125130
val navigationStack = remember { mutableListOf<NavDestination>() }
126131
val searchTextValue = rememberSaveable(stateSaver = TextFieldValue.Saver) {
127132
mutableStateOf(TextFieldValue(text = "", selection = TextRange(0)))
@@ -278,6 +283,25 @@ private fun parseRoute(route: String): NavDestination? = when {
278283
else -> null
279284
}
280285

286+
private fun parseDeeplink(url: String?): NavDestination? {
287+
if (url == null) return null
288+
289+
return when {
290+
url.endsWith("/basics.html") || url.endsWith("/basics") -> NavDestination.Basics
291+
url.endsWith("/tips.html") || url.endsWith("/tips") -> NavDestination.Tips
292+
url.contains("/man/") -> {
293+
val commandName = url.substringAfterLast("/man/").removeSuffix(".html")
294+
NavDestination.CommandDetail(commandName)
295+
}
296+
url.contains("/basic/") -> {
297+
val categoryId = url.substringAfterLast("/basic/").removeSuffix(".html")
298+
NavDestination.BasicGroups(categoryId)
299+
}
300+
url.endsWith("/") || url.endsWith("/index.html") -> NavDestination.Commands
301+
else -> null
302+
}
303+
}
304+
281305
@Composable
282306
private fun getTitleForDestination(dest: NavDestination): String = when (dest) {
283307
NavDestination.Basics -> "Basics"
@@ -307,7 +331,12 @@ private fun GenericTopBar(
307331

308332
TopAppBar(
309333
title = {
310-
Text(title, maxLines = 1, overflow = TextOverflow.Ellipsis)
334+
Text(
335+
title,
336+
modifier = Modifier.semantics { contentDescription = "TopAppBarTitle" },
337+
maxLines = 1,
338+
overflow = TextOverflow.Ellipsis,
339+
)
311340
},
312341
backgroundColor = MaterialTheme.colors.primary,
313342
contentColor = Color.White,
@@ -361,7 +390,12 @@ private fun DetailTopBar(
361390

362391
TopAppBar(
363392
title = {
364-
Text(commandName, maxLines = 1, overflow = TextOverflow.Ellipsis)
393+
Text(
394+
commandName,
395+
modifier = Modifier.semantics { contentDescription = "TopAppBarTitle" },
396+
maxLines = 1,
397+
overflow = TextOverflow.Ellipsis,
398+
)
365399
},
366400
backgroundColor = MaterialTheme.colors.primary,
367401
contentColor = Color.White,
@@ -476,7 +510,10 @@ private fun SearchTopBar(
476510
} else {
477511
Text(
478512
title,
479-
modifier = Modifier.weight(1f).padding(start = 16.dp),
513+
modifier = Modifier
514+
.weight(1f)
515+
.padding(start = 16.dp)
516+
.semantics { contentDescription = "TopAppBarTitle" },
480517
style = MaterialTheme.typography.h6.copy(color = LocalContentColor.current),
481518
maxLines = 1,
482519
overflow = TextOverflow.Ellipsis,

gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ spotless = "8.2.1"
1818
kotlinxCollectionsImmutable = "0.4.0"
1919
benManesVersions = "0.53.0"
2020
mordant = "3.0.2"
21+
preferenceKtx = "1.2.1"
2122

2223

2324
[libraries]
@@ -39,11 +40,13 @@ koin-core = { module = "io.insert-koin:koin-core", version.ref = "koinCore" }
3940
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
4041
kotlinx-html-jvm = { module = "org.jetbrains.kotlinx:kotlinx-html-jvm", version.ref = "kotlinxHtmlJvm" }
4142
kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutable" }
43+
androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "preferenceKtx" }
4244

4345

4446
[plugins]
4547
android-application = { id = "com.android.application", version.ref = "agp" }
4648
android-library = { id = "com.android.library", version.ref = "agp" }
49+
android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
4750
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
4851
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
4952
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

0 commit comments

Comments
 (0)