diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e4a8d97..b17a620 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -183,6 +183,7 @@ dependencies { implementation(libs.acra.core) implementation(libs.acra.dialog) implementation(libs.acra.mail) + implementation(libs.androidx.palette.ktx) //noinspection KaptUsageInsteadOfKsp kapt(libs.room.compiler) diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/helper/PreferenceHelper.kt b/app/src/main/java/com/github/droidworksstudio/launcher/helper/PreferenceHelper.kt index 3c242e5..697cd1f 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/helper/PreferenceHelper.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/helper/PreferenceHelper.kt @@ -87,6 +87,10 @@ class PreferenceHelper @Inject constructor(@ApplicationContext context: Context) get() = prefs.getBoolean(Constants.SHOW_APP_ICON, false) set(value) = prefs.edit().putBoolean(Constants.SHOW_APP_ICON, value).apply() + var showAppIconAsDots: Boolean + get() = prefs.getBoolean(Constants.SHOW_APP_ICON_DOTS, true) + set(value) = prefs.edit().putBoolean(Constants.SHOW_APP_ICON_DOTS, value).apply() + var locationDenied: Boolean get() = prefs.getBoolean(Constants.LOCATION_DENIED, false) set(value) = prefs.edit().putBoolean(Constants.LOCATION_DENIED, value).apply() diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt index 9d2a1f2..29ef4a1 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt @@ -2,16 +2,25 @@ package com.github.droidworksstudio.launcher.ui.home import android.annotation.SuppressLint import android.content.pm.PackageManager -import android.util.Log +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable import android.view.Gravity import android.view.View -import androidx.appcompat.widget.LinearLayoutCompat +import androidx.core.content.ContextCompat +import androidx.core.graphics.ColorUtils +import androidx.core.graphics.drawable.DrawableCompat +import androidx.palette.graphics.Palette import androidx.recyclerview.widget.RecyclerView +import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.data.entities.AppInfo import com.github.droidworksstudio.launcher.databinding.ItemHomeBinding import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.listener.OnItemClickedListener import javax.inject.Inject +import kotlin.math.min class HomeViewHolder @Inject constructor( private val binding: ItemHomeBinding, @@ -22,46 +31,60 @@ class HomeViewHolder @Inject constructor( @SuppressLint("ClickableViewAccessibility") fun bind(appInfo: AppInfo) { binding.apply { - // Get the current LayoutParams of appHomeName - val layoutParams = appHomeName.layoutParams as LinearLayoutCompat.LayoutParams - - // Set the margins - layoutParams.topMargin = preferenceHelper.homeAppPadding.toInt() - layoutParams.bottomMargin = preferenceHelper.homeAppPadding.toInt() - - appHomeName.layoutParams = layoutParams + // Update appHomeName properties appHomeName.text = appInfo.appName appHomeName.setTextColor(preferenceHelper.appColor) appHomeName.textSize = preferenceHelper.appTextSize appHomeName.gravity = preferenceHelper.homeAppAlignment - Log.d("Tag", "Home Adapter Color: ${preferenceHelper.appColor}") if (preferenceHelper.showAppIcon) { val pm: PackageManager = binding.root.context.packageManager - val appIcon = pm.getApplicationIcon(appInfo.packageName) - when (preferenceHelper.homeAppAlignment) { - Gravity.START -> { - appHomeLeftIcon.setImageDrawable(appIcon) - appHomeLeftIcon.layoutParams.width = - preferenceHelper.appTextSize.toInt() * 3 - appHomeLeftIcon.layoutParams.height = - preferenceHelper.appTextSize.toInt() * 3 - appHomeLeftIcon.visibility = View.VISIBLE - } - Gravity.END -> { - appHomeRightIcon.setImageDrawable(appIcon) - appHomeRightIcon.layoutParams.width = - preferenceHelper.appTextSize.toInt() * 3 - appHomeRightIcon.layoutParams.height = - preferenceHelper.appTextSize.toInt() * 3 - appHomeRightIcon.visibility = View.VISIBLE + if (preferenceHelper.showAppIconAsDots) { + val appNewIcon: Drawable = ContextCompat.getDrawable(itemView.context, R.drawable.app_dot_icon)!! + + val bitmap = drawableToBitmap(appIcon) + val dominantColor = getDominantColor(bitmap) + val recoloredDrawable = recolorDrawable(appNewIcon, dominantColor) + + val appIconSize = (preferenceHelper.appTextSize * 1.1f).toInt() + appHomeDotsIcon.setImageDrawable(recoloredDrawable) + appHomeDotsIcon.layoutParams.width = appIconSize + appHomeDotsIcon.layoutParams.height = appIconSize + appHomeDotsIcon.visibility = View.VISIBLE + } else { + val appIconSize = (preferenceHelper.appTextSize * 2f).toInt() + when (preferenceHelper.homeAppAlignment) { + Gravity.START -> { + appHomeLeftIcon.setImageDrawable(appIcon) + appHomeLeftIcon.layoutParams.width = appIconSize + appHomeLeftIcon.layoutParams.height = appIconSize + appHomeLeftIcon.visibility = View.VISIBLE + } + + Gravity.END -> { + appHomeRightIcon.setImageDrawable(appIcon) + appHomeRightIcon.layoutParams.width = appIconSize + appHomeRightIcon.layoutParams.height = appIconSize + appHomeRightIcon.visibility = View.VISIBLE + } + + else -> { + appHomeLeftIcon.visibility = View.GONE + appHomeRightIcon.visibility = View.GONE + } } } + } else { + // Hide icons if app icon is not shown + appHomeLeftIcon.visibility = View.GONE + appHomeRightIcon.visibility = View.GONE + appHomeDotsIcon.visibility = View.GONE } } + itemView.setOnClickListener { onAppClickedListener.onAppClicked(appInfo) } @@ -71,4 +94,77 @@ class HomeViewHolder @Inject constructor( true } } + + private fun drawableToBitmap(drawable: Drawable): Bitmap { + if (drawable is BitmapDrawable) { + return drawable.bitmap + } + + val width = drawable.intrinsicWidth.coerceAtLeast(1) + val height = drawable.intrinsicHeight.coerceAtLeast(1) + + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + drawable.setBounds(0, 0, canvas.width, canvas.height) + drawable.draw(canvas) + + return bitmap + } + + private fun getDominantColor(bitmap: Bitmap): Int { + // Scale the bitmap to a manageable size + val scaledBitmap = Bitmap.createScaledBitmap( + bitmap, + min(bitmap.width / 4, 1280), + min(bitmap.height / 4, 1280), + true + ) + + // Generate a palette from the scaled bitmap + val palette = Palette.from(scaledBitmap) + .maximumColorCount(128) + .generate() + + // Extract the colors from the palette + val colors = palette.swatches.map { it.rgb } + + // Combine the colors into a single color + return increaseColorVibrancy(combineColors(colors)) + } + + private fun combineColors(colors: List): Int { + if (colors.isEmpty()) return Color.DKGRAY + + var red = 0 + var green = 0 + var blue = 0 + + // Calculate the average color values + for (color in colors) { + red += Color.red(color) + green += Color.green(color) + blue += Color.blue(color) + } + + val count = colors.size + return Color.rgb(red / count, green / count, blue / count) + } + + private fun increaseColorVibrancy(color: Int): Int { + // Convert RGB to HSL + val hsl = FloatArray(3) + ColorUtils.colorToHSL(color, hsl) + + // Increase the saturation + hsl[1] = (hsl[1] * 15f).coerceIn(0f, 1f) + + // Convert HSL back to RGB + return ColorUtils.HSLToColor(hsl) + } + + private fun recolorDrawable(drawable: Drawable, color: Int): Drawable { + val wrappedDrawable = DrawableCompat.wrap(drawable) + DrawableCompat.setTint(wrappedDrawable, color) + return wrappedDrawable + } } diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt index 20ffd72..711ed91 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt @@ -19,7 +19,6 @@ import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import com.github.droidworksstudio.common.getAppNameFromPackageName import com.github.droidworksstudio.common.resetDefaultLauncher -import com.github.droidworksstudio.launcher.utils.Constants import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.adapter.font.FontAdapter import com.github.droidworksstudio.launcher.databinding.FragmentSettingsBinding @@ -33,6 +32,7 @@ import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AlignmentBottom import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.ColorBottomSheetDialogFragment import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.PaddingBottomSheetDialogFragment import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.TextBottomSheetDialogFragment +import com.github.droidworksstudio.launcher.utils.Constants import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint @@ -137,6 +137,7 @@ class SettingsFragment : Fragment(), binding.batterySwitchCompat.isChecked = preferenceHelper.showBattery binding.dailyWordSwitchCompat.isChecked = preferenceHelper.showDailyWord binding.appIconsSwitchCompat.isChecked = preferenceHelper.showAppIcon + binding.appIconDotsSwitchCompat.isChecked = preferenceHelper.showAppIconAsDots binding.automaticKeyboardSwitchCompat.isChecked = preferenceHelper.automaticKeyboard binding.automaticOpenAppSwitchCompat.isChecked = preferenceHelper.automaticOpenApp binding.lockSettingsSwitchCompat.isChecked = preferenceHelper.settingsLock @@ -236,6 +237,14 @@ class SettingsFragment : Fragment(), binding.appIconsSwitchCompat.setOnCheckedChangeListener { _, isChecked -> preferenceViewModel.setShowAppIcons(isChecked) + + // Disable and gray out the other setting if appIconsSwitchCompat is checked + binding.appIconDotsSwitchCompat.isEnabled = isChecked + binding.appIconDotsSwitchCompat.isChecked = false + } + + binding.appIconDotsSwitchCompat.setOnCheckedChangeListener { _, isChecked -> + preferenceViewModel.setShowAppIconDots(isChecked) } binding.automaticKeyboardSwitchCompat.setOnCheckedChangeListener { _, isChecked -> diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt b/app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt index 0640fa6..38d3fb3 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt @@ -53,6 +53,7 @@ object Constants { const val APP_TEXT_PADDING = "APP_TEXT_PADDING" const val SHOW_APP_ICON = "SHOW_APP_ICON" + const val SHOW_APP_ICON_DOTS = "SHOW_APP_ICON_DOTS" const val AUTOMATIC_KEYBOARD = "AUTOMATIC_KEYBOARD" const val AUTOMATIC_OPEN_APP = "AUTOMATIC_OPEN_APP" diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt b/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt index b0fa4ca..088cbce 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt @@ -2,8 +2,8 @@ package com.github.droidworksstudio.launcher.viewmodel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.github.droidworksstudio.launcher.utils.Constants import com.github.droidworksstudio.launcher.helper.PreferenceHelper +import com.github.droidworksstudio.launcher.utils.Constants import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -22,6 +22,7 @@ class PreferenceViewModel @Inject constructor( private val showWeatherWidgetSunSetRiseLiveData: MutableLiveData = MutableLiveData() private val showBatteryWidgetLiveData: MutableLiveData = MutableLiveData() private val showAppIconLiveData: MutableLiveData = MutableLiveData() + private val showAppIconAsDotsLiveData: MutableLiveData = MutableLiveData() private val homeAppAlignmentLiveData: MutableLiveData = MutableLiveData() private val homeDateAlignmentLiveData: MutableLiveData = MutableLiveData() private val homeTimeAlignmentLiveData: MutableLiveData = MutableLiveData() @@ -88,6 +89,11 @@ class PreferenceViewModel @Inject constructor( showAppIconLiveData.postValue(preferenceHelper.showAppIcon) } + fun setShowAppIconDots(showAppIconAsDots: Boolean) { + preferenceHelper.showAppIconAsDots = showAppIconAsDots + showAppIconAsDotsLiveData.postValue(preferenceHelper.showAppIconAsDots) + } + fun setDailyWordColor(dailyWordColor: Int) { preferenceHelper.dailyWordColor = dailyWordColor dailyWordColorLiveData.postValue(preferenceHelper.dailyWordColor) diff --git a/app/src/main/res/drawable/app_dot_icon.xml b/app/src/main/res/drawable/app_dot_icon.xml new file mode 100644 index 0000000..f0ddf1c --- /dev/null +++ b/app/src/main/res/drawable/app_dot_icon.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 8298d5a..818af1c 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -8,14 +8,14 @@ + android:layout_height="match_parent" + android:layout_marginVertical="20dp" /> + android:textSize="@dimen/text_super_large" /> + android:textSize="@dimen/text_large" /> + android:textSize="@dimen/text_large" /> + android:textSize="@dimen/text_super_large" /> + tools:ignore="RtlHardcoded" /> @@ -128,12 +128,12 @@ tools:ignore="MissingConstraints"> + android:textSize="@dimen/text_super_large" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> + android:textSize="@dimen/text_super_large" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> + + + + + + + + + android:textSize="@dimen/text_super_large" /> + tools:ignore="RtlHardcoded" /> @@ -488,6 +520,7 @@ tools:ignore="MissingConstraints"> + tools:ignore="RtlHardcoded" /> @@ -576,6 +608,7 @@ + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> @@ -614,12 +646,12 @@ tools:ignore="MissingConstraints"> + android:textSize="@dimen/text_super_large" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> @@ -664,6 +696,7 @@ + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> @@ -697,6 +729,7 @@ + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> @@ -730,6 +762,7 @@ + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> @@ -763,6 +795,7 @@ + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> @@ -803,12 +835,12 @@ tools:ignore="MissingConstraints"> + android:textSize="@dimen/text_super_large" /> + tools:ignore="RtlHardcoded" /> + tools:ignore="RtlHardcoded" /> @@ -860,12 +892,12 @@ tools:ignore="MissingConstraints"> + android:textSize="@dimen/text_super_large" /> + android:textSize="@dimen/text_large" /> - - + android:text="@string/settings_backups_clear" + android:textSize="@dimen/text_large" /> + + @@ -920,50 +952,50 @@ tools:ignore="MissingConstraints"> + android:textSize="@dimen/text_super_large" /> + android:textSize="@dimen/text_large" /> - - + android:text="@string/settings_others_github" + android:textSize="@dimen/text_large" /> + + diff --git a/app/src/main/res/layout/item_home.xml b/app/src/main/res/layout/item_home.xml index 883b471..e4b6e13 100644 --- a/app/src/main/res/layout/item_home.xml +++ b/app/src/main/res/layout/item_home.xml @@ -2,51 +2,46 @@ + android:layout_height="wrap_content"> + + + android:layout_marginEnd="10dp" + android:visibility="gone" /> - - - - - + android:gravity="center" + android:textSize="24sp" /> + android:layout_marginStart="10dp" + android:visibility="gone" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f34a563..241e245 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -51,6 +51,7 @@ Show Battery Show Daily Word Show App Icons + Show App Icons As Dots Auto Show Keyboard Auto Open Last App Lock Settings diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7b35f68..fe202ed 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,6 +20,7 @@ biometric = "1.2.0-alpha05" color-chooser = "0.7.3" composeAndroid = "1.6.8" acra = "5.11.3" +paletteKtx = "1.0.0" [libraries] core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -58,6 +59,7 @@ androidx-ui-android = { group = "androidx.compose.ui", name = "ui-android", vers acra-core = { group = "ch.acra", name = "acra-core", version.ref = "acra" } acra-dialog = { group = "ch.acra", name = "acra-dialog", version.ref = "acra" } acra-mail = { group = "ch.acra", name = "acra-mail", version.ref = "acra" } +androidx-palette-ktx = { group = "androidx.palette", name = "palette-ktx", version.ref = "paletteKtx" } [plugins]