Add Icon Picker

This commit is contained in:
deniscerri 2026-01-01 19:36:04 +01:00
parent e1b8fd9d28
commit 9637d8a85e
No known key found for this signature in database
GPG key ID: 95C43D517D830350
9 changed files with 209 additions and 44 deletions

View file

@ -0,0 +1,58 @@
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.databinding.AppIconItemBinding
import com.deniscerri.ytdl.util.ThemeUtil
class IconsSheetAdapter(val activity: Activity) : RecyclerView.Adapter<IconsSheetAdapter.IconsSheetViewHolder>() {
class IconsSheetViewHolder(
val binding: AppIconItemBinding
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): IconsSheetViewHolder {
val binding = AppIconItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return IconsSheetViewHolder(binding)
}
override fun getItemCount() = availableIcons.size
override fun onBindViewHolder(holder: IconsSheetViewHolder, position: Int) {
val appIcon = availableIcons[position]
holder.binding.apply {
iconIV.setImageResource(appIcon.iconResource)
iconName.text = root.context.getString(appIcon.nameResource)
root.setOnClickListener {
val preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(activity)
preferences.edit().putString("ytdlnis_icon", appIcon.activityAlias).apply()
val theme = preferences.getString("ytdlnis_theme", "System")!!
ThemeUtil.updateAppIcon(activity, theme,appIcon.activityAlias)
activity.recreate()
}
}
}
companion object {
sealed class AppIcon(
@StringRes val nameResource: Int,
@DrawableRes val iconResource: Int,
val activityAlias: String
) {
object Default : AppIcon(R.string.auto, R.mipmap.ic_launcher, "default")
object DefaultLight : AppIcon(R.string.light, R.mipmap.ic_launcher_light, "Light")
object DefaultDark : AppIcon(R.string.dark, R.mipmap.ic_launcher_dark, "Dark")
}
val availableIcons = listOf(
AppIcon.Default,
AppIcon.DefaultLight,
AppIcon.DefaultDark
)
}
}

View file

@ -12,6 +12,9 @@ import android.net.Uri
import android.os.Bundle
import android.os.PowerManager
import android.provider.Settings
import android.util.DisplayMetrics
import android.view.ViewGroup
import android.view.Window
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
@ -24,6 +27,7 @@ import androidx.preference.MultiSelectListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceManager
import androidx.preference.SwitchPreferenceCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -32,11 +36,13 @@ import androidx.work.WorkManager
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.databinding.NavOptionsItemBinding
import com.deniscerri.ytdl.ui.adapter.IconsSheetAdapter
import com.deniscerri.ytdl.ui.adapter.NavBarOptionsAdapter
import com.deniscerri.ytdl.util.NavbarUtil
import com.deniscerri.ytdl.util.ThemeUtil
import com.deniscerri.ytdl.util.UiUtil
import com.deniscerri.ytdl.util.UpdateUtil
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -202,6 +208,33 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
}
}
findPreference<Preference>("ytdlnis_icon")?.apply {
val currentValue = preferences.getString("ytdlnis_icon", "default")
IconsSheetAdapter.availableIcons.firstOrNull { it.activityAlias == currentValue }?.let {
summary = getString(it.nameResource)
}
setOnPreferenceClickListener {
val bottomSheet = BottomSheetDialog(context)
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet.setContentView(R.layout.generic_list)
val recycler = bottomSheet.findViewById<RecyclerView>(R.id.download_recyclerview)!!
recycler.layoutManager = GridLayoutManager(context, 3)
recycler.adapter = IconsSheetAdapter(requireActivity())
bottomSheet.show()
val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
false
}
}
findPreference<ListPreference>("theme_accent")?.apply {
summary = entry
setOnPreferenceChangeListener { _, _ ->

View file

@ -113,61 +113,23 @@ object ThemeUtil {
activity.theme.applyStyle(R.style.Pure, true)
}
//disable old icons
for (appIcon in availableIcons) {
val activityClass = "com.deniscerri.ytdl." + appIcon.activityAlias
// remove old icons
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, activityClass),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
)
}
when (sharedPreferences.getString("ytdlnis_theme", "System")!!) {
"System" -> {
//set dynamic icon
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, "com.deniscerri.ytdl.Default"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
val theme = sharedPreferences.getString("ytdlnis_theme", "System")!!
when (theme) {
"Light" -> {
//set light icon
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, "com.deniscerri.ytdl.LightIcon"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
"Dark" -> {
//set dark icon
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, "com.deniscerri.ytdl.DarkIcon"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
// or "System"
else -> {
//set dynamic icon
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, "com.deniscerri.ytdl.Default"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
val iconMode = sharedPreferences.getString("ytdlnis_icon", "default")!!
updateAppIcon(activity,theme, iconMode)
}
fun getThemeColor(context: Context, colorCode: Int): Int {
@ -192,4 +154,52 @@ object ThemeUtil {
return "<span style='color:$hexColor';>YTDL</span>nis"
.parseAsHtml(HtmlCompat.FROM_HTML_MODE_COMPACT)
}
fun updateAppIcon(activity: Activity, theme: String, appIconMode: String) {
//disable old icons
for (appIcon in availableIcons) {
val activityClass = "com.deniscerri.ytdl." + appIcon.activityAlias
// remove old icons
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, activityClass),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
)
}
var iconMode = appIconMode
if (appIconMode == "default") {
iconMode = theme
}
when (iconMode) {
"Light" -> {
//set light icon
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, "com.deniscerri.ytdl.LightIcon"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
}
"Dark" -> {
//set dark icon
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, "com.deniscerri.ytdl.DarkIcon"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
}
// or "System"
else -> {
//set dynamic icon
activity.packageManager.setComponentEnabledSetting(
ComponentName(activity.packageName, "com.deniscerri.ytdl.Default"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
}
}
}
}

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:colorAccent"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:fillColor="#FF000000"
android:pathData="M13.05,21.7 L24.05,4 35.05,21.7ZM35.3,44Q31.6,44 29.1,41.5Q26.6,39 26.6,35.3Q26.6,31.6 29.1,29.1Q31.6,26.6 35.3,26.6Q39,26.6 41.5,29.1Q44,31.6 44,35.3Q44,39 41.5,41.5Q39,44 35.3,44ZM6,42.75V27.55H21.2V42.75Z" />
</vector>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#000000" />
<corners android:radius="15dp" />
</shape>
</item>
</ripple>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:background="@drawable/rounded_ripple"
android:orientation="vertical"
android:paddingVertical="10dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/iconIV"
android:layout_width="75dp"
android:layout_height="75dp"
android:layout_gravity="center"
android:padding="10dp"
app:shapeAppearance="@style/CircleImageView"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/iconName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
tools:text="YTDLnis"
android:textSize="11sp" />
</LinearLayout>

View file

@ -506,4 +506,5 @@
<string name="potoken_guide">Auth\n-----------------------\n1. Click \'Auth\' to open the sign in page in WebView.\n2. Sign in to your Google Account.\n3. Play any video that supports auto-translated subtitles.\n4. Turn on auto-translated subtitles and see if it works.\n\t4.1 If auto-translated subtitles don\'t work, switch to another video that supports auto-translated subtitles and try step 4 again.\n5. Click OK.\n\nNo Auth\n-----------------------\n1. Click \'No Auth\'.\n2. Write any youtube video url\n3. Wait for the video to load and play the video for at least 3 seconds.\n4. Click OK.</string>
<string name="no_auth">No Auth</string>
<string name="auth">Auth</string>
<string name="app_icon">App Icon</string>
</resources>

View file

@ -33,6 +33,11 @@
<item name="cornerSize">5dp</item>
</style>
<style name="CircleImageView">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">50%</item>
</style>
<style name="ShapeAppearanceOverlay.Avatar2" parent="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">7dp</item>

View file

@ -21,6 +21,13 @@
app:summary="@string/defaultValue"
app:title="@string/Theme" />
<Preference
android:defaultValue="default"
android:icon="@drawable/ic_frame"
android:title="@string/app_icon"
android:summary="@string/defaultValue"
app:key="ytdlnis_icon" />
<ListPreference
android:entries="@array/accents"
android:entryValues="@array/accents_values"