Compare commits
1
Commits
v2.24.0-beta.1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5c4a73de1 |
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2.23.1] — 2026-10-28
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **The split month view fits more events.** With a day selected, its date is no longer shown twice: the filter chip now stands in for the day's header. Tapping the chip opens the day, and its ✕ clears the filter. The day headers in the month agenda below the grid take less room too ([#142]).
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **Event dots in the split month grid stay in place on busy days.** A day with a "+N" next to its dots used to push them further down the cell ([#142]).
|
||||||
|
|
||||||
## [2.23.0] — 2026-10-21
|
## [2.23.0] — 2026-10-21
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -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 = 2230199
|
||||||
versionName = "2.23.0"
|
versionName = "2.23.1"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,11 +59,16 @@ import java.util.Locale
|
|||||||
// split style can list a day with exactly the same visual language instead of
|
// split style can list a day with exactly the same visual language instead of
|
||||||
// growing a parallel set of event rows.
|
// growing a parallel set of event rows.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A day's header; tapping it opens the Day view. [compact] trims the padding for
|
||||||
|
* the month view's split pane, where vertical space is short (#142).
|
||||||
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
internal fun AgendaDayHeader(
|
internal fun AgendaDayHeader(
|
||||||
date: LocalDate,
|
date: LocalDate,
|
||||||
today: LocalDate,
|
today: LocalDate,
|
||||||
onOpenDay: (LocalDate) -> Unit,
|
onOpenDay: (LocalDate) -> Unit,
|
||||||
|
compact: Boolean = false,
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
color = MaterialTheme.colorScheme.surface,
|
color = MaterialTheme.colorScheme.surface,
|
||||||
@@ -79,7 +84,12 @@ internal fun AgendaDayHeader(
|
|||||||
} else {
|
} else {
|
||||||
MaterialTheme.colorScheme.onSurfaceVariant
|
MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
},
|
},
|
||||||
modifier = Modifier.padding(start = 28.dp, end = 28.dp, top = 16.dp, bottom = 8.dp),
|
modifier = Modifier.padding(
|
||||||
|
start = 28.dp,
|
||||||
|
end = 28.dp,
|
||||||
|
top = if (compact) 8.dp else 16.dp,
|
||||||
|
bottom = if (compact) 4.dp else 8.dp,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,10 +230,11 @@ internal fun LazyListScope.agendaDays(
|
|||||||
dimmed: (EventInstance, LocalDate) -> Boolean,
|
dimmed: (EventInstance, LocalDate) -> Boolean,
|
||||||
onOpenDay: (LocalDate) -> Unit,
|
onOpenDay: (LocalDate) -> Unit,
|
||||||
onEventClick: (EventInstance) -> Unit,
|
onEventClick: (EventInstance) -> Unit,
|
||||||
|
compact: Boolean = false,
|
||||||
) {
|
) {
|
||||||
days.forEach { day ->
|
days.forEach { day ->
|
||||||
stickyHeader(key = "header-${day.date}") {
|
stickyHeader(key = "header-${day.date}") {
|
||||||
AgendaDayHeader(date = day.date, today = today, onOpenDay = onOpenDay)
|
AgendaDayHeader(date = day.date, today = today, onOpenDay = onOpenDay, compact = compact)
|
||||||
}
|
}
|
||||||
if (day.events.isEmpty()) {
|
if (day.events.isEmpty()) {
|
||||||
item(key = "placeholder-${day.date}") {
|
item(key = "placeholder-${day.date}") {
|
||||||
@@ -251,6 +262,6 @@ internal fun LazyListScope.agendaDays(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item(key = "gap-${day.date}") { Spacer(Modifier.height(8.dp)) }
|
item(key = "gap-${day.date}") { Spacer(Modifier.height(if (compact) 4.dp else 8.dp)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ import androidx.compose.foundation.layout.offset
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
@@ -157,10 +158,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import de.jeanlucmakiola.calendula.R
|
import de.jeanlucmakiola.calendula.R
|
||||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||||
import de.jeanlucmakiola.calendula.domain.hasEnded
|
import de.jeanlucmakiola.calendula.domain.hasEnded
|
||||||
import de.jeanlucmakiola.calendula.ui.agenda.AgendaDayHeader
|
import de.jeanlucmakiola.calendula.ui.agenda.agendaDayLabel
|
||||||
import de.jeanlucmakiola.calendula.ui.agenda.AgendaEmptyDayRow
|
import de.jeanlucmakiola.calendula.ui.agenda.AgendaEmptyDayRow
|
||||||
import de.jeanlucmakiola.calendula.ui.agenda.AgendaEventRow
|
import de.jeanlucmakiola.calendula.ui.agenda.AgendaEventRow
|
||||||
import de.jeanlucmakiola.calendula.ui.agenda.agendaDayLabel
|
|
||||||
import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle
|
import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle
|
||||||
import de.jeanlucmakiola.calendula.ui.common.AppBarSpacing
|
import de.jeanlucmakiola.calendula.ui.common.AppBarSpacing
|
||||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||||
@@ -1423,24 +1423,13 @@ private fun SplitMonthCollapsed(
|
|||||||
.then(paneModifier)
|
.then(paneModifier)
|
||||||
.then(rememberSplitPaneSwipe(onPaneSwipeNext, onPaneSwipePrev)),
|
.then(rememberSplitPaneSwipe(onPaneSwipeNext, onPaneSwipePrev)),
|
||||||
) {
|
) {
|
||||||
InputChip(
|
|
||||||
selected = true,
|
|
||||||
onClick = onClearSelection,
|
|
||||||
label = { Text(agendaDayLabel(selected, state.today)) },
|
|
||||||
trailingIcon = {
|
|
||||||
Icon(
|
|
||||||
Icons.Default.Close,
|
|
||||||
contentDescription = stringResource(R.string.month_split_clear_filter),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier.padding(start = 16.dp),
|
|
||||||
)
|
|
||||||
SplitDayPane(
|
SplitDayPane(
|
||||||
date = selected,
|
date = selected,
|
||||||
today = state.today,
|
today = state.today,
|
||||||
events = state.instancesByDay[selected],
|
events = state.instancesByDay[selected],
|
||||||
zone = state.zone,
|
zone = state.zone,
|
||||||
onOpenDay = onOpenDay,
|
onOpenDay = onOpenDay,
|
||||||
|
onClearSelection = onClearSelection,
|
||||||
onEventClick = onEventClick,
|
onEventClick = onEventClick,
|
||||||
onCreateEvent = onCreateEvent,
|
onCreateEvent = onCreateEvent,
|
||||||
modifier = Modifier.weight(1f).fillMaxWidth(),
|
modifier = Modifier.weight(1f).fillMaxWidth(),
|
||||||
@@ -1814,7 +1803,10 @@ private fun SplitDots(
|
|||||||
if (events.isEmpty()) return
|
if (events.isEmpty()) return
|
||||||
val soften = LocalSoftenColors.current
|
val soften = LocalSoftenColors.current
|
||||||
val dimCutoff = LocalDimCutoff.current
|
val dimCutoff = LocalDimCutoff.current
|
||||||
|
// Held to the dots' height so a "+N" doesn't grow the row and push the dots
|
||||||
|
// down; the label overflows it evenly instead (#142).
|
||||||
Row(
|
Row(
|
||||||
|
modifier = Modifier.height(SPLIT_DOT_SIZE),
|
||||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
@@ -1849,6 +1841,7 @@ private fun SplitDots(
|
|||||||
style = MaterialTheme.typography.labelSmall,
|
style = MaterialTheme.typography.labelSmall,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.wrapContentHeight(unbounded = true)
|
||||||
.morphBounds(MonthMorphKey.Overflow(date))
|
.morphBounds(MonthMorphKey.Overflow(date))
|
||||||
.alpha(if (allEnded(hidden, date, dimCutoff)) EventDimAlpha else 1f),
|
.alpha(if (allEnded(hidden, date, dimCutoff)) EventDimAlpha else 1f),
|
||||||
)
|
)
|
||||||
@@ -1872,7 +1865,7 @@ private fun SplitMonthAgendaPane(
|
|||||||
.sorted()
|
.sorted()
|
||||||
val dimCutoff = LocalDimCutoff.current
|
val dimCutoff = LocalDimCutoff.current
|
||||||
val listState = key(state.month) { rememberLazyListState() }
|
val listState = key(state.month) { rememberLazyListState() }
|
||||||
LazyColumn(state = listState, contentPadding = PaddingValues(top = 8.dp, bottom = 96.dp)) {
|
LazyColumn(state = listState, contentPadding = PaddingValues(top = 4.dp, bottom = 96.dp)) {
|
||||||
agendaDays(
|
agendaDays(
|
||||||
days = days.map { AgendaDay(it, state.instancesByDay[it].orEmpty()) },
|
days = days.map { AgendaDay(it, state.instancesByDay[it].orEmpty()) },
|
||||||
today = state.today,
|
today = state.today,
|
||||||
@@ -1882,6 +1875,7 @@ private fun SplitMonthAgendaPane(
|
|||||||
dimmed = { event, day -> dimCutoff != null && event.isPastOn(day, dimCutoff) },
|
dimmed = { event, day -> dimCutoff != null && event.isPastOn(day, dimCutoff) },
|
||||||
onOpenDay = onOpenDay,
|
onOpenDay = onOpenDay,
|
||||||
onEventClick = onEventClick,
|
onEventClick = onEventClick,
|
||||||
|
compact = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1889,7 +1883,8 @@ private fun SplitMonthAgendaPane(
|
|||||||
/**
|
/**
|
||||||
* The selected day's events, in the agenda's own row vocabulary so the two
|
* The selected day's events, in the agenda's own row vocabulary so the two
|
||||||
* surfaces read as one app. The date header opens the full Day view, matching
|
* surfaces read as one app. The date header opens the full Day view, matching
|
||||||
* the Week and Agenda headers (#37).
|
* the Week and Agenda headers (#37). It is shown as the filter chip itself,
|
||||||
|
* whose ✕ clears the day filter back to the whole month (#142).
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
internal fun SplitDayPane(
|
internal fun SplitDayPane(
|
||||||
@@ -1899,6 +1894,7 @@ internal fun SplitDayPane(
|
|||||||
events: List<EventInstance>?,
|
events: List<EventInstance>?,
|
||||||
zone: TimeZone,
|
zone: TimeZone,
|
||||||
onOpenDay: (LocalDate) -> Unit,
|
onOpenDay: (LocalDate) -> Unit,
|
||||||
|
onClearSelection: () -> Unit,
|
||||||
onEventClick: (EventInstance) -> Unit,
|
onEventClick: (EventInstance) -> Unit,
|
||||||
onCreateEvent: (LocalDate) -> Unit,
|
onCreateEvent: (LocalDate) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
@@ -1910,7 +1906,23 @@ internal fun SplitDayPane(
|
|||||||
val enter = itemEnter()
|
val enter = itemEnter()
|
||||||
val fadeSpec = rememberCalendarFadeSpec()
|
val fadeSpec = rememberCalendarFadeSpec()
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
AgendaDayHeader(date = date, today = today, onOpenDay = onOpenDay)
|
InputChip(
|
||||||
|
selected = true,
|
||||||
|
onClick = { onOpenDay(date) },
|
||||||
|
label = {
|
||||||
|
Text(agendaDayLabel(date, today), style = MaterialTheme.typography.titleSmall)
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Close,
|
||||||
|
contentDescription = stringResource(R.string.month_split_clear_filter),
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.clickable(onClick = onClearSelection),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier.padding(start = 16.dp),
|
||||||
|
)
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
targetState = date to events,
|
targetState = date to events,
|
||||||
modifier = Modifier.weight(1f).fillMaxWidth(),
|
modifier = Modifier.weight(1f).fillMaxWidth(),
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ internal fun MonthStylePreview(
|
|||||||
events = sample.month.instancesByDay[today].orEmpty(),
|
events = sample.month.instancesByDay[today].orEmpty(),
|
||||||
zone = zone,
|
zone = zone,
|
||||||
onOpenDay = {},
|
onOpenDay = {},
|
||||||
|
onClearSelection = {},
|
||||||
onEventClick = {},
|
onEventClick = {},
|
||||||
onCreateEvent = {},
|
onCreateEvent = {},
|
||||||
modifier = Modifier.fillMaxWidth().height(SPLIT_PANE_HEIGHT),
|
modifier = Modifier.fillMaxWidth().height(SPLIT_PANE_HEIGHT),
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
إصلاحات
|
||||||
|
• يعرض عرض الشهر المقسّم أحداثًا أكثر: يظهر تاريخ اليوم المحدد مرة واحدة فقط في شريحة التصفية، وصارت رؤوس الأيام تشغل مساحة أقل.
|
||||||
|
• لم تعد نقاط الأحداث في الشبكة المقسّمة تنزل للأسفل في الأيام التي تعرض „+N“.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Выпраўлена
|
||||||
|
• Падзелены выгляд месяца змяшчае больш падзей: дата абранага дня паказваецца толькі раз, у чыпе фільтра, а загалоўкі дзён займаюць менш месца.
|
||||||
|
• Кропкі падзей у падзеленай сетцы больш не з'язджаюць уніз у днях з «+N».
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Opraveno
|
||||||
|
• Rozdělený měsíční pohled pojme více událostí: vybraný den ukazuje datum jen jednou, v čipu filtru, a záhlaví dnů zabírají méně místa.
|
||||||
|
• Tečky událostí v rozdělené mřížce už ve dnech s „+N“ nesjíždějí dolů.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Behoben
|
||||||
|
• Die geteilte Monatsansicht zeigt mehr Termine: Ein gewählter Tag zeigt sein Datum nur noch einmal, im Filter-Chip, und die Tageskopfzeilen brauchen weniger Platz.
|
||||||
|
• Die Termin-Punkte im geteilten Raster rutschen an Tagen mit „+N“ nicht mehr nach unten.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Fixed
|
||||||
|
• The split month view fits more events: a selected day shows its date once, in the filter chip, and the day headers take less room.
|
||||||
|
• Event dots in the split grid no longer drop down on days with a "+N".
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Corregido
|
||||||
|
• La vista mensual dividida muestra más eventos: el día seleccionado muestra su fecha una sola vez, en el chip del filtro, y las cabeceras de día ocupan menos espacio.
|
||||||
|
• Los puntos de eventos de la cuadrícula dividida ya no bajan en los días con «+N».
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Corrigé
|
||||||
|
• La vue mensuelle partagée affiche plus d’événements : le jour sélectionné n’affiche plus sa date qu’une fois, dans la puce de filtre, et les en-têtes de jour prennent moins de place.
|
||||||
|
• Les points d’événements de la grille partagée ne descendent plus les jours affichant « +N ».
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Javítva
|
||||||
|
• A megosztott havi nézet több eseményt mutat: a kiválasztott nap dátuma csak egyszer, a szűrőchipben jelenik meg, és a napfejlécek kevesebb helyet foglalnak.
|
||||||
|
• A megosztott rács eseménypöttyei már nem csúsznak lejjebb a „+N” jelzésű napokon.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Corretto
|
||||||
|
• La vista mensile divisa mostra più eventi: il giorno selezionato mostra la data una sola volta, nel chip del filtro, e le intestazioni dei giorni occupano meno spazio.
|
||||||
|
• I puntini degli eventi nella griglia divisa non scendono più nei giorni con «+N».
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
修正
|
||||||
|
• 分割月表示に表示できる予定が増えました。選択した日の日付はフィルターチップに一度だけ表示され、日付見出しも小さくなりました。
|
||||||
|
• 「+N」が表示される日に、分割グリッドの予定ドットが下にずれなくなりました。
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Opgelost
|
||||||
|
• De gesplitste maandweergave toont meer afspraken: een gekozen dag toont zijn datum nog maar één keer, in de filterchip, en de dagkoppen nemen minder ruimte in.
|
||||||
|
• De afspraakstippen in het gesplitste raster zakken niet meer weg op dagen met „+N”.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Poprawki
|
||||||
|
• Podzielony widok miesiąca mieści więcej wydarzeń: wybrany dzień pokazuje datę tylko raz, w chipie filtra, a nagłówki dni zajmują mniej miejsca.
|
||||||
|
• Kropki wydarzeń w podzielonej siatce nie zjeżdżają już w dół w dniach z „+N”.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Corrigido
|
||||||
|
• A visualização mensal dividida mostra mais eventos: o dia selecionado mostra a data só uma vez, no chip do filtro, e os cabeçalhos dos dias ocupam menos espaço.
|
||||||
|
• Os pontos de eventos na grade dividida não descem mais nos dias com “+N”.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Corrigido
|
||||||
|
• A vista mensal dividida mostra mais eventos: o dia selecionado mostra a data só uma vez, no chip do filtro, e os cabeçalhos dos dias ocupam menos espaço.
|
||||||
|
• Os pontos de eventos na grelha dividida já não descem nos dias com «+N».
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Исправлено
|
||||||
|
• Разделённый вид месяца вмещает больше событий: дата выбранного дня показывается один раз, в чипе фильтра, а заголовки дней занимают меньше места.
|
||||||
|
• Точки событий в разделённой сетке больше не съезжают вниз в днях с «+N».
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Opravené
|
||||||
|
• Rozdelené mesačné zobrazenie pojme viac udalostí: vybraný deň ukazuje dátum len raz, v čipe filtra, a záhlavia dní zaberajú menej miesta.
|
||||||
|
• Bodky udalostí v rozdelenej mriežke už v dňoch s „+N“ neklesajú nadol.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
修复
|
||||||
|
• 分割月视图可以显示更多日程:所选日期只在筛选标签中显示一次,日期标题也更紧凑。
|
||||||
|
• 显示“+N”的日子里,分割网格中的日程圆点不再下移。
|
||||||
Reference in New Issue
Block a user