Skip to content

Commit 34f32ff

Browse files
Feat: Added app dot icons.
Signed-off-by: HeCodes2Much <wayne6324@gmail.com>
1 parent b11d909 commit 34f32ff

File tree

11 files changed

+319
-156
lines changed

11 files changed

+319
-156
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ dependencies {
183183
implementation(libs.acra.core)
184184
implementation(libs.acra.dialog)
185185
implementation(libs.acra.mail)
186+
implementation(libs.androidx.palette.ktx)
186187

187188
//noinspection KaptUsageInsteadOfKsp
188189
kapt(libs.room.compiler)

app/src/main/java/com/github/droidworksstudio/launcher/helper/PreferenceHelper.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ class PreferenceHelper @Inject constructor(@ApplicationContext context: Context)
8787
get() = prefs.getBoolean(Constants.SHOW_APP_ICON, false)
8888
set(value) = prefs.edit().putBoolean(Constants.SHOW_APP_ICON, value).apply()
8989

90+
var showAppIconAsDots: Boolean
91+
get() = prefs.getBoolean(Constants.SHOW_APP_ICON_DOTS, true)
92+
set(value) = prefs.edit().putBoolean(Constants.SHOW_APP_ICON_DOTS, value).apply()
93+
9094
var locationDenied: Boolean
9195
get() = prefs.getBoolean(Constants.LOCATION_DENIED, false)
9296
set(value) = prefs.edit().putBoolean(Constants.LOCATION_DENIED, value).apply()

app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt

Lines changed: 124 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@ package com.github.droidworksstudio.launcher.ui.home
22

33
import android.annotation.SuppressLint
44
import android.content.pm.PackageManager
5-
import android.util.Log
5+
import android.graphics.Bitmap
6+
import android.graphics.Canvas
7+
import android.graphics.Color
8+
import android.graphics.drawable.BitmapDrawable
9+
import android.graphics.drawable.Drawable
610
import android.view.Gravity
711
import android.view.View
8-
import androidx.appcompat.widget.LinearLayoutCompat
12+
import androidx.core.content.ContextCompat
13+
import androidx.core.graphics.ColorUtils
14+
import androidx.core.graphics.drawable.DrawableCompat
15+
import androidx.palette.graphics.Palette
916
import androidx.recyclerview.widget.RecyclerView
17+
import com.github.droidworksstudio.launcher.R
1018
import com.github.droidworksstudio.launcher.data.entities.AppInfo
1119
import com.github.droidworksstudio.launcher.databinding.ItemHomeBinding
1220
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
1321
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
1422
import javax.inject.Inject
23+
import kotlin.math.min
1524

1625
class HomeViewHolder @Inject constructor(
1726
private val binding: ItemHomeBinding,
@@ -22,46 +31,60 @@ class HomeViewHolder @Inject constructor(
2231
@SuppressLint("ClickableViewAccessibility")
2332
fun bind(appInfo: AppInfo) {
2433
binding.apply {
25-
// Get the current LayoutParams of appHomeName
26-
val layoutParams = appHomeName.layoutParams as LinearLayoutCompat.LayoutParams
27-
28-
// Set the margins
29-
layoutParams.topMargin = preferenceHelper.homeAppPadding.toInt()
30-
layoutParams.bottomMargin = preferenceHelper.homeAppPadding.toInt()
31-
32-
appHomeName.layoutParams = layoutParams
34+
// Update appHomeName properties
3335
appHomeName.text = appInfo.appName
3436
appHomeName.setTextColor(preferenceHelper.appColor)
3537
appHomeName.textSize = preferenceHelper.appTextSize
3638
appHomeName.gravity = preferenceHelper.homeAppAlignment
37-
Log.d("Tag", "Home Adapter Color: ${preferenceHelper.appColor}")
3839

3940
if (preferenceHelper.showAppIcon) {
4041
val pm: PackageManager = binding.root.context.packageManager
41-
4242
val appIcon = pm.getApplicationIcon(appInfo.packageName)
43-
when (preferenceHelper.homeAppAlignment) {
44-
Gravity.START -> {
45-
appHomeLeftIcon.setImageDrawable(appIcon)
46-
appHomeLeftIcon.layoutParams.width =
47-
preferenceHelper.appTextSize.toInt() * 3
48-
appHomeLeftIcon.layoutParams.height =
49-
preferenceHelper.appTextSize.toInt() * 3
50-
appHomeLeftIcon.visibility = View.VISIBLE
51-
}
5243

53-
Gravity.END -> {
54-
appHomeRightIcon.setImageDrawable(appIcon)
55-
appHomeRightIcon.layoutParams.width =
56-
preferenceHelper.appTextSize.toInt() * 3
57-
appHomeRightIcon.layoutParams.height =
58-
preferenceHelper.appTextSize.toInt() * 3
59-
appHomeRightIcon.visibility = View.VISIBLE
44+
if (preferenceHelper.showAppIconAsDots) {
45+
val appNewIcon: Drawable = ContextCompat.getDrawable(itemView.context, R.drawable.app_dot_icon)!!
46+
47+
val bitmap = drawableToBitmap(appIcon)
48+
val dominantColor = getDominantColor(bitmap)
49+
val recoloredDrawable = recolorDrawable(appNewIcon, dominantColor)
50+
51+
val appIconSize = (preferenceHelper.appTextSize * 1.1f).toInt()
52+
appHomeDotsIcon.setImageDrawable(recoloredDrawable)
53+
appHomeDotsIcon.layoutParams.width = appIconSize
54+
appHomeDotsIcon.layoutParams.height = appIconSize
55+
appHomeDotsIcon.visibility = View.VISIBLE
56+
} else {
57+
val appIconSize = (preferenceHelper.appTextSize * 2f).toInt()
58+
when (preferenceHelper.homeAppAlignment) {
59+
Gravity.START -> {
60+
appHomeLeftIcon.setImageDrawable(appIcon)
61+
appHomeLeftIcon.layoutParams.width = appIconSize
62+
appHomeLeftIcon.layoutParams.height = appIconSize
63+
appHomeLeftIcon.visibility = View.VISIBLE
64+
}
65+
66+
Gravity.END -> {
67+
appHomeRightIcon.setImageDrawable(appIcon)
68+
appHomeRightIcon.layoutParams.width = appIconSize
69+
appHomeRightIcon.layoutParams.height = appIconSize
70+
appHomeRightIcon.visibility = View.VISIBLE
71+
}
72+
73+
else -> {
74+
appHomeLeftIcon.visibility = View.GONE
75+
appHomeRightIcon.visibility = View.GONE
76+
}
6077
}
6178
}
79+
} else {
80+
// Hide icons if app icon is not shown
81+
appHomeLeftIcon.visibility = View.GONE
82+
appHomeRightIcon.visibility = View.GONE
83+
appHomeDotsIcon.visibility = View.GONE
6284
}
6385
}
6486

87+
6588
itemView.setOnClickListener {
6689
onAppClickedListener.onAppClicked(appInfo)
6790
}
@@ -71,4 +94,77 @@ class HomeViewHolder @Inject constructor(
7194
true
7295
}
7396
}
97+
98+
private fun drawableToBitmap(drawable: Drawable): Bitmap {
99+
if (drawable is BitmapDrawable) {
100+
return drawable.bitmap
101+
}
102+
103+
val width = drawable.intrinsicWidth.coerceAtLeast(1)
104+
val height = drawable.intrinsicHeight.coerceAtLeast(1)
105+
106+
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
107+
val canvas = Canvas(bitmap)
108+
drawable.setBounds(0, 0, canvas.width, canvas.height)
109+
drawable.draw(canvas)
110+
111+
return bitmap
112+
}
113+
114+
private fun getDominantColor(bitmap: Bitmap): Int {
115+
// Scale the bitmap to a manageable size
116+
val scaledBitmap = Bitmap.createScaledBitmap(
117+
bitmap,
118+
min(bitmap.width / 4, 1280),
119+
min(bitmap.height / 4, 1280),
120+
true
121+
)
122+
123+
// Generate a palette from the scaled bitmap
124+
val palette = Palette.from(scaledBitmap)
125+
.maximumColorCount(128)
126+
.generate()
127+
128+
// Extract the colors from the palette
129+
val colors = palette.swatches.map { it.rgb }
130+
131+
// Combine the colors into a single color
132+
return increaseColorVibrancy(combineColors(colors))
133+
}
134+
135+
private fun combineColors(colors: List<Int>): Int {
136+
if (colors.isEmpty()) return Color.DKGRAY
137+
138+
var red = 0
139+
var green = 0
140+
var blue = 0
141+
142+
// Calculate the average color values
143+
for (color in colors) {
144+
red += Color.red(color)
145+
green += Color.green(color)
146+
blue += Color.blue(color)
147+
}
148+
149+
val count = colors.size
150+
return Color.rgb(red / count, green / count, blue / count)
151+
}
152+
153+
private fun increaseColorVibrancy(color: Int): Int {
154+
// Convert RGB to HSL
155+
val hsl = FloatArray(3)
156+
ColorUtils.colorToHSL(color, hsl)
157+
158+
// Increase the saturation
159+
hsl[1] = (hsl[1] * 15f).coerceIn(0f, 1f)
160+
161+
// Convert HSL back to RGB
162+
return ColorUtils.HSLToColor(hsl)
163+
}
164+
165+
private fun recolorDrawable(drawable: Drawable, color: Int): Drawable {
166+
val wrappedDrawable = DrawableCompat.wrap(drawable)
167+
DrawableCompat.setTint(wrappedDrawable, color)
168+
return wrappedDrawable
169+
}
74170
}

app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import androidx.navigation.NavController
1919
import androidx.navigation.fragment.findNavController
2020
import com.github.droidworksstudio.common.getAppNameFromPackageName
2121
import com.github.droidworksstudio.common.resetDefaultLauncher
22-
import com.github.droidworksstudio.launcher.utils.Constants
2322
import com.github.droidworksstudio.launcher.R
2423
import com.github.droidworksstudio.launcher.adapter.font.FontAdapter
2524
import com.github.droidworksstudio.launcher.databinding.FragmentSettingsBinding
@@ -33,6 +32,7 @@ import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AlignmentBottom
3332
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.ColorBottomSheetDialogFragment
3433
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.PaddingBottomSheetDialogFragment
3534
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.TextBottomSheetDialogFragment
35+
import com.github.droidworksstudio.launcher.utils.Constants
3636
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
3737
import com.google.android.material.dialog.MaterialAlertDialogBuilder
3838
import dagger.hilt.android.AndroidEntryPoint
@@ -137,6 +137,7 @@ class SettingsFragment : Fragment(),
137137
binding.batterySwitchCompat.isChecked = preferenceHelper.showBattery
138138
binding.dailyWordSwitchCompat.isChecked = preferenceHelper.showDailyWord
139139
binding.appIconsSwitchCompat.isChecked = preferenceHelper.showAppIcon
140+
binding.appIconDotsSwitchCompat.isChecked = preferenceHelper.showAppIconAsDots
140141
binding.automaticKeyboardSwitchCompat.isChecked = preferenceHelper.automaticKeyboard
141142
binding.automaticOpenAppSwitchCompat.isChecked = preferenceHelper.automaticOpenApp
142143
binding.lockSettingsSwitchCompat.isChecked = preferenceHelper.settingsLock
@@ -236,6 +237,14 @@ class SettingsFragment : Fragment(),
236237

237238
binding.appIconsSwitchCompat.setOnCheckedChangeListener { _, isChecked ->
238239
preferenceViewModel.setShowAppIcons(isChecked)
240+
241+
// Disable and gray out the other setting if appIconsSwitchCompat is checked
242+
binding.appIconDotsSwitchCompat.isEnabled = isChecked
243+
binding.appIconDotsSwitchCompat.isChecked = false
244+
}
245+
246+
binding.appIconDotsSwitchCompat.setOnCheckedChangeListener { _, isChecked ->
247+
preferenceViewModel.setShowAppIconDots(isChecked)
239248
}
240249

241250
binding.automaticKeyboardSwitchCompat.setOnCheckedChangeListener { _, isChecked ->

app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ object Constants {
5353
const val APP_TEXT_PADDING = "APP_TEXT_PADDING"
5454

5555
const val SHOW_APP_ICON = "SHOW_APP_ICON"
56+
const val SHOW_APP_ICON_DOTS = "SHOW_APP_ICON_DOTS"
5657

5758
const val AUTOMATIC_KEYBOARD = "AUTOMATIC_KEYBOARD"
5859
const val AUTOMATIC_OPEN_APP = "AUTOMATIC_OPEN_APP"

app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package com.github.droidworksstudio.launcher.viewmodel
22

33
import androidx.lifecycle.MutableLiveData
44
import androidx.lifecycle.ViewModel
5-
import com.github.droidworksstudio.launcher.utils.Constants
65
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
6+
import com.github.droidworksstudio.launcher.utils.Constants
77
import dagger.hilt.android.lifecycle.HiltViewModel
88
import javax.inject.Inject
99

@@ -22,6 +22,7 @@ class PreferenceViewModel @Inject constructor(
2222
private val showWeatherWidgetSunSetRiseLiveData: MutableLiveData<Boolean> = MutableLiveData()
2323
private val showBatteryWidgetLiveData: MutableLiveData<Boolean> = MutableLiveData()
2424
private val showAppIconLiveData: MutableLiveData<Boolean> = MutableLiveData()
25+
private val showAppIconAsDotsLiveData: MutableLiveData<Boolean> = MutableLiveData()
2526
private val homeAppAlignmentLiveData: MutableLiveData<Int> = MutableLiveData()
2627
private val homeDateAlignmentLiveData: MutableLiveData<Int> = MutableLiveData()
2728
private val homeTimeAlignmentLiveData: MutableLiveData<Int> = MutableLiveData()
@@ -88,6 +89,11 @@ class PreferenceViewModel @Inject constructor(
8889
showAppIconLiveData.postValue(preferenceHelper.showAppIcon)
8990
}
9091

92+
fun setShowAppIconDots(showAppIconAsDots: Boolean) {
93+
preferenceHelper.showAppIconAsDots = showAppIconAsDots
94+
showAppIconAsDotsLiveData.postValue(preferenceHelper.showAppIconAsDots)
95+
}
96+
9197
fun setDailyWordColor(dailyWordColor: Int) {
9298
preferenceHelper.dailyWordColor = dailyWordColor
9399
dailyWordColorLiveData.postValue(preferenceHelper.dailyWordColor)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="50dp"
3+
android:height="50dp"
4+
android:autoMirrored="true"
5+
android:viewportWidth="50"
6+
android:viewportHeight="50">
7+
<path
8+
android:fillColor="#FFFFFFFF"
9+
android:pathData="M47.693,25.859c-0.314,1.046 -0.837,2.616 -1.57,3.872c-1.988,3.453 -5.546,5.755 -9.313,5.755c-4.081,0 -7.929,-1.807 -10.755,-3.586c-2.114,-1.331 -4.197,-1.9 -6.088,-1.9c-3.164,0 -5.787,1.596 -7.097,3.889c-2.198,3.767 0,9.627 3.977,11.93C19.004,47.085 22.02,48 24.655,48c7.595,0 16.171,-4.758 19.899,-11.362C46.542,33.289 47.589,29.522 47.693,25.859L47.693,25.859z" />
10+
<path
11+
android:fillColor="#FFFFFFFF"
12+
android:pathData="M15.825,6C14.134,6 12.426,6.387 11,7.137C5.348,10.134 2.077,17.853 2,25c-0.041,3.837 0.757,7.657 2.475,10.8c1.884,3.558 4.5,6.383 7.534,8.372c-0.733,-0.733 -1.779,-2.093 -2.511,-3.349c-1.988,-3.558 -1.779,-7.639 0,-10.988c1.884,-3.558 5.479,-5.955 8.409,-7.525c7.011,-3.663 6.802,-8.79 5.128,-12.453C21.827,7.24 18.853,6 15.825,6L15.825,6z" />
13+
<path
14+
android:fillColor="#FFFFFFFF"
15+
android:pathData="M24.671,2c-3.977,0.105 -7.744,1.046 -10.883,2.825c1.046,-0.419 2.721,-0.733 4.186,-0.733c0.103,-0.003 0.205,-0.004 0.307,-0.004c3.958,0 7.487,1.969 9.425,5.132C29.799,12.569 30,16.651 30,20c0,7.953 4.299,10 8.485,10c4.5,0 8.515,-4.769 8.515,-9.268C46.895,10.999 34.927,2 24.671,2L24.671,2z" />
16+
</vector>

0 commit comments

Comments
 (0)