Reorganize and group modules
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
/
|
||||
</manifest>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package de.mm20.launcher2.search.data
|
||||
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.UnitValue
|
||||
|
||||
class CurrencyUnitConverter(dimension: Dimension, inputValue: UnitValue, values: List<UnitValue>, val updateTimestamp: Long)
|
||||
: UnitConverter(dimension, inputValue, values)
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.mm20.launcher2.search.data
|
||||
|
||||
import de.mm20.launcher2.search.Searchable
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.UnitValue
|
||||
|
||||
open class UnitConverter(
|
||||
val dimension: Dimension,
|
||||
val inputValue: UnitValue,
|
||||
val values: List<UnitValue>
|
||||
): Searchable
|
||||
@@ -0,0 +1,27 @@
|
||||
package de.mm20.launcher2.unitconverter
|
||||
|
||||
import android.content.Context
|
||||
import java.text.DecimalFormat
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
internal object ConverterUtils {
|
||||
|
||||
fun formatName(context: Context, unit: MeasureUnit, value: Double): String {
|
||||
val resId = unit.nameResource
|
||||
val text = context.resources.getQuantityString(resId, value.roundToInt())
|
||||
return text
|
||||
}
|
||||
|
||||
fun formatValue(context: Context, unit: MeasureUnit, value: Double): String {
|
||||
if (abs(value) > 1e5 || abs(value) < 1e-3) {
|
||||
return DecimalFormat("#.###E0").apply {
|
||||
}.format(value)
|
||||
}
|
||||
|
||||
return DecimalFormat("#.###").apply {
|
||||
}.format(value)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.mm20.launcher2.unitconverter
|
||||
|
||||
enum class Dimension {
|
||||
Length,
|
||||
Mass,
|
||||
Velocity,
|
||||
Volume,
|
||||
Area,
|
||||
Currency,
|
||||
Data,
|
||||
Bitrate,
|
||||
Pressure,
|
||||
Energy,
|
||||
Frequency,
|
||||
Temperature,
|
||||
Time
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package de.mm20.launcher2.unitconverter
|
||||
|
||||
interface MeasureUnit {
|
||||
val symbol: String
|
||||
val nameResource: Int
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.mm20.launcher2.unitconverter
|
||||
|
||||
import de.mm20.launcher2.currencies.CurrencyRepository
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.dsl.module
|
||||
|
||||
val unitConverterModule = module {
|
||||
single { CurrencyRepository(androidContext()) }
|
||||
single<UnitConverterRepository> { UnitConverterRepositoryImpl(androidContext(), get()) }
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package de.mm20.launcher2.unitconverter
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.currencies.CurrencyRepository
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.data.UnitConverter
|
||||
import de.mm20.launcher2.unitconverter.converters.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
interface UnitConverterRepository {
|
||||
fun search(query: String, includeCurrencies: Boolean): Flow<UnitConverter?>
|
||||
}
|
||||
|
||||
internal class UnitConverterRepositoryImpl(
|
||||
private val context: Context,
|
||||
private val currencyRepository: CurrencyRepository,
|
||||
) : UnitConverterRepository, KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
dataStore.data.map { it.unitConverterSearch }.distinctUntilChanged().collectLatest {
|
||||
if (it.enabled && it.currencies) currencyRepository.enableCurrencyUpdateWorker()
|
||||
else currencyRepository.disableCurrencyUpdateWorker()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String, includeCurrencies: Boolean): Flow<UnitConverter?> = channelFlow {
|
||||
if (query.isBlank()) {
|
||||
send(null)
|
||||
return@channelFlow
|
||||
}
|
||||
send(queryUnitConverter(query, includeCurrencies))
|
||||
}
|
||||
|
||||
private suspend fun queryUnitConverter(
|
||||
query: String,
|
||||
includeCurrencies: Boolean
|
||||
): UnitConverter? {
|
||||
if (!query.matches(Regex("[0-9,.:]+ [^\\s]+")) && !query.matches(Regex("[0-9,.:]+ [^\\s]+ >> [^\\s]+"))) return null
|
||||
val valueStr: String
|
||||
val unitStr: String
|
||||
val targetUnitStr: String?
|
||||
|
||||
query.split(" ").also {
|
||||
valueStr = it.get(0)
|
||||
unitStr = it.get(1)
|
||||
targetUnitStr = it.getOrNull(3)
|
||||
}
|
||||
val value = valueStr.toDoubleOrNull() ?: valueStr.replace(',', '.').toDoubleOrNull()
|
||||
?: return null
|
||||
|
||||
val converters = mutableListOf(
|
||||
MassConverter(context),
|
||||
LengthConverter(context),
|
||||
DataConverter(context),
|
||||
TimeConverter(context),
|
||||
VelocityConverter(context),
|
||||
AreaConverter(context),
|
||||
TemperatureConverter(context)
|
||||
)
|
||||
|
||||
if (includeCurrencies) converters.add(CurrencyConverter(currencyRepository))
|
||||
|
||||
for (converter in converters) {
|
||||
if (!converter.isValidUnit(unitStr)) continue
|
||||
if (targetUnitStr != null && !converter.isValidUnit(targetUnitStr)) continue
|
||||
return converter.convert(context, unitStr, value, targetUnitStr)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.mm20.launcher2.unitconverter
|
||||
|
||||
data class UnitValue(
|
||||
val value: Double,
|
||||
val symbol: String,
|
||||
val formattedName: String,
|
||||
val formattedValue: String
|
||||
)
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.R
|
||||
|
||||
class AreaConverter(context: Context) : SimpleFactorConverter() {
|
||||
override val dimension = Dimension.Area
|
||||
|
||||
override val standardUnits = listOf(
|
||||
MeasureUnitWithFactor(
|
||||
0.000001,
|
||||
context.getString(R.string.unit_sqkilometer_symbol),
|
||||
R.plurals.unit_sqkilometer
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
0.0001,
|
||||
context.getString(R.string.unit_hectare_symbol),
|
||||
R.plurals.unit_hectare
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0,
|
||||
context.getString(R.string.unit_sqmeter_symbol),
|
||||
R.plurals.unit_sqmeter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
10000.0,
|
||||
context.getString(R.string.unit_sqcentimeter_symbol),
|
||||
R.plurals.unit_sqcentimeter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1000000.0,
|
||||
context.getString(R.string.unit_sqmillimeter_symbol),
|
||||
R.plurals.unit_sqmillimeter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100 * 100 / (2.54 * 2.54),
|
||||
context.getString(R.string.unit_sqinch_symbol),
|
||||
R.plurals.unit_sqinch
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100 * 100 / (2.54 * 2.54 * 144),
|
||||
context.getString(R.string.unit_sqfoot_symbol),
|
||||
R.plurals.unit_sqfoot
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100 * 100 / (2.54 * 2.54 * 1296),
|
||||
context.getString(R.string.unit_sqyard_symbol),
|
||||
R.plurals.unit_sqyard
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100 * 100 / (2.54 * 2.54 * 144 * 43560),
|
||||
context.getString(R.string.unit_acre_symbol),
|
||||
R.plurals.unit_acre
|
||||
)
|
||||
)
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.search.data.UnitConverter
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
|
||||
interface Converter {
|
||||
val dimension: Dimension
|
||||
|
||||
suspend fun isValidUnit(symbol: String): Boolean
|
||||
|
||||
suspend fun convert(
|
||||
context: Context,
|
||||
fromUnit: String,
|
||||
value: Double,
|
||||
toUnit: String?
|
||||
): UnitConverter
|
||||
}
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import android.icu.text.PluralRules
|
||||
import android.icu.util.Currency
|
||||
import de.mm20.launcher2.currencies.CurrencyRepository
|
||||
import de.mm20.launcher2.search.data.CurrencyUnitConverter
|
||||
import de.mm20.launcher2.search.data.UnitConverter
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.UnitValue
|
||||
import java.text.DecimalFormat
|
||||
import java.util.Locale
|
||||
import java.util.Currency as JCurrency
|
||||
import kotlin.math.abs
|
||||
|
||||
class CurrencyConverter(
|
||||
private val repository: CurrencyRepository,
|
||||
) : Converter {
|
||||
|
||||
override val dimension: Dimension = Dimension.Currency
|
||||
|
||||
|
||||
private val topCurrencies = arrayOf("USD", "EUR", "JPY", "GBP", "AUD")
|
||||
|
||||
override suspend fun isValidUnit(symbol: String): Boolean {
|
||||
return repository.isValidCurrency(symbol)
|
||||
}
|
||||
|
||||
|
||||
private fun formatName(symbol: String, value: Double): String {
|
||||
val text = StringBuilder()
|
||||
val currency = Currency.getInstance(symbol) ?: return formatNameFallback(symbol)
|
||||
val pluralCount = PluralRules.forLocale(Locale.getDefault()).select(value)
|
||||
text.append(currency.getName(Locale.getDefault(), Currency.PLURAL_LONG_NAME, pluralCount, booleanArrayOf(false)))
|
||||
|
||||
return text.toString()
|
||||
}
|
||||
|
||||
private fun formatNameFallback(symbol: String): String {
|
||||
return symbol
|
||||
}
|
||||
|
||||
private fun formatValue(symbol: String, value: Double): String {
|
||||
if (abs(value) > 1e10) {
|
||||
return DecimalFormat("#.###E0").apply {
|
||||
}.format(value)
|
||||
}
|
||||
val currency = JCurrency.getInstance(symbol)
|
||||
return if (currency != null) {
|
||||
val format = StringBuilder("#,##0")
|
||||
val digits = currency.defaultFractionDigits
|
||||
if (digits > 0) format.append(".")
|
||||
for (i in 0 until digits) format.append("0")
|
||||
DecimalFormat(format.toString()).format(value)
|
||||
} else {
|
||||
DecimalFormat("#,##0.00").format(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun convert(context: Context, fromUnit: String, value: Double, toUnit: String?): UnitConverter {
|
||||
val values = repository.convertCurrency(fromUnit, value, toUnit).map {
|
||||
UnitValue(it.second, it.first, formatName(it.first, it.second), formatValue(it.first, it.second))
|
||||
}.toMutableList()
|
||||
|
||||
val ownCurrencySymbol = JCurrency.getInstance(Locale.getDefault()).currencyCode ?: "USD"
|
||||
val index = values.indexOfFirst { it.symbol == ownCurrencySymbol }
|
||||
|
||||
val ownCurrency = if (index != -1) {
|
||||
values.removeAt(index)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
values.sortBy {
|
||||
val i = topCurrencies.indexOf(it.symbol)
|
||||
if (i != -1) i.toString()
|
||||
else it.formattedName
|
||||
}
|
||||
|
||||
if (ownCurrency != null) {
|
||||
values.add(0, ownCurrency)
|
||||
}
|
||||
|
||||
val inputValue = UnitValue(value, fromUnit, formatName(fromUnit, value), formatValue(fromUnit, value))
|
||||
val lastUpdate = repository.getLastUpdate(fromUnit)
|
||||
return CurrencyUnitConverter(dimension, inputValue, values, lastUpdate)
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.R
|
||||
|
||||
class DataConverter(context: Context) : SimpleFactorConverter() {
|
||||
override val dimension = Dimension.Data
|
||||
|
||||
override val standardUnits = listOf(
|
||||
MeasureUnitWithFactor(
|
||||
1.0,
|
||||
context.getString(R.string.unit_byte_symbol),
|
||||
R.plurals.unit_byte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
0.001,
|
||||
context.getString(R.string.unit_kilobyte_symbol),
|
||||
R.plurals.unit_kilobyte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
0.000001,
|
||||
context.getString(R.string.unit_megabyte_symbol),
|
||||
R.plurals.unit_megabyte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
0.000000001,
|
||||
context.getString(R.string.unit_gigabyte_symbol),
|
||||
R.plurals.unit_gigabyte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
0.000000000001,
|
||||
context.getString(R.string.unit_terabyte_symbol),
|
||||
R.plurals.unit_terabyte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0 / 1024,
|
||||
context.getString(R.string.unit_kibibyte_symbol),
|
||||
R.plurals.unit_kibibyte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0 / (1024 * 1024),
|
||||
context.getString(R.string.unit_mebibyte_symbol),
|
||||
R.plurals.unit_mebibyte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0 / (1024 * 1024 * 1024),
|
||||
context.getString(R.string.unit_gibibyte_symbol),
|
||||
R.plurals.unit_gibibyte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0 / (1024.0 * 1024 * 1024 * 1024),
|
||||
context.getString(R.string.unit_tebibyte_symbol),
|
||||
R.plurals.unit_tebibyte
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
8.0,
|
||||
context.getString(R.string.unit_bit_symbol),
|
||||
R.plurals.unit_bit
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
8.0 / 1000,
|
||||
context.getString(R.string.unit_kilobit_symbol),
|
||||
R.plurals.unit_kilobit
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
8.0 / 1000000,
|
||||
context.getString(R.string.unit_megabit_symbol),
|
||||
R.plurals.unit_megabit
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
8.0 / 1000000000,
|
||||
context.getString(R.string.unit_gigabit_symbol),
|
||||
R.plurals.unit_gigabit
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
8.0 / 1000000000000,
|
||||
context.getString(R.string.unit_terabit_symbol),
|
||||
R.plurals.unit_terabit
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.R
|
||||
|
||||
class LengthConverter(context: Context) : SimpleFactorConverter() {
|
||||
override val dimension = Dimension.Length
|
||||
|
||||
override val standardUnits = listOf(
|
||||
MeasureUnitWithFactor(
|
||||
1.0,
|
||||
context.getString(R.string.unit_meter_symbol),
|
||||
R.plurals.unit_meter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
0.001,
|
||||
context.getString(R.string.unit_kilometer_symbol),
|
||||
R.plurals.unit_kilometer
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100.0,
|
||||
context.getString(R.string.unit_centimeter_symbol),
|
||||
R.plurals.unit_centimeter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1000.0,
|
||||
context.getString(R.string.unit_millimeter_symbol),
|
||||
R.plurals.unit_millimeter
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100 / 2.54,
|
||||
context.getString(R.string.unit_inch_symbol),
|
||||
R.plurals.unit_inch
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100 / (2.54 * 12),
|
||||
context.getString(R.string.unit_foot_symbol),
|
||||
R.plurals.unit_foot
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100 / (2.54 * 12 * 3),
|
||||
context.getString(R.string.unit_yard_symbol),
|
||||
R.plurals.unit_yard
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
100 / (2.54 * 12 * 3 * 1760),
|
||||
context.getString(R.string.unit_mile_symbol),
|
||||
R.plurals.unit_mile
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1 / 1852.0,
|
||||
context.getString(R.string.unit_nautic_mile_symbol),
|
||||
R.plurals.unit_nautic_mile
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.R
|
||||
|
||||
class MassConverter(context: Context): SimpleFactorConverter() {
|
||||
override val dimension = Dimension.Mass
|
||||
|
||||
override val standardUnits = listOf(
|
||||
MeasureUnitWithFactor(
|
||||
1.0,
|
||||
context.getString(R.string.unit_kilogram_symbol),
|
||||
R.plurals.unit_kilogram
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1000.0,
|
||||
context.getString(R.string.unit_gram_symbol),
|
||||
R.plurals.unit_gram
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
0.001,
|
||||
context.getString(R.string.unit_metric_ton_symbol),
|
||||
R.plurals.unit_metric_ton
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1000.0 / (453.59237 * 2240.0),
|
||||
context.getString(R.string.unit_long_ton_symbol),
|
||||
R.plurals.unit_long_ton
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1000.0 / (453.59237 * 14.0),
|
||||
context.getString(R.string.unit_stone_symbol),
|
||||
R.plurals.unit_stone
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1000.0 / 453.59237,
|
||||
context.getString(R.string.unit_pound_symbol),
|
||||
R.plurals.unit_pound
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
16.0 * 1000.0 / 453.59237,
|
||||
context.getString(R.string.unit_ounce_symbol),
|
||||
R.plurals.unit_ounce
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1000.0 / (453.59237 * 2000.0),
|
||||
context.getString(R.string.unit_short_ton_symbol),
|
||||
R.plurals.unit_short_ton
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.search.data.UnitConverter
|
||||
import de.mm20.launcher2.unitconverter.ConverterUtils
|
||||
import de.mm20.launcher2.unitconverter.MeasureUnit
|
||||
import de.mm20.launcher2.unitconverter.UnitValue
|
||||
|
||||
/**
|
||||
* A converter for units that can converted into each other by simply multiplicating with a constant factor
|
||||
*/
|
||||
abstract class SimpleFactorConverter: Converter {
|
||||
open val standardUnits: List<MeasureUnitWithFactor> = emptyList()
|
||||
|
||||
/**
|
||||
* Returns true if a symbol is a valid unit of this converter
|
||||
*/
|
||||
override suspend fun isValidUnit(symbol: String): Boolean {
|
||||
return standardUnits.any { it.symbol == symbol }
|
||||
}
|
||||
|
||||
override suspend fun convert(context: Context, fromUnit: String, value: Double, toUnit: String?): UnitConverter {
|
||||
val results = mutableListOf<UnitValue>()
|
||||
val unit = standardUnits.first { it.symbol == fromUnit }
|
||||
if (toUnit == null) {
|
||||
for (targetUnit in standardUnits) {
|
||||
if (targetUnit.symbol == unit.symbol) continue
|
||||
val v = value * targetUnit.factor / unit.factor
|
||||
results += UnitValue(v, targetUnit.symbol, ConverterUtils.formatName(context, targetUnit, v), ConverterUtils.formatValue(context, unit, v))
|
||||
}
|
||||
} else {
|
||||
val targetUnit = standardUnits.first { it.symbol == toUnit }
|
||||
val v = value * targetUnit.factor / unit.factor
|
||||
results += UnitValue(v, targetUnit.symbol, ConverterUtils.formatName(context, targetUnit, v), ConverterUtils.formatValue(context, unit, v))
|
||||
}
|
||||
val inputValue = UnitValue(value, fromUnit, ConverterUtils.formatName(context, unit, value), ConverterUtils.formatValue(context, unit, value))
|
||||
return UnitConverter(dimension, inputValue, results)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class MeasureUnitWithFactor(
|
||||
val factor: Double,
|
||||
override val symbol: String,
|
||||
override val nameResource: Int
|
||||
): MeasureUnit
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.search.data.UnitConverter
|
||||
import de.mm20.launcher2.unitconverter.*
|
||||
|
||||
class TemperatureConverter(context: Context) : Converter {
|
||||
override val dimension = Dimension.Temperature
|
||||
|
||||
private val units = listOf(
|
||||
TemperatureMeasureUnit(
|
||||
context.getString(R.string.unit_degree_celsius_symbol),
|
||||
R.plurals.unit_degree_celsius,
|
||||
TemperatureUnit.DegreeCelsius
|
||||
),
|
||||
TemperatureMeasureUnit(
|
||||
context.getString(R.string.unit_degree_fahrenheit_symbol),
|
||||
R.plurals.unit_degree_fahrenheit,
|
||||
TemperatureUnit.DegreeFahrenheit
|
||||
),
|
||||
TemperatureMeasureUnit(
|
||||
context.getString(R.string.unit_kelvin_symbol),
|
||||
R.plurals.unit_kelvin,
|
||||
TemperatureUnit.Kelvin
|
||||
),
|
||||
)
|
||||
|
||||
override suspend fun isValidUnit(symbol: String): Boolean {
|
||||
return units.any { it.symbol == symbol }
|
||||
}
|
||||
|
||||
override suspend fun convert(
|
||||
context: Context,
|
||||
fromUnit: String,
|
||||
value: Double,
|
||||
toUnit: String?
|
||||
): UnitConverter {
|
||||
val from = units.first { it.symbol == fromUnit }
|
||||
val to = toUnit?.let { unit -> units.first { it.symbol == unit } }
|
||||
|
||||
val values = mutableListOf<UnitValue>()
|
||||
|
||||
if (to != null) {
|
||||
val toValue = convertTemperature(value, from.unit, to.unit)
|
||||
|
||||
values += UnitValue(
|
||||
value = value,
|
||||
symbol = toUnit,
|
||||
formattedName = ConverterUtils.formatName(context, to, toValue),
|
||||
formattedValue = ConverterUtils.formatValue(context, to, toValue),
|
||||
)
|
||||
} else {
|
||||
for (to in units) {
|
||||
if (to.symbol == from.symbol) continue
|
||||
val v = convertTemperature(value, from.unit, to.unit)
|
||||
values += UnitValue(
|
||||
v,
|
||||
to.symbol,
|
||||
ConverterUtils.formatName(context, to, v),
|
||||
ConverterUtils.formatValue(context, to, v)
|
||||
)
|
||||
}
|
||||
}
|
||||
return UnitConverter(
|
||||
dimension = Dimension.Temperature,
|
||||
inputValue = UnitValue(
|
||||
value = value,
|
||||
symbol = fromUnit,
|
||||
formattedName = ConverterUtils.formatName(context, from, value),
|
||||
formattedValue = ConverterUtils.formatValue(context, from, value),
|
||||
),
|
||||
values = values
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertTemperature(
|
||||
value: Double,
|
||||
from: TemperatureUnit,
|
||||
to: TemperatureUnit
|
||||
): Double {
|
||||
if (from == to) return value
|
||||
if (from == TemperatureUnit.Kelvin && to == TemperatureUnit.DegreeCelsius) {
|
||||
return value - 273.15
|
||||
}
|
||||
if (from == TemperatureUnit.DegreeCelsius && to == TemperatureUnit.Kelvin) {
|
||||
return value + 273.15
|
||||
}
|
||||
if (from === TemperatureUnit.DegreeCelsius && to == TemperatureUnit.DegreeFahrenheit) {
|
||||
return value * (9.0 / 5.0) + 32.0
|
||||
}
|
||||
if (from === TemperatureUnit.DegreeFahrenheit && to == TemperatureUnit.DegreeCelsius) {
|
||||
return (value - 32.0) * (5.0 / 9.0)
|
||||
}
|
||||
|
||||
if (from === TemperatureUnit.Kelvin && to == TemperatureUnit.DegreeFahrenheit) {
|
||||
return (value - 273.15) * (9.0 / 5.0) + 32.0
|
||||
}
|
||||
if (from === TemperatureUnit.DegreeFahrenheit && to == TemperatureUnit.Kelvin) {
|
||||
return (value - 32.0) * (5.0 / 9.0) + 273.15
|
||||
}
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
||||
private data class TemperatureMeasureUnit(
|
||||
override val symbol: String,
|
||||
override val nameResource: Int,
|
||||
val unit: TemperatureUnit
|
||||
) :
|
||||
MeasureUnit
|
||||
|
||||
private enum class TemperatureUnit {
|
||||
DegreeCelsius,
|
||||
DegreeFahrenheit,
|
||||
Kelvin,
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.R
|
||||
|
||||
class TimeConverter(context: Context) : SimpleFactorConverter() {
|
||||
override val dimension = Dimension.Time
|
||||
|
||||
override val standardUnits = listOf(
|
||||
MeasureUnitWithFactor(
|
||||
1.0,
|
||||
context.getString(R.string.unit_second_symbol),
|
||||
R.plurals.unit_second
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1000.0,
|
||||
context.getString(R.string.unit_millisecond_symbol),
|
||||
R.plurals.unit_millisecond
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0 / 60,
|
||||
context.getString(R.string.unit_minute_symbol),
|
||||
R.plurals.unit_minute
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0 / (60 * 60),
|
||||
context.getString(R.string.unit_hour_symbol),
|
||||
R.plurals.unit_hour
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0 / (60 * 60 * 24),
|
||||
context.getString(R.string.unit_day_symbol),
|
||||
R.plurals.unit_day
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
1.0 / (60 * 60 * 24 * 365),
|
||||
context.getString(R.string.unit_year_symbol),
|
||||
R.plurals.unit_year
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package de.mm20.launcher2.unitconverter.converters
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.unitconverter.Dimension
|
||||
import de.mm20.launcher2.unitconverter.R
|
||||
|
||||
class VelocityConverter(context: Context) : SimpleFactorConverter() {
|
||||
override val dimension = Dimension.Velocity
|
||||
|
||||
override val standardUnits = listOf(
|
||||
MeasureUnitWithFactor(
|
||||
1.0,
|
||||
context.getString(R.string.unit_meter_per_second_symbol),
|
||||
R.plurals.unit_meter_per_second
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
3.6,
|
||||
context.getString(R.string.unit_kilometer_per_hour_symbol),
|
||||
R.plurals.unit_kilometer_per_hour
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
3600.0 / 1609.344,
|
||||
context.getString(R.string.unit_mile_per_hour_symbol),
|
||||
R.plurals.unit_mile_per_hour
|
||||
),
|
||||
MeasureUnitWithFactor(
|
||||
3600.0 / 1852.0,
|
||||
context.getString(R.string.unit_knot_symbol),
|
||||
R.plurals.unit_knot
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user