From b3d49a94b348fc27f5eb53a6db3f812416b30d4c Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 8 Feb 2025 11:40:49 +0100 Subject: [PATCH] feat: support for changing widget text color (closes #364) --- .../clock/domain/model/ClockWidgetOptions.kt | 6 ++ .../presentation/widgets/ClockWidgetConfig.kt | 94 ++++++++++++++++++- .../widgets/DigitalClockWidget.kt | 12 ++- .../widgets/DigitalClockWidgetConfig.kt | 5 +- .../widgets/VerticalClockWidget.kt | 16 +++- .../widgets/VerticalClockWidgetConfig.kt | 5 +- .../clock/util/widgets/TextClockWIdget.kt | 20 ++++ .../com/bnyro/clock/util/widgets/TextColor.kt | 16 ++++ .../clock/util/widgets/WidgetPreferences.kt | 2 + app/src/main/res/values/strings.xml | 2 + 10 files changed, 165 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/com/bnyro/clock/util/widgets/TextColor.kt diff --git a/app/src/main/java/com/bnyro/clock/domain/model/ClockWidgetOptions.kt b/app/src/main/java/com/bnyro/clock/domain/model/ClockWidgetOptions.kt index 33fee00d..9562f1f0 100644 --- a/app/src/main/java/com/bnyro/clock/domain/model/ClockWidgetOptions.kt +++ b/app/src/main/java/com/bnyro/clock/domain/model/ClockWidgetOptions.kt @@ -1,5 +1,7 @@ package com.bnyro.clock.domain.model +import com.bnyro.clock.util.widgets.TextColor + data class ClockWidgetOptions( var showDate: Boolean = true, var showTime: Boolean = true, @@ -8,6 +10,8 @@ data class ClockWidgetOptions( var showBackground: Boolean = true, var dateTextSize: Float, var timeTextSize: Float, + var timeColor: TextColor = TextColor.Primary, + var dateColor: TextColor = TextColor.Secondary ) { companion object { val dateSizeOptions = listOf( @@ -38,5 +42,7 @@ data class ClockWidgetOptions( 96f, 100f ) + + val textColorOptions = TextColor.entries.toList() } } \ No newline at end of file diff --git a/app/src/main/java/com/bnyro/clock/presentation/widgets/ClockWidgetConfig.kt b/app/src/main/java/com/bnyro/clock/presentation/widgets/ClockWidgetConfig.kt index 6d25bf53..ceaacc61 100644 --- a/app/src/main/java/com/bnyro/clock/presentation/widgets/ClockWidgetConfig.kt +++ b/app/src/main/java/com/bnyro/clock/presentation/widgets/ClockWidgetConfig.kt @@ -2,6 +2,7 @@ package com.bnyro.clock.presentation.widgets import android.app.Activity import android.appwidget.AppWidgetManager +import android.content.Context import android.content.Intent import android.os.Bundle import android.widget.RemoteViews @@ -13,14 +14,21 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.rounded.CalendarToday import androidx.compose.material.icons.rounded.ExpandMore import androidx.compose.material.icons.rounded.FormatSize @@ -35,6 +43,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf @@ -44,6 +53,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -57,6 +68,8 @@ import com.bnyro.clock.presentation.screens.clock.model.ClockModel import com.bnyro.clock.presentation.screens.settings.model.SettingsModel import com.bnyro.clock.ui.theme.ClockYouTheme import com.bnyro.clock.util.ThemeUtil +import com.bnyro.clock.util.widgets.TextColor +import com.bnyro.clock.util.widgets.getColorValue import com.bnyro.clock.util.widgets.loadClockWidgetSettings import com.bnyro.clock.util.widgets.saveClockWidgetSettings @@ -64,6 +77,7 @@ import com.bnyro.clock.util.widgets.saveClockWidgetSettings abstract class ClockWidgetConfig : ComponentActivity() { abstract val defaultOptions: ClockWidgetOptions + @get:LayoutRes abstract val widgetLayoutResource: Int @@ -100,6 +114,7 @@ abstract class ClockWidgetConfig : ComponentActivity() { darkTheme ) ) { + val context = LocalContext.current Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background @@ -109,20 +124,22 @@ abstract class ClockWidgetConfig : ComponentActivity() { }) { pV -> DigitalClockWidgetSettings( modifier = Modifier.padding(pV), - options = options, onComplete = this::complete - ) + options = options + ) { + complete(context, options) + } } } } } } - private fun complete(options: ClockWidgetOptions) { + private fun complete(context: Context, options: ClockWidgetOptions) { saveClockWidgetSettings(appWidgetId, options) val appWidgetManager = AppWidgetManager.getInstance(this) val views = RemoteViews(packageName, widgetLayoutResource) - updateClockWidget(views, options) + updateClockWidget(context, views, options) appWidgetManager.updateAppWidget(appWidgetId, views) // return the result @@ -131,7 +148,11 @@ abstract class ClockWidgetConfig : ComponentActivity() { finish() } - abstract fun updateClockWidget(views: RemoteViews, options: ClockWidgetOptions) + abstract fun updateClockWidget( + context: Context, + views: RemoteViews, + options: ClockWidgetOptions + ) } @Composable @@ -153,6 +174,9 @@ fun DigitalClockWidgetSettings( var showBackgroundOption by remember { mutableStateOf(options.showBackground) } var selectedDateSize by remember { mutableFloatStateOf(options.dateTextSize) } var selectedTimeSize by remember { mutableFloatStateOf(options.timeTextSize) } + var selectedTimeColor by remember { mutableStateOf(options.timeColor) } + var selectedDateColor by remember { mutableStateOf(options.dateColor) } + Column( modifier = modifier.padding(8.dp), horizontalAlignment = Alignment.CenterHorizontally, @@ -194,6 +218,20 @@ fun DigitalClockWidgetSettings( ) { selectedTimeSize = it } + ColorSelectSetting( + label = stringResource(R.string.date_text_color), + availableColors = ClockWidgetOptions.textColorOptions, + currentColor = selectedDateColor + ) { + selectedDateColor = it + } + ColorSelectSetting( + label = stringResource(R.string.time_text_color), + availableColors = ClockWidgetOptions.textColorOptions, + currentColor = selectedTimeColor + ) { + selectedTimeColor = it + } SwitchWithDivider( title = stringResource(R.string.timezone), description = stringResource(R.string.use_a_different_time_zone_for_the_widget), @@ -219,6 +257,8 @@ fun DigitalClockWidgetSettings( showTime = showTimeOption dateTextSize = selectedDateSize timeTextSize = selectedTimeSize + dateColor = selectedDateColor + timeColor = selectedTimeColor timeZone = customTimeZone timeZoneName = customTimeZoneName showBackground = showBackgroundOption @@ -314,6 +354,50 @@ fun TextSizeSelectSetting( } } +@Composable +fun ColorSelectSetting( + label: String, + availableColors: List, + currentColor: TextColor, + onColorSelected: (TextColor) -> Unit +) { + val context = LocalContext.current + + Column( + Modifier.padding(horizontal = 12.dp, vertical = 8.dp) + ) { + Text(label) + Spacer(modifier = Modifier.height(6.dp)) + LazyRow( + verticalAlignment = Alignment.CenterVertically + ) { + items(availableColors) { textColor -> + val colorValue = Color(textColor.getColorValue(context)) + + Box( + modifier = Modifier + .padding(horizontal = 8.dp) + .clip(CircleShape) + .size(36.dp) + .background(colorValue) + .clickable { + onColorSelected(textColor) + } + ) { + if (currentColor == textColor) { + Icon( + modifier = Modifier.align(Alignment.Center), + imageVector = Icons.Default.Check, + contentDescription = null, + tint = MaterialTheme.colorScheme.contentColorFor(colorValue) + ) + } + } + } + } + } +} + @Preview(showBackground = true) @Composable fun DefaultPreview() { diff --git a/app/src/main/java/com/bnyro/clock/presentation/widgets/DigitalClockWidget.kt b/app/src/main/java/com/bnyro/clock/presentation/widgets/DigitalClockWidget.kt index 75f6d884..315b0556 100644 --- a/app/src/main/java/com/bnyro/clock/presentation/widgets/DigitalClockWidget.kt +++ b/app/src/main/java/com/bnyro/clock/presentation/widgets/DigitalClockWidget.kt @@ -6,6 +6,7 @@ import android.view.View import android.widget.RemoteViews import com.bnyro.clock.R import com.bnyro.clock.domain.model.ClockWidgetOptions +import com.bnyro.clock.util.widgets.getColorValue import com.bnyro.clock.util.widgets.loadClockWidgetSettings class DigitalClockWidget : TextWidgetProvider() { @@ -13,7 +14,7 @@ class DigitalClockWidget : TextWidgetProvider() { override fun applyClockWidgetOptions(context: Context, appWidgetId: Int, views: RemoteViews) { val options = context.loadClockWidgetSettings(appWidgetId, DefaultConfig) - views.applyDigitalClockWidgetOptions(options) + views.applyDigitalClockWidgetOptions(context, options) } companion object { @@ -23,6 +24,7 @@ class DigitalClockWidget : TextWidgetProvider() { ) fun RemoteViews.applyDigitalClockWidgetOptions( + context: Context, options: ClockWidgetOptions ) { val dateVisibility = when (options.showDate) { @@ -53,6 +55,14 @@ class DigitalClockWidget : TextWidgetProvider() { setString(R.id.textClock, "setTimeZone", options.timeZone) setString(R.id.textClock2, "setTimeZone", options.timeZone) + val timeColor = options.timeColor.getColorValue(context) + val dateColor = options.dateColor.getColorValue(context) + if (timeColor != -1 && dateColor != -1) { + setTextColor(R.id.textClock, dateColor) + setTextColor(R.id.cityName, dateColor) + setTextColor(R.id.textClock2, timeColor) + } + setInt(R.id.frameLayout, "setBackgroundResource", backgroundResource) setViewVisibility(R.id.cityName, timeZoneVisibility) diff --git a/app/src/main/java/com/bnyro/clock/presentation/widgets/DigitalClockWidgetConfig.kt b/app/src/main/java/com/bnyro/clock/presentation/widgets/DigitalClockWidgetConfig.kt index ef1c490f..9d26265d 100644 --- a/app/src/main/java/com/bnyro/clock/presentation/widgets/DigitalClockWidgetConfig.kt +++ b/app/src/main/java/com/bnyro/clock/presentation/widgets/DigitalClockWidgetConfig.kt @@ -1,5 +1,6 @@ package com.bnyro.clock.presentation.widgets +import android.content.Context import android.widget.RemoteViews import com.bnyro.clock.R import com.bnyro.clock.domain.model.ClockWidgetOptions @@ -9,7 +10,7 @@ class DigitalClockWidgetConfig: ClockWidgetConfig() { override val defaultOptions: ClockWidgetOptions = DigitalClockWidget.DefaultConfig override val widgetLayoutResource: Int = R.layout.digital_clock - override fun updateClockWidget(views: RemoteViews, options: ClockWidgetOptions) { - views.applyDigitalClockWidgetOptions(options) + override fun updateClockWidget(context: Context, views: RemoteViews, options: ClockWidgetOptions) { + views.applyDigitalClockWidgetOptions(context, options) } } \ No newline at end of file diff --git a/app/src/main/java/com/bnyro/clock/presentation/widgets/VerticalClockWidget.kt b/app/src/main/java/com/bnyro/clock/presentation/widgets/VerticalClockWidget.kt index 357f4bc9..533005a1 100644 --- a/app/src/main/java/com/bnyro/clock/presentation/widgets/VerticalClockWidget.kt +++ b/app/src/main/java/com/bnyro/clock/presentation/widgets/VerticalClockWidget.kt @@ -6,7 +6,7 @@ import android.view.View import android.widget.RemoteViews import com.bnyro.clock.R import com.bnyro.clock.domain.model.ClockWidgetOptions -import com.bnyro.clock.presentation.widgets.DigitalClockWidget.Companion.applyDigitalClockWidgetOptions +import com.bnyro.clock.util.widgets.getColorValue import com.bnyro.clock.util.widgets.loadClockWidgetSettings class VerticalClockWidget : TextWidgetProvider() { @@ -14,7 +14,7 @@ class VerticalClockWidget : TextWidgetProvider() { override fun applyClockWidgetOptions(context: Context, appWidgetId: Int, views: RemoteViews) { val options = context.loadClockWidgetSettings(appWidgetId, DefaultConfig) - views.applyDigitalClockWidgetOptions(options) + views.applyVerticalClockWidgetOptions(context, options) } companion object { @@ -24,6 +24,7 @@ class VerticalClockWidget : TextWidgetProvider() { ) fun RemoteViews.applyVerticalClockWidgetOptions( + context: Context, options: ClockWidgetOptions ) { val dateVisibility = when (options.showDate) { @@ -51,12 +52,21 @@ class VerticalClockWidget : TextWidgetProvider() { setTextViewTextSize(R.id.textClockDate, TypedValue.COMPLEX_UNIT_SP, options.dateTextSize) setTextViewTextSize(R.id.textClockHours, TypedValue.COMPLEX_UNIT_SP, options.timeTextSize) setTextViewTextSize(R.id.textClockMinutes, TypedValue.COMPLEX_UNIT_SP, options.timeTextSize) - setTextViewTextSize(R.id.cityName, TypedValue.COMPLEX_UNIT_SP, options.dateTextSize - 4) + setTextViewTextSize(R.id.cityName, TypedValue.COMPLEX_UNIT_SP, options.dateTextSize) setString(R.id.textClockHours, "setTimeZone", options.timeZone) setString(R.id.textClockMinutes, "setTimeZone", options.timeZone) setString(R.id.textClockDate, "setTimeZone", options.timeZone) + val timeColor = options.timeColor.getColorValue(context) + val dateColor = options.dateColor.getColorValue(context) + if (timeColor != -1 && dateColor != -1) { + setTextColor(R.id.textClockHours, timeColor) + setTextColor(R.id.textClockMinutes, timeColor) + setTextColor(R.id.textClockDate, dateColor) + setTextColor(R.id.cityName, dateColor) + } + setInt(R.id.frameLayout, "setBackgroundResource", backgroundResource) setViewVisibility(R.id.cityName, timeZoneVisibility) diff --git a/app/src/main/java/com/bnyro/clock/presentation/widgets/VerticalClockWidgetConfig.kt b/app/src/main/java/com/bnyro/clock/presentation/widgets/VerticalClockWidgetConfig.kt index 7c640c51..ef8480b8 100644 --- a/app/src/main/java/com/bnyro/clock/presentation/widgets/VerticalClockWidgetConfig.kt +++ b/app/src/main/java/com/bnyro/clock/presentation/widgets/VerticalClockWidgetConfig.kt @@ -1,5 +1,6 @@ package com.bnyro.clock.presentation.widgets +import android.content.Context import android.widget.RemoteViews import com.bnyro.clock.R import com.bnyro.clock.domain.model.ClockWidgetOptions @@ -9,7 +10,7 @@ class VerticalClockWidgetConfig: ClockWidgetConfig() { override val defaultOptions: ClockWidgetOptions = VerticalClockWidget.DefaultConfig override val widgetLayoutResource: Int = R.layout.vertical_clock - override fun updateClockWidget(views: RemoteViews, options: ClockWidgetOptions) { - views.applyVerticalClockWidgetOptions(options) + override fun updateClockWidget(context: Context, views: RemoteViews, options: ClockWidgetOptions) { + views.applyVerticalClockWidgetOptions(context, options) } } \ No newline at end of file diff --git a/app/src/main/java/com/bnyro/clock/util/widgets/TextClockWIdget.kt b/app/src/main/java/com/bnyro/clock/util/widgets/TextClockWIdget.kt index 03482d6b..1fade8ae 100644 --- a/app/src/main/java/com/bnyro/clock/util/widgets/TextClockWIdget.kt +++ b/app/src/main/java/com/bnyro/clock/util/widgets/TextClockWIdget.kt @@ -15,6 +15,8 @@ fun Context.saveClockWidgetSettings( putString(PREF_TIME_ZONE + appWidgetId, options.timeZone) putString(PREF_TIME_ZONE_NAME + appWidgetId, options.timeZoneName) putBoolean(PREF_SHOW_BACKGROUND + appWidgetId, options.showBackground) + putInt(PREF_DATE_TEXT_COLOR + appWidgetId, options.dateColor.attrInt) + putInt(PREF_TIME_TEXT_COLOR + appWidgetId, options.timeColor.attrInt) } fun Context.loadClockWidgetSettings( @@ -53,11 +55,27 @@ fun Context.loadClockWidgetSettings( defaultClockWidgetOptions.showBackground ) + val dateColor = getInt( + PREF_DATE_TEXT_COLOR + appWidgetId, + defaultClockWidgetOptions.dateColor.attrInt + ).let { attrInt -> + ClockWidgetOptions.textColorOptions.find { it.attrInt == attrInt } + } ?: defaultClockWidgetOptions.dateColor + + val timeColor = getInt( + PREF_TIME_TEXT_COLOR + appWidgetId, + defaultClockWidgetOptions.timeColor.attrInt + ).let { attrInt -> + ClockWidgetOptions.textColorOptions.find { it.attrInt == attrInt } + } ?: defaultClockWidgetOptions.timeColor + return ClockWidgetOptions( showDate = showDate, showTime = showTime, dateTextSize = dateTextSize, timeTextSize = timeTextSize, + dateColor = dateColor, + timeColor = timeColor, timeZone = timeZone, timeZoneName = timeZoneName, showBackground = showBackground @@ -73,4 +91,6 @@ fun Context.deleteClockWidgetPref(appWidgetId: Int) = remove(PREF_TIME_TEXT_SIZE + appWidgetId) remove(PREF_TIME_ZONE + appWidgetId) remove(PREF_TIME_ZONE_NAME + appWidgetId) + remove(PREF_DATE_TEXT_COLOR + appWidgetId) + remove(PREF_TIME_TEXT_COLOR + appWidgetId) } diff --git a/app/src/main/java/com/bnyro/clock/util/widgets/TextColor.kt b/app/src/main/java/com/bnyro/clock/util/widgets/TextColor.kt new file mode 100644 index 00000000..b7a92815 --- /dev/null +++ b/app/src/main/java/com/bnyro/clock/util/widgets/TextColor.kt @@ -0,0 +1,16 @@ +package com.bnyro.clock.util.widgets + +import android.content.Context +import com.google.android.material.color.MaterialColors + +enum class TextColor(val attrInt: Int) { + Primary(com.google.android.material.R.attr.colorPrimary), + PrimaryDark(com.google.android.material.R.attr.colorPrimaryDark), + Secondary(com.google.android.material.R.attr.colorSecondary), + SecondaryVariant(com.google.android.material.R.attr.colorSecondaryVariant), + Tertiary(com.google.android.material.R.attr.colorTertiary) +} + +fun TextColor.getColorValue(context: Context): Int { + return MaterialColors.getColor(context, this.attrInt, -1) +} \ No newline at end of file diff --git a/app/src/main/java/com/bnyro/clock/util/widgets/WidgetPreferences.kt b/app/src/main/java/com/bnyro/clock/util/widgets/WidgetPreferences.kt index 036eb25c..404df37a 100644 --- a/app/src/main/java/com/bnyro/clock/util/widgets/WidgetPreferences.kt +++ b/app/src/main/java/com/bnyro/clock/util/widgets/WidgetPreferences.kt @@ -15,6 +15,8 @@ internal const val PREF_DATE_TEXT_SIZE = "dateTextSize:" internal const val PREF_TIME_TEXT_SIZE = "timeTextSize:" internal const val PREF_TIME_ZONE = "timeZone:" internal const val PREF_TIME_ZONE_NAME = "timeZoneName:" +internal const val PREF_TIME_TEXT_COLOR = "timeTextColor:" +internal const val PREF_DATE_TEXT_COLOR = "dateTextColor:" // Analog Clock widget internal const val PREF_CLOCK_HOUR_HAND = "analogClockHour:" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4f363e3c..9db9acc3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -135,4 +135,6 @@ Snooze %d minutes Add %d minutes Subtract %d minutes + Date text color + Time text color \ No newline at end of file