use Column instead of LazyColumn to avoid janky scroll

This commit is contained in:
Helium314 2025-02-09 10:43:30 +01:00
parent a03bf2924f
commit 324aebf754
12 changed files with 94 additions and 71 deletions

View file

@ -3,7 +3,6 @@ package helium314.keyboard.settings
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.WindowInsets
@ -16,6 +15,8 @@ import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@ -47,28 +48,49 @@ import helium314.keyboard.latin.R
import helium314.keyboard.settings.preferences.PreferenceCategory
@Composable
fun SearchPrefScreen(
fun SearchSettingsScreen(
onClickBack: () -> Unit,
title: String,
prefs: List<Any>,
content: @Composable (ColumnScope.() -> Unit)? = null // overrides prefs if not null
settings: List<Any?>,
content: @Composable (ColumnScope.() -> Unit)? = null // overrides settings if not null
) {
SearchScreen(
onClickBack = onClickBack,
title = title,
content = {
if (content != null) content()
else LazyColumn {
items(prefs, key = { it }) {
Box(Modifier.animateItem()) {
if (it is Int)
PreferenceCategory(stringResource(it))
else
SettingsActivity.settingsContainer[it]!!.Preference()
else {
Column(Modifier.verticalScroll(rememberScrollState())) {
settings.forEach {
if (it is Int) {
PreferenceCategory(stringResource(it))
} else {
// this only animates appearing prefs
// a solution would be using a list(visible to key)
AnimatedVisibility(visible = it != null) {
if (it != null)
SettingsActivity.settingsContainer[it]?.Preference()
}
}
}
}
// lazyColumn has janky scroll for a while (not sure why compose gets smoother after a while)
// maybe related to unnecessary recompositions? but even for just displaying text it's there
// didn't manage to improve things with @Immutable list wrapper and other lazy list hints
// so for now: just use "normal" Column
// even though it takes up to ~50% longer to load it's much better UX
// and the missing appear animations could be added
// LazyColumn {
// items(prefs.filterNotNull(), key = { it }) {
// Box(Modifier.animateItem()) {
// if (it is Int)
// PreferenceCategory(stringResource(it))
// else
// SettingsActivity.settingsContainer[it]!!.Preference()
// }
// }
// }
}
},
filteredItems = { SettingsActivity.settingsContainer.filter(it) },
itemContent = { it.Preference() }

View file

@ -13,19 +13,11 @@ import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.prefs
import kotlinx.coroutines.flow.MutableStateFlow
// todo
// performance
// find a nice way of testing (probably add logs for measuring time and recompositions)
// consider that stuff in composables can get called quite often on any changes
// -> use remember for things that are slow, but be careful they don't change from outside the composable
// not so nice now on S4 mini, try non-debug
// maybe related to lazy column?
// PRs adding prefs -> need to finish and merge main before finishing this PR
// 1263 (no response for several weeks now...)
// what should be done, but not in this PR
// merge PREF_TOOLBAR_CUSTOM_KEY_CODES and PREF_TOOLBAR_CUSTOM_LONGPRESS_CODES into one pref (don't forget settings upgrade)
// replace the setup wizard
// initially: just move view to settingsFragmentContainer, don't use activity (only if little work)
// then: put it in compose, in or outside the navHost?
// platformActivityTheme background color should align with compose background (also consider dynamic colors)
// probably no need for appcompat any more
// replace color settings (should at least change how colors are stored, and have a color search/filter)
@ -75,6 +67,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
// initially it was 900 kB, and another 300 kB for Material3
// textField and others add more (not sure what exactly), and now we're already at 2 MB...
// todo: with compose, app startup is slower and UI needs some "warmup" time to be snappy
// maybe baseline profiles help?
// https://developer.android.com/codelabs/android-baseline-profiles-improve
// https://developer.android.com/codelabs/jetpack-compose-performance#2
// https://developer.android.com/topic/performance/baselineprofiles/overview
class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
private val prefs by lazy { this.prefs() }
val prefChanged = MutableStateFlow(0) // simple counter, as the only relevant information is that something changed

View file

@ -4,13 +4,14 @@ package helium314.keyboard.settings
import android.content.Context
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import helium314.keyboard.settings.screens.createAboutSettings
import helium314.keyboard.settings.screens.createAdvancedSettings
import helium314.keyboard.settings.screens.createAppearanceSettings
import helium314.keyboard.settings.screens.createCorrectionSettings
import helium314.keyboard.settings.screens.createGestureTypingSettings
import helium314.keyboard.settings.screens.createPreferencesSettings
import helium314.keyboard.settings.screens.createToolbarSettingss
import helium314.keyboard.settings.screens.createToolbarSettings
class SettingsContainer(context: Context) {
private val list = createSettings(context)
@ -37,6 +38,7 @@ class SettingsContainer(context: Context) {
}
}
@Immutable
class Setting(
context: Context,
val key: String,
@ -55,7 +57,7 @@ class Setting(
// intentionally not putting individual debug settings in here so user knows the context
private fun createSettings(context: Context) = createAboutSettings(context) +
createCorrectionSettings(context) + createPreferencesSettings(context) + createToolbarSettingss(context) +
createCorrectionSettings(context) + createPreferencesSettings(context) + createToolbarSettings(context) +
createGestureTypingSettings(context) + createAdvancedSettings(context) + createAppearanceSettings(context)
object SettingsWithoutKey {

View file

@ -33,7 +33,7 @@ import helium314.keyboard.settings.SettingsContainer
import helium314.keyboard.settings.SettingsWithoutKey
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.preferences.Preference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.Theme
import kotlinx.coroutines.Dispatchers
@ -51,10 +51,10 @@ fun AboutScreen(
SettingsWithoutKey.GITHUB,
SettingsWithoutKey.SAVE_LOG
)
SearchPrefScreen(
SearchSettingsScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_about),
prefs = items
settings = items
)
}

View file

@ -38,7 +38,7 @@ import helium314.keyboard.settings.preferences.ListPreference
import helium314.keyboard.settings.SettingsWithoutKey
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.preferences.Preference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.SettingsDestination
import helium314.keyboard.settings.preferences.SliderPreference
@ -55,7 +55,7 @@ fun AdvancedSettingsScreen(
onClickBack: () -> Unit,
) {
val prefs = LocalContext.current.prefs()
val items = listOfNotNull(
val items = listOf(
Settings.PREF_ALWAYS_INCOGNITO_MODE,
Settings.PREF_KEY_LONGPRESS_TIMEOUT,
Settings.PREF_SPACE_HORIZONTAL_SWIPE,
@ -82,10 +82,10 @@ fun AdvancedSettingsScreen(
Settings.PREF_URL_DETECTION,
if (BuildConfig.BUILD_TYPE != "nouserlib") SettingsWithoutKey.LOAD_GESTURE_LIB else null
)
SearchPrefScreen(
SearchSettingsScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_advanced),
prefs = items
settings = items
)
}

View file

@ -9,7 +9,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
@ -32,7 +31,7 @@ import helium314.keyboard.settings.preferences.ListPreference
import helium314.keyboard.settings.SettingsWithoutKey
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.preferences.Preference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.preferences.SliderPreference
import helium314.keyboard.settings.preferences.SwitchPreference
@ -53,7 +52,7 @@ fun AppearanceScreen(
if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val dayNightMode = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && Settings.readDayNightPref(prefs, ctx.resources)
val items = listOfNotNull(
val items = listOf(
R.string.settings_screen_theme,
Settings.PREF_THEME_STYLE,
Settings.PREF_ICON_STYLE,
@ -85,10 +84,10 @@ fun AppearanceScreen(
Settings.PREF_FONT_SCALE,
Settings.PREF_EMOJI_FONT_SCALE,
)
SearchPrefScreen(
SearchSettingsScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_appearance),
prefs = items
settings = items
)
}

View file

@ -20,7 +20,7 @@ import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.SettingsContainer
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.preferences.Preference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.preferences.SwitchPreference
import helium314.keyboard.settings.Theme
@ -41,7 +41,7 @@ fun DebugScreen(
DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW,
R.string.prefs_dump_dynamic_dicts
) + DictionaryFacilitator.DYNAMIC_DICTIONARY_TYPES.map { DebugSettingsFragment.PREF_KEY_DUMP_DICT_PREFIX + it }
SearchPrefScreen(
SearchSettingsScreen(
onClickBack = {
if (needsRestart) {
val intent = Intent.makeRestartActivityTask(ctx.packageManager.getLaunchIntentForPackage(ctx.packageName)?.component)
@ -52,8 +52,9 @@ fun DebugScreen(
onClickBack()
},
title = stringResource(R.string.debug_settings_title),
prefs = items
settings = emptyList()
) {
// the preferences are not in SettingsContainer, so set content instead
LazyColumn {
items(items, key = { it }) { item ->
if (item is Int) PreferenceCategory(stringResource(item))

View file

@ -15,7 +15,7 @@ import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.SettingsContainer
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.preferences.SliderPreference
import helium314.keyboard.settings.preferences.SwitchPreference
@ -31,23 +31,26 @@ fun GestureTypingScreen(
if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val gestureFloatingPreviewEnabled = prefs.getBoolean(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true)
val items = listOf(Settings.PREF_GESTURE_INPUT) +
if (prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true))
listOfNotNull(
Settings.PREF_GESTURE_PREVIEW_TRAIL,
Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT,
if (gestureFloatingPreviewEnabled)
Settings.PREF_GESTURE_FLOATING_PREVIEW_DYNAMIC else null,
Settings.PREF_GESTURE_SPACE_AWARE,
Settings.PREF_GESTURE_FAST_TYPING_COOLDOWN,
if (prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true) || gestureFloatingPreviewEnabled)
Settings.PREF_GESTURE_TRAIL_FADEOUT_DURATION else null
)
else emptyList()
SearchPrefScreen(
val gestureEnabled = prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true)
val items = listOf(
Settings.PREF_GESTURE_INPUT,
if (gestureEnabled)
Settings.PREF_GESTURE_PREVIEW_TRAIL else null,
if (gestureEnabled)
Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT else null,
if (gestureEnabled && gestureFloatingPreviewEnabled)
Settings.PREF_GESTURE_FLOATING_PREVIEW_DYNAMIC else null,
if (gestureEnabled)
Settings.PREF_GESTURE_SPACE_AWARE else null,
if (gestureEnabled)
Settings.PREF_GESTURE_FAST_TYPING_COOLDOWN else null,
if (gestureEnabled && (prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true) || gestureFloatingPreviewEnabled))
Settings.PREF_GESTURE_TRAIL_FADEOUT_DURATION else null
)
SearchSettingsScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_gesture),
prefs = items
settings = items
)
}

View file

@ -27,7 +27,7 @@ import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.switchTo
import helium314.keyboard.settings.preferences.Preference
import helium314.keyboard.settings.preferences.PreferenceCategory
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.Theme
@Composable
@ -42,10 +42,10 @@ fun MainSettingsScreen(
onClickBack: () -> Unit,
) {
val ctx = LocalContext.current
SearchPrefScreen(
SearchSettingsScreen(
onClickBack = onClickBack,
title = stringResource(R.string.ime_settings),
prefs = emptyList(),
settings = emptyList(),
) {
Column(Modifier.verticalScroll(rememberScrollState())) {
Preference(

View file

@ -26,7 +26,7 @@ import helium314.keyboard.settings.SettingsContainer
import helium314.keyboard.settings.preferences.ListPreference
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.preferences.ReorderSwitchPreference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.preferences.SliderPreference
import helium314.keyboard.settings.preferences.SwitchPreference
@ -41,7 +41,7 @@ fun PreferencesScreen(
val b = (LocalContext.current.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState()
if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val items = listOfNotNull(
val items = listOf(
R.string.settings_category_input,
Settings.PREF_SHOW_HINTS,
if (prefs.getBoolean(Settings.PREF_SHOW_HINTS, true))
@ -72,10 +72,10 @@ fun PreferencesScreen(
if (prefs.getBoolean(Settings.PREF_ENABLE_CLIPBOARD_HISTORY, true))
Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME else null
)
SearchPrefScreen(
SearchSettingsScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_preferences),
prefs = items
settings = items
)
}

View file

@ -34,7 +34,7 @@ import helium314.keyboard.settings.preferences.ListPreference
import helium314.keyboard.settings.SettingsWithoutKey
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.preferences.Preference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.preferences.SwitchPreference
import helium314.keyboard.settings.Theme
@ -51,7 +51,7 @@ fun TextCorrectionScreen(
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val autocorrectEnabled = prefs.getBoolean(Settings.PREF_AUTO_CORRECTION, true)
val suggestionsEnabled = prefs.getBoolean(Settings.PREF_SHOW_SUGGESTIONS, true)
val items = listOfNotNull(
val items = listOf(
SettingsWithoutKey.EDIT_PERSONAL_DICTIONARY,
R.string.settings_category_correction,
Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE,
@ -73,10 +73,10 @@ fun TextCorrectionScreen(
if (prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true))
Settings.PREF_ADD_TO_PERSONAL_DICTIONARY else null
)
SearchPrefScreen(
SearchSettingsScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_correction),
prefs = items
settings = items
)
}

View file

@ -11,7 +11,6 @@ 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.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
@ -35,7 +34,7 @@ import helium314.keyboard.settings.SettingsWithoutKey
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.preferences.Preference
import helium314.keyboard.settings.preferences.ReorderSwitchPreference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SearchSettingsScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.preferences.SwitchPreference
import helium314.keyboard.settings.Theme
@ -56,14 +55,14 @@ fun ToolbarScreen(
Settings.PREF_AUTO_HIDE_TOOLBAR,
Settings.PREF_VARIABLE_TOOLBAR_DIRECTION
)
SearchPrefScreen(
SearchSettingsScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_toolbar),
prefs = items
settings = items
)
}
fun createToolbarSettingss(context: Context) = listOf(
fun createToolbarSettings(context: Context) = listOf(
Setting(context, Settings.PREF_TOOLBAR_KEYS, R.string.toolbar_keys) {
ReorderSwitchPreference(it, defaultToolbarPref)
},