فهرست منبع

add network dependencies
add service, get serializable answer from network

MrOzOn 4 سال پیش
والد
کامیت
261fe75597

+ 1 - 0
README.md

@@ -26,6 +26,7 @@
 ## Используемый стек
 - MVVM
 - Kotlin Coroutines
+- Dagger2 and Hilt
 - Room
 - Retrofit
 

+ 8 - 0
app/build.gradle

@@ -43,6 +43,14 @@ dependencies {
     //Dagger Hilt
     implementation "com.google.dagger:hilt-android:$hilt_version"
     kapt "com.google.dagger:hilt-compiler:$hilt_version"
+    //Network
+    implementation "com.squareup.okhttp3:logging-interceptor:$okHttpLogging_version"
+    implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
+    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
+    implementation "com.google.code.gson:gson:$gson_version"
+    //
+    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
+    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
 
     testImplementation 'junit:junit:4.13.2'
     androidTestImplementation 'androidx.test.ext:junit:1.1.2'

+ 46 - 0
app/src/main/java/com/mrozon/currencyconverter/data/network/CurrenciesResponse.kt

@@ -0,0 +1,46 @@
+package com.mrozon.currencyconverter.data.network
+
+import com.google.gson.annotations.SerializedName
+
+data class CurrenciesResponse(
+
+	@field:SerializedName("PreviousURL")
+	val previousURL: String? = null,
+
+	@field:SerializedName("Timestamp")
+	val timestamp: String? = null,
+
+	@field:SerializedName("Date")
+	val date: String? = null,
+
+	@field:SerializedName("PreviousDate")
+	val previousDate: String? = null,
+
+	@field:SerializedName("Valute")
+	val valute: Map<String, Valute>? = null
+)
+
+data class Valute(
+
+	@field:SerializedName("CharCode")
+	val charCode: String? = null,
+
+	@field:SerializedName("Value")
+	val value: Double? = null,
+
+	@field:SerializedName("Previous")
+	val previous: Double? = null,
+
+	@field:SerializedName("ID")
+	val iD: String? = null,
+
+	@field:SerializedName("Nominal")
+	val nominal: Int? = null,
+
+	@field:SerializedName("NumCode")
+	val numCode: String? = null,
+
+	@field:SerializedName("Name")
+	val name: String? = null
+)
+

+ 34 - 0
app/src/main/java/com/mrozon/currencyconverter/data/network/CurrencyService.kt

@@ -0,0 +1,34 @@
+package com.mrozon.currencyconverter.data.network
+
+import com.mrozon.currencyconverter.BuildConfig
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.http.GET
+import okhttp3.logging.HttpLoggingInterceptor.Level.BODY
+import okhttp3.logging.HttpLoggingInterceptor.Level.NONE
+
+interface CurrencyService {
+    @GET("archive/2021/06/18/daily_json.js")
+    suspend fun getCurrencies(): CurrenciesResponse
+
+    companion object {
+        private const val BASE_URL = "https://www.cbr-xml-daily.ru/"
+
+        fun create(): CurrencyService {
+            val logger = HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) BODY else NONE }
+
+            val client = OkHttpClient.Builder()
+                .addInterceptor(logger)
+                .build()
+
+            return Retrofit.Builder()
+                .baseUrl(BASE_URL)
+                .client(client)
+                .addConverterFactory(GsonConverterFactory.create())
+                .build()
+                .create(CurrencyService::class.java)
+        }
+    }
+}

+ 24 - 0
app/src/main/java/com/mrozon/currencyconverter/data/network/MapValutesDeserializer.kt

@@ -0,0 +1,24 @@
+package com.mrozon.currencyconverter.data.network
+
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonParseException
+import com.google.gson.JsonElement
+import com.google.gson.JsonDeserializationContext
+import com.google.gson.Gson
+import java.lang.reflect.Type
+
+class MapValutesDeserializer : JsonDeserializer<Map<String, Valute>?> {
+    @Throws(JsonParseException::class)
+    override fun deserialize(
+        json: JsonElement,
+        typeOfT: Type?,
+        context: JsonDeserializationContext?
+    ): Map<String, Valute> {
+        val result = mutableMapOf<String, Valute>()
+        val valutes = json.asJsonObject.entrySet()
+        valutes.forEach { (key, value) ->
+            result[key] = Gson().fromJson(value, Valute::class.java)
+        }
+        return result.toMap()
+    }
+}

+ 18 - 0
app/src/main/java/com/mrozon/currencyconverter/di/NetworkModule.kt

@@ -0,0 +1,18 @@
+package com.mrozon.currencyconverter.di
+
+import com.mrozon.currencyconverter.data.network.CurrencyService
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@InstallIn(SingletonComponent::class)
+@Module
+class NetworkModule {
+    @Singleton
+    @Provides
+    fun provideCurrencyService(): CurrencyService {
+        return CurrencyService.create()
+    }
+}

+ 329 - 3
app/src/test/java/com/mrozon/currencyconverter/ExampleUnitTest.kt

@@ -1,8 +1,13 @@
 package com.mrozon.currencyconverter
 
+import CurrenciesResponse
+import Valute
+import com.google.gson.*
+import com.mrozon.currencyconverter.data.network.MapValutesDeserializer
+import org.junit.Assert.assertEquals
 import org.junit.Test
+import java.lang.reflect.Type
 
-import org.junit.Assert.*
 
 /**
  * Example local unit test, which will execute on the development machine (host).
@@ -11,7 +16,328 @@ import org.junit.Assert.*
  */
 class ExampleUnitTest {
     @Test
-    fun addition_isCorrect() {
-        assertEquals(4, 2 + 2)
+    fun `check correct json to POJO`() {
+        val json = """
+            {
+                "Date": "2021-06-19T11:30:00+03:00",
+                "PreviousDate": "2021-06-18T11:30:00+03:00",
+                "PreviousURL": "\/\/www.cbr-xml-daily.ru\/archive\/2021\/06\/18\/daily_json.js",
+                "Timestamp": "2021-06-19T22:00:00+03:00",
+                "Valute": {
+                    "AUD": {
+                        "ID": "R01010",
+                        "NumCode": "036",
+                        "CharCode": "AUD",
+                        "Nominal": 1,
+                        "Name": "Австралийский доллар",
+                        "Value": 54.5056,
+                        "Previous": 55.1834
+                    },
+                    "AZN": {
+                        "ID": "R01020A",
+                        "NumCode": "944",
+                        "CharCode": "AZN",
+                        "Nominal": 1,
+                        "Name": "Азербайджанский манат",
+                        "Value": 42.5083,
+                        "Previous": 42.675
+                    },
+                    "GBP": {
+                        "ID": "R01035",
+                        "NumCode": "826",
+                        "CharCode": "GBP",
+                        "Nominal": 1,
+                        "Name": "Фунт стерлингов Соединенного королевства",
+                        "Value": 100.3808,
+                        "Previous": 101.427
+                    },
+                    "AMD": {
+                        "ID": "R01060",
+                        "NumCode": "051",
+                        "CharCode": "AMD",
+                        "Nominal": 100,
+                        "Name": "Армянских драмов",
+                        "Value": 13.941,
+                        "Previous": 13.9903
+                    },
+                    "BYN": {
+                        "ID": "R01090B",
+                        "NumCode": "933",
+                        "CharCode": "BYN",
+                        "Nominal": 1,
+                        "Name": "Белорусский рубль",
+                        "Value": 28.7415,
+                        "Previous": 28.7729
+                    },
+                    "BGN": {
+                        "ID": "R01100",
+                        "NumCode": "975",
+                        "CharCode": "BGN",
+                        "Nominal": 1,
+                        "Name": "Болгарский лев",
+                        "Value": 44.0295,
+                        "Previous": 44.321
+                    },
+                    "BRL": {
+                        "ID": "R01115",
+                        "NumCode": "986",
+                        "CharCode": "BRL",
+                        "Nominal": 1,
+                        "Name": "Бразильский реал",
+                        "Value": 14.4198,
+                        "Previous": 14.3415
+                    },
+                    "HUF": {
+                        "ID": "R01135",
+                        "NumCode": "348",
+                        "CharCode": "HUF",
+                        "Nominal": 100,
+                        "Name": "Венгерских форинтов",
+                        "Value": 24.2774,
+                        "Previous": 24.5218
+                    },
+                    "HKD": {
+                        "ID": "R01200",
+                        "NumCode": "344",
+                        "CharCode": "HKD",
+                        "Nominal": 10,
+                        "Name": "Гонконгских долларов",
+                        "Value": 93.0223,
+                        "Previous": 93.3763
+                    },
+                    "DKK": {
+                        "ID": "R01215",
+                        "NumCode": "208",
+                        "CharCode": "DKK",
+                        "Nominal": 1,
+                        "Name": "Датская крона",
+                        "Value": 11.5799,
+                        "Previous": 11.6565
+                    },
+                    "USD": {
+                        "ID": "R01235",
+                        "NumCode": "840",
+                        "CharCode": "USD",
+                        "Nominal": 1,
+                        "Name": "Доллар США",
+                        "Value": 72.2216,
+                        "Previous": 72.5048
+                    },
+                    "EUR": {
+                        "ID": "R01239",
+                        "NumCode": "978",
+                        "CharCode": "EUR",
+                        "Nominal": 1,
+                        "Name": "Евро",
+                        "Value": 85.9943,
+                        "Previous": 86.7012
+                    },
+                    "INR": {
+                        "ID": "R01270",
+                        "NumCode": "356",
+                        "CharCode": "INR",
+                        "Nominal": 100,
+                        "Name": "Индийских рупий",
+                        "Value": 97.7354,
+                        "Previous": 98.2377
+                    },
+                    "KZT": {
+                        "ID": "R01335",
+                        "NumCode": "398",
+                        "CharCode": "KZT",
+                        "Nominal": 100,
+                        "Name": "Казахстанских тенге",
+                        "Value": 16.8527,
+                        "Previous": 16.9505
+                    },
+                    "CAD": {
+                        "ID": "R01350",
+                        "NumCode": "124",
+                        "CharCode": "CAD",
+                        "Nominal": 1,
+                        "Name": "Канадский доллар",
+                        "Value": 58.4412,
+                        "Previous": 58.9326
+                    },
+                    "KGS": {
+                        "ID": "R01370",
+                        "NumCode": "417",
+                        "CharCode": "KGS",
+                        "Nominal": 100,
+                        "Name": "Киргизских сомов",
+                        "Value": 85.3006,
+                        "Previous": 85.7008
+                    },
+                    "CNY": {
+                        "ID": "R01375",
+                        "NumCode": "156",
+                        "CharCode": "CNY",
+                        "Nominal": 1,
+                        "Name": "Китайский юань",
+                        "Value": 11.2126,
+                        "Previous": 11.279
+                    },
+                    "MDL": {
+                        "ID": "R01500",
+                        "NumCode": "498",
+                        "CharCode": "MDL",
+                        "Nominal": 10,
+                        "Name": "Молдавских леев",
+                        "Value": 40.4037,
+                        "Previous": 40.733
+                    },
+                    "NOK": {
+                        "ID": "R01535",
+                        "NumCode": "578",
+                        "CharCode": "NOK",
+                        "Nominal": 10,
+                        "Name": "Норвежских крон",
+                        "Value": 84.4282,
+                        "Previous": 85.3691
+                    },
+                    "PLN": {
+                        "ID": "R01565",
+                        "NumCode": "985",
+                        "CharCode": "PLN",
+                        "Nominal": 1,
+                        "Name": "Польский злотый",
+                        "Value": 18.9354,
+                        "Previous": 19.1265
+                    },
+                    "RON": {
+                        "ID": "R01585F",
+                        "NumCode": "946",
+                        "CharCode": "RON",
+                        "Nominal": 1,
+                        "Name": "Румынский лей",
+                        "Value": 17.4803,
+                        "Previous": 17.5987
+                    },
+                    "XDR": {
+                        "ID": "R01589",
+                        "NumCode": "960",
+                        "CharCode": "XDR",
+                        "Nominal": 1,
+                        "Name": "СДР (специальные права заимствования)",
+                        "Value": 103.2271,
+                        "Previous": 104.3844
+                    },
+                    "SGD": {
+                        "ID": "R01625",
+                        "NumCode": "702",
+                        "CharCode": "SGD",
+                        "Nominal": 1,
+                        "Name": "Сингапурский доллар",
+                        "Value": 53.8766,
+                        "Previous": 54.1566
+                    },
+                    "TJS": {
+                        "ID": "R01670",
+                        "NumCode": "972",
+                        "CharCode": "TJS",
+                        "Nominal": 10,
+                        "Name": "Таджикских сомони",
+                        "Value": 63.3245,
+                        "Previous": 63.5728
+                    },
+                    "TRY": {
+                        "ID": "R01700J",
+                        "NumCode": "949",
+                        "CharCode": "TRY",
+                        "Nominal": 10,
+                        "Name": "Турецких лир",
+                        "Value": 83.2871,
+                        "Previous": 84.1025
+                    },
+                    "TMT": {
+                        "ID": "R01710A",
+                        "NumCode": "934",
+                        "CharCode": "TMT",
+                        "Nominal": 1,
+                        "Name": "Новый туркменский манат",
+                        "Value": 20.6643,
+                        "Previous": 20.7453
+                    },
+                    "UZS": {
+                        "ID": "R01717",
+                        "NumCode": "860",
+                        "CharCode": "UZS",
+                        "Nominal": 10000,
+                        "Name": "Узбекских сумов",
+                        "Value": 68.2557,
+                        "Previous": 68.2975
+                    },
+                    "UAH": {
+                        "ID": "R01720",
+                        "NumCode": "980",
+                        "CharCode": "UAH",
+                        "Nominal": 10,
+                        "Name": "Украинских гривен",
+                        "Value": 26.5806,
+                        "Previous": 26.6856
+                    },
+                    "CZK": {
+                        "ID": "R01760",
+                        "NumCode": "203",
+                        "CharCode": "CZK",
+                        "Nominal": 10,
+                        "Name": "Чешских крон",
+                        "Value": 33.7642,
+                        "Previous": 34.0366
+                    },
+                    "SEK": {
+                        "ID": "R01770",
+                        "NumCode": "752",
+                        "CharCode": "SEK",
+                        "Nominal": 10,
+                        "Name": "Шведских крон",
+                        "Value": 84.3878,
+                        "Previous": 85.2045
+                    },
+                    "CHF": {
+                        "ID": "R01775",
+                        "NumCode": "756",
+                        "CharCode": "CHF",
+                        "Nominal": 1,
+                        "Name": "Швейцарский франк",
+                        "Value": 78.7071,
+                        "Previous": 79.4486
+                    },
+                    "ZAR": {
+                        "ID": "R01810",
+                        "NumCode": "710",
+                        "CharCode": "ZAR",
+                        "Nominal": 10,
+                        "Name": "Южноафриканских рэндов",
+                        "Value": 51.3273,
+                        "Previous": 51.7097
+                    },
+                    "KRW": {
+                        "ID": "R01815",
+                        "NumCode": "410",
+                        "CharCode": "KRW",
+                        "Nominal": 1000,
+                        "Name": "Вон Республики Корея",
+                        "Value": 63.9421,
+                        "Previous": 64.1329
+                    },
+                    "JPY": {
+                        "ID": "R01820",
+                        "NumCode": "392",
+                        "CharCode": "JPY",
+                        "Nominal": 100,
+                        "Name": "Японских иен",
+                        "Value": 65.6292,
+                        "Previous": 65.55
+                    }
+                }
+            }
+        """.trimIndent()
+        val gson = GsonBuilder()
+            .registerTypeAdapter(Map::class.java, MapValutesDeserializer())
+            .create()
+        val response = gson.fromJson(json, CurrenciesResponse::class.java)
+        assertEquals(response.valute?.size?:0, 34)
     }
+
 }

+ 9 - 3
build.gradle

@@ -1,8 +1,14 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 buildscript {
-    ext.kotlin_version = "1.5.10"
-    ext.detekt_version = "1.17.1"
-    ext.hilt_version = "2.37"
+    ext {
+        kotlin_version = "1.5.10"
+        detekt_version = "1.17.1"
+        hilt_version = "2.37"
+        okHttpLogging_version = '4.7.2'
+        retrofit_version = '2.9.0'
+        gson_version = '2.8.6'
+        coroutines_version = "1.4.2"
+    }
     repositories {
         google()
         mavenCentral()