Make unit converter parsing more lenient and add units of volume
Close #1323
This commit is contained in:
@@ -39,6 +39,7 @@ import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.icons.Cube
|
||||
import de.mm20.launcher2.search.data.CurrencyUnitConverter
|
||||
import de.mm20.launcher2.search.data.UnitConverter
|
||||
import de.mm20.launcher2.ui.R
|
||||
@@ -220,7 +221,7 @@ fun getDimensionIcon(dimension: Dimension): ImageVector {
|
||||
Dimension.Mass -> Icons.Rounded.FitnessCenter
|
||||
Dimension.Length -> Icons.Rounded.Straighten
|
||||
Dimension.Velocity -> Icons.Rounded.Speed
|
||||
Dimension.Volume -> TODO()
|
||||
Dimension.Volume -> Icons.Rounded.Cube
|
||||
Dimension.Area -> Icons.Rounded.SquareFoot
|
||||
Dimension.Currency -> Icons.Rounded.Toll
|
||||
Dimension.Data -> Icons.Rounded.Storage
|
||||
|
||||
@@ -714,7 +714,7 @@ fun CustomizeCustomIntent(viewModel: EditSearchActionSheetVM) {
|
||||
supportingText = {
|
||||
Text(
|
||||
if (action.queryKey == null) {
|
||||
"The URI template that is used to construct the intent\\'s data URI. Use ‘\${1}’ as a placeholder for the actual search term, e.g. geo:0,0?q=,\${1}"
|
||||
"The URI template that is used to construct the intent\\'s data URI. Use ‘\${1}’ as a placeholder for the actual search term"
|
||||
} else {
|
||||
"The template that is used to construct the string that is passed to the intent as a string extra. Use ‘\${1}’ as a placeholder for the actual search term"
|
||||
}
|
||||
|
||||
@@ -2305,3 +2305,47 @@ private val _Climbing = materialIcon("Icons.Rounded.Climbing") {
|
||||
|
||||
val Icons.Rounded.Climbing
|
||||
get() = _Climbing
|
||||
|
||||
private val _Cube = materialIcon("Icons.Rounded.Cube") {
|
||||
materialPath {
|
||||
moveTo(11f, 19.425f)
|
||||
verticalLineToRelative(-6.85f)
|
||||
lineTo(5f, 9.1f)
|
||||
verticalLineToRelative(6.85f)
|
||||
close()
|
||||
moveToRelative(2f, 0f)
|
||||
lineToRelative(6f, -3.475f)
|
||||
verticalLineTo(9.1f)
|
||||
lineToRelative(-6f, 3.475f)
|
||||
close()
|
||||
moveTo(12f, 10.85f)
|
||||
lineTo(17.925f, 7.425f)
|
||||
lineTo(12f, 4f)
|
||||
lineTo(6.075f, 7.425f)
|
||||
close()
|
||||
moveTo(4f, 17.7f)
|
||||
quadTo(3.525f, 17.425f, 3.2625f, 16.975f)
|
||||
quadTo(3f, 16.525f, 3f, 15.975f)
|
||||
verticalLineToRelative(-7.95f)
|
||||
quadToRelative(0f, -0.55f, 0.2625f, -1f)
|
||||
quadTo(3.525f, 6.575f, 4f, 6.3f)
|
||||
lineTo(11f, 2.275f)
|
||||
quadTo(11.475f, 2f, 12f, 2f)
|
||||
quadTo(12.525f, 2f, 13f, 2.275f)
|
||||
lineTo(20f, 6.3f)
|
||||
quadTo(20.475f, 6.575f, 20.7375f, 7.025f)
|
||||
quadTo(21f, 7.475f, 21f, 8.025f)
|
||||
verticalLineToRelative(7.95f)
|
||||
quadToRelative(0f, 0.55f, -0.2625f, 1f)
|
||||
quadTo(20.475f, 17.425f, 20f, 17.7f)
|
||||
lineToRelative(-7f, 4.025f)
|
||||
quadTo(12.525f, 22f, 12f, 22f)
|
||||
quadTo(11.475f, 22f, 11f, 21.725f)
|
||||
close()
|
||||
moveTo(12f, 12f)
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
val Icons.Rounded.Cube
|
||||
get() = _Cube
|
||||
18
core/i18n/src/main/res/values-en-rGB/units.xml
Normal file
18
core/i18n/src/main/res/values-en-rGB/units.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="unit_gallon_imp_symbol">gal</string>
|
||||
<plurals name="unit_gallon_imp">
|
||||
<item quantity="one">gallon</item>
|
||||
<item quantity="other">gallons</item>
|
||||
</plurals>
|
||||
<string name="unit_pint_imp_symbol">pt</string>
|
||||
<plurals name="unit_pint_imp">
|
||||
<item quantity="one">pint</item>
|
||||
<item quantity="other">pints</item>
|
||||
</plurals>
|
||||
<string name="unit_fluid_ounce_imp_symbol">fl oz</string>
|
||||
<plurals name="unit_fluid_ounce_imp">
|
||||
<item quantity="one">fluid ounce</item>
|
||||
<item quantity="other">fluid ounces</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
18
core/i18n/src/main/res/values-en-rUS/units.xml
Normal file
18
core/i18n/src/main/res/values-en-rUS/units.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="unit_gallon_us_symbol">gal</string>
|
||||
<plurals name="unit_gallon_us">
|
||||
<item quantity="one">gallon</item>
|
||||
<item quantity="other">gallons</item>
|
||||
</plurals>
|
||||
<string name="unit_pint_us_symbol">pt</string>
|
||||
<plurals name="unit_pint_us">
|
||||
<item quantity="one">pint</item>
|
||||
<item quantity="other">pints</item>
|
||||
</plurals>
|
||||
<string name="unit_fluid_ounce_us_symbol">fl oz</string>
|
||||
<plurals name="unit_fluid_ounce_us">
|
||||
<item quantity="one">fluid ounce</item>
|
||||
<item quantity="other">fluid ounces</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
@@ -294,4 +294,92 @@
|
||||
<item quantity="one">kelvin</item>
|
||||
<item quantity="other">kelvins</item>
|
||||
</plurals>
|
||||
<!-- UNITS OF VOLUME -->
|
||||
<string name="unit_liter_symbol">l</string>
|
||||
<plurals name="unit_liter">
|
||||
<item quantity="one">liter</item>
|
||||
<item quantity="other">liters</item>
|
||||
</plurals>
|
||||
<string name="unit_milliliter_symbol">ml</string>
|
||||
<plurals name="unit_milliliter">
|
||||
<item quantity="one">milliliter</item>
|
||||
<item quantity="other">milliliters</item>
|
||||
</plurals>
|
||||
<string name="unit_cubic_meter_symbol">m³</string>
|
||||
<plurals name="unit_cubic_meter">
|
||||
<item quantity="one">cubic meter</item>
|
||||
<item quantity="other">cubic meters</item>
|
||||
</plurals>
|
||||
<string name="unit_cubic_centimeter_symbol">cm³</string>
|
||||
<plurals name="unit_cubic_centimeter">
|
||||
<item quantity="one">cubic centimeter</item>
|
||||
<item quantity="other">cubic centimeters</item>
|
||||
</plurals>
|
||||
<string name="unit_cubic_millimeter_symbol">mm³</string>
|
||||
<plurals name="unit_cubic_millimeter">
|
||||
<item quantity="one">cubic millimeter</item>
|
||||
<item quantity="other">cubic millimeters</item>
|
||||
</plurals>
|
||||
<string name="unit_cubic_inch_symbol">cuin</string>
|
||||
<plurals name="unit_cubic_inch">
|
||||
<item quantity="one">cubic inch</item>
|
||||
<item quantity="other">cubic inches</item>
|
||||
</plurals>
|
||||
<string name="unit_cubic_foot_symbol">cuft</string>
|
||||
<plurals name="unit_cubic_foot">
|
||||
<item quantity="one">cubic foot</item>
|
||||
<item quantity="other">cubic feet</item>
|
||||
</plurals>
|
||||
<string name="unit_cubic_yard_symbol">cuyd</string>
|
||||
<plurals name="unit_cubic_yard">
|
||||
<item quantity="one">cubic yard</item>
|
||||
<item quantity="other">cubic yards</item>
|
||||
</plurals>
|
||||
<string name="unit_gallon_us_symbol">gal US</string>
|
||||
<plurals name="unit_gallon_us">
|
||||
<item quantity="one">gallon (US)</item>
|
||||
<item quantity="other">gallons (US)</item>
|
||||
</plurals>
|
||||
<string name="unit_gallon_imp_symbol">gal imp</string>
|
||||
<plurals name="unit_gallon_imp">
|
||||
<item quantity="one">gallon (imperial)</item>
|
||||
<item quantity="other">gallons (imperial)</item>
|
||||
</plurals>
|
||||
<string name="unit_pint_us_symbol">pt US</string>
|
||||
<plurals name="unit_pint_us">
|
||||
<item quantity="one">pint (US)</item>
|
||||
<item quantity="other">pints (US)</item>
|
||||
</plurals>
|
||||
<string name="unit_pint_imp_symbol">pt imp</string>
|
||||
<plurals name="unit_pint_imp">
|
||||
<item quantity="one">pint (imperial)</item>
|
||||
<item quantity="other">pints (imperial)</item>
|
||||
</plurals>
|
||||
<string name="unit_fluid_ounce_us_symbol">fl.oz.US</string>
|
||||
<plurals name="unit_fluid_ounce_us">
|
||||
<item quantity="one">US fluid ounce</item>
|
||||
<item quantity="other">US fluid ounces</item>
|
||||
</plurals>
|
||||
<string name="unit_fluid_ounce_imp_symbol">fl.oz.imp</string>
|
||||
<plurals name="unit_fluid_ounce_imp">
|
||||
<item quantity="one">fluid ounce (imperial)</item>
|
||||
<item quantity="other">fluid ounces (imperial)</item>
|
||||
</plurals>
|
||||
<string name="unit_cup_symbol">cup</string>
|
||||
<plurals name="unit_cup">
|
||||
<item quantity="one">cup (US)</item>
|
||||
<item quantity="other">cups (US)</item>
|
||||
</plurals>
|
||||
<string name="unit_tablespoon_symbol">tbsp</string>
|
||||
<plurals name="unit_tablespoon">
|
||||
<item quantity="one">tablespoon (US)</item>
|
||||
<item quantity="other">tablespoons (US)</item>
|
||||
</plurals>
|
||||
<string name="unit_teaspoon_symbol">tsp</string>
|
||||
<plurals name="unit_teaspoon">
|
||||
<item quantity="one">teaspoon (US)</item>
|
||||
<item quantity="other">teaspoons (US)</item>
|
||||
</plurals>
|
||||
|
||||
|
||||
</resources>
|
||||
@@ -13,13 +13,13 @@ import de.mm20.launcher2.unitconverter.converters.MassConverter
|
||||
import de.mm20.launcher2.unitconverter.converters.TemperatureConverter
|
||||
import de.mm20.launcher2.unitconverter.converters.TimeConverter
|
||||
import de.mm20.launcher2.unitconverter.converters.VelocityConverter
|
||||
import de.mm20.launcher2.unitconverter.converters.VolumeConverter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -27,7 +27,7 @@ import org.koin.core.component.KoinComponent
|
||||
|
||||
interface UnitConverterRepository {
|
||||
fun search(query: String): Flow<UnitConverter?>
|
||||
suspend fun getAvailableConverters(includeCurrencies: Boolean) : List<Converter>
|
||||
suspend fun getAvailableConverters(includeCurrencies: Boolean): List<Converter>
|
||||
}
|
||||
|
||||
internal class UnitConverterRepositoryImpl(
|
||||
@@ -56,7 +56,7 @@ internal class UnitConverterRepositoryImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAvailableConverters(includeCurrencies: Boolean) : List<Converter> {
|
||||
override suspend fun getAvailableConverters(includeCurrencies: Boolean): List<Converter> {
|
||||
val converters = mutableListOf(
|
||||
MassConverter(context),
|
||||
LengthConverter(context),
|
||||
@@ -64,7 +64,8 @@ internal class UnitConverterRepositoryImpl(
|
||||
TimeConverter(context),
|
||||
VelocityConverter(context),
|
||||
AreaConverter(context),
|
||||
TemperatureConverter(context)
|
||||
TemperatureConverter(context),
|
||||
VolumeConverter(context),
|
||||
)
|
||||
if (includeCurrencies) converters.add(CurrencyConverter(currencyRepository))
|
||||
|
||||
@@ -75,28 +76,51 @@ internal class UnitConverterRepositoryImpl(
|
||||
query: String,
|
||||
includeCurrencies: Boolean
|
||||
): UnitConverter? {
|
||||
if (!query.matches(Regex("[0-9,.:]+ [^\\s]+")) &&
|
||||
!query.matches(Regex("[0-9,.:]+ [^\\s]+ >> [^\\s]+")) &&
|
||||
!query.matches(Regex("[0-9,.:]+ [^\\s]+ > [^\\s]+")) &&
|
||||
!query.matches(Regex("[0-9,.:]+ [^\\s]+ - [^\\s]+"))) return null
|
||||
val valueStr: String
|
||||
val unitStr: String
|
||||
val targetUnitStr: String?
|
||||
val regex = Regex("""([+\-]?[\d+\-e,.]+|[^\d>\-]+)""")
|
||||
|
||||
query.split(" ").also {
|
||||
valueStr = it.get(0)
|
||||
unitStr = it.get(1)
|
||||
targetUnitStr = it.getOrNull(3)
|
||||
val matches = regex.findAll(query)
|
||||
|
||||
var inputStr: String? = null
|
||||
var inputValue: Double? = null
|
||||
var inputUnit: String? = null
|
||||
var outputUnit: String? = null
|
||||
|
||||
for ((i, match) in matches.withIndex()) {
|
||||
when (i) {
|
||||
0 -> {
|
||||
inputStr = match.value.trim()
|
||||
inputValue = inputStr.toDoubleOrNull()
|
||||
?: inputStr.replace(',', '.').toDoubleOrNull()
|
||||
?: return null
|
||||
}
|
||||
1 -> inputUnit = match.value.trim()
|
||||
2 -> {
|
||||
if (!match.value.contains("-") && !match.value.contains(">")) {
|
||||
outputUnit = match.value.trim()
|
||||
}
|
||||
}
|
||||
3 -> {
|
||||
if (outputUnit == null) {
|
||||
outputUnit = match.value.trim()
|
||||
break
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
if (inputValue == null || inputUnit == null) {
|
||||
return null
|
||||
}
|
||||
val value = valueStr.toDoubleOrNull() ?: valueStr.replace(',', '.').toDoubleOrNull()
|
||||
?: return null
|
||||
|
||||
val converters = getAvailableConverters(includeCurrencies)
|
||||
|
||||
for (converter in converters) {
|
||||
if (!converter.isValidUnit(unitStr)) continue
|
||||
if (targetUnitStr != null && !converter.isValidUnit(targetUnitStr)) continue
|
||||
return converter.convert(context, unitStr, value, targetUnitStr)
|
||||
if (!converter.isValidUnit(inputUnit)) continue
|
||||
if (outputUnit != null && !converter.isValidUnit(outputUnit)) continue
|
||||
return converter.convert(context, inputUnit, inputValue, outputUnit)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.R
|
||||
|
||||
internal class VolumeConverter(context: Context) : SimpleFactorConverter() {
|
||||
override val dimension: Dimension = Dimension.Volume
|
||||
|
||||
override val standardUnits = listOf(
|
||||
// SI units
|
||||
MeasureUnitWithFactor(
|
||||
factor = 1.0,
|
||||
symbol = context.getString(R.string.unit_cubic_meter_symbol),
|
||||
nameResource = R.plurals.unit_cubic_meter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 1_000_000.0,
|
||||
symbol = context.getString(R.string.unit_cubic_centimeter_symbol),
|
||||
nameResource = R.plurals.unit_cubic_centimeter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 1_000_000_000.0,
|
||||
symbol = context.getString(R.string.unit_cubic_millimeter_symbol),
|
||||
nameResource = R.plurals.unit_cubic_millimeter
|
||||
),
|
||||
// Other metric units
|
||||
MeasureUnitWithFactor(
|
||||
factor = 1000.0,
|
||||
symbol = context.getString(R.string.unit_liter_symbol),
|
||||
nameResource = R.plurals.unit_liter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 1_000_000.0,
|
||||
symbol = context.getString(R.string.unit_milliliter_symbol),
|
||||
nameResource = R.plurals.unit_milliliter
|
||||
),
|
||||
|
||||
// Imperial geometric units
|
||||
MeasureUnitWithFactor(
|
||||
factor = 61023.74409473228,
|
||||
symbol = context.getString(R.string.unit_cubic_inch_symbol),
|
||||
nameResource = R.plurals.unit_cubic_inch
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 61023.74409473228 / 1728.0,
|
||||
symbol = context.getString(R.string.unit_cubic_foot_symbol),
|
||||
nameResource = R.plurals.unit_cubic_foot
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 61023.74409473228 / (1728.0 * 27.0),
|
||||
symbol = context.getString(R.string.unit_cubic_yard_symbol),
|
||||
nameResource = R.plurals.unit_cubic_yard
|
||||
),
|
||||
|
||||
// US fluid units
|
||||
MeasureUnitWithFactor(
|
||||
factor = 264.1720523581484,
|
||||
symbol = context.getString(R.string.unit_gallon_us_symbol),
|
||||
nameResource = R.plurals.unit_gallon_us
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 264.1720523581484 * 8,
|
||||
symbol = context.getString(R.string.unit_pint_us_symbol),
|
||||
nameResource = R.plurals.unit_pint_us
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 264.1720523581484 * 16,
|
||||
symbol = context.getString(R.string.unit_cup_symbol),
|
||||
nameResource = R.plurals.unit_cup
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 264.1720523581484 * 128,
|
||||
symbol = context.getString(R.string.unit_fluid_ounce_us_symbol),
|
||||
nameResource = R.plurals.unit_fluid_ounce_us
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 264.1720523581484 * 256,
|
||||
symbol = context.getString(R.string.unit_tablespoon_symbol),
|
||||
nameResource = R.plurals.unit_tablespoon
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 264.1720523581484 * 768,
|
||||
symbol = context.getString(R.string.unit_teaspoon_symbol),
|
||||
nameResource = R.plurals.unit_teaspoon
|
||||
),
|
||||
|
||||
// Imperial fluid units
|
||||
MeasureUnitWithFactor(
|
||||
factor = 219.9692482990878,
|
||||
symbol = context.getString(R.string.unit_gallon_imp_symbol),
|
||||
nameResource = R.plurals.unit_gallon_imp
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 219.969248299087 * 8,
|
||||
symbol = context.getString(R.string.unit_pint_imp_symbol),
|
||||
nameResource = R.plurals.unit_pint_imp
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
factor = 219.969248299087 * 128,
|
||||
symbol = context.getString(R.string.unit_fluid_ounce_imp_symbol),
|
||||
nameResource = R.plurals.unit_fluid_ounce_imp
|
||||
),
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user