Add support for different calendar systems, add secondary calendar
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
package de.mm20.launcher2.ui.base
|
||||
|
||||
import android.icu.util.Calendar
|
||||
import android.icu.util.LocaleData
|
||||
import android.icu.util.ULocale
|
||||
import android.text.format.DateFormat
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -17,6 +19,8 @@ import de.mm20.launcher2.preferences.ui.GridSettings
|
||||
import de.mm20.launcher2.preferences.ui.LocaleSettings
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.ui.component.ProvideIconShape
|
||||
import de.mm20.launcher2.ui.locals.LocalCalendarSystemIds
|
||||
import de.mm20.launcher2.ui.locals.LocalCalendarSystems
|
||||
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
||||
import de.mm20.launcher2.ui.locals.LocalGridSettings
|
||||
import de.mm20.launcher2.ui.locals.LocalMeasurementSystem
|
||||
@@ -82,13 +86,41 @@ fun ProvideSettings(
|
||||
}.distinctUntilChanged()
|
||||
}.collectAsState(null)
|
||||
|
||||
val calendarIds by remember {
|
||||
localeSettings.primaryCalendar.combine(localeSettings.secondaryCalendar) { p, s ->
|
||||
listOf(p, s)
|
||||
}
|
||||
}.collectAsState(listOf(null, null))
|
||||
|
||||
val calendars by remember {
|
||||
derivedStateOf {
|
||||
val p = calendarIds.first()
|
||||
val s = calendarIds.last()
|
||||
val primary = if (p == null) {
|
||||
Calendar.getInstance(ULocale.getDefault())
|
||||
} else {
|
||||
Calendar.getInstance(ULocale.getDefault().setKeywordValue("calendar", p))
|
||||
}
|
||||
val secondary = if (s == null) {
|
||||
null
|
||||
} else {
|
||||
Calendar.getInstance(ULocale.getDefault().setKeywordValue("calendar", s))
|
||||
}
|
||||
listOfNotNull(
|
||||
primary, secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (timeFormat == null || measurementSystem == null) return
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalFavoritesEnabled provides favoritesEnabled,
|
||||
LocalGridSettings provides gridSettings,
|
||||
LocalTimeFormat provides timeFormat!!,
|
||||
LocalMeasurementSystem provides measurementSystem!!
|
||||
LocalMeasurementSystem provides measurementSystem!!,
|
||||
LocalCalendarSystems provides calendars,
|
||||
LocalCalendarSystemIds provides calendarIds,
|
||||
) {
|
||||
ProvideIconShape(iconShape) {
|
||||
content()
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package de.mm20.launcher2.ui.launcher.search.calendar
|
||||
|
||||
import android.content.Context
|
||||
import android.icu.text.DateFormat
|
||||
import android.icu.text.DateIntervalFormat
|
||||
import android.icu.util.DateInterval
|
||||
import android.icu.util.ULocale
|
||||
import android.text.Html
|
||||
import android.text.format.DateUtils
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
@@ -18,6 +22,7 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
@@ -46,10 +51,12 @@ import de.mm20.launcher2.ui.ktx.toPixels
|
||||
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
|
||||
import de.mm20.launcher2.ui.launcher.search.listItemViewModel
|
||||
import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
|
||||
import de.mm20.launcher2.ui.locals.LocalCalendarSystemIds
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
||||
import de.mm20.launcher2.ui.locals.LocalGridSettings
|
||||
import de.mm20.launcher2.ui.locals.LocalTimeFormat
|
||||
import de.mm20.launcher2.ui.utils.isTwentyFourHours
|
||||
import palettes.TonalPalette
|
||||
|
||||
@Composable
|
||||
@@ -147,15 +154,33 @@ fun CalendarItem(
|
||||
painter = painterResource(R.drawable.schedule_24px),
|
||||
contentDescription = null
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.sharedBounds(
|
||||
rememberSharedContentState("date"),
|
||||
this@AnimatedContent
|
||||
),
|
||||
text = calendar.formatTime(context, timeFormat),
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
Column {
|
||||
val primaryCalendar = LocalCalendarSystemIds.current.first()
|
||||
val secondaryCalendar = LocalCalendarSystemIds.current.last()
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.sharedBounds(
|
||||
rememberSharedContentState("date"),
|
||||
this@AnimatedContent
|
||||
),
|
||||
text = calendar.formatTime(context, timeFormat, primaryCalendar),
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
|
||||
if (secondaryCalendar != null) {
|
||||
Text(
|
||||
modifier = modifier.padding(top = 2.dp),
|
||||
text = calendar.formatTime(
|
||||
context,
|
||||
timeFormat,
|
||||
secondaryCalendar
|
||||
),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!calendar.description.isNullOrBlank()) {
|
||||
Row(
|
||||
@@ -258,10 +283,10 @@ fun CalendarItem(
|
||||
val sheetManager = LocalBottomSheetManager.current
|
||||
toolbarActions.add(
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_customize),
|
||||
icon = R.drawable.tune_24px,
|
||||
action = { sheetManager.showCustomizeSearchableModal(calendar) }
|
||||
))
|
||||
label = stringResource(R.string.menu_customize),
|
||||
icon = R.drawable.tune_24px,
|
||||
action = { sheetManager.showCustomizeSearchableModal(calendar) }
|
||||
))
|
||||
|
||||
Toolbar(
|
||||
leftActions = listOf(
|
||||
@@ -321,7 +346,7 @@ fun CalendarItem(
|
||||
rememberSharedContentState("date"),
|
||||
this@AnimatedContent
|
||||
),
|
||||
text = calendar.getSummary(context, timeFormat),
|
||||
text = calendar.getSummary(context, timeFormat, LocalCalendarSystemIds.current.first()),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
@@ -366,54 +391,47 @@ fun CalendarItemGridPopup(
|
||||
private fun CalendarEvent.formatTime(
|
||||
context: Context,
|
||||
timeFormat: TimeFormat,
|
||||
calendarSystem: String?,
|
||||
): String {
|
||||
val timeFormatFlag = when (timeFormat) {
|
||||
TimeFormat.System -> 0
|
||||
TimeFormat.TwelveHour -> DateUtils.FORMAT_12HOUR
|
||||
TimeFormat.TwentyFourHour -> DateUtils.FORMAT_24HOUR
|
||||
val locale = ULocale.getDefault().setKeywordValue("calendar", calendarSystem)
|
||||
|
||||
val time = if (timeFormat.isTwentyFourHours(context)) {
|
||||
"HH:mm"
|
||||
} else {
|
||||
"hh:mm a"
|
||||
}
|
||||
|
||||
val startTime = startTime
|
||||
if (startTime == null || isTask) {
|
||||
if (allDay) {
|
||||
return DateUtils.formatDateRange(
|
||||
context,
|
||||
endTime,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_DATE or timeFormatFlag
|
||||
)
|
||||
return DateFormat.getInstanceForSkeleton("EEE, MMMM d yyyy", locale)
|
||||
.format(endTime)
|
||||
}
|
||||
return DateUtils.formatDateRange(
|
||||
context,
|
||||
endTime,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_TIME or timeFormatFlag
|
||||
)
|
||||
return DateFormat.getInstanceForSkeleton("EEE, MMMM d yyyy, $time", locale)
|
||||
.format(endTime)
|
||||
}
|
||||
|
||||
if (allDay) return DateUtils.formatDateRange(
|
||||
context,
|
||||
startTime,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_WEEKDAY or timeFormatFlag
|
||||
)
|
||||
return DateUtils.formatDateRange(
|
||||
context,
|
||||
startTime,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_TIME or DateUtils.FORMAT_SHOW_WEEKDAY or timeFormatFlag
|
||||
)
|
||||
if (allDay) {
|
||||
return DateIntervalFormat.getInstance("EEE, MMMM d yyyy", locale)
|
||||
.format(DateInterval(startTime, endTime))
|
||||
}
|
||||
|
||||
return DateIntervalFormat.getInstance("EEE, MMMM d yyyy, $time", locale)
|
||||
.format(DateInterval(startTime, endTime))
|
||||
|
||||
}
|
||||
|
||||
private fun CalendarEvent.getSummary(
|
||||
context: Context,
|
||||
timeFormat: TimeFormat,
|
||||
calendarSystem: String?,
|
||||
): String {
|
||||
val timeFormatFlag = when (timeFormat) {
|
||||
TimeFormat.System -> 0
|
||||
TimeFormat.TwelveHour -> DateUtils.FORMAT_12HOUR
|
||||
TimeFormat.TwentyFourHour -> DateUtils.FORMAT_24HOUR
|
||||
val locale = ULocale.getDefault().setKeywordValue("calendar", calendarSystem)
|
||||
|
||||
val time = if (timeFormat.isTwentyFourHours(context)) {
|
||||
"HH:mm"
|
||||
} else {
|
||||
"hh:mm a"
|
||||
}
|
||||
|
||||
val startTime = startTime
|
||||
@@ -424,28 +442,22 @@ private fun CalendarEvent.getSummary(
|
||||
return context.getString(R.string.task_due_today)
|
||||
}
|
||||
return context.getString(
|
||||
R.string.task_due_time, DateUtils.formatDateTime(
|
||||
context,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_TIME or timeFormatFlag
|
||||
)
|
||||
R.string.task_due_time,
|
||||
DateIntervalFormat.getInstance(time, locale)
|
||||
.format(DateInterval(endTime, endTime))
|
||||
)
|
||||
}
|
||||
if (allDay) {
|
||||
return context.getString(
|
||||
R.string.task_due_date, DateUtils.formatDateTime(
|
||||
context,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_DATE or timeFormatFlag
|
||||
)
|
||||
R.string.task_due_date,
|
||||
DateFormat.getInstanceForSkeleton("EEE, MMMM d", locale)
|
||||
.format(endTime)
|
||||
)
|
||||
}
|
||||
return context.getString(
|
||||
R.string.task_due_date, DateUtils.formatDateTime(
|
||||
context,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_TIME or timeFormatFlag
|
||||
)
|
||||
R.string.task_due_date,
|
||||
DateFormat.getInstanceForSkeleton("EEE, MMMM d, $time", locale)
|
||||
.format(endTime)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -455,28 +467,17 @@ private fun CalendarEvent.getSummary(
|
||||
if (allDay) {
|
||||
context.getString(R.string.calendar_event_allday)
|
||||
} else {
|
||||
DateUtils.formatDateRange(
|
||||
context,
|
||||
startTime,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_TIME or timeFormatFlag
|
||||
)
|
||||
DateIntervalFormat.getInstance(time, locale)
|
||||
.format(DateInterval(startTime, endTime))
|
||||
}
|
||||
} else {
|
||||
if (allDay) {
|
||||
DateUtils.formatDateRange(
|
||||
context,
|
||||
startTime,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_DATE or timeFormatFlag
|
||||
)
|
||||
DateIntervalFormat.getInstance("MMMM d", locale)
|
||||
.format(DateInterval(startTime, endTime))
|
||||
} else {
|
||||
DateUtils.formatDateRange(
|
||||
context,
|
||||
startTime,
|
||||
endTime,
|
||||
DateUtils.FORMAT_SHOW_TIME or DateUtils.FORMAT_SHOW_DATE or timeFormatFlag
|
||||
)
|
||||
|
||||
DateIntervalFormat.getInstance("MMMM d, $time", locale)
|
||||
.format(DateInterval(startTime, endTime))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets.calendar
|
||||
|
||||
import android.content.Context
|
||||
import android.icu.text.DateFormat
|
||||
import android.icu.util.Calendar
|
||||
import android.icu.util.ULocale
|
||||
import android.text.format.DateUtils
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
@@ -50,7 +53,9 @@ import de.mm20.launcher2.Quintuple
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList
|
||||
import de.mm20.launcher2.ui.locals.LocalCalendarSystems
|
||||
import de.mm20.launcher2.widgets.CalendarWidget
|
||||
import java.sql.Date
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneId
|
||||
|
||||
@@ -92,7 +97,7 @@ fun CalendarWidget(
|
||||
var showDropdown by remember { mutableStateOf(false) }
|
||||
TextButton(onClick = { showDropdown = true }) {
|
||||
Text(
|
||||
text = formatDay(context, selectedDate),
|
||||
text = formatDay(context, selectedDate, LocalCalendarSystems.current[0]!!),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 1,
|
||||
@@ -120,7 +125,7 @@ fun CalendarWidget(
|
||||
else -> MenuDefaults.middleItemShape
|
||||
},
|
||||
text = {
|
||||
Text(formatDay(context, date))
|
||||
Text(formatDay(context, date, LocalCalendarSystems.current[0]!!))
|
||||
},
|
||||
onClick = {
|
||||
viewModel.selectDate(date)
|
||||
@@ -316,15 +321,15 @@ private fun Info(
|
||||
}
|
||||
|
||||
|
||||
private fun formatDay(context: Context, day: LocalDate): String {
|
||||
private fun formatDay(context: Context, day: LocalDate, calendar: Calendar): String {
|
||||
val today = LocalDate.now()
|
||||
return when {
|
||||
today == day -> context.getString(R.string.date_today)
|
||||
today.plusDays(1) == day -> context.getString(R.string.date_tomorrow)
|
||||
else -> DateUtils.formatDateTime(
|
||||
context,
|
||||
day.atStartOfDay(ZoneId.systemDefault()).toEpochSecond() * 1000,
|
||||
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_WEEKDAY or DateUtils.FORMAT_ABBREV_WEEKDAY
|
||||
)
|
||||
else -> DateFormat.getInstanceForSkeleton(
|
||||
calendar,
|
||||
"E MMMM d",
|
||||
ULocale.getDefault(),
|
||||
).format(Date.from(day.atStartOfDay(ZoneId.systemDefault()).toInstant()))
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,23 @@ package de.mm20.launcher2.ui.launcher.widgets.clock.parts
|
||||
import android.content.ContentUris
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.icu.text.DateFormat
|
||||
import android.icu.util.ULocale
|
||||
import android.provider.CalendarContract
|
||||
import android.text.format.DateFormat
|
||||
import android.text.format.DateUtils
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.em
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.ui.base.LocalTime
|
||||
import de.mm20.launcher2.ui.locals.LocalCalendarSystems
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class DatePartProvider : PartProvider {
|
||||
@@ -26,8 +30,15 @@ class DatePartProvider : PartProvider {
|
||||
@Composable
|
||||
override fun Component(compactLayout: Boolean) {
|
||||
val time = LocalTime.current
|
||||
val date = Date(time)
|
||||
val verticalLayout = !compactLayout
|
||||
val context = LocalContext.current
|
||||
|
||||
val calendars = LocalCalendarSystems.current
|
||||
|
||||
val primaryCal = calendars.first()
|
||||
val secondaryCal = calendars.getOrNull(1)
|
||||
|
||||
TextButton(
|
||||
colors = ButtonDefaults.textButtonColors(
|
||||
contentColor = LocalContentColor.current
|
||||
@@ -44,26 +55,84 @@ class DatePartProvider : PartProvider {
|
||||
context.tryStartActivity(intent)
|
||||
}) {
|
||||
if (verticalLayout) {
|
||||
Text(
|
||||
text = DateUtils.formatDateTime(
|
||||
context,
|
||||
time,
|
||||
DateUtils.FORMAT_SHOW_WEEKDAY or DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_YEAR
|
||||
),
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
} else {
|
||||
val line1Format = DateFormat.getBestDateTimePattern(Locale.getDefault(), "EEEE")
|
||||
val line2Format =
|
||||
DateFormat.getBestDateTimePattern(Locale.getDefault(), "MMMM dd")
|
||||
val format = SimpleDateFormat("$line1Format\n$line2Format")
|
||||
Text(
|
||||
text = format.format(time),
|
||||
lineHeight = 1.2.em,
|
||||
style = MaterialTheme.typography.titleLarge.copy(
|
||||
fontWeight = FontWeight.Medium
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = DateFormat.getInstanceForSkeleton(
|
||||
primaryCal,
|
||||
"EEEE, MMMM d, yyyy",
|
||||
ULocale.getDefault(),
|
||||
).format(date),
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
)
|
||||
|
||||
if (secondaryCal != null) {
|
||||
Text(
|
||||
text = DateFormat.getInstanceForSkeleton(
|
||||
secondaryCal,
|
||||
"MMMM dd, yyyy",
|
||||
ULocale.getDefault(),
|
||||
).format(date),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = LocalContentColor.current.copy(
|
||||
LocalContentColor.current.alpha * 0.7f
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (secondaryCal == null) {
|
||||
val line1 = DateFormat.getInstanceForSkeleton(
|
||||
primaryCal,
|
||||
"EEEE",
|
||||
ULocale.getDefault(),
|
||||
).format(date)
|
||||
val line2 =
|
||||
DateFormat.getInstanceForSkeleton(
|
||||
primaryCal,
|
||||
"MMMM d",
|
||||
ULocale.getDefault(),
|
||||
).format(date)
|
||||
Text(
|
||||
text = "$line1\n$line2",
|
||||
lineHeight = 1.2.em,
|
||||
style = MaterialTheme.typography.titleLarge.copy(
|
||||
fontWeight = FontWeight.Medium,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val line2 =
|
||||
DateFormat.getInstanceForSkeleton(
|
||||
secondaryCal,
|
||||
"MMMM d",
|
||||
ULocale.getDefault(),
|
||||
).format(date)
|
||||
Column {
|
||||
Text(
|
||||
text = DateFormat.getInstanceForSkeleton(
|
||||
primaryCal,
|
||||
"E MMMM d",
|
||||
ULocale.getDefault(),
|
||||
).format(date),
|
||||
lineHeight = 1.2.em,
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
Text(
|
||||
text = DateFormat.getInstanceForSkeleton(
|
||||
secondaryCal,
|
||||
"MMMM d",
|
||||
ULocale.getDefault(),
|
||||
).format(date),
|
||||
lineHeight = 1.2.em,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = LocalContentColor.current.copy(
|
||||
LocalContentColor.current.alpha * 0.7f
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.mm20.launcher2.ui.locals
|
||||
|
||||
import android.icu.util.Calendar
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
@@ -22,8 +23,10 @@ val LocalFavoritesEnabled = compositionLocalOf { true }
|
||||
|
||||
val LocalGridSettings = compositionLocalOf { GridSettings() }
|
||||
|
||||
val LocalTimeFormat = compositionLocalOf { TimeFormat.TwentyFourHour }
|
||||
val LocalMeasurementSystem = compositionLocalOf { MeasurementSystem.Metric }
|
||||
val LocalTimeFormat = staticCompositionLocalOf { TimeFormat.TwentyFourHour }
|
||||
val LocalMeasurementSystem = staticCompositionLocalOf { MeasurementSystem.Metric }
|
||||
val LocalCalendarSystems = staticCompositionLocalOf<List<Calendar?>> { listOf(null, null) }
|
||||
val LocalCalendarSystemIds = staticCompositionLocalOf<List<String?>> { listOf(null, null) }
|
||||
|
||||
val LocalSnackbarHostState = compositionLocalOf { SnackbarHostState() }
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ import de.mm20.launcher2.ui.settings.crashreporter.CrashReporterRoute
|
||||
import de.mm20.launcher2.ui.settings.crashreporter.CrashReporterScreen
|
||||
import de.mm20.launcher2.ui.settings.debug.DebugSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.debug.DebugSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.debug.StringNormalizerTestRoute
|
||||
import de.mm20.launcher2.ui.settings.debug.StringNormalizerTestScreen
|
||||
import de.mm20.launcher2.ui.settings.easteregg.EasterEggSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.easteregg.EasterEggSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.favorites.FavoritesSettingsRoute
|
||||
@@ -96,6 +98,8 @@ import de.mm20.launcher2.ui.settings.integrations.IntegrationsSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.integrations.IntegrationsSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.license.LicenseRoute
|
||||
import de.mm20.launcher2.ui.settings.license.LicenseScreen
|
||||
import de.mm20.launcher2.ui.settings.locale.CalendarSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.locale.CalendarSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.locale.LocaleSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.locale.LocaleSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.locations.LocationsSettingsRoute
|
||||
@@ -291,9 +295,15 @@ class SettingsActivity : BaseActivity() {
|
||||
entry<DebugSettingsRoute> {
|
||||
DebugSettingsScreen()
|
||||
}
|
||||
entry<StringNormalizerTestRoute> {
|
||||
StringNormalizerTestScreen()
|
||||
}
|
||||
entry<LocaleSettingsRoute> {
|
||||
LocaleSettingsScreen()
|
||||
}
|
||||
entry<CalendarSettingsRoute> {
|
||||
CalendarSettingsScreen()
|
||||
}
|
||||
entry<BackupSettingsRoute> {
|
||||
BackupSettingsScreen()
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -24,7 +23,6 @@ import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.locals.LocalBackStack
|
||||
import de.mm20.launcher2.ui.settings.crashreporter.CrashReporterRoute
|
||||
import de.mm20.launcher2.ui.settings.log.LogRoute
|
||||
@@ -38,7 +36,7 @@ import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
||||
@Serializable
|
||||
data object DebugSettingsRoute: NavKey
|
||||
data object DebugSettingsRoute : NavKey
|
||||
|
||||
@Composable
|
||||
fun DebugSettingsScreen() {
|
||||
@@ -133,6 +131,15 @@ fun DebugSettingsScreen() {
|
||||
onClick = {
|
||||
viewModel.reinstallIconPacks()
|
||||
})
|
||||
if (BuildConfig.DEBUG) {
|
||||
Preference(
|
||||
title = "String normalization test",
|
||||
summary = "Test string transliteration and normalization",
|
||||
onClick = {
|
||||
backStack += StringNormalizerTestRoute
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package de.mm20.launcher2.ui.settings.debug
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation3.runtime.NavKey
|
||||
import de.mm20.launcher2.search.StringNormalizer
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@Serializable
|
||||
data object StringNormalizerTestRoute: NavKey
|
||||
|
||||
@Composable
|
||||
fun StringNormalizerTestScreen() {
|
||||
PreferenceScreen(
|
||||
title = "String normalization test"
|
||||
) {
|
||||
item {
|
||||
val normalizer: StringNormalizer = koinInject()
|
||||
var string by remember { mutableStateOf("") }
|
||||
val normalizedString by remember {
|
||||
derivedStateOf {
|
||||
normalizer.normalize(string)
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceCategory {
|
||||
Surface {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
||||
value = string,
|
||||
onValueChange = { string = it },
|
||||
)
|
||||
}
|
||||
Surface {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
||||
text = normalizedString,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package de.mm20.launcher2.ui.settings.locale
|
||||
|
||||
import android.icu.util.Calendar
|
||||
import android.icu.util.ULocale
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation3.runtime.NavKey
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.text.Collator
|
||||
|
||||
@Serializable
|
||||
data object CalendarSettingsRoute: NavKey
|
||||
|
||||
@Composable
|
||||
fun CalendarSettingsScreen() {
|
||||
|
||||
val viewModel: CalendarSettingsScreenVM = viewModel()
|
||||
|
||||
val primaryCalendar by viewModel.primaryCalendar.collectAsState(null)
|
||||
val secondaryCalendar by viewModel.secondaryCalendar.collectAsState(null)
|
||||
|
||||
val locale = ULocale.getDefault()
|
||||
|
||||
val calendars = remember(locale) {
|
||||
val collator = Collator.getInstance().apply { strength = Collator.SECONDARY }
|
||||
val cals = Calendar.getKeywordValuesForLocale("calendar", locale, false)
|
||||
|
||||
cals.map {
|
||||
ULocale.getDefault().setKeywordValue("calendar", it).getDisplayKeywordValue("calendar") to it
|
||||
}.sortedWith { el1, el2 ->
|
||||
collator.compare(el1.first, el2.first)
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceScreen(
|
||||
title = stringResource(R.string.preference_calendar_system),
|
||||
) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_calendar_system_primary),
|
||||
items = listOf(
|
||||
stringResource(R.string.preference_value_system_default) to null,
|
||||
) + calendars,
|
||||
value = primaryCalendar,
|
||||
onValueChanged = {
|
||||
viewModel.setPrimaryCalendar(it)
|
||||
}
|
||||
)
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_calendar_system_secondary),
|
||||
items = listOf(
|
||||
stringResource(R.string.preference_value_disabled) to null
|
||||
) + calendars,
|
||||
value = secondaryCalendar,
|
||||
onValueChanged = {
|
||||
viewModel.setSecondaryCalendar(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package de.mm20.launcher2.ui.settings.locale
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.preferences.MeasurementSystem
|
||||
import de.mm20.launcher2.preferences.TimeFormat
|
||||
import de.mm20.launcher2.preferences.ui.LocaleSettings
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
class CalendarSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
private val localeSettings: LocaleSettings by inject()
|
||||
|
||||
val primaryCalendar = localeSettings.primaryCalendar
|
||||
fun setPrimaryCalendar(calendar: String?) {
|
||||
localeSettings.setPrimaryCalendar(calendar)
|
||||
}
|
||||
|
||||
val secondaryCalendar = localeSettings.secondaryCalendar
|
||||
fun setSecondaryCalendar(calendar: String?) {
|
||||
localeSettings.setSecondaryCalendar(calendar)
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,16 @@
|
||||
package de.mm20.launcher2.ui.settings.locale
|
||||
|
||||
import android.content.Intent
|
||||
import android.icu.text.ListFormatter
|
||||
import android.icu.text.Transliterator
|
||||
import android.icu.util.ULocale
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.toLowerCase
|
||||
import androidx.compose.ui.text.toUpperCase
|
||||
import androidx.core.app.GrammaticalInflectionManagerCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@@ -28,8 +25,8 @@ import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.locals.LocalBackStack
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.util.Locale
|
||||
|
||||
@Serializable
|
||||
data object LocaleSettingsRoute : NavKey
|
||||
@@ -40,9 +37,12 @@ fun LocaleSettingsScreen() {
|
||||
val resources = LocalResources.current
|
||||
val viewModel: LocaleSettingsScreenVM = viewModel()
|
||||
|
||||
val backstack = LocalBackStack.current
|
||||
|
||||
val timeFormat by viewModel.timeFormat.collectAsStateWithLifecycle(null)
|
||||
val measurementSystem by viewModel.measurementSystem.collectAsStateWithLifecycle(null)
|
||||
val transliterator by viewModel.transliterator.collectAsStateWithLifecycle(null)
|
||||
val calendars by viewModel.calendars.collectAsStateWithLifecycle(emptyList())
|
||||
|
||||
// The language that has been selected by the user, or null to use the system language
|
||||
val selectedLocale = remember {
|
||||
@@ -57,13 +57,13 @@ fun LocaleSettingsScreen() {
|
||||
val transliterators: List<Pair<String, String?>> = remember(locales) {
|
||||
if (!isAtLeastApiLevel(29)) return@remember listOf()
|
||||
|
||||
if (locales?.isEmpty == true) return@remember listOf(resources.getString(R.string.preference_transliteration_disabled) to null)
|
||||
if (locales?.isEmpty == true) return@remember listOf(resources.getString(R.string.preference_value_disabled) to null)
|
||||
|
||||
val scripts = mutableSetOf<String>()
|
||||
val languages = mutableSetOf<String>()
|
||||
|
||||
val transliterators = mutableMapOf<String?, String>(
|
||||
null to resources.getString(R.string.preference_transliteration_disabled),
|
||||
null to resources.getString(R.string.preference_value_disabled),
|
||||
"" to resources.getString(R.string.preference_transliteration_auto),
|
||||
)
|
||||
|
||||
@@ -82,7 +82,11 @@ fun LocaleSettingsScreen() {
|
||||
val ids = availableIds.filter { it.startsWith(filter) }
|
||||
|
||||
for (id in ids) {
|
||||
transliterators[id] = "${ulocale.displayLanguage.replaceFirstChar { ulocale.displayLanguage.first().uppercase() }} ($id)"
|
||||
transliterators[id] = "${
|
||||
ulocale.displayLanguage.replaceFirstChar {
|
||||
ulocale.displayLanguage.first().uppercase()
|
||||
}
|
||||
} ($id)"
|
||||
}
|
||||
|
||||
languages.add(lng)
|
||||
@@ -94,7 +98,11 @@ fun LocaleSettingsScreen() {
|
||||
val ids = availableIds.filter { it.startsWith(filter) }
|
||||
|
||||
for (id in ids) {
|
||||
transliterators[id] = "${ulocale.displayScript.replaceFirstChar { ulocale.displayScript.first().uppercase() }} ($id)"
|
||||
transliterators[id] = "${
|
||||
ulocale.displayScript.replaceFirstChar {
|
||||
ulocale.displayScript.first().uppercase()
|
||||
}
|
||||
} ($id)"
|
||||
}
|
||||
scripts.add(ulocale.script)
|
||||
}
|
||||
@@ -197,6 +205,35 @@ fun LocaleSettingsScreen() {
|
||||
stringResource(R.string.preference_measurement_system_us) to MeasurementSystem.UnitedStates,
|
||||
)
|
||||
)
|
||||
Preference(
|
||||
title = stringResource(R.string.preference_calendar_system),
|
||||
icon = R.drawable.calendar_today_24px,
|
||||
onClick = {
|
||||
backstack += CalendarSettingsRoute
|
||||
},
|
||||
summary = remember(calendars) {
|
||||
val primary = calendars.getOrNull(0)
|
||||
val secondary = calendars.getOrNull(1)
|
||||
|
||||
val primaryName = if (primary == null) {
|
||||
resources.getString(R.string.preference_value_system_default)
|
||||
} else {
|
||||
ULocale.getDefault().setKeywordValue("calendar", primary)
|
||||
.getDisplayKeywordValue("calendar")
|
||||
}
|
||||
|
||||
val secondaryName = if (secondary == null) {
|
||||
null
|
||||
} else {
|
||||
ULocale.getDefault().setKeywordValue("calendar", secondary)
|
||||
.getDisplayKeywordValue("calendar")
|
||||
}
|
||||
|
||||
ListFormatter.getInstance().format(
|
||||
listOfNotNull(primaryName, secondaryName)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.preferences.MeasurementSystem
|
||||
import de.mm20.launcher2.preferences.TimeFormat
|
||||
import de.mm20.launcher2.preferences.ui.LocaleSettings
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
class LocaleSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
class LocaleSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val localeSettings: LocaleSettings by inject()
|
||||
|
||||
val timeFormat = localeSettings.timeFormat
|
||||
@@ -24,4 +26,8 @@ class LocaleSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
fun setTransliterator(transliterator: String?) {
|
||||
localeSettings.setTransliterator(transliterator)
|
||||
}
|
||||
|
||||
val calendars = combine(localeSettings.primaryCalendar, localeSettings.secondaryCalendar) {
|
||||
it.toImmutableList()
|
||||
}
|
||||
}
|
||||
10
core/base/src/main/res/drawable/calendar_today_24px.xml
Normal file
10
core/base/src/main/res/drawable/calendar_today_24px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M200,880Q167,880 143.5,856.5Q120,833 120,800L120,240Q120,207 143.5,183.5Q167,160 200,160L240,160L240,120Q240,103 251.5,91.5Q263,80 280,80Q297,80 308.5,91.5Q320,103 320,120L320,160L640,160L640,120Q640,103 651.5,91.5Q663,80 680,80Q697,80 708.5,91.5Q720,103 720,120L720,160L760,160Q793,160 816.5,183.5Q840,207 840,240L840,800Q840,833 816.5,856.5Q793,880 760,880L200,880ZM200,800L760,800Q760,800 760,800Q760,800 760,800L760,400L200,400L200,800Q200,800 200,800Q200,800 200,800ZM200,320L760,320L760,240Q760,240 760,240Q760,240 760,240L200,240Q200,240 200,240Q200,240 200,240L200,320ZM200,320L200,240Q200,240 200,240Q200,240 200,240L200,240Q200,240 200,240Q200,240 200,240L200,320Z"/>
|
||||
</vector>
|
||||
@@ -925,7 +925,7 @@
|
||||
<string name="preference_tasks_integration_ready">تم الربط بنجاح. التطبيق جاهز للاستخدام.</string>
|
||||
<string name="preference_transliteration">طريقة كتابة الأحرف</string>
|
||||
<string name="preference_transliteration_auto">تلقائي</string>
|
||||
<string name="preference_transliteration_disabled">معطل</string>
|
||||
<string name="preference_value_disabled">معطل</string>
|
||||
<string name="preference_value_system_default">إعدادات النظام</string>
|
||||
<string name="preference_widgets_on_home_screen">أدوات الشاشة الرئيسية</string>
|
||||
<string name="preference_widgets_on_home_screen_summary">عرض الأدوات في الشاشة الرئيسية بدلاً من صفحة منفصلة</string>
|
||||
|
||||
@@ -889,7 +889,7 @@
|
||||
<string name="preference_measurement_system_us">Spojené státy</string>
|
||||
<string name="preference_transliteration">Preferovaná transkripce</string>
|
||||
<string name="preference_transliteration_auto">Automatická</string>
|
||||
<string name="preference_transliteration_disabled">Zakázaná</string>
|
||||
<string name="preference_value_disabled">Zakázaná</string>
|
||||
<string name="select_tag">Vybrat štítek</string>
|
||||
<string name="widget_name_apps">Aplikace</string>
|
||||
<string name="preference_category_enabled_plugins">Povoleno</string>
|
||||
|
||||
@@ -878,7 +878,7 @@
|
||||
<string name="preference_measurement_system_us">Vereinigte Staaten</string>
|
||||
<string name="preference_transliteration">Bevorzugte Transliteration</string>
|
||||
<string name="preference_transliteration_auto">Automatisch</string>
|
||||
<string name="preference_transliteration_disabled">Deaktiviert</string>
|
||||
<string name="preference_value_disabled">Deaktiviert</string>
|
||||
<string name="preference_category_enabled_plugins">Aktiviert</string>
|
||||
<string name="preference_category_installed_plugins">Installiert</string>
|
||||
<string name="tag_icon_customicon">Icon</string>
|
||||
|
||||
@@ -889,7 +889,7 @@
|
||||
<string name="preference_measurement_system_us">Estados Unidos</string>
|
||||
<string name="preference_transliteration">Transliteración preferida</string>
|
||||
<string name="preference_transliteration_auto">Automática</string>
|
||||
<string name="preference_transliteration_disabled">Deshabilitada</string>
|
||||
<string name="preference_value_disabled">Deshabilitada</string>
|
||||
<string name="preference_category_enabled_plugins">Activado</string>
|
||||
<string name="preference_category_installed_plugins">Instalado</string>
|
||||
<string name="widget_name_apps">Aplicaciones</string>
|
||||
|
||||
@@ -849,6 +849,6 @@
|
||||
<string name="preference_measurement_system_us">Ameriketako Estatu Batuak</string>
|
||||
<string name="preference_transliteration">Hobetsitako transliterazioa</string>
|
||||
<string name="preference_transliteration_auto">Automatikoa</string>
|
||||
<string name="preference_transliteration_disabled">Ezgaitua</string>
|
||||
<string name="preference_value_disabled">Ezgaitua</string>
|
||||
<string name="select_tag">Etiketa hautatu</string>
|
||||
</resources>
|
||||
|
||||
@@ -878,7 +878,7 @@
|
||||
<string name="preference_measurement_system_us">Egyesült Államok</string>
|
||||
<string name="preference_transliteration">Előnyben részesített átírás</string>
|
||||
<string name="preference_transliteration_auto">Automatikus</string>
|
||||
<string name="preference_transliteration_disabled">Letiltva</string>
|
||||
<string name="preference_value_disabled">Letiltva</string>
|
||||
<string name="select_tag">Címke kiválasztása</string>
|
||||
<string name="widget_name_apps">Alkalmazások</string>
|
||||
<string name="preference_category_enabled_plugins">Engedélyezve</string>
|
||||
|
||||
@@ -889,7 +889,7 @@
|
||||
<string name="preference_measurement_system_uk">Regno Unito</string>
|
||||
<string name="preference_transliteration">Traslitterazione preferita</string>
|
||||
<string name="preference_transliteration_auto">Automatica</string>
|
||||
<string name="preference_transliteration_disabled">Disabilitata</string>
|
||||
<string name="preference_value_disabled">Disabilitata</string>
|
||||
<string name="select_tag">Seleziona tag</string>
|
||||
<string name="widget_name_apps">App</string>
|
||||
<string name="preference_category_enabled_plugins">Abilitato</string>
|
||||
|
||||
@@ -885,7 +885,7 @@
|
||||
<string name="preference_measurement_system_metric">מטרית</string>
|
||||
<string name="preference_measurement_system_uk">הממלכה המאוחדת</string>
|
||||
<string name="preference_measurement_system_us">ארצות הברית</string>
|
||||
<string name="preference_transliteration_disabled">מושבת</string>
|
||||
<string name="preference_value_disabled">מושבת</string>
|
||||
<string name="select_tag">בחירת תגית</string>
|
||||
<string name="preference_transliteration">תעתיק מועדף</string>
|
||||
<string name="preference_transliteration_auto">תעתיק אוטומטי</string>
|
||||
|
||||
@@ -876,7 +876,7 @@
|
||||
<string name="preference_measurement_system_metric">Metrisch</string>
|
||||
<string name="preference_measurement_system_uk">Verenigd Koninkrijk</string>
|
||||
<string name="preference_measurement_system_us">Verenigde Staten</string>
|
||||
<string name="preference_transliteration_disabled">Uitgeschakeld</string>
|
||||
<string name="preference_value_disabled">Uitgeschakeld</string>
|
||||
<string name="preference_transliteration">Voorkeurstransliteratie</string>
|
||||
<string name="preference_transliteration_auto">Automatisch</string>
|
||||
<string name="select_tag">Label selecteren</string>
|
||||
|
||||
@@ -878,6 +878,6 @@
|
||||
<string name="preference_measurement_system_us">EUA</string>
|
||||
<string name="preference_transliteration">Transliteração preferencial</string>
|
||||
<string name="preference_transliteration_auto">Automática</string>
|
||||
<string name="preference_transliteration_disabled">Inativa</string>
|
||||
<string name="preference_value_disabled">Inativa</string>
|
||||
<string name="select_tag">Selecione a etiqueta</string>
|
||||
</resources>
|
||||
|
||||
@@ -1082,7 +1082,7 @@
|
||||
<string name="preference_measurement_system_us">Amerika Birleşik Devletleri</string>
|
||||
<string name="preference_transliteration">Tercih edilen tercüme</string>
|
||||
<string name="preference_transliteration_auto">Otomatik</string>
|
||||
<string name="preference_transliteration_disabled">Devre dışı</string>
|
||||
<string name="preference_value_disabled">Devre dışı</string>
|
||||
<string name="select_tag">Etiket seçin</string>
|
||||
<string name="action_quit">Çık</string>
|
||||
<string name="preference_create_colors">Yeni renk şeması</string>
|
||||
|
||||
@@ -872,7 +872,7 @@
|
||||
<string name="preference_measurement_system_us">美制</string>
|
||||
<string name="preference_transliteration">翻译语言偏好</string>
|
||||
<string name="preference_transliteration_auto">自动</string>
|
||||
<string name="preference_transliteration_disabled">禁用</string>
|
||||
<string name="preference_value_disabled">禁用</string>
|
||||
<string name="select_tag">选择标签</string>
|
||||
<string name="action_quit">退出</string>
|
||||
<string name="preference_clockwidget_smartspacer">由 Smartspacer 主管</string>
|
||||
|
||||
@@ -876,7 +876,7 @@
|
||||
<string name="preference_smartspacer_enable">啟用 Smartspacer 整合</string>
|
||||
<string name="preference_launch_smartspacer_app">開啟 Smartspacer</string>
|
||||
<string name="preference_transliteration">字母轉寫偏好</string>
|
||||
<string name="preference_transliteration_disabled">停用</string>
|
||||
<string name="preference_value_disabled">停用</string>
|
||||
<string name="preference_feed_integration">Feed</string>
|
||||
<string name="preference_category_feed_provider">Feed 提供者</string>
|
||||
<string name="preference_feed_enable_summary">在主畫面向右滑動開啟 Feed</string>
|
||||
|
||||
@@ -1085,6 +1085,7 @@
|
||||
<string name="preference_screen_locale_summary">Language, units, time format</string>
|
||||
<string name="preference_language">Language</string>
|
||||
<string name="preference_value_system_default">System default</string>
|
||||
<string name="preference_value_disabled">Disabled</string>
|
||||
<string name="preference_form_of_address">Form of address</string>
|
||||
<string name="preference_form_of_address_neutral">Neutral</string>
|
||||
<string name="preference_form_of_address_fem">Feminine</string>
|
||||
@@ -1095,7 +1096,9 @@
|
||||
<string name="preference_measurement_system_us">United States</string>
|
||||
<string name="preference_transliteration">Preferred transliteration</string>
|
||||
<string name="preference_transliteration_auto">Automatic</string>
|
||||
<string name="preference_transliteration_disabled">Disabled</string>
|
||||
<string name="preference_calendar_system">Calendar system</string>
|
||||
<string name="preference_calendar_system_primary">Primary calendar</string>
|
||||
<string name="preference_calendar_system_secondary">Secondary calendar</string>
|
||||
<string name="select_tag">Select tag</string>
|
||||
<string name="create_tag_title">New tag</string>
|
||||
<string name="edit_tag_title">Edit tag</string>
|
||||
|
||||
@@ -202,6 +202,16 @@ data class LauncherSettingsData internal constructor(
|
||||
*/
|
||||
val localeTransliterator: String? = "",
|
||||
|
||||
/**
|
||||
* The ICU id of the primary calendar. `null` to use the default.
|
||||
*/
|
||||
val localePrimaryCalendar: String? = null,
|
||||
|
||||
/**
|
||||
* The ICU id of the secondary calendar. `null` to disable.
|
||||
*/
|
||||
val localeSecondaryCalendar: String? = null,
|
||||
|
||||
val feedProviderPackage: String? = null
|
||||
|
||||
|
||||
|
||||
@@ -35,4 +35,22 @@ class LocaleSettings internal constructor(
|
||||
it.copy(localeTransliterator = transliterator)
|
||||
}
|
||||
}
|
||||
|
||||
val primaryCalendar
|
||||
get() = launcherDataStore.data.map { it.localePrimaryCalendar }
|
||||
|
||||
fun setPrimaryCalendar(primaryCalendar: String?) {
|
||||
launcherDataStore.update {
|
||||
it.copy(localePrimaryCalendar = primaryCalendar)
|
||||
}
|
||||
}
|
||||
|
||||
val secondaryCalendar
|
||||
get() = launcherDataStore.data.map { it.localeSecondaryCalendar }
|
||||
|
||||
fun setSecondaryCalendar(secondaryCalendar: String?) {
|
||||
launcherDataStore.update {
|
||||
it.copy(localeSecondaryCalendar = secondaryCalendar)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user