mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
parent
544a37b760
commit
8dfb63d4a1
@ -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(
|
||||
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
|
||||
modifier = uiSectionModifier
|
||||
.background(GlanceTheme.colors.surfaceVariant),
|
||||
output = output,
|
||||
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,
|
||||
) {
|
||||
Text(
|
||||
text = input.formatExpression(formatterSymbols),
|
||||
Column(
|
||||
modifier = modifier,
|
||||
maxLines = maxLines,
|
||||
style = TextStyle(
|
||||
fontSize = fontSize,
|
||||
textAlign = TextAlign.End,
|
||||
color = GlanceTheme.colors.onSurfaceVariant
|
||||
verticalAlignment = Alignment.Bottom
|
||||
) {
|
||||
val textModifier = GlanceModifier.fillMaxWidth()
|
||||
|
||||
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
|
||||
@ -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)
|
||||
)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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>
|
@ -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" />
|
Loading…
x
Reference in New Issue
Block a user