Bladeren bron

add main logic

MrOzOn 4 jaren geleden
bovenliggende
commit
a4676236fe

+ 1 - 0
app/build.gradle

@@ -48,6 +48,7 @@ dependencies {
     implementation 'androidx.appcompat:appcompat:1.3.0'
     implementation 'com.google.android.material:material:1.3.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+    implementation "androidx.recyclerview:recyclerview:1.2.1"
     //Timber
     implementation 'com.jakewharton.timber:timber:4.7.1'
     //Dagger Hilt

+ 12 - 20
app/src/main/java/com/mrozon/currencyconverter/domain/CalculateCurrencyUseCase.kt

@@ -33,26 +33,18 @@ class CalculateCurrencyUseCase @Inject constructor(
     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
-                }
-            }
-        }
-    }
+    ) =
+//        return if (to.charCode==rub.charCode) {
+//            //  переводим в рубли любую валюту
+//            value * from.value
+//        } else {
+//            //  переводим в другую валюту
+//            (from.value * value) / to.value
+//        }
+
+            from.value * value / to.value
+
+
 
 }

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

@@ -8,6 +8,5 @@ interface ICalculateCurrencyUseCase {
     fun loadCurrencies(): Flow<List<Currency>>
     fun convertCurrency(from: Currency,
                         to: Currency,
-                        rub: Currency,
                         value: Double, ): Double
 }

+ 19 - 0
app/src/main/java/com/mrozon/currencyconverter/presentation/BindingUtils.kt

@@ -0,0 +1,19 @@
+package com.mrozon.currencyconverter.presentation
+
+import android.graphics.Color
+import android.widget.TextView
+import androidx.databinding.BindingAdapter
+
+@BindingAdapter("show_total")
+fun TextView.showTotal(currencyUI: CurrencyUI) {
+//    text = currencyUI.total.format(4)
+    if(currencyUI.selected) {
+        setTextColor(Color.MAGENTA)
+        text = currencyUI.total.format(4)
+    } else {
+        setTextColor(Color.BLACK)
+        text = currencyUI.total.format(4)
+    }
+}
+
+fun Double.format(digits: Int) = "%.${digits}f".format(this).trimEnd('0')//.trim('.')

+ 26 - 4
app/src/main/java/com/mrozon/currencyconverter/presentation/ConverterCurrencyFragment.kt

@@ -4,9 +4,12 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.Button
+import android.widget.Toast
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.viewModels
 import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
 import com.mrozon.currencyconverter.databinding.FragmentConverterCurrencyBinding
 import dagger.hilt.android.AndroidEntryPoint
 import kotlinx.coroutines.flow.collect
@@ -16,24 +19,43 @@ import timber.log.Timber
 class ConverterCurrencyFragment: Fragment() {
     private val viewModel: ConverterCurrencyViewModel by viewModels()
 
+    private var binding: FragmentConverterCurrencyBinding? = null
+    private val currencyAdapter by lazy {
+        CurrencyAdapter { currencyUI ->
+            viewModel.selectCurrency(currencyUI.charCode)
+        }
+    }
+
     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View {
-        val binding = FragmentConverterCurrencyBinding.inflate(inflater, container, false)
-        return binding.root
+        binding = FragmentConverterCurrencyBinding.inflate(inflater, container, false)
+        binding?.rvCurrencies?.apply {
+            layoutManager = LinearLayoutManager(requireContext())
+            adapter = currencyAdapter
+        }
+        binding?.setClickListener { view ->
+            val button = view as Button
+//            Toast.makeText(requireContext(),button.text,Toast.LENGTH_SHORT).show()
+            viewModel.input(button.text.toString())
+        }
+        return binding?.root!!
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
         lifecycleScope.launchWhenStarted {
-            viewModel.state.collect { listVH ->
-                Timber.d(listVH.toString())
+            viewModel.state.collect { list ->
+                Timber.d(list.toString())
+                currencyAdapter.submitList(list)
             }
         }
 
     }
 
+
+
 }

+ 31 - 13
app/src/main/java/com/mrozon/currencyconverter/presentation/ConverterCurrencyViewModel.kt

@@ -19,6 +19,8 @@ class ConverterCurrencyViewModel @Inject constructor(
 ): ViewModel() {
 
     private val rubCharCode = application.getString(R.string.rub_char_code)
+    private val delChar = application.getString(R.string.buttonDel)
+    private val comma = application.getString(R.string.buttonComma)
 
     private val flowCurrencies = useCase.loadCurrencies().stateIn(
         viewModelScope,
@@ -27,7 +29,7 @@ class ConverterCurrencyViewModel @Inject constructor(
     private val flowSelected = MutableStateFlow(rubCharCode)
     private val flowInputValue = MutableStateFlow(1.0)
 
-    val state: Flow<List<CurrencyVH>> = combine(
+    val state: Flow<List<CurrencyUI>> = combine(
         flowCurrencies,
         flowSelected,
         flowInputValue
@@ -39,14 +41,13 @@ class ConverterCurrencyViewModel @Inject constructor(
         currencies: List<Currency>,
         selected: String,
         inputValue: Double
-    ): List<CurrencyVH> {
+    ): List<CurrencyUI> {
         val selectedCurrency = currencies.firstOrNull { it.charCode == selected } ?: return emptyList()
-        val rubCurrency = currencies.firstOrNull { it.charCode == rubCharCode } ?: return emptyList()
 
-        val listCurrencyVH = mutableListOf<CurrencyVH>()
+        val listCurrencyVH = mutableListOf<CurrencyUI>()
         currencies.forEach { currency ->
-            val total = useCase.convertCurrency(currency, selectedCurrency, rubCurrency, inputValue)
-            val currencyVH = CurrencyVH(
+            val total = useCase.convertCurrency(selectedCurrency, currency, inputValue)
+            val currencyVH = CurrencyUI(
                 charCode = currency.charCode,
                 name = currency.name,
                 total = total,
@@ -57,13 +58,30 @@ class ConverterCurrencyViewModel @Inject constructor(
         return listCurrencyVH.toList()
     }
 
-    data class CurrencyVH (
-        val charCode: String,
-        val name: String,
-        val total: Double,
-        val selected: Boolean,
-        )
-
+    fun selectCurrency(charCode: String) {
+        flowSelected.value = charCode
+        flowInputValue.value = 1.0
+    }
 
+    fun input(text: String) {
+        when (text) {
+            delChar -> {
+                val v: String = flowInputValue.value.format(4)
+                if(v.length==1) {
+                    flowInputValue.value = 0.0
+                } else {
+                    flowInputValue.value = v.dropLast(1).toDouble()
+                }
+            }
+            comma -> {
+                val v: Double = flowInputValue.value
+                flowInputValue.value = (v.format(4)+text).toDouble()
+            }
+            else -> {
+                val v: Double = flowInputValue.value
+                flowInputValue.value = (v.format(4)+text).toDouble()
+            }
+        }
+    }
 }
 

+ 58 - 0
app/src/main/java/com/mrozon/currencyconverter/presentation/CurrencyAdapter.kt

@@ -0,0 +1,58 @@
+package com.mrozon.currencyconverter.presentation
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.mrozon.currencyconverter.databinding.IemCurrencyBinding
+import timber.log.Timber
+
+class CurrencyAdapter(
+    private var click: ((CurrencyUI) -> Unit)
+): ListAdapter<CurrencyUI, RecyclerView.ViewHolder>(CurrencyDiffCallback()) {
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
+        CurrencyViewHolder(
+            IemCurrencyBinding.inflate(
+                LayoutInflater.from(parent.context),
+                parent,
+                false
+            ),
+            click
+        )
+
+    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+        val currency = getItem(position)
+        (holder as CurrencyViewHolder).bind(currency)
+    }
+
+    class CurrencyViewHolder(
+        private val binding: IemCurrencyBinding,
+        private var click: ((CurrencyUI) -> Unit)
+    ):  RecyclerView.ViewHolder(binding.root) {
+
+        fun bind(item: CurrencyUI) {
+            binding.apply {
+                currencyUI = item
+                executePendingBindings()
+            }
+            binding.setClickListener {
+                Timber.d("Click!")
+                click(item)
+            }
+        }
+    }
+
+}
+
+private class CurrencyDiffCallback : DiffUtil.ItemCallback<CurrencyUI>() {
+
+    override fun areItemsTheSame(oldItem: CurrencyUI, newItem: CurrencyUI): Boolean {
+        return oldItem.charCode == newItem.charCode
+    }
+
+    override fun areContentsTheSame(oldItem: CurrencyUI, newItem: CurrencyUI): Boolean {
+        return oldItem == newItem
+    }
+}

+ 8 - 0
app/src/main/java/com/mrozon/currencyconverter/presentation/CurrencyUI.kt

@@ -0,0 +1,8 @@
+package com.mrozon.currencyconverter.presentation
+
+data class CurrencyUI (
+    val charCode: String,
+    val name: String,
+    val total: Double,
+    val selected: Boolean,
+)

+ 15 - 1
app/src/main/res/layout/fragment_converter_currency.xml

@@ -4,7 +4,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android">
 
     <data>
-
+        <variable
+            name="clickListener"
+            type="android.view.View.OnClickListener"/>
     </data>
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -43,6 +45,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button9"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/button6"
@@ -56,6 +59,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button8"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/button5"
@@ -69,6 +73,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button7"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/button4"
@@ -82,6 +87,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button6"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/button3"
@@ -95,6 +101,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button5"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/button2"
@@ -108,6 +115,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button4"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/button1"
@@ -121,6 +129,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button3"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/buttonComma"
@@ -134,6 +143,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button2"
+            android:onClick="@{clickListener}"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/button0"
             app:layout_constraintEnd_toStartOf="@+id/button3"
@@ -147,6 +157,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/button1"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toTopOf="@+id/buttonDelete"
@@ -161,6 +172,7 @@
             android:layout_height="wrap_content"
             android:layout_marginBottom="8dp"
             android:text="@string/buttonComma"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toBottomOf="parent"
@@ -175,6 +187,7 @@
             android:layout_height="wrap_content"
             android:layout_marginBottom="8dp"
             android:text="@string/button0"
+            android:onClick="@{clickListener}"
             android:textAppearance="@style/TextAppearance.AppCompat.Large"
             android:textColor="@color/design_default_color_primary"
             app:layout_constraintBottom_toBottomOf="parent"
@@ -189,6 +202,7 @@
             android:layout_height="wrap_content"
             android:layout_marginBottom="8dp"
             android:text="@string/buttonDel"
+            android:onClick="@{clickListener}"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toStartOf="@+id/button0"
             app:layout_constraintHorizontal_bias="0.5"

+ 12 - 2
app/src/main/res/layout/iem_currency.xml

@@ -4,7 +4,12 @@
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <data>
-
+        <variable
+            name="clickListener"
+            type="android.view.View.OnClickListener"/>
+        <variable
+            name="currencyUI"
+            type="com.mrozon.currencyconverter.presentation.CurrencyUI" />
     </data>
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -25,6 +30,7 @@
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent"
+            android:text="@{currencyUI.charCode}"
             tools:text="RUB" />
 
         <TextView
@@ -41,6 +47,8 @@
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toEndOf="@+id/tvCharCode"
             app:layout_constraintTop_toTopOf="parent"
+            app:show_total="@{currencyUI}"
+            android:onClick="@{clickListener}"
             tools:text="10,3" />
 
         <TextView
@@ -53,6 +61,8 @@
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/tvValue"
-            tools:text="Российский рубль" />
+            android:text="@{currencyUI.name}"
+            tools:text="Российский рубль"
+            tools:ignore="SmallSp" />
     </androidx.constraintlayout.widget.ConstraintLayout>
 </layout>

+ 1 - 1
app/src/main/res/values/strings.xml

@@ -9,7 +9,7 @@
     <string name="button3">3</string>
     <string name="button2">2</string>
     <string name="button1">1</string>
-    <string name="buttonComma">,</string>
+    <string name="buttonComma">.</string>
     <string name="button0">0</string>
     <string name="buttonDel">Del</string>
     <string name="rub_char_code">RUB</string>

+ 8 - 11
app/src/test/java/com/mrozon/currencyconverter/domain/CalculateCurrencyUseCaseTest.kt

@@ -98,14 +98,13 @@ class CalculateCurrencyUseCaseTest {
     }
 
     @Test
-    fun convertCurrency_change_rub()  {
-        val rub = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
+    fun convertCurrency_change_rub2eur()  {
         val from = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
-        val to = Currency(charCode = "RUB", name = "Российский рубль", value = 1.0)
+        val to = Currency(charCode = "EUR", name = "Евро", value = 85.9943)
 
-        val expected = 5.0
+        val expected = 0.01162
 
-        val actual = useCase.convertCurrency(from, to, rub, 5.0)
+        val actual = useCase.convertCurrency(from, to, 1.0)
         assertEquals(
             expected,
             actual,
@@ -115,13 +114,12 @@ class CalculateCurrencyUseCaseTest {
 
     @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)
+        val actual = useCase.convertCurrency(from, to, 5.0)
         assertEquals(
             expected,
             actual,
@@ -131,13 +129,12 @@ class CalculateCurrencyUseCaseTest {
 
     @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 to = Currency(charCode = "USD", name = "Доллар США", value = 72.5048)
 
-        val expected = 1.1907
+        val expected = 5.9302
 
-        val actual = useCase.convertCurrency(from, to, rub, 1.0)
+        val actual = useCase.convertCurrency(from, to, 5.0)
         assertEquals(
             expected,
             actual,