mirror of
https://github.com/He4eT/yamf_launcher.git
synced 2026-05-05 01:47:24 +00:00
Rewriting the app into a single activity is in progress
This commit is contained in:
parent
ce78b5f37e
commit
1f0a91e2df
5 changed files with 542 additions and 163 deletions
|
|
@ -17,6 +17,7 @@ import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.widget.AppCompatButton
|
import androidx.appcompat.widget.AppCompatButton
|
||||||
import eu.ottop.yamlauncher.databinding.ActivityAppMenuBinding
|
import eu.ottop.yamlauncher.databinding.ActivityAppMenuBinding
|
||||||
|
import eu.ottop.yamlauncher.databinding.ActivityMainBinding
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
@ -26,9 +27,9 @@ class AppActionMenu {
|
||||||
private val appUtils = AppUtils()
|
private val appUtils = AppUtils()
|
||||||
|
|
||||||
fun setActionListeners(
|
fun setActionListeners(
|
||||||
activity: AppMenuActivity,
|
activity: MainActivity,
|
||||||
uiScope: CoroutineScope,
|
uiScope: CoroutineScope,
|
||||||
binding: ActivityAppMenuBinding,
|
binding: ActivityMainBinding,
|
||||||
textView: TextView,
|
textView: TextView,
|
||||||
editLayout: LinearLayout,
|
editLayout: LinearLayout,
|
||||||
actionMenu: View,
|
actionMenu: View,
|
||||||
|
|
|
||||||
|
|
@ -15,26 +15,24 @@ import android.widget.EditText
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.ottop.yamlauncher.databinding.ActivityAppMenuBinding
|
import eu.ottop.yamlauncher.databinding.ActivityAppMenuBinding
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.ensureActive
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
class AppMenuActivity : AppCompatActivity(), AppMenuAdapter.OnItemClickListener, AppMenuAdapter.OnShortcutListener, AppMenuAdapter.OnItemLongClickListener {
|
class AppMenuActivity : AppCompatActivity(), AppMenuAdapter.OnItemClickListener, AppMenuAdapter.OnShortcutListener, AppMenuAdapter.OnItemLongClickListener {
|
||||||
|
/*
|
||||||
private lateinit var binding: ActivityAppMenuBinding
|
private lateinit var binding: ActivityAppMenuBinding
|
||||||
private lateinit var recyclerView: RecyclerView
|
private lateinit var recyclerView: RecyclerView
|
||||||
private lateinit var searchView: EditText
|
private lateinit var searchView: EditText
|
||||||
private lateinit var adapter: AppMenuAdapter
|
private lateinit var adapter: AppMenuAdapter
|
||||||
private lateinit var filteredApps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>
|
|
||||||
private var job: Job? = null
|
private var job: Job? = null
|
||||||
private var appActionMenu = AppActionMenu()
|
private var appActionMenu = AppActionMenu()
|
||||||
private lateinit var launcherApps: LauncherApps
|
private lateinit var launcherApps: LauncherApps
|
||||||
|
|
@ -79,14 +77,19 @@ class AppMenuActivity : AppCompatActivity(), AppMenuAdapter.OnItemClickListener,
|
||||||
recyclerView = findViewById(R.id.recycler_view)
|
recyclerView = findViewById(R.id.recycler_view)
|
||||||
recyclerView.scrollToPosition(0)
|
recyclerView.scrollToPosition(0)
|
||||||
installedApps = currentApps
|
installedApps = currentApps
|
||||||
filteredApps = mutableListOf()
|
|
||||||
filteredApps.addAll(installedApps)
|
|
||||||
val newApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
|
val newApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
|
||||||
newApps.addAll(installedApps)
|
newApps.addAll(installedApps)
|
||||||
adapter = AppMenuAdapter(this@AppMenuActivity, newApps, this, this,this, menuMode)
|
adapter = AppMenuAdapter(this@AppMenuActivity, newApps, this, this,this, menuMode)
|
||||||
recyclerView.adapter = adapter
|
recyclerView.adapter = adapter
|
||||||
|
|
||||||
setupSearch()
|
setupSearch()
|
||||||
|
|
||||||
|
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
finish()
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle) {
|
override fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle) {
|
||||||
|
|
@ -218,7 +221,6 @@ class AppMenuActivity : AppCompatActivity(), AppMenuAdapter.OnItemClickListener,
|
||||||
private fun startTask() {
|
private fun startTask() {
|
||||||
job = CoroutineScope(Dispatchers.Default).launch {
|
job = CoroutineScope(Dispatchers.Default).launch {
|
||||||
while (true) {
|
while (true) {
|
||||||
ensureActive()
|
|
||||||
manualRefresh()
|
manualRefresh()
|
||||||
delay(5000)
|
delay(5000)
|
||||||
}
|
}
|
||||||
|
|
@ -317,5 +319,32 @@ class AppMenuActivity : AppCompatActivity(), AppMenuAdapter.OnItemClickListener,
|
||||||
data class Change(val type: ChangeType, val position: Int, val newPosition: Int = 0)
|
data class Change(val type: ChangeType, val position: Int, val newPosition: Int = 0)
|
||||||
|
|
||||||
enum class ChangeType {
|
enum class ChangeType {
|
||||||
INSERT, REMOVE, UPDATE
|
INSERT, REMOVE, UPDATE*/
|
||||||
|
override fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override fun onItemLongClick(
|
||||||
|
appInfo: LauncherActivityInfo,
|
||||||
|
userHandle: UserHandle,
|
||||||
|
userProfile: Int,
|
||||||
|
textView: TextView,
|
||||||
|
actionMenuLayout: LinearLayout,
|
||||||
|
editView: LinearLayout,
|
||||||
|
position: Int
|
||||||
|
) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onShortcut(
|
||||||
|
appInfo: LauncherActivityInfo,
|
||||||
|
userHandle: UserHandle,
|
||||||
|
textView: TextView,
|
||||||
|
userProfile: Int,
|
||||||
|
shortcutView: TextView
|
||||||
|
) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,15 +14,17 @@ import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.widget.AppCompatButton
|
import androidx.appcompat.widget.AppCompatButton
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
class AppMenuAdapter(
|
class AppMenuAdapter(
|
||||||
private val activity: AppMenuActivity,
|
private val activity: FragmentActivity,
|
||||||
var apps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>,
|
var apps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>,
|
||||||
private val itemClickListener: OnItemClickListener,
|
private val itemClickListener: OnItemClickListener,
|
||||||
private val shortcutListener: OnShortcutListener,
|
private val shortcutListener: OnShortcutListener,
|
||||||
private val itemLongClickListener: OnItemLongClickListener,
|
private val itemLongClickListener: OnItemLongClickListener,
|
||||||
private val menuMode: String
|
private val menuMode: String = "app",
|
||||||
|
private val shortcutTextView: TextView? = null
|
||||||
) :
|
) :
|
||||||
RecyclerView.Adapter<AppMenuAdapter.AppViewHolder>() {
|
RecyclerView.Adapter<AppMenuAdapter.AppViewHolder>() {
|
||||||
|
|
||||||
|
|
@ -33,7 +35,7 @@ class AppMenuAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnShortcutListener {
|
interface OnShortcutListener {
|
||||||
fun onShortcut(appInfo: LauncherActivityInfo, userHandle: UserHandle, textView: TextView, userProfile: Int)
|
fun onShortcut(appInfo: LauncherActivityInfo, userHandle: UserHandle, textView: TextView, userProfile: Int, shortcutView: TextView)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnItemLongClickListener {
|
interface OnItemLongClickListener {
|
||||||
|
|
@ -62,7 +64,7 @@ class AppMenuAdapter(
|
||||||
val position = bindingAdapterPosition
|
val position = bindingAdapterPosition
|
||||||
val app = apps[position].first
|
val app = apps[position].first
|
||||||
if (menuMode == "shortcut") {
|
if (menuMode == "shortcut") {
|
||||||
shortcutListener.onShortcut(app, apps[position].second.first, textView, apps[position].second.second)
|
shortcutListener.onShortcut(app, apps[position].second.first, textView, apps[position].second.second, shortcutTextView!!)
|
||||||
}
|
}
|
||||||
else if (menuMode == "app") {
|
else if (menuMode == "app") {
|
||||||
itemClickListener.onItemClick(app, apps[position].second.first)
|
itemClickListener.onItemClick(app, apps[position].second.first)
|
||||||
|
|
|
||||||
|
|
@ -5,27 +5,43 @@ import android.content.pm.LauncherActivityInfo
|
||||||
import android.content.pm.LauncherApps
|
import android.content.pm.LauncherApps
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.UserHandle
|
import android.os.UserHandle
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.util.Log
|
||||||
import android.view.GestureDetector
|
import android.view.GestureDetector
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import android.widget.EditText
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.view.children
|
import androidx.core.view.children
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.ottop.yamlauncher.databinding.ActivityMainBinding
|
import eu.ottop.yamlauncher.databinding.ActivityMainBinding
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity(), AppMenuAdapter.OnItemClickListener, AppMenuAdapter.OnShortcutListener, AppMenuAdapter.OnItemLongClickListener {
|
||||||
|
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
private lateinit var gestureDetector: GestureDetector
|
private lateinit var gestureDetector: GestureDetector
|
||||||
private lateinit var launcherApps: LauncherApps
|
private lateinit var launcherApps: LauncherApps
|
||||||
private lateinit var installedApps: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>
|
private lateinit var installedApps: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>
|
||||||
|
|
||||||
|
private lateinit var recyclerView: RecyclerView
|
||||||
|
private lateinit var searchView: EditText
|
||||||
|
private lateinit var adapter: AppMenuAdapter
|
||||||
|
private var job: Job? = null
|
||||||
|
private var appActionMenu = AppActionMenu()
|
||||||
|
|
||||||
private val sharedPreferenceManager = SharedPreferenceManager()
|
private val sharedPreferenceManager = SharedPreferenceManager()
|
||||||
private val appUtils = AppUtils()
|
private val appUtils = AppUtils()
|
||||||
|
|
||||||
|
|
@ -36,9 +52,6 @@ class MainActivity : AppCompatActivity() {
|
||||||
setSupportActionBar(null)
|
setSupportActionBar(null)
|
||||||
|
|
||||||
launcherApps = getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
launcherApps = getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
|
||||||
installedApps = appUtils.getInstalledApps(this@MainActivity)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in findViewById<LinearLayout>(R.id.shortcuts).children) {
|
for (i in findViewById<LinearLayout>(R.id.shortcuts).children) {
|
||||||
|
|
||||||
|
|
@ -74,35 +87,122 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
i.setOnLongClickListener {
|
i.setOnLongClickListener {
|
||||||
AppMenuActivity.start(this@MainActivity, installedApps, "shortcut") { newText ->
|
binding.homeView.visibility = View.GONE
|
||||||
|
|
||||||
if (newText.first.second != 0) {
|
val newApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
|
||||||
textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_work_app, null),null,null,null)
|
newApps.addAll(installedApps)
|
||||||
}
|
adapter = AppMenuAdapter(this@MainActivity, newApps, this@MainActivity, this@MainActivity, this@MainActivity, "shortcut", i)
|
||||||
else {
|
recyclerView.adapter = adapter
|
||||||
textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_empty, null),null,null,null)
|
binding.appView.visibility = View.VISIBLE
|
||||||
}
|
|
||||||
textView.text = newText.first.first
|
|
||||||
i.setOnClickListener {
|
|
||||||
val mainActivity = launcherApps.getActivityList(newText.second.first.applicationInfo.packageName, newText.second.second).firstOrNull()
|
|
||||||
if (mainActivity != null) {
|
|
||||||
launcherApps.startMainActivity(mainActivity.componentName, newText.second.second, null, null)
|
|
||||||
} else {
|
|
||||||
Toast.makeText(this, "Cannot launch app", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sharedPreferenceManager.setShortcut(this, textView, newText.second.first.applicationInfo.packageName, newText.first.second)
|
|
||||||
}
|
|
||||||
|
|
||||||
return@setOnLongClickListener true
|
return@setOnLongClickListener true
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
|
|
||||||
gestureDetector = GestureDetector(this, GestureListener())
|
gestureDetector = GestureDetector(this, GestureListener())
|
||||||
|
|
||||||
|
|
||||||
|
//Experimental
|
||||||
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
installedApps = appUtils.getInstalledApps(this@MainActivity)
|
||||||
|
|
||||||
|
recyclerView = findViewById(R.id.recycler_view)
|
||||||
|
recyclerView.scrollToPosition(0)
|
||||||
|
|
||||||
|
searchView = findViewById(R.id.searchView)
|
||||||
|
setupSearch()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupSearch() {
|
||||||
|
binding.root.addOnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom ->
|
||||||
|
if (bottom - top > oldBottom - oldTop) {
|
||||||
|
searchView.clearFocus()
|
||||||
|
if (searchView.text.isNullOrEmpty()) {
|
||||||
|
job?.cancel()
|
||||||
|
startTask()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
job?.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchView.addTextChangedListener(object :
|
||||||
|
TextWatcher {
|
||||||
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||||
|
filterItems(searchView.text.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterTextChanged(s: Editable?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun filterItems(query: String?) {
|
||||||
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
val cleanQuery = query?.clean()
|
||||||
|
val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
|
||||||
|
val updatedApps = appUtils.getInstalledApps(this@MainActivity)
|
||||||
|
|
||||||
|
if (cleanQuery.isNullOrEmpty()) {
|
||||||
|
manualRefresh()
|
||||||
|
newFilteredApps.addAll(installedApps)
|
||||||
|
} else {
|
||||||
|
updatedApps.forEach {
|
||||||
|
val cleanItemText = sharedPreferenceManager.getAppName(this@MainActivity, it.first.applicationInfo.packageName, it.second.second, it.first.applicationInfo.loadLabel(packageManager)).toString().clean()
|
||||||
|
if (cleanItemText.contains(cleanQuery, ignoreCase = true)) {
|
||||||
|
newFilteredApps.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val changes = detectChanges(installedApps, newFilteredApps)
|
||||||
|
installedApps = newFilteredApps
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
applyChanges(changes, installedApps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.clean(): String {
|
||||||
|
return this.replace("[^a-zA-Z0-9]".toRegex(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
job?.cancel()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
job?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
startTask()
|
||||||
|
|
||||||
|
// Keyboard is sometimes open when going back to the app, so close it.
|
||||||
|
val imm =
|
||||||
|
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
imm.hideSoftInputFromWindow(binding.root.windowToken, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startTask() {
|
||||||
|
job = CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
while (true) {
|
||||||
|
manualRefresh()
|
||||||
|
delay(5000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||||
gestureDetector.onTouchEvent(event)
|
gestureDetector.onTouchEvent(event)
|
||||||
|
|
@ -134,9 +234,178 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openAppMenuActivity() {
|
fun openAppMenuActivity() {
|
||||||
AppMenuActivity.start(this, installedApps) {
|
//AppMenuActivity.start(this, installedApps) {
|
||||||
|
//}
|
||||||
|
binding.homeView.visibility = View.GONE
|
||||||
|
val newApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
|
||||||
|
newApps.addAll(installedApps)
|
||||||
|
adapter = AppMenuAdapter(this@MainActivity, newApps, this@MainActivity, this@MainActivity, this@MainActivity, "app")
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
binding.appView.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle) {
|
||||||
|
val mainActivity = launcherApps.getActivityList(appInfo.applicationInfo.packageName, userHandle).firstOrNull()
|
||||||
|
if (mainActivity != null) {
|
||||||
|
launcherApps.startMainActivity(mainActivity.componentName, userHandle, null, null)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "Cannot launch app", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onShortcut(
|
||||||
|
appInfo: LauncherActivityInfo,
|
||||||
|
userHandle: UserHandle,
|
||||||
|
textView: TextView,
|
||||||
|
userProfile: Int,
|
||||||
|
shortcutView: TextView
|
||||||
|
) {
|
||||||
|
if (userProfile != 0) {
|
||||||
|
shortcutView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_work_app, null),null,null,null)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
shortcutView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_empty, null),null,null,null)
|
||||||
|
}
|
||||||
|
shortcutView.text = textView.text.toString()
|
||||||
|
shortcutView.setOnClickListener {
|
||||||
|
val mainActivity = launcherApps.getActivityList(appInfo.applicationInfo.packageName, userHandle).firstOrNull()
|
||||||
|
if (mainActivity != null) {
|
||||||
|
launcherApps.startMainActivity(mainActivity.componentName, userHandle, null, null)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "Cannot launch app", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sharedPreferenceManager.setShortcut(this, shortcutView, appInfo.applicationInfo.packageName, userProfile)
|
||||||
|
binding.appView.visibility = View.GONE
|
||||||
|
binding.homeView.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onItemLongClick(
|
||||||
|
appInfo: LauncherActivityInfo,
|
||||||
|
userHandle: UserHandle,
|
||||||
|
userProfile: Int,
|
||||||
|
textView: TextView,
|
||||||
|
actionMenuLayout: LinearLayout,
|
||||||
|
editView: LinearLayout,
|
||||||
|
position: Int
|
||||||
|
) {
|
||||||
|
textView.visibility = View.INVISIBLE
|
||||||
|
actionMenuLayout.visibility = View.VISIBLE
|
||||||
|
val mainActivity =
|
||||||
|
launcherApps.getActivityList(appInfo.applicationInfo.packageName, userHandle)
|
||||||
|
.firstOrNull()
|
||||||
|
appActionMenu.setActionListeners(
|
||||||
|
this@MainActivity,
|
||||||
|
CoroutineScope(Dispatchers.Main),
|
||||||
|
binding,
|
||||||
|
textView,
|
||||||
|
editView,
|
||||||
|
actionMenuLayout,
|
||||||
|
searchView,
|
||||||
|
appInfo.applicationInfo,
|
||||||
|
userHandle,
|
||||||
|
userProfile,
|
||||||
|
launcherApps,
|
||||||
|
mainActivity,
|
||||||
|
position
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun manualRefresh() {
|
||||||
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
try {
|
||||||
|
val updatedApps = appUtils.getInstalledApps(this@MainActivity)
|
||||||
|
val changes = detectChanges(installedApps, updatedApps)
|
||||||
|
installedApps = updatedApps
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
applyChanges(changes, installedApps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (_: UninitializedPropertyAccessException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun detectChanges(oldList: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>, newList: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>): List<Change> {
|
||||||
|
val changes = mutableListOf<Change>()
|
||||||
|
val removalChanges = mutableListOf<Change>()
|
||||||
|
val oldSet = oldList.map { Pair(it.first.applicationInfo.packageName, it.second.second) }.toSet()
|
||||||
|
val newSet = newList.map { Pair(it.first.applicationInfo.packageName, it.second.second) }.toSet()
|
||||||
|
|
||||||
|
//Detect updates
|
||||||
|
oldList.forEachIndexed { index, oldItem ->
|
||||||
|
if (newSet.contains(Pair(oldItem.first.applicationInfo.packageName, oldItem.second.second))) {
|
||||||
|
val newIndex = newList.indexOfFirst { it.first.applicationInfo.packageName == oldItem.first.applicationInfo.packageName && it.second.second == oldItem.second.second }
|
||||||
|
if (oldItem.first.componentName != newList[newIndex].first.componentName) {
|
||||||
|
changes.add(Change(ChangeType.UPDATE, index))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect insertions
|
||||||
|
newList.forEachIndexed { index, newItem ->
|
||||||
|
if (!oldSet.contains(Pair(newItem.first.applicationInfo.packageName, newItem.second.second))) {
|
||||||
|
changes.add(Change(ChangeType.INSERT, index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect removals
|
||||||
|
oldList.forEachIndexed { index, oldItem ->
|
||||||
|
if (!newSet.contains(Pair(oldItem.first.applicationInfo.packageName, oldItem.second.second))) {
|
||||||
|
removalChanges.add(Change(ChangeType.REMOVE, index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changes.addAll(removalChanges.reversed())
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyChanges(changes: List<Change>, updatedApps: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>) {
|
||||||
|
changes.forEach { change ->
|
||||||
|
when (change.type) {
|
||||||
|
ChangeType.INSERT -> {
|
||||||
|
insertItem(change.position, updatedApps[change.position])
|
||||||
|
}
|
||||||
|
ChangeType.REMOVE -> {
|
||||||
|
try {
|
||||||
|
removeItem(change.position)
|
||||||
|
}
|
||||||
|
catch (_: IndexOutOfBoundsException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ChangeType.UPDATE -> {
|
||||||
|
updateItem(change.position, updatedApps[change.position])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun insertItem(position: Int, app: Pair<LauncherActivityInfo, Pair<UserHandle, Int>>) {
|
||||||
|
adapter.addApp(position, app)
|
||||||
|
adapter.notifyItemInserted(position)
|
||||||
|
}
|
||||||
|
private fun removeItem(position: Int) {
|
||||||
|
adapter.removeApp(position)
|
||||||
|
adapter.notifyItemRemoved(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateItem(position: Int, app: Pair<LauncherActivityInfo, Pair<UserHandle, Int>>) {
|
||||||
|
adapter.updateApp(position, app)
|
||||||
|
adapter.notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveItem(position: Int, newPosition: Int) {
|
||||||
|
Log.d("Movestatus","MOVED")
|
||||||
|
adapter.moveApp(position, newPosition)
|
||||||
|
adapter.notifyItemMoved(position, newPosition)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Change(val type: ChangeType, val position: Int, val newPosition: Int = 0)
|
||||||
|
|
||||||
|
enum class ChangeType {
|
||||||
|
INSERT, REMOVE, UPDATE
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,88 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="fill_vertical"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/app_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/menutitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="false"
|
||||||
|
android:gravity="start"
|
||||||
|
android:paddingLeft="40dp"
|
||||||
|
android:paddingTop="20dp"
|
||||||
|
android:paddingRight="40dp"
|
||||||
|
android:paddingBottom="20dp"
|
||||||
|
android:text="Select an app"
|
||||||
|
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
||||||
|
android:textColor="#C1F3F3F3"
|
||||||
|
android:textSize="36sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:fadingEdgeLength="20dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:requiresFadingEdge="vertical"
|
||||||
|
android:scrollbars="none"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:stackFromEnd="true">
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/searchView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginHorizontal="40dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginBottom="40dp"
|
||||||
|
android:layout_weight="0.1"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:cursorVisible="true"
|
||||||
|
android:drawableLeft="@android:drawable/ic_menu_search"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:editTextColor="#f3f3f3"
|
||||||
|
android:hint="Search..."
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
||||||
|
android:textSize="25sp" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
android:id="@+id/home_view"
|
android:id="@+id/home_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="fill_vertical"
|
||||||
android:fillViewport="true"
|
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
android:gravity="bottom"
|
android:gravity="fill_vertical"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical">
|
||||||
tools:context=".MainActivity">
|
|
||||||
|
|
||||||
<TextClock
|
<TextClock
|
||||||
android:id="@+id/text_clock"
|
android:id="@+id/text_clock"
|
||||||
|
|
@ -26,7 +98,9 @@
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/shortcuts"
|
android:id="@+id/shortcuts"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:layout_weight="1"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
|
@ -34,6 +108,7 @@
|
||||||
android:id="@+id/app1"
|
android:id="@+id/app1"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:gravity="start"
|
android:gravity="start"
|
||||||
android:paddingLeft="40dp"
|
android:paddingLeft="40dp"
|
||||||
|
|
@ -108,7 +183,7 @@
|
||||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
||||||
android:textColor="#F3F3F3"
|
android:textColor="#F3F3F3"
|
||||||
android:textSize="28sp"
|
android:textSize="28sp"
|
||||||
android:visibility="visible" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app6"
|
android:id="@+id/app6"
|
||||||
|
|
@ -124,7 +199,7 @@
|
||||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
||||||
android:textColor="#F3F3F3"
|
android:textColor="#F3F3F3"
|
||||||
android:textSize="28sp"
|
android:textSize="28sp"
|
||||||
android:visibility="visible" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app7"
|
android:id="@+id/app7"
|
||||||
|
|
@ -140,7 +215,7 @@
|
||||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
||||||
android:textColor="#F3F3F3"
|
android:textColor="#F3F3F3"
|
||||||
android:textSize="28sp"
|
android:textSize="28sp"
|
||||||
android:visibility="visible" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app8"
|
android:id="@+id/app8"
|
||||||
|
|
@ -156,13 +231,16 @@
|
||||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
|
||||||
android:textColor="#F3F3F3"
|
android:textColor="#F3F3F3"
|
||||||
android:textSize="28sp"
|
android:textSize="28sp"
|
||||||
android:visibility="visible" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1" />
|
android:layout_weight="0.15" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue