diff options
| author | test@dangofactory.cos <you@example.com> | 2026-08-21 14:30:20 +0000 |
|---|---|---|
| committer | test@dangofactory.cos <you@example.com> | 2026-08-21 14:30:20 +0000 |
| commit | 112e4d709b56fb64e38d6af2b4309d9089c3b6ee (patch) | |
| tree | 24020c1674a3f001b7aaf7eebc98f7438181744d /app/src | |
| parent | b78a78c2a1a1dbd10550f055b6311eb0cc4d7890 (diff) | |
| download | SidePhOnelauncher-112e4d709b56fb64e38d6af2b4309d9089c3b6ee.tar.gz SidePhOnelauncher-112e4d709b56fb64e38d6af2b4309d9089c3b6ee.tar.bz2 SidePhOnelauncher-112e4d709b56fb64e38d6af2b4309d9089c3b6ee.zip | |
claude
Diffstat (limited to 'app/src')
3 files changed, 128 insertions, 8 deletions
diff --git a/app/src/main/java/app/sidephonelauncher/data/Prefs.kt b/app/src/main/java/app/sidephonelauncher/data/Prefs.kt index dc7b631..1938994 100644 --- a/app/src/main/java/app/sidephonelauncher/data/Prefs.kt +++ b/app/src/main/java/app/sidephonelauncher/data/Prefs.kt @@ -148,7 +148,11 @@ class Prefs(context: Context) { set(value) = prefs.edit { putBoolean(LOCK_MODE, value).apply() } var autoShowKeyboard: Boolean - get() = prefs.getBoolean(AUTO_SHOW_KEYBOARD, true) + // Default to false so the app list underneath the search box receives + // initial focus when the drawer opens, instead of the keyboard/search + // box grabbing focus first. Users who prefer keyboard-first search can + // still re-enable this from Settings. + get() = prefs.getBoolean(AUTO_SHOW_KEYBOARD, false) set(value) = prefs.edit { putBoolean(AUTO_SHOW_KEYBOARD, value).apply() } var keyboardMessageShown: Boolean @@ -686,3 +690,4 @@ class Prefs(context: Context) { fun setAppRenameLabel(appPackage: String, renameLabel: String) = prefs.edit { putString(appPackage, renameLabel) } } + diff --git a/app/src/main/java/app/sidephonelauncher/ui/AppDrawerAdapter.kt b/app/src/main/java/app/sidephonelauncher/ui/AppDrawerAdapter.kt index 9bc0da2..6c8c0a0 100644 --- a/app/src/main/java/app/sidephonelauncher/ui/AppDrawerAdapter.kt +++ b/app/src/main/java/app/sidephonelauncher/ui/AppDrawerAdapter.kt @@ -301,8 +301,36 @@ class AppDrawerAdapter( } updateFocusAppearance(root.context, appTitle, otherProfileIndicator, appRow.isFocused, focusIndicatorStyle) + // On the plain app drawer / hidden-apps list, long-press opens the + // hide/rename overlay. But when this list is being used as a picker + // (setting a home slot / seed-dial app, swipe app, clock app, etc.) + // that overlay makes no sense here: long-press should just be + // disabled for that purpose and instead cancel back out of the + // picker, leaving DPAD-center short-press as the only way to + // confirm a selection. + val isPickerFlag = flag != Constants.FLAG_LAUNCH_APP && flag != Constants.FLAG_HIDDEN_APPS + + // Tracks whether the current DPAD-center/Enter press-and-hold has + // already fired a long click, and whether we've actually seen a + // *fresh* key-down (repeatCount == 0) for this row. Without this, + // KeyEvent.ACTION_UP always reports repeatCount == 0 (release + // events don't carry the hold count), so the old `repeatCount == + // 0` check on ACTION_UP fired performClick() every single time - + // even right after a long click had just been triggered, or when + // a press was still being held down from a previous screen (e.g. + // the long-press on the home slot that opened this list as a + // picker) and simply carried over onto the newly focused row. + // That's what caused holding DPAD-center to launch/select an app + // immediately instead of respecting long-press-first semantics. + var dpadFreshPress = false + var dpadLongPressTriggered = false + appRow.setOnClickListener { clickListener(appModel) } appRow.setOnLongClickListener { + if (isPickerFlag) { + appBackListener() + return@setOnLongClickListener true + } if (isSpecialActionItem) return@setOnLongClickListener true if (appModel.appPackage.isNotEmpty()) { appDelete.alpha = when ( @@ -335,14 +363,27 @@ class AppDrawerAdapter( KeyEvent.KEYCODE_NUMPAD_ENTER -> { when (event.action) { KeyEvent.ACTION_DOWN -> { - if (event.repeatCount > 0) { + if (event.repeatCount == 0) { + // Genuine new press on this row. + dpadFreshPress = true + dpadLongPressTriggered = false + } else if (dpadFreshPress && !dpadLongPressTriggered) { + dpadLongPressTriggered = true appRow.performLongClick() } + // If repeatCount > 0 but we never saw a fresh + // down (dpadFreshPress == false), this is a + // held-over key repeat from before this row + // had focus - swallow it instead of acting. true } KeyEvent.ACTION_UP -> { - if (event.repeatCount == 0) appRow.performClick() + if (dpadFreshPress && !dpadLongPressTriggered) { + appRow.performClick() + } + dpadFreshPress = false + dpadLongPressTriggered = false true } @@ -494,3 +535,4 @@ class AppDrawerAdapter( } } } + diff --git a/app/src/main/java/app/sidephonelauncher/ui/HomeFragment.kt b/app/src/main/java/app/sidephonelauncher/ui/HomeFragment.kt index 25b4376..858af5c 100644 --- a/app/src/main/java/app/sidephonelauncher/ui/HomeFragment.kt +++ b/app/src/main/java/app/sidephonelauncher/ui/HomeFragment.kt @@ -297,6 +297,20 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener val binding = _binding ?: return false val visibleApps = getVisibleHomeApps() + if (event.action == KeyEvent.ACTION_DOWN && event.repeatCount == 0) { + val appIndex = when (keyCode) { + KeyEvent.KEYCODE_F1 -> 1 + KeyEvent.KEYCODE_F2 -> 2 + KeyEvent.KEYCODE_F3 -> 3 + KeyEvent.KEYCODE_F4 -> 4 + else -> 0 + } + if (appIndex != 0) { + homeAppClicked(appIndex) + return true + } + } + if (activity?.currentFocus == binding.mainLayout) { when (keyCode) { KeyEvent.KEYCODE_DPAD_UP, @@ -504,6 +518,12 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener binding.tvScreenTime.setOnLongClickListener(this) listOf(binding.clock, binding.date).forEach { headerView -> + // See the matching comment in AppDrawerAdapter: ACTION_UP always + // reports repeatCount == 0, so without this tracking a long + // press-and-hold on DPAD-center would fire performClick() again + // on release right after performLongClick() had already fired. + var dpadFreshPress = false + var dpadLongPressTriggered = false headerView.setOnKeyListener { view, keyCode, event -> when (keyCode) { KeyEvent.KEYCODE_DPAD_UP -> { @@ -512,6 +532,14 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener val currentIndex = headerTargets.indexOf(view) if (currentIndex > 0) { headerTargets[currentIndex - 1].requestFocus() + } else { + // Already at the topmost header item: there's nothing + // further up to focus, so treat DPAD-up here the same + // as the existing swipe-down-from-top touch gesture, + // making the status/notification bar reachable + // without touch (e.g. when the status bar is shown + // but the system swipe gesture is unavailable). + swipeDownAction() } true } @@ -551,14 +579,20 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener KeyEvent.KEYCODE_NUMPAD_ENTER -> { when (event.action) { KeyEvent.ACTION_DOWN -> { - if (event.repeatCount > 0) { + if (event.repeatCount == 0) { + dpadFreshPress = true + dpadLongPressTriggered = false + } else if (dpadFreshPress && !dpadLongPressTriggered) { + dpadLongPressTriggered = true view.performLongClick() } true } KeyEvent.ACTION_UP -> { - if (event.repeatCount == 0) view.performClick() + if (dpadFreshPress && !dpadLongPressTriggered) view.performClick() + dpadFreshPress = false + dpadLongPressTriggered = false true } @@ -586,6 +620,8 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener homeApp.onFocusChangeListener = View.OnFocusChangeListener { view, hasFocus -> rememberHomeFocus(view, hasFocus) } + var dpadFreshPress = false + var dpadLongPressTriggered = false homeApp.setOnKeyListener { view, keyCode, event -> when (keyCode) { KeyEvent.KEYCODE_DPAD_DOWN -> { @@ -619,14 +655,31 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener KeyEvent.KEYCODE_NUMPAD_ENTER -> { when (event.action) { KeyEvent.ACTION_DOWN -> { - if (event.repeatCount > 0) { + if (event.repeatCount == 0) { + dpadFreshPress = true + dpadLongPressTriggered = false + } else if (dpadFreshPress && !dpadLongPressTriggered) { + // Long-press: opens the AppDrawer as a + // picker for this home slot (seed-dial + // style assignment). Short click (below, + // on release) launches the assigned app. + dpadLongPressTriggered = true view.performLongClick() } true } KeyEvent.ACTION_UP -> { - if (event.repeatCount == 0) view.performClick() + // Only launch on release if this row never + // fired a long click for this press. This is + // also what stops a DPAD-center held over + // from a previous screen (e.g. still down + // right as the picker opens) from being + // misread as "confirm" on whatever item ends + // up focused first. + if (dpadFreshPress && !dpadLongPressTriggered) view.performClick() + dpadFreshPress = false + dpadLongPressTriggered = false true } @@ -1110,7 +1163,26 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener private fun swipeDownAction() { when (prefs.swipeDownAction) { Constants.SwipeDownAction.SEARCH -> openSearch(requireContext()) - else -> expandNotificationDrawer(requireContext()) + else -> { + // When prefs.showStatusBar is off, the status bar surface is + // hidden (immersive mode), so there is no bar for the + // notification shade to render into: expandNotificationsPanel() + // was being invoked successfully but had nothing visible to + // expand, which is why the panel never appeared. Reveal the + // status bar surface first so the DPAD-triggered "swipe down" + // can actually show it, same as it would if the user were + // allowed to swipe down from the top edge by touch. + if (!prefs.showStatusBar) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + requireActivity().window.insetsController?.show(WindowInsets.Type.statusBars()) + } else { + @Suppress("DEPRECATION") + requireActivity().window.decorView.systemUiVisibility = + View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + } + } + expandNotificationDrawer(requireContext()) + } } } @@ -1289,3 +1361,4 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener _binding = null } } + |
