mirror of
https://github.com/jrpie/Launcher.git
synced 2025-04-11 14:54:31 +02:00
implement #45: show pinned shortcuts in app list
Some checks are pending
Android CI / build (push) Waiting to run
Some checks are pending
Android CI / build (push) Waiting to run
This commit is contained in:
parent
1f825d6f00
commit
9fe1a37ed6
23 changed files with 467 additions and 138 deletions
|
@ -15,15 +15,15 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import de.jrpie.android.launcher.actions.TorchManager
|
import de.jrpie.android.launcher.actions.TorchManager
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AbstractAppInfo
|
||||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
import de.jrpie.android.launcher.apps.AbstractDetailedAppInfo
|
||||||
import de.jrpie.android.launcher.apps.isPrivateSpaceLocked
|
import de.jrpie.android.launcher.apps.isPrivateSpaceLocked
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion
|
import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion
|
||||||
import de.jrpie.android.launcher.preferences.resetPreferences
|
import de.jrpie.android.launcher.preferences.resetPreferences
|
||||||
|
|
||||||
class Application : android.app.Application() {
|
class Application : android.app.Application() {
|
||||||
val apps = MutableLiveData<List<DetailedAppInfo>>()
|
val apps = MutableLiveData<List<AbstractDetailedAppInfo>>()
|
||||||
val privateSpaceLocked = MutableLiveData<Boolean>()
|
val privateSpaceLocked = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() {
|
private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() {
|
||||||
|
@ -82,10 +82,12 @@ class Application : android.app.Application() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var torchManager: TorchManager? = null
|
var torchManager: TorchManager? = null
|
||||||
private var customAppNames: HashMap<AppInfo, String>? = null
|
private var customAppNames: HashMap<AbstractAppInfo, String>? = null
|
||||||
private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, pref ->
|
private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, pref ->
|
||||||
if (pref == getString(R.string.settings_apps_custom_names_key)) {
|
if (pref == getString(R.string.settings_apps_custom_names_key)) {
|
||||||
customAppNames = LauncherPreferences.apps().customNames()
|
customAppNames = LauncherPreferences.apps().customNames()
|
||||||
|
} else if (pref == LauncherPreferences.apps().keys().pinnedShortcuts()) {
|
||||||
|
loadApps()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +145,7 @@ class Application : android.app.Application() {
|
||||||
loadApps()
|
loadApps()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCustomAppNames(): HashMap<AppInfo, String> {
|
fun getCustomAppNames(): HashMap<AbstractAppInfo, String> {
|
||||||
return (customAppNames ?: LauncherPreferences.apps().customNames() ?: HashMap())
|
return (customAppNames ?: LauncherPreferences.apps().customNames() ?: HashMap())
|
||||||
.also { customAppNames = it }
|
.also { customAppNames = it }
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,12 @@ import androidx.annotation.RequiresApi
|
||||||
import de.jrpie.android.launcher.actions.Action
|
import de.jrpie.android.launcher.actions.Action
|
||||||
import de.jrpie.android.launcher.actions.Gesture
|
import de.jrpie.android.launcher.actions.Gesture
|
||||||
import de.jrpie.android.launcher.actions.ShortcutAction
|
import de.jrpie.android.launcher.actions.ShortcutAction
|
||||||
import de.jrpie.android.launcher.actions.shortcuts.PinnedShortcutInfo
|
import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER
|
||||||
|
import de.jrpie.android.launcher.apps.AbstractDetailedAppInfo
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AppInfo
|
||||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||||
|
import de.jrpie.android.launcher.apps.DetailedPinnedShortcutInfo
|
||||||
|
import de.jrpie.android.launcher.apps.PinnedShortcutInfo
|
||||||
import de.jrpie.android.launcher.apps.getPrivateSpaceUser
|
import de.jrpie.android.launcher.apps.getPrivateSpaceUser
|
||||||
import de.jrpie.android.launcher.apps.isPrivateSpaceSupported
|
import de.jrpie.android.launcher.apps.isPrivateSpaceSupported
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
|
@ -99,9 +102,10 @@ fun removeUnusedShortcuts(context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
||||||
val boundActions: Set<PinnedShortcutInfo> =
|
val boundActions: MutableSet<PinnedShortcutInfo> =
|
||||||
Gesture.entries.mapNotNull { Action.forGesture(it) as? ShortcutAction }.map { it.shortcut }
|
Gesture.entries.mapNotNull { Action.forGesture(it) as? ShortcutAction }.map { it.shortcut }
|
||||||
.toSet()
|
.toMutableSet()
|
||||||
|
boundActions.addAll(LauncherPreferences.apps().pinnedShortcuts())
|
||||||
try {
|
try {
|
||||||
userManager.userProfiles.filter { !userManager.isQuietModeEnabled(it) }.forEach { profile ->
|
userManager.userProfiles.filter { !userManager.isQuietModeEnabled(it) }.forEach { profile ->
|
||||||
getShortcuts(profile)?.groupBy { it.`package` }?.forEach { (p, shortcuts) ->
|
getShortcuts(profile)?.groupBy { it.`package` }?.forEach { (p, shortcuts) ->
|
||||||
|
@ -135,9 +139,12 @@ fun openTutorial(context: Context) {
|
||||||
/**
|
/**
|
||||||
* Load all apps.
|
* Load all apps.
|
||||||
*/
|
*/
|
||||||
fun getApps(packageManager: PackageManager, context: Context): MutableList<DetailedAppInfo> {
|
fun getApps(
|
||||||
val start = System.currentTimeMillis()
|
packageManager: PackageManager,
|
||||||
val loadList = mutableListOf<DetailedAppInfo>()
|
context: Context
|
||||||
|
): MutableList<AbstractDetailedAppInfo> {
|
||||||
|
var start = System.currentTimeMillis()
|
||||||
|
val loadList = mutableListOf<AbstractDetailedAppInfo>()
|
||||||
|
|
||||||
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||||
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
||||||
|
@ -174,7 +181,7 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList<Detai
|
||||||
i.addCategory(Intent.CATEGORY_LAUNCHER)
|
i.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
val allApps = packageManager.queryIntentActivities(i, 0)
|
val allApps = packageManager.queryIntentActivities(i, 0)
|
||||||
for (ri in allApps) {
|
for (ri in allApps) {
|
||||||
val app = AppInfo(ri.activityInfo.packageName, null, AppInfo.INVALID_USER)
|
val app = AppInfo(ri.activityInfo.packageName, null, INVALID_USER)
|
||||||
val detailedAppInfo = DetailedAppInfo(
|
val detailedAppInfo = DetailedAppInfo(
|
||||||
app,
|
app,
|
||||||
ri.loadLabel(packageManager),
|
ri.loadLabel(packageManager),
|
||||||
|
@ -186,8 +193,18 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList<Detai
|
||||||
}
|
}
|
||||||
loadList.sortBy { it.getCustomLabel(context).toString() }
|
loadList.sortBy { it.getCustomLabel(context).toString() }
|
||||||
|
|
||||||
val end = System.currentTimeMillis()
|
var end = System.currentTimeMillis()
|
||||||
Log.i(LOG_TAG, "${loadList.size} apps loaded (${end - start}ms)")
|
Log.i(LOG_TAG, "${loadList.size} apps loaded (${end - start}ms)")
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
|
start = System.currentTimeMillis()
|
||||||
|
LauncherPreferences.apps().pinnedShortcuts()
|
||||||
|
?.mapNotNull { DetailedPinnedShortcutInfo.fromPinnedShortcutInfo(it, context) }
|
||||||
|
?.let {
|
||||||
|
end = System.currentTimeMillis()
|
||||||
|
Log.i(LOG_TAG, "${it.size} shortcuts loaded (${end - start}ms)")
|
||||||
|
loadList.addAll(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return loadList
|
return loadList
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import android.graphics.drawable.Drawable
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import de.jrpie.android.launcher.R
|
import de.jrpie.android.launcher.R
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AppInfo
|
||||||
import de.jrpie.android.launcher.apps.AppInfo.Companion.INVALID_USER
|
import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER
|
||||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||||
import de.jrpie.android.launcher.ui.list.apps.openSettings
|
import de.jrpie.android.launcher.ui.list.apps.openSettings
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
@ -67,7 +67,7 @@ class AppAction(val app: AppInfo) : Action {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getIcon(context: Context): Drawable? {
|
override fun getIcon(context: Context): Drawable? {
|
||||||
return DetailedAppInfo.fromAppInfo(app, context)?.icon
|
return DetailedAppInfo.fromAppInfo(app, context)?.getIcon(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isAvailable(context: Context): Boolean {
|
override fun isAvailable(context: Context): Boolean {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import android.content.pm.LauncherApps
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import de.jrpie.android.launcher.actions.shortcuts.PinnedShortcutInfo
|
import de.jrpie.android.launcher.apps.PinnedShortcutInfo
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package de.jrpie.android.launcher.apps
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is implemented by [AppInfo] and [PinnedShortcutInfo].
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
sealed interface AbstractAppInfo {
|
||||||
|
fun serialize(): String {
|
||||||
|
return Json.encodeToString(this)
|
||||||
|
}
|
||||||
|
companion object {
|
||||||
|
const val INVALID_USER = -1
|
||||||
|
|
||||||
|
fun deserialize(serialized: String): AbstractAppInfo {
|
||||||
|
return Json.decodeFromString(serialized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package de.jrpie.android.launcher.apps
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.os.UserHandle
|
||||||
|
import android.util.Log
|
||||||
|
import de.jrpie.android.launcher.Application
|
||||||
|
import de.jrpie.android.launcher.actions.Action
|
||||||
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is implemented by [DetailedAppInfo] and [DetailedPinnedShortcutInfo]
|
||||||
|
*/
|
||||||
|
sealed interface AbstractDetailedAppInfo {
|
||||||
|
fun getRawInfo(): AbstractAppInfo
|
||||||
|
fun getLabel(): String
|
||||||
|
fun getIcon(context: Context): Drawable
|
||||||
|
fun getUser(context: Context): UserHandle
|
||||||
|
fun isPrivate(): Boolean
|
||||||
|
fun isRemovable(): Boolean
|
||||||
|
fun getAction(): Action
|
||||||
|
|
||||||
|
|
||||||
|
fun getCustomLabel(context: Context): String {
|
||||||
|
val map = (context.applicationContext as? Application)?.getCustomAppNames()
|
||||||
|
return map?.get(getRawInfo()) ?: getLabel()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun setCustomLabel(label: CharSequence?) {
|
||||||
|
Log.i("Launcher", "Setting custom label for ${this.getRawInfo()} to ${label}.")
|
||||||
|
val map = LauncherPreferences.apps().customNames() ?: HashMap<AbstractAppInfo, String>()
|
||||||
|
|
||||||
|
if (label.isNullOrEmpty()) {
|
||||||
|
map.remove(getRawInfo())
|
||||||
|
} else {
|
||||||
|
map[getRawInfo()] = label.toString()
|
||||||
|
}
|
||||||
|
LauncherPreferences.apps().customNames(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import android.os.Build
|
||||||
import de.jrpie.android.launcher.actions.Action
|
import de.jrpie.android.launcher.actions.Action
|
||||||
import de.jrpie.android.launcher.actions.AppAction
|
import de.jrpie.android.launcher.actions.AppAction
|
||||||
import de.jrpie.android.launcher.actions.Gesture
|
import de.jrpie.android.launcher.actions.Gesture
|
||||||
|
import de.jrpie.android.launcher.actions.ShortcutAction
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.text.Regex.Companion.escape
|
import kotlin.text.Regex.Companion.escape
|
||||||
|
@ -18,13 +19,14 @@ class AppFilter(
|
||||||
var privateSpaceVisibility: AppSetVisibility = AppSetVisibility.VISIBLE
|
var privateSpaceVisibility: AppSetVisibility = AppSetVisibility.VISIBLE
|
||||||
) {
|
) {
|
||||||
|
|
||||||
operator fun invoke(apps: List<DetailedAppInfo>): List<DetailedAppInfo> {
|
operator fun invoke(apps: List<AbstractDetailedAppInfo>): List<AbstractDetailedAppInfo> {
|
||||||
var apps =
|
var apps =
|
||||||
apps.sortedBy { app -> app.getCustomLabel(context).toString().lowercase(Locale.ROOT) }
|
apps.sortedBy { app -> app.getCustomLabel(context).lowercase(Locale.ROOT) }
|
||||||
|
|
||||||
val hidden = LauncherPreferences.apps().hidden() ?: setOf()
|
val hidden = LauncherPreferences.apps().hidden() ?: setOf()
|
||||||
val favorites = LauncherPreferences.apps().favorites() ?: setOf()
|
val favorites = LauncherPreferences.apps().favorites() ?: setOf()
|
||||||
val private = apps.filter { it.isPrivateSpaceApp }.map { it.app }.toSet()
|
val private = apps.filter { it.isPrivate() }
|
||||||
|
.map { it.getRawInfo() }.toSet()
|
||||||
|
|
||||||
apps = apps.filter { info ->
|
apps = apps.filter { info ->
|
||||||
favoritesVisibility.predicate(favorites, info)
|
favoritesVisibility.predicate(favorites, info)
|
||||||
|
@ -35,9 +37,13 @@ class AppFilter(
|
||||||
if (LauncherPreferences.apps().hideBoundApps()) {
|
if (LauncherPreferences.apps().hideBoundApps()) {
|
||||||
val boundApps = Gesture.entries
|
val boundApps = Gesture.entries
|
||||||
.filter(Gesture::isEnabled)
|
.filter(Gesture::isEnabled)
|
||||||
.mapNotNull { g -> (Action.forGesture(g) as? AppAction)?.app }
|
.mapNotNull { g -> Action.forGesture(g) }
|
||||||
|
.mapNotNull {
|
||||||
|
(it as? AppAction)?.app
|
||||||
|
?: (it as? ShortcutAction)?.shortcut
|
||||||
|
}
|
||||||
.toSet()
|
.toSet()
|
||||||
apps = apps.filterNot { info -> boundApps.contains(info.app) }
|
apps = apps.filterNot { info -> boundApps.contains(info.getRawInfo()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize text for search
|
// normalize text for search
|
||||||
|
@ -57,11 +63,11 @@ class AppFilter(
|
||||||
if (query.isEmpty()) {
|
if (query.isEmpty()) {
|
||||||
return apps
|
return apps
|
||||||
} else {
|
} else {
|
||||||
val r: MutableList<DetailedAppInfo> = ArrayList()
|
val r: MutableList<AbstractDetailedAppInfo> = ArrayList()
|
||||||
val appsSecondary: MutableList<DetailedAppInfo> = ArrayList()
|
val appsSecondary: MutableList<AbstractDetailedAppInfo> = ArrayList()
|
||||||
val normalizedQuery: String = normalize(query)
|
val normalizedQuery: String = normalize(query)
|
||||||
for (item in apps) {
|
for (item in apps) {
|
||||||
val itemLabel: String = normalize(item.getCustomLabel(context).toString())
|
val itemLabel: String = normalize(item.getCustomLabel(context))
|
||||||
|
|
||||||
if (itemLabel.startsWith(normalizedQuery)) {
|
if (itemLabel.startsWith(normalizedQuery)) {
|
||||||
r.add(item)
|
r.add(item)
|
||||||
|
@ -77,11 +83,11 @@ class AppFilter(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
enum class AppSetVisibility(
|
enum class AppSetVisibility(
|
||||||
val predicate: (set: Set<AppInfo>, DetailedAppInfo) -> Boolean
|
val predicate: (set: Set<AbstractAppInfo>, AbstractDetailedAppInfo) -> Boolean
|
||||||
) {
|
) {
|
||||||
VISIBLE({ _, _ -> true }),
|
VISIBLE({ _, _ -> true }),
|
||||||
HIDDEN({ set, appInfo -> !set.contains(appInfo.app) }),
|
HIDDEN({ set, appInfo -> !set.contains(appInfo.getRawInfo()) }),
|
||||||
EXCLUSIVE({ set, appInfo -> set.contains(appInfo.app) }),
|
EXCLUSIVE({ set, appInfo -> set.contains(appInfo.getRawInfo()) }),
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,21 +4,18 @@ import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.LauncherActivityInfo
|
import android.content.pm.LauncherActivityInfo
|
||||||
import android.content.pm.LauncherApps
|
import android.content.pm.LauncherApps
|
||||||
|
import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER
|
||||||
import de.jrpie.android.launcher.getUserFromId
|
import de.jrpie.android.launcher.getUserFromId
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an app installed on the users device.
|
* Represents an app installed on the users device.
|
||||||
* Contains the minimal amount of data required to identify the app.
|
* Contains the minimal amount of data required to identify the app.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class AppInfo(val packageName: String, val activityName: String?, val user: Int = INVALID_USER) {
|
@SerialName("app")
|
||||||
|
class AppInfo(val packageName: String, val activityName: String?, val user: Int = INVALID_USER): AbstractAppInfo {
|
||||||
fun serialize(): String {
|
|
||||||
return Json.encodeToString(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if(other is AppInfo) {
|
if(other is AppInfo) {
|
||||||
|
@ -47,11 +44,4 @@ class AppInfo(val packageName: String, val activityName: String?, val user: Int
|
||||||
return "AppInfo {package=$packageName, activity=$activityName, user=$user}"
|
return "AppInfo {package=$packageName, activity=$activityName, user=$user}"
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val INVALID_USER = -1
|
|
||||||
|
|
||||||
fun deserialize(serialized: String): AppInfo {
|
|
||||||
return Json.decodeFromString(serialized)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -4,20 +4,21 @@ import android.content.Context
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.LauncherActivityInfo
|
import android.content.pm.LauncherActivityInfo
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.Log
|
import android.os.UserHandle
|
||||||
import de.jrpie.android.launcher.Application
|
import de.jrpie.android.launcher.actions.Action
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.actions.AppAction
|
||||||
|
import de.jrpie.android.launcher.getUserFromId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores information used to create [de.jrpie.android.launcher.ui.list.apps.AppsRecyclerAdapter] rows.
|
* Stores information used to create [de.jrpie.android.launcher.ui.list.apps.AppsRecyclerAdapter] rows.
|
||||||
*/
|
*/
|
||||||
class DetailedAppInfo(
|
class DetailedAppInfo(
|
||||||
val app: AppInfo,
|
private val app: AppInfo,
|
||||||
val label: CharSequence,
|
private val label: CharSequence,
|
||||||
val icon: Drawable,
|
private val icon: Drawable,
|
||||||
val isPrivateSpaceApp: Boolean,
|
private val privateSpace: Boolean,
|
||||||
val isSystemApp: Boolean = false,
|
private val removable: Boolean = true,
|
||||||
) {
|
): AbstractDetailedAppInfo {
|
||||||
|
|
||||||
constructor(activityInfo: LauncherActivityInfo, private: Boolean) : this(
|
constructor(activityInfo: LauncherActivityInfo, private: Boolean) : this(
|
||||||
AppInfo(
|
AppInfo(
|
||||||
|
@ -28,29 +29,41 @@ class DetailedAppInfo(
|
||||||
activityInfo.label,
|
activityInfo.label,
|
||||||
activityInfo.getBadgedIcon(0),
|
activityInfo.getBadgedIcon(0),
|
||||||
private,
|
private,
|
||||||
activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) != 0
|
// App can be uninstalled iff it is not a system app
|
||||||
|
activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getCustomLabel(context: Context): CharSequence {
|
|
||||||
val map = (context.applicationContext as? Application)?.getCustomAppNames() ?: return label
|
|
||||||
|
|
||||||
return map[app] ?: label
|
|
||||||
|
override fun getLabel(): String {
|
||||||
|
return label.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setCustomLabel(label: CharSequence?) {
|
override fun getIcon(context: Context): Drawable {
|
||||||
|
return icon
|
||||||
Log.i("Launcher", "Setting custom label for ${this.app} to ${label}.")
|
|
||||||
val map = LauncherPreferences.apps().customNames() ?: HashMap<AppInfo, String>()
|
|
||||||
|
|
||||||
if (label.isNullOrEmpty()) {
|
|
||||||
map.remove(app)
|
|
||||||
} else {
|
|
||||||
map[app] = label.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
LauncherPreferences.apps().customNames(map)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getRawInfo(): AppInfo {
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUser(context: Context): UserHandle {
|
||||||
|
return getUserFromId(app.user, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isPrivate(): Boolean {
|
||||||
|
return privateSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isRemovable(): Boolean {
|
||||||
|
return removable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAction(): Action {
|
||||||
|
return AppAction(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromAppInfo(appInfo: AppInfo, context: Context): DetailedAppInfo? {
|
fun fromAppInfo(appInfo: AppInfo, context: Context): DetailedAppInfo? {
|
||||||
return appInfo.getLauncherActivityInfo(context)?.let {
|
return appInfo.getLauncherActivityInfo(context)?.let {
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package de.jrpie.android.launcher.apps
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.LauncherApps
|
||||||
|
import android.content.pm.ShortcutInfo
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.UserHandle
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import de.jrpie.android.launcher.actions.Action
|
||||||
|
import de.jrpie.android.launcher.actions.ShortcutAction
|
||||||
|
import de.jrpie.android.launcher.getUserFromId
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||||
|
class DetailedPinnedShortcutInfo(
|
||||||
|
private val shortcutInfo: PinnedShortcutInfo,
|
||||||
|
private val label: String,
|
||||||
|
private val icon: Drawable,
|
||||||
|
private val privateSpace: Boolean
|
||||||
|
) : AbstractDetailedAppInfo {
|
||||||
|
|
||||||
|
constructor(context: Context, shortcut: ShortcutInfo) : this(
|
||||||
|
PinnedShortcutInfo(shortcut),
|
||||||
|
shortcut.longLabel.toString(),
|
||||||
|
(context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps)
|
||||||
|
.getShortcutBadgedIconDrawable(shortcut, 0),
|
||||||
|
shortcut.userHandle == getPrivateSpaceUser(context)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getRawInfo(): AbstractAppInfo {
|
||||||
|
return shortcutInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLabel(): String {
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(context: Context): Drawable {
|
||||||
|
return icon
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUser(context: Context): UserHandle {
|
||||||
|
return getUserFromId(shortcutInfo.user, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isPrivate(): Boolean {
|
||||||
|
return privateSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isRemovable(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAction(): Action {
|
||||||
|
return ShortcutAction(shortcutInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromPinnedShortcutInfo(shortcutInfo: PinnedShortcutInfo, context: Context): DetailedPinnedShortcutInfo? {
|
||||||
|
return shortcutInfo.getShortcutInfo(context)?.let {
|
||||||
|
DetailedPinnedShortcutInfo(context, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package de.jrpie.android.launcher.actions.shortcuts
|
package de.jrpie.android.launcher.apps
|
||||||
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
|
@ -9,17 +9,19 @@ import android.content.pm.ShortcutInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import de.jrpie.android.launcher.getUserFromId
|
import de.jrpie.android.launcher.getUserFromId
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("shortcut")
|
||||||
class PinnedShortcutInfo(
|
class PinnedShortcutInfo(
|
||||||
val id: String,
|
val id: String,
|
||||||
val packageName: String,
|
val packageName: String,
|
||||||
val activityName: String,
|
val activityName: String,
|
||||||
val user: Int
|
val user: Int
|
||||||
) {
|
): AbstractAppInfo {
|
||||||
|
|
||||||
constructor(info: ShortcutInfo) : this(info.id, info.`package`, info.activity?.className ?: "", info.userHandle.hashCode())
|
constructor(info: ShortcutInfo) : this(info.id, info.`package`, info.activity?.className ?: "", info.userHandle.hashCode())
|
||||||
|
|
|
@ -5,8 +5,9 @@ import java.util.Set;
|
||||||
|
|
||||||
import de.jrpie.android.launcher.R;
|
import de.jrpie.android.launcher.R;
|
||||||
import de.jrpie.android.launcher.actions.lock.LockMethod;
|
import de.jrpie.android.launcher.actions.lock.LockMethod;
|
||||||
import de.jrpie.android.launcher.preferences.serialization.MapAppInfoStringPreferenceSerializer;
|
import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer;
|
||||||
import de.jrpie.android.launcher.preferences.serialization.SetAppInfoPreferenceSerializer;
|
import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer;
|
||||||
|
import de.jrpie.android.launcher.preferences.serialization.SetPinnedShortcutInfoPreferenceSerializer;
|
||||||
import de.jrpie.android.launcher.preferences.theme.Background;
|
import de.jrpie.android.launcher.preferences.theme.Background;
|
||||||
import de.jrpie.android.launcher.preferences.theme.ColorTheme;
|
import de.jrpie.android.launcher.preferences.theme.ColorTheme;
|
||||||
import de.jrpie.android.launcher.preferences.theme.Font;
|
import de.jrpie.android.launcher.preferences.theme.Font;
|
||||||
|
@ -25,9 +26,10 @@ import eu.jonahbauer.android.preference.annotations.Preferences;
|
||||||
@Preference(name = "version_code", type = int.class, defaultValue = "-1"),
|
@Preference(name = "version_code", type = int.class, defaultValue = "-1"),
|
||||||
}),
|
}),
|
||||||
@PreferenceGroup(name = "apps", prefix = "settings_apps_", suffix = "_key", value = {
|
@PreferenceGroup(name = "apps", prefix = "settings_apps_", suffix = "_key", value = {
|
||||||
@Preference(name = "favorites", type = Set.class, serializer = SetAppInfoPreferenceSerializer.class),
|
@Preference(name = "favorites", type = Set.class, serializer = SetAbstractAppInfoPreferenceSerializer.class),
|
||||||
@Preference(name = "hidden", type = Set.class, serializer = SetAppInfoPreferenceSerializer.class),
|
@Preference(name = "hidden", type = Set.class, serializer = SetAbstractAppInfoPreferenceSerializer.class),
|
||||||
@Preference(name = "custom_names", type = HashMap.class, serializer = MapAppInfoStringPreferenceSerializer.class),
|
@Preference(name = "pinned_shortcuts", type = Set.class, serializer = SetPinnedShortcutInfoPreferenceSerializer.class),
|
||||||
|
@Preference(name = "custom_names", type = HashMap.class, serializer = MapAbstractAppInfoStringPreferenceSerializer.class),
|
||||||
@Preference(name = "hide_bound_apps", type = boolean.class, defaultValue = "false"),
|
@Preference(name = "hide_bound_apps", type = boolean.class, defaultValue = "false"),
|
||||||
@Preference(name = "hide_paused_apps", type = boolean.class, defaultValue = "false"),
|
@Preference(name = "hide_paused_apps", type = boolean.class, defaultValue = "false"),
|
||||||
@Preference(name = "hide_private_space_apps", type = boolean.class, defaultValue = "false"),
|
@Preference(name = "hide_private_space_apps", type = boolean.class, defaultValue = "false"),
|
||||||
|
|
|
@ -5,6 +5,8 @@ import android.util.Log
|
||||||
import de.jrpie.android.launcher.BuildConfig
|
import de.jrpie.android.launcher.BuildConfig
|
||||||
import de.jrpie.android.launcher.actions.Action
|
import de.jrpie.android.launcher.actions.Action
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AppInfo
|
||||||
|
import de.jrpie.android.launcher.apps.AbstractAppInfo
|
||||||
|
import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER
|
||||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||||
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion1
|
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion1
|
||||||
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion2
|
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion2
|
||||||
|
@ -15,7 +17,7 @@ import de.jrpie.android.launcher.ui.HomeActivity
|
||||||
* Increase when breaking changes are introduced and write an appropriate case in
|
* Increase when breaking changes are introduced and write an appropriate case in
|
||||||
* `migratePreferencesToNewVersion`
|
* `migratePreferencesToNewVersion`
|
||||||
*/
|
*/
|
||||||
const val PREFERENCE_VERSION = 3
|
const val PREFERENCE_VERSION = 4
|
||||||
const val UNKNOWN_PREFERENCE_VERSION = -1
|
const val UNKNOWN_PREFERENCE_VERSION = -1
|
||||||
private const val TAG = "Launcher - Preferences"
|
private const val TAG = "Launcher - Preferences"
|
||||||
|
|
||||||
|
@ -66,16 +68,16 @@ fun resetPreferences(context: Context) {
|
||||||
LauncherPreferences.internal().versionCode(PREFERENCE_VERSION)
|
LauncherPreferences.internal().versionCode(PREFERENCE_VERSION)
|
||||||
|
|
||||||
|
|
||||||
val hidden: MutableSet<AppInfo> = mutableSetOf()
|
val hidden: MutableSet<AbstractAppInfo> = mutableSetOf()
|
||||||
val launcher = DetailedAppInfo.fromAppInfo(
|
val launcher = DetailedAppInfo.fromAppInfo(
|
||||||
AppInfo(
|
AppInfo(
|
||||||
BuildConfig.APPLICATION_ID,
|
BuildConfig.APPLICATION_ID,
|
||||||
HomeActivity::class.java.name,
|
HomeActivity::class.java.name,
|
||||||
AppInfo.INVALID_USER
|
INVALID_USER
|
||||||
), context
|
), context
|
||||||
)
|
)
|
||||||
launcher?.app?.let { hidden.add(it) }
|
launcher?.getRawInfo()?.let { hidden.add(it) }
|
||||||
Log.i(TAG,"Hiding ${launcher?.app}")
|
Log.i(TAG,"Hiding ${launcher?.getRawInfo()}")
|
||||||
LauncherPreferences.apps().hidden(hidden)
|
LauncherPreferences.apps().hidden(hidden)
|
||||||
|
|
||||||
Action.resetToDefaultActions(context)
|
Action.resetToDefaultActions(context)
|
||||||
|
|
|
@ -5,15 +5,26 @@ import de.jrpie.android.launcher.actions.AppAction
|
||||||
import de.jrpie.android.launcher.actions.Gesture
|
import de.jrpie.android.launcher.actions.Gesture
|
||||||
import de.jrpie.android.launcher.actions.LauncherAction
|
import de.jrpie.android.launcher.actions.LauncherAction
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AppInfo
|
||||||
import de.jrpie.android.launcher.apps.AppInfo.Companion.INVALID_USER
|
import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION
|
import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION
|
||||||
import de.jrpie.android.launcher.preferences.serialization.MapAppInfoStringPreferenceSerializer
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private class LegacyMapEntry(val key: AppInfo, val value: String)
|
||||||
|
|
||||||
|
private fun serializeMapAppInfo(value: Map<AppInfo, String>?): Set<String>? {
|
||||||
|
return value?.map { (key, value) ->
|
||||||
|
Json.encodeToString(LegacyMapEntry(key, value))
|
||||||
|
}?.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val oldLauncherActionIds: Map<String, LauncherAction> =
|
val oldLauncherActionIds: Map<String, LauncherAction> =
|
||||||
mapOf(
|
mapOf(
|
||||||
Pair("launcher:settings", LauncherAction.SETTINGS),
|
Pair("launcher:settings", LauncherAction.SETTINGS),
|
||||||
|
@ -77,7 +88,7 @@ private fun Action.Companion.legacyFromPreference(id: String): Action? {
|
||||||
|
|
||||||
private fun migrateAppInfoStringMap(key: String) {
|
private fun migrateAppInfoStringMap(key: String) {
|
||||||
val preferences = LauncherPreferences.getSharedPreferences()
|
val preferences = LauncherPreferences.getSharedPreferences()
|
||||||
MapAppInfoStringPreferenceSerializer().serialize(
|
serializeMapAppInfo(
|
||||||
preferences.getStringSet(key, setOf())?.mapNotNull { entry ->
|
preferences.getStringSet(key, setOf())?.mapNotNull { entry ->
|
||||||
try {
|
try {
|
||||||
val obj = JSONObject(entry)
|
val obj = JSONObject(entry)
|
||||||
|
|
|
@ -12,9 +12,9 @@ import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION
|
||||||
* (see [PREFERENCE_VERSION])
|
* (see [PREFERENCE_VERSION])
|
||||||
*/
|
*/
|
||||||
fun migratePreferencesFromVersion2() {
|
fun migratePreferencesFromVersion2() {
|
||||||
assert(PREFERENCE_VERSION == 3)
|
|
||||||
assert(LauncherPreferences.internal().versionCode() == 2)
|
assert(LauncherPreferences.internal().versionCode() == 2)
|
||||||
// previously there was no setting for this
|
// previously there was no setting for this
|
||||||
Action.setActionForGesture(Gesture.BACK, LauncherAction.CHOOSE)
|
Action.setActionForGesture(Gesture.BACK, LauncherAction.CHOOSE)
|
||||||
LauncherPreferences.internal().versionCode(3)
|
LauncherPreferences.internal().versionCode(3)
|
||||||
|
migratePreferencesFromVersion3()
|
||||||
}
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
package de.jrpie.android.launcher.preferences.legacy
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.SharedPreferences.Editor
|
||||||
|
import de.jrpie.android.launcher.apps.AppInfo
|
||||||
|
import de.jrpie.android.launcher.apps.AbstractAppInfo
|
||||||
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
|
import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION
|
||||||
|
import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer
|
||||||
|
import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate preferences from version 3 (used until version 0.0.23) to the current format
|
||||||
|
* (see [PREFERENCE_VERSION])
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
fun deserializeSet(value: Set<String>?): Set<AppInfo>? {
|
||||||
|
return value?.map {
|
||||||
|
Json.decodeFromString<AppInfo>(it)
|
||||||
|
}?.toHashSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deserializeMap(value: Set<String>?): HashMap<AppInfo, String>? {
|
||||||
|
return value?.associateTo(HashMap()) {
|
||||||
|
val entry = Json.decodeFromString<MapEntry>(it)
|
||||||
|
Pair(entry.key, entry.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private class MapEntry(val key: AppInfo, val value: String)
|
||||||
|
|
||||||
|
private fun migrateSetAppInfo(key: String, preferences: SharedPreferences, editor: Editor) {
|
||||||
|
try {
|
||||||
|
val serializer = SetAbstractAppInfoPreferenceSerializer()
|
||||||
|
val set = HashSet<AbstractAppInfo>()
|
||||||
|
|
||||||
|
deserializeSet(preferences.getStringSet(key, null))?.let {
|
||||||
|
set.addAll(it)
|
||||||
|
}
|
||||||
|
editor.putStringSet(
|
||||||
|
key,
|
||||||
|
serializer.serialize(set as java.util.Set<AbstractAppInfo>) as Set<String>?
|
||||||
|
)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
editor.putStringSet(key, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private fun migrateMapAppInfoString(key: String, preferences: SharedPreferences, editor: Editor ) {
|
||||||
|
try {
|
||||||
|
val serializer = MapAbstractAppInfoStringPreferenceSerializer()
|
||||||
|
val map = HashMap<AbstractAppInfo, String>()
|
||||||
|
|
||||||
|
deserializeMap(preferences.getStringSet(key, null))?.let {
|
||||||
|
map.putAll(it)
|
||||||
|
}
|
||||||
|
editor.putStringSet(key, serializer.serialize(map) as Set<String>?)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
editor.putStringSet(key, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun migratePreferencesFromVersion3() {
|
||||||
|
assert(PREFERENCE_VERSION == 4)
|
||||||
|
assert(LauncherPreferences.internal().versionCode() == 3)
|
||||||
|
|
||||||
|
val preferences = LauncherPreferences.getSharedPreferences()
|
||||||
|
val editor = preferences.edit()
|
||||||
|
migrateSetAppInfo(LauncherPreferences.apps().keys().favorites(), preferences, editor)
|
||||||
|
migrateSetAppInfo(LauncherPreferences.apps().keys().hidden(), preferences, editor)
|
||||||
|
migrateSetAppInfo(LauncherPreferences.apps().keys().customNames(), preferences, editor)
|
||||||
|
|
||||||
|
editor.apply()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LauncherPreferences.internal().versionCode(4)
|
||||||
|
}
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
package de.jrpie.android.launcher.preferences.serialization
|
package de.jrpie.android.launcher.preferences.serialization
|
||||||
|
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AbstractAppInfo
|
||||||
|
import de.jrpie.android.launcher.apps.PinnedShortcutInfo
|
||||||
import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializationException
|
import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializationException
|
||||||
import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializer
|
import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializer
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
@ -10,40 +11,61 @@ import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
|
||||||
// Serializers for [LauncherPreference$Config]
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
class SetAppInfoPreferenceSerializer :
|
class SetAbstractAppInfoPreferenceSerializer :
|
||||||
PreferenceSerializer<java.util.Set<AppInfo>?, java.util.Set<java.lang.String>?> {
|
PreferenceSerializer<java.util.Set<AbstractAppInfo>?, java.util.Set<java.lang.String>?> {
|
||||||
@Throws(PreferenceSerializationException::class)
|
@Throws(PreferenceSerializationException::class)
|
||||||
override fun serialize(value: java.util.Set<AppInfo>?): java.util.Set<java.lang.String> {
|
override fun serialize(value: java.util.Set<AbstractAppInfo>?): java.util.Set<java.lang.String> {
|
||||||
return value?.map(AppInfo::serialize)?.toHashSet() as java.util.Set<java.lang.String>
|
return value?.map(AbstractAppInfo::serialize)
|
||||||
|
?.toHashSet() as java.util.Set<java.lang.String>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(PreferenceSerializationException::class)
|
@Throws(PreferenceSerializationException::class)
|
||||||
override fun deserialize(value: java.util.Set<java.lang.String>?): java.util.Set<AppInfo>? {
|
override fun deserialize(value: java.util.Set<java.lang.String>?): java.util.Set<AbstractAppInfo>? {
|
||||||
return value?.map (java.lang.String::toString)?.map(AppInfo::deserialize)?.toHashSet() as? java.util.Set<AppInfo>
|
return value?.map(java.lang.String::toString)?.map(AbstractAppInfo::deserialize)
|
||||||
|
?.toHashSet() as? java.util.Set<AbstractAppInfo>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
class MapAppInfoStringPreferenceSerializer :
|
class SetPinnedShortcutInfoPreferenceSerializer :
|
||||||
PreferenceSerializer<java.util.HashMap<AppInfo, String>?, java.util.Set<java.lang.String>?> {
|
PreferenceSerializer<java.util.Set<PinnedShortcutInfo>?, java.util.Set<java.lang.String>?> {
|
||||||
|
@Throws(PreferenceSerializationException::class)
|
||||||
@Serializable
|
override fun serialize(value: java.util.Set<PinnedShortcutInfo>?): java.util.Set<java.lang.String> {
|
||||||
private class MapEntry(val key: AppInfo, val value: String)
|
return value?.map { Json.encodeToString<PinnedShortcutInfo>(it) }
|
||||||
|
?.toHashSet() as java.util.Set<java.lang.String>
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(PreferenceSerializationException::class)
|
@Throws(PreferenceSerializationException::class)
|
||||||
override fun serialize(value: java.util.HashMap<AppInfo, String>?): java.util.Set<java.lang.String>? {
|
override fun deserialize(value: java.util.Set<java.lang.String>?): java.util.Set<PinnedShortcutInfo>? {
|
||||||
|
return value?.map(java.lang.String::toString)
|
||||||
|
?.map { Json.decodeFromString<PinnedShortcutInfo>(it) }
|
||||||
|
?.toHashSet() as? java.util.Set<PinnedShortcutInfo>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
class MapAbstractAppInfoStringPreferenceSerializer :
|
||||||
|
PreferenceSerializer<java.util.HashMap<AbstractAppInfo, String>?, java.util.Set<java.lang.String>?> {
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private class MapEntry(val key: AbstractAppInfo, val value: String)
|
||||||
|
|
||||||
|
@Throws(PreferenceSerializationException::class)
|
||||||
|
override fun serialize(value: java.util.HashMap<AbstractAppInfo, String>?): java.util.Set<java.lang.String>? {
|
||||||
return value?.map { (key, value) ->
|
return value?.map { (key, value) ->
|
||||||
Json.encodeToString(MapEntry(key, value))
|
Json.encodeToString(MapEntry(key, value))
|
||||||
}?.toHashSet() as? java.util.Set<java.lang.String>
|
}?.toHashSet() as? java.util.Set<java.lang.String>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(PreferenceSerializationException::class)
|
@Throws(PreferenceSerializationException::class)
|
||||||
override fun deserialize(value: java.util.Set<java.lang.String>?): java.util.HashMap<AppInfo, String>? {
|
override fun deserialize(value: java.util.Set<java.lang.String>?): java.util.HashMap<AbstractAppInfo, String>? {
|
||||||
return value?.associateTo(HashMap()) {
|
return value?.associateTo(HashMap()) {
|
||||||
val entry = Json.decodeFromString<MapEntry>(it.toString())
|
val entry = Json.decodeFromString<MapEntry>(it.toString())
|
||||||
Pair(entry.key, entry.value)
|
Pair(entry.key, entry.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import de.jrpie.android.launcher.R
|
||||||
import de.jrpie.android.launcher.actions.Action
|
import de.jrpie.android.launcher.actions.Action
|
||||||
import de.jrpie.android.launcher.actions.Gesture
|
import de.jrpie.android.launcher.actions.Gesture
|
||||||
import de.jrpie.android.launcher.actions.ShortcutAction
|
import de.jrpie.android.launcher.actions.ShortcutAction
|
||||||
import de.jrpie.android.launcher.actions.shortcuts.PinnedShortcutInfo
|
import de.jrpie.android.launcher.apps.PinnedShortcutInfo
|
||||||
import de.jrpie.android.launcher.databinding.ActivityPinShortcutBinding
|
import de.jrpie.android.launcher.databinding.ActivityPinShortcutBinding
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ class PinShortcutActivity : AppCompatActivity(), UIObject {
|
||||||
private lateinit var binding: ActivityPinShortcutBinding
|
private lateinit var binding: ActivityPinShortcutBinding
|
||||||
|
|
||||||
private var isBound = false
|
private var isBound = false
|
||||||
|
private var request: PinItemRequest? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super<AppCompatActivity>.onCreate(savedInstanceState)
|
super<AppCompatActivity>.onCreate(savedInstanceState)
|
||||||
|
@ -46,6 +47,7 @@ class PinShortcutActivity : AppCompatActivity(), UIObject {
|
||||||
val launcherApps = getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
val launcherApps = getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||||
|
|
||||||
val request = launcherApps.getPinItemRequest(intent)
|
val request = launcherApps.getPinItemRequest(intent)
|
||||||
|
this.request = request
|
||||||
if (request == null || request.requestType != PinItemRequest.REQUEST_TYPE_SHORTCUT) {
|
if (request == null || request.requestType != PinItemRequest.REQUEST_TYPE_SHORTCUT) {
|
||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
|
@ -84,6 +86,7 @@ class PinShortcutActivity : AppCompatActivity(), UIObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.pinShortcutClose.setOnClickListener { finish() }
|
binding.pinShortcutClose.setOnClickListener { finish() }
|
||||||
|
binding.pinShortcutButtonOk.setOnClickListener { finish() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
|
@ -91,6 +94,24 @@ class PinShortcutActivity : AppCompatActivity(), UIObject {
|
||||||
super<UIObject>.onStart()
|
super<UIObject>.onStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
|
super.onDestroy()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(binding.pinShortcutSwitchVisible.isChecked) {
|
||||||
|
if(!isBound) {
|
||||||
|
request?.accept()
|
||||||
|
}
|
||||||
|
request?.shortcutInfo?.let {
|
||||||
|
val set = LauncherPreferences.apps().pinnedShortcuts() ?: mutableSetOf()
|
||||||
|
set.add(PinnedShortcutInfo(it))
|
||||||
|
LauncherPreferences.apps().pinnedShortcuts(set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getTheme(): Resources.Theme {
|
override fun getTheme(): Resources.Theme {
|
||||||
return modifyTheme(super.getTheme())
|
return modifyTheme(super.getTheme())
|
||||||
}
|
}
|
||||||
|
@ -124,5 +145,6 @@ class PinShortcutActivity : AppCompatActivity(), UIObject {
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return gestures.size
|
return gestures.size
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,11 +16,10 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import de.jrpie.android.launcher.Application
|
import de.jrpie.android.launcher.Application
|
||||||
import de.jrpie.android.launcher.R
|
import de.jrpie.android.launcher.R
|
||||||
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
|
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
|
||||||
import de.jrpie.android.launcher.actions.AppAction
|
import de.jrpie.android.launcher.apps.AbstractDetailedAppInfo
|
||||||
import de.jrpie.android.launcher.apps.AppFilter
|
import de.jrpie.android.launcher.apps.AppFilter
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AppInfo
|
||||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||||
import de.jrpie.android.launcher.getUserFromId
|
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
import de.jrpie.android.launcher.preferences.ListLayout
|
import de.jrpie.android.launcher.preferences.ListLayout
|
||||||
import de.jrpie.android.launcher.ui.list.ListActivity
|
import de.jrpie.android.launcher.ui.list.ListActivity
|
||||||
|
@ -47,7 +46,7 @@ class AppsRecyclerAdapter(
|
||||||
RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() {
|
RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() {
|
||||||
|
|
||||||
private val apps = (activity.applicationContext as Application).apps
|
private val apps = (activity.applicationContext as Application).apps
|
||||||
private val appsListDisplayed: MutableList<DetailedAppInfo> = mutableListOf()
|
private val appsListDisplayed: MutableList<AbstractDetailedAppInfo> = mutableListOf()
|
||||||
|
|
||||||
// temporarily disable auto launch
|
// temporarily disable auto launch
|
||||||
var disableAutoLaunch: Boolean = false
|
var disableAutoLaunch: Boolean = false
|
||||||
|
@ -83,11 +82,11 @@ class AppsRecyclerAdapter(
|
||||||
if (layout.useBadgedText) {
|
if (layout.useBadgedText) {
|
||||||
appLabel = activity.packageManager.getUserBadgedLabel(
|
appLabel = activity.packageManager.getUserBadgedLabel(
|
||||||
appLabel,
|
appLabel,
|
||||||
getUserFromId(appsListDisplayed[i].app.user, activity)
|
appsListDisplayed[i].getUser(activity)
|
||||||
).toString()
|
).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
val appIcon = appsListDisplayed[i].icon
|
val appIcon = appsListDisplayed[i].getIcon(activity)
|
||||||
|
|
||||||
viewHolder.textView.text = appLabel
|
viewHolder.textView.text = appLabel
|
||||||
viewHolder.img.setImageDrawable(appIcon)
|
viewHolder.img.setImageDrawable(appIcon)
|
||||||
|
@ -118,22 +117,26 @@ class AppsRecyclerAdapter(
|
||||||
@Suppress("SameReturnValue")
|
@Suppress("SameReturnValue")
|
||||||
private fun showOptionsPopup(
|
private fun showOptionsPopup(
|
||||||
viewHolder: ViewHolder,
|
viewHolder: ViewHolder,
|
||||||
appInfo: DetailedAppInfo
|
appInfo: AbstractDetailedAppInfo
|
||||||
): Boolean {
|
): Boolean {
|
||||||
//create the popup menu
|
//create the popup menu
|
||||||
|
|
||||||
val popup = PopupMenu(activity, viewHolder.img)
|
val popup = PopupMenu(activity, viewHolder.img)
|
||||||
popup.inflate(R.menu.menu_app)
|
popup.inflate(R.menu.menu_app)
|
||||||
|
|
||||||
if (appInfo.isSystemApp) {
|
if (!appInfo.isRemovable()) {
|
||||||
popup.menu.findItem(R.id.app_menu_delete).setVisible(false)
|
popup.menu.findItem(R.id.app_menu_delete).setVisible(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LauncherPreferences.apps().hidden()?.contains(appInfo.app) == true) {
|
if (appInfo !is DetailedAppInfo) {
|
||||||
|
popup.menu.findItem(R.id.app_menu_info).setVisible(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LauncherPreferences.apps().hidden()?.contains(appInfo.getRawInfo()) == true) {
|
||||||
popup.menu.findItem(R.id.app_menu_hidden).setTitle(R.string.list_app_hidden_remove)
|
popup.menu.findItem(R.id.app_menu_hidden).setTitle(R.string.list_app_hidden_remove)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LauncherPreferences.apps().favorites()?.contains(appInfo.app) == true) {
|
if (LauncherPreferences.apps().favorites()?.contains(appInfo.getRawInfo()) == true) {
|
||||||
popup.menu.findItem(R.id.app_menu_favorite).setTitle(R.string.list_app_favorite_remove)
|
popup.menu.findItem(R.id.app_menu_favorite).setTitle(R.string.list_app_favorite_remove)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,19 +144,19 @@ class AppsRecyclerAdapter(
|
||||||
popup.setOnMenuItemClickListener {
|
popup.setOnMenuItemClickListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.app_menu_delete -> {
|
R.id.app_menu_delete -> {
|
||||||
appInfo.app.uninstall(activity); true
|
appInfo.getRawInfo().uninstall(activity); true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.app_menu_info -> {
|
R.id.app_menu_info -> {
|
||||||
appInfo.app.openSettings(activity); true
|
(appInfo.getRawInfo() as? AppInfo)?.openSettings(activity); true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.app_menu_favorite -> {
|
R.id.app_menu_favorite -> {
|
||||||
appInfo.app.toggleFavorite(); true
|
appInfo.getRawInfo().toggleFavorite(); true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.app_menu_hidden -> {
|
R.id.app_menu_hidden -> {
|
||||||
appInfo.app.toggleHidden(root); true
|
appInfo.getRawInfo().toggleHidden(root); true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.app_menu_rename -> {
|
R.id.app_menu_rename -> {
|
||||||
|
@ -188,12 +191,12 @@ class AppsRecyclerAdapter(
|
||||||
val appInfo = appsListDisplayed[pos]
|
val appInfo = appsListDisplayed[pos]
|
||||||
when (intention) {
|
when (intention) {
|
||||||
ListActivity.ListActivityIntention.VIEW -> {
|
ListActivity.ListActivityIntention.VIEW -> {
|
||||||
AppAction(appInfo.app).invoke(activity, rect)
|
appInfo.getAction().invoke(activity, rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
ListActivity.ListActivityIntention.PICK -> {
|
ListActivity.ListActivityIntention.PICK -> {
|
||||||
val returnIntent = Intent()
|
val returnIntent = Intent()
|
||||||
AppAction(appInfo.app).writeToIntent(returnIntent)
|
appInfo.getAction().writeToIntent(returnIntent)
|
||||||
returnIntent.putExtra("forGesture", forGesture)
|
returnIntent.putExtra("forGesture", forGesture)
|
||||||
activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
|
activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
|
||||||
activity.finish()
|
activity.finish()
|
||||||
|
@ -211,8 +214,8 @@ class AppsRecyclerAdapter(
|
||||||
&& !disableAutoLaunch
|
&& !disableAutoLaunch
|
||||||
&& LauncherPreferences.functionality().searchAutoLaunch()
|
&& LauncherPreferences.functionality().searchAutoLaunch()
|
||||||
) {
|
) {
|
||||||
val info = appsListDisplayed[0]
|
val app = appsListDisplayed[0]
|
||||||
AppAction(info.app).invoke(activity)
|
app.getAction().invoke(activity)
|
||||||
|
|
||||||
val inputMethodManager =
|
val inputMethodManager =
|
||||||
activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
|
activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package de.jrpie.android.launcher.ui.list.apps
|
package de.jrpie.android.launcher.ui.list.apps
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
@ -15,7 +16,10 @@ import com.google.android.material.snackbar.Snackbar
|
||||||
import de.jrpie.android.launcher.R
|
import de.jrpie.android.launcher.R
|
||||||
import de.jrpie.android.launcher.REQUEST_UNINSTALL
|
import de.jrpie.android.launcher.REQUEST_UNINSTALL
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AppInfo
|
||||||
|
import de.jrpie.android.launcher.apps.AbstractAppInfo
|
||||||
|
import de.jrpie.android.launcher.apps.AbstractDetailedAppInfo
|
||||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||||
|
import de.jrpie.android.launcher.apps.PinnedShortcutInfo
|
||||||
import de.jrpie.android.launcher.getUserFromId
|
import de.jrpie.android.launcher.getUserFromId
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
|
|
||||||
|
@ -32,27 +36,33 @@ fun AppInfo.openSettings(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AppInfo.uninstall(activity: android.app.Activity) {
|
fun AbstractAppInfo.uninstall(activity: Activity) {
|
||||||
val packageName = this.packageName
|
if (this is AppInfo) {
|
||||||
val userId = this.user
|
val packageName = this.packageName
|
||||||
|
val userId = this.user
|
||||||
|
|
||||||
Log.i(LOG_TAG, "uninstalling $this")
|
Log.i(LOG_TAG, "uninstalling $this")
|
||||||
|
|
||||||
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
|
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
|
||||||
intent.data = Uri.parse("package:$packageName")
|
intent.data = Uri.parse("package:$packageName")
|
||||||
getUserFromId(userId, activity).let { user ->
|
getUserFromId(userId, activity).let { user ->
|
||||||
intent.putExtra(Intent.EXTRA_USER, user)
|
intent.putExtra(Intent.EXTRA_USER, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
|
||||||
|
activity.startActivityForResult(
|
||||||
|
intent,
|
||||||
|
REQUEST_UNINSTALL
|
||||||
|
)
|
||||||
|
} else if(this is PinnedShortcutInfo) {
|
||||||
|
val pinned = LauncherPreferences.apps().pinnedShortcuts() ?: mutableSetOf()
|
||||||
|
pinned.remove(this)
|
||||||
|
LauncherPreferences.apps().pinnedShortcuts(pinned)
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
|
|
||||||
activity.startActivityForResult(
|
|
||||||
intent,
|
|
||||||
REQUEST_UNINSTALL
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AppInfo.toggleFavorite() {
|
fun AbstractAppInfo.toggleFavorite() {
|
||||||
val favorites: MutableSet<AppInfo> =
|
val favorites: MutableSet<AbstractAppInfo> =
|
||||||
LauncherPreferences.apps().favorites() ?: mutableSetOf()
|
LauncherPreferences.apps().favorites() ?: mutableSetOf()
|
||||||
|
|
||||||
if (favorites.contains(this)) {
|
if (favorites.contains(this)) {
|
||||||
|
@ -69,8 +79,8 @@ fun AppInfo.toggleFavorite() {
|
||||||
/**
|
/**
|
||||||
* @param view: used to show a snackbar letting the user undo the action
|
* @param view: used to show a snackbar letting the user undo the action
|
||||||
*/
|
*/
|
||||||
fun AppInfo.toggleHidden(view: View) {
|
fun AbstractAppInfo.toggleHidden(view: View) {
|
||||||
val hidden: MutableSet<AppInfo> =
|
val hidden: MutableSet<AbstractAppInfo> =
|
||||||
LauncherPreferences.apps().hidden() ?: mutableSetOf()
|
LauncherPreferences.apps().hidden() ?: mutableSetOf()
|
||||||
if (hidden.contains(this)) {
|
if (hidden.contains(this)) {
|
||||||
hidden.remove(this)
|
hidden.remove(this)
|
||||||
|
@ -87,9 +97,9 @@ fun AppInfo.toggleHidden(view: View) {
|
||||||
LauncherPreferences.apps().hidden(hidden)
|
LauncherPreferences.apps().hidden(hidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DetailedAppInfo.showRenameDialog(context: Context) {
|
fun AbstractDetailedAppInfo.showRenameDialog(context: Context) {
|
||||||
AlertDialog.Builder(context, R.style.AlertDialogCustom).apply {
|
AlertDialog.Builder(context, R.style.AlertDialogCustom).apply {
|
||||||
setTitle(context.getString(R.string.dialog_rename_title, label))
|
setTitle(context.getString(R.string.dialog_rename_title, getLabel()))
|
||||||
setView(R.layout.dialog_rename_app)
|
setView(R.layout.dialog_rename_app)
|
||||||
setNegativeButton(R.string.dialog_cancel) { d, _ -> d.cancel() }
|
setNegativeButton(R.string.dialog_cancel) { d, _ -> d.cancel() }
|
||||||
setPositiveButton(R.string.dialog_rename_ok) { d, _ ->
|
setPositiveButton(R.string.dialog_rename_ok) { d, _ ->
|
||||||
|
@ -102,7 +112,7 @@ fun DetailedAppInfo.showRenameDialog(context: Context) {
|
||||||
}.create().also { it.show() }.apply {
|
}.create().also { it.show() }.apply {
|
||||||
val input = findViewById<EditText>(R.id.dialog_rename_app_edit_text)
|
val input = findViewById<EditText>(R.id.dialog_rename_app_edit_text)
|
||||||
input?.setText(getCustomLabel(context))
|
input?.setText(getCustomLabel(context))
|
||||||
input?.hint = label
|
input?.hint = getLabel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,6 @@
|
||||||
android:minHeight="40dp"
|
android:minHeight="40dp"
|
||||||
tools:drawableLeft="@drawable/baseline_settings_24"
|
tools:drawableLeft="@drawable/baseline_settings_24"
|
||||||
tools:text="Shortcut name" />
|
tools:text="Shortcut name" />
|
||||||
<!--
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="10dp" />
|
android:layout_height="10dp" />
|
||||||
|
@ -90,8 +89,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textColor="?android:textColor"
|
android:textColor="?android:textColor"
|
||||||
|
android:checked="true"
|
||||||
android:text="@string/pin_shortcut_switch_visible" />
|
android:text="@string/pin_shortcut_switch_visible" />
|
||||||
-->
|
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -103,8 +102,21 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/pin_shortcut_button_bind" />
|
android:text="@string/pin_shortcut_button_bind" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="10dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/pin_shortcut_button_ok"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pin_shortcut_button_ok"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -11,6 +11,7 @@
|
||||||
<string name="settings_internal_version_code_key" translatable="false">internal.version_code</string>
|
<string name="settings_internal_version_code_key" translatable="false">internal.version_code</string>
|
||||||
<string name="settings_apps_favorites_key" translatable="false">apps.favorites</string>
|
<string name="settings_apps_favorites_key" translatable="false">apps.favorites</string>
|
||||||
<string name="settings_apps_hidden_key" translatable="false">apps.hidden</string>
|
<string name="settings_apps_hidden_key" translatable="false">apps.hidden</string>
|
||||||
|
<string name="settings_apps_pinned_shortcuts_key" translatable="false">apps.pinned_shortcuts</string>
|
||||||
<string name="settings_apps_custom_names_key" translatable="false">apps.custom_names</string>
|
<string name="settings_apps_custom_names_key" translatable="false">apps.custom_names</string>
|
||||||
<string name="settings_apps_hide_bound_apps_key" translatable="false">apps.hide_bound_apps</string>
|
<string name="settings_apps_hide_bound_apps_key" translatable="false">apps.hide_bound_apps</string>
|
||||||
<string name="settings_apps_hide_paused_apps_key" translatable="false">apps.hide_paused_apps</string>
|
<string name="settings_apps_hide_paused_apps_key" translatable="false">apps.hide_paused_apps</string>
|
||||||
|
|
|
@ -263,6 +263,7 @@
|
||||||
<!-- Pin shortcuts -->
|
<!-- Pin shortcuts -->
|
||||||
<string name="pin_shortcut_title">Add Shortcut</string>
|
<string name="pin_shortcut_title">Add Shortcut</string>
|
||||||
<string name="pin_shortcut_button_bind">Bind to gesture</string>
|
<string name="pin_shortcut_button_bind">Bind to gesture</string>
|
||||||
|
<string name="pin_shortcut_button_ok">Ok</string>
|
||||||
<string name="pin_shortcut_switch_visible">Show in app list</string>
|
<string name="pin_shortcut_switch_visible">Show in app list</string>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
Loading…
Add table
Reference in a new issue