Skip to content

Commit 5ea6f56

Browse files
committed
Add build in debian linux on android 15+ section to tips
1 parent 938fba8 commit 5ea6f56

15 files changed

Lines changed: 201 additions & 12 deletions

File tree

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
![Icon](https://raw.githubusercontent.com/SimonSchubert/LinuxCommandLibrary/master/art/web_hi_res_144.png)
44

5-
The app currently has **8290** manual pages, **28+** basic categories and a bunch of general terminal tips. It works 100% offline, doesn't need an internet connection and has no tracking software.
5+
The app currently has **8293** manual pages, **28+** basic categories and a bunch of general terminal tips. It works 100% offline, doesn't need an internet connection and has no tracking software.
66

77
[![App Store](https://raw.githubusercontent.com/SimonSchubert/LinuxCommandBibliotheca/master/art/app_store_badge.png)](https://apps.apple.com/us/app/linux-command-library/id1219649976)
88
[![Play Store](https://raw.githubusercontent.com/SimonSchubert/LinuxCommandBibliotheca/master/art/play_store_badge.png)](https://play.google.com/store/apps/details?id=com.inspiredandroid.linuxcommandbibliotheca)
@@ -13,9 +13,13 @@ Native CLI and GUI binaries for Linux, macOS, and Windows are available in [Rele
1313

1414
#### Homebrew
1515

16-
GUI: ```brew install --cask simonschubert/tap/linux-command-library```
16+
GUI:
1717

18-
CLI: ```brew install simonschubert/tap/linux-command-library-cli```
18+
```brew install --cask simonschubert/tap/linux-command-library```
19+
20+
CLI:
21+
22+
```brew install simonschubert/tap/linux-command-library-cli```
1923

2024
### Android screenshots
2125

cli/src/commonMain/kotlin/com/linuxcommandlibrary/nativecli/screens/BasicDetailScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class BasicDetailScreen(
6262
is com.linuxcommandlibrary.shared.TextElement.Bold -> Theme.boldText(element.text)
6363
is com.linuxcommandlibrary.shared.TextElement.Italic -> Theme.italicText(element.text)
6464
is com.linuxcommandlibrary.shared.TextElement.Man -> element.man
65+
is com.linuxcommandlibrary.shared.TextElement.Link -> element.text
6566
}
6667
}
6768

cli/src/commonMain/kotlin/com/linuxcommandlibrary/nativecli/screens/TipDetailScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class TipDetailScreen(private val tip: TipInfo) : Screen {
5252
is TextElement.Bold -> Theme.boldText(element.text)
5353
is TextElement.Italic -> Theme.italicText(element.text)
5454
is TextElement.Man -> element.man
55+
is TextElement.Link -> element.text
5556
}
5657
}
5758

common/src/commonMain/kotlin/com/linuxcommandlibrary/shared/TipSectionElement.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ sealed class TextElement {
1010
data class Bold(val text: String) : TextElement()
1111
data class Italic(val text: String) : TextElement()
1212
data class Man(val man: String) : TextElement()
13+
data class Link(val text: String, val action: String) : TextElement()
1314
}
1415

1516
/**
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,47 @@
11
package com.linuxcommandlibrary.app.platform
22

3+
import android.content.Intent
4+
import android.os.Build
5+
import android.provider.Settings
36
import androidx.compose.material.icons.Icons
47
import androidx.compose.material.icons.automirrored.filled.ArrowBack
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.runtime.remember
510
import androidx.compose.ui.graphics.vector.ImageVector
11+
import androidx.compose.ui.platform.LocalContext
612

713
actual val showRateAppButton: Boolean = true
14+
actual val showAndroidTerminalTip: Boolean = Build.VERSION.SDK_INT >= 35
815
actual val backIcon: ImageVector = Icons.AutoMirrored.Filled.ArrowBack
16+
17+
@Composable
18+
actual fun rememberOpenAppAction(): (String) -> Unit {
19+
val context = LocalContext.current
20+
return remember(context) {
21+
{ action ->
22+
try {
23+
when (action) {
24+
"settings" -> {
25+
context.startActivity(
26+
Intent(Settings.ACTION_SETTINGS).apply {
27+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
28+
},
29+
)
30+
}
31+
32+
"terminal" -> {
33+
val intent = context.packageManager.getLaunchIntentForPackage(
34+
"com.android.virtualization.terminal",
35+
)
36+
if (intent != null) {
37+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
38+
context.startActivity(intent)
39+
}
40+
}
41+
}
42+
} catch (e: Exception) {
43+
e.printStackTrace()
44+
}
45+
}
46+
}
47+
}

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import androidx.navigation.toRoute
6363
import com.linuxcommandlibrary.app.data.BasicsRepository
6464
import com.linuxcommandlibrary.app.data.CommandsRepository
6565
import com.linuxcommandlibrary.app.platform.backIcon
66+
import com.linuxcommandlibrary.app.platform.rememberOpenAppAction
6667
import com.linuxcommandlibrary.app.ui.composables.AppIcon
6768
import com.linuxcommandlibrary.app.ui.composables.rememberIconPainter
6869
import com.linuxcommandlibrary.app.ui.screens.AppInfoDialog
@@ -128,11 +129,16 @@ fun LinuxApp(initialDeeplink: String? = null) {
128129
}
129130
val showSearch = rememberSaveable { mutableStateOf(false) }
130131

131-
val onNavigate: (String) -> Unit = remember(navController) {
132+
val openAppAction = rememberOpenAppAction()
133+
val onNavigate: (String) -> Unit = remember(navController, openAppAction) {
132134
{ route ->
133-
val dest = parseRoute(route)
134-
if (dest != null) {
135-
navController.navigate(dest)
135+
if (route.startsWith("action:")) {
136+
openAppAction(route.removePrefix("action:"))
137+
} else {
138+
val dest = parseRoute(route)
139+
if (dest != null) {
140+
navController.navigate(dest)
141+
}
136142
}
137143
}
138144
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package com.linuxcommandlibrary.app.platform
22

3+
import androidx.compose.runtime.Composable
34
import androidx.compose.ui.graphics.vector.ImageVector
45

56
expect val showRateAppButton: Boolean
7+
expect val showAndroidTerminalTip: Boolean
68
expect val backIcon: ImageVector
9+
10+
@Composable
11+
expect fun rememberOpenAppAction(): (String) -> Unit

composeApp/src/commonMain/kotlin/com/linuxcommandlibrary/app/ui/composables/TableView.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ fun TableView(
105105
end,
106106
)
107107
}
108+
109+
is TextElement.Link -> append(element.text)
108110
}
109111
}
110112
}
@@ -126,5 +128,6 @@ private fun List<TextElement>.toPlainText(): String = this.joinToString("") { el
126128
is TextElement.Bold -> element.text
127129
is TextElement.Italic -> element.text
128130
is TextElement.Man -> element.man
131+
is TextElement.Link -> element.text
129132
}
130133
}

composeApp/src/commonMain/kotlin/com/linuxcommandlibrary/app/ui/composables/TipSectionContent.kt

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package com.linuxcommandlibrary.app.ui.composables
22

33
import androidx.compose.foundation.layout.padding
4+
import androidx.compose.foundation.text.ClickableText
5+
import androidx.compose.material.MaterialTheme
46
import androidx.compose.material.Text
57
import androidx.compose.runtime.Composable
68
import androidx.compose.runtime.remember
79
import androidx.compose.ui.Modifier
810
import androidx.compose.ui.graphics.Color
911
import androidx.compose.ui.text.AnnotatedString
12+
import androidx.compose.ui.text.LinkAnnotation
1013
import androidx.compose.ui.text.SpanStyle
1114
import androidx.compose.ui.text.buildAnnotatedString
1215
import androidx.compose.ui.text.font.FontStyle
1316
import androidx.compose.ui.text.font.FontWeight
17+
import androidx.compose.ui.text.style.TextDecoration
1418
import androidx.compose.ui.text.withStyle
1519
import androidx.compose.ui.unit.Dp
1620
import androidx.compose.ui.unit.dp
@@ -20,6 +24,8 @@ import com.linuxcommandlibrary.shared.TipSectionElement
2024
fun buildTextElementString(
2125
elements: List<TextElement>,
2226
textColor: Color = Color.Unspecified,
27+
linkColor: Color = Color.Unspecified,
28+
onNavigate: ((String) -> Unit)? = null,
2329
): AnnotatedString = buildAnnotatedString {
2430
elements.forEach { textElement ->
2531
when (textElement) {
@@ -38,6 +44,36 @@ fun buildTextElementString(
3844
}
3945

4046
is TextElement.Man -> append(textElement.man)
47+
48+
is TextElement.Link -> {
49+
if (onNavigate != null) {
50+
val start = this.length
51+
withStyle(
52+
style = SpanStyle(
53+
color = linkColor,
54+
fontWeight = FontWeight.Bold,
55+
textDecoration = TextDecoration.Underline,
56+
),
57+
) {
58+
append(textElement.text)
59+
}
60+
val end = this.length
61+
addLink(
62+
LinkAnnotation.Clickable(
63+
tag = "action:${textElement.action}",
64+
linkInteractionListener = {
65+
onNavigate("action:${textElement.action}")
66+
},
67+
),
68+
start,
69+
end,
70+
)
71+
} else {
72+
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = textColor)) {
73+
append(textElement.text)
74+
}
75+
}
76+
}
4177
}
4278
}
4379
}
@@ -49,11 +85,12 @@ fun TipSectionContent(
4985
textColor: Color = Color.Unspecified,
5086
commandVerticalPadding: Dp = 0.dp,
5187
) {
88+
val linkColor = MaterialTheme.colors.primary
5289
sections.forEach { section ->
5390
when (section) {
5491
is TipSectionElement.Text -> {
55-
val annotatedString = remember(section.elements, textColor) {
56-
buildTextElementString(section.elements, textColor)
92+
val annotatedString = remember(section.elements, textColor, linkColor) {
93+
buildTextElementString(section.elements, textColor, linkColor, onNavigate)
5794
}
5895
Text(
5996
text = annotatedString,

composeApp/src/commonMain/kotlin/com/linuxcommandlibrary/app/ui/screens/tips/TipsViewModel.kt

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package com.linuxcommandlibrary.app.ui.screens.tips
22

33
import com.linuxcommandlibrary.app.data.TipInfo
44
import com.linuxcommandlibrary.app.data.TipsRepository
5+
import com.linuxcommandlibrary.app.platform.showAndroidTerminalTip
6+
import com.linuxcommandlibrary.shared.TextElement
7+
import com.linuxcommandlibrary.shared.TipSectionElement
58
import kotlinx.collections.immutable.ImmutableList
69
import kotlinx.collections.immutable.persistentListOf
710
import kotlinx.collections.immutable.toImmutableList
@@ -20,7 +23,80 @@ class TipsViewModel(
2023

2124
init {
2225
scope.launch(Dispatchers.Default) {
23-
_tips.value = tipsRepository.getTips().toImmutableList()
26+
val tips = tipsRepository.getTips()
27+
_tips.value = if (showAndroidTerminalTip) {
28+
(tips + createTerminalSetupTip()).toImmutableList()
29+
} else {
30+
tips.toImmutableList()
31+
}
2432
}
2533
}
34+
35+
private fun createTerminalSetupTip(): TipInfo {
36+
val sections = listOf(
37+
TipSectionElement.Text(
38+
listOf(
39+
TextElement.Plain("Android 15+ includes a built-in Linux terminal running Debian. Here's how to enable it:"),
40+
),
41+
),
42+
TipSectionElement.Text(
43+
listOf(
44+
TextElement.Plain("1. Open "),
45+
TextElement.Link("Settings", "settings"),
46+
),
47+
),
48+
TipSectionElement.Text(
49+
listOf(
50+
TextElement.Plain("2. Scroll down and tap "),
51+
TextElement.Bold("System"),
52+
),
53+
),
54+
TipSectionElement.Text(
55+
listOf(
56+
TextElement.Plain("3. Tap "),
57+
TextElement.Bold("Developer options"),
58+
),
59+
),
60+
TipSectionElement.Text(
61+
listOf(
62+
TextElement.Plain("If not visible, go to "),
63+
TextElement.Bold("Settings > About phone"),
64+
TextElement.Plain(" and tap "),
65+
TextElement.Bold("Build number"),
66+
TextElement.Plain(" 7 times to unlock it"),
67+
),
68+
),
69+
TipSectionElement.Text(
70+
listOf(
71+
TextElement.Plain("4. Scroll down to the "),
72+
TextElement.Bold("Linux terminal"),
73+
TextElement.Plain(" toggle and enable it"),
74+
),
75+
),
76+
TipSectionElement.Text(
77+
listOf(
78+
TextElement.Plain("5. Open the "),
79+
TextElement.Link("Terminal", "terminal"),
80+
TextElement.Plain(" app from your app drawer"),
81+
),
82+
),
83+
TipSectionElement.Text(
84+
listOf(
85+
TextElement.Plain("6. Follow the on-screen setup to complete the installation"),
86+
),
87+
),
88+
TipSectionElement.Text(
89+
listOf(
90+
TextElement.Plain("The terminal runs a Debian Linux environment with full package management via "),
91+
TextElement.Bold("apt"),
92+
TextElement.Plain(". You can install tools, compilers, and servers just like on a regular Debian system."),
93+
),
94+
),
95+
)
96+
return TipInfo(
97+
id = -1,
98+
title = "Set up the built-in Linux terminal",
99+
sections = sections.toImmutableList(),
100+
)
101+
}
26102
}

0 commit comments

Comments
 (0)