summaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
authorDirk Sierd de Vries <contact@lecapuchon.nl>2026-08-09 19:19:49 +0200
committerDirk Sierd de Vries <contact@lecapuchon.nl>2026-08-09 19:19:49 +0200
commit7971690ac82fc5a0f3e547a8c2f3f1acfa5608ab (patch)
tree84201ee351cd7e623b2375780873dcc86aaeeda7 /app/src/main
parent3dc9370c4ea3319f027bcb6be137c000c523d497 (diff)
downloadSidePhOnelauncher-7971690ac82fc5a0f3e547a8c2f3f1acfa5608ab.tar.gz
SidePhOnelauncher-7971690ac82fc5a0f3e547a8c2f3f1acfa5608ab.tar.bz2
SidePhOnelauncher-7971690ac82fc5a0f3e547a8c2f3f1acfa5608ab.zip
Add D-pad navigation and keypad-friendly app search
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/app/olauncher/MainActivity.kt24
-rw-r--r--app/src/main/java/app/olauncher/listener/ViewSwipeTouchListener.kt8
-rw-r--r--app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt36
-rw-r--r--app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt72
-rw-r--r--app/src/main/java/app/olauncher/ui/HomeFragment.kt214
-rw-r--r--app/src/main/res/layout/adapter_app_drawer.xml23
-rw-r--r--app/src/main/res/layout/fragment_app_drawer.xml2
-rw-r--r--app/src/main/res/layout/fragment_home.xml16
8 files changed, 339 insertions, 56 deletions
diff --git a/app/src/main/java/app/olauncher/MainActivity.kt b/app/src/main/java/app/olauncher/MainActivity.kt
index 27a66b9..ebd05d5 100644
--- a/app/src/main/java/app/olauncher/MainActivity.kt
+++ b/app/src/main/java/app/olauncher/MainActivity.kt
@@ -11,6 +11,7 @@ import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.provider.Settings
+import android.view.KeyEvent
import android.view.View
import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
import androidx.activity.OnBackPressedCallback
@@ -74,6 +75,7 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
+ setDefaultKeyMode(Activity.DEFAULT_KEYS_DISABLE)
navController = this.findNavController(R.id.nav_host_fragment)
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
@@ -124,6 +126,28 @@ class MainActivity : AppCompatActivity() {
}
}
+ override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+ val dpadKey = when (event.keyCode) {
+ KeyEvent.KEYCODE_DPAD_UP,
+ KeyEvent.KEYCODE_DPAD_DOWN,
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.KEYCODE_DPAD_CENTER,
+ KeyEvent.KEYCODE_ENTER -> true
+ else -> false
+ }
+ if (dpadKey) {
+ val focusedView = currentFocus
+ if (focusedView == null || focusedView == window.decorView) {
+ val navHost = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
+ val currentFragment = navHost?.childFragmentManager?.fragments?.firstOrNull()
+ val fragmentView = currentFragment?.view
+ if (fragmentView != null && fragmentView.dispatchKeyEvent(event)) return true
+ }
+ }
+ return super.dispatchKeyEvent(event)
+ }
+
override fun onStart() {
super.onStart()
restartLauncherOrCheckTheme()
diff --git a/app/src/main/java/app/olauncher/listener/ViewSwipeTouchListener.kt b/app/src/main/java/app/olauncher/listener/ViewSwipeTouchListener.kt
index 9d7009e..633b779 100644
--- a/app/src/main/java/app/olauncher/listener/ViewSwipeTouchListener.kt
+++ b/app/src/main/java/app/olauncher/listener/ViewSwipeTouchListener.kt
@@ -22,7 +22,7 @@ internal open class ViewSwipeTouchListener(c: Context?, v: View) : OnTouchListen
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
when (motionEvent.action) {
MotionEvent.ACTION_DOWN -> view.isPressed = true
- MotionEvent.ACTION_UP -> view.isPressed = false
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> view.isPressed = false
}
return gestureDetector.onTouchEvent(motionEvent)
}
@@ -36,8 +36,8 @@ internal open class ViewSwipeTouchListener(c: Context?, v: View) : OnTouchListen
}
override fun onSingleTapUp(e: MotionEvent): Boolean {
- onClick(view)
- return super.onSingleTapUp(e)
+ view.performClick()
+ return true
}
override fun onDoubleTap(e: MotionEvent): Boolean {
@@ -51,7 +51,7 @@ internal open class ViewSwipeTouchListener(c: Context?, v: View) : OnTouchListen
delay(Constants.LONG_PRESS_DELAY_MS)
withContext(Dispatchers.Main) {
if (isActive && longPressOn)
- onLongClick(view)
+ view.performLongClick()
}
}
super.onLongPress(e)
diff --git a/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt b/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt
index 7d519f8..07428b5 100644
--- a/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt
+++ b/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt
@@ -5,6 +5,7 @@ import android.content.pm.LauncherApps
import android.os.UserHandle
import android.text.Editable
import android.text.TextWatcher
+import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -86,7 +87,6 @@ class AppDrawerAdapter(
false
)
)
-
else -> ViewHolder(
AdapterAppDrawerBinding.inflate(
LayoutInflater.from(parent.context),
@@ -109,7 +109,6 @@ class AppDrawerAdapter(
privateSpaceSettingsListener,
)
}
-
is ViewHolder -> holder.bind(
flag,
appLabelGravity,
@@ -184,7 +183,6 @@ class AppDrawerAdapter(
.replace(separatorsRegex, "")
fun setAppList(appsList: MutableList<AppModel>) {
- // Add empty app for bottom padding in recyclerview and assign to list
appsList.add(
AppModel.App(
appLabel = "",
@@ -238,7 +236,6 @@ class AppDrawerAdapter(
renameLayout.visibility = View.GONE
appTitle.visibility = View.VISIBLE
- // Show indicators in title based on app type and state
appTitle.text = buildString {
append(appModel.appLabel)
if (appModel.isNew) append(" ✦")
@@ -246,9 +243,8 @@ class AppDrawerAdapter(
appTitle.gravity = appLabelGravity
otherProfileIndicator.isVisible = appModel.user != myUserHandle
- appTitle.setOnClickListener { clickListener(appModel) }
-
- appTitle.setOnLongClickListener {
+ appRow.setOnClickListener { clickListener(appModel) }
+ appRow.setOnLongClickListener {
if (appModel.appPackage.isNotEmpty()) {
appDelete.alpha = when (
appModel is AppModel.PinnedShortcut || !root.context.isSystemApp(appModel.appPackage, appModel.user)
@@ -266,13 +262,33 @@ class AppDrawerAdapter(
false -> 1.0f
}
appHideLayout.visibility = View.VISIBLE
- // Only allow renaming non hidden apps
appRename.isVisible = flag != Constants.FLAG_HIDDEN_APPS
}
true
}
+ appRow.setOnKeyListener { _, keyCode, event ->
+ when (keyCode) {
+ KeyEvent.KEYCODE_ENTER,
+ KeyEvent.KEYCODE_DPAD_CENTER,
+ KeyEvent.KEYCODE_NUMPAD_ENTER -> {
+ when (event.action) {
+ KeyEvent.ACTION_DOWN -> {
+ if (event.repeatCount > 0) {
+ appRow.performLongClick()
+ }
+ true
+ }
+ KeyEvent.ACTION_UP -> {
+ if (event.repeatCount == 0) appRow.performClick()
+ true
+ }
+ else -> false
+ }
+ }
+ else -> false
+ }
+ }
- // Configure rename behavior
appRename.setOnClickListener {
if (appModel.appPackage.isNotEmpty()) {
etAppRename.hint = getAppName(etAppRename.context, appModel.appPackage, appModel.user)
@@ -355,7 +371,7 @@ class AppDrawerAdapter(
).toString()
}
} catch (_: Exception) {
- "" // As a fallback, display an empty string.
+ ""
}
}
}
diff --git a/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt b/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt
index c2cee1c..b4b7ef1 100644
--- a/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt
+++ b/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt
@@ -4,12 +4,15 @@ import android.content.Context
import android.os.Build
import android.os.Bundle
import android.os.Process
+import android.text.InputType
import android.text.Spannable
+import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.view.inputmethod.BaseInputConnection
+import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import androidx.appcompat.widget.SearchView
@@ -77,6 +80,41 @@ class AppDrawerFragment : Fragment() {
initAdapter()
initObservers()
initClickListeners()
+ initKeyNavigation()
+ }
+
+ private fun initKeyNavigation() {
+ binding.recyclerView.setOnKeyListener { _, keyCode, event ->
+ if (event.action != KeyEvent.ACTION_DOWN) return@setOnKeyListener false
+ when (keyCode) {
+ KeyEvent.KEYCODE_DPAD_UP -> {
+ if (!binding.recyclerView.canScrollVertically(-1)) {
+ val firstVisible = (binding.recyclerView.layoutManager as? LinearLayoutManager)
+ ?.findFirstVisibleItemPosition() ?: -1
+ if (firstVisible <= 0) {
+ binding.search.requestFocus()
+ return@setOnKeyListener true
+ }
+ }
+ false
+ }
+ KeyEvent.KEYCODE_DEL -> {
+ val query = binding.search.query
+ if (query.isNullOrEmpty()) {
+ findNavController().popBackStack()
+ true
+ } else false
+ }
+ else -> false
+ }
+ }
+
+ binding.search.setOnKeyListener { _, keyCode, event ->
+ if (event.action != KeyEvent.ACTION_DOWN) return@setOnKeyListener false
+ if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ focusFirstLaunchableItem()
+ } else false
+ }
}
private fun initViews() {
@@ -87,6 +125,10 @@ class AppDrawerFragment : Fragment() {
try {
searchTextView = binding.search.findViewById(R.id.search_src_text)
searchTextView?.gravity = prefs.appLabelAlignment
+ searchTextView?.inputType =
+ InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
+ searchTextView?.imeOptions =
+ EditorInfo.IME_ACTION_SEARCH or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
} catch (e: Exception) {
e.printStackTrace()
}
@@ -135,8 +177,8 @@ class AppDrawerFragment : Fragment() {
val subtype = imm.currentInputMethodSubtype
val language = when {
subtype == null -> ""
- subtype.languageTag.isNotEmpty() -> subtype.languageTag // e.g. "zh-CN", "ja-JP", "en-US"
- else -> subtype.locale // deprecated fallback, e.g. "zh_CN"
+ subtype.languageTag.isNotEmpty() -> subtype.languageTag
+ else -> subtype.locale
}
language.startsWith("zh") || language.startsWith("ja") || language.startsWith("ko")
} catch (e: Exception) {
@@ -260,8 +302,7 @@ class AppDrawerFragment : Fragment() {
}
private fun initObservers() {
- viewModel.firstOpen.observe(viewLifecycleOwner) {
- }
+ viewModel.firstOpen.observe(viewLifecycleOwner) {}
if (flag == Constants.FLAG_HIDDEN_APPS) {
viewModel.hiddenApps.observe(viewLifecycleOwner) {
it?.let {
@@ -305,6 +346,26 @@ class AppDrawerFragment : Fragment() {
adapter.filter.filter(binding.search.query)
}
+ private fun findFirstLaunchablePosition(): Int {
+ return adapter.appFilteredList.indexOfFirst { appModel ->
+ appModel !is AppModel.PrivateSpaceHeader && appModel.appPackage.isNotBlank()
+ }.takeIf { it >= 0 } ?: RecyclerView.NO_POSITION
+ }
+
+ private fun focusFirstLaunchableItem(): Boolean {
+ val position = findFirstLaunchablePosition()
+ if (position == RecyclerView.NO_POSITION) return false
+
+ binding.recyclerView.requestFocus()
+ binding.recyclerView.scrollToPosition(position)
+ binding.recyclerView.post {
+ val holder = binding.recyclerView.findViewHolderForAdapterPosition(position)
+ val itemView = holder?.itemView?.findViewById<View>(R.id.appRow) ?: holder?.itemView
+ itemView?.requestFocus()
+ }
+ return true
+ }
+
private fun initClickListeners() {
binding.appRename.setOnClickListener {
val name = binding.search.query.toString().trim()
@@ -330,19 +391,16 @@ class AppDrawerFragment : Fragment() {
private fun getRecyclerViewOnScrollListener(): RecyclerView.OnScrollListener {
return object : RecyclerView.OnScrollListener() {
-
var onTop = false
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
when (newState) {
-
RecyclerView.SCROLL_STATE_DRAGGING -> {
onTop = !recyclerView.canScrollVertically(-1)
if (onTop)
binding.search.hideKeyboard()
}
-
RecyclerView.SCROLL_STATE_IDLE -> {
if (!recyclerView.canScrollVertically(1))
binding.search.hideKeyboard()
diff --git a/app/src/main/java/app/olauncher/ui/HomeFragment.kt b/app/src/main/java/app/olauncher/ui/HomeFragment.kt
index 80061c3..535002c 100644
--- a/app/src/main/java/app/olauncher/ui/HomeFragment.kt
+++ b/app/src/main/java/app/olauncher/ui/HomeFragment.kt
@@ -9,6 +9,7 @@ import android.os.BatteryManager
import android.os.Build
import android.os.Bundle
import android.view.Gravity
+import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -59,6 +60,9 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
+ private var dpadLeftKeyDownTime = 0L
+ private var dpadRightKeyDownTime = 0L
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
@@ -77,28 +81,29 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
setHomeAlignment(prefs.homeAlignment)
initSwipeTouchListener()
initClickListeners()
+ initKeyNavigation()
}
override fun onResume() {
super.onResume()
+ dpadLeftKeyDownTime = 0L
+ dpadRightKeyDownTime = 0L
populateHomeScreen(false)
viewModel.isOlauncherDefault()
if (prefs.showStatusBar) showStatusBar()
else hideStatusBar()
+ requestInitialFocus()
}
override fun onClick(view: View) {
when (view.id) {
R.id.lock -> {}
- // Home button for recents feature disabled
- // R.id.recents -> {}
R.id.clock -> openClockApp()
R.id.date -> openCalendarApp()
R.id.setDefaultLauncher -> viewModel.resetLauncherLiveData.call()
R.id.tvScreenTime -> openScreenTimeDigitalWellbeing()
-
else -> {
- try { // Launch app
+ try {
val appLocation = view.tag.toString().toInt()
homeAppClicked(appLocation)
} catch (e: Exception) {
@@ -148,21 +153,18 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
prefs.clockAppClassName = ""
prefs.clockAppUser = ""
}
-
R.id.date -> {
showAppList(Constants.FLAG_SET_CALENDAR_APP)
prefs.calendarAppPackage = ""
prefs.calendarAppClassName = ""
prefs.calendarAppUser = ""
}
-
R.id.tvScreenTime -> {
showAppList(Constants.FLAG_SET_SCREEN_TIME_APP)
prefs.screenTimeAppPackage = ""
prefs.screenTimeAppClassName = ""
prefs.screenTimeAppUser = ""
}
-
R.id.setDefaultLauncher -> {
prefs.hideSetDefaultLauncher = true
binding.setDefaultLauncher.visibility = View.GONE
@@ -205,10 +207,105 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
viewModel.screenTimeValue.observe(viewLifecycleOwner) {
it?.let { binding.tvScreenTime.text = it }
}
- // Home button for recents feature disabled
- // viewModel.showRecentApps.observe(viewLifecycleOwner) {
- // binding.recents.performClick()
- // }
+ }
+
+ private fun initKeyNavigation() {
+ binding.mainLayout.isFocusable = true
+ binding.mainLayout.setOnKeyListener { _, keyCode, event ->
+ handleHomeKeyEvent(keyCode, event)
+ }
+ }
+
+ private fun handleHomeKeyEvent(keyCode: Int, event: KeyEvent): Boolean {
+ val visibleApps = getVisibleHomeApps()
+ if (visibleApps.isEmpty()) return false
+
+ val focusedIndex = visibleApps.indexOf(activity?.currentFocus)
+
+ when (event.action) {
+ KeyEvent.ACTION_DOWN -> {
+ when (keyCode) {
+ KeyEvent.KEYCODE_DPAD_UP -> {
+ if (event.repeatCount > 0) return true
+ if (focusedIndex > 0) {
+ visibleApps[focusedIndex - 1].requestFocus()
+ } else {
+ swipeDownAction()
+ }
+ return true
+ }
+ KeyEvent.KEYCODE_DPAD_DOWN -> {
+ if (event.repeatCount > 0) return true
+ if (focusedIndex < visibleApps.size - 1) {
+ visibleApps[focusedIndex + 1].requestFocus()
+ } else if (focusedIndex == visibleApps.size - 1) {
+ showAppList(Constants.FLAG_LAUNCH_APP)
+ }
+ return true
+ }
+ KeyEvent.KEYCODE_DPAD_LEFT -> {
+ if (dpadLeftKeyDownTime == 0L) dpadLeftKeyDownTime = System.currentTimeMillis()
+ if (event.repeatCount > 0) {
+ val elapsed = System.currentTimeMillis() - dpadLeftKeyDownTime
+ if (elapsed >= Constants.LONG_PRESS_DELAY_MS) {
+ dpadLeftKeyDownTime = 0L
+ openSwipeLeftApp()
+ }
+ }
+ return true
+ }
+ KeyEvent.KEYCODE_DPAD_RIGHT -> {
+ if (dpadRightKeyDownTime == 0L) dpadRightKeyDownTime = System.currentTimeMillis()
+ if (event.repeatCount > 0) {
+ val elapsed = System.currentTimeMillis() - dpadRightKeyDownTime
+ if (elapsed >= Constants.LONG_PRESS_DELAY_MS) {
+ dpadRightKeyDownTime = 0L
+ openSwipeRightApp()
+ }
+ }
+ return true
+ }
+ KeyEvent.KEYCODE_DPAD_CENTER,
+ KeyEvent.KEYCODE_ENTER,
+ KeyEvent.KEYCODE_NUMPAD_ENTER -> return false
+ }
+ }
+ KeyEvent.ACTION_UP -> {
+ when (keyCode) {
+ KeyEvent.KEYCODE_DPAD_DOWN -> return true
+ KeyEvent.KEYCODE_DPAD_LEFT -> {
+ dpadLeftKeyDownTime = 0L
+ return true
+ }
+ KeyEvent.KEYCODE_DPAD_RIGHT -> {
+ dpadRightKeyDownTime = 0L
+ return true
+ }
+ KeyEvent.KEYCODE_DPAD_CENTER,
+ KeyEvent.KEYCODE_ENTER,
+ KeyEvent.KEYCODE_NUMPAD_ENTER -> return false
+ }
+ }
+ }
+ return false
+ }
+
+ private fun requestInitialFocus() {
+ if (binding.mainLayout.isInTouchMode) return
+ getVisibleHomeApps().firstOrNull()?.requestFocus()
+ }
+
+ private fun getVisibleHomeApps(): List<View> {
+ return listOf(
+ binding.homeApp1,
+ binding.homeApp2,
+ binding.homeApp3,
+ binding.homeApp4,
+ binding.homeApp5,
+ binding.homeApp6,
+ binding.homeApp7,
+ binding.homeApp8,
+ ).filter { it.visibility == View.VISIBLE }
}
private fun initSwipeTouchListener() {
@@ -226,8 +323,6 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
private fun initClickListeners() {
binding.lock.setOnClickListener(this)
- // Home button for recents feature disabled
- // binding.recents.setOnClickListener(this)
binding.clock.setOnClickListener(this)
binding.date.setOnClickListener(this)
binding.clock.setOnLongClickListener(this)
@@ -236,6 +331,55 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
binding.setDefaultLauncher.setOnLongClickListener(this)
binding.tvScreenTime.setOnClickListener(this)
binding.tvScreenTime.setOnLongClickListener(this)
+
+ listOf(
+ binding.homeApp1,
+ binding.homeApp2,
+ binding.homeApp3,
+ binding.homeApp4,
+ binding.homeApp5,
+ binding.homeApp6,
+ binding.homeApp7,
+ binding.homeApp8,
+ ).forEach { homeApp ->
+ homeApp.setOnClickListener(this)
+ homeApp.setOnLongClickListener(this)
+ homeApp.setOnKeyListener { view, keyCode, event ->
+ when (keyCode) {
+ KeyEvent.KEYCODE_DPAD_DOWN -> {
+ if (event.action != KeyEvent.ACTION_DOWN) return@setOnKeyListener true
+ if (event.repeatCount > 0) return@setOnKeyListener true
+ val visibleApps = getVisibleHomeApps()
+ val focusedIndex = visibleApps.indexOf(view)
+ if (focusedIndex < 0) return@setOnKeyListener true
+ if (focusedIndex < visibleApps.size - 1) {
+ visibleApps[focusedIndex + 1].requestFocus()
+ } else {
+ showAppList(Constants.FLAG_LAUNCH_APP)
+ }
+ true
+ }
+ KeyEvent.KEYCODE_ENTER,
+ KeyEvent.KEYCODE_DPAD_CENTER,
+ KeyEvent.KEYCODE_NUMPAD_ENTER -> {
+ when (event.action) {
+ KeyEvent.ACTION_DOWN -> {
+ if (event.repeatCount > 0) {
+ view.performLongClick()
+ }
+ true
+ }
+ KeyEvent.ACTION_UP -> {
+ if (event.repeatCount == 0) view.performClick()
+ true
+ }
+ else -> false
+ }
+ }
+ else -> false
+ }
+ }
+ }
}
private fun setHomeAlignment(horizontalGravity: Int = prefs.homeAlignment) {
@@ -257,7 +401,6 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
binding.clock.isVisible = Constants.DateTime.isTimeVisible(prefs.dateTimeVisibility)
binding.date.isVisible = Constants.DateTime.isDateVisible(prefs.dateTimeVisibility)
-// var dateText = SimpleDateFormat("EEE, d MMM", Locale.getDefault()).format(Date())
val dateFormat = SimpleDateFormat("EEE, d MMM", Locale.getDefault())
var dateText = dateFormat.format(Date())
@@ -299,6 +442,7 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
private fun populateHomeScreen(appCountUpdated: Boolean) {
if (appCountUpdated) hideHomeApps()
+ restoreHomeAppFocusability()
populateDateTime()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
@@ -371,14 +515,10 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
isShortcut: Boolean,
shortcutId: String?,
): Boolean {
- // Get user handle for the app/shortcut
val userHandle = getUserHandleFromString(requireContext(), userString)
- // If it's a shortcut, verify it still exists
if (isShortcut) {
val launcherApps = requireContext().getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
-
- // Query for the specific shortcut
val query = LauncherApps.ShortcutQuery().apply {
setPackage(packageName)
setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED)
@@ -386,7 +526,6 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
try {
val shortcuts = launcherApps.getShortcuts(query, userHandle)
- // Check if our shortcut still exists
if (shortcuts?.any { it.id == shortcutId } == true) {
textView.text = appName
return true
@@ -400,7 +539,6 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
}
}
- // Regular app check
if (isPackageInstalled(requireContext(), packageName, userString)) {
textView.text = appName
return true
@@ -409,15 +547,33 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
return false
}
+ private fun restoreHomeAppFocusability() {
+ listOf(
+ binding.homeApp1,
+ binding.homeApp2,
+ binding.homeApp3,
+ binding.homeApp4,
+ binding.homeApp5,
+ binding.homeApp6,
+ binding.homeApp7,
+ binding.homeApp8,
+ ).forEach { it.isFocusable = true }
+ }
+
private fun hideHomeApps() {
- binding.homeApp1.visibility = View.GONE
- binding.homeApp2.visibility = View.GONE
- binding.homeApp3.visibility = View.GONE
- binding.homeApp4.visibility = View.GONE
- binding.homeApp5.visibility = View.GONE
- binding.homeApp6.visibility = View.GONE
- binding.homeApp7.visibility = View.GONE
- binding.homeApp8.visibility = View.GONE
+ listOf(
+ binding.homeApp1,
+ binding.homeApp2,
+ binding.homeApp3,
+ binding.homeApp4,
+ binding.homeApp5,
+ binding.homeApp6,
+ binding.homeApp7,
+ binding.homeApp8,
+ ).forEach {
+ it.visibility = View.GONE
+ it.isFocusable = false
+ }
}
private fun launchAppOrShortcut(
@@ -715,4 +871,4 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
super.onDestroyView()
_binding = null
}
-} \ No newline at end of file
+}
diff --git a/app/src/main/res/layout/adapter_app_drawer.xml b/app/src/main/res/layout/adapter_app_drawer.xml
index 9168741..a68f88d 100644
--- a/app/src/main/res/layout/adapter_app_drawer.xml
+++ b/app/src/main/res/layout/adapter_app_drawer.xml
@@ -6,15 +6,26 @@
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
- <TextView
- android:id="@+id/appTitle"
- style="@style/TextLarge"
+ <LinearLayout
+ android:id="@+id/appRow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:maxLines="1"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
android:paddingHorizontal="24dp"
- android:paddingVertical="@dimen/app_padding_vertical"
- android:text="@string/app" />
+ android:paddingVertical="@dimen/app_padding_vertical">
+
+ <TextView
+ android:id="@+id/appTitle"
+ style="@style/TextLarge"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:maxLines="1"
+ android:text="@string/app" />
+ </LinearLayout>
<ImageView
android:id="@+id/otherProfileIndicator"
diff --git a/app/src/main/res/layout/fragment_app_drawer.xml b/app/src/main/res/layout/fragment_app_drawer.xml
index 7935654..665a01a 100644
--- a/app/src/main/res/layout/fragment_app_drawer.xml
+++ b/app/src/main/res/layout/fragment_app_drawer.xml
@@ -64,7 +64,9 @@
android:layout_marginBottom="24dp"
android:clipChildren="false"
android:clipToPadding="false"
+ android:descendantFocusability="afterDescendants"
android:fadingEdgeLength="24dp"
+ android:focusable="true"
android:requiresFadingEdge="vertical" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 385532e..7de8a4a 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -88,6 +88,8 @@
style="@style/TextLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
android:hint="@string/app"
android:paddingVertical="@dimen/home_app_padding_vertical"
android:tag="@string/tag_1"
@@ -99,6 +101,8 @@
style="@style/TextLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
android:hint="@string/app"
android:paddingVertical="@dimen/home_app_padding_vertical"
android:tag="@string/tag_2"
@@ -110,6 +114,8 @@
style="@style/TextLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
android:hint="@string/app"
android:paddingVertical="@dimen/home_app_padding_vertical"
android:tag="@string/tag_3"
@@ -121,6 +127,8 @@
style="@style/TextLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
android:hint="@string/app"
android:paddingVertical="@dimen/home_app_padding_vertical"
android:tag="@string/tag_4"
@@ -132,6 +140,8 @@
style="@style/TextLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
android:hint="@string/app"
android:paddingVertical="@dimen/home_app_padding_vertical"
android:tag="@string/tag_5"
@@ -143,6 +153,8 @@
style="@style/TextLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
android:hint="@string/app"
android:paddingVertical="@dimen/home_app_padding_vertical"
android:tag="@string/tag_6"
@@ -154,6 +166,8 @@
style="@style/TextLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
android:hint="@string/app"
android:paddingVertical="@dimen/home_app_padding_vertical"
android:tag="@string/tag_7"
@@ -165,6 +179,8 @@
style="@style/TextLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="false"
android:hint="@string/app"
android:paddingVertical="@dimen/home_app_padding_vertical"
android:tag="@string/tag_8"