Refactor CalculatorWidget

closes #173
This commit is contained in:
Sad Ellie 2024-01-25 22:58:00 +03:00
parent 544a37b760
commit 8dfb63d4a1
4 changed files with 154 additions and 107 deletions

View File

@ -22,7 +22,7 @@ import android.content.Context
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.datastore.preferences.core.Preferences
@ -32,9 +32,11 @@ import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.LocalContext
import androidx.glance.LocalSize
import androidx.glance.action.Action
import androidx.glance.action.ActionParameters
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.SizeMode
import androidx.glance.appwidget.action.actionRunCallback
import androidx.glance.appwidget.appWidgetBackground
import androidx.glance.appwidget.provideContent
@ -46,12 +48,12 @@ import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.state.GlanceStateDefinition
import androidx.glance.state.PreferencesGlanceStateDefinition
import androidx.glance.text.Text
import androidx.glance.text.TextAlign
import androidx.glance.text.TextStyle
import androidx.glance.unit.ColorProvider
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
@ -72,18 +74,25 @@ class CalculatorWidget : GlanceAppWidget() {
fun userPrefRep(): UserPreferencesRepository
}
override val sizeMode = SizeMode.Responsive(
setOf(SMALL, BIG)
)
override val stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition
companion object {
val inputKey = ActionParameters.Key<String>("inputKey")
val outputKey = ActionParameters.Key<String>("outputKey")
val equalClickedKey = ActionParameters.Key<Boolean>("equalClickedKey")
val precisionKey = ActionParameters.Key<Int>("precisionKey")
val outputFormatKey = ActionParameters.Key<Int>("outputFormatKey")
internal val inputKey = ActionParameters.Key<String>("inputKey")
internal val outputKey = ActionParameters.Key<String>("outputKey")
internal val equalClickedKey = ActionParameters.Key<Boolean>("equalClickedKey")
internal val precisionKey = ActionParameters.Key<Int>("precisionKey")
internal val outputFormatKey = ActionParameters.Key<Int>("outputFormatKey")
val inputPrefKey = stringPreferencesKey("GLANCE_INPUT")
val outputPrefKey = stringPreferencesKey("GLANCE_OUTPUT")
val equalClickedPrefKey = booleanPreferencesKey("GLANCE_EQUAL_CLICKED")
internal val inputPrefKey = stringPreferencesKey("GLANCE_INPUT")
internal val outputPrefKey = stringPreferencesKey("GLANCE_OUTPUT")
internal val equalClickedPrefKey = booleanPreferencesKey("GLANCE_EQUAL_CLICKED")
internal val SMALL = DpSize(200.dp, 250.dp)
internal val BIG = DpSize(250.dp, 400.dp)
}
override suspend fun provideGlance(context: Context, id: GlanceId) {
@ -148,38 +157,28 @@ private fun ReadyUI(
.background(GlanceTheme.colors.background)
.fillMaxSize()
) {
Column(
modifier = GlanceModifier
.background(GlanceTheme.colors.surfaceVariant)
.padding(8.dp)
) {
val uiSectionModifier = GlanceModifier.fillMaxWidth()
if (LocalSize.current != CalculatorWidget.SMALL) {
ActionButtons(
modifier = GlanceModifier.fillMaxWidth().padding(vertical = 8.dp),
onCopyClick = copyAction(
modifier = uiSectionModifier
.background(GlanceTheme.colors.surfaceVariant),
output = output,
fractional = formatterSymbols.fractional
),
onLaunchClick = launchAction(LocalContext.current)
)
TextField(
modifier = GlanceModifier.fillMaxWidth(),
input = input,
formatterSymbols = formatterSymbols,
fontSize = 36.sp,
maxLines = 1
)
TextField(
modifier = GlanceModifier.fillMaxWidth(),
input = output,
formatterSymbols = formatterSymbols,
fontSize = 28.sp,
maxLines = 1
formatterSymbols = formatterSymbols
)
}
TextFields(
modifier = uiSectionModifier
.background(GlanceTheme.colors.surfaceVariant)
.defaultWeight(),
input = input,
formatterSymbols = formatterSymbols,
output = output
)
GlanceKeyboard(
modifier = GlanceModifier
.padding(8.dp),
modifier = uiSectionModifier,
addTokenAction = {
runCalculateAction(
// Clear input if equal is clicked and new token is a Digit
@ -210,47 +209,66 @@ private fun ReadyUI(
@Composable
private fun ActionButtons(
modifier: GlanceModifier,
onCopyClick: Action,
onLaunchClick: Action,
output: String,
formatterSymbols: FormatterSymbols,
) {
Row(
modifier = modifier
) {
val boxModifier = GlanceModifier.fillMaxWidth().defaultWeight()
val buttonModifier = GlanceModifier.fillMaxWidth().defaultWeight()
IconButton(
glanceModifier = boxModifier,
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primary,
iconRes = R.drawable.content_copy,
onClick = onCopyClick
onClick = copyAction(
output = output,
fractional = formatterSymbols.fractional
)
)
IconButton(
glanceModifier = boxModifier,
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primary,
iconRes = R.drawable.open_in_new,
onClick = onLaunchClick
onClick = launchAction(LocalContext.current)
)
}
}
@Composable
private fun TextField(
private fun TextFields(
modifier: GlanceModifier,
input: String,
formatterSymbols: FormatterSymbols,
fontSize: TextUnit,
maxLines: Int,
output: String,
) {
Column(
modifier = modifier,
verticalAlignment = Alignment.Bottom
) {
val textModifier = GlanceModifier.fillMaxWidth()
Text(
text = input.formatExpression(formatterSymbols),
modifier = modifier,
maxLines = maxLines,
modifier = textModifier,
maxLines = 1,
style = TextStyle(
fontSize = fontSize,
fontSize = 36.sp,
textAlign = TextAlign.End,
color = GlanceTheme.colors.onSurfaceVariant
)
)
Text(
text = output.formatExpression(formatterSymbols),
modifier = textModifier,
maxLines = 1,
style = TextStyle(
fontSize = 36.sp,
textAlign = TextAlign.End,
color = GlanceTheme.colors.onSurfaceVariant.withAlpha(alpha = 0.5f)
)
)
}
}
@Composable
@ -264,12 +282,10 @@ private fun GlanceKeyboard(
useDot: Boolean,
middleZero: Boolean,
) = Column(modifier = modifier) {
val rowModifier = GlanceModifier.defaultWeight().fillMaxWidth()
val rowModifier = GlanceModifier.fillMaxWidth()
Row(
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
Row(rowModifier) {
val buttonModifier = GlanceModifier.defaultWeight()
IconButton(
glanceModifier = buttonModifier,
@ -296,11 +312,8 @@ private fun GlanceKeyboard(
onClick = addTokenAction(Token.Operator.divide)
)
}
Row(
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
Row(rowModifier) {
val buttonModifier = GlanceModifier.defaultWeight()
IconButton(
glanceModifier = buttonModifier,
@ -327,11 +340,8 @@ private fun GlanceKeyboard(
onClick = addTokenAction(Token.Operator.multiply)
)
}
Row(
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
Row(rowModifier) {
val buttonModifier = GlanceModifier.defaultWeight()
IconButton(
glanceModifier = buttonModifier,
@ -358,11 +368,8 @@ private fun GlanceKeyboard(
onClick = addTokenAction(Token.Operator.minus)
)
}
Row(
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
Row(rowModifier) {
val buttonModifier = GlanceModifier.defaultWeight()
IconButton(
glanceModifier = buttonModifier,
@ -389,11 +396,8 @@ private fun GlanceKeyboard(
onClick = addTokenAction(Token.Operator.plus)
)
}
Row(
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
Row(rowModifier) {
val buttonModifier = GlanceModifier.defaultWeight()
if (middleZero) {
IconButton(
@ -436,3 +440,11 @@ private fun GlanceKeyboard(
)
}
}
@Composable
private fun ColorProvider.withAlpha(alpha: Float): ColorProvider =
ColorProvider(
this
.getColor(LocalContext.current)
.copy(alpha = alpha)
)

View File

@ -18,14 +18,20 @@
package com.sadellie.unitto.feature.glance.glance
import android.content.Context
import android.os.Build
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.IconCompat
import androidx.glance.ColorFilter
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.LocalContext
import androidx.glance.action.Action
import androidx.glance.action.clickable
import androidx.glance.appwidget.cornerRadius
@ -34,8 +40,10 @@ import androidx.glance.color.ColorProviders
import androidx.glance.layout.Alignment
import androidx.glance.layout.Box
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.height
import androidx.glance.layout.padding
import androidx.glance.unit.ColorProvider
import com.sadellie.unitto.feature.glance.R
@Composable
internal fun IconButton(
@ -43,11 +51,11 @@ internal fun IconButton(
containerColor: ColorProvider,
@DrawableRes iconRes: Int,
contentColor: ColorProvider = GlanceTheme.colors.contentColorFor(containerColor),
onClickKey: String = iconRes.toString(),
onClick: Action,
) {
Box(
modifier = glanceModifier
.height(48.dp)
.padding(4.dp),
contentAlignment = Alignment.Center
) {
@ -55,8 +63,11 @@ internal fun IconButton(
modifier = GlanceModifier
.fillMaxWidth()
.clickable(onClick)
.cornerRadius(100.dp)
.background(containerColor)
.cornerRadius(
context = LocalContext.current,
cornerRadius = 24.dp,
color = containerColor
)
.padding(horizontal = 16.dp, vertical = 8.dp),
provider = ImageProvider(iconRes),
contentDescription = null,
@ -74,22 +85,24 @@ private fun ColorProviders.contentColorFor(backgroundColor: ColorProvider): Colo
else -> onBackground
}
// https://gist.github.com/rozPierog/1145af6e1f10c9199000828ab4bd6bad
// Kinda works, but corners parameter needs to be split
//@SuppressLint("RestrictedApi")
//fun GlanceModifier.cornerRadiusCompat(
// cornerRadius: Int,
// @ColorInt color: Int,
// @FloatRange(from = 0.0, to = 1.0) backgroundAlpha: Float = 1f,
//): GlanceModifier {
// return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// this.background(Color(color).copy(alpha = backgroundAlpha))
// .cornerRadius(cornerRadius.dp)
// } else {
// val radii = FloatArray(8) { cornerRadius.toFloat() }
// val shape = ShapeDrawable(RoundRectShape(radii, null, null))
// shape.paint.color = ColorUtils.setAlphaComponent(color, (255 * backgroundAlpha).toInt())
// val bitmap = shape.toBitmap(width = 150, height = 75)
// this.background(BitmapImageProvider(bitmap))
// }
//}
fun GlanceModifier.cornerRadius(
context: Context,
cornerRadius: Dp,
color: ColorProvider,
): GlanceModifier = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> this.background(color).cornerRadius(cornerRadius)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> this.background(
// This
ImageProvider(
// is
IconCompat
// so
.createWithResource(context, R.drawable.rounded_corners_rectangle_shape)
// fucking
.toIcon(context)
// stupid
.setTint(color.getColor(context).toArgb())
)
)
else -> this.background(color)
}

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="24dp" />
<solid android:color="@color/ic_shortcut_background" />
</shape>

View File

@ -18,13 +18,12 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:description="@string/app_name"
android:description="@string/calculator_title"
android:initialLayout="@layout/glance_default_loading_layout"
android:targetCellHeight="4"
android:targetCellWidth="4"
android:minWidth="276dp"
android:minHeight="176.dp"
android:minResizeHeight="176.dp"
android:resizeMode="vertical"
android:minWidth="220dp"
android:minHeight="276dp"
android:resizeMode="vertical|horizontal"
android:widgetCategory="home_screen"
tools:targetApi="s" />