mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
Spotless and ktlint
This commit is contained in:
parent
8b21721f48
commit
eb00d8a76e
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# https://editorconfig.org/
|
||||||
|
# This configuration is used by ktlint when spotless invokes it
|
||||||
|
|
||||||
|
[*.{kt,kts}]
|
||||||
|
ij_kotlin_allow_trailing_comma=true
|
||||||
|
ij_kotlin_allow_trailing_comma_on_call_site=true
|
||||||
|
ktlint_function_naming_ignore_when_annotated_with=Composable, Test
|
42
.run/spotlessApply.run.xml
Normal file
42
.run/spotlessApply.run.xml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!--
|
||||||
|
~ Unitto is a calculator for Android
|
||||||
|
~ Copyright (c) 2024 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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spotlessApply" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="--init-script gradle/init.gradle.kts --no-configuration-cache" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="spotlessApply" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<ForceTestExec>false</ForceTestExec>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
42
.run/spotlessCheck.run.xml
Normal file
42
.run/spotlessCheck.run.xml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!--
|
||||||
|
~ Unitto is a calculator for Android
|
||||||
|
~ Copyright (c) 2024 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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spotlessCheck" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="--init-script gradle/init.gradle.kts --no-configuration-cache" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="spotlessCheck" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<ForceTestExec>false</ForceTestExec>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
@ -76,14 +76,14 @@ internal fun ComponentActivity.App(prefs: AppPreferences?) {
|
|||||||
dynamicThemeEnabled = prefs.enableDynamicTheme,
|
dynamicThemeEnabled = prefs.enableDynamicTheme,
|
||||||
amoledThemeEnabled = prefs.enableAmoledTheme,
|
amoledThemeEnabled = prefs.enableAmoledTheme,
|
||||||
customColor = prefs.customColor.toColor(),
|
customColor = prefs.customColor.toColor(),
|
||||||
monetMode = prefs.monetMode
|
monetMode = prefs.monetMode,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Themmo(
|
Themmo(
|
||||||
themmoController = themmoController,
|
themmoController = themmoController,
|
||||||
typography = TypographySystem,
|
typography = TypographySystem,
|
||||||
animationSpec = tween(250)
|
animationSpec = tween(250),
|
||||||
) {
|
) {
|
||||||
val backgroundColor = MaterialTheme.colorScheme.background
|
val backgroundColor = MaterialTheme.colorScheme.background
|
||||||
val isDarkThemeEnabled = remember(backgroundColor) { backgroundColor.luminance() < 0.5f }
|
val isDarkThemeEnabled = remember(backgroundColor) { backgroundColor.luminance() < 0.5f }
|
||||||
@ -113,9 +113,9 @@ internal fun ComponentActivity.App(prefs: AppPreferences?) {
|
|||||||
navController = navController,
|
navController = navController,
|
||||||
themmoController = it,
|
themmoController = it,
|
||||||
startDestination = prefs.startingScreen,
|
startDestination = prefs.startingScreen,
|
||||||
openDrawer = { drawerScope.launch { drawerState.open() } }
|
openDrawer = { drawerScope.launch { drawerState.open() } },
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
DisposableEffect(isDarkThemeEnabled) {
|
DisposableEffect(isDarkThemeEnabled) {
|
||||||
|
@ -68,7 +68,7 @@ internal class MainActivity : AppCompatActivity() {
|
|||||||
LocalLocale provides locale,
|
LocalLocale provides locale,
|
||||||
LocalWindowSize provides calculateWindowSizeClass(this@MainActivity),
|
LocalWindowSize provides calculateWindowSizeClass(this@MainActivity),
|
||||||
LocalNumberTypography provides numbersTypography,
|
LocalNumberTypography provides numbersTypography,
|
||||||
LocalHapticPreference provides (prefs?.enableVibrations ?: true)
|
LocalHapticPreference provides (prefs?.enableVibrations ?: true),
|
||||||
) {
|
) {
|
||||||
App(prefs)
|
App(prefs)
|
||||||
}
|
}
|
||||||
|
@ -22,4 +22,4 @@ import android.app.Application
|
|||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
internal class UnittoApplication: Application()
|
internal class UnittoApplication : Application()
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package com.sadellie.unitto
|
package com.sadellie.unitto
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@ -26,6 +27,7 @@ import androidx.annotation.RequiresApi
|
|||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
class UnittoTileService : TileService() {
|
class UnittoTileService : TileService() {
|
||||||
|
@SuppressLint("StartActivityAndCollapseDeprecated")
|
||||||
override fun onClick() {
|
override fun onClick() {
|
||||||
super.onClick()
|
super.onClick()
|
||||||
|
|
||||||
@ -33,7 +35,7 @@ class UnittoTileService : TileService() {
|
|||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
startActivityAndCollapse(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE))
|
startActivityAndCollapse(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE))
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
startActivityAndCollapse(intent)
|
startActivityAndCollapse(intent)
|
||||||
|
@ -31,7 +31,7 @@ class StartupBaselineProfile {
|
|||||||
@Test
|
@Test
|
||||||
fun generate() = baselineProfileRule.collect(
|
fun generate() = baselineProfileRule.collect(
|
||||||
packageName = "com.sadellie.unitto",
|
packageName = "com.sadellie.unitto",
|
||||||
includeInStartupProfile = true
|
includeInStartupProfile = true,
|
||||||
) {
|
) {
|
||||||
startActivityAndWait()
|
startActivityAndWait()
|
||||||
device.pressBack()
|
device.pressBack()
|
||||||
|
@ -61,7 +61,7 @@ class StartupBenchmark {
|
|||||||
fun startupFullyPrecompiled() = startup(CompilationMode.Full())
|
fun startupFullyPrecompiled() = startup(CompilationMode.Full())
|
||||||
|
|
||||||
private fun startup(
|
private fun startup(
|
||||||
compilationMode: CompilationMode
|
compilationMode: CompilationMode,
|
||||||
) = benchmarkRule.measureRepeated(
|
) = benchmarkRule.measureRepeated(
|
||||||
packageName = "com.sadellie.unitto",
|
packageName = "com.sadellie.unitto",
|
||||||
metrics = listOf(StartupTimingMetric()),
|
metrics = listOf(StartupTimingMetric()),
|
||||||
@ -70,7 +70,7 @@ class StartupBenchmark {
|
|||||||
startupMode = StartupMode.COLD,
|
startupMode = StartupMode.COLD,
|
||||||
setupBlock = {
|
setupBlock = {
|
||||||
pressHome()
|
pressHome()
|
||||||
}
|
},
|
||||||
) {
|
) {
|
||||||
startActivityAndWait()
|
startActivityAndWait()
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,10 @@ package com.sadellie.unitto.core.base
|
|||||||
object OutputFormat {
|
object OutputFormat {
|
||||||
// Never use engineering notation
|
// Never use engineering notation
|
||||||
const val PLAIN = 0
|
const val PLAIN = 0
|
||||||
|
|
||||||
// Use format that a lower API returns
|
// Use format that a lower API returns
|
||||||
const val ALLOW_ENGINEERING = 1
|
const val ALLOW_ENGINEERING = 1
|
||||||
|
|
||||||
// App will try it's best to use engineering notation
|
// App will try it's best to use engineering notation
|
||||||
const val FORCE_ENGINEERING = 2
|
const val FORCE_ENGINEERING = 2
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.base
|
package com.sadellie.unitto.core.base
|
||||||
|
|
||||||
@Suppress("ObjectPropertyName")
|
@Suppress("ObjectPropertyName")
|
||||||
@ -100,14 +102,14 @@ object Token {
|
|||||||
|
|
||||||
val all by lazy {
|
val all by lazy {
|
||||||
listOf(
|
listOf(
|
||||||
arsin, arcos, actan, sin, cos, tan, log, exp, ln
|
arsin, arcos, actan, sin, cos, tan, log, exp, ln,
|
||||||
).sortedByDescending { it.length }
|
).sortedByDescending { it.length }
|
||||||
}
|
}
|
||||||
|
|
||||||
val allWithOpeningBracket by lazy {
|
val allWithOpeningBracket by lazy {
|
||||||
listOf(
|
listOf(
|
||||||
arsinBracket, arcosBracket, actanBracket, sinBracket, cosBracket, tanBracket,
|
arsinBracket, arcosBracket, actanBracket, sinBracket, cosBracket, tanBracket,
|
||||||
logBracket, expBracket, lnBracket
|
logBracket, expBracket, lnBracket,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,7 +146,7 @@ object Token {
|
|||||||
Operator.multiply to listOf("*", "•"),
|
Operator.multiply to listOf("*", "•"),
|
||||||
Func.arsin to listOf("arsin"),
|
Func.arsin to listOf("arsin"),
|
||||||
Func.arcos to listOf("arcos"),
|
Func.arcos to listOf("arcos"),
|
||||||
Func.actan to listOf("actan")
|
Func.actan to listOf("actan"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,12 @@ class TokenTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testSexyToUgly() {
|
fun testSexyToUgly() {
|
||||||
listOf(
|
listOf(
|
||||||
"−", "÷", "×", "sin⁻¹", "cos⁻¹", "tan⁻¹"
|
"−",
|
||||||
|
"÷",
|
||||||
|
"×",
|
||||||
|
"sin⁻¹",
|
||||||
|
"cos⁻¹",
|
||||||
|
"tan⁻¹",
|
||||||
).forEach {
|
).forEach {
|
||||||
assert(it in Token.sexyToUgly.keys)
|
assert(it in Token.sexyToUgly.keys)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import java.time.ZonedDateTime
|
|||||||
|
|
||||||
class ZonedDateTimeUtilsTest {
|
class ZonedDateTimeUtilsTest {
|
||||||
|
|
||||||
@get: Rule
|
@get:Rule
|
||||||
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
|
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -83,7 +83,7 @@ fun calculateWindowSizeClass(activity: Activity): WindowSizeClass {
|
|||||||
@Immutable
|
@Immutable
|
||||||
class WindowSizeClass(
|
class WindowSizeClass(
|
||||||
val widthSizeClass: WindowWidthSizeClass,
|
val widthSizeClass: WindowWidthSizeClass,
|
||||||
val heightSizeClass: WindowHeightSizeClass
|
val heightSizeClass: WindowHeightSizeClass,
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
@ -118,7 +118,7 @@ class WindowSizeClass(
|
|||||||
supportedWidthSizeClasses: Set<WindowWidthSizeClass> =
|
supportedWidthSizeClasses: Set<WindowWidthSizeClass> =
|
||||||
WindowWidthSizeClass.DefaultSizeClasses,
|
WindowWidthSizeClass.DefaultSizeClasses,
|
||||||
supportedHeightSizeClasses: Set<WindowHeightSizeClass> =
|
supportedHeightSizeClasses: Set<WindowHeightSizeClass> =
|
||||||
WindowHeightSizeClass.DefaultSizeClasses
|
WindowHeightSizeClass.DefaultSizeClasses,
|
||||||
): WindowSizeClass {
|
): WindowSizeClass {
|
||||||
val windowWidthSizeClass =
|
val windowWidthSizeClass =
|
||||||
WindowWidthSizeClass.fromWidth(size.width, density, supportedWidthSizeClasses)
|
WindowWidthSizeClass.fromWidth(size.width, density, supportedWidthSizeClasses)
|
||||||
@ -225,7 +225,9 @@ value class WindowWidthSizeClass private constructor(private val value: Int) :
|
|||||||
/** Calculates the [WindowWidthSizeClass] for a given [width] */
|
/** Calculates the [WindowWidthSizeClass] for a given [width] */
|
||||||
internal fun fromWidth(width: Dp): WindowWidthSizeClass {
|
internal fun fromWidth(width: Dp): WindowWidthSizeClass {
|
||||||
return fromWidth(
|
return fromWidth(
|
||||||
with(defaultDensity) { width.toPx() }, defaultDensity, DefaultSizeClasses
|
with(defaultDensity) { width.toPx() },
|
||||||
|
defaultDensity,
|
||||||
|
DefaultSizeClasses,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +238,7 @@ value class WindowWidthSizeClass private constructor(private val value: Int) :
|
|||||||
internal fun fromWidth(
|
internal fun fromWidth(
|
||||||
width: Float,
|
width: Float,
|
||||||
density: Density,
|
density: Density,
|
||||||
supportedSizeClasses: Set<WindowWidthSizeClass>
|
supportedSizeClasses: Set<WindowWidthSizeClass>,
|
||||||
): WindowWidthSizeClass {
|
): WindowWidthSizeClass {
|
||||||
require(width >= 0) { "Width must not be negative" }
|
require(width >= 0) { "Width must not be negative" }
|
||||||
require(supportedSizeClasses.isNotEmpty()) { "Must support at least one size class" }
|
require(supportedSizeClasses.isNotEmpty()) { "Must support at least one size class" }
|
||||||
@ -323,7 +325,9 @@ value class WindowHeightSizeClass private constructor(private val value: Int) :
|
|||||||
/** Calculates the [WindowHeightSizeClass] for a given [height] */
|
/** Calculates the [WindowHeightSizeClass] for a given [height] */
|
||||||
internal fun fromHeight(height: Dp): WindowHeightSizeClass {
|
internal fun fromHeight(height: Dp): WindowHeightSizeClass {
|
||||||
return fromHeight(
|
return fromHeight(
|
||||||
with(defaultDensity) { height.toPx() }, defaultDensity, DefaultSizeClasses
|
with(defaultDensity) { height.toPx() },
|
||||||
|
defaultDensity,
|
||||||
|
DefaultSizeClasses,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +338,7 @@ value class WindowHeightSizeClass private constructor(private val value: Int) :
|
|||||||
internal fun fromHeight(
|
internal fun fromHeight(
|
||||||
height: Float,
|
height: Float,
|
||||||
density: Density,
|
density: Density,
|
||||||
supportedSizeClasses: Set<WindowHeightSizeClass>
|
supportedSizeClasses: Set<WindowHeightSizeClass>,
|
||||||
): WindowHeightSizeClass {
|
): WindowHeightSizeClass {
|
||||||
require(height >= 0) { "Width must not be negative" }
|
require(height >= 0) { "Width must not be negative" }
|
||||||
require(supportedSizeClasses.isNotEmpty()) { "Must support at least one size class" }
|
require(supportedSizeClasses.isNotEmpty()) { "Must support at least one size class" }
|
||||||
|
@ -44,16 +44,22 @@ fun NavGraphBuilder.unittoComposable(
|
|||||||
route: String,
|
route: String,
|
||||||
arguments: List<NamedNavArgument> = emptyList(),
|
arguments: List<NamedNavArgument> = emptyList(),
|
||||||
deepLinks: List<NavDeepLink> = emptyList(),
|
deepLinks: List<NavDeepLink> = emptyList(),
|
||||||
enterTransition: (@JvmSuppressWildcards
|
enterTransition: (
|
||||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? = { unittoFadeIn() },
|
@JvmSuppressWildcards
|
||||||
exitTransition: (@JvmSuppressWildcards
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?
|
||||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? = { unittoFadeOut() },
|
)? = { unittoFadeIn() },
|
||||||
popEnterTransition: (@JvmSuppressWildcards
|
exitTransition: (
|
||||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? =
|
@JvmSuppressWildcards
|
||||||
enterTransition,
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?
|
||||||
popExitTransition: (@JvmSuppressWildcards
|
)? = { unittoFadeOut() },
|
||||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? =
|
popEnterTransition: (
|
||||||
exitTransition,
|
@JvmSuppressWildcards
|
||||||
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?
|
||||||
|
)? = enterTransition,
|
||||||
|
popExitTransition: (
|
||||||
|
@JvmSuppressWildcards
|
||||||
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?
|
||||||
|
)? = exitTransition,
|
||||||
content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit,
|
content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit,
|
||||||
): Unit = composable(
|
): Unit = composable(
|
||||||
route = route,
|
route = route,
|
||||||
@ -79,22 +85,26 @@ fun NavGraphBuilder.unittoStackedComposable(
|
|||||||
enterTransition = {
|
enterTransition = {
|
||||||
slideInHorizontally(
|
slideInHorizontally(
|
||||||
animationSpec = unittoEnterTween(),
|
animationSpec = unittoEnterTween(),
|
||||||
initialOffsetX = { (it * 0.2f).toInt() }) + unittoFadeIn()
|
initialOffsetX = { (it * 0.2f).toInt() },
|
||||||
|
) + unittoFadeIn()
|
||||||
},
|
},
|
||||||
exitTransition = {
|
exitTransition = {
|
||||||
slideOutHorizontally(
|
slideOutHorizontally(
|
||||||
animationSpec = unittoExitTween(),
|
animationSpec = unittoExitTween(),
|
||||||
targetOffsetX = { -(it * 0.2f).toInt() }) + unittoFadeOut()
|
targetOffsetX = { -(it * 0.2f).toInt() },
|
||||||
|
) + unittoFadeOut()
|
||||||
},
|
},
|
||||||
popEnterTransition = {
|
popEnterTransition = {
|
||||||
slideInHorizontally(
|
slideInHorizontally(
|
||||||
animationSpec = unittoEnterTween(),
|
animationSpec = unittoEnterTween(),
|
||||||
initialOffsetX = { -(it * 0.2f).toInt() }) + unittoFadeIn()
|
initialOffsetX = { -(it * 0.2f).toInt() },
|
||||||
|
) + unittoFadeIn()
|
||||||
},
|
},
|
||||||
popExitTransition = {
|
popExitTransition = {
|
||||||
slideOutHorizontally(
|
slideOutHorizontally(
|
||||||
animationSpec = unittoExitTween(),
|
animationSpec = unittoExitTween(),
|
||||||
targetOffsetX = { (it * 0.2f).toInt() }) + unittoFadeOut()
|
targetOffsetX = { (it * 0.2f).toInt() },
|
||||||
|
) + unittoFadeOut()
|
||||||
},
|
},
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
@ -113,10 +123,10 @@ fun NavGraphBuilder.unittoNavigation(
|
|||||||
exitTransition: (AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? =
|
exitTransition: (AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? =
|
||||||
null,
|
null,
|
||||||
popEnterTransition: (
|
popEnterTransition: (
|
||||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?
|
||||||
)? = enterTransition,
|
)? = enterTransition,
|
||||||
popExitTransition: (
|
popExitTransition: (
|
||||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?
|
||||||
)? = exitTransition,
|
)? = exitTransition,
|
||||||
builder: NavGraphBuilder.() -> Unit,
|
builder: NavGraphBuilder.() -> Unit,
|
||||||
): Unit = navigation(
|
): Unit = navigation(
|
||||||
@ -128,7 +138,7 @@ fun NavGraphBuilder.unittoNavigation(
|
|||||||
exitTransition = exitTransition,
|
exitTransition = exitTransition,
|
||||||
popEnterTransition = popEnterTransition,
|
popEnterTransition = popEnterTransition,
|
||||||
popExitTransition = popExitTransition,
|
popExitTransition = popExitTransition,
|
||||||
builder = builder
|
builder = builder,
|
||||||
)
|
)
|
||||||
|
|
||||||
private const val ENTER_DURATION = 350
|
private const val ENTER_DURATION = 350
|
||||||
|
@ -48,7 +48,7 @@ suspend fun Context.pushDynamicShortcut(
|
|||||||
val shortcutCompat = shortcutInfoCompat(
|
val shortcutCompat = shortcutInfoCompat(
|
||||||
context = context,
|
context = context,
|
||||||
route = drawerItem.graph,
|
route = drawerItem.graph,
|
||||||
shortcut = shortcut
|
shortcut = shortcut,
|
||||||
)
|
)
|
||||||
|
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
@ -71,7 +71,7 @@ fun Context.addShortcut(
|
|||||||
val shortcutCompat = shortcutInfoCompat(
|
val shortcutCompat = shortcutInfoCompat(
|
||||||
context = context,
|
context = context,
|
||||||
route = drawerItem.graph,
|
route = drawerItem.graph,
|
||||||
shortcut = shortcut
|
shortcut = shortcut,
|
||||||
)
|
)
|
||||||
|
|
||||||
val shortCutIntent = ShortcutManagerCompat.createShortcutResultIntent(context, shortcutCompat)
|
val shortCutIntent = ShortcutManagerCompat.createShortcutResultIntent(context, shortcutCompat)
|
||||||
@ -80,7 +80,7 @@ fun Context.addShortcut(
|
|||||||
ShortcutManagerCompat.requestPinShortcut(
|
ShortcutManagerCompat.requestPinShortcut(
|
||||||
context,
|
context,
|
||||||
shortcutCompat,
|
shortcutCompat,
|
||||||
PendingIntent.getBroadcast(context, 0, shortCutIntent, FLAG_IMMUTABLE).intentSender
|
PendingIntent.getBroadcast(context, 0, shortCutIntent, FLAG_IMMUTABLE).intentSender,
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
showToast(context, e.message ?: "Error")
|
showToast(context, e.message ?: "Error")
|
||||||
@ -101,8 +101,8 @@ private fun Context.shortcutInfoCompat(
|
|||||||
Intent.ACTION_VIEW,
|
Intent.ACTION_VIEW,
|
||||||
Uri.parse("app://com.sadellie.unitto/$route"),
|
Uri.parse("app://com.sadellie.unitto/$route"),
|
||||||
context,
|
context,
|
||||||
context.javaClass
|
context.javaClass,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ fun Button(
|
|||||||
border: BorderStroke? = null,
|
border: BorderStroke? = null,
|
||||||
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
content: @Composable RowScope.() -> Unit
|
content: @Composable RowScope.() -> Unit,
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier.squashable(
|
modifier = modifier.squashable(
|
||||||
@ -58,7 +58,7 @@ fun Button(
|
|||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
cornerRadiusRange = 30..50,
|
cornerRadiusRange = 30..50,
|
||||||
enabled = enabled
|
enabled = enabled,
|
||||||
),
|
),
|
||||||
color = containerColor,
|
color = containerColor,
|
||||||
contentColor = contentColor,
|
contentColor = contentColor,
|
||||||
@ -70,12 +70,12 @@ fun Button(
|
|||||||
Modifier
|
Modifier
|
||||||
.defaultMinSize(
|
.defaultMinSize(
|
||||||
minWidth = ButtonDefaults.MinWidth,
|
minWidth = ButtonDefaults.MinWidth,
|
||||||
minHeight = ButtonDefaults.MinHeight
|
minHeight = ButtonDefaults.MinHeight,
|
||||||
)
|
)
|
||||||
.padding(contentPadding),
|
.padding(contentPadding),
|
||||||
horizontalArrangement = Arrangement.Center,
|
horizontalArrangement = Arrangement.Center,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
content = content
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,16 +70,16 @@ fun FilterChip(
|
|||||||
.border(
|
.border(
|
||||||
width = 1.dp,
|
width = 1.dp,
|
||||||
color = borderColor.value,
|
color = borderColor.value,
|
||||||
shape = FilterChipDefaults.shape
|
shape = FilterChipDefaults.shape,
|
||||||
)
|
)
|
||||||
.height(FilterChipDefaults.Height)
|
.height(FilterChipDefaults.Height)
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = label,
|
text = label,
|
||||||
style = MaterialTheme.typography.labelLarge,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
color = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant
|
color = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,17 +100,17 @@ fun AssistChip(
|
|||||||
.border(
|
.border(
|
||||||
width = 1.dp,
|
width = 1.dp,
|
||||||
color = MaterialTheme.colorScheme.outline,
|
color = MaterialTheme.colorScheme.outline,
|
||||||
shape = AssistChipDefaults.shape
|
shape = AssistChipDefaults.shape,
|
||||||
)
|
)
|
||||||
.height(32.dp)
|
.height(32.dp)
|
||||||
.padding(horizontal = 8.dp),
|
.padding(horizontal = 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.height(AssistChipDefaults.IconSize),
|
modifier = Modifier.height(AssistChipDefaults.IconSize),
|
||||||
imageVector = imageVector,
|
imageVector = imageVector,
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ fun PreviewAssistChip() {
|
|||||||
AssistChip(
|
AssistChip(
|
||||||
onClick = {},
|
onClick = {},
|
||||||
imageVector = Icons.Default.Settings,
|
imageVector = Icons.Default.Settings,
|
||||||
contentDescription = ""
|
contentDescription = "",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,13 +33,13 @@ internal fun DrawerItem(
|
|||||||
destination: DrawerItem,
|
destination: DrawerItem,
|
||||||
icon: ImageVector,
|
icon: ImageVector,
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
onClick: (DrawerItem) -> Unit
|
onClick: (DrawerItem) -> Unit,
|
||||||
) {
|
) {
|
||||||
NavigationDrawerItem(
|
NavigationDrawerItem(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
label = { Text(stringResource(destination.name)) },
|
label = { Text(stringResource(destination.name)) },
|
||||||
icon = { Icon(icon, stringResource(destination.name)) },
|
icon = { Icon(icon, stringResource(destination.name)) },
|
||||||
selected = selected,
|
selected = selected,
|
||||||
onClick = { onClick(destination) }
|
onClick = { onClick(destination) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,8 @@ fun Header(
|
|||||||
start = 56.dp,
|
start = 56.dp,
|
||||||
end = 16.dp,
|
end = 16.dp,
|
||||||
top = 24.dp,
|
top = 24.dp,
|
||||||
bottom = 12.dp
|
bottom = 12.dp,
|
||||||
)
|
),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@ -53,6 +53,6 @@ fun Header(
|
|||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
text = text,
|
text = text,
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -64,15 +64,24 @@ fun BasicKeyboardButton(
|
|||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.squashable(
|
.squashable(
|
||||||
onClick = { onClick(); vibrate() },
|
onClick = {
|
||||||
onLongClick = if (onLongClick != null) { { onLongClick(); vibrate() } } else null,
|
onClick()
|
||||||
|
vibrate()
|
||||||
|
},
|
||||||
|
onLongClick = if (onLongClick != null) {
|
||||||
|
{
|
||||||
|
onLongClick()
|
||||||
|
vibrate()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
cornerRadiusRange = 30..50,
|
cornerRadiusRange = 30..50,
|
||||||
animationSpec = tween(200)
|
animationSpec = tween(200),
|
||||||
)
|
)
|
||||||
.background(containerColor)
|
.background(containerColor),
|
||||||
,
|
contentAlignment = Alignment.Center,
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
@ -84,7 +93,7 @@ fun BasicKeyboardButton(
|
|||||||
scaleX = contentHeight
|
scaleX = contentHeight
|
||||||
scaleY = contentHeight
|
scaleY = contentHeight
|
||||||
},
|
},
|
||||||
tint = iconColor
|
tint = iconColor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,22 +182,25 @@ fun KeyboardButtonTertiary(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
object KeyboardButtonToken {
|
||||||
* Mostly for main button in portrait mode. Changes icon size inside.
|
|
||||||
*/
|
|
||||||
const val KeyboardButtonContentHeightTall = 1.1f
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mostly for additional button in portrait mode. Changes icon size inside.
|
* Mostly for main button in portrait mode. Changes icon size inside.
|
||||||
*/
|
*/
|
||||||
const val KeyboardButtonContentHeightTallAdditional = 1.6f
|
const val CONTENT_HEIGHT_TALL = 1.1f
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mostly for main button in landscape mode. Changes icon size inside.
|
* Mostly for additional button in portrait mode. Changes icon size inside.
|
||||||
*/
|
*/
|
||||||
const val KeyboardButtonContentHeightShort = 1.3f
|
const val CONTENT_HEIGHT_TALL_ADDITIONAL = 1.6f
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mostly for additional button in landscape mode. Changes icon size inside.
|
* Mostly for main button in landscape mode. Changes icon size inside.
|
||||||
*/
|
*/
|
||||||
const val KeyboardButtonContentHeightShortAdditional = 1.1f
|
const val CONTENT_HEIGHT_SHORT = 1.3f
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mostly for additional button in landscape mode. Changes icon size inside.
|
||||||
|
*/
|
||||||
|
const val CONTENT_HEIGHT_SHORT_ADDITIONAL = 1.1f
|
||||||
|
}
|
||||||
|
@ -49,7 +49,7 @@ fun KeypadFlow(
|
|||||||
columns: Int,
|
columns: Int,
|
||||||
@IntRange(0, 100) horizontalPadding: Int = 10,
|
@IntRange(0, 100) horizontalPadding: Int = 10,
|
||||||
@IntRange(0, 100) verticalPadding: Int = 10,
|
@IntRange(0, 100) verticalPadding: Int = 10,
|
||||||
content: @Composable FlowRowScope.(width: Float, height: Float) -> Unit
|
content: @Composable FlowRowScope.(width: Float, height: Float) -> Unit,
|
||||||
) {
|
) {
|
||||||
val height: Float = remember { (1f - verticalPadding / 100f) / rows }
|
val height: Float = remember { (1f - verticalPadding / 100f) / rows }
|
||||||
val width: Float = remember { (1f - horizontalPadding / 100f) / columns }
|
val width: Float = remember { (1f - horizontalPadding / 100f) / columns }
|
||||||
@ -58,7 +58,7 @@ fun KeypadFlow(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
maxItemsInEachRow = columns,
|
maxItemsInEachRow = columns,
|
||||||
horizontalArrangement = Arrangement.SpaceAround,
|
horizontalArrangement = Arrangement.SpaceAround,
|
||||||
verticalArrangement = Arrangement.SpaceAround
|
verticalArrangement = Arrangement.SpaceAround,
|
||||||
) {
|
) {
|
||||||
content(width, height)
|
content(width, height)
|
||||||
}
|
}
|
||||||
|
@ -57,12 +57,12 @@ fun ListItem(
|
|||||||
.padding(start = 16.dp, end = 24.dp)
|
.padding(start = 16.dp, end = 24.dp)
|
||||||
.heightIn(min = if (supportingContent == null) 56.dp else 72.dp),
|
.heightIn(min = if (supportingContent == null) 56.dp else 72.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
leadingContent?.let {
|
leadingContent?.let {
|
||||||
ProvideColor(
|
ProvideColor(
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
content = it
|
content = it,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,20 +70,20 @@ fun ListItem(
|
|||||||
ProvideStyle(
|
ProvideStyle(
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
textStyle = MaterialTheme.typography.bodyLarge,
|
textStyle = MaterialTheme.typography.bodyLarge,
|
||||||
content = headlineContent
|
content = headlineContent,
|
||||||
)
|
)
|
||||||
supportingContent?.let {
|
supportingContent?.let {
|
||||||
ProvideStyle(
|
ProvideStyle(
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
textStyle = MaterialTheme.typography.bodyMedium,
|
textStyle = MaterialTheme.typography.bodyMedium,
|
||||||
content = it
|
content = it,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trailingContent?.let {
|
trailingContent?.let {
|
||||||
ProvideColor(
|
ProvideColor(
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
content = it
|
content = it,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,10 +106,10 @@ fun ListItem(
|
|||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = iconDescription,
|
contentDescription = iconDescription,
|
||||||
modifier = Modifier.size(24.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
trailingContent = trailing
|
trailingContent = trailing,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -120,14 +120,14 @@ fun ListItem(
|
|||||||
iconDescription: String = headlineText,
|
iconDescription: String = headlineText,
|
||||||
supportingText: String? = null,
|
supportingText: String? = null,
|
||||||
switchState: Boolean,
|
switchState: Boolean,
|
||||||
onSwitchChange: (Boolean) -> Unit
|
onSwitchChange: (Boolean) -> Unit,
|
||||||
) = ListItem(
|
) = ListItem(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clickable(
|
.clickable(
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
indication = rememberRipple(),
|
indication = rememberRipple(),
|
||||||
onClick = { onSwitchChange(!switchState) },
|
onClick = { onSwitchChange(!switchState) },
|
||||||
role = Role.Switch
|
role = Role.Switch,
|
||||||
),
|
),
|
||||||
headlineText = headlineText,
|
headlineText = headlineText,
|
||||||
supportingText = supportingText,
|
supportingText = supportingText,
|
||||||
@ -136,9 +136,9 @@ fun ListItem(
|
|||||||
trailing = {
|
trailing = {
|
||||||
Switch(
|
Switch(
|
||||||
checked = switchState,
|
checked = switchState,
|
||||||
onCheckedChange = { onSwitchChange(it) }
|
onCheckedChange = { onSwitchChange(it) },
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@ -152,7 +152,7 @@ fun PreviewListItem1() {
|
|||||||
leadingContent = {
|
leadingContent = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Home,
|
imageVector = Icons.Default.Home,
|
||||||
contentDescription = null
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -171,7 +171,7 @@ fun PreviewListItem1() {
|
|||||||
supportingText = "Support text support text support text support text",
|
supportingText = "Support text support text support text support text",
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
trailing = {},
|
trailing = {},
|
||||||
iconDescription = ""
|
iconDescription = "",
|
||||||
)
|
)
|
||||||
|
|
||||||
ListItem(
|
ListItem(
|
||||||
|
@ -47,7 +47,7 @@ fun Modifier.squashable(
|
|||||||
val cornerRadius: Int by animateIntAsState(
|
val cornerRadius: Int by animateIntAsState(
|
||||||
targetValue = if (isPressed) cornerRadiusRange.first else cornerRadiusRange.last,
|
targetValue = if (isPressed) cornerRadiusRange.first else cornerRadiusRange.last,
|
||||||
animationSpec = animationSpec,
|
animationSpec = animationSpec,
|
||||||
label = "Squashed animation"
|
label = "Squashed animation",
|
||||||
)
|
)
|
||||||
|
|
||||||
this
|
this
|
||||||
@ -58,7 +58,7 @@ fun Modifier.squashable(
|
|||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
indication = rememberRipple(),
|
indication = rememberRipple(),
|
||||||
role = role,
|
role = role,
|
||||||
enabled = enabled
|
enabled = enabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ fun Modifier.squashable(
|
|||||||
val cornerRadius: Dp by animateDpAsState(
|
val cornerRadius: Dp by animateDpAsState(
|
||||||
targetValue = if (isPressed) cornerRadiusRange.start else cornerRadiusRange.endInclusive,
|
targetValue = if (isPressed) cornerRadiusRange.start else cornerRadiusRange.endInclusive,
|
||||||
animationSpec = animationSpec,
|
animationSpec = animationSpec,
|
||||||
label = "Squashed animation"
|
label = "Squashed animation",
|
||||||
)
|
)
|
||||||
|
|
||||||
this
|
this
|
||||||
@ -86,6 +86,6 @@ fun Modifier.squashable(
|
|||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
indication = rememberRipple(),
|
indication = rememberRipple(),
|
||||||
role = role,
|
role = role,
|
||||||
enabled = enabled
|
enabled = enabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ fun NavigateUpButton(onClick: () -> Unit) {
|
|||||||
IconButton(onClick = onClick) {
|
IconButton(onClick = onClick) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.AutoMirrored.Outlined.ArrowBack,
|
Icons.AutoMirrored.Outlined.ArrowBack,
|
||||||
contentDescription = stringResource(R.string.navigate_up_description)
|
contentDescription = stringResource(R.string.navigate_up_description),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ class DrawerState(
|
|||||||
initialValue = initialValue,
|
initialValue = initialValue,
|
||||||
positionalThreshold = { distance -> distance * 0.5f },
|
positionalThreshold = { distance -> distance * 0.5f },
|
||||||
velocityThreshold = { with(requireNotNull(density)) { 400.dp.toPx() } },
|
velocityThreshold = { with(requireNotNull(density)) { 400.dp.toPx() } },
|
||||||
animationSpec = tween()
|
animationSpec = tween(),
|
||||||
)
|
)
|
||||||
|
|
||||||
val isOpen: Boolean
|
val isOpen: Boolean
|
||||||
@ -89,10 +89,10 @@ class DrawerState(
|
|||||||
suspend fun close() = anchoredDraggableState.animateTo(DrawerValue.Closed)
|
suspend fun close() = anchoredDraggableState.animateTo(DrawerValue.Closed)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
internal fun Saver() =
|
internal fun saver() =
|
||||||
Saver<DrawerState, DrawerValue>(
|
Saver<DrawerState, DrawerValue>(
|
||||||
save = { it.currentValue },
|
save = { it.currentValue },
|
||||||
restore = { DrawerState(it) }
|
restore = { DrawerState(it) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ class DrawerState(
|
|||||||
fun rememberDrawerState(
|
fun rememberDrawerState(
|
||||||
initialValue: DrawerValue = DrawerValue.Closed,
|
initialValue: DrawerValue = DrawerValue.Closed,
|
||||||
): DrawerState {
|
): DrawerState {
|
||||||
return rememberSaveable(saver = DrawerState.Saver()) {
|
return rememberSaveable(saver = DrawerState.saver()) {
|
||||||
DrawerState(initialValue)
|
DrawerState(initialValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,17 +124,17 @@ fun NavigationDrawer(
|
|||||||
PermanentDrawerSheet(
|
PermanentDrawerSheet(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState()),
|
||||||
) {
|
) {
|
||||||
SheetContent(
|
SheetContent(
|
||||||
mainTabs = mainTabs,
|
mainTabs = mainTabs,
|
||||||
additionalTabs = additionalTabs,
|
additionalTabs = additionalTabs,
|
||||||
currentDestination = currentDestination,
|
currentDestination = currentDestination,
|
||||||
onItemClick = onItemClick
|
onItemClick = onItemClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
content = content
|
content = content,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
UnittoModalNavigationDrawer(
|
UnittoModalNavigationDrawer(
|
||||||
@ -143,19 +143,19 @@ fun NavigationDrawer(
|
|||||||
ModalDrawerSheet(
|
ModalDrawerSheet(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState()),
|
||||||
) {
|
) {
|
||||||
SheetContent(
|
SheetContent(
|
||||||
mainTabs = mainTabs,
|
mainTabs = mainTabs,
|
||||||
additionalTabs = additionalTabs,
|
additionalTabs = additionalTabs,
|
||||||
currentDestination = currentDestination,
|
currentDestination = currentDestination,
|
||||||
onItemClick = onItemClick
|
onItemClick = onItemClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
gesturesEnabled = gesturesEnabled,
|
gesturesEnabled = gesturesEnabled,
|
||||||
state = state,
|
state = state,
|
||||||
content = content
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +173,7 @@ private fun UnittoModalNavigationDrawer(
|
|||||||
val drawerScope = rememberCoroutineScope()
|
val drawerScope = rememberCoroutineScope()
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier.fillMaxSize()
|
modifier = modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
val drawerWidth = 360.dp
|
val drawerWidth = 360.dp
|
||||||
val drawerWidthPx = with(density) { drawerWidth.toPx() }
|
val drawerWidthPx = with(density) { drawerWidth.toPx() }
|
||||||
@ -186,7 +186,7 @@ private fun UnittoModalNavigationDrawer(
|
|||||||
DraggableAnchors {
|
DraggableAnchors {
|
||||||
DrawerValue.Closed at minValue
|
DrawerValue.Closed at minValue
|
||||||
DrawerValue.Open at maxValue
|
DrawerValue.Open at maxValue
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ private fun UnittoModalNavigationDrawer(
|
|||||||
state = state.anchoredDraggableState,
|
state = state.anchoredDraggableState,
|
||||||
orientation = Orientation.Horizontal,
|
orientation = Orientation.Horizontal,
|
||||||
enabled = gesturesEnabled or state.isOpen,
|
enabled = gesturesEnabled or state.isOpen,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
Scrim(
|
Scrim(
|
||||||
@ -210,7 +210,9 @@ private fun UnittoModalNavigationDrawer(
|
|||||||
onClose = { if (gesturesEnabled) drawerScope.launch { state.close() } },
|
onClose = { if (gesturesEnabled) drawerScope.launch { state.close() } },
|
||||||
fraction = {
|
fraction = {
|
||||||
fraction(
|
fraction(
|
||||||
minValue, maxValue, state.anchoredDraggableState.requireOffset()
|
minValue,
|
||||||
|
maxValue,
|
||||||
|
state.anchoredDraggableState.requireOffset(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -224,14 +226,14 @@ private fun UnittoModalNavigationDrawer(
|
|||||||
.anchoredDraggableState
|
.anchoredDraggableState
|
||||||
.requireOffset()
|
.requireOffset()
|
||||||
.roundToInt(),
|
.roundToInt(),
|
||||||
y = 0
|
y = 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.anchoredDraggable(
|
.anchoredDraggable(
|
||||||
state = state.anchoredDraggableState,
|
state = state.anchoredDraggableState,
|
||||||
orientation = Orientation.Horizontal,
|
orientation = Orientation.Horizontal,
|
||||||
enabled = gesturesEnabled or state.isOpen,
|
enabled = gesturesEnabled or state.isOpen,
|
||||||
)
|
),
|
||||||
) {
|
) {
|
||||||
drawerContent()
|
drawerContent()
|
||||||
}
|
}
|
||||||
@ -254,7 +256,7 @@ private fun Scrim(
|
|||||||
Canvas(
|
Canvas(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.then(dismissDrawer)
|
.then(dismissDrawer),
|
||||||
) {
|
) {
|
||||||
drawRect(color, alpha = fraction())
|
drawRect(color, alpha = fraction())
|
||||||
}
|
}
|
||||||
@ -266,12 +268,12 @@ private fun fraction(a: Float, b: Float, pos: Float) =
|
|||||||
@Preview(
|
@Preview(
|
||||||
backgroundColor = 0xFFC8F7D4,
|
backgroundColor = 0xFFC8F7D4,
|
||||||
showBackground = true,
|
showBackground = true,
|
||||||
device = "spec:width=320dp,height=500dp,dpi=320"
|
device = "spec:width=320dp,height=500dp,dpi=320",
|
||||||
)
|
)
|
||||||
@Preview(
|
@Preview(
|
||||||
backgroundColor = 0xFFC8F7D4,
|
backgroundColor = 0xFFC8F7D4,
|
||||||
showBackground = true,
|
showBackground = true,
|
||||||
device = "spec:width=440dp,height=500dp,dpi=440"
|
device = "spec:width=440dp,height=500dp,dpi=440",
|
||||||
)
|
)
|
||||||
@Composable
|
@Composable
|
||||||
private fun PreviewUnittoModalNavigationDrawerClose() {
|
private fun PreviewUnittoModalNavigationDrawerClose() {
|
||||||
@ -290,11 +292,11 @@ private fun PreviewUnittoModalNavigationDrawerClose() {
|
|||||||
Column {
|
Column {
|
||||||
Text(text = "Content")
|
Text(text = "Content")
|
||||||
Button(
|
Button(
|
||||||
onClick = { corScope.launch { drawerState.open() } }
|
onClick = { corScope.launch { drawerState.open() } },
|
||||||
) {
|
) {
|
||||||
Text(text = "BUTTON")
|
Text(text = "BUTTON")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -81,12 +81,12 @@ fun PagedIsland(
|
|||||||
corScope.launch {
|
corScope.launch {
|
||||||
pagerState.animateScrollToPage(
|
pagerState.animateScrollToPage(
|
||||||
// Animate to first page if target page is out of bounds
|
// Animate to first page if target page is out of bounds
|
||||||
if (targetPage >= pagerState.pageCount) 0 else targetPage
|
if (targetPage >= pagerState.pageCount) 0 else targetPage,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background(backgroundColor)
|
.background(backgroundColor)
|
||||||
.padding(16.dp)
|
.padding(16.dp),
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -105,7 +105,7 @@ fun PagedIsland(
|
|||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.Top,
|
verticalAlignment = Alignment.Top,
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
pageContent = { page -> pageContent(page % pageCount) }
|
pageContent = { page -> pageContent(page % pageCount) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,11 @@ fun PortraitLandscape(
|
|||||||
.weight(1f)
|
.weight(1f)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(
|
.padding(
|
||||||
it.maxWidth * 0.015f, 0.dp,
|
it.maxWidth * 0.015f,
|
||||||
it.maxHeight * 0.03f, it.maxHeight * 0.03f)
|
0.dp,
|
||||||
|
it.maxHeight * 0.03f,
|
||||||
|
it.maxHeight * 0.03f,
|
||||||
|
)
|
||||||
content1(contentModifier)
|
content1(contentModifier)
|
||||||
content2(contentModifier)
|
content2(contentModifier)
|
||||||
}
|
}
|
||||||
|
@ -41,10 +41,10 @@ fun ScaffoldWithLargeTopBar(
|
|||||||
title: String,
|
title: String,
|
||||||
navigationIcon: @Composable () -> Unit,
|
navigationIcon: @Composable () -> Unit,
|
||||||
actions: @Composable RowScope.() -> Unit = {},
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
content: @Composable (PaddingValues) -> Unit
|
content: @Composable (PaddingValues) -> Unit,
|
||||||
) {
|
) {
|
||||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
|
||||||
rememberTopAppBarState()
|
rememberTopAppBarState(),
|
||||||
)
|
)
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -56,9 +56,9 @@ fun ScaffoldWithLargeTopBar(
|
|||||||
},
|
},
|
||||||
navigationIcon = navigationIcon,
|
navigationIcon = navigationIcon,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
actions = actions
|
actions = actions,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = content
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ fun ScaffoldWithTopBar(
|
|||||||
floatingActionButton: @Composable () -> Unit = {},
|
floatingActionButton: @Composable () -> Unit = {},
|
||||||
floatingActionButtonPosition: FabPosition = FabPosition.End,
|
floatingActionButtonPosition: FabPosition = FabPosition.End,
|
||||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||||
content: @Composable (PaddingValues) -> Unit
|
content: @Composable (PaddingValues) -> Unit,
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
@ -67,7 +67,7 @@ fun ScaffoldWithTopBar(
|
|||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = LocalWindowSize.current.heightSizeClass > WindowHeightSizeClass.Compact,
|
visible = LocalWindowSize.current.heightSizeClass > WindowHeightSizeClass.Compact,
|
||||||
enter = slideInVertically() + fadeIn(),
|
enter = slideInVertically() + fadeIn(),
|
||||||
exit = slideOutVertically() + fadeOut()
|
exit = slideOutVertically() + fadeOut(),
|
||||||
) {
|
) {
|
||||||
CenterAlignedTopAppBar(
|
CenterAlignedTopAppBar(
|
||||||
title = title,
|
title = title,
|
||||||
@ -84,6 +84,6 @@ fun ScaffoldWithTopBar(
|
|||||||
},
|
},
|
||||||
floatingActionButton = floatingActionButton,
|
floatingActionButton = floatingActionButton,
|
||||||
floatingActionButtonPosition = floatingActionButtonPosition,
|
floatingActionButtonPosition = floatingActionButtonPosition,
|
||||||
content = content
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ fun SearchBar(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
.windowInsetsPadding(TopAppBarDefaults.windowInsets)
|
.windowInsetsPadding(TopAppBarDefaults.windowInsets)
|
||||||
.height(height),
|
.height(height),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -121,10 +121,9 @@ fun SearchBar(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
) {
|
) {
|
||||||
ProvideColor(MaterialTheme.colorScheme.onSurface) {
|
ProvideColor(MaterialTheme.colorScheme.onSurface) {
|
||||||
|
|
||||||
NavigateButton { if (notEmpty) clear() else navigateUp() }
|
NavigateButton { if (notEmpty) clear() else navigateUp() }
|
||||||
|
|
||||||
SearchTextField(
|
SearchTextField(
|
||||||
@ -135,7 +134,7 @@ fun SearchBar(
|
|||||||
value = query,
|
value = query,
|
||||||
placeholder = stringResource(R.string.search_text_field_placeholder),
|
placeholder = stringResource(R.string.search_text_field_placeholder),
|
||||||
onValueChange = onQueryChange,
|
onValueChange = onQueryChange,
|
||||||
onSearch = onSearch
|
onSearch = onSearch,
|
||||||
)
|
)
|
||||||
|
|
||||||
ClearButton(notEmpty, ::clear)
|
ClearButton(notEmpty, ::clear)
|
||||||
@ -152,7 +151,7 @@ private fun SearchTextField(
|
|||||||
value: TextFieldValue,
|
value: TextFieldValue,
|
||||||
placeholder: String,
|
placeholder: String,
|
||||||
onValueChange: (TextFieldValue) -> Unit,
|
onValueChange: (TextFieldValue) -> Unit,
|
||||||
onSearch: KeyboardActionScope.() -> Unit
|
onSearch: KeyboardActionScope.() -> Unit,
|
||||||
) {
|
) {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
@ -171,33 +170,33 @@ private fun SearchTextField(
|
|||||||
modifier = Modifier.alpha(0.7f),
|
modifier = Modifier.alpha(0.7f),
|
||||||
text = placeholder,
|
text = placeholder,
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
color = MaterialTheme.colorScheme.onSurface
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SearchButton(
|
private fun SearchButton(
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
SearchBarIconButton(onClick) {
|
SearchBarIconButton(onClick) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Search,
|
imageVector = Icons.Default.Search,
|
||||||
contentDescription = stringResource(R.string.search_button_description)
|
contentDescription = stringResource(R.string.search_button_description),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NavigateButton(
|
private fun NavigateButton(
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
SearchBarIconButton(onClick) {
|
SearchBarIconButton(onClick) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.AutoMirrored.Outlined.ArrowBack,
|
imageVector = Icons.AutoMirrored.Outlined.ArrowBack,
|
||||||
contentDescription = stringResource(R.string.navigate_up_description)
|
contentDescription = stringResource(R.string.navigate_up_description),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,17 +204,17 @@ private fun NavigateButton(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun ClearButton(
|
private fun ClearButton(
|
||||||
visible: Boolean,
|
visible: Boolean,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = visible,
|
visible = visible,
|
||||||
enter = fadeIn(),
|
enter = fadeIn(),
|
||||||
exit = fadeOut()
|
exit = fadeOut(),
|
||||||
) {
|
) {
|
||||||
SearchBarIconButton(onClick) {
|
SearchBarIconButton(onClick) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Outlined.Clear,
|
imageVector = Icons.Outlined.Clear,
|
||||||
contentDescription = stringResource(R.string.clear_input_description)
|
contentDescription = stringResource(R.string.clear_input_description),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,7 +223,7 @@ private fun ClearButton(
|
|||||||
@Composable
|
@Composable
|
||||||
fun SearchBarIconButton(
|
fun SearchBarIconButton(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -236,10 +235,10 @@ fun SearchBarIconButton(
|
|||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
indication = rememberRipple(
|
indication = rememberRipple(
|
||||||
bounded = false,
|
bounded = false,
|
||||||
radius = 20.dp
|
radius = 20.dp,
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
content()
|
content()
|
||||||
}
|
}
|
||||||
@ -259,6 +258,6 @@ fun UnittoSearchBarPreview() {
|
|||||||
query = TextFieldValue("test"),
|
query = TextFieldValue("test"),
|
||||||
onQueryChange = {},
|
onQueryChange = {},
|
||||||
navigateUp = {},
|
navigateUp = {},
|
||||||
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -41,29 +41,29 @@ import com.sadellie.unitto.core.base.R
|
|||||||
fun SearchPlaceholder(
|
fun SearchPlaceholder(
|
||||||
onButtonClick: () -> Unit,
|
onButtonClick: () -> Unit,
|
||||||
supportText: String,
|
supportText: String,
|
||||||
buttonLabel: String
|
buttonLabel: String,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.SearchOff,
|
imageVector = Icons.Default.SearchOff,
|
||||||
contentDescription = stringResource(R.string.no_results_description),
|
contentDescription = stringResource(R.string.no_results_description),
|
||||||
modifier = Modifier.size(48.dp)
|
modifier = Modifier.size(48.dp),
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.no_results_label),
|
text = stringResource(R.string.no_results_label),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = MaterialTheme.typography.bodyLarge
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = supportText,
|
text = supportText,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = MaterialTheme.typography.bodySmall
|
style = MaterialTheme.typography.bodySmall,
|
||||||
)
|
)
|
||||||
ElevatedButton(onClick = onButtonClick) {
|
ElevatedButton(onClick = onButtonClick) {
|
||||||
Text(text = buttonLabel)
|
Text(text = buttonLabel)
|
||||||
|
@ -47,14 +47,14 @@ import androidx.compose.ui.unit.dp
|
|||||||
@Composable
|
@Composable
|
||||||
fun SegmentedButtonsRow(
|
fun SegmentedButtonsRow(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
content: @Composable RowScope.() -> Unit
|
content: @Composable RowScope.() -> Unit,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier
|
modifier
|
||||||
.width(IntrinsicSize.Max)
|
.width(IntrinsicSize.Max)
|
||||||
.height(40.dp)
|
.height(40.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.border(1.dp, MaterialTheme.colorScheme.outline, CircleShape)
|
.border(1.dp, MaterialTheme.colorScheme.outline, CircleShape),
|
||||||
) {
|
) {
|
||||||
content()
|
content()
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ fun RowScope.SegmentedButton(
|
|||||||
label: String,
|
label: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
icon: ImageVector? = null
|
icon: ImageVector? = null,
|
||||||
) {
|
) {
|
||||||
val containerColor =
|
val containerColor =
|
||||||
if (selected) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface
|
if (selected) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface
|
||||||
@ -77,9 +77,9 @@ fun RowScope.SegmentedButton(
|
|||||||
shape = RectangleShape,
|
shape = RectangleShape,
|
||||||
colors = ButtonDefaults.outlinedButtonColors(
|
colors = ButtonDefaults.outlinedButtonColors(
|
||||||
containerColor = containerColor,
|
containerColor = containerColor,
|
||||||
contentColor = contentColorFor(containerColor)
|
contentColor = contentColorFor(containerColor),
|
||||||
),
|
),
|
||||||
contentPadding = PaddingValues(horizontal = 12.dp)
|
contentPadding = PaddingValues(horizontal = 12.dp),
|
||||||
) {
|
) {
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
Crossfade(selected, label = "Selected state") {
|
Crossfade(selected, label = "Selected state") {
|
||||||
|
@ -67,14 +67,14 @@ internal fun ColumnScope.SheetContent(
|
|||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
indication = null,
|
indication = null,
|
||||||
onClick = { showHello = true }
|
onClick = { showHello = true },
|
||||||
)
|
),
|
||||||
) { hello ->
|
) { hello ->
|
||||||
Text(
|
Text(
|
||||||
text = if (hello) stringResource(R.string.hello_label) else stringResource(R.string.app_name),
|
text = if (hello) stringResource(R.string.hello_label) else stringResource(R.string.app_name),
|
||||||
modifier = Modifier.padding(horizontal = 28.dp, vertical = 24.dp),
|
modifier = Modifier.padding(horizontal = 28.dp, vertical = 24.dp),
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ internal fun ColumnScope.SheetContent(
|
|||||||
destination = drawerItem,
|
destination = drawerItem,
|
||||||
icon = if (selected) drawerItem.selectedIcon else drawerItem.defaultIcon,
|
icon = if (selected) drawerItem.selectedIcon else drawerItem.defaultIcon,
|
||||||
selected = selected,
|
selected = selected,
|
||||||
onClick = onItemClick
|
onClick = onItemClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ internal fun ColumnScope.SheetContent(
|
|||||||
destination = drawerItem,
|
destination = drawerItem,
|
||||||
icon = if (selected) drawerItem.selectedIcon else drawerItem.defaultIcon,
|
icon = if (selected) drawerItem.selectedIcon else drawerItem.defaultIcon,
|
||||||
selected = selected,
|
selected = selected,
|
||||||
onClick = onItemClick
|
onClick = onItemClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ private fun PreviewDrawerSheet() {
|
|||||||
DrawerItem.Calculator,
|
DrawerItem.Calculator,
|
||||||
),
|
),
|
||||||
currentDestination = DrawerItem.Calculator.start,
|
currentDestination = DrawerItem.Calculator.start,
|
||||||
onItemClick = {}
|
onItemClick = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,12 @@ fun Slider(
|
|||||||
value: Float,
|
value: Float,
|
||||||
valueRange: ClosedFloatingPointRange<Float>,
|
valueRange: ClosedFloatingPointRange<Float>,
|
||||||
onValueChange: (Float) -> Unit,
|
onValueChange: (Float) -> Unit,
|
||||||
onValueChangeFinished: (Float) -> Unit = {}
|
onValueChangeFinished: (Float) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val animated = animateFloatAsState(
|
val animated = animateFloatAsState(
|
||||||
targetValue = value.roundToInt().toFloat(),
|
targetValue = value.roundToInt().toFloat(),
|
||||||
animationSpec = spring(),
|
animationSpec = spring(),
|
||||||
label = "Thumb animation"
|
label = "Thumb animation",
|
||||||
)
|
)
|
||||||
|
|
||||||
Slider(
|
Slider(
|
||||||
@ -81,14 +81,14 @@ private fun SquigglyTrack(
|
|||||||
@FloatRange(0.0, 1.0) waveHeight: Float = 0.7f,
|
@FloatRange(0.0, 1.0) waveHeight: Float = 0.7f,
|
||||||
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 { mutableFloatStateOf(waveHeight * (100f - strokeWidth * 2f ) / 100f ) }
|
var direct by remember { mutableFloatStateOf(waveHeight * (100f - strokeWidth * 2f) / 100f) }
|
||||||
val animatedDirect = animateFloatAsState(
|
val animatedDirect = animateFloatAsState(
|
||||||
targetValue = direct,
|
targetValue = direct,
|
||||||
animationSpec = spring(stiffness = Spring.StiffnessLow),
|
animationSpec = spring(stiffness = Spring.StiffnessLow),
|
||||||
label = "Track animation"
|
label = "Track animation",
|
||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(sliderState.value) {
|
LaunchedEffect(sliderState.value) {
|
||||||
@ -101,7 +101,7 @@ private fun SquigglyTrack(
|
|||||||
Canvas(
|
Canvas(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(20.dp)
|
.height(20.dp),
|
||||||
) {
|
) {
|
||||||
val width = size.width
|
val width = size.width
|
||||||
val height = size.height
|
val height = size.height
|
||||||
@ -114,7 +114,7 @@ private fun SquigglyTrack(
|
|||||||
val path = Path().apply {
|
val path = Path().apply {
|
||||||
moveTo(
|
moveTo(
|
||||||
x = initialOffset,
|
x = initialOffset,
|
||||||
y = height.times(0.5f)
|
y = height.times(0.5f),
|
||||||
)
|
)
|
||||||
val amount = ceil(width.div(eachWaveWidth))
|
val amount = ceil(width.div(eachWaveWidth))
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ private fun SquigglyTrack(
|
|||||||
dx1 = eachWaveWidth * 0.5f,
|
dx1 = eachWaveWidth * 0.5f,
|
||||||
dy1 = height.times(peek),
|
dy1 = height.times(peek),
|
||||||
dx2 = eachWaveWidth,
|
dx2 = eachWaveWidth,
|
||||||
dy2 = 0f
|
dy2 = 0f,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,12 +135,12 @@ private fun SquigglyTrack(
|
|||||||
left = 0f,
|
left = 0f,
|
||||||
right = thumbPosition,
|
right = thumbPosition,
|
||||||
bottom = height,
|
bottom = height,
|
||||||
clipOp = ClipOp.Intersect
|
clipOp = ClipOp.Intersect,
|
||||||
) {
|
) {
|
||||||
drawPath(
|
drawPath(
|
||||||
path = path,
|
path = path,
|
||||||
color = filledColor,
|
color = filledColor,
|
||||||
style = Stroke(strokeWidth, cap = StrokeCap.Round)
|
style = Stroke(strokeWidth, cap = StrokeCap.Round),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ private fun SquigglyTrack(
|
|||||||
start = Offset(thumbPosition, height.times(0.5f)),
|
start = Offset(thumbPosition, height.times(0.5f)),
|
||||||
end = Offset(width, height.times(0.5f)),
|
end = Offset(width, height.times(0.5f)),
|
||||||
strokeWidth = strokeWidth,
|
strokeWidth = strokeWidth,
|
||||||
cap = StrokeCap.Round
|
cap = StrokeCap.Round,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,6 +165,6 @@ private fun PreviewNewSlider() {
|
|||||||
com.sadellie.unitto.core.ui.common.Slider(
|
com.sadellie.unitto.core.ui.common.Slider(
|
||||||
value = currentValue,
|
value = currentValue,
|
||||||
valueRange = 0f..16f,
|
valueRange = 0f..16f,
|
||||||
onValueChange = { currentValue = it }
|
onValueChange = { currentValue = it },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ fun Switch(
|
|||||||
)
|
)
|
||||||
val thumbOffset = animateDpAsState(
|
val thumbOffset = animateDpAsState(
|
||||||
targetValue = if (checked) ThumbPaddingEnd else ThumbPaddingStart,
|
targetValue = if (checked) ThumbPaddingEnd else ThumbPaddingStart,
|
||||||
label = "Thumb offset"
|
label = "Thumb offset",
|
||||||
)
|
)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
@ -81,15 +81,15 @@ fun Switch(
|
|||||||
enabled = true,
|
enabled = true,
|
||||||
onClickLabel = null,
|
onClickLabel = null,
|
||||||
role = Role.Switch,
|
role = Role.Switch,
|
||||||
onClick = { onCheckedChange(!checked) }
|
onClick = { onCheckedChange(!checked) },
|
||||||
)
|
)
|
||||||
.background(trackColor.value, CircleShape)
|
.background(trackColor.value, CircleShape)
|
||||||
.size(TrackWidth, TrackHeight)
|
.size(TrackWidth, TrackHeight)
|
||||||
.border(
|
.border(
|
||||||
TrackOutlineWidth,
|
TrackOutlineWidth,
|
||||||
borderColor(enabled, checked, colors),
|
borderColor(enabled, checked, colors),
|
||||||
CircleShape
|
CircleShape,
|
||||||
)
|
),
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -100,7 +100,7 @@ fun Switch(
|
|||||||
)
|
)
|
||||||
.align(Alignment.CenterStart)
|
.align(Alignment.CenterStart)
|
||||||
.background(thumbColor.value, CircleShape)
|
.background(thumbColor.value, CircleShape)
|
||||||
.size(thumbSize.value)
|
.size(thumbSize.value),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ fun Switch(
|
|||||||
private fun trackColor(
|
private fun trackColor(
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
checked: Boolean,
|
checked: Boolean,
|
||||||
colors: SwitchColors
|
colors: SwitchColors,
|
||||||
): Color =
|
): Color =
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (checked) colors.checkedTrackColor else colors.uncheckedTrackColor
|
if (checked) colors.checkedTrackColor else colors.uncheckedTrackColor
|
||||||
@ -121,7 +121,7 @@ private fun trackColor(
|
|||||||
private fun thumbColor(
|
private fun thumbColor(
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
checked: Boolean,
|
checked: Boolean,
|
||||||
colors: SwitchColors
|
colors: SwitchColors,
|
||||||
): Color =
|
): Color =
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (checked) colors.checkedThumbColor else colors.uncheckedThumbColor
|
if (checked) colors.checkedThumbColor else colors.uncheckedThumbColor
|
||||||
@ -133,7 +133,7 @@ private fun thumbColor(
|
|||||||
private fun borderColor(
|
private fun borderColor(
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
checked: Boolean,
|
checked: Boolean,
|
||||||
colors: SwitchColors
|
colors: SwitchColors,
|
||||||
): Color =
|
): Color =
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (checked) colors.checkedBorderColor else colors.uncheckedBorderColor
|
if (checked) colors.checkedBorderColor else colors.uncheckedBorderColor
|
||||||
@ -147,7 +147,7 @@ val TrackOutlineWidth = 1.8.dp
|
|||||||
val SelectedHandleSize = 20.0.dp
|
val SelectedHandleSize = 20.0.dp
|
||||||
val UnselectedHandleSize = 20.0.dp
|
val UnselectedHandleSize = 20.0.dp
|
||||||
|
|
||||||
val ThumbPaddingStart = (TrackHeight - UnselectedHandleSize) / 2
|
val ThumbPaddingStart = (TrackHeight - UnselectedHandleSize) / 2
|
||||||
val ThumbPaddingEnd = TrackWidth - SelectedHandleSize / 2 - TrackHeight / 2
|
val ThumbPaddingEnd = TrackWidth - SelectedHandleSize / 2 - TrackHeight / 2
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@ -156,6 +156,6 @@ fun PreviewPixelSwitch() {
|
|||||||
var checked by remember { mutableStateOf(false) }
|
var checked by remember { mutableStateOf(false) }
|
||||||
Switch(
|
Switch(
|
||||||
checked = checked,
|
checked = checked,
|
||||||
onCheckedChange = { checked = !checked }
|
onCheckedChange = { checked = !checked },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,11 @@ fun ColumnWithConstraints(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
|
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
|
||||||
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
|
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
|
||||||
content: @Composable (ColumnScope.(BoxWithConstraintsScope)-> Unit)
|
content: @Composable (ColumnScope.(BoxWithConstraintsScope) -> Unit),
|
||||||
) = BoxWithConstraints(modifier) {
|
) = BoxWithConstraints(modifier) {
|
||||||
Column(
|
Column(
|
||||||
verticalArrangement = verticalArrangement,
|
verticalArrangement = verticalArrangement,
|
||||||
horizontalAlignment = horizontalAlignment
|
horizontalAlignment = horizontalAlignment,
|
||||||
) { content(this@BoxWithConstraints) }
|
) { content(this@BoxWithConstraints) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,10 +47,10 @@ fun RowWithConstraints(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
|
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
|
||||||
verticalAlignment: Alignment.Vertical = Alignment.Top,
|
verticalAlignment: Alignment.Vertical = Alignment.Top,
|
||||||
content: @Composable (RowScope.(BoxWithConstraintsScope)-> Unit)
|
content: @Composable (RowScope.(BoxWithConstraintsScope) -> Unit),
|
||||||
) = BoxWithConstraints(modifier) {
|
) = BoxWithConstraints(modifier) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = horizontalArrangement,
|
horizontalArrangement = horizontalArrangement,
|
||||||
verticalAlignment = verticalAlignment
|
verticalAlignment = verticalAlignment,
|
||||||
) { content(this@BoxWithConstraints) }
|
) { content(this@BoxWithConstraints) }
|
||||||
}
|
}
|
||||||
|
@ -43,54 +43,6 @@ import androidx.compose.ui.unit.TextUnit
|
|||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
// HUGE performance drop. Don't use for buttons
|
|
||||||
///**
|
|
||||||
// * Composable function that automatically adjusts the text size to fit within given constraints using AnnotatedString, considering the ratio of line spacing to text size.
|
|
||||||
// *
|
|
||||||
// * Features:
|
|
||||||
// * Similar to AutoSizeText(String), with support for AnnotatedString.
|
|
||||||
// *
|
|
||||||
// * @param inlineContent a map storing composables that replaces certain ranges of the text, used to
|
|
||||||
// * insert composables into text layout. See [InlineTextContent].
|
|
||||||
// * @see AutoSizeText
|
|
||||||
// */
|
|
||||||
//@Composable
|
|
||||||
//internal fun AutoSizeText(
|
|
||||||
// text: AnnotatedString,
|
|
||||||
// modifier: Modifier = Modifier,
|
|
||||||
// minRatio: Float = 1f,
|
|
||||||
// maxTextSize: TextUnit = TextUnit.Unspecified,
|
|
||||||
// alignment: Alignment = Alignment.TopStart,
|
|
||||||
// overflow: TextOverflow = TextOverflow.Clip,
|
|
||||||
// softWrap: Boolean = true,
|
|
||||||
// maxLines: Int = Int.MAX_VALUE,
|
|
||||||
// minLines: Int = 1,
|
|
||||||
// inlineContent: Map<String, InlineTextContent> = mapOf(),
|
|
||||||
// onTextLayout: (TextLayoutResult) -> Unit = {},
|
|
||||||
// style: TextStyle = LocalTextStyle.current,
|
|
||||||
//) = AutoSizeTextStyleBox(
|
|
||||||
// modifier = modifier,
|
|
||||||
// text = text,
|
|
||||||
// maxTextSize = maxTextSize,
|
|
||||||
// maxLines = maxLines,
|
|
||||||
// minLines = minLines,
|
|
||||||
// softWrap = softWrap,
|
|
||||||
// style = style,
|
|
||||||
// minRatio = minRatio,
|
|
||||||
// alignment = alignment
|
|
||||||
//) {
|
|
||||||
// Text(
|
|
||||||
// text = text,
|
|
||||||
// overflow = overflow,
|
|
||||||
// softWrap = softWrap,
|
|
||||||
// maxLines = maxLines,
|
|
||||||
// minLines = minLines,
|
|
||||||
// inlineContent = inlineContent,
|
|
||||||
// onTextLayout = onTextLayout,
|
|
||||||
// style = LocalTextStyle.current,
|
|
||||||
// )
|
|
||||||
//}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [BoxWithConstraints] with [autoTextStyle] passed via [LocalTextStyle].
|
* [BoxWithConstraints] with [autoTextStyle] passed via [LocalTextStyle].
|
||||||
*
|
*
|
||||||
@ -122,11 +74,11 @@ internal fun AutoSizeTextStyleBox(
|
|||||||
style: TextStyle,
|
style: TextStyle,
|
||||||
minRatio: Float,
|
minRatio: Float,
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalDensity provides Density(density = density.density, fontScale = 1F)
|
LocalDensity provides Density(density = density.density, fontScale = 1F),
|
||||||
) {
|
) {
|
||||||
BoxWithConstraints(
|
BoxWithConstraints(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
@ -141,12 +93,12 @@ internal fun AutoSizeTextStyleBox(
|
|||||||
style = style,
|
style = style,
|
||||||
alignment = alignment,
|
alignment = alignment,
|
||||||
density = density,
|
density = density,
|
||||||
minRatio = minRatio
|
minRatio = minRatio,
|
||||||
)
|
)
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
value = LocalTextStyle.provides(autoTextStyle),
|
value = LocalTextStyle.provides(autoTextStyle),
|
||||||
content = content
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,10 +242,11 @@ private fun <E> IntProgression.findElectedValue(
|
|||||||
var high = last
|
var high = last
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
val mid = low + (high - low) / 2
|
val mid = low + (high - low) / 2
|
||||||
if (shouldMoveBackward(transform(mid)))
|
if (shouldMoveBackward(transform(mid))) {
|
||||||
high = mid - 1
|
high = mid - 1
|
||||||
else
|
} else {
|
||||||
low = mid + 1
|
low = mid + 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
transform(high.coerceAtLeast(minimumValue = first))
|
transform(high.coerceAtLeast(minimumValue = first))
|
||||||
}
|
}
|
||||||
|
@ -27,5 +27,8 @@ import androidx.compose.ui.unit.isSpecified
|
|||||||
internal fun Density.roundToPx(sp: TextUnit): Int = sp.roundToPx()
|
internal fun Density.roundToPx(sp: TextUnit): Int = sp.roundToPx()
|
||||||
internal fun Density.toSp(px: Int): TextUnit = px.toSp()
|
internal fun Density.toSp(px: Int): TextUnit = px.toSp()
|
||||||
internal fun Density.toIntSize(dpSize: DpSize): IntSize =
|
internal fun Density.toIntSize(dpSize: DpSize): IntSize =
|
||||||
if (dpSize.isSpecified) IntSize(dpSize.width.roundToPx(), dpSize.height.roundToPx())
|
if (dpSize.isSpecified) {
|
||||||
else IntSize.Zero
|
IntSize(dpSize.width.roundToPx(), dpSize.height.roundToPx())
|
||||||
|
} else {
|
||||||
|
IntSize.Zero
|
||||||
|
}
|
||||||
|
@ -67,7 +67,7 @@ fun DatePickerDialog(
|
|||||||
BasicAlertDialog(
|
BasicAlertDialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
modifier = modifier.wrapContentHeight(),
|
modifier = modifier.wrapContentHeight(),
|
||||||
properties = DialogProperties(usePlatformDefaultWidth = false)
|
properties = DialogProperties(usePlatformDefaultWidth = false),
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@ -83,15 +83,14 @@ fun DatePickerDialog(
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.End)
|
.align(Alignment.End)
|
||||||
.padding(_dialogButtonsPadding)
|
.padding(_dialogButtonsPadding),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
AlertDialogFlowRow(
|
AlertDialogFlowRow(
|
||||||
mainAxisSpacing = _dialogButtonsMainAxisSpacing,
|
mainAxisSpacing = _dialogButtonsMainAxisSpacing,
|
||||||
crossAxisSpacing = _dialogButtonsCrossAxisSpacing
|
crossAxisSpacing = _dialogButtonsCrossAxisSpacing,
|
||||||
) {
|
) {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = onDismiss
|
onClick = onDismiss,
|
||||||
) {
|
) {
|
||||||
Text(text = dismissLabel)
|
Text(text = dismissLabel)
|
||||||
}
|
}
|
||||||
@ -100,16 +99,17 @@ fun DatePickerDialog(
|
|||||||
val millis = pickerState.selectedDateMillis ?: return@TextButton
|
val millis = pickerState.selectedDateMillis ?: return@TextButton
|
||||||
|
|
||||||
val date = LocalDateTime.ofInstant(
|
val date = LocalDateTime.ofInstant(
|
||||||
Instant.ofEpochMilli(millis), ZoneId.systemDefault()
|
Instant.ofEpochMilli(millis),
|
||||||
|
ZoneId.systemDefault(),
|
||||||
)
|
)
|
||||||
|
|
||||||
onConfirm(
|
onConfirm(
|
||||||
localDateTime
|
localDateTime
|
||||||
.withYear(date.year)
|
.withYear(date.year)
|
||||||
.withMonth(date.monthValue)
|
.withMonth(date.monthValue)
|
||||||
.withDayOfMonth(date.dayOfMonth)
|
.withDayOfMonth(date.dayOfMonth),
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
) {
|
) {
|
||||||
Text(text = confirmLabel)
|
Text(text = confirmLabel)
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ fun DatePickerDialog(
|
|||||||
private fun AlertDialogFlowRow(
|
private fun AlertDialogFlowRow(
|
||||||
mainAxisSpacing: Dp,
|
mainAxisSpacing: Dp,
|
||||||
crossAxisSpacing: Dp,
|
crossAxisSpacing: Dp,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
Layout(content) { measurables, constraints ->
|
Layout(content) { measurables, constraints ->
|
||||||
val sequences = mutableListOf<List<Placeable>>()
|
val sequences = mutableListOf<List<Placeable>>()
|
||||||
@ -142,7 +142,7 @@ private fun AlertDialogFlowRow(
|
|||||||
// Return whether the placeable can be added to the current sequence.
|
// Return whether the placeable can be added to the current sequence.
|
||||||
fun canAddToCurrentSequence(placeable: Placeable) =
|
fun canAddToCurrentSequence(placeable: Placeable) =
|
||||||
currentSequence.isEmpty() || currentMainAxisSize + mainAxisSpacing.roundToPx() +
|
currentSequence.isEmpty() || currentMainAxisSize + mainAxisSpacing.roundToPx() +
|
||||||
placeable.width <= constraints.maxWidth
|
placeable.width <= constraints.maxWidth
|
||||||
|
|
||||||
// Store current sequence information and start a new sequence.
|
// Store current sequence information and start a new sequence.
|
||||||
fun startNewSequence() {
|
fun startNewSequence() {
|
||||||
@ -187,20 +187,22 @@ private fun AlertDialogFlowRow(
|
|||||||
sequences.forEachIndexed { i, placeables ->
|
sequences.forEachIndexed { i, placeables ->
|
||||||
val childrenMainAxisSizes = IntArray(placeables.size) { j ->
|
val childrenMainAxisSizes = IntArray(placeables.size) { j ->
|
||||||
placeables[j].width +
|
placeables[j].width +
|
||||||
if (j < placeables.lastIndex) mainAxisSpacing.roundToPx() else 0
|
if (j < placeables.lastIndex) mainAxisSpacing.roundToPx() else 0
|
||||||
}
|
}
|
||||||
val arrangement = Arrangement.End
|
val arrangement = Arrangement.End
|
||||||
val mainAxisPositions = IntArray(childrenMainAxisSizes.size) { 0 }
|
val mainAxisPositions = IntArray(childrenMainAxisSizes.size) { 0 }
|
||||||
with(arrangement) {
|
with(arrangement) {
|
||||||
arrange(
|
arrange(
|
||||||
mainAxisLayoutSize, childrenMainAxisSizes,
|
mainAxisLayoutSize,
|
||||||
layoutDirection, mainAxisPositions
|
childrenMainAxisSizes,
|
||||||
|
layoutDirection,
|
||||||
|
mainAxisPositions,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
placeables.forEachIndexed { j, placeable ->
|
placeables.forEachIndexed { j, placeable ->
|
||||||
placeable.place(
|
placeable.place(
|
||||||
x = mainAxisPositions[j],
|
x = mainAxisPositions[j],
|
||||||
y = crossAxisPositions[i]
|
y = crossAxisPositions[i],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ fun TimePickerDialog(
|
|||||||
val pickerState = rememberTimePickerState(
|
val pickerState = rememberTimePickerState(
|
||||||
initialHour = hour,
|
initialHour = hour,
|
||||||
initialMinute = minute,
|
initialMinute = minute,
|
||||||
is24Hour = DateFormat.is24HourFormat(LocalContext.current)
|
is24Hour = DateFormat.is24HourFormat(LocalContext.current),
|
||||||
)
|
)
|
||||||
val configuration = LocalConfiguration.current
|
val configuration = LocalConfiguration.current
|
||||||
var showingPicker by rememberSaveable { mutableStateOf(true) }
|
var showingPicker by rememberSaveable { mutableStateOf(true) }
|
||||||
@ -81,8 +81,8 @@ fun TimePickerDialog(
|
|||||||
BasicAlertDialog(
|
BasicAlertDialog(
|
||||||
onDismissRequest = onCancel,
|
onDismissRequest = onCancel,
|
||||||
properties = DialogProperties(
|
properties = DialogProperties(
|
||||||
usePlatformDefaultWidth = false
|
usePlatformDefaultWidth = false,
|
||||||
)
|
),
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
shape = MaterialTheme.shapes.extraLarge,
|
shape = MaterialTheme.shapes.extraLarge,
|
||||||
@ -92,7 +92,7 @@ fun TimePickerDialog(
|
|||||||
.height(IntrinsicSize.Min)
|
.height(IntrinsicSize.Min)
|
||||||
.background(
|
.background(
|
||||||
shape = MaterialTheme.shapes.extraLarge,
|
shape = MaterialTheme.shapes.extraLarge,
|
||||||
color = MaterialTheme.colorScheme.surface
|
color = MaterialTheme.colorScheme.surface,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
if (configuration.screenHeightDp > 400) {
|
if (configuration.screenHeightDp > 400) {
|
||||||
@ -103,7 +103,7 @@ fun TimePickerDialog(
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.semantics {
|
.semantics {
|
||||||
isTraversalGroup = true
|
isTraversalGroup = true
|
||||||
}
|
},
|
||||||
) {
|
) {
|
||||||
IconButton(
|
IconButton(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -114,7 +114,8 @@ fun TimePickerDialog(
|
|||||||
.size(64.dp, 72.dp)
|
.size(64.dp, 72.dp)
|
||||||
.align(Alignment.BottomStart)
|
.align(Alignment.BottomStart)
|
||||||
.zIndex(5f),
|
.zIndex(5f),
|
||||||
onClick = { showingPicker = !showingPicker }) {
|
onClick = { showingPicker = !showingPicker },
|
||||||
|
) {
|
||||||
val icon = if (showingPicker) {
|
val icon = if (showingPicker) {
|
||||||
Icons.Outlined.Keyboard
|
Icons.Outlined.Keyboard
|
||||||
} else {
|
} else {
|
||||||
@ -122,21 +123,21 @@ fun TimePickerDialog(
|
|||||||
}
|
}
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = stringResource(R.string.select_time_label)
|
contentDescription = stringResource(R.string.select_time_label),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(24.dp),
|
modifier = Modifier.padding(24.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(bottom = 20.dp),
|
.padding(bottom = 20.dp),
|
||||||
text = stringResource(R.string.select_time_label),
|
text = stringResource(R.string.select_time_label),
|
||||||
style = MaterialTheme.typography.labelMedium
|
style = MaterialTheme.typography.labelMedium,
|
||||||
)
|
)
|
||||||
if (showingPicker && configuration.screenHeightDp > 400) {
|
if (showingPicker && configuration.screenHeightDp > 400) {
|
||||||
TimePicker(state = pickerState)
|
TimePicker(state = pickerState)
|
||||||
@ -146,14 +147,14 @@ fun TimePickerDialog(
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(40.dp)
|
.height(40.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = onCancel
|
onClick = onCancel,
|
||||||
) { Text(stringResource(R.string.cancel_label)) }
|
) { Text(stringResource(R.string.cancel_label)) }
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = { onConfirm(pickerState.hour, pickerState.minute) }
|
onClick = { onConfirm(pickerState.hour, pickerState.minute) },
|
||||||
) { Text(confirmLabel) }
|
) { Text(confirmLabel) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("ktlint:standard:property-naming")
|
||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
package com.sadellie.unitto.core.ui.common.icons.iconpack
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -32,20 +32,20 @@ import com.sadellie.unitto.core.base.Token
|
|||||||
*/
|
*/
|
||||||
internal class ExpressionClipboardManager(
|
internal class ExpressionClipboardManager(
|
||||||
private val formatterSymbols: FormatterSymbols,
|
private val formatterSymbols: FormatterSymbols,
|
||||||
private val clipboardManager: android.content.ClipboardManager
|
private val clipboardManager: android.content.ClipboardManager,
|
||||||
): ClipboardManager {
|
) : ClipboardManager {
|
||||||
override fun setText(annotatedString: AnnotatedString) = clipboardManager.setPrimaryClip(
|
override fun setText(annotatedString: AnnotatedString) = clipboardManager.setPrimaryClip(
|
||||||
ClipData.newPlainText(
|
ClipData.newPlainText(
|
||||||
PLAIN_TEXT_LABEL,
|
PLAIN_TEXT_LABEL,
|
||||||
annotatedString
|
annotatedString
|
||||||
.text
|
.text
|
||||||
.replace(Token.Digit.dot, formatterSymbols.fractional)
|
.replace(Token.Digit.dot, formatterSymbols.fractional),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun getText(): AnnotatedString? = clipboardManager.primaryClip?.let { primaryClip ->
|
override fun getText(): AnnotatedString? = clipboardManager.primaryClip?.let { primaryClip ->
|
||||||
if (primaryClip.itemCount > 0) {
|
if (primaryClip.itemCount > 0) {
|
||||||
val clipText = primaryClip.getItemAt(0)?.text ?:return@let null
|
val clipText = primaryClip.getItemAt(0)?.text ?: return@let null
|
||||||
|
|
||||||
clipText
|
clipText
|
||||||
.toString()
|
.toString()
|
||||||
|
@ -22,7 +22,6 @@ import com.sadellie.unitto.core.base.Token
|
|||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
fun String.fixCursor(pos: Int, grouping: String): Int {
|
fun String.fixCursor(pos: Int, grouping: String): Int {
|
||||||
|
|
||||||
if (isEmpty()) return pos
|
if (isEmpty()) return pos
|
||||||
|
|
||||||
// Best position if we move cursor left
|
// Best position if we move cursor left
|
||||||
@ -75,7 +74,7 @@ private fun Int.isAtToken(str: String, token: String): Boolean {
|
|||||||
return str
|
return str
|
||||||
.substring(
|
.substring(
|
||||||
startIndex = (this - checkBound).coerceAtLeast(0),
|
startIndex = (this - checkBound).coerceAtLeast(0),
|
||||||
endIndex = (this + checkBound).coerceAtMost(str.length)
|
endIndex = (this + checkBound).coerceAtMost(str.length),
|
||||||
)
|
)
|
||||||
.contains(token)
|
.contains(token)
|
||||||
}
|
}
|
||||||
@ -86,7 +85,6 @@ private fun Int.isAfterToken(str: String, token: String): Boolean {
|
|||||||
.contains(token)
|
.contains(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This can also make [TextFieldValue.addTokens] better by checking tokens both ways. Needs more tests
|
// This can also make [TextFieldValue.addTokens] better by checking tokens both ways. Needs more tests
|
||||||
fun String.tokenAfter(pos: Int): String {
|
fun String.tokenAfter(pos: Int): String {
|
||||||
Token.Func.allWithOpeningBracket.forEach {
|
Token.Func.allWithOpeningBracket.forEach {
|
||||||
@ -96,23 +94,6 @@ fun String.tokenAfter(pos: Int): String {
|
|||||||
return substring(pos, (pos + 1).coerceAtMost(this.length))
|
return substring(pos, (pos + 1).coerceAtMost(this.length))
|
||||||
}
|
}
|
||||||
|
|
||||||
//private fun String.numberNearby(cursor: Int): String {
|
|
||||||
// val text = this
|
|
||||||
//
|
|
||||||
// var aheadCursor = cursor
|
|
||||||
// var afterCursor = cursor
|
|
||||||
//
|
|
||||||
// while (text.tokenAhead(aheadCursor) in Token.Digit.allWithDot) {
|
|
||||||
// aheadCursor--
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// while (text.tokenAfter(afterCursor) in Token.Digit.allWithDot) {
|
|
||||||
// afterCursor++
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return text.substring(aheadCursor, afterCursor)
|
|
||||||
//}
|
|
||||||
|
|
||||||
private fun Int.isBeforeToken(str: String, token: String): Boolean {
|
private fun Int.isBeforeToken(str: String, token: String): Boolean {
|
||||||
return str
|
return str
|
||||||
.substring(this, (this + token.length).coerceAtMost(str.length))
|
.substring(this, (this + token.length).coerceAtMost(str.length))
|
||||||
|
@ -30,13 +30,13 @@ class ExpressionTransformer(private val formatterSymbols: FormatterSymbols) : Vi
|
|||||||
val formatted = text.text.formatExpression(formatterSymbols)
|
val formatted = text.text.formatExpression(formatterSymbols)
|
||||||
return TransformedText(
|
return TransformedText(
|
||||||
text = AnnotatedString(formatted),
|
text = AnnotatedString(formatted),
|
||||||
offsetMapping = ExpressionMapping(text.text, formatted)
|
offsetMapping = ExpressionMapping(text.text, formatted),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ExpressionMapping(
|
inner class ExpressionMapping(
|
||||||
private val original: String,
|
private val original: String,
|
||||||
private val transformed: String
|
private val transformed: String,
|
||||||
) : OffsetMapping {
|
) : OffsetMapping {
|
||||||
// Called when entering text (on each text change)
|
// Called when entering text (on each text change)
|
||||||
// Basically moves cursor to the right position
|
// Basically moves cursor to the right position
|
||||||
|
@ -49,15 +49,15 @@ fun FixedExpressionInputTextField(
|
|||||||
val clipboardManager = FormattedExpressionClipboardManager(
|
val clipboardManager = FormattedExpressionClipboardManager(
|
||||||
formatterSymbols = formatterSymbols,
|
formatterSymbols = formatterSymbols,
|
||||||
clipboardManager = LocalContext.current.getSystemService(Context.CLIPBOARD_SERVICE)
|
clipboardManager = LocalContext.current.getSystemService(Context.CLIPBOARD_SERVICE)
|
||||||
as android.content.ClipboardManager
|
as android.content.ClipboardManager,
|
||||||
)
|
)
|
||||||
|
|
||||||
CompositionLocalProvider(LocalClipboardManager provides clipboardManager) {
|
CompositionLocalProvider(LocalClipboardManager provides clipboardManager) {
|
||||||
SelectionContainer(
|
SelectionContainer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.horizontalScroll(rememberScrollState()) // Must be first
|
.horizontalScroll(rememberScrollState()) // Must be first
|
||||||
.clickable(onClick = onClick)
|
.clickable(onClick = onClick)
|
||||||
.then(modifier)
|
.then(modifier),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@ -71,8 +71,8 @@ fun FixedExpressionInputTextField(
|
|||||||
|
|
||||||
private class FormattedExpressionClipboardManager(
|
private class FormattedExpressionClipboardManager(
|
||||||
private val formatterSymbols: FormatterSymbols,
|
private val formatterSymbols: FormatterSymbols,
|
||||||
private val clipboardManager: android.content.ClipboardManager
|
private val clipboardManager: android.content.ClipboardManager,
|
||||||
): ClipboardManager {
|
) : ClipboardManager {
|
||||||
override fun getText(): AnnotatedString? = null
|
override fun getText(): AnnotatedString? = null
|
||||||
|
|
||||||
override fun setText(annotatedString: AnnotatedString) {
|
override fun setText(annotatedString: AnnotatedString) {
|
||||||
@ -81,8 +81,8 @@ private class FormattedExpressionClipboardManager(
|
|||||||
PLAIN_TEXT_LABEL,
|
PLAIN_TEXT_LABEL,
|
||||||
annotatedString
|
annotatedString
|
||||||
.text
|
.text
|
||||||
.replace(formatterSymbols.grouping, "")
|
.replace(formatterSymbols.grouping, ""),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ internal fun String.clearAndFilterNumberBase(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun String.formatExpression(
|
fun String.formatExpression(
|
||||||
formatterSymbols: FormatterSymbols
|
formatterSymbols: FormatterSymbols,
|
||||||
): String {
|
): String {
|
||||||
var input = this
|
var input = this
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ fun String.formatExpression(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun String.formatNumber(
|
private fun String.formatNumber(
|
||||||
formatterSymbols: FormatterSymbols
|
formatterSymbols: FormatterSymbols,
|
||||||
): String {
|
): String {
|
||||||
val input = this
|
val input = this
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ private fun String.leaveLegalTokensOnly(legalTokens: List<String>): String {
|
|||||||
val subs = streamOfTokens
|
val subs = streamOfTokens
|
||||||
.substring(
|
.substring(
|
||||||
cursor,
|
cursor,
|
||||||
(cursor + token.length).coerceAtMost(streamOfTokens.length)
|
(cursor + token.length).coerceAtMost(streamOfTokens.length),
|
||||||
)
|
)
|
||||||
if (subs == token) {
|
if (subs == token) {
|
||||||
// Got a digit, see if there are other digits coming after
|
// Got a digit, see if there are other digits coming after
|
||||||
|
@ -64,7 +64,7 @@ fun ExpressionTextField(
|
|||||||
ExpressionClipboardManager(
|
ExpressionClipboardManager(
|
||||||
formatterSymbols = formatterSymbols,
|
formatterSymbols = formatterSymbols,
|
||||||
clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE)
|
clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE)
|
||||||
as android.content.ClipboardManager
|
as android.content.ClipboardManager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val expressionTransformer = remember(formatterSymbols) {
|
val expressionTransformer = remember(formatterSymbols) {
|
||||||
@ -72,7 +72,7 @@ fun ExpressionTextField(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalClipboardManager provides clipboardManager
|
LocalClipboardManager provides clipboardManager,
|
||||||
) {
|
) {
|
||||||
AutoSizeTextField(
|
AutoSizeTextField(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
@ -85,7 +85,7 @@ fun ExpressionTextField(
|
|||||||
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
|
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
|
||||||
visualTransformation = expressionTransformer,
|
visualTransformation = expressionTransformer,
|
||||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
|
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
|
||||||
minRatio = minRatio
|
minRatio = minRatio,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ fun NumberBaseTextField(
|
|||||||
readOnly = readOnly,
|
readOnly = readOnly,
|
||||||
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
|
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
|
||||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
|
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
|
||||||
minRatio = minRatio
|
minRatio = minRatio,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ fun SimpleTextField(
|
|||||||
readOnly = readOnly,
|
readOnly = readOnly,
|
||||||
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
|
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
|
||||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
|
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
|
||||||
minRatio = minRatio
|
minRatio = minRatio,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ private fun AutoSizeTextField(
|
|||||||
softWrap = false,
|
softWrap = false,
|
||||||
style = textStyle,
|
style = textStyle,
|
||||||
minRatio = minRatio,
|
minRatio = minRatio,
|
||||||
alignment = alignment
|
alignment = alignment,
|
||||||
) {
|
) {
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalTextInputService provides null,
|
LocalTextInputService provides null,
|
||||||
@ -204,8 +204,8 @@ private fun AutoSizeTextField(
|
|||||||
text = placeholder!!,
|
text = placeholder!!,
|
||||||
style = style.copy(
|
style = style.copy(
|
||||||
textAlign = TextAlign.End,
|
textAlign = TextAlign.End,
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(0.5f)
|
color = MaterialTheme.colorScheme.onSurface.copy(0.5f),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
innerTextField()
|
innerTextField()
|
||||||
|
@ -62,8 +62,8 @@ fun OutlinedDecimalTextField(
|
|||||||
visualTransformation = expressionFormatter,
|
visualTransformation = expressionFormatter,
|
||||||
keyboardOptions = KeyboardOptions(
|
keyboardOptions = KeyboardOptions(
|
||||||
keyboardType = KeyboardType.Decimal,
|
keyboardType = KeyboardType.Decimal,
|
||||||
imeAction = imeAction
|
imeAction = imeAction,
|
||||||
),
|
),
|
||||||
colors = colors
|
colors = colors,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,8 @@ fun TextFieldValue.addTokens(tokens: String): TextFieldValue {
|
|||||||
Token.Operator.plus,
|
Token.Operator.plus,
|
||||||
Token.Operator.multiply,
|
Token.Operator.multiply,
|
||||||
Token.Operator.divide,
|
Token.Operator.divide,
|
||||||
Token.Operator.power -> {
|
Token.Operator.power,
|
||||||
|
-> {
|
||||||
if (ahead == Token.Operator.plus) return deleteAheadAndAdd(tokens)
|
if (ahead == Token.Operator.plus) return deleteAheadAndAdd(tokens)
|
||||||
if (ahead == Token.Operator.minus) return deleteAheadAndAdd(tokens)
|
if (ahead == Token.Operator.minus) return deleteAheadAndAdd(tokens)
|
||||||
if (ahead == Token.Operator.multiply) return deleteAheadAndAdd(tokens)
|
if (ahead == Token.Operator.multiply) return deleteAheadAndAdd(tokens)
|
||||||
@ -50,7 +51,7 @@ fun TextFieldValue.addTokens(tokens: String): TextFieldValue {
|
|||||||
|
|
||||||
return this.copy(
|
return this.copy(
|
||||||
text = text.replaceRange(selection.start, selection.end, tokens),
|
text = text.replaceRange(selection.start, selection.end, tokens),
|
||||||
selection = TextRange(selection.start + tokens.length)
|
selection = TextRange(selection.start + tokens.length),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ fun TextFieldValue.addBracket(): TextFieldValue {
|
|||||||
Token.Operator.plus,
|
Token.Operator.plus,
|
||||||
Token.Operator.minus,
|
Token.Operator.minus,
|
||||||
Token.Operator.power,
|
Token.Operator.power,
|
||||||
Token.Operator.leftBracket
|
Token.Operator.leftBracket,
|
||||||
)
|
)
|
||||||
if (text.tokenAhead(selection.start) in operators2) {
|
if (text.tokenAhead(selection.start) in operators2) {
|
||||||
return addTokens(Token.Operator.leftBracket)
|
return addTokens(Token.Operator.leftBracket)
|
||||||
@ -122,7 +123,7 @@ fun TextFieldValue.deleteTokens(): TextFieldValue {
|
|||||||
|
|
||||||
return this.copy(
|
return this.copy(
|
||||||
text = newText,
|
text = newText,
|
||||||
selection = TextRange((newText.length - distanceFromEnd).coerceAtLeast(0))
|
selection = TextRange((newText.length - distanceFromEnd).coerceAtLeast(0)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import androidx.annotation.RequiresApi
|
|||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
internal class FloatingTextActionModeCallback(
|
internal class FloatingTextActionModeCallback(
|
||||||
private val callback: UnittoActionModeCallback
|
private val callback: UnittoActionModeCallback,
|
||||||
) : ActionMode.Callback2() {
|
) : ActionMode.Callback2() {
|
||||||
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
||||||
return callback.onActionItemClicked(mode, item)
|
return callback.onActionItemClicked(mode, item)
|
||||||
@ -48,14 +48,14 @@ internal class FloatingTextActionModeCallback(
|
|||||||
override fun onGetContentRect(
|
override fun onGetContentRect(
|
||||||
mode: ActionMode?,
|
mode: ActionMode?,
|
||||||
view: View?,
|
view: View?,
|
||||||
outRect: android.graphics.Rect?
|
outRect: android.graphics.Rect?,
|
||||||
) {
|
) {
|
||||||
val rect = callback.rect
|
val rect = callback.rect
|
||||||
outRect?.set(
|
outRect?.set(
|
||||||
rect.left.toInt(),
|
rect.left.toInt(),
|
||||||
rect.top.toInt(),
|
rect.top.toInt(),
|
||||||
rect.right.toInt(),
|
rect.right.toInt(),
|
||||||
rect.bottom.toInt()
|
rect.bottom.toInt(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ internal class UnittoActionModeCallback(
|
|||||||
var onCopyRequested: (() -> Unit)? = null,
|
var onCopyRequested: (() -> Unit)? = null,
|
||||||
var onPasteRequested: (() -> Unit)? = null,
|
var onPasteRequested: (() -> Unit)? = null,
|
||||||
var onCutRequested: (() -> Unit)? = null,
|
var onCutRequested: (() -> Unit)? = null,
|
||||||
var onSelectAllRequested: (() -> Unit)? = null
|
var onSelectAllRequested: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
requireNotNull(menu)
|
requireNotNull(menu)
|
||||||
|
@ -23,7 +23,7 @@ import android.view.Menu
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
|
||||||
internal class UnittoPrimaryTextActionModeCallback(
|
internal class UnittoPrimaryTextActionModeCallback(
|
||||||
private val callback: UnittoActionModeCallback
|
private val callback: UnittoActionModeCallback,
|
||||||
) : ActionMode.Callback {
|
) : ActionMode.Callback {
|
||||||
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
||||||
return callback.onActionItemClicked(mode, item)
|
return callback.onActionItemClicked(mode, item)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user