Refactor widget

This commit is contained in:
Sad Ellie 2024-01-07 00:20:19 +03:00
parent 3638af2e45
commit f88fba44bb
5 changed files with 527 additions and 284 deletions

View File

@ -0,0 +1,95 @@
/*
* Unitto is a unit converter 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/>.
*/
package com.sadellie.unitto.feature.glance.glance
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.glance.ColorFilter
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.action.Action
import androidx.glance.action.clickable
import androidx.glance.appwidget.cornerRadius
import androidx.glance.background
import androidx.glance.color.ColorProviders
import androidx.glance.layout.Alignment
import androidx.glance.layout.Box
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.unit.ColorProvider
@Composable
internal fun IconButton(
glanceModifier: GlanceModifier,
containerColor: ColorProvider,
@DrawableRes iconRes: Int,
contentColor: ColorProvider = GlanceTheme.colors.contentColorFor(containerColor),
onClickKey: String = iconRes.toString(),
onClick: Action,
) {
Box(
modifier = glanceModifier
.padding(4.dp),
contentAlignment = Alignment.Center
) {
Image(
modifier = GlanceModifier
.fillMaxWidth()
.clickable(onClick)
.cornerRadius(100.dp)
.background(containerColor)
.padding(horizontal = 16.dp, vertical = 8.dp),
provider = ImageProvider(iconRes),
contentDescription = null,
colorFilter = ColorFilter.tint(contentColor)
)
}
}
private fun ColorProviders.contentColorFor(backgroundColor: ColorProvider): ColorProvider =
when (backgroundColor) {
primary -> onPrimary
primaryContainer -> onPrimaryContainer
inverseOnSurface -> onSurfaceVariant
tertiaryContainer -> onTertiaryContainer
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))
// }
//}

View File

@ -0,0 +1,30 @@
/*
* Unitto is a unit converter 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/>.
*/
package com.sadellie.unitto.feature.glance.glance
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.ui.common.textfield.addBracket
import com.sadellie.unitto.core.ui.common.textfield.addTokens
internal fun String.addToken(token: String): String =
TextFieldValue(this, TextRange(length)).addTokens(token).text
internal fun String.addBracket(): String =
TextFieldValue(this, TextRange(length)).addBracket().text

View File

@ -18,60 +18,42 @@
package com.sadellie.unitto.feature.glance.glance
import android.content.ComponentName
import android.content.Context
import android.os.Build
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.glance.ColorFilter
import androidx.glance.GlanceId
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.ActionParameters
import androidx.glance.action.actionParametersOf
import androidx.glance.action.actionStartActivity
import androidx.glance.action.clickable
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.action.actionRunCallback
import androidx.glance.appwidget.appWidgetBackground
import androidx.glance.appwidget.cornerRadius
import androidx.glance.appwidget.provideContent
import androidx.glance.background
import androidx.glance.color.ColorProviders
import androidx.glance.currentState
import androidx.glance.layout.Alignment
import androidx.glance.layout.Box
import androidx.glance.layout.Column
import androidx.glance.layout.ColumnScope
import androidx.glance.layout.Row
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.material3.ColorProviders
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.addBracket
import com.sadellie.unitto.core.ui.common.textfield.addTokens
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.core.ui.theme.DarkThemeColors
import com.sadellie.unitto.core.ui.theme.LightThemeColors
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import com.sadellie.unitto.data.model.userprefs.CalculatorPreferences
import com.sadellie.unitto.feature.glance.R
@ -102,123 +84,15 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
val userPrefsRepository = EntryPoints.get(context, UserPrefEntryPoint::class.java).userPrefRep()
val userPrefsRepository =
EntryPoints.get(context, UserPrefEntryPoint::class.java).userPrefRep()
provideContent {
val appPrefs = userPrefsRepository.calculatorPrefs.collectAsState(initial = null).value
WidgetTheme {
if (appPrefs == null) {
LoadingUI()
return@WidgetTheme
if (appPrefs == null) LoadingUI() else ReadyUI(appPrefs)
}
ReadyUI(appPrefs)
}
}
}
@Composable
private fun WidgetTheme(content: @Composable () -> Unit) =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
GlanceTheme {
content()
}
} else {
GlanceTheme(
colors = ColorProviders(light = LightThemeColors, dark = DarkThemeColors)
) {
content()
}
}
@Composable
private fun ReadyUI(
appPrefs: CalculatorPreferences,
) {
val glancePrefs = currentState<Preferences>()
val input = glancePrefs[inputPrefKey] ?: ""
val output = glancePrefs[outputPrefKey] ?: ""
val formatterSymbols = AllFormatterSymbols.getById(appPrefs.separator)
fun runCalculateAction(input: String): Action = actionRunCallback<UpdateInputAction>(
actionParametersOf(
inputKey to input,
precisionKey to appPrefs.precision,
outputFormatKey to appPrefs.outputFormat
)
)
fun runCopyAction(): Action = actionRunCallback<CopyResultAction>(
actionParametersOf(
outputKey to output.replace(Token.Digit.dot, formatterSymbols.fractional)
)
)
Column(
modifier = GlanceModifier
.appWidgetBackground()
.background(GlanceTheme.colors.background)
.fillMaxSize()
) {
Column(
modifier = GlanceModifier
.background(GlanceTheme.colors.surfaceVariant)
) {
Row(modifier = GlanceModifier.fillMaxWidth().padding(8.dp)) {
val boxModifier = GlanceModifier.fillMaxWidth().defaultWeight()
GlanceKeyboardButton(boxModifier, GlanceTheme.colors.primary, R.drawable.content_copy, onClick = runCopyAction())
GlanceKeyboardButton(boxModifier, GlanceTheme.colors.primary, R.drawable.open_in_new, onClick = actionStartActivity(ComponentName(LocalContext.current, "com.sadellie.unitto.MainActivity")))
}
Text(
text = input.formatExpression(formatterSymbols),
modifier = GlanceModifier.fillMaxWidth(),
maxLines = 2,
style = TextStyle(
fontSize = 36.sp,
textAlign = TextAlign.End,
color = GlanceTheme.colors.onSurfaceVariant
),
)
Text(
text = output.formatExpression(formatterSymbols),
modifier = GlanceModifier.fillMaxWidth(),
maxLines = 1,
style = TextStyle(
fontSize = 36.sp,
textAlign = TextAlign.End,
color = GlanceTheme.colors.onSurfaceVariant
),
)
}
Column(
modifier = GlanceModifier
.padding(8.dp)
) {
GlanceKeyboard(
addTokenAction = {
runCalculateAction(input.addToken(it))
},
replaceInputAction = {
runCalculateAction(it)
},
addBracketAction = {
runCalculateAction(input.addBracket())
},
deleteTokenAction = {
runCalculateAction(input.dropLast(1))
},
equalAction = equal@{
if (input.isEmpty()) return@equal actionRunCallback<UpdateInputAction>()
runCalculateAction(output)
},
useDot = formatterSymbols.fractional == Token.Digit.dot,
middleZero = appPrefs.middleZero
)
}
}
}
@ -232,7 +106,7 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
.fillMaxSize(),
contentAlignment = Alignment.Center
) {
GlanceKeyboardButton(
IconButton(
glanceModifier = GlanceModifier,
containerColor = GlanceTheme.colors.primary,
iconRes = R.drawable.refresh,
@ -242,7 +116,129 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
}
@Composable
private fun ColumnScope.GlanceKeyboard(
private fun ReadyUI(
appPrefs: CalculatorPreferences,
) {
val glancePrefs = currentState<Preferences>()
val input = glancePrefs[UnittoCalculatorWidget.inputPrefKey] ?: ""
val output = glancePrefs[UnittoCalculatorWidget.outputPrefKey] ?: ""
val formatterSymbols = AllFormatterSymbols.getById(appPrefs.separator)
fun runCalculateAction(input: String): Action = updateInputAction(
input = input,
precision = appPrefs.precision,
outputFormat = appPrefs.outputFormat
)
Column(
modifier = GlanceModifier
.appWidgetBackground()
.background(GlanceTheme.colors.background)
.fillMaxSize()
) {
Column(
modifier = GlanceModifier
.background(GlanceTheme.colors.surfaceVariant)
) {
ActionButtons(
modifier = GlanceModifier.fillMaxWidth().padding(8.dp),
onCopyClick = copyAction(
output = output,
fractional = formatterSymbols.fractional
),
onLaunchClick = launchAction(LocalContext.current)
)
TextField(
modifier = GlanceModifier.fillMaxWidth(),
input = input,
formatterSymbols = formatterSymbols,
fontSize = 36.sp,
maxLines = 2
)
TextField(
modifier = GlanceModifier.fillMaxWidth(),
input = output,
formatterSymbols = formatterSymbols,
fontSize = 28.sp,
maxLines = 1
)
}
GlanceKeyboard(
modifier = GlanceModifier
.padding(8.dp),
addTokenAction = {
runCalculateAction(input.addToken(it))
},
replaceInputAction = {
runCalculateAction(it)
},
addBracketAction = {
runCalculateAction(input.addBracket())
},
deleteTokenAction = {
runCalculateAction(input.dropLast(1))
},
equalAction = equal@{
if (output.isEmpty()) return@equal actionRunCallback<UpdateInputAction>()
runCalculateAction(output)
},
useDot = formatterSymbols.fractional == Token.Digit.dot,
middleZero = appPrefs.middleZero
)
}
}
@Composable
private fun ActionButtons(
modifier: GlanceModifier,
onCopyClick: Action,
onLaunchClick: Action,
) {
Row(
modifier = modifier
) {
val boxModifier = GlanceModifier.fillMaxWidth().defaultWeight()
IconButton(
glanceModifier = boxModifier,
containerColor = GlanceTheme.colors.primary,
iconRes = R.drawable.content_copy,
onClick = onCopyClick
)
IconButton(
glanceModifier = boxModifier,
containerColor = GlanceTheme.colors.primary,
iconRes = R.drawable.open_in_new,
onClick = onLaunchClick
)
}
}
@Composable
private fun TextField(
modifier: GlanceModifier,
input: String,
formatterSymbols: FormatterSymbols,
fontSize: TextUnit,
maxLines: Int,
) {
Text(
text = input.formatExpression(formatterSymbols),
modifier = modifier,
maxLines = maxLines,
style = TextStyle(
fontSize = fontSize,
textAlign = TextAlign.End,
color = GlanceTheme.colors.onSurfaceVariant
)
)
}
@Composable
private fun GlanceKeyboard(
modifier: GlanceModifier,
addTokenAction: (String) -> Action,
replaceInputAction: (String) -> Action,
addBracketAction: () -> Action,
@ -250,7 +246,7 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
equalAction: () -> Action,
useDot: Boolean,
middleZero: Boolean,
) {
) = Column(modifier = modifier) {
val rowModifier = GlanceModifier.defaultWeight().fillMaxWidth()
Row(
@ -258,10 +254,30 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.tertiaryContainer, R.drawable.clear, onClick = replaceInputAction(""))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.primaryContainer, R.drawable.brackets, onClick = addBracketAction())
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.primaryContainer, R.drawable.percent, onClick = addTokenAction(Token.Operator.percent))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.primaryContainer, R.drawable.divide, onClick = addTokenAction(Token.Operator.divide))
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.tertiaryContainer,
iconRes = R.drawable.clear,
onClick = replaceInputAction("")
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primaryContainer,
iconRes = R.drawable.brackets,
onClick = addBracketAction()
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primaryContainer,
iconRes = R.drawable.percent,
onClick = addTokenAction(Token.Operator.percent)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primaryContainer,
iconRes = R.drawable.divide,
onClick = addTokenAction(Token.Operator.divide)
)
}
Row(
@ -269,10 +285,30 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key7, onClick = addTokenAction(Token.Digit._7))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key8, onClick = addTokenAction(Token.Digit._8))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key9, onClick = addTokenAction(Token.Digit._9))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.primaryContainer, R.drawable.multiply, onClick = addTokenAction(Token.Operator.multiply))
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key7,
onClick = addTokenAction(Token.Digit._7)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key8,
onClick = addTokenAction(Token.Digit._8)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key9,
onClick = addTokenAction(Token.Digit._9)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primaryContainer,
iconRes = R.drawable.multiply,
onClick = addTokenAction(Token.Operator.multiply)
)
}
Row(
@ -280,10 +316,30 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key4, onClick = addTokenAction(Token.Digit._4))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key5, onClick = addTokenAction(Token.Digit._5))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key6, onClick = addTokenAction(Token.Digit._6))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.primaryContainer, R.drawable.minus, onClick = addTokenAction(Token.Operator.minus))
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key4,
onClick = addTokenAction(Token.Digit._4)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key5,
onClick = addTokenAction(Token.Digit._5)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key6,
onClick = addTokenAction(Token.Digit._6)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primaryContainer,
iconRes = R.drawable.minus,
onClick = addTokenAction(Token.Operator.minus)
)
}
Row(
@ -291,10 +347,30 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
) {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key1, onClick = addTokenAction(Token.Digit._1))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key2, onClick = addTokenAction(Token.Digit._2))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key3, onClick = addTokenAction(Token.Digit._3))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.primaryContainer, R.drawable.plus, onClick = addTokenAction(Token.Operator.plus))
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key1,
onClick = addTokenAction(Token.Digit._1)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key2,
onClick = addTokenAction(Token.Digit._2)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key3,
onClick = addTokenAction(Token.Digit._3)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primaryContainer,
iconRes = R.drawable.plus,
onClick = addTokenAction(Token.Operator.plus)
)
}
Row(
@ -303,77 +379,43 @@ class UnittoCalculatorWidget : GlanceAppWidget() {
val buttonModifier = GlanceModifier.fillMaxSize().defaultWeight()
if (middleZero) {
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, if (useDot) R.drawable.dot else R.drawable.comma, onClick = addTokenAction(Token.Digit.dot))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key0, onClick = addTokenAction(Token.Digit._0))
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = if (useDot) R.drawable.dot else R.drawable.comma,
onClick = addTokenAction(Token.Digit.dot)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key0,
onClick = addTokenAction(Token.Digit._0)
)
} else {
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.key0, onClick = addTokenAction(Token.Digit._0))
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, if (useDot) R.drawable.dot else R.drawable.comma, onClick = addTokenAction(Token.Digit.dot))
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.key0,
onClick = addTokenAction(Token.Digit._0)
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = if (useDot) R.drawable.dot else R.drawable.comma,
onClick = addTokenAction(Token.Digit.dot)
)
}
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.inverseOnSurface, R.drawable.backspace, onClick = deleteTokenAction())
GlanceKeyboardButton(buttonModifier, GlanceTheme.colors.primaryContainer, R.drawable.equal, onClick = equalAction())
}
}
@Composable
private fun GlanceKeyboardButton(
glanceModifier: GlanceModifier,
containerColor: ColorProvider,
@DrawableRes iconRes: Int,
contentColor: ColorProvider = GlanceTheme.colors.contentColorFor(containerColor),
onClickKey: String = iconRes.toString(),
onClick: Action,
) {
Box(
modifier = glanceModifier
.padding(4.dp),
contentAlignment = Alignment.Center
) {
Image(
modifier = GlanceModifier
.fillMaxWidth()
.clickable(onClick)
.cornerRadius(100.dp)
.background(containerColor)
.padding(horizontal = 16.dp, vertical = 8.dp),
provider = ImageProvider(iconRes),
contentDescription = null,
colorFilter = ColorFilter.tint(contentColor)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.inverseOnSurface,
iconRes = R.drawable.backspace,
onClick = deleteTokenAction()
)
IconButton(
glanceModifier = buttonModifier,
containerColor = GlanceTheme.colors.primaryContainer,
iconRes = R.drawable.equal,
onClick = equalAction()
)
}
}
}
// 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))
// }
//}
private fun String.addToken(token: String): String =
TextFieldValue(this, TextRange(length)).addTokens(token).text
private fun String.addBracket(): String =
TextFieldValue(this, TextRange(length)).addBracket().text
private fun ColorProviders.contentColorFor(backgroundColor: ColorProvider): ColorProvider =
when (backgroundColor) {
primary -> onPrimary
primaryContainer -> onPrimaryContainer
inverseOnSurface -> onSurfaceVariant
tertiaryContainer -> onTertiaryContainer
else -> onBackground
}

View File

@ -20,11 +20,17 @@ package com.sadellie.unitto.feature.glance.glance
import android.content.ClipData
import android.content.ClipboardManager
import android.content.ComponentName
import android.content.Context
import androidx.glance.GlanceId
import androidx.glance.action.Action
import androidx.glance.action.ActionParameters
import androidx.glance.action.actionParametersOf
import androidx.glance.action.actionStartActivity
import androidx.glance.appwidget.action.ActionCallback
import androidx.glance.appwidget.action.actionRunCallback
import androidx.glance.appwidget.state.updateAppWidgetState
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.data.common.format
import com.sadellie.unitto.data.common.isExpression
import io.github.sadellie.evaluatto.Expression
@ -87,6 +93,36 @@ internal class RestartWidget : ActionCallback {
}
}
internal fun updateInputAction(
input: String,
precision: Int,
outputFormat: Int
): Action = actionRunCallback<UpdateInputAction>(
actionParametersOf(
UnittoCalculatorWidget.inputKey to input,
UnittoCalculatorWidget.precisionKey to precision,
UnittoCalculatorWidget.outputFormatKey to outputFormat
)
)
internal fun copyAction(
output: String,
fractional: String
): Action = actionRunCallback<CopyResultAction>(
actionParametersOf(
UnittoCalculatorWidget.outputKey to output.replace(Token.Digit.dot, fractional)
)
)
internal fun launchAction(
mContext: Context
): Action = actionStartActivity(
ComponentName(
mContext,
"com.sadellie.unitto.MainActivity"
)
)
private fun calculate(
input: String,
precision: Int,

View File

@ -0,0 +1,40 @@
/*
* Unitto is a unit converter 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/>.
*/
package com.sadellie.unitto.feature.glance.glance
import android.os.Build
import androidx.compose.runtime.Composable
import androidx.glance.GlanceTheme
import androidx.glance.material3.ColorProviders
import com.sadellie.unitto.core.ui.theme.DarkThemeColors
import com.sadellie.unitto.core.ui.theme.LightThemeColors
@Composable
internal fun WidgetTheme(content: @Composable () -> Unit) =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
GlanceTheme {
content()
}
} else {
GlanceTheme(
colors = ColorProviders(light = LightThemeColors, dark = DarkThemeColors)
) {
content()
}
}