mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
Tools screen
Added basic tools screen Added epoch converter screen Little refactor to avoid code duplication
This commit is contained in:
parent
541e13908b
commit
0bf3ac6155
@ -110,6 +110,8 @@ dependencies {
|
|||||||
implementation(project(mapOf("path" to ":feature:converter")))
|
implementation(project(mapOf("path" to ":feature:converter")))
|
||||||
implementation(project(mapOf("path" to ":feature:settings")))
|
implementation(project(mapOf("path" to ":feature:settings")))
|
||||||
implementation(project(mapOf("path" to ":feature:unitslist")))
|
implementation(project(mapOf("path" to ":feature:unitslist")))
|
||||||
|
implementation(project(mapOf("path" to ":feature:tools")))
|
||||||
|
implementation(project(mapOf("path" to ":feature:epoch")))
|
||||||
implementation(project(mapOf("path" to ":data")))
|
implementation(project(mapOf("path" to ":data")))
|
||||||
implementation(project(mapOf("path" to ":core:base")))
|
implementation(project(mapOf("path" to ":core:base")))
|
||||||
implementation(project(mapOf("path" to ":core:ui")))
|
implementation(project(mapOf("path" to ":core:ui")))
|
||||||
|
@ -24,10 +24,14 @@ import androidx.navigation.compose.NavHost
|
|||||||
import com.sadellie.unitto.feature.converter.MainViewModel
|
import com.sadellie.unitto.feature.converter.MainViewModel
|
||||||
import com.sadellie.unitto.feature.converter.navigation.converterRoute
|
import com.sadellie.unitto.feature.converter.navigation.converterRoute
|
||||||
import com.sadellie.unitto.feature.converter.navigation.converterScreen
|
import com.sadellie.unitto.feature.converter.navigation.converterScreen
|
||||||
|
import com.sadellie.unitto.feature.epoch.navigation.epochScreen
|
||||||
|
import com.sadellie.unitto.feature.epoch.navigation.navigateToEpoch
|
||||||
import com.sadellie.unitto.feature.settings.SettingsViewModel
|
import com.sadellie.unitto.feature.settings.SettingsViewModel
|
||||||
import com.sadellie.unitto.feature.settings.navigation.navigateToSettings
|
import com.sadellie.unitto.feature.settings.navigation.navigateToSettings
|
||||||
import com.sadellie.unitto.feature.settings.navigation.navigateToUnitGroups
|
import com.sadellie.unitto.feature.settings.navigation.navigateToUnitGroups
|
||||||
import com.sadellie.unitto.feature.settings.navigation.settingGraph
|
import com.sadellie.unitto.feature.settings.navigation.settingGraph
|
||||||
|
import com.sadellie.unitto.feature.tools.navigation.navigateToTools
|
||||||
|
import com.sadellie.unitto.feature.tools.navigation.toolsScreen
|
||||||
import com.sadellie.unitto.feature.unitslist.SecondViewModel
|
import com.sadellie.unitto.feature.unitslist.SecondViewModel
|
||||||
import com.sadellie.unitto.feature.unitslist.navigation.leftScreen
|
import com.sadellie.unitto.feature.unitslist.navigation.leftScreen
|
||||||
import com.sadellie.unitto.feature.unitslist.navigation.navigateToLeftSide
|
import com.sadellie.unitto.feature.unitslist.navigation.navigateToLeftSide
|
||||||
@ -53,6 +57,7 @@ fun UnittoNavigation(
|
|||||||
navController.navigateToRightSide(unitFrom, unitTo, input)
|
navController.navigateToRightSide(unitFrom, unitTo, input)
|
||||||
},
|
},
|
||||||
navigateToSettings = { navController.navigateToSettings() },
|
navigateToSettings = { navController.navigateToSettings() },
|
||||||
|
navigateToTools = { navController.navigateToTools() },
|
||||||
viewModel = mainViewModel
|
viewModel = mainViewModel
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -75,5 +80,14 @@ fun UnittoNavigation(
|
|||||||
themmoController = themmoController,
|
themmoController = themmoController,
|
||||||
navController = navController
|
navController = navController
|
||||||
)
|
)
|
||||||
|
|
||||||
|
toolsScreen(
|
||||||
|
navigateUpAction = navController::navigateUp,
|
||||||
|
navigateToEpoch = navController::navigateToEpoch
|
||||||
|
)
|
||||||
|
|
||||||
|
epochScreen(
|
||||||
|
navigateUpAction = navController::navigateUp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,17 @@
|
|||||||
|
|
||||||
import org.gradle.api.Plugin
|
import org.gradle.api.Plugin
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||||
import org.gradle.kotlin.dsl.dependencies
|
import org.gradle.kotlin.dsl.dependencies
|
||||||
|
import org.gradle.kotlin.dsl.getByType
|
||||||
|
|
||||||
class UnittoLibraryFeaturePlugin : Plugin<Project> {
|
class UnittoLibraryFeaturePlugin : Plugin<Project> {
|
||||||
override fun apply(target: Project) {
|
override fun apply(target: Project) {
|
||||||
with(target) {
|
with(target) {
|
||||||
|
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||||
dependencies {
|
dependencies {
|
||||||
|
"implementation"(libs.findLibrary("androidx.navigation").get())
|
||||||
|
|
||||||
"implementation"(project(mapOf("path" to ":data")))
|
"implementation"(project(mapOf("path" to ":data")))
|
||||||
"implementation"(project(mapOf("path" to ":core:base")))
|
"implementation"(project(mapOf("path" to ":core:base")))
|
||||||
"implementation"(project(mapOf("path" to ":core:ui")))
|
"implementation"(project(mapOf("path" to ":core:ui")))
|
||||||
|
@ -992,6 +992,7 @@
|
|||||||
<string name="units_screen_from">Convert from</string>
|
<string name="units_screen_from">Convert from</string>
|
||||||
<string name="units_screen_to">Convert to</string>
|
<string name="units_screen_to">Convert to</string>
|
||||||
<string name="settings_screen">Settings</string>
|
<string name="settings_screen">Settings</string>
|
||||||
|
<string name="tools_screen">Tools</string>
|
||||||
|
|
||||||
<!--Settings items-->
|
<!--Settings items-->
|
||||||
<string name="theme_setting">Themes</string>
|
<string name="theme_setting">Themes</string>
|
||||||
@ -1014,6 +1015,10 @@
|
|||||||
<string name="formatting_settings_group">Formatting</string>
|
<string name="formatting_settings_group">Formatting</string>
|
||||||
<string name="additional_settings_group">Additional</string>
|
<string name="additional_settings_group">Additional</string>
|
||||||
|
|
||||||
|
<!--Tools-->
|
||||||
|
<string name="epoch_converter">Epoch converter</string>
|
||||||
|
<string name="epoch_converter_support">Convert Unix timestamp</string>
|
||||||
|
|
||||||
<!--Precision-->
|
<!--Precision-->
|
||||||
<string name="precision_setting_support">Number of decimal places</string>
|
<string name="precision_setting_support">Number of decimal places</string>
|
||||||
<string name="precision_setting_info">Converted values may have a precision higher than the preferred one.</string>
|
<string name="precision_setting_info">Converted values may have a precision higher than the preferred one.</string>
|
||||||
@ -1092,4 +1097,8 @@
|
|||||||
<string name="about_unitto_support">Learn about the app</string>
|
<string name="about_unitto_support">Learn about the app</string>
|
||||||
<string name="unit_groups_support">Disable and rearrange units</string>
|
<string name="unit_groups_support">Disable and rearrange units</string>
|
||||||
|
|
||||||
|
<!--Epoch-->
|
||||||
|
<string name="year_short">y</string>
|
||||||
|
<string name="month_short">m</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Unitto is a unit converter for Android
|
* Unitto is a unit converter for Android
|
||||||
* Copyright (c) 2022-2022 Elshan Agaev
|
* Copyright (c) 2022-2023 Elshan Agaev
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.sadellie.unitto.feature.converter.components
|
package com.sadellie.unitto.core.ui.common
|
||||||
|
|
||||||
import android.view.HapticFeedbackConstants
|
import android.view.HapticFeedbackConstants
|
||||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
@ -36,7 +36,6 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.sadellie.unitto.core.ui.common.UnittoButton
|
|
||||||
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleTitleLarge
|
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleTitleLarge
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +50,7 @@ import com.sadellie.unitto.core.ui.theme.NumbersTextStyleTitleLarge
|
|||||||
* @param onClick Action to perform when clicking this button.
|
* @param onClick Action to perform when clicking this button.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
internal fun KeyboardButton(
|
fun KeyboardButton(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
digit: String,
|
digit: String,
|
||||||
allowVibration: Boolean,
|
allowVibration: Boolean,
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Unitto is a unit converter for Android
|
||||||
|
* Copyright (c) 2022 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.common
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commonly used TopAppBar with scroll behavior.
|
||||||
|
*
|
||||||
|
* @param title Text that is displayed in top bar.
|
||||||
|
* @param navigateUpAction Action when user click arrow button at the top.
|
||||||
|
* @param content Content that can be scrolled. Don't forget to use padding values.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun UnittoTopAppBar(
|
||||||
|
title: String,
|
||||||
|
navigateUpAction: () -> Unit,
|
||||||
|
content: @Composable (PaddingValues) -> Unit
|
||||||
|
) {
|
||||||
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
|
||||||
|
rememberTopAppBarState()
|
||||||
|
)
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier
|
||||||
|
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = {
|
||||||
|
Text(text = title)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
NavigateUpButton { navigateUpAction() }
|
||||||
|
},
|
||||||
|
scrollBehavior = scrollBehavior
|
||||||
|
)
|
||||||
|
},
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
@ -21,6 +21,7 @@ package com.sadellie.unitto.feature.converter
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
import androidx.compose.material.icons.outlined.MoreVert
|
||||||
|
import androidx.compose.material.icons.outlined.Science
|
||||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
import androidx.compose.material3.CenterAlignedTopAppBar
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@ -37,8 +38,8 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.sadellie.unitto.core.ui.common.AnimatedTopBarText
|
|
||||||
import com.sadellie.unitto.core.ui.R
|
import com.sadellie.unitto.core.ui.R
|
||||||
|
import com.sadellie.unitto.core.ui.common.AnimatedTopBarText
|
||||||
import com.sadellie.unitto.feature.converter.components.Keyboard
|
import com.sadellie.unitto.feature.converter.components.Keyboard
|
||||||
import com.sadellie.unitto.feature.converter.components.PortraitLandscape
|
import com.sadellie.unitto.feature.converter.components.PortraitLandscape
|
||||||
import com.sadellie.unitto.feature.converter.components.TopScreenPart
|
import com.sadellie.unitto.feature.converter.components.TopScreenPart
|
||||||
@ -49,6 +50,7 @@ internal fun MainScreen(
|
|||||||
navigateToLeftScreen: (String) -> Unit,
|
navigateToLeftScreen: (String) -> Unit,
|
||||||
navigateToRightScreen: (unitFrom: String, unitTo: String, input: String) -> Unit,
|
navigateToRightScreen: (unitFrom: String, unitTo: String, input: String) -> Unit,
|
||||||
navigateToSettings: () -> Unit,
|
navigateToSettings: () -> Unit,
|
||||||
|
navigateToTools: () -> Unit,
|
||||||
viewModel: MainViewModel = viewModel()
|
viewModel: MainViewModel = viewModel()
|
||||||
) {
|
) {
|
||||||
var launched: Boolean by rememberSaveable { mutableStateOf(false) }
|
var launched: Boolean by rememberSaveable { mutableStateOf(false) }
|
||||||
@ -61,6 +63,14 @@ internal fun MainScreen(
|
|||||||
CenterAlignedTopAppBar(
|
CenterAlignedTopAppBar(
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
title = { AnimatedTopBarText(launched) },
|
title = { AnimatedTopBarText(launched) },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = navigateToTools) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Science,
|
||||||
|
contentDescription = stringResource(R.string.open_settings_description)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
actions = {
|
actions = {
|
||||||
IconButton(onClick = navigateToSettings) {
|
IconButton(onClick = navigateToSettings) {
|
||||||
Icon(
|
Icon(
|
||||||
|
@ -56,6 +56,7 @@ import com.sadellie.unitto.core.base.KEY_PLUS
|
|||||||
import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET
|
import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET
|
||||||
import com.sadellie.unitto.core.base.KEY_SQRT
|
import com.sadellie.unitto.core.base.KEY_SQRT
|
||||||
import com.sadellie.unitto.core.ui.Formatter
|
import com.sadellie.unitto.core.ui.Formatter
|
||||||
|
import com.sadellie.unitto.core.ui.common.KeyboardButton
|
||||||
import com.sadellie.unitto.feature.converter.ConverterMode
|
import com.sadellie.unitto.feature.converter.ConverterMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +29,7 @@ fun NavGraphBuilder.converterScreen(
|
|||||||
navigateToLeftScreen: (String) -> Unit,
|
navigateToLeftScreen: (String) -> Unit,
|
||||||
navigateToRightScreen: (unitFrom: String, unitTo: String, input: String) -> Unit,
|
navigateToRightScreen: (unitFrom: String, unitTo: String, input: String) -> Unit,
|
||||||
navigateToSettings: () -> Unit,
|
navigateToSettings: () -> Unit,
|
||||||
|
navigateToTools: () -> Unit,
|
||||||
viewModel: MainViewModel
|
viewModel: MainViewModel
|
||||||
) {
|
) {
|
||||||
composable(converterRoute) {
|
composable(converterRoute) {
|
||||||
@ -36,6 +37,7 @@ fun NavGraphBuilder.converterScreen(
|
|||||||
navigateToLeftScreen = navigateToLeftScreen,
|
navigateToLeftScreen = navigateToLeftScreen,
|
||||||
navigateToRightScreen = navigateToRightScreen,
|
navigateToRightScreen = navigateToRightScreen,
|
||||||
navigateToSettings = navigateToSettings,
|
navigateToSettings = navigateToSettings,
|
||||||
|
navigateToTools = navigateToTools,
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
1
feature/epoch/.gitignore
vendored
Normal file
1
feature/epoch/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
28
feature/epoch/build.gradle.kts
Normal file
28
feature/epoch/build.gradle.kts
Normal file
@ -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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("unitto.library")
|
||||||
|
id("unitto.library.compose")
|
||||||
|
id("unitto.library.feature")
|
||||||
|
id("unitto.android.hilt")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.sadellie.unitto.feature.epoch"
|
||||||
|
}
|
0
feature/epoch/consumer-rules.pro
Normal file
0
feature/epoch/consumer-rules.pro
Normal file
4
feature/epoch/src/main/AndroidManifest.xml
Normal file
4
feature/epoch/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* 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.feature.epoch
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.SwapHoriz
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.sadellie.unitto.core.ui.common.UnittoTopAppBar
|
||||||
|
import com.sadellie.unitto.feature.epoch.component.DateTextField
|
||||||
|
import com.sadellie.unitto.feature.epoch.component.EpochKeyboard
|
||||||
|
import com.sadellie.unitto.feature.epoch.component.TopPart
|
||||||
|
import com.sadellie.unitto.feature.epoch.component.UnixTextField
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun EpochRoute(
|
||||||
|
navigateUpAction: () -> Unit,
|
||||||
|
viewModel: EpochViewModel = hiltViewModel()
|
||||||
|
) {
|
||||||
|
val uiState = viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
|
EpochScreen(
|
||||||
|
navigateUpAction = navigateUpAction,
|
||||||
|
uiState = uiState.value,
|
||||||
|
addSymbol = viewModel::addSymbol,
|
||||||
|
deleteSymbol = viewModel::deleteSymbol,
|
||||||
|
swap = viewModel::swap,
|
||||||
|
clearSymbols = viewModel::clearSymbols
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun EpochScreen(
|
||||||
|
navigateUpAction: () -> Unit,
|
||||||
|
uiState: EpochUIState,
|
||||||
|
addSymbol: (String) -> Unit,
|
||||||
|
deleteSymbol: () -> Unit,
|
||||||
|
clearSymbols: () -> Unit,
|
||||||
|
swap: () -> Unit
|
||||||
|
) {
|
||||||
|
UnittoTopAppBar(
|
||||||
|
title = stringResource(R.string.epoch_converter),
|
||||||
|
navigateUpAction = navigateUpAction
|
||||||
|
) { padding ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(padding),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
TopPart(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
.weight(1f),
|
||||||
|
unixToDate = !uiState.dateToUnix,
|
||||||
|
dateField = {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.background)
|
||||||
|
.animateItemPlacement()
|
||||||
|
) {
|
||||||
|
DateTextField(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
date = uiState.dateField
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "date",
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textAlign = TextAlign.End
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unixField = {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.background)
|
||||||
|
.animateItemPlacement()
|
||||||
|
) {
|
||||||
|
UnixTextField(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
unix = uiState.unixField
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "unix",
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textAlign = TextAlign.End
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = swap,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 8.dp),
|
||||||
|
) {
|
||||||
|
Icon(Icons.Default.SwapHoriz, null)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text("SWAP")
|
||||||
|
}
|
||||||
|
|
||||||
|
EpochKeyboard(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
.weight(1f),
|
||||||
|
addSymbol = addSymbol,
|
||||||
|
clearSymbols = clearSymbols,
|
||||||
|
deleteSymbol = deleteSymbol
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* 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.feature.epoch
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
data class EpochUIState(
|
||||||
|
val dateField: String = "",
|
||||||
|
val unixField: String = "",
|
||||||
|
val dateToUnix: Boolean = true
|
||||||
|
)
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class EpochViewModel @Inject constructor() : ViewModel() {
|
||||||
|
|
||||||
|
private val _input: MutableStateFlow<String> = MutableStateFlow("")
|
||||||
|
private val _fromDateToUnix: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||||
|
|
||||||
|
val uiState: StateFlow<EpochUIState> = combine(
|
||||||
|
_input, _fromDateToUnix
|
||||||
|
) { input, fromDateToUnix ->
|
||||||
|
if (fromDateToUnix) {
|
||||||
|
EpochUIState(
|
||||||
|
dateField = input,
|
||||||
|
unixField = convertDateToUnix(input),
|
||||||
|
dateToUnix = fromDateToUnix
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
EpochUIState(
|
||||||
|
unixField = input,
|
||||||
|
dateField = convertUnixToDate(input),
|
||||||
|
dateToUnix = fromDateToUnix
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.stateIn(
|
||||||
|
viewModelScope, SharingStarted.WhileSubscribed(5000L), EpochUIState()
|
||||||
|
)
|
||||||
|
|
||||||
|
fun addSymbol(symbol: String) {
|
||||||
|
val maxSymbols = if (_fromDateToUnix.value) 14 else 10
|
||||||
|
if (_input.value.length < maxSymbols) _input.update { it + symbol }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteSymbol() = _input.update { it.dropLast(1) }
|
||||||
|
|
||||||
|
fun clearSymbols() = _input.update { "" }
|
||||||
|
|
||||||
|
fun swap() = _fromDateToUnix.update {
|
||||||
|
clearSymbols()
|
||||||
|
!it
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertDateToUnix(date: String): String {
|
||||||
|
// Here we add some zeros, so that input is 14 symbols long
|
||||||
|
val inputWithPadding = date.padEnd(14, '0')
|
||||||
|
|
||||||
|
// Now we break input that is 14 symbols into pieces
|
||||||
|
val day = inputWithPadding.substring(0, 2)
|
||||||
|
val month = inputWithPadding.substring(2, 4)
|
||||||
|
val year = inputWithPadding.substring(4, 8)
|
||||||
|
val hour = inputWithPadding.substring(8, 10)
|
||||||
|
val minute = inputWithPadding.substring(10, 12)
|
||||||
|
val second = inputWithPadding.substring(12, 14)
|
||||||
|
|
||||||
|
val cal = Calendar.getInstance()
|
||||||
|
cal.set(
|
||||||
|
year.toIntOrNull() ?: 1970,
|
||||||
|
(month.toIntOrNull() ?: 1) - 1,
|
||||||
|
day.toIntOrNull() ?: 0,
|
||||||
|
hour.toIntOrNull() ?: 0,
|
||||||
|
minute.toIntOrNull() ?: 0,
|
||||||
|
second.toIntOrNull() ?: 0,
|
||||||
|
)
|
||||||
|
return (cal.timeInMillis / 1000).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertUnixToDate(unix: String): String {
|
||||||
|
var date = ""
|
||||||
|
val cal2 = Calendar.getInstance()
|
||||||
|
cal2.clear()
|
||||||
|
cal2.isLenient = true
|
||||||
|
|
||||||
|
// This lets us bypass calendars limits (it uses Int, we want BigDecimal)
|
||||||
|
try {
|
||||||
|
val unixBg = BigDecimal(unix)
|
||||||
|
val division = unixBg.divideAndRemainder(BigDecimal(Int.MAX_VALUE))
|
||||||
|
val intTimes = division.component1()
|
||||||
|
val rem = division.component2()
|
||||||
|
repeat(intTimes.intValueExact()) {
|
||||||
|
cal2.add(Calendar.SECOND, Int.MAX_VALUE)
|
||||||
|
}
|
||||||
|
cal2.add(Calendar.SECOND, rem.intValueExact())
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
date += cal2.get(Calendar.DAY_OF_MONTH).toString().padStart(2, '0')
|
||||||
|
date += (cal2.get(Calendar.MONTH) + 1).toString().padStart(2, '0')
|
||||||
|
// Year is 4 symbols long
|
||||||
|
date += cal2.get(Calendar.YEAR).toString().padStart(4, '0')
|
||||||
|
date += cal2.get(Calendar.HOUR_OF_DAY).toString().padStart(2, '0')
|
||||||
|
date += cal2.get(Calendar.MINUTE).toString().padStart(2, '0')
|
||||||
|
date += cal2.get(Calendar.SECOND).toString().padStart(2, '0')
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* 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.feature.epoch.component
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.SizeTransform
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.compose.animation.with
|
||||||
|
import androidx.compose.foundation.horizontalScroll
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.material3.Divider
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium
|
||||||
|
import com.sadellie.unitto.feature.epoch.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DateTextField(
|
||||||
|
modifier: Modifier,
|
||||||
|
date: String
|
||||||
|
) {
|
||||||
|
val inputWithPadding: String = date.padEnd(14, '0')
|
||||||
|
|
||||||
|
val day: String = inputWithPadding.substring(0, 2)
|
||||||
|
val month: String = inputWithPadding.substring(2, 4)
|
||||||
|
val year: String = inputWithPadding.substring(4, 8)
|
||||||
|
val hour: String = inputWithPadding.substring(8, 10)
|
||||||
|
val minute: String = inputWithPadding.substring(10, 12)
|
||||||
|
val second: String = inputWithPadding.substring(12, 14)
|
||||||
|
|
||||||
|
fun inFocus(range: Int): Boolean = date.length > range
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.height(IntrinsicSize.Min)
|
||||||
|
.horizontalScroll(rememberScrollState()),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.End)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(2.dp)
|
||||||
|
) {
|
||||||
|
Row {
|
||||||
|
DateTextAnimated(text = day, focus = inFocus(0))
|
||||||
|
DateText(text = stringResource(R.string.day_short), focus = inFocus(0))
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
DateTextAnimated(text = month, focus = inFocus(2))
|
||||||
|
DateText(text = stringResource(R.string.month_short), focus = inFocus(2))
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
DateTextAnimated(text = year, focus = inFocus(4))
|
||||||
|
DateText(text = stringResource(R.string.year_short), focus = inFocus(4))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Divider(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.width(1.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(2.dp)
|
||||||
|
) {
|
||||||
|
DateTextAnimated(text = hour, focus = inFocus(8))
|
||||||
|
DateText(text = ":", focus = inFocus(8))
|
||||||
|
DateTextAnimated(text = minute, focus = inFocus(10))
|
||||||
|
DateText(text = ":", focus = inFocus(10))
|
||||||
|
DateTextAnimated(text = second, focus = inFocus(12))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun BaseDateText(
|
||||||
|
focus: Boolean,
|
||||||
|
content: @Composable (Color) -> Unit
|
||||||
|
) {
|
||||||
|
val color = animateColorAsState(
|
||||||
|
if (focus) {
|
||||||
|
MaterialTheme.colorScheme.onBackground
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.outline.copy(alpha = 0.5f)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
content(color.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DateText(
|
||||||
|
focus: Boolean = true,
|
||||||
|
text: String
|
||||||
|
) {
|
||||||
|
BaseDateText(focus = focus) { color ->
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
style = NumbersTextStyleDisplayMedium,
|
||||||
|
color = color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DateTextAnimated(
|
||||||
|
focus: Boolean = true,
|
||||||
|
text: String
|
||||||
|
) {
|
||||||
|
BaseDateText(focus = focus) { color ->
|
||||||
|
AnimatedContent(
|
||||||
|
targetState = text,
|
||||||
|
transitionSpec = {
|
||||||
|
if (targetState.toInt() > initialState.toInt()) {
|
||||||
|
slideInVertically { height -> height } + fadeIn() with
|
||||||
|
slideOutVertically { height -> -height } + fadeOut()
|
||||||
|
} else {
|
||||||
|
slideInVertically { height -> -height } + fadeIn() with
|
||||||
|
slideOutVertically { height -> height } + fadeOut()
|
||||||
|
}.using(
|
||||||
|
SizeTransform(clip = false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = it,
|
||||||
|
style = NumbersTextStyleDisplayMedium,
|
||||||
|
color = color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* 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.feature.epoch.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.sadellie.unitto.core.base.KEY_0
|
||||||
|
import com.sadellie.unitto.core.base.KEY_1
|
||||||
|
import com.sadellie.unitto.core.base.KEY_2
|
||||||
|
import com.sadellie.unitto.core.base.KEY_3
|
||||||
|
import com.sadellie.unitto.core.base.KEY_4
|
||||||
|
import com.sadellie.unitto.core.base.KEY_5
|
||||||
|
import com.sadellie.unitto.core.base.KEY_6
|
||||||
|
import com.sadellie.unitto.core.base.KEY_7
|
||||||
|
import com.sadellie.unitto.core.base.KEY_8
|
||||||
|
import com.sadellie.unitto.core.base.KEY_9
|
||||||
|
import com.sadellie.unitto.core.base.KEY_CLEAR
|
||||||
|
import com.sadellie.unitto.core.ui.common.KeyboardButton
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun EpochKeyboard(
|
||||||
|
modifier: Modifier,
|
||||||
|
addSymbol: (String) -> Unit,
|
||||||
|
clearSymbols: () -> Unit,
|
||||||
|
deleteSymbol: () -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
) {
|
||||||
|
// Button modifier
|
||||||
|
val bModifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.weight(1f)
|
||||||
|
.padding(4.dp)
|
||||||
|
// Column modifier
|
||||||
|
val cModifier = Modifier.weight(1f)
|
||||||
|
val dModifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.weight(2f)
|
||||||
|
.padding(4.dp)
|
||||||
|
Row(cModifier) {
|
||||||
|
KeyboardButton(bModifier, KEY_7, allowVibration = false, onClick = addSymbol)
|
||||||
|
KeyboardButton(bModifier, KEY_8, allowVibration = false, onClick = addSymbol)
|
||||||
|
KeyboardButton(bModifier, KEY_9, allowVibration = false, onClick = addSymbol)
|
||||||
|
}
|
||||||
|
Row(cModifier) {
|
||||||
|
KeyboardButton(bModifier, KEY_4, allowVibration = false, onClick = addSymbol)
|
||||||
|
KeyboardButton(bModifier, KEY_5, allowVibration = false, onClick = addSymbol)
|
||||||
|
KeyboardButton(bModifier, KEY_6, allowVibration = false, onClick = addSymbol)
|
||||||
|
}
|
||||||
|
Row(cModifier) {
|
||||||
|
KeyboardButton(bModifier, KEY_1, allowVibration = false, onClick = addSymbol)
|
||||||
|
KeyboardButton(bModifier, KEY_2, allowVibration = false, onClick = addSymbol)
|
||||||
|
KeyboardButton(bModifier, KEY_3, allowVibration = false, onClick = addSymbol)
|
||||||
|
}
|
||||||
|
Row(cModifier) {
|
||||||
|
KeyboardButton(bModifier, KEY_0, allowVibration = false, onClick = addSymbol)
|
||||||
|
KeyboardButton(
|
||||||
|
dModifier,
|
||||||
|
KEY_CLEAR,
|
||||||
|
allowVibration = false,
|
||||||
|
onLongClick = clearSymbols
|
||||||
|
) { deleteSymbol() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.feature.epoch.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.LazyItemScope
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TopPart(
|
||||||
|
modifier: Modifier,
|
||||||
|
unixToDate: Boolean,
|
||||||
|
dateField: @Composable() (LazyItemScope.() -> Unit),
|
||||||
|
unixField: @Composable() (LazyItemScope.() -> Unit),
|
||||||
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = modifier,
|
||||||
|
verticalArrangement = Arrangement.Bottom
|
||||||
|
) {
|
||||||
|
if (unixToDate) {
|
||||||
|
item("unix") { unixField() }
|
||||||
|
item("date") { dateField() }
|
||||||
|
} else {
|
||||||
|
item("date") { dateField() }
|
||||||
|
item("unix") { unixField() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.feature.epoch.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.horizontalScroll
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UnixTextField(
|
||||||
|
modifier: Modifier,
|
||||||
|
unix: String
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.height(IntrinsicSize.Min)
|
||||||
|
.horizontalScroll(rememberScrollState()),
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = unix.ifEmpty { "0" },
|
||||||
|
modifier = modifier,
|
||||||
|
style = NumbersTextStyleDisplayMedium,
|
||||||
|
textAlign = TextAlign.End
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.feature.epoch.navigation
|
||||||
|
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.NavGraphBuilder
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import com.sadellie.unitto.feature.epoch.EpochRoute
|
||||||
|
|
||||||
|
private const val epochRoute = "epoch_route"
|
||||||
|
|
||||||
|
fun NavController.navigateToEpoch() {
|
||||||
|
navigate(epochRoute)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun NavGraphBuilder.epochScreen(
|
||||||
|
navigateUpAction: () -> Unit
|
||||||
|
) {
|
||||||
|
composable(epochRoute) {
|
||||||
|
EpochRoute(
|
||||||
|
navigateUpAction = navigateUpAction
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
1
feature/tools/.gitignore
vendored
Normal file
1
feature/tools/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
28
feature/tools/build.gradle.kts
Normal file
28
feature/tools/build.gradle.kts
Normal file
@ -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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("unitto.library")
|
||||||
|
id("unitto.library.compose")
|
||||||
|
id("unitto.library.feature")
|
||||||
|
id("unitto.android.hilt")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.sadellie.unitto.feature.tools"
|
||||||
|
}
|
0
feature/tools/consumer-rules.pro
Normal file
0
feature/tools/consumer-rules.pro
Normal file
4
feature/tools/src/main/AndroidManifest.xml
Normal file
4
feature/tools/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.sadellie.unitto.feature.tools
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Schedule
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ToolsScreen(
|
||||||
|
navigateUpAction: () -> Unit,
|
||||||
|
navigateToEpoch: () -> Unit
|
||||||
|
) {
|
||||||
|
UnittoLargeTopAppBar(
|
||||||
|
title = stringResource(R.string.tools_screen),
|
||||||
|
navigateUpAction = navigateUpAction
|
||||||
|
) { padding ->
|
||||||
|
LazyColumn(contentPadding = padding) {
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Schedule,
|
||||||
|
null // TODO describe
|
||||||
|
)
|
||||||
|
},
|
||||||
|
headlineText = { Text(stringResource(R.string.epoch_converter)) },
|
||||||
|
supportingText = { Text(stringResource(R.string.epoch_converter_support)) },
|
||||||
|
modifier = Modifier.clickable { navigateToEpoch() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
internal fun PreviewToolsScreen() {
|
||||||
|
ToolsScreen(
|
||||||
|
navigateUpAction = {},
|
||||||
|
navigateToEpoch = {}
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.feature.tools.navigation
|
||||||
|
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.NavGraphBuilder
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import com.sadellie.unitto.feature.tools.ToolsScreen
|
||||||
|
|
||||||
|
private const val toolsRoute = "tools_route"
|
||||||
|
|
||||||
|
fun NavController.navigateToTools() {
|
||||||
|
navigate(toolsRoute)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun NavGraphBuilder.toolsScreen(
|
||||||
|
navigateUpAction: () -> Unit,
|
||||||
|
navigateToEpoch: () -> Unit
|
||||||
|
) {
|
||||||
|
composable(toolsRoute) {
|
||||||
|
ToolsScreen(
|
||||||
|
navigateUpAction = navigateUpAction,
|
||||||
|
navigateToEpoch = navigateToEpoch
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -23,3 +23,5 @@ include(":core:ui")
|
|||||||
include(":feature:converter")
|
include(":feature:converter")
|
||||||
include(":feature:unitslist")
|
include(":feature:unitslist")
|
||||||
include(":feature:settings")
|
include(":feature:settings")
|
||||||
|
include(":feature:tools")
|
||||||
|
include(":feature:epoch")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user