Compare commits

...
Author SHA1 Message Date
makiolaj 14c10c6d0b 2.24.0-beta.2
Beta — Codeberg pre-release / detect (push) Successful in 5s
Beta — Codeberg pre-release / beta (push) Successful in 10m9s
2026-10-28 15:35:38 +01:00
Jean-Luc Makiolaandmakiolaj f5e28eae8d Widget fixes and tweaks from the 2.24 beta feedback (#449)
Beta — Codeberg pre-release / detect (push) Successful in 5s
Beta — Codeberg pre-release / beta (push) Skipped
Feedback on 2.24.0-beta.1 from #90, #376 and #71. floret-kit is pinned to its main after floret-kit#24, which carries the shared parts.

- Transparent background: switching to or from it now shows right away on Date, Countdown, Week strip, Quick add, Upcoming and Today (and the Month and day grid). Their backings always set a fill, so a reapplied rendering can't keep the old one.
- App language: changing it in Settings redraws every widget, which now render in the app language. Below Android 13 the choice is mirrored for the widget process, since AppCompat only applies it inside an activity.
- Picker previews: Countdown and Week strip previews inflate on Android 14 and below (they used View/Space, which RemoteViews refuses).
- Month widget: days outside the month take a 40% lighter shade, in the widget and its XML preview.
- Add button: the filled header action is 44dp instead of 36dp wide (floret-kit).
- Tinted background: the tonal header and weekday pills had the same tone as the fill and disappeared; they now use inversePrimary there (floret-kit). Not in the issues, found while testing.
- Dimmed past events (Month and day, Today, Agenda): the fill fades to 30% and the text to 65% instead of both to 40%, so the title stays readable.
- Widget picker: names drop the Calendula prefix, and each widget gets its own description instead of repeating its name (#71).

The config screen stalling until touched (#90, item 2) is not addressed: it didn't reproduce on an Android 12 emulator.

Closes #376
Closes #71

Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/449
2026-10-28 15:34:16 +01:00
makiolaj b6cec2f95e 2.24.0-beta.1
Beta — Codeberg pre-release / detect (push) Successful in 5s
Beta — Codeberg pre-release / beta (push) Successful in 8m50s
2026-10-26 20:32:16 +01:00
makiolaj d012948de6 Pin floret-kit to main after #22 2026-10-26 20:28:37 +01:00
makiolaj 8ff8a2de1f Merge the widget refactor and new widgets into 2.24.0 2026-10-26 20:16:34 +01:00
37 changed files with 207 additions and 118 deletions
+31
View File
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Added
- **Six new home-screen widgets.** Quick add (1×1) opens a new event on today with the same defaults as the app's + button ([#435]). Date (1×1) shows today's weekday and day number on a rounded shape and opens today ([#376]). Week strip (4×1) shows this week's days with a dot in each event's colour and today filled ([#436]). Upcoming (2×2) shows today's date over your next events, as many as fit ([#437]). Today lists today's events; once they're over it says "Nothing left today" and shows tomorrow's first one or two ([#438]). Countdown counts down to your next timed event, or to an event or series you pick, like a holiday in 12 days ([#439]).
- **A month and day widget.** A compact month grid sits beside the events of one day. Tap a day in the grid to see its events, and tap the list to open that day in the app ([#441]).
- **Each widget has its own settings.** Placing a widget, or long-pressing it and choosing Edit, opens a settings screen with a live preview. Pick a solid, tinted or transparent background, a light or dark theme or the app's, and which calendars it shows. Widgets that list events also have their time range, text size and how past events look. Settings → Widgets lists the widgets on your home screen so you can change them from there. These options used to be shared by all widgets; widgets you already placed keep what you had set ([#292]).
### Changed
- **The agenda and month widgets have a new look.** The agenda puts each day in its own card, with a round date pill beside the first event and today's pill filled. The month widget has rounded day cells, weekday pills, shaded days outside the month and a + for a new event. The agenda's refresh button is gone, since widgets now update on their own ([#71], [#90]).
- **Tapping a day in the month widget opens that day,** wherever in its cell you tap ([#386]).
- **The widget picker shows what each widget looks like.** On Android 15 and later the previews are the real widgets with sample events, in your language and colours; on older versions they are redrawn to match.
- **Widgets are listed by their name alone,** without "Calendula" in front, and each has a short description in the picker ([#71]).
- **Past events in widgets stay readable when dimmed.** Their background fades further and their text less ([#90]).
### Fixed
- **Widgets show your changes straight away.** After you added, edited or deleted an event, a widget could keep showing the old events until something else redrew it ([#420], [#229]).
- **Widgets follow the app's language.** After you picked a language in Settings, widgets kept the old one until something redrew them ([#90]).
- **The month widget handles busy months.** It could show "Can't show content", or only one or two events per day. Each day now shows as many events as its height fits, and the rest fold into +N ([#372]).
## [2.23.0] — 2026-10-21 ## [2.23.0] — 2026-10-21
### Added ### Added
@@ -1889,3 +1906,17 @@ automatically, with zero telemetry and no internet permission.
[#178]: https://codeberg.org/jlmakiola/calendula/issues/178 [#178]: https://codeberg.org/jlmakiola/calendula/issues/178
[#116]: https://codeberg.org/jlmakiola/calendula/issues/116 [#116]: https://codeberg.org/jlmakiola/calendula/issues/116
[#413]: https://codeberg.org/jlmakiola/calendula/issues/413 [#413]: https://codeberg.org/jlmakiola/calendula/issues/413
[#71]: https://codeberg.org/jlmakiola/calendula/issues/71
[#90]: https://codeberg.org/jlmakiola/calendula/issues/90
[#229]: https://codeberg.org/jlmakiola/calendula/issues/229
[#292]: https://codeberg.org/jlmakiola/calendula/issues/292
[#372]: https://codeberg.org/jlmakiola/calendula/issues/372
[#376]: https://codeberg.org/jlmakiola/calendula/issues/376
[#386]: https://codeberg.org/jlmakiola/calendula/issues/386
[#420]: https://codeberg.org/jlmakiola/calendula/issues/420
[#435]: https://codeberg.org/jlmakiola/calendula/issues/435
[#436]: https://codeberg.org/jlmakiola/calendula/issues/436
[#437]: https://codeberg.org/jlmakiola/calendula/issues/437
[#438]: https://codeberg.org/jlmakiola/calendula/issues/438
[#439]: https://codeberg.org/jlmakiola/calendula/issues/439
[#441]: https://codeberg.org/jlmakiola/calendula/issues/441
+2 -2
View File
@@ -32,8 +32,8 @@ android {
// (up to 2.22.3: 2.22.3 -> 22203; from 2.22.4: 2.23.0-beta.1 -> 2230001, // (up to 2.22.3: 2.22.3 -> 22203; from 2.22.4: 2.23.0-beta.1 -> 2230001,
// 2.22.4 -> 2220499), and CI fails if the committed one doesn't match. // 2.22.4 -> 2220499), and CI fails if the committed one doesn't match.
// See docs/RELEASING.md. // See docs/RELEASING.md.
versionCode = 2230099 versionCode = 2240002
versionName = "2.23.0" versionName = "2.24.0-beta.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -15,6 +15,7 @@ import de.jeanlucmakiola.calendula.widget.syncWidgetRollover
import de.jeanlucmakiola.calendula.widget.widgetEntryPoint import de.jeanlucmakiola.calendula.widget.widgetEntryPoint
import de.jeanlucmakiola.floret.crash.CrashConfig import de.jeanlucmakiola.floret.crash.CrashConfig
import de.jeanlucmakiola.floret.crash.CrashReporter import de.jeanlucmakiola.floret.crash.CrashReporter
import de.jeanlucmakiola.floret.locale.AppLanguage
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
@@ -45,6 +46,9 @@ class CalendulaApp : Application() {
chooseIssueUrl = getString(R.string.report_issue_choose_url), chooseIssueUrl = getString(R.string.report_issue_choose_url),
), ),
) )
// Below API 33 only AppCompat activities get the app language; a process
// woken for a widget formats in it too (#90).
AppLanguage.applyDefault(this)
// Before anything that writes, so the widgets see every change (#420). // Before anything that writes, so the widgets see every change (#420).
widgetEntryPoint().widgetRefreshCoordinator().start() widgetEntryPoint().widgetRefreshCoordinator().start()
reconcileAutoBackup() reconcileAutoBackup()
@@ -30,6 +30,7 @@ import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import de.jeanlucmakiola.calendula.data.calendar.CalendarRepository import de.jeanlucmakiola.calendula.data.calendar.CalendarRepository
import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs
import de.jeanlucmakiola.floret.locale.AppLanguage
import de.jeanlucmakiola.floret.prefs.ThemeMode import de.jeanlucmakiola.floret.prefs.ThemeMode
import de.jeanlucmakiola.floret.prefs.isDark import de.jeanlucmakiola.floret.prefs.isDark
import de.jeanlucmakiola.floret.prefs.isPureBlack import de.jeanlucmakiola.floret.prefs.isPureBlack
@@ -278,6 +279,7 @@ class MainActivity : AppCompatActivity() {
super.onResume() super.onResume()
// Reaching a running UI means startup succeeded; reset the loop trail. // Reaching a running UI means startup succeeded; reset the loop trail.
CrashReporter.markHealthy(this) CrashReporter.markHealthy(this)
AppLanguage.syncMirror(this)
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
@@ -63,6 +63,7 @@ import de.jeanlucmakiola.floret.components.GroupedListInset
import de.jeanlucmakiola.floret.components.GroupedRow import de.jeanlucmakiola.floret.components.GroupedRow
import de.jeanlucmakiola.floret.components.GroupedSectionHeader import de.jeanlucmakiola.floret.components.GroupedSectionHeader
import de.jeanlucmakiola.floret.components.LanguagePickerRow import de.jeanlucmakiola.floret.components.LanguagePickerRow
import de.jeanlucmakiola.calendula.widget.requestWidgetRedraw
import de.jeanlucmakiola.floret.components.Position import de.jeanlucmakiola.floret.components.Position
import de.jeanlucmakiola.floret.crash.CrashReportDialog import de.jeanlucmakiola.floret.crash.CrashReportDialog
import de.jeanlucmakiola.floret.crash.CrashReporter import de.jeanlucmakiola.floret.crash.CrashReporter
@@ -258,15 +259,16 @@ private fun SettingsHub(
leading = { CategoryIcon(Icons.Default.Widgets, ChipAccent.Tertiary) }, leading = { CategoryIcon(Icons.Default.Widgets, ChipAccent.Tertiary) },
onClick = { onOpenSection(SettingsSection.Widgets) }, onClick = { onOpenSection(SettingsSection.Widgets) },
) )
val context = LocalContext.current
LanguagePickerRow( LanguagePickerRow(
position = Position.Middle, position = Position.Middle,
title = stringResource(R.string.settings_language), title = stringResource(R.string.settings_language),
autoLabel = stringResource(R.string.settings_language_auto), autoLabel = stringResource(R.string.settings_language_auto),
localesConfig = R.xml.locales_config, localesConfig = R.xml.locales_config,
predictiveBack = true, predictiveBack = true,
onChange = { requestWidgetRedraw(context) },
// Invite contributions right where users pick their language. // Invite contributions right where users pick their language.
header = { header = {
val context = LocalContext.current
val translateUrl = stringResource(R.string.about_translate_url) val translateUrl = stringResource(R.string.about_translate_url)
GroupedRow( GroupedRow(
title = stringResource(R.string.settings_translate), title = stringResource(R.string.settings_translate),
@@ -23,7 +23,6 @@ import de.jeanlucmakiola.calendula.R
import de.jeanlucmakiola.calendula.domain.EventInstance import de.jeanlucmakiola.calendula.domain.EventInstance
import de.jeanlucmakiola.calendula.domain.isDeclined import de.jeanlucmakiola.calendula.domain.isDeclined
import de.jeanlucmakiola.calendula.ui.common.CalendarView import de.jeanlucmakiola.calendula.ui.common.CalendarView
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
import de.jeanlucmakiola.calendula.ui.common.SECONDARY_INK_ALPHA import de.jeanlucmakiola.calendula.ui.common.SECONDARY_INK_ALPHA
import de.jeanlucmakiola.calendula.ui.common.eventFill import de.jeanlucmakiola.calendula.ui.common.eventFill
import de.jeanlucmakiola.calendula.ui.common.eventInk import de.jeanlucmakiola.calendula.ui.common.eventInk
@@ -32,6 +31,16 @@ import de.jeanlucmakiola.floret.components.Position
import de.jeanlucmakiola.floret.glance.WidgetGroupedRow import de.jeanlucmakiola.floret.glance.WidgetGroupedRow
import de.jeanlucmakiola.floret.glance.themedColor import de.jeanlucmakiola.floret.glance.themedColor
/** A past event's fill when dimmed: fainter than the app's whole-row dim, so its text can stay readable (#90). */
internal const val WidgetDimFillAlpha = 0.3f
/** A dimmed event's ink, held above its fill. */
private const val WidgetDimInkAlpha = 0.65f
/** Ink for an event on [fill], picked against the opaque tone and faded when the fill is dimmed. */
internal fun widgetEventInk(fill: Color, alpha: Float): Color =
eventInk(fill.copy(alpha = 1f), if (fill.alpha < 1f) alpha * WidgetDimInkAlpha else alpha)
/** Text and row sizes of a compact event list, from a widget's [WidgetSize]. */ /** Text and row sizes of a compact event list, from a widget's [WidgetSize]. */
internal data class EventRowMetrics(val title: TextUnit, val time: TextUnit, val rowHeight: Dp, val message: TextUnit) internal data class EventRowMetrics(val title: TextUnit, val time: TextUnit, val rowHeight: Dp, val message: TextUnit)
@@ -63,11 +72,9 @@ internal fun WidgetEventRow(
quiet: Boolean = false, quiet: Boolean = false,
) { ) {
val context = LocalContext.current val context = LocalContext.current
fun tone(dark: Boolean): Color = eventFill(event.color, dark, soften).let { if (dimmed) it.copy(alpha = EventDimAlpha) else it } fun tone(dark: Boolean): Color = eventFill(event.color, dark, soften).let { if (dimmed) it.copy(alpha = WidgetDimFillAlpha) else it }
val day = tone(dark = false) val day = tone(dark = false)
val night = tone(dark = true) val night = tone(dark = true)
// Ink is picked against the opaque fill, then carries the dim along with it.
fun ink(fill: Color, alpha: Float) = eventInk(fill.copy(alpha = 1f), alpha * fill.alpha)
val card = widgetCardColor() val card = widgetCardColor()
WidgetGroupedRow(position = position, color = if (quiet) card else themedColor(day = day, night = night)) { WidgetGroupedRow(position = position, color = if (quiet) card else themedColor(day = day, night = night)) {
Column( Column(
@@ -91,12 +98,12 @@ internal fun WidgetEventRow(
val titleInk = if (quiet) { val titleInk = if (quiet) {
GlanceTheme.colors.onSurface GlanceTheme.colors.onSurface
} else { } else {
themedColor(day = ink(day, 1f), night = ink(night, 1f)) themedColor(day = widgetEventInk(day, 1f), night = widgetEventInk(night, 1f))
} }
val timeInk = if (quiet) { val timeInk = if (quiet) {
GlanceTheme.colors.onSurfaceVariant GlanceTheme.colors.onSurfaceVariant
} else { } else {
themedColor(day = ink(day, SECONDARY_INK_ALPHA), night = ink(night, SECONDARY_INK_ALPHA)) themedColor(day = widgetEventInk(day, SECONDARY_INK_ALPHA), night = widgetEventInk(night, SECONDARY_INK_ALPHA))
} }
Text( Text(
text = event.title.ifBlank { context.getString(R.string.event_untitled) }, text = event.title.ifBlank { context.getString(R.string.event_untitled) },
@@ -34,6 +34,17 @@ internal val WIDGET_RECEIVER_CLASSES: List<Class<*>> = WidgetKind.entries.map {
/** The app's own midnight wake-up (#228). */ /** The app's own midnight wake-up (#228). */
internal const val ACTION_WIDGET_ROLLOVER = "de.jeanlucmakiola.calendula.widget.ROLLOVER" internal const val ACTION_WIDGET_ROLLOVER = "de.jeanlucmakiola.calendula.widget.ROLLOVER"
/** Redraws every widget, for app changes they draw with that no other signal reaches, like its language (#90). */
internal const val ACTION_WIDGET_REDRAW = "de.jeanlucmakiola.calendula.widget.REDRAW"
/**
* Asks [WidgetUpdateReceiver] to redraw every widget. A broadcast rather than a
* coroutine, so it outlives the activity a language change recreates.
*/
fun requestWidgetRedraw(context: Context) {
context.sendBroadcast(Intent(context, WidgetUpdateReceiver::class.java).setAction(ACTION_WIDGET_REDRAW))
}
/** Fixed: there is only ever one rollover alarm, and re-arming must replace it. */ /** Fixed: there is only ever one rollover alarm, and re-arming must replace it. */
private const val ROLLOVER_REQUEST_CODE = 0x0DA1 private const val ROLLOVER_REQUEST_CODE = 0x0DA1
@@ -1,12 +1,17 @@
package de.jeanlucmakiola.calendula.widget package de.jeanlucmakiola.calendula.widget
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.glance.LocalContext
import androidx.glance.text.TextDecoration import androidx.glance.text.TextDecoration
import de.jeanlucmakiola.calendula.ui.theme.CalendulaDarkFallback import de.jeanlucmakiola.calendula.ui.theme.CalendulaDarkFallback
import de.jeanlucmakiola.calendula.ui.theme.CalendulaLightFallback import de.jeanlucmakiola.calendula.ui.theme.CalendulaLightFallback
import de.jeanlucmakiola.floret.glance.FloretGlanceTheme import de.jeanlucmakiola.floret.glance.FloretGlanceTheme
import de.jeanlucmakiola.floret.glance.WidgetSurface import de.jeanlucmakiola.floret.glance.WidgetSurface
import de.jeanlucmakiola.floret.glance.WidgetThemeMode import de.jeanlucmakiola.floret.glance.WidgetThemeMode
import de.jeanlucmakiola.floret.locale.AppLanguage
import de.jeanlucmakiola.floret.prefs.ThemeMode import de.jeanlucmakiola.floret.prefs.ThemeMode
/** /**
@@ -39,3 +44,20 @@ internal fun CalendulaWidgetRoot(appearance: WidgetAppearance, appTheme: ThemeMo
*/ */
fun glanceDeclinedDecoration(isDeclined: Boolean): TextDecoration = fun glanceDeclinedDecoration(isDeclined: Boolean): TextDecoration =
if (isDeclined) TextDecoration.LineThrough else TextDecoration.None if (isDeclined) TextDecoration.LineThrough else TextDecoration.None
/** Static, so a language change recomposes the whole widget rather than letting unchanged parts skip. */
private val LocalWidgetLanguage = staticCompositionLocalOf<String?> { null }
/**
* Draws [content] in the app's own language (#90): [LocalContext] and the
* default locale follow it, which below API 33 nothing else does outside an
* AppCompat activity. Read on every recomposition, so a redraw picks up a change.
*/
@Composable
internal fun InAppLanguage(content: @Composable () -> Unit) {
val base = LocalContext.current
val tag = AppLanguage.currentTag(base)
AppLanguage.applyDefault(base, tag)
val localized = remember(base, tag) { AppLanguage.localized(base, tag) }
CompositionLocalProvider(LocalContext provides localized, LocalWidgetLanguage provides tag, content = content)
}
@@ -4,10 +4,11 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import de.jeanlucmakiola.floret.glance.FloretWidgetUpdateReceiver import de.jeanlucmakiola.floret.glance.FloretWidgetUpdateReceiver
import de.jeanlucmakiola.floret.locale.AppLanguage
import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.minutes
/** /**
* Redraws both widgets when their data, day or language goes stale, and keeps * Redraws the widgets when their data, day or language goes stale, and keeps
* the midnight rollover armed. `PROVIDER_CHANGED` covers changes made outside * the midnight rollover armed. `PROVIDER_CHANGED` covers changes made outside
* the app; the app's own writes go through [WidgetRefreshCoordinator]. A data * the app; the app's own writes go through [WidgetRefreshCoordinator]. A data
* change also re-arms, at most every 15 minutes: the inexact alarm can be * change also re-arms, at most every 15 minutes: the inexact alarm can be
@@ -18,12 +19,15 @@ import kotlin.time.Duration.Companion.minutes
class WidgetUpdateReceiver : FloretWidgetUpdateReceiver() { class WidgetUpdateReceiver : FloretWidgetUpdateReceiver() {
override val rolloverAction = ACTION_WIDGET_ROLLOVER override val rolloverAction = ACTION_WIDGET_ROLLOVER
override val widgetReceiverClasses = WIDGET_RECEIVER_CLASSES override val widgetReceiverClasses = WIDGET_RECEIVER_CLASSES
override val extraHandledActions = setOf(Intent.ACTION_PROVIDER_CHANGED) override val extraHandledActions = setOf(Intent.ACTION_PROVIDER_CHANGED, ACTION_WIDGET_REDRAW)
override val extraRearmInterval = 15.minutes override val extraRearmInterval = 15.minutes
override fun rolloverPendingIntent(context: Context): PendingIntent = widgetRolloverPendingIntent(context) override fun rolloverPendingIntent(context: Context): PendingIntent = widgetRolloverPendingIntent(context)
override fun skipRedraw(action: String) = action == Intent.ACTION_PROVIDER_CHANGED && isProviderEcho() override fun skipRedraw(action: String) = action == Intent.ACTION_PROVIDER_CHANGED && isProviderEcho()
override suspend fun redraw(context: Context) = redrawWidgets(context) override suspend fun redraw(context: Context) {
AppLanguage.applyDefault(context)
redrawWidgets(context)
}
} }
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.agenda package de.jeanlucmakiola.calendula.widget.agenda
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -50,11 +51,11 @@ import de.jeanlucmakiola.calendula.domain.EventInstance
import de.jeanlucmakiola.calendula.domain.hasEnded import de.jeanlucmakiola.calendula.domain.hasEnded
import de.jeanlucmakiola.calendula.ui.agenda.anchorTodayIfMissing import de.jeanlucmakiola.calendula.ui.agenda.anchorTodayIfMissing
import de.jeanlucmakiola.calendula.ui.common.CalendarView import de.jeanlucmakiola.calendula.ui.common.CalendarView
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle
import de.jeanlucmakiola.floret.locale.localizedDateFormatter import de.jeanlucmakiola.floret.locale.localizedDateFormatter
import de.jeanlucmakiola.calendula.ui.common.eventFill import de.jeanlucmakiola.calendula.ui.common.eventFill
import de.jeanlucmakiola.calendula.ui.common.eventInk import de.jeanlucmakiola.calendula.widget.WidgetDimFillAlpha
import de.jeanlucmakiola.calendula.widget.widgetEventInk
import de.jeanlucmakiola.calendula.ui.common.SECONDARY_INK_ALPHA import de.jeanlucmakiola.calendula.ui.common.SECONDARY_INK_ALPHA
import de.jeanlucmakiola.calendula.widget.AgendaWidgetData import de.jeanlucmakiola.calendula.widget.AgendaWidgetData
import de.jeanlucmakiola.calendula.widget.WidgetSize import de.jeanlucmakiola.calendula.widget.WidgetSize
@@ -110,11 +111,13 @@ class AgendaWidget : GlanceAppWidget() {
// A running session never re-runs this preamble, so every redraw // A running session never re-runs this preamble, so every redraw
// moves the stamp and the data reloads here instead (#420). // moves the stamp and the data reloads here instead (#420).
val loaded = widgetData.current(currentRefreshStamp()) { context.loadAgendaWidget(id) } val loaded = widgetData.current(currentRefreshStamp()) { context.loadAgendaWidget(id) }
AgendaWidgetContent( InAppLanguage {
data = loaded.content, AgendaWidgetContent(
appearance = currentState<Preferences>().widgetAppearance, data = loaded.content,
appTheme = loaded.appTheme, appearance = currentState<Preferences>().widgetAppearance,
) appTheme = loaded.appTheme,
)
}
} }
} }
} }
@@ -392,7 +395,7 @@ private data class EventFill(val day: Color, val night: Color)
private fun AgendaRow.Event.fill(data: AgendaWidgetData.Ready): EventFill { private fun AgendaRow.Event.fill(data: AgendaWidgetData.Ready): EventFill {
val dimmed = data.pastDisplay == PastEventDisplay.DIM && event.hasEnded(data.now) val dimmed = data.pastDisplay == PastEventDisplay.DIM && event.hasEnded(data.now)
fun tone(dark: Boolean) = eventFill(event.color, dark, data.soften).let { fun tone(dark: Boolean) = eventFill(event.color, dark, data.soften).let {
if (dimmed) it.copy(alpha = EventDimAlpha) else it if (dimmed) it.copy(alpha = WidgetDimFillAlpha) else it
} }
return EventFill(day = tone(dark = false), night = tone(dark = true)) return EventFill(day = tone(dark = false), night = tone(dark = true))
} }
@@ -407,12 +410,10 @@ private fun EventRow(
) { ) {
val context = androidx.glance.LocalContext.current val context = androidx.glance.LocalContext.current
val title = event.title.ifBlank { context.getString(R.string.event_untitled) } val title = event.title.ifBlank { context.getString(R.string.event_untitled) }
// Ink is picked against the opaque fill, then carries the dim along with it. val titleInk = themedColor(day = widgetEventInk(fill.day, 1f), night = widgetEventInk(fill.night, 1f))
fun ink(fill: Color, alpha: Float) = eventInk(fill.copy(alpha = 1f), alpha * fill.alpha)
val titleInk = themedColor(day = ink(fill.day, 1f), night = ink(fill.night, 1f))
val timeInk = themedColor( val timeInk = themedColor(
day = ink(fill.day, SECONDARY_INK_ALPHA), day = widgetEventInk(fill.day, SECONDARY_INK_ALPHA),
night = ink(fill.night, SECONDARY_INK_ALPHA), night = widgetEventInk(fill.night, SECONDARY_INK_ALPHA),
) )
Column( Column(
modifier = GlanceModifier modifier = GlanceModifier
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.countdown package de.jeanlucmakiola.calendula.widget.countdown
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -49,9 +50,7 @@ import de.jeanlucmakiola.calendula.widget.formatWidgetTime
import de.jeanlucmakiola.calendula.widget.relativeDayLabel import de.jeanlucmakiola.calendula.widget.relativeDayLabel
import de.jeanlucmakiola.calendula.widget.systemZone import de.jeanlucmakiola.calendula.widget.systemZone
import de.jeanlucmakiola.calendula.widget.widgetAppearance import de.jeanlucmakiola.calendula.widget.widgetAppearance
import de.jeanlucmakiola.calendula.widget.widgetCardColor import de.jeanlucmakiola.floret.glance.wallpaperBacking
import de.jeanlucmakiola.floret.glance.LocalWidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetData import de.jeanlucmakiola.floret.glance.WidgetData
import de.jeanlucmakiola.floret.glance.WidgetMessage import de.jeanlucmakiola.floret.glance.WidgetMessage
import de.jeanlucmakiola.floret.glance.currentRefreshStamp import de.jeanlucmakiola.floret.glance.currentRefreshStamp
@@ -82,7 +81,9 @@ class CountdownWidget : GlanceAppWidget() {
val widgetData = WidgetData(context.loadPlacedCountdown(id), refreshStamp(context, id)) val widgetData = WidgetData(context.loadPlacedCountdown(id), refreshStamp(context, id))
provideContent { provideContent {
val loaded = widgetData.current(currentRefreshStamp()) { context.loadPlacedCountdown(id) } val loaded = widgetData.current(currentRefreshStamp()) { context.loadPlacedCountdown(id) }
CountdownWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme) InAppLanguage {
CountdownWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme)
}
} }
} }
} }
@@ -144,11 +145,7 @@ private fun EventCountdown(event: EventInstance, data: CountdownData.Ready) {
), ),
) )
// Over a wallpaper the text sits on its own card, as every other widget's rows do. // Over a wallpaper the text sits on its own card, as every other widget's rows do.
val card = if (LocalWidgetBackground.current == WidgetBackground.TRANSPARENT) { val card = GlanceModifier.wallpaperBacking(radius = 16.dp)
GlanceModifier.cornerRadius(16.dp).background(widgetCardColor())
} else {
GlanceModifier
}
Box(modifier = GlanceModifier.fillMaxSize().padding(6.dp)) { Box(modifier = GlanceModifier.fillMaxSize().padding(6.dp)) {
Row( Row(
modifier = card.fillMaxSize().clickable(open).padding(horizontal = 10.dp, vertical = 8.dp), modifier = card.fillMaxSize().clickable(open).padding(horizontal = 10.dp, vertical = 8.dp),
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.date package de.jeanlucmakiola.calendula.widget.date
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -24,7 +25,6 @@ import androidx.glance.layout.Column
import androidx.glance.layout.Spacer import androidx.glance.layout.Spacer
import androidx.glance.layout.fillMaxSize import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.height import androidx.glance.layout.height
import androidx.glance.layout.padding
import androidx.glance.semantics.contentDescription import androidx.glance.semantics.contentDescription
import androidx.glance.semantics.semantics import androidx.glance.semantics.semantics
import androidx.glance.state.PreferencesGlanceStateDefinition import androidx.glance.state.PreferencesGlanceStateDefinition
@@ -40,8 +40,6 @@ import de.jeanlucmakiola.calendula.widget.WidgetAppearance
import de.jeanlucmakiola.calendula.widget.loadToday import de.jeanlucmakiola.calendula.widget.loadToday
import de.jeanlucmakiola.calendula.widget.widgetAppearance import de.jeanlucmakiola.calendula.widget.widgetAppearance
import de.jeanlucmakiola.calendula.widget.widgetLocale import de.jeanlucmakiola.calendula.widget.widgetLocale
import de.jeanlucmakiola.floret.glance.LocalWidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetData import de.jeanlucmakiola.floret.glance.WidgetData
import de.jeanlucmakiola.floret.glance.WidgetShape import de.jeanlucmakiola.floret.glance.WidgetShape
import de.jeanlucmakiola.floret.glance.WidgetShapedBox import de.jeanlucmakiola.floret.glance.WidgetShapedBox
@@ -71,7 +69,9 @@ class DateWidget : GlanceAppWidget() {
val widgetData = WidgetData(context.loadToday(), refreshStamp(context, id)) val widgetData = WidgetData(context.loadToday(), refreshStamp(context, id))
provideContent { provideContent {
val loaded = widgetData.current(currentRefreshStamp()) { context.loadToday() } val loaded = widgetData.current(currentRefreshStamp()) { context.loadToday() }
DateWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme) InAppLanguage {
DateWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme)
}
} }
} }
} }
@@ -105,11 +105,7 @@ internal fun DateWidgetContent(today: LocalDate, appearance: WidgetAppearance, a
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
val name = today.dayOfWeek.toJavaDayOfWeek().getDisplayName(JavaTextStyle.SHORT, widgetLocale()) val name = today.dayOfWeek.toJavaDayOfWeek().getDisplayName(JavaTextStyle.SHORT, widgetLocale())
val backing = if (LocalWidgetBackground.current == WidgetBackground.TRANSPARENT) { val backing = GlanceModifier.wallpaperBacking(radius = 8.dp, horizontalPadding = 6.dp)
GlanceModifier.wallpaperBacking(radius = 8.dp).padding(horizontal = 6.dp)
} else {
GlanceModifier
}
Text(text = name.uppercase(widgetLocale()), maxLines = 1, style = weekday, modifier = backing) Text(text = name.uppercase(widgetLocale()), maxLines = 1, style = weekday, modifier = backing)
Spacer(GlanceModifier.height(2.dp)) Spacer(GlanceModifier.height(2.dp))
WidgetShapedBox(shape = WidgetShape.COOKIE, color = GlanceTheme.colors.primary, size = side) { WidgetShapedBox(shape = WidgetShape.COOKIE, color = GlanceTheme.colors.primary, size = side) {
@@ -147,9 +147,9 @@ private fun openDayIntent(context: Context, date: LocalDate): PendingIntent = Pe
) )
private val STRIP_IDS = intArrayOf(R.id.strip_0, R.id.strip_1, R.id.strip_2, R.id.strip_3, R.id.strip_4, R.id.strip_5, R.id.strip_6) private val STRIP_IDS = intArrayOf(R.id.strip_0, R.id.strip_1, R.id.strip_2, R.id.strip_3, R.id.strip_4, R.id.strip_5, R.id.strip_6)
/** The shade over a day outside the month: a dark cell needs more of it to read as dimmed. */ /** The shade over a day outside the month: a dark cell needs more of it to read as dimmed. Mirrored by `widget_preview_outside_shade`. */
private val OUTSIDE_SHADE_DAY = Color.Black.copy(alpha = 0.18f) private val OUTSIDE_SHADE_DAY = Color.Black.copy(alpha = 0.11f)
private val OUTSIDE_SHADE_NIGHT = Color.Black.copy(alpha = 0.50f) private val OUTSIDE_SHADE_NIGHT = Color.Black.copy(alpha = 0.30f)
private val CELL_DIM_IDS = intArrayOf( private val CELL_DIM_IDS = intArrayOf(
R.id.cell_dim_0, R.id.cell_dim_1, R.id.cell_dim_2, R.id.cell_dim_3, R.id.cell_dim_4, R.id.cell_dim_5, R.id.cell_dim_6, R.id.cell_dim_0, R.id.cell_dim_1, R.id.cell_dim_2, R.id.cell_dim_3, R.id.cell_dim_4, R.id.cell_dim_5, R.id.cell_dim_6,
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.month package de.jeanlucmakiola.calendula.widget.month
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -169,12 +170,14 @@ class MonthWidget : GlanceAppWidget() {
else -> index.coerceIn(source.months) else -> index.coerceIn(source.months)
} }
SideEffect { lastShown = shown } SideEffect { lastShown = shown }
MonthWidgetContent( InAppLanguage {
source = source, MonthWidgetContent(
index = shown, source = source,
appearance = currentState<Preferences>().widgetAppearance, index = shown,
appTheme = loaded.appTheme, appearance = currentState<Preferences>().widgetAppearance,
) appTheme = loaded.appTheme,
)
}
} }
} }
} }
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.quickadd package de.jeanlucmakiola.calendula.widget.quickadd
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -59,7 +60,9 @@ class QuickAddWidget : GlanceAppWidget() {
provideContent { provideContent {
// The rollover moves the stamp, so the editor opens on the new day. // The rollover moves the stamp, so the editor opens on the new day.
val loaded = widgetData.current(currentRefreshStamp()) { context.loadToday() } val loaded = widgetData.current(currentRefreshStamp()) { context.loadToday() }
QuickAddWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme) InAppLanguage {
QuickAddWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme)
}
} }
} }
} }
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.split package de.jeanlucmakiola.calendula.widget.split
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -84,9 +85,7 @@ import kotlinx.datetime.toJavaLocalDate
import de.jeanlucmakiola.calendula.widget.widgetTimeLabel import de.jeanlucmakiola.calendula.widget.widgetTimeLabel
import de.jeanlucmakiola.calendula.data.prefs.is24Hour import de.jeanlucmakiola.calendula.data.prefs.is24Hour
import de.jeanlucmakiola.floret.components.positionOf import de.jeanlucmakiola.floret.components.positionOf
import de.jeanlucmakiola.floret.glance.LocalWidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetActionStyle import de.jeanlucmakiola.floret.glance.WidgetActionStyle
import de.jeanlucmakiola.floret.glance.WidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetData import de.jeanlucmakiola.floret.glance.WidgetData
import de.jeanlucmakiola.floret.glance.WidgetHeader import de.jeanlucmakiola.floret.glance.WidgetHeader
import de.jeanlucmakiola.floret.glance.WidgetHeaderAction import de.jeanlucmakiola.floret.glance.WidgetHeaderAction
@@ -168,7 +167,9 @@ class MonthDayWidget : GlanceAppWidget() {
val currentStamp = currentRefreshStamp() val currentStamp = currentRefreshStamp()
val loaded = widgetData.current(currentCenter, currentStamp) { load(currentCenter, currentStamp) } val loaded = widgetData.current(currentCenter, currentStamp) { load(currentCenter, currentStamp) }
val selected = currentState(SELECTED_KEY)?.let(LocalDate::parse) val selected = currentState(SELECTED_KEY)?.let(LocalDate::parse)
MonthDayWidgetContent(loaded.content, index, selected, currentState<Preferences>().widgetAppearance, loaded.appTheme) InAppLanguage {
MonthDayWidgetContent(loaded.content, index, selected, currentState<Preferences>().widgetAppearance, loaded.appTheme)
}
} }
} }
} }
@@ -331,11 +332,7 @@ private fun Grid(
) { ) {
val locale = widgetLocale() val locale = widgetLocale()
val month = index % 12 + 1 val month = index % 12 + 1
val backing = if (LocalWidgetBackground.current == WidgetBackground.TRANSPARENT) { val backing = GlanceModifier.wallpaperBacking(radius = 14.dp)
GlanceModifier.cornerRadius(14.dp).background(widgetCardColor())
} else {
GlanceModifier
}
Column(modifier = backing.fillMaxSize().padding(2.dp)) { Column(modifier = backing.fillMaxSize().padding(2.dp)) {
Row(modifier = GlanceModifier.fillMaxWidth()) { Row(modifier = GlanceModifier.fillMaxWidth()) {
for (i in 0 until 7) { for (i in 0 until 7) {
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.today package de.jeanlucmakiola.calendula.widget.today
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -62,8 +63,6 @@ import de.jeanlucmakiola.calendula.widget.widgetLocale
import de.jeanlucmakiola.calendula.widget.widgetLoadContext import de.jeanlucmakiola.calendula.widget.widgetLoadContext
import de.jeanlucmakiola.calendula.widget.widgetTimeLabel import de.jeanlucmakiola.calendula.widget.widgetTimeLabel
import de.jeanlucmakiola.floret.components.positionOf import de.jeanlucmakiola.floret.components.positionOf
import de.jeanlucmakiola.floret.glance.LocalWidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetData import de.jeanlucmakiola.floret.glance.WidgetData
import de.jeanlucmakiola.floret.glance.WidgetMessage import de.jeanlucmakiola.floret.glance.WidgetMessage
import de.jeanlucmakiola.floret.glance.currentRefreshStamp import de.jeanlucmakiola.floret.glance.currentRefreshStamp
@@ -99,7 +98,9 @@ class TodayWidget : GlanceAppWidget() {
val widgetData = WidgetData(context.loadTodayList(context.widgetLoadContext(id)), refreshStamp(context, id)) val widgetData = WidgetData(context.loadTodayList(context.widgetLoadContext(id)), refreshStamp(context, id))
provideContent { provideContent {
val loaded = widgetData.current(currentRefreshStamp()) { context.loadTodayList(context.widgetLoadContext(id)) } val loaded = widgetData.current(currentRefreshStamp()) { context.loadTodayList(context.widgetLoadContext(id)) }
TodayWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme) InAppLanguage {
TodayWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme)
}
} }
} }
} }
@@ -189,11 +190,7 @@ private fun NothingLeft(tomorrow: List<EventInstance>, data: DaysWidgetData.Read
val room = LocalSize.current.height - 12.dp - lineHeight val room = LocalSize.current.height - 12.dp - lineHeight
val fits = ((room + RowGap) / (metrics.rowHeight + RowGap)).toInt().coerceIn(0, 2) val fits = ((room + RowGap) / (metrics.rowHeight + RowGap)).toInt().coerceIn(0, 2)
val ahead = tomorrow.take(fits) val ahead = tomorrow.take(fits)
val backing = if (LocalWidgetBackground.current == WidgetBackground.TRANSPARENT) { val backing = GlanceModifier.wallpaperBacking(radius = 8.dp, horizontalPadding = 8.dp, filledHorizontalPadding = 4.dp)
GlanceModifier.wallpaperBacking(radius = 8.dp).padding(horizontal = 8.dp)
} else {
GlanceModifier.padding(horizontal = 4.dp)
}
Column(modifier = GlanceModifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically) { Column(modifier = GlanceModifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically) {
Text( Text(
text = context.getString(R.string.widget_nothing_left_today), text = context.getString(R.string.widget_nothing_left_today),
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.upcoming package de.jeanlucmakiola.calendula.widget.upcoming
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -54,8 +55,6 @@ import de.jeanlucmakiola.calendula.widget.widgetLocale
import de.jeanlucmakiola.calendula.widget.widgetLoadContext import de.jeanlucmakiola.calendula.widget.widgetLoadContext
import de.jeanlucmakiola.calendula.widget.widgetTimeLabel import de.jeanlucmakiola.calendula.widget.widgetTimeLabel
import de.jeanlucmakiola.floret.components.positionOf import de.jeanlucmakiola.floret.components.positionOf
import de.jeanlucmakiola.floret.glance.LocalWidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetBackground
import de.jeanlucmakiola.floret.glance.WidgetData import de.jeanlucmakiola.floret.glance.WidgetData
import de.jeanlucmakiola.floret.glance.WidgetMessage import de.jeanlucmakiola.floret.glance.WidgetMessage
import de.jeanlucmakiola.floret.glance.currentRefreshStamp import de.jeanlucmakiola.floret.glance.currentRefreshStamp
@@ -89,7 +88,9 @@ class UpcomingWidget : GlanceAppWidget() {
val widgetData = WidgetData(context.loadUpcoming(context.widgetLoadContext(id)), refreshStamp(context, id)) val widgetData = WidgetData(context.loadUpcoming(context.widgetLoadContext(id)), refreshStamp(context, id))
provideContent { provideContent {
val loaded = widgetData.current(currentRefreshStamp()) { context.loadUpcoming(context.widgetLoadContext(id)) } val loaded = widgetData.current(currentRefreshStamp()) { context.loadUpcoming(context.widgetLoadContext(id)) }
UpcomingWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme) InAppLanguage {
UpcomingWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme)
}
} }
} }
} }
@@ -155,11 +156,7 @@ internal fun UpcomingWidgetContent(data: DaysWidgetData, appearance: WidgetAppea
private fun DateHeader(today: LocalDate, height: Dp) { private fun DateHeader(today: LocalDate, height: Dp) {
val context = LocalContext.current val context = LocalContext.current
val locale = widgetLocale() val locale = widgetLocale()
val backing = if (LocalWidgetBackground.current == WidgetBackground.TRANSPARENT) { val backing = GlanceModifier.wallpaperBacking(radius = 12.dp, horizontalPadding = 8.dp, filledHorizontalPadding = 4.dp)
GlanceModifier.wallpaperBacking(radius = 12.dp).padding(horizontal = 8.dp)
} else {
GlanceModifier.padding(horizontal = 4.dp)
}
Box(modifier = GlanceModifier.fillMaxWidth().height(height), contentAlignment = Alignment.CenterStart) { Box(modifier = GlanceModifier.fillMaxWidth().height(height), contentAlignment = Alignment.CenterStart) {
Row( Row(
modifier = backing.clickable(actionStartActivity(MainActivity.openViewIntent(context, CalendarView.Agenda))), modifier = backing.clickable(actionStartActivity(MainActivity.openViewIntent(context, CalendarView.Agenda))),
@@ -1,5 +1,6 @@
package de.jeanlucmakiola.calendula.widget.week package de.jeanlucmakiola.calendula.widget.week
import de.jeanlucmakiola.calendula.widget.InAppLanguage
import de.jeanlucmakiola.calendula.widget.WidgetKind import de.jeanlucmakiola.calendula.widget.WidgetKind
import de.jeanlucmakiola.calendula.widget.previewSizeOf import de.jeanlucmakiola.calendula.widget.previewSizeOf
import de.jeanlucmakiola.calendula.widget.provideSamplePreview import de.jeanlucmakiola.calendula.widget.provideSamplePreview
@@ -91,7 +92,9 @@ class WeekStripWidget : GlanceAppWidget() {
val widgetData = WidgetData(context.loadWeek(id), refreshStamp(context, id)) val widgetData = WidgetData(context.loadWeek(id), refreshStamp(context, id))
provideContent { provideContent {
val loaded = widgetData.current(currentRefreshStamp()) { context.loadWeek(id) } val loaded = widgetData.current(currentRefreshStamp()) { context.loadWeek(id) }
WeekStripWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme) InAppLanguage {
WeekStripWidgetContent(loaded.content, currentState<Preferences>().widgetAppearance, loaded.appTheme)
}
} }
} }
} }
@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" <!-- A day outside the month: its cell under the widget's shade (MonthGridViews). -->
android:shape="rectangle"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/widget_preview_outside" /> <item android:drawable="@drawable/preview_widget_cell_bg" />
<corners android:radius="12dp" /> <item>
</shape> <shape android:shape="rectangle">
<solid android:color="@color/widget_preview_outside_shade" />
<corners android:radius="12dp" />
</shape>
</item>
</layer-list>
@@ -9,9 +9,9 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="12dp" android:padding="12dp"
tools:ignore="HardcodedText,NestedWeights,DisableBaselineAlignment,SmallSp,TooManyViews,UselessParent"> tools:ignore="HardcodedText,NestedWeights,DisableBaselineAlignment,SmallSp,TooManyViews,UselessLeaf,UselessParent">
<View <FrameLayout
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@drawable/preview_stripe" android:background="@drawable/preview_stripe"
@@ -8,7 +8,7 @@
android:background="@drawable/preview_widget_bg" android:background="@drawable/preview_widget_bg"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="6dp" android:padding="6dp"
tools:ignore="HardcodedText,NestedWeights,DisableBaselineAlignment,SmallSp,TooManyViews,UselessParent"> tools:ignore="HardcodedText,NestedWeights,DisableBaselineAlignment,SmallSp,TooManyViews,UselessLeaf,UselessParent">
<LinearLayout <LinearLayout
style="@style/WidgetPreviewWeekDay" style="@style/WidgetPreviewWeekDay"
@@ -32,19 +32,19 @@
android:layout_height="6dp" android:layout_height="6dp"
android:gravity="center" android:gravity="center"
android:orientation="horizontal"> android:orientation="horizontal">
<View <FrameLayout
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="4dp" android:layout_height="4dp"
android:layout_marginHorizontal="1dp" android:layout_marginHorizontal="1dp"
android:background="@drawable/preview_today_circle" android:background="@drawable/preview_today_circle"
android:backgroundTint="@color/widget_preview_event_blue" /> android:backgroundTint="@color/widget_preview_event_blue" />
<View <FrameLayout
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="4dp" android:layout_height="4dp"
android:layout_marginHorizontal="1dp" android:layout_marginHorizontal="1dp"
android:background="@drawable/preview_today_circle" android:background="@drawable/preview_today_circle"
android:backgroundTint="@color/widget_preview_event_green" /> android:backgroundTint="@color/widget_preview_event_green" />
<View <FrameLayout
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="4dp" android:layout_height="4dp"
android:layout_marginHorizontal="1dp" android:layout_marginHorizontal="1dp"
@@ -73,7 +73,7 @@
android:layout_height="6dp" android:layout_height="6dp"
android:gravity="center" android:gravity="center"
android:orientation="horizontal"> android:orientation="horizontal">
<View <FrameLayout
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="4dp" android:layout_height="4dp"
android:layout_marginHorizontal="1dp" android:layout_marginHorizontal="1dp"
@@ -102,7 +102,7 @@
android:layout_height="6dp" android:layout_height="6dp"
android:gravity="center" android:gravity="center"
android:orientation="horizontal"> android:orientation="horizontal">
<View <FrameLayout
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="4dp" android:layout_height="4dp"
android:layout_marginHorizontal="1dp" android:layout_marginHorizontal="1dp"
@@ -126,7 +126,7 @@
android:textColor="@color/widget_preview_on_surface" android:textColor="@color/widget_preview_on_surface"
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold" /> android:textStyle="bold" />
<Space <FrameLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="6dp" /> android:layout_height="6dp" />
</LinearLayout> </LinearLayout>
@@ -146,7 +146,7 @@
android:textColor="@color/widget_preview_on_surface" android:textColor="@color/widget_preview_on_surface"
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold" /> android:textStyle="bold" />
<Space <FrameLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="6dp" /> android:layout_height="6dp" />
</LinearLayout> </LinearLayout>
@@ -171,7 +171,7 @@
android:layout_height="6dp" android:layout_height="6dp"
android:gravity="center" android:gravity="center"
android:orientation="horizontal"> android:orientation="horizontal">
<View <FrameLayout
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="4dp" android:layout_height="4dp"
android:layout_marginHorizontal="1dp" android:layout_marginHorizontal="1dp"
@@ -195,7 +195,7 @@
android:textColor="@color/widget_preview_on_surface" android:textColor="@color/widget_preview_on_surface"
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold" /> android:textStyle="bold" />
<Space <FrameLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="6dp" /> android:layout_height="6dp" />
</LinearLayout> </LinearLayout>
@@ -2,7 +2,6 @@
<resources> <resources>
<color name="widget_preview_surface">@android:color/system_accent2_700</color> <color name="widget_preview_surface">@android:color/system_accent2_700</color>
<color name="widget_preview_cell">@android:color/system_accent2_900</color> <color name="widget_preview_cell">@android:color/system_accent2_900</color>
<color name="widget_preview_outside">@android:color/system_neutral2_600</color>
<color name="widget_preview_on_surface">@android:color/system_neutral1_50</color> <color name="widget_preview_on_surface">@android:color/system_neutral1_50</color>
<color name="widget_preview_variant">@android:color/system_neutral2_200</color> <color name="widget_preview_variant">@android:color/system_neutral2_200</color>
<color name="widget_preview_primary">@android:color/system_accent1_200</color> <color name="widget_preview_primary">@android:color/system_accent1_200</color>
@@ -2,7 +2,7 @@
<resources> <resources>
<color name="widget_preview_surface">#2B3742</color> <color name="widget_preview_surface">#2B3742</color>
<color name="widget_preview_cell">#1C252D</color> <color name="widget_preview_cell">#1C252D</color>
<color name="widget_preview_outside">#3A4651</color> <color name="widget_preview_outside_shade">#4D000000</color>
<color name="widget_preview_on_surface">#E1E3E6</color> <color name="widget_preview_on_surface">#E1E3E6</color>
<color name="widget_preview_variant">#A8ADB2</color> <color name="widget_preview_variant">#A8ADB2</color>
<color name="widget_preview_primary">#A3CBE2</color> <color name="widget_preview_primary">#A3CBE2</color>
@@ -2,7 +2,6 @@
<resources> <resources>
<color name="widget_preview_surface">@android:color/system_accent2_100</color> <color name="widget_preview_surface">@android:color/system_accent2_100</color>
<color name="widget_preview_cell">@android:color/system_accent2_10</color> <color name="widget_preview_cell">@android:color/system_accent2_10</color>
<color name="widget_preview_outside">@android:color/system_neutral2_300</color>
<color name="widget_preview_on_surface">@android:color/system_neutral1_900</color> <color name="widget_preview_on_surface">@android:color/system_neutral1_900</color>
<color name="widget_preview_variant">@android:color/system_neutral2_700</color> <color name="widget_preview_variant">@android:color/system_neutral2_700</color>
<color name="widget_preview_primary">@android:color/system_accent1_600</color> <color name="widget_preview_primary">@android:color/system_accent1_600</color>
+18 -9
View File
@@ -433,21 +433,29 @@
<!-- Home-screen widgets --> <!-- Home-screen widgets -->
<string name="widget_agenda_title">Upcoming</string> <string name="widget_agenda_title">Upcoming</string>
<string name="widget_agenda_label">Calendula agenda</string> <string name="widget_agenda_label">Agenda</string>
<string name="widget_month_label">Calendula month</string> <string name="widget_agenda_description">Your next events, grouped by day</string>
<string name="widget_quick_add_label">Calendula quick add</string> <string name="widget_month_label">Month</string>
<string name="widget_date_label">Calendula date</string> <string name="widget_month_description">The month at a glance, with your events</string>
<string name="widget_week_strip_label">Calendula week strip</string> <string name="widget_quick_add_label">Quick add</string>
<string name="widget_quick_add_description">Start a new event in one tap</string>
<string name="widget_date_label">Date</string>
<string name="widget_date_description">Today\'s date</string>
<string name="widget_week_strip_label">Week strip</string>
<string name="widget_week_strip_description">This week, with the days that have events</string>
<!-- A day in the week strip widget, for screen readers: "Wednesday, 7 October, 2 events" --> <!-- A day in the week strip widget, for screen readers: "Wednesday, 7 October, 2 events" -->
<plurals name="widget_day_with_events"> <plurals name="widget_day_with_events">
<item quantity="one">%1$s, %2$d event</item> <item quantity="one">%1$s, %2$d event</item>
<item quantity="other">%1$s, %2$d events</item> <item quantity="other">%1$s, %2$d events</item>
</plurals> </plurals>
<string name="widget_upcoming_label">Calendula upcoming</string> <string name="widget_upcoming_label">Upcoming</string>
<string name="widget_upcoming_description">Today\'s date over your next events</string>
<string name="widget_upcoming_empty">No upcoming events</string> <string name="widget_upcoming_empty">No upcoming events</string>
<string name="widget_today_label">Calendula today</string> <string name="widget_today_label">Today</string>
<string name="widget_today_description">Today\'s events, then tomorrow\'s</string>
<string name="widget_nothing_left_today">Nothing left today</string> <string name="widget_nothing_left_today">Nothing left today</string>
<string name="widget_countdown_label">Calendula countdown</string> <string name="widget_countdown_label">Countdown</string>
<string name="widget_countdown_description">Time until an event, or the next one</string>
<string name="widget_countdown_now">Now</string> <string name="widget_countdown_now">Now</string>
<string name="widget_countdown_ending_now">Ending now</string> <string name="widget_countdown_ending_now">Ending now</string>
<string name="widget_countdown_tomorrow">Tomorrow</string> <string name="widget_countdown_tomorrow">Tomorrow</string>
@@ -492,7 +500,8 @@
<string name="widget_config_countdown_load_failed">Couldn\'t load your events.</string> <string name="widget_config_countdown_load_failed">Couldn\'t load your events.</string>
<!-- A repeating event in the countdown's event list: "Next: Fri, 24 Oct · repeats" --> <!-- A repeating event in the countdown's event list: "Next: Fri, 24 Oct · repeats" -->
<string name="widget_config_countdown_repeats">%1$s · repeats</string> <string name="widget_config_countdown_repeats">%1$s · repeats</string>
<string name="widget_month_day_label">Calendula month and day</string> <string name="widget_month_day_label">Month and day</string>
<string name="widget_month_day_description">The month and the events of the day you pick</string>
<string name="widget_day_empty">No events</string> <string name="widget_day_empty">No events</string>
<string name="widget_refresh">Refresh</string> <string name="widget_refresh">Refresh</string>
<string name="widget_new_event">New event</string> <string name="widget_new_event">New event</string>
@@ -6,7 +6,7 @@
<resources> <resources>
<color name="widget_preview_surface">#D6E4F0</color> <color name="widget_preview_surface">#D6E4F0</color>
<color name="widget_preview_cell">#EEF3F8</color> <color name="widget_preview_cell">#EEF3F8</color>
<color name="widget_preview_outside">#C2CCD6</color> <color name="widget_preview_outside_shade">#1C000000</color>
<color name="widget_preview_on_surface">#191C1F</color> <color name="widget_preview_on_surface">#191C1F</color>
<color name="widget_preview_variant">#6E7479</color> <color name="widget_preview_variant">#6E7479</color>
<color name="widget_preview_primary">#3B5364</color> <color name="widget_preview_primary">#3B5364</color>
@@ -10,7 +10,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_agenda_label" android:description="@string/widget_agenda_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_agenda" android:previewLayout="@layout/widget_preview_agenda"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />
@@ -10,7 +10,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_countdown_label" android:description="@string/widget_countdown_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_countdown" android:previewLayout="@layout/widget_preview_countdown"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />
+1 -1
View File
@@ -8,7 +8,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_date_label" android:description="@string/widget_date_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_date" android:previewLayout="@layout/widget_preview_date"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />
@@ -10,7 +10,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_month_label" android:description="@string/widget_month_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_month" android:previewLayout="@layout/widget_preview_month"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />
@@ -10,7 +10,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_month_day_label" android:description="@string/widget_month_day_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_month_day" android:previewLayout="@layout/widget_preview_month_day"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />
@@ -8,7 +8,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_quick_add_label" android:description="@string/widget_quick_add_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_quick_add" android:previewLayout="@layout/widget_preview_quick_add"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />
@@ -12,7 +12,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_today_label" android:description="@string/widget_today_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_today" android:previewLayout="@layout/widget_preview_today"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />
@@ -10,7 +10,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_upcoming_label" android:description="@string/widget_upcoming_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_upcoming" android:previewLayout="@layout/widget_preview_upcoming"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />
@@ -10,7 +10,7 @@
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity" android:configure="de.jeanlucmakiola.calendula.widget.config.WidgetConfigActivity"
android:widgetFeatures="reconfigurable" android:widgetFeatures="reconfigurable"
android:description="@string/widget_week_strip_label" android:description="@string/widget_week_strip_description"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:previewLayout="@layout/widget_preview_week_strip" android:previewLayout="@layout/widget_preview_week_strip"
android:initialLayout="@layout/glance_default_loading_layout" /> android:initialLayout="@layout/glance_default_loading_layout" />