From 97f11418cb99bfd0c88277e32923862e0eadf8a4 Mon Sep 17 00:00:00 2001 From: Kane Blueriver Date: Sat, 4 Jul 2026 21:46:43 +0800 Subject: [PATCH] feat(settings): add portrait drag toggle with position reset - Add drag_enabled boolean setting (default true) persisted via DataStore + SharedPreferences dual-write. - Settings UI: Switch below portrait effect section. - WallpaperService: onTouchEvent skips drag logic when disabled. - prefsListener resets all portrait offsets/velocities when drag is turned off, so cards snap back to default positions. - Strings added for en/zh/ja/ko. --- .../app/floatdeck/data/SettingsRepository.kt | 20 +++++++++++- .../app/floatdeck/gl/FloatDeckRenderer.kt | 11 +++++++ .../service/FloatDeckWallpaperService.kt | 32 ++++++++++++------- .../floatdeck/settings/SettingsActivity.kt | 24 ++++++++++++++ app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-zh/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 8 files changed, 79 insertions(+), 12 deletions(-) diff --git a/app/src/main/kotlin/app/floatdeck/data/SettingsRepository.kt b/app/src/main/kotlin/app/floatdeck/data/SettingsRepository.kt index 5e6c82f..873466d 100644 --- a/app/src/main/kotlin/app/floatdeck/data/SettingsRepository.kt +++ b/app/src/main/kotlin/app/floatdeck/data/SettingsRepository.kt @@ -3,6 +3,7 @@ package app.floatdeck.data import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore @@ -26,6 +27,7 @@ class SettingsRepository( private val KEY_TEMPLATE = stringPreferencesKey("template_id") private val KEY_WALLPAPER_URI = stringPreferencesKey("wallpaper_uri") private val KEY_PORTRAIT_EFFECT = stringPreferencesKey("portrait_effect") + private val KEY_DRAG_ENABLED = booleanPreferencesKey("drag_enabled") } /** 当前选中的模板 ID。 */ @@ -67,7 +69,23 @@ class SettingsRepository( .apply() } - /** 保存壁纸 URI(传 null 则移除,恢复使用内置壁纸)。 */ + /** Whether portrait drag is enabled, default true. */ + val dragEnabled: Flow = + context.dataStore.data.map { prefs -> + prefs[KEY_DRAG_ENABLED] ?: true + } + + /** Save portrait drag enabled state. */ + suspend fun setDragEnabled(enabled: Boolean) { + context.dataStore.edit { it[KEY_DRAG_ENABLED] = enabled } + context + .getSharedPreferences("settings_prefs", Context.MODE_PRIVATE) + .edit() + .putBoolean("drag_enabled", enabled) + .apply() + } + + /** Save wallpaper URI (null removes it, reverting to the built-in wallpaper). */ suspend fun setWallpaperUri(uri: String?) { context.dataStore.edit { prefs -> if (uri != null) { diff --git a/app/src/main/kotlin/app/floatdeck/gl/FloatDeckRenderer.kt b/app/src/main/kotlin/app/floatdeck/gl/FloatDeckRenderer.kt index 29fb80f..f57407b 100644 --- a/app/src/main/kotlin/app/floatdeck/gl/FloatDeckRenderer.kt +++ b/app/src/main/kotlin/app/floatdeck/gl/FloatDeckRenderer.kt @@ -732,6 +732,17 @@ class FloatDeckRenderer( draggedPortraitIndex = -1 } + /** Reset all portrait drag offsets and velocities to their default positions. */ + fun resetDragOffsets() { + portraitStates.forEach { state -> + state.offsetX = 0f + state.offsetY = 0f + state.velocityX = 0f + state.velocityY = 0f + } + draggedPortraitIndex = -1 + } + fun onDoubleTap( touchX: Float, touchY: Float, diff --git a/app/src/main/kotlin/app/floatdeck/service/FloatDeckWallpaperService.kt b/app/src/main/kotlin/app/floatdeck/service/FloatDeckWallpaperService.kt index 273763b..fb1e763 100644 --- a/app/src/main/kotlin/app/floatdeck/service/FloatDeckWallpaperService.kt +++ b/app/src/main/kotlin/app/floatdeck/service/FloatDeckWallpaperService.kt @@ -26,6 +26,7 @@ private const val TAG = "FloatDeckWallpaper" private const val PREFS_NAME = "settings_prefs" private const val KEY_TEMPLATE_ID = "template_id" private const val KEY_PORTRAIT_EFFECT = "portrait_effect" +private const val KEY_DRAG_ENABLED = "drag_enabled" /** * FloatDeck 动态壁纸服务入口。 @@ -46,8 +47,13 @@ class FloatDeckWallpaperService : WallpaperService() { * 使用强引用字段,避免 SharedPreferences 内部弱引用导致被 GC。 */ private val prefsListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> - if (key == KEY_TEMPLATE_ID || key == KEY_PORTRAIT_EFFECT) { - glThread?.requestReload() + when (key) { + KEY_TEMPLATE_ID, KEY_PORTRAIT_EFFECT -> glThread?.requestReload() + KEY_DRAG_ENABLED -> { + val enabled = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + .getBoolean(KEY_DRAG_ENABLED, true) + if (!enabled) renderer.resetDragOffsets() + } } } @@ -142,15 +148,19 @@ class FloatDeckWallpaperService : WallpaperService() { } override fun onTouchEvent(event: MotionEvent) { - when (event.action) { - MotionEvent.ACTION_DOWN -> { - renderer.onTouchDown(event.x, event.y) - } - MotionEvent.ACTION_MOVE -> { - renderer.onTouchMove(event.x, event.y) - } - MotionEvent.ACTION_UP -> { - renderer.onTouchUp() + val dragEnabled = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + .getBoolean(KEY_DRAG_ENABLED, true) + if (dragEnabled) { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + renderer.onTouchDown(event.x, event.y) + } + MotionEvent.ACTION_MOVE -> { + renderer.onTouchMove(event.x, event.y) + } + MotionEvent.ACTION_UP -> { + renderer.onTouchUp() + } } } super.onTouchEvent(event) diff --git a/app/src/main/kotlin/app/floatdeck/settings/SettingsActivity.kt b/app/src/main/kotlin/app/floatdeck/settings/SettingsActivity.kt index b1eb08c..c4226a0 100644 --- a/app/src/main/kotlin/app/floatdeck/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/app/floatdeck/settings/SettingsActivity.kt @@ -38,6 +38,7 @@ import androidx.compose.material3.Snackbar import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface +import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar @@ -112,6 +113,7 @@ fun SettingsScreen( val context = LocalContext.current var templateId by remember { mutableStateOf("") } var selectedEffect by remember { mutableStateOf(PortraitEffect.NONE) } + var dragEnabled by remember { mutableStateOf(true) } var remoteTemplates by remember { mutableStateOf>(emptyList()) } var urlText by remember { mutableStateOf("") } var isLoading by remember { mutableStateOf(false) } @@ -136,6 +138,11 @@ fun SettingsScreen( repo.portraitEffect.collect { selectedEffect = it } } } + remember { + scope.launch { + repo.dragEnabled.collect { dragEnabled = it } + } + } // 加载已导入的远程模板 fun refreshRemoteTemplates() { @@ -371,6 +378,23 @@ fun SettingsScreen( } } + // Portrait drag toggle + item { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth(), + ) { + Text( + stringResource(R.string.drag_enabled), + modifier = Modifier.weight(1f), + ) + Switch( + checked = dragEnabled, + onCheckedChange = { scope.launch { repo.setDragEnabled(it) } }, + ) + } + } + item { HorizontalDivider() Text(stringResource(R.string.import_remote_template), style = MaterialTheme.typography.titleSmall) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 8c18622..3ab49b1 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -10,6 +10,7 @@ なし ホログラム + ドラッグを許可 リモートテンプレートをインポート ZIPのURLを入力してテンプレートをダウンロード・インポート ZIPのURL diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index faa65ea..408a52d 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -10,6 +10,7 @@ 없음 얼음 홀로그램 + 드래그 허용 원격 템플릿 가져오기 ZIP URL을 입력해 템플릿을 다운로드하고 가져옵니다 ZIP URL diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 5ab9d59..1f33f8d 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -10,6 +10,7 @@ 碎碎冰 炫彩 + 允许拖拽 导入远程模板 输入 ZIP 包 URL,从远程下载并导入模板 ZIP 包 URL diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a201b49..e9411bc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -10,6 +10,7 @@ None Ice Holographic + Allow Drag Import Remote Template Enter ZIP URL to download and import template ZIP URL