Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile

plugins {
alias(libs.plugins.aboutlibraries)
alias(libs.plugins.android.application)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlin)
Expand Down Expand Up @@ -75,6 +76,9 @@ ktlint {
}

dependencies {
// AboutLibraries
implementation(libs.aboutlibraries.compose.m3)

// AndroidX
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.rickyhu.hushkeyboard.libraries

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
import com.rickyhu.hushkeyboard.R

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LibrariesScreen(onBackClick: () -> Unit = {}) {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(
text = stringResource(R.string.libraries),
style = MaterialTheme.typography.headlineMedium,
)
},
navigationIcon = {
IconButton(onClick = onBackClick) {
Icon(
painter = painterResource(R.drawable.ic_return),
contentDescription = stringResource(R.string.libraries),
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

The content description for the back button should be more descriptive. Using "Libraries" as the content description for a back/return button is misleading for accessibility.

Consider using a more appropriate description like "Navigate back" or "Back" that accurately describes the action performed when the button is pressed, rather than repeating the screen title.

Suggested change
contentDescription = stringResource(R.string.libraries),
contentDescription = "Back",

Copilot uses AI. Check for mistakes.
)
}
},
)
},
) { padding ->
LibrariesContainer(
modifier = Modifier
.fillMaxSize()
.padding(padding),
)
}
}
10 changes: 9 additions & 1 deletion app/src/main/java/com/rickyhu/hushkeyboard/main/MainApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.navigation.compose.rememberNavController
import com.rickyhu.hushkeyboard.data.ThemeOption
import com.rickyhu.hushkeyboard.home.HomeScreen
import com.rickyhu.hushkeyboard.introduction.IntroductionScreen
import com.rickyhu.hushkeyboard.libraries.LibrariesScreen
import com.rickyhu.hushkeyboard.settings.SettingsScreen
import com.rickyhu.hushkeyboard.theme.HushKeyboardTheme
import org.koin.androidx.compose.koinViewModel
Expand Down Expand Up @@ -50,7 +51,14 @@ fun MainApp(viewModel: MainViewModel = koinViewModel()) {
)
}
composable<Route.Settings> {
SettingsScreen()
SettingsScreen(
onLibrariesClick = { navController.navigate(route = Route.Libraries) },
)
}
composable<Route.Libraries> {
LibrariesScreen(
onBackClick = { navController.popBackStack() },
)
}
composable<Route.Introduction> {
IntroductionScreen(
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/com/rickyhu/hushkeyboard/main/Route.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ sealed interface Route {
@Serializable
object Settings : Route

@Serializable
object Libraries : Route

@Serializable
object Introduction : Route
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.rickyhu.hushkeyboard.settings

import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -12,6 +13,7 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
Expand All @@ -38,7 +40,10 @@ import com.rickyhu.hushkeyboard.theme.HushKeyboardTheme
import org.koin.androidx.compose.koinViewModel

@Composable
fun SettingsScreen(viewModel: SettingsViewModel = koinViewModel()) {
fun SettingsScreen(
viewModel: SettingsViewModel = koinViewModel(),
onLibrariesClick: () -> Unit = {},
) {
val state by viewModel.settingsState.collectAsState(SettingsState())

SettingsContent(
Expand All @@ -49,6 +54,7 @@ fun SettingsScreen(viewModel: SettingsViewModel = koinViewModel()) {
onSmartDeleteChanged = viewModel::updateSmartDelete,
onAddSpaceBetweenNotationChanged = viewModel::updateAddSpaceBetweenNotation,
onVibrateOnTapChanged = viewModel::updateVibrateOnTap,
onLibrariesClick = onLibrariesClick,
)
}

Expand All @@ -63,6 +69,7 @@ fun SettingsContent(
onSmartDeleteChanged: (smartDelete: Boolean) -> Unit,
onAddSpaceBetweenNotationChanged: (addSpaceAfterNotation: Boolean) -> Unit,
onVibrateOnTapChanged: (vibrateOnTap: Boolean) -> Unit,
onLibrariesClick: () -> Unit = {},
) {
val context = LocalContext.current

Expand Down Expand Up @@ -197,6 +204,17 @@ fun SettingsContent(
trailing = { Text(versionName) },
)

ListItem(
headlineContent = { Text(stringResource(R.string.libraries)) },
leadingContent = {
Icon(
painter = painterResource(R.drawable.ic_library),
contentDescription = stringResource(R.string.libraries),
)
},
modifier = Modifier.clickable { onLibrariesClick() },
)
Comment on lines +207 to +216
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

The Libraries list item should follow the established codebase pattern of using a generic composable like UrlLauncherListItem, SwitchListItem, or DropdownListItem. Currently, this directly uses ListItem with clickable modifier, which is inconsistent with the other items in SettingsContent (Version uses UrlLauncherListItem, switches use SwitchListItem, etc.).

Consider creating a NavigationListItem composable similar to UrlLauncherListItem that accepts a title, leading icon, and onClick callback. This would provide consistency with the existing UI component patterns and make the code more maintainable. The pattern should be:

  • Create NavigationListItem.kt in settings/ui/
  • Use it here instead of the raw ListItem + clickable
  • This maintains the established convention of using generic composables for settings UI

Copilot uses AI. Check for mistakes.
Comment on lines +207 to +216
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

The new Libraries list item lacks test coverage. The existing test suite (SettingsScreenUiTest.kt) includes tests for all other interactive items in SettingsContent (theme dropdown, keyboard color, switches, version, etc.).

Add tests to verify:

  • The Libraries item exists, is enabled, and has click action
  • The onLibrariesClick callback is invoked when the item is clicked

This maintains consistency with the comprehensive test coverage pattern established for other settings UI elements.

Copilot uses AI. Check for mistakes.

UrlLauncherListItem(
title = stringResource(R.string.donate),
url = stringResource(R.string.buy_me_a_coffee_url),
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_library.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#000000">
<path
android:fillColor="@android:color/white"
android:pathData="M18,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM9,4h2v5l-1,-0.75L9,9V4zM18,20H6V4h1v9l3,-2.25L13,13V4h5v16z" />
</vector>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<string name="version">Version</string>
<string name="version_unknown">Unknown Version</string>
<string name="hush_keyboard_github">https://github.com/ricky9667/HushKeyboard</string>
<string name="libraries">Open-source libraries</string>
Copy link
Owner

Choose a reason for hiding this comment

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

@copilot Change Opens-source libraries to Libraries

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 6f3b337.

<string name="donate">Donate</string>
<string name="buy_me_a_coffee_url">https://coff.ee/ricky9667</string>

Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ buildscript {

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.aboutlibraries) apply false
alias(libs.plugins.android.application) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.kotlin) apply false
Expand Down
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[versions]
aboutlibraries = "11.2.3"
activity-compose = "1.12.4"
android-gradle-plugin = "9.0.1"
android-lifecycle = "2.10.0"
Expand All @@ -19,6 +20,7 @@ robolectric = "4.16.1"
splitties-systemservices = "3.0.0"

[libraries]
aboutlibraries-compose-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlibraries" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "android-lifecycle" }
androidx-lifecycle-service = { group = "androidx.lifecycle", name = "lifecycle-service", version.ref = "android-lifecycle" }
Expand All @@ -44,6 +46,7 @@ robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "
splitties-systemservices = { group = "com.louiscad.splitties", name = "splitties-systemservices", version.ref = "splitties-systemservices" }

[plugins]
aboutlibraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutlibraries" }
android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
Expand Down