add generic reorder dialog and prelimiary toolbar pref screen

This commit is contained in:
Helium314 2025-01-28 16:14:42 +01:00
parent d61963453f
commit ce37888985
9 changed files with 203 additions and 14 deletions

View file

@ -114,6 +114,7 @@ dependencies {
implementation("androidx.compose.ui:ui-tooling-preview")
debugImplementation("androidx.compose.ui:ui-tooling")
implementation("androidx.navigation:navigation-compose:2.8.5")
implementation("sh.calvin.reorderable:reorderable:2.4.2")
// color picker for user-defined colors
implementation("com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0")

View file

@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
import helium314.keyboard.settings.screens.createAboutPrefs
import helium314.keyboard.settings.screens.createCorrectionPrefs
import helium314.keyboard.settings.screens.createPreferencesPrefs
import helium314.keyboard.settings.screens.createToolbarPrefs
class AllPrefs(context: Context) {
private val list = createPrefDefs(context)
@ -51,7 +52,7 @@ class PrefDef(
}
private fun createPrefDefs(context: Context) = createAboutPrefs(context) +
createCorrectionPrefs(context) + createPreferencesPrefs(context)
createCorrectionPrefs(context) + createPreferencesPrefs(context) + createToolbarPrefs(context)
// todo: move somewhere else
fun Context.getActivity(): ComponentActivity? {

View file

@ -14,10 +14,13 @@ import helium314.keyboard.latin.utils.DeviceProtectedUtils
import kotlinx.coroutines.flow.MutableStateFlow
// todo
// add reorder / enable dialog (maybe not as dialog?)
// add reorder / enable dialog
// reorder part is already done
// more pref screens, and other super-custom things
// consider IME insets when searching
// improve performance when loading screens with many settings (lazyColumn?)
// screens could have a lazy column of preferences and category separators, and the list has an if-setting-then-null for hiding
// lazyColumn also has the key, this should be used! and must be unique
// consider that stuff in composables can get called quite often on any changes -> use remember for things that are slow (maybe add test logging)
// later
@ -29,7 +32,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
// rename some classes
// split the preferences in allPrefs.createDefs into multiple files, this will get horribly long
// maybe have sub-lists in the pref screens using the settings?
// spdx headers everywhere
// spdx headers everywhere (except DragDropColumn, which is from stackoverflow without explicit license)
// changes to anything but the compose settings package should not be in the initial PR
// commit them separately if possible
// though some might be necessary
@ -43,6 +46,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
// show as disabled -> users confused
// show (but change will not do anything because another setting needs to be enabled first)
// -> users confused, but probably better than the 2 above
// adjust layout a little, there is too much empty space
// maybe later
// weird problem with app sometimes closing on back, but that's related to "old" settings (don't care if all are removed)
@ -69,6 +73,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
// another 300 kb when switching material2 to material3
// ca 150 kb reduction when removing androidx.preference
// -> too much, but still ok if we can get nicer preference stuff
// meh, and using a TextField adds another 300 kb... huge chunks for sth that seems so small
class SettingsActivity2 : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
private val prefs by lazy { DeviceProtectedUtils.getSharedPreferences(this) }

View file

@ -14,6 +14,7 @@ import helium314.keyboard.settings.screens.AboutScreen
import helium314.keyboard.settings.screens.MainSettingsScreen
import helium314.keyboard.settings.screens.PreferencesScreen
import helium314.keyboard.settings.screens.TextCorrectionScreen
import helium314.keyboard.settings.screens.ToolbarScreen
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
@ -48,6 +49,7 @@ fun SettingsNavHost(
onClickAbout = { navController.navigate(SettingsDestination.About) },
onClickTextCorrection = { navController.navigate(SettingsDestination.TextCorrection) },
onClickPreferences = { navController.navigate(SettingsDestination.Preferences) },
onClickToolbar = { navController.navigate(SettingsDestination.Toolbar) },
onClickBack = ::goBack,
)
}
@ -66,6 +68,11 @@ fun SettingsNavHost(
onClickBack = ::goBack
)
}
composable(SettingsDestination.Toolbar) {
ToolbarScreen (
onClickBack = ::goBack
)
}
}
}
@ -74,6 +81,7 @@ object SettingsDestination {
const val About = "about"
const val TextCorrection = "text_correction"
const val Preferences = "preferences"
const val Toolbar = "toolbar"
val navTarget = MutableStateFlow(Settings)
private val navScope = CoroutineScope(Dispatchers.Default)

View file

@ -0,0 +1,105 @@
package helium314.keyboard.settings.dialogs
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import helium314.keyboard.latin.R
import sh.calvin.reorderable.ReorderableItem
import sh.calvin.reorderable.rememberReorderableLazyListState
@Composable
fun <T: Any> ReorderDialog(
onDismissRequest: () -> Unit,
onConfirmed: (List<T>) -> Unit,
items: List<T>,
getKey: (T) -> Any, // actually it's not "Any", but "anything that can be stored in a bundle"
displayItem: @Composable (T) -> Unit,
modifier: Modifier = Modifier,
title: @Composable (() -> Unit)? = null,
confirmButtonText: String = stringResource(android.R.string.ok),
cancelButtonText: String = stringResource(android.R.string.cancel),
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colorScheme.surface,
contentColor: Color = contentColorFor(backgroundColor),
properties: DialogProperties = DialogProperties(),
) {
var reorderableItems by remember(items) { mutableStateOf(items) }
val listState = rememberLazyListState()
val dragDropState = rememberReorderableLazyListState(listState) { from, to ->
reorderableItems = reorderableItems.toMutableList().apply {
add(to.index, removeAt(from.index))
}
}
AlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = {
TextButton(onClick = { onConfirmed(reorderableItems); onDismissRequest() }) { Text(confirmButtonText) }
},
modifier = modifier,
dismissButton = { TextButton(onClick = onDismissRequest) { Text(cancelButtonText) } },
title = title,
text = {
LazyColumn(
state = listState,
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
items(reorderableItems, key = getKey) { item ->
ReorderableItem(
state = dragDropState,
key = getKey(item)
) { dragging ->
val elevation by animateDpAsState(if (dragging) 4.dp else 0.dp)
Surface(shadowElevation = elevation) {
Row(modifier = Modifier.longPressDraggableHandle()) {
Icon(painterResource(R.drawable.ic_drag_indicator), "Reorder")
displayItem(item)
}
}
}
}
}
},
shape = shape,
containerColor = backgroundColor,
textContentColor = contentColor,
properties = properties,
)
}
@Preview
@Composable
private fun Preview() {
ReorderDialog(
onConfirmed = {},
onDismissRequest = {},
items = listOf(1, 2, 3),
displayItem = { Text(it.toString(), Modifier.fillMaxWidth(), textAlign = TextAlign.Center) },
getKey = { it.toString() }
)
}

View file

@ -1,8 +1,6 @@
package helium314.keyboard.settings.dialogs
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material3.AlertDialog
@ -23,7 +21,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import helium314.keyboard.latin.R

View file

@ -36,6 +36,7 @@ fun MainSettingsScreen(
onClickAbout: () -> Unit,
onClickTextCorrection: () -> Unit,
onClickPreferences: () -> Unit,
onClickToolbar: () -> Unit,
onClickBack: () -> Unit,
) {
val ctx = LocalContext.current
@ -54,6 +55,17 @@ fun MainSettingsScreen(
contentDescription = null
)
}
Preference(
name = stringResource(R.string.settings_screen_toolbar),
onClick = onClickToolbar,
icon = R.drawable.ic_settings_toolbar_foreground
) {
Icon(
painter = painterResource(R.drawable.ic_arrow_left),
modifier = Modifier.scale(-1f, 1f),
contentDescription = null
)
}
Preference(
name = stringResource(R.string.settings_screen_correction),
onClick = onClickTextCorrection,
@ -129,7 +141,7 @@ fun Activity.switchTo(fragment: androidx.fragment.app.Fragment) {
private fun PreviewScreen() {
Theme(true) {
Surface {
MainSettingsScreen({}, {}, {}, {})
MainSettingsScreen({}, {}, {}, {}, {})
}
}
}

View file

@ -4,25 +4,18 @@ import android.content.Context
import android.media.AudioManager
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import helium314.keyboard.latin.AudioAndHapticFeedbackManager
import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.DeviceProtectedUtils
import helium314.keyboard.settings.AllPrefs
import helium314.keyboard.settings.PrefDef
import helium314.keyboard.settings.Preference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SettingsActivity2
import helium314.keyboard.settings.SliderPreference
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.dialogs.SliderDialog
@Composable
fun PreferencesScreen(

View file

@ -0,0 +1,67 @@
package helium314.keyboard.settings.screens
import android.content.Context
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.settings.AllPrefs
import helium314.keyboard.settings.PrefDef
import helium314.keyboard.settings.Preference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SettingsActivity2
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.dialogs.ReorderDialog
@Composable
fun ToolbarScreen(
onClickBack: () -> Unit,
) {
SearchPrefScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_toolbar),
) {
SettingsActivity2.allPrefs.map[Settings.PREF_PINNED_TOOLBAR_KEYS]!!.Preference()
}
}
fun createToolbarPrefs(context: Context) = listOf(
PrefDef(context, Settings.PREF_PINNED_TOOLBAR_KEYS, R.string.pinned_toolbar_keys) { def ->
var showDialog by remember { mutableStateOf(false) }
Preference(
name = def.title,
onClick = { showDialog = true },
)
if (showDialog) {
ReorderDialog(
onConfirmed = { },
onDismissRequest = { showDialog = false },
items = (1..40).toList(),
displayItem = { Text(it.toString(), Modifier.fillMaxWidth(), textAlign = TextAlign.Center) },
getKey = { it.hashCode() }
)
}
},
)
@Preview
@Composable
private fun Preview() {
SettingsActivity2.allPrefs = AllPrefs(LocalContext.current)
Theme(true) {
Surface {
ToolbarScreen { }
}
}
}