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 android.util.Log
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.Preferences
@ -32,9 +32,11 @@ import androidx.glance.GlanceId
import androidx.glance.GlanceModifier import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme import androidx.glance.GlanceTheme
import androidx.glance.LocalContext import androidx.glance.LocalContext
import androidx.glance.LocalSize
import androidx.glance.action.Action import androidx.glance.action.Action
import androidx.glance.action.ActionParameters import androidx.glance.action.ActionParameters
import androidx.glance.appwidget.GlanceAppWidget import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.SizeMode
import androidx.glance.appwidget.action.actionRunCallback import androidx.glance.appwidget.action.actionRunCallback
import androidx.glance.appwidget.appWidgetBackground import androidx.glance.appwidget.appWidgetBackground
import androidx.glance.appwidget.provideContent import androidx.glance.appwidget.provideContent
@ -46,12 +48,12 @@ import androidx.glance.layout.Column
import androidx.glance.layout.Row import androidx.glance.layout.Row
import androidx.glance.layout.fillMaxSize import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.fillMaxWidth import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.state.GlanceStateDefinition import androidx.glance.state.GlanceStateDefinition
import androidx.glance.state.PreferencesGlanceStateDefinition import androidx.glance.state.PreferencesGlanceStateDefinition
import androidx.glance.text.Text import androidx.glance.text.Text
import androidx.glance.text.TextAlign import androidx.glance.text.TextAlign
import androidx.glance.text.TextStyle import androidx.glance.text.TextStyle
import androidx.glance.unit.ColorProvider
import com.sadellie.unitto.core.base.Token import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
@ -72,18 +74,25 @@ class CalculatorWidget : GlanceAppWidget() {
fun userPrefRep(): UserPreferencesRepository fun userPrefRep(): UserPreferencesRepository
} }
override val sizeMode = SizeMode.Responsive(
setOf(SMALL, BIG)
)
override val stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition override val stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition
companion object { companion object {
val inputKey = ActionParameters.Key<String>("inputKey") internal val inputKey = ActionParameters.Key<String>("inputKey")
val outputKey = ActionParameters.Key<String>("outputKey") internal val outputKey = ActionParameters.Key<String>("outputKey")
val equalClickedKey = ActionParameters.Key<Boolean>("equalClickedKey") internal val equalClickedKey = ActionParameters.Key<Boolean>("equalClickedKey")
val precisionKey = ActionParameters.Key<Int>("precisionKey") internal val precisionKey = ActionParameters.Key<Int>("precisionKey")
val outputFormatKey = ActionParameters.Key<Int>("outputFormatKey") internal val outputFormatKey = ActionParameters.Key<Int>("outputFormatKey")
val inputPrefKey = stringPreferencesKey("GLANCE_INPUT") internal val inputPrefKey = stringPreferencesKey("GLANCE_INPUT")
val outputPrefKey = stringPreferencesKey("GLANCE_OUTPUT") internal val outputPrefKey = stringPreferencesKey("GLANCE_OUTPUT")
val equalClickedPrefKey = booleanPreferencesKey("GLANCE_EQUAL_CLICKED") 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) { override suspend fun provideGlance(context: Context, id: GlanceId) {
@ -148,38 +157,28 @@ private fun ReadyUI(
.background(GlanceTheme.colors.background) .background(GlanceTheme.colors.background)
.fillMaxSize() .fillMaxSize()
) { ) {
Column( val uiSectionModifier = GlanceModifier.fillMaxWidth()
modifier = GlanceModifier
.background(GlanceTheme.colors.surfaceVariant) if (LocalSize.current != CalculatorWidget.SMALL) {
.padding(8.dp)
) {
ActionButtons( ActionButtons(
modifier = GlanceModifier.fillMaxWidth().padding(vertical = 8.dp), modifier = uiSectionModifier
onCopyClick = copyAction( .background(GlanceTheme.colors.surfaceVariant),
output = output, output = output,
fractional = formatterSymbols.fractional formatterSymbols = formatterSymbols
),
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
) )
} }
TextFields(
modifier = uiSectionModifier
.background(GlanceTheme.colors.surfaceVariant)
.defaultWeight(),
input = input,
formatterSymbols = formatterSymbols,
output = output
)
GlanceKeyboard( GlanceKeyboard(
modifier = GlanceModifier modifier = uiSectionModifier,
.padding(8.dp),
addTokenAction = { addTokenAction = {
runCalculateAction( runCalculateAction(
// Clear input if equal is clicked and new token is a Digit // Clear input if equal is clicked and new token is a Digit
@ -210,47 +209,66 @@ private fun ReadyUI(
@Composable @Composable
private fun ActionButtons( private fun ActionButtons(
modifier: GlanceModifier, modifier: GlanceModifier,
onCopyClick: Action, output: String,
onLaunchClick: Action, formatterSymbols: FormatterSymbols,
) { ) {
Row( Row(
modifier = modifier modifier = modifier
) { ) {
val boxModifier = GlanceModifier.fillMaxWidth().defaultWeight() val buttonModifier = GlanceModifier.fillMaxWidth().defaultWeight()
IconButton( IconButton(
glanceModifier = boxModifier, glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primary, containerColor = GlanceTheme.colors.primary,
iconRes = R.drawable.content_copy, iconRes = R.drawable.content_copy,
onClick = onCopyClick onClick = copyAction(
output = output,
fractional = formatterSymbols.fractional
)
) )
IconButton( IconButton(
glanceModifier = boxModifier, glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primary, containerColor = GlanceTheme.colors.primary,
iconRes = R.drawable.open_in_new, iconRes = R.drawable.open_in_new,
onClick = onLaunchClick onClick = launchAction(LocalContext.current)
) )
} }
} }
@Composable @Composable
private fun TextField( private fun TextFields(
modifier: GlanceModifier, modifier: GlanceModifier,
input: String, input: String,
formatterSymbols: FormatterSymbols, formatterSymbols: FormatterSymbols,
fontSize: TextUnit, output: String,
maxLines: Int,
) { ) {
Text( Column(
text = input.formatExpression(formatterSymbols),
modifier = modifier, modifier = modifier,
maxLines = maxLines, verticalAlignment = Alignment.Bottom
style = TextStyle( ) {
fontSize = fontSize, val textModifier = GlanceModifier.fillMaxWidth()
textAlign = TextAlign.End,
color = GlanceTheme.colors.onSurfaceVariant Text(
text = input.formatExpression(formatterSymbols),
modifier = textModifier,
maxLines = 1,
style = TextStyle(
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 @Composable
@ -264,12 +282,10 @@ private fun GlanceKeyboard(
useDot: Boolean, useDot: Boolean,
middleZero: Boolean, middleZero: Boolean,
) = Column(modifier = modifier) { ) = Column(modifier = modifier) {
val rowModifier = GlanceModifier.defaultWeight().fillMaxWidth() val rowModifier = GlanceModifier.fillMaxWidth()
Row( Row(rowModifier) {
modifier = rowModifier val buttonModifier = GlanceModifier.defaultWeight()
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
IconButton( IconButton(
glanceModifier = buttonModifier, glanceModifier = buttonModifier,
@ -296,11 +312,8 @@ private fun GlanceKeyboard(
onClick = addTokenAction(Token.Operator.divide) onClick = addTokenAction(Token.Operator.divide)
) )
} }
Row(rowModifier) {
Row( val buttonModifier = GlanceModifier.defaultWeight()
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
IconButton( IconButton(
glanceModifier = buttonModifier, glanceModifier = buttonModifier,
@ -327,11 +340,8 @@ private fun GlanceKeyboard(
onClick = addTokenAction(Token.Operator.multiply) onClick = addTokenAction(Token.Operator.multiply)
) )
} }
Row(rowModifier) {
Row( val buttonModifier = GlanceModifier.defaultWeight()
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
IconButton( IconButton(
glanceModifier = buttonModifier, glanceModifier = buttonModifier,
@ -358,11 +368,8 @@ private fun GlanceKeyboard(
onClick = addTokenAction(Token.Operator.minus) onClick = addTokenAction(Token.Operator.minus)
) )
} }
Row(rowModifier) {
Row( val buttonModifier = GlanceModifier.defaultWeight()
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
IconButton( IconButton(
glanceModifier = buttonModifier, glanceModifier = buttonModifier,
@ -389,11 +396,8 @@ private fun GlanceKeyboard(
onClick = addTokenAction(Token.Operator.plus) onClick = addTokenAction(Token.Operator.plus)
) )
} }
Row(rowModifier) {
Row( val buttonModifier = GlanceModifier.defaultWeight()
modifier = rowModifier
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
if (middleZero) { if (middleZero) {
IconButton( 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 package com.sadellie.unitto.feature.glance.glance
import android.content.Context
import android.os.Build
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable 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.compose.ui.unit.dp
import androidx.core.graphics.drawable.IconCompat
import androidx.glance.ColorFilter import androidx.glance.ColorFilter
import androidx.glance.GlanceModifier import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme import androidx.glance.GlanceTheme
import androidx.glance.Image import androidx.glance.Image
import androidx.glance.ImageProvider import androidx.glance.ImageProvider
import androidx.glance.LocalContext
import androidx.glance.action.Action import androidx.glance.action.Action
import androidx.glance.action.clickable import androidx.glance.action.clickable
import androidx.glance.appwidget.cornerRadius import androidx.glance.appwidget.cornerRadius
@ -34,8 +40,10 @@ import androidx.glance.color.ColorProviders
import androidx.glance.layout.Alignment import androidx.glance.layout.Alignment
import androidx.glance.layout.Box import androidx.glance.layout.Box
import androidx.glance.layout.fillMaxWidth import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.height
import androidx.glance.layout.padding import androidx.glance.layout.padding
import androidx.glance.unit.ColorProvider import androidx.glance.unit.ColorProvider
import com.sadellie.unitto.feature.glance.R
@Composable @Composable
internal fun IconButton( internal fun IconButton(
@ -43,11 +51,11 @@ internal fun IconButton(
containerColor: ColorProvider, containerColor: ColorProvider,
@DrawableRes iconRes: Int, @DrawableRes iconRes: Int,
contentColor: ColorProvider = GlanceTheme.colors.contentColorFor(containerColor), contentColor: ColorProvider = GlanceTheme.colors.contentColorFor(containerColor),
onClickKey: String = iconRes.toString(),
onClick: Action, onClick: Action,
) { ) {
Box( Box(
modifier = glanceModifier modifier = glanceModifier
.height(48.dp)
.padding(4.dp), .padding(4.dp),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
@ -55,8 +63,11 @@ internal fun IconButton(
modifier = GlanceModifier modifier = GlanceModifier
.fillMaxWidth() .fillMaxWidth()
.clickable(onClick) .clickable(onClick)
.cornerRadius(100.dp) .cornerRadius(
.background(containerColor) context = LocalContext.current,
cornerRadius = 24.dp,
color = containerColor
)
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
provider = ImageProvider(iconRes), provider = ImageProvider(iconRes),
contentDescription = null, contentDescription = null,
@ -74,22 +85,24 @@ private fun ColorProviders.contentColorFor(backgroundColor: ColorProvider): Colo
else -> onBackground else -> onBackground
} }
// https://gist.github.com/rozPierog/1145af6e1f10c9199000828ab4bd6bad fun GlanceModifier.cornerRadius(
// Kinda works, but corners parameter needs to be split context: Context,
//@SuppressLint("RestrictedApi") cornerRadius: Dp,
//fun GlanceModifier.cornerRadiusCompat( color: ColorProvider,
// cornerRadius: Int, ): GlanceModifier = when {
// @ColorInt color: Int, Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> this.background(color).cornerRadius(cornerRadius)
// @FloatRange(from = 0.0, to = 1.0) backgroundAlpha: Float = 1f, Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> this.background(
//): GlanceModifier { // This
// return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ImageProvider(
// this.background(Color(color).copy(alpha = backgroundAlpha)) // is
// .cornerRadius(cornerRadius.dp) IconCompat
// } else { // so
// val radii = FloatArray(8) { cornerRadius.toFloat() } .createWithResource(context, R.drawable.rounded_corners_rectangle_shape)
// val shape = ShapeDrawable(RoundRectShape(radii, null, null)) // fucking
// shape.paint.color = ColorUtils.setAlphaComponent(color, (255 * backgroundAlpha).toInt()) .toIcon(context)
// val bitmap = shape.toBitmap(width = 150, height = 75) // stupid
// this.background(BitmapImageProvider(bitmap)) .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" <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" 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:initialLayout="@layout/glance_default_loading_layout"
android:targetCellHeight="4" android:targetCellHeight="4"
android:targetCellWidth="4" android:targetCellWidth="4"
android:minWidth="276dp" android:minWidth="220dp"
android:minHeight="176.dp" android:minHeight="276dp"
android:minResizeHeight="176.dp" android:resizeMode="vertical|horizontal"
android:resizeMode="vertical"
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
tools:targetApi="s" /> tools:targetApi="s" />