mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 00:35:26 +02:00
Added Time zone converter
Hidden as "tools experiment" Missing: - Clean data - Translations - UI/UX clean up - Relative time change functionality - Custom user time zone functionality closes #59 this is a squashed commit
This commit is contained in:
parent
bba2f24c7c
commit
caf025778e
@ -72,11 +72,19 @@ internal fun UnittoApp(uiPrefs: UIPreferences) {
|
||||
// Navigation drawer stuff
|
||||
val drawerState = rememberUnittoDrawerState()
|
||||
val drawerScope = rememberCoroutineScope()
|
||||
val mainTabs = listOf(
|
||||
DrawerItems.Calculator,
|
||||
DrawerItems.Converter,
|
||||
DrawerItems.DateDifference
|
||||
)
|
||||
val mainTabs by remember(uiPrefs.enableToolsExperiment) {
|
||||
derivedStateOf {
|
||||
if (uiPrefs.enableToolsExperiment) {
|
||||
listOf(
|
||||
DrawerItems.Calculator, DrawerItems.Converter, DrawerItems.DateDifference, DrawerItems.TimeZones
|
||||
)
|
||||
} else {
|
||||
listOf(
|
||||
DrawerItems.Calculator, DrawerItems.Converter, DrawerItems.DateDifference,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
val additionalTabs = listOf(DrawerItems.Settings)
|
||||
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
@ -129,7 +137,7 @@ internal fun UnittoApp(uiPrefs: UIPreferences) {
|
||||
UnittoNavigation(
|
||||
navController = navController,
|
||||
themmoController = it,
|
||||
startDestination = uiPrefs.startingScreen,
|
||||
startDestination = TopLevelDestinations.TimeZone.route,
|
||||
openDrawer = { drawerScope.launch { drawerState.open() } }
|
||||
)
|
||||
}
|
||||
|
@ -95,7 +95,8 @@ internal fun UnittoNavigation(
|
||||
|
||||
timeZoneScreen(
|
||||
navigateToMenu = openDrawer,
|
||||
navigateToSettings = navController::navigateToSettings
|
||||
navigateToSettings = navController::navigateToSettings,
|
||||
navController = navController,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ sealed class TopLevelDestinations(
|
||||
)
|
||||
|
||||
object TimeZone : TopLevelDestinations(
|
||||
route = "time_zone_route",
|
||||
name = R.string.time_zone
|
||||
route = "time_zone_graph",
|
||||
name = R.string.time_zone_screen
|
||||
)
|
||||
|
||||
object Settings : TopLevelDestinations(
|
||||
@ -54,5 +54,6 @@ val TOP_LEVEL_DESTINATIONS: Map<TopLevelDestinations, Int> by lazy {
|
||||
mapOf(
|
||||
TopLevelDestinations.Converter to R.string.unit_converter,
|
||||
TopLevelDestinations.Calculator to R.string.calculator,
|
||||
TopLevelDestinations.DateDifference to R.string.date_difference,
|
||||
)
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -37,6 +37,7 @@ android {
|
||||
|
||||
dependencies {
|
||||
testImplementation(libs.junit)
|
||||
testImplementation(libs.org.robolectric)
|
||||
testImplementation(libs.androidx.compose.ui.test.junit4)
|
||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.sadellie.unitto.core.ui.common
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.text.format.DateFormat
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@ -44,6 +45,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.layout.Placeable
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
@ -59,23 +61,25 @@ import kotlin.math.max
|
||||
@Composable
|
||||
fun TimePickerDialog(
|
||||
modifier: Modifier = Modifier,
|
||||
localDateTime: LocalDateTime,
|
||||
hour: Int,
|
||||
minute: Int,
|
||||
confirmLabel: String = stringResource(R.string.ok_label),
|
||||
dismissLabel: String = stringResource(R.string.cancel_label),
|
||||
onDismiss: () -> Unit = {},
|
||||
onConfirm: (LocalDateTime) -> Unit,
|
||||
vertical: Boolean
|
||||
onConfirm: (hour: Int, minute: Int) -> Unit,
|
||||
) {
|
||||
val isVertical = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
|
||||
val pickerState = rememberTimePickerState(
|
||||
localDateTime.hour,
|
||||
localDateTime.minute,
|
||||
DateFormat.is24HourFormat(LocalContext.current)
|
||||
initialHour = hour,
|
||||
initialMinute = minute,
|
||||
is24Hour = DateFormat.is24HourFormat(LocalContext.current)
|
||||
)
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
modifier = modifier.wrapContentHeight(),
|
||||
properties = DialogProperties(usePlatformDefaultWidth = vertical)
|
||||
properties = DialogProperties(usePlatformDefaultWidth = isVertical)
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
@ -97,7 +101,7 @@ fun TimePickerDialog(
|
||||
TimePicker(
|
||||
state = pickerState,
|
||||
modifier = Modifier.padding(top = 20.dp),
|
||||
layoutType = if (vertical) TimePickerLayoutType.Vertical else TimePickerLayoutType.Horizontal
|
||||
layoutType = if (isVertical) TimePickerLayoutType.Vertical else TimePickerLayoutType.Horizontal
|
||||
)
|
||||
|
||||
Row(
|
||||
@ -110,13 +114,7 @@ fun TimePickerDialog(
|
||||
Text(text = dismissLabel)
|
||||
}
|
||||
TextButton(
|
||||
onClick = {
|
||||
onConfirm(
|
||||
localDateTime
|
||||
.withHour(pickerState.hour)
|
||||
.withMinute(pickerState.minute)
|
||||
)
|
||||
}
|
||||
onClick = { onConfirm(pickerState.hour, pickerState.minute) }
|
||||
) {
|
||||
Text(text = confirmLabel)
|
||||
}
|
||||
|
@ -21,9 +21,11 @@ package com.sadellie.unitto.core.ui.common
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
||||
import androidx.compose.material3.FabPosition
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.TopAppBarColors
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@ -35,6 +37,8 @@ import androidx.compose.ui.Modifier
|
||||
* @param navigationIcon See [CenterAlignedTopAppBar]
|
||||
* @param actions See [CenterAlignedTopAppBar]
|
||||
* @param colors See [CenterAlignedTopAppBar]
|
||||
* @param floatingActionButton See [Scaffold]
|
||||
* @param scrollBehavior See [CenterAlignedTopAppBar]
|
||||
* @param content See [Scaffold]
|
||||
*/
|
||||
@Composable
|
||||
@ -44,6 +48,9 @@ fun UnittoScreenWithTopBar(
|
||||
navigationIcon: @Composable () -> Unit,
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(),
|
||||
floatingActionButton: @Composable () -> Unit = {},
|
||||
floatingActionButtonPosition: FabPosition = FabPosition.End,
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||
content: @Composable (PaddingValues) -> Unit
|
||||
) {
|
||||
Scaffold(
|
||||
@ -53,9 +60,12 @@ fun UnittoScreenWithTopBar(
|
||||
title = title,
|
||||
navigationIcon = navigationIcon,
|
||||
actions = actions,
|
||||
colors = colors
|
||||
colors = colors,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
floatingActionButton = floatingActionButton,
|
||||
floatingActionButtonPosition = floatingActionButtonPosition,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.core.ui.datetime
|
||||
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
// FIXME Duplicate from date difference
|
||||
internal val time24Formatter by lazy { DateTimeFormatter.ofPattern("HH:mm") }
|
||||
internal val time12Formatter by lazy { DateTimeFormatter.ofPattern("hh:mm a") }
|
||||
internal val dayMonthYear by lazy { DateTimeFormatter.ofPattern("d MMM y") }
|
||||
internal val zoneFormatPattern by lazy { DateTimeFormatter.ofPattern("O") }
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.core.ui.datetime
|
||||
|
||||
import android.text.format.DateFormat
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Composable
|
||||
fun LocalDateTime.formatLocal(): String {
|
||||
return if (DateFormat.is24HourFormat(LocalContext.current)) format24()
|
||||
else format12()
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats [LocalDateTime] into string that looks like
|
||||
*
|
||||
* 23:58
|
||||
*
|
||||
* @return Formatted string.
|
||||
*/
|
||||
fun LocalDateTime.format24(): String = this.format(time24Formatter)
|
||||
|
||||
/**
|
||||
* Formats [LocalDateTime] into string that looks like
|
||||
*
|
||||
* 11:58 am
|
||||
*
|
||||
* @return Formatted string.
|
||||
*/
|
||||
fun LocalDateTime.format12(): String = this.format(time12Formatter)
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.core.ui.datetime
|
||||
|
||||
import android.text.format.DateFormat
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.temporal.ChronoUnit
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@Composable
|
||||
fun ZonedDateTime.formatLocal(): String {
|
||||
return if (DateFormat.is24HourFormat(LocalContext.current)) format24()
|
||||
else format12()
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats [ZonedDateTime] into string that looks like
|
||||
*
|
||||
* 23:58
|
||||
*
|
||||
* @return Formatted string.
|
||||
*/
|
||||
fun ZonedDateTime.format24(): String = this.format(time24Formatter)
|
||||
|
||||
/**
|
||||
* Formats [ZonedDateTime] into string that looks like
|
||||
*
|
||||
* 11:58 am
|
||||
*
|
||||
* @return Formatted string.
|
||||
*/
|
||||
fun ZonedDateTime.format12(): String = this.format(time12Formatter)
|
||||
|
||||
/**
|
||||
* Formats [ZonedDateTime] into string that looks like
|
||||
*
|
||||
* 21 Jul 2023
|
||||
*
|
||||
* @return Formatted string.
|
||||
*/
|
||||
fun ZonedDateTime.formatDayMonthYear(): String = this.format(dayMonthYear)
|
||||
|
||||
fun ZonedDateTime.formatTimeZoneOffset(): String = this.format(zoneFormatPattern)
|
||||
|
||||
/**
|
||||
* Format offset string. Examples:
|
||||
*
|
||||
* 0
|
||||
*
|
||||
* +8
|
||||
*
|
||||
* +8, tomorrow
|
||||
*
|
||||
* -8, yesterday
|
||||
*
|
||||
* @receiver [ZonedDateTime] Time with offset.
|
||||
* @param currentTime Time without offset.
|
||||
* @return Formatted string.
|
||||
*/
|
||||
@Composable
|
||||
fun ZonedDateTime.formatOffset(
|
||||
currentTime: ZonedDateTime
|
||||
): String? {
|
||||
|
||||
val offsetFixed = ChronoUnit.SECONDS.between(currentTime, this)
|
||||
|
||||
if (offsetFixed == 0L) return null
|
||||
|
||||
var resultBuffer = ""
|
||||
val absoluteOffset = offsetFixed.absoluteValue
|
||||
|
||||
// Add a positive/negative prefix symbol
|
||||
when {
|
||||
offsetFixed > 0 -> resultBuffer += "+"
|
||||
offsetFixed < 0 -> resultBuffer += "-"
|
||||
}
|
||||
|
||||
// Formatted hours and minutes
|
||||
val hour = absoluteOffset / 3600
|
||||
val minute = absoluteOffset % 3600 / 60
|
||||
|
||||
if (hour != 0L) {
|
||||
resultBuffer += "${hour}${stringResource(R.string.hour_short)}"
|
||||
}
|
||||
|
||||
// TODO Very ugly
|
||||
if (minute != 0L) {
|
||||
if (hour != 0L) resultBuffer += " "
|
||||
resultBuffer += "${minute}${stringResource(R.string.minute_short)}"
|
||||
}
|
||||
|
||||
// Day after time string
|
||||
val diff = this.dayOfYear - currentTime.dayOfYear
|
||||
when {
|
||||
diff > 0 -> resultBuffer += ", ${stringResource(R.string.tomorrow).lowercase()}"
|
||||
diff < 0 -> resultBuffer += ", ${stringResource(R.string.yesterday).lowercase()}"
|
||||
}
|
||||
|
||||
return resultBuffer
|
||||
}
|
@ -21,10 +21,12 @@ package com.sadellie.unitto.core.ui.model
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Calculate
|
||||
import androidx.compose.material.icons.filled.Event
|
||||
import androidx.compose.material.icons.filled.Schedule
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.SwapHoriz
|
||||
import androidx.compose.material.icons.outlined.Calculate
|
||||
import androidx.compose.material.icons.outlined.Event
|
||||
import androidx.compose.material.icons.outlined.Schedule
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material.icons.outlined.SwapHoriz
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
@ -53,6 +55,12 @@ sealed class DrawerItems(
|
||||
defaultIcon = Icons.Outlined.Event
|
||||
)
|
||||
|
||||
object TimeZones : DrawerItems(
|
||||
destination = TopLevelDestinations.TimeZone,
|
||||
selectedIcon = Icons.Filled.Schedule,
|
||||
defaultIcon = Icons.Outlined.Schedule
|
||||
)
|
||||
|
||||
object Settings : DrawerItems(
|
||||
destination = TopLevelDestinations.Settings,
|
||||
selectedIcon = Icons.Filled.Settings,
|
||||
|
@ -27,14 +27,14 @@ import androidx.compose.ui.unit.em
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.sadellie.unitto.core.base.R
|
||||
|
||||
private val Montserrat = FontFamily(
|
||||
val Montserrat = FontFamily(
|
||||
Font(R.font.montserrat_light, weight = FontWeight.Light),
|
||||
Font(R.font.montserrat_regular, weight = FontWeight.Normal),
|
||||
Font(R.font.montserrat_medium, weight = FontWeight.Medium),
|
||||
Font(R.font.montserrat_semibold, weight = FontWeight.SemiBold),
|
||||
)
|
||||
|
||||
private val Lato = FontFamily(
|
||||
val Lato = FontFamily(
|
||||
Font(R.font.lato_regular)
|
||||
)
|
||||
|
||||
|
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.core.ui
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import com.sadellie.unitto.core.ui.datetime.formatOffset
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class ZonedDateTimeUtilsTest {
|
||||
|
||||
@get: Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun `no difference`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val formatted = currentTime.formatOffset(currentTime)
|
||||
|
||||
assertEquals(null, formatted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show positive hour`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val offset = currentTime
|
||||
.plusSeconds(7200) // + 2h = 14:00
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("+2h", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show positive hour minute`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val offset = currentTime
|
||||
.plusSeconds(9000) // + 2h 30m = 14:30
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("+2h 30m", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show positive hour minute day`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val offset = currentTime
|
||||
.plusSeconds(50400) // + 14h = 02:00 tomorrow
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("+14h, tomorrow", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show positive minute`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val offset = currentTime
|
||||
.plusSeconds(1800) // + 30m = 12:30
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("+30m", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show positive minute day`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(23)
|
||||
.withMinute(45)
|
||||
|
||||
val offset = currentTime
|
||||
.plusSeconds(1800) // + 30m = 00:15 tomorrow
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("+30m, tomorrow", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show negative hour`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val offset = currentTime
|
||||
.minusSeconds(7200) // - 2h = 10:00
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("-2h", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show negative hour minute`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val offset = currentTime
|
||||
.minusSeconds(9000) // - 2h 30m = 09:30 tomorrow
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("-2h 30m", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show negative hour minute day`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val offset = currentTime
|
||||
.minusSeconds(50400) // - 14h = 22:00 yesterday
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("-14h, yesterday", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show negative minute`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(12)
|
||||
.withMinute(0)
|
||||
|
||||
val offset = currentTime
|
||||
.minusSeconds(1800) // - 30m = 11:30
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("-30m", offset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show negative minute day`() = composeTestRule.setContent {
|
||||
val currentTime = ZonedDateTime.now()
|
||||
.withHour(0)
|
||||
.withMinute(15)
|
||||
|
||||
val offset = currentTime
|
||||
.minusSeconds(1800) // - 30m = 23:45 yesterday
|
||||
.formatOffset(currentTime)
|
||||
|
||||
assertEquals("-30m, yesterday", offset)
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "d5dca9e0346c3400b7ff5b31e85c7827",
|
||||
"identityHash": "ab71572ff5556256d1f042af36243f6f",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "units",
|
||||
@ -34,10 +34,10 @@
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"unitId"
|
||||
],
|
||||
"autoGenerate": false
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
@ -72,10 +72,42 @@
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"entityId"
|
||||
],
|
||||
"autoGenerate": true
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "time_zones",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `position` INTEGER NOT NULL, `label` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "position",
|
||||
"columnName": "position",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "label",
|
||||
"columnName": "label",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
@ -84,7 +116,7 @@
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd5dca9e0346c3400b7ff5b31e85c7827')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ab71572ff5556256d1f042af36243f6f')"
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 3,
|
||||
"identityHash": "ab71572ff5556256d1f042af36243f6f",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "units",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`unitId` TEXT NOT NULL, `is_favorite` INTEGER, `paired_unit_id` TEXT, `frequency` INTEGER, PRIMARY KEY(`unitId`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "unitId",
|
||||
"columnName": "unitId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isFavorite",
|
||||
"columnName": "is_favorite",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "pairedUnitId",
|
||||
"columnName": "paired_unit_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "frequency",
|
||||
"columnName": "frequency",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"unitId"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "calculator_history",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`entityId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `expression` TEXT NOT NULL, `result` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "entityId",
|
||||
"columnName": "entityId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "timestamp",
|
||||
"columnName": "timestamp",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "expression",
|
||||
"columnName": "expression",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "result",
|
||||
"columnName": "result",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"entityId"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "time_zones",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `position` INTEGER NOT NULL, `label` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "position",
|
||||
"columnName": "position",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "label",
|
||||
"columnName": "label",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ab71572ff5556256d1f042af36243f6f')"
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.data.database
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface TimeZoneDao {
|
||||
@Query("SELECT * FROM time_zones ORDER BY position ASC")
|
||||
fun getAll(): Flow<List<TimeZoneEntity>>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(vararg timeZoneEntity: TimeZoneEntity)
|
||||
|
||||
@Query("UPDATE time_zones SET position = ( SELECT SUM(position) FROM time_zones WHERE id IN (:fromId, :toId) ) - position WHERE id IN (:fromId, :toId)")
|
||||
suspend fun swap(fromId: String, toId: String)
|
||||
|
||||
@Delete
|
||||
suspend fun remove(timeZoneEntity: TimeZoneEntity)
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.data.database
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "time_zones")
|
||||
class TimeZoneEntity(
|
||||
@PrimaryKey val id: String,
|
||||
@ColumnInfo(name = "position") val position: Int,
|
||||
@ColumnInfo(name = "label") val label: String = "",
|
||||
)
|
@ -23,17 +23,20 @@ import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
|
||||
@Database(
|
||||
version = 2,
|
||||
version = 3,
|
||||
exportSchema = true,
|
||||
entities = [
|
||||
UnitsEntity::class,
|
||||
CalculatorHistoryEntity::class
|
||||
CalculatorHistoryEntity::class,
|
||||
TimeZoneEntity::class
|
||||
],
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2)
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3),
|
||||
]
|
||||
)
|
||||
abstract class UnittoDatabase : RoomDatabase() {
|
||||
abstract fun unitsDao(): UnitsDao
|
||||
abstract fun calculatorHistoryDao(): CalculatorHistoryDao
|
||||
abstract fun timeZoneDao(): TimeZoneDao
|
||||
}
|
||||
|
@ -56,6 +56,17 @@ class UnittoDatabaseModule {
|
||||
return unittoDatabase.calculatorHistoryDao()
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells Hilt to use this method to get [TimeZoneDao]
|
||||
*
|
||||
* @param unittoDatabase Database for which we need DAO
|
||||
* @return Singleton of [TimeZoneDao]
|
||||
*/
|
||||
@Provides
|
||||
fun provideTimeZoneDao(unittoDatabase: UnittoDatabase): TimeZoneDao {
|
||||
return unittoDatabase.timeZoneDao()
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells Hilt to use this method to get [UnittoDatabase]
|
||||
*
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.data.model
|
||||
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
data class UnittoTimeZone(
|
||||
val id: String,
|
||||
// For beta only, will change to StringRes later
|
||||
val nameRes: String,
|
||||
val position: Int = 0,
|
||||
val offsetSeconds: Long = 0,
|
||||
val code: String = "CODE",
|
||||
) {
|
||||
fun offsetFrom(currentTime: ZonedDateTime): ZonedDateTime {
|
||||
val offsetSeconds = currentTime.offset.totalSeconds.toLong()
|
||||
val currentTimeWithoutOffset = currentTime.minusSeconds(offsetSeconds)
|
||||
|
||||
return currentTimeWithoutOffset.plusSeconds(this.offsetSeconds)
|
||||
}
|
||||
}
|
1
data/timezone/.gitignore
vendored
Normal file
1
data/timezone/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
33
data/timezone/build.gradle.kts
Normal file
33
data/timezone/build.gradle.kts
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("unitto.library")
|
||||
id("unitto.android.hilt")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.sadellie.unitto.data.timezone"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(mapOf("path" to ":core:base")))
|
||||
implementation(project(mapOf("path" to ":data:common")))
|
||||
implementation(project(mapOf("path" to ":data:model")))
|
||||
implementation(project(mapOf("path" to ":data:database")))
|
||||
}
|
0
data/timezone/consumer-rules.pro
Normal file
0
data/timezone/consumer-rules.pro
Normal file
22
data/timezone/src/main/AndroidManifest.xml
Normal file
22
data/timezone/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Unitto is a unit converter for Android
|
||||
~ Copyright (c) 2023 Elshan Agaev
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<manifest>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,490 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.data.timezone
|
||||
|
||||
import com.sadellie.unitto.data.common.lev
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class TimeZonesRepository @Inject constructor() {
|
||||
private val allTimeZones: HashMap<String, UnittoTimeZone> = hashMapOf(
|
||||
"alfa_time_zone" to UnittoTimeZone(id = "alfa_time_zone", nameRes = "Alfa Time Zone", offsetSeconds = 3600),
|
||||
"australian_central_daylight_time" to UnittoTimeZone(id = "australian_central_daylight_time", nameRes = "Australian Central Daylight Time", offsetSeconds = 37800),
|
||||
"australian_central_standard_time" to UnittoTimeZone(id = "australian_central_standard_time", nameRes = "Australian Central Standard Time", offsetSeconds = 34200),
|
||||
"acre_time" to UnittoTimeZone(id = "acre_time", nameRes = "Acre Time", offsetSeconds = -18000),
|
||||
"australian_central_western_standard_time" to UnittoTimeZone(id = "australian_central_western_standard_time", nameRes = "Australian Central Western Standard Time", offsetSeconds = 31500),
|
||||
"arabia_daylight_time" to UnittoTimeZone(id = "arabia_daylight_time", nameRes = "Arabia Daylight Time", offsetSeconds = 14400),
|
||||
"atlantic_daylight_time" to UnittoTimeZone(id = "atlantic_daylight_time", nameRes = "Atlantic Daylight Time", offsetSeconds = -10800),
|
||||
"heure_avanc_e_de_latlantique_french" to UnittoTimeZone(id = "heure_avanc_e_de_latlantique_french", nameRes = "Heure Avanc-e de l'Atlantique (French)", offsetSeconds = -10800),
|
||||
"australian_eastern_daylight_time" to UnittoTimeZone(id = "australian_eastern_daylight_time", nameRes = "Australian Eastern Daylight Time", offsetSeconds = 39600),
|
||||
"eastern_daylight_time" to UnittoTimeZone(id = "eastern_daylight_time", nameRes = "Eastern Daylight Time", offsetSeconds = 39600),
|
||||
"eastern_daylight_saving_time" to UnittoTimeZone(id = "eastern_daylight_saving_time", nameRes = "Eastern Daylight Saving Time", offsetSeconds = 39600),
|
||||
"australian_eastern_standard_time" to UnittoTimeZone(id = "australian_eastern_standard_time", nameRes = "Australian Eastern Standard Time", offsetSeconds = 36000),
|
||||
"eastern_standard_time" to UnittoTimeZone(id = "eastern_standard_time", nameRes = "Eastern Standard Time", offsetSeconds = 36000),
|
||||
"australian_eastern_time" to UnittoTimeZone(id = "australian_eastern_time", nameRes = "Australian Eastern Time", offsetSeconds = 36000),
|
||||
"afghanistan_time" to UnittoTimeZone(id = "afghanistan_time", nameRes = "Afghanistan Time", offsetSeconds = 16200),
|
||||
"alaska_daylight_time" to UnittoTimeZone(id = "alaska_daylight_time", nameRes = "Alaska Daylight Time", offsetSeconds = -28800),
|
||||
"alaska_standard_time" to UnittoTimeZone(id = "alaska_standard_time", nameRes = "Alaska Standard Time", offsetSeconds = -32400),
|
||||
"alma_ata_time" to UnittoTimeZone(id = "alma_ata_time", nameRes = "Alma-Ata Time", offsetSeconds = 21600),
|
||||
"amazon_summer_time" to UnittoTimeZone(id = "amazon_summer_time", nameRes = "Amazon Summer Time", offsetSeconds = -10800),
|
||||
"armenia_daylight_time" to UnittoTimeZone(id = "armenia_daylight_time", nameRes = "Armenia Daylight Time", offsetSeconds = 18000),
|
||||
"amazon_time" to UnittoTimeZone(id = "amazon_time", nameRes = "Amazon Time", offsetSeconds = -14400),
|
||||
"armenia_time" to UnittoTimeZone(id = "armenia_time", nameRes = "Armenia Time", offsetSeconds = 14400),
|
||||
"anadyr_summer_time" to UnittoTimeZone(id = "anadyr_summer_time", nameRes = "Anadyr Summer Time", offsetSeconds = 43200),
|
||||
"anadyr_time" to UnittoTimeZone(id = "anadyr_time", nameRes = "Anadyr Time", offsetSeconds = 43200),
|
||||
"aqtobe_time" to UnittoTimeZone(id = "aqtobe_time", nameRes = "Aqtobe Time", offsetSeconds = 18000),
|
||||
"argentina_time" to UnittoTimeZone(id = "argentina_time", nameRes = "Argentina Time", offsetSeconds = -10800),
|
||||
"arabic_standard_time" to UnittoTimeZone(id = "arabic_standard_time", nameRes = "Arabic Standard Time", offsetSeconds = 10800),
|
||||
"atlantic_standard_time" to UnittoTimeZone(id = "atlantic_standard_time", nameRes = "Atlantic Standard Time", offsetSeconds = -14400),
|
||||
"tiempo_est_ndar_del_atl_ntico_spanish" to UnittoTimeZone(id = "tiempo_est_ndar_del_atl_ntico_spanish", nameRes = "Tiempo Est-ndar del Atl-ntico (Spanish)", offsetSeconds = -14400),
|
||||
"heure_normale_de_latlantique_french" to UnittoTimeZone(id = "heure_normale_de_latlantique_french", nameRes = "Heure Normale de l'Atlantique (French)", offsetSeconds = -14400),
|
||||
"australian_western_daylight_time" to UnittoTimeZone(id = "australian_western_daylight_time", nameRes = "Australian Western Daylight Time", offsetSeconds = 32400),
|
||||
"western_daylight_time" to UnittoTimeZone(id = "western_daylight_time", nameRes = "Western Daylight Time", offsetSeconds = 32400),
|
||||
"western_summer_time" to UnittoTimeZone(id = "western_summer_time", nameRes = "Western Summer Time", offsetSeconds = 32400),
|
||||
"australian_western_standard_time" to UnittoTimeZone(id = "australian_western_standard_time", nameRes = "Australian Western Standard Time", offsetSeconds = 28800),
|
||||
"western_standard_time" to UnittoTimeZone(id = "western_standard_time", nameRes = "Western Standard Time", offsetSeconds = 28800),
|
||||
"western_australia_time" to UnittoTimeZone(id = "western_australia_time", nameRes = "Western Australia Time", offsetSeconds = 28800),
|
||||
"azores_summer_time" to UnittoTimeZone(id = "azores_summer_time", nameRes = "Azores Summer Time", offsetSeconds = 0),
|
||||
"azores_daylight_time" to UnittoTimeZone(id = "azores_daylight_time", nameRes = "Azores Daylight Time", offsetSeconds = 0),
|
||||
"azores_time" to UnittoTimeZone(id = "azores_time", nameRes = "Azores Time", offsetSeconds = -3600),
|
||||
"azores_standard_time" to UnittoTimeZone(id = "azores_standard_time", nameRes = "Azores Standard Time", offsetSeconds = -3600),
|
||||
"azerbaijan_summer_time" to UnittoTimeZone(id = "azerbaijan_summer_time", nameRes = "Azerbaijan Summer Time", offsetSeconds = 18000),
|
||||
"azerbaijan_time" to UnittoTimeZone(id = "azerbaijan_time", nameRes = "Azerbaijan Time", offsetSeconds = 14400),
|
||||
"anywhere_on_earth" to UnittoTimeZone(id = "anywhere_on_earth", nameRes = "Anywhere on Earth", offsetSeconds = -43200),
|
||||
"bravo_time_zone" to UnittoTimeZone(id = "bravo_time_zone", nameRes = "Bravo Time Zone", offsetSeconds = 7200),
|
||||
"brunei_darussalam_time" to UnittoTimeZone(id = "brunei_darussalam_time", nameRes = "Brunei Darussalam Time", offsetSeconds = 28800),
|
||||
"brunei_time" to UnittoTimeZone(id = "brunei_time", nameRes = "Brunei Time", offsetSeconds = 28800),
|
||||
"bolivia_time" to UnittoTimeZone(id = "bolivia_time", nameRes = "Bolivia Time", offsetSeconds = -14400),
|
||||
"brasilia_summer_time" to UnittoTimeZone(id = "brasilia_summer_time", nameRes = "Brasilia Summer Time", offsetSeconds = -7200),
|
||||
"brazil_summer_time" to UnittoTimeZone(id = "brazil_summer_time", nameRes = "Brazil Summer Time", offsetSeconds = -7200),
|
||||
"brazilian_summer_time" to UnittoTimeZone(id = "brazilian_summer_time", nameRes = "Brazilian Summer Time", offsetSeconds = -7200),
|
||||
"bras_lia_time" to UnittoTimeZone(id = "bras_lia_time", nameRes = "Bras-lia Time", offsetSeconds = -10800),
|
||||
"brazil_time" to UnittoTimeZone(id = "brazil_time", nameRes = "Brazil Time", offsetSeconds = -10800),
|
||||
"brazilian_time" to UnittoTimeZone(id = "brazilian_time", nameRes = "Brazilian Time", offsetSeconds = -10800),
|
||||
"bangladesh_standard_time" to UnittoTimeZone(id = "bangladesh_standard_time", nameRes = "Bangladesh Standard Time", offsetSeconds = 21600),
|
||||
"bougainville_standard_time" to UnittoTimeZone(id = "bougainville_standard_time", nameRes = "Bougainville Standard Time", offsetSeconds = 39600),
|
||||
"british_summer_time" to UnittoTimeZone(id = "british_summer_time", nameRes = "British Summer Time", offsetSeconds = 3600),
|
||||
"british_daylight_time" to UnittoTimeZone(id = "british_daylight_time", nameRes = "British Daylight Time", offsetSeconds = 3600),
|
||||
"british_daylight_saving_time" to UnittoTimeZone(id = "british_daylight_saving_time", nameRes = "British Daylight Saving Time", offsetSeconds = 3600),
|
||||
"bhutan_time" to UnittoTimeZone(id = "bhutan_time", nameRes = "Bhutan Time", offsetSeconds = 21600),
|
||||
"charlie_time_zone" to UnittoTimeZone(id = "charlie_time_zone", nameRes = "Charlie Time Zone", offsetSeconds = 10800),
|
||||
"casey_time" to UnittoTimeZone(id = "casey_time", nameRes = "Casey Time", offsetSeconds = 28800),
|
||||
"central_africa_time" to UnittoTimeZone(id = "central_africa_time", nameRes = "Central Africa Time", offsetSeconds = 7200),
|
||||
"cocos_islands_time" to UnittoTimeZone(id = "cocos_islands_time", nameRes = "Cocos Islands Time", offsetSeconds = 23400),
|
||||
"central_daylight_time" to UnittoTimeZone(id = "central_daylight_time", nameRes = "Central Daylight Time", offsetSeconds = -18000),
|
||||
"central_daylight_saving_time" to UnittoTimeZone(id = "central_daylight_saving_time", nameRes = "Central Daylight Saving Time", offsetSeconds = -18000),
|
||||
"north_american_central_daylight_time" to UnittoTimeZone(id = "north_american_central_daylight_time", nameRes = "North American Central Daylight Time", offsetSeconds = -18000),
|
||||
"heure_avanc_e_du_centre_french" to UnittoTimeZone(id = "heure_avanc_e_du_centre_french", nameRes = "Heure Avanc-e du Centre (French)", offsetSeconds = -18000),
|
||||
"cuba_daylight_time" to UnittoTimeZone(id = "cuba_daylight_time", nameRes = "Cuba Daylight Time", offsetSeconds = -14400),
|
||||
"central_european_summer_time" to UnittoTimeZone(id = "central_european_summer_time", nameRes = "Central European Summer Time", offsetSeconds = 7200),
|
||||
"central_european_daylight_time" to UnittoTimeZone(id = "central_european_daylight_time", nameRes = "Central European Daylight Time", offsetSeconds = 7200),
|
||||
"european_central_summer_time" to UnittoTimeZone(id = "european_central_summer_time", nameRes = "European Central Summer Time", offsetSeconds = 7200),
|
||||
"mitteleurop_ische_sommerzeit_german" to UnittoTimeZone(id = "mitteleurop_ische_sommerzeit_german", nameRes = "Mitteleurop-ische Sommerzeit (German)", offsetSeconds = 7200),
|
||||
"central_european_time" to UnittoTimeZone(id = "central_european_time", nameRes = "Central European Time", offsetSeconds = 3600),
|
||||
"european_central_time" to UnittoTimeZone(id = "european_central_time", nameRes = "European Central Time", offsetSeconds = 3600),
|
||||
"central_europe_time" to UnittoTimeZone(id = "central_europe_time", nameRes = "Central Europe Time", offsetSeconds = 3600),
|
||||
"mitteleurop_ische_zeit_german" to UnittoTimeZone(id = "mitteleurop_ische_zeit_german", nameRes = "Mitteleurop-ische Zeit (German)", offsetSeconds = 3600),
|
||||
"chatham_island_daylight_time" to UnittoTimeZone(id = "chatham_island_daylight_time", nameRes = "Chatham Island Daylight Time", offsetSeconds = 49500),
|
||||
"chatham_daylight_time" to UnittoTimeZone(id = "chatham_daylight_time", nameRes = "Chatham Daylight Time", offsetSeconds = 49500),
|
||||
"chatham_island_standard_time" to UnittoTimeZone(id = "chatham_island_standard_time", nameRes = "Chatham Island Standard Time", offsetSeconds = 45900),
|
||||
"choibalsan_summer_time" to UnittoTimeZone(id = "choibalsan_summer_time", nameRes = "Choibalsan Summer Time", offsetSeconds = 32400),
|
||||
"choibalsan_daylight_time" to UnittoTimeZone(id = "choibalsan_daylight_time", nameRes = "Choibalsan Daylight Time", offsetSeconds = 32400),
|
||||
"choibalsan_daylight_saving_time" to UnittoTimeZone(id = "choibalsan_daylight_saving_time", nameRes = "Choibalsan Daylight Saving Time", offsetSeconds = 32400),
|
||||
"choibalsan_time" to UnittoTimeZone(id = "choibalsan_time", nameRes = "Choibalsan Time", offsetSeconds = 28800),
|
||||
"chuuk_time" to UnittoTimeZone(id = "chuuk_time", nameRes = "Chuuk Time", offsetSeconds = 36000),
|
||||
"cayman_islands_daylight_saving_time" to UnittoTimeZone(id = "cayman_islands_daylight_saving_time", nameRes = "Cayman Islands Daylight Saving Time", offsetSeconds = -14400),
|
||||
"cayman_islands_standard_time" to UnittoTimeZone(id = "cayman_islands_standard_time", nameRes = "Cayman Islands Standard Time", offsetSeconds = -18000),
|
||||
"cayman_islands_time" to UnittoTimeZone(id = "cayman_islands_time", nameRes = "Cayman Islands Time", offsetSeconds = -18000),
|
||||
"cook_island_time" to UnittoTimeZone(id = "cook_island_time", nameRes = "Cook Island Time", offsetSeconds = -36000),
|
||||
"chile_summer_time" to UnittoTimeZone(id = "chile_summer_time", nameRes = "Chile Summer Time", offsetSeconds = -10800),
|
||||
"chile_daylight_time" to UnittoTimeZone(id = "chile_daylight_time", nameRes = "Chile Daylight Time", offsetSeconds = -10800),
|
||||
"chile_standard_time" to UnittoTimeZone(id = "chile_standard_time", nameRes = "Chile Standard Time", offsetSeconds = -14400),
|
||||
"chile_time" to UnittoTimeZone(id = "chile_time", nameRes = "Chile Time", offsetSeconds = -14400),
|
||||
"chile_standard_time" to UnittoTimeZone(id = "chile_standard_time", nameRes = "Chile Standard Time", offsetSeconds = -14400),
|
||||
"colombia_time" to UnittoTimeZone(id = "colombia_time", nameRes = "Colombia Time", offsetSeconds = -18000),
|
||||
"central_standard_time" to UnittoTimeZone(id = "central_standard_time", nameRes = "Central Standard Time", offsetSeconds = -21600),
|
||||
"central_time" to UnittoTimeZone(id = "central_time", nameRes = "Central Time", offsetSeconds = -21600),
|
||||
"north_american_central_standard_time" to UnittoTimeZone(id = "north_american_central_standard_time", nameRes = "North American Central Standard Time", offsetSeconds = -21600),
|
||||
"tiempo_central_est_ndar_spanish" to UnittoTimeZone(id = "tiempo_central_est_ndar_spanish", nameRes = "Tiempo Central Est-ndar (Spanish)", offsetSeconds = -21600),
|
||||
"heure_normale_du_centre_french" to UnittoTimeZone(id = "heure_normale_du_centre_french", nameRes = "Heure Normale du Centre (French)", offsetSeconds = -21600),
|
||||
"china_standard_time" to UnittoTimeZone(id = "china_standard_time", nameRes = "China Standard Time", offsetSeconds = 28800),
|
||||
"cuba_standard_time" to UnittoTimeZone(id = "cuba_standard_time", nameRes = "Cuba Standard Time", offsetSeconds = -18000),
|
||||
"cape_verde_time" to UnittoTimeZone(id = "cape_verde_time", nameRes = "Cape Verde Time", offsetSeconds = -3600),
|
||||
"christmas_island_time" to UnittoTimeZone(id = "christmas_island_time", nameRes = "Christmas Island Time", offsetSeconds = 25200),
|
||||
"chamorro_standard_time" to UnittoTimeZone(id = "chamorro_standard_time", nameRes = "Chamorro Standard Time", offsetSeconds = 36000),
|
||||
"guam_standard_time" to UnittoTimeZone(id = "guam_standard_time", nameRes = "Guam Standard Time", offsetSeconds = 36000),
|
||||
"delta_time_zone" to UnittoTimeZone(id = "delta_time_zone", nameRes = "Delta Time Zone", offsetSeconds = 14400),
|
||||
"davis_time" to UnittoTimeZone(id = "davis_time", nameRes = "Davis Time", offsetSeconds = 25200),
|
||||
"dumont_durville_time" to UnittoTimeZone(id = "dumont_durville_time", nameRes = "Dumont-d'Urville Time", offsetSeconds = 36000),
|
||||
"echo_time_zone" to UnittoTimeZone(id = "echo_time_zone", nameRes = "Echo Time Zone", offsetSeconds = 18000),
|
||||
"easter_island_summer_time" to UnittoTimeZone(id = "easter_island_summer_time", nameRes = "Easter Island Summer Time", offsetSeconds = -18000),
|
||||
"easter_island_daylight_time" to UnittoTimeZone(id = "easter_island_daylight_time", nameRes = "Easter Island Daylight Time", offsetSeconds = -18000),
|
||||
"easter_island_standard_time" to UnittoTimeZone(id = "easter_island_standard_time", nameRes = "Easter Island Standard Time", offsetSeconds = -21600),
|
||||
"eastern_africa_time" to UnittoTimeZone(id = "eastern_africa_time", nameRes = "Eastern Africa Time", offsetSeconds = 10800),
|
||||
"east_africa_time" to UnittoTimeZone(id = "east_africa_time", nameRes = "East Africa Time", offsetSeconds = 10800),
|
||||
"ecuador_time" to UnittoTimeZone(id = "ecuador_time", nameRes = "Ecuador Time", offsetSeconds = -18000),
|
||||
"eastern_daylight_time" to UnittoTimeZone(id = "eastern_daylight_time", nameRes = "Eastern Daylight Time", offsetSeconds = -14400),
|
||||
"eastern_daylight_savings_time" to UnittoTimeZone(id = "eastern_daylight_savings_time", nameRes = "Eastern Daylight Savings Time", offsetSeconds = -14400),
|
||||
"north_american_eastern_daylight_time" to UnittoTimeZone(id = "north_american_eastern_daylight_time", nameRes = "North American Eastern Daylight Time", offsetSeconds = -14400),
|
||||
"heure_avanc_e_de_lest_french" to UnittoTimeZone(id = "heure_avanc_e_de_lest_french", nameRes = "Heure Avanc-e de l'Est (French)", offsetSeconds = -14400),
|
||||
"tiempo_de_verano_del_este_spanish" to UnittoTimeZone(id = "tiempo_de_verano_del_este_spanish", nameRes = "Tiempo de verano del Este (Spanish)", offsetSeconds = -14400),
|
||||
"eastern_european_summer_time" to UnittoTimeZone(id = "eastern_european_summer_time", nameRes = "Eastern European Summer Time", offsetSeconds = 10800),
|
||||
"eastern_european_daylight_time" to UnittoTimeZone(id = "eastern_european_daylight_time", nameRes = "Eastern European Daylight Time", offsetSeconds = 10800),
|
||||
"osteurop_ische_sommerzeit_german" to UnittoTimeZone(id = "osteurop_ische_sommerzeit_german", nameRes = "Osteurop-ische Sommerzeit (German)", offsetSeconds = 10800),
|
||||
"eastern_european_time" to UnittoTimeZone(id = "eastern_european_time", nameRes = "Eastern European Time", offsetSeconds = 7200),
|
||||
"osteurop_ische_zeit_german" to UnittoTimeZone(id = "osteurop_ische_zeit_german", nameRes = "Osteurop-ische Zeit (German)", offsetSeconds = 7200),
|
||||
"eastern_greenland_summer_time" to UnittoTimeZone(id = "eastern_greenland_summer_time", nameRes = "Eastern Greenland Summer Time", offsetSeconds = 0),
|
||||
"east_greenland_summer_time" to UnittoTimeZone(id = "east_greenland_summer_time", nameRes = "East Greenland Summer Time", offsetSeconds = 0),
|
||||
"east_greenland_time" to UnittoTimeZone(id = "east_greenland_time", nameRes = "East Greenland Time", offsetSeconds = -3600),
|
||||
"eastern_greenland_time" to UnittoTimeZone(id = "eastern_greenland_time", nameRes = "Eastern Greenland Time", offsetSeconds = -3600),
|
||||
"eastern_standard_time" to UnittoTimeZone(id = "eastern_standard_time", nameRes = "Eastern Standard Time", offsetSeconds = -18000),
|
||||
"eastern_time_" to UnittoTimeZone(id = "eastern_time_", nameRes = "Eastern Time ", offsetSeconds = -18000),
|
||||
"north_american_eastern_standard_time" to UnittoTimeZone(id = "north_american_eastern_standard_time", nameRes = "North American Eastern Standard Time", offsetSeconds = -18000),
|
||||
"tiempo_del_este_spanish" to UnittoTimeZone(id = "tiempo_del_este_spanish", nameRes = "Tiempo del Este (Spanish)", offsetSeconds = -18000),
|
||||
"heure_normale_de_lest_french" to UnittoTimeZone(id = "heure_normale_de_lest_french", nameRes = "Heure Normale de l'Est (French)", offsetSeconds = -18000),
|
||||
"foxtrot_time_zone" to UnittoTimeZone(id = "foxtrot_time_zone", nameRes = "Foxtrot Time Zone", offsetSeconds = 21600),
|
||||
"further_eastern_european_time" to UnittoTimeZone(id = "further_eastern_european_time", nameRes = "Further-Eastern European Time", offsetSeconds = 10800),
|
||||
"fiji_summer_time" to UnittoTimeZone(id = "fiji_summer_time", nameRes = "Fiji Summer Time", offsetSeconds = 46800),
|
||||
"fiji_daylight_time" to UnittoTimeZone(id = "fiji_daylight_time", nameRes = "Fiji Daylight Time", offsetSeconds = 46800),
|
||||
"fiji_time" to UnittoTimeZone(id = "fiji_time", nameRes = "Fiji Time", offsetSeconds = 43200),
|
||||
"falkland_islands_summer_time" to UnittoTimeZone(id = "falkland_islands_summer_time", nameRes = "Falkland Islands Summer Time", offsetSeconds = -10800),
|
||||
"falkland_island_daylight_time" to UnittoTimeZone(id = "falkland_island_daylight_time", nameRes = "Falkland Island Daylight Time", offsetSeconds = -10800),
|
||||
"falkland_island_time" to UnittoTimeZone(id = "falkland_island_time", nameRes = "Falkland Island Time", offsetSeconds = -14400),
|
||||
"falkland_island_standard_time" to UnittoTimeZone(id = "falkland_island_standard_time", nameRes = "Falkland Island Standard Time", offsetSeconds = -14400),
|
||||
"fernando_de_noronha_time" to UnittoTimeZone(id = "fernando_de_noronha_time", nameRes = "Fernando de Noronha Time", offsetSeconds = -7200),
|
||||
"golf_time_zone" to UnittoTimeZone(id = "golf_time_zone", nameRes = "Golf Time Zone", offsetSeconds = 25200),
|
||||
"galapagos_time" to UnittoTimeZone(id = "galapagos_time", nameRes = "Galapagos Time", offsetSeconds = -21600),
|
||||
"gambier_time" to UnittoTimeZone(id = "gambier_time", nameRes = "Gambier Time", offsetSeconds = -32400),
|
||||
"gambier_islands_time" to UnittoTimeZone(id = "gambier_islands_time", nameRes = "Gambier Islands Time", offsetSeconds = -32400),
|
||||
"georgia_standard_time" to UnittoTimeZone(id = "georgia_standard_time", nameRes = "Georgia Standard Time", offsetSeconds = 14400),
|
||||
"french_guiana_time" to UnittoTimeZone(id = "french_guiana_time", nameRes = "French Guiana Time", offsetSeconds = -10800),
|
||||
"gilbert_island_time" to UnittoTimeZone(id = "gilbert_island_time", nameRes = "Gilbert Island Time", offsetSeconds = 43200),
|
||||
"greenwich_mean_time" to UnittoTimeZone(id = "greenwich_mean_time", nameRes = "Greenwich Mean Time", offsetSeconds = 0),
|
||||
"coordinated_universal_time" to UnittoTimeZone(id = "coordinated_universal_time", nameRes = "Coordinated Universal Time", offsetSeconds = 0),
|
||||
"greenwich_time" to UnittoTimeZone(id = "greenwich_time", nameRes = "Greenwich Time", offsetSeconds = 0),
|
||||
"gulf_standard_time" to UnittoTimeZone(id = "gulf_standard_time", nameRes = "Gulf Standard Time", offsetSeconds = 14400),
|
||||
"south_georgia_time" to UnittoTimeZone(id = "south_georgia_time", nameRes = "South Georgia Time", offsetSeconds = -7200),
|
||||
"guyana_time" to UnittoTimeZone(id = "guyana_time", nameRes = "Guyana Time", offsetSeconds = -14400),
|
||||
"hotel_time_zone" to UnittoTimeZone(id = "hotel_time_zone", nameRes = "Hotel Time Zone", offsetSeconds = 28800),
|
||||
"hawaii_aleutian_daylight_time" to UnittoTimeZone(id = "hawaii_aleutian_daylight_time", nameRes = "Hawaii-Aleutian Daylight Time", offsetSeconds = -32400),
|
||||
"hawaii_daylight_time" to UnittoTimeZone(id = "hawaii_daylight_time", nameRes = "Hawaii Daylight Time", offsetSeconds = -32400),
|
||||
"hong_kong_time" to UnittoTimeZone(id = "hong_kong_time", nameRes = "Hong Kong Time", offsetSeconds = 28800),
|
||||
"hovd_summer_time" to UnittoTimeZone(id = "hovd_summer_time", nameRes = "Hovd Summer Time", offsetSeconds = 28800),
|
||||
"hovd_daylight_time" to UnittoTimeZone(id = "hovd_daylight_time", nameRes = "Hovd Daylight Time", offsetSeconds = 28800),
|
||||
"hovd_daylight_saving_time" to UnittoTimeZone(id = "hovd_daylight_saving_time", nameRes = "Hovd Daylight Saving Time", offsetSeconds = 28800),
|
||||
"hovd_time" to UnittoTimeZone(id = "hovd_time", nameRes = "Hovd Time", offsetSeconds = 25200),
|
||||
"hawaii_standard_time" to UnittoTimeZone(id = "hawaii_standard_time", nameRes = "Hawaii Standard Time", offsetSeconds = -36000),
|
||||
"hawaii_aleutian_standard_time" to UnittoTimeZone(id = "hawaii_aleutian_standard_time", nameRes = "Hawaii-Aleutian Standard Time", offsetSeconds = -36000),
|
||||
"india_time_zone" to UnittoTimeZone(id = "india_time_zone", nameRes = "India Time Zone", offsetSeconds = 32400),
|
||||
"indochina_time" to UnittoTimeZone(id = "indochina_time", nameRes = "Indochina Time", offsetSeconds = 25200),
|
||||
"israel_daylight_time" to UnittoTimeZone(id = "israel_daylight_time", nameRes = "Israel Daylight Time", offsetSeconds = 10800),
|
||||
"indian_chagos_time" to UnittoTimeZone(id = "indian_chagos_time", nameRes = "Indian Chagos Time", offsetSeconds = 21600),
|
||||
"iran_daylight_time" to UnittoTimeZone(id = "iran_daylight_time", nameRes = "Iran Daylight Time", offsetSeconds = 16200),
|
||||
"iran_summer_time" to UnittoTimeZone(id = "iran_summer_time", nameRes = "Iran Summer Time", offsetSeconds = 16200),
|
||||
"iran_daylight_time" to UnittoTimeZone(id = "iran_daylight_time", nameRes = "Iran Daylight Time", offsetSeconds = 16200),
|
||||
"irkutsk_summer_time" to UnittoTimeZone(id = "irkutsk_summer_time", nameRes = "Irkutsk Summer Time", offsetSeconds = 32400),
|
||||
"irkutsk_time" to UnittoTimeZone(id = "irkutsk_time", nameRes = "Irkutsk Time", offsetSeconds = 28800),
|
||||
"iran_standard_time" to UnittoTimeZone(id = "iran_standard_time", nameRes = "Iran Standard Time", offsetSeconds = 12600),
|
||||
"iran_time" to UnittoTimeZone(id = "iran_time", nameRes = "Iran Time", offsetSeconds = 12600),
|
||||
"india_standard_time" to UnittoTimeZone(id = "india_standard_time", nameRes = "India Standard Time", offsetSeconds = 19800),
|
||||
"india_time" to UnittoTimeZone(id = "india_time", nameRes = "India Time", offsetSeconds = 19800),
|
||||
"indian_standard_time" to UnittoTimeZone(id = "indian_standard_time", nameRes = "Indian Standard Time", offsetSeconds = 19800),
|
||||
"irish_standard_time" to UnittoTimeZone(id = "irish_standard_time", nameRes = "Irish Standard Time", offsetSeconds = 3600),
|
||||
"irish_summer_time" to UnittoTimeZone(id = "irish_summer_time", nameRes = "Irish Summer Time", offsetSeconds = 3600),
|
||||
"israel_standard_time" to UnittoTimeZone(id = "israel_standard_time", nameRes = "Israel Standard Time", offsetSeconds = 7200),
|
||||
"japan_standard_time" to UnittoTimeZone(id = "japan_standard_time", nameRes = "Japan Standard Time", offsetSeconds = 32400),
|
||||
"kilo_time_zone" to UnittoTimeZone(id = "kilo_time_zone", nameRes = "Kilo Time Zone", offsetSeconds = 36000),
|
||||
"kyrgyzstan_time" to UnittoTimeZone(id = "kyrgyzstan_time", nameRes = "Kyrgyzstan Time", offsetSeconds = 21600),
|
||||
"kosrae_time" to UnittoTimeZone(id = "kosrae_time", nameRes = "Kosrae Time", offsetSeconds = 39600),
|
||||
"krasnoyarsk_summer_time" to UnittoTimeZone(id = "krasnoyarsk_summer_time", nameRes = "Krasnoyarsk Summer Time", offsetSeconds = 28800),
|
||||
"krasnoyarsk_time" to UnittoTimeZone(id = "krasnoyarsk_time", nameRes = "Krasnoyarsk Time", offsetSeconds = 25200),
|
||||
"korea_standard_time" to UnittoTimeZone(id = "korea_standard_time", nameRes = "Korea Standard Time", offsetSeconds = 32400),
|
||||
"korean_standard_time" to UnittoTimeZone(id = "korean_standard_time", nameRes = "Korean Standard Time", offsetSeconds = 32400),
|
||||
"korea_time" to UnittoTimeZone(id = "korea_time", nameRes = "Korea Time", offsetSeconds = 32400),
|
||||
"kuybyshev_time" to UnittoTimeZone(id = "kuybyshev_time", nameRes = "Kuybyshev Time", offsetSeconds = 14400),
|
||||
"samara_summer_time" to UnittoTimeZone(id = "samara_summer_time", nameRes = "Samara Summer Time", offsetSeconds = 14400),
|
||||
"lima_time_zone" to UnittoTimeZone(id = "lima_time_zone", nameRes = "Lima Time Zone", offsetSeconds = 39600),
|
||||
"lord_howe_daylight_time" to UnittoTimeZone(id = "lord_howe_daylight_time", nameRes = "Lord Howe Daylight Time", offsetSeconds = 39600),
|
||||
"lord_howe_standard_time" to UnittoTimeZone(id = "lord_howe_standard_time", nameRes = "Lord Howe Standard Time", offsetSeconds = 37800),
|
||||
"line_islands_time" to UnittoTimeZone(id = "line_islands_time", nameRes = "Line Islands Time", offsetSeconds = 50400),
|
||||
"mike_time_zone" to UnittoTimeZone(id = "mike_time_zone", nameRes = "Mike Time Zone", offsetSeconds = 43200),
|
||||
"magadan_summer_time" to UnittoTimeZone(id = "magadan_summer_time", nameRes = "Magadan Summer Time", offsetSeconds = 43200),
|
||||
"magadan_island_summer_time" to UnittoTimeZone(id = "magadan_island_summer_time", nameRes = "Magadan Island Summer Time", offsetSeconds = 43200),
|
||||
"magadan_time" to UnittoTimeZone(id = "magadan_time", nameRes = "Magadan Time", offsetSeconds = 39600),
|
||||
"magadan_island_time" to UnittoTimeZone(id = "magadan_island_time", nameRes = "Magadan Island Time", offsetSeconds = 39600),
|
||||
"marquesas_time" to UnittoTimeZone(id = "marquesas_time", nameRes = "Marquesas Time", offsetSeconds = -34200),
|
||||
"mawson_time" to UnittoTimeZone(id = "mawson_time", nameRes = "Mawson Time", offsetSeconds = 18000),
|
||||
"mountain_daylight_time" to UnittoTimeZone(id = "mountain_daylight_time", nameRes = "Mountain Daylight Time", offsetSeconds = -21600),
|
||||
"mountain_daylight_saving_time" to UnittoTimeZone(id = "mountain_daylight_saving_time", nameRes = "Mountain Daylight Saving Time", offsetSeconds = -21600),
|
||||
"north_american_mountain_daylight_time" to UnittoTimeZone(id = "north_american_mountain_daylight_time", nameRes = "North American Mountain Daylight Time", offsetSeconds = -21600),
|
||||
"heure_avanc_e_des_rocheuses_french" to UnittoTimeZone(id = "heure_avanc_e_des_rocheuses_french", nameRes = "Heure Avanc-e des Rocheuses (French)", offsetSeconds = -21600),
|
||||
"marshall_islands_time" to UnittoTimeZone(id = "marshall_islands_time", nameRes = "Marshall Islands Time", offsetSeconds = 43200),
|
||||
"myanmar_time" to UnittoTimeZone(id = "myanmar_time", nameRes = "Myanmar Time", offsetSeconds = 23400),
|
||||
"moscow_daylight_time" to UnittoTimeZone(id = "moscow_daylight_time", nameRes = "Moscow Daylight Time", offsetSeconds = 14400),
|
||||
"moscow_summer_time" to UnittoTimeZone(id = "moscow_summer_time", nameRes = "Moscow Summer Time", offsetSeconds = 14400),
|
||||
"moscow_standard_time" to UnittoTimeZone(id = "moscow_standard_time", nameRes = "Moscow Standard Time", offsetSeconds = 10800),
|
||||
"moscow_time" to UnittoTimeZone(id = "moscow_time", nameRes = "Moscow Time", offsetSeconds = 10800),
|
||||
"mountain_standard_time" to UnittoTimeZone(id = "mountain_standard_time", nameRes = "Mountain Standard Time", offsetSeconds = -25200),
|
||||
"mountain_time" to UnittoTimeZone(id = "mountain_time", nameRes = "Mountain Time", offsetSeconds = -25200),
|
||||
"north_american_mountain_standard_time" to UnittoTimeZone(id = "north_american_mountain_standard_time", nameRes = "North American Mountain Standard Time", offsetSeconds = -25200),
|
||||
"heure_normale_des_rocheuses_french" to UnittoTimeZone(id = "heure_normale_des_rocheuses_french", nameRes = "Heure Normale des Rocheuses (French)", offsetSeconds = -25200),
|
||||
"mauritius_time" to UnittoTimeZone(id = "mauritius_time", nameRes = "Mauritius Time", offsetSeconds = 14400),
|
||||
"maldives_time" to UnittoTimeZone(id = "maldives_time", nameRes = "Maldives Time", offsetSeconds = 18000),
|
||||
"malaysia_time" to UnittoTimeZone(id = "malaysia_time", nameRes = "Malaysia Time", offsetSeconds = 28800),
|
||||
"malaysian_standard_time" to UnittoTimeZone(id = "malaysian_standard_time", nameRes = "Malaysian Standard Time", offsetSeconds = 28800),
|
||||
"november_time_zone" to UnittoTimeZone(id = "november_time_zone", nameRes = "November Time Zone", offsetSeconds = -3600),
|
||||
"new_caledonia_time" to UnittoTimeZone(id = "new_caledonia_time", nameRes = "New Caledonia Time", offsetSeconds = 39600),
|
||||
"newfoundland_daylight_time" to UnittoTimeZone(id = "newfoundland_daylight_time", nameRes = "Newfoundland Daylight Time", offsetSeconds = -9000),
|
||||
"heure_avanc_e_de_terre_neuve_french" to UnittoTimeZone(id = "heure_avanc_e_de_terre_neuve_french", nameRes = "Heure Avanc-e de Terre-Neuve (French)", offsetSeconds = -9000),
|
||||
"norfolk_daylight_time" to UnittoTimeZone(id = "norfolk_daylight_time", nameRes = "Norfolk Daylight Time", offsetSeconds = 43200),
|
||||
"norfolk_island_daylight_time" to UnittoTimeZone(id = "norfolk_island_daylight_time", nameRes = "Norfolk Island Daylight Time", offsetSeconds = 43200),
|
||||
"norfolk_time" to UnittoTimeZone(id = "norfolk_time", nameRes = "Norfolk Time", offsetSeconds = 39600),
|
||||
"norfolk_island_time" to UnittoTimeZone(id = "norfolk_island_time", nameRes = "Norfolk Island Time", offsetSeconds = 39600),
|
||||
"novosibirsk_summer_time" to UnittoTimeZone(id = "novosibirsk_summer_time", nameRes = "Novosibirsk Summer Time", offsetSeconds = 25200),
|
||||
"omsk_summer_time" to UnittoTimeZone(id = "omsk_summer_time", nameRes = "Omsk Summer Time", offsetSeconds = 25200),
|
||||
"novosibirsk_time" to UnittoTimeZone(id = "novosibirsk_time", nameRes = "Novosibirsk Time", offsetSeconds = 25200),
|
||||
"omsk_standard_time" to UnittoTimeZone(id = "omsk_standard_time", nameRes = "Omsk Standard Time", offsetSeconds = 25200),
|
||||
"nepal_time" to UnittoTimeZone(id = "nepal_time", nameRes = "Nepal Time", offsetSeconds = 20700),
|
||||
"nauru_time" to UnittoTimeZone(id = "nauru_time", nameRes = "Nauru Time", offsetSeconds = 43200),
|
||||
"newfoundland_standard_time" to UnittoTimeZone(id = "newfoundland_standard_time", nameRes = "Newfoundland Standard Time", offsetSeconds = -12600),
|
||||
"heure_normale_de_terre_neuve_french" to UnittoTimeZone(id = "heure_normale_de_terre_neuve_french", nameRes = "Heure Normale de Terre-Neuve (French)", offsetSeconds = -12600),
|
||||
"niue_time" to UnittoTimeZone(id = "niue_time", nameRes = "Niue Time", offsetSeconds = -39600),
|
||||
"new_zealand_daylight_time" to UnittoTimeZone(id = "new_zealand_daylight_time", nameRes = "New Zealand Daylight Time", offsetSeconds = 46800),
|
||||
"new_zealand_standard_time" to UnittoTimeZone(id = "new_zealand_standard_time", nameRes = "New Zealand Standard Time", offsetSeconds = 43200),
|
||||
"oscar_time_zone" to UnittoTimeZone(id = "oscar_time_zone", nameRes = "Oscar Time Zone", offsetSeconds = -7200),
|
||||
"omsk_summer_time" to UnittoTimeZone(id = "omsk_summer_time", nameRes = "Omsk Summer Time", offsetSeconds = 25200),
|
||||
"novosibirsk_summer_time" to UnittoTimeZone(id = "novosibirsk_summer_time", nameRes = "Novosibirsk Summer Time", offsetSeconds = 25200),
|
||||
"omsk_standard_time" to UnittoTimeZone(id = "omsk_standard_time", nameRes = "Omsk Standard Time", offsetSeconds = 21600),
|
||||
"omsk_time" to UnittoTimeZone(id = "omsk_time", nameRes = "Omsk Time", offsetSeconds = 21600),
|
||||
"novosibirsk_time" to UnittoTimeZone(id = "novosibirsk_time", nameRes = "Novosibirsk Time", offsetSeconds = 21600),
|
||||
"oral_time" to UnittoTimeZone(id = "oral_time", nameRes = "Oral Time", offsetSeconds = 18000),
|
||||
"papa_time_zone" to UnittoTimeZone(id = "papa_time_zone", nameRes = "Papa Time Zone", offsetSeconds = -10800),
|
||||
"pacific_daylight_time" to UnittoTimeZone(id = "pacific_daylight_time", nameRes = "Pacific Daylight Time", offsetSeconds = -25200),
|
||||
"pacific_daylight_saving_time" to UnittoTimeZone(id = "pacific_daylight_saving_time", nameRes = "Pacific Daylight Saving Time", offsetSeconds = -25200),
|
||||
"north_american_pacific_daylight_time" to UnittoTimeZone(id = "north_american_pacific_daylight_time", nameRes = "North American Pacific Daylight Time", offsetSeconds = -25200),
|
||||
"heure_avanc_e_du_pacifique_french" to UnittoTimeZone(id = "heure_avanc_e_du_pacifique_french", nameRes = "Heure Avanc-e du Pacifique (French)", offsetSeconds = -25200),
|
||||
"peru_time" to UnittoTimeZone(id = "peru_time", nameRes = "Peru Time", offsetSeconds = -18000),
|
||||
"kamchatka_summer_time" to UnittoTimeZone(id = "kamchatka_summer_time", nameRes = "Kamchatka Summer Time", offsetSeconds = 43200),
|
||||
"kamchatka_time" to UnittoTimeZone(id = "kamchatka_time", nameRes = "Kamchatka Time", offsetSeconds = 43200),
|
||||
"petropavlovsk_kamchatski_time" to UnittoTimeZone(id = "petropavlovsk_kamchatski_time", nameRes = "Petropavlovsk-Kamchatski Time", offsetSeconds = 43200),
|
||||
"papua_new_guinea_time" to UnittoTimeZone(id = "papua_new_guinea_time", nameRes = "Papua New Guinea Time", offsetSeconds = 36000),
|
||||
"phoenix_island_time" to UnittoTimeZone(id = "phoenix_island_time", nameRes = "Phoenix Island Time", offsetSeconds = 46800),
|
||||
"philippine_time" to UnittoTimeZone(id = "philippine_time", nameRes = "Philippine Time", offsetSeconds = 28800),
|
||||
"philippine_standard_time" to UnittoTimeZone(id = "philippine_standard_time", nameRes = "Philippine Standard Time", offsetSeconds = 28800),
|
||||
"pakistan_standard_time" to UnittoTimeZone(id = "pakistan_standard_time", nameRes = "Pakistan Standard Time", offsetSeconds = 18000),
|
||||
"pakistan_time" to UnittoTimeZone(id = "pakistan_time", nameRes = "Pakistan Time", offsetSeconds = 18000),
|
||||
"pierre_&_miquelon_daylight_time" to UnittoTimeZone(id = "pierre_&_miquelon_daylight_time", nameRes = "Pierre & Miquelon Daylight Time", offsetSeconds = -7200),
|
||||
"pierre_&_miquelon_standard_time" to UnittoTimeZone(id = "pierre_&_miquelon_standard_time", nameRes = "Pierre & Miquelon Standard Time", offsetSeconds = -10800),
|
||||
"pohnpei_standard_time" to UnittoTimeZone(id = "pohnpei_standard_time", nameRes = "Pohnpei Standard Time", offsetSeconds = 39600),
|
||||
"pacific_standard_time" to UnittoTimeZone(id = "pacific_standard_time", nameRes = "Pacific Standard Time", offsetSeconds = -28800),
|
||||
"pacific_time" to UnittoTimeZone(id = "pacific_time", nameRes = "Pacific Time", offsetSeconds = -28800),
|
||||
"north_american_pacific_standard_time" to UnittoTimeZone(id = "north_american_pacific_standard_time", nameRes = "North American Pacific Standard Time", offsetSeconds = -28800),
|
||||
"tiempo_del_pac_fico_spanish" to UnittoTimeZone(id = "tiempo_del_pac_fico_spanish", nameRes = "Tiempo del Pac-fico (Spanish)", offsetSeconds = -28800),
|
||||
"heure_normale_du_pacifique_french" to UnittoTimeZone(id = "heure_normale_du_pacifique_french", nameRes = "Heure Normale du Pacifique (French)", offsetSeconds = -28800),
|
||||
"pitcairn_standard_time" to UnittoTimeZone(id = "pitcairn_standard_time", nameRes = "Pitcairn Standard Time", offsetSeconds = -28800),
|
||||
"palau_time" to UnittoTimeZone(id = "palau_time", nameRes = "Palau Time", offsetSeconds = 32400),
|
||||
"paraguay_summer_time" to UnittoTimeZone(id = "paraguay_summer_time", nameRes = "Paraguay Summer Time", offsetSeconds = -10800),
|
||||
"paraguay_time" to UnittoTimeZone(id = "paraguay_time", nameRes = "Paraguay Time", offsetSeconds = -14400),
|
||||
"pyongyang_time" to UnittoTimeZone(id = "pyongyang_time", nameRes = "Pyongyang Time", offsetSeconds = 30600),
|
||||
"pyongyang_standard_time" to UnittoTimeZone(id = "pyongyang_standard_time", nameRes = "Pyongyang Standard Time", offsetSeconds = 30600),
|
||||
"quebec_time_zone" to UnittoTimeZone(id = "quebec_time_zone", nameRes = "Quebec Time Zone", offsetSeconds = -14400),
|
||||
"qyzylorda_time" to UnittoTimeZone(id = "qyzylorda_time", nameRes = "Qyzylorda Time", offsetSeconds = 21600),
|
||||
"romeo_time_zone" to UnittoTimeZone(id = "romeo_time_zone", nameRes = "Romeo Time Zone", offsetSeconds = -18000),
|
||||
"reunion_time" to UnittoTimeZone(id = "reunion_time", nameRes = "Reunion Time", offsetSeconds = 14400),
|
||||
"rothera_time" to UnittoTimeZone(id = "rothera_time", nameRes = "Rothera Time", offsetSeconds = -10800),
|
||||
"sierra_time_zone" to UnittoTimeZone(id = "sierra_time_zone", nameRes = "Sierra Time Zone", offsetSeconds = -21600),
|
||||
"sakhalin_time" to UnittoTimeZone(id = "sakhalin_time", nameRes = "Sakhalin Time", offsetSeconds = 39600),
|
||||
"samara_time" to UnittoTimeZone(id = "samara_time", nameRes = "Samara Time", offsetSeconds = 14400),
|
||||
"samara_standard_time" to UnittoTimeZone(id = "samara_standard_time", nameRes = "Samara Standard Time", offsetSeconds = 14400),
|
||||
"south_africa_standard_time" to UnittoTimeZone(id = "south_africa_standard_time", nameRes = "South Africa Standard Time", offsetSeconds = 7200),
|
||||
"south_african_standard_time" to UnittoTimeZone(id = "south_african_standard_time", nameRes = "South African Standard Time", offsetSeconds = 7200),
|
||||
"solomon_islands_time" to UnittoTimeZone(id = "solomon_islands_time", nameRes = "Solomon Islands Time", offsetSeconds = 39600),
|
||||
"solomon_island_time" to UnittoTimeZone(id = "solomon_island_time", nameRes = "Solomon Island Time", offsetSeconds = 39600),
|
||||
"seychelles_time" to UnittoTimeZone(id = "seychelles_time", nameRes = "Seychelles Time", offsetSeconds = 14400),
|
||||
"singapore_time" to UnittoTimeZone(id = "singapore_time", nameRes = "Singapore Time", offsetSeconds = 28800),
|
||||
"singapore_standard_time" to UnittoTimeZone(id = "singapore_standard_time", nameRes = "Singapore Standard Time", offsetSeconds = 28800),
|
||||
"srednekolymsk_time" to UnittoTimeZone(id = "srednekolymsk_time", nameRes = "Srednekolymsk Time", offsetSeconds = 39600),
|
||||
"suriname_time" to UnittoTimeZone(id = "suriname_time", nameRes = "Suriname Time", offsetSeconds = -10800),
|
||||
"samoa_standard_time" to UnittoTimeZone(id = "samoa_standard_time", nameRes = "Samoa Standard Time", offsetSeconds = -39600),
|
||||
"syowa_time" to UnittoTimeZone(id = "syowa_time", nameRes = "Syowa Time", offsetSeconds = 10800),
|
||||
"tango_time_zone" to UnittoTimeZone(id = "tango_time_zone", nameRes = "Tango Time Zone", offsetSeconds = -25200),
|
||||
"tahiti_time" to UnittoTimeZone(id = "tahiti_time", nameRes = "Tahiti Time", offsetSeconds = -36000),
|
||||
"french_southern_and_antarctic_time" to UnittoTimeZone(id = "french_southern_and_antarctic_time", nameRes = "French Southern and Antarctic Time", offsetSeconds = 18000),
|
||||
"kerguelen_islands_time" to UnittoTimeZone(id = "kerguelen_islands_time", nameRes = "Kerguelen (Islands) Time", offsetSeconds = 18000),
|
||||
"tajikistan_time" to UnittoTimeZone(id = "tajikistan_time", nameRes = "Tajikistan Time", offsetSeconds = 18000),
|
||||
"tokelau_time" to UnittoTimeZone(id = "tokelau_time", nameRes = "Tokelau Time", offsetSeconds = 46800),
|
||||
"east_timor_time" to UnittoTimeZone(id = "east_timor_time", nameRes = "East Timor Time", offsetSeconds = 32400),
|
||||
"turkmenistan_time" to UnittoTimeZone(id = "turkmenistan_time", nameRes = "Turkmenistan Time", offsetSeconds = 18000),
|
||||
"tonga_summer_time" to UnittoTimeZone(id = "tonga_summer_time", nameRes = "Tonga Summer Time", offsetSeconds = 50400),
|
||||
"tonga_time" to UnittoTimeZone(id = "tonga_time", nameRes = "Tonga Time", offsetSeconds = 46800),
|
||||
"turkey_time" to UnittoTimeZone(id = "turkey_time", nameRes = "Turkey Time", offsetSeconds = 10800),
|
||||
"tuvalu_time" to UnittoTimeZone(id = "tuvalu_time", nameRes = "Tuvalu Time", offsetSeconds = 43200),
|
||||
"uniform_time_zone" to UnittoTimeZone(id = "uniform_time_zone", nameRes = "Uniform Time Zone", offsetSeconds = -28800),
|
||||
"ulaanbaatar_summer_time" to UnittoTimeZone(id = "ulaanbaatar_summer_time", nameRes = "Ulaanbaatar Summer Time", offsetSeconds = 32400),
|
||||
"ulan_bator_summer_time" to UnittoTimeZone(id = "ulan_bator_summer_time", nameRes = "Ulan Bator Summer Time", offsetSeconds = 32400),
|
||||
"ulaanbaatar_time" to UnittoTimeZone(id = "ulaanbaatar_time", nameRes = "Ulaanbaatar Time", offsetSeconds = 28800),
|
||||
"ulan_bator_time" to UnittoTimeZone(id = "ulan_bator_time", nameRes = "Ulan Bator Time", offsetSeconds = 28800),
|
||||
"coordinated_universal_time" to UnittoTimeZone(id = "coordinated_universal_time", nameRes = "Coordinated Universal Time", offsetSeconds = 0),
|
||||
"uruguay_summer_time" to UnittoTimeZone(id = "uruguay_summer_time", nameRes = "Uruguay Summer Time", offsetSeconds = -7200),
|
||||
"uruguay_time" to UnittoTimeZone(id = "uruguay_time", nameRes = "Uruguay Time", offsetSeconds = -10800),
|
||||
"uzbekistan_time" to UnittoTimeZone(id = "uzbekistan_time", nameRes = "Uzbekistan Time", offsetSeconds = 18000),
|
||||
"victor_time_zone" to UnittoTimeZone(id = "victor_time_zone", nameRes = "Victor Time Zone", offsetSeconds = -32400),
|
||||
"venezuelan_standard_time" to UnittoTimeZone(id = "venezuelan_standard_time", nameRes = "Venezuelan Standard Time", offsetSeconds = -14400),
|
||||
"hora_legal_de_venezuela_spanish" to UnittoTimeZone(id = "hora_legal_de_venezuela_spanish", nameRes = "Hora Legal de Venezuela (Spanish)", offsetSeconds = -14400),
|
||||
"vladivostok_summer_time" to UnittoTimeZone(id = "vladivostok_summer_time", nameRes = "Vladivostok Summer Time", offsetSeconds = 39600),
|
||||
"vladivostok_time" to UnittoTimeZone(id = "vladivostok_time", nameRes = "Vladivostok Time", offsetSeconds = 36000),
|
||||
"vostok_time" to UnittoTimeZone(id = "vostok_time", nameRes = "Vostok Time", offsetSeconds = 21600),
|
||||
"vanuatu_time" to UnittoTimeZone(id = "vanuatu_time", nameRes = "Vanuatu Time", offsetSeconds = 39600),
|
||||
"efate_time" to UnittoTimeZone(id = "efate_time", nameRes = "Efate Time", offsetSeconds = 39600),
|
||||
"whiskey_time_zone" to UnittoTimeZone(id = "whiskey_time_zone", nameRes = "Whiskey Time Zone", offsetSeconds = -36000),
|
||||
"wake_time" to UnittoTimeZone(id = "wake_time", nameRes = "Wake Time", offsetSeconds = 43200),
|
||||
"western_argentine_summer_time" to UnittoTimeZone(id = "western_argentine_summer_time", nameRes = "Western Argentine Summer Time", offsetSeconds = -10800),
|
||||
"west_africa_summer_time" to UnittoTimeZone(id = "west_africa_summer_time", nameRes = "West Africa Summer Time", offsetSeconds = 7200),
|
||||
"west_africa_time" to UnittoTimeZone(id = "west_africa_time", nameRes = "West Africa Time", offsetSeconds = 3600),
|
||||
"western_european_summer_time" to UnittoTimeZone(id = "western_european_summer_time", nameRes = "Western European Summer Time", offsetSeconds = 3600),
|
||||
"western_european_daylight_time" to UnittoTimeZone(id = "western_european_daylight_time", nameRes = "Western European Daylight Time", offsetSeconds = 3600),
|
||||
"westeurop_ische_sommerzeit_german" to UnittoTimeZone(id = "westeurop_ische_sommerzeit_german", nameRes = "Westeurop-ische Sommerzeit (German)", offsetSeconds = 3600),
|
||||
"western_european_time" to UnittoTimeZone(id = "western_european_time", nameRes = "Western European Time", offsetSeconds = 0),
|
||||
"greenwich_mean_time" to UnittoTimeZone(id = "greenwich_mean_time", nameRes = "Greenwich Mean Time", offsetSeconds = 0),
|
||||
"westeurop_ische_zeit_german" to UnittoTimeZone(id = "westeurop_ische_zeit_german", nameRes = "Westeurop-ische Zeit (German)", offsetSeconds = 0),
|
||||
"wallis_and_futuna_time" to UnittoTimeZone(id = "wallis_and_futuna_time", nameRes = "Wallis and Futuna Time", offsetSeconds = 43200),
|
||||
"western_greenland_summer_time" to UnittoTimeZone(id = "western_greenland_summer_time", nameRes = "Western Greenland Summer Time", offsetSeconds = -7200),
|
||||
"west_greenland_summer_time" to UnittoTimeZone(id = "west_greenland_summer_time", nameRes = "West Greenland Summer Time", offsetSeconds = -7200),
|
||||
"west_greenland_time" to UnittoTimeZone(id = "west_greenland_time", nameRes = "West Greenland Time", offsetSeconds = -10800),
|
||||
"western_greenland_time" to UnittoTimeZone(id = "western_greenland_time", nameRes = "Western Greenland Time", offsetSeconds = -10800),
|
||||
"western_indonesian_time" to UnittoTimeZone(id = "western_indonesian_time", nameRes = "Western Indonesian Time", offsetSeconds = 25200),
|
||||
"waktu_indonesia_barat" to UnittoTimeZone(id = "waktu_indonesia_barat", nameRes = "Waktu Indonesia Barat", offsetSeconds = 25200),
|
||||
"eastern_indonesian_time" to UnittoTimeZone(id = "eastern_indonesian_time", nameRes = "Eastern Indonesian Time", offsetSeconds = 32400),
|
||||
"waktu_indonesia_timur" to UnittoTimeZone(id = "waktu_indonesia_timur", nameRes = "Waktu Indonesia Timur", offsetSeconds = 32400),
|
||||
"central_indonesian_time" to UnittoTimeZone(id = "central_indonesian_time", nameRes = "Central Indonesian Time", offsetSeconds = 28800),
|
||||
"waktu_indonesia_tengah" to UnittoTimeZone(id = "waktu_indonesia_tengah", nameRes = "Waktu Indonesia Tengah", offsetSeconds = 28800),
|
||||
"west_samoa_time" to UnittoTimeZone(id = "west_samoa_time", nameRes = "West Samoa Time", offsetSeconds = 46800),
|
||||
"samoa_time" to UnittoTimeZone(id = "samoa_time", nameRes = "Samoa Time", offsetSeconds = 46800),
|
||||
"western_sahara_summer_time" to UnittoTimeZone(id = "western_sahara_summer_time", nameRes = "Western Sahara Summer Time", offsetSeconds = 3600),
|
||||
"western_sahara_standard_time" to UnittoTimeZone(id = "western_sahara_standard_time", nameRes = "Western Sahara Standard Time", offsetSeconds = 0),
|
||||
"x_ray_time_zone" to UnittoTimeZone(id = "x_ray_time_zone", nameRes = "X-ray Time Zone", offsetSeconds = -39600),
|
||||
"yankee_time_zone" to UnittoTimeZone(id = "yankee_time_zone", nameRes = "Yankee Time Zone", offsetSeconds = -43200),
|
||||
"yakutsk_summer_time" to UnittoTimeZone(id = "yakutsk_summer_time", nameRes = "Yakutsk Summer Time", offsetSeconds = 36000),
|
||||
"yakutsk_time" to UnittoTimeZone(id = "yakutsk_time", nameRes = "Yakutsk Time", offsetSeconds = 32400),
|
||||
"yap_time" to UnittoTimeZone(id = "yap_time", nameRes = "Yap Time", offsetSeconds = 36000),
|
||||
"yekaterinburg_summer_time" to UnittoTimeZone(id = "yekaterinburg_summer_time", nameRes = "Yekaterinburg Summer Time", offsetSeconds = 21600),
|
||||
"yekaterinburg_time" to UnittoTimeZone(id = "yekaterinburg_time", nameRes = "Yekaterinburg Time", offsetSeconds = 18000),
|
||||
"zulu_time_zone" to UnittoTimeZone(id = "zulu_time_zone", nameRes = "Zulu Time Zone", offsetSeconds = 0)
|
||||
)
|
||||
|
||||
val favoriteTimeZones: MutableStateFlow<List<UnittoTimeZone>> = MutableStateFlow(emptyList())
|
||||
|
||||
// UNCOMMENT FOR RELEASE
|
||||
// val favoriteTimeZones: Flow<List<UnittoTimeZone>> = dao
|
||||
// .getAll()
|
||||
// .map { list ->
|
||||
// val favorites = mutableListOf<UnittoTimeZone>()
|
||||
// list.forEach { entity ->
|
||||
// val foundTimeZone = allTimeZones[entity.id] ?: return@forEach
|
||||
// val mapped = foundTimeZone.copy(
|
||||
// position = entity.position
|
||||
// )
|
||||
// favorites.add(mapped)
|
||||
// }
|
||||
//
|
||||
// favorites
|
||||
// }
|
||||
|
||||
suspend fun swapTimeZones(from: String, to: String) = withContext(Dispatchers.IO) {
|
||||
// UNCOMMENT FOR RELEASE
|
||||
// dao.swap(from, to)
|
||||
|
||||
favoriteTimeZones.update {
|
||||
val fromIndex = it.indexOfFirst { it.id == from }
|
||||
val toIndex = it.indexOfFirst { it.id == to }
|
||||
|
||||
it
|
||||
.toMutableList()
|
||||
.apply {
|
||||
add(toIndex, removeAt(fromIndex))
|
||||
}
|
||||
}
|
||||
|
||||
return@withContext
|
||||
}
|
||||
|
||||
suspend fun delete(timeZone: UnittoTimeZone) = withContext(Dispatchers.IO) {
|
||||
// UNCOMMENT FOR RELEASE
|
||||
// // Only PrimaryKey is needed
|
||||
// dao.remove(TimeZoneEntity(id = timeZone.id, position = 0))
|
||||
|
||||
favoriteTimeZones.update { it.minus(timeZone) }
|
||||
}
|
||||
|
||||
suspend fun filterAllTimeZones(searchQuery: String): List<UnittoTimeZone> =
|
||||
withContext(Dispatchers.IO) {
|
||||
val query = searchQuery.trim().lowercase()
|
||||
val threshold: Int = query.length / 2
|
||||
val timeZonesWithDist = mutableListOf<Pair<UnittoTimeZone, Int>>()
|
||||
|
||||
allTimeZones.values.forEach { timeZone ->
|
||||
val timeZoneName = timeZone.nameRes
|
||||
|
||||
if (timeZone.code.lowercase() == query) {
|
||||
timeZonesWithDist.add(timeZone to 1)
|
||||
return@forEach
|
||||
}
|
||||
|
||||
when {
|
||||
// not zero, so that lev can have that
|
||||
timeZoneName.startsWith(query) -> {
|
||||
timeZonesWithDist.add(timeZone to 1)
|
||||
return@forEach
|
||||
}
|
||||
|
||||
timeZoneName.contains(query) -> {
|
||||
timeZonesWithDist.add(timeZone to 2)
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
val levDist = timeZoneName
|
||||
.substring(0, minOf(query.length, timeZoneName.length))
|
||||
.lev(query)
|
||||
|
||||
if (levDist < threshold) {
|
||||
timeZonesWithDist.add(timeZone to levDist)
|
||||
}
|
||||
}
|
||||
|
||||
return@withContext timeZonesWithDist.sortedBy { it.second }.map { it.first }
|
||||
}
|
||||
|
||||
suspend fun addToFavorites(timeZone: UnittoTimeZone) {
|
||||
// UNCOMMENT FOR RELEASE
|
||||
// dao.insert(
|
||||
// TimeZoneEntity(
|
||||
// id = timeZone.id,
|
||||
// position = System.currentTimeMillis().toInt()
|
||||
// )
|
||||
// )
|
||||
favoriteTimeZones.update { it.plus(timeZone) }
|
||||
}
|
||||
}
|
@ -92,6 +92,7 @@ data class UIPreferences(
|
||||
val customColor: Color = Color.Unspecified,
|
||||
val monetMode: MonetMode = MonetMode.TONAL_SPOT,
|
||||
val startingScreen: String = TopLevelDestinations.Converter.route,
|
||||
val enableToolsExperiment: Boolean = false,
|
||||
)
|
||||
|
||||
data class MainPreferences(
|
||||
@ -153,6 +154,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
val monetMode: MonetMode = preferences[PrefsKeys.MONET_MODE]?.let { MonetMode.valueOf(it) }
|
||||
?: MonetMode.TONAL_SPOT
|
||||
val startingScreen: String = preferences[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.Converter.route
|
||||
val enableToolsExperiment: Boolean = preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false
|
||||
|
||||
UIPreferences(
|
||||
themingMode = themingMode,
|
||||
@ -160,7 +162,8 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
enableAmoledTheme = enableAmoledTheme,
|
||||
customColor = customColor,
|
||||
monetMode = monetMode,
|
||||
startingScreen = startingScreen
|
||||
startingScreen = startingScreen,
|
||||
enableToolsExperiment = enableToolsExperiment
|
||||
)
|
||||
}
|
||||
|
||||
@ -228,7 +231,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
latestRightSideUnit = main.latestRightSideUnit,
|
||||
shownUnitGroups = main.shownUnitGroups,
|
||||
enableVibrations = main.enableVibrations,
|
||||
enableToolsExperiment = false,
|
||||
enableToolsExperiment = ui.enableToolsExperiment,
|
||||
startingScreen = ui.startingScreen,
|
||||
radianMode = main.radianMode,
|
||||
unitConverterFavoritesOnly = main.unitConverterFavoritesOnly,
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
package com.sadellie.unitto.feature.datedifference
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
@ -34,7 +33,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
@ -62,8 +60,10 @@ internal fun DateDifferenceRoute(
|
||||
navigateToMenu = navigateToMenu,
|
||||
navigateToSettings = navigateToSettings,
|
||||
uiState = uiState.value,
|
||||
updateStart = viewModel::setStartTime,
|
||||
updateEnd = viewModel::setEndTime
|
||||
setStartTime = viewModel::setStartTime,
|
||||
setEndTime = viewModel::setEndTime,
|
||||
setStartDate = viewModel::setStartDate,
|
||||
setEndDate = viewModel::setEndDate,
|
||||
)
|
||||
}
|
||||
|
||||
@ -72,12 +72,13 @@ internal fun DateDifferenceRoute(
|
||||
internal fun DateDifferenceScreen(
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
updateStart: (LocalDateTime) -> Unit,
|
||||
updateEnd: (LocalDateTime) -> Unit,
|
||||
setStartTime: (Int, Int) -> Unit,
|
||||
setEndTime: (Int, Int) -> Unit,
|
||||
setStartDate: (LocalDateTime) -> Unit,
|
||||
setEndDate: (LocalDateTime) -> Unit,
|
||||
uiState: UIState,
|
||||
) {
|
||||
var dialogState by remember { mutableStateOf(DialogState.NONE) }
|
||||
val isVertical = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
|
||||
UnittoScreenWithTopBar(
|
||||
title = { Text(stringResource(R.string.date_difference)) },
|
||||
@ -138,26 +139,26 @@ internal fun DateDifferenceScreen(
|
||||
when (dialogState) {
|
||||
DialogState.FROM -> {
|
||||
TimePickerDialog(
|
||||
localDateTime = uiState.start,
|
||||
hour = uiState.start.hour,
|
||||
minute = uiState.start.minute,
|
||||
onDismiss = ::resetDialog,
|
||||
onConfirm = {
|
||||
updateStart(it)
|
||||
onConfirm = { hour, minute ->
|
||||
setStartTime(hour, minute)
|
||||
dialogState = DialogState.FROM_DATE
|
||||
},
|
||||
confirmLabel = stringResource(R.string.next_label),
|
||||
vertical = isVertical,
|
||||
)
|
||||
}
|
||||
|
||||
DialogState.FROM_TIME -> {
|
||||
TimePickerDialog(
|
||||
localDateTime = uiState.start,
|
||||
hour = uiState.start.hour,
|
||||
minute = uiState.start.minute,
|
||||
onDismiss = ::resetDialog,
|
||||
onConfirm = {
|
||||
updateStart(it)
|
||||
onConfirm = { hour, minute ->
|
||||
setStartTime(hour, minute)
|
||||
resetDialog()
|
||||
},
|
||||
vertical = isVertical,
|
||||
)
|
||||
}
|
||||
|
||||
@ -166,7 +167,7 @@ internal fun DateDifferenceScreen(
|
||||
localDateTime = uiState.start,
|
||||
onDismiss = ::resetDialog,
|
||||
onConfirm = {
|
||||
updateStart(it)
|
||||
setStartDate(it)
|
||||
resetDialog()
|
||||
}
|
||||
)
|
||||
@ -174,26 +175,26 @@ internal fun DateDifferenceScreen(
|
||||
|
||||
DialogState.TO -> {
|
||||
TimePickerDialog(
|
||||
localDateTime = uiState.end,
|
||||
hour = uiState.end.hour,
|
||||
minute = uiState.end.minute,
|
||||
onDismiss = ::resetDialog,
|
||||
onConfirm = {
|
||||
updateEnd(it)
|
||||
onConfirm = { hour, minute ->
|
||||
setEndTime(hour, minute)
|
||||
dialogState = DialogState.TO_DATE
|
||||
},
|
||||
confirmLabel = stringResource(R.string.next_label),
|
||||
vertical = isVertical,
|
||||
)
|
||||
}
|
||||
|
||||
DialogState.TO_TIME -> {
|
||||
TimePickerDialog(
|
||||
localDateTime = uiState.end,
|
||||
hour = uiState.end.hour,
|
||||
minute = uiState.end.minute,
|
||||
onDismiss = ::resetDialog,
|
||||
onConfirm = {
|
||||
updateEnd(it)
|
||||
onConfirm = { hour, minute ->
|
||||
setEndTime(hour, minute)
|
||||
resetDialog()
|
||||
},
|
||||
vertical = isVertical,
|
||||
)
|
||||
}
|
||||
|
||||
@ -202,7 +203,7 @@ internal fun DateDifferenceScreen(
|
||||
localDateTime = uiState.end,
|
||||
onDismiss = ::resetDialog,
|
||||
onConfirm = {
|
||||
updateEnd(it)
|
||||
setEndDate(it)
|
||||
resetDialog()
|
||||
}
|
||||
)
|
||||
@ -222,10 +223,12 @@ private fun DateDifferenceScreenPreview() {
|
||||
DateDifferenceScreen(
|
||||
navigateToMenu = {},
|
||||
navigateToSettings = {},
|
||||
updateStart = {},
|
||||
updateEnd = {},
|
||||
setStartTime = { _, _ -> },
|
||||
setEndTime = { _, _ -> },
|
||||
uiState = UIState(
|
||||
result = DateDifference.Default(4, 1, 2, 3, 4)
|
||||
)
|
||||
),
|
||||
setStartDate = {},
|
||||
setEndDate = {},
|
||||
)
|
||||
}
|
||||
|
@ -46,9 +46,13 @@ internal class DateDifferenceViewModel @Inject constructor() : ViewModel() {
|
||||
viewModelScope, SharingStarted.WhileSubscribed(5000L), UIState()
|
||||
)
|
||||
|
||||
fun setStartTime(newTime: LocalDateTime) = _start.update { newTime }
|
||||
fun setStartTime(hour: Int, minute: Int) = _start.update { it.withHour(hour).withMinute(minute) }
|
||||
|
||||
fun setEndTime(newTime: LocalDateTime) = _end.update { newTime }
|
||||
fun setEndTime(hour: Int, minute: Int) = _end.update { it.withHour(hour).withMinute(minute) }
|
||||
|
||||
fun setStartDate(dateTime: LocalDateTime) = _start.update { dateTime }
|
||||
|
||||
fun setEndDate(dateTime: LocalDateTime) = _end.update { dateTime }
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
|
@ -30,9 +30,11 @@ android {
|
||||
dependencies {
|
||||
testImplementation(libs.junit)
|
||||
implementation(libs.com.github.sadellie.themmo)
|
||||
implementation(libs.org.burnoutcrew.composereorderable)
|
||||
|
||||
implementation(project(mapOf("path" to ":data:common")))
|
||||
implementation(project(mapOf("path" to ":data:userprefs")))
|
||||
implementation(project(mapOf("path" to ":data:database")))
|
||||
implementation(project(mapOf("path" to ":data:timezone")))
|
||||
implementation(project(mapOf("path" to ":data:model")))
|
||||
}
|
||||
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.timezone
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.LinearOutSlowInEasing
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import com.sadellie.unitto.timezone.components.SelectableTimeZone
|
||||
import com.sadellie.unitto.timezone.components.UnittoSearchBar
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
@Composable
|
||||
internal fun AddTimeZoneRoute(
|
||||
viewModel: AddTimeZoneViewModel = hiltViewModel(),
|
||||
navigateUp: () -> Unit,
|
||||
userTime: ZonedDateTime? = null
|
||||
) {
|
||||
val uiState = viewModel.addTimeZoneUIState.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (userTime == null) {
|
||||
while (isActive) {
|
||||
viewModel.setTime(ZonedDateTime.now())
|
||||
delay(1000)
|
||||
}
|
||||
} else {
|
||||
viewModel.setTime(userTime)
|
||||
}
|
||||
}
|
||||
|
||||
AddTimeZoneScreen(
|
||||
uiState = uiState.value,
|
||||
navigateUp = navigateUp,
|
||||
onQueryChange = viewModel::onQueryChange,
|
||||
addToFavorites = viewModel::addToFavorites,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddTimeZoneScreen(
|
||||
uiState: AddTimeZoneUIState,
|
||||
navigateUp: () -> Unit,
|
||||
onQueryChange: (String) -> Unit,
|
||||
addToFavorites: (UnittoTimeZone) -> Unit,
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
|
||||
rememberTopAppBarState()
|
||||
)
|
||||
val elevatedColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp)
|
||||
val needToTint by remember {
|
||||
derivedStateOf { scrollBehavior.state.overlappedFraction > 0.01f }
|
||||
}
|
||||
|
||||
val searchBarBackground = animateColorAsState(
|
||||
targetValue = if (needToTint) elevatedColor else MaterialTheme.colorScheme.surface,
|
||||
animationSpec = tween(durationMillis = 500, easing = LinearOutSlowInEasing),
|
||||
label = "Search bar background"
|
||||
)
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
topBar = {
|
||||
UnittoSearchBar(
|
||||
modifier = Modifier,
|
||||
query = uiState.query,
|
||||
onQueryChange = onQueryChange,
|
||||
navigateUp = navigateUp,
|
||||
title = stringResource(R.string.add_time_zone_title),
|
||||
placeholder = stringResource(R.string.search_text_field_placeholder),
|
||||
scrollBehavior = scrollBehavior,
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = searchBarBackground.value
|
||||
)
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
state = listState
|
||||
) {
|
||||
items(uiState.list) {
|
||||
SelectableTimeZone(
|
||||
timeZone = it,
|
||||
modifier = Modifier
|
||||
.clickable { addToFavorites(it); navigateUp() }
|
||||
.fillMaxWidth(),
|
||||
currentTime = uiState.userTime
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewAddTimeZoneScreen() {
|
||||
AddTimeZoneScreen(
|
||||
navigateUp = {},
|
||||
uiState = AddTimeZoneUIState(
|
||||
list = List(50) {
|
||||
UnittoTimeZone(
|
||||
id = "timezone $it",
|
||||
nameRes = "Time zone $it",
|
||||
)
|
||||
}
|
||||
),
|
||||
onQueryChange = {},
|
||||
addToFavorites = {},
|
||||
)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.timezone
|
||||
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
data class AddTimeZoneUIState(
|
||||
val query: String = "",
|
||||
val list: List<UnittoTimeZone> = emptyList(),
|
||||
val userTime: ZonedDateTime? = null,
|
||||
)
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.timezone
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import com.sadellie.unitto.data.timezone.TimeZonesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.ZonedDateTime
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AddTimeZoneViewModel @Inject constructor(
|
||||
private val timezonesRepository: TimeZonesRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _userTime = MutableStateFlow<ZonedDateTime?>(ZonedDateTime.now())
|
||||
private val _query = MutableStateFlow("")
|
||||
|
||||
private val _filteredTimeZones = MutableStateFlow(emptyList<UnittoTimeZone>())
|
||||
val addTimeZoneUIState = combine(
|
||||
_query,
|
||||
_filteredTimeZones,
|
||||
_userTime,
|
||||
) { query, filteredTimeZone, userTime ->
|
||||
return@combine AddTimeZoneUIState(
|
||||
query = query,
|
||||
list = filteredTimeZone,
|
||||
userTime = userTime,
|
||||
)
|
||||
}.stateIn(
|
||||
viewModelScope, SharingStarted.WhileSubscribed(5000), AddTimeZoneUIState()
|
||||
)
|
||||
|
||||
fun onQueryChange(query: String) {
|
||||
_query.update { query }
|
||||
filterTimeZones(query)
|
||||
}
|
||||
|
||||
private fun filterTimeZones(query: String = "") = viewModelScope.launch {
|
||||
_filteredTimeZones.update {
|
||||
timezonesRepository.filterAllTimeZones(query)
|
||||
}
|
||||
}
|
||||
|
||||
fun addToFavorites(timeZone: UnittoTimeZone) = viewModelScope.launch(Dispatchers.IO) {
|
||||
timezonesRepository.addToFavorites(timeZone)
|
||||
}
|
||||
|
||||
fun setTime(time: ZonedDateTime) = viewModelScope.launch(Dispatchers.Default) {
|
||||
_userTime.update { time }
|
||||
}
|
||||
|
||||
init {
|
||||
// TODO Maybe only when actually needed?
|
||||
filterTimeZones()
|
||||
}
|
||||
}
|
@ -18,10 +18,364 @@
|
||||
|
||||
package com.sadellie.unitto.timezone
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.SizeTransform
|
||||
import androidx.compose.animation.animateColor
|
||||
import androidx.compose.animation.core.animateDp
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.AnchoredDraggableState
|
||||
import androidx.compose.foundation.gestures.DraggableAnchors
|
||||
import androidx.compose.foundation.gestures.animateTo
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.outlined.History
|
||||
import androidx.compose.material3.FabPosition
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LargeFloatingActionButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.MenuButton
|
||||
import com.sadellie.unitto.core.ui.common.SettingsButton
|
||||
import com.sadellie.unitto.core.ui.common.TimePickerDialog
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithTopBar
|
||||
import com.sadellie.unitto.core.ui.common.squashable
|
||||
import com.sadellie.unitto.core.ui.datetime.formatDayMonthYear
|
||||
import com.sadellie.unitto.core.ui.datetime.formatLocal
|
||||
import com.sadellie.unitto.core.ui.datetime.formatTimeZoneOffset
|
||||
import com.sadellie.unitto.core.ui.theme.AppTypography
|
||||
import com.sadellie.unitto.core.ui.theme.DarkThemeColors
|
||||
import com.sadellie.unitto.core.ui.theme.LightThemeColors
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import com.sadellie.unitto.timezone.components.TimeZoneListItem
|
||||
import io.github.sadellie.themmo.Themmo
|
||||
import io.github.sadellie.themmo.rememberThemmoController
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import org.burnoutcrew.reorderable.ReorderableItem
|
||||
import org.burnoutcrew.reorderable.detectReorderAfterLongPress
|
||||
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
|
||||
import org.burnoutcrew.reorderable.reorderable
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
@Composable
|
||||
internal fun TimeZoneRoute() {}
|
||||
internal fun TimeZoneRoute(
|
||||
viewModel: TimeZoneViewModel = hiltViewModel(),
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
navigateToAddTimeZone: (ZonedDateTime?) -> Unit,
|
||||
) {
|
||||
val uiState = viewModel.timeZoneUIState.collectAsStateWithLifecycle()
|
||||
|
||||
TimeZoneScreen(
|
||||
uiState = uiState.value,
|
||||
navigateToMenu = navigateToMenu,
|
||||
navigateToSettings = navigateToSettings,
|
||||
navigateToAddTimeZone = {
|
||||
navigateToAddTimeZone(
|
||||
if (uiState.value.updateTime) null
|
||||
else uiState.value.userTime
|
||||
)
|
||||
},
|
||||
onDragEnd = viewModel::onDragEnd,
|
||||
onDelete = viewModel::onDelete,
|
||||
setSelectedTime = viewModel::setCustomTime,
|
||||
setCurrentTime = viewModel::setCurrentTime,
|
||||
resetTime = viewModel::resetTime,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TimeZoneScreen() {}
|
||||
private fun TimeZoneScreen(
|
||||
uiState: TimeZoneUIState,
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
navigateToAddTimeZone: () -> Unit,
|
||||
onDragEnd: (String, String) -> Unit,
|
||||
onDelete: (UnittoTimeZone) -> Unit,
|
||||
setSelectedTime: (ZonedDateTime) -> Unit,
|
||||
setCurrentTime: () -> Unit,
|
||||
resetTime: () -> Unit,
|
||||
) {
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
|
||||
LaunchedEffect(uiState.updateTime) {
|
||||
while (uiState.updateTime and isActive) {
|
||||
setCurrentTime()
|
||||
delay(1000)
|
||||
}
|
||||
}
|
||||
|
||||
val copiedList = rememberUpdatedState(newValue = uiState.list) as MutableState
|
||||
val state = rememberReorderableLazyListState(
|
||||
onMove = onMove@{ from, to ->
|
||||
// -1 because we use fake item. It fixes animation for the first item in list
|
||||
copiedList.value = copiedList.value
|
||||
.toMutableList()
|
||||
.apply {
|
||||
add(to.index - 1, removeAt(from.index - 1))
|
||||
}
|
||||
onDragEnd(from.key as String, to.key as String)
|
||||
},
|
||||
canDragOver = { draggedOver, _ ->
|
||||
// Don't allow dragging over fake item
|
||||
draggedOver.index > 0
|
||||
}
|
||||
)
|
||||
// TODO Unswipe on dragging
|
||||
var swiped by remember<MutableState<UnittoTimeZone?>> { mutableStateOf(null) }
|
||||
var showTimeSelector by rememberSaveable { mutableStateOf(false) }
|
||||
val maxDrag = -with(LocalDensity.current) { 80.dp.toPx() }
|
||||
|
||||
UnittoScreenWithTopBar(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
title = { Text(stringResource(R.string.time_zone_screen)) },
|
||||
navigationIcon = { MenuButton(navigateToMenu) },
|
||||
actions = { SettingsButton(navigateToSettings) },
|
||||
floatingActionButton = {
|
||||
LargeFloatingActionButton(navigateToAddTimeZone) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Add,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(FloatingActionButtonDefaults.LargeIconSize),
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButtonPosition = FabPosition.Center,
|
||||
scrollBehavior = scrollBehavior,
|
||||
|
||||
) { paddingValues ->
|
||||
|
||||
LazyColumn(
|
||||
state = state.listState,
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.fillMaxHeight()
|
||||
.reorderable(state)
|
||||
.detectReorderAfterLongPress(state),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
contentPadding = PaddingValues(bottom = 124.dp)
|
||||
) {
|
||||
// This is a fake item. First item in list can not animated, so we do this magic fuckery
|
||||
item {
|
||||
UserTimeZone(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
userTime = uiState.userTime,
|
||||
onClick = { showTimeSelector = true },
|
||||
onResetClick = resetTime,
|
||||
showReset = !uiState.updateTime,
|
||||
)
|
||||
}
|
||||
items(copiedList.value, { it.id }) { item ->
|
||||
ReorderableItem(state, key = item.id) { isDragging ->
|
||||
val transition = updateTransition(isDragging, label = "draggedTransition")
|
||||
val background by transition.animateColor(label = "background") {
|
||||
if (it) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.secondaryContainer
|
||||
}
|
||||
val itemPadding by transition.animateDp(label = "itemPadding") {
|
||||
if (it) 32.dp else 16.dp
|
||||
}
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val draggableState = rememberDraggableTimeZone(maxDrag) { swiped = item }
|
||||
|
||||
LaunchedEffect(swiped) {
|
||||
if (swiped != item) scope.launch {
|
||||
draggableState.animateTo(false)
|
||||
}
|
||||
}
|
||||
|
||||
TimeZoneListItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = itemPadding),
|
||||
timeZone = item,
|
||||
currentTime = uiState.userTime,
|
||||
onDelete = onDelete,
|
||||
color = background,
|
||||
onSwipe = {},
|
||||
draggableState = draggableState,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showTimeSelector) {
|
||||
TimePickerDialog(
|
||||
hour = uiState.userTime.hour,
|
||||
minute = uiState.userTime.minute,
|
||||
onConfirm = { hour, minute ->
|
||||
setSelectedTime(
|
||||
uiState.userTime
|
||||
.withHour(hour)
|
||||
.withMinute(minute)
|
||||
)
|
||||
showTimeSelector = false
|
||||
},
|
||||
onDismiss = { showTimeSelector = false }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UserTimeZone(
|
||||
modifier: Modifier,
|
||||
userTime: ZonedDateTime,
|
||||
onClick: () -> Unit,
|
||||
onResetClick: () -> Unit,
|
||||
showReset: Boolean,
|
||||
) {
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.squashable(
|
||||
onClick = onClick,
|
||||
onLongClick = onResetClick,
|
||||
cornerRadiusRange = 8.dp..32.dp,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
.background(MaterialTheme.colorScheme.tertiaryContainer)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = userTime.formatTimeZoneOffset(),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer
|
||||
)
|
||||
// TODO Swipe to increase, touch to set
|
||||
AnimatedContent(
|
||||
targetState = userTime.formatLocal(),
|
||||
label = "user time change",
|
||||
transitionSpec = {
|
||||
slideInVertically { height -> height } + fadeIn() togetherWith
|
||||
slideOutVertically { height -> -height } + fadeOut() using
|
||||
SizeTransform()
|
||||
}
|
||||
) { time ->
|
||||
Text(
|
||||
text = time,
|
||||
style = MaterialTheme.typography.displayLarge,
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = userTime.formatDayMonthYear(),
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = showReset,
|
||||
enter = scaleIn() + fadeIn(),
|
||||
exit = scaleOut() + fadeOut(),
|
||||
) {
|
||||
IconButton(onResetClick) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.History,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberDraggableTimeZone(
|
||||
maxDrag: Float,
|
||||
onSwipe: () -> Unit,
|
||||
) = remember {
|
||||
AnchoredDraggableState(
|
||||
initialValue = false,
|
||||
anchors = DraggableAnchors {
|
||||
false at 0f
|
||||
true at maxDrag
|
||||
},
|
||||
positionalThreshold = { it * 0.5f },
|
||||
velocityThreshold = { maxDrag },
|
||||
animationSpec = tween(),
|
||||
confirmValueChange = {
|
||||
onSwipe()
|
||||
true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewTimeZoneScreen() {
|
||||
Themmo(
|
||||
themmoController = rememberThemmoController(
|
||||
lightColorScheme = LightThemeColors,
|
||||
darkColorScheme = DarkThemeColors,
|
||||
),
|
||||
typography = AppTypography,
|
||||
) {
|
||||
TimeZoneScreen(
|
||||
uiState = TimeZoneUIState(
|
||||
list = List(50) {
|
||||
UnittoTimeZone(
|
||||
id = "timezone $it",
|
||||
nameRes = "Time zone $it",
|
||||
)
|
||||
}
|
||||
),
|
||||
navigateToMenu = {},
|
||||
navigateToSettings = {},
|
||||
navigateToAddTimeZone = {},
|
||||
onDragEnd = { _, _ -> },
|
||||
onDelete = {},
|
||||
setSelectedTime = {},
|
||||
setCurrentTime = {},
|
||||
resetTime = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.timezone
|
||||
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
data class TimeZoneUIState(
|
||||
val list: List<UnittoTimeZone> = emptyList(),
|
||||
val userTime: ZonedDateTime = ZonedDateTime.now(),
|
||||
val updateTime: Boolean = true,
|
||||
)
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.timezone
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import com.sadellie.unitto.data.timezone.TimeZonesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.ZonedDateTime
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class TimeZoneViewModel @Inject constructor(
|
||||
private val timezonesRepository: TimeZonesRepository
|
||||
): ViewModel() {
|
||||
|
||||
private val _userTime = MutableStateFlow(ZonedDateTime.now())
|
||||
private val _updateTime = MutableStateFlow(true)
|
||||
|
||||
val timeZoneUIState = combine(
|
||||
_userTime,
|
||||
_updateTime,
|
||||
timezonesRepository.favoriteTimeZones
|
||||
) { userTime, updateTime, favorites ->
|
||||
return@combine TimeZoneUIState(
|
||||
list = favorites,
|
||||
userTime = userTime,
|
||||
updateTime = updateTime
|
||||
)
|
||||
}.stateIn(
|
||||
viewModelScope, SharingStarted.WhileSubscribed(5000), TimeZoneUIState()
|
||||
)
|
||||
|
||||
fun onDragEnd(from: String, to: String) = viewModelScope.launch {
|
||||
timezonesRepository.swapTimeZones(from, to)
|
||||
}
|
||||
|
||||
fun onDelete(timeZone: UnittoTimeZone) = viewModelScope.launch {
|
||||
timezonesRepository.delete(timeZone)
|
||||
}
|
||||
|
||||
fun setCustomTime(time: ZonedDateTime) = viewModelScope.launch(Dispatchers.Default) {
|
||||
_updateTime.update { false }
|
||||
_userTime.update { time }
|
||||
}
|
||||
|
||||
fun resetTime() = viewModelScope.launch(Dispatchers.Default) {
|
||||
_updateTime.update { true }
|
||||
}
|
||||
|
||||
fun setCurrentTime() = viewModelScope.launch(Dispatchers.Default) {
|
||||
_userTime.update { ZonedDateTime.now() }
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.timezone.components
|
||||
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sadellie.unitto.core.ui.datetime.formatLocal
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
@Composable
|
||||
fun SelectableTimeZone(
|
||||
modifier: Modifier = Modifier,
|
||||
timeZone: UnittoTimeZone,
|
||||
currentTime: ZonedDateTime?,
|
||||
) {
|
||||
val offsetTime: ZonedDateTime? by remember(currentTime) {
|
||||
mutableStateOf(currentTime?.let { timeZone.offsetFrom(it) })
|
||||
}
|
||||
|
||||
ListItem(
|
||||
modifier = modifier,
|
||||
headlineContent = {
|
||||
Text(text = timeZone.nameRes)
|
||||
},
|
||||
supportingContent = {
|
||||
Text(text = timeZone.id)
|
||||
},
|
||||
trailingContent = {
|
||||
Text(text = offsetTime?.formatLocal() ?: "", style = MaterialTheme.typography.headlineSmall)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFFFFFFF)
|
||||
@Composable
|
||||
fun PreviewSelectableTimeZone() {
|
||||
SelectableTimeZone(
|
||||
timeZone = UnittoTimeZone(
|
||||
id = "text",
|
||||
nameRes = "Time zone"
|
||||
),
|
||||
modifier = Modifier.width(440.dp),
|
||||
currentTime = ZonedDateTime.now(),
|
||||
)
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.timezone.components
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.SizeTransform
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.AnchoredDraggableState
|
||||
import androidx.compose.foundation.gestures.DraggableAnchors
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.anchoredDraggable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sadellie.unitto.core.ui.datetime.formatLocal
|
||||
import com.sadellie.unitto.core.ui.datetime.formatOffset
|
||||
import com.sadellie.unitto.data.model.UnittoTimeZone
|
||||
import java.time.ZonedDateTime
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
fun TimeZoneListItem(
|
||||
modifier: Modifier,
|
||||
timeZone: UnittoTimeZone,
|
||||
currentTime: ZonedDateTime,
|
||||
onClick: () -> Unit = {},
|
||||
onDelete: (UnittoTimeZone) -> Unit = {},
|
||||
color: Color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
onSwipe: (UnittoTimeZone) -> Unit = {},
|
||||
draggableState: AnchoredDraggableState<Boolean>,
|
||||
) {
|
||||
val offsetTime by remember(currentTime) { mutableStateOf(timeZone.offsetFrom(currentTime)) }
|
||||
val offsetTimeFormatted = offsetTime.formatOffset(currentTime)
|
||||
|
||||
// TODO Animate deleting
|
||||
Box(
|
||||
modifier = modifier
|
||||
.heightIn(72.dp)
|
||||
.clip(RoundedCornerShape(25))
|
||||
.anchoredDraggable(
|
||||
state = draggableState,
|
||||
orientation = Orientation.Horizontal,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
// TODO Reveal animation
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clickable { onDelete(timeZone) }
|
||||
.background(MaterialTheme.colorScheme.errorContainer)
|
||||
.matchParentSize()
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(horizontal = 24.dp)
|
||||
.size(32.dp),
|
||||
imageVector = Icons.Outlined.Delete,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onErrorContainer
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.offset {
|
||||
IntOffset(
|
||||
y = 0,
|
||||
x = draggableState
|
||||
.requireOffset()
|
||||
.roundToInt()
|
||||
)
|
||||
}
|
||||
.clickable {}
|
||||
.background(color)
|
||||
.matchParentSize()
|
||||
.padding(12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
// TODO Name
|
||||
Text(
|
||||
text = timeZone.nameRes,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = offsetTimeFormatted != null,
|
||||
label = "Nullable offset"
|
||||
) {
|
||||
Text(offsetTimeFormatted ?: "", style = MaterialTheme.typography.bodyMedium)
|
||||
}
|
||||
}
|
||||
Column {
|
||||
// Time
|
||||
AnimatedContent(
|
||||
targetState = offsetTime.formatLocal(),
|
||||
label = "Time change",
|
||||
transitionSpec = {
|
||||
fadeIn() togetherWith fadeOut() using (SizeTransform(clip = false))
|
||||
}
|
||||
) { time ->
|
||||
Text(time, style = MaterialTheme.typography.headlineMedium)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFFFFFFF)
|
||||
@Composable
|
||||
fun PreviewTimeZoneListItem() {
|
||||
|
||||
val maxDrag = -with(LocalDensity.current) { 80.dp.toPx() }
|
||||
val draggableState = remember {
|
||||
AnchoredDraggableState(
|
||||
initialValue = false,
|
||||
anchors = DraggableAnchors {
|
||||
false at 0f
|
||||
true at maxDrag
|
||||
},
|
||||
positionalThreshold = { 0f },
|
||||
velocityThreshold = { 0f },
|
||||
animationSpec = tween(),
|
||||
confirmValueChange = { true }
|
||||
)
|
||||
}
|
||||
|
||||
TimeZoneListItem(
|
||||
modifier = Modifier,
|
||||
timeZone = UnittoTimeZone(
|
||||
id = "timezone",
|
||||
offsetSeconds = -10800,
|
||||
nameRes = "Time zone"
|
||||
),
|
||||
currentTime = ZonedDateTime.now(),
|
||||
draggableState = draggableState
|
||||
)
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.timezone.components
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardActionScope
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.outlined.Clear
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarColors
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
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.draw.alpha
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
|
||||
@Composable
|
||||
fun UnittoSearchBar(
|
||||
modifier: Modifier = Modifier,
|
||||
query: String,
|
||||
onQueryChange: (String) -> Unit,
|
||||
navigateUp: () -> Unit,
|
||||
title: String,
|
||||
searchActions: @Composable (RowScope.() -> Unit) = {},
|
||||
noSearchActions: @Composable (RowScope.() -> Unit) = {},
|
||||
placeholder: String,
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors()
|
||||
) {
|
||||
var showSearch by remember { mutableStateOf(false) }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
fun stagedNavigateUp() {
|
||||
if (showSearch) {
|
||||
// Search text field is open, need to close it and clear search query
|
||||
showSearch = false
|
||||
// focusManager.clearFocus()
|
||||
onQueryChange("")
|
||||
} else {
|
||||
// No search text field is shown, can go back as usual
|
||||
navigateUp()
|
||||
}
|
||||
}
|
||||
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
title = {
|
||||
Crossfade(showSearch) { _showSearch ->
|
||||
if (_showSearch) {
|
||||
LaunchedEffect(Unit) { focusRequester.requestFocus() }
|
||||
|
||||
SearchTextField(
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester),
|
||||
value = query,
|
||||
placeholder = placeholder,
|
||||
onValueChange = onQueryChange,
|
||||
onSearch = {}
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = title,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
NavigateUpButton { stagedNavigateUp() }
|
||||
},
|
||||
actions = {
|
||||
Crossfade(showSearch) { _showSearch ->
|
||||
if (_showSearch) {
|
||||
ClearButton(visible = query.isNotEmpty()) { onQueryChange("") }
|
||||
searchActions()
|
||||
} else {
|
||||
SearchButton { showSearch = true }
|
||||
noSearchActions()
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
colors = colors,
|
||||
)
|
||||
|
||||
BackHandler { stagedNavigateUp() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SearchTextField(
|
||||
modifier: Modifier,
|
||||
value: String,
|
||||
placeholder: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
onSearch: KeyboardActionScope.() -> Unit
|
||||
) {
|
||||
BasicTextField(
|
||||
modifier = modifier,
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
singleLine = true,
|
||||
textStyle = MaterialTheme.typography.titleLarge.copy(color = MaterialTheme.colorScheme.onSurface),
|
||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurface),
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
|
||||
keyboardActions = KeyboardActions(onSearch = onSearch),
|
||||
decorationBox = { innerTextField ->
|
||||
innerTextField()
|
||||
// Showing placeholder only when there is query is empty
|
||||
value.ifEmpty {
|
||||
Text(
|
||||
modifier = Modifier.alpha(0.7f),
|
||||
text = placeholder,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SearchButton(
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
IconButton(onClick) {
|
||||
Icon(
|
||||
Icons.Default.Search,
|
||||
contentDescription = stringResource(R.string.search_button_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ClearButton(
|
||||
visible: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
IconButton(onClick = onClick) {
|
||||
AnimatedVisibility(
|
||||
visible = visible,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut()
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Clear,
|
||||
contentDescription = stringResource(R.string.clear_input_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -18,24 +18,72 @@
|
||||
|
||||
package com.sadellie.unitto.timezone.navigation
|
||||
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.navigation
|
||||
import androidx.navigation.navArgument
|
||||
import androidx.navigation.navDeepLink
|
||||
import com.sadellie.unitto.core.base.TopLevelDestinations
|
||||
import com.sadellie.unitto.timezone.AddTimeZoneRoute
|
||||
import com.sadellie.unitto.timezone.TimeZoneRoute
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
private val timeZoneRoute: String by lazy { TopLevelDestinations.TimeZone.route }
|
||||
private val timeZoneGraph: String by lazy { TopLevelDestinations.TimeZone.route }
|
||||
internal const val timeZoneRoute = "time_zone_route"
|
||||
internal const val addTimeZoneRoute = "add_time_zone_route"
|
||||
internal const val userTimeArg = "userTime"
|
||||
|
||||
fun NavController.navigateToAddTimeZone(
|
||||
userTime: ZonedDateTime?
|
||||
) {
|
||||
val formattedTime = userTime
|
||||
?.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)
|
||||
?.replace("/", "|") // this is so wrong
|
||||
|
||||
navigate("$addTimeZoneRoute/$formattedTime")
|
||||
}
|
||||
|
||||
fun NavGraphBuilder.timeZoneScreen(
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit
|
||||
navigateToSettings: () -> Unit,
|
||||
navController: NavHostController,
|
||||
) {
|
||||
composable(
|
||||
route = timeZoneRoute,
|
||||
deepLinks = listOf(
|
||||
navDeepLink { uriPattern = "app://com.sadellie.unitto/$timeZoneRoute" }
|
||||
)
|
||||
navigation(
|
||||
startDestination = timeZoneRoute,
|
||||
route = timeZoneGraph,
|
||||
deepLinks = listOf(navDeepLink { uriPattern = "app://com.sadellie.unitto/$timeZoneRoute" })
|
||||
) {
|
||||
TimeZoneRoute()
|
||||
composable(timeZoneRoute) {
|
||||
TimeZoneRoute(
|
||||
navigateToMenu = navigateToMenu,
|
||||
navigateToSettings = navigateToSettings,
|
||||
navigateToAddTimeZone = navController::navigateToAddTimeZone
|
||||
)
|
||||
}
|
||||
|
||||
composable(
|
||||
route = "$addTimeZoneRoute/{$userTimeArg}",
|
||||
arguments = listOf(
|
||||
navArgument(userTimeArg) {
|
||||
defaultValue = null
|
||||
nullable = true
|
||||
type = NavType.StringType
|
||||
}
|
||||
)
|
||||
) { stackEntry ->
|
||||
val userTime = stackEntry.arguments
|
||||
?.getString(userTimeArg)
|
||||
?.replace("|", "/") // war crime, don't look
|
||||
?.let { ZonedDateTime.parse(it, DateTimeFormatter.ISO_ZONED_DATE_TIME) }
|
||||
|
||||
AddTimeZoneRoute(
|
||||
navigateUp = navController::navigateUp,
|
||||
userTime = userTime
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,3 +35,4 @@ include(":data:database")
|
||||
include(":data:model")
|
||||
include(":data:common")
|
||||
include(":data:evaluatto")
|
||||
include(":data:timezone")
|
||||
|
Loading…
x
Reference in New Issue
Block a user