Several changes
- Add different launcher icons - Improve input method preset - Improve settings hiding - Add new translations - Add "Random SSAID" option in settings templates - Other fixes and improvements
This commit is contained in:
parent
3b5d8a35c9
commit
6466cfbea0
57 changed files with 1398 additions and 267 deletions
|
|
@ -38,6 +38,42 @@
|
|||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".MainActivityLauncherAlt"
|
||||
android:exported="true"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/ic_launcher_alt"
|
||||
android:targetActivity="org.frknkrc44.hma_oss.ui.activity.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".MainActivityLauncherAlt2"
|
||||
android:exported="true"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/ic_launcher_alt_2"
|
||||
android:targetActivity="org.frknkrc44.hma_oss.ui.activity.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".MainActivityLauncherAlt3"
|
||||
android:exported="true"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/ic_launcher_alt_3"
|
||||
android:targetActivity="org.frknkrc44.hma_oss.ui.activity.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<provider
|
||||
android:name="icu.nullptr.hidemyapplist.service.ServiceProvider"
|
||||
android:authorities="${applicationId}.ServiceProvider"
|
||||
|
|
|
|||
BIN
app/src/main/ic_launcher_alt-playstore.png
Normal file
BIN
app/src/main/ic_launcher_alt-playstore.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
BIN
app/src/main/ic_launcher_alt_2-playstore.png
Normal file
BIN
app/src/main/ic_launcher_alt_2-playstore.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
app/src/main/ic_launcher_alt_3-playstore.png
Normal file
BIN
app/src/main/ic_launcher_alt_3-playstore.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
|
|
@ -0,0 +1,10 @@
|
|||
package icu.nullptr.hidemyapplist.data
|
||||
|
||||
import org.frknkrc44.hma_oss.BuildConfig
|
||||
|
||||
object AppConstants {
|
||||
const val COMPONENT_NAME_DEFAULT = "${BuildConfig.APPLICATION_ID}.MainActivityLauncher"
|
||||
const val COMPONENT_NAME_ALT = "${BuildConfig.APPLICATION_ID}.MainActivityLauncherAlt"
|
||||
const val COMPONENT_NAME_ALT_2 = "${BuildConfig.APPLICATION_ID}.MainActivityLauncherAlt2"
|
||||
const val COMPONENT_NAME_ALT_3 = "${BuildConfig.APPLICATION_ID}.MainActivityLauncherAlt3"
|
||||
}
|
||||
|
|
@ -258,19 +258,39 @@ object ConfigManager {
|
|||
fun clearUninstalledAppConfigs(onFinish: (success: Boolean) -> Unit) {
|
||||
PackageHelper.invalidateCache { throwable ->
|
||||
if (throwable == null) {
|
||||
val markedToRemove = mutableListOf<String>()
|
||||
// --- STEP 1: Clear uninstalled app configs ---
|
||||
val scopeMarkedToRemove = mutableListOf<String>()
|
||||
config.scope.keys.forEach { packageName ->
|
||||
if (!PackageHelper.exists(packageName)) {
|
||||
markedToRemove.add(packageName)
|
||||
scopeMarkedToRemove.add(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
if (markedToRemove.isNotEmpty()) {
|
||||
markedToRemove.forEach { config.scope.remove(it) }
|
||||
saveConfig()
|
||||
if (scopeMarkedToRemove.isNotEmpty()) {
|
||||
scopeMarkedToRemove.forEach { config.scope.remove(it) }
|
||||
}
|
||||
|
||||
ServiceClient.log(Log.INFO, TAG, "Pruned ${markedToRemove.size} app config(s)")
|
||||
// --- STEP 2: Clear uninstalled apps from templates ---
|
||||
var cleanedAppCount = 0
|
||||
config.templates.forEach { (key, value) ->
|
||||
val newList = value.appList.mapNotNull { if (PackageHelper.exists(it)) it else null }.toSet()
|
||||
val count = value.appList.size - newList.size
|
||||
|
||||
if (count > 0) {
|
||||
cleanedAppCount += count
|
||||
config.templates[key] = JsonConfig.Template(
|
||||
isWhitelist = value.isWhitelist,
|
||||
appList = newList
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (scopeMarkedToRemove.isNotEmpty() || cleanedAppCount > 0) {
|
||||
ServiceClient.log(Log.INFO, TAG, "Pruned ${scopeMarkedToRemove.size} app config(s) and $cleanedAppCount app(s) from template(s)")
|
||||
saveConfig()
|
||||
} else {
|
||||
ServiceClient.log(Log.INFO, TAG, "No actions are required")
|
||||
}
|
||||
|
||||
onFinish(true)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -5,8 +5,12 @@ import android.content.Context.MODE_PRIVATE
|
|||
import android.content.pm.PackageManager
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.edit
|
||||
import icu.nullptr.hidemyapplist.data.AppConstants
|
||||
import icu.nullptr.hidemyapplist.hmaApp
|
||||
import org.frknkrc44.hma_oss.BuildConfig
|
||||
import icu.nullptr.hidemyapplist.ui.util.get
|
||||
import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
object PrefManager {
|
||||
|
||||
|
|
@ -21,7 +25,6 @@ object PrefManager {
|
|||
private const val PREF_FOLLOW_SYSTEM_ACCENT = "follow_system_accent"
|
||||
private const val PREF_THEME_COLOR = "theme_color"
|
||||
|
||||
private const val PREF_HIDE_ICON = "hide_icon"
|
||||
private const val PREF_BYPASS_RISKY_PACKAGE_WARNING = "bypass_risky_package_warning"
|
||||
|
||||
private const val PREF_APP_FILTER_SHOW_SYSTEM = "app_filter_show_system"
|
||||
|
|
@ -35,6 +38,7 @@ object PrefManager {
|
|||
}
|
||||
|
||||
private val pref = hmaApp.getSharedPreferences("settings", MODE_PRIVATE)
|
||||
val isLauncherIconInvisible = MutableSharedFlow<Boolean>(replay = 1)
|
||||
|
||||
var lastVersion: Int
|
||||
get() = pref.getInt(PREF_LAST_VERSION, 0)
|
||||
|
|
@ -69,14 +73,24 @@ object PrefManager {
|
|||
set(value) = pref.edit { putString(PREF_THEME_COLOR, value) }
|
||||
|
||||
var hideIcon: Boolean
|
||||
get() = pref.getBoolean(PREF_HIDE_ICON, false)
|
||||
get() = isLauncherIconInvisible.get()
|
||||
set(value) {
|
||||
pref.edit { putBoolean(PREF_HIDE_ICON, value) }
|
||||
val component = ComponentName(hmaApp, "${BuildConfig.APPLICATION_ID}.MainActivityLauncher")
|
||||
val status =
|
||||
if (value) PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|
||||
else PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
hmaApp.packageManager.setComponentEnabledSetting(component, status, PackageManager.DONT_KILL_APP)
|
||||
val enabled = findEnabledAppComponent(hmaApp)
|
||||
if (value && enabled != null) {
|
||||
hmaApp.packageManager.setComponentEnabledSetting(
|
||||
enabled,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
} else if (!value && enabled == null) {
|
||||
hmaApp.packageManager.setComponentEnabledSetting(
|
||||
ComponentName(hmaApp, AppConstants.COMPONENT_NAME_DEFAULT),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
|
||||
runBlocking { isLauncherIconInvisible.emit(value) }
|
||||
}
|
||||
|
||||
var bypassRiskyPackageWarning: Boolean
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import android.view.View
|
|||
import android.view.WindowInsets
|
||||
import android.widget.Toast
|
||||
import androidx.activity.addCallback
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.clearFragmentResultListener
|
||||
|
|
@ -192,7 +191,7 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
|
|||
preferenceManager.preferenceDataStore = AppPreferenceDataStore(pack)
|
||||
setPreferencesFromResource(R.xml.app_settings, rootKey)
|
||||
findPreference<Preference>("appInfo")?.let {
|
||||
it.icon = PackageHelper.loadAppIcon(pack.app).toDrawable(resources)
|
||||
it.icon = PackageHelper.loadAppIcon(pack.app)
|
||||
it.title = PackageHelper.loadAppLabel(pack.app)
|
||||
it.summary = pack.app
|
||||
it.setOnPreferenceClickListener { pref ->
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.view.WindowInsets
|
|||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.net.toUri
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
|
|
@ -31,11 +32,14 @@ import icu.nullptr.hidemyapplist.ui.util.setupToolbar
|
|||
import icu.nullptr.hidemyapplist.ui.util.showToast
|
||||
import icu.nullptr.hidemyapplist.util.ConfigUtils.Companion.getLocale
|
||||
import icu.nullptr.hidemyapplist.util.LangList
|
||||
import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent
|
||||
import icu.nullptr.hidemyapplist.util.SuUtils
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.frknkrc44.hma_oss.R
|
||||
import org.frknkrc44.hma_oss.databinding.FragmentSettingsBinding
|
||||
import org.frknkrc44.hma_oss.ui.activity.BaseActivity
|
||||
import org.frknkrc44.hma_oss.ui.preference.AppIconPreference
|
||||
import java.util.Locale
|
||||
|
||||
class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||
|
|
@ -53,6 +57,10 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen
|
|||
// isTitleCentered = true
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
PrefManager.isLauncherIconInvisible.emit(findEnabledAppComponent(hmaApp) == null)
|
||||
}
|
||||
|
||||
if (childFragmentManager.findFragmentById(R.id.settings_container) == null) {
|
||||
childFragmentManager.beginTransaction()
|
||||
.replace(R.id.settings_container, SettingsPreferenceFragment())
|
||||
|
|
@ -315,6 +323,16 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen
|
|||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
PrefManager.isLauncherIconInvisible
|
||||
.flowWithLifecycle(lifecycle)
|
||||
.collect { _ ->
|
||||
findPreference<AppIconPreference>("launcherIcon")?.apply {
|
||||
updateHolder()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<Preference>("clearUninstalledPackageConfigs")?.apply {
|
||||
setOnPreferenceClickListener {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package icu.nullptr.hidemyapplist.ui.util
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Resources
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import org.frknkrc44.hma_oss.R
|
||||
|
||||
fun Boolean.enabledString(resources: Resources, lower: Boolean = false): String {
|
||||
|
|
@ -9,3 +12,7 @@ fun Boolean.enabledString(resources: Resources, lower: Boolean = false): String
|
|||
|
||||
return if (lower) returnedStr.lowercase() else returnedStr
|
||||
}
|
||||
|
||||
fun ActivityInfo.asComponentName() = ComponentName(packageName, name)
|
||||
|
||||
fun <T> MutableSharedFlow<T>.get() = replayCache.first()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import androidx.annotation.AttrRes
|
|||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.StyleRes
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import icu.nullptr.hidemyapplist.service.PrefManager
|
||||
|
|
@ -129,4 +130,6 @@ object ThemeUtils {
|
|||
}
|
||||
|
||||
fun Fragment.homeItemBackgroundColor(forceNoTrans: Boolean = false) = requireContext().homeItemBackgroundColor(forceNoTrans)
|
||||
|
||||
fun Int.asDrawable(context: Context) = ResourcesCompat.getDrawable(context.resources, this, context.theme)!!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class AppItemView @JvmOverloads constructor(
|
|||
binding.packageName.text = packageName
|
||||
try {
|
||||
binding.label.text = PackageHelper.loadAppLabel(packageName)
|
||||
binding.icon.setImageBitmap(PackageHelper.loadAppIcon(packageName))
|
||||
binding.icon.setImageDrawable(PackageHelper.loadAppIcon(packageName))
|
||||
} catch (e: Throwable) {
|
||||
binding.label.text = packageName
|
||||
binding.icon.setImageResource(android.R.drawable.sym_def_app_icon)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,27 @@
|
|||
package icu.nullptr.hidemyapplist.util
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageInfo
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import icu.nullptr.hidemyapplist.common.Constants
|
||||
import icu.nullptr.hidemyapplist.hmaApp
|
||||
import icu.nullptr.hidemyapplist.service.ConfigManager
|
||||
import icu.nullptr.hidemyapplist.service.PrefManager
|
||||
import icu.nullptr.hidemyapplist.service.ServiceClient
|
||||
import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.asDrawable
|
||||
import icu.nullptr.hidemyapplist.ui.util.asComponentName
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.frknkrc44.hma_oss.BuildConfig
|
||||
import org.frknkrc44.hma_oss.R
|
||||
import java.text.Collator
|
||||
import java.util.Locale
|
||||
|
||||
|
|
@ -22,7 +29,7 @@ object PackageHelper {
|
|||
class PackageCache(
|
||||
val info: PackageInfo,
|
||||
val label: String,
|
||||
val icon: Bitmap
|
||||
val icon: Drawable
|
||||
)
|
||||
|
||||
object Comparators {
|
||||
|
|
@ -85,7 +92,7 @@ object PackageHelper {
|
|||
if (packageInfo.packageName in Constants.packagesShouldNotHide) continue
|
||||
packageInfo.applicationInfo?.let { appInfo ->
|
||||
val label = pm.getApplicationLabel(appInfo).toString()
|
||||
val icon = hmaApp.appIconLoader.loadIcon(appInfo)
|
||||
val icon = loadAppIconFromAppInfo(appInfo)
|
||||
it[packageInfo.packageName] = PackageCache(packageInfo, label, icon)
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +104,7 @@ object PackageHelper {
|
|||
if (packageInfo.packageName in Constants.packagesShouldNotHide) continue
|
||||
packageInfo.applicationInfo?.let { appInfo ->
|
||||
val label = pm.getApplicationLabel(appInfo).toString()
|
||||
val icon = hmaApp.appIconLoader.loadIcon(appInfo)
|
||||
val icon = loadAppIconFromAppInfo(appInfo)
|
||||
it[packageInfo.packageName] = PackageCache(packageInfo, label, icon)
|
||||
}
|
||||
}
|
||||
|
|
@ -144,15 +151,33 @@ object PackageHelper {
|
|||
getCacheNoThrow()[packageName]?.label ?: packageName
|
||||
}
|
||||
|
||||
fun loadAppIcon(packageName: String): Bitmap = runBlocking {
|
||||
fun loadAppIcon(packageName: String): Drawable = runBlocking {
|
||||
getCacheNoThrow()[packageName]?.icon ?:
|
||||
BitmapFactory.decodeResource(
|
||||
hmaApp.resources,
|
||||
android.R.drawable.sym_def_app_icon
|
||||
)
|
||||
android.R.drawable.sym_def_app_icon.asDrawable(hmaApp)
|
||||
}
|
||||
|
||||
fun isSystem(packageName: String): Boolean = runBlocking {
|
||||
getCacheNoThrow()[packageName]?.info?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM) != 0
|
||||
}
|
||||
|
||||
fun loadAppIconFromAppInfo(appInfo: ApplicationInfo): Drawable {
|
||||
return if (appInfo.packageName == BuildConfig.APPLICATION_ID) {
|
||||
val activityName = findEnabledAppComponent(hmaApp)
|
||||
if (activityName == null) {
|
||||
R.mipmap.ic_launcher.asDrawable(hmaApp)
|
||||
} else {
|
||||
hmaApp.packageManager.getActivityIcon(activityName)
|
||||
}
|
||||
} else {
|
||||
hmaApp.appIconLoader.loadIcon(appInfo).toDrawable(hmaApp.resources)
|
||||
}
|
||||
}
|
||||
|
||||
fun findEnabledAppComponent(context: Context): ComponentName? {
|
||||
with (context.packageManager) {
|
||||
val pkgInfo = getPackageInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_ACTIVITIES)!!
|
||||
|
||||
return pkgInfo.activities?.firstOrNull { it.targetActivity != null }?.asComponentName()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.bumptech.glide.Glide
|
|||
import icu.nullptr.hidemyapplist.service.PrefManager
|
||||
import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor
|
||||
import icu.nullptr.hidemyapplist.ui.util.navController
|
||||
import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent
|
||||
import org.frknkrc44.hma_oss.R
|
||||
import org.frknkrc44.hma_oss.common.BuildConfig
|
||||
import org.frknkrc44.hma_oss.databinding.FragmentAboutBinding
|
||||
|
|
@ -67,10 +68,14 @@ class AboutFragment : Fragment(R.layout.fragment_about) {
|
|||
backgroundTintList = tint
|
||||
}
|
||||
|
||||
Glide.with(this@AboutFragment)
|
||||
.load(R.mipmap.ic_launcher)
|
||||
.circleCrop()
|
||||
.into(appIcon)
|
||||
Glide.with(this@AboutFragment).let {
|
||||
val activityName = findEnabledAppComponent(requireContext())
|
||||
return@let if (activityName == null) {
|
||||
it.load(R.mipmap.ic_launcher)
|
||||
} else {
|
||||
it.load(requireContext().packageManager.getActivityIcon(activityName))
|
||||
}
|
||||
}.circleCrop().into(appIcon)
|
||||
|
||||
appName.setText(R.string.app_name)
|
||||
appVersion.text = BuildConfig.APP_VERSION_NAME
|
||||
|
|
@ -120,6 +125,7 @@ class AboutFragment : Fragment(R.layout.fragment_about) {
|
|||
// HMA-OSS devs
|
||||
with(binding.listHmaOss) {
|
||||
addDevItem(this, R.drawable.cont_fk, "frknkrc44", "HMA-OSS Developer", "https://github.com/frknkrc44")
|
||||
addDevItem(this, R.drawable.cont_oukaromf, "OukaroMF", "HMA-OSS Alt Icon Designer", "https://github.com/OukaroMF")
|
||||
}
|
||||
|
||||
// Original HMA devs
|
||||
|
|
|
|||
|
|
@ -9,12 +9,15 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import icu.nullptr.hidemyapplist.common.Constants
|
||||
import icu.nullptr.hidemyapplist.service.ServiceClient
|
||||
import icu.nullptr.hidemyapplist.ui.util.get
|
||||
import icu.nullptr.hidemyapplist.ui.util.navController
|
||||
import icu.nullptr.hidemyapplist.ui.util.setupToolbar
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import org.frknkrc44.hma_oss.R
|
||||
import org.frknkrc44.hma_oss.databinding.FragmentEditSettingBinding
|
||||
|
||||
|
|
@ -23,6 +26,8 @@ class EditSettingFragment : Fragment(R.layout.fragment_edit_setting) {
|
|||
|
||||
private val args by navArgs<EditSettingFragmentArgs>()
|
||||
|
||||
var settingsItems = MutableSharedFlow<Array<String>>(replay = 1)
|
||||
|
||||
fun saveResult() {
|
||||
val databaseName = getEditTextValue(binding.databaseSelector)
|
||||
val settingName = getEditTextValue(binding.settingName)
|
||||
|
|
@ -83,6 +88,20 @@ class EditSettingFragment : Fragment(R.layout.fragment_edit_setting) {
|
|||
}
|
||||
}
|
||||
|
||||
with(binding.settingsGroupShowAll) {
|
||||
setOnClickListener {
|
||||
if (settingsItems.replayCache.isEmpty()) return@setOnClickListener
|
||||
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.settings_templates_name)
|
||||
.setItems(settingsItems.get()) { _, which ->
|
||||
binding.settingName.editText?.setText(settingsItems.get()[which])
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
with(binding.settingName.editText as MaterialAutoCompleteTextView) {
|
||||
setText(args.name)
|
||||
}
|
||||
|
|
@ -126,9 +145,10 @@ class EditSettingFragment : Fragment(R.layout.fragment_edit_setting) {
|
|||
fun fillSettingNames(databaseName: String) {
|
||||
with(binding.settingName) {
|
||||
isEnabled = true
|
||||
(editText as MaterialAutoCompleteTextView).setSimpleItems(
|
||||
ServiceClient.listAllSettings(databaseName)
|
||||
)
|
||||
|
||||
settingsItems.tryEmit(ServiceClient.listAllSettings(databaseName))
|
||||
|
||||
(editText as MaterialAutoCompleteTextView).setSimpleItems(settingsItems.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
package org.frknkrc44.hma_oss.ui.fragment
|
||||
|
||||
import android.provider.Settings
|
||||
import android.view.MenuItem
|
||||
import androidx.fragment.app.clearFragmentResultListener
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import icu.nullptr.hidemyapplist.common.Constants
|
||||
import icu.nullptr.hidemyapplist.common.Utils.generateRandomHex
|
||||
import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem
|
||||
import icu.nullptr.hidemyapplist.ui.util.navigate
|
||||
import org.frknkrc44.hma_oss.R
|
||||
import org.frknkrc44.hma_oss.ui.adapter.SettingsTemplateListAdapter
|
||||
|
|
@ -53,8 +57,28 @@ class SettingsTemplateInnerFragment : BaseSettingsPTFragment() {
|
|||
fun onMenuOptionSelected(item: MenuItem) {
|
||||
when (item.itemId) {
|
||||
R.id.menu_add -> {
|
||||
val args = EditSettingFragmentArgs(database = null, name = "", value = null)
|
||||
launchEditSettingFragment(args)
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setTitle(R.string.add)
|
||||
setItems(R.array.settings_template_inner_add_texts) { dialog, which ->
|
||||
when (which) {
|
||||
0 -> {
|
||||
val args = EditSettingFragmentArgs(database = null, name = "", value = null)
|
||||
launchEditSettingFragment(args)
|
||||
}
|
||||
1 -> {
|
||||
processIncomingSetting(
|
||||
ReplacementItem(
|
||||
name = Settings.Secure.ANDROID_ID,
|
||||
value = generateRandomHex(16),
|
||||
database = Constants.SETTINGS_SECURE,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
dialog.dismiss()
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -62,19 +86,8 @@ class SettingsTemplateInnerFragment : BaseSettingsPTFragment() {
|
|||
fun launchEditSettingFragment(args: EditSettingFragmentArgs) {
|
||||
setFragmentResultListener("edit_setting") { _, bundle ->
|
||||
fun deal() {
|
||||
val item = bundle.toTargetSettingList().firstOrNull()
|
||||
|
||||
if (item != null) {
|
||||
val index = adapter.items.indexOfFirst { it.name == item.name && it.database == item.database }
|
||||
|
||||
if (index >= 0) {
|
||||
adapter.items[index] = item
|
||||
adapter.notifyItemChanged(index)
|
||||
} else {
|
||||
adapter.items.add(item)
|
||||
adapter.notifyItemInserted(adapter.items.size - 1)
|
||||
}
|
||||
}
|
||||
val item = bundle.toTargetSettingList().firstOrNull() ?: return
|
||||
processIncomingSetting(item)
|
||||
}
|
||||
deal()
|
||||
clearFragmentResultListener("edit_setting")
|
||||
|
|
@ -83,6 +96,18 @@ class SettingsTemplateInnerFragment : BaseSettingsPTFragment() {
|
|||
navigate(R.id.nav_settings_templates_edit_setting, args.toBundle())
|
||||
}
|
||||
|
||||
private fun processIncomingSetting(item: ReplacementItem) {
|
||||
val index = adapter.items.indexOfFirst { it.name == item.name && it.database == item.database }
|
||||
|
||||
if (index >= 0) {
|
||||
adapter.items[index] = item
|
||||
adapter.notifyItemChanged(index)
|
||||
} else {
|
||||
adapter.items.add(item)
|
||||
adapter.notifyItemInserted(adapter.items.size - 1)
|
||||
}
|
||||
}
|
||||
|
||||
override val menu = Pair(
|
||||
R.menu.menu_settings_template,
|
||||
this::onMenuOptionSelected,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
package org.frknkrc44.hma_oss.ui.preference
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RadioGroup
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.widget.AppCompatRadioButton
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import icu.nullptr.hidemyapplist.data.AppConstants
|
||||
import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.asDrawable
|
||||
import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent
|
||||
import org.frknkrc44.hma_oss.BuildConfig
|
||||
import org.frknkrc44.hma_oss.R
|
||||
|
||||
|
||||
@Suppress("deprecation")
|
||||
class AppIconPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
|
||||
val appIconsList = listOf(
|
||||
R.mipmap.ic_launcher.asDrawable(context),
|
||||
R.mipmap.ic_launcher_alt.asDrawable(context),
|
||||
R.mipmap.ic_launcher_alt_2.asDrawable(context),
|
||||
R.mipmap.ic_launcher_alt_3.asDrawable(context),
|
||||
)
|
||||
|
||||
val allAppIcons = listOf(
|
||||
ComponentName(BuildConfig.APPLICATION_ID, AppConstants.COMPONENT_NAME_DEFAULT),
|
||||
ComponentName(BuildConfig.APPLICATION_ID, AppConstants.COMPONENT_NAME_ALT),
|
||||
ComponentName(BuildConfig.APPLICATION_ID, AppConstants.COMPONENT_NAME_ALT_2),
|
||||
ComponentName(BuildConfig.APPLICATION_ID, AppConstants.COMPONENT_NAME_ALT_3),
|
||||
)
|
||||
|
||||
var viewHolder: PreferenceViewHolder? = null
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
viewHolder = holder
|
||||
|
||||
super.onBindViewHolder(holder)
|
||||
|
||||
updateHolder()
|
||||
}
|
||||
|
||||
fun updateHolder() {
|
||||
if (viewHolder == null) return
|
||||
|
||||
(viewHolder!!.itemView as ViewGroup).apply {
|
||||
val summary = findViewById<View>(android.R.id.summary)
|
||||
val parent = summary.parent as ViewGroup
|
||||
parent.removeView(summary)
|
||||
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.preference_app_icon, parent, false)
|
||||
view.id = android.R.id.summary
|
||||
(view.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.BELOW, android.R.id.title)
|
||||
|
||||
val appIconSelector: RadioGroup = view.findViewById(R.id.app_icon_selector)
|
||||
|
||||
val selected = findEnabledAppComponent(context)
|
||||
val selectedIdx = allAppIcons.indexOfFirst { it.className == selected?.className }
|
||||
|
||||
for (idx in 0 ..< appIconsList.size) {
|
||||
val radioButton = object : AppCompatRadioButton(context) {
|
||||
override fun setChecked(checked: Boolean) {
|
||||
super.setChecked(checked)
|
||||
|
||||
alpha = if (checked) 1.0f else 0.4f
|
||||
|
||||
if (checked) {
|
||||
setEnabledComponent(allAppIcons[idx])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radioButton.layoutParams = RadioGroup.LayoutParams(-2, -2).apply {
|
||||
val padding = context.resources.getDimensionPixelOffset(R.dimen.item_padding_mini2x)
|
||||
setMargins(padding, padding, padding, padding)
|
||||
}
|
||||
|
||||
radioButton.gravity = Gravity.CENTER_VERTICAL
|
||||
radioButton.id = idx
|
||||
radioButton.isChecked = idx == selectedIdx
|
||||
|
||||
radioButton.buttonDrawable = appIconsList.elementAt(idx)
|
||||
radioButton.text = ""
|
||||
radioButton.buttonTintList = null
|
||||
|
||||
appIconSelector.addView(radioButton)
|
||||
}
|
||||
|
||||
appIconSelector.check(selectedIdx)
|
||||
|
||||
parent.addView(view)
|
||||
}
|
||||
}
|
||||
|
||||
private fun disableAppIcon() {
|
||||
val enabled = findEnabledAppComponent(context)
|
||||
|
||||
if (enabled != null) {
|
||||
context.packageManager.setComponentEnabledSetting(
|
||||
enabled,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setEnabledComponent(componentName: ComponentName) {
|
||||
disableAppIcon()
|
||||
|
||||
context.packageManager.setComponentEnabledSetting(
|
||||
componentName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
}
|
||||
7
app/src/main/res/drawable/check_box.xml
Normal file
7
app/src/main/res/drawable/check_box.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:enterFadeDuration="200"
|
||||
android:exitFadeDuration="200">
|
||||
<item android:state_checked="true" android:drawable="@drawable/check_box_24px" />
|
||||
<item android:state_checked="false" android:drawable="@drawable/check_box_outline_blank_24px" />
|
||||
</animated-selector>
|
||||
10
app/src/main/res/drawable/check_box_24px.xml
Normal file
10
app/src/main/res/drawable/check_box_24px.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="@color/switch_accent_enabled">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M424,648L706,366L650,310L424,536L310,422L254,478L424,648ZM200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840Z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/check_box_outline_blank_24px.xml
Normal file
10
app/src/main/res/drawable/check_box_outline_blank_24px.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="@color/switch_accent_enabled">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,760L760,760Q760,760 760,760Q760,760 760,760L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760Z"/>
|
||||
</vector>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue