Bumpy bumps

Updated navigation logic
This commit is contained in:
sadellie 2023-07-21 21:38:07 +03:00
parent eb9b12da28
commit 7c70258b84
33 changed files with 297 additions and 157 deletions

View File

@ -28,12 +28,12 @@ plugins {
android { android {
namespace = "com.sadellie.unitto" namespace = "com.sadellie.unitto"
compileSdk = 33 compileSdk = 34
defaultConfig { defaultConfig {
applicationId = "com.sadellie.unitto" applicationId = "com.sadellie.unitto"
minSdk = 21 minSdk = 21
targetSdk = 33 targetSdk = 34
versionCode = 22 versionCode = 22
versionName = "Lilac Luster" versionName = "Lilac Luster"
} }

View File

@ -19,10 +19,8 @@
package com.sadellie.unitto package com.sadellie.unitto
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.material3.DrawerValue import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
@ -40,6 +38,10 @@ import androidx.navigation.compose.rememberNavController
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.sadellie.unitto.core.base.TopLevelDestinations import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.core.ui.common.UnittoDrawerSheet import com.sadellie.unitto.core.ui.common.UnittoDrawerSheet
import com.sadellie.unitto.core.ui.common.UnittoModalNavigationDrawer
import com.sadellie.unitto.core.ui.common.close
import com.sadellie.unitto.core.ui.common.open
import com.sadellie.unitto.core.ui.common.rememberUnittoDrawerState
import com.sadellie.unitto.core.ui.model.DrawerItems import com.sadellie.unitto.core.ui.model.DrawerItems
import com.sadellie.unitto.core.ui.theme.AppTypography import com.sadellie.unitto.core.ui.theme.AppTypography
import com.sadellie.unitto.core.ui.theme.DarkThemeColors import com.sadellie.unitto.core.ui.theme.DarkThemeColors
@ -49,13 +51,13 @@ import io.github.sadellie.themmo.Themmo
import io.github.sadellie.themmo.rememberThemmoController import io.github.sadellie.themmo.rememberThemmoController
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
internal fun UnittoApp(uiPrefs: UIPreferences) { internal fun UnittoApp(uiPrefs: UIPreferences) {
val themmoController = rememberThemmoController( val themmoController = rememberThemmoController(
lightColorScheme = LightThemeColors, lightColorScheme = LightThemeColors,
darkColorScheme = DarkThemeColors, darkColorScheme = DarkThemeColors,
// Anything below will not be called if theming mode is still loading from DataStore
themingMode = uiPrefs.themingMode, themingMode = uiPrefs.themingMode,
dynamicThemeEnabled = uiPrefs.enableDynamicTheme, dynamicThemeEnabled = uiPrefs.enableDynamicTheme,
amoledThemeEnabled = uiPrefs.enableAmoledTheme, amoledThemeEnabled = uiPrefs.enableAmoledTheme,
@ -66,7 +68,7 @@ internal fun UnittoApp(uiPrefs: UIPreferences) {
val sysUiController = rememberSystemUiController() val sysUiController = rememberSystemUiController()
// Navigation drawer stuff // Navigation drawer stuff
val drawerState = rememberDrawerState(DrawerValue.Closed) val drawerState = rememberUnittoDrawerState()
val drawerScope = rememberCoroutineScope() val drawerScope = rememberCoroutineScope()
val mainTabs = listOf( val mainTabs = listOf(
DrawerItems.Calculator, DrawerItems.Calculator,
@ -88,14 +90,6 @@ internal fun UnittoApp(uiPrefs: UIPreferences) {
} }
} }
} }
val gesturesEnabled: Boolean by remember(navBackStackEntry?.destination) {
derivedStateOf {
// Will be true for routes like
// [null, calculator_route, settings_graph, settings_route, themes_route]
// We disable drawer drag gesture when we are too deep
navController.backQueue.size <= 4
}
}
Themmo( Themmo(
themmoController = themmoController, themmoController = themmoController,
@ -107,10 +101,8 @@ internal fun UnittoApp(uiPrefs: UIPreferences) {
mutableStateOf(backgroundColor.luminance() > 0.5f) mutableStateOf(backgroundColor.luminance() > 0.5f)
} }
ModalNavigationDrawer( UnittoModalNavigationDrawer(
drawerState = drawerState, drawer = {
gesturesEnabled = gesturesEnabled,
drawerContent = {
UnittoDrawerSheet( UnittoDrawerSheet(
modifier = Modifier, modifier = Modifier,
mainTabs = mainTabs, mainTabs = mainTabs,
@ -126,15 +118,20 @@ internal fun UnittoApp(uiPrefs: UIPreferences) {
restoreState = true restoreState = true
} }
} }
},
modifier = Modifier,
state = drawerState,
gesturesEnabled = true,
scope = drawerScope,
content = {
UnittoNavigation(
navController = navController,
themmoController = it,
startDestination = uiPrefs.startingScreen,
openDrawer = { drawerScope.launch { drawerState.open() } }
)
} }
) { )
UnittoNavigation(
navController = navController,
themmoController = it,
startDestination = uiPrefs.startingScreen,
openDrawer = { drawerScope.launch { drawerState.open() } }
)
}
LaunchedEffect(useDarkIcons) { LaunchedEffect(useDarkIcons) {
sysUiController.setNavigationBarColor(Color.Transparent, useDarkIcons) sysUiController.setNavigationBarColor(Color.Transparent, useDarkIcons)

View File

@ -23,7 +23,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import com.sadellie.unitto.feature.calculator.navigation.calculatorScreen import com.sadellie.unitto.feature.calculator.navigation.calculatorScreen
@ -55,20 +54,10 @@ internal fun UnittoNavigation(
startDestination = startDestination, startDestination = startDestination,
modifier = Modifier.background(MaterialTheme.colorScheme.background) modifier = Modifier.background(MaterialTheme.colorScheme.background)
) { ) {
fun navigateToSettings() {
navController.navigateToSettings {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
converterScreen( converterScreen(
navigateToLeftScreen = navController::navigateToLeftSide, navigateToLeftScreen = navController::navigateToLeftSide,
navigateToRightScreen = navController::navigateToRightSide, navigateToRightScreen = navController::navigateToRightSide,
navigateToSettings = ::navigateToSettings, navigateToSettings = navController::navigateToSettings,
navigateToMenu = openDrawer, navigateToMenu = openDrawer,
viewModel = converterViewModel viewModel = converterViewModel
) )
@ -95,12 +84,12 @@ internal fun UnittoNavigation(
calculatorScreen( calculatorScreen(
navigateToMenu = openDrawer, navigateToMenu = openDrawer,
navigateToSettings = ::navigateToSettings navigateToSettings = navController::navigateToSettings
) )
dateDifferenceScreen( dateDifferenceScreen(
navigateToMenu = openDrawer, navigateToMenu = openDrawer,
navigateToSettings = ::navigateToSettings navigateToSettings = navController::navigateToSettings
) )
} }
} }

View File

@ -22,6 +22,7 @@ import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
@Suppress("UNUSED")
class UnittoHiltPlugin : Plugin<Project> { class UnittoHiltPlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {

View File

@ -25,6 +25,7 @@ import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
@Suppress("UNUSED")
class UnittoLibraryComposePlugin : Plugin<Project> { class UnittoLibraryComposePlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {

View File

@ -22,6 +22,7 @@ import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
@Suppress("UNUSED")
class UnittoLibraryFeaturePlugin : Plugin<Project> { class UnittoLibraryFeaturePlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {

View File

@ -25,6 +25,7 @@ import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
@Suppress("UNUSED")
class UnittoLibraryPlugin : Plugin<Project> { class UnittoLibraryPlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {

View File

@ -34,7 +34,7 @@ internal fun Project.configureKotlinAndroid(
commonExtension: CommonExtension<*, *, *, *>, commonExtension: CommonExtension<*, *, *, *>,
) { ) {
commonExtension.apply { commonExtension.apply {
compileSdk = 33 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 21 minSdk = 21

View File

@ -37,7 +37,6 @@ android {
dependencies { dependencies {
testImplementation(libs.junit) testImplementation(libs.junit)
testImplementation(libs.org.robolectric)
testImplementation(libs.androidx.compose.ui.test.junit4) testImplementation(libs.androidx.compose.ui.test.junit4)
debugImplementation(libs.androidx.compose.ui.test.manifest) debugImplementation(libs.androidx.compose.ui.test.manifest)

View File

@ -0,0 +1,195 @@
/*
* 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.common
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
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.gestures.animateTo
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.DrawerDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
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.model.DrawerItems
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlin.math.roundToInt
// Why do I have to do it myself?
@Composable
fun UnittoModalNavigationDrawer(
drawer: @Composable () -> Unit,
modifier: Modifier,
state: AnchoredDraggableState<UnittoDrawerState>,
gesturesEnabled: Boolean,
scope: CoroutineScope,
content: @Composable () -> Unit,
) {
Box(modifier.fillMaxSize()) {
content()
Scrim(
open = state.isOpen,
onClose = { if (gesturesEnabled) scope.launch { state.close() } },
fraction = {
fraction(state.anchors.minAnchor(), state.anchors.maxAnchor(), state.offset)
},
color = DrawerDefaults.scrimColor
)
// Drawer
Box(Modifier
.offset {
IntOffset(
x = state
.requireOffset()
.roundToInt(), y = 0
)
}
.anchoredDraggable(
state = state,
orientation = Orientation.Horizontal,
enabled = gesturesEnabled or state.isOpen,
)
.padding(end = 18.dp) // Draggable when closed
) {
drawer()
}
}
}
@Composable
private fun Scrim(
open: Boolean,
onClose: () -> Unit,
fraction: () -> Float,
color: Color,
) {
val dismissDrawer = if (open) {
Modifier.pointerInput(onClose) { detectTapGestures { onClose() } }
} else {
Modifier
}
Canvas(
Modifier
.fillMaxSize()
.then(dismissDrawer)
) {
drawRect(color, alpha = fraction())
}
}
enum class UnittoDrawerState { OPEN, CLOSED }
@Composable
fun rememberUnittoDrawerState(
initialValue: UnittoDrawerState = UnittoDrawerState.CLOSED,
): AnchoredDraggableState<UnittoDrawerState> {
val minValue = -with(LocalDensity.current) { 360.dp.toPx() }
val positionalThreshold = -minValue * 0.5f
val velocityThreshold = with(LocalDensity.current) { 400.dp.toPx() }
return remember {
AnchoredDraggableState(
initialValue = initialValue,
anchors = DraggableAnchors {
UnittoDrawerState.OPEN at 0F
UnittoDrawerState.CLOSED at minValue
},
positionalThreshold = { positionalThreshold },
velocityThreshold = { velocityThreshold },
animationSpec = tween()
)
}
}
private val AnchoredDraggableState<UnittoDrawerState>.isOpen
get() = this.currentValue == UnittoDrawerState.OPEN
suspend fun AnchoredDraggableState<UnittoDrawerState>.close() {
this.animateTo(UnittoDrawerState.CLOSED)
}
suspend fun AnchoredDraggableState<UnittoDrawerState>.open() {
this.animateTo(UnittoDrawerState.OPEN)
}
private fun fraction(a: Float, b: Float, pos: Float) =
((pos - a) / (b - a)).coerceIn(0f, 1f)
@Preview(backgroundColor = 0xFFC8F7D4, showBackground = true, showSystemUi = true)
@Composable
private fun PreviewUnittoModalNavigationDrawer() {
val drawerState = rememberUnittoDrawerState(initialValue = UnittoDrawerState.OPEN)
val corScope = rememberCoroutineScope()
UnittoModalNavigationDrawer(
drawer = {
UnittoDrawerSheet(
modifier = Modifier,
mainTabs = listOf(
DrawerItems.Calculator,
DrawerItems.Calculator,
DrawerItems.Calculator,
),
additionalTabs = listOf(
DrawerItems.Calculator,
DrawerItems.Calculator,
DrawerItems.Calculator,
),
currentDestination = DrawerItems.Calculator.destination,
onItemClick = {}
)
},
modifier = Modifier,
state = drawerState,
gesturesEnabled = true,
scope = corScope,
content = {
Column {
Text(text = "Content")
Button(
onClick = { corScope.launch { drawerState.open() } }
) {
Text(text = "BUTTON")
}
}
}
)
}

View File

@ -26,11 +26,11 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.SliderPositions import androidx.compose.material3.SliderState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -72,18 +72,18 @@ fun UnittoSlider(
@Composable @Composable
private fun SquigglyTrack( private fun SquigglyTrack(
sliderPosition: SliderPositions, sliderState: SliderState,
eachWaveWidth: Float = 80f, eachWaveWidth: Float = 80f,
strokeWidth: Float = 15f, strokeWidth: Float = 15f,
filledColor: Color = MaterialTheme.colorScheme.primary, filledColor: Color = MaterialTheme.colorScheme.primary,
unfilledColor: Color = MaterialTheme.colorScheme.surfaceVariant unfilledColor: Color = MaterialTheme.colorScheme.surfaceVariant
) { ) {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
var direct by remember { mutableStateOf(0.72f) } var direct by remember { mutableFloatStateOf(0.72f) }
val animatedDirect = animateFloatAsState(direct, spring(stiffness = Spring.StiffnessLow)) val animatedDirect = animateFloatAsState(direct, spring(stiffness = Spring.StiffnessLow))
val slider = sliderPosition.activeRange.endInclusive val slider = sliderState.valueRange.endInclusive
LaunchedEffect(sliderPosition.activeRange.endInclusive) { LaunchedEffect(sliderState.valueRange.endInclusive) {
coroutineScope.launch { coroutineScope.launch {
delay(200L) delay(200L)
direct *= -1 direct *= -1
@ -148,7 +148,7 @@ private fun SquigglyTrack(
@Preview(device = "spec:width=1920dp,height=1080dp,dpi=480") @Preview(device = "spec:width=1920dp,height=1080dp,dpi=480")
@Composable @Composable
private fun PreviewNewSlider() { private fun PreviewNewSlider() {
var currentValue by remember { mutableStateOf(0.9f) } var currentValue by remember { mutableFloatStateOf(0.9f) }
UnittoSlider( UnittoSlider(
value = currentValue, value = currentValue,

View File

@ -20,8 +20,8 @@ package com.sadellie.unitto.core.ui
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
class ExpressionTransformerTest { class ExpressionTransformerTest {

View File

@ -18,8 +18,8 @@
package com.sadellie.unitto.data.common package com.sadellie.unitto.data.common
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
class IsExpressionText { class IsExpressionText {

View File

@ -18,8 +18,8 @@
package com.sadellie.unitto.data.epoch package com.sadellie.unitto.data.epoch
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
class DateToEpochTest { class DateToEpochTest {

View File

@ -18,7 +18,7 @@
package io.github.sadellie.evaluatto package io.github.sadellie.evaluatto
import org.junit.Test import org.junit.jupiter.api.Test
class ExpressionComplexTest { class ExpressionComplexTest {

View File

@ -18,7 +18,7 @@
package io.github.sadellie.evaluatto package io.github.sadellie.evaluatto
import org.junit.Test import org.junit.jupiter.api.Test
class ExpressionExceptionsTest { class ExpressionExceptionsTest {

View File

@ -18,7 +18,7 @@
package io.github.sadellie.evaluatto package io.github.sadellie.evaluatto
import org.junit.Test import org.junit.jupiter.api.Test
class ExpressionSimpleTest { class ExpressionSimpleTest {

View File

@ -18,9 +18,10 @@
package io.github.sadellie.evaluatto package io.github.sadellie.evaluatto
import org.junit.Test import org.junit.jupiter.api.Test
class FixLexiconTest { class FixLexiconTest {
@Test @Test
fun `missing multiply`() { fun `missing multiply`() {
assertLex( assertLex(

View File

@ -18,12 +18,13 @@
package io.github.sadellie.evaluatto package io.github.sadellie.evaluatto
import org.junit.Assert import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertThrows
import java.math.BigDecimal import java.math.BigDecimal
import java.math.RoundingMode import java.math.RoundingMode
fun assertExpr(expr: String, result: String, radianMode: Boolean = true) = fun assertExpr(expr: String, result: String, radianMode: Boolean = true) =
Assert.assertEquals( assertEquals(
BigDecimal(result).setScale(10, RoundingMode.HALF_EVEN), BigDecimal(result).setScale(10, RoundingMode.HALF_EVEN),
Expression(expr, radianMode).calculate().setScale(10, RoundingMode.HALF_EVEN) Expression(expr, radianMode).calculate().setScale(10, RoundingMode.HALF_EVEN)
) )
@ -33,13 +34,13 @@ fun <T : Throwable?> assertExprFail(
expr: String, expr: String,
radianMode: Boolean = true radianMode: Boolean = true
) { ) {
Assert.assertThrows(expectedThrowable) { assertThrows(expectedThrowable) {
Expression(expr, radianMode = radianMode).calculate() Expression(expr, radianMode = radianMode).calculate()
} }
} }
fun assertLex(expected: List<String>, actual: String) = fun assertLex(expected: List<String>, actual: String) =
Assert.assertEquals(expected, Tokenizer(actual).tokenize()) assertEquals(expected, Tokenizer(actual).tokenize())
fun assertLex(expected: String, actual: String) = fun assertLex(expected: String, actual: String) =
Assert.assertEquals(expected, Tokenizer(actual).tokenize().joinToString("")) assertEquals(expected, Tokenizer(actual).tokenize().joinToString(""))

View File

@ -18,9 +18,10 @@
package io.github.sadellie.evaluatto package io.github.sadellie.evaluatto
import org.junit.Test import org.junit.jupiter.api.Test
class TokenizerTest { class TokenizerTest {
@Test @Test
fun tokens1() = assertLex(listOf("789"), "789") fun tokens1() = assertLex(listOf("789"), "789")

View File

@ -21,8 +21,8 @@ package com.sadellie.unitto.data.units
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
import java.math.BigDecimal import java.math.BigDecimal
class AllUnitsRepositoryTest { class AllUnitsRepositoryTest {

View File

@ -20,14 +20,11 @@ package com.sadellie.unitto.data.units
import com.sadellie.unitto.data.model.NumberBaseUnit import com.sadellie.unitto.data.model.NumberBaseUnit
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import org.junit.After import org.junit.jupiter.api.AfterEach
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.math.BigDecimal import java.math.BigDecimal
@RunWith(JUnit4::class)
class AllUnitsTest { class AllUnitsTest {
// Group and it's tested unit ids // Group and it's tested unit ids
@ -527,7 +524,7 @@ class AllUnitsTest {
history[unitFrom.group] = content.plus(this) history[unitFrom.group] = content.plus(this)
} }
@After @AfterEach
fun after() { fun after() {
val unitGroup = history.keys.first() val unitGroup = history.keys.first()
// GROUP : testedCount / totalCount // GROUP : testedCount / totalCount

View File

@ -22,8 +22,8 @@ import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.DefaultUnit import com.sadellie.unitto.data.model.DefaultUnit
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.sortByLev import com.sadellie.unitto.data.model.sortByLev
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
import java.math.BigDecimal import java.math.BigDecimal
val baseList: List<AbstractUnit> = listOf( val baseList: List<AbstractUnit> = listOf(

View File

@ -19,8 +19,8 @@
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.units
import com.sadellie.unitto.data.common.lev import com.sadellie.unitto.data.common.lev
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
class LevenshteinTest { class LevenshteinTest {

View File

@ -19,8 +19,8 @@
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.units
import com.sadellie.unitto.data.common.setMinimumRequiredScale import com.sadellie.unitto.data.common.setMinimumRequiredScale
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
import java.math.BigDecimal import java.math.BigDecimal
class MinimumRequiredScaleTest { class MinimumRequiredScaleTest {

View File

@ -47,6 +47,7 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -120,8 +121,8 @@ private fun CalculatorScreen(
val dragCoroutineScope = rememberCoroutineScope() val dragCoroutineScope = rememberCoroutineScope()
val dragAnimSpec = rememberSplineBasedDecay<Float>() val dragAnimSpec = rememberSplineBasedDecay<Float>()
var textThingyHeight by remember { mutableStateOf(0) } var textThingyHeight by remember { mutableIntStateOf(0) }
var historyItemHeight by remember { mutableStateOf(0) } var historyItemHeight by remember { mutableIntStateOf(0) }
var showClearHistoryDialog by rememberSaveable { mutableStateOf(false) } var showClearHistoryDialog by rememberSaveable { mutableStateOf(false) }
val showClearHistoryButton by remember(dragAmount.value, historyItemHeight) { val showClearHistoryButton by remember(dragAmount.value, historyItemHeight) {

View File

@ -30,7 +30,6 @@ android {
dependencies { dependencies {
testImplementation(libs.junit) testImplementation(libs.junit)
testImplementation(libs.org.jetbrains.kotlinx.coroutines.test) testImplementation(libs.org.jetbrains.kotlinx.coroutines.test)
testImplementation(libs.org.robolectric)
testImplementation(libs.androidx.room.runtime) testImplementation(libs.androidx.room.runtime)
testImplementation(libs.androidx.room.ktx) testImplementation(libs.androidx.room.ktx)
kapt(libs.androidx.room.compiler) kapt(libs.androidx.room.compiler)

View File

@ -1,44 +0,0 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2022-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.converter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.rules.TestWatcher
import org.junit.runner.Description
@ExperimentalCoroutinesApi
class CoroutineTestRule(private val dispatcher: TestDispatcher = UnconfinedTestDispatcher()) :
TestWatcher() {
override fun starting(description: Description) {
super.starting(description)
Dispatchers.setMain(dispatcher)
}
override fun finished(description: Description) {
super.finished(description)
Dispatchers.resetMain()
}
}

View File

@ -18,8 +18,8 @@
package com.sadellie.unitto.feature.datedifference package com.sadellie.unitto.feature.datedifference
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Test import org.junit.jupiter.api.Test
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter

View File

@ -37,6 +37,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -59,7 +60,7 @@ internal fun AboutScreen(
) { ) {
val mContext = LocalContext.current val mContext = LocalContext.current
val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle() val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle()
var aboutItemClick: Int by rememberSaveable { mutableStateOf(0) } var aboutItemClick: Int by rememberSaveable { mutableIntStateOf(0) }
var showDialog: Boolean by rememberSaveable { mutableStateOf(false) } var showDialog: Boolean by rememberSaveable { mutableStateOf(false) }
UnittoScreenWithLargeTopBar( UnittoScreenWithLargeTopBar(

View File

@ -40,7 +40,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -56,10 +56,10 @@ import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Separator import com.sadellie.unitto.core.base.Separator
import com.sadellie.unitto.core.ui.common.NavigateUpButton import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.UnittoSlider
import com.sadellie.unitto.core.ui.common.SegmentedButton import com.sadellie.unitto.core.ui.common.SegmentedButton
import com.sadellie.unitto.core.ui.common.SegmentedButtonsRow import com.sadellie.unitto.core.ui.common.SegmentedButtonsRow
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.common.UnittoSlider
import com.sadellie.unitto.core.ui.common.squashable import com.sadellie.unitto.core.ui.common.squashable
import com.sadellie.unitto.core.ui.common.textfield.formatExpression import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium
@ -255,9 +255,9 @@ fun FormattingScreen(
@Preview @Preview
@Composable @Composable
private fun PreviewFormattingScreen() { private fun PreviewFormattingScreen() {
var currentPrecision by remember { mutableStateOf(6) } var currentPrecision by remember { mutableIntStateOf(6) }
var currentSeparator by remember { mutableStateOf(Separator.COMMA) } var currentSeparator by remember { mutableIntStateOf(Separator.COMMA) }
var currentOutputFormat by remember { mutableStateOf(OutputFormat.PLAIN) } var currentOutputFormat by remember { mutableIntStateOf(OutputFormat.PLAIN) }
FormattingScreen( FormattingScreen(
uiState = FormattingUIState( uiState = FormattingUIState(

View File

@ -21,7 +21,6 @@ package com.sadellie.unitto.feature.settings.navigation
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.NavOptionsBuilder
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation import androidx.navigation.compose.navigation
import com.sadellie.unitto.core.base.TopLevelDestinations import com.sadellie.unitto.core.base.TopLevelDestinations
@ -41,8 +40,8 @@ internal const val thirdPartyRoute = "third_party_route"
internal const val aboutRoute = "about_route" internal const val aboutRoute = "about_route"
internal const val formattingRoute = "formatting_route" internal const val formattingRoute = "formatting_route"
fun NavController.navigateToSettings(builder: NavOptionsBuilder.() -> Unit) { fun NavController.navigateToSettings() {
navigate(settingsRoute, builder) navigate(settingsRoute)
} }
fun NavController.navigateToUnitGroups() { fun NavController.navigateToUnitGroups() {

View File

@ -1,39 +1,39 @@
[versions] [versions]
appCode = "22" appCode = "22"
appName = "Lilac Luster" appName = "Lilac Luster"
kotlin = "1.8.21" kotlin = "1.9.0"
androidxCore = "1.10.0" androidxCore = "1.10.1"
androidGradlePlugin = "8.0.1" androidGradlePlugin = "8.0.2"
orgJetbrainsKotlinxCoroutinesTest = "1.6.4" orgJetbrainsKotlinxCoroutinesTest = "1.7.2"
androidxCompose = "1.5.0-alpha02" androidxCompose = "1.5.0-alpha02"
androidxComposeCompiler = "1.4.7" androidxComposeCompiler = "1.5.0"
androidxComposeUi = "1.5.0-alpha04" androidxComposeUi = "1.6.0-alpha01"
androidxComposeMaterial3 = "1.2.0-alpha01" androidxComposeMaterial3 = "1.2.0-alpha03"
androidxNavigation = "2.5.3" androidxNavigation = "2.6.0"
androidxLifecycleRuntimeCompose = "2.6.1" androidxLifecycleRuntimeCompose = "2.6.1"
androidxHilt = "1.0.0" androidxHilt = "1.0.0"
comGoogleDagger = "2.45" comGoogleDagger = "2.47"
androidxComposeMaterialIconsExtended = "1.5.0-alpha04" androidxComposeMaterialIconsExtended = "1.6.0-alpha01"
androidxDatastore = "1.0.0" androidxDatastore = "1.0.0"
comGoogleAccompanist = "0.30.1" comGoogleAccompanist = "0.30.1"
androidxRoom = "2.5.1" androidxRoom = "2.6.0-alpha02"
comSquareupMoshi = "1.14.0" comSquareupMoshi = "1.15.0"
comSquareupRetrofit2 = "2.9.0" comSquareupRetrofit2 = "2.9.0"
comGithubSadellieThemmo = "ed4063f70f" comGithubSadellieThemmo = "1.0.0"
orgBurnoutcrewComposereorderable = "0.9.6" orgBurnoutcrewComposereorderable = "0.9.6"
junit = "4.13.2" junit = "5.9.3"
androidxTest = "1.5.0" androidxTest = "1.5.0"
androidxTestExt = "1.1.4" androidxTestExt = "1.1.5"
androidDesugarJdkLibs = "2.0.3" androidDesugarJdkLibs = "2.0.3"
androidxTestRunner = "1.5.1" androidxTestRunner = "1.5.2"
androidxTestRules = "1.5.0" androidxTestRules = "1.5.0"
orgRobolectric = "4.9" orgRobolectric = "4.10.3"
[libraries] [libraries]
androidx-core = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCore" } androidx-core = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCore" }
androidx-test = { group = "androidx.test", name = "core", version.ref = "androidxTest" } androidx-test = { group = "androidx.test", name = "core", version.ref = "androidxTest" }
androidx-test-ext = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "androidxTestExt" } androidx-test-ext = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "androidxTestExt" }
junit = { group = "junit", name = "junit", version.ref = "junit" } junit = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" }
androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidxTestRunner" } androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidxTestRunner" }
androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "androidxTestRules" } androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "androidxTestRules" }
org-robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "orgRobolectric" } org-robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "orgRobolectric" }