From 9637d8a85ec4de6344a6fd7c315de07be90e452d Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Thu, 1 Jan 2026 19:36:04 +0100 Subject: [PATCH] Add Icon Picker --- .../ytdl/ui/adapter/IconsSheetAdapter.kt | 58 ++++++++++++ .../more/settings/GeneralSettingsFragment.kt | 33 +++++++ .../com/deniscerri/ytdl/util/ThemeUtil.kt | 90 ++++++++++--------- app/src/main/res/drawable/ic_frame.xml | 10 +++ app/src/main/res/drawable/rounded_ripple.xml | 10 +++ app/src/main/res/layout/app_icon_item.xml | 31 +++++++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 5 ++ app/src/main/res/xml/general_preferences.xml | 7 ++ 9 files changed, 205 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/com/deniscerri/ytdl/ui/adapter/IconsSheetAdapter.kt create mode 100644 app/src/main/res/drawable/ic_frame.xml create mode 100644 app/src/main/res/drawable/rounded_ripple.xml create mode 100644 app/src/main/res/layout/app_icon_item.xml diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/IconsSheetAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/IconsSheetAdapter.kt new file mode 100644 index 00000000..e1b18536 --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/IconsSheetAdapter.kt @@ -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() { + + 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 + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/GeneralSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/GeneralSettingsFragment.kt index b2de49a3..9d0fab18 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/GeneralSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/GeneralSettingsFragment.kt @@ -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("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(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("theme_accent")?.apply { summary = entry setOnPreferenceChangeListener { _, _ -> diff --git a/app/src/main/java/com/deniscerri/ytdl/util/ThemeUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/ThemeUtil.kt index 6c37fc24..c497728d 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/ThemeUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/ThemeUtil.kt @@ -113,6 +113,50 @@ object ThemeUtil { activity.theme.applyStyle(R.style.Pure, true) } + val theme = sharedPreferences.getString("ytdlnis_theme", "System")!! + when (theme) { + "Light" -> { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + } + "Dark" -> { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) + } + // or "System" + else -> { + 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 { + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + val accent = sharedPreferences.getString("theme_accent", "blue") + return if (accent == "blue"){ + "d43c3b".toInt(16) + }else{ + val value = TypedValue() + context.theme.resolveAttribute(colorCode, value, true) + value.data + } + + } + + /** + * Get the styled app name + */ + fun getStyledAppName(context: Context): Spanned { + val colorPrimary = getThemeColor(context, androidx.appcompat.R.attr.colorPrimaryDark) + val hexColor = "#%06X".format(0xFFFFFF and colorPrimary) + return "YTDLnis" + .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 @@ -125,17 +169,12 @@ object ThemeUtil { ) } - 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 - ) + var iconMode = appIconMode + if (appIconMode == "default") { + iconMode = theme + } - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) - } + when (iconMode) { "Light" -> { //set light icon activity.packageManager.setComponentEnabledSetting( @@ -143,8 +182,6 @@ object ThemeUtil { PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP ) - - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) } "Dark" -> { //set dark icon @@ -153,9 +190,8 @@ object ThemeUtil { PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP ) - - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) } + // or "System" else -> { //set dynamic icon activity.packageManager.setComponentEnabledSetting( @@ -163,33 +199,7 @@ object ThemeUtil { PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP ) - - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) } } - - } - - fun getThemeColor(context: Context, colorCode: Int): Int { - val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - val accent = sharedPreferences.getString("theme_accent", "blue") - return if (accent == "blue"){ - "d43c3b".toInt(16) - }else{ - val value = TypedValue() - context.theme.resolveAttribute(colorCode, value, true) - value.data - } - - } - - /** - * Get the styled app name - */ - fun getStyledAppName(context: Context): Spanned { - val colorPrimary = getThemeColor(context, androidx.appcompat.R.attr.colorPrimaryDark) - val hexColor = "#%06X".format(0xFFFFFF and colorPrimary) - return "YTDLnis" - .parseAsHtml(HtmlCompat.FROM_HTML_MODE_COMPACT) } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_frame.xml b/app/src/main/res/drawable/ic_frame.xml new file mode 100644 index 00000000..a2164edc --- /dev/null +++ b/app/src/main/res/drawable/ic_frame.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_ripple.xml b/app/src/main/res/drawable/rounded_ripple.xml new file mode 100644 index 00000000..59a9bc04 --- /dev/null +++ b/app/src/main/res/drawable/rounded_ripple.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/app_icon_item.xml b/app/src/main/res/layout/app_icon_item.xml new file mode 100644 index 00000000..1628d103 --- /dev/null +++ b/app/src/main/res/layout/app_icon_item.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2ae655c8..38251b9d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -506,4 +506,5 @@ 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. No Auth Auth + App Icon diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c4e550f5..edaadb45 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -33,6 +33,11 @@ 5dp + +