Browse Source

add convert currency for any combination currency
add test

MrOzOn 4 years ago
parent
commit
0b5e7e3526

+ 4 - 2
app/src/main/java/com/mrozon/currencyconverter/di/ProvidersModule.kt

@@ -15,6 +15,8 @@ import javax.inject.Singleton
 class ProvidersModule {
 class ProvidersModule {
     @Singleton
     @Singleton
     @Provides
     @Provides
-    fun provideUpdateValutesRepository(currencyService: CurrencyService, currencyDao: CurrencyDao) =
-        UpdateValutesRepository(currencyService, currencyDao)
+    fun provideUpdateValutesRepository(
+        currencyService: CurrencyService,
+        currencyDao: CurrencyDao
+    ): IUpdateValutesRepository = UpdateValutesRepository(currencyService, currencyDao)
 }
 }

+ 27 - 0
app/src/main/java/com/mrozon/currencyconverter/di/UseCasesModule.kt

@@ -0,0 +1,27 @@
+package com.mrozon.currencyconverter.di
+
+import android.app.Application
+import com.mrozon.currencyconverter.data.db.CurrencyDao
+import com.mrozon.currencyconverter.data.network.CurrencyService
+import com.mrozon.currencyconverter.data.repository.IUpdateValutesRepository
+import com.mrozon.currencyconverter.data.repository.UpdateValutesRepository
+import com.mrozon.currencyconverter.domain.CalculateCurrencyUseCase
+import com.mrozon.currencyconverter.domain.ICalculateCurrencyUseCase
+import com.mrozon.currencyconverter.domain.dto.CurrencyMapper
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@InstallIn(SingletonComponent::class)
+@Module
+class UseCasesModule {
+    @Singleton
+    @Provides
+    fun provideCalculateCurrencyUseCase(
+        currencyDao: CurrencyDao,
+        dto: CurrencyMapper,
+        application: Application
+    ): ICalculateCurrencyUseCase = CalculateCurrencyUseCase(currencyDao, dto, application)
+}

+ 37 - 4
app/src/main/java/com/mrozon/currencyconverter/domain/CalculateCurrencyUseCase.kt

@@ -1,9 +1,13 @@
 package com.mrozon.currencyconverter.domain
 package com.mrozon.currencyconverter.domain
 
 
+import android.app.Application
+import android.content.res.Resources
+import com.mrozon.currencyconverter.R
 import com.mrozon.currencyconverter.data.db.CurrencyDao
 import com.mrozon.currencyconverter.data.db.CurrencyDao
 import com.mrozon.currencyconverter.domain.dto.CurrencyMapper
 import com.mrozon.currencyconverter.domain.dto.CurrencyMapper
 import com.mrozon.currencyconverter.domain.model.Currency
 import com.mrozon.currencyconverter.domain.model.Currency
 import com.mrozon.currencyconverter.domain.model.CurrentCurrencies
 import com.mrozon.currencyconverter.domain.model.CurrentCurrencies
+import dagger.hilt.android.qualifiers.ApplicationContext
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flow
@@ -11,15 +15,44 @@ import javax.inject.Inject
 
 
 class CalculateCurrencyUseCase @Inject constructor(
 class CalculateCurrencyUseCase @Inject constructor(
     private val currencyDao: CurrencyDao,
     private val currencyDao: CurrencyDao,
-    private val dto: CurrencyMapper
+    private val dto: CurrencyMapper,
+    private val application: Application
 ): ICalculateCurrencyUseCase {
 ): ICalculateCurrencyUseCase {
-    override fun loadCurrencies(): Flow<CurrentCurrencies> = flow{
+    override fun loadCurrencies(): Flow<List<Currency>> = flow{
+        val rubCharCode = application.getString(R.string.rub_char_code)
+        val rubName = application.getString(R.string.rub_name)
         currencyDao.getValutes().collect { listValuteDb ->
         currencyDao.getValutes().collect { listValuteDb ->
             val currencies = mutableListOf<Currency>()
             val currencies = mutableListOf<Currency>()
-            val rub = Currency("RUB", "Российский рубль", 1.0, true)
+            val rub = Currency(rubCharCode, rubName, 1.0)
             currencies.add(rub)
             currencies.add(rub)
             currencies.addAll(dto.map(listValuteDb))
             currencies.addAll(dto.map(listValuteDb))
-            emit(CurrentCurrencies(currencies, 1.0))
+            emit(currencies.toList())
         }
         }
     }
     }
+
+    override fun convertCurrency(
+        from: Currency,
+        to: Currency,
+        rub: Currency,
+        value: Double
+    ): Double {
+        if (to.charCode==rub.charCode) {
+            //  переводим в рубли любую валюту
+            return value * from.value
+        } else {
+            //  переводим в другую валюту
+            return when (from.charCode) {
+                to.charCode -> {
+                    value
+                }
+                rub.charCode -> {
+                    from.value * value
+                }
+                else -> {
+                    (from.value * value) / to.value
+                }
+            }
+        }
+    }
+
 }
 }

+ 6 - 1
app/src/main/java/com/mrozon/currencyconverter/domain/ICalculateCurrencyUseCase.kt

@@ -1,8 +1,13 @@
 package com.mrozon.currencyconverter.domain
 package com.mrozon.currencyconverter.domain
 
 
+import com.mrozon.currencyconverter.domain.model.Currency
 import com.mrozon.currencyconverter.domain.model.CurrentCurrencies
 import com.mrozon.currencyconverter.domain.model.CurrentCurrencies
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.Flow
 
 
 interface ICalculateCurrencyUseCase {
 interface ICalculateCurrencyUseCase {
-    fun loadCurrencies(): Flow<CurrentCurrencies>
+    fun loadCurrencies(): Flow<List<Currency>>
+    fun convertCurrency(from: Currency,
+                        to: Currency,
+                        rub: Currency,
+                        value: Double, ): Double
 }
 }

+ 1 - 2
app/src/main/java/com/mrozon/currencyconverter/domain/dto/CurrencyMapper.kt

@@ -12,7 +12,6 @@ class CurrencyMapper @Inject constructor(): BaseMapper<ValuteDb, Currency>() {
     override fun map(entity: ValuteDb) = Currency(
     override fun map(entity: ValuteDb) = Currency(
         charCode = entity.charCode,
         charCode = entity.charCode,
         name = entity.name,
         name = entity.name,
-        value = entity.value,
-        selected = false
+        value = entity.value
     )
     )
 }
 }

+ 1 - 2
app/src/main/java/com/mrozon/currencyconverter/domain/model/Currency.kt

@@ -3,6 +3,5 @@ package com.mrozon.currencyconverter.domain.model
 data class Currency(
 data class Currency(
     val charCode: String,
     val charCode: String,
     val name: String,
     val name: String,
-    val value: Double,
-    val selected: Boolean
+    val value: Double
 )
 )

+ 14 - 0
app/src/main/java/com/mrozon/currencyconverter/presentation/ConverterCurrencyFragment.kt

@@ -6,8 +6,11 @@ import android.view.View
 import android.view.ViewGroup
 import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.viewModels
 import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
 import com.mrozon.currencyconverter.databinding.FragmentConverterCurrencyBinding
 import com.mrozon.currencyconverter.databinding.FragmentConverterCurrencyBinding
 import dagger.hilt.android.AndroidEntryPoint
 import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.flow.collect
+import timber.log.Timber
 
 
 @AndroidEntryPoint
 @AndroidEntryPoint
 class ConverterCurrencyFragment: Fragment() {
 class ConverterCurrencyFragment: Fragment() {
@@ -22,4 +25,15 @@ class ConverterCurrencyFragment: Fragment() {
         return binding.root
         return binding.root
     }
     }
 
 
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        lifecycleScope.launchWhenStarted {
+            viewModel.state.collect { listVH ->
+                Timber.d(listVH.toString())
+            }
+        }
+
+    }
+
 }
 }

+ 65 - 1
app/src/main/java/com/mrozon/currencyconverter/presentation/ConverterCurrencyViewModel.kt

@@ -1,11 +1,75 @@
 package com.mrozon.currencyconverter.presentation
 package com.mrozon.currencyconverter.presentation
 
 
+import android.app.Application
+import android.content.res.Resources
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.mrozon.currencyconverter.CoroutineContextDispatchers
+import com.mrozon.currencyconverter.R
+import com.mrozon.currencyconverter.data.repository.IUpdateValutesRepository
+import com.mrozon.currencyconverter.domain.ICalculateCurrencyUseCase
+import com.mrozon.currencyconverter.domain.model.Currency
 import dagger.hilt.android.lifecycle.HiltViewModel
 import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.combine
 import javax.inject.Inject
 import javax.inject.Inject
 
 
 @HiltViewModel
 @HiltViewModel
 class ConverterCurrencyViewModel @Inject constructor(
 class ConverterCurrencyViewModel @Inject constructor(
+    private val useCase: ICalculateCurrencyUseCase,
+    private val dispatchers: CoroutineContextDispatchers,
+    application: Application
+): ViewModel() {
 
 
-): ViewModel()
+    private val rubCharCode = application.getString(R.string.rub_char_code)
+
+    private val flowCurrencies = useCase.loadCurrencies().stateIn(
+        viewModelScope,
+        started = SharingStarted.Lazily,
+        initialValue = emptyList())
+    private val flowSelected = MutableStateFlow(rubCharCode)
+    private val flowInputValue = MutableStateFlow(1.0)
+
+    val state: Flow<List<CurrencyVH>> = combine(
+        flowCurrencies,
+        flowSelected,
+        flowInputValue
+    ) { currencies, selected, inputValue ->
+        calculateCorrectExchange(currencies, selected, inputValue)
+    }.stateIn(viewModelScope, started = SharingStarted.Lazily, initialValue = emptyList())
+
+    private fun calculateCorrectExchange(
+        currencies: List<Currency>,
+        selected: String,
+        inputValue: Double
+    ): List<CurrencyVH> {
+        val selectedCurrency = currencies.firstOrNull { it.charCode == selected } ?: return emptyList()
+        val rubCurrency = currencies.firstOrNull { it.charCode == rubCharCode } ?: return emptyList()
+
+        val listCurrencyVH = mutableListOf<CurrencyVH>()
+        currencies.forEach { currency ->
+            val total = useCase.convertCurrency(currency, selectedCurrency, rubCurrency, inputValue)
+            val currencyVH = CurrencyVH(
+                charCode = currency.charCode,
+                name = currency.name,
+                total = total,
+                selected = currency.charCode == selected
+            )
+            listCurrencyVH.add(currencyVH)
+        }
+        return listCurrencyVH.toList()
+    }
+
+    data class CurrencyVH (
+        val charCode: String,
+        val name: String,
+        val total: Double,
+        val selected: Boolean,
+        )
+
+
+}
 
 

+ 2 - 0
app/src/main/res/values/strings.xml

@@ -12,4 +12,6 @@
     <string name="buttonComma">,</string>
     <string name="buttonComma">,</string>
     <string name="button0">0</string>
     <string name="button0">0</string>
     <string name="buttonDel">Del</string>
     <string name="buttonDel">Del</string>
+    <string name="rub_char_code">RUB</string>
+    <string name="rub_name">Российский рубль</string>
 </resources>
 </resources>

+ 57 - 13
app/src/test/java/com/mrozon/currencyconverter/domain/CalculateCurrencyUseCaseTest.kt

@@ -64,14 +64,12 @@ class CalculateCurrencyUseCaseTest {
         Mockito.`when`(dao.getValutes()).thenReturn(
         Mockito.`when`(dao.getValutes()).thenReturn(
             flowOf(listOf(valute1, valute2, valute3))
             flowOf(listOf(valute1, valute2, valute3))
         )
         )
-        val expected = CurrentCurrencies(
-            valutes= listOf(
-                Currency(charCode="RUB", name="Российский рубль", value=1.0, selected=true),
-                Currency(charCode="HKD", name="Гонконгских долларов", value=93.0223, selected=false),
-                Currency(charCode="HKS", name="Гонконгских долларов", value=93.0223, selected=false),
-                Currency(charCode="HKY", name="Гонконгских долларов", value=93.0223, selected=false)
-            ),
-            value=1.0)
+        val expected = listOf(
+                Currency(charCode="RUB", name="Российский рубль", value=1.0),
+                Currency(charCode="HKD", name="Гонконгских долларов", value=93.0223),
+                Currency(charCode="HKS", name="Гонконгских долларов", value=93.0223),
+                Currency(charCode="HKY", name="Гонконгских долларов", value=93.0223)
+            )
 
 
         val actual = useCase.loadCurrencies()
         val actual = useCase.loadCurrencies()
 
 
@@ -86,11 +84,9 @@ class CalculateCurrencyUseCaseTest {
         Mockito.`when`(dao.getValutes()).thenReturn(
         Mockito.`when`(dao.getValutes()).thenReturn(
             flowOf(listOf())
             flowOf(listOf())
         )
         )
-        val expected = CurrentCurrencies(
-            valutes= listOf(
-                Currency(charCode="RUB", name="Российский рубль", value=1.0, selected=true),
-            ),
-            value=1.0)
+        val expected = listOf(
+                Currency(charCode="RUB", name="Российский рубль", value=1.0),
+            )
 
 
         val actual = useCase.loadCurrencies()
         val actual = useCase.loadCurrencies()
 
 
@@ -100,4 +96,52 @@ class CalculateCurrencyUseCaseTest {
         )
         )
     }
     }
 
 
+    @Test
+    fun convertCurrency_change_rub()  {
+        val rub = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
+        val from = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
+        val to = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
+
+        val expected = 5.0
+
+        val actual = useCase.convertCurrency(from, to, rub, 5.0)
+        assertEquals(
+            expected,
+            actual,
+            0.0001
+        )
+    }
+
+    @Test
+    fun convertCurrency_change_eur2rub()  {
+        val rub = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
+        val from = Currency(charCode = "EUR", name = "Евро", value = 85.9943)
+        val to = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
+
+        val expected = 429.9715
+
+        val actual = useCase.convertCurrency(from, to, rub, 5.0)
+        assertEquals(
+            expected,
+            actual,
+            0.0001
+        )
+    }
+
+    @Test
+    fun convertCurrency_change_eur2usd()  {
+        val rub = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
+        val from = Currency(charCode = "EUR", name = "Евро", value = 85.9943)
+        val to = Currency(charCode = "USD", name = "Доллар США", value = 72.2216)
+
+        val expected = 1.1907
+
+        val actual = useCase.convertCurrency(from, to, rub, 1.0)
+        assertEquals(
+            expected,
+            actual,
+            0.0001
+        )
+    }
+
 }
 }