Compare commits
35 Commits
v2.11.0
...
fdee311658
| Author | SHA1 | Date | |
|---|---|---|---|
| fdee311658 | |||
|
|
5844539db2 | ||
|
|
2cc83d7714 | ||
|
|
dada1bbe72 | ||
|
|
e061cbe127 | ||
|
|
67511ce9be | ||
|
|
2e90682874 | ||
|
|
2a4cb6a896 | ||
| 69460bc35a | |||
|
|
bf10deaf5c | ||
|
|
b9e861af62 | ||
|
|
2eadda937b | ||
|
|
71b90fa184 | ||
|
|
4e9cf88bd4 | ||
|
|
b999202629 | ||
|
|
6f0e13a4a2 | ||
|
|
9ef7b33800 | ||
|
|
d04b431f2c | ||
|
|
dbeeadff80 | ||
|
|
f4a169ef5f | ||
|
|
604099b3f2 | ||
|
|
a3e6541512 | ||
| fb2a40114a | |||
| e1f79df67a | |||
| e258a4a7f2 | |||
| 3f27a47d1e | |||
| feb87a1e73 | |||
| 28e464a616 | |||
| 93df6d6d62 | |||
| 49ddb9437b | |||
| e1cf00999d | |||
| 2d0d707a7d | |||
| de1fe31223 | |||
| 273cfce969 | |||
| b6a45b7264 |
44
CHANGELOG.md
44
CHANGELOG.md
@@ -5,6 +5,46 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.12.0] — 2026-06-28
|
||||
|
||||
### Added
|
||||
- See past events your way. Two new settings change how events that have already
|
||||
ended are shown. **Past events** (Settings → Appearance → Agenda) lets the
|
||||
agenda — both in the app and the home-screen "Upcoming" widget — keep them as
|
||||
usual, dim them, or hide them from the list entirely. **Dim completed events**
|
||||
(Settings → Appearance) separately fades finished events in the month and week
|
||||
views. Both are off by default, an event only counts as finished once it has
|
||||
actually ended (events still in progress are never dimmed), and the lists
|
||||
update on their own as the day goes on. Thanks to @ptab for the suggestion
|
||||
([#12]).
|
||||
|
||||
### Changed
|
||||
- Readable titles on overlapping events. In the week and day views, events that
|
||||
overlap split a day into slim columns where the title used to be clipped to a
|
||||
character or two. The title now wraps across as many lines as the block can
|
||||
fit, and the time is hidden on those narrow blocks so the name can fill the
|
||||
space — so you can tell events apart without opening each one. Thanks to @ptab
|
||||
for the suggestion ([#13]).
|
||||
|
||||
## [2.11.2] — 2026-06-28
|
||||
|
||||
### Added
|
||||
- Jump straight to typing a title. When you start a new event, Calendula now puts
|
||||
the cursor in the title field and opens the keyboard right away, so you can type
|
||||
the name without an extra tap. It's on by default and only affects creating an
|
||||
event — editing never grabs focus — and a new **Focus title on new event**
|
||||
switch (Settings → New event form) turns it off. Thanks to @abrossimow for the
|
||||
suggestion ([#10]).
|
||||
|
||||
## [2.11.1] — 2026-06-28
|
||||
|
||||
### Fixed
|
||||
- Calendula can now be set as your default calendar app. It registers the
|
||||
calendar-app intent filters the system uses, so it appears in the chooser when
|
||||
you tap a date in a launcher or clock — and opening one takes you straight to
|
||||
that day. Android has no way for an app to make itself the default, so you pick
|
||||
it once from the system picker. Thanks to @abrossimow for the report ([#9]).
|
||||
|
||||
## [2.11.0] — 2026-06-27
|
||||
|
||||
### Added
|
||||
@@ -685,3 +725,7 @@ automatically, with zero telemetry and no internet permission.
|
||||
[#6]: https://codeberg.org/jlmakiola/calendula/issues/6
|
||||
[#7]: https://codeberg.org/jlmakiola/calendula/issues/7
|
||||
[#8]: https://codeberg.org/jlmakiola/calendula/issues/8
|
||||
[#9]: https://codeberg.org/jlmakiola/calendula/issues/9
|
||||
[#10]: https://codeberg.org/jlmakiola/calendula/issues/10
|
||||
[#12]: https://codeberg.org/jlmakiola/calendula/issues/12
|
||||
[#13]: https://codeberg.org/jlmakiola/calendula/issues/13
|
||||
|
||||
@@ -28,8 +28,8 @@ android {
|
||||
// which builds this version and then creates the matching vX.Y.Z tag +
|
||||
// release itself (versionCode is pinned to MAJOR*10000 + MINOR*100 +
|
||||
// PATCH from versionName, e.g. 2.7.2 -> 20702). See docs/RELEASING.md.
|
||||
versionCode = 21100
|
||||
versionName = "2.11.0"
|
||||
versionCode = 21200
|
||||
versionName = "2.12.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@@ -59,6 +59,35 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Be selectable as the system calendar app. Android has no API for
|
||||
an app to make itself the default, so registering the filters
|
||||
launchers and the OS use is what lets the user pick Calendula
|
||||
from the system chooser when a date action fires (issue #9).
|
||||
APP_CALENDAR is the "open the calendar app" action; the VIEW
|
||||
filters below catch a tapped date. -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.APP_CALENDAR" />
|
||||
</intent-filter>
|
||||
<!-- A launcher/clock date tap fires ACTION_VIEW on the provider's
|
||||
time Uri (content://com.android.calendar/time/<epochMillis>);
|
||||
some surfaces use the time/epoch mime type. We open the day view
|
||||
on that date (MainActivity.calendarTimeDateOrNull). -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:scheme="content"
|
||||
android:host="com.android.calendar"
|
||||
android:pathPrefix="/time" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="time/epoch" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Open a .ics file (file manager / email attachment / browser). -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
@@ -35,6 +35,9 @@ import de.jeanlucmakiola.calendula.ui.crash.submitCrashReport
|
||||
import de.jeanlucmakiola.calendula.ui.settings.SettingsViewModel
|
||||
import de.jeanlucmakiola.calendula.ui.theme.CalendulaTheme
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import kotlin.time.Instant
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity() {
|
||||
@@ -156,10 +159,33 @@ class MainActivity : AppCompatActivity() {
|
||||
Intent.ACTION_SEND -> IntentCompat.getParcelableExtra(this, Intent.EXTRA_STREAM, Uri::class.java)
|
||||
else -> null
|
||||
} ?: return null
|
||||
// The calendar "view time" Uri (a date tap) is also ACTION_VIEW/content;
|
||||
// it's a navigation, not a file to import, so [navRequestOrNull] owns it.
|
||||
if (uri.host == CALENDAR_PROVIDER_HOST) return null
|
||||
return uri.takeIf { it.scheme == "content" || it.scheme == "file" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The date a launcher/clock date tap points at, parsed from the AOSP calendar
|
||||
* "view time" intent: ACTION_VIEW on `content://com.android.calendar/time/
|
||||
* <epochMillis>`. Null for any other intent. The matching manifest filter is
|
||||
* what lets users pick Calendula from the system calendar chooser (issue #9).
|
||||
*/
|
||||
private fun Intent.calendarTimeDateOrNull(): LocalDate? {
|
||||
if (action != Intent.ACTION_VIEW) return null
|
||||
val uri = data ?: return null
|
||||
if (uri.host != CALENDAR_PROVIDER_HOST) return null
|
||||
val segments = uri.pathSegments
|
||||
if (segments.firstOrNull() != "time") return null
|
||||
val millis = segments.getOrNull(1)?.toLongOrNull() ?: return null
|
||||
return Instant.fromEpochMilliseconds(millis)
|
||||
.toLocalDateTime(TimeZone.currentSystemDefault()).date
|
||||
}
|
||||
|
||||
private fun Intent.navRequestOrNull(): WidgetNavRequest? {
|
||||
// An external date tap (launcher/clock) has no widget source, so it opens
|
||||
// the day view rooted over the default home view (OpenDate source = null).
|
||||
calendarTimeDateOrNull()?.let { return WidgetNavRequest.OpenDate(it.toString(), source = null) }
|
||||
val source = sourceViewOrNull()
|
||||
val eventId = getLongExtra(EXTRA_EVENT_ID, -1L)
|
||||
return when {
|
||||
@@ -201,6 +227,10 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
// The calendar provider's authority/host. A date tap arrives as
|
||||
// ACTION_VIEW on content://com.android.calendar/time/<epochMillis>.
|
||||
private const val CALENDAR_PROVIDER_HOST = "com.android.calendar"
|
||||
|
||||
private const val EXTRA_EVENT_ID = "de.jeanlucmakiola.calendula.extra.EVENT_ID"
|
||||
private const val EXTRA_BEGIN_MILLIS = "de.jeanlucmakiola.calendula.extra.BEGIN"
|
||||
private const val EXTRA_END_MILLIS = "de.jeanlucmakiola.calendula.extra.END"
|
||||
|
||||
@@ -38,6 +38,19 @@ sealed interface WeekStartPref {
|
||||
*/
|
||||
enum class TimeFormatPref { AUTO, TWELVE_HOUR, TWENTY_FOUR_HOUR }
|
||||
|
||||
/**
|
||||
* How the Agenda screen treats events that have already finished today: [SHOW]
|
||||
* leaves them as-is (the historical behaviour), [DIM] fades them, [HIDE] drops
|
||||
* them from the list entirely.
|
||||
*/
|
||||
enum class PastEventDisplay { SHOW, DIM, HIDE }
|
||||
|
||||
/** Parse a stored [PastEventDisplay.name]; unknown/null falls back to [default]. */
|
||||
fun parsePastEventDisplay(
|
||||
stored: String?,
|
||||
default: PastEventDisplay = PastEventDisplay.SHOW,
|
||||
): PastEventDisplay = PastEventDisplay.entries.firstOrNull { it.name == stored } ?: default
|
||||
|
||||
/**
|
||||
* Resolve to a concrete 24-hour flag. AUTO defers to [systemIs24Hour] (the
|
||||
* device's `DateFormat.is24HourFormat` value).
|
||||
@@ -116,6 +129,31 @@ class SettingsPrefs @Inject constructor(
|
||||
store.edit { it[SHOW_HOUR_LINES_KEY] = enabled }
|
||||
}
|
||||
|
||||
/**
|
||||
* How the Agenda screen treats events that already ended today. Defaults to
|
||||
* [PastEventDisplay.SHOW] — the historical behaviour; users opt into dimming
|
||||
* or hiding.
|
||||
*/
|
||||
val pastEventDisplay: Flow<PastEventDisplay> = store.data.map { prefs ->
|
||||
prefs[PAST_EVENT_DISPLAY_KEY].toEnum(PastEventDisplay.SHOW)
|
||||
}
|
||||
|
||||
suspend fun setPastEventDisplay(mode: PastEventDisplay) {
|
||||
store.edit { it[PAST_EVENT_DISPLAY_KEY] = mode.name }
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the month/week grids fade events that have already finished.
|
||||
* Defaults to OFF — independent of the Agenda's [pastEventDisplay].
|
||||
*/
|
||||
val dimCompletedEvents: Flow<Boolean> = store.data.map { prefs ->
|
||||
prefs[DIM_COMPLETED_EVENTS_KEY] ?: false
|
||||
}
|
||||
|
||||
suspend fun setDimCompletedEvents(enabled: Boolean) {
|
||||
store.edit { it[DIM_COMPLETED_EVENTS_KEY] = enabled }
|
||||
}
|
||||
|
||||
/**
|
||||
* How far ahead the in-app Agenda screen shows events (v2.11). Defaults to
|
||||
* [AgendaRange.Month] — a month of upcoming events. Independent of the
|
||||
@@ -182,6 +220,20 @@ class SettingsPrefs @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether opening the new-event form focuses the title field and raises the
|
||||
* keyboard straight away (issue #10). Default ON — a new event almost always
|
||||
* gets a title, so this saves a tap; users who set the time/calendar first
|
||||
* can turn it off. Only the create form auto-focuses — editing never does.
|
||||
*/
|
||||
val autofocusEventTitle: Flow<Boolean> = store.data.map { prefs ->
|
||||
prefs[AUTOFOCUS_EVENT_TITLE_KEY] ?: true
|
||||
}
|
||||
|
||||
suspend fun setAutofocusEventTitle(enabled: Boolean) {
|
||||
store.edit { it[AUTOFOCUS_EVENT_TITLE_KEY] = enabled }
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether Calendula posts reminder notifications (v1.4). Defaults to ON —
|
||||
* for users whose only calendar app this is, reminders are essential; the
|
||||
@@ -390,8 +442,11 @@ class SettingsPrefs @Inject constructor(
|
||||
internal val AGENDA_SHOW_RANGE_BAR_KEY = booleanPreferencesKey("agenda_show_range_bar")
|
||||
internal val TIME_FORMAT_KEY = stringPreferencesKey("time_format")
|
||||
internal val SHOW_HOUR_LINES_KEY = booleanPreferencesKey("show_hour_lines")
|
||||
internal val PAST_EVENT_DISPLAY_KEY = stringPreferencesKey("agenda_past_event_display")
|
||||
internal val DIM_COMPLETED_EVENTS_KEY = booleanPreferencesKey("dim_completed_events")
|
||||
internal val DEFAULT_VIEW_KEY = stringPreferencesKey("default_view")
|
||||
internal val FORM_FIELDS_KEY = stringPreferencesKey("event_form_default_fields")
|
||||
internal val AUTOFOCUS_EVENT_TITLE_KEY = booleanPreferencesKey("autofocus_event_title")
|
||||
internal val REMINDERS_ENABLED_KEY = booleanPreferencesKey("reminders_enabled")
|
||||
internal val REMINDER_ONBOARDING_KEY = booleanPreferencesKey("reminder_onboarding_done")
|
||||
internal val ALLOW_COLOR_UNSUPPORTED_KEY =
|
||||
|
||||
@@ -40,6 +40,14 @@ data class EventInstance(
|
||||
val location: String?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Whether this event has finished relative to [now] — its end is at or before
|
||||
* the current instant. An in-progress event (already started but not yet ended)
|
||||
* is *not* considered ended. All-day events end at the exclusive next-midnight,
|
||||
* so they only count as ended once their day is fully over.
|
||||
*/
|
||||
fun EventInstance.hasEnded(now: Instant): Boolean = end <= now
|
||||
|
||||
data class EventDetail(
|
||||
val instance: EventInstance,
|
||||
val description: String?,
|
||||
|
||||
@@ -196,7 +196,9 @@ fun CalendarHost(
|
||||
dismissCoveringOverlays()
|
||||
createDateIso = null
|
||||
pendingDayIso = req.dateIso
|
||||
viewStack = viewBaseStack(defaultView, req.source).drillToDay()
|
||||
// No widget source (an external date tap) roots over the default
|
||||
// home view, so backing out of the day returns home then exits.
|
||||
viewStack = viewBaseStack(defaultView, req.source ?: defaultView).drillToDay()
|
||||
onWidgetNavConsumed()
|
||||
}
|
||||
is WidgetNavRequest.OpenEvent -> {
|
||||
|
||||
@@ -13,8 +13,13 @@ import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
* detail-key channel and leave the base view untouched.)
|
||||
*/
|
||||
sealed interface WidgetNavRequest {
|
||||
/** Open the day view anchored on [dateIso] (an ISO `yyyy-MM-dd` date), over [source]. */
|
||||
data class OpenDate(val dateIso: String, val source: CalendarView) : WidgetNavRequest
|
||||
/**
|
||||
* Open the day view anchored on [dateIso] (an ISO `yyyy-MM-dd` date), over
|
||||
* [source]. A null [source] means the request came from outside the app (a
|
||||
* launcher/clock date tap, issue #9) rather than a widget, so it roots over
|
||||
* the default home view instead of a widget's view.
|
||||
*/
|
||||
data class OpenDate(val dateIso: String, val source: CalendarView?) : WidgetNavRequest
|
||||
|
||||
/** Open one occurrence's detail (an agenda-widget event tap), over [source]. */
|
||||
data class OpenEvent(
|
||||
|
||||
@@ -45,6 +45,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -53,7 +54,9 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.data.prefs.PastEventDisplay
|
||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||
import de.jeanlucmakiola.calendula.domain.hasEnded
|
||||
import de.jeanlucmakiola.calendula.ui.common.AgendaRangePicker
|
||||
import de.jeanlucmakiola.calendula.ui.common.agendaRangeLabel
|
||||
import de.jeanlucmakiola.calendula.ui.common.calendarAnimateItem
|
||||
@@ -61,12 +64,14 @@ import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
|
||||
import de.jeanlucmakiola.calendula.ui.common.GroupedRow
|
||||
import de.jeanlucmakiola.calendula.ui.common.Position
|
||||
import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill
|
||||
import de.jeanlucmakiola.calendula.ui.common.next
|
||||
import de.jeanlucmakiola.calendula.ui.common.pastelize
|
||||
import de.jeanlucmakiola.calendula.ui.common.positionOf
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCurrentMinute
|
||||
import de.jeanlucmakiola.calendula.ui.common.currentLocale
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatTimeOfDay
|
||||
@@ -96,6 +101,7 @@ fun AgendaScreen(
|
||||
) {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
val anchor by viewModel.anchor.collectAsStateWithLifecycle()
|
||||
val pastDisplay by viewModel.pastEventDisplay.collectAsStateWithLifecycle()
|
||||
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||
@@ -178,6 +184,7 @@ fun AgendaScreen(
|
||||
}
|
||||
AgendaContent(
|
||||
state = state,
|
||||
pastDisplay = pastDisplay,
|
||||
onRetry = viewModel::goToToday,
|
||||
onEventClick = onEventClick,
|
||||
modifier = Modifier
|
||||
@@ -275,6 +282,7 @@ private fun AgendaRangeBanner(
|
||||
@Composable
|
||||
private fun AgendaContent(
|
||||
state: AgendaUiState,
|
||||
pastDisplay: PastEventDisplay,
|
||||
onRetry: () -> Unit,
|
||||
onEventClick: (EventInstance) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -284,19 +292,42 @@ private fun AgendaContent(
|
||||
is AgendaUiState.Failure -> Box(modifier) {
|
||||
CalendarFailure(reason = state.reason, onRetry = onRetry)
|
||||
}
|
||||
is AgendaUiState.Success ->
|
||||
if (state.days.isEmpty()) {
|
||||
is AgendaUiState.Success -> {
|
||||
val now by rememberCurrentMinute()
|
||||
// Hiding drops finished events — and any day they leave empty; dimming
|
||||
// keeps them but fades the row. Recomputed each minute so events fall
|
||||
// away (or fade) as they end while the screen stays open.
|
||||
val days = if (pastDisplay == PastEventDisplay.HIDE) {
|
||||
state.days.mapNotNull { day ->
|
||||
val remaining = day.events.filterNot { it.hasEnded(now) }
|
||||
if (remaining.isEmpty()) null else day.copy(events = remaining)
|
||||
}
|
||||
} else {
|
||||
state.days
|
||||
}
|
||||
if (days.isEmpty()) {
|
||||
AgendaEmpty(modifier)
|
||||
} else {
|
||||
AgendaList(state = state, onEventClick = onEventClick, modifier = modifier)
|
||||
AgendaList(
|
||||
days = days,
|
||||
today = state.today,
|
||||
dimPast = pastDisplay == PastEventDisplay.DIM,
|
||||
now = now,
|
||||
onEventClick = onEventClick,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun AgendaList(
|
||||
state: AgendaUiState.Success,
|
||||
days: List<AgendaDay>,
|
||||
today: LocalDate,
|
||||
dimPast: Boolean,
|
||||
now: Instant,
|
||||
onEventClick: (EventInstance) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -305,9 +336,9 @@ private fun AgendaList(
|
||||
// Bottom inset clears the FAB stack so the last row stays tappable.
|
||||
contentPadding = PaddingValues(top = 8.dp, bottom = 96.dp),
|
||||
) {
|
||||
state.days.forEach { day ->
|
||||
days.forEach { day ->
|
||||
stickyHeader(key = "header-${day.date}") {
|
||||
AgendaDayHeader(date = day.date, today = state.today)
|
||||
AgendaDayHeader(date = day.date, today = today)
|
||||
}
|
||||
itemsIndexed(
|
||||
items = day.events,
|
||||
@@ -316,6 +347,7 @@ private fun AgendaList(
|
||||
AgendaEventRow(
|
||||
event = event,
|
||||
position = positionOf(index, day.events.size),
|
||||
dimmed = dimPast && event.hasEnded(now),
|
||||
modifier = calendarAnimateItem(),
|
||||
onClick = { onEventClick(event) },
|
||||
)
|
||||
@@ -348,13 +380,14 @@ private fun AgendaDayHeader(date: LocalDate, today: LocalDate) {
|
||||
private fun AgendaEventRow(
|
||||
event: EventInstance,
|
||||
position: Position,
|
||||
dimmed: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val dark = isSystemInDarkTheme()
|
||||
val title = event.title.ifBlank { stringResource(R.string.event_untitled) }
|
||||
GroupedRow(
|
||||
modifier = modifier,
|
||||
modifier = if (dimmed) modifier.alpha(EventDimAlpha) else modifier,
|
||||
title = title,
|
||||
summary = agendaTimeSummary(event),
|
||||
position = position,
|
||||
|
||||
@@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import de.jeanlucmakiola.calendula.data.calendar.CalendarRepository
|
||||
import de.jeanlucmakiola.calendula.data.di.IoDispatcher
|
||||
import de.jeanlucmakiola.calendula.data.prefs.PastEventDisplay
|
||||
import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs
|
||||
import de.jeanlucmakiola.calendula.data.prefs.resolveFirstDay
|
||||
import de.jeanlucmakiola.calendula.domain.CalendarSource
|
||||
@@ -53,6 +54,18 @@ class AgendaViewModel @Inject constructor(
|
||||
private val weekStartDay = settingsPrefs.weekStart
|
||||
.map { it.resolveFirstDay(Locale.getDefault()) }
|
||||
|
||||
/**
|
||||
* How to treat events that already ended today (show / dim / hide). A display
|
||||
* concern only, so it rides alongside the data state rather than re-querying;
|
||||
* the screen combines it with a per-minute "now" to fade or drop past rows.
|
||||
*/
|
||||
val pastEventDisplay: StateFlow<PastEventDisplay> = settingsPrefs.pastEventDisplay
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000L),
|
||||
initialValue = PastEventDisplay.SHOW,
|
||||
)
|
||||
|
||||
private val zone = TimeZone.currentSystemDefault()
|
||||
|
||||
private val todayDate: LocalDate
|
||||
|
||||
@@ -34,7 +34,7 @@ private val LineThickness = 2.dp
|
||||
* the middle of a minute. Drives the "now" line in the day/week grids.
|
||||
*/
|
||||
@Composable
|
||||
private fun rememberCurrentMinute(): State<Instant> {
|
||||
fun rememberCurrentMinute(): State<Instant> {
|
||||
val instant = remember { mutableStateOf(Clock.System.now()) }
|
||||
LaunchedEffect(Unit) {
|
||||
while (true) {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.jeanlucmakiola.calendula.ui.common
|
||||
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import kotlin.time.Instant
|
||||
|
||||
/**
|
||||
* The cut-off instant before which a calendar event counts as "completed" and is
|
||||
* drawn dimmed in the month/week grids — i.e. the current wall-clock minute when
|
||||
* the "dim completed events" setting is on, or `null` when it is off (nothing
|
||||
* dims). Provided per grid screen so only the event chips that read it recompose
|
||||
* as the minute ticks, mirroring [LocalShowHourLines] / [LocalUse24HourFormat].
|
||||
*/
|
||||
val LocalDimCutoff = compositionLocalOf<Instant?> { null }
|
||||
|
||||
/** Opacity applied to a completed/past event chip when it is dimmed. */
|
||||
const val EventDimAlpha = 0.4f
|
||||
@@ -81,6 +81,8 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.isSpecified
|
||||
@@ -479,6 +481,17 @@ private fun EventEditContent(
|
||||
?: MaterialTheme.colorScheme.primary
|
||||
val gap = 12.dp
|
||||
|
||||
// Issue #10: on a fresh create form (setting on, nothing typed yet) focus the
|
||||
// title and raise the keyboard so the user can type straight away. Keyed on
|
||||
// Unit so it runs once per open — not on every keystroke — and guarded so
|
||||
// editing or an imported/prefilled form never grabs focus.
|
||||
val titleFocusRequester = remember { FocusRequester() }
|
||||
LaunchedEffect(Unit) {
|
||||
if (state.autofocusTitle && !state.isEditing && form.title.isBlank()) {
|
||||
runCatching { titleFocusRequester.requestFocus() }
|
||||
}
|
||||
}
|
||||
|
||||
// Per-event colour applicability for the resolved calendar:
|
||||
// - palette calendars (Google, …) and local calendars always support it;
|
||||
// - synced calendars with no palette only when the user opted in, and even
|
||||
@@ -506,6 +519,10 @@ private fun EventEditContent(
|
||||
placeholder = stringResource(R.string.event_edit_title_hint),
|
||||
textStyle = MaterialTheme.typography.headlineMedium
|
||||
.copy(fontWeight = FontWeight.SemiBold),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp)
|
||||
.focusRequester(titleFocusRequester),
|
||||
)
|
||||
Spacer(Modifier.height(10.dp))
|
||||
Box(
|
||||
|
||||
@@ -29,6 +29,12 @@ data class EventEditUiState(
|
||||
val hiddenFields: List<EventFormField> = emptyList(),
|
||||
/** True while editing an existing event (the calendar is then fixed). */
|
||||
val isEditing: Boolean = false,
|
||||
/**
|
||||
* Whether to focus the title and raise the keyboard when this is a fresh
|
||||
* create form (issue #10). Mirrors the settings flag; the screen only acts
|
||||
* on it for a new event with an empty title, never when editing/importing.
|
||||
*/
|
||||
val autofocusTitle: Boolean = true,
|
||||
/**
|
||||
* True while an edit changed the recurrence rule — the save-scope dialog
|
||||
* then drops "only this event" (an exception row can't carry a rule).
|
||||
|
||||
@@ -119,6 +119,7 @@ class EventEditViewModel @Inject constructor(
|
||||
val lastUsed: Long?,
|
||||
val defaultFields: Set<EventFormField>,
|
||||
val allowColorOnUnsupported: Boolean,
|
||||
val autofocusTitle: Boolean,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -160,6 +161,7 @@ class EventEditViewModel @Inject constructor(
|
||||
prefs.lastUsedCalendarId,
|
||||
settingsPrefs.defaultFormFields,
|
||||
settingsPrefs.allowColorOnUnsupportedCalendars,
|
||||
settingsPrefs.autofocusEventTitle,
|
||||
::ExternalInputs,
|
||||
).flowOn(io),
|
||||
colorPalette,
|
||||
@@ -178,6 +180,7 @@ class EventEditViewModel @Inject constructor(
|
||||
visibleFields = visibleFields,
|
||||
hiddenFields = (EventFormField.entries.toSet() - visibleFields).sorted(),
|
||||
isEditing = local.editTarget != null,
|
||||
autofocusTitle = external.autofocusTitle,
|
||||
// A modified-occurrence exception can't carry its own rule, so
|
||||
// the scope dialog drops "only this event" after a rule change.
|
||||
recurrenceChanged = local.editTarget != null &&
|
||||
|
||||
@@ -36,6 +36,8 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberDrawerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
@@ -44,6 +46,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -60,10 +63,14 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.domain.hasEnded
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalDimCutoff
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCurrentMinute
|
||||
import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill
|
||||
import de.jeanlucmakiola.calendula.ui.common.calendarSlideTransition
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCalendarFadeSpec
|
||||
@@ -97,6 +104,14 @@ fun MonthScreen(
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
val month by viewModel.month.collectAsStateWithLifecycle()
|
||||
val weekStart by viewModel.weekStart.collectAsStateWithLifecycle()
|
||||
val dimCompleted by viewModel.dimCompletedEvents.collectAsStateWithLifecycle()
|
||||
// The instant before which an event counts as completed, or null when dimming
|
||||
// is off. derivedStateOf keeps the per-minute "now" from recomposing the
|
||||
// screen while the setting is off (it stays null regardless of the tick).
|
||||
val nowState = rememberCurrentMinute()
|
||||
val dimCutoff by remember(dimCompleted) {
|
||||
derivedStateOf { if (dimCompleted) nowState.value else null }
|
||||
}
|
||||
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||
@@ -193,14 +208,16 @@ fun MonthScreen(
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
WeekdayHeader(weekStart = weekStart)
|
||||
MonthContent(
|
||||
state = state,
|
||||
slideDir = slideDir,
|
||||
onSwipeNext = goNext,
|
||||
onSwipePrev = goPrev,
|
||||
onRetry = jumpToToday,
|
||||
onOpenDay = onOpenDay,
|
||||
)
|
||||
CompositionLocalProvider(LocalDimCutoff provides dimCutoff) {
|
||||
MonthContent(
|
||||
state = state,
|
||||
slideDir = slideDir,
|
||||
onSwipeNext = goNext,
|
||||
onSwipePrev = goPrev,
|
||||
onRetry = jumpToToday,
|
||||
onOpenDay = onOpenDay,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -558,6 +575,8 @@ private fun MonthBar(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val title = event.title.ifBlank { stringResource(R.string.event_untitled) }
|
||||
val dimCutoff = LocalDimCutoff.current
|
||||
val dimmed = dimCutoff != null && event.hasEnded(dimCutoff)
|
||||
val shape = RoundedCornerShape(
|
||||
topStart = if (continuesLeft) 0.dp else 4.dp,
|
||||
bottomStart = if (continuesLeft) 0.dp else 4.dp,
|
||||
@@ -565,7 +584,7 @@ private fun MonthBar(
|
||||
bottomEnd = if (continuesRight) 0.dp else 4.dp,
|
||||
)
|
||||
Box(
|
||||
modifier = modifier
|
||||
modifier = (if (dimmed) modifier.alpha(EventDimAlpha) else modifier)
|
||||
.background(pastelize(event.color, dark), shape)
|
||||
.padding(horizontal = 4.dp)
|
||||
.semantics { contentDescription = title },
|
||||
|
||||
@@ -59,6 +59,14 @@ class MonthViewModel @Inject constructor(
|
||||
initialValue = DayOfWeek.MONDAY,
|
||||
)
|
||||
|
||||
/** Whether to fade events that have already finished (display concern only). */
|
||||
val dimCompletedEvents: StateFlow<Boolean> = settingsPrefs.dimCompletedEvents
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000L),
|
||||
initialValue = false,
|
||||
)
|
||||
|
||||
private val todayDate: LocalDate
|
||||
get() = Clock.System.now().toLocalDateTime(zone).date
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import androidx.compose.material.icons.filled.ExpandLess
|
||||
import androidx.compose.material.icons.filled.ExpandMore
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.Gavel
|
||||
import androidx.compose.material.icons.filled.Keyboard
|
||||
import androidx.compose.material.icons.filled.Language
|
||||
import androidx.compose.material.icons.filled.Notifications
|
||||
import androidx.compose.material.icons.filled.Palette
|
||||
@@ -85,6 +86,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.data.crash.CrashReporter
|
||||
import de.jeanlucmakiola.calendula.data.prefs.CalendarReminderOverride
|
||||
import de.jeanlucmakiola.calendula.data.prefs.PastEventDisplay
|
||||
import de.jeanlucmakiola.calendula.data.prefs.ThemeMode
|
||||
import de.jeanlucmakiola.calendula.data.prefs.TimeFormatPref
|
||||
import de.jeanlucmakiola.calendula.data.prefs.WeekStartPref
|
||||
@@ -474,6 +476,7 @@ private fun AppearanceScreen(
|
||||
var showDefaultView by remember { mutableStateOf(false) }
|
||||
var showAgendaScreenRange by remember { mutableStateOf(false) }
|
||||
var showAgendaWidgetRange by remember { mutableStateOf(false) }
|
||||
var showPastEvents by remember { mutableStateOf(false) }
|
||||
|
||||
CollapsingScaffold(
|
||||
title = stringResource(R.string.settings_section_appearance),
|
||||
@@ -532,7 +535,7 @@ private fun AppearanceScreen(
|
||||
GroupedRow(
|
||||
title = stringResource(R.string.settings_hour_lines),
|
||||
summary = stringResource(R.string.settings_hour_lines_summary),
|
||||
position = Position.Bottom,
|
||||
position = Position.Middle,
|
||||
trailing = {
|
||||
Switch(
|
||||
checked = state.showHourLines,
|
||||
@@ -541,16 +544,36 @@ private fun AppearanceScreen(
|
||||
},
|
||||
onClick = { viewModel.setShowHourLines(!state.showHourLines) },
|
||||
)
|
||||
GroupedRow(
|
||||
title = stringResource(R.string.settings_dim_completed),
|
||||
summary = stringResource(R.string.settings_dim_completed_summary),
|
||||
position = Position.Bottom,
|
||||
trailing = {
|
||||
Switch(
|
||||
checked = state.dimCompletedEvents,
|
||||
onCheckedChange = viewModel::setDimCompletedEvents,
|
||||
)
|
||||
},
|
||||
onClick = { viewModel.setDimCompletedEvents(!state.dimCompletedEvents) },
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
// Agenda
|
||||
// Agenda — the only group labelled, so its agenda-specific rows are easy
|
||||
// to pick out among the otherwise unheadered Appearance settings.
|
||||
SectionHeader(stringResource(R.string.settings_agenda_header))
|
||||
GroupedRow(
|
||||
title = stringResource(R.string.settings_agenda_range),
|
||||
summary = agendaRangeLabel(state.agendaScreenRange),
|
||||
position = Position.Top,
|
||||
onClick = { showAgendaScreenRange = true },
|
||||
)
|
||||
GroupedRow(
|
||||
title = stringResource(R.string.settings_past_events),
|
||||
summary = pastEventDisplayLabel(state.pastEventDisplay),
|
||||
position = Position.Middle,
|
||||
onClick = { showPastEvents = true },
|
||||
)
|
||||
GroupedRow(
|
||||
title = stringResource(R.string.settings_agenda_widget_range),
|
||||
summary = agendaRangeLabel(state.agendaWidgetRange),
|
||||
@@ -619,6 +642,16 @@ private fun AppearanceScreen(
|
||||
onDismiss = { showTimeFormat = false },
|
||||
)
|
||||
}
|
||||
if (showPastEvents) {
|
||||
OptionPicker(
|
||||
title = stringResource(R.string.settings_past_events),
|
||||
options = PastEventDisplay.entries,
|
||||
selected = state.pastEventDisplay,
|
||||
label = { pastEventDisplayLabel(it) },
|
||||
onSelect = viewModel::setPastEventDisplay,
|
||||
onDismiss = { showPastEvents = false },
|
||||
)
|
||||
}
|
||||
if (showDefaultView) {
|
||||
OptionPicker(
|
||||
title = stringResource(R.string.settings_default_view),
|
||||
@@ -673,6 +706,30 @@ private fun EventFormScreen(
|
||||
)
|
||||
}
|
||||
|
||||
// Auto-focus the title on a new event (issue #10) — on by default, since
|
||||
// most events get a title; raising the keyboard saves a tap. Off lets you
|
||||
// set the time/calendar first without the keyboard in the way.
|
||||
Spacer(Modifier.height(24.dp))
|
||||
GroupedRow(
|
||||
title = stringResource(R.string.settings_autofocus_title),
|
||||
summary = stringResource(R.string.settings_autofocus_title_hint),
|
||||
position = Position.Alone,
|
||||
leading = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Keyboard,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
},
|
||||
trailing = {
|
||||
Switch(
|
||||
checked = state.autofocusEventTitle,
|
||||
onCheckedChange = { viewModel.setAutofocusEventTitle(it) },
|
||||
)
|
||||
},
|
||||
onClick = { viewModel.setAutofocusEventTitle(!state.autofocusEventTitle) },
|
||||
)
|
||||
|
||||
// Per-event colour on calendars that publish no colour set (some
|
||||
// CalDAV) — off by default, with the honest caveat that the colour may
|
||||
// not survive their next sync. Local and palette calendars ignore it.
|
||||
@@ -1145,6 +1202,26 @@ private fun timeFormatLabel(pref: TimeFormatPref): String = stringResource(
|
||||
},
|
||||
)
|
||||
|
||||
/** A small primary-coloured group label, matching the Calendars settings screen. */
|
||||
@Composable
|
||||
private fun SectionHeader(text: String) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.padding(start = 24.dp, end = 24.dp, top = 16.dp, bottom = 4.dp),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun pastEventDisplayLabel(mode: PastEventDisplay): String = stringResource(
|
||||
when (mode) {
|
||||
PastEventDisplay.SHOW -> R.string.settings_past_events_show
|
||||
PastEventDisplay.DIM -> R.string.settings_past_events_dim
|
||||
PastEventDisplay.HIDE -> R.string.settings_past_events_hide
|
||||
},
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun languageLabel(tag: String?): String =
|
||||
if (tag == null) stringResource(R.string.settings_language_auto) else AppLanguage.displayName(tag)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.jeanlucmakiola.calendula.ui.settings
|
||||
|
||||
import de.jeanlucmakiola.calendula.data.prefs.PastEventDisplay
|
||||
import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs
|
||||
import de.jeanlucmakiola.calendula.data.prefs.ThemeMode
|
||||
import de.jeanlucmakiola.calendula.data.prefs.TimeFormatPref
|
||||
@@ -24,6 +25,10 @@ data class SettingsUiState(
|
||||
val timeFormat: TimeFormatPref = TimeFormatPref.AUTO,
|
||||
/** Whether the week/day timeline draws an hour separator line (v2.11). */
|
||||
val showHourLines: Boolean = false,
|
||||
/** How the Agenda screen treats events that already ended today. */
|
||||
val pastEventDisplay: PastEventDisplay = PastEventDisplay.SHOW,
|
||||
/** Whether the month/week grids fade events that have already finished. */
|
||||
val dimCompletedEvents: Boolean = false,
|
||||
/** How far ahead the in-app Agenda screen shows events (v2.11). */
|
||||
val agendaScreenRange: AgendaRange = AgendaRange.Month,
|
||||
/** How far ahead the agenda widget shows events (v2.11). */
|
||||
@@ -34,6 +39,8 @@ data class SettingsUiState(
|
||||
val defaultView: CalendarView = CalendarView.Week,
|
||||
/** Optional event-form fields shown by default (rest behind "more fields"). */
|
||||
val defaultFormFields: Set<EventFormField> = SettingsPrefs.DEFAULT_FORM_FIELDS,
|
||||
/** Whether the new-event form auto-focuses the title and shows the keyboard (#10). */
|
||||
val autofocusEventTitle: Boolean = true,
|
||||
/** Whether Calendula posts reminder notifications (v1.4). */
|
||||
val remindersEnabled: Boolean = true,
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import de.jeanlucmakiola.calendula.data.calendar.CalendarRepository
|
||||
import de.jeanlucmakiola.calendula.data.prefs.CalendarReminderOverride
|
||||
import de.jeanlucmakiola.calendula.data.prefs.PastEventDisplay
|
||||
import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs
|
||||
import de.jeanlucmakiola.calendula.data.prefs.ThemeMode
|
||||
import de.jeanlucmakiola.calendula.data.prefs.TimeFormatPref
|
||||
@@ -20,6 +21,7 @@ import de.jeanlucmakiola.calendula.domain.EventFormField
|
||||
import de.jeanlucmakiola.calendula.ui.agenda.AgendaRange
|
||||
import de.jeanlucmakiola.calendula.ui.agenda.storageValue
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.widget.agenda.AGENDA_PAST_DISPLAY_KEY
|
||||
import de.jeanlucmakiola.calendula.widget.agenda.AGENDA_RANGE_KEY
|
||||
import de.jeanlucmakiola.calendula.widget.agenda.AgendaWidget
|
||||
import de.jeanlucmakiola.calendula.widget.month.MonthWidget
|
||||
@@ -96,15 +98,24 @@ class SettingsViewModel @Inject constructor(
|
||||
) { view, screenRange, widgetRange, timeFormat, showHourLines ->
|
||||
ViewSettings(view, screenRange, widgetRange, timeFormat, showHourLines)
|
||||
},
|
||||
prefs.agendaShowRangeBar,
|
||||
) { base, defaults, overrides, views, showRangeBar ->
|
||||
combine(
|
||||
prefs.agendaShowRangeBar,
|
||||
prefs.autofocusEventTitle,
|
||||
prefs.pastEventDisplay,
|
||||
prefs.dimCompletedEvents,
|
||||
::MiscSettings,
|
||||
),
|
||||
) { base, defaults, overrides, views, misc ->
|
||||
base.copy(
|
||||
defaultView = views.defaultView,
|
||||
agendaScreenRange = views.agendaScreenRange,
|
||||
agendaWidgetRange = views.agendaWidgetRange,
|
||||
timeFormat = views.timeFormat,
|
||||
showHourLines = views.showHourLines,
|
||||
agendaShowRangeBar = showRangeBar,
|
||||
agendaShowRangeBar = misc.showRangeBar,
|
||||
autofocusEventTitle = misc.autofocusEventTitle,
|
||||
pastEventDisplay = misc.pastEventDisplay,
|
||||
dimCompletedEvents = misc.dimCompletedEvents,
|
||||
allowColorOnUnsupportedCalendars = defaults.allowColor,
|
||||
defaultReminderMinutes = defaults.defaultReminder,
|
||||
defaultAllDayReminderMinutes = defaults.allDayReminder,
|
||||
@@ -148,6 +159,13 @@ class SettingsViewModel @Inject constructor(
|
||||
val showHourLines: Boolean,
|
||||
)
|
||||
|
||||
private data class MiscSettings(
|
||||
val showRangeBar: Boolean,
|
||||
val autofocusEventTitle: Boolean,
|
||||
val pastEventDisplay: PastEventDisplay,
|
||||
val dimCompletedEvents: Boolean,
|
||||
)
|
||||
|
||||
fun setThemeMode(mode: ThemeMode) {
|
||||
viewModelScope.launch { prefs.setThemeMode(mode) }
|
||||
}
|
||||
@@ -201,6 +219,26 @@ class SettingsViewModel @Inject constructor(
|
||||
viewModelScope.launch { prefs.setShowHourLines(enabled) }
|
||||
}
|
||||
|
||||
fun setPastEventDisplay(mode: PastEventDisplay) {
|
||||
viewModelScope.launch {
|
||||
prefs.setPastEventDisplay(mode)
|
||||
// The agenda widget honours this setting too, so push it into each
|
||||
// instance's Glance state and recompose — same reliable-update path as
|
||||
// setAgendaWidgetRange (updateAll alone won't re-run the data preamble).
|
||||
widgetRefreshMutex.withLock {
|
||||
val manager = GlanceAppWidgetManager(appContext)
|
||||
manager.getGlanceIds(AgendaWidget::class.java).forEach { id ->
|
||||
updateAppWidgetState(appContext, id) { it[AGENDA_PAST_DISPLAY_KEY] = mode.name }
|
||||
}
|
||||
AgendaWidget().updateAll(appContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setDimCompletedEvents(enabled: Boolean) {
|
||||
viewModelScope.launch { prefs.setDimCompletedEvents(enabled) }
|
||||
}
|
||||
|
||||
fun setDefaultView(view: CalendarView) {
|
||||
viewModelScope.launch { prefs.setDefaultView(view) }
|
||||
}
|
||||
@@ -213,6 +251,10 @@ class SettingsViewModel @Inject constructor(
|
||||
viewModelScope.launch { prefs.setRemindersEnabled(enabled) }
|
||||
}
|
||||
|
||||
fun setAutofocusEventTitle(enabled: Boolean) {
|
||||
viewModelScope.launch { prefs.setAutofocusEventTitle(enabled) }
|
||||
}
|
||||
|
||||
fun setDefaultReminderMinutes(minutes: Int?) {
|
||||
viewModelScope.launch { prefs.setDefaultReminderMinutes(minutes) }
|
||||
}
|
||||
|
||||
@@ -45,7 +45,9 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberDrawerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
@@ -55,6 +57,7 @@ import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -73,11 +76,15 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||
import de.jeanlucmakiola.calendula.domain.hasEnded
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarFailure
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
|
||||
import de.jeanlucmakiola.calendula.ui.common.LocalDimCutoff
|
||||
import de.jeanlucmakiola.calendula.ui.common.NowLine
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCurrentMinute
|
||||
import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill
|
||||
import de.jeanlucmakiola.calendula.ui.common.calendarSlideTransition
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCalendarFadeSpec
|
||||
@@ -129,6 +136,14 @@ fun WeekScreen(
|
||||
) {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
val weekStart by viewModel.weekStartDate.collectAsStateWithLifecycle()
|
||||
val dimCompleted by viewModel.dimCompletedEvents.collectAsStateWithLifecycle()
|
||||
// The instant before which an event counts as completed, or null when dimming
|
||||
// is off. derivedStateOf keeps the per-minute "now" from recomposing the
|
||||
// screen while the setting is off (it stays null regardless of the tick).
|
||||
val nowState = rememberCurrentMinute()
|
||||
val dimCutoff by remember(dimCompleted) {
|
||||
derivedStateOf { if (dimCompleted) nowState.value else null }
|
||||
}
|
||||
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||
@@ -221,19 +236,21 @@ fun WeekScreen(
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
WeekContent(
|
||||
state = state,
|
||||
slideDir = slideDir,
|
||||
topSectionColor = topSectionColor,
|
||||
onSwipeNext = goNext,
|
||||
onSwipePrev = goPrev,
|
||||
onRetry = jumpToToday,
|
||||
onEventClick = onEventClick,
|
||||
onCreateAt = { d, minutes -> onCreateEvent(d, minutes) },
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
)
|
||||
CompositionLocalProvider(LocalDimCutoff provides dimCutoff) {
|
||||
WeekContent(
|
||||
state = state,
|
||||
slideDir = slideDir,
|
||||
topSectionColor = topSectionColor,
|
||||
onSwipeNext = goNext,
|
||||
onSwipePrev = goPrev,
|
||||
onRetry = jumpToToday,
|
||||
onEventClick = onEventClick,
|
||||
onCreateAt = { d, minutes -> onCreateEvent(d, minutes) },
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -550,8 +567,10 @@ private fun AllDayBar(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val title = event.title.ifBlank { stringResource(R.string.event_untitled) }
|
||||
val dimCutoff = LocalDimCutoff.current
|
||||
val dimmed = dimCutoff != null && event.hasEnded(dimCutoff)
|
||||
Box(
|
||||
modifier = modifier
|
||||
modifier = (if (dimmed) modifier.alpha(EventDimAlpha) else modifier)
|
||||
.background(pastelize(event.color, dark), RoundedCornerShape(4.dp))
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 6.dp, vertical = 2.dp)
|
||||
@@ -692,6 +711,7 @@ private fun DayColumnCard(
|
||||
EventBlock(
|
||||
block = block,
|
||||
dark = dark,
|
||||
height = height,
|
||||
onClick = { onEventClick(block.event) },
|
||||
modifier = Modifier
|
||||
.offset(x = laneWidth * block.lane, y = top)
|
||||
@@ -712,6 +732,7 @@ private fun DayColumnCard(
|
||||
private fun EventBlock(
|
||||
block: TimedBlock,
|
||||
dark: Boolean,
|
||||
height: Dp,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -720,9 +741,26 @@ private fun EventBlock(
|
||||
val locale = currentLocale()
|
||||
val timeLabel = "${minToHm(block.startMin, use24Hour, locale)}–" +
|
||||
minToHm(block.endMin, use24Hour, locale)
|
||||
val showTime = block.endMin - block.startMin >= 45
|
||||
// Only full-width (non-overlapping) blocks that are tall enough show the time.
|
||||
// On narrow overlapping columns we drop it so the title can wrap to fill the
|
||||
// whole block, mirroring Google Calendar.
|
||||
val showTime = block.endMin - block.startMin >= 45 && block.laneCount == 1
|
||||
val density = LocalDensity.current
|
||||
val titleLineHeight = with(density) {
|
||||
MaterialTheme.typography.labelMedium.lineHeight.toDp()
|
||||
}
|
||||
val timeLineHeight = with(density) {
|
||||
MaterialTheme.typography.labelSmall.lineHeight.toDp()
|
||||
}
|
||||
// Wrap the title across as many lines as the block can fit (minus the 2.dp
|
||||
// top/bottom padding and the reserved time line) instead of clipping it to a
|
||||
// single character on slim, overlapping blocks.
|
||||
val contentHeight = height - 4.dp - if (showTime) timeLineHeight else 0.dp
|
||||
val titleMaxLines = (contentHeight / titleLineHeight).toInt().coerceAtLeast(1)
|
||||
val dimCutoff = LocalDimCutoff.current
|
||||
val dimmed = dimCutoff != null && block.event.hasEnded(dimCutoff)
|
||||
Box(
|
||||
modifier = modifier
|
||||
modifier = (if (dimmed) modifier.alpha(EventDimAlpha) else modifier)
|
||||
.background(pastelize(block.event.color, dark), RoundedCornerShape(4.dp))
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 4.dp, vertical = 2.dp)
|
||||
@@ -732,18 +770,15 @@ private fun EventBlock(
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
maxLines = if (showTime) 1 else 2,
|
||||
maxLines = titleMaxLines,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = Color.Black.copy(alpha = 0.85f),
|
||||
)
|
||||
if (showTime) {
|
||||
// Narrow columns can't fit "13:00–14:00" on one line, so let it
|
||||
// wrap to a second line (after the dash) instead of clipping the
|
||||
// end time.
|
||||
Text(
|
||||
text = timeLabel,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
maxLines = 2,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = Color.Black.copy(alpha = 0.6f),
|
||||
)
|
||||
|
||||
@@ -50,6 +50,14 @@ class WeekViewModel @Inject constructor(
|
||||
private val zone = TimeZone.currentSystemDefault()
|
||||
private val locale: Locale = Locale.getDefault()
|
||||
|
||||
/** Whether to fade events that have already finished (display concern only). */
|
||||
val dimCompletedEvents: StateFlow<Boolean> = settingsPrefs.dimCompletedEvents
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000L),
|
||||
initialValue = false,
|
||||
)
|
||||
|
||||
private val todayDate: LocalDate
|
||||
get() = Clock.System.now().toLocalDateTime(zone).date
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.jeanlucmakiola.calendula.data.prefs.PastEventDisplay
|
||||
import de.jeanlucmakiola.calendula.data.prefs.is24Hour
|
||||
import de.jeanlucmakiola.calendula.data.prefs.resolveFirstDay
|
||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||
@@ -24,6 +25,7 @@ import kotlinx.datetime.toInstant
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import java.util.Locale
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
/**
|
||||
* How far either side of today the month widget pre-loads. The displayed month
|
||||
@@ -52,6 +54,8 @@ sealed interface AgendaWidgetData {
|
||||
* range is sliced from this in the composition (read reactively from
|
||||
* Glance state), so a range change is pure recomposition rather than a
|
||||
* flaky widget session restart — the same approach the month widget uses.
|
||||
* Kept unfiltered: hiding/dimming finished events also happens reactively
|
||||
* in the composition, against [now], for the same reliable-update reason.
|
||||
*/
|
||||
val days: List<AgendaDay>,
|
||||
/** Resolved clock convention for event time labels (the time-format pref). */
|
||||
@@ -60,6 +64,10 @@ sealed interface AgendaWidgetData {
|
||||
val weekStart: DayOfWeek,
|
||||
/** Saved range pref — the fallback when an instance has no Glance state yet. */
|
||||
val savedRange: AgendaRange,
|
||||
/** Saved past-event display pref — the fallback before Glance state is set. */
|
||||
val savedPastDisplay: PastEventDisplay,
|
||||
/** Snapshot instant the data was read at, for "has this event ended?" tests. */
|
||||
val now: Instant,
|
||||
) : AgendaWidgetData
|
||||
}
|
||||
|
||||
@@ -108,6 +116,7 @@ internal suspend fun Context.loadAgendaWidgetData(): AgendaWidgetData {
|
||||
val ep = widgetEntryPoint()
|
||||
val prefs = ep.settingsPrefs()
|
||||
val savedRange = prefs.agendaWidgetRange.first()
|
||||
val savedPastDisplay = prefs.pastEventDisplay.first()
|
||||
val weekStart = prefs.weekStart.first().resolveFirstDay(Locale.getDefault())
|
||||
// Load the widest selectable window once; the displayed range is sliced in
|
||||
// the composition from Glance state, so changing the range is a plain
|
||||
@@ -122,6 +131,8 @@ internal suspend fun Context.loadAgendaWidgetData(): AgendaWidgetData {
|
||||
is24Hour = is24Hour,
|
||||
weekStart = weekStart,
|
||||
savedRange = savedRange,
|
||||
savedPastDisplay = savedPastDisplay,
|
||||
now = Clock.System.now(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -43,11 +43,15 @@ import androidx.glance.text.Text
|
||||
import androidx.glance.text.TextStyle
|
||||
import de.jeanlucmakiola.calendula.MainActivity
|
||||
import de.jeanlucmakiola.calendula.R
|
||||
import de.jeanlucmakiola.calendula.data.prefs.PastEventDisplay
|
||||
import de.jeanlucmakiola.calendula.data.prefs.parsePastEventDisplay
|
||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||
import de.jeanlucmakiola.calendula.domain.hasEnded
|
||||
import de.jeanlucmakiola.calendula.ui.agenda.AgendaRange
|
||||
import de.jeanlucmakiola.calendula.ui.agenda.dayCount
|
||||
import de.jeanlucmakiola.calendula.ui.agenda.parseAgendaRange
|
||||
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
|
||||
import de.jeanlucmakiola.calendula.ui.common.formatTimeOfDay
|
||||
import de.jeanlucmakiola.calendula.ui.common.pastelize
|
||||
import de.jeanlucmakiola.calendula.widget.AgendaWidgetData
|
||||
@@ -79,6 +83,14 @@ import java.util.Locale
|
||||
*/
|
||||
internal val AGENDA_RANGE_KEY = stringPreferencesKey("agenda_range")
|
||||
|
||||
/**
|
||||
* Per-instance Glance state key holding the past-event display mode (as
|
||||
* [PastEventDisplay.name]). Read reactively in the composition for the same
|
||||
* reason as [AGENDA_RANGE_KEY] — so toggling the setting reflects on the live
|
||||
* widget without depending on the `provideGlance` preamble re-running.
|
||||
*/
|
||||
internal val AGENDA_PAST_DISPLAY_KEY = stringPreferencesKey("agenda_past_display")
|
||||
|
||||
class AgendaWidget : GlanceAppWidget() {
|
||||
|
||||
override val stateDefinition = PreferencesGlanceStateDefinition
|
||||
@@ -125,11 +137,26 @@ private fun AgendaWidgetBody(data: AgendaWidgetData, dark: Boolean) {
|
||||
// to the saved pref for a freshly placed widget), then the wide
|
||||
// pre-loaded window is sliced to it — pure recomposition.
|
||||
val range = parseAgendaRange(currentState(AGENDA_RANGE_KEY), data.savedRange)
|
||||
val pastDisplay =
|
||||
parsePastEventDisplay(currentState(AGENDA_PAST_DISPLAY_KEY), data.savedPastDisplay)
|
||||
val rangeEnd = data.today.plus(
|
||||
range.dayCount(data.today, data.weekStart) - 1,
|
||||
DateTimeUnit.DAY,
|
||||
)
|
||||
val visibleDays = data.days.filter { it.date <= rangeEnd }
|
||||
// Slice to the chosen range, then drop finished events (and any day
|
||||
// they leave empty) when the mode is Hide — so "Upcoming" really is.
|
||||
val visibleDays = data.days
|
||||
.filter { it.date <= rangeEnd }
|
||||
.let { days ->
|
||||
if (pastDisplay == PastEventDisplay.HIDE) {
|
||||
days.mapNotNull { day ->
|
||||
val remaining = day.events.filterNot { it.hasEnded(data.now) }
|
||||
if (remaining.isEmpty()) null else day.copy(events = remaining)
|
||||
}
|
||||
} else {
|
||||
days
|
||||
}
|
||||
}
|
||||
if (visibleDays.isEmpty()) {
|
||||
WidgetMessage(R.string.agenda_empty_title)
|
||||
} else {
|
||||
@@ -143,7 +170,13 @@ private fun AgendaWidgetBody(data: AgendaWidgetData, dark: Boolean) {
|
||||
items(rows.size) { index ->
|
||||
when (val row = rows[index]) {
|
||||
is AgendaRow.Header -> DayHeaderRow(row.date, row.today)
|
||||
is AgendaRow.Event -> EventRow(row.event, dark, data.is24Hour)
|
||||
is AgendaRow.Event -> EventRow(
|
||||
event = row.event,
|
||||
dark = dark,
|
||||
is24Hour = data.is24Hour,
|
||||
dimmed = pastDisplay == PastEventDisplay.DIM &&
|
||||
row.event.hasEnded(data.now),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,9 +257,15 @@ private fun DayHeaderRow(date: LocalDate, today: LocalDate) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EventRow(event: EventInstance, dark: Boolean, is24Hour: Boolean) {
|
||||
private fun EventRow(event: EventInstance, dark: Boolean, is24Hour: Boolean, dimmed: Boolean) {
|
||||
val context = androidx.glance.LocalContext.current
|
||||
val title = event.title.ifBlank { context.getString(R.string.event_untitled) }
|
||||
// Glance has no generic alpha modifier, so dim by fading the colour stripe and
|
||||
// dropping both text lines to the lower-emphasis on-surface-variant tone.
|
||||
val stripeColor = pastelize(event.color, dark).let {
|
||||
if (dimmed) it.copy(alpha = EventDimAlpha) else it
|
||||
}
|
||||
val titleColor = if (dimmed) GlanceTheme.colors.onSurfaceVariant else GlanceTheme.colors.onSurface
|
||||
Row(
|
||||
modifier = GlanceModifier
|
||||
.fillMaxWidth()
|
||||
@@ -249,14 +288,14 @@ private fun EventRow(event: EventInstance, dark: Boolean, is24Hour: Boolean) {
|
||||
.width(5.dp)
|
||||
.height(36.dp)
|
||||
.cornerRadius(3.dp)
|
||||
.background(pastelize(event.color, dark)),
|
||||
.background(stripeColor),
|
||||
) {}
|
||||
Spacer(GlanceModifier.width(10.dp))
|
||||
Column(modifier = GlanceModifier.defaultWeight()) {
|
||||
Text(
|
||||
text = title,
|
||||
maxLines = 1,
|
||||
style = TextStyle(color = GlanceTheme.colors.onSurface, fontSize = 14.sp),
|
||||
style = TextStyle(color = titleColor, fontSize = 14.sp),
|
||||
)
|
||||
Text(
|
||||
text = eventTimeSummary(context, event, is24Hour),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Calendula</string>
|
||||
<string name="app_tagline">Ein moderner Kalender.</string>
|
||||
|
||||
<string name="state_loading">Lädt…</string>
|
||||
<string name="state_retry">Erneut versuchen</string>
|
||||
<string name="state_failure_unknown">Etwas ist schiefgelaufen.</string>
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="state_failure_no_calendars">Keine Kalender eingerichtet.</string>
|
||||
<string name="state_failure_no_calendars_action">System-Kalender-Einstellungen öffnen</string>
|
||||
<string name="state_failure_provider">Kalender konnte nicht gelesen werden.</string>
|
||||
|
||||
<!-- Permission-Flow (F1) -->
|
||||
<string name="permission_rationale_title">Alle Termine, schön im Blick</string>
|
||||
<string name="permission_rationale_body">Calendula braucht Zugriff auf deinen Kalender, um deine Termine zu zeigen und zu verwalten. Mehr verlangt die App nie.</string>
|
||||
@@ -26,7 +25,6 @@
|
||||
<string name="permission_benefit_privacy_title">Kein Tracking, niemals</string>
|
||||
<string name="permission_benefit_privacy_body">Keine Telemetrie, keine Analyse, keine Werbung.</string>
|
||||
<string name="permission_privacy_footnote">Bleibt auf deinem Gerät · keine Internet-Berechtigung</string>
|
||||
|
||||
<!-- Monatsansicht (S1) -->
|
||||
<string name="month_prev">Vorheriger Monat</string>
|
||||
<string name="month_next">Nächster Monat</string>
|
||||
@@ -35,14 +33,11 @@
|
||||
<string name="month_open_menu">Menü öffnen</string>
|
||||
<string name="month_action_settings">Einstellungen</string>
|
||||
<string name="month_a11y_today_prefix">Heute</string>
|
||||
|
||||
<!-- Wochenansicht (S2) -->
|
||||
<string name="week_today_action">Diese Woche</string>
|
||||
<string name="week_number_label">KW</string>
|
||||
|
||||
<!-- Tagesansicht (S3) -->
|
||||
<string name="day_today_action">Heute</string>
|
||||
|
||||
<!-- Event-Detail-Screen (S4) -->
|
||||
<string name="event_detail_back">Zurück</string>
|
||||
<string name="event_detail_edit">Bearbeiten</string>
|
||||
@@ -61,7 +56,6 @@
|
||||
<string name="event_delete_write_denied">Calendula braucht Schreibzugriff, um Termine zu löschen</string>
|
||||
<string name="dialog_cancel">Abbrechen</string>
|
||||
<string name="dialog_ok">OK</string>
|
||||
|
||||
<!-- Termin-Formular (v1.2 Erstellen) -->
|
||||
<string name="event_edit_new_title">Neuer Termin</string>
|
||||
<string name="event_edit_close">Schließen</string>
|
||||
@@ -94,7 +88,6 @@
|
||||
<string name="reminder_unit_weeks">Wochen</string>
|
||||
<string name="event_edit_availability">Verfügbarkeit</string>
|
||||
<string name="event_edit_visibility">Sichtbarkeit</string>
|
||||
|
||||
<!-- Termin-Formular — eigene Terminfarbe -->
|
||||
<string name="event_edit_color">Farbe</string>
|
||||
<string name="event_edit_color_default">Kalenderfarbe</string>
|
||||
@@ -103,7 +96,6 @@
|
||||
<string name="event_edit_color_unsupported">Für diesen Kalender nicht verfügbar</string>
|
||||
<string name="event_edit_color_unsupported_hint">Dieser Kalender stellt keine Farbpalette bereit. Du kannst eigene Farben für solche Kalender in den Einstellungen aktivieren.</string>
|
||||
<string name="event_edit_color_sync_warning">Dieser Kalender verwirft oder überschreibt die Farbe unter Umständen bei der nächsten Synchronisierung.</string>
|
||||
|
||||
<!-- Termin-Formular — Speicher-Konflikt (v2.0) -->
|
||||
<string name="event_edit_conflict_title">Termin wurde extern geändert</string>
|
||||
<string name="event_edit_conflict_body">Während du bearbeitet hast, wurde dieser Termin anderswo geändert — durch Synchronisierung oder eine andere App. Was soll mit deinen Änderungen passieren?</string>
|
||||
@@ -113,7 +105,6 @@
|
||||
<string name="event_edit_conflict_discard_hint">Der Termin bleibt, wie er jetzt ist</string>
|
||||
<string name="event_edit_gone_title">Termin wurde gelöscht</string>
|
||||
<string name="event_edit_gone_body">Dieser Termin wurde zwischenzeitlich gelöscht, etwa auf einem anderen Gerät. Deine Änderungen können nicht mehr gespeichert werden.</string>
|
||||
|
||||
<!-- Termin-Formular — Wiederholungs-Picker (v1.3) -->
|
||||
<string name="event_edit_recurrence_none">Wiederholt sich nicht</string>
|
||||
<string name="event_edit_recurrence_custom">Benutzerdefiniert</string>
|
||||
@@ -156,7 +147,6 @@
|
||||
<string name="event_attendee_tentative">Vorläufig</string>
|
||||
<string name="event_attendee_needs_action">Keine Antwort</string>
|
||||
<string name="event_attendee_unknown">—</string>
|
||||
|
||||
<!-- Event-Detail — vollständiges Auslesen (v0.6) -->
|
||||
<string name="event_detail_reminders">Erinnerungen</string>
|
||||
<string name="event_detail_timezone">Zeitzone</string>
|
||||
@@ -196,10 +186,8 @@
|
||||
<item quantity="one">%d Stunde</item>
|
||||
<item quantity="other">%d Stunden</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Geteilte Event-Strings -->
|
||||
<string name="event_untitled">(Ohne Titel)</string>
|
||||
|
||||
<!-- Erinnerungs-Benachrichtigungen (v1.4) -->
|
||||
<string name="reminder_channel_name">Termin-Erinnerungen</string>
|
||||
<string name="reminder_channel_description">Benachrichtigungen zu den Erinnerungszeiten deiner Termine</string>
|
||||
@@ -215,23 +203,19 @@
|
||||
<string name="reminder_onboarding_skip_button">Später</string>
|
||||
<string name="reminder_action_snooze">Schlummern</string>
|
||||
<string name="reminder_action_dismiss">Verwerfen</string>
|
||||
|
||||
<!-- View-Switcher (M1) -->
|
||||
<string name="view_month">Monat</string>
|
||||
<string name="view_week">Woche</string>
|
||||
<string name="view_day">Tag</string>
|
||||
<string name="view_agenda">Agenda</string>
|
||||
<string name="view_section">Ansicht</string>
|
||||
|
||||
<!-- Zu Datum springen (Navigationsleiste) -->
|
||||
<string name="drawer_jump_to_date">Zu Datum springen</string>
|
||||
|
||||
<!-- Agenda-Ansicht -->
|
||||
<string name="agenda_today_action">Heute</string>
|
||||
<string name="agenda_header_today">Heute</string>
|
||||
<string name="agenda_header_tomorrow">Morgen</string>
|
||||
<string name="agenda_empty_title">Alles erledigt</string>
|
||||
|
||||
<!-- Terminsuche -->
|
||||
<string name="search_action">Suchen</string>
|
||||
<string name="search_hint">Termine suchen</string>
|
||||
@@ -239,7 +223,6 @@
|
||||
<string name="search_clear">Löschen</string>
|
||||
<string name="search_idle_hint">Durchsuche deine Termine nach Titel, Ort oder Notizen.</string>
|
||||
<string name="search_empty">Keine Termine passen zu „%1$s“.</string>
|
||||
|
||||
<!-- Startbildschirm-Widgets -->
|
||||
<string name="widget_agenda_title">Anstehend</string>
|
||||
<string name="widget_agenda_label">Calendula Agenda</string>
|
||||
@@ -250,19 +233,15 @@
|
||||
<string name="widget_prev_month">Vorheriger Monat</string>
|
||||
<string name="widget_next_month">Nächster Monat</string>
|
||||
<string name="widget_today">Heute</string>
|
||||
|
||||
<!-- Verknüpfungen (Long-Press auf das App-Symbol) -->
|
||||
<string name="shortcut_new_event_short">Neuer Termin</string>
|
||||
<string name="shortcut_new_event_long">Neuen Termin erstellen</string>
|
||||
|
||||
<!-- Schnelleinstellungen-Kachel -->
|
||||
<string name="qs_tile_new_event_label">Neuer Termin</string>
|
||||
<string name="settings_qs_tile">Schnelleinstellungen-Kachel hinzufügen</string>
|
||||
<string name="settings_qs_tile_hint">Eine Kachel „Neuer Termin“ zu den Schnelleinstellungen hinzufügen.</string>
|
||||
|
||||
<!-- Kalender-Filter (M3) -->
|
||||
<string name="filter_title">Kalender</string>
|
||||
|
||||
<!-- Einstellungen (M4) -->
|
||||
<string name="settings_title">Einstellungen</string>
|
||||
<string name="settings_back">Zurück</string>
|
||||
@@ -302,6 +281,8 @@
|
||||
</plurals>
|
||||
<string name="settings_section_event_form">Termin-Formular</string>
|
||||
<string name="settings_form_fields_hint">Standardmäßig angezeigte Felder — alles Weitere liegt hinter \"Weitere Felder\"</string>
|
||||
<string name="settings_autofocus_title">Titel bei neuem Termin fokussieren</string>
|
||||
<string name="settings_autofocus_title_hint">Beim Anlegen eines neuen Termins den Cursor direkt ins Titelfeld setzen und die Tastatur öffnen.</string>
|
||||
<string name="settings_color_unsupported">Farben auf nicht unterstützten Kalendern erlauben</string>
|
||||
<string name="settings_color_unsupported_hint">Manche Kalender (z. B. bestimmte CalDAV) stellen keine Farbpalette bereit; eine eigene Terminfarbe wird dort bei der nächsten Synchronisierung unter Umständen verworfen oder überschrieben. Das ist eine Einschränkung dieser Kalender und kann von Calendula nicht behoben werden.</string>
|
||||
<string name="settings_section_notifications">Benachrichtigungen</string>
|
||||
@@ -342,7 +323,6 @@
|
||||
<string name="settings_about_logo_desc">Calendula-App-Symbol</string>
|
||||
<string name="settings_report_problem">Problem melden</string>
|
||||
<string name="settings_report_problem_hint">Absturzbericht senden oder Issue-Tracker öffnen</string>
|
||||
|
||||
<!-- Calendar manager -->
|
||||
<string name="calendars_title">Kalender</string>
|
||||
<string name="calendars_local_header">Deine Kalender</string>
|
||||
@@ -397,7 +377,6 @@
|
||||
<item quantity="one">%d bereits in diesem Kalender übersprungen.</item>
|
||||
<item quantity="other">%d bereits in diesem Kalender übersprungen.</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Absturzberichte: vom Nutzer selbst als Gitea-Issue einreichbar -->
|
||||
<string name="crash_dialog_title">Calendula ist abgestürzt</string>
|
||||
<string name="crash_dialog_message">Calendula wurde beim letzten Mal unerwartet beendet. Du kannst bei der Behebung helfen, indem du diesen Bericht als Issue sendest. Er bleibt auf deinem Gerät, bis du ihn teilst, und enthält keine persönlichen Daten oder Kalenderinhalte — nur die technischen Angaben unten.</string>
|
||||
|
||||
422
app/src/main/res/values-es/strings.xml
Normal file
422
app/src/main/res/values-es/strings.xml
Normal file
@@ -0,0 +1,422 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="backup_interval_units">
|
||||
<item>Minutes</item>
|
||||
<item>Hours</item>
|
||||
<item>Days</item>
|
||||
<item>Weeks</item>
|
||||
</string-array>
|
||||
<string name="app_name">Calendula</string>
|
||||
<string name="app_tagline">Un calendario moderno.</string>
|
||||
<string name="state_loading">Cargando…</string>
|
||||
<string name="state_retry">Vuelve a intentarlo</string>
|
||||
<string name="state_failure_unknown">Algo salio mal.</string>
|
||||
<string name="state_failure_permission">Se requiere acceso al calendario.</string>
|
||||
<string name="state_failure_permission_action">Permite el acceso</string>
|
||||
<string name="state_failure_no_calendars">No se han configurado calendarios.</string>
|
||||
<string name="state_failure_no_calendars_action">Abrir los ajustes del calendario del sistema</string>
|
||||
<string name="state_failure_provider">No se pudo leer el calendario.</string>
|
||||
<string name="permission_rationale_title">Mira todos sus eventos, a la perfección</string>
|
||||
<string name="permission_rationale_body">Calendula necesita acceso a tu calendario para mostrarte y administrar eventos. Ese es el único permiso que pedirá.</string>
|
||||
<string name="permission_request_button">Conceder el acceso al calendario</string>
|
||||
<string name="permission_denied_title">Acceso a calendario denegado</string>
|
||||
<string name="permission_denied_body">Calendula no puede mostrar eventos sin acceso al calendario. Puedes concederlo en ajustes del sistema.</string>
|
||||
<string name="permission_open_settings_button">Abrir ajustes del sistema</string>
|
||||
<string name="permission_retry_button">Intentarlo de nuevo</string>
|
||||
<string name="permission_benefit_private_title">Permanece en tu dispositivo</string>
|
||||
<string name="permission_benefit_private_body">Tus calendarios se leen localmente y nunca abandonan tu celular.</string>
|
||||
<string name="permission_benefit_sync_title">Todos tus calendarios, juntos</string>
|
||||
<string name="permission_benefit_sync_body">Google, CalDAV, local — todo lo sincronizado en el dispositivo aparecerá.</string>
|
||||
<string name="permission_benefit_privacy_title">Sin rastreo, jamás</string>
|
||||
<string name="permission_benefit_privacy_body">Sin telemetría, sin analíticas, sin anuncios.</string>
|
||||
<string name="permission_privacy_footnote">Permanece en tu dispositivo, no necesita acceso a internet</string>
|
||||
<string name="month_prev">Mes anterior</string>
|
||||
<string name="month_next">Siguiente mes</string>
|
||||
<string name="month_today_action">Hoy</string>
|
||||
<string name="month_more_actions">Mas acciones</string>
|
||||
<string name="month_open_menu">Abrir menu</string>
|
||||
<string name="month_action_settings">Ajustes</string>
|
||||
<string name="month_a11y_today_prefix">Hoy</string>
|
||||
<string name="week_today_action">Esta semana</string>
|
||||
<string name="week_number_label">Sem</string>
|
||||
<string name="day_today_action">Hoy</string>
|
||||
<string name="event_detail_back">Atras</string>
|
||||
<string name="event_detail_edit">Editar</string>
|
||||
<string name="event_detail_delete">Eliminar</string>
|
||||
<string name="event_detail_share">Compartir</string>
|
||||
<string name="event_share_chooser_title">Compartir evento</string>
|
||||
<string name="event_share_failed">No se pudo compartir el evento.</string>
|
||||
<string name="event_delete_title">¿Eliminar evento?</string>
|
||||
<string name="event_delete_body">El evento se elimino de tu calendario y de todos los dispositivos con los cuales se sincroniza.</string>
|
||||
<string name="event_delete_recurring_title">Eliminar evento recurrente</string>
|
||||
<string name="event_delete_option_occurrence">Solo este evento</string>
|
||||
<string name="event_delete_option_following">Este y todos los eventos siguientes</string>
|
||||
<string name="event_delete_option_series">Todos los eventos en la serie</string>
|
||||
<string name="event_edit_recurring_title">Editar evento recurrente</string>
|
||||
<string name="event_delete_failed">No se pudo eliminar el evento</string>
|
||||
<string name="event_delete_write_denied">Calendula necesita acceso de escritura para eliminar eventos</string>
|
||||
<string name="dialog_cancel">Cancelar</string>
|
||||
<string name="dialog_ok">Okey</string>
|
||||
<string name="event_edit_new_title">Nuevo evento</string>
|
||||
<string name="event_edit_close">Cerrar</string>
|
||||
<string name="event_edit_save">Guardar</string>
|
||||
<string name="event_edit_title_hint">Añadir título</string>
|
||||
<string name="event_edit_starts">Inicio</string>
|
||||
<string name="event_edit_ends">Final</string>
|
||||
<string name="event_edit_error_end_before_start">Termina antes de comenzar</string>
|
||||
<string name="event_edit_error_no_calendar">No hay ningún calendario en donde se pueda escribir disponible</string>
|
||||
<string name="event_edit_save_failed">No se pudo guardar el evento</string>
|
||||
<string name="event_edit_write_denied">Calendula necesita acceso de escritura para crear eventos</string>
|
||||
<string name="event_edit_more_fields">Mas campos</string>
|
||||
<string name="event_edit_add">Añadir</string>
|
||||
<string name="event_edit_add_reminder">Añadir recordatorio</string>
|
||||
<string name="event_edit_remove_reminder">Eliminar recordatorio</string>
|
||||
<string name="event_edit_attendees">Invitados</string>
|
||||
<string name="event_edit_add_guest">Añadir invitados</string>
|
||||
<string name="event_edit_add_guest_hint">Añadir invitados por correo…</string>
|
||||
<string name="event_edit_add_guest_from_contacts">Añadir desde contactos</string>
|
||||
<string name="event_edit_location_from_contacts">Seleccionar dirección desde contactos</string>
|
||||
<string name="event_edit_remove_guest">Eliminar invitado</string>
|
||||
<string name="event_edit_attendee_required">Obligatorio</string>
|
||||
<string name="event_edit_attendee_optional">Opcional</string>
|
||||
<string name="event_edit_attendees_note_synced">Calendula no envia invitaciones. Tu cuenta de calendario puede enviar correos a los invitados cuando se sincronice.</string>
|
||||
<string name="event_edit_attendees_note_local">Guardado en el dispositivo. No se avisa a nadie.</string>
|
||||
<string name="event_edit_reminder_custom">Personalizado</string>
|
||||
<string name="reminder_unit_minutes">minutos</string>
|
||||
<string name="reminder_unit_hours">horas</string>
|
||||
<string name="reminder_unit_days">días</string>
|
||||
<string name="reminder_unit_weeks">semanas</string>
|
||||
<string name="event_edit_availability">Disponibilidad</string>
|
||||
<string name="event_edit_visibility">Visibilidad</string>
|
||||
<string name="event_edit_color">Color</string>
|
||||
<string name="event_edit_color_default">Color del calendario</string>
|
||||
<string name="event_edit_color_custom">Color personalizado</string>
|
||||
<string name="event_edit_color_reset">Reiniciar</string>
|
||||
<string name="event_edit_color_unsupported">No disponible para este calendario</string>
|
||||
<string name="event_edit_color_unsupported_hint">Este calendario no admite un ser de colores. Puedes permitir colores personalizados para este tipo de calendarios en ajustes.</string>
|
||||
<string name="event_edit_color_sync_warning">Este calendario puede eliminar o cambiar el color la próxima vez que se sincronice.</string>
|
||||
<string name="event_edit_conflict_title">El evento fue cambiado por otra fuente</string>
|
||||
<string name="event_edit_conflict_body">Mientras lo editabas, este evento fue cambiado — debido a la sincronización u otra aplicación ¿Que deberia le ocurrir a tus cambios?</string>
|
||||
<string name="event_edit_conflict_overwrite">Guardar mis cambios</string>
|
||||
<string name="event_edit_conflict_overwrite_hint">Sobreescribir el cambio externo en solo los aspectos que he cambiado</string>
|
||||
<string name="event_edit_conflict_discard">Descartar todos mis cambios</string>
|
||||
<string name="event_edit_conflict_discard_hint">El evento permanece tal y como esta ahora</string>
|
||||
<string name="event_edit_gone_title">Evento eliminado</string>
|
||||
<string name="event_edit_gone_body">Este evento fue eliminado durante el proceso, en otro dispositivo o aplicación por ejemplo. Tus cambios no pudieron ser guardados.</string>
|
||||
<string name="event_edit_recurrence_none">No se repite</string>
|
||||
<string name="event_edit_recurrence_custom">Personalizado</string>
|
||||
<string name="event_edit_recurrence_every">Cada</string>
|
||||
<string name="recurrence_unit_days">días</string>
|
||||
<string name="recurrence_unit_weeks">semanas</string>
|
||||
<string name="recurrence_unit_months">meses</string>
|
||||
<string name="recurrence_unit_years">años</string>
|
||||
<string name="event_edit_recurrence_ends">Finaliza</string>
|
||||
<string name="event_edit_recurrence_end_never">Nunca</string>
|
||||
<string name="event_edit_recurrence_end_until">En una fecha</string>
|
||||
<string name="event_edit_recurrence_end_count">Después de cierto numero de veces</string>
|
||||
<string name="event_edit_recurrence_times">veces</string>
|
||||
<string name="event_edit_error_recurrence_ends_before_start">El evento se deja de repetir antes de que este comience</string>
|
||||
<string name="event_availability_busy">Ocupado</string>
|
||||
<string name="event_access_default">Por defecto</string>
|
||||
<string name="event_access_public">Público</string>
|
||||
<string name="event_detail_all_day">Todo el día</string>
|
||||
<string name="event_detail_calendar">Calendario</string>
|
||||
<string name="event_detail_calendar_unknown">Calendario desconocido</string>
|
||||
<string name="event_detail_location">Ubicación</string>
|
||||
<string name="event_detail_description">Descripción</string>
|
||||
<string name="event_detail_attendees">Participantes</string>
|
||||
<string name="event_detail_recurrence">Recurrencia</string>
|
||||
<string name="agenda_today_action">Hoy</string>
|
||||
<string name="agenda_header_today">Hoy</string>
|
||||
<string name="search_back">Atras</string>
|
||||
<string name="widget_new_event">Nuevo evento</string>
|
||||
<string name="widget_prev_month">Mes anterior</string>
|
||||
<string name="widget_next_month">Siguiente mes</string>
|
||||
<string name="widget_today">Hoy</string>
|
||||
<string name="filter_title">Calendarios</string>
|
||||
<string name="settings_title">Ajustes</string>
|
||||
<string name="settings_back">Atras</string>
|
||||
<string name="agenda_range_day">Hoy</string>
|
||||
<string name="agenda_range_this_week">Esta semana</string>
|
||||
<string name="settings_section_calendars">Calendarios</string>
|
||||
<string name="calendars_title">Calendarios</string>
|
||||
<string name="calendars_color_label">Color</string>
|
||||
<string name="import_close">Cerrar</string>
|
||||
<string name="shortcut_new_event_short">Nuevo evento</string>
|
||||
<string name="qs_tile_new_event_label">Nuevo evento</string>
|
||||
<string name="event_detail_recurring">Repetir el evento</string>
|
||||
<string name="recurrence_daily">Todos los días</string>
|
||||
<string name="recurrence_weekly">Todas las semanas</string>
|
||||
<string name="recurrence_monthly">Todos los meses</string>
|
||||
<string name="recurrence_yearly">Todos los años</string>
|
||||
<string name="recurrence_every_n_days">Cada %1$d días</string>
|
||||
<string name="recurrence_every_n_weeks">Cada %1$d semanas</string>
|
||||
<string name="recurrence_every_n_months">Cada %1$d meses</string>
|
||||
<string name="recurrence_every_n_years">Cada %1$d años</string>
|
||||
<string name="event_detail_not_found">Este evento ya no existe.</string>
|
||||
<string name="event_attendee_accepted">Aceptado</string>
|
||||
<string name="event_attendee_declined">Rechazado</string>
|
||||
<string name="event_attendee_tentative">Tentativo</string>
|
||||
<string name="event_attendee_needs_action">Sin respuesta</string>
|
||||
<string name="event_attendee_unknown">—</string>
|
||||
<string name="event_detail_reminders">Recordatorios</string>
|
||||
<string name="event_detail_timezone">Zona horaria</string>
|
||||
<string name="event_status_tentative">Tentativo</string>
|
||||
<string name="event_status_cancelled">Cancelado</string>
|
||||
<string name="event_availability_free">Disponible</string>
|
||||
<string name="event_access_private">Privado</string>
|
||||
<string name="event_access_confidential">Confidencial</string>
|
||||
<string name="event_attendee_organizer">Organizador</string>
|
||||
<string name="event_attendee_optional">Opcional</string>
|
||||
<string name="agenda_range_custom">Personalizado…</string>
|
||||
<string name="calendars_backup_header">Respaldo</string>
|
||||
<string name="backup_channel_name">Respaldo</string>
|
||||
<string name="event_detail_self_response">Tu respuesta: %1$s</string>
|
||||
<string name="reminder_at_time">Al la hora del evento</string>
|
||||
<string name="reminder_default">Recordatorio por defecto</string>
|
||||
<plurals name="reminder_minutes">
|
||||
<item quantity="one">%d minuto antes</item>
|
||||
<item quantity="many">%d minutos antes</item>
|
||||
<item quantity="other">%d minutos antes</item>
|
||||
</plurals>
|
||||
<plurals name="reminder_hours">
|
||||
<item quantity="one">%d hora antes</item>
|
||||
<item quantity="many">%d horas antes</item>
|
||||
<item quantity="other">%d horas antes</item>
|
||||
</plurals>
|
||||
<plurals name="reminder_days">
|
||||
<item quantity="one">%d día antes</item>
|
||||
<item quantity="many">%d días antes</item>
|
||||
<item quantity="other">%d días antes</item>
|
||||
</plurals>
|
||||
<plurals name="reminder_weeks">
|
||||
<item quantity="one">%d semana antes</item>
|
||||
<item quantity="many">%d semanas antes</item>
|
||||
<item quantity="other">%d semanas antes</item>
|
||||
</plurals>
|
||||
<plurals name="duration_minutes">
|
||||
<item quantity="one">%d minuto</item>
|
||||
<item quantity="many">%d minutos</item>
|
||||
<item quantity="other">%d minutos</item>
|
||||
</plurals>
|
||||
<plurals name="duration_hours">
|
||||
<item quantity="one">%d hora</item>
|
||||
<item quantity="many">%d horas</item>
|
||||
<item quantity="other">%d horas</item>
|
||||
</plurals>
|
||||
<plurals name="duration_days">
|
||||
<item quantity="one">%d dia</item>
|
||||
<item quantity="many">%d días</item>
|
||||
<item quantity="other">%d días</item>
|
||||
</plurals>
|
||||
<plurals name="duration_weeks">
|
||||
<item quantity="one">%d semana</item>
|
||||
<item quantity="many">%d semanas</item>
|
||||
<item quantity="other">%d semanas</item>
|
||||
</plurals>
|
||||
<string name="event_untitled">(Sin título)</string>
|
||||
<string name="reminder_channel_name">Recordatorios del evento</string>
|
||||
<string name="reminder_channel_description">Notificaciones a la hora de los recordatorios de tus eventos</string>
|
||||
<string name="reminder_onboarding_title">Nunca te pierdas un evento</string>
|
||||
<string name="reminder_onboarding_body">Android no muestra recordatorios de eventos por su cuenta — una app de calendario tiene que hacerlo. Deja que calendula cumpla ese trabajo.</string>
|
||||
<string name="reminder_benefit_delivery_title">Recordatorios, enviados</string>
|
||||
<string name="reminder_benefit_delivery_body">Cada recordatorio de tus eventos aparece como notificación, justo a tiempo.</string>
|
||||
<string name="reminder_benefit_duplicates_title">¿Utilizas otra aplicación de calendario?</string>
|
||||
<string name="reminder_benefit_duplicates_body">Si otra aplicación tambien muestra recordatorios, los veras dos veces — desactivalos en esta o la otra aplicación.</string>
|
||||
<string name="reminder_benefit_reversible_title">Cambialo en cualquier momento</string>
|
||||
<string name="reminder_benefit_reversible_body">El interruptor se encuentra en Ajustes, en la sección de Notificaciones.</string>
|
||||
<string name="reminder_onboarding_enable_button">Activar recordatorios</string>
|
||||
<string name="reminder_onboarding_skip_button">Mas tarde</string>
|
||||
<string name="reminder_action_snooze">Posponer</string>
|
||||
<string name="reminder_action_dismiss">Descartar</string>
|
||||
<string name="view_month">Mes</string>
|
||||
<string name="view_week">Semana</string>
|
||||
<string name="view_day">Día</string>
|
||||
<string name="view_agenda">Agenda</string>
|
||||
<string name="view_section">Vista</string>
|
||||
<string name="drawer_jump_to_date">Ir a la fecha</string>
|
||||
<string name="agenda_header_tomorrow">Mañana</string>
|
||||
<string name="agenda_empty_title">Ya estas al día</string>
|
||||
<string name="search_action">Buscar</string>
|
||||
<string name="search_hint">Buscar eventos</string>
|
||||
<string name="search_clear">Limpiar</string>
|
||||
<string name="search_idle_hint">Buscar eventos por titulo, ubicación o notas.</string>
|
||||
<string name="search_empty">No evento coincide con “%1$s”.</string>
|
||||
<string name="widget_agenda_title">Próximamente</string>
|
||||
<string name="widget_agenda_label">Calendula agenda</string>
|
||||
<string name="widget_month_label">Calendula mes</string>
|
||||
<string name="widget_refresh">Actualizar</string>
|
||||
<string name="widget_needs_permission">Abre Calendula para conceder acceso al calendario</string>
|
||||
<string name="settings_section_appearance">Apariencia</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="settings_theme_system">Igual que el sistema</string>
|
||||
<string name="settings_theme_light">Claro</string>
|
||||
<string name="settings_theme_dark">Oscuro</string>
|
||||
<string name="settings_default_view">Vista por defecto</string>
|
||||
<string name="settings_dynamic_color">Color dinámico</string>
|
||||
<string name="settings_dynamic_color_unavailable">Requiere android 12 o una versión posterior</string>
|
||||
<string name="settings_week_start">La semana empieza en</string>
|
||||
<string name="settings_week_start_auto">Automático</string>
|
||||
<string name="settings_time_format">Formato de la hora</string>
|
||||
<string name="settings_time_format_auto">Automático</string>
|
||||
<string name="settings_time_format_12h">12-horas (2:00 PM)</string>
|
||||
<string name="settings_time_format_24h">24-horas (14:00)</string>
|
||||
<string name="settings_hour_lines">Lineas entre horas</string>
|
||||
<string name="settings_hour_lines_summary">Muestra una linea que separa cada hora en la vista diaria y semanal</string>
|
||||
<string name="settings_dim_completed">Oscurecer eventos completados</string>
|
||||
<string name="settings_dim_completed_summary">Oscurece eventos que ya han terminado en vista semanal y mensual</string>
|
||||
<string name="settings_past_events">Eventos pasados</string>
|
||||
<string name="settings_past_events_show">Mostrar</string>
|
||||
<string name="settings_past_events_dim">Oscurecer</string>
|
||||
<string name="settings_past_events_hide">Ocultar</string>
|
||||
<string name="settings_agenda_header">Agenda</string>
|
||||
<string name="settings_agenda_range">Rango de agenda</string>
|
||||
<string name="settings_agenda_range_hint">Cuanto tiempo abarca la agenda al mostrar eventos.</string>
|
||||
<string name="settings_agenda_widget_range">Rango del widget de agenda</string>
|
||||
<string name="settings_agenda_widget_range_hint">Cuanto tiempo abarca el widget de agenda en la pantalla principal al mostrar eventos.</string>
|
||||
<string name="settings_agenda_range_bar">Barra de tiempo</string>
|
||||
<string name="settings_agenda_range_bar_hint">Muestra una barra en la parte superior de la agenda con las fechas mostradas, con un botón para cambiar el rango durante la sesión</string>
|
||||
<string name="agenda_range_this_month">Este mes</string>
|
||||
<string name="agenda_range_week">Próximos 7 días</string>
|
||||
<string name="agenda_range_month">Próximos 30 días</string>
|
||||
<string name="agenda_range_custom_hint">Días</string>
|
||||
<string name="agenda_range_override_hint">Solo por ahora — reinicia tu rango guardado cuando reabras calendula.</string>
|
||||
<string name="agenda_range_showing_label">Mostrando todos los próximos eventos por</string>
|
||||
<plurals name="agenda_range_days">
|
||||
<item quantity="one">%d dia</item>
|
||||
<item quantity="many">%d dias</item>
|
||||
<item quantity="other">%d dias</item>
|
||||
</plurals>
|
||||
<string name="settings_section_event_form">Nueva formulario de evento</string>
|
||||
<string name="settings_form_fields_hint">Campos mostrados por defecto — todo lo demás se encuentra bajo \"mas campos\"</string>
|
||||
<string name="settings_autofocus_title">Enfocar titulo en nuevos eventos</string>
|
||||
<string name="settings_autofocus_title_hint">Cuando comienzas un nuevo evento, coloca el cursor en el titulo y abre el teclado inmediatamente.</string>
|
||||
<string name="settings_color_unsupported">Permitir colores en calendarios no admitidos</string>
|
||||
<string name="settings_color_unsupported_hint">Algunas calendarios (como algunos CalDAV) no publican un set de colores; un color customizado puede ser eliminado o sobreescrito por su servicio de sincronización. Eso es una limitacion de estos calendarios, no algo que calendula pueda solucionar.</string>
|
||||
<string name="settings_section_notifications">Notificaciones</string>
|
||||
<string name="settings_reminders">Recordatorios de eventos</string>
|
||||
<string name="settings_reminders_hint">Los recordatorios aparecen dos veces? Otra aplicación de calendario tambien los esta generando — desactivarlo en una de las dos apps.</string>
|
||||
<string name="settings_default_reminder">Recordatorio por defecto</string>
|
||||
<string name="settings_default_reminder_allday">Eventos que duran todo el dia</string>
|
||||
<string name="settings_allday_reminder_time">Hora del recordatorio de todo el día</string>
|
||||
<string name="settings_allday_reminder_time_hint">Los recordatorios para eventos de todo el día se generaran a las %1$s</string>
|
||||
<string name="reminder_none">Ninguno</string>
|
||||
<string name="reminder_use_default">Usar recordatorio por defecto</string>
|
||||
<string name="reminder_custom_amount">Cantidad</string>
|
||||
<string name="reminder_custom_with_value">Personalizado (%1$s)</string>
|
||||
<string name="reminder_custom_set">Guardar</string>
|
||||
<string name="settings_calendar_reminders_title">Recordatorios por calendario</string>
|
||||
<string name="settings_calendar_reminders_hint">Sobreescribe el por recordatorio defecto por calendario — De forma separada para eventos con duración fija o que duran todo el dia. Un calendario puede mantener el por defecto o tener su propia configuracion.</string>
|
||||
<string name="settings_calendar_reminder_inherits">Por defecto (%1$s)</string>
|
||||
<string name="settings_reliable_delivery">Notificaciones confiables</string>
|
||||
<string name="settings_reliable_delivery_hint">Android puede atrasar los recordatorios para guardar batería. Excluye calendula de la optimización de batería para que se puedan generar a tiempo.</string>
|
||||
<string name="settings_reliable_delivery_exempt">Excluido de la optimización de batería — los recordatorios llegaran a tiempo.</string>
|
||||
<string name="settings_snooze_duration">Duración al posponer</string>
|
||||
<string name="settings_manage_calendars">Administrar calendarios</string>
|
||||
<string name="settings_manage_calendars_hint">Crear calendarios locales; administrar calendarios sincronizados</string>
|
||||
<string name="settings_section_language">Idioma</string>
|
||||
<string name="settings_language">Idioma de la aplicación</string>
|
||||
<string name="settings_language_auto">Igual que el sistema</string>
|
||||
<string name="settings_translate">Ayuda a traducir</string>
|
||||
<string name="settings_translate_hint">Añade o mejora un idioma en Weblate</string>
|
||||
<string name="settings_appearance_subtitle">Tema, vista por defecto, inicio de semana</string>
|
||||
<string name="settings_event_form_subtitle">Campos por defecto en nuevos eventos</string>
|
||||
<string name="settings_notifications_subtitle">Recordatorios de eventos</string>
|
||||
<string name="settings_license">Licencia</string>
|
||||
<string name="settings_license_value">MIT</string>
|
||||
<string name="settings_about_author">Por Jean-Luc Makiola</string>
|
||||
<string name="settings_about_source">Fuente</string>
|
||||
<string name="settings_about_support">Ayuda al desarrollo</string>
|
||||
<string name="settings_about_version">Version %1$s</string>
|
||||
<string name="settings_about_logo_desc">Icono de la aplicación calendula</string>
|
||||
<string name="settings_report_problem">Reportar un problema</string>
|
||||
<string name="settings_report_problem_hint">Enviar un reporte de error o abre el sistema de seguimiento de errores</string>
|
||||
<string name="calendars_local_header">Tus calendarios</string>
|
||||
<string name="calendars_local_empty">Sin calendarios locales todavia. Crea uno para mantener eventos solo en este dispositivo.</string>
|
||||
<string name="calendars_add">Añadir calendario</string>
|
||||
<string name="calendars_disable_hint">Desactiva un calendario para removerlo de la aplicación — sus eventos, filtros y selectores. Nada se eliminara, y puedes reactivarlo en cualquier momento.</string>
|
||||
<string name="calendars_show_in_app_a11y">Mostrar \"%1$s\" en la aplicación</string>
|
||||
<string name="calendars_synced_header">Calendarios sincronizados</string>
|
||||
<string name="calendars_synced_hint">Estos provienen de cuentas en tu dispositivo. Crea o editalos en su propia aplicación.</string>
|
||||
<string name="calendars_manage_in_app">Gestionar en aplicación</string>
|
||||
<string name="calendars_account_menu_a11y">Mas opciones para %1$s</string>
|
||||
<string name="calendars_enable_all">Habilitar todos</string>
|
||||
<string name="calendars_disable_all">Desactivar todos</string>
|
||||
<string name="calendars_add_account">Añadir cuenta</string>
|
||||
<string name="calendars_new_title">Nuevo calendario</string>
|
||||
<string name="calendars_edit_title">Editar calendario</string>
|
||||
<string name="calendars_name_label">Nombre</string>
|
||||
<string name="calendars_description_hint">Añadir descripción</string>
|
||||
<string name="calendars_delete_confirm_title">¿Eliminar calendario?</string>
|
||||
<string name="calendars_delete_confirm_message">\"%1$s\" y todos sus eventos serán eliminados permanentemente de este dispositivo.</string>
|
||||
<string name="calendars_write_error">No se pudieron guardar los cambios.</string>
|
||||
<string name="calendars_backup_hint">Los calendarios locales no se sincronizan, exportalos como un archivo .ics para mantener una copia.</string>
|
||||
<string name="calendars_backup_action">Exportar como archivo .ics</string>
|
||||
<string name="calendars_auto_backup">Respaldo automático</string>
|
||||
<string name="calendars_auto_backup_hint">Exporta tus calendarios a una carpeta como un archivo .ics de forma periodica.</string>
|
||||
<string name="calendars_auto_backup_folder">Carpeta de respaldo</string>
|
||||
<string name="calendars_auto_backup_folder_unset">Toca para seleccionar una carpeta</string>
|
||||
<string name="calendars_auto_backup_interval">Intervalo</string>
|
||||
<string name="calendars_auto_backup_every">Cada %1$s</string>
|
||||
<string name="calendars_auto_backup_interval_min">Mínimo 30 minutos.</string>
|
||||
<string name="calendars_auto_backup_status_never">Sin respaldos automáticos todavía</string>
|
||||
<string name="calendars_auto_backup_status_ok">Ultimo respaldo: %1$s</string>
|
||||
<string name="calendars_auto_backup_status_failed">Ultimo respaldo fallido: %1$s</string>
|
||||
<string name="backup_channel_description">Advierte si los respaldos automáticos fallan repetidamente.</string>
|
||||
<string name="backup_failed_title">El respaldo automático fallo</string>
|
||||
<string name="backup_failed_text">Calendula no pudo generar el archivo de respaldo, comprueba la carpeta de respaldo en ajustes.</string>
|
||||
<string name="calendars_backup_failed">No se pudo exportar el respaldo.</string>
|
||||
<plurals name="calendars_backup_done">
|
||||
<item quantity="one">Se exporto %d evento.</item>
|
||||
<item quantity="many">Se exportaron %d eventos.</item>
|
||||
<item quantity="other">Se exportaron %d eventos.</item>
|
||||
</plurals>
|
||||
<string name="import_title">Importar eventos</string>
|
||||
<string name="import_target_header">Añadir a calendario</string>
|
||||
<string name="import_empty">No se encontraron eventos en este archivo.</string>
|
||||
<string name="import_failed">No se pudo leer el archivo.</string>
|
||||
<string name="import_no_calendar">No hay ningún calendario editable en el cual importar los eventos. Crea un calendario local primero.</string>
|
||||
<string name="import_done_title">Importación completa</string>
|
||||
<string name="import_warning_recurrence">Se omitieron algunas ocurrencias editadas de eventos recurrentes.</string>
|
||||
<string name="import_warning_no_start">Se omitió un evento sin hora de inicio.</string>
|
||||
<string name="import_warning_attendees">No se importaron las listas de invitados.</string>
|
||||
<string name="import_warning_timezone">Se reemplazo una zona horaria desconocida con la de tu dispositivo.</string>
|
||||
<plurals name="import_event_count">
|
||||
<item quantity="one">%d evento en este archivo.</item>
|
||||
<item quantity="many">%d eventos en este archivo.</item>
|
||||
<item quantity="other">%d eventos en este archivo.</item>
|
||||
</plurals>
|
||||
<plurals name="import_action">
|
||||
<item quantity="one">Importar %d evento</item>
|
||||
<item quantity="many">Importar %d eventos</item>
|
||||
<item quantity="other">Importar %d eventos</item>
|
||||
</plurals>
|
||||
<plurals name="import_done_imported">
|
||||
<item quantity="one">%d evento importado.</item>
|
||||
<item quantity="many">%d eventos importados.</item>
|
||||
<item quantity="other">%d eventos importados.</item>
|
||||
</plurals>
|
||||
<plurals name="import_done_skipped">
|
||||
<item quantity="one">Se omitió %d archivo ya presente en este calendario.</item>
|
||||
<item quantity="many">Se omitieron %d archivos ya presentes en este calendario.</item>
|
||||
<item quantity="other">Se omitieron %d archivos ya presentes en este calendario.</item>
|
||||
</plurals>
|
||||
<string name="shortcut_new_event_long">Crear un nuevo evento</string>
|
||||
<string name="settings_qs_tile">Añadir mosaico de ajustes rápidos</string>
|
||||
<string name="settings_qs_tile_hint">Añadir un recuadro de \"nuevo evento\" al panel de ajustes rápidos.</string>
|
||||
<string name="crash_dialog_title">Calendula ha fallado</string>
|
||||
<string name="crash_dialog_message">Calendula se cerro de forma inesperada la ultima vez. Puedes ayudar a solucionarlo enviando un reporte del problema. Este permanece en tu dispositivo hasta que decidas enviarlo, y no contiene información personal o contenido de tu calendario — solo los detalles técnicos de mas abajo.</string>
|
||||
<string name="crash_dialog_report">Reportar</string>
|
||||
<string name="crash_dialog_dismiss">No por ahora</string>
|
||||
<string name="crash_report_issue_title">Reporte de error</string>
|
||||
<string name="crash_report_clip_label">Reporte de error de Calendula</string>
|
||||
<string name="crash_report_copied">Reporte copiado a tu porta papeles</string>
|
||||
<string name="crash_report_open_failed">No se pudo abrir el sistema de seguimiento de errores. El reporte es en tu portapapeles.</string>
|
||||
<string name="crash_report_body_template">Gracias por reportar un error en Calendula. Por favor añade todo lo que recuerdas sobre lo que estabas haciendo y luego publicalo.\n\n### que sucedió\n\n\n### reporte de error\n%1$s\n</string>
|
||||
<string name="crash_report_body_paste">_(el reporte es demasiado largo para este link — pegalo aquí desde su portapeles.)_</string>
|
||||
<string name="event_attendee_resource">Recurso</string>
|
||||
<string name="settings_section_about">Acerca de</string>
|
||||
<string name="recurrence_with_count">%1$s, %2$d veces</string>
|
||||
<string name="recurrence_with_until">%1$s hasta %2$s</string>
|
||||
<string name="recurrence_on_days">%1$s los %2$s</string>
|
||||
</resources>
|
||||
9
app/src/main/res/values-fr/strings.xml
Normal file
9
app/src/main/res/values-fr/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="backup_interval_units">
|
||||
<item>Minutes</item>
|
||||
<item>Hours</item>
|
||||
<item>Days</item>
|
||||
<item>Weeks</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
422
app/src/main/res/values-it/strings.xml
Normal file
422
app/src/main/res/values-it/strings.xml
Normal file
@@ -0,0 +1,422 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="backup_interval_units">
|
||||
<item>Minutes</item>
|
||||
<item>Hours</item>
|
||||
<item>Days</item>
|
||||
<item>Weeks</item>
|
||||
</string-array>
|
||||
<string name="app_name">Calendula</string>
|
||||
<string name="app_tagline">Un calendario moderno.</string>
|
||||
<string name="state_loading">Caricamento…</string>
|
||||
<string name="state_retry">Riprova</string>
|
||||
<string name="state_failure_unknown">Qualcosa è andato storto.</string>
|
||||
<string name="state_failure_permission">È richiesto l\'accesso al calendario.</string>
|
||||
<string name="state_failure_permission_action">Concedi l\'accesso</string>
|
||||
<string name="state_failure_no_calendars">Nessun calendario configurato.</string>
|
||||
<string name="state_failure_no_calendars_action">Apri le impostazioni calendario di sistema</string>
|
||||
<string name="state_failure_provider">Errore nella lettura del calendario.</string>
|
||||
<string name="permission_rationale_title">Guarda tutti i tuoi eventi, magnificamente</string>
|
||||
<string name="permission_rationale_body">Calendula ha bisogno di accedere al tuo calendario per mostrare e gestire gli eventi. È l\'unica cosa che ti chiederà.</string>
|
||||
<string name="permission_request_button">Concedi l\'accesso al calendario</string>
|
||||
<string name="permission_denied_title">Accesso al calendario negato</string>
|
||||
<string name="permission_denied_body">Calendula non può mostrare gli eventi senza accesso al calendario. Puoi concederlo dalle impostazioni di sistema.</string>
|
||||
<string name="permission_open_settings_button">Apri le impostazioni di sistema</string>
|
||||
<string name="permission_retry_button">Riprova</string>
|
||||
<string name="permission_benefit_private_title">Rimane sul tuo dispositivo</string>
|
||||
<string name="permission_benefit_private_body">I tuoi calendari sono letti localmente e non lasciano mai il tuo telefono.</string>
|
||||
<string name="permission_benefit_sync_title">Tutti i tuoi calendari, insieme</string>
|
||||
<string name="permission_benefit_sync_body">Google, CalDAV, locali - qualsiasi calendario sincronizzato sul dispositivo semplicemente compare.</string>
|
||||
<string name="permission_benefit_privacy_title">Nessun tracking, per sempre</string>
|
||||
<string name="permission_benefit_privacy_body">Zero telemetria, zero analytics, zero pubblicità.</string>
|
||||
<string name="permission_privacy_footnote">Rimane sul tuo dispositivo - nessun accesso a internet</string>
|
||||
<string name="month_prev">Mese precedente</string>
|
||||
<string name="month_next">Mese prossimo</string>
|
||||
<string name="month_today_action">Oggi</string>
|
||||
<string name="month_more_actions">Altre azioni</string>
|
||||
<string name="month_open_menu">Apri il menù</string>
|
||||
<string name="month_action_settings">Impostazioni</string>
|
||||
<string name="month_a11y_today_prefix">Oggi</string>
|
||||
<string name="week_today_action">Questa settimana</string>
|
||||
<string name="week_number_label">Wk</string>
|
||||
<string name="day_today_action">Oggi</string>
|
||||
<string name="event_detail_back">Indietro</string>
|
||||
<string name="event_detail_edit">Modifica</string>
|
||||
<string name="event_detail_delete">Elimina</string>
|
||||
<string name="event_detail_share">Condividi</string>
|
||||
<string name="event_share_chooser_title">Condividi evento</string>
|
||||
<string name="event_share_failed">Impossibile condividere questo evento.</string>
|
||||
<string name="event_delete_title">Eliminare l\'evento?</string>
|
||||
<string name="event_delete_body">Questo evento viene rimosso dal tuo calendario e da tutti i dispositivi sincronizzati.</string>
|
||||
<string name="event_delete_recurring_title">Elimina ricorrenza</string>
|
||||
<string name="event_delete_option_occurrence">Solo questo evento</string>
|
||||
<string name="event_delete_option_following">Questo e gli eventi successivi</string>
|
||||
<string name="event_delete_option_series">Tutti gli eventi della serie</string>
|
||||
<string name="event_edit_recurring_title">Modifica ricorrenza</string>
|
||||
<string name="event_delete_failed">Impossibile eliminare l\'evento</string>
|
||||
<string name="event_delete_write_denied">Calendula ha bisogno dei permessi di scrittura per eliminare gli eventi</string>
|
||||
<string name="dialog_cancel">Annulla</string>
|
||||
<string name="dialog_ok">Ok</string>
|
||||
<string name="event_edit_new_title">Nuovo evento</string>
|
||||
<string name="event_edit_close">Chiudi</string>
|
||||
<string name="event_edit_save">Salva</string>
|
||||
<string name="event_edit_title_hint">Aggiungi titolo</string>
|
||||
<string name="event_edit_starts">Inizio</string>
|
||||
<string name="event_edit_ends">Fine</string>
|
||||
<string name="event_edit_error_end_before_start">Fine antecedente l\'inizio</string>
|
||||
<string name="event_edit_error_no_calendar">Non sono disponibili calendari</string>
|
||||
<string name="event_edit_save_failed">Impossibile salvare l\'evento</string>
|
||||
<string name="event_edit_write_denied">Calendula ha bisogno dei permessi di scrittura per creare gli eventi</string>
|
||||
<string name="event_edit_more_fields">Altri campi</string>
|
||||
<string name="event_edit_add">Aggiungi</string>
|
||||
<string name="event_edit_add_reminder">Aggiungi promemoria</string>
|
||||
<string name="event_edit_remove_reminder">Rimuovi promemoria</string>
|
||||
<string name="event_edit_attendees">Partecipanti</string>
|
||||
<string name="event_edit_add_guest">Aggiungi partecipante</string>
|
||||
<string name="event_edit_add_guest_hint">Aggiungi un partecipante via email…</string>
|
||||
<string name="event_edit_add_guest_from_contacts">Aggiungi dai contatti</string>
|
||||
<string name="event_edit_location_from_contacts">Scegli un indirizzo dai contatti</string>
|
||||
<string name="event_edit_remove_guest">Rimuovi partecipante</string>
|
||||
<string name="event_edit_attendee_required">Obbligatorio</string>
|
||||
<string name="event_edit_attendee_optional">Facoltativo</string>
|
||||
<string name="event_edit_attendees_note_synced">Calendula non manda gli inviti agli eventi. Il tuo account calendario potrà inviare le email ai partecipanti al momento della sincronizzazione.</string>
|
||||
<string name="event_edit_attendees_note_local">Salvato sul dispositivo. Nessuno ha ricevuto notifiche.</string>
|
||||
<string name="event_edit_reminder_custom">Personalizza</string>
|
||||
<string name="reminder_unit_minutes">minuti</string>
|
||||
<string name="reminder_unit_hours">ore</string>
|
||||
<string name="reminder_unit_days">giorni</string>
|
||||
<string name="reminder_unit_weeks">settimane</string>
|
||||
<string name="event_edit_availability">Disponibilità</string>
|
||||
<string name="event_edit_visibility">Visibilità</string>
|
||||
<string name="event_edit_color">Colore</string>
|
||||
<string name="event_edit_color_default">Colore calendario</string>
|
||||
<string name="event_edit_color_custom">Colore personalizzato</string>
|
||||
<string name="event_edit_color_reset">Reset</string>
|
||||
<string name="event_edit_color_unsupported">Non disponibile per questo calendario</string>
|
||||
<string name="event_edit_color_unsupported_hint">I colori non sono ammessi per questo calendario. Puoi abilitare i colori personalizzati per questo tipo di calendario dalle Impostazioni.</string>
|
||||
<string name="event_edit_color_sync_warning">Il colore per questo calendario potrà andare perso o essere sovrascritto alla prossima sincronizzazione.</string>
|
||||
<string name="event_edit_conflict_title">Evento modificato altrove</string>
|
||||
<string name="event_edit_conflict_body">Durante la modifica l\'evento è stato cambiato, tramite sincronizzazione o tramite altra app. Cosa fare con le modifiche in corso?</string>
|
||||
<string name="event_edit_conflict_overwrite">Salva le modifiche</string>
|
||||
<string name="event_edit_conflict_overwrite_hint">Sovrascrivi solo i campi modificati</string>
|
||||
<string name="event_edit_conflict_discard">Annulla le mie modifiche</string>
|
||||
<string name="event_edit_conflict_discard_hint">Mantieni l\'evento com\'è ora</string>
|
||||
<string name="event_edit_gone_title">Evento eliminato</string>
|
||||
<string name="event_edit_gone_body">Nel frattempo, questo evento è stato eliminato, ad esempio su un altro dispositivo. Le modifiche non possono più essere salvate.</string>
|
||||
<string name="event_edit_recurrence_none">Non si ripete</string>
|
||||
<string name="event_edit_recurrence_custom">Personalizza</string>
|
||||
<string name="event_edit_recurrence_every">La serie</string>
|
||||
<string name="recurrence_unit_days">giorni</string>
|
||||
<string name="recurrence_unit_weeks">settimane</string>
|
||||
<string name="recurrence_unit_months">mesi</string>
|
||||
<string name="recurrence_unit_years">anni</string>
|
||||
<string name="event_edit_recurrence_ends">Fine</string>
|
||||
<string name="event_edit_recurrence_end_never">Mai</string>
|
||||
<string name="event_edit_recurrence_end_until">Fino alla data</string>
|
||||
<string name="event_edit_recurrence_end_count">Dopo un certo numero di occorrenze</string>
|
||||
<string name="event_edit_recurrence_times">occorrenze</string>
|
||||
<string name="event_edit_error_recurrence_ends_before_start">Fine antecedente l\'inizio</string>
|
||||
<string name="event_availability_busy">Occupato</string>
|
||||
<string name="event_access_default">Default</string>
|
||||
<string name="event_access_public">Pubblico</string>
|
||||
<string name="event_detail_all_day">Tutto il giorno</string>
|
||||
<string name="event_detail_calendar">Calendario</string>
|
||||
<string name="event_detail_calendar_unknown">Calendario sconosciuto</string>
|
||||
<string name="event_detail_location">Luogo</string>
|
||||
<string name="event_detail_description">Descrizione</string>
|
||||
<string name="event_detail_attendees">Partecipanti</string>
|
||||
<string name="recurrence_daily">Ogni giorni</string>
|
||||
<string name="recurrence_weekly">Ogni settimana</string>
|
||||
<string name="recurrence_monthly">Ogni mese</string>
|
||||
<string name="recurrence_yearly">Ogni anno</string>
|
||||
<string name="recurrence_every_n_days">Ogni %1$d giorni</string>
|
||||
<string name="recurrence_every_n_weeks">Ogni %1$d settimane</string>
|
||||
<string name="recurrence_every_n_months">Ogni %1$d mesi</string>
|
||||
<string name="recurrence_every_n_years">Ogni %1$d anni</string>
|
||||
<string name="event_detail_not_found">Questo evento è stato eliminato.</string>
|
||||
<string name="event_attendee_accepted">Accettato</string>
|
||||
<string name="event_attendee_declined">Rifiutato</string>
|
||||
<string name="event_attendee_tentative">Provvisorio</string>
|
||||
<string name="event_attendee_needs_action">Nessuna risposta</string>
|
||||
<string name="event_attendee_unknown">—</string>
|
||||
<string name="event_detail_reminders">Promemoria</string>
|
||||
<string name="event_detail_timezone">Fuso orario</string>
|
||||
<string name="event_status_tentative">Provvisorio</string>
|
||||
<string name="event_status_cancelled">Annullato</string>
|
||||
<string name="event_availability_free">Disponibile</string>
|
||||
<string name="event_access_private">Privato</string>
|
||||
<string name="event_access_confidential">Confidenziale</string>
|
||||
<string name="event_attendee_organizer">Organizzatore</string>
|
||||
<string name="event_attendee_optional">Facoltativo</string>
|
||||
<string name="event_detail_self_response">La tua risposta: %1$s</string>
|
||||
<string name="reminder_at_time">All\'ora dell\'evento</string>
|
||||
<string name="reminder_default">Promemoria standard</string>
|
||||
<plurals name="reminder_minutes">
|
||||
<item quantity="one">%d minuto prima</item>
|
||||
<item quantity="many">%d minuti prima</item>
|
||||
<item quantity="other">%d minuti prima</item>
|
||||
</plurals>
|
||||
<plurals name="reminder_hours">
|
||||
<item quantity="one">%d ora prima</item>
|
||||
<item quantity="many">%d ore prima</item>
|
||||
<item quantity="other">%d ore prima</item>
|
||||
</plurals>
|
||||
<plurals name="reminder_days">
|
||||
<item quantity="one">%d giorno prima</item>
|
||||
<item quantity="many">%d giorni prima</item>
|
||||
<item quantity="other">%d giorni prima</item>
|
||||
</plurals>
|
||||
<plurals name="reminder_weeks">
|
||||
<item quantity="one">%d settimana prima</item>
|
||||
<item quantity="many">%d settimanw prima</item>
|
||||
<item quantity="other">%d settimane prima</item>
|
||||
</plurals>
|
||||
<plurals name="duration_minutes">
|
||||
<item quantity="one">%d minuto</item>
|
||||
<item quantity="many">%d minuti</item>
|
||||
<item quantity="other">%d minuti</item>
|
||||
</plurals>
|
||||
<plurals name="duration_hours">
|
||||
<item quantity="one">%d ora</item>
|
||||
<item quantity="many">%d ore</item>
|
||||
<item quantity="other">%d ore</item>
|
||||
</plurals>
|
||||
<plurals name="duration_days">
|
||||
<item quantity="one">%d giorno</item>
|
||||
<item quantity="many">%d giorni</item>
|
||||
<item quantity="other">%d giorni</item>
|
||||
</plurals>
|
||||
<plurals name="duration_weeks">
|
||||
<item quantity="one">%d settimana</item>
|
||||
<item quantity="many">%d settimane</item>
|
||||
<item quantity="other">%d settimane</item>
|
||||
</plurals>
|
||||
<string name="event_untitled">(nessun titolo)</string>
|
||||
<string name="reminder_channel_name">Promemoria evento</string>
|
||||
<string name="event_attendee_resource">Risorsa</string>
|
||||
<string name="reminder_onboarding_title">Non perderti nessun evento</string>
|
||||
<string name="reminder_onboarding_body">Android non mostra i promemoria per gli eventi autonomamente, serve un\'app. Lascia che sia Calendula a farlo.</string>
|
||||
<string name="reminder_benefit_delivery_title">Promemoria, eccoli</string>
|
||||
<string name="reminder_benefit_delivery_body">Tutti i promemoria dei tuoi eventi arrivano tramite notifica, proprio al momento giusto.</string>
|
||||
<string name="reminder_benefit_duplicates_title">Stai usando un\'altra app calendario?</string>
|
||||
<string name="reminder_benefit_duplicates_body">Se un\'altra app manda promemoria li vedrai due volte. Disattivali qui o nell\'altra app.</string>
|
||||
<string name="reminder_benefit_reversible_title">Cambialo in ogni momento</string>
|
||||
<string name="reminder_benefit_reversible_body">Lo switch è nelle Impostazioni, sezione Notifiche.</string>
|
||||
<string name="reminder_onboarding_enable_button">Attiva i promemoria</string>
|
||||
<string name="reminder_onboarding_skip_button">Non ora</string>
|
||||
<string name="reminder_action_snooze">Posponi</string>
|
||||
<string name="reminder_action_dismiss">Ignora</string>
|
||||
<string name="view_month">Mese</string>
|
||||
<string name="view_week">Settimana</string>
|
||||
<string name="view_day">Giorno</string>
|
||||
<string name="view_agenda">Agenda</string>
|
||||
<string name="view_section">Vista</string>
|
||||
<string name="drawer_jump_to_date">Vai alla data</string>
|
||||
<string name="agenda_today_action">Oggi</string>
|
||||
<string name="agenda_header_tomorrow">Domani</string>
|
||||
<string name="agenda_empty_title">Hai fatto tutto</string>
|
||||
<string name="search_action">Cerca</string>
|
||||
<string name="search_hint">Cerca eventi</string>
|
||||
<string name="search_back">Indietro</string>
|
||||
<string name="search_clear">Pulisci</string>
|
||||
<string name="search_idle_hint">Cerca gli eventi per titolo, luogo o note.</string>
|
||||
<string name="search_empty">Nessun risultato per \"%1$s\".</string>
|
||||
<string name="widget_agenda_title">Prossimamente</string>
|
||||
<string name="widget_agenda_label">Agenda Calendula</string>
|
||||
<string name="widget_month_label">Mese Calendula</string>
|
||||
<string name="widget_refresh">Aggiorna</string>
|
||||
<string name="widget_new_event">Nuovo evento</string>
|
||||
<string name="widget_needs_permission">Apri Calendula per concedere l\'accesso al calendario</string>
|
||||
<string name="widget_prev_month">Mese precedente</string>
|
||||
<string name="filter_title">Calendari</string>
|
||||
<string name="settings_section_appearance">Aspetto</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="settings_theme_system">Sistema</string>
|
||||
<string name="settings_theme_light">Chiaro</string>
|
||||
<string name="settings_theme_dark">Scuro</string>
|
||||
<string name="settings_default_view">Vista di default</string>
|
||||
<string name="settings_dynamic_color">Colori dinamici</string>
|
||||
<string name="settings_dynamic_color_unavailable">Richiede Android 12 o superiore</string>
|
||||
<string name="settings_week_start">La settimana comincia di</string>
|
||||
<string name="settings_week_start_auto">Automatico</string>
|
||||
<string name="settings_time_format">Formato ora</string>
|
||||
<string name="settings_time_format_auto">Automatico</string>
|
||||
<string name="settings_time_format_12h">12 ore</string>
|
||||
<string name="settings_time_format_24h">24 ore</string>
|
||||
<string name="settings_hour_lines">Righe per le ore</string>
|
||||
<string name="settings_hour_lines_summary">Mostra una riga separatrice per ogni ora nella vista Settimana e Giorno</string>
|
||||
<string name="settings_dim_completed">Attenua gli eventi completati</string>
|
||||
<string name="settings_dim_completed_summary">Attenua gli eventi conclusi nella vista Mese e Settimana</string>
|
||||
<string name="settings_past_events">Eventi passati</string>
|
||||
<string name="settings_past_events_show">Mostra</string>
|
||||
<string name="settings_past_events_dim">Attenua</string>
|
||||
<string name="settings_past_events_hide">Nascondi</string>
|
||||
<string name="settings_agenda_header">Agenda</string>
|
||||
<string name="settings_agenda_range">Intervallo dell\'Agenda</string>
|
||||
<string name="settings_agenda_range_hint">Anticipo con cui vengono visualizzati gli eventi nell\'Agenda.</string>
|
||||
<string name="settings_agenda_widget_range">Intervallo del widget Agenda</string>
|
||||
<string name="settings_agenda_widget_range_hint">Anticipo con cui vengono visualizzati gli eventi nel widget Agenda.</string>
|
||||
<string name="settings_agenda_range_bar">Barra dell\'intervallo</string>
|
||||
<string name="settings_agenda_range_bar_hint">Mostra una barra sopra l\'agenda che indica le date mostrate, con un pulsante per cambiare l\'intervallo scelto per la sessione</string>
|
||||
<string name="agenda_range_day">Oggi</string>
|
||||
<string name="agenda_range_this_month">Questo mese</string>
|
||||
<string name="agenda_range_week">Prossimi 7 giorni</string>
|
||||
<string name="agenda_range_month">Prossimi 30 giorni</string>
|
||||
<string name="agenda_range_custom">Personalizza…</string>
|
||||
<string name="agenda_range_custom_hint">Giorni</string>
|
||||
<string name="agenda_range_override_hint">Solo questa volta, ripristina l\'intervallo salvato al riavvio di Calendula.</string>
|
||||
<string name="agenda_range_showing_label">Mostra tutti gli eventi in arrivo per</string>
|
||||
<plurals name="agenda_range_days">
|
||||
<item quantity="one">%d giorno</item>
|
||||
<item quantity="many">%d giorni</item>
|
||||
<item quantity="other">%d giorni</item>
|
||||
</plurals>
|
||||
<string name="settings_section_event_form">Scheda Nuovo Evento</string>
|
||||
<string name="settings_form_fields_hint">Campi mostrati di default, tutti gli altri saranno in \"Altri campi\"</string>
|
||||
<string name="settings_autofocus_title">Subito al titolo su un nuovo evento</string>
|
||||
<string name="settings_autofocus_title_hint">Quando crei un nuovo evento, posiziona subito il cursore sul campo Titolo e mostra la tastiera.</string>
|
||||
<string name="settings_color_unsupported">Abilita i colori sui calendari non supportati</string>
|
||||
<string name="settings_color_unsupported_hint">Alcuni calendari (e.g. alcuni CalDAV) non pubblicano il set di colori di cui sono dotati; i colori personalizzati assegnati a un evento possono essere persi o sovrascritti alla prossima sincronizzazione. È una limitazione di questo tipo di calendari, Calendula non può farci nulla.</string>
|
||||
<string name="settings_section_notifications">Notifiche</string>
|
||||
<string name="settings_reminders_hint">Vedi promemoria duplicati? Vuol dire che li sta mostrando anche un\'altra app. Disattivali qui o nell\'altra app.</string>
|
||||
<string name="settings_default_reminder_allday">Eventi giornalieri</string>
|
||||
<string name="settings_allday_reminder_time">Ora per i promemoria degli eventi giornalieri</string>
|
||||
<string name="settings_allday_reminder_time_hint">I promemoria per gli eventi giornalieri vengono mandati alle %1$s</string>
|
||||
<string name="reminder_none">Nessuno</string>
|
||||
<string name="reminder_use_default">Usa il promemoria standard</string>
|
||||
<string name="reminder_custom_amount">Valore</string>
|
||||
<string name="reminder_custom_with_value">Personalizza (%1$s)</string>
|
||||
<string name="reminder_custom_set">Imposta</string>
|
||||
<string name="settings_calendar_reminders_title">Promemoria per calendario</string>
|
||||
<string name="settings_calendar_reminders_hint">Sovrascrivi i reminder standard con reminder specifici per calendario, separati per eventi giornalieri ed eventi ad ore. Ogni calendario può usare i promemoria di default, ignorarli o avere i suoi personalizzati.</string>
|
||||
<string name="settings_calendar_reminder_inherits">Default (%1$s)</string>
|
||||
<string name="settings_reliable_delivery">Notifiche affidabili</string>
|
||||
<string name="settings_reliable_delivery_hint">Android potrebbe posticipare le notifiche per risparmiare batteria. Escludi Calendula così che le notifiche possano arrivare puntuali.</string>
|
||||
<string name="settings_reliable_delivery_exempt">Escludi dall\'ottimizzazione batteria. I promemoria arriveranno puntuali.</string>
|
||||
<string name="settings_snooze_duration">Durata del posticipo</string>
|
||||
<string name="settings_section_calendars">Calendari</string>
|
||||
<string name="settings_manage_calendars">Gestisci calendari</string>
|
||||
<string name="settings_manage_calendars_hint">Crea calendari locali; gestisci quelli sincronizzati</string>
|
||||
<string name="settings_section_language">Lingua</string>
|
||||
<string name="settings_language">Lingua dell\'app</string>
|
||||
<string name="settings_language_auto">Lingua di sistema</string>
|
||||
<string name="settings_translate">Aiuta a tradurre</string>
|
||||
<string name="settings_translate_hint">Aggiungi o migliora una traduzione su Weblate</string>
|
||||
<string name="settings_appearance_subtitle">Tema, vista di default, inizio settimana</string>
|
||||
<string name="settings_event_form_subtitle">Campi di default per nuovi eventi</string>
|
||||
<string name="settings_section_about">A proposito</string>
|
||||
<string name="settings_license">Licenza</string>
|
||||
<string name="settings_license_value">MIT</string>
|
||||
<string name="settings_about_author">da Jean-Luc Makiola</string>
|
||||
<string name="settings_about_source">Sorgente</string>
|
||||
<string name="settings_about_support">Sostieni lo sviluppo</string>
|
||||
<string name="settings_about_version">Versione %1$s</string>
|
||||
<string name="settings_about_logo_desc">Icona dell\'app</string>
|
||||
<string name="settings_report_problem">Segnala un problema</string>
|
||||
<string name="settings_report_problem_hint">Invia un crash report o apri il gestore dei problemi</string>
|
||||
<string name="calendars_title">Calendari</string>
|
||||
<string name="calendars_local_header">I tuoi calendari</string>
|
||||
<string name="calendars_local_empty">Non ci sono ancora calendari locali. Creane uno per avere gli eventi solo su questo dispositivo.</string>
|
||||
<string name="calendars_add">Aggiungi calendario</string>
|
||||
<string name="calendars_disable_hint">.Disattiva un calendario per non vederlo più sull\'app. Non viene cancellato nulla, puoi riattivarlo in qualsiasi momento.</string>
|
||||
<string name="calendars_show_in_app_a11y">Mostra \"%1$s\" nell\'app</string>
|
||||
<string name="calendars_synced_header">Calendari sincronizzati</string>
|
||||
<string name="calendars_synced_hint">Questi vengono dagli account presenti sul tuo dispositivo. Creali e modificali nella loro app.</string>
|
||||
<string name="calendars_manage_in_app">Gestisci in app</string>
|
||||
<string name="calendars_account_menu_a11y">Altre opzioni per %1$s</string>
|
||||
<string name="calendars_enable_all">Attiva tutti</string>
|
||||
<string name="calendars_disable_all">Disattiva tutti</string>
|
||||
<string name="calendars_add_account">Aggiungi account</string>
|
||||
<string name="calendars_new_title">Nuovo calendario</string>
|
||||
<string name="calendars_edit_title">Modifica calendario</string>
|
||||
<string name="calendars_name_label">Nome</string>
|
||||
<string name="calendars_color_label">Colore</string>
|
||||
<string name="calendars_description_hint">Aggiungi descrizione</string>
|
||||
<string name="calendars_delete_confirm_title">Eliminare calendario?</string>
|
||||
<string name="calendars_delete_confirm_message">\"%1$s\" e tutti i suoi eventi saranno definitivamente rimossi da questo dispositivo.</string>
|
||||
<string name="calendars_write_error">Impossibile salvare le modifiche.</string>
|
||||
<string name="calendars_backup_header">Backup</string>
|
||||
<string name="calendars_backup_hint">I calendari locali non vengono sincronizzati da nessuna parte, esportali in un file .ics per conservarne una copia.</string>
|
||||
<string name="calendars_backup_action">Esporta come file .ics</string>
|
||||
<string name="calendars_auto_backup">Backup automatico</string>
|
||||
<string name="calendars_auto_backup_hint">Esporta periodicamente in una cartella i tuoi calendari in formato .ics.</string>
|
||||
<string name="calendars_auto_backup_folder">Cartella di backup</string>
|
||||
<string name="calendars_auto_backup_folder_unset">Scegli una cartella</string>
|
||||
<string name="calendars_auto_backup_interval">Intervallo</string>
|
||||
<string name="calendars_auto_backup_every">Ogni %1$s</string>
|
||||
<string name="calendars_auto_backup_interval_min">Minimo 30 minuti.</string>
|
||||
<string name="calendars_auto_backup_status_never">Backup automatico non attivo</string>
|
||||
<string name="calendars_auto_backup_status_ok">Ultimo backup: %1$s</string>
|
||||
<string name="calendars_auto_backup_status_failed">Ultimo backup fallito: %1$s</string>
|
||||
<string name="backup_channel_name">Backup</string>
|
||||
<string name="backup_channel_description">Avvisa se i backup automatici falliscono ripetutamente.</string>
|
||||
<string name="backup_failed_title">Backup automatico fallito</string>
|
||||
<string name="backup_failed_text">Calendula non è riuscito a esportare il file di backup. Controlla la cartella di backup nelle Impostazioni.</string>
|
||||
<string name="calendars_backup_failed">Impossibile esportare il backup.</string>
|
||||
<plurals name="calendars_backup_done">
|
||||
<item quantity="one">Esportato %d evento.</item>
|
||||
<item quantity="many">Esportati %d eventi.</item>
|
||||
<item quantity="other">Esportati %d eventi.</item>
|
||||
</plurals>
|
||||
<string name="import_title">Importa eventi</string>
|
||||
<string name="import_target_header">Aggiungi al calendario</string>
|
||||
<string name="import_empty">Non ci sono eventi in questo file.</string>
|
||||
<string name="import_failed">Impossibile leggere il file.</string>
|
||||
<string name="import_no_calendar">Non ci sono calendari su cui importare. Crea prima un calendario locale.</string>
|
||||
<string name="import_done_title">Import completato</string>
|
||||
<string name="import_close">Chiudi</string>
|
||||
<string name="import_warning_recurrence">Alcune occorrenze degli eventi ricorrenti, che erano state modificate, sono state saltate.</string>
|
||||
<string name="import_warning_no_start">Un evento senza orario di inizio è stato saltato.</string>
|
||||
<string name="import_warning_attendees">Gli elenchi dei partecipanti non sono stati importati.</string>
|
||||
<string name="import_warning_timezone">Un fuso orario sconosciuto è tornato sul tuo dispositivo.</string>
|
||||
<plurals name="import_event_count">
|
||||
<item quantity="one">%d evento in questo file.</item>
|
||||
<item quantity="many">%d eventi in questo file.</item>
|
||||
<item quantity="other">%d eventi in questo file.</item>
|
||||
</plurals>
|
||||
<plurals name="import_action">
|
||||
<item quantity="one">Importa %d evento</item>
|
||||
<item quantity="many">Importa %d eventi</item>
|
||||
<item quantity="other">Importa %d eventi</item>
|
||||
</plurals>
|
||||
<plurals name="import_done_imported">
|
||||
<item quantity="one">Importato %d evento.</item>
|
||||
<item quantity="many">Importati %d eventi.</item>
|
||||
<item quantity="other">Importati %d eventi.</item>
|
||||
</plurals>
|
||||
<plurals name="import_done_skipped">
|
||||
<item quantity="one">Saltato %d evento già presente nel calendario.</item>
|
||||
<item quantity="many">SaltatI %d eventi già presentI nel calendario.</item>
|
||||
<item quantity="other">SaltatI %d eventi già presentI nel calendario.</item>
|
||||
</plurals>
|
||||
<string name="shortcut_new_event_long">Crea un nuovo evento</string>
|
||||
<string name="qs_tile_new_event_label">Nuovo evento</string>
|
||||
<string name="settings_qs_tile">Aggiungi un toggle nelle Impostazioni Rapide</string>
|
||||
<string name="settings_qs_tile_hint">Aggiungi un toggle \"Nuovo evento\" nel pannello delle Impostazioni Rapide.</string>
|
||||
<string name="crash_dialog_title">Calendula è crashato</string>
|
||||
<string name="crash_dialog_message">Calendula si è chiuso inaspettatamente l\'ultima volta. Puoi contribuire allo sviluppo inviando questo report, che rimane sul tuo dispositivo finchè non scegli di inviarlo e non include informazioni personali o sui tuoi calendari:solo le informazioni tecniche qui sotto.</string>
|
||||
<string name="crash_dialog_report">Report</string>
|
||||
<string name="crash_dialog_dismiss">Non ora</string>
|
||||
<string name="crash_report_issue_title">Crash report</string>
|
||||
<string name="crash_report_clip_label">Calendula crash report</string>
|
||||
<string name="crash_report_copied">Report copiato negli Appunti</string>
|
||||
<string name="crash_report_open_failed">Impossibile aprire il gestore dei problemi. Il report è sugli Appunti.</string>
|
||||
<string name="crash_report_body_template">Grazie per riportare un crash di Calendula. Per favore, aggiungi ogni informazione che ricordi in merito a quello che stavi facendo, quindi invia\n\n### Cosa è successo\n\n\n###Crash report\n%1$s\n</string>
|
||||
<string name="crash_report_body_paste">_(Il report era troppo lungo per questo link - copialo qui dai tuoi Appunti.)_</string>
|
||||
<string name="event_detail_recurrence">Ricorrenza</string>
|
||||
<string name="event_detail_recurring">Evento ricorrente</string>
|
||||
<string name="recurrence_on_days">%1$s da %2$s</string>
|
||||
<string name="recurrence_with_until">%1$s fino a %2$s</string>
|
||||
<string name="recurrence_with_count">%1$s, %2$d volte</string>
|
||||
<string name="reminder_channel_description">Notifiche al momento del promemoria dei tuoi eventi</string>
|
||||
<string name="agenda_header_today">Oggi</string>
|
||||
<string name="widget_next_month">Mese prossimo</string>
|
||||
<string name="widget_today">Oggi</string>
|
||||
<string name="settings_title">Impostazioni</string>
|
||||
<string name="settings_back">Indietro</string>
|
||||
<string name="agenda_range_this_week">Questa settimana</string>
|
||||
<string name="settings_reminders">Promemoria evento</string>
|
||||
<string name="settings_default_reminder">Promemoria standard</string>
|
||||
<string name="settings_notifications_subtitle">Promemoria evento</string>
|
||||
<string name="shortcut_new_event_short">Nuovo evento</string>
|
||||
</resources>
|
||||
9
app/src/main/res/values-pl/strings.xml
Normal file
9
app/src/main/res/values-pl/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="backup_interval_units">
|
||||
<item>Minutes</item>
|
||||
<item>Hours</item>
|
||||
<item>Days</item>
|
||||
<item>Weeks</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
9
app/src/main/res/values-pt/strings.xml
Normal file
9
app/src/main/res/values-pt/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="backup_interval_units">
|
||||
<item>Minutes</item>
|
||||
<item>Hours</item>
|
||||
<item>Days</item>
|
||||
<item>Weeks</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
9
app/src/main/res/values-ru/strings.xml
Normal file
9
app/src/main/res/values-ru/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="backup_interval_units">
|
||||
<item>Minutes</item>
|
||||
<item>Hours</item>
|
||||
<item>Days</item>
|
||||
<item>Weeks</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -282,6 +282,13 @@
|
||||
<string name="settings_time_format_24h">24-hour (14:00)</string>
|
||||
<string name="settings_hour_lines">Hour lines</string>
|
||||
<string name="settings_hour_lines_summary">Show a separator line at each hour in week and day view</string>
|
||||
<string name="settings_dim_completed">Dim completed events</string>
|
||||
<string name="settings_dim_completed_summary">Fade events that have already ended in month and week view</string>
|
||||
<string name="settings_past_events">Past events</string>
|
||||
<string name="settings_past_events_show">Show</string>
|
||||
<string name="settings_past_events_dim">Dim</string>
|
||||
<string name="settings_past_events_hide">Hide</string>
|
||||
<string name="settings_agenda_header">Agenda</string>
|
||||
<string name="settings_agenda_range">Agenda range</string>
|
||||
<string name="settings_agenda_range_hint">How far ahead the Agenda screen lists events.</string>
|
||||
<string name="settings_agenda_widget_range">Agenda widget range</string>
|
||||
@@ -303,6 +310,8 @@
|
||||
</plurals>
|
||||
<string name="settings_section_event_form">New event form</string>
|
||||
<string name="settings_form_fields_hint">Fields shown by default — everything else sits behind \"More fields\"</string>
|
||||
<string name="settings_autofocus_title">Focus title on new event</string>
|
||||
<string name="settings_autofocus_title_hint">When you start a new event, place the cursor in the title field and open the keyboard right away.</string>
|
||||
<string name="settings_color_unsupported">Allow colors on unsupported calendars</string>
|
||||
<string name="settings_color_unsupported_hint">Some calendars (e.g. certain CalDAV) publish no color set; a custom event color may be dropped or overwritten on their next sync. That\'s a limitation of those calendars, not something Calendula can fix.</string>
|
||||
<string name="settings_section_notifications">Notifications</string>
|
||||
|
||||
@@ -90,6 +90,14 @@ class SettingsPrefsTest {
|
||||
assertThat(prefs.showHourLines.first()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `autofocus event title defaults on and round-trips`(@TempDir tempDir: Path) = runTest {
|
||||
val prefs = SettingsPrefs(newDataStore(tempDir))
|
||||
assertThat(prefs.autofocusEventTitle.first()).isTrue()
|
||||
prefs.setAutofocusEventTitle(false)
|
||||
assertThat(prefs.autofocusEventTitle.first()).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `agenda ranges default to month and round-trip independently`(@TempDir tempDir: Path) = runTest {
|
||||
val prefs = SettingsPrefs(newDataStore(tempDir))
|
||||
|
||||
6
fastlane/metadata/android/en-US/changelogs/21101.txt
Normal file
6
fastlane/metadata/android/en-US/changelogs/21101.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
### Fixed
|
||||
- Calendula can now be set as your default calendar app. It registers the
|
||||
calendar-app intent filters the system uses, so it appears in the chooser when
|
||||
you tap a date in a launcher or clock — and opening one takes you straight to
|
||||
that day. Android has no way for an app to make itself the default, so you pick
|
||||
it once from the system picker. Thanks to @abrossimow for the report ([#9]).
|
||||
7
fastlane/metadata/android/en-US/changelogs/21102.txt
Normal file
7
fastlane/metadata/android/en-US/changelogs/21102.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
### Added
|
||||
- Jump straight to typing a title. When you start a new event, Calendula now puts
|
||||
the cursor in the title field and opens the keyboard right away, so you can type
|
||||
the name without an extra tap. It's on by default and only affects creating an
|
||||
event — editing never grabs focus — and a new **Focus title on new event**
|
||||
switch (Settings → New event form) turns it off. Thanks to @abrossimow for the
|
||||
suggestion ([#10]).
|
||||
19
fastlane/metadata/android/en-US/changelogs/21200.txt
Normal file
19
fastlane/metadata/android/en-US/changelogs/21200.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
### Added
|
||||
- See past events your way. Two new settings change how events that have already
|
||||
ended are shown. **Past events** (Settings → Appearance → Agenda) lets the
|
||||
agenda — both in the app and the home-screen "Upcoming" widget — keep them as
|
||||
usual, dim them, or hide them from the list entirely. **Dim completed events**
|
||||
(Settings → Appearance) separately fades finished events in the month and week
|
||||
views. Both are off by default, an event only counts as finished once it has
|
||||
actually ended (events still in progress are never dimmed), and the lists
|
||||
update on their own as the day goes on. Thanks to @ptab for the suggestion
|
||||
([#12]).
|
||||
|
||||
### Changed
|
||||
- Readable titles on overlapping events. In the week and day views, events that
|
||||
overlap split a day into slim columns where the title used to be clipped to a
|
||||
character or two. The title now wraps across as many lines as the block can
|
||||
fit, and the time is hidden on those narrow blocks so the name can fill the
|
||||
space — so you can tell events apart without opening each one. Thanks to @ptab
|
||||
for the suggestion ([#13]).
|
||||
|
||||
Reference in New Issue
Block a user