move stuff out of Functions.kt

This commit is contained in:
Josia Pietsch 2024-12-20 02:42:58 +01:00
parent c84675904d
commit 3353719cc3
Signed by: jrpie
GPG key ID: E70B571D66986A2D
9 changed files with 188 additions and 184 deletions

View file

@ -7,9 +7,6 @@ import android.content.Context
import android.content.Intent
import android.content.pm.LauncherApps
import android.content.pm.PackageManager
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Rect
import android.net.Uri
import android.os.Build
import android.os.Bundle
@ -17,11 +14,6 @@ import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
import android.util.Log
import android.view.View
import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.apps.AppInfo
@ -42,25 +34,6 @@ const val REQUEST_SET_DEFAULT_HOME = 42
const val LOG_TAG = "Launcher"
/* Animate */
// Taken from https://stackoverflow.com/questions/47293269
fun View.blink(
times: Int = Animation.INFINITE,
duration: Long = 1000L,
offset: Long = 20L,
minAlpha: Float = 0.2f,
maxAlpha: Float = 1.0f,
repeatMode: Int = Animation.REVERSE
) {
startAnimation(AlphaAnimation(minAlpha, maxAlpha).also {
it.duration = duration
it.startOffset = offset
it.repeatMode = repeatMode
it.repeatCount = times
})
}
fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) {
if (checkDefault
@ -90,61 +63,19 @@ fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) {
context.startActivity(intent)
}
fun getIntent(packageName: String, context: Context): Intent? {
val intent: Intent? = context.packageManager.getLaunchIntentForPackage(packageName)
intent?.addCategory(Intent.CATEGORY_LAUNCHER)
return intent
}
/* --- */
fun getUserFromId(user: Int?, context: Context): UserHandle {
fun getUserFromId(userId: Int?, context: Context): UserHandle {
/* TODO: this is an ugly hack.
Use userManager#getUserForSerialNumber instead (breaking change to SharedPreferences!)
*/
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
val profiles = userManager.userProfiles
return profiles.firstOrNull { it.hashCode() == user } ?: profiles[0]
return profiles.firstOrNull { it.hashCode() == userId } ?: profiles[0]
}
fun uninstallApp(appInfo: AppInfo, activity: Activity) {
val packageName = appInfo.packageName.toString()
val user = appInfo.user
Log.i(LOG_TAG, "uninstalling $appInfo")
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
intent.data = Uri.parse("package:$packageName")
getUserFromId(user, activity).let { user ->
intent.putExtra(Intent.EXTRA_USER, user)
}
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
activity.startActivityForResult(
intent,
REQUEST_UNINSTALL
)
}
fun openNewTabWindow(urls: String, context: Context) {
val uris = Uri.parse(urls)
val intents = Intent(Intent.ACTION_VIEW, uris)
val b = Bundle()
b.putBoolean("new_window", true)
intents.putExtras(b)
context.startActivity(intents)
}
fun openAppSettings(
appInfo: AppInfo,
context: Context,
sourceBounds: Rect? = null,
opts: Bundle? = null
) {
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
appInfo.getLauncherActivityInfo(context)?.let { app ->
launcherApps.startAppDetailsActivity(app.componentName, app.user, sourceBounds, opts)
}
fun openInBrowser(url: String, context: Context) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
intent.putExtras(Bundle().apply { putBoolean("new_window", true) })
context.startActivity(intent)
}
fun openTutorial(context: Context) {
@ -199,19 +130,3 @@ fun saveListActivityChoice(data: Intent?) {
Gesture.byId(forGesture)?.let { Action.setActionForGesture(it, Action.fromIntent(data)) }
}
// Taken from https://stackoverflow.com/a/50743764/12787264
fun openSoftKeyboard(context: Context, view: View) {
view.requestFocus()
// open the soft keyboard
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
}
// Taken from: https://stackoverflow.com/a/30340794/12787264
fun transformGrayscale(imageView: ImageView) {
val matrix = ColorMatrix()
matrix.setSaturation(0f)
val filter = ColorMatrixColorFilter(matrix)
imageView.colorFilter = filter
}

View file

@ -13,8 +13,7 @@ import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.apps.AppInfo.Companion.INVALID_USER
import de.jrpie.android.launcher.apps.DetailedAppInfo
import de.jrpie.android.launcher.getIntent
import de.jrpie.android.launcher.openAppSettings
import de.jrpie.android.launcher.ui.list.apps.openSettings
class AppAction(val appInfo: AppInfo) : Action {
@ -30,14 +29,12 @@ class AppAction(val appInfo: AppInfo) : Action {
}
}
val intent = getIntent(packageName, context)
if (intent != null) {
context.startActivity(intent)
context.packageManager.getLaunchIntentForPackage(packageName)?.let {
it.addCategory(Intent.CATEGORY_LAUNCHER)
context.startActivity(it)
return true
}
/* check if app is installed */
if (isAvailable(context)) {
AlertDialog.Builder(
@ -47,7 +44,7 @@ class AppAction(val appInfo: AppInfo) : Action {
.setTitle(context.getString(R.string.alert_cant_open_title))
.setMessage(context.getString(R.string.alert_cant_open_message))
.setPositiveButton(android.R.string.ok) { _, _ ->
openAppSettings(appInfo, context)
appInfo.openSettings(context)
}
.setNegativeButton(android.R.string.cancel, null)
.setIcon(android.R.drawable.ic_dialog_info)

View file

@ -0,0 +1,43 @@
package de.jrpie.android.launcher.ui
import android.content.Context
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.view.View
import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
// Taken from https://stackoverflow.com/questions/47293269
fun View.blink(
times: Int = Animation.INFINITE,
duration: Long = 1000L,
offset: Long = 20L,
minAlpha: Float = 0.2f,
maxAlpha: Float = 1.0f,
repeatMode: Int = Animation.REVERSE
) {
startAnimation(AlphaAnimation(minAlpha, maxAlpha).also {
it.duration = duration
it.startOffset = offset
it.repeatMode = repeatMode
it.repeatCount = times
})
}
// Taken from: https://stackoverflow.com/a/30340794/12787264
fun ImageView.transformGrayscale() {
this.colorFilter = ColorMatrixColorFilter(ColorMatrix().apply {
setSaturation(0f)
})
}
// Taken from https://stackoverflow.com/a/50743764/12787264
fun View.openSoftKeyboard(context: Context) {
this.requestFocus()
// open the soft keyboard
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}

View file

@ -5,18 +5,14 @@ import android.app.Activity
import android.content.Intent
import android.graphics.Rect
import android.os.AsyncTask
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.ImageView
import android.widget.PopupMenu
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.actions.AppAction
@ -26,12 +22,10 @@ import de.jrpie.android.launcher.apps.DetailedAppInfo
import de.jrpie.android.launcher.appsList
import de.jrpie.android.launcher.getUserFromId
import de.jrpie.android.launcher.loadApps
import de.jrpie.android.launcher.openAppSettings
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.preferences.ListLayout
import de.jrpie.android.launcher.transformGrayscale
import de.jrpie.android.launcher.ui.list.ListActivity
import de.jrpie.android.launcher.uninstallApp
import de.jrpie.android.launcher.ui.transformGrayscale
/**
* A [RecyclerView] (efficient scrollable list) containing all apps on the users device.
@ -53,8 +47,6 @@ class AppsRecyclerAdapter(
) :
RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() {
private val LOG_TAG = "Launcher"
private val appsListDisplayed: MutableList<DetailedAppInfo> = mutableListOf()
@ -90,9 +82,8 @@ class AppsRecyclerAdapter(
viewHolder.textView.text = appLabel
viewHolder.img.setImageDrawable(appIcon)
if (LauncherPreferences.theme().monochromeIcons()) transformGrayscale(
viewHolder.img
)
if (LauncherPreferences.theme().monochromeIcons())
viewHolder.img.transformGrayscale()
// decide when to show the options popup menu about
if (intention == ListActivity.ListActivityIntention.VIEW) {
@ -140,73 +131,23 @@ class AppsRecyclerAdapter(
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.app_menu_delete -> {
uninstallApp(appInfo.app, activity)
true
appInfo.app.uninstall(activity); true
}
R.id.app_menu_info -> {
openAppSettings(appInfo.app, activity)
true
appInfo.app.openSettings(activity); true
}
R.id.app_menu_favorite -> {
val favorites: MutableSet<AppInfo> =
LauncherPreferences.apps().favorites() ?: mutableSetOf()
if (favorites.contains(appInfo.app)) {
favorites.remove(appInfo.app)
Log.i(LOG_TAG, "Removing $appInfo from favorites.")
} else {
Log.i(LOG_TAG, "Adding $appInfo to favorites.")
favorites.add(appInfo.app)
}
LauncherPreferences.apps().favorites(favorites)
true
appInfo.app.toggleFavorite(); true
}
R.id.app_menu_hidden -> {
val hidden: MutableSet<AppInfo> =
LauncherPreferences.apps().hidden() ?: mutableSetOf()
if (hidden.contains(appInfo.app)) {
hidden.remove(appInfo.app)
} else {
hidden.add(appInfo.app)
Snackbar.make(root, R.string.snackbar_app_hidden, Snackbar.LENGTH_LONG)
.setAction(R.string.undo) {
LauncherPreferences.apps().hidden(
LauncherPreferences.apps().hidden().minus(appInfo.app)
)
}.show()
}
LauncherPreferences.apps().hidden(hidden)
true
appInfo.app.toggleHidden(root); true
}
R.id.app_menu_rename -> {
val builder = AlertDialog.Builder(activity, R.style.AlertDialogCustom)
val title = activity.getString(R.string.dialog_rename_title, appInfo.label)
builder.setTitle(title)
builder.setView(R.layout.dialog_rename_app)
builder.setNegativeButton(R.string.dialog_cancel) { d, _ -> d.cancel() }
builder.setPositiveButton(R.string.dialog_rename_ok) { d, _ ->
appInfo.setCustomLabel(
(d as? AlertDialog)
?.findViewById<EditText>(R.id.dialog_rename_app_edit_text)
?.text.toString()
)
}
val dialog = builder.create()
dialog.show()
val input = dialog.findViewById<EditText>(R.id.dialog_rename_app_edit_text)
input?.setText(appInfo.getCustomLabel(activity))
input?.hint = appInfo.label
true
appInfo.showRenameDialog(activity); true
}
else -> false

View file

@ -0,0 +1,109 @@
package de.jrpie.android.launcher.ui.list.apps
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.LauncherApps
import android.graphics.Rect
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import com.google.android.material.snackbar.Snackbar
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_UNINSTALL
import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.apps.DetailedAppInfo
import de.jrpie.android.launcher.getUserFromId
import de.jrpie.android.launcher.preferences.LauncherPreferences
private const val LOG_TAG = "AppContextMenu"
fun AppInfo.openSettings(
context: Context,
sourceBounds: Rect? = null,
opts: Bundle? = null
) {
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
this.getLauncherActivityInfo(context)?.let { app ->
launcherApps.startAppDetailsActivity(app.componentName, app.user, sourceBounds, opts)
}
}
fun AppInfo.uninstall(activity: android.app.Activity) {
val packageName = this.packageName.toString()
val userId = this.user
Log.i(LOG_TAG, "uninstalling $this")
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
intent.data = Uri.parse("package:$packageName")
getUserFromId(userId, activity).let { user ->
intent.putExtra(Intent.EXTRA_USER, user)
}
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
activity.startActivityForResult(
intent,
REQUEST_UNINSTALL
)
}
fun AppInfo.toggleFavorite() {
val favorites: MutableSet<AppInfo> =
LauncherPreferences.apps().favorites() ?: mutableSetOf()
if (favorites.contains(this)) {
favorites.remove(this)
Log.i(LOG_TAG, "Removing $this from favorites.")
} else {
Log.i(LOG_TAG, "Adding $this to favorites.")
favorites.add(this)
}
LauncherPreferences.apps().favorites(favorites)
}
/**
* @param view: used to show a snackbar letting the user undo the action
*/
fun AppInfo.toggleHidden(view: View) {
val hidden: MutableSet<AppInfo> =
LauncherPreferences.apps().hidden() ?: mutableSetOf()
if (hidden.contains(this)) {
hidden.remove(this)
} else {
hidden.add(this)
Snackbar.make(view, R.string.snackbar_app_hidden, Snackbar.LENGTH_LONG)
.setAction(R.string.undo) {
LauncherPreferences.apps().hidden(
LauncherPreferences.apps().hidden().minus(this)
)
}.show()
}
LauncherPreferences.apps().hidden(hidden)
}
fun DetailedAppInfo.showRenameDialog(context: Context) {
AlertDialog.Builder(context, R.style.AlertDialogCustom).apply {
setTitle(context.getString(R.string.dialog_rename_title, label))
setView(R.layout.dialog_rename_app)
setNegativeButton(R.string.dialog_cancel) { d, _ -> d.cancel() }
setPositiveButton(R.string.dialog_rename_ok) { d, _ ->
setCustomLabel(
(d as? AlertDialog)
?.findViewById<EditText>(R.id.dialog_rename_app_edit_text)
?.text.toString()
)
}
}.create().also { it.show() }.apply {
val input = findViewById<EditText>(R.id.dialog_rename_app_edit_text)
input?.setText(getCustomLabel(context))
input?.hint = label
}
}

View file

@ -8,7 +8,6 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.apps.AppFilter
import de.jrpie.android.launcher.databinding.ListAppsBinding
import de.jrpie.android.launcher.openSoftKeyboard
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.list.ListActivity
@ -16,6 +15,7 @@ import de.jrpie.android.launcher.ui.list.favoritesVisibility
import de.jrpie.android.launcher.ui.list.forGesture
import de.jrpie.android.launcher.ui.list.hiddenVisibility
import de.jrpie.android.launcher.ui.list.intention
import de.jrpie.android.launcher.ui.openSoftKeyboard
/**
@ -110,7 +110,7 @@ class ListFragmentApps : Fragment(), UIObject {
if (intention == ListActivity.ListActivityIntention.VIEW
&& LauncherPreferences.functionality().searchAutoOpenKeyboard()
) {
openSoftKeyboard(requireContext(), binding.listAppsSearchview)
binding.listAppsSearchview.openSoftKeyboard(requireContext())
}
}
}

View file

@ -1,5 +1,6 @@
package de.jrpie.android.launcher.ui.settings.actions
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences
@ -20,9 +21,9 @@ import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.apps.AppFilter
import de.jrpie.android.launcher.databinding.SettingsActionsRecyclerBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.transformGrayscale
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.list.ListActivity
import de.jrpie.android.launcher.ui.transformGrayscale
/**
* The [SettingsFragmentActionsRecycler] is a fragment containing the [ActionsRecyclerAdapter],
@ -93,7 +94,8 @@ class SettingsFragmentActionsRecycler : Fragment(), UIObject {
class ActionsRecyclerAdapter(val activity: Activity) :
RecyclerView.Adapter<ActionsRecyclerAdapter.ViewHolder>() {
private val gesturesList: ArrayList<Gesture>
private val gesturesList: ArrayList<Gesture> =
Gesture.entries.filter(Gesture::isEnabled) as ArrayList<Gesture>
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
@ -137,7 +139,8 @@ class ActionsRecyclerAdapter(val activity: Activity) :
if (LauncherPreferences.theme().monochromeIcons())
transformGrayscale(viewHolder.img)
viewHolder.img.transformGrayscale()
updateViewHolder(gesture, viewHolder)
viewHolder.img.setOnClickListener { chooseApp(gesture) }
viewHolder.chooseButton.setOnClickListener { chooseApp(gesture) }
@ -154,10 +157,7 @@ class ActionsRecyclerAdapter(val activity: Activity) :
return ViewHolder(view)
}
init {
gesturesList = Gesture.entries.filter(Gesture::isEnabled) as ArrayList<Gesture>
}
@SuppressLint("NotifyDataSetChanged")
fun updateActions() {
val doubleActions = LauncherPreferences.enabled_gestures().doubleSwipe()
val edgeActions = LauncherPreferences.enabled_gestures().edgeSwipe()
@ -170,7 +170,6 @@ class ActionsRecyclerAdapter(val activity: Activity) :
notifyDataSetChanged()
}
/* */
private fun chooseApp(gesture: Gesture) {
val intent = Intent(activity, ListActivity::class.java)
intent.putExtra("intention", ListActivity.ListActivityIntention.PICK.toString())

View file

@ -10,7 +10,7 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.databinding.SettingsMetaBinding
import de.jrpie.android.launcher.openNewTabWindow
import de.jrpie.android.launcher.openInBrowser
import de.jrpie.android.launcher.preferences.resetPreferences
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
@ -79,7 +79,7 @@ class SettingsFragmentMeta : Fragment(), UIObject {
// view code
binding.settingsMetaButtonViewCode.setOnClickListener {
openNewTabWindow(
openInBrowser(
getString(R.string.settings_meta_link_github),
requireContext()
)
@ -87,7 +87,7 @@ class SettingsFragmentMeta : Fragment(), UIObject {
// report a bug
binding.settingsMetaButtonReportBug.setOnClickListener {
openNewTabWindow(
openInBrowser(
getString(R.string.settings_meta_report_bug_link),
requireContext()
)
@ -96,7 +96,7 @@ class SettingsFragmentMeta : Fragment(), UIObject {
// join chat
binding.settingsMetaButtonJoinChat.setOnClickListener {
openNewTabWindow(
openInBrowser(
getString(R.string.settings_meta_chat_url),
requireContext()
)
@ -106,7 +106,7 @@ class SettingsFragmentMeta : Fragment(), UIObject {
// contact developer
binding.settingsMetaButtonContact.setOnClickListener {
openNewTabWindow(
openInBrowser(
getString(R.string.settings_meta_contact_url),
requireContext()
)
@ -114,7 +114,7 @@ class SettingsFragmentMeta : Fragment(), UIObject {
// contact fork developer
binding.settingsMetaButtonForkContact.setOnClickListener {
openNewTabWindow(
openInBrowser(
getString(R.string.settings_meta_fork_contact_url),
requireContext()
)
@ -122,7 +122,7 @@ class SettingsFragmentMeta : Fragment(), UIObject {
// privacy policy
binding.settingsMetaButtonPrivacy.setOnClickListener {
openNewTabWindow(
openInBrowser(
getString(R.string.settings_meta_privacy_url),
requireContext()
)

View file

@ -5,9 +5,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.blink
import de.jrpie.android.launcher.databinding.TutorialStartBinding
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.blink
/**
* The [TutorialFragmentStart] is a used as a tab in the TutorialActivity.