From 3bebcb7b47e164095e3d16b29a17ce4e8e8651db Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 6 Jan 2023 20:24:09 +0300 Subject: [PATCH 001/201] feature_coin_list module initial commit --- feature_coin_list/.gitignore | 1 + feature_coin_list/build.gradle | 41 +++++++++++++++++++ feature_coin_list/consumer-rules.pro | 0 feature_coin_list/proguard-rules.pro | 21 ++++++++++ .../ExampleInstrumentedTest.kt | 24 +++++++++++ .../src/main/AndroidManifest.xml | 4 ++ .../feature_coin_list/ExampleUnitTest.kt | 17 ++++++++ settings.gradle | 1 + 8 files changed, 109 insertions(+) create mode 100644 feature_coin_list/.gitignore create mode 100644 feature_coin_list/build.gradle create mode 100644 feature_coin_list/consumer-rules.pro create mode 100644 feature_coin_list/proguard-rules.pro create mode 100644 feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/ExampleInstrumentedTest.kt create mode 100644 feature_coin_list/src/main/AndroidManifest.xml create mode 100644 feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/ExampleUnitTest.kt diff --git a/feature_coin_list/.gitignore b/feature_coin_list/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/feature_coin_list/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature_coin_list/build.gradle b/feature_coin_list/build.gradle new file mode 100644 index 0000000..3d3f823 --- /dev/null +++ b/feature_coin_list/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.ryankoech.krypto.feature_coin_list' + compileSdk 33 + + defaultConfig { + minSdk 21 + targetSdk 33 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'com.google.android.material:material:1.7.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.4' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' +} \ No newline at end of file diff --git a/feature_coin_list/consumer-rules.pro b/feature_coin_list/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/feature_coin_list/proguard-rules.pro b/feature_coin_list/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/feature_coin_list/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/ExampleInstrumentedTest.kt b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..ddec370 --- /dev/null +++ b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.ryankoech.krypto.feature_coin_list + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.ryankoech.krypto.feature_coin_list.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/feature_coin_list/src/main/AndroidManifest.xml b/feature_coin_list/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/feature_coin_list/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/ExampleUnitTest.kt b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/ExampleUnitTest.kt new file mode 100644 index 0000000..05ad837 --- /dev/null +++ b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.ryankoech.krypto.feature_coin_list + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 1185bd2..b5de30d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,3 +16,4 @@ rootProject.name = "Krypto" include ':app' include ':feature_home' include ':common' +include ':feature_coin_list' From eeee2c09684b511d1ae1a521d549833613aff46d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 13:44:39 +0300 Subject: [PATCH 002/201] set up dependencies --- build.gradle | 2 ++ feature_coin_list/build.gradle | 41 +++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 281fe88..93b22ca 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,8 @@ buildscript { mockk_version = '1.13.3' coroutines_test_version = '1.6.4' turbine_version = '0.12.1' + okhttp_logging_interceptor_version = '5.0.0-alpha.9' + retrofit_version = '2.9.0' } dependencies { classpath "com.google.dagger:hilt-android-gradle-plugin:2.42" diff --git a/feature_coin_list/build.gradle b/feature_coin_list/build.gradle index 3d3f823..17f1b8d 100644 --- a/feature_coin_list/build.gradle +++ b/feature_coin_list/build.gradle @@ -1,6 +1,8 @@ plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'dagger.hilt.android.plugin' + id 'kotlin-kapt' } android { @@ -32,10 +34,37 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.5.1' - implementation 'com.google.android.material:material:1.7.0' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.4' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' + // core android + implementation "androidx.core:core-ktx:$ktx_core_version" + implementation "androidx.appcompat:appcompat:$app_compat_version" + implementation "com.google.android.material:material:$material_version" + + // local modules + implementation project(path: ':app') + implementation project(":common") + + // dagger-hilt - for dependency injection + implementation "com.google.dagger:hilt-android:$hilt_android_version" + implementation "androidx.hilt:hilt-navigation-compose:$hilt_navigation_compose_version" + kapt "com.google.dagger:hilt-android-compiler:$hilt_android_compile_version" + kapt "androidx.hilt:hilt-compiler:$hilt_compile_version" + + // retrofit - for network call + implementation "com.squareup.retrofit2:retrofit:$retrofit_version" + implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" + + // okhttp logging interceptor + implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_logging_interceptor_version" + + // timber + implementation "com.jakewharton.timber:timber:$timber_version" + + // junit4 + testImplementation "junit:junit:$junit_version" + + // junit4 + androidTestImplementation "androidx.test.ext:junit:$junit_ext_version" + + // espresso + androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" } \ No newline at end of file From eec0f85ef4c234964f4b29b14c29eacac798954d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 13:46:47 +0300 Subject: [PATCH 003/201] implement api service --- .../data/data_source/remote/CoinServiceApi.kt | 19 ++++++++ .../feature_coin_list/data/dto/CoinDto.kt | 48 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/remote/CoinServiceApi.kt create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/remote/CoinServiceApi.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/remote/CoinServiceApi.kt new file mode 100644 index 0000000..d3ca7f3 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/remote/CoinServiceApi.kt @@ -0,0 +1,19 @@ +package com.ryankoech.krypto.feature_coin_list.data.data_source.remote + +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface CoinServiceApi { + + @GET("coins/markets") + suspend fun getCoins( + @Query("vs_currency") currency : String = "usd", + @Query("order") order : String = "market_cap_desc", + @Query("per_page") perPage : Int = 500, + @Query("page") page : Int = 1, + @Query("sparkline") sparkline : Boolean = false + ) : Response> + +} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt new file mode 100644 index 0000000..e502032 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt @@ -0,0 +1,48 @@ +package com.ryankoech.krypto.feature_coin_list.data.dto + +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin + +data class CoinDto( + val ath: Double, + val ath_change_percentage: Double, + val ath_date: String, + val atl: Double, + val atl_change_percentage: Double, + val atl_date: String, + val circulating_supply: Double, + val current_price: Double, + val fully_diluted_valuation: Long, + val high_24h: Double, + val id: String, + val image: String, + val last_updated: String, + val low_24h: Double, + val market_cap: Long, + val market_cap_change_24h: Double, + val market_cap_change_percentage_24h: Double, + val market_cap_rank: Int, + val max_supply: Double, + val name: String, + val price_change_24h: Double, + val price_change_percentage_24h: Double, + val roi: Any, + val symbol: String, + val total_supply: Double, + val total_volume: Long +) + +fun List.toCoinEntity() : List = + map { + Coin( + id = it.id, + symbol = it.symbol, + price = it.current_price, + marketCapRank = it.market_cap_rank, + image = it.image, + change = it.price_change_24h.toFloat(), + marketCap = it.market_cap, + allTimeHigh = it.ath, + high24Hr = it.high_24h, + totalVolume = it.total_volume + ) + } \ No newline at end of file From a273b817c5332c52c9308a7ba9b62c1f63dc5f74 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 13:47:36 +0300 Subject: [PATCH 004/201] implement api service di module --- .../core/di/ApiServiceModule.kt | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt new file mode 100644 index 0000000..79f405c --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt @@ -0,0 +1,53 @@ +package com.ryankoech.krypto.feature_coin_list.core.di + +import com.ryankoech.krypto.BuildConfig +import com.ryankoech.krypto.feature_coin_list.data.data_source.remote.CoinServiceApi +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.create +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +private const val BASE_URL = "https://api.coingecko.com/api/v3/" + +@Module +@InstallIn(SingletonComponent::class) +object ApiServiceModule { + + @Singleton + @Provides + fun provideLoggingInterceptor() : OkHttpClient { + + val loggingInterceptor = HttpLoggingInterceptor() + loggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY + else HttpLoggingInterceptor.Level.NONE + + return OkHttpClient.Builder() + .readTimeout(120, TimeUnit.SECONDS) + .connectTimeout(120, TimeUnit.SECONDS) + .addInterceptor(loggingInterceptor) + .build() + } + + @Singleton + @Provides + fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { + return Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .client(okHttpClient) + .build() + } + + @Singleton + @Provides + fun provideCoinServiceApi(retrofit: Retrofit) : CoinServiceApi = + retrofit.create(CoinServiceApi::class.java) + +} \ No newline at end of file From 9b755a749373e269e4087434b21016bb9ba51397 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 13:48:56 +0300 Subject: [PATCH 005/201] implement repository --- .../data/repository/CoinRepositoryImpl.kt | 15 +++++++++++++++ .../domain/repository/CoinRepository.kt | 10 ++++++++++ 2 files changed, 25 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt new file mode 100644 index 0000000..1c89cdb --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt @@ -0,0 +1,15 @@ +package com.ryankoech.krypto.feature_coin_list.data.repository + +import com.ryankoech.krypto.feature_coin_list.data.data_source.remote.CoinServiceApi +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import retrofit2.Response +import javax.inject.Inject + +class CoinRepositoryImpl @Inject constructor( + private val api : CoinServiceApi +) : CoinRepository { + + override suspend fun getCoins(): Response> = api.getCoins() + +} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt new file mode 100644 index 0000000..19236f1 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt @@ -0,0 +1,10 @@ +package com.ryankoech.krypto.feature_coin_list.domain.repository + +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto +import retrofit2.Response + +interface CoinRepository { + + suspend fun getCoins() : Response> + +} \ No newline at end of file From 9f43c421d56db3ebfa22ba1ce7f55f644b0f1847 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 13:49:26 +0300 Subject: [PATCH 006/201] defined entity --- .../krypto/feature_coin_list/domain/entity/Coin.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt new file mode 100644 index 0000000..53216f8 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt @@ -0,0 +1,14 @@ +package com.ryankoech.krypto.feature_coin_list.domain.entity + +data class Coin( + val id : String, + val symbol : String, + val marketCapRank : Int, + val image : String, + val change : Float, + val price : Double, + val marketCap : Long, + val allTimeHigh : Double, + val high24Hr : Double, + val totalVolume : Long, +) From 6d58a8b62dc7e70321cac048aa8d9bae9f077b49 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 13:50:03 +0300 Subject: [PATCH 007/201] implement getCoins usecase --- .../domain/usecase/GetCoinsUseCase.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt new file mode 100644 index 0000000..02cb22b --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -0,0 +1,32 @@ +package com.ryankoech.krypto.feature_coin_list.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import timber.log.Timber +import javax.inject.Inject + +class GetCoinsUseCase @Inject constructor( + private val repository: CoinRepository +) { + + operator fun invoke() = flow { + val response = repository.getCoins() + + if(response.isSuccessful && !response.body().isNullOrEmpty()){ + emit(Resource.Success(data = response.body()!!.toCoinEntity())) + }else{ + emit(Resource.Error("Response not Successful.")) + } + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + Timber.e(e) + emit(Resource.Error(e.localizedMessage ?: "Unexpected Error Occurred.")) + } +} \ No newline at end of file From cddfe4908deb7c77731dcabd07883d7a5c05a9a0 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 15:08:40 +0300 Subject: [PATCH 008/201] fix data types --- .../ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt | 4 ++-- .../com/ryankoech/krypto/feature_coin_list/data/dto/Roi.kt | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/Roi.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt index e502032..e861048 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt @@ -21,11 +21,11 @@ data class CoinDto( val market_cap_change_24h: Double, val market_cap_change_percentage_24h: Double, val market_cap_rank: Int, - val max_supply: Double, + val max_supply: Double?, val name: String, val price_change_24h: Double, val price_change_percentage_24h: Double, - val roi: Any, + val roi: Roi?, val symbol: String, val total_supply: Double, val total_volume: Long diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/Roi.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/Roi.kt new file mode 100644 index 0000000..a163758 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/Roi.kt @@ -0,0 +1,7 @@ +package com.ryankoech.krypto.feature_coin_list.data.dto + +data class Roi( + val currency: String, + val percentage: Double, + val times: Double +) \ No newline at end of file From fbec7c838f67b2081adfe359d01d6f0aaa91fedb Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 15:09:23 +0300 Subject: [PATCH 009/201] implement repository fake --- .../data/repository/FakeCoinRepositoryImpl.kt | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt new file mode 100644 index 0000000..8a01ca8 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt @@ -0,0 +1,215 @@ +package com.ryankoech.krypto.feature_coin_list.data.repository + +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto +import com.ryankoech.krypto.feature_coin_list.data.dto.Roi +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import retrofit2.Response + +val FAKE_COIN_LIST = listOf( + CoinDto( + id = "bitcoin", + symbol = "btc", + name = "Bitcoin", + image = "https://assets.coingecko.com/coins/images/1/large/bitcoin.png?1547033579", + current_price = 16923.04, + market_cap = 325934668465, + market_cap_rank = 1, + fully_diluted_valuation = 355472891513, + total_volume = 17324993150, + high_24h = 17021.29, + low_24h = 16710.14, + price_change_24h = 154.92, + price_change_percentage_24h = 0.92388, + market_cap_change_24h = 2557781776.0, + market_cap_change_percentage_24h = 0.79096, + circulating_supply = 19254993.0, + total_supply = 21000000.0, + max_supply = 21000000.0, + ath = 69045.0, + ath_change_percentage = -75.48315, + ath_date = "2021-11-10T14:24:11.849Z", + atl = 67.81, + atl_change_percentage = 24863.64704, + atl_date = "2013-07-06T00:00:00.000Z", + roi = null, + last_updated = "2023-01-07T10:58:06.894Z", + ), + CoinDto( + id = "ethereum", + symbol = "eth", + name = "Ethereum", + image = "https://assets.coingecko.com/coins/images/279/large/ethereum.png?1595348880", + current_price = 1264.4, + market_cap = 152465403313, + market_cap_rank = 2, + fully_diluted_valuation = 152465403313, + total_volume = 4738147647, + high_24h = 1275.78, + low_24h = 1242.1, + price_change_24h = 18.52, + price_change_percentage_24h = 1.48649, + market_cap_change_24h = 2033182578.0, + market_cap_change_percentage_24h = 1.35156, + circulating_supply = 120524497.701488, + total_supply = 120524497.701488, + max_supply = null, + ath = 4878.26, + ath_change_percentage = -74.06476, + ath_date = "2021-11-10T14:24:19.604Z", + atl = 0.432979, + atl_change_percentage = 292105.57124, + atl_date = "2015-10-20T00:00:00.000Z", + roi = Roi( + times = 98.89428081326518, + currency = "btc", + percentage = 9889.428081326518, + ), + last_updated = "2023-01-07T10:58:08.421Z", + ), + CoinDto( + id = "tether", + symbol = "usdt", + name = "Tether", + image = "https://assets.coingecko.com/coins/images/325/large/Tether.png?1668148663", + current_price = 1.0, + market_cap = 66308002007, + market_cap_rank = 3, + fully_diluted_valuation = 66308002007, + total_volume = 22830407217, + high_24h = 1.002, + low_24h = 0.997607, + price_change_24h = -0.000014506074960785, + price_change_percentage_24h = -0.00145, + market_cap_change_24h = 26631461.0, + market_cap_change_percentage_24h = 0.04018, + circulating_supply = 66272490385.2966, + total_supply = 66272490385.2966, + max_supply = null, + ath = 1.32, + ath_change_percentage = -24.38936, + ath_date = "2018-07-24T00:00:00.000Z", + atl = 0.572521, + atl_change_percentage = 74.73609, + atl_date = "2015-03-02T00:00:00.000Z", + roi = null, + last_updated = "2023-01-07T10:55:07.354Z", + ), + CoinDto( + id = "usd-coin", + symbol = "usdc", + name = "USD Coin", + image = "https://assets.coingecko.com/coins/images/6319/large/USD_Coin_icon.png?1547042389", + current_price = 1.0, + market_cap = 43793762275, + market_cap_rank = 4, + fully_diluted_valuation = 43790483878, + total_volume = 2138738912, + high_24h = 1.002, + low_24h = 0.997155, + price_change_24h = 0.00025959, + price_change_percentage_24h = 0.02596, + market_cap_change_24h = -67821872.7326355, + market_cap_change_percentage_24h = -0.15463, + circulating_supply = 43775348278.3757, + total_supply = 43772071259.4457, + max_supply = null, + ath = 1.17, + ath_change_percentage = -14.7167, + ath_date = "2019-05-08T00:40:28.300Z", + atl = 0.891848, + atl_change_percentage = 12.14047, + atl_date = "2021-05-19T13:14:05.611Z", + roi = null, + last_updated = "2023-01-07T10:58:02.371Z", + ), + CoinDto( + id = "binancecoin", + symbol = "bnb", + name = "BNB", + image = "https://assets.coingecko.com/coins/images/825/large/bnb-icon2_2x.png?1644979850", + current_price = 261.01, + market_cap = 42629851070, + market_cap_rank = 5, + fully_diluted_valuation = 52217835573, + total_volume = 429267785, + high_24h = 262.55, + low_24h = 255.42, + price_change_24h = 4.84, + price_change_percentage_24h = 1.88825, + market_cap_change_24h = 737476415.0, + market_cap_change_percentage_24h = 1.76041, + circulating_supply = 163276974.63, + total_supply = 163276974.63, + max_supply = 200000000.0, + ath = 686.31, + ath_change_percentage = -61.94239, + ath_date = "2021-05-10T07:24:17.097Z", + atl = 0.0398177, + atl_change_percentage = 655869.36318, + atl_date = "2017-10-19T00:00:00.000Z", + roi = null, + last_updated = "2023-01-07T10:58:10.067Z", + ), + CoinDto( + id = "ripple", + symbol = "xrp", + name = "XRP", + image = "https://assets.coingecko.com/coins/images/44/large/xrp-symbol-white-128.png?1605778731", + current_price = 0.343551, + market_cap = 17368882302, + market_cap_rank = 6, + fully_diluted_valuation = 34350451021, + total_volume = 575571042, + high_24h = 0.346053, + low_24h = 0.334424, + price_change_24h = 0.00761656, + price_change_percentage_24h = 2.26727, + market_cap_change_24h = 346730797.0, + market_cap_change_percentage_24h = 2.03694, + circulating_supply = 50563767827.0, + total_supply = 99989171756.0, + max_supply = 100000000000.0, + ath = 3.4, + ath_change_percentage = -89.89294, + ath_date = "2018-01-07T00:00:00.000Z", + atl = 0.00268621, + atl_change_percentage = 12686.92874, + atl_date = "2014-05-22T00:00:00.000Z", + roi = null, + last_updated = "2023-01-07T10:58:10.468Z", + ), + CoinDto( + id = "binance-usd", + symbol = "busd", + name = "Binance USD", + image = "https://assets.coingecko.com/coins/images/9576/large/BUSD.png?1568947766", + current_price = 1.001, + market_cap = 16437019062, + market_cap_rank = 7, + fully_diluted_valuation = 16437019062, + total_volume = 5323587945, + high_24h = 1.004, + low_24h = 0.999316, + price_change_24h = 0.00102026, + price_change_percentage_24h = 0.10205, + market_cap_change_24h = -255937616.80016136, + market_cap_change_percentage_24h = -1.53321, + circulating_supply = 16424967238.39, + total_supply = 16424967238.39, + max_supply = null, + ath = 1.15, + ath_change_percentage = -13.3031, + ath_date = "2020-03-13T02:35:42.953Z", + atl = 0.901127, + atl_change_percentage = 11.04527, + atl_date = "2021-05-19T13:04:37.445Z", + roi = null, + last_updated = "2023-01-07T10:57:59.111Z", + ) +) + +class FakeCoinRepositoryImpl : CoinRepository { + override suspend fun getCoins(): Response> { + return Response.success(FAKE_COIN_LIST) + } +} \ No newline at end of file From 609dfc5f50d88eeefdcc6d470acc965ee0eef003 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 15:09:55 +0300 Subject: [PATCH 010/201] add test dependencies --- feature_coin_list/build.gradle | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/feature_coin_list/build.gradle b/feature_coin_list/build.gradle index 17f1b8d..94b22eb 100644 --- a/feature_coin_list/build.gradle +++ b/feature_coin_list/build.gradle @@ -62,6 +62,19 @@ dependencies { // junit4 testImplementation "junit:junit:$junit_version" + // google truth + testImplementation "com.google.truth:truth:$google_truth_version" + + // mockk + testImplementation "io.mockk:mockk-android:$mockk_version" + testImplementation "io.mockk:mockk-agent:$mockk_version" + + // coroutines test + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_test_version" + + // turbine + testImplementation "app.cash.turbine:turbine:$turbine_version" + // junit4 androidTestImplementation "androidx.test.ext:junit:$junit_ext_version" From fd2bcd161ce85210fbfe2cd832d10b46c5035caf Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 15:10:21 +0300 Subject: [PATCH 011/201] implement tests --- .../domain/usecase/GetCoinsUseCaseTest.kt | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt diff --git a/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt new file mode 100644 index 0000000..8cfcb38 --- /dev/null +++ b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt @@ -0,0 +1,107 @@ +package com.ryankoech.krypto.feature_coin_list.domain.usecase + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_coin_list.data.repository.FakeCoinRepositoryImpl +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import io.mockk.coEvery +import io.mockk.mockk +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest + +import org.junit.After +import org.junit.Before +import org.junit.Test +import retrofit2.Response + +@ExperimentalCoroutinesApi +class GetCoinsUseCaseTest { + + @Before + fun setUp() { + } + + @After + fun tearDown() { + } + + @Test + fun `response successful, return Resource type Success with data`() = runTest { + val getCoinsUseCase = GetCoinsUseCase(FakeCoinRepositoryImpl()) + + getCoinsUseCase().test { + + awaitItem() + val resource = awaitItem() + assertThat(resource).isInstanceOf(Resource.Success::class.java) + assertThat(resource.data).isEqualTo(FAKE_COIN_LIST.toCoinEntity()) + awaitComplete() + + } + } + + @Test + fun `call flow onStart, return Resource type Loading`() = runTest{ + val getCoinsUseCase = GetCoinsUseCase(FakeCoinRepositoryImpl()) + + getCoinsUseCase().test { + + assertThat(awaitItem()).isInstanceOf(Resource.Loading::class.java) + awaitItem() + awaitComplete() + + } + } + + @Test + fun `repository return null data, return Resource type Error`() = runTest { + val repository = mockk() + coEvery { repository.getCoins() } returns Response.success(null) + val getCoinsUseCase = GetCoinsUseCase(repository) + + getCoinsUseCase().test { + + awaitItem() + assertThat(awaitItem()).isInstanceOf(Resource.Error::class.java) + awaitComplete() + + } + } + + @Test + fun `repository return empty list, return Resource type Error`() = runTest { + val repository = mockk() + coEvery { repository.getCoins() } returns Response.success(listOf()) + val getCoinsUseCase = GetCoinsUseCase(repository) + + getCoinsUseCase().test { + + awaitItem() + assertThat(awaitItem()).isInstanceOf(Resource.Error::class.java) + awaitComplete() + + } + } + + @Test + fun `repository throws exception, return Resource type Error`() = runTest { + val exceptionMessage = "Mock Exception Message" + val repository = mockk() + coEvery { repository.getCoins() } throws Exception(exceptionMessage) + val getCoinsUseCase = GetCoinsUseCase(repository) + + getCoinsUseCase().test { + + awaitItem() + val resource = awaitItem() + assertThat(resource).isInstanceOf(Resource.Error::class.java) + assertThat(resource.message).isEqualTo(exceptionMessage) + awaitComplete() + + } + } + +} \ No newline at end of file From bc387357ab5e23c2c5d62f94a5529f1f5acb0b88 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 18:50:28 +0300 Subject: [PATCH 012/201] correct build import --- .../krypto/feature_coin_list/core/di/ApiServiceModule.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt index 79f405c..4a99e6b 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt @@ -1,6 +1,6 @@ package com.ryankoech.krypto.feature_coin_list.core.di -import com.ryankoech.krypto.BuildConfig +import com.ryankoech.krypto.feature_coin_list.BuildConfig import com.ryankoech.krypto.feature_coin_list.data.data_source.remote.CoinServiceApi import dagger.Module import dagger.Provides @@ -10,7 +10,6 @@ import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory -import retrofit2.create import java.util.concurrent.TimeUnit import javax.inject.Singleton From 5ab3af1cab7045ec5b916bc6a0ce526b70e3457b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 18:51:26 +0300 Subject: [PATCH 013/201] fix circular dependency --- feature_coin_list/build.gradle | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/feature_coin_list/build.gradle b/feature_coin_list/build.gradle index 94b22eb..6b31427 100644 --- a/feature_coin_list/build.gradle +++ b/feature_coin_list/build.gradle @@ -30,6 +30,12 @@ android { kotlinOptions { jvmTarget = '1.8' } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion compose_version + } } dependencies { @@ -40,7 +46,6 @@ dependencies { implementation "com.google.android.material:material:$material_version" // local modules - implementation project(path: ':app') implementation project(":common") // dagger-hilt - for dependency injection @@ -59,6 +64,12 @@ dependencies { // timber implementation "com.jakewharton.timber:timber:$timber_version" + //Compose + implementation "androidx.compose.ui:ui:$compose_version" + implementation "androidx.compose.material:material:$compose_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" + implementation "androidx.activity:activity-compose:$compose_activity_version" + // junit4 testImplementation "junit:junit:$junit_version" @@ -80,4 +91,9 @@ dependencies { // espresso androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" + + // compose ui + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" + debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" } \ No newline at end of file From de9e207cb3c68ca78575c6de9c79cb077f9b319c Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 18:52:26 +0300 Subject: [PATCH 014/201] implement searchbar component --- .../presentation/components/SearchBar.kt | 77 +++++++++++++++++++ common/src/main/res/drawable/icon_search.xml | 9 +++ 2 files changed, 86 insertions(+) create mode 100644 common/src/main/java/com/ryankoech/krypto/common/presentation/components/SearchBar.kt create mode 100644 common/src/main/res/drawable/icon_search.xml diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/SearchBar.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/SearchBar.kt new file mode 100644 index 0000000..4bd3177 --- /dev/null +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/SearchBar.kt @@ -0,0 +1,77 @@ +package com.ryankoech.krypto.common.presentation.components + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.constraintlayout.widget.Placeholder +import com.ryankoech.krypto.common.R +import com.ryankoech.krypto.common.presentation.theme.Green200 +import com.ryankoech.krypto.common.presentation.theme.Green500 +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme + +@Composable +fun SearchBar( + value : String, + onValueChange : (String) -> Unit, + placeholder: String, + modifier: Modifier = Modifier +) { + + TextField( + modifier = modifier + .fillMaxWidth() + .padding(bottom = 8.dp) + .border(width = 1.dp, shape = MaterialTheme.shapes.small, color = Color.Black), + shape = MaterialTheme.shapes.small, + leadingIcon = { + Icon( + painter = painterResource(id = R.drawable.icon_search), + contentDescription = "Search icon" + ) + }, + placeholder = { + Text( + text = placeholder, + style = MaterialTheme.typography.caption, + color = Color.Black + ) + }, + textStyle = MaterialTheme.typography.caption, + value = value, + onValueChange = onValueChange, + singleLine = true, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = Color.Unspecified, + unfocusedIndicatorColor = Color.Unspecified, + cursorColor = Green200, + backgroundColor = Color.White + ), + ) + + +} + +@Preview +@Composable +fun SearchBarPreview() { + KryptoTheme { + Surface( + modifier = Modifier.fillMaxWidth() + ) { + + + SearchBar( + value = "", + onValueChange = {}, + placeholder = "Discover asset, coin or token" + ) + } + } +} \ No newline at end of file diff --git a/common/src/main/res/drawable/icon_search.xml b/common/src/main/res/drawable/icon_search.xml new file mode 100644 index 0000000..ec342c0 --- /dev/null +++ b/common/src/main/res/drawable/icon_search.xml @@ -0,0 +1,9 @@ + + + + From d51a901193e100d65fb2d38aed4c964edc1a8dda Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 18:53:58 +0300 Subject: [PATCH 015/201] add basic screens --- .../presentation/CoinListScreen.kt | 29 ++++++++++++++++ .../presentation/CoinListScreenSuccess.kt | 34 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt new file mode 100644 index 0000000..1597860 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -0,0 +1,29 @@ +package com.ryankoech.krypto.feature_coin_list.presentation + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Surface +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.ryankoech.krypto.common.presentation.components.SearchBar +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme + +@Composable +fun CoinListScreen() { + + Surface( + modifier = Modifier.fillMaxSize() + ) { + CoinListScreenSuccess() + } +} + +@Preview +@Composable +fun CoinListScreenPreview() { + + KryptoTheme { + CoinListScreen() + } +} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt new file mode 100644 index 0000000..7e91dda --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -0,0 +1,34 @@ +package com.ryankoech.krypto.feature_coin_list.presentation + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.SearchBar + +@Composable +fun CoinListScreenSuccess( + modifier: Modifier = Modifier +) { + + Column( + modifier = modifier + .fillMaxSize() + .padding( + top = 12.dp, start = 12.dp, end = 12.dp + ) + ) { + var value by remember { + mutableStateOf("") + } + + SearchBar( + value = value, + onValueChange = { value = it }, + placeholder = "Discover asset, coin or token" + ) + } + +} \ No newline at end of file From 7112927b40d1e04441172ada7884081c2c9467a3 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 7 Jan 2023 18:55:34 +0300 Subject: [PATCH 016/201] remove unused imports --- .../krypto/common/presentation/components/SearchBar.kt | 2 -- .../krypto/feature_coin_list/presentation/CoinListScreen.kt | 2 -- 2 files changed, 4 deletions(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/SearchBar.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/SearchBar.kt index 4bd3177..bba6338 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/SearchBar.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/SearchBar.kt @@ -10,10 +10,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.constraintlayout.widget.Placeholder import com.ryankoech.krypto.common.R import com.ryankoech.krypto.common.presentation.theme.Green200 -import com.ryankoech.krypto.common.presentation.theme.Green500 import com.ryankoech.krypto.common.presentation.theme.KryptoTheme @Composable diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index 1597860..9c64da3 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -1,12 +1,10 @@ package com.ryankoech.krypto.feature_coin_list.presentation -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.Surface import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import com.ryankoech.krypto.common.presentation.components.SearchBar import com.ryankoech.krypto.common.presentation.theme.KryptoTheme @Composable From 7900ef3be59b8f2573150591c21d56111bc956c5 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 12:56:51 +0300 Subject: [PATCH 017/201] update coin entity structure --- .../com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt | 1 + .../com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt index e861048..dff85af 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt @@ -35,6 +35,7 @@ fun List.toCoinEntity() : List = map { Coin( id = it.id, + name = it.name, symbol = it.symbol, price = it.current_price, marketCapRank = it.market_cap_rank, diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt index 53216f8..69d8f91 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt @@ -2,6 +2,7 @@ package com.ryankoech.krypto.feature_coin_list.domain.entity data class Coin( val id : String, + val name : String, val symbol : String, val marketCapRank : Int, val image : String, From 86bac40ecd13adfefa2b8002fe51739d72ebacd6 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 12:59:44 +0300 Subject: [PATCH 018/201] implemented market cap string util --- .../krypto/common/presentation/util/Utils.kt | 43 +++++++++++++++++++ common/src/main/res/values/strings.xml | 1 + 2 files changed, 44 insertions(+) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt index 0849e66..cc8e1c8 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt @@ -32,4 +32,47 @@ fun getChangeColor(change : Float) : Color { fun getInTwoDecimalPlaces(value : Double) : String{ val df = DecimalFormat("#.##") return df.format(value) +} +fun getFormattedMarketCap(context: Context, value : Long) : String { + val million = 1_000_000 + val billion = 1_000_000_000 + val trillion = 1_000_000_000_000 + val quadrillion = 1_000_000_000_000_000 + val quintillion = 1_000_000_000_000_000_000 + + return if(value < million) { + val df = DecimalFormat("#,###.##") + context.getString(R.string.coin_market_cap, df.format(value), "") + }else if(value < billion){ + context.getString( + R.string.coin_market_cap, + getInFourDecimalPlaces(value.toDouble() / million.toDouble()), + "M" + ) + }else if(value < trillion){ + context.getString( + R.string.coin_market_cap, + getInFourDecimalPlaces(value.toDouble() / billion.toDouble()), + "Bn" + ) + }else if(value < quadrillion){ + context.getString( + R.string.coin_market_cap, + getInFourDecimalPlaces(value.toDouble() / trillion.toDouble()), + "Tr" + ) + }else if(value < quintillion){ + context.getString( + R.string.coin_market_cap, + getInFourDecimalPlaces(value.toDouble() / quadrillion.toDouble()), + "Tr" + ) + }else { + "Over $1 Qnt" + } +} + +fun getInFourDecimalPlaces(value : Double) : String{ + val df = DecimalFormat("#,##0.0000") + return df.format(value) } \ No newline at end of file diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index a1631b7..fad1980 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -3,4 +3,5 @@ %s Image %s%s%% %s%s + MCap $%s %s \ No newline at end of file From 3585370df293682bbd1b57bde368b22d66cf2bd7 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 13:00:21 +0300 Subject: [PATCH 019/201] update string format --- .../java/com/ryankoech/krypto/common/presentation/util/Utils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt index cc8e1c8..780debf 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt @@ -30,7 +30,7 @@ fun getChangeColor(change : Float) : Color { } fun getInTwoDecimalPlaces(value : Double) : String{ - val df = DecimalFormat("#.##") + val df = DecimalFormat("#,##0.00") return df.format(value) } fun getFormattedMarketCap(context: Context, value : Long) : String { From 98b20935358bd683f35f03f1869529e36981eff4 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 13:01:46 +0300 Subject: [PATCH 020/201] implement search tag --- .../components/success/SearchTag.kt | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt new file mode 100644 index 0000000..94cbb65 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt @@ -0,0 +1,84 @@ +package com.ryankoech.krypto.feature_coin_list.presentation.components.success + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_coin_list.R +import com.ryankoech.krypto.feature_coin_list.domain.entity.Order +import com.ryankoech.krypto.feature_coin_list.presentation.theme.black100 +import com.ryankoech.krypto.feature_coin_list.presentation.theme.limeGreenYellow400 + +@Composable +fun SearchTag( + onClick : () -> Unit, + isSelected : Boolean, + order : Order, + text : String, + modifier: Modifier = Modifier, +) { + + val spacingValue = 4.dp + + Button( + modifier = modifier, + colors = ButtonDefaults.buttonColors( + backgroundColor = if(isSelected) limeGreenYellow400 else black100, + ), + elevation = ButtonDefaults.elevation( + defaultElevation = 0.dp + ), + onClick = onClick + ) { + + Spacer(modifier = Modifier.width(spacingValue/2)) + + Text( + modifier = Modifier + .padding(vertical = spacingValue), + text = text, + style = MaterialTheme.typography.caption, + ) + + Spacer(modifier = Modifier.width(spacingValue/2)) + + if (isSelected) { + + Icon( + modifier = Modifier + .size(14.dp) + .rotate(if (order == Order.DESC) 180F else 0F), + painter = painterResource(R.drawable.icon_arrow_up), + contentDescription = null + ) + + Spacer(modifier = Modifier.width(spacingValue/2)) + } + } + +} + +@Preview +@Composable +fun SearchTagPreview() { + + KryptoTheme { + Surface { + SearchTag( + onClick = {}, + isSelected = true, + order = Order.ASC, + text = "Market Cap" + ) + } + } + +} \ No newline at end of file From dcd8afd85d2d7a9b2c54cef1bf9a89a7c7b0ead1 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 13:03:23 +0300 Subject: [PATCH 021/201] add enum class --- .../krypto/feature_coin_list/domain/entity/Order.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Order.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Order.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Order.kt new file mode 100644 index 0000000..0c2d7de --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Order.kt @@ -0,0 +1,6 @@ +package com.ryankoech.krypto.feature_coin_list.domain.entity + +enum class Order { + ASC, + DESC +} \ No newline at end of file From 0c80779fd58927c728bc82d0dd81af64a8e4eb0e Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 13:03:48 +0300 Subject: [PATCH 022/201] add color resources --- .../krypto/feature_coin_list/presentation/theme/Color.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/theme/Color.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/theme/Color.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/theme/Color.kt new file mode 100644 index 0000000..b7efe08 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/theme/Color.kt @@ -0,0 +1,7 @@ +package com.ryankoech.krypto.feature_coin_list.presentation.theme + +import androidx.compose.ui.graphics.Color + +val limeGreenYellow400 = Color(0xffe3f379) +val black100 = Color(0xffeeeeee) +val black200 = Color(0xffaaaaaa) \ No newline at end of file From baa93fb4a1507470aed0ee521c4185662fc68bd8 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 13:04:15 +0300 Subject: [PATCH 023/201] add arrow icon resource --- feature_coin_list/src/main/res/drawable/icon_arrow_up.xml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 feature_coin_list/src/main/res/drawable/icon_arrow_up.xml diff --git a/feature_coin_list/src/main/res/drawable/icon_arrow_up.xml b/feature_coin_list/src/main/res/drawable/icon_arrow_up.xml new file mode 100644 index 0000000..a12aecf --- /dev/null +++ b/feature_coin_list/src/main/res/drawable/icon_arrow_up.xml @@ -0,0 +1,8 @@ + + + + From 73205cc153530615d18bc910176dff54b1801424 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 13:04:48 +0300 Subject: [PATCH 024/201] implement coin item component --- .../components/success/CoinItem.kt | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt new file mode 100644 index 0000000..ea455d0 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt @@ -0,0 +1,152 @@ +package com.ryankoech.krypto.feature_coin_list.presentation.components.success + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.VerticalAlignmentLine +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.CoinImage +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.* +import com.ryankoech.krypto.feature_coin_list.R +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_coin_list.presentation.theme.black100 +import com.ryankoech.krypto.feature_coin_list.presentation.theme.black200 + +@Composable +fun CoinItem( + onClick : () -> Unit, + coin: Coin, + modifier: Modifier = Modifier +) { + + val context = LocalContext.current + + Row( + modifier = modifier + .fillMaxWidth() + .height(IntrinsicSize.Min) + .background( + color = Color.White, + shape = RoundedCornerShape(10.dp) + ) + .clickable { + onClick() + }, + ) { + CoinImage(coin.image, coin.id) + + Spacer(modifier = Modifier.width(8.dp)) + + Column( + modifier = Modifier + .padding(4.dp) + .fillMaxHeight() + .weight(1.0f), + verticalArrangement = Arrangement.SpaceBetween + ) { + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + modifier = Modifier + .padding(end = 2.dp), + text = coin.name, + style = MaterialTheme.typography.h3, + ) + Text( + text = getFormattedBalance( + context = context, + balance = coin.price, + displayCurrency = DisplayCurrency.USD + ), + style = MaterialTheme.typography.h4 + ) + } + + Row( + modifier = Modifier + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .padding( + end = 4.dp + ) + .background( + color = black200, + shape = RoundedCornerShape(3.dp) + ), + + ){ + Text( + modifier = Modifier + .padding( + vertical = 0.dp, + horizontal = 3.dp + ), + text = coin.marketCapRank.toString(), + style = MaterialTheme.typography.h4, + color = Color.White + ) + } + Text( + modifier = Modifier + .padding(end = 2.dp) + .alpha(0.6f), + text = coin.symbol.uppercase(), + style = MaterialTheme.typography.h3, + ) + Text( + text = getFormattedChange(context, coin.change), + style = MaterialTheme.typography.body1, + color = getChangeColor(coin.change) + ) + Spacer(modifier = Modifier.weight(1.0f)) + Text( + modifier = Modifier + .alpha(0.6f), + text = getFormattedMarketCap(context, coin.marketCap), + style = MaterialTheme.typography.body1 + ) + } + } + } + +} + +@Preview(showBackground = true) +@Composable +fun CoinItemPreview() { + KryptoTheme { + Surface( + modifier = Modifier + .fillMaxSize() + ) { + Column { + CoinItem( + {}, + FAKE_COIN_LIST.toCoinEntity().first() + ) + } + } + } +} \ No newline at end of file From a70c3b419d0cf90ca30f7381317158889685a501 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 14:21:15 +0300 Subject: [PATCH 025/201] implement repo di module --- .../core/di/CoinRepositoryModule.kt | 35 +++++++++++++++++++ .../data/repository/FakeCoinRepositoryImpl.kt | 3 +- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinRepositoryModule.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinRepositoryModule.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinRepositoryModule.kt new file mode 100644 index 0000000..3a981e8 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinRepositoryModule.kt @@ -0,0 +1,35 @@ +package com.ryankoech.krypto.feature_coin_list.core.di + +import com.ryankoech.krypto.feature_coin_list.data.repository.CoinRepositoryImpl +import com.ryankoech.krypto.feature_coin_list.data.repository.FakeCoinRepositoryImpl +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Named +import javax.inject.Singleton + +const val HILT_NAMED_REPO_FAKE = "FakeRepo" +const val HILT_NAMED_REPO = "Repo" +const val HILT_NAME_REPO_FOR_ALL = HILT_NAMED_REPO_FAKE + +@Module +@InstallIn(SingletonComponent::class) +abstract class CoinRepositoryModule { + + @Binds + @Singleton + @Named(HILT_NAMED_REPO_FAKE) + abstract fun provideFakeCoinRepository( + coinRepositoryImpl: FakeCoinRepositoryImpl + ) : CoinRepository + + @Binds + @Singleton + @Named(HILT_NAMED_REPO) + abstract fun provideCoinRepository( + coinRepositoryImpl: CoinRepositoryImpl + ) : CoinRepository + +} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt index 8a01ca8..a0ac29f 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt @@ -4,6 +4,7 @@ import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto import com.ryankoech.krypto.feature_coin_list.data.dto.Roi import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository import retrofit2.Response +import javax.inject.Inject val FAKE_COIN_LIST = listOf( CoinDto( @@ -208,7 +209,7 @@ val FAKE_COIN_LIST = listOf( ) ) -class FakeCoinRepositoryImpl : CoinRepository { +class FakeCoinRepositoryImpl @Inject constructor() : CoinRepository { override suspend fun getCoins(): Response> { return Response.success(FAKE_COIN_LIST) } From bd4dddc2201836a17ac6ae47c029c8a9a5b4d538 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 14:22:26 +0300 Subject: [PATCH 026/201] implement sorting logic --- .../domain/entity/SortCoinBy.kt | 7 +++ .../domain/entity/SortInfo.kt | 6 +++ .../domain/usecase/GetCoinsUseCase.kt | 48 +++++++++++++++++-- 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/SortCoinBy.kt create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/SortInfo.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/SortCoinBy.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/SortCoinBy.kt new file mode 100644 index 0000000..9c9e9c7 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/SortCoinBy.kt @@ -0,0 +1,7 @@ +package com.ryankoech.krypto.feature_coin_list.domain.entity + +enum class SortCoinBy { + MARKET_CAP, + TOTAL_VOLUME, + PRICE +} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/SortInfo.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/SortInfo.kt new file mode 100644 index 0000000..85dd5cd --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/SortInfo.kt @@ -0,0 +1,6 @@ +package com.ryankoech.krypto.feature_coin_list.domain.entity + +data class SortInfo( + val sortBy : SortCoinBy, + val order: Order +) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index 02cb22b..c2a58d6 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -1,25 +1,30 @@ package com.ryankoech.krypto.feature_coin_list.domain.usecase import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_coin_list.domain.entity.Order +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.onStart import timber.log.Timber import javax.inject.Inject +import javax.inject.Named class GetCoinsUseCase @Inject constructor( - private val repository: CoinRepository + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinRepository ) { - operator fun invoke() = flow { + operator fun invoke(sortInfo: SortInfo) = flow { val response = repository.getCoins() if(response.isSuccessful && !response.body().isNullOrEmpty()){ - emit(Resource.Success(data = response.body()!!.toCoinEntity())) + val sortedData = sortData(sortInfo, response.body()!!.toCoinEntity()) + emit(Resource.Success(data = sortedData)) }else{ emit(Resource.Error("Response not Successful.")) } @@ -29,4 +34,39 @@ class GetCoinsUseCase @Inject constructor( Timber.e(e) emit(Resource.Error(e.localizedMessage ?: "Unexpected Error Occurred.")) } + + private fun sortData(sortInfo: SortInfo, unsortedData : List) : List { + return when(sortInfo.sortBy){ + SortCoinBy.MARKET_CAP -> { + when(sortInfo.order){ + Order.ASC -> { + unsortedData.sortedBy { it.marketCap } + } + Order.DESC -> { + unsortedData.sortedByDescending { it.marketCap } + } + } + } + SortCoinBy.TOTAL_VOLUME -> { + when(sortInfo.order){ + Order.ASC -> { + unsortedData.sortedBy { it.totalVolume } + } + Order.DESC -> { + unsortedData.sortedByDescending { it.totalVolume } + } + } + } + SortCoinBy.PRICE -> { + when(sortInfo.order){ + Order.ASC -> { + unsortedData.sortedBy { it.marketCap } + } + Order.DESC -> { + unsortedData.sortedByDescending { it.marketCap } + } + } + } + } + } } \ No newline at end of file From f527c949d6e17889659cc63f50d835462f588dde Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 14:23:07 +0300 Subject: [PATCH 027/201] implement viewmodel --- .../viewmodel/CoinListScreenViewModel.kt | 72 +++++++++++++++++++ .../viewstate/CoinListScreenviewState.kt | 9 +++ 2 files changed, 81 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewstate/CoinListScreenviewState.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt new file mode 100644 index 0000000..20cda01 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt @@ -0,0 +1,72 @@ +package com.ryankoech.krypto.feature_coin_list.presentation.viewmodel + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_list.domain.entity.Order +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo +import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetCoinsUseCase +import com.ryankoech.krypto.feature_coin_list.presentation.viewstate.CoinListScreenviewState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import timber.log.Timber +import javax.inject.Inject + +val sortInfo = SortInfo( + sortBy = SortCoinBy.MARKET_CAP, + order = Order.DESC +) + +@HiltViewModel +class CoinListScreenViewModel @Inject constructor( + private val getCoinsUseCase: GetCoinsUseCase +) : ViewModel() { + + private val _viewState = mutableStateOf(CoinListScreenviewState()) + val viewState : State = _viewState + + init { + getCoins(sortInfo) + } + + private fun getCoins(sortInfo: SortInfo) { + + getCoinsUseCase(sortInfo) + .onEach { res -> + when(res){ + is Resource.Error -> { + Timber.d("VM Error") + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + is Resource.Loading -> { + Timber.d("VM Loading") + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING + ) + } + is Resource.Success -> { + Timber.d("VM Success") + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS, + coins = res.data!! + ) + } + else -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + } + + }.launchIn(viewModelScope) + + } + +} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewstate/CoinListScreenviewState.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewstate/CoinListScreenviewState.kt new file mode 100644 index 0000000..bb068c1 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewstate/CoinListScreenviewState.kt @@ -0,0 +1,9 @@ +package com.ryankoech.krypto.feature_coin_list.presentation.viewstate + +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin + +data class CoinListScreenviewState( + val screenState: ScreenState = ScreenState.LOADING, + val coins : List = listOf(), +) From b304bd3945154482dcb9144c63bdbfdb18eb7b37 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 14:23:51 +0300 Subject: [PATCH 028/201] add screen state logic --- .../presentation/CoinListScreen.kt | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index 9c64da3..cd6042b 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -5,15 +5,34 @@ import androidx.compose.material.Surface import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.ViewModel import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel @Composable -fun CoinListScreen() { +fun CoinListScreen( + viewModel: CoinListScreenViewModel = hiltViewModel(), + modifier: Modifier = Modifier +) { + + val viewState = viewModel.viewState.value Surface( modifier = Modifier.fillMaxSize() ) { - CoinListScreenSuccess() + when(viewState.screenState){ + ScreenState.LOADING -> { + //TODO : Show Loading Screen + } + ScreenState.ERROR -> { + //TODO : Show Error Screen + } + ScreenState.SUCCESS -> { + CoinListScreenSuccess() + } + } } } From e6269c38bc5cb230a9e23a0b0d252552abd4e542 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 15:01:05 +0300 Subject: [PATCH 029/201] change function visibility and val name --- .../presentation/viewmodel/CoinListScreenViewModel.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt index 20cda01..b7c8f4e 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.onEach import timber.log.Timber import javax.inject.Inject -val sortInfo = SortInfo( +val DEFAULT_SORT_INFO = SortInfo( sortBy = SortCoinBy.MARKET_CAP, order = Order.DESC ) @@ -31,10 +31,10 @@ class CoinListScreenViewModel @Inject constructor( val viewState : State = _viewState init { - getCoins(sortInfo) + getCoins(DEFAULT_SORT_INFO) } - private fun getCoins(sortInfo: SortInfo) { + fun getCoins(sortInfo: SortInfo) { getCoinsUseCase(sortInfo) .onEach { res -> From 8e94abad0b0afe47860f50c28e2aa1d0153b2407 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 15:01:55 +0300 Subject: [PATCH 030/201] update logic to use state and state callback --- .../components/success/SearchTag.kt | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt index 94cbb65..e73a7e0 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt @@ -1,5 +1,6 @@ package com.ryankoech.krypto.feature_coin_list.presentation.components.success +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -14,29 +15,36 @@ import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.feature_coin_list.R import com.ryankoech.krypto.feature_coin_list.domain.entity.Order +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.theme.black100 import com.ryankoech.krypto.feature_coin_list.presentation.theme.limeGreenYellow400 +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SORT_INFO @Composable fun SearchTag( - onClick : () -> Unit, - isSelected : Boolean, - order : Order, + editSortingInfo : (sortCoinBy : SortCoinBy) -> Unit, + sortCoinBy: SortCoinBy, + sortInfoState : SortInfo, text : String, modifier: Modifier = Modifier, ) { val spacingValue = 4.dp + val isSelected = sortCoinBy == sortInfoState.sortBy + val order = sortInfoState.order Button( - modifier = modifier, + modifier = modifier.animateContentSize(), colors = ButtonDefaults.buttonColors( backgroundColor = if(isSelected) limeGreenYellow400 else black100, ), elevation = ButtonDefaults.elevation( defaultElevation = 0.dp ), - onClick = onClick + onClick = { + editSortingInfo(sortCoinBy) + } ) { Spacer(modifier = Modifier.width(spacingValue/2)) @@ -73,9 +81,9 @@ fun SearchTagPreview() { KryptoTheme { Surface { SearchTag( - onClick = {}, - isSelected = true, - order = Order.ASC, + editSortingInfo = {}, + sortCoinBy = SortCoinBy.MARKET_CAP, + sortInfoState = DEFAULT_SORT_INFO, text = "Market Cap" ) } From b6d83beaf27dfe2d2897967d882a3f079319233b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 15:02:46 +0300 Subject: [PATCH 031/201] implement search tag display and parameters --- .../presentation/CoinListScreenSuccess.kt | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index 7e91dda..0005c18 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -1,15 +1,22 @@ package com.ryankoech.krypto.feature_coin_list.presentation -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* +import androidx.compose.material.Surface import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.components.SearchBar +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo +import com.ryankoech.krypto.feature_coin_list.presentation.components.success.SearchTag +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SORT_INFO @Composable fun CoinListScreenSuccess( + editSortInfo : (sortCoinBy : SortCoinBy) -> Unit, + sortInfoState : SortInfo, modifier: Modifier = Modifier ) { @@ -17,7 +24,7 @@ fun CoinListScreenSuccess( modifier = modifier .fillMaxSize() .padding( - top = 12.dp, start = 12.dp, end = 12.dp + top = 12.dp, ) ) { var value by remember { @@ -25,10 +32,59 @@ fun CoinListScreenSuccess( } SearchBar( + modifier = Modifier + .padding(horizontal = 12.dp), value = value, onValueChange = { value = it }, placeholder = "Discover asset, coin or token" ) + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 12.dp, start = 12.dp, end = 12.dp), + horizontalArrangement = Arrangement.SpaceAround + ){ + + SearchTag( + editSortingInfo = editSortInfo, + sortInfoState = sortInfoState, + sortCoinBy = SortCoinBy.MARKET_CAP, + text = "Market Cap" + ) + + SearchTag( + editSortingInfo = editSortInfo, + sortInfoState = sortInfoState, + sortCoinBy = SortCoinBy.TOTAL_VOLUME, + text = "Volume" + ) + + SearchTag( + editSortingInfo = editSortInfo, + sortInfoState = sortInfoState, + sortCoinBy = SortCoinBy.PRICE, + text = "Price" + ) + + } } +} + +@Preview +@Composable +fun CoinListSuccessScreenPreview(){ + KryptoTheme { + Surface( + modifier = Modifier.fillMaxSize() + ) { + + CoinListScreenSuccess( + editSortInfo = {}, + sortInfoState = DEFAULT_SORT_INFO, + ) + + } + } } \ No newline at end of file From a6f99e91413c464bc61cc61f9343b33b74be7a8e Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 15:04:03 +0300 Subject: [PATCH 032/201] implement sorting info state management --- .../presentation/CoinListScreen.kt | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index cd6042b..9ce66fc 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -6,9 +6,11 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.ViewModel import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_list.domain.entity.Order +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel @Composable @@ -18,6 +20,37 @@ fun CoinListScreen( ) { val viewState = viewModel.viewState.value + var sortInfoState by remember { + mutableStateOf( + SortInfo( + sortBy = SortCoinBy.MARKET_CAP, + order = Order.DESC + ) + ) + } + + fun editSortingInfo(sortCoinBy: SortCoinBy) { + + val newSortInfo = if(sortCoinBy == sortInfoState.sortBy){ + if(sortInfoState.order == Order.ASC) { + sortInfoState.copy( + order = Order.DESC + ) + }else { + sortInfoState.copy( + order = Order.ASC + ) + } + }else { + sortInfoState.copy( + sortBy = sortCoinBy, + order = Order.DESC + ) + } + + viewModel.getCoins(newSortInfo) + sortInfoState = newSortInfo + } Surface( modifier = Modifier.fillMaxSize() @@ -30,7 +63,10 @@ fun CoinListScreen( //TODO : Show Error Screen } ScreenState.SUCCESS -> { - CoinListScreenSuccess() + CoinListScreenSuccess( + editSortInfo = ::editSortingInfo, + sortInfoState = sortInfoState + ) } } } From 6e8ad7832ea91808d47b1fada198067390be4196 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 15:20:48 +0300 Subject: [PATCH 033/201] implement coin list logic --- .../presentation/CoinListScreen.kt | 3 ++- .../presentation/CoinListScreenSuccess.kt | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index 9ce66fc..8c34ca4 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -65,7 +65,8 @@ fun CoinListScreen( ScreenState.SUCCESS -> { CoinListScreenSuccess( editSortInfo = ::editSortingInfo, - sortInfoState = sortInfoState + sortInfoState = sortInfoState, + coins = viewState.coins ) } } diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index 0005c18..bcf440b 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -1,6 +1,8 @@ package com.ryankoech.krypto.feature_coin_list.presentation import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material.Surface import androidx.compose.runtime.* import androidx.compose.ui.Modifier @@ -8,8 +10,12 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.components.SearchBar import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo +import com.ryankoech.krypto.feature_coin_list.presentation.components.success.CoinItem import com.ryankoech.krypto.feature_coin_list.presentation.components.success.SearchTag import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SORT_INFO @@ -17,6 +23,7 @@ import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SOR fun CoinListScreenSuccess( editSortInfo : (sortCoinBy : SortCoinBy) -> Unit, sortInfoState : SortInfo, + coins : List, modifier: Modifier = Modifier ) { @@ -66,7 +73,22 @@ fun CoinListScreenSuccess( sortCoinBy = SortCoinBy.PRICE, text = "Price" ) + } + LazyColumn( + modifier = Modifier + .weight(1f), + contentPadding = PaddingValues( + top = 12.dp, start = 12.dp, end = 12.dp + ) + ){ + items( + items = coins, + key = { it.id } + ){ coin -> + CoinItem(onClick = {}, coin = coin) + Spacer(modifier = Modifier.height(24.dp)) + } } } @@ -83,6 +105,7 @@ fun CoinListSuccessScreenPreview(){ CoinListScreenSuccess( editSortInfo = {}, sortInfoState = DEFAULT_SORT_INFO, + coins = FAKE_COIN_LIST.toCoinEntity() ) } From e73faff89e9f2e8c0210cbf8e292fcaa84938c33 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 15:22:02 +0300 Subject: [PATCH 034/201] fix sorting logic --- .../feature_coin_list/domain/usecase/GetCoinsUseCase.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index c2a58d6..763086c 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -60,10 +60,10 @@ class GetCoinsUseCase @Inject constructor( SortCoinBy.PRICE -> { when(sortInfo.order){ Order.ASC -> { - unsortedData.sortedBy { it.marketCap } + unsortedData.sortedBy { it.price } } Order.DESC -> { - unsortedData.sortedByDescending { it.marketCap } + unsortedData.sortedByDescending { it.price} } } } From fa4869cfe45debca9b2bd78bbbcd3243e4d57912 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 15:43:07 +0300 Subject: [PATCH 035/201] implement basic cache --- .../feature_coin_list/domain/usecase/GetCoinsUseCase.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index 763086c..92caf1f 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -2,6 +2,7 @@ package com.ryankoech.krypto.feature_coin_list.domain.usecase import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import com.ryankoech.krypto.feature_coin_list.domain.entity.Order @@ -11,6 +12,7 @@ import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.onStart +import retrofit2.Response import timber.log.Timber import javax.inject.Inject import javax.inject.Named @@ -19,8 +21,11 @@ class GetCoinsUseCase @Inject constructor( @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinRepository ) { + var cacheCoin : List? = null + operator fun invoke(sortInfo: SortInfo) = flow { - val response = repository.getCoins() + // Basic Cache + val response : Response> = if(cacheCoin.isNullOrEmpty()) repository.getCoins() else Response.success(cacheCoin) if(response.isSuccessful && !response.body().isNullOrEmpty()){ val sortedData = sortData(sortInfo, response.body()!!.toCoinEntity()) From d5b003fef1b540e23420acf61906e7d711d984c0 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 15:43:57 +0300 Subject: [PATCH 036/201] refactor total volume data type --- .../krypto/feature_coin_list/data/dto/CoinDto.kt | 2 +- .../data/repository/FakeCoinRepositoryImpl.kt | 14 +++++++------- .../krypto/feature_coin_list/domain/entity/Coin.kt | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt index dff85af..0b860a3 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt @@ -28,7 +28,7 @@ data class CoinDto( val roi: Roi?, val symbol: String, val total_supply: Double, - val total_volume: Long + val total_volume: Double ) fun List.toCoinEntity() : List = diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt index a0ac29f..7cef8fa 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt @@ -16,7 +16,7 @@ val FAKE_COIN_LIST = listOf( market_cap = 325934668465, market_cap_rank = 1, fully_diluted_valuation = 355472891513, - total_volume = 17324993150, + total_volume = 17324993150.0, high_24h = 17021.29, low_24h = 16710.14, price_change_24h = 154.92, @@ -44,7 +44,7 @@ val FAKE_COIN_LIST = listOf( market_cap = 152465403313, market_cap_rank = 2, fully_diluted_valuation = 152465403313, - total_volume = 4738147647, + total_volume = 4738147647.0, high_24h = 1275.78, low_24h = 1242.1, price_change_24h = 18.52, @@ -76,7 +76,7 @@ val FAKE_COIN_LIST = listOf( market_cap = 66308002007, market_cap_rank = 3, fully_diluted_valuation = 66308002007, - total_volume = 22830407217, + total_volume = 22830407217.0, high_24h = 1.002, low_24h = 0.997607, price_change_24h = -0.000014506074960785, @@ -104,7 +104,7 @@ val FAKE_COIN_LIST = listOf( market_cap = 43793762275, market_cap_rank = 4, fully_diluted_valuation = 43790483878, - total_volume = 2138738912, + total_volume = 2138738912.0, high_24h = 1.002, low_24h = 0.997155, price_change_24h = 0.00025959, @@ -132,7 +132,7 @@ val FAKE_COIN_LIST = listOf( market_cap = 42629851070, market_cap_rank = 5, fully_diluted_valuation = 52217835573, - total_volume = 429267785, + total_volume = 429267785.0, high_24h = 262.55, low_24h = 255.42, price_change_24h = 4.84, @@ -160,7 +160,7 @@ val FAKE_COIN_LIST = listOf( market_cap = 17368882302, market_cap_rank = 6, fully_diluted_valuation = 34350451021, - total_volume = 575571042, + total_volume = 575571042.0, high_24h = 0.346053, low_24h = 0.334424, price_change_24h = 0.00761656, @@ -188,7 +188,7 @@ val FAKE_COIN_LIST = listOf( market_cap = 16437019062, market_cap_rank = 7, fully_diluted_valuation = 16437019062, - total_volume = 5323587945, + total_volume = 5323587945.0, high_24h = 1.004, low_24h = 0.999316, price_change_24h = 0.00102026, diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt index 69d8f91..941da70 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/entity/Coin.kt @@ -11,5 +11,5 @@ data class Coin( val marketCap : Long, val allTimeHigh : Double, val high24Hr : Double, - val totalVolume : Long, + val totalVolume : Double, ) From 2bdbaf6a273fc1bea6cd566cc84fa467aeb3f08c Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 18:06:53 +0300 Subject: [PATCH 037/201] implemented coin search logic in vm and usecase --- .../domain/usecase/GetCoinsUseCase.kt | 13 +++++++++++-- .../viewmodel/CoinListScreenViewModel.kt | 6 +++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index 92caf1f..35e4f58 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -23,12 +23,21 @@ class GetCoinsUseCase @Inject constructor( var cacheCoin : List? = null - operator fun invoke(sortInfo: SortInfo) = flow { + operator fun invoke(sortInfo: SortInfo, filterString : String = "") = flow { // Basic Cache val response : Response> = if(cacheCoin.isNullOrEmpty()) repository.getCoins() else Response.success(cacheCoin) if(response.isSuccessful && !response.body().isNullOrEmpty()){ - val sortedData = sortData(sortInfo, response.body()!!.toCoinEntity()) + val filteredCoins = response.body()!!.toCoinEntity().filter { + it.name.contains( + filterString, + true + ) || it.symbol.contains( + filterString, + true + ) + } + val sortedData = sortData(sortInfo, filteredCoins) emit(Resource.Success(data = sortedData)) }else{ emit(Resource.Error("Response not Successful.")) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt index b7c8f4e..35357fb 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt @@ -31,12 +31,12 @@ class CoinListScreenViewModel @Inject constructor( val viewState : State = _viewState init { - getCoins(DEFAULT_SORT_INFO) + getCoins(DEFAULT_SORT_INFO, "") } - fun getCoins(sortInfo: SortInfo) { + fun getCoins(sortInfo: SortInfo, filterString : String) { - getCoinsUseCase(sortInfo) + getCoinsUseCase(sortInfo, filterString) .onEach { res -> when(res){ is Resource.Error -> { From 6adb1894dbd14997d374064eb2161d069c0d1810 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 8 Jan 2023 18:07:52 +0300 Subject: [PATCH 038/201] updated search bar logic to seach coins --- .../presentation/CoinListScreen.kt | 15 +++++++++++++-- .../presentation/CoinListScreenSuccess.kt | 15 ++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index 8c34ca4..cc20c9f 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -29,6 +29,15 @@ fun CoinListScreen( ) } + var filterStringState by remember { + mutableStateOf("") + } + + fun editFilterStringState(subString :String) { + viewModel.getCoins(sortInfoState, subString) + filterStringState = subString + } + fun editSortingInfo(sortCoinBy: SortCoinBy) { val newSortInfo = if(sortCoinBy == sortInfoState.sortBy){ @@ -48,7 +57,7 @@ fun CoinListScreen( ) } - viewModel.getCoins(newSortInfo) + viewModel.getCoins(newSortInfo, filterStringState) sortInfoState = newSortInfo } @@ -66,7 +75,9 @@ fun CoinListScreen( CoinListScreenSuccess( editSortInfo = ::editSortingInfo, sortInfoState = sortInfoState, - coins = viewState.coins + coins = viewState.coins, + filterStringState = filterStringState, + editFilterStringState = ::editFilterStringState ) } } diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index bcf440b..af1336c 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -21,9 +21,11 @@ import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SOR @Composable fun CoinListScreenSuccess( - editSortInfo : (sortCoinBy : SortCoinBy) -> Unit, + editSortInfo : (SortCoinBy) -> Unit, sortInfoState : SortInfo, coins : List, + filterStringState : String, + editFilterStringState : (String) -> Unit, modifier: Modifier = Modifier ) { @@ -34,15 +36,12 @@ fun CoinListScreenSuccess( top = 12.dp, ) ) { - var value by remember { - mutableStateOf("") - } SearchBar( modifier = Modifier .padding(horizontal = 12.dp), - value = value, - onValueChange = { value = it }, + value = filterStringState, + onValueChange = editFilterStringState, placeholder = "Discover asset, coin or token" ) @@ -105,7 +104,9 @@ fun CoinListSuccessScreenPreview(){ CoinListScreenSuccess( editSortInfo = {}, sortInfoState = DEFAULT_SORT_INFO, - coins = FAKE_COIN_LIST.toCoinEntity() + coins = FAKE_COIN_LIST.toCoinEntity(), + filterStringState = "", + editFilterStringState = {} ) } From 2068d3fa56a4e48cb3712648c15e7d7574b6183e Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 20:29:25 +0300 Subject: [PATCH 039/201] implement loading component --- .../components/success/CoinListLoading.kt | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinListLoading.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinListLoading.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinListLoading.kt new file mode 100644 index 0000000..70a73eb --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinListLoading.kt @@ -0,0 +1,47 @@ +package com.ryankoech.krypto.feature_coin_list.presentation.components.success + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.loading.CoinCardLoading +import com.ryankoech.krypto.common.presentation.components.loading.loadingEffect +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme + +@Composable +fun CoinListLoading( + modifier: Modifier = Modifier +) { + + val brush = loadingEffect() + + LazyColumn( + modifier = modifier.fillMaxSize(), + contentPadding = PaddingValues( + 12.dp + ) + ){ + items( + count = 15 + ){ + CoinCardLoading(brush) + Spacer(modifier = Modifier.height(24.dp)) + } + } + +} + +@Preview +@Composable +fun CoinListScreenLoadingPreview() { + KryptoTheme { + Surface( + modifier = Modifier.fillMaxSize() + ) { + CoinListLoading() + } + } +} \ No newline at end of file From 36ce8ec95814541ee0f43082a7a1ff608fb5c306 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 20:30:50 +0300 Subject: [PATCH 040/201] fix not caching bug --- .../domain/usecase/GetCoinsUseCase.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index 35e4f58..d28bf04 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -21,11 +21,18 @@ class GetCoinsUseCase @Inject constructor( @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinRepository ) { + // Basic Cache var cacheCoin : List? = null operator fun invoke(sortInfo: SortInfo, filterString : String = "") = flow { - // Basic Cache - val response : Response> = if(cacheCoin.isNullOrEmpty()) repository.getCoins() else Response.success(cacheCoin) + + val response : Response> = if(cacheCoin.isNullOrEmpty()) { + val response = repository.getCoins() + cacheCoin = response.body() + response + } else { + Response.success(cacheCoin) + } if(response.isSuccessful && !response.body().isNullOrEmpty()){ val filteredCoins = response.body()!!.toCoinEntity().filter { From 7524dcaf4a7d5f6c3a518cba6e5ddf6740828e4b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 20:31:58 +0300 Subject: [PATCH 041/201] update work flow of screenstate --- .../presentation/CoinListScreen.kt | 30 +++++++------ .../presentation/CoinListScreenSuccess.kt | 42 +++++++++++++------ 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index cc20c9f..6a62208 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -12,6 +12,7 @@ import com.ryankoech.krypto.feature_coin_list.domain.entity.Order import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel +import timber.log.Timber @Composable fun CoinListScreen( @@ -64,22 +65,19 @@ fun CoinListScreen( Surface( modifier = Modifier.fillMaxSize() ) { - when(viewState.screenState){ - ScreenState.LOADING -> { - //TODO : Show Loading Screen - } - ScreenState.ERROR -> { - //TODO : Show Error Screen - } - ScreenState.SUCCESS -> { - CoinListScreenSuccess( - editSortInfo = ::editSortingInfo, - sortInfoState = sortInfoState, - coins = viewState.coins, - filterStringState = filterStringState, - editFilterStringState = ::editFilterStringState - ) - } + + if(viewState.screenState == ScreenState.ERROR) { + //TODO : Show Error Screen + Timber.d("Display Coin List Error Screen") + }else { + CoinListScreenSuccess( + screenState = viewState.screenState, + editSortInfo = ::editSortingInfo, + sortInfoState = sortInfoState, + coins = viewState.coins, + filterStringState = filterStringState, + editFilterStringState = ::editFilterStringState + ) } } } diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index af1336c..d306a44 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -10,17 +10,21 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.components.SearchBar import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.components.success.CoinItem +import com.ryankoech.krypto.feature_coin_list.presentation.components.success.CoinListLoading import com.ryankoech.krypto.feature_coin_list.presentation.components.success.SearchTag import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SORT_INFO +import timber.log.Timber @Composable fun CoinListScreenSuccess( + screenState : ScreenState, editSortInfo : (SortCoinBy) -> Unit, sortInfoState : SortInfo, coins : List, @@ -74,19 +78,30 @@ fun CoinListScreenSuccess( ) } - LazyColumn( - modifier = Modifier - .weight(1f), - contentPadding = PaddingValues( - top = 12.dp, start = 12.dp, end = 12.dp - ) - ){ - items( - items = coins, - key = { it.id } - ){ coin -> - CoinItem(onClick = {}, coin = coin) - Spacer(modifier = Modifier.height(24.dp)) + if(screenState == ScreenState.LOADING) { + CoinListLoading() + } else { + + if( coins.isEmpty() ) { + // TODO: Show No Coins Screen + Timber.d("Display Coin List Empty List") + }else { + + LazyColumn( + modifier = Modifier + .weight(1f), + contentPadding = PaddingValues( + top = 12.dp, start = 12.dp, end = 12.dp + ) + ){ + items( + items = coins, + key = { it.id } + ){ coin -> + CoinItem(onClick = {}, coin = coin) + Spacer(modifier = Modifier.height(24.dp)) + } + } } } } @@ -102,6 +117,7 @@ fun CoinListSuccessScreenPreview(){ ) { CoinListScreenSuccess( + screenState = ScreenState.SUCCESS, editSortInfo = {}, sortInfoState = DEFAULT_SORT_INFO, coins = FAKE_COIN_LIST.toCoinEntity(), From ef445f8f0594428e832b749d7c0c049ee2b90ddd Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 21:57:52 +0300 Subject: [PATCH 042/201] fix component bug and update --- .../com/ryankoech/krypto/common/presentation/ErrorScreen.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/ErrorScreen.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/ErrorScreen.kt index fe5a30c..802f864 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/ErrorScreen.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/ErrorScreen.kt @@ -27,8 +27,9 @@ fun ErrorScreen( horizontalAlignment = Alignment.CenterHorizontally ) { - Box(modifier = Modifier.size(112.dp)) { + Box(modifier = Modifier.size(40.dp)) { GifImage( + modifier = Modifier.fillMaxSize(), res = res ) } From 52661c8dce719a0bb265cdba85b74a23c67e52ad Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 21:58:38 +0300 Subject: [PATCH 043/201] add gif resources --- .../src/main/res/drawable/icon_gif_caution.gif | Bin 0 -> 113953 bytes .../src/main/res/drawable/icon_gif_search.gif | Bin 0 -> 466384 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 common/src/main/res/drawable/icon_gif_caution.gif create mode 100644 common/src/main/res/drawable/icon_gif_search.gif diff --git a/common/src/main/res/drawable/icon_gif_caution.gif b/common/src/main/res/drawable/icon_gif_caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..008cad60162bf509d89c8c1015aa94a617abdb2a GIT binary patch literal 113953 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 Nss^g|*Hblx{{<&DK_UPE literal 0 HcmV?d00001 diff --git a/common/src/main/res/drawable/icon_gif_search.gif b/common/src/main/res/drawable/icon_gif_search.gif new file mode 100644 index 0000000000000000000000000000000000000000..16126288e8da566217bbcc8eb109c379e7079440 GIT binary patch literal 466384 zcmeF&_gm8cBV{9gtFfglhF3Dz7V`F1$Yingw+9zI*p>5{cyF-6T-4^GqoWTTI1m#PbMWB7Lx&C>K79Ddkt4CO zu~aHGK0ZDnAt5m_F)1l2IXU^*v16&JsmG5WPfJTnPftI2@+6&3XD}E{CNnE5D<>x> zH#avwKfj=$ps=v8sHmv8xR}Lam6Vi}mX?;4l~q(!R904=IdkUh=FV-dYID`q)#uNj zzi{CKo6WARt*x)Gzqq-E|LoG{8XFrgU%q^0b5}Rlw7F~l+4bw!TUuILTU&45ym@PL zZJWEjx%SO1-@bqUzP7gZV{<<@_iJzsDr|zYocOACmu@4+(Sw0D&sFaM)cLP|0n7&YKGmN2Q2{@ZIqW!3!lsUUhX<;p)$m}im`>X7a^o7tI zwQh~!@IM6A(G$AcE~2cLsI8t1W5Y%^-DGZ%Z2oep4x=lv$EHziWxI+TOHdl zU(x9KBUJ4b!~74e!)+R#=3k6~kF~Dk+(0NAK95^!uK1Rx-5%J`kG4<1hr{*P`lJq+ zj-Ho`ZCz>5EV6h(xS6G%H)Q;wU>0oI+&=#*rO0yIpEA#wuVYJun_p9Vc54}QNepeL ztMnFF7QuoEUHIb)Av@QG-b!e-GF9>j5eoHCo7cw3<(@CY>p?re-HpiC;xJD=R)jp= zvcgr7^|+b%YU<6Ua*G+!C2E4Etg-RLp3UY!yP98w%h|FH9mn)|rnXRO(`c0u#_ z?)V`^P2j6y3}y!o6SQjMIbw>rRE7jRg$RkE!+og? zsh}K?Y>)_?Y|NICiMCg#c1bOhv&|}Vijs!j9Pw-dyED6rkL2j>exKuP@{9`9Nvp~9 z6^KeT@qq^H8gwdwiO11%99QX>SeG8@8_xE)qat+swVoaC46Md~aCT19UhWDQ=#@CI zZA&PbAtRBKDPm4X99k1o)sM^d@U4|7YV1|h^@8m+w8O-37*b8-9>1e>=s`Bv>RGfI zMtK;gPXSu*kg}4i30LZ-c1t&N?PNXU(OG~#{ViTFr$ciRHB%1e_6E7T%xWczh(P&v zE>P}<0O3RwGyXWb@zBEa{aO9XS#l-*Dse;MxQt#qv6exwBkzWI2NI-B7C{6Lb=S(= z%G3!c8Fq_M!A4UVVwlQDhNN(%A+^SsSKqQL=C7aKNE|S#C%bDWcER?w+iT*zhDik~ zvK&B+egGZekG$2`LG9BgE9ZOAy2X=e-MD`aFn73o%KjrYU_Pdds&Hp)y`in1ni2ul z(prTFQSG*1<950nvXj2S&D7m5g4jEBt2z0WPRQXnuc9M!m?pK$;sQbM?_16aYh+jB zg}6)N`U~>kIAW5}XdjLGuBw7T<_N>hx9;e-#`BIJqA0U@o>~k9LfIVbVGJwXwqk{9TxW7eZ6d#K^if)}!U zP-N>0ebIE@tI*J_3$Y`!8z<2Mb7C^2T|w7UZ61e?-Z?GB1k9_~;31y-%N47AbG6qf zJ9<1%i`y?SL|Xtk?v=?h1B%UzuXo6Ao|Q`{r@RHUaG4=fZ{)XmoYV61F2ss@U0q=J zOSj|gb$Ugl-l2{}``-=yexveU2hLHx0XL|6x9ir3!JLw}_msCvg}5`7zhi)q>lD%5 zh4eH$b=nf)zgjD?N1;Xhgl%!W%VhRXvZLFPqOlo-**~zqh^aiVM z7}-wLBibuv`e?h!EPLZq?YE}#G*H*b*_UnvJ~`}p>uekau~SRrZYWMvJ4pWC?V4Vh zcLur%H@(1GQ`Fu<8c4t9=!L|sW?(eCvMe~}c4YA|XlOu&J98q zfu&p!9_%iynQTP(NpqApx0PBi4AuG-De)ptRVjXL26vC0;|a99-ldgAD6=lOh^dop zCYi-WmgKv-JcSQL03qKs(do1~wfD5ed+jY?4WO?iS_pKVH}2C4J*qvhcU%^wWP~zNu(H8FLo39w@1W% zy!)bCYDsBX{39S_v9`$6YQQ_8?2UCu-*veNYPb4zT9$kC-FmKN}n6vt_Z2&#!r%MMqIoWoD*H~auW!R^K{qP5@W1arAKHBl>TZnoh zm_)Sq7J!!l4zZ;$&Cz`}w`F3y)GnUV$QnRJvQzFPfy;?r-v0ijkP}*s$Ey4pZGvMU zwbc5kSVJH5Z@@MUWzGL@Uc?k&m`A+p@-uGi8_pHoiHVeuWSqX|?5u2i*AB zNhX&T3e7<@VUfuM_tW#h8zkpHQf^uzu-{zej~OyCqnM@JT61JfGaG2<1ft?~bSwQk z07$VZgyXIJ#3Zjnc*@6b$Yp#6Cc|878T?w*YK5efq+%C*DryYi63X^tladW?hrZ21 z%sb`kXav{u9LxK_(`=`wiTYY1e$C4|0r4hB1k`8{C=WobHa*cD;LqVBXk4wUF+C9?s!Ge$rrA2Hi1Eq7J zGy-hLPP^v~5d3YsfK^C04KBU2DtRC#i3&W)3~~d&c52e)og}C{D1!!NvY=VS>U;sD zpJ#?rMX%sd1Yh^~js4K%=n8k4q*N;j z5GO+IH3yJC8`2;^#FwYP|B=sdwt!fje&WDEE9A2b+$w)5lW|CX#D{xVxyLM zsDTaV!nrZI_xzZ&Kv!oXI2jLb!y|`beOr}( z@{#cbpfAU*Jj>4)4{`^9-0_ay1Q%7O1L$6mCjgYfLiK;Sbd?f^+jzhIIS*687cpj| zl1nRBY3Mc**i8^q8slSRY;Q8}9FPb+!h?-)P+{K{mZ*v*B}m!*n9dhhaZJj(6#NL= z;(h~YhuZljI)4sMMVy>k%Khk5D9%s?6U6{wVkv0%Ez}Yx*I~kjqK+jd)Ub9a`2bfGSv;H`4&mjpZ0s5)tLP#CJ8|xu`V#Rnfgo ztSw3hrE~QxTOc+rx5I+bl41Y}_STq8mPOcQRRaAA>SpX7HOE*=N^UkYCs;O6+4H#%Bk0C>E;$JTEKh#u5d)|Q`0fGhxTn2q@e9RanV*SN|hY1?GJ zgC`4yeOg31ba|jz#2Oycerlj%4z)r=;dzgq4{gB~V&@Iy!z{PQW`G?j4;R-*VP24r zJ!pTGCuKMGjL}4zHr5rlRb#X84gsgU-&83Tu7J7=`jg|v;dID$ZwFoE_#zjz!b2+X z27cY$;&2apkBIrrao4OZ7>m?AIDxsFCI%!+tsC_E+`}f|k++sG%4IkK;}M)enWid! zq~&~4O%dab`dDhTvyWSvidVDFMvr1L)8tZ)v|-GH+=}y**f@-h_v^ zLJc3@2!Qut!MIUKEgv~W#C+jqte9^3gU5WNJ~)lt3-=nIQc!53!5hi&8@#j129G2S zpD#>rc^?U9laXYW-UUAy;s zedhI_->(5md{JvY@YO33k-wq}+Z0uC02+`4paB5?Z&9)bzyM~n1cK5L64!qIc=LX@=I->>`(BdZ#loTTZ4lagyKlr; z-4;iyx=SOkEsrluC0X1~+Pm|}`}Ue&@ARwhUs)U5Vh>EB?W)-B)0U+59@kmD+?)Hw z@3Z`!goQ^J#dIsFcjDjQFaM(Pxyq{gh3~@%xf|Mp9f-`C!rMpoh8=zVELTkL?CJvV z(yqGD$!o#4Q&!g_uSOU)AFimxJQEs`(quwb21Lm+IAwOO=RZcIrssdZ>Kt2WMDvI3 zPv7ZW{HL+&>V}fd3wi$&YwQDu9=@_oqNnnHSZFpYth`yveQ(Yl2e2+gickDZxIe)RW(CR0b;dT6<%X66MUo-D7gEfBZ&>P_oZ7r?dqa)2O~d5QZmVf( zHm@{W9NHKsX*RMA^K^5ABOn(m`!6q6-5Xw$wLsEK3bb31ZjwwdBi$eLbpXRHv8 zNQoj4)xN|!jKw2IPqnb8`%ArySJK2xi(Uxainh&^^-rUKmiv!WK(bD0 z&0y7uL8IbU^~nVf%g^ntg*Hf|rQ%lO(<#GqQ$*2zanESFqig_~k}2cgj(M=|-#7x2 zaw1c5jMo6NC*qd)Fe{pBQ9dbL@%5EgWgHERR~ZEw#IciYVo;Q@G=|BD3F$m zE&M}1e%&}4Xrh&&M6XeP_Aaidhf^mfEe^K1Q(^{HJgn5sV@PuNAatroj<;5ioPY;$ z#4*IPT!33wcv(hkJXq);9&}w`@68c2zWvL|{E)2N5r-$r#dVaESk+>ZLKob=;I(u! zAd}Eb$Fc@{)eXIJ-OOqwN;wYdh9WQrUJcT^Y2SL58IV}Xv)*Im`J!MH>$Hl=e6{ne z1zwq{??Qr0-t3nB#)XoIwGst9KTUn{JP+gX%F|Q_P26&}VQ?2rslHp5$;*y!&tQdE zqRb=uSTP(izYU#&4g~`yqI)-j#P3$X$H5}Te54v#AYH1#2I9m@f=m+$q-AzM_$hb6 zf^%LkXK}I<6`V?F^cP!kEBA<3_E**6X2G3opfONXs<6^Q)q#>1B1FyRL68o$WURbl zLb{WhsiQv%b6oSxke+T(dBoT?-lVEH7BHx`M#tq;*emsryDgU9GfjC$XKHAUHjxI1 zfGNfmzrGK9uEyjCPIXJwaDa+zf(=Z9E+yvv{;Hsb70pw1vyxUbZ(GjPSwB^mP}!@V z=bBe}rR?I#!`kE!xv9!p70Kg7Eszm3Gpgy$VNacUn-6U47P~~<)rB7Mn*vXbL1oEQ zM5gYcl0D5aUvD;eT(h>PLvA!nz>l=+hAns%FgFHk;^XwrS|6Qd>ZGw?u~2nYQp@fx zIaAJ{x-KPzl2789OR4RrT{kt9yPN@BI$ZVI32^JSPTCb{f1J^C9TiIpfUfQ1FA&4u#N}j(GCi^b` z(vD0(?lGicmHxDt-C%QT zh^q=go(n5%PL?Y(Or~MO^RQc{7qS8oj_VfU61C=t^y4tu6tt zqw`b6whnL@z{|u;(?k_1Ek!fRNxC2$X#dVHs(nIoD382G8N44Ms?#>**!bfR-td=U z7&isDY}kc9L+)$z(SI6z^X^;1!11Akni13RB$-aKLyEl_&}*trA!c7y1f21Hg843* z>s_tK=2%`FSC+ammFl)fydZPm%$ERJCqh8YkKo2R*#dsJ-5Efxj>QvJ0|B~}V{|qp zz>MT{V^;r#^@=$yOy*5Rrf!<@m%9(9-}VVWg2fYi0(Iqc_a`|7MQNbZdhg?lZbPis zy`+y0LX+3IjvKKVuGwDrU)P(kPD8dMCn%O_QwtEVYT4&q>crYRk>8y)kYgcny*-*% z%gXKkY6pCfZun470z}h4;pA;Za&lT~6f$jqwg;5LI86#BrDUH@`OSlZl~K2ZTEtD) z=}rF)@PB5H86t$rCW2z{aKQkXOG93WN;1qwF34oiF2cDyi2G?034r)X3-N5VN+n~5 zuo!xmoyef%8eVHp1ggK)a=8L_;!=DkfF6|N?O(aa)E{CF0X@WGY@&>!ya_-9#OqS@ zXA&b?HU>H$&8)E>%T_78A zC%?9!_jF1A=3({#HRgzzG&b-fR3QvBw%3*{trh)Ah$_B>cbFi0!+c@4a4H^BJh;}yAndB5o0OqloagMqW zTVH0EwxNXH904=TP86uR*HZUL1r&w21aH>;yng%uFw74CX-GPhx@J;qs8UC^F7A zgbX~%PuLJMAtYj(S&Fco#;*w&9?9v!Q)oLYPb9Fw{n?&cwzK4h8mOC%xh-R8M%g<- zLXJ{>Ile|`79dqQprd=h-N{9A55t=Ih**61hjHJJJjwzM8_R;G73@xO(#t`9jrJ<{!`e|{^#78hDxn;;aw(ryP(Ru5A74C4cyJ9i zr^uDw#6dK%z!|0vPUKyJwaB>*JmyOPHl7X51)QY|&gA2vSpeAGsqLC|5O=IyPY*Dh z1?$3}GwO)2#KG5hkYVbeLsZ;yprO746zl~lz(f08t1#Q3gp*b*eZa*|ZD_X|b)g6zNdA9FTjs7$n%i^(_0I2YS zeG-pcVdYL!eWx_^UihI7vut1&%f7z>?jt~Qu<+*xsGU5jh6y~M1o`|f=u3u>a=?Q` z#{if~3J06ScReSlrC(ONM-|oKBVWlHqBGGaxIlLSNdBv}6V@S$4Nelu5fPHa10Ucz zpSu+h|HD3>igMGsQg17BF;#q$Exj%P;gumL4UN9pV%h{m`+A2f#-SuOki-RgvVqRV zuE9L(e|iF|qG45DS&P20-?PO3uu+|T*MZD~_naAQ#!sMs^dVhiLHY za-AZrW=cL12Xo4m$8d#l=qV!%hi+9kX};eF)lWq}+908Buz|8ffF~O>`$PAYG0Lzj z>V+WuO}sHnNRoO&Dn6#M_qQ_oj{q6Y7r|3Rv`0lh zs2F5PK@Qg(wt_vdd4^gi!Bha^K)i@~{dqrnlFLO0vf7mAP>}}MlLT001e7F{Bc3eI{lHHi;`Xu(x=BpTL3sv`St4Rj3m^}V!48)| zi(9)v>yc(}#FTUu0f26M6Z?VLzU2)PmW730HispQLVmK)-v)cSP95Zu2B|F%VN}uS zuDjD@49FLoM!iymg;sWfe-j^`tctQ75YtxfQ96{*&p-<$G$0WhNrXh6lNZX-OIH8x zH<)@r??;htc|H<&$R*{n21prICQ$+|$o)wb17gL?x}@+;z~9)be*|}j-LY(f$tuMQ zK5tjget5X)VFw%Y89R)y-TBqvNwg8hi2cw%?FoP+_7E_F++?G2m7$6-7Zzu@ZFU6R zC7&za$22^@ohyFBeG7aBn}pB(h*hmv*U;~U?iqUc(Q6byW}^j(a-sqljNbL^)cyD#3~Q7%9h2dwvkS?mAjyncw-)2<1z*i_MLR- zy!5d5!#QP_mPZPQ&6w6=V~3F=@wXA?b>h`nl%DA6y>zF%+-~)p*z|Jy zr{_ODzLcI(x~VtagPN8)JpHHOMSs&Yyzu4lHQvon5~F%EdLc7C*T$!wj89M`gr({K zFBPKUX~jV6`2Q~|l!JtM&wHJ!JwH1BKK8s-;>SDH<9Dtp+)kM0r6-*B+`1=iu|PT1 zoU8u$wDxoJvV?+};gq@FV>;haGdmOCj{QbinuT;Eynb{{GI{vC=iw_6@xg98FHbYO zKlbmvjWXzrUFuCoTLl?MkJs1F`}k|0{0-Sphjnbyc*bqP|IqFbtrpg+ zCH+6QFaPRUmK_;+z-e#!Ln!r1RP4C4Sq-66kVUeg$tXLs(0{8TT+93O+y10ATuA>- zZ-1SmlBfQ+8k$vd-K>Tr`q%gc;$xLB(*CU9m~*Taw32hTg16MN)LvzKnnFJ>{96rW zm^i`SmKnNrC|DP0U1nLNNbj6K9hwEJr~IvkD!>+ioCxvK(WMw#Kj@ zpMRwLF9_M2iMno){o28Ap8ode>UGR{)nZ!w#W$0!!wpwIw7wFAA9Q3v#~;%F6--H3=t0@*8np`3As74Q;e$Li{j8?g=&Lnvgdha1LOkf(88eO!k`Fln|=dS5`x@qa=C=zVWVL$;4hzqF4Rj+mrM z7F&Ei^rl!*R{g43$=BI8?pu8olrv=lsBs_}zi5LKKi+4IfMkLQ6o)M}EZyM?B(dA* z-K*;w!;TZ{dS+#3SDf%10#iSr2I0HFkU}niw#|Feg9X)MlI`4Om@=x3JFw3|=6u4M z*j9uE#CnA+e)|mC=Ifbk!Xq+M?0jr`0F5EVCW3UDb|btw49R+dl`adD79tFaHr80E zW9#7kG}{65cX8?0I+7jEc{*gR%tdMf4!Pu6K3ROkE^k@JbFo9C`}4X0SJCn1Rg*T!{bHZ z&h8BH3Mx>`P&vO+925Je6rNeH{V%_5gCJms9*TY;)ro8SD<@Vdg6Br_x zMWDgztVG4yTU8HR-9Ub~OnarHWmFB^Cvi@qJesM{jNKSm7GBbw@R{28ew@Deo38vP zV0eR6inivRVg!>#6>uVOCtp#CkJFht@hx6{{Mx#$PostHP@Y@j943+^D(WA@B=?FP zMua$<*SD}-1#bvIy#Y(S7k7n1zmPKMppJ`!c@2fhw6Xeh$t4pPca&dti~Qi_=;dW% zW}9ZCxYc+%uJ@<7Fc=DOFr8BoVeDGquNUGo3cU9+T z4cuGG@#1J%x161r>Oqactx2Sum(UlzhgozuTj7G#It%7(CMw-Vjq$zk==qb>qcZt- z9ORqLt@Us<;%jUDUrDaTVQLQOHJ2jFOKGV32HBP#Lhe=?gTVs1D%X>qUZrO2n!bA{ zOs3pLOww-~NSDx~6q#OaYF&!;5rjuKNDf$@rGQp%{evp62I>~U_dGd!`|iT0CLj4x z;ujHP%(7Xwf1yt+)3@j3kgBf5I)S-e7YmOBG^p;Mh4basn)@6H)a21@9e18E^#TXV zZ0okdGZj}mm4Yse`kf4--zXqC?jQdZC~?96-kXpNDdJ_2`ZQhX>zV6HU%TK;hiwmP z7qhIfT|oI0E68ecuhxmHd=<=hZffCs4H?`3&^%n}ctoiAGuy(9UXeIMeMr=>;NFUt z2)1<4A=k_OoxyQGnGRZp7UD^o%`So;)r@TsEY7$Dazhf(LeBc35v z=AOybI)_T~EptlY`)~}MJKr8yn_t1d zEW4g{VJh=Nj0il6)~jy!`?=^pbF%l>9KAaZhx)HE#C4uAWQqXLw4vDha|@8ILC+Q@ zlX{eTI1I7Qr7VxcTG@qoO#Wylfuk*x8->S@M!y^@7axQwfsRO z=7df9{zd9DBTBC+!T;)?s*ME2!|`gS4a*rz>C?WPgQaf$MJb`Jcax zv&5sbh5wGB^@0PnJ3?b8kHgK7N#EmBE+q#%O%68M_m+pz^}&wu%$Km3iSM=(lbF!= z_!%zd94}m)2}?9**Z+i*Tp%`{-sS$XbXMSCE6N3ca8{LvW zvoW+$?TKJq+6^+Ii3B!u1|8tyuKH<+*kfB+Bw;tClp=FE zQg!qaQgrRa0WzF_n|cm{1ScOG6b3pC$9i@kYIza+h`?mpzLW`Ph_D$VZe1cuJ56Cc zHhk5Xw^8Bb7+);7f|_~glCS(*M3+#4Sco$LM;;KNp4>1eF7&71$fW&W3F??LU*XDo z+|b)&XmX4QM9qWTiO`kaZ0^O(`%W2&0sjA}LEHe&SPf)UxL{ITQU|}B@F4m8?S`NtA!gr9dEAI#Jc!JK0Za>Yg=yA%$OTPn zVRK_k@rcYuKy6V`pdC`0kp3upcQ&LG5H#IbsQ(_mpBE`Kpf;{UL#we`B9=o_baP0( zGl%+3gulE*ynT_;y^wEW7Tn50FsX;`q=27eG0IwoW+m8I4(j0s9yN!@7=R6!!Z?f^ z;|~BO@)134h4W5fZbDM?v2FmtF1wI~803x>k^q#(f(dbF57VO-4@A`y{kc#s4gNKy z0^W8amVd&R1`1`NJR?_@W@YXEqzXY%fJs>& zR_bb-;tH(@WD6`LL#wtx&uu(EBP^Y&Sy@eX2g)E@% zYRdv8*J8#UDQiS1I1beLvC=*bz}m?%Z2xT#6V_QwMpoG0mM8Y z$c+HGe7c%WPk_V$i&)UPE$82Cfj;AvDA#Fs(DEf$L2d#NU4U>YKNg*f5Vp|g-h;i_ z7IF0lqOdYIqho~_1oeX5T|CEig&scuyB3f8YNXjf2Ika*>UzOvScv<0gfLu+lxc8@ zEIUcvRnlkeNd-UU?zz+(0~3d^1d#cMXM~c|%{TkVb5JTpuh8HDG4`<4Vy=Q zf-PV8NCH5#9gj(sGF-%B#@ND|$Ei)tQm+^lt(Cy{d zhT8F;d6&_nVxkn(qaIAUK-`I^Ns!cg&xQK&;`ncTYK-mO{$@lD7ry%hMB2X#2S(wM zEl*EQO2&TK^q^JZHDwNB`&&0cH)e~k0zgIz?8`M2Hc;pnI@+{o= znvjGDsbAQ#m+!>n7+{vE$P_Nf0RV#Btg2yJ+dKsYu`JxFz;FSioB!8$PNIEt8uBch6ltt<) zewm0G#-eIyV&W9xOKPH37NtA9_c@OudFr)5q{1IQ+!`+-6q=tF;DBek=~9qGl%m1M z_od&XzEHu4k1|I}kjv!jJ5;R9HDyhovWF2SuXz|YRsu03rC=a#!8gvR4bM8h zW~iW$0!I!h#Zq8N`_;dZG)3beOhTJM3j{AD?t}U|ED4Wgam2J}U!ck>qKue_T5oc(;dwhEz5RkL?@l5?AEe zG$;2h6S3|97#({hA1|A}!N#UbLJ0yq z(9|`0XMs{8Y|+2_=z*~A>btxSaD-66u>|1f5@GdY8vV;C-2p7Dq4rPrm~js+@|+WM zHH6PbO1fJv1}j8^P+K^U$_&JF22pSMn8*1;U=g^d(bndx+nK6hD}^C6RW$Op_KUmN zCH@hs=R@i%s8tT~r@VL?atMHjOrIG>Yve>c9+P{VDU~m&i$@FCmZRm z{A8=`2;>tsiIekDpwc<5p<)a?75q@!KwL6JJd1BjsLlIqS-ZwZU}pxD#mA)S5Qv1G zbk*qM1{?L8E2i+VhcG)P^REiAWRa~rPeYrZJWL&+PxqdbWxBYqA^Ji{KRGV_Xzl^3 zHt5-1h3JI~|Jd;qnnvo_@K!2GZWK1krLXfaD_FUlWz-B?_Q>z8r4Lhob0vihQN$(J6o+mpzC3Q*n?)52h?3!Y@865u`3&Go9@9R(bx&0dp z$v-w4c!pNLiJ_$4;-lK=wFbvK*8R?b-Pz7 zC1+nt;`8 zLgzvb)@UW?*0tL+?~ea-;4ME~&prSt3D<6B#j{k_)54G3SulJ|puC-W!&1D#F@$f! z$xYPXpZ>fQH_&)2yx0g8;^nSY#|g``ox;5kbfX9EHvNr-c%7YqaG?#IDEOZ?bThyv z!!qb^EVO$cW*`{7Z>cvNW3?tMhAh{nGKwv~uDp$!pq)1=Zr=nV*Pb&)rYl1k#XERY z5_!suk0OIx3uqfE1x9asdoT^JZif5^h#u-Lm|lCNiqc7A+kzw=aJE26Cj|pxF+`5b z+S=?J{&lC1h5kH+_b(8Io0Yv(*DX*aBWHnEko{fJN8bw|))Gh2 zY4cqw>*S%wMBudqqA1)Qf8l3;vM>!2f%{=!|Eec~G)Z*$8;c7v8#lQiRdS7F#E&QN zrPiWjRXv1{jZTh#-z!^da+>Bin=Ig&`oR>2-vUE|cN=WB+J(s{09ApuITk~+ND59> z8sE;{?lKEa_y=St;V8Kt0do?i zl}uG#uiRb1r^M4qVzO1VOr3fRB8X(Sg{@rNgNrBZ|I0-5;vYhIo8~zi+-DKN=B(ty zBnNfkXpSpkPJ#vK({O0XB?XI06%pTQh$?5#iImX&0dq#vl*iVFP{roIOw_fl@<+DP zBc2^_^t-iYJso?l5~wD(?7pWxOh)*2mmalbV|Q9@nAEv;2X$--SgGQl^n^4g%QBa? zH-t|Z69Yk#%YK?crXHl7swJ2c& z1=(&^gFp_kaYwobbVT+3ErwBs?Qv-0sa{-wdF}5dq3^e0<>BX528A`)O3g&ZksB#*;j;r%dO^yyPYg@hE5ui;5 zy+nBDbYmm=iaUxqIop0pnJ}6%?7Y_=#ShuzoTESdxKDiO6rgf7u^upxO+>BuIeyfETaQ9V+iu^y!M9%?8^}~< zcPm}?(Rm`_jRJVD%C9tnx3B?S`UG2ac_mZ5>@k1dyt3o**Q>fOSRU|DIuec`kGV}X zW_UfkPZa38^TSUq}bEW%XP7$?q@1s2O zkS&~YlOcf{#pvuma{wY_B4R<239+lJ!NEb@j-J2c+?~EgnNPa$aWHMOQ?OXBRONp$ zQN^FCzWkYq_7gE4V7YPiLz{bmSf7c(SgIOk22#5$heF} z=mn6z(r|EKV_43Zx}DfIEOq(vxb@0P*v*i)-L%Ye9u`T4 z4p@XIwa1)T&^{;yRNM+gMQ8Qv+%Ho;7eW=4!_f^QTW?P6j!m7f9!@0JPb}-{WjLdz z!B%0@TXl4x76qzjQ-(5vL+!5Y;PF4`1k@l)37M(86~C0#O@F#An?-1Hi^n~#WiQrs zZ^=7q)0TA}-)O702|~aVZazBp=zCnIk(r&$E~U1!>X@$&qLVr3ewzsHYJD_ z^}AbgB^z_n8@&R6I`Mq{u+ZO=$1g_4i?zo;;Ky%d2Xzu)j(!PDGKLlI8M(4u%m5)# zj{Z!hN6|4qHI!fRFsIqTeGVW$5~P)wM0*RrbDIiFMt0y&3`Qb4h)^e*kMPZ%dTOea zy379{A@eEBZeO+i8G&!>K*u(s;D4f+b#LLF{J$i`CG9zwyhoVGPz47*iGesKu~#zw zl2E&f#a|KbN!og#+FJm*hfhAImAhez=;T1xl0lA42m-X9E{TFtFk99P7V(%`0`O=A z`3Nn4#U)$oBK$rVyv5hr9Sfh1G`pGk*M@%hooonP&;imxUujBE}@(X z`j7z%Jki5%oAF)yYZdz|Y;Bg0mG z&}$MINkkx{9~eo7cXCeYJv?=G0rY;{!jlA9fJXd=GJFrKkoet;e7`)KPhU z<2cXjJg@71uGf7(&vV~@J%9FZ%4>e_d4Jwt1}cY)I?6+TWSF#MVtISr+{nll0f*RJ za(WCCMJz8&O#lAXJS^B4Je7`e%YY&j0YlxR5Q1zBT<4MQkiwWySSla0)#aG++PHQ) z(m@XnCU*I(@a+hd@;$^Ol35w5DF+2i8jb)pE-V|EcX~!fEQGna^D4%ka)>#pKu623 zOB^SvT!R<9*-Ol4q1eodT>hEz@5muyI(exWKS#zoQ(dsJu%ldzcJ@g^)(!y^xfkW^ zOU5p;0*`HT;4mfpsip2zCJXpPC?N98j2g!rm(jUpU+09pMrGnF3MhJ*W-=yPbns$m z$QelHH3encEMh(vl_oqhVSvgPA^Qb!p4M3e&rL9#p^qp$ij{D41_L5V6CqQD}yMFdXRs+g$^K|R&)6F7GB^7B0 z+gIy!a-yWje5Tm(&(u2n zoHW!6H!s5dV4*cg(pwhHPi(}+5jOZ;?op3&5mEXN2 zevpYQVT>=mf+DjZ+&cZtut|h)fJ7vO(Fi45RWq*niQqE(5j-w7PqVsyNJV9-2PfQ&=trWO^tEf2~72{QPidVP<^{mM13 zSXdq(8AV3yU^v>x!bA9o6oyO>U-C|V0l6(1lnJm8+X&x%Q*Q2&ojH^*uV79ICPXjb zo{O=AbZj5x_G3ZDF9Co#mNOJw7x06)*bV`HoPi!@?f2u@Y>$@RiE7X}PqDpKSQDQ7 zSy;AEq{c1+v=7_O!U~1hSS}Pog$^<{3CGj4!40T#zA;H4itEO16-xI1az+slG%XR{!O?6uIXJ&QI&up*1hg=%IYZ; zFnxy2R*;6E*R0flCFBh(Av(h7IDV0GhS9KpK?p6uDuJ0;9N%pC10gy`mxMCdW7|jb zj>_S7z~)J+)Z2gxb?om)N};!mcpN)zG$Vu#x_84wfJSLfh7O<`@$Wt7sTw(FZ;>)4)^?c!fk4n&Zp;;&q5yzPnOKq)cmarLA+Laje157=5u9A`6xc)pSlpGS)nQA zUr30&T_&xgHF6MI$~Z$oeojNEvDIycFh`NJk)i|r0R`yYtDmo|d?s#q zekE|E`oM}Smxtq9pIu-5d^>LZcIwEZl&38o|*&X6tIu%Y`9MhG|v#l9rpP z(zChQ>L_0oy(?xvx;!15`k@a^Pxx2wv95!jjI8T}N)khs^4Y5r13KTboAi(%=eqr4@eS2ifv~7ChcI_0f5kj1Ggvs0fb5%J2(!x1~*hBiJ_9b&&>}_ z-2K;nv+;2@sqZ}bkmm8e<E^?~rSX2nx~fKwE#jc5T@cI)p9Wd>8I9 z72LBJJdU${S-lV=+;DW{dQVl{^s!C9zs&F-&gi@?{D&vhn|^HlVz1nzwJG1fTk_ua z%SqN_*Ix`-9Vs5P{=x{vSv0U5T*-%F^F2D}$xCtrw)3+cy5l7$svfDRd@UY(cvS06 z;re$vF*$0%HkB}vGqH_Ba=})@@$!rT$&4SMGzZpa751Y7I1J?^ygZBXtoC+2jl9Icfm)$%eHwpXV3g3b_+0bdB3MAL<2 zg{6bp@NW@P7)NS4MeKF%1P-D8p}c1;wxe*LkCXCGNF}6Y1a}0Mj&+<3oNHosXfq}; zQQUNm-vX2a1xie-byVvX!B+)nvT?9<*=i9gc{DulT+;a7rbf#w{VN%ZY5w{=a@&_c z8pemqR(i?5y*aX7wyeBUM=dDFEudZYglngI9|LYs`$vf%#bIU5qN>xIi;>-XQQBfN zjrO8$)gOGAT(vL*6HSu|;Y#bRYXd+?ORo5zKz|tn;05n!L-D+cWC$L+AouO9__aGCA5OAE5pE9Tc1Ra1*h?62_m~UQx#4Xta|v zT&`@vxNtjmcgEkpum3j?3Pr9wD0WovY+{&R7Q-DAkCRSt;Ks?5=zu0Ir3Q+Do5vlD zzi8@QF$*X;g3ZW1as-;pWa5(|e1vhR>`$9~qb{>!VG~|wTuK~NzTG-GwB zW<#BCX+57`zd79Nw#V2c8f#ZeGE5`fE-j`^33?pP(~iAu98i6{vx8(lw%M>DNUo68 zslzxlTwF7H)$rE`Hz`bBAV*6+c@`?4{A{xUF!F6T;xrdZxC(bK_-!pRRP-pDd7owB6`ykx&9|SWdr>VPk*-jElSup+Nw177t%0T>W zWWpe!O#>FdCmd;eK8DdP3L&6^kd6wOrEAqHF;@>bZe7>-=+7%pTPc~Q5n)9b8da+9 zSV~~3w^Di3Y`Ov}$tP5*7c1OEOlSAPbeMA@T_fxEE%9*G{Er!$0q1wUaPL_LLi&Y0 zlxs+>LZ%b{UXWZqy=!k+{~M+2NlVpv%C87@TtxS583nnW<0O;t!b(4_kxqdnZ+vLMt`lb_c6wgq zxTn)PD|Tm;ej=O-JSPwJlG*B7I!bxD(Udimx2yO3xdT>lD{2|`hS`-WpU39Dbq*2i ztNYa-DUwwi1XP1;8tD}ITcwxE`ykl#@`NnY45O>MqxrjKqf+7n&K|zBbEI~)7IvyH znm?@)%9~UlpyYVm@E`rSRN6)HHOUV)zB}`mQ&N7=WS%{>GTWa4y)e*cerQ%&9ZX0U?RlZN?_WaR}+}(jMz+d%9v>($ZaOO zR=qSy|FFxocIg2U|1*HB{pDQQkG9lFX3co8VqT<335`0uMumxs)q3je z!#Au60}S{F9e5NGovat*yDGsrJf-_j3`RMj6(Yk5hZRs0GoKO)7{p=7I$#YwcX4?B zlyFc%6Xb3l(;ek|5M|WllL-M^%8tAX$8r?Yb-R-CC`t94Bus0D2SjpW@ZO`6vRYh^2+A>h7TS1>x=V~*;6^Qa z@04uDSW(b&!-x#D8-0&26>&v;;CXMs^I7zL9&*<#ES9D8(U#BsNm9 zI2<1ecO#;IK_afD>x4%W3xv*~2E-O4d3238Qz2XiYzNcLoqbs6#dFQva6cbKy>Y9c- zQLy_)JTA5EhG`9!nHCJ}XwSJdaA94+4Yp))E|h;es5bKyclD^Nt4F&8@z z_KS}tAhdt5h^b=d*=H5A4^XKh%tt}#!Fk*Q9T&lbec9w3$b`jG&~1>EujT3WV$3xv z>Z7yWnpN;?Jc8PuKv#1tY7UXy%>zv^;)P8YF{;Ey18-ZI+hJgeT`VjmKvy{bjzHhpfntfL>Ls4$b9_jtr`nt>|O@!u8-4)YENqDTFI7707KN;TXn+y zd5-xk{NRa;ELzkzz>3=OZy9hr1G%Br^x!mpiY^nfM22}bQRTjzh}}k$>)iZ04CV_# zHi@vob5|w2s0jOwVaYeVRGOsxgN`c(y&@*emjw@`mlt;0BW~VYn*j48BdbIbOJ|63 zxNMc0nf3t{+U6+%|B7|!6*Iz=2%Sthbf*J$8bOn@&hZhgrHc{8fVqgVT|8`$06WeM zq)J}^6(RtQjJ~LrCaJ~mA$(@x1OgOrr*;u5)|J?Yi4iOyR|u8o=(wCbY_2M9S3P0e zEcGW-cBV10uUuuYgYV}^7-!%HMc58L2o&L-Qr7%}P`6Cs1{mOv5>@G!5ZfTS@S$mS zX7MV$Lz#~ZwX%zLvz9^*-?FZ{RJ?nJQqT+bZDgE)2Umqa){EDKY+W{pD#M?1TMo%G z21o8gl2m5-SjR&MRU!$n4-VICvhS4M5cd7vYh^|^ZET?$MGzUHtQN)av93O6Ss#k6 zyYC`>?iw8`7bLZs2Ej8B4dtt!IL1eke1xbr+_at^6{1L#b#IeZtXT!S0ay{LD+iTNK|~gzaxFSucF;^22C%!p z_>pPbh|;n?wBe_QYJZ5QH`s;~%($|XcRO4Qmh~YP;WvaDm}dM`b>+bh+~qcW#B6nF z_~@g6p$Z84ys&5mFo?)(U=YDOl_eD-o>Iy$4X=>He;Y*C^W|*=SD-GVxI*yN0oofF zM65ewL~HHY$NyqQ)a|IYPNRZH1!u}mke6A}3I(Wa7Mjj|jBFehetf=T z{>h;Ob_L^At6!K5Jck~5Vd60% zY;m4L=VgAmm;D2RY_P@xBLfy8TI0nT}Umnjae{nl*$}U||{YT8Zp_-?0Mo(9- zTz~YLVFhQi>iIBET>ba!x4#BVzG8s`44#RJ;^?V6jUO(WDsSrBeCFlKS>ze}q;cVy zm!5Z8BL1lD$Xfb#t5m~&ugcE)1WF)pW$f?49Ha2NO{tTA=1jlZ?LXmvv_BN~!u3-` z`Xk$khJ_dGsk9#TbV6>~pw+ioX^ivxo7ODD--#!7r~XW<{f}{3Wu^1-xQx_2E6OJh zXP=ae%g%#wS=B$sWzWI54EcF%d0gi4&v99uWL#G9Ka9)Z7bXe+J}zU#y6C0;J1^QR z5s2`|1iX2SA>c(@{+$>3=(y`&VQKXf|0^%DdHqnoCVOcrPge0i^P6)a z>q>ahjjUCyfX<8m;6=887fJmWUX-fYZ_>g4H(qpAA`q203IGDq5C1Q`$fpDYLfOYL zN{BUef86>jzJD$PB&qWq+qmX#`fxc;K_%8`Lj15VdHNU`*L>-PTtDtOAHVi zn#Ktoq|Xdm+aERlhd_k4ZU|gE(`iAl|01$@WH&DgIktYT$?7Ogrptm{%ObNvm)g-5k9$M5?RJf_0|L?O(_mrN_ERr-eyn4_H0Q=- zhO7&*Xstvb;>gmoHC=QcR)dgH{>D!;L64RNBKemw1*uo6j#(6NHM@vDu9F!Gy8`Cm z;`W_GaCvXkA&}nn>3Fo(< z>-X)I{7;+0NufUNxb^dg9=)=)n>2m3anv7qtHf7ZC#;G@XFwJ1QQ;=^N(=#ZR$grk zZV*dj%U83NWR(%yQ?9BGuN(MJylCXw4+uh|ohnV@vogK_Nc6UfEti}CS9?iJqVw4b zOM`#fBk^tcQ9g2_51|~JLP(xrxU8}4A`oTicD%|Somw6Y;VWkEuz@N$xn$inV-xdx zPpN@vn2B0Y>aKF0!aY#D_<3Gq%bnneLS2=EmIIpk`zuoi8}YFp+fZvl&nfb#8D>Hn z5sb@p4TEG{-P=hgYCBgMn&nV?)6#r|(7&1>a6MN0$|-U2`}Z+cA(kA{BKO$1w{$Cr z0cR1gtK^2c$j$!2a{1*jZQT{Qp4nP*m5X88=4LsYMk@hB<4Ly)HoA(nk6m}d+3oa^kyI1S#tMRz{2E49aotTp+JeN$Bn zocCML{O|&CZ242=PO8;px|g@q3K~s6=pWY5n5EkB{2+LRFA)=u+DNeu!uX#at=8!> za$87#TJi=ee^<24Zd6yG)hS0(jL+DM=Se|Fgm4LGQ2E zz2fRuyG!L-GuNaBDm#$h(AG4bO<&pNnyn^IJH37B;E1e)SWBUSjBMV;mTwhaV*b_l zbn0`QQY~tu3gQw?o22=Pf z(91LIYcK8o8xmz1s_PXd(xut&(yy*GpG0}Rc4(dXYMi|7=jis%HktFUp>nS&CO=ks zXf#lJs~pPlNwLAG-F%)L#Wu$SR@Q`eHfLu&MDLE&D%|Y@wXie}Y`UDTg3OVg_FbVY zsHUMU^9?l2rE<3O61xmM7m@-e^VU++mNNb6Y)$;W=@_+85-x71Q?Zn=Z=V$Q1cPJv zF`2PS^^P#topx-lh_6pzSlkPw2;UXemMJ!k)( zkz)~*Z0kpjeZsv}Sh~$Q1pyei^*Ri^`xS4RB9$MA${U^S3fHaW-!oCuBt%wSwfWJ8 zOlN2hZ;~Th8tymaglg8~{>lDs)gK-&!6C^Ihbi976?yE9ZFi1%(j$AD#5r~MN>|;+g5TR>K zpCUK+I#g#n8yM%4@=G+T-XVdpleu2(^!7a7nI)P#+g2#`BR}G!A?l&;cU-DJwCHWM zg9cR!6T9KDfuZ|7iiDQ3F!;JFN=BWXxItUS7#=VI9Ww@XBk9SF}Zo6B62QqI++wO6q#Rj%MZ+VA7%#79>3eCeytgk~`}7Ff zAL67RnzrYQ+nLV-jZD*kp~DO9?Mg=zEpXt)Yx`DBqrtQ{VqXE_C_O_x=h*OpjNeqf z*?WT0o~|WR`722S8romBnbxh2CS^C6a#8K9D@Q88xD4xIzdSCx5hN;6m*0z|r!dgh zxd}|YggEPj_^bp`O+w1sgtxFnww^2a@GHSYLaGEpvB#Be!jc2=y6_*%vPJSb!uj;aEPIt3o6kUw7}}&8 zWMRFmvGbN$;00YtL_B-q8_BYLu3L)_Gqi|;kYC)tbUrPWQ(QUTnJYUsgDh|#eq>5mUuXiO8y*o1* zZHP$oZ0`mlHiiuE4uQKf1Fu`HyB|%oSMbcvig5zyf`V~c<3#5n8t5q}Y75R~U>bPq zoIvzhgdeThux;5P%Iz`(RiI%a;^!OcDZ%07@*~@nlJh}JB_0+{b=~%DhXfW8BYycA zPEiO+0@&MFIGu`YrKX&1DhS`>XMqfNA)+I)>F&i2NHfeLweW13=`4|O&cUN+8qO18 z%>0ktul4KBL>-u+2JqldxcFO1B4&|i*mUYT!!*p@629CdTAUyl#E&QIq}s7b5y~tTaF&YQ&^X{(LJ45$|wVy zvTSA<$VT@HcJyl%WK&^`8?F%)j6rGnL8N!3cpbD0?!*TvjeVprg4g%(iJag4)Xlh*Db;})nvN?AI<9&(__u!+2u z3RG(areUV+!aQz~fnmH0^pn(qWLoH3_{`YW+ZS{mW3EF`!94EA5Oy#CihL((hVoAy zF^^ex`uiES=*%;*l4rFkknF%0_ny47h4JwH5Si{wOxw)aRvYhDE=E8^vzLIGTpjmq z6KszNy9lY?W@R$LCzgrMuz*R#E$bCn&2uGIhL<+}8v`4{gfVpJ-Vk^gv!X@s$n-5h znY_<1P)xdi(?#B#1uTk=+hFM14m2VGF_rILK-@bhQksV#WypxYi>ABQ;-bm0(D3NKZ$JUKH(VG4&e<`lAxsdpoTZf;NUQdAtS#H6VQW|Dl&s;j>K=M0SyJ=%x89b!`$ZR680nMz0S*lze0m`ozef zPT2bqcuuHeE(adSwRaJ21R~obKzLZVg_|{PnifMfq(&zztroL-8UbLOGBOer_8rOa zk}#TVHTa!p=MM3!r{emT0ZtbL_tL`h_!CK;TEc~1tI{xP`EB@(Hn=NP6qAW4oq=6F zxj%w}%%fnWBM2Wv*d8vnmvQrn&~zlJNiSOVHR+ZT(t328;yjr!M#Vi8fa3M-r#u|H zgOL3c_nCq7eTeO1VuwV8X5!I+B%2@HReH3{trZ&Cld90pH48*SjI{RrWZ4HWb7Nq^ zXpF~`)@VfTTtZmPi0~t1xx^Y=-Ko`iW%w=aiK0n`2XtH|1Qt~U2~Y}b3YKij-X}Kh z*sSpjf~7H}$TSF;l{pCX-b}ef3lz5%=Wpu{`AkRRDI}P?s@fF&S@im#9!2|`l@G@$ z1(O)HNr>i&9$i!?`X{6M>!;|+z zvj}DalK$OJZ62=7LF=Um|A9>8ifeLNcYzu7L!e}F+R{c71z~o4kRt67SdfNs7i@{) zI;c!m*Ywp7!0?;7Ay}$<3BTF}sU=enc zB;jB7K$nVEnP9oWH4)Kp^d6=vz(F7PcY14E>QW&dX+0zo+Q>&@4{ePl`tY@u14F%k zv27BF-60=kSF@DP7U7TRlA={a2ev>6cDCz;3*@0_l!|$;P`WP*>=9A)AJDD;F`q^@CNDcIc==J|05dEgD z@f}(24e{wK=LUsdgL`kF?)1R^6&n(!Jx);kO|g~?%7p$XDWU3tfqXtHkB2HCW}W~7 zQQB}~k>%)-9 z@!KBb2A9XxJ)ReS8Yd1sC#;_M8t}aOzy$HkaQ_SWJ`dscUlR{sOlWDoApYuoa$r>R zko><-%KncMp`z&j-9*R){=nx#K*s+(H`MtM_21=&_{U4Cc6P7+f0r8yBR5;KtQH$O z25d!ZY<4BSSgSml_%1T!m_46y<7`^};zGrdZ(o(Bj_4HXpRoDKpUzBENu7RV_0C;i zn`7zbAF^-Z`vN9UF|M7EuFKZ1&UQSJsA2m;r#HlLbT+2Yn($mdti)%~W+r-(axK*1 zvnWibh;hVV4>vQl;}~V9VoBzPuO1O$rPlWh!qmWCinZV3JMLiBq> zNp2_CoS+t$6!Y@+H%I7faKRdEuMcXoE^@2#1y{UKnV8Uo#%r!6^;dvhjK?n3Ub> z4dNF6760&$o|RRS{!o?D)wjq`dLuthR2{p#0vJU7tP|Rec8_a^kt+VmhhU^Kiy&~bj6%y; zk<8aBu$%8hSyW_gJmuj$)LRwXW2vaV#jfp3Wrm!iKTUF}>=68qdkcdZa&+wEM)mfT zsx6oJ+S zNhW3T|1l|h_c^98u2Wmi--f*?On{rr4#s#39B>0~VFuJm^cv$=Kft66rbmUU&n;&D zLZnMhm8oS0xvVkN!XAm8PM6=|pdlaPio~$m&RNWGjJ>^>tn%9mh;q-RZM_F)V8!1eLFkQ=>_Q1^_DqGC# zTxDF8<7U}TI4FQZr(MBYmxg`7cNyy2bME?zD$RUBPs&96$=D`smEAlCoNDc6gS(T2 zQz9L0-Jxto=6SjEy)b>lMsUw6ST;W~U8!7@fjUAf+7>|6xSw9=XI8Beyis61Ub#-`UG}XRnshEpRZ5d1&bxodt|0Do3>%;xvCqGpiSsYf~_N zV*{mA<6*?Ey-(8cl9JDdDz*}j1z#H(EGvX<)Q^D; z@z=2+g@6f6DL-?)Ny)b5@{rVp1M%r#8P#smD&kO3Q2BhmlYaD};gTz(SB-z|-z;_M zv8N3{QG5dh0hvSX)Q<3X!jV7lxbm{zY710^f=Y##sWQN5O|YsPCm&xvu6U_-{U_r+ zW@y)d*pxLoY|~k<4Zce&GykSTMQZ0xXycv5Q)ub?18h#FwW(j z^Z9N!s4J^gmWubL4l>|tgDr81pPZsA{+ejBEpNm7!qrRY118io?5OMcEi2NGC8=}N zkDh$K`(7HsPfaR?+S#rJ$YJT(Z(V!KVhCcKWN;0q9Fs>_sL$1|YErl_? zlPCpW2X%kr++Ebg2ZO21nC+ze4UEw=Uz?5;t-mT_8zgWjeaZ=|tYa>Xp6Y1-oY|c7 zZO~?^n{p&3<+3fp$Wj*k&qyxwi3#OF`RVW+x(n2Ctawg-)Piq$lX<~*=W`2;IKPuBekZD43JyJ{U9(Z z2}(I1>!@o*du(&jSMi!S!}LfI=1BdIiI!Pux#&pP)-Q<}lJXFijZ2`f3k98P{Y;*~ zgpx+!QsBlXUQ7h2IVuxeoGGliS(ocj<$Qe#yn>7}ieACZrSyh<(#-Zc^#_`@)XOoP z=-(InSG#h%awa906ca@J@S^$*+{9t1S7l`z{|5vM#*XQP2sl+Y&+K+ zjVo6T87h1d{<<|WgTmCNjKiu8uSI~<^jUukSOFUoQAtSH%X}Hr_XIQ%u>@Y2r;Fy<@*Zem!cCIlP<-q z{D4Wg;da0*&sr^wyYAOiVaA5d@GkZ#(?Wg{q`g=IE(fKB>QizQpsfN2oA#sAC=#-KCg(OUyju zcf{&;blIPNEmU+U1di8%9}q>tG#wt4@J8O=xZ(=A} zSmH%ie6KgKGO~H=raEBxkX`ohe|bc9OGAWTkd3R@+xvN&XPw~TR5YqKeK5q#YW}Xg5p`A)$ygkUT@O)lC;Gcd?+{j+t zBi)JKA!3f=H~0{RpfhII2Igg5PI)~k8^Lr=gfzcl@5x7g?8y;j$6OboTPZRpW?iEM zcza*`42M|H+4yk^Ej>&1qa&sh^V_nIwP#~uS)qZJpvq%9euDyzm4R*9?{7!bhMk@f z5i?beK73TG2;Hev7~P%053~0dVdohI`O}tqvBYZ(!UsCOpvUy&c~o>QERwk;)jxf) z7A+tneMGU|WaPq9@jZ6g01-KT*HeotvF_I0c}`{a2HW`FF(%{Q*P6H};2b!f0Fbq?4sMAkI@5%S<>l_6ItdtrDf)ik5g{vK zr7Un!2nE!hOt9k;D>UhAOCe=|*AwdmkAYwVZl8#^!L&e76Sof~vIvi|H-g_qfDUnp zr+F11D2=*KA$+YgOdG=O6T#lhxF(4)h1-j4^f0YdlvKwVgS zS|%5~Vbsm1Q>uiVcj<+zR$=62D%QT;ca4rb_BsP}l=7)NU%k`dClc3lWsWk>zR5Yu z5}}@RoisX3a+$#$7uE$aWD1T)Qe^xasNMp)%s%cZZ$?Cl(8>0@#U^vC%p{7<;{oR( z4V*Z#$mBqk7g(qAVsiiptQ29IsNUE3`?{v~wKC9gOh5WU-x# zo6Sr+4wHr|prRyPh=EFFU^ZG2o`V&WxP~^Rw7{34Q)s*N>*&<@!wi`k2BsO@E(7k6 z2y=^vE)^s96P**{?O$8Ka)^xZuS%ZjNUSEZ{Rv7+0sECk$Yw}w5aK=yPx&6V{3XVO zQkl5`QHs`rTy?l)VTO!nA)^F{-8{H6Z{2*ImoJNYMTEy*3o3YvKmDG#UMwvwz_w1} zeh8r&Lzug3)_}OwVEbRz2pNP2Lk+B=sJ}8v zrc;KQOev}WcTURkrI6OOBtm#nBjV&~_*fbt_GO$>WB>| z@B?JjqX#fYD%@88(qm3IoeX<`MBS(09ttI%PZt9>P;v4VP-B)c5!jq*C#$7u66!~> zl|p1B6|t`yX3v2$_=p6iOgkUvJA?x%>PwffeLRI+%XfJ5SjyK-v0dA8JiM}M&K|XIW5)Vkx(HdOSU%G`ZmeR2;wO;tg0_-pZWdXweEOS6d0BfNyU{N5Fl5r(+7HHA4@etV5W^-HzJLcC_oG; zAtX3zswsX-x|oMDIxK&f!Y*BR{^Kn8+PuR9Y{kg1@%>sYss)wg`a=48U=a14x>1yY z|0b4(Fr}i3dSrx}&*fLXpp-zR5cv!MJ5kmhia9)+HB0@w9nae}3FU)N%UX~#$=6!u zC`3EH%u#x88gm7>W_IUPr^d9Ut*G-uT2C6Q^LR!DTnd>OCo>AxX1o^CPs(p7##mDw z2E-{o&S~vGco9t?;YIh{fPT2oNTc1V}dBio>b$VLOJI#ch`dG*Y?*4g^$Gg+S4=lo$wt--_RvA~8i+vzR zLjUCM{0?{#i!e_%IB%@|fs3bzI%$SDS`Q_zZ2E0yJS~MhG^Vz zxlf%zG(FJw-MyDhMCAw&pEV6tu01X~J$Mw{Xe2*#5YPjjZ5Pu znp#Jb-6uRe$VDIJdsmNqtQ;R1n)q%!0n>V69{5}}_{ECWiQtA8t2A*h4oDI^ZSC4p1ybOFna`{iYv;VKusF))2x#%WV)i&kV&$)%Nn2YwwuWDt| zzv#XZ9CKNli_ICWb@qBR`)y;#zgl@foMG z{YHIjyFJ704o%%H{VVgc+MVckKcR}JuS_&Y&D_md7jAmdYMWUpJD}eDibGHw@QC97 zTaPGZ{Mv=TJ)({;Q3kUcED_rLLoZjx$qH=Lbxd38kNjb3neP)-M7-9cjQkoE7# zVowgm7EmLL^NQy-+^^m1rT0_c^?VkUt^7LsYvss5nyr;nf&JUW5pn_D-XJXB%P@~+P5zSk zW{qW!=%6oJ?+WD`*queAv@u4#{v}{{_PYY?&i?j@O1gCl0&e`fM+E6E_58QpnbPF& zLyG@OaN0g7Vtn=O#pnBXtX-6!;jX%#FPlq=Q2y8M%nt0%e4Icwn?IFHMwnInaqGu_ zctmAmT73fG5qbQFM?~nxH5<9#mG&4u-}7h9g5+S?vPbl5s@3l36G^1HqpSnB|Ls#d zpb!!4=Y3Fzzuxnpah3I4)AXR#@3BKejd_^w zW$Pz6-p+4!{H+jG9{&FJ6re^^j+GqwWc?V%^fO?$ZTPY%iBvbFe-aVV`RkdL2+e>= z^e!$`5+XwEsKlT{c_30vHEl3WI4aDv8#{4Be7Zwpkvg_kT!hRMhnQWwv}Ns^O5A#V zDRdzD-1jSdssSYp-BC5EP%DBNxK6UBM*@|W_zVtZk-gHi{?%?_BM1>y{YQu>mbva- zHqxS3#6gIe4%}B#I zmUmc9%~_O@!vEf#ku=6Cbk*mXaMBxpnqkQ`d^ULB%v#B~0M1i6%h5NN%H1TX;4opD z!z_?i;-VSK?W$L31pDW*Yi9QdE*&?F;jj?KTe5M!g)$7b*Ed zmXo%F89JahSgAn(($$jFW%7!x;B=W42wL~H$zTE)R`2Ne1e>~J<8vpMl_F)`jJM1z zOZJ$jemRYFW-kbAOM!c3P{qGa!+palA2%F~Q~VjaQQxF3OS+Gbadd^PpG_ES%LdW$ z9K^zv*%k43Y0KoQgrDgg8%(ND?lK7g1ti5=7c%4C1;t2V{6e*emOeT_>f!`O3eQi< zgsRI&w>#X6lXdog{e#CvxcY(3}|7D{<^j5#dhFQ4&Aj88TF%6Y0R-tdQSWZ``%8IQ&wqIy?Xlm&+f%fhM+@?G8#Js&dToGnOZ~eCBODk|A|~uL?qJ_(VJkb;>)X9r+ruBMH##DP(&HXWWC>hYA6#lA>FSrAN;N5FFw@zusOWO1 zeV2>_cUJo-KyKc+;9-kaVHe39qz`6qkn1fWaZb13#;wJTDDAt-7;llIuG68%cK3bH z-Osi*x$^#f@}poJU1X|wK5gn&Zk0v~1!Xlccc&ofGTwQS4ZSKrx%N*Dmkef@7HVR1 zwWpO@85uX~9_BKHQda{r+fBcaBG1CTNr)wb>iA(Qd>taW`*Y3J)$Abba=Tj4OiA{7 z?0+?0v6aG+?au1+8cV;tdO=lk#cZQrdR|~RdxeQqZob7SgWZJvkQTimd^T)tw*UcM^TESDdprqlq*r0hF_y&4m!T;F6nyQV>G zvQCpAsM$~chf*|G-qV!LDNM9+M9+)>-;6Kgw-|7V`sn+srCl-Y9ZwW%l(ldL+^j^- zcxlvyRGR1Y;FQG>!;jpQrS!XIgz(6xXg_~xeV@7SrS(%vfqJb^Gc>V{+P;02ko0p` zAsOq&LO!M5u&iJZ->$;X3FYkCG!1TPyyfE`6CJB=A}T0}_C4DkhR3j;V&s)$GP4rV zHxus_Ng&c=Z{n~>Qm%f5ba?fYumQf36O2QKMfy<@A1)?y9%JPFlIQ(me8Z3Okl1_% zoB(D^0@N>hbh_hup0|V}9VI!)G|4Rz^&`pfc#cN_8PjunTN5Q&c`@OhFvct^r4@p5 zba8YNpo5e?> zK{0m82D|j9M_Md6&P14R#BXhs+%Vf>sr8CSs9+rYwGpYhxNmy~rVT(OK6t2S*7R<> z!bAuXs0;?KMUVZ1DcPf4)h4vG=`2l?;}WqhTxy^QwvUKD>ldMvi4mUg?%x~q8-}*I z;O9(5y36m1%OEC#q4518j7k=FeNxyTeloomwmQ&d?p!Qz3D!kvf{rv;mX))K zp-|C*=!uKUA)`l}5yU;Ik%` z35kMT&o=?!iSdi8NJe1p0mF-O_G2}yo$nhgqkN>8$c3Q3tUWhxfXas87R2llEwxA% z{a23T0ZG{jQ%gM1QsE7XKWrkxjS=Z#1*@l;;#5>z+VxR$$Q&}N|J~{S2vnXxZ*GX< zaS>-=xTEHE_)!u19yft6$oTxNM)wY;jG1vEbmtBVj3+uz_$on3bczgzcuxEPRb02z zqo=C5-D!M@i*RGX-}b4+3&wEzs*#QB4>k@;US&0I`A5lLsjkHagRi0C=;k@02A zD3&h6fq=i-sv|;~8VkZMO@eZg;ief}0^{JPjrQK6a3%!x;m0NX3Z()}-3yu)AKL2{r#mP+wyqtY6cs1vi4)F48) z2;oF`qusDK@#A}n9RNWJ_#SLN>KY()Jjy@o`sev2MW*tQRuc!UzVv^w_ufxU@BQ9x zfb>r97<$JbD5#V`Xd+-l1Vq%(K~X~$DH^IYAqXgnXecV8Vh{_6XlR0h5Q+){8j6Zb zbOl63MLD0~T6^#NzW09io^#G~=FFM%2Qb4A$xOc2_j+G1irBTvV@gxFS8LIJT z`zVzmJjQ*@$952L1zw>*G)K0+j50fz`$`;8w#AW*k}-^n5^Cw_3r zFG*zNti);;joYHM z^!T7L+;m$%rd;t@f5$F06I*&uvBg6Tkh5lH&GOZjmw%8ZG_Z--0l%dIFmbkOLG815 z?^oj#sqU5z0||>2>qxCCt@>V14X=-OcIbD=8uDz_@LhA)dE6wQV9gaL7|MIB5G1cD z!ml>zuE@vOfhRyZigk*t=7_bO9sFZ!e#oe1N{ za%-Obf$cs06A@2C5q3UvoO^Lwr1#3m^VSdICwKKca((Llr1MGHkm!xE0r7FzHI=xZ z63=$^-%T0;D#dtvv&yTa@o`Jilwn`rxXjz6@gZf2_q+Pv{d_swJT~t-Fyi~l!cxNF ze@KwZ+n^972*ataq9aERCrY9anU10=X2D9EZUlB@O2R~$It4+_g=E-&L69i=W-+oK#wNk((lXK<~FCQmS58-z;Mkg)9-Ml`I-HCkJURHlg4`IsscG$bp#`|3$Wqnw+$Dl?-9cCXITlvTN?lX_C0_0ukO7%8( zN6AQkIL)pdo4>p7Iu7jKA7xx<6V9BK3TMv1?tRsw8deAF-f#J9=IkVxIkR6s?YO!! zZ634gKg^tAz|5JH>zW*$t0e{F1B(-7oFqfxr{TE#~4Rf8@Sw|MUeAB)_dUa+il?t@=q7>EdpT za@e2X2rXUu_4)I^q$l^4|B%h~sIQtDd4H$ZZDBzx4-lmKYh5^J#73S-)@o#V;tE0H z!}OwC(7R}CG3CXLsQ4DNx16XvMZ6)Jcwoglk`a1G{*N;a9ubR}01{J@f$ zggI4AFGYEFM%{2zDqiRv&3eB^?|6;3#)`zfok|gXPtS63u`MYj!t{c{c}oxQjyS?m z_+?{Spju%JN9o(JS(<&s6n?A=6G*=W|Z)Cvq^tK{4=n<2AIq;nk3Qk9dY*ckM-miZ)2iFc& zEu*nhH!6!~Uva)w!@f`xYQ1lZCo=_4Bb}GYqaQnbw)RN!dW2J=~g7 zp0+xE0vX9k)08XMd7yCTde`eKk$%ZJZue|1qVJ_h28uWC53V;s8N;kIwCW={Z6JUn z`sYwq#wM@=_etr4$ENO=pYPtODJ7>$J;bD&nxd*(>UP-HOgtdOMoHR+(&d`y$PgK` z#-px+h~iTE9+Fz^pi+vSN8=NTk0PpKf&P1L8^iU6i5OZ5Ra;IqJN~xWO>NJEp?(E9 z>zza}-U2@bwAfC5A{EF+$STgv@gtcPcf{LU!DA{~Mm??tZM7!y^JTOVJvqf~INhpt zrgM-}ydoP(>|MKFCmFLYP*lZe{eV>Iw`RSIH3o@w$5z+(Eh7_Io!*k@l2n7%^6)|3 zwZoS{3CK^p7-_$|u!pXpc=vh@fLqmB_l<_9k2Wd?+Jx6Bo(3_n8d_^m(qe`SrL`v1 z$|RfmVYk=9B#y=@mnmXl5^u74GbTE1P9zib-eZ*KknQW`yV9)ViW<|venvz&dM8xz z5xB2X%VSYiW0S?_ycO+Wr{Sqg$?_3ur-J*FjjIhNC9ZNhs=X{QzK|)|`tbvfqbiE+=& z3`0Ldd=l>p>223FD~9Src^{khN@7@fL1_+MNnK9w=-tN!{g{AN_o`|j8OkZ zDeM5osDeUi{1}Rq5JxDdbqo}Dqy4JRPS85g-2#D1lR{xy)vehIA;$nV zVjV^xOy?jw&)*EmrxBkfxY#m=CnEq}NQ3m@R#<;5SsB`I*UwDj0 z0<4$8%DN)~{ttCe>=x@L(m% z4H6&~0kVSHf5z>)ItZbd@_Te$b|4ktvT8bFQUzEHZ+V*zWDA$Mh2P-EJ-%heu(ME^~#FsOEvhTZ!~+iNT6H|@?v!RQba7jozc%E$dPCWl3-v3CGyBz{wf z>PP>?q}Q^pc{$6PlIF>O?cav&D|3_fqU1$>SdgtOtrFm2X!aIqglub2xzfm z9)N)}4!GIGl+%$>0+<`oimXL_l?v}C7KbS)30iQQ z6y501yff#CMSJ;CZV_yB9{?>NAkD^h^W+@@c4;wr`8)pq9s2oQ^d;&9i%k+DY z)DuW-x*|8JPOS?9lY&f)^N^0t=nHqTzBNPT~sz6ip)P0OKmTQuKg z55PpE6nRAx%~mlTK$b)#6j_Z$dTRZtcrgyVR}Xm#BAZ3ITbOO{7JxcntOzd2+!<}e z0i2aC@i4GC4V5G?WAFm$Rlk_`+QHO4 zaqWq{-R|zTOb8^z_o2R@2#@PHuv3__W}fZ2JTE)W6kWu02+P|<=!RtMo8NK~QTGK_ zHN^ulf3^Fj2pSvH_i8~UC#th8B5sr<3gt=(u1d+$h4*NzHoRfQ{k#6=k>p3BWn3v& zVbIzrvh0tgcyKYfiuvFPRzlTPJdQ@vuxn9R#wiR1z(qf_t^R$F#>!g~uNZ05=%2!= z@_PE}gvWWpj}h=v{ybnTGpxzd6UH4m!hixy&g4I=uO?9%~p;$^JH4gG|KsueE8 zlnsBfDo^q+E(9|qCXRKA@9#a#GK--+QU7fg@z$#y!B=LA!{=P*sEoF*T12FXE(W&#tzWy5+lKTyYKJjy~4`%=vYW^DxA^!qHlZi9Y z+x`Ya2LC-6YX1*l2T2=Y+ap(>BPG^ppRyRmKXbqV z{jSQrA~nxK>YFM?uY#kNZGSv+Du`YAD{Sv&W>#UZ1^!(@j!rdeImOvN)?6>FwCMif z_c@7mQ!Mgrc8ZIlRQU+5=7`$ny*KV>P35h_8%J(Zkbaj%svZ90%==pGIrV%Y6Oyg( zKAE8Rn+X*zsbTe3n9xXM(}(8IznRcY2XaN4f49a86PiA^ul5Fdg$aG0tI@CY@aCOZ z+*|tRLxs|nTeS8Ja(UW`&EZf#>P#!jWHwTmw9ce{xWAL9VGtR95Y()}Et=)>SX7_# z=#O1yzlx^&cH{J~l+?@)2N0~bKceP)EcE1zuXoi>?6u(ggEO>Yc}q>+e0%B^v!MlB zw0hR;MCYo!@Og~Mxw(=vy+3-4m6msJ~!2C(Ka;EF76&(o-X6rlV|_cEAh{t(k}uc(j>w-^Bn(OsSW>z zgQE8LqvN#*YvY`3>}014flu@o4I;8daG4a?vtBecE|t76cPjVrTcuyz&X(Tfd<&1X zRoUN^BHXkI+vqkZZ@%c_J#CndIT++B8HZfpLiMha6Q=`GB#~S3wzu+~gzf5OB#2kj zK)iYe{_6e|E}k((pwcEFO(270K7sahYExX~A?!&h;whvwl|PtpV_$K!hYK56HEE_r zM#?fSL?vq5@v8N93^i=8*_*96Gi*7=dr?KUmITwSn!x9j*l8O@pqxBf3ktiS>hdC) zX3@#0WU2Gg*GbrfqN!sx-_IB;v?3GlU5cxzKV~`re)Q;oDrSSN0&)ULGp_*mW*Rz1 z;@NI#lM-c2JFP!XW^PE#XNu-dh#xT~m>bpE%+Q4r5q|rvtE*qJ9M|?T(ne7Os6auR zmVpS$!5f?g(b5fr>w0~MTV-yPr0Y4?v<^q=V|3m}HP4eX?JBK&=xQVn z?HTA`aW>0Za8>>H71~xg@d|a7B)Jr`>l6Kc53+h;*yvj{$w{J%sBW@Llw@NffrR!Uu-3y+@RK;q(+jXcs z`_8pwl+kP8Us3?!IZ%G_a)7dwsO|Z?>IxH>Drr&OOb0hn>DeMZ53?&Hy;d&UaU@VU*p*a!|JH!3g zoQkWz?UX7Be*{zGrYx(RFRG*CZ)B#OagD2$Yn8pxnPx^Gl8UyBOwO?gy;mbDca&`_ zeH{YZ013M5T^9h7){W^|0V;)*Oaz=Bq#aWa(zTNGFCjOmP%9%j)}Y zve)Y=mt+s8*QF=S&`DIePD-3nw&mEN6j8L;QY-O0S*HC)WnMNp6Dhkb%laV^eY7D> zuYGC1cf%FA)@5*oM%#_ub9Q}m1I1phinm4ko}coZTk*=q8M{{T`(hjB5)w%(8tQ`n z32ROD%e`QxEdQsHc|?>SJSnyX71oup@!SXbs%uwB`tQ#yEHI$b7ir>b$gS#r{hU3f zyI$)YYa*x3eds;&9Oour$X!*fjr;Mz7-r*`W;rEa(LbXIjCH9l1k6|`Me4!H4Muc7 z?8S{g=bI_<5j#Y3&B$`-J(&+JD#BYfoM|P^lJKFE{XG~2O8FzZO&k)MzS`7Q>UQ-H z=C=EhFFTW7v!7W;CfFeGQ;evm!Kcjy5#Liv96A>TogTx+i?Fo?cz0%)mw0(LfA9U; zTFSR&V*~477xQ0Lrr|H^9hrmcdu&D1nHkZt**9I}G@5)q0x&ck|7w9l2zqYm%|u>g z$KFL?4?a(bbUd`WGxj#~Q2ZfWlJ;MxXajU16&g5YGw_^H)oHgxLM}N(9p&%Ce%*SN zZ}i6TNDBjt`I>}qfO}8FX6kWYzqrhDEaK_JHLqnAZXVs3Ot88k$L2?X#B@9p-T0j8 z3d3;O%w{hvm!C!}##GWMYh@8vZu65r?q%Sw{}1W9sQBLrvIjGBlG&2&$*WtawC%-yYF2k3f}DdrJwbFWec#ihX-= z2ZxDqMqnRs+)gigaQK)6&H+OQ^q*QGM?lq@uCGz0xH-~#%{=_E7R8;1e4}|derAL;|34z5=?R7V`oV@5!3pJmTk#?x<)B_lXOBR1Nzg>DH`JLDVH4+vYSobL59J? zcpB@UQ~R03FT|7=^V>SPd!W03}NI~!6Y%y+!f>rv6b$gtqY!Gw784-q~1GptV(gm`ua4q~cJ7?ZI z{5A`dz;hj`ghr6?KNsbJKE&V?QkLHu(qoJYop7ldOgAoq%SYoLv8vW#8hOWG23S?I zve!SCMH}O4=%{i!8Wg3PKzNFajK4_P#X{X@L`P2w-*;#0)ccbDAki1of9WL@&)GBEJ?V z+TOq)WF1OrhsN;TQZ|)nyaADKB4`*PT1HY_xd0+K-GJc4t3%=s1@fP{jDbMU2iHzBhj$XdGJ zkpZ7(Iy7bN+5Hss0|*9l`8Z7z)4;+U=4@OV3QmHAT!AS~vI(dNcrFt;I#M>O3vTkz zA;qivrO>uC%HAqy5DOe90bMOTFbq?}!88Ko$`0MOu!SLzfBH4t0UV^wi4{YTVtY%o z1&D_foo7-yKq|=-IG$Kb1sY2;2a__watYe~fQe3^IGwlv^JPHyvy@~Xm0)a;IS}NF zM`dG=kk4tZbFA|P1156}lr7omZ5Ygx1d9f#BPQknIq;9=_MEF6Og$~Vf`JI2#csDd z?+iiIY|s3uV>HGko?;=HbmT2vB$I{xNJ)}#zi_m|XMv5T(d;KBot#OV6L`oHP|*el zX{=)^w@^m~@YG_LS7P9{5aBgHS@DKywA!HXN^C?kGm2p0C!#TPM+?kee zy(sD2Wmp&=9!o(aQV^iw97KY75Scj7gmWXPFKnOh-x5CxE=&1AZGi%pVw%Ypw_*li z3;jkRNO!KEH`yvB2IfYg)``LHQ=>3Vw!fmG`&d}1>C#9o{HF}@^{M#hXRZwgtxjwq zbWjj>G^c$-bZ9$e&EAdI12?*Hee;&-*imA@*9{8qISTU0*w1>F@7TD{Xv<+^!g~@n z8e-F=?u|oRr4-o$Io*K)&m>`cS=cVNTx7;7P_LF#-ML0r<|WhFb&X{Y$;TVA(UIa5 zmPT0}2n8%Dh>ZX{RbV3RF_@(XQ&1$8pnVa5)OJ%ON+GuMgSUL6!p^m0tM~{|Y4W8x zIa6R>MEJ2GWD5iLg=pQyzU6ZTYdFw2pz8_1&}2jv>$WyQop7TA7ngv2#J~>FaMvFZ z=12tVC_IpmdKlQpBrHM=)5RtvcbgrF($q4}*z!*Gyi|bCJNyn4!YpN7M$6iVE!Ykw zwhw}10-tA@BvQ>F8&sYG@=(l0oXL94-UXBNw;CVGIDobCNMaHZA`qVFYmVJ#0EQTO z*-bu4EvL;n;!u*%5Q=3symog4RLJt?wf9XXKdwNDsv`O}ib`}`$|d8Nv^D!$wp~@= zqEk(e@Wthplt2#1hkK7H8eQojAI3D6JZo%bgM=_297t|K@i9Lcq;P+YK_>ht2bIke z+gFDmnU}GvPCey|I0H7MD!!gc5Ytq9$!-$kA&QE?ha9jW8yUx=zeq5B3&r{Z?kP$e zVE`=S;YItwO&R+nO+Jfcu0D3};{4ifKE!>glT;v@)KZsZvk%}Q2KCb8WsEGiIA!gH2StJq&6#eC9CH*)f>Iz^Y{@QmFJ=O>NFwA{ zbiYhCHRH>KVIkTy+>@HV!D*G$%1)a}vnr+pPeg*GDvAc$5I1vU_1%{)3a9+VCTF`R z6qRMmh#5>9Blo-bU0uHzC^+_sl_dR(LA_^5uw*mvJCUd!0`u@?p+<9}cW3vI@qmW>YY z8t-TxZ$s~Y^wM(hVVU^k^*TT!wm=U?#9 zg}Kc-)oIH&Hvc0Yq8T-n_~)+rXFMc-B1`Fijfai`JY@7Qc&I9kT#-5XH~^;G+GqA3 z@X#%QhsqcI{|OJJ0X!s%(TDw~c&O)^**n1)ZiAKBczv(@F>rLI`K{io?XjL`?}m?H zDGA`AfP9Zn4ckfvSC@jLv)_1VBxj%ZLYE0)T_0D%SuJg50zo>R>F;9tzP*yL;a&7H zHTpg{I&*ONsq}0utEN}7&!l|F4=(MDjYt!Brn$9?JIB>!kQ(Tqi=BO|=k>FXfvHf*Jzd0*-L4~%GbVwK*yzV%gA zeo#rz6-ESh&SWO?_gKkz#T|r!34~-9i`Y8sz@_mRcKb{l~2G2l-wI6 z;cpec6XCK*Co3aw5btGBS1D}Gas%6DpcSN{U6AFdmqG|@NRhnBOt;>|g>NMsE9wJX%Cln7u)%6NcUL1c}PM1&? zLLZOxsBC0)7&)o-Y;LbD?*S`jQk6Do*{OL0-d!4tTjjp3f3Fb4u$6sy2&R{*Dt@ZO zPJKf%+PBAFh7+glUVO$QZr%2>8^{i=?;J|fcN*bS<`&8)b^MAf6e=NQP3^S6ieSa> z*~)9RcsjB{FMBxD@%115jYo=VWi``vAmZ=|c_Ie5@Mzr$lq@w{bq1g0 zp(CcDHIeDU^)GV^stGpf-cdCvDpN^JlWh%wQT-?6=XrXcMgJWSdEUWCFMFqAeAp?f zw|Fo|mvxfouK_$1|9tYrQ)$i&^}zTHOl>+jFW@QO??C}^8}?-UB zNjE%mcc}No*L$Ug*Y#&8>29%qB3oFF2bYFVm4Jfv5B)P{Z|1OODm;v1HI=ryAZH5y zyaBOJ;IJh)Lq9qn?H)(9@ZE5R2)v9G&Tb2{QRlzs*)@^?UZp`2p z3^y)PpgUq!^9qOC3lL>|+rjP9_Zg|u(FriEG=ENd$72R#V=XG;(%>Z|(HJqbk|H)6a;Y{G4PIN1NA5K*muZB^gQ>0*DKKp`esX$@Dn*4AB>bTd==}Ce^+&nQ@ zH9yqhlyW>MSTB{}&2?I0-&Jq^=hFA-X;SmwHaX5vl@_Fh z1#4E6#-Bz(Ghwo4nQ(^^7k(qno{U$)29U?!buO-JTaW&OM&@CtMCgdo$J3QUJQU!w zzQ`Od`_&XzjD%J1`sKE>YH9kQ<6+~BIgD4;;mfb^9ibZ^rETmIE7is-wIEx~2IDe9 zwmCa)xLRiq)tkT-f&0^@hUNO{2K^{;pRQgA;+1Vu9c zaOP&a$xOsriLOn$96!k#xj)DKtgwx31RvVow^-Oz8}iiC{b$x4)wd#t2uUY9> zLsq>fOK%kRiWvCa653bk&{c3)BrBoKYd0vbw2}@u-pX=K2bH%F*?3ki-IQQA%RTt3B5cD2K;)WvlCOf~HRHCW0+{sC` z>PguPGrPUm$R;i`Tsu2V%bm%E@&{oKbma5Fy=meEAtVwcf3pBj3;!RaGmd}wlJOd)x7MrPFRbRuJ!Pk6@wix>ET zFPe&4n3LXCUJO(-CyjWz=#3`kJ_NZc#LAb5yBwOAR8AZh=v6Y&eN6mEZl3!jew+tC zU756xmt&ZfQmBooV8DFol;d#Zck-@*H0ec}76|Snt=L0Hx#*fmy^$b{GjG?9Xhbs! zGp3X67=#I>XHT`kzSkeUvQ{gJMJy&F1AcQNHrmQj7paR_JMFNG4b9?4e(gGTRe*`0 zz%F!z*+S5@ow=8jGhuazY$mvY5}ua{@6vc!t1vxZ6z<^6?%6xYW2Z}uybd%|5H$Yo zqhH`Lo=V^e>|G`i;2Ize0Z25y37NJ`L|<0d9hyc9W+(tk=CF@lWt{9>ySs^m&;kn+ zZ?Ink`2$k6X)NMN67t@=(tDS|MH>o7bxq@YTiiMqPsfbt6jZ%I*YhwJ+3@~v!9EP= z4Q~3=Z?YRM5sx#GuSUvV=^`^|sEsBehe%LKyEBdgco`A9Ni+ODGWA(&DCbC!!J2#w9oEaz9;@SYVUlmna!I?~Y@d6bFaNfCzW1jM^SCK>wbQ}A>p zbQd4aWT0Z7uOJ~lCf*6nVj;pvu>CWx<0jM!(oXBk1&*l*oDCu%7Iok*rsfddf+NDD z(>~jJ&(YB?OsC|K7{2kqmveAtVHPwLKy=A}AZes!q_k|gy z?6Yc;cu=muBzx{Elb`%0QhJVMNo7+jU++OKP*68(>xV1>huKR<_poJcmeDG|!I11m z#|r0~V}pv|M5uxd2XN0$HeISQPJb@8$5e;im8H|aYmUbEodt$r%t zmWA|J43h-siou+T@p#i{P%v`gLc=J?Cwy!#aCrb2A~{bcXUIOs-FA{FrP(IURT*x> zr~45;ac~_B)FBT1y*7+Sx){iXGw)&@Yzf0O>|=0M#=!QmH+<*f<(hniY{=%a8Aicc z(srKcIl{v}0Xt@FUw+3=iE^!x2h9 z+APA<3A5z03F30IY+M%&{8zXxHe6#F0x@FXeA?CsJJ!UNjUK0uP&ZRFRrF#XU zL_Z-U+Qr$Nu6Q6S}_Ge6qk2a6@f4iKI`;;6ypvENF`Vx`|?Q<)T}oL3J=SurEMc8>c@zp;bSclEiJ{|2LKYq2cBwJfkY=p?%A%< ziex>y?)yZSwoM3$*!Q}9iR4^zQLdq`9Zr??Xx}}FYt^{tJ6y-XRT+~Yh-j^rFbSnV z41J$C*NIej5W0AOL!#DhoNfFNOXMw97~Xbc6Z~fTFa?Sk{hih~>H>&eMza9j^-FC< z9Ph##O7yKr@obFN+~p}LIZ|P@%LZMf0tkp$$5BWmkCp+`jK}Op ztp+{o_y5%>I+RRSeynjT7p9ZkcVg?1Fl)V{5&dYB?zC-xX?%H%qwrKe=_4J1DpUD& z6_F@F?934_BNYRUXkH+nF^3yx%EmUY${3CReO?CDBzhP;b?)ztq$6U8h#Y^3B(Ubk z#4V5siX~5hNi?)sXcA?{5UFLn54poJG(;Q`E}8bnlRe;CzIdKPXlMm#z^18RvVps(k~+M|2Bt6I&(m?`+t61_TM=~F16vK|Lt+v ze+`KYE8Cv_R}RsL7VCG<`d=KPqH|2q%m0Z(l(%wR_Kyyc4>&ISCx-~XwX$#h%YSr; z(Eof~76y*X{?Q>~dJOz0kf_SpsCH@K(Z4_<<9+~%SOfnGiNwWSgpg=J=^r5xPlsEg zmaF;Ckmy@omdgJc5;2z4Tvi7u3G+lj-5+i*zSt?u6WJG#t1|r`U;1ZAWCI}44TYP5 z_h0;RCF0@5!vXmw%Xy+#R{zC^uKuMD9bA&Y-h;ZfPCgv__)d6IRv*>3(d^M&^Q+${ zWluRbkmuXnEEb0Y@+}rTG>a`hN@?LAzd2_@Xpl3U!pGXRHE2KZ_NvU)EhS21sxXNs z9_e(^B=ar4ENMoMocK3~=&_amTfF64rNJ&mfAffTqN7|nRJ?FiIaKbTxqDCB$JydF zr+k_UR~#bTD|~i0VQo3v2JD)d_y6q>?U?|(X50e~S_6WBcRW_SWd6pF;Zym_GV+__ zj=ic1*s?Z&w*Tq%YnJAJbKbc%S5-f4NpKIr--fyC)l-ODval zPNucOBx!Me_OkALQR#c2WGzKziW%^iMZtS>3Q&X~>7DnI@BS%l5}6B|M8~oPRO4Ap zui3&}t{HX$?L#~-bCm(pX<#Hw6oQ2>22AP&Bf(qFR`FzceyhQL^BM0>i{)M$xmb^> zJ-{LAl_<(HuB*T}K*Xe>P80)hkFzIEO!*f$6_862XF}|hCy8()9UBbHf-jrLPN(sy zN}s8_B!NRz2^=ETS=X~l5ow}F`p}|9DYDZLBq-uYp5#C^^y<1c1-42QlI)bbNK~Vx zh*$@royFojb=Bb~ayUPz)k}59h+!(xk*6%y#7J8+pzJ577 zicDnRq@^3Uv~;^r)Clmg-Cr9hX;xj-{JtM70EU*q8Cl5bb8`;XS_RIK$mDc?TAHR& zUFK${txWAO%pkG_?c0!2A#)+rD6k-hmR2Eg+$mKW515gH=qf3wPTaEse3(I?#F7s7 z`TgYlJ>-cDFP5z$SSNK#OOc*A3o{5;#gt1tt+rRLG01$3rg_`q4WQ>`a+&C)@N0!% z#1U3961ezT!#%G`I!)Vo*6`gExH5*Fre3*Q?(Ulv2cPKpj%QcrWu)M}%}J0Z9`?E? z&ot(0s;yO*RdmA?-l0TUCQ|R1t7+>cJIfmP0_TxOJ~Fabk@m`0Nqt5-s`#0%w~St! ze18o){Gz$r$bfjhFLnYG>s7vB3G()Y?fGl}!`28-ZKbo|Jcjk>Ox zx{G!7Md`1x9>eF>b&|nA9Vn`Et_I#I_4w#{`|P!;S^sO~jPT5TXWGNS8JW$4pjhfI z7f7H8@a?@{th;ls zO|9wW(*uXhmd2}k)nw!8DVnz+>1zU~Oe$c#$Q{Wh`Npg5^rwNmHc9T7`BR}N7>k&@!h8!Y7Am+5L)03v>h3?G;h9AAA-GkmLMzs zDs^`YzI51b^%obf?ZXunHN5&-pu^bFCXRYCQdAZS_7*=g#=(={tUnS5I`YXSx-RV+ z-o}{Kn`32^K6La%w!A(t+A4FAr-ClyWXzPWC;!e@AMYKOt>i=wujw@Y{){%5@;kyQ~km zH(%cBFH4d=+-1Ex*Kcgy zVDQ&;)hZ@clLaEI)a$QQwy}6;wAe-``Y-ryrmWUUCY)}#Rr_NU6G$qXanSy59Gg7S zv294EfdOs3EP$z|wRYjIR|-qklT0lYhhV|6P;`zuy*@FHQ-3Sxk8EcBt`FdgZ4hjY z@mlbg@Sse1X!||2*c-C|`_^PBm;e`L>VnHTokqL6qqJtrB~L#8Y6QW5t5j5$Z{)z1 zTgJ07J1HqB+A3R}+?_U+L9L`G(vBAKt%bPDyR8=>8Io0-Ve8XcN5^466o|dk8GFFd zEhq%TAsvdoV+qF2bU}>y_r}?ZK=kC8&6DSZJ;i~uJZx!5Tm%Gdc{_kZ$L4>H6EQo| z6ohF6=Rh5YsSxZuBM^SkVhA*dIGdJkNG^alq1w?Q3Pslr7A&CMyOYpJW2&2BUl%cN zzQsh6gS{xQZZcsm;y}QpP$2qM1Xx9KaPlGJ3b{~5I#Uat%L*9zy1(H0L6RA!_-%^( zYcxP2+ZSLjD0bUJNUu~Ur%>*ol^Wd%9(o*Y{gZ`qW?6brU<^je;f#HEGIA^~qPY;{t${Yawm3Ld(U0-PHx&@jO~n=G8U8F|R=md61;^n5II-LRsn2VU49@*}J& zF@7b0=dYtUGm$QrqGM-LUdf;b%_-ox>KT#nE^c+z@0&7`>+3bPg>>k3ZCDs3cBCuI z_oPk~Sx6?13LFl5X#C>YfU~m9dXsYn`UaXfjSkx!0fwTPf3JEEJr*T;)60>C#e6xo zvwk~L1n~=U{QWX>?QpWe^f1DKL1V_khs}!^U;Pe}{JrQ7ksN%tOma&(ah8Lv;i9kd zvD3r(=y~uUj(stGB8lntspNzuJT*fQEiz==NXtE%z5<5820PIK2t?&9Tz{J0)-Q+< zC}`Fon@AY^<>Q-fg|W$2qf^i*GRrMYZi%6doIrqhH9$7NAxdJQ#(C=-Km>%28(y&P zzW}SGx%uhlyGX+iKRp5LtiIh{;>_7$-*>~j+8C39DuUJ zMTT%rjRjCVh}aIV?3As0(Gk!xK0+nFECT|(B*Hj}(D6)bj7@k%hC2w@39q4^ba)m8 z-NMA2$;8~gm{SY-(?o+@CcI_&c9bX-9sTyug$p2X^q5`{sG#HkAW<^> zBoBE?fJh^wC7cL8Op$Pw-52+YF$mIDUTChMxx+Ee4dCw(X=H40LG#Br=i8J^#)U zaqB3Xix)dw@TuUy`&el%sdc$O%i_7G}s2p39hZK|Gjp#s{7}UvuEsTBf zmN|Iu!@0jX(HG9z8DdT4kst3vb8miOd9?lJa61&Fkz#1Y0L0ARs&X4y z({)n3Qc7h>$5BO*@PdqvC5BPCHKC>f+uEVcQ_!DxQ2ktNFW8xeiHr!PZ!)@h)RzuFNI}*Tae=A?aQxN1q8$y<@Y^S3A9fP7R8_`x z3oo~vUSgPy(pHK_TyW-w8zB*7w;9JFLjn2mVfmb2{(V_i7yN>9xil=sah>{)I_y&>#+xA` z0f-C}-Q;Ke2e5~jc{!&YUvmk4e3&x8Llg*nNi^2R+(8|&&n7QQ@A~3^%So;XF#_C( zNhC5%F%cW}o!|2b?+tvhZF8 zLT?EqwS`aOKGAWxkSi&-K!7N@?aUg(DJYPY3g+4kLmJd3gSEOZGg&AvpbqhH_({+{V}sc}p*mzR_P~1nfd#V-azmU{huUNU z$0k8+yy$2}KTrcS8s-kyInG!DI z^1z<*V%-x=5R`p;U?S*EROekiS`H?tW(&pjvzVV;oa9@V;j=`0%&NyqTGNZ7P)2JX zRzf0K%(|P<#p(q=Sr=(Hu6K1+O_=3zx@U|PFNdSPQxM;0iH&}8o0PQP@kDh*l;OZF z;_#%mA~FCT66KASTO1`mYR>JK@k7c^tI5>##HWc$HA}g=49FxSpcOWROy>VY*-JskG73y&m3Pd>;*IVx?$Xroepg`w&5}rH+=7afqi2eMMznaywwTfMdfCtTU@xrAu zT02a209FS1Zh$B&=M znTZ$9$DeQMk-C8!T(3OxN5p7{@91Hy#J%JF7s>`(j`v^v+0)U?yKDIH(Y3M8@i7c; zR6=AN<2uT99q-@88*Uz4fkGk>)o5QA-zhM;vX7N9)wR=Wy8oF9Nq+!aW>pIV_W!I7Nr_0J^~#~kQLulcLPYh}l6j2&KU1Nnb(={4 zYbvyBK`nQ6^uJJ{twuGOYR;$si3&->B(wGF;F-pifV^3&EQd!1U6g5bc zZN|PgqNu2`RC20wq@+z_i=>P;N@{39Nn<(7+2(qV&h!2Le6Q>H9^dPS>xb(&{002r zc-@}2$L)UJa^^r5e#qYPc|_mW^pStmp?;-jl{Tx}W}sJ1uwNQ2KM^)>RwLZ7$SfLO zJ4fGUUYt_bz1eo!d5fq1F^G7+8cW;J!-OBtDCo z;yU!GtGtJTne$r@BA7b!pvC2?)>^&6+odU|?+JalYgHXeXiIwC0E*ND`U|3!GcgzW zZKB%H_0Q=p@}B&My~>wk9v`vV_1*42z3R}imbwi6XSVlWf`+m`eHbPe5CE>yfI9R` zc1LnXjC)Q#kF(C3_fH0_@}U~K^-NtZsR9Bs1X-0J5UoDw2BywvEO?AS zLLLmD>x<#K_(v`M&vO!%CDai%2>S(^WV-&Y^voHYeT*brlcA9|*_|oZOo!>Yi=k)M zsf#Qkuv4Bo-7PM=QYy%c;Y%C}E+<$&lXU3f)+@WJ>1Jd(?lC^DI+0qXIdODyq}qt4~bv+bCzj`|&kCLn0clp@J6MfnN%lCtkH5oScAVtJmP@DX^B#$wjb#%*6o2(`Y@j^#2c}064U#i?UO4why5*Fd+ z*^8B}O+z8dORxI=a$sxvAww8rhfh#{0>lQ#4zs+#+ z5jq{&dO*rLpqIUe>$KJAqu0<24s=b`XS5&EN!_q^(3K)CQ_p}IGt4lD4F}}7%wB!U z{K_WR{)r+%YnSFRW}zQ`!O~4ssxDJ`CwW&ju02v*H5q2%*(C+G(9L4Y^aI{z%C@`9 zxJy6v3CzwslWj#3KP#XZE@>W7feu+e(kRLC%v8@g@!C?zLTXk?r-fXRSZB5oePjTr zL)>1U@*93ad#i1-D4iWq=LJjIZ z_?@%AdZFsJv2R=`x+C~%g%h{uXS?;81b)2&s!YPZG@5 zyN=(yOn3g)p9j;K4OP3S70U<)O={uL{#P6~RStCZM04vgLSmUOM->>tLz zI8cN&AKlMG$o@pANdjMJRv`UY>U{AK+7F!p=%FWT^XENsx75D~ZG&pzdd5dF&ePqt z17*(NKxe4OI={Xt*}xgwSrkljR5tWM(cZS*f&4OMe{L!aF?Yle0|mdn^>zLpHItaQ zb+Gh6gcH`E@|qzA;#S$qH#PAIyMl%>mK3qH9b`vc?2E}CDiJG^SREsW_+h8QldPs@ zVH7j()|7pojC>p2Sz-HO=!S}L?%0MGpfhyp&*A#>?T<61zX<%d=l^}b3U0O~wzhCB zEi`wg$Tj=vUWIfOZAJ9M_e#wqH-pqpVkNQHy;nx^ z(+LOQ3%znyxj!(0k5(aKy4On_F}*#$eXvgcHpJD`(c{y=!!Y?`_CBow4)QQJ`B=K7 z+wXHSr^IDPH{0S+sI}Z-sX7I-Gb=GgVMqzZE~{K}cG=#WO?C2|WpNof{T!V4ElL-&CyU3?0p zu6p8)xCW(c;ar!vf{r}=p4;hzM|LZnxeX4-xJtO2oKwBul0B(>R^X7x7dmPgbGzN$ zb-7*84!JvAQo7VT(kf`{&r$s_PSLZ?Ul z8fo~%^OVV9>C-XpUCT2!GKTT{nbhyUzK?w}K!5-;B0u~%y3TuqMp3h zbKAByGNzxOTvBEL%ypQQNwHZ!dCTrTjFmCKPUoxVJ zfB1<7;4|^9yW_hAhmY%ExXj3sx6r);#RiMjAT^J6$pye5f>3wMED!5R@!~DQA74xB zxQY?iV?ai-4HdRE3ow-&7|ze>Ae|sz<&^dhZm* z#?@Q8gGYAY3LUOmH-8nYB<~i;gw>HS?aZRM(cP_V43lywgbYn1%dHz#Jog(0v6;AT z{C<8)06F>&BjxdOK1mmInGD~)%iDvAS>|qCOfc6L=|Zx$Z<3ya5E2t@J>?!jMn93y zY_%$CB4N`6du6u5`=~Kz;-pb#g|E8si!@LG)X7`P#erjc`*G01<(`ZOr7VYE3l|Ia#Roq4AXG) z#N2ngwRIDS4J2f|1PG6!ek7N7cP5R~;Nudp{v^1|@?ocqC7XbhM4>k{z}z5cdU6ue zOymuP(UD+r3?zq&1&CrAZd-v-Wx**bY~Z00=CK1dOo)MD%um$U$!k7U1DZL-e`q;b|nGsfc1C z^5yj!-EW9tM&J!_@W(`Zlc+%yryV?`d;VVSjS=oTSdI`t2ud6j?j(ed2~TwED~TK; z7Cg$FbEDu?Asts!YiufqcICSlo3r;ZP@wkX;8sO?k3Mx3!{sA*P98TCpwWU8QZp6d zUBpvDgnkn;mxQb(5ylzE9w4;F$q6=ZU8G@d`{}4lL~I*-XFI*9pm1}?3R6_n&fvND z64U?M(D0N_!04Wu?80F?^I2f$jE#idK#sEUU+CbEUy^Zo%XJPc^ld=V6{jdBqLhR# z8##N28N2)h#S*}IkJ-fy6$g2^1^&6|gQA-j}Xrk^MtV03=kd& z;Eqfi)D=oF59-TK#v3B3=LCJOR z>z)ok4|cA(r$HE^Abcs%d21@xyq@V1=+ChUSfN0}A;^A#SHOut5gQUqbH+&IuM3bIoa{lWH4R;Vqk?K>{n0tI2~vR~42 zK=v8tBlmN;VBw6WOvS%#qLHEH1BiC8SkD*jkad%AQ*5PsSyBIRBD!N*Z6&5&VV0{s zL_sr!@JL9k&0FXWA*fm-$|2YhBEha-)GY!LqCT$TQ?nZH?V5lSrF>}hyMq5IupOb` z?s2ibz$aqhUQ*WEMUlWQC%9$1RfP4JMBn3CbR(?*Bnm{X>3BO}L5ZJ@SvB*YM$lbXOAf?VmF3QKsz5#!HyLCDzoRd0wEp$l6L zQdj)Y)zpTA@b(FnK@?kJovYG}&@C?dzJvy@H2#X(n2xX;tH6=D^h5F#NAH3!{ujM# zAdtx6m|xbuYrf#-&4%nT9^8e6n9vgnYOTg^5kC^ka(@gqNAw(x8zN&NNp#i^Cie5- z>b99s|K^}7GXXkNe9yQ{Y?MM+zc@7hRxQWr_OmQP7k^-rn4~Ra7_gy_{I)gm4dewk zTMmD^Q^bbU-fG@eO8COYJi(IG%OLm_<|-eOa@4901b3@8?1z+UHH(r}Z;0Xieg2gG zlI#~I`f2gd2eT(wK!_OYfAK_w$nFo)#cmwP56y8>-*LsMYX3@1d z2X3ny%l+dGfw|MoKf8$I@clv%p)dOliEwrV>8k$$iRc0F&`0Q>LpedCam-ah#2V($ z5ACCk?xAP-rpcUC9b74Xwg+66QC}R@82cmW88vpyS9Nsl#W9PLhq|A}?mQS%*LbNv z{=y{mrOKMeG}WgAB|6irheNpGp4*a-al`GZk|Pg>Z`~eOLD!7EvU~E-OX`1Kmi-^_ zkX7|+ks2XJBq2FktWpTM5EQAydO%Xv8p4r^yjLmywSPx0PPHTb*Ye-p7q+P1-v1<< zdRQWX?pCivO}E`4Q{T9IY3c7%y9uf{_f2v48TEZqu{`kl<=Mx2vLV*t`6tn~&wbCn zD2Oj@xv#jn+G_v1j#`_%OM%uM>0;-NlIC`9*gyI3dG`gct;1(G+TBP!MH_vY{IN}T z*Vot@tB0ql8FRMQ<}-=o1Bpd$Lm_P*I@>QtZc+@b+4E~Q(oU~E>GhpEX$btUo7L_6 zX1~o~EPO97-n)ue{v94V+gkL>`{d1;&u4B&io!!D`;W!eZh7`w8phv3#vOhtjm%eIjk)-N-~5DIIy->Ie7D z-5iCqH$xUPR@0N2WDAA*=+A#IVhUvvyM|br@zeEr4!Kt9*5kzdaHl8J38j|kf$4~H zTF0_>{4zN{!g212jy5}R-%R9@thDYUjmEnJ;P5n>WbLYZM!`vbUF!eknBWI>oj(jINmGXc1hvjhcl9?fq2A`j-b# zjg9HYJwAj?Hmnd(5Ck4ul&t-BNRs9!x} zmfEk`u%zi_`K@O~YiP)IY-g$cUiyh!_OcCNj(#NnWy-|Y0?vaXx0+nPJGr2^=~E?-6Fkm$0kL+;g1P#*$Yas-=OEk7o# zt%ti$S;_jemR`N5H7f6Lm)%Wl=Ghn?prQlyN%Giy3Lr&H?AtD&5<&H!P?Z+k`#y+& ztr6iNxCjqXB-6EB({bT$)(T=Uozx?#(~revMMGvJB4+aD>XF%8bZu%NFZ2D1V<$c- zUn1u(YM-^ECGdyBHM<0EmIre=2|e9P`>Zl$JNOh+_fE7YGD~rqiEu<_O6JqE)qjxk zEZ9d-L7Xn}n{=27c=sLQnsbmZMhCAKLgWh5L5aRrSwp+ps4ZW+-5n zz4MgN)P9b1^VF0%$NY_l9)TS*dXAY<*$Rr<(21JX3X!iS!W&i0Vl+Kos4Gko-a;Q5 zJ`T_}Im?IXAE?Ejs>&u)HGn^)xq4(~Yv_CQ2Dmq?a?ztqylwrB2E zonhZ~)a@j6af?kSm!~!W|AmZn+{Xr!;}I;(_CayEHin_!S*54vU(}s$Cidz=sBXeT z6UYSjK0^oX)g!aRgXb)lh7ohB49+fhXFY|o0vhv5gSu*T@W!TXw=!kqICST^W|Egi zpkwgQEGg1Q4pDmGv-0w2uVgM7w$?emN~@-6>xF^m4-WgwwJG#!#v|-atTYto^VJ=v z{=F>Ai!0UDk6EeiLc^^kQlq&yhC%b4ilANqPI&t%YHwV8| z5w{56><(*n)5)dm5dYG7jZ>Agd;O+YO~zG1(K}w)FA)w(pxmOwdC)R1KRi0y;L_4>GNAvK_-bR1ulrrs&rZ3f0 zy3ZWy+Y2tst~Ke6_lWoQ!88Xm)!qfHNeAH}e^P@F2JO=y#Js`Ym6X!&Hfvue)2`4`<>eXn(E6!NP`l$Ymjc^0 zD6tZ=@bf-ZZkS(Riy@vY(vp1-DRdPq_A@OmbL;>_crt+uUg{!RutxPmbl9+#oPETD zoQ$?gNj9<9xZn1@bjph+?r4ryGv7|ND^zvuTuBxFC^przCH#9zu8YA3=z6P3sZLe% zqp@bbLF&)tLTL#uouraOWP_HoVi8K%Nw2sYo+@8xIZ}N2fenG;GS`>Q4_SUH3WkKs zFTXWEzk3*CtxwGiw8|vEs{YWC|9ibmGthLCnIn<_X6GPgsBP_a{fLJ-X4x!kD5ypA zXfR$G7E2-jjrMHsNmRx4N6R{=PgdorwtsapA%#h6%2{q@`CvmUQWbPp)N@S(H5MMM zT`&D!yIB${d4mCWQ~3tTp+4-ijx!!D3Rv#aUTYQ+B>znTPPoe>*fT=(U-D8ST}&yR zF4op8{1>Y>ukv%3GMfjZ=^L^(6cobUv&FBxC~YEpnqVu=1S;HJ&M~%*eY%~iIcgOV z(*8m9Lc6uq4a=ZOHtyfWIe~vjc z_y*HFhdOFjJ=7DfHX$w<(nf_F22!s@S3!+>#-h*RUw(?+Z8LCc$1bV*&c6bgj!IP# zi@XY8%NRVcoMjO*++A|;O>2}G9}lmK$&_(HSQ({K51rejHrFxt$IAN)n{&*Qbx)n$ z2+qkegW`I!^lXNSx$}=J&5MK3k<4r({;QNmU5~GjC@hbhv}P(JDG65GWB-xjp60W9 zP{yLxND>}?r9K=X?5HG7lM${&w?Gc8l!Gq4#?Xw!++C%61%F@If=g&(olQi#-_)lfSSR_oe+tyB6{Qhm&ZXw1vDf==TbBqLYcmi|gBG&!0Q4GEboB60=6|W#y+sE~T1%$N=F?YC`YFi6@*MqNoxF?BPas|5} zi0QQyg{ZGywq9T>dvrOx)bM}Gbb`NyhO<$|qq(WQd)qna47qe|7^ayIyRn`Y#lS7; zhTe`R+QAf#J<@EbbB<^1D}Dz{n|RP<5S6l zCcX`gW~U`K79}Qc#mKn8r`#5NMaxlJDgdtHDXr^k#e z06zx4NzrW^2|i(QBw}NPuRJ;o0xNKZrb5z6{k01-iS6J#Nr*^9p@wMk4UasYw7b(t zh}*(!?Dh(s#7yQt(ohB+Im9{U3p^_bG73rcK%+ZoaFla3bQ3I$1K^|utrcb6nCBl*B_O(!?cYi_F1`Ig2 zOXXL_9E4NXWmxPkpQ<9B5F!f6Cs^#7Jy6`&UftAk3~hy2hH!?Z5wXpTqh|{OHKQ;o z9O(648#m?-C7E*RT*Bu}Vz2<2%{&F{p?nCS0=qKAx0h0&1rhdOk-m-ZhdxogMF#^k zoMs{-ZDW8F5&gxf^jj?fO@#r4p@>`a;yN;>a=hW{F?@C*tI8$gZ0l#<>%Rw#j0P z>F}oO6gml7#8i}$Q*v30#fYJ@g=el8AVJW3gH>s2m+~wffoyUI#+*L`Q7^=J<>;R| zcNQd}Ye@)SV%FRGC=iB|yO8sPN7Oord~pF>*}3LO2Az@DX>7wQy9E#{_Jz?9wPZ}E zpkU>Fk=9wpW#-wNG}J)~EJWr^@Cpf<4arrEIy2FQ!8|7(wT(5&s6y=C!s_|kNjoMmc=Dfpo4!oO|Ih>4nS!&eng>JsHs1v#{x1?4G|_QqC|}QtELg_8|@Y7)To_ zn6<_zNNzgQqBJRJdHzT~J0F|DhJSQ|`U{|_C5q8Os5hAs$wA&F;RaSm>ATsuDH`d~ zfVBt)k)=-29VxQA-DC)0n(7_{mCA*OQ7GPAr$8b+hK;D9V_$)@9gb+P3>=q%QL+n< z2pOHV+P+egE!R?^<_{hd4E=DAc-MWuV_!hF2fUFde!&ia`!zE59#_4Vfs==y%B>|F zylj5At9D^t?bfjE0#9ikVv|)S&uh`{XJGrtxclH}k^<2o;)K%P?^eJ;8ASTPIo#Yg zO{RqTUj|x}B-}#?E|D)TSq4Etpw{I9OIu|guoL54OD(SBnF4WD4Y5sB$R+NdZ^Yf@ zwulbOGM4M_y}>O&a8@K`IeI6ABEd~CHQRE_Yj{iX^E(5Yx-L{B9+UC#I)iE zDXC8J0XxA~GSUTnI{TlW63AhIpZCWs@nma5Ld_v#}6Bvl=+c_%5JDI!I6v z85D$k7rd@02peS*)`iq#^(D=UH%w`OYqHILqHD4(&wH0N@e3)PGc2`a#+~XiJX5BU zYfF5@*MGEOAW&*uhOnosOok{aE`#z0x{#X6Aebrh)Y?Q;(aI{r>$2}(2302tTp_&t zrL!nGvon5U2IK*s(tn@h=2~2+pAKMK!wz#02iX2iF{S zh8h=QdpeqxT;8Vkla$rHluNda$226#gx!f79c*L+;k@U!od;payP);{|s2QBHDS~mMeeo^ve%;sNJ)(c96rWiWkQp+uZJMQ3XRyPp-y}wO;JLUc*0~Hg>y) ze|}u5Gj_-$?&U+Dmv`-6dR}~KweUiD;^mWDV~=8ojDyBexJRQw!=ANrV*l@`P^}XL zui~*vg|Z+>87R9!1$ zb@=SQyV80OcV6E={jk=k(%UrT&dfl~cmIc{+7rIS?Afy3+`#w9#<8_Ba+a@d#AZED z+o|WhZud})W!^92!$H^L$0vsuD=$8BhZu&QuPEkvug~~$>9oXP%Knhow^zi!26+cs z9{jlk!~EU8VbcropPa{f`;~7Dk5c!_->$jx_2H{a3oG3S+}nXs{aV65IqF=@nUz!N zfC`BfegAOexy#fC)Nd+;PeP`T1OY0v9Q2zCt>_R1kf!DO|4^anW5218-2bFPTED4~ z)c=DDY5lKM=xrRJLfVdVga1+?)+!Z}`oB@3@L@%^pJuiT$WeO*)6*6I%~8`DT+O(= zFi#*2g>z2EigMIGq8zm}OB`f{cwzm{CGn5{$x)|?a@0}dI8|}u z&>uyITHf##`#G7I6Zo2cbJVw1bJQiF8?~fo4*ip(#)xv%v1iNwo1^w{X+%E0uZu9# zIopG>g|yEv>vM zwQ>2pY7WKuIAnJkPlkRJY#AUu4YszZqB`|3Or;pvT4FyZbAI_k=7v)x zA~fXnV*HTS5!)BcgsIrlXuk*byg~JuYb{^<_6GE#(r>ACZm{g zIQ{cXmX{7)Wg=THfbq{!+28N$GhoYs?xESTOiI>JJALdL-g{|Q7Y}yI5@HvTg)eMf zeR4ITfHVYpLk+x~*FLO&mhO3A@f`G3x-@W~=922niW5JF;i6HX&Fc zTYc8!%7 zCYUam<4|Dw6&kpM?aCSotbCWHP{Mw93E7zG9E70|?QbQn|EyMVR6}3&&oQiJ#d~7U z1sZt~nIqNA%vlPWKzlEDDT{*!PN1grvBqpILo*-^g-MsYJF7mVb%TUY>S+~6bu0Z+ ztpPWY{h%eBSF<_iq;`tvC{NVSf#N^oi@=nZac91Vd7X462=!zuqTRu~Sq&XZ8Whdj z)6gNrOx4qsZU$?Ss?A~U>ql!1D{HcHPLR6v9)Jr*Iu&2i4mC}hG29OPrBk#|2Ib)xwpH3x`<9M5{jQ$v0PsI-dyG`M$W~+{#1kj>y<%lJtNOL9+_mS4(y= zp_gH{iKHQ+zPsIr!l3pp*-A*Srho%QnvhR21Kf&cmsL-Aglm)w^5{GK@rU#!&;bFj zzg2N^T_Z9j%ON>NlLkfGd0lc|X?y%?Kltq&?2>Cl_Ug>iy%i6KB5V53SpGwWmgrKD z?+duK0TY>5{Tx+_?;&Z$Ve%@fGj2{dwv{a;Ht243(ftO2jc=u)2BuFURIdPk2%1Cx zo@)mQg|1Wbnx@*$mvJki4;x$s1jAwe49_`pG$3=5^{mfz1bR)vo5K9TK)%@7vuO zpUaZGrJb|YZc}j6amy?3RCAP<581=KyH&@{&kjoY;#Q)KRp*5;$qo|LSg3L0T(Vx= zUmo-cxov+ojrQu?g}{)m>m(O=_3NolVAH-~@2d!e3RB6?@Jgt3F|ya#IVD)?)YqQc z#2nLK5LoS{{ij~vQlqa@p&lQbkGXcmp)gBbwq(Dtkcl&XD}nfm-IgqntzvKau=YUV zN6ua9B(pv9GN0%gMUt< z16ap*AhWe>_Po{jetjry9A-EG$ua(LT(R(M^zNevi96rs27(*4wGCW*V_GLR_#kZe zy}=o?ly4Wf!d_LY;v6kMz{J>QjGhDR2!Ym(n};Lyb9t{#^e6Caz6>X)7$fqBT<~pc zVp>q?z7rUTSKmt1jXrY)=v{B=KHDW8RCrq!WIbRe)6K0&>ygr~I} zrWTTt(6l6m&Z>SBbu=p(=~h2SeU8n< z18s0s7P`IrRt{FTxEyr=B(E)g&Lr2VyfezPxt}!QUFDW2ca!Oy<#Y&@QsFd}uAvf+ z&MZB#Z`V496rZxp7FX2)F_}ir4N&VYKIbq#gOJZ92Wb2q*w`gs?*2*d1QVHNb*L*v z1c)@M9|Ax$Dekj5r#4$+ANXfg1-l-pfeE={J7>80kXd?d%F#tNc@9Ziyo8RdKJu4o z9D1s^h?yMh)JwWcNz!o*PDY?+dtpv&R5~I#1#lwD z8kh#|QY(I*k*0AV?I*|o@p{6L5Qh8WA5BERl@H`Gu~mq~&6bI#R)=^HWJ#WT9WzKy z@Apm_Aw|RSN1pUzxccE1Tm%Jn+8Gu}M;+ALp`(+EvBK)E&+$#%b%>G>$boi|2pjam z!&bZ0XaI@Gnc=KGWM6zd1G+uJzLayI7sP*vSts&9${JI>JCFAsvnQK!`i+e4azx6% zgow7nlKv^M2-L)XAtJAigr?D%rxOFgn%W&A_9h+k=3IfO_e_Ba>UYeCdSsj@06f&T zV7!(s(=jC+==Pfat2MHAi@RU) zzV{m7iF}w8m-ht5fovr-<_N5|a`_;kv&VyjZhW?n^}9O6$p1^zCXVTp)P}et%)=&S z)l|}JA#mKeh^L&G&2map6oQBlK|;t9dgn;q-CD3+JoH3k!9fJ(CKq8o0&`;^b}y#h zDKpmv8WCC6At8AbU>ph#doZAow6C}7$W8dxMy@?N0_IJ}EUf4S)lsEUVnwfnmWvR% zr^)ISQAjt4eV#VFneTVgt<2yHCSCwNc5cVv&O#s%EiQs_ZOlV1E;`3(z!mqdp5jM> z#S^g~5XIk+zD-1I0b@62Y3pUOsrBEAE{?{?P;4y`nE?SYAmjj9{%oc~F{g;54a;X7 zk^Z~Hpbb;U3)%e@u69p3>=6PDPN|5`Lfzpb+PI1wy{gLi*Xa)^!0(Yp<&-(5#$aL`XibtjMFysT_@I>X|H-oL&aE#Hj+ z17vC3$jb#3P{mr5;=J_H?&cDU=txu{C!fc;EwKKjmoiVrg$eC)p)fiH$rWN~SN*DW zF`L$dD>F-QHQ6oU5x{|7Ci(ks0Nd)s1b)NY=+o8PaSaV=CP(qJWE}QOHp*{Lv=Bj( z#a`xa>$rP-Yz2-LRv@oQRALX4EMi2HJE4S1A$!A61O(1N8jS#zqi3>DWC;wykAt_aXzL~RkR zB=Hm{&%!RzJR)-xo!w3T3@1G0A$QSiuQu%O++lyIX}^s#bQ=lL4BQ+t_6cua`Hb?~ zH!<>^9!37vA1@fC9L4`+;@T*P2nzIW0?cUC^;4F}Hd5??bNE<3M^vN+x#)~aJp6L2 zbsJWr1*QL_X6qi45sme0px9y>B8pLH;pY@WgYOq0ngrMx?)t}c(7ndqV`BMC{5)q% z(N3E7TB(W9i<^({8LH11EZr?KU{G%uRl#Ww4O@X+Z?dZc=6 zIvW}OHXs(@A%^^i`)jNZVijmoQ$A7%TM5SvB0Th*kGON8PEJ>`fN7;O+XH_`@MLuQ zVIhjf$O0oxhXMl$-lhURDrg0w3i!}%o4eQRa_@2FF2|{9aAo`NKSkj#3}J|GdSmj(r!I)`_PXO$mB`H50Fy zDI7M|GpPpN!=8WUqgYEhCX(uK9OC$EPFQP zuszOLI8C~67uVQ{-`hxFl6p}kYJ>;yeMCe6L-AKE^z?C{OxyVIJL4xqEn}am$FgxR3FFUqd%Yx-ym(yvvNQJO zyTO;87hjf&jgQTaMSG5q6_2ec9v^!-wpXfieEj0LK=oyd-K%>)$4vg0Is5;;JoNto zCMx{@B_@i^O6Sj%U&D=0f8?|lJ@dYivU~rwzb96*;PH_$6+?&*)Tz(a?eX0?_gCy3 ztbTrH_NM*SHyf64d?-3=$oge->p1IGT%Kws=5Xahi!aj>MH#3DJ+|SmDF2Yu<+!NV zd1{As@D8)>p%X5zms`E8aczxYwXDniWXi7}@srLq!f<-N@|V%tBcy>mZ%c_+qr~;! zs^55Jnpxa?TW(@~NX5Qb;RM?z0rvNs<2w%C3#Y#pY84-Yot+@0g0cIv#e3SeDkdWKH?A!rM_NVfvTXcv!uZ0#f^MnJ z3#*16?Q*7u&uRE%)5S~I=b8i?7M4c*tq-lgKYRVW#YddO8Q&`f0 zf1mPa)H{Jzg>xcQx={bRf-hV1M{4-K8`CEDg(2@o*ZJt2<2s^^Tcs)*I$q9wjO(ix zWrwbaOAqMZBsvl;vMg?KyU9kP12gxfeIPqjH`#adWNs-qFaz??m-yoS|6n4!;yoLZ z&VoCy%|5CkOay>Y+QeTAT~mWvmt5|*hmQ}hIhm{D@XAjMYgDZLs82oBIDVt)Jx10` z>yO4O(W_bNyDmS8atZl)K{a0F>?@rx8L(gfFCn6t-Bqn2YX#Ap(tn<%5A6yUWvR2; z4$kDy;>`;9Gl#y^B;?gk)4a^*G}Zu;Yc(wi-9|0@sC4$Myc)tPr>T^cPeTPBd+ z*((cf%V5is<$vaUeYGyMN1=wI|M0YTM*F{nNcht-db$V9DuPImJb0EB$wLxL;<7PG z6qDI~EVwgiIhzUJ=J_t>yYhn#KUhbyYb4YURUsYlZ`Mw7vebIkii_PFu`{Ny(56=$ zzg_{$23AzGuT{wM!x5OiekcBERo}i95B-Kjq#1d(G1ob}lkk>hY%|X2vo@h-zh2Ks z^5%%k^7(MPB`P>5%htelB5b*x*zMVw^6g1BM&t=hU*m}MsS5nlSdlU0K9S$Ac`!em z;H2<+nah9~QEIUX?mgNTp#`3PbyB5`J=(@T1)f%p#5kmcOfw^gntKFQUxoP5__dz9 znx)Q5@vl6&?+Fzdk}nYZlalLTE-q6Rk*%XLT;Q1KZXW6TJ}1P*r9v`)+Dn~2@p z&@N2Lek(3X(O7W?>(j~Uql6;jA?!wFj7jRJPBrsg>S0UTp9_4Cq z1LM!>lB$6~l`3ewqxep__(0XHe~UxJ;`^^EP-4f2auVCKbq*+^x8Hhvp38;Na;%Fu z_(ZujB1~Ut7_KLfPW7X^+U6=a5DFyJF$HkDvZh@(n;w4as46V8cSa{|z!R;<0hG+DCFy|!GCC9ZBUfplYs$+_q> z`DocZ8Sp(Qm;a(ixf*T1MukQEvJ5xK`qvn8iz{t2aaIw-AOISgBYV58@Wkcz2N?w> z{W12c&b>POl_Xed3?Ef9QQ%H zi+3BaK4b#DZ$s0K+7qBf{q1{z^`u6=Mk=*AoV!yiVxsWnw`&(WV2pi9^9W-KXhsw7 zuB$gVNf6zZDMX&(gX=2Nakd}7TUUXF-pP=^rH(hvkNXbSKj4e;WM|n5x?g=?-LTKE zPkx3=H_t?^{Sl;SVT^u>Uhcc~(=;$nqliXir`&OJ-CUupl;taGQ3w9WJPy~7qUQPv zopemZiij!CZ)#p@Ha=*E&<(tfai%-}{84Zw%Q$R>vs_1BS4yLpT6JPexz75=N)aSP z`_R6~UQ;EXe(@b*xMwp)2UjuC-9Xbz*^*p_y*{5+7NXX2uG@3_&gzLI1^>IYj(vTd zqNy^bmHDi zBcam)ZWcWddt-MNwzNIl$Rh1|?9`-u$8rv>b2f6dqhr+~^@Vce>(x=y-|-<_(&&8f zD^A|p=1)AM#!%@~(~W=rG>W3DI4SfKbIlG9e{8#vDI3HIm9G%OFReYHnhdhkyR44{ zt8}sg8IG#@@a^%NpUHNtC;&_ZM55-G3Z4B|B6ruqjY1~Sq3!VNqqAyh%r4RtJ=Vdx zHrq(Sn!q8!&aB*e76k29=(4)|xL&O|d{$iEQ_qV0ijt$1(5bj{>y_O{pP6J{nGMZn zWkWjkawrEJ<#a1&jZ=pgj{o^`&e(LrwVN+7woe}3SUTM1AfacP$;tZjl-S9l8?^*y z!RW!jWhea~)jLCJsvms&ZjnM&;?o7hkI7zLlXyd)dI`O41mF1 z6gpYk;LiH_#*5pb5}$dy51EjS7R|nQ4nqAL$#1Dohl3OUf+;>&^@u1rs;Ri`4pKf# z5_={Hjnk$p?}FwR?w?wbZ&GM?-7bl>eZpn>B6IDJ-n`QQ;zN{#&9(=QmSgV)lfN)f zd)=He$mlj=5@kK+4lT)~FCG_wRm)|%fDcs$BI7*Fo0$B$P5z$%(dyaRvp(vx5rW(` z)%6x=Z+7@L3ZjX=_w;%HoAmS(c?=PWsl+r1G5eX@THeEk$b_#JZfE9g50g#jx$>${ zGOSnxHD6E}!Fn(vk4PixxJl0Mz#LUPJ|G>@m_s=R-{9vSNmE^sUl+O{$`DD2q$0qJ z2rko#uPKBfn(vH1yrnMvChRa$J`p*E*))}RM;CLBzwuf)G@c@RZzb0aA%^-XRQm{# zwOUP7@0^s4qQC;^^k4`ov_D#}5}eeDs8P2bOK%EOL=W2`*q+TK%vtPEXh@aa2GkXp}kZ}AG7t~E@ujQum2vWNrJ{IHKMdC zR$Mk|6+m4podW3S%PWH7b?xOHV5W?olK37PP6IbYM_#x~qiT!#yYT=VEwvZCW5Z9o zui8J{SoIUfG|qWnBEhR=ia=ERO8(I#|;Caf2=`GC=Y(AvO z)e>4vC#3WygaUTtgD3(L4!AjESGAJ~t|*sfB6fX*&D|;hvM@8(vTQG)J0YkRxt-oj z_y~PJAzJBB1+kp+k6QFV5jjLFBdtwi(xEL;!Jd5hN52!5Gm)9kP022x42r;~~$LP-@JBY|_wBU-nG^d_~ z4h?*JBXJIOW&w5P{2|og$GShYum|8&fTx0lhz_P7^m^9JZlAy;n|Eh7jPiW%JyUcB zUJ(mX%&8uXM&{FznM8E@mD*M}LMsQFt?f>(fFA=#V!UHB$lxD2ejNgIrVwVn!F>k= z7DmEtfz@Y7>S8CLYzp$T;+e(gh(Xf&&yRIyNQAZ(%DL~+QQi>nJC5NocPgCSTWOuz zNyjwu5mDsm;3>y&N?GC(r-5n$*ijO(k;N1xUDC4xmODLe+sdo%u!}rn<2e^m?3Sti(Zslil{{ZFSvxCN4n_l#*hLkl)OF}tB z>@XLvs*g~dfbCEIV{{ve*A1J}vah&%&>jl&6hJ*VE`LYZzX^v%urW{08*G}iXnXpU<_8AG!3#j%eQj)KY zD0m@#6@5+_@KzFGfQN{BmMJ;a{Pfu79dsLSI+PBWgg_J*s&l-^G+Q@#P_jw;><5?D z@jAUZ4uKCr@1vJ^3U|;16!enSHu45%5};!kunN`>&c!$YA9*e59TeF`M5$9`$HVjX zzuv0NQ3$g{+$9Jyo(6Amg>8?3g#zD-gS^(O25e3)OMVMz>KWoAD@>U@d(HR`l#w>DJTXeJ}TVhuBs?LQP z%tKPRQ}_>&s=f2dQxM!;2FN7gjuWLXE^kDh>t<^W9aJtc{2YJwh0~Ql`0fKSS(t zsG15Ea)(0r(zS*)L3mXpXZBY`YN6p;G-l&)XK9(FK2_oyttcoS|B-^b!xV8O<;6R3 z7K9FAmq}o6F1M)N(d03^s)UO?+Jew;XU!%WkcC|yVS6d{hS?p9^sbQxB?=wK!_+O!LO`%PzID>AHR=rr2(N3ZOv-^AjstcPLu41lF+?|K7q@f{9QArm6TeKo z$7Z4VPerY24`-2G1eDAAX5Hi^ILHm9H1i-tiCONIx*WIc=s~b|U+Q?Z{g%9+4^B;R z|HyD>Cb4TSuG6yl0Tc*EtsXvTE!Jarn#u#<9tDMx9=UkUf?PGFXz#7=+ZsW`T(Qe$ z_l$hthVgiCbN2K1Cy8^<+FMM2_a+b#3z@vADm}2F#l9(S7 zJjf%+mV#NXro<^-^_2$L`N6&mvyWs#k;*-quAUcxQrpkvZKOU_t$i%RLWoaN^=>&N zYeR>shqe7_H|I$rfya=cd)@Pkl}sRk9(r18xorQ!No4#3z>eY?2~^sU zm7OvPa2^5NZ|BGM$-k5Qe{|ZJr0cqj?X%j&L zlr^5V%=3>2!6TV)In6O?F~zn|DnC8pTpXN1ekNWvp!k!Yd~u{>4bk<}{a&x9iLpcX zN}hzKjk%4#Bt3X>aLqVj&2xI}IO(?BeH`h9e(WIM>*4G1AzsPjH{(M?cF(6CJRC1k z`&ja-@8_$Ln#T(lAA7KXWc2?gOeBIwS|Z0t(-8tii}Ttg>w1rnoIIccUOf-0Eygi6 zxUAFpzj2J(%k=w7poRFK`u|7A=#t+?saWR?eWT;WdfwI7;$QP?oVJ;azv{?%e9Y$S z#cIpAsoCdG&h3fvZBQ-05vlLF?^fa%vh{nL_sjPW&)6l%flR@TeeZ7c)=!!4)G3SE zbjgeS`|>QvPQKkT1YDj;{P*$H1yjs`cxltRk!xz zZ+O&`cOPLN0^ku#1dj&m7MHI6hDY7wtk;Q^03N0P3y=7c4TTP;p31AIE5Dcu%?mE* zCfMxrTOPLj6;tk=Wo$UDnPqzX{b`3gRaQQFKNOI4xwi46Z}JvuA3tDPSUZ>4PbHU= ziakwcB8t2;L95cm@GU-w@~tuQc;KA=sO1mjmb298Wr>h-n!RH9$(Z9#L+j-X9)acg zPZLKh4(atnW%cUeF5Hj!QH&iw3e$mU@T=Y z@ZflQ=D<{A-8UU?>qX}XHDDY0D?)O(pX8-^j(GnOZi z`dwCAylsDS!Y!UJtmdla{@S8&pOl{U!S*rtGD69pOwE>b){pCvbn+~PDWx|$K6o-^ z>}7Q!%ixrk$SlIWMjYjA*n%&oT`x$l^VMijHM{lAf-~- zDs?LNdpf`8_x@hjab3rK|NA?R-~Sx^F_zC`9mV+yVc5u3>#vuTon zZ(%wRI?IPYA##zvSqGbne?%P5qrd%qZYCx?H=~e_QZx=caC>IH!3y^3@OALG4A$O3 z&j{Sw?`Dfiou#zT#e^q;8x|=Ix2-Q()W0Y1pv!FEBGq!A`q>!)WYagn1vcIv7tHC%khk z3_9BieoW6v*9qE;1+CuYTw4tdLzIJ8m3RqVO?8zEHvsOE=ZX@xi~84UU zi=b4rd*~EcvG0&O*t6F1$=6qQaend{&GzP2YR9^sB7c+DRyZStN)`~hu%87v+o@IH zgJHU{fFnf%j;Og+B^{Nn zuuh5`k!$bKCe_G1xTCE0d0*t|D~&9ej*J!j&(npd2eYVUTc^Lv)l^shqx$2l;q2@wr$~L7&F@y{Vr1CH=P8RXZ}HgA6Z*$fyaa# zL?w>es%|Lq?l<^yuiWl>P|!kl;L+HkdLJB?{_Q{|IA*bH^+)O@3p&!2E! z)>&9754f0H;j-js&#y!P$Ece7SA~Nyk4n>FSYc0Xf6tKsj*;ZS5&P3H`C{ULf$5~| z9EZ8^$?A+Hc{z)ka}_f5pmA5)Yw)`#)^L0 zIQpIyYOKLpMuC*a&w6o1b3OdgA7PQcys04#`*xFhN~SR{sB7C$cL%b{WRMvcq<9iOpA)`%PTs3I zFS4=q0S6CK(P3{hw$Gr!rdca^=w~KEM!lyuA>Leq)f^yvXxyDNX#yOh8q? z!6bf!3D>=4Stf9ej`zF|cfbEN4bzCJVZhhaVY_*-XY}~NTe5c|iDsSTlQ&d2D)?nK z!Wm)%S~iJ%Oq@yH6f&uSi#blu1@=P}56_nlijxr5tL1t$-Vq5msL(?Jp$EaD`DkGW zvfzP$0gr~cFi<033ZOQ>O(Ow*6T;k14c?e#N#`M(`K~)nk3at!SQ_HD`T00c9PlhP786Q6D{++)Hx>Rvn^s>jg!GM?rF(*)AMY)l0}1!eX?6*@wX z5_x31Ld9Z8@RJlI8hsXsR0Tw(Z$azkC&2-bujG%^C<+>!pi#b^)qbW6ZZ0e72q1iw z!fov72;O97$-{%#Nn{4E>J2cc7?>UKbs>vVvoz!p_<48Ufp`Y0g^hWz2Em|44rQKT zHZw4r(dcLhT;9P>Owuc!cf2vj{3SR?bAy-Akat6X`c(=ND6?GL68ob3jf>?BJ8FmJ z_)=Dg0C9?iz9GQ8>^htfj4tCN4$@%jiU^^>jc?|M+zQ&yLcjldMe3_ml@7@o zf^OtsFGq&Uq>9B^>)CtZUTAIJyJ^b}1dPu4eT&9{T4XtCW>_|N2JzWhy>}{rY$WNc z@rfh%lqDtyL1%dBzw{#v8$olkc42I3dOK-GYl*NYFxUY;s)vu8;#}W$6Mw~*)I*ON zSul7pU)wXKbjKINq`~Y3myEO=r_w`q$k+FFf{>BW{#hp9cJ&_JiW?%s)0$LB?L_^eY^ONZ=0ffg8@p6Gx%EGOqgJw(g zsK-Qf;ym1se++m}ca7i&*@)A0>UFtQah@=ShV=0VX|3HJf}SC z#XPnT44^@po`RV{KH*`5(G2Z3Bw_>8NU9c?JTt*ZZPZn)vZBu7y8+;}~dP+J@?2u)dA-)!8!RO6RLbNC{ zv@weG>wCfV=AE)F7pFD^(;#@dcws6@T^SK4ZZONkHbGz~i{MgA_m`$jKw?OGzE!(b zq>s3(5OnM5*dz#&&9?}yN5}@3iG2ZAVOS?pyP-vgE2rtG3ci4TF^z$`1vnAU_;zmN zPmb8zfiCR@jCHXFFpWmpwRr+W2}BXptF@n;QX1TOgGbt3APJ?3siJkdcWBerDCm3! z3Jw#RMuF4qPt)+r95HJJ`7>uB84M%9iE2%WTPO&BhAQAhf&RQoQH@F(q|mTO%U2XO z*bO+5z41S7qO%$^Dq;<(NE6iGS)1E%M9}t3K^C$&hy$qTgq6%(@Ff*dy{ixL zyrI8Q(K4M3wdo9%L6n^xas>PcXh!T!zvx@N4fPUoDOv5fE3NoQH@rGq9NjCvelHxD zgD&&JhP4zxMO2HN1>7q^!%Ozak9y-j|3*a&x;*WvJZ^A51@6azu~dJfB5v&xBXx!L z{1=5VM-$GPk+u_UpA1s2j`|Ye0SuL33hBqafkNd02K9vx55CKiXoq_t()%n-aV(_h zMS8(leapl1EkpNk{aIH#TaOKgv^?zmIcR=(RG6!75%0wf-nlw7fE#SMD*aS{ptfb4 zS23|udTQ+LBp^u>&dM)eC_Z^}`00fHe~T0mK*Kr(@;@}Jtsqb(Ybb4?vNK=C=%5;s zCjv=BnTsOdMN~UwB?joXXW{p6O<7%SDY#Pj(&S(prN!(Bw~Cer)pA|!X_$q$_0PUr zGU-<`kDchVo7i=H%q(p7e)G1=;oA43yNI&Mvqi6aj{6%uGV8(zT0~6UJM~xACxtta z@8+hSmR}oh4xhP~yE*9d#Z5ay(nY1@jIY}H9-h8B_O)cZ*o3!;Xsb>uBrL< zayWUMi*NhaD+hu-Gtn@w$z$ZH8sEg(=%xJy(!cl2B%7v+>@{*#PP9+9BiWedrDw;@ zb~(+Q+Vu4cZfhIu2-q{L%YJ>r`G(`0vKf9@C0kgo-oDq{?}~p#eA~C}7Bc}E zj}2;(Cz1APD-wdzK#jcFDrccxL{3)5YSm?kKC#P;^gnQ}{N=ll%SVJqXwt_f^R+G% zfT6QkncCp8f^%!%-{;2E`xmWm=vjPx5|{cMR}(AxIE33Iq(suneol(g549fq;82}d7a+(E8ykNr!#9#A4@`xxxWZB%=ijsgpByKNtD&fodqZMHHO?Pge6;DU(Ye6!+h%3crF-?B zhsE0`c0mIo=Zy%Ba{AN9qb)U8wwu4=4@Gb6Z4%E@PMcfkUdPT!D=?nxsV*$_eIP6o zg{}<~7#jXwWtJbPLk|`FX_ZitJ+ZZeS zuFR0wPj7`uHGQz2yDp22?xPDsh*f?dw?zOv_6-(TgW4DdPxR>trYH=Cu(Y2{4Iu*#RveOtkhU;`n_K zt}e{w^luu%9hI5J+OQNqHL015a+?QWGu#Z7MMjn` zO@!^)Q%RboUluslJ>cy_T%T?wgpL3o3vtaIXBgrqYsO}go}r8X~>RL+8`DS)~U zw@s?KEmNPVjEQ~JCRx>#p|Zwqa!L3D;~d}Kd+pNN{c*_e8#JbKH!k_LHQGJ+fNnTB z$6>>icp2aj36sCeM0H#(d;L2Y(6E-Q^m_eX9L)>p^NrScB%k(=XEgtq*P&b(bThKt ztk_yst_bB|+;+B+ZAT9h$*+{&DQ&y4*4(@Du?3?w<(qMv%ADaQil1Yl&@;+#&=2=| zgR^HGzzy+tIJ#I@H3O^ZY3;zRu;QyAfTLwSfLOmmV(nsD8x)(iLI;YxQSSsjgV0>% zRT9SCFz509N^4)fgPhMFQOD7VQ2{+6d%=i7Yw{~eQERWcx zu*9|5bhpIG+gwGmnH_rI*5iqugt!~EtaQn_D=;n7^n+*rBt8;%KlZ)zvHS`#OERp4 zuCZJx-aH2jJ978c?H_ShLAG0~jp?%OWooU?Q&;#m7BO~y$hGiMI_VDEN%KOh`0IeT zakuYIesbR>eWNE+#o%F!u2-t;lGh&zGfTK+uBdWWt<1J+5t?!2B*C)NE+wvRZ0-H& zig3=jPBt$m-nilVyFG}Fc=7B9QripJrq=lDw9Jj*3a}<#FMBIkHX}<(w=grL{DP-8 zFlJiMTXb7VEA!7)*sS3tc2OiCMUV3qZ+BbVUkZzJgX@m>q3QFPTkb^o{Pnb+(pZD5 z?`u6CJU*XtfZ3s@&^6;6{(bO7h245k<(`X3Mdot42dwXw=qswpu27ac+Ag9sd@4_Q z#M@|U6zy8~%B;G!sqSjr)x3StZ5ZfsgB-d-(fm>?WvEWB)jl7oLT|d4Qq!T8@!l7I z*Y9`3Izhy5TcQj(SmyJlyA)i}Rj+@`MeM%4FWC+X2YX=JtX5(lu?X zm9Ehe8lS$Ckg0@-3*QYAZ9vYtXz;Pmn?TJo=Z(%1X&OD1;@q5sfu|_urOhqxL_TNg zFR$*3%}cw#PeznNIVX6+ACQFmW`}Q(D7;!NyMBh9y`ifBrt|oWRH>_uUXoSh?YqgZ zwf83)&?+tUs8)ofnm11tQh%f+y^(iY>UL+vaiY1?vaTzy`ls2skEN5}H`Cy2Z}cB5 zr~K6>INSYG&pws6K4*)P&mUC&24CXaJXIy5qK6rLm!V+jhRdN4bTlGzkW%iR#?gbJ6y)1VGQQ3W`uVG73(sZs2YU5 zOTo0>PE6)U3QuilJ1?9j@9`5VMWR3{;-&5*MU9Fi#|WU;1Fh5M(<%@cRZy}H!Zxtd z+_Mv#s0atXGtf7l2=L1%8PUHX(ffM*wuSVcblVmynNw>FFR3hqSZRj+Qw)%azlYjbPU7BKf$V$}V@?=S28=sN+e#8`|rb_T`YlnGhQYdP{T|@1M#0 z0l(yA8gxIK?#xBR#OHsS%@Uu1?Pl5U=3qCuC7d?gy&6dz7T_O!)1G1wns`vNWous+ zdN}Y{vDaZx#yQH5JiQG6AUJkk#8@7fL;^{F|9HN*LI9*7Z5Yu8@PpThcO{rhbog@z znAc_W9)!b-0dZ7Bo?8(f?8=m`4QOXXpx7%O`zdJYTWs{hy^Jgbw9MN46t3E_=q|WF z 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%0AMR!1w0j1$dBggEMUH{qv@t!|Tr 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 z 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�k6uOT)<3X1nVC?!hWjIb5YfU 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

ECQ_VvS;?~p53>_ESI$tyWr~i)Pexu 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 Jawul~e*jP}mVy8P literal 0 HcmV?d00001 From c78b2a785bb0cc0db4499657eb66ab7ef2975fc4 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 21:59:11 +0300 Subject: [PATCH 044/201] implement no coin found screen --- .../components/success/NoCoinsFound.kt | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt new file mode 100644 index 0000000..ca95567 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt @@ -0,0 +1,56 @@ +package com.ryankoech.krypto.feature_coin_list.presentation.components.success + +import androidx.compose.foundation.layout.* +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.GifImage +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.R + +@Composable +fun NoCoinsFound( + modifier: Modifier = Modifier, +) { + + Column( + modifier = modifier + .fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + + Box(modifier = Modifier.size(112.dp)) { + GifImage( + modifier = Modifier.fillMaxSize(), + res = R.drawable.icon_gif_search + ) + } + + Spacer(modifier = Modifier.height(20.dp)) + + Text( + text = "No coins to show.", + style = MaterialTheme.typography.body1 + ) + + } + +} + +@Preview +@Composable +fun NoCoinsFoundPreview() { + KryptoTheme { + Surface( + modifier = Modifier.fillMaxSize() + ) { + NoCoinsFound() + } + } +} \ No newline at end of file From c9a1eb2e2c34d1e3974fdd58f6fd959b76f99e0f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 22:05:09 +0300 Subject: [PATCH 045/201] update to make more flexible --- .../krypto/common/presentation/ErrorScreen.kt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/ErrorScreen.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/ErrorScreen.kt index 802f864..5d42d58 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/ErrorScreen.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/ErrorScreen.kt @@ -14,9 +14,10 @@ import com.ryankoech.krypto.common.presentation.components.KryptoButton @Composable fun ErrorScreen( modifier : Modifier = Modifier, - onButtonClick : () -> Unit, + onButtonClick : () -> Unit = {}, messageText : String, - buttonText : String, + buttonText : String = "Try Again", + showButton : Boolean = true, @DrawableRes res : Int, ) { @@ -27,7 +28,7 @@ fun ErrorScreen( horizontalAlignment = Alignment.CenterHorizontally ) { - Box(modifier = Modifier.size(40.dp)) { + Box(modifier = Modifier.size(80.dp)) { GifImage( modifier = Modifier.fillMaxSize(), res = res @@ -41,12 +42,14 @@ fun ErrorScreen( style = MaterialTheme.typography.body1 ) - Spacer(modifier = Modifier.height(24.dp)) + if(showButton){ + Spacer(modifier = Modifier.height(24.dp)) - KryptoButton( - text = buttonText, - onClick = onButtonClick - ) + KryptoButton( + text = buttonText, + onClick = onButtonClick + ) + } } From 558a7c83531a716f4ae734964bb3fe8369763df1 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 22:05:32 +0300 Subject: [PATCH 046/201] refactored to utli error component --- .../components/success/NoCoinsFound.kt | 34 ++++--------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt index ca95567..a3ac3fc 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt @@ -1,45 +1,25 @@ package com.ryankoech.krypto.feature_coin_list.presentation.components.success import androidx.compose.foundation.layout.* -import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface -import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.ryankoech.krypto.common.presentation.components.GifImage import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.R +import com.ryankoech.krypto.common.presentation.ErrorScreen @Composable fun NoCoinsFound( modifier: Modifier = Modifier, ) { - Column( - modifier = modifier - .fillMaxSize(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - - Box(modifier = Modifier.size(112.dp)) { - GifImage( - modifier = Modifier.fillMaxSize(), - res = R.drawable.icon_gif_search - ) - } - - Spacer(modifier = Modifier.height(20.dp)) - - Text( - text = "No coins to show.", - style = MaterialTheme.typography.body1 - ) - - } + ErrorScreen( + modifier = modifier, + messageText = "No coins to show.", + res = R.drawable.icon_gif_search, + showButton = false, + ) } From 77f724759f2a15637d0025840706f63c9252f5c2 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 22:05:59 +0300 Subject: [PATCH 047/201] implement error screen --- .../presentation/CoinListScreenError.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenError.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenError.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenError.kt new file mode 100644 index 0000000..6e86a66 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenError.kt @@ -0,0 +1,31 @@ +package com.ryankoech.krypto.feature_coin_list.presentation + +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.ryankoech.krypto.common.presentation.ErrorScreen +import com.ryankoech.krypto.common.R +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme + +@Composable +fun CoinListScreenError( + onButtonClick: () -> Unit, + modifier: Modifier = Modifier, +){ + + ErrorScreen(onButtonClick = onButtonClick, messageText = "Hmm, can't seem to find any coins", buttonText = "Try Again", res = R.drawable.icon_gif_caution) + +} + +@Preview +@Composable +fun CoinListScreenErrorPreview(){ + + KryptoTheme { + Surface { + CoinListScreenError(onButtonClick = {}) + } + } + +} \ No newline at end of file From 4cd82bcc6c70f672d51a8b7c26976d65cc96e473 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 10 Jan 2023 22:07:12 +0300 Subject: [PATCH 048/201] add logic to display fallback error screens --- .../krypto/feature_coin_list/presentation/CoinListScreen.kt | 4 +--- .../feature_coin_list/presentation/CoinListScreenSuccess.kt | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index 6a62208..f1732af 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -12,7 +12,6 @@ import com.ryankoech.krypto.feature_coin_list.domain.entity.Order import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel -import timber.log.Timber @Composable fun CoinListScreen( @@ -67,8 +66,7 @@ fun CoinListScreen( ) { if(viewState.screenState == ScreenState.ERROR) { - //TODO : Show Error Screen - Timber.d("Display Coin List Error Screen") + CoinListScreenError(onButtonClick = { viewModel.getCoins(sortInfoState, filterStringState) }) }else { CoinListScreenSuccess( screenState = viewState.screenState, diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index d306a44..f06da54 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -18,6 +18,7 @@ import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.components.success.CoinItem import com.ryankoech.krypto.feature_coin_list.presentation.components.success.CoinListLoading +import com.ryankoech.krypto.feature_coin_list.presentation.components.success.NoCoinsFound import com.ryankoech.krypto.feature_coin_list.presentation.components.success.SearchTag import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SORT_INFO import timber.log.Timber @@ -83,8 +84,7 @@ fun CoinListScreenSuccess( } else { if( coins.isEmpty() ) { - // TODO: Show No Coins Screen - Timber.d("Display Coin List Empty List") + NoCoinsFound() }else { LazyColumn( From 2a735004c0b8ff554d3343dc81e2ae42601cdcfd Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:10:32 +0300 Subject: [PATCH 049/201] add room dependencies --- feature_coin_list/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/feature_coin_list/build.gradle b/feature_coin_list/build.gradle index 6b31427..f0a1c7e 100644 --- a/feature_coin_list/build.gradle +++ b/feature_coin_list/build.gradle @@ -70,6 +70,12 @@ dependencies { implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation "androidx.activity:activity-compose:$compose_activity_version" + // room - for storing data locally + implementation "androidx.room:room-ktx:$room_version" + implementation "androidx.room:room-runtime:$room_version" + annotationProcessor "androidx.room:room-compiler:$room_version" + kapt "androidx.room:room-compiler:$room_version" + // junit4 testImplementation "junit:junit:$junit_version" From 72b3235506ca03b24cda67eab93552056b28ab81 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:12:32 +0300 Subject: [PATCH 050/201] add local coin dto --- .../data/dto/CoinLocalDto.kt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinLocalDto.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinLocalDto.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinLocalDto.kt new file mode 100644 index 0000000..f542b3b --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinLocalDto.kt @@ -0,0 +1,40 @@ +package com.ryankoech.krypto.feature_coin_list.data.dto + +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin + +const val TANLENAME_COIN_DTO = "table_coin_dto" + +@Entity(tableName = TANLENAME_COIN_DTO) +data class CoinLocalDto( + val id : String, + val name : String, + val symbol : String, + @PrimaryKey(autoGenerate = false) + val marketCapRank : Int, + val image : String, + val change : Float, + val price : Double, + val marketCap : Long, + val allTimeHigh : Double, + val high24Hr : Double, + val totalVolume : Double, +) + + +fun List.toCoinEntity() : List = map { + Coin( + id = it.id, + name = it.name, + symbol = it.symbol, + price = it.price, + marketCapRank = it.marketCapRank, + image = it.image, + change = it.change, + marketCap = it.marketCap, + allTimeHigh = it.allTimeHigh, + high24Hr = it.high24Hr, + totalVolume = it.totalVolume + ) +} \ No newline at end of file From d02ed0ee2b1bbbd04ada39413c109614785b863d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:14:28 +0300 Subject: [PATCH 051/201] implement database and dao --- .../data/data_source/local/db/CoinDao.kt | 18 ++++++++++++++++++ .../data/data_source/local/db/CoinDatabase.kt | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDatabase.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt new file mode 100644 index 0000000..f316a1a --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt @@ -0,0 +1,18 @@ +package com.ryankoech.krypto.feature_coin_list.data.data_source.local.db + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto +import com.ryankoech.krypto.feature_coin_list.data.dto.TANLENAME_COIN_DTO + +@Dao +interface CoinDao { + + @Insert + suspend fun insertCoins(coins : List) + + @Query("SELECT * FROM $TANLENAME_COIN_DTO") + suspend fun getCoins() : List + +} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDatabase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDatabase.kt new file mode 100644 index 0000000..4bfdbd1 --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDatabase.kt @@ -0,0 +1,18 @@ +package com.ryankoech.krypto.feature_coin_list.data.data_source.local.db + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto + +const val DB_NAME = "coin_db" + +@Database( + entities = [CoinLocalDto::class], + version = 1, + exportSchema = false +) +abstract class CoinDatabase : RoomDatabase() { + + abstract fun getCoinDao() : CoinDao + +} \ No newline at end of file From d7f4d74a51600e663e062a842282316320ae33cc Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:15:26 +0300 Subject: [PATCH 052/201] implement local coin databse di mobule --- .../core/di/CoinListDatabaseModule.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinListDatabaseModule.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinListDatabaseModule.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinListDatabaseModule.kt new file mode 100644 index 0000000..262196b --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinListDatabaseModule.kt @@ -0,0 +1,33 @@ +package com.ryankoech.krypto.feature_coin_list.core.di + +import android.content.Context +import androidx.room.Room +import com.ryankoech.krypto.feature_coin_list.data.data_source.local.db.CoinDao +import com.ryankoech.krypto.feature_coin_list.data.data_source.local.db.CoinDatabase +import com.ryankoech.krypto.feature_coin_list.data.data_source.local.db.DB_NAME +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object CoinListDatabaseModule { + + @Provides + @Singleton + fun getCoinDatabase(@ApplicationContext context: Context) : CoinDatabase { + return Room.databaseBuilder( + context, + CoinDatabase::class.java, + DB_NAME, + ).fallbackToDestructiveMigration().build() + } + + @Provides + @Singleton + fun getCoinDao(coinDatabase: CoinDatabase) : CoinDao = coinDatabase.getCoinDao() + +} \ No newline at end of file From f7a625ae2edd148e9944765872031a99cffdddfe Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:19:19 +0300 Subject: [PATCH 053/201] implement type converter --- .../feature_coin_list/data/dto/CoinDto.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt index 0b860a3..554c023 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinDto.kt @@ -46,4 +46,21 @@ fun List.toCoinEntity() : List = high24Hr = it.high_24h, totalVolume = it.total_volume ) + } + +fun List.toLocalCoinDto() : List = + map { + CoinLocalDto( + id = it.id, + name = it.name, + symbol = it.symbol, + price = it.current_price, + marketCapRank = it.market_cap_rank, + image = it.image, + change = it.price_change_24h.toFloat(), + marketCap = it.market_cap, + allTimeHigh = it.ath, + high24Hr = it.high_24h, + totalVolume = it.total_volume + ) } \ No newline at end of file From cc6c0d47bbf06f3e77fac5ee40b9bd20312ddcf8 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:20:28 +0300 Subject: [PATCH 054/201] implement repositories to interact with dao --- .../data/repository/CoinRepositoryImpl.kt | 11 ++++++++++- .../data/repository/FakeCoinRepositoryImpl.kt | 9 +++++++++ .../domain/repository/CoinRepository.kt | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt index 1c89cdb..a0a4983 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt @@ -1,15 +1,24 @@ package com.ryankoech.krypto.feature_coin_list.data.repository +import com.ryankoech.krypto.feature_coin_list.data.data_source.local.db.CoinDao import com.ryankoech.krypto.feature_coin_list.data.data_source.remote.CoinServiceApi import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository import retrofit2.Response import javax.inject.Inject class CoinRepositoryImpl @Inject constructor( - private val api : CoinServiceApi + private val api : CoinServiceApi, + private val dao : CoinDao ) : CoinRepository { override suspend fun getCoins(): Response> = api.getCoins() + override suspend fun getLocalCoins(): List = dao.getCoins() + + override suspend fun saveCoins(coins: List) { + dao.insertCoins(coins) + } + } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt index 7cef8fa..4660107 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt @@ -1,9 +1,12 @@ package com.ryankoech.krypto.feature_coin_list.data.repository import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto import com.ryankoech.krypto.feature_coin_list.data.dto.Roi +import com.ryankoech.krypto.feature_coin_list.data.dto.toLocalCoinDto import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository import retrofit2.Response +import timber.log.Timber import javax.inject.Inject val FAKE_COIN_LIST = listOf( @@ -213,4 +216,10 @@ class FakeCoinRepositoryImpl @Inject constructor() : CoinRepository { override suspend fun getCoins(): Response> { return Response.success(FAKE_COIN_LIST) } + + override suspend fun getLocalCoins(): List = FAKE_COIN_LIST.toLocalCoinDto() + + override suspend fun saveCoins(coins: List) { + Timber.d("Saved Coins Successfully") + } } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt index 19236f1..d196128 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt @@ -1,10 +1,14 @@ package com.ryankoech.krypto.feature_coin_list.domain.repository import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto import retrofit2.Response interface CoinRepository { suspend fun getCoins() : Response> + suspend fun getLocalCoins() : List + + suspend fun saveCoins(coins : List) } \ No newline at end of file From 56db3ef872d79591c5b7e4db43257081c56ede09 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:23:47 +0300 Subject: [PATCH 055/201] implement usecase to fetch local coins --- .../domain/usecase/GetLocalCoinsUseCase.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinsUseCase.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinsUseCase.kt new file mode 100644 index 0000000..83f361a --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinsUseCase.kt @@ -0,0 +1,29 @@ +package com.ryankoech.krypto.feature_coin_list.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAMED_REPO +import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Named + +class GetLocalCoinsUseCase @Inject constructor( + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinRepository, +) { + + operator fun invoke() = flow>> { + emit(Resource.Success(repository.getLocalCoins().toCoinEntity())) + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + Timber.e(e) + emit(Resource.Error(e.localizedMessage ?: "An unexpected error occurred.")) + } + +} \ No newline at end of file From edb878349edbfe9967a2eed557a1e369801a129a Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:41:45 +0300 Subject: [PATCH 056/201] implement logic to save remote coins to db --- .../feature_coin_list/domain/usecase/GetCoinsUseCase.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index d28bf04..91a0008 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -4,6 +4,7 @@ import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.dto.toLocalCoinDto import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import com.ryankoech.krypto.feature_coin_list.domain.entity.Order import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy @@ -14,6 +15,7 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.onStart import retrofit2.Response import timber.log.Timber +import java.util.* import javax.inject.Inject import javax.inject.Named @@ -22,13 +24,18 @@ class GetCoinsUseCase @Inject constructor( ) { // Basic Cache - var cacheCoin : List? = null + private var cacheCoin : List? = null operator fun invoke(sortInfo: SortInfo, filterString : String = "") = flow { val response : Response> = if(cacheCoin.isNullOrEmpty()) { val response = repository.getCoins() cacheCoin = response.body() + + // Save to local + if(!cacheCoin.isNullOrEmpty()) { + repository.saveCoins(cacheCoin!!.toLocalCoinDto()) + } response } else { Response.success(cacheCoin) From b6696b42b5d64397880d31b5ce3e8760488a4ec7 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:43:44 +0300 Subject: [PATCH 057/201] implement local fallback when remote coin fetching fails --- .../viewmodel/CoinListScreenViewModel.kt | 50 ++++++++++++++++--- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt index 35357fb..5ce9d46 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt @@ -10,11 +10,11 @@ import com.ryankoech.krypto.feature_coin_list.domain.entity.Order import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetCoinsUseCase +import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetLocalCoinsUseCase import com.ryankoech.krypto.feature_coin_list.presentation.viewstate.CoinListScreenviewState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import timber.log.Timber import javax.inject.Inject val DEFAULT_SORT_INFO = SortInfo( @@ -24,7 +24,8 @@ val DEFAULT_SORT_INFO = SortInfo( @HiltViewModel class CoinListScreenViewModel @Inject constructor( - private val getCoinsUseCase: GetCoinsUseCase + private val getCoinsUseCase: GetCoinsUseCase, + private val getLocalCoinsUseCase : GetLocalCoinsUseCase ) : ViewModel() { private val _viewState = mutableStateOf(CoinListScreenviewState()) @@ -40,19 +41,14 @@ class CoinListScreenViewModel @Inject constructor( .onEach { res -> when(res){ is Resource.Error -> { - Timber.d("VM Error") - _viewState.value = _viewState.value.copy( - screenState = ScreenState.ERROR - ) + getLocalCoins() } is Resource.Loading -> { - Timber.d("VM Loading") _viewState.value = _viewState.value.copy( screenState = ScreenState.LOADING ) } is Resource.Success -> { - Timber.d("VM Success") _viewState.value = _viewState.value.copy( screenState = ScreenState.SUCCESS, coins = res.data!! @@ -69,4 +65,42 @@ class CoinListScreenViewModel @Inject constructor( } + + private fun getLocalCoins() { + + getLocalCoinsUseCase() + .onEach { res -> + when(res) { + is Resource.Error -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + is Resource.Loading -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING + ) + } + is Resource.Success -> { + if(res.data.isNullOrEmpty()){ + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + }else{ + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS, + coins = res.data!! + ) + } + } + else -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + } + }.launchIn(viewModelScope) + + } + } \ No newline at end of file From c1e2d32cfcda43d5e32a2724899e54c0fb6a976a Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 09:45:52 +0300 Subject: [PATCH 058/201] clear cache after period --- .../feature_coin_list/domain/usecase/GetCoinsUseCase.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index 91a0008..f49472f 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -32,6 +32,13 @@ class GetCoinsUseCase @Inject constructor( val response = repository.getCoins() cacheCoin = response.body() + // Clear cache after 1 minute + Timer().schedule(object : TimerTask() { + override fun run() { + cacheCoin = null + } + }, 60_000) + // Save to local if(!cacheCoin.isNullOrEmpty()) { repository.saveCoins(cacheCoin!!.toLocalCoinDto()) From 1df655d443894ba22bc63533e47ea16f2e645335 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 12:12:30 +0300 Subject: [PATCH 059/201] implement pull to refresh --- .../presentation/CoinListScreen.kt | 59 ++++++++++++++++--- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index f1732af..123ba76 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -1,8 +1,14 @@ package com.ryankoech.krypto.feature_coin_list.presentation +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Surface +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel @@ -12,7 +18,11 @@ import com.ryankoech.krypto.feature_coin_list.domain.entity.Order import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import timber.log.Timber +@OptIn(ExperimentalMaterialApi::class) @Composable fun CoinListScreen( viewModel: CoinListScreenViewModel = hiltViewModel(), @@ -20,6 +30,8 @@ fun CoinListScreen( ) { val viewState = viewModel.viewState.value + val refreshScope = rememberCoroutineScope() + var sortInfoState by remember { mutableStateOf( SortInfo( @@ -38,6 +50,22 @@ fun CoinListScreen( filterStringState = subString } + var isRefreshingState by remember { + mutableStateOf(false) + } + + fun refresh() = refreshScope.launch { + isRefreshingState = true + viewModel.getCoins(sortInfoState, filterStringState) + delay(500) + isRefreshingState = false + } + + val pullRefreshState = rememberPullRefreshState( + refreshing = isRefreshingState, + onRefresh = ::refresh + ) + fun editSortingInfo(sortCoinBy: SortCoinBy) { val newSortInfo = if(sortCoinBy == sortInfoState.sortBy){ @@ -68,14 +96,29 @@ fun CoinListScreen( if(viewState.screenState == ScreenState.ERROR) { CoinListScreenError(onButtonClick = { viewModel.getCoins(sortInfoState, filterStringState) }) }else { - CoinListScreenSuccess( - screenState = viewState.screenState, - editSortInfo = ::editSortingInfo, - sortInfoState = sortInfoState, - coins = viewState.coins, - filterStringState = filterStringState, - editFilterStringState = ::editFilterStringState - ) + + Box( + modifier = Modifier + .pullRefresh(pullRefreshState) + ){ + + CoinListScreenSuccess( + screenState = viewState.screenState, + editSortInfo = ::editSortingInfo, + sortInfoState = sortInfoState, + coins = viewState.coins, + filterStringState = filterStringState, + editFilterStringState = ::editFilterStringState + ) + + PullRefreshIndicator( + modifier = Modifier + .align(Alignment.TopCenter), + refreshing = isRefreshingState, + state = pullRefreshState, + ) + + } } } } From eab0fc263880505e859afe324ce84e389bb6e28f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 12:14:26 +0300 Subject: [PATCH 060/201] fix indentation --- .../viewmodel/CoinListScreenViewModel.kt | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt index 5ce9d46..a64b7a1 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt @@ -39,29 +39,29 @@ class CoinListScreenViewModel @Inject constructor( getCoinsUseCase(sortInfo, filterString) .onEach { res -> - when(res){ - is Resource.Error -> { - getLocalCoins() - } - is Resource.Loading -> { - _viewState.value = _viewState.value.copy( - screenState = ScreenState.LOADING - ) - } - is Resource.Success -> { - _viewState.value = _viewState.value.copy( - screenState = ScreenState.SUCCESS, - coins = res.data!! - ) - } - else -> { - _viewState.value = _viewState.value.copy( - screenState = ScreenState.ERROR - ) + when(res){ + is Resource.Error -> { + getLocalCoins() + } + is Resource.Loading -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING + ) + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS, + coins = res.data!! + ) + } + else -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } } - } - }.launchIn(viewModelScope) + }.launchIn(viewModelScope) } From 46a8d5e6d00354e1257691084c11e8c0f7fcb3a0 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 12:40:17 +0300 Subject: [PATCH 061/201] add coinItemCallbackOnClick callback --- .../krypto/feature_coin_list/presentation/CoinListScreen.kt | 4 +++- .../feature_coin_list/presentation/CoinListScreenSuccess.kt | 4 +++- .../presentation/components/success/CoinItem.kt | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index 123ba76..e4cc1fb 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -25,6 +25,7 @@ import timber.log.Timber @OptIn(ExperimentalMaterialApi::class) @Composable fun CoinListScreen( + coinItemOnClick : (String) -> Unit, viewModel: CoinListScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { @@ -103,6 +104,7 @@ fun CoinListScreen( ){ CoinListScreenSuccess( + coinItemOnClick = coinItemOnClick, screenState = viewState.screenState, editSortInfo = ::editSortingInfo, sortInfoState = sortInfoState, @@ -128,6 +130,6 @@ fun CoinListScreen( fun CoinListScreenPreview() { KryptoTheme { - CoinListScreen() + CoinListScreen({}) } } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index f06da54..c25eb55 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -25,6 +25,7 @@ import timber.log.Timber @Composable fun CoinListScreenSuccess( + coinItemOnClick : (String) -> Unit, screenState : ScreenState, editSortInfo : (SortCoinBy) -> Unit, sortInfoState : SortInfo, @@ -98,7 +99,7 @@ fun CoinListScreenSuccess( items = coins, key = { it.id } ){ coin -> - CoinItem(onClick = {}, coin = coin) + CoinItem(onClick = coinItemOnClick, coin = coin) Spacer(modifier = Modifier.height(24.dp)) } } @@ -117,6 +118,7 @@ fun CoinListSuccessScreenPreview(){ ) { CoinListScreenSuccess( + coinItemOnClick = {}, screenState = ScreenState.SUCCESS, editSortInfo = {}, sortInfoState = DEFAULT_SORT_INFO, diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt index ea455d0..23f408f 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt @@ -29,7 +29,7 @@ import com.ryankoech.krypto.feature_coin_list.presentation.theme.black200 @Composable fun CoinItem( - onClick : () -> Unit, + onClick : (String) -> Unit, coin: Coin, modifier: Modifier = Modifier ) { @@ -45,7 +45,7 @@ fun CoinItem( shape = RoundedCornerShape(10.dp) ) .clickable { - onClick() + onClick(coin.id) }, ) { CoinImage(coin.image, coin.id) From 80afdf36988b681a4c6dee14ea84076a54c6f086 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 13:22:26 +0300 Subject: [PATCH 062/201] add logic to get coin from db --- .../feature_coin_list/data/data_source/local/db/CoinDao.kt | 3 +++ .../feature_coin_list/data/repository/CoinRepositoryImpl.kt | 3 +++ .../data/repository/FakeCoinRepositoryImpl.kt | 2 ++ .../feature_coin_list/domain/repository/CoinRepository.kt | 2 ++ 4 files changed, 10 insertions(+) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt index f316a1a..f4cac38 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt @@ -15,4 +15,7 @@ interface CoinDao { @Query("SELECT * FROM $TANLENAME_COIN_DTO") suspend fun getCoins() : List + @Query("SELECT * FROM $TANLENAME_COIN_DTO WHERE id = :coinId") + suspend fun getCoin(coinId : String) : CoinLocalDto + } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt index a0a4983..1536968 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt @@ -21,4 +21,7 @@ class CoinRepositoryImpl @Inject constructor( dao.insertCoins(coins) } + override suspend fun getCoin(coinId: String): CoinLocalDto = dao.getCoin(coinId) + + } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt index 4660107..fd41d1f 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/FakeCoinRepositoryImpl.kt @@ -222,4 +222,6 @@ class FakeCoinRepositoryImpl @Inject constructor() : CoinRepository { override suspend fun saveCoins(coins: List) { Timber.d("Saved Coins Successfully") } + + override suspend fun getCoin(coinId: String): CoinLocalDto = FAKE_COIN_LIST.toLocalCoinDto().first() } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt index d196128..7f61d12 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt @@ -11,4 +11,6 @@ interface CoinRepository { suspend fun getLocalCoins() : List suspend fun saveCoins(coins : List) + + suspend fun getCoin(coinId : String) : CoinLocalDto } \ No newline at end of file From 18975d888fae85eaf3d6c0a56e4b68e47897257e Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 13:40:28 +0300 Subject: [PATCH 063/201] update name to use real repository --- .../krypto/feature_coin_list/core/di/CoinRepositoryModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinRepositoryModule.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinRepositoryModule.kt index 3a981e8..1f2e6f7 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinRepositoryModule.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/CoinRepositoryModule.kt @@ -12,7 +12,7 @@ import javax.inject.Singleton const val HILT_NAMED_REPO_FAKE = "FakeRepo" const val HILT_NAMED_REPO = "Repo" -const val HILT_NAME_REPO_FOR_ALL = HILT_NAMED_REPO_FAKE +const val HILT_NAME_REPO_FOR_ALL = HILT_NAMED_REPO @Module @InstallIn(SingletonComponent::class) From c0f79458200836ed2d35824a734a90bf8244256b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 13:41:12 +0300 Subject: [PATCH 064/201] update theme font size --- .../java/com/ryankoech/krypto/common/presentation/theme/Type.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Type.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Type.kt index defd285..4d10722 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Type.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Type.kt @@ -42,7 +42,7 @@ val Typography = Typography( caption = TextStyle( fontFamily = CircularStd, fontWeight = FontWeight.Medium, - fontSize = 12.sp, + fontSize = 14.sp, ), button = TextStyle( fontFamily = CircularStd, From 16eeae6e8a20ff5b563f88497b194b3d48c2a563 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 18:27:34 +0300 Subject: [PATCH 065/201] refactor varaible into companion object --- .../presentation/CoinListScreenSuccess.kt | 2 +- .../presentation/components/success/SearchTag.kt | 2 +- .../viewmodel/CoinListScreenViewModel.kt | 13 ++++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index c25eb55..61702b8 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -20,7 +20,7 @@ import com.ryankoech.krypto.feature_coin_list.presentation.components.success.Co import com.ryankoech.krypto.feature_coin_list.presentation.components.success.CoinListLoading import com.ryankoech.krypto.feature_coin_list.presentation.components.success.NoCoinsFound import com.ryankoech.krypto.feature_coin_list.presentation.components.success.SearchTag -import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SORT_INFO +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel.Companion.DEFAULT_SORT_INFO import timber.log.Timber @Composable diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt index e73a7e0..ef6191e 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/SearchTag.kt @@ -19,7 +19,7 @@ import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.theme.black100 import com.ryankoech.krypto.feature_coin_list.presentation.theme.limeGreenYellow400 -import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.DEFAULT_SORT_INFO +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel.Companion.DEFAULT_SORT_INFO @Composable fun SearchTag( diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt index a64b7a1..e4a6735 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt @@ -17,17 +17,20 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import javax.inject.Inject -val DEFAULT_SORT_INFO = SortInfo( - sortBy = SortCoinBy.MARKET_CAP, - order = Order.DESC -) - @HiltViewModel class CoinListScreenViewModel @Inject constructor( private val getCoinsUseCase: GetCoinsUseCase, private val getLocalCoinsUseCase : GetLocalCoinsUseCase ) : ViewModel() { + companion object{ + + val DEFAULT_SORT_INFO = SortInfo( + sortBy = SortCoinBy.MARKET_CAP, + order = Order.DESC + ) + } + private val _viewState = mutableStateOf(CoinListScreenviewState()) val viewState : State = _viewState From 687889f2de7b97b464e8ccd5b7af45bee890921d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 18:33:36 +0300 Subject: [PATCH 066/201] cleaned up code --- .../domain/usecase/GetCoinsUseCaseTest.kt | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt index 8cfcb38..a3e3576 100644 --- a/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt +++ b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt @@ -6,33 +6,27 @@ import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.data.repository.FakeCoinRepositoryImpl +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel.Companion.DEFAULT_SORT_INFO import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository import io.mockk.coEvery import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest -import org.junit.After -import org.junit.Before import org.junit.Test import retrofit2.Response @ExperimentalCoroutinesApi class GetCoinsUseCaseTest { - @Before - fun setUp() { - } - - @After - fun tearDown() { - } + private lateinit var repository: CoinRepository + private lateinit var getCoinsUseCase: GetCoinsUseCase @Test fun `response successful, return Resource type Success with data`() = runTest { - val getCoinsUseCase = GetCoinsUseCase(FakeCoinRepositoryImpl()) + getCoinsUseCase = GetCoinsUseCase(FakeCoinRepositoryImpl()) - getCoinsUseCase().test { + getCoinsUseCase(DEFAULT_SORT_INFO).test { awaitItem() val resource = awaitItem() @@ -45,9 +39,9 @@ class GetCoinsUseCaseTest { @Test fun `call flow onStart, return Resource type Loading`() = runTest{ - val getCoinsUseCase = GetCoinsUseCase(FakeCoinRepositoryImpl()) + getCoinsUseCase = GetCoinsUseCase(FakeCoinRepositoryImpl()) - getCoinsUseCase().test { + getCoinsUseCase(DEFAULT_SORT_INFO).test { assertThat(awaitItem()).isInstanceOf(Resource.Loading::class.java) awaitItem() @@ -58,11 +52,11 @@ class GetCoinsUseCaseTest { @Test fun `repository return null data, return Resource type Error`() = runTest { - val repository = mockk() + repository = mockk() coEvery { repository.getCoins() } returns Response.success(null) - val getCoinsUseCase = GetCoinsUseCase(repository) + getCoinsUseCase = GetCoinsUseCase(repository) - getCoinsUseCase().test { + getCoinsUseCase(DEFAULT_SORT_INFO).test { awaitItem() assertThat(awaitItem()).isInstanceOf(Resource.Error::class.java) @@ -73,11 +67,11 @@ class GetCoinsUseCaseTest { @Test fun `repository return empty list, return Resource type Error`() = runTest { - val repository = mockk() + repository = mockk() coEvery { repository.getCoins() } returns Response.success(listOf()) - val getCoinsUseCase = GetCoinsUseCase(repository) + getCoinsUseCase = GetCoinsUseCase(repository) - getCoinsUseCase().test { + getCoinsUseCase(DEFAULT_SORT_INFO).test { awaitItem() assertThat(awaitItem()).isInstanceOf(Resource.Error::class.java) @@ -89,11 +83,11 @@ class GetCoinsUseCaseTest { @Test fun `repository throws exception, return Resource type Error`() = runTest { val exceptionMessage = "Mock Exception Message" - val repository = mockk() + repository = mockk() coEvery { repository.getCoins() } throws Exception(exceptionMessage) - val getCoinsUseCase = GetCoinsUseCase(repository) + getCoinsUseCase = GetCoinsUseCase(repository) - getCoinsUseCase().test { + getCoinsUseCase(DEFAULT_SORT_INFO).test { awaitItem() val resource = awaitItem() From ab0dd8f4d35bb86b8356d16a791a2840f0188125 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 19:48:29 +0300 Subject: [PATCH 067/201] moved logic to handle remote failure to usecase --- .../domain/usecase/GetCoinsUseCase.kt | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index f49472f..e54e6ca 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -26,7 +26,7 @@ class GetCoinsUseCase @Inject constructor( // Basic Cache private var cacheCoin : List? = null - operator fun invoke(sortInfo: SortInfo, filterString : String = "") = flow { + operator fun invoke(sortInfo: SortInfo, filterString : String = "") = flow>> { val response : Response> = if(cacheCoin.isNullOrEmpty()) { val response = repository.getCoins() @@ -49,59 +49,73 @@ class GetCoinsUseCase @Inject constructor( } if(response.isSuccessful && !response.body().isNullOrEmpty()){ - val filteredCoins = response.body()!!.toCoinEntity().filter { - it.name.contains( - filterString, - true - ) || it.symbol.contains( - filterString, - true - ) - } - val sortedData = sortData(sortInfo, filteredCoins) - emit(Resource.Success(data = sortedData)) + val processedCoins = response.body()!!.toCoinEntity().processCoins(filterString, sortInfo) + emit(Resource.Success(processedCoins)) }else{ - emit(Resource.Error("Response not Successful.")) + throw Exception("Response not Successful.") } }.onStart { emit(Resource.Loading()) }.catch { e -> Timber.e(e) - emit(Resource.Error(e.localizedMessage ?: "Unexpected Error Occurred.")) + try{ + val coins = repository.getLocalCoins().toCoinEntity() + if(coins.isEmpty()){ + emit(Resource.Error(e.localizedMessage ?: "Unexpected Error Occurred.")) + }else { + val processedCoins = coins.processCoins(filterString, sortInfo) + emit(Resource.Success(processedCoins)) + } + }catch(e : Throwable) { + Timber.e(e) + emit(Resource.Error(e.localizedMessage ?: "Unexpected Error Occurred.")) + } } - private fun sortData(sortInfo: SortInfo, unsortedData : List) : List { + private fun List.sortData(sortInfo: SortInfo) : List { return when(sortInfo.sortBy){ SortCoinBy.MARKET_CAP -> { when(sortInfo.order){ Order.ASC -> { - unsortedData.sortedBy { it.marketCap } + sortedBy { it.marketCap } } Order.DESC -> { - unsortedData.sortedByDescending { it.marketCap } + sortedByDescending { it.marketCap } } } } SortCoinBy.TOTAL_VOLUME -> { when(sortInfo.order){ Order.ASC -> { - unsortedData.sortedBy { it.totalVolume } + sortedBy { it.totalVolume } } Order.DESC -> { - unsortedData.sortedByDescending { it.totalVolume } + sortedByDescending { it.totalVolume } } } } SortCoinBy.PRICE -> { when(sortInfo.order){ Order.ASC -> { - unsortedData.sortedBy { it.price } + sortedBy { it.price } } Order.DESC -> { - unsortedData.sortedByDescending { it.price} + sortedByDescending { it.price} } } } } } + + private fun List.processCoins(filterString: String, sortInfo: SortInfo) : List = + filter { + it.name.contains( + filterString, + true + ) || it.symbol.contains( + filterString, + true + ) + }.sortData(sortInfo) + } \ No newline at end of file From 5eebb742b71f263bcc4e471a07dc5b3996e60073 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 19:48:56 +0300 Subject: [PATCH 068/201] implement tests --- .../domain/usecase/GetCoinsUseCaseTest.kt | 82 +++++++++++++++++-- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt index a3e3576..8d84e15 100644 --- a/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt +++ b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt @@ -4,6 +4,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.dto.toLocalCoinDto import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.data.repository.FakeCoinRepositoryImpl import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel.Companion.DEFAULT_SORT_INFO @@ -12,6 +13,7 @@ import io.mockk.coEvery import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import okhttp3.ResponseBody import org.junit.Test import retrofit2.Response @@ -21,9 +23,10 @@ class GetCoinsUseCaseTest { private lateinit var repository: CoinRepository private lateinit var getCoinsUseCase: GetCoinsUseCase + private val exceptionMessage = "Mock Exception Message" @Test - fun `response successful, return Resource type Success with data`() = runTest { + fun `remote response successful, return Resource type Success with data`() = runTest { getCoinsUseCase = GetCoinsUseCase(FakeCoinRepositoryImpl()) getCoinsUseCase(DEFAULT_SORT_INFO).test { @@ -37,6 +40,27 @@ class GetCoinsUseCaseTest { } } + @Test + fun `remote response unsuccessful local successful, return Resource type Success with data`() = runTest { + repository = mockk() + val responseBody = mockk( + relaxed = true + ) + coEvery { repository.getCoins() } returns Response.error(400, responseBody) + coEvery { repository.getLocalCoins() } returns FAKE_COIN_LIST.toLocalCoinDto() + getCoinsUseCase = GetCoinsUseCase(repository) + + getCoinsUseCase(DEFAULT_SORT_INFO).test { + + awaitItem() + val resource = awaitItem() + assertThat(resource).isInstanceOf(Resource.Success::class.java) + assertThat(resource.data).isEqualTo(FAKE_COIN_LIST.toCoinEntity()) + awaitComplete() + + } + } + @Test fun `call flow onStart, return Resource type Loading`() = runTest{ getCoinsUseCase = GetCoinsUseCase(FakeCoinRepositoryImpl()) @@ -51,40 +75,67 @@ class GetCoinsUseCaseTest { } @Test - fun `repository return null data, return Resource type Error`() = runTest { + fun `remote return null data local return list, return Resource type Success with data`() = runTest { repository = mockk() coEvery { repository.getCoins() } returns Response.success(null) + coEvery { repository.getLocalCoins() } returns FAKE_COIN_LIST.toLocalCoinDto() getCoinsUseCase = GetCoinsUseCase(repository) getCoinsUseCase(DEFAULT_SORT_INFO).test { awaitItem() - assertThat(awaitItem()).isInstanceOf(Resource.Error::class.java) + val resource = awaitItem() + assertThat(resource).isInstanceOf(Resource.Success::class.java) + assertThat(resource.data).isEqualTo(FAKE_COIN_LIST.toCoinEntity()) awaitComplete() } } @Test - fun `repository return empty list, return Resource type Error`() = runTest { + fun `remote return empty list local return list, return Resource type Success with data`() = runTest { repository = mockk() coEvery { repository.getCoins() } returns Response.success(listOf()) + coEvery { repository.getLocalCoins() } returns FAKE_COIN_LIST.toLocalCoinDto() getCoinsUseCase = GetCoinsUseCase(repository) getCoinsUseCase(DEFAULT_SORT_INFO).test { awaitItem() - assertThat(awaitItem()).isInstanceOf(Resource.Error::class.java) + val resource = awaitItem() + assertThat(resource).isInstanceOf(Resource.Success::class.java) + assertThat(resource.data).isEqualTo(FAKE_COIN_LIST.toCoinEntity()) awaitComplete() } } @Test - fun `repository throws exception, return Resource type Error`() = runTest { - val exceptionMessage = "Mock Exception Message" + fun `remote throws exception list local return list, return Resource type Success with data`() = runTest { repository = mockk() coEvery { repository.getCoins() } throws Exception(exceptionMessage) + coEvery { repository.getLocalCoins() } returns FAKE_COIN_LIST.toLocalCoinDto() + getCoinsUseCase = GetCoinsUseCase(repository) + + getCoinsUseCase(DEFAULT_SORT_INFO).test { + + awaitItem() + val resource = awaitItem() + assertThat(resource).isInstanceOf(Resource.Success::class.java) + assertThat(resource.data).isEqualTo(FAKE_COIN_LIST.toCoinEntity()) + awaitComplete() + + } + } + + @Test + fun `remote unsuccessful local throw Exception, return Resource type Error`() = runTest { + repository = mockk() + val responseBody = mockk( + relaxed = true + ) + coEvery { repository.getCoins() } returns Response.error(400, responseBody) + coEvery { repository.getLocalCoins() } throws Exception(exceptionMessage) getCoinsUseCase = GetCoinsUseCase(repository) getCoinsUseCase(DEFAULT_SORT_INFO).test { @@ -98,4 +149,21 @@ class GetCoinsUseCaseTest { } } + @Test + fun `remote unsuccessful local return empty list, return Resource type Error`() = runTest { + repository = mockk() + coEvery { repository.getCoins() } throws Exception(exceptionMessage) + coEvery { repository.getLocalCoins() } returns listOf() + getCoinsUseCase = GetCoinsUseCase(repository) + + getCoinsUseCase(DEFAULT_SORT_INFO).test { + + awaitItem() + val resource = awaitItem() + assertThat(resource).isInstanceOf(Resource.Error::class.java) + assertThat(resource.message).isEqualTo(exceptionMessage) + awaitComplete() + + } + } } \ No newline at end of file From 25eea344d22b3bc1f630f8e8ab2c0ddaa92db05e Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 19:49:26 +0300 Subject: [PATCH 069/201] refactored usecase deletion --- .../domain/usecase/GetLocalCoinsUseCase.kt | 29 ------------ .../viewmodel/CoinListScreenViewModel.kt | 44 ++----------------- 2 files changed, 3 insertions(+), 70 deletions(-) delete mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinsUseCase.kt diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinsUseCase.kt deleted file mode 100644 index 83f361a..0000000 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinsUseCase.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.ryankoech.krypto.feature_coin_list.domain.usecase - -import com.ryankoech.krypto.common.core.util.Resource -import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAMED_REPO -import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL -import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity -import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin -import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.onStart -import timber.log.Timber -import javax.inject.Inject -import javax.inject.Named - -class GetLocalCoinsUseCase @Inject constructor( - @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinRepository, -) { - - operator fun invoke() = flow>> { - emit(Resource.Success(repository.getLocalCoins().toCoinEntity())) - }.onStart { - emit(Resource.Loading()) - }.catch { e -> - Timber.e(e) - emit(Resource.Error(e.localizedMessage ?: "An unexpected error occurred.")) - } - -} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt index e4a6735..d79b462 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/viewmodel/CoinListScreenViewModel.kt @@ -10,7 +10,6 @@ import com.ryankoech.krypto.feature_coin_list.domain.entity.Order import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetCoinsUseCase -import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetLocalCoinsUseCase import com.ryankoech.krypto.feature_coin_list.presentation.viewstate.CoinListScreenviewState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn @@ -20,7 +19,6 @@ import javax.inject.Inject @HiltViewModel class CoinListScreenViewModel @Inject constructor( private val getCoinsUseCase: GetCoinsUseCase, - private val getLocalCoinsUseCase : GetLocalCoinsUseCase ) : ViewModel() { companion object{ @@ -44,7 +42,9 @@ class CoinListScreenViewModel @Inject constructor( .onEach { res -> when(res){ is Resource.Error -> { - getLocalCoins() + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) } is Resource.Loading -> { _viewState.value = _viewState.value.copy( @@ -68,42 +68,4 @@ class CoinListScreenViewModel @Inject constructor( } - - private fun getLocalCoins() { - - getLocalCoinsUseCase() - .onEach { res -> - when(res) { - is Resource.Error -> { - _viewState.value = _viewState.value.copy( - screenState = ScreenState.ERROR - ) - } - is Resource.Loading -> { - _viewState.value = _viewState.value.copy( - screenState = ScreenState.LOADING - ) - } - is Resource.Success -> { - if(res.data.isNullOrEmpty()){ - _viewState.value = _viewState.value.copy( - screenState = ScreenState.ERROR - ) - }else{ - _viewState.value = _viewState.value.copy( - screenState = ScreenState.SUCCESS, - coins = res.data!! - ) - } - } - else -> { - _viewState.value = _viewState.value.copy( - screenState = ScreenState.ERROR - ) - } - } - }.launchIn(viewModelScope) - - } - } \ No newline at end of file From 33c8d5058c2785a00861f2cd05b4410217173b92 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 20:00:27 +0300 Subject: [PATCH 070/201] android test truth dependency --- feature_coin_list/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feature_coin_list/build.gradle b/feature_coin_list/build.gradle index f0a1c7e..de4f685 100644 --- a/feature_coin_list/build.gradle +++ b/feature_coin_list/build.gradle @@ -102,4 +102,7 @@ dependencies { androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" + + // google truth + androidTestImplementation "com.google.truth:truth:$google_truth_version" } \ No newline at end of file From 1ab04e4f87e2fe8236b5608d285d196f81ceb969 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 12 Jan 2023 20:00:49 +0300 Subject: [PATCH 071/201] implement dao tests --- .../data/data_source/local/db/CoinDaoTest.kt | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDaoTest.kt diff --git a/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDaoTest.kt b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDaoTest.kt new file mode 100644 index 0000000..10b2b24 --- /dev/null +++ b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDaoTest.kt @@ -0,0 +1,66 @@ +package com.ryankoech.krypto.feature_coin_list.data.data_source.local.db + +import android.content.Context +import androidx.room.Room +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import com.ryankoech.krypto.feature_coin_list.data.dto.toLocalCoinDto +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@RunWith(AndroidJUnit4::class) +class CoinDaoTest { + + + private lateinit var database: CoinDatabase + private lateinit var dao : CoinDao + + @Before + fun setUp() { + database = Room.inMemoryDatabaseBuilder( + ApplicationProvider.getApplicationContext().applicationContext, + CoinDatabase::class.java + ) + .allowMainThreadQueries() + .build() + dao = database.getCoinDao() + } + + @After + fun tearDown() { + database.close() + } + + @Test + fun insert_into_and_fetch_list_from_Db__both_lists_equal() = runTest{ + + dao.insertCoins(FAKE_COIN_LIST.toLocalCoinDto()) + + runBlocking{ + val listOfCoins = dao.getCoins() + assertThat(listOfCoins).isEqualTo(FAKE_COIN_LIST.toLocalCoinDto()) + } + } + + + @Test + fun insert_into_and_fetch_from_Db__contain_element_in_list() = runTest{ + + dao.insertCoins(FAKE_COIN_LIST.toLocalCoinDto()) + + runBlocking{ + val coin = dao.getCoin(FAKE_COIN_LIST.toLocalCoinDto().first().id) + assertThat(coin).isEqualTo(FAKE_COIN_LIST.toLocalCoinDto().first()) + } + } + + +} \ No newline at end of file From d9e86d4a5a23a8697cd74a0d3ef9927a26e549a4 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 13 Jan 2023 12:09:23 +0300 Subject: [PATCH 072/201] add test tags --- .../presentation/CoinListScreen.kt | 9 ++++++++- .../presentation/CoinListScreenError.kt | 4 +++- .../presentation/CoinListScreenSuccess.kt | 13 ++++++++----- .../components/success/CoinListLoading.kt | 2 ++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index e4cc1fb..fbc2501 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import com.ryankoech.krypto.common.presentation.theme.KryptoTheme @@ -95,7 +96,11 @@ fun CoinListScreen( ) { if(viewState.screenState == ScreenState.ERROR) { - CoinListScreenError(onButtonClick = { viewModel.getCoins(sortInfoState, filterStringState) }) + CoinListScreenError( + modifier = Modifier + .testTag(TEST_TAG_COIN_LIST_SCREEN_ERROR), + onButtonClick = { viewModel.getCoins(sortInfoState, filterStringState) } + ) }else { Box( @@ -104,6 +109,8 @@ fun CoinListScreen( ){ CoinListScreenSuccess( + modifier = Modifier + .testTag(TEST_TAG_COIN_LIST_SCREEN_SUCCESS), coinItemOnClick = coinItemOnClick, screenState = viewState.screenState, editSortInfo = ::editSortingInfo, diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenError.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenError.kt index 6e86a66..f43787e 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenError.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenError.kt @@ -8,13 +8,15 @@ import com.ryankoech.krypto.common.presentation.ErrorScreen import com.ryankoech.krypto.common.R import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +const val TEST_TAG_COIN_LIST_SCREEN_ERROR = "test tag coin list screen error" + @Composable fun CoinListScreenError( onButtonClick: () -> Unit, modifier: Modifier = Modifier, ){ - ErrorScreen(onButtonClick = onButtonClick, messageText = "Hmm, can't seem to find any coins", buttonText = "Try Again", res = R.drawable.icon_gif_caution) + ErrorScreen(modifier = modifier, onButtonClick = onButtonClick, messageText = "Hmm, can't seem to find any coins", buttonText = "Try Again", res = R.drawable.icon_gif_caution) } diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index 61702b8..42ae98b 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.lazy.items import androidx.compose.material.Surface import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.components.SearchBar @@ -16,13 +17,12 @@ import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo -import com.ryankoech.krypto.feature_coin_list.presentation.components.success.CoinItem -import com.ryankoech.krypto.feature_coin_list.presentation.components.success.CoinListLoading -import com.ryankoech.krypto.feature_coin_list.presentation.components.success.NoCoinsFound -import com.ryankoech.krypto.feature_coin_list.presentation.components.success.SearchTag +import com.ryankoech.krypto.feature_coin_list.presentation.components.success.* import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel.Companion.DEFAULT_SORT_INFO import timber.log.Timber +const val TEST_TAG_COIN_LIST_SCREEN_SUCCESS = "test tag coin list screen success" + @Composable fun CoinListScreenSuccess( coinItemOnClick : (String) -> Unit, @@ -81,7 +81,10 @@ fun CoinListScreenSuccess( } if(screenState == ScreenState.LOADING) { - CoinListLoading() + CoinListLoading( + modifier = Modifier + .testTag(TEST_TAG_COIN_LIST_LOADING) + ) } else { if( coins.isEmpty() ) { diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinListLoading.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinListLoading.kt index 70a73eb..fe2a4e3 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinListLoading.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinListLoading.kt @@ -11,6 +11,8 @@ import com.ryankoech.krypto.common.presentation.components.loading.CoinCardLoadi import com.ryankoech.krypto.common.presentation.components.loading.loadingEffect import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +const val TEST_TAG_COIN_LIST_LOADING = "test tag coin list loading" + @Composable fun CoinListLoading( modifier: Modifier = Modifier From f0501610f8a35bdaeb299d316d10a68fc275ed3b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 13 Jan 2023 12:12:43 +0300 Subject: [PATCH 073/201] update dependencies --- feature_coin_list/build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/feature_coin_list/build.gradle b/feature_coin_list/build.gradle index de4f685..39b5259 100644 --- a/feature_coin_list/build.gradle +++ b/feature_coin_list/build.gradle @@ -36,6 +36,9 @@ android { composeOptions { kotlinCompilerExtensionVersion compose_version } + packagingOptions { + resources.excludes.add("META-INF/*") + } } dependencies { @@ -105,4 +108,8 @@ dependencies { // google truth androidTestImplementation "com.google.truth:truth:$google_truth_version" + + // mockk + androidTestImplementation "io.mockk:mockk-android:$mockk_version" + androidTestImplementation "io.mockk:mockk-agent:$mockk_version" } \ No newline at end of file From 1ae3b45d26b983e3df6fa7197aff8d629cd99b8d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 13 Jan 2023 12:18:47 +0300 Subject: [PATCH 074/201] implement tests --- .../feature_coin_list/core/util/Util.kt | 9 ++ .../presentation/CoinListScreenTest.kt | 101 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/core/util/Util.kt create mode 100644 feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenTest.kt diff --git a/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/core/util/Util.kt b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/core/util/Util.kt new file mode 100644 index 0000000..8452a2a --- /dev/null +++ b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/core/util/Util.kt @@ -0,0 +1,9 @@ +package com.ryankoech.krypto.feature_coin_list.core.util + +class Util { + + companion object { + const val MOCK_EXCEPTION_MESSAGE = "mock exception message" + } + +} \ No newline at end of file diff --git a/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenTest.kt b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenTest.kt new file mode 100644 index 0000000..7216cc9 --- /dev/null +++ b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenTest.kt @@ -0,0 +1,101 @@ +package com.ryankoech.krypto.feature_coin_list.presentation + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithTag +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_coin_list.core.util.Util.Companion.MOCK_EXCEPTION_MESSAGE +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetCoinsUseCase +import com.ryankoech.krypto.feature_coin_list.presentation.components.success.TEST_TAG_COIN_LIST_LOADING +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel +import io.mockk.coEvery +import io.mockk.impl.annotations.MockK +import io.mockk.junit4.MockKRule +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +import org.junit.Rule +import org.junit.Test + +class CoinListScreenTest { + + + @get:Rule + val composeTestRule = createAndroidComposeRule() + + @get:Rule + val mockkRule = MockKRule(this) + + @MockK + private lateinit var getCoinsUseCase: GetCoinsUseCase + + private lateinit var coinFlow : Flow>> + + private lateinit var viewModel: CoinListScreenViewModel + + @Test + fun fetchCoinsError_displayErrorScreen() { + coinFlow = flow { + emit(Resource.Error(MOCK_EXCEPTION_MESSAGE)) + } + + coEvery { getCoinsUseCase(any()) } returns coinFlow + viewModel = CoinListScreenViewModel(getCoinsUseCase) + + composeTestRule.setContent { + KryptoTheme { + CoinListScreen( + coinItemOnClick = {}, + viewModel = viewModel + ) + } + } + + composeTestRule.onNodeWithTag(TEST_TAG_COIN_LIST_SCREEN_ERROR).assertIsDisplayed() + } + + @Test + fun fetchCoinsLoading_displayCoinListLoading() { + coinFlow = flow { + emit(Resource.Loading()) + } + + coEvery { getCoinsUseCase(any()) } returns coinFlow + viewModel = CoinListScreenViewModel(getCoinsUseCase) + + composeTestRule.setContent { + KryptoTheme { + CoinListScreen( + coinItemOnClick = {}, + viewModel = viewModel + ) + } + } + + composeTestRule.onNodeWithTag(TEST_TAG_COIN_LIST_LOADING).assertIsDisplayed() + } + + @Test + fun fetchCoinsSuccess_displayCoinListScreenSuccess() { + coinFlow = flow { + emit(Resource.Success(listOf())) + } + + coEvery { getCoinsUseCase(any()) } returns coinFlow + viewModel = CoinListScreenViewModel(getCoinsUseCase) + + composeTestRule.setContent { + KryptoTheme { + CoinListScreen( + coinItemOnClick = {}, + viewModel = viewModel + ) + } + } + + composeTestRule.onNodeWithTag(TEST_TAG_COIN_LIST_SCREEN_SUCCESS).assertIsDisplayed() + } +} \ No newline at end of file From 057eb14b1fb189806251afbf0ba2d57aa136f997 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 13 Jan 2023 13:32:07 +0300 Subject: [PATCH 075/201] add test tags --- .../presentation/CoinListScreenSuccess.kt | 9 +++++++-- .../presentation/components/success/NoCoinsFound.kt | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index 42ae98b..86e5bdc 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -22,6 +22,7 @@ import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScr import timber.log.Timber const val TEST_TAG_COIN_LIST_SCREEN_SUCCESS = "test tag coin list screen success" +const val TEST_TAG_COIN_LIST_SCREEN_SUCCESS_COINS_LAZY_COLUMN = "test tag coin list screen success coins lazy column" @Composable fun CoinListScreenSuccess( @@ -88,12 +89,16 @@ fun CoinListScreenSuccess( } else { if( coins.isEmpty() ) { - NoCoinsFound() + NoCoinsFound( + modifier = Modifier + .testTag(TEST_TAG_NO_COINS_FOUND) + ) }else { LazyColumn( modifier = Modifier - .weight(1f), + .weight(1f) + .testTag(TEST_TAG_COIN_LIST_SCREEN_SUCCESS_COINS_LAZY_COLUMN), contentPadding = PaddingValues( top = 12.dp, start = 12.dp, end = 12.dp ) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt index a3ac3fc..64fbe99 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/NoCoinsFound.kt @@ -9,6 +9,8 @@ import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.R import com.ryankoech.krypto.common.presentation.ErrorScreen +const val TEST_TAG_NO_COINS_FOUND = "test tag no coins found" + @Composable fun NoCoinsFound( modifier: Modifier = Modifier, From f40cc0607b81055546c67d2e8c73e9ab92925f68 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 13 Jan 2023 13:32:28 +0300 Subject: [PATCH 076/201] implement tests --- .../presentation/CoinListScreenSuccessTest.kt | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccessTest.kt diff --git a/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccessTest.kt b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccessTest.kt new file mode 100644 index 0000000..82114aa --- /dev/null +++ b/feature_coin_list/src/androidTest/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccessTest.kt @@ -0,0 +1,66 @@ +package com.ryankoech.krypto.feature_coin_list.presentation + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetCoinsUseCase +import com.ryankoech.krypto.feature_coin_list.presentation.components.success.TEST_TAG_NO_COINS_FOUND +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test + +class CoinListScreenSuccessTest { + + @get:Rule + val composeTest = createComposeRule() + + @Test + fun receivesEmptyCoinList_displayNoCoinFallback() { + + composeTest.setContent { + KryptoTheme { + CoinListScreenSuccess( + coinItemOnClick = {}, + screenState = ScreenState.SUCCESS, + editSortInfo = {}, + sortInfoState = CoinListScreenViewModel.DEFAULT_SORT_INFO, + coins = listOf(), + filterStringState = "", + editFilterStringState = {} + ) + } + } + + composeTest.onNodeWithTag(TEST_TAG_NO_COINS_FOUND).assertIsDisplayed() + + } + + @Test + fun receivesCoinList_displayCoinsList() { + + composeTest.setContent { + KryptoTheme { + CoinListScreenSuccess( + coinItemOnClick = {}, + screenState = ScreenState.SUCCESS, + editSortInfo = {}, + sortInfoState = CoinListScreenViewModel.DEFAULT_SORT_INFO, + coins = FAKE_COIN_LIST.toCoinEntity(), + filterStringState = "", + editFilterStringState = {} + ) + } + } + + composeTest.onNodeWithTag(TEST_TAG_COIN_LIST_SCREEN_SUCCESS_COINS_LAZY_COLUMN).assertIsDisplayed() + composeTest.onNodeWithText(FAKE_COIN_LIST.toCoinEntity().first().name).assertIsDisplayed() + + } + +} \ No newline at end of file From efe413bca58fd1ab7aba865e112581f0b9af5d25 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 13 Jan 2023 13:36:30 +0300 Subject: [PATCH 077/201] implement sorting tests --- .../domain/usecase/GetCoinsUseCase.kt | 78 +++++----- .../domain/usecase/GetCoinsUseCaseTest.kt | 147 +++++++++++++++++- 2 files changed, 187 insertions(+), 38 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt index e54e6ca..9e6c955 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCase.kt @@ -13,6 +13,7 @@ import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.onStart +import org.jetbrains.annotations.VisibleForTesting import retrofit2.Response import timber.log.Timber import java.util.* @@ -71,51 +72,54 @@ class GetCoinsUseCase @Inject constructor( emit(Resource.Error(e.localizedMessage ?: "Unexpected Error Occurred.")) } } - - private fun List.sortData(sortInfo: SortInfo) : List { - return when(sortInfo.sortBy){ - SortCoinBy.MARKET_CAP -> { - when(sortInfo.order){ - Order.ASC -> { - sortedBy { it.marketCap } - } - Order.DESC -> { - sortedByDescending { it.marketCap } + companion object{ + @VisibleForTesting + fun List.sortData(sortInfo: SortInfo): List { + return when (sortInfo.sortBy) { + SortCoinBy.MARKET_CAP -> { + when (sortInfo.order) { + Order.ASC -> { + sortedBy { it.marketCap } + } + Order.DESC -> { + sortedByDescending { it.marketCap } + } } } - } - SortCoinBy.TOTAL_VOLUME -> { - when(sortInfo.order){ - Order.ASC -> { - sortedBy { it.totalVolume } - } - Order.DESC -> { - sortedByDescending { it.totalVolume } + SortCoinBy.TOTAL_VOLUME -> { + when (sortInfo.order) { + Order.ASC -> { + sortedBy { it.totalVolume } + } + Order.DESC -> { + sortedByDescending { it.totalVolume } + } } } - } - SortCoinBy.PRICE -> { - when(sortInfo.order){ - Order.ASC -> { - sortedBy { it.price } - } - Order.DESC -> { - sortedByDescending { it.price} + SortCoinBy.PRICE -> { + when (sortInfo.order) { + Order.ASC -> { + sortedBy { it.price } + } + Order.DESC -> { + sortedByDescending { it.price } + } } } } } - } - private fun List.processCoins(filterString: String, sortInfo: SortInfo) : List = - filter { - it.name.contains( - filterString, - true - ) || it.symbol.contains( - filterString, - true - ) - }.sortData(sortInfo) + @VisibleForTesting + fun List.processCoins(filterString: String, sortInfo: SortInfo): List = + filter { + it.name.contains( + filterString, + true + ) || it.symbol.contains( + filterString, + true + ) + }.sortData(sortInfo) + } } \ No newline at end of file diff --git a/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt index 8d84e15..cf0e605 100644 --- a/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt +++ b/feature_coin_list/src/test/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetCoinsUseCaseTest.kt @@ -7,13 +7,19 @@ import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.dto.toLocalCoinDto import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.data.repository.FakeCoinRepositoryImpl +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_coin_list.domain.entity.Order +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy +import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel.Companion.DEFAULT_SORT_INFO import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetCoinsUseCase.Companion.sortData import io.mockk.coEvery import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import okhttp3.ResponseBody +import org.junit.Before import org.junit.Test import retrofit2.Response @@ -21,9 +27,60 @@ import retrofit2.Response @ExperimentalCoroutinesApi class GetCoinsUseCaseTest { + private val sortByPrice = "price" + private val sortByTotalVolume = "totalVolume" + private val sortByMarketCap = "marketCap" + private val rank1 = "#1" + private val rank3 = "#3" + private val exceptionMessage = "Mock Exception Message" private lateinit var repository: CoinRepository private lateinit var getCoinsUseCase: GetCoinsUseCase - private val exceptionMessage = "Mock Exception Message" + private lateinit var testCoinsList : List + + @Before + fun setUp() { + testCoinsList = listOf( + Coin( + id = "$sortByPrice$rank1,$sortByMarketCap$rank3", + name = "coin1", + marketCap = 0, + marketCapRank = 3, + symbol = "", + image = "", + change = 0f, + price = 3.0, + allTimeHigh = 0.0, + high24Hr = 0.0, + totalVolume = 2.0, + ), + Coin( + id = "$sortByTotalVolume$rank1", + name = "coin2", + marketCap = 0, + marketCapRank = 2, + symbol = "", + image = "", + change = 0f, + price = 2.0, + allTimeHigh = 0.0, + high24Hr = 0.0, + totalVolume = 3.0, + ), + Coin( + id = "$sortByPrice$rank3,$sortByTotalVolume$rank3,$sortByMarketCap$rank1", + name = "coin3", + marketCap = 0, + marketCapRank = 1, + symbol = "", + image = "", + change = 0f, + price = 1.0, + allTimeHigh = 0.0, + high24Hr = 0.0, + totalVolume = 1.0, + ) + ) + } @Test fun `remote response successful, return Resource type Success with data`() = runTest { @@ -166,4 +223,92 @@ class GetCoinsUseCaseTest { } } + + @Test + fun `coin list sorting function sort by market cap descending`() { + + testCoinsList.sortData( + SortInfo( + sortBy = SortCoinBy.MARKET_CAP, + order = Order.DESC + ) + ).apply { + this.first().id.contains("$sortByMarketCap$rank1") + this.last().id.contains("$sortByMarketCap$rank3") + } + } + + @Test + fun `coin list sorting function sort by market cap ascending`() { + + testCoinsList.sortData( + SortInfo( + sortBy = SortCoinBy.MARKET_CAP, + order = Order.ASC + ) + ).apply { + this.first().id.contains("$sortByMarketCap$rank3") + this.last().id.contains("$sortByMarketCap$rank1") + } + } + + + @Test + fun `coin list sorting function sort by price descending`() { + + testCoinsList.sortData( + SortInfo( + sortBy = SortCoinBy.PRICE, + order = Order.DESC + ) + ).apply { + this.first().id.contains("$sortByPrice$rank1") + this.last().id.contains("$sortByPrice$rank3") + } + } + + + @Test + fun `coin list sorting function sort by price ascending`() { + + testCoinsList.sortData( + SortInfo( + sortBy = SortCoinBy.PRICE, + order = Order.ASC + ) + ).apply { + this.first().id.contains("$sortByMarketCap$rank3") + this.last().id.contains("$sortByMarketCap$rank1") + } + } + + @Test + fun `coin list sorting function sort by total volume descending`() { + + testCoinsList.sortData( + SortInfo( + sortBy = SortCoinBy.TOTAL_VOLUME, + order = Order.DESC + ) + ).apply { + this.first().id.contains("$sortByTotalVolume$rank1") + this.last().id.contains("$sortByPrice$rank3") + } + } + + + @Test + fun `coin list sorting function sort by total volume ascending`() { + + testCoinsList.sortData( + SortInfo( + sortBy = SortCoinBy.TOTAL_VOLUME, + order = Order.ASC + ) + ).apply { + this.first().id.contains("$sortByTotalVolume$rank3") + this.last().id.contains("$sortByPrice$rank1") + } + } + } \ No newline at end of file From 108e8a8067d927f8290e4096632cd34e5eb60d8f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 13 Jan 2023 13:36:48 +0300 Subject: [PATCH 078/201] added internet permission --- feature_coin_list/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature_coin_list/src/main/AndroidManifest.xml b/feature_coin_list/src/main/AndroidManifest.xml index a5918e6..ecebd57 100644 --- a/feature_coin_list/src/main/AndroidManifest.xml +++ b/feature_coin_list/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file From caaef2d583d8eb205186522c88446263a7b3a44b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 16 Jan 2023 15:24:06 +0300 Subject: [PATCH 079/201] add transaction feature module --- feature_transaction/.gitignore | 1 + feature_transaction/build.gradle | 41 +++++++++++++++++++ feature_transaction/consumer-rules.pro | 0 feature_transaction/proguard-rules.pro | 21 ++++++++++ .../ExampleInstrumentedTest.kt | 24 +++++++++++ .../src/main/AndroidManifest.xml | 4 ++ .../feature_transaction/ExampleUnitTest.kt | 17 ++++++++ settings.gradle | 1 + 8 files changed, 109 insertions(+) create mode 100644 feature_transaction/.gitignore create mode 100644 feature_transaction/build.gradle create mode 100644 feature_transaction/consumer-rules.pro create mode 100644 feature_transaction/proguard-rules.pro create mode 100644 feature_transaction/src/androidTest/java/com/ryankoech/krypto/feature_transaction/ExampleInstrumentedTest.kt create mode 100644 feature_transaction/src/main/AndroidManifest.xml create mode 100644 feature_transaction/src/test/java/com/ryankoech/krypto/feature_transaction/ExampleUnitTest.kt diff --git a/feature_transaction/.gitignore b/feature_transaction/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/feature_transaction/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature_transaction/build.gradle b/feature_transaction/build.gradle new file mode 100644 index 0000000..82abc0a --- /dev/null +++ b/feature_transaction/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.ryankoech.krypto.feature_transaction' + compileSdk 32 + + defaultConfig { + minSdk 21 + targetSdk 32 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'com.google.android.material:material:1.7.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} \ No newline at end of file diff --git a/feature_transaction/consumer-rules.pro b/feature_transaction/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/feature_transaction/proguard-rules.pro b/feature_transaction/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/feature_transaction/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature_transaction/src/androidTest/java/com/ryankoech/krypto/feature_transaction/ExampleInstrumentedTest.kt b/feature_transaction/src/androidTest/java/com/ryankoech/krypto/feature_transaction/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..2c8491c --- /dev/null +++ b/feature_transaction/src/androidTest/java/com/ryankoech/krypto/feature_transaction/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.ryankoech.krypto.feature_transaction + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.ryankoech.krypto.feature_transaction.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/feature_transaction/src/main/AndroidManifest.xml b/feature_transaction/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/feature_transaction/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/feature_transaction/src/test/java/com/ryankoech/krypto/feature_transaction/ExampleUnitTest.kt b/feature_transaction/src/test/java/com/ryankoech/krypto/feature_transaction/ExampleUnitTest.kt new file mode 100644 index 0000000..8ab1ca1 --- /dev/null +++ b/feature_transaction/src/test/java/com/ryankoech/krypto/feature_transaction/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.ryankoech.krypto.feature_transaction + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index b5de30d..d721631 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,3 +17,4 @@ include ':app' include ':feature_home' include ':common' include ':feature_coin_list' +include ':feature_transaction' From 8014dd691e76b08b6c94ea17e0fe66231ba65abd Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 16 Jan 2023 15:56:02 +0300 Subject: [PATCH 080/201] setup basic dependencies --- feature_transaction/build.gradle | 39 +++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/feature_transaction/build.gradle b/feature_transaction/build.gradle index 82abc0a..6c24d08 100644 --- a/feature_transaction/build.gradle +++ b/feature_transaction/build.gradle @@ -1,15 +1,17 @@ plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'dagger.hilt.android.plugin' + id 'kotlin-kapt' } android { namespace 'com.ryankoech.krypto.feature_transaction' - compileSdk 32 + compileSdk 33 defaultConfig { minSdk 21 - targetSdk 32 + targetSdk 33 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -32,10 +34,31 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.5.1' - implementation 'com.google.android.material:material:1.7.0' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + // core android + implementation "androidx.core:core-ktx:$ktx_core_version" + implementation "androidx.appcompat:appcompat:$app_compat_version" + implementation "com.google.android.material:material:$material_version" + + // local modules + implementation project(":feature_coin_list") + implementation project(":common") + + // timber + implementation "com.jakewharton.timber:timber:$timber_version" + + // dagger-hilt - for dependency injection + implementation "com.google.dagger:hilt-android:$hilt_android_version" + implementation "androidx.hilt:hilt-navigation-compose:$hilt_navigation_compose_version" + implementation project(path: ':feature_coin_list') + kapt "com.google.dagger:hilt-android-compiler:$hilt_android_compile_version" + kapt "androidx.hilt:hilt-compiler:$hilt_compile_version" + + // junit4 + testImplementation "junit:junit:$junit_version" + + // junit4 + androidTestImplementation "androidx.test.ext:junit:$junit_ext_version" + + // espresso + androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" } \ No newline at end of file From 51f4233433bae79a7aa01e06d06070e98f31229d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:46:33 +0300 Subject: [PATCH 081/201] improved resusability of component --- .../common/presentation/components/CoinImage.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/CoinImage.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/CoinImage.kt index 940cc5a..405e776 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/CoinImage.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/CoinImage.kt @@ -18,12 +18,17 @@ import coil.request.ImageRequest import com.ryankoech.krypto.common.R @Composable -fun CoinImage(url : String, name : String) { +fun CoinImage( + url : String, + name : String, + backgroundColor : Color = Color.Black, + modifier: Modifier = Modifier, +) { Box( - modifier = Modifier + modifier = modifier .size(60.dp) .background( - color = Color.Black, + color = backgroundColor, shape = RoundedCornerShape(10.dp) ), contentAlignment = Alignment.Center From 8af6ae791cf85d3162d46a729306f48dc9bc021e Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:47:13 +0300 Subject: [PATCH 082/201] added compose and retrofit dependencies --- feature_transaction/build.gradle | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/feature_transaction/build.gradle b/feature_transaction/build.gradle index 6c24d08..648433c 100644 --- a/feature_transaction/build.gradle +++ b/feature_transaction/build.gradle @@ -30,6 +30,12 @@ android { kotlinOptions { jvmTarget = '1.8' } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion compose_version + } } dependencies { @@ -53,6 +59,15 @@ dependencies { kapt "com.google.dagger:hilt-android-compiler:$hilt_android_compile_version" kapt "androidx.hilt:hilt-compiler:$hilt_compile_version" + //Compose + implementation "androidx.compose.ui:ui:$compose_version" + implementation "androidx.compose.material:material:$compose_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" + implementation "androidx.activity:activity-compose:$compose_activity_version" + + // retrofit - for network call + implementation "com.squareup.retrofit2:retrofit:$retrofit_version" + // junit4 testImplementation "junit:junit:$junit_version" @@ -61,4 +76,9 @@ dependencies { // espresso androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" + + // compose ui + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" + debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" } \ No newline at end of file From 4d1c446b311e0169c0d278a44f61194e1ef55d06 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:49:00 +0300 Subject: [PATCH 083/201] implement usecase with entity data class --- .../feature_transaction/domain/entity/Coin.kt | 24 ++++++++ .../domain/usecase/GetCoinListUseCase.kt | 58 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt new file mode 100644 index 0000000..848acb4 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt @@ -0,0 +1,24 @@ +package com.ryankoech.krypto.feature_transaction.domain.entity + +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto + +data class Coin ( + val name : String, + val image : String, +) + +fun List.toCoinEntity() : List = map { + Coin( + name = it.name, + image = it.image + ) +} + +@JvmName("toCoinEntityCoinDto") +fun List.toCoinEntity() : List = map { + Coin( + name = it.name, + image = it.image + ) +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt new file mode 100644 index 0000000..c23e096 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt @@ -0,0 +1,58 @@ +package com.ryankoech.krypto.feature_transaction.domain.usecase + + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAMED_REPO_FAKE +import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_coin_list.data.dto.toLocalCoinDto +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin +import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Named + +class GetCoinListUseCase @Inject constructor( + @Named(HILT_NAMED_REPO_FAKE) private val repository: CoinRepository, +) { + + private var cache : List? = null + + operator fun invoke() = flow>> { + val coins : List = if(cache.isNullOrEmpty()) { + val localCoins = repository.getLocalCoins().toCoinEntity() + cache = localCoins + localCoins + } else { + cache!! + } + if(coins.isEmpty()) { + + val response = repository.getCoins() + + if(response.isSuccessful && !response.body().isNullOrEmpty()){ + val responseCoins = response.body()!! + repository.saveCoins(responseCoins.toLocalCoinDto()) + val processedCoins = response.body()!!.toCoinEntity() + cache = processedCoins + + emit(Resource.Success(processedCoins)) + }else{ + throw Exception("Response not Successful.") + } + + }else { + emit(Resource.Success(coins)) + } + + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + Timber.e(e) + emit(Resource.Error(e.localizedMessage ?: "An unexpected error occurred")) + } + +} \ No newline at end of file From 462af772611ed752f1303bdb018c07b59fa92705 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:49:59 +0300 Subject: [PATCH 084/201] implement extension function --- .../feature_transaction/core/ktx/Modifier.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/ktx/Modifier.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/ktx/Modifier.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/ktx/Modifier.kt new file mode 100644 index 0000000..90577ca --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/ktx/Modifier.kt @@ -0,0 +1,29 @@ +package com.ryankoech.krypto.feature_transaction.core.ktx + +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp + +fun Modifier.bottomBorder(strokeWidth: Dp, color: Color) = composed( + factory = { + val density = LocalDensity.current + + val strokeWidthPx = density.run { strokeWidth.toPx() } + + Modifier.drawBehind { + val width = size.width + val height = size.height - strokeWidthPx/2 + + drawLine( + color = color, + start = Offset(x = 0f, y = height), + end = Offset(x = width , y = height), + strokeWidth = strokeWidthPx + ) + } + } +) \ No newline at end of file From 1580ef6872f5c86a6b728dd55ae52e4746ce3081 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:50:19 +0300 Subject: [PATCH 085/201] added icon resource --- .../src/main/res/drawable/icon_chevron_right.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 feature_transaction/src/main/res/drawable/icon_chevron_right.xml diff --git a/feature_transaction/src/main/res/drawable/icon_chevron_right.xml b/feature_transaction/src/main/res/drawable/icon_chevron_right.xml new file mode 100644 index 0000000..1aa3b5f --- /dev/null +++ b/feature_transaction/src/main/res/drawable/icon_chevron_right.xml @@ -0,0 +1,5 @@ + + + From 190b8196c4ba1f719e0a084ceaab2b923bb4368d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:50:52 +0300 Subject: [PATCH 086/201] implement viewmodel --- .../viewmodel/ChooseAssetScreenViewModel.kt | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewmodel/ChooseAssetScreenViewModel.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewmodel/ChooseAssetScreenViewModel.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewmodel/ChooseAssetScreenViewModel.kt new file mode 100644 index 0000000..693b527 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewmodel/ChooseAssetScreenViewModel.kt @@ -0,0 +1,55 @@ +package com.ryankoech.krypto.feature_transaction.presentation.choose_asset.viewmodel + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_transaction.domain.usecase.GetCoinListUseCase +import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.viewstate.ChooseAssetScreenViewState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject + +@HiltViewModel +class ChooseAssetScreenViewModel @Inject constructor( + private val getCoinListUseCase: GetCoinListUseCase +): ViewModel() { + + private val _viewState = mutableStateOf(ChooseAssetScreenViewState()) + val viewState : State = _viewState + + init { + getCoinList() + } + + private fun getCoinList() { + getCoinListUseCase() + .onEach { res -> + when(res) { + is Resource.Error -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + is Resource.Loading -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING + ) + + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS, + coins = res.data!! + ) + + } + } + }.launchIn(viewModelScope) + } + +} \ No newline at end of file From 83d617e802fbc9f79343e8ed53a47d9803ba4353 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:52:12 +0300 Subject: [PATCH 087/201] defined viewstate --- .../choose_asset/viewstate/ChooseAssetScreenViewState.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewstate/ChooseAssetScreenViewState.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewstate/ChooseAssetScreenViewState.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewstate/ChooseAssetScreenViewState.kt new file mode 100644 index 0000000..781ec02 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewstate/ChooseAssetScreenViewState.kt @@ -0,0 +1,9 @@ +package com.ryankoech.krypto.feature_transaction.presentation.choose_asset.viewstate + +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin + +data class ChooseAssetScreenViewState( + val screenState: ScreenState = ScreenState.LOADING, + val coins : List = listOf(), +) From 955c673656566677ea509aeacfc3eb34736f20ab Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:52:32 +0300 Subject: [PATCH 088/201] implement item --- .../components/success/ChooseAssetItem.kt | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt new file mode 100644 index 0000000..98216ae --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt @@ -0,0 +1,89 @@ +package com.ryankoech.krypto.feature_transaction.presentation.choose_asset.components.success + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.CoinImage +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_transaction.R +import com.ryankoech.krypto.feature_transaction.core.ktx.bottomBorder +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin + +@Composable +fun ChooseAssetItem( + coin: Coin, + modifier: Modifier = Modifier +) { + + Row( + modifier = modifier + .fillMaxWidth() + // .padding( + // vertical = 8.dp + // ) + .bottomBorder( + 1.dp, + Color(0xfff6f6f6) + ), + verticalAlignment = Alignment.CenterVertically, + ) { + + CoinImage( + modifier = Modifier + .padding( + vertical = 8.dp + ), + url = coin.image, + name = coin.name, + backgroundColor = Color.Transparent + ) + + Text( + modifier = Modifier + .padding(end = 2.dp), + text = coin.name, + style = MaterialTheme.typography.h3, + ) + + Spacer( + modifier = Modifier + .weight(1f) + ) + + Icon( + painter = painterResource(R.drawable.icon_chevron_right), + contentDescription = null + ) + + } + +} + +@Preview +@Composable +fun PreviewChooseAssetItem() { + + KryptoTheme { + Surface { + Column { + ChooseAssetItem( + Coin( + image = "", + name = "Bitcoin" + ) + ) + } + } + } + +} From 8841d4c5dac30e470f91612d101df41681cd1726 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 12:53:31 +0300 Subject: [PATCH 089/201] implement chooseasset screen --- .../presentation/ChooseAssetScreen.kt | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt new file mode 100644 index 0000000..6eabee0 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt @@ -0,0 +1,51 @@ +package com.ryankoech.krypto.feature_transaction.presentation + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel +import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.components.success.ChooseAssetItem +import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.viewmodel.ChooseAssetScreenViewModel + +@Composable +fun ChooseAssetScreen( + viewModel : ChooseAssetScreenViewModel = hiltViewModel(), + modifier: Modifier = Modifier +) { + + val viewState = viewModel.viewState.value + + when(viewState.screenState){ + ScreenState.LOADING -> { + + } + ScreenState.ERROR -> { + + } + ScreenState.SUCCESS -> { + + } + } + +} + +@Preview +@Composable +fun PreviewChooseAssetScreen() { + + KryptoTheme { + Surface { + ChooseAssetScreen() + } + } + +} \ No newline at end of file From 8d76d5b8d14a16dac5133e075af60f6f22ca2c3f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 13:47:22 +0300 Subject: [PATCH 090/201] add search functionality --- .../domain/usecase/GetCoinListUseCase.kt | 8 ++++++-- .../choose_asset/viewmodel/ChooseAssetScreenViewModel.kt | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt index c23e096..31c99ba 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt @@ -21,7 +21,7 @@ class GetCoinListUseCase @Inject constructor( private var cache : List? = null - operator fun invoke() = flow>> { + operator fun invoke(filterString : String = "") = flow>> { val coins : List = if(cache.isNullOrEmpty()) { val localCoins = repository.getLocalCoins().toCoinEntity() cache = localCoins @@ -45,7 +45,11 @@ class GetCoinListUseCase @Inject constructor( } }else { - emit(Resource.Success(coins)) + emit(Resource.Success( + coins.filter { + it.name.contains(filterString,true) + } + )) } }.onStart { diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewmodel/ChooseAssetScreenViewModel.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewmodel/ChooseAssetScreenViewModel.kt index 693b527..202e4c5 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewmodel/ChooseAssetScreenViewModel.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/viewmodel/ChooseAssetScreenViewModel.kt @@ -23,11 +23,11 @@ class ChooseAssetScreenViewModel @Inject constructor( val viewState : State = _viewState init { - getCoinList() + getCoinList("") } - private fun getCoinList() { - getCoinListUseCase() + fun getCoinList(filterString : String) { + getCoinListUseCase(filterString) .onEach { res -> when(res) { is Resource.Error -> { From 94ae0479d674269dfd1c156e372df780c5ab690f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 13:47:54 +0300 Subject: [PATCH 091/201] update data structure --- .../ryankoech/krypto/feature_transaction/domain/entity/Coin.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt index 848acb4..ac7c0ce 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt @@ -4,12 +4,14 @@ import com.ryankoech.krypto.feature_coin_list.data.dto.CoinDto import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto data class Coin ( + val id : String, val name : String, val image : String, ) fun List.toCoinEntity() : List = map { Coin( + id = it.id, name = it.name, image = it.image ) @@ -18,6 +20,7 @@ fun List.toCoinEntity() : List = map { @JvmName("toCoinEntityCoinDto") fun List.toCoinEntity() : List = map { Coin( + id = it.id, name = it.name, image = it.image ) From 9e729d6fd580b87512c790a59b9c337463df40be Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 13:49:04 +0300 Subject: [PATCH 092/201] added onclick --- .../components/success/ChooseAssetItem.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt index 98216ae..429740c 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt @@ -1,6 +1,7 @@ package com.ryankoech.krypto.feature_transaction.presentation.choose_asset.components.success import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme @@ -21,6 +22,7 @@ import com.ryankoech.krypto.feature_transaction.domain.entity.Coin @Composable fun ChooseAssetItem( + onClick : (String) -> Unit, coin: Coin, modifier: Modifier = Modifier ) { @@ -28,13 +30,13 @@ fun ChooseAssetItem( Row( modifier = modifier .fillMaxWidth() - // .padding( - // vertical = 8.dp - // ) .bottomBorder( 1.dp, Color(0xfff6f6f6) - ), + ) + .clickable { + onClick(coin.id) + }, verticalAlignment = Alignment.CenterVertically, ) { @@ -77,7 +79,9 @@ fun PreviewChooseAssetItem() { Surface { Column { ChooseAssetItem( + {}, Coin( + id = "bitcoin", image = "", name = "Bitcoin" ) From 7a69a0552db746fbe56823e0d9b78142feeb3e7f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 13:49:54 +0300 Subject: [PATCH 093/201] implement success screen --- .../choose_asset/ChooseAssetScreenSuccess.kt | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenSuccess.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenSuccess.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenSuccess.kt new file mode 100644 index 0000000..1ad65fd --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenSuccess.kt @@ -0,0 +1,87 @@ +package com.ryankoech.krypto.feature_transaction.presentation.choose_asset + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.ErrorScreen +import com.ryankoech.krypto.common.presentation.components.SearchBar +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.R as commonR +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin +import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity +import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.components.success.ChooseAssetItem + +@Composable +fun ChooseAssetScreenSuccess( + onChooseAssetItemClick : (String) -> Unit, + coins : List, + searchValue : String, + onSearchValueChange : (String) -> Unit, + modifier: Modifier = Modifier, +) { + + Column( + modifier = modifier + .padding( 12.dp ) + ) { + + SearchBar( + modifier = Modifier + .padding( + bottom = 16.dp + ), + value = searchValue, + onValueChange = onSearchValueChange, + placeholder = "Look up asset, coin or token" + ) + + LazyColumn( + modifier = Modifier + .weight(1f), + ) { + + if(coins.isEmpty()) { + item { + ErrorScreen( + modifier = Modifier + .fillParentMaxHeight(), + messageText = "No assets to show.", + res = commonR.drawable.icon_gif_search + ) + } + + }else { + items(items = coins){ coin -> + ChooseAssetItem(onChooseAssetItemClick, coin) + } + } + } + + } + +} + +@Preview +@Composable +fun ChooseAssetScreenSuccessPreview () { + + KryptoTheme { + Surface { + ChooseAssetScreenSuccess( + onChooseAssetItemClick = {}, + coins = FAKE_COIN_LIST.toCoinEntity(), + searchValue = "", + onSearchValueChange = {} + ) + } + } + +} \ No newline at end of file From a6627d7ef9db085a9c9dad2eb840d58b5aabe148 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 13:53:30 +0300 Subject: [PATCH 094/201] implement state with success screen --- .../presentation/ChooseAssetScreen.kt | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt index 6eabee0..a41d9c6 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt @@ -5,15 +5,13 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.Surface -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.ScreenState -import com.ryankoech.krypto.feature_coin_list.presentation.viewmodel.CoinListScreenViewModel -import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.components.success.ChooseAssetItem +import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.ChooseAssetScreenSuccess import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.viewmodel.ChooseAssetScreenViewModel @Composable @@ -23,6 +21,14 @@ fun ChooseAssetScreen( ) { val viewState = viewModel.viewState.value + var searchValue by remember { + mutableStateOf("") + } + + fun editSearchValueState(newValue : String ){ + viewModel.getCoinList(newValue) + searchValue = newValue + } when(viewState.screenState){ ScreenState.LOADING -> { @@ -33,6 +39,13 @@ fun ChooseAssetScreen( } ScreenState.SUCCESS -> { + ChooseAssetScreenSuccess( + onChooseAssetItemClick = {}, + coins = viewState.coins, + searchValue = searchValue, + onSearchValueChange = ::editSearchValueState + ) + } } From 63bd1028699db99ce57eac062efa8cbc005e9c76 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 14:04:27 +0300 Subject: [PATCH 095/201] refactored file location --- .../presentation/{ => choose_asset}/ChooseAssetScreen.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) rename feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/{ => choose_asset}/ChooseAssetScreen.kt (79%) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt similarity index 79% rename from feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt rename to feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt index a41d9c6..a2cf18d 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/ChooseAssetScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt @@ -1,9 +1,5 @@ -package com.ryankoech.krypto.feature_transaction.presentation +package com.ryankoech.krypto.feature_transaction.presentation.choose_asset -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.material.Surface import androidx.compose.runtime.* import androidx.compose.ui.Modifier @@ -11,7 +7,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.ScreenState -import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.ChooseAssetScreenSuccess import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.viewmodel.ChooseAssetScreenViewModel @Composable From d746fd90a7af258237f4a4ca18d9abdcff5e9db3 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 14:45:31 +0300 Subject: [PATCH 096/201] implement component --- .../loading/ChooseAssetItemLoading.kt | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/loading/ChooseAssetItemLoading.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/loading/ChooseAssetItemLoading.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/loading/ChooseAssetItemLoading.kt new file mode 100644 index 0000000..5d19b49 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/loading/ChooseAssetItemLoading.kt @@ -0,0 +1,66 @@ +package com.ryankoech.krypto.feature_transaction.presentation.choose_asset.components.loading + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.loading.CoinCardLoading +import com.ryankoech.krypto.common.presentation.components.loading.LoadingText +import com.ryankoech.krypto.common.presentation.components.loading.loadingEffect +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme + +@Composable +fun ChooseAssetItemLoading( + brush : Brush, + modifier: Modifier = Modifier, +) { + + Row( + modifier = modifier + .fillMaxWidth() + .height(IntrinsicSize.Min), + verticalAlignment = Alignment.CenterVertically, + ) { + Spacer( + modifier = Modifier + .size(56.dp) + .background( + brush = brush, + shape = MaterialTheme.shapes.small + ) + ) + + Spacer( + modifier = Modifier + .width(16.dp) + ) + + LoadingText(130.dp, brush) + + } + +} + +@Preview +@Composable +fun ChooseAssetItemLoadingPreview(){ + KryptoTheme { + Surface( + modifier = Modifier + .fillMaxSize() + ) { + val brush = loadingEffect() + + Column{ + ChooseAssetItemLoading(brush = brush) + } + + } + } +} \ No newline at end of file From 2d385f409ca28f4c7cba7d8e9960acee3fb2807c Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 14:45:52 +0300 Subject: [PATCH 097/201] implement error screen --- .../choose_asset/ChooseAssetScreenError.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenError.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenError.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenError.kt new file mode 100644 index 0000000..9c2c79a --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenError.kt @@ -0,0 +1,32 @@ +package com.ryankoech.krypto.feature_transaction.presentation.choose_asset + +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.ryankoech.krypto.common.presentation.ErrorScreen +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.R + +@Composable +fun ChooseAssetScreenError( + modifier: Modifier = Modifier +) { + ErrorScreen( + modifier = modifier, + messageText = "Hmm, it's kinda empty here.", + res = R.drawable.icon_gif_caution + ) +} + +@Preview +@Composable +fun ChooseAssetScreenErrorPreview() { + + KryptoTheme { + Surface { + ChooseAssetScreenError() + } + } + +} \ No newline at end of file From 53fd47927229aea5a56f0588900ab89d07555495 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 14:46:22 +0300 Subject: [PATCH 098/201] implement loading screen --- .../choose_asset/ChooseAssetScreenLoading.kt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenLoading.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenLoading.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenLoading.kt new file mode 100644 index 0000000..0d7e623 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenLoading.kt @@ -0,0 +1,45 @@ +package com.ryankoech.krypto.feature_transaction.presentation.choose_asset + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.loading.loadingEffect +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.components.loading.ChooseAssetItemLoading + +@Composable +fun ChooseAssetScreenLoading( + modifier: Modifier = Modifier +) { + + val brush = loadingEffect() + + LazyColumn( + modifier = modifier, + contentPadding = PaddingValues(12.dp), + ) { + items(count = 15) { + Spacer(Modifier.height(8.dp)) + ChooseAssetItemLoading(brush) + Spacer(Modifier.height(8.dp)) + } + } +} + +@Preview +@Composable +fun ChooseAssetScreenLoadingPreview() { + + KryptoTheme { + Surface { + ChooseAssetScreenLoading() + } + } + +} \ No newline at end of file From 7a63ab2ef875ef42cb5f79a543d8d4f5bbbf4fd9 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 14:48:50 +0300 Subject: [PATCH 099/201] add retry callback --- .../presentation/choose_asset/ChooseAssetScreenError.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenError.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenError.kt index 9c2c79a..9257376 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenError.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenError.kt @@ -10,12 +10,14 @@ import com.ryankoech.krypto.common.R @Composable fun ChooseAssetScreenError( + onRetryButtonClick : () -> Unit, modifier: Modifier = Modifier ) { ErrorScreen( modifier = modifier, messageText = "Hmm, it's kinda empty here.", - res = R.drawable.icon_gif_caution + res = R.drawable.icon_gif_caution, + onButtonClick = onRetryButtonClick, ) } @@ -25,7 +27,7 @@ fun ChooseAssetScreenErrorPreview() { KryptoTheme { Surface { - ChooseAssetScreenError() + ChooseAssetScreenError({}) } } From 1983e56c2ed81e63e6fcd761ba2b786190ab9d6d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 14:49:23 +0300 Subject: [PATCH 100/201] add fallback screens --- .../presentation/choose_asset/ChooseAssetScreen.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt index a2cf18d..64422fa 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt @@ -27,10 +27,14 @@ fun ChooseAssetScreen( when(viewState.screenState){ ScreenState.LOADING -> { - + ChooseAssetScreenLoading() } ScreenState.ERROR -> { - + ChooseAssetScreenError( + onRetryButtonClick = { + viewModel.getCoinList(searchValue) + } + ) } ScreenState.SUCCESS -> { From f373c244a1e25f8a5876d92ada6a463044b44cd4 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 17 Jan 2023 15:03:01 +0300 Subject: [PATCH 101/201] update hilt named string --- .../feature_transaction/domain/usecase/GetCoinListUseCase.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt index 31c99ba..095f0f7 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinListUseCase.kt @@ -2,7 +2,6 @@ package com.ryankoech.krypto.feature_transaction.domain.usecase import com.ryankoech.krypto.common.core.util.Resource -import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAMED_REPO_FAKE import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL import com.ryankoech.krypto.feature_coin_list.data.dto.toLocalCoinDto import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository @@ -16,7 +15,7 @@ import javax.inject.Inject import javax.inject.Named class GetCoinListUseCase @Inject constructor( - @Named(HILT_NAMED_REPO_FAKE) private val repository: CoinRepository, + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinRepository, ) { private var cache : List? = null From cb8bb1aeb214f9062d8cba4755ac9f9331b90b6f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 20 Jan 2023 17:54:16 +0300 Subject: [PATCH 102/201] add pager accompanist dependencies --- build.gradle | 1 + feature_transaction/build.gradle | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 93b22ca..39115a3 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,7 @@ buildscript { turbine_version = '0.12.1' okhttp_logging_interceptor_version = '5.0.0-alpha.9' retrofit_version = '2.9.0' + accompanist_version = '0.28.0' } dependencies { classpath "com.google.dagger:hilt-android-gradle-plugin:2.42" diff --git a/feature_transaction/build.gradle b/feature_transaction/build.gradle index 648433c..e522b17 100644 --- a/feature_transaction/build.gradle +++ b/feature_transaction/build.gradle @@ -65,6 +65,10 @@ dependencies { implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation "androidx.activity:activity-compose:$compose_activity_version" + // accompanist pager + implementation "com.google.accompanist:accompanist-pager:$accompanist_version" // Pager + implementation "com.google.accompanist:accompanist-pager-indicators:$accompanist_version" // Pager Indicators + // retrofit - for network call implementation "com.squareup.retrofit2:retrofit:$retrofit_version" From 2414270f81e09833a7c3b6f21a7197d7e8bc9612 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 10:47:28 +0300 Subject: [PATCH 103/201] update body1 font size --- .../java/com/ryankoech/krypto/common/presentation/theme/Type.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Type.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Type.kt index 4d10722..6109825 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Type.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Type.kt @@ -17,7 +17,7 @@ val Typography = Typography( body1 = TextStyle( fontFamily = CircularStd, fontWeight = FontWeight.Medium, - fontSize = 14.sp, + fontSize = 16.sp, ), h1 = TextStyle( fontFamily = CircularStd, From cc5d3f0fa9a0427bcd89178fe2e13151d212c280 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 10:49:38 +0300 Subject: [PATCH 104/201] refactor entity structure --- .../krypto/feature_transaction/domain/entity/Coin.kt | 10 ++++++++-- .../choose_asset/components/success/ChooseAssetItem.kt | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt index ac7c0ce..a07132f 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/entity/Coin.kt @@ -5,15 +5,19 @@ import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto data class Coin ( val id : String, + val symbol : String, val name : String, val image : String, + val price : Double, ) fun List.toCoinEntity() : List = map { Coin( id = it.id, name = it.name, - image = it.image + symbol = it.symbol, + image = it.image, + price = it.price, ) } @@ -22,6 +26,8 @@ fun List.toCoinEntity() : List = map { Coin( id = it.id, name = it.name, - image = it.image + symbol = it.symbol, + image = it.image, + price = it.current_price, ) } \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt index 429740c..5ed6d31 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt @@ -1,6 +1,5 @@ package com.ryankoech.krypto.feature_transaction.presentation.choose_asset.components.success -import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.material.Icon @@ -83,7 +82,9 @@ fun PreviewChooseAssetItem() { Coin( id = "bitcoin", image = "", - name = "Bitcoin" + name = "Bitcoin", + symbol = "BTC", + price = 20_000.0 ) ) } From 8e71c6457eac179e83c3aa9e881af70d1bcc44b8 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 10:50:29 +0300 Subject: [PATCH 105/201] add room dependencies --- feature_transaction/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/feature_transaction/build.gradle b/feature_transaction/build.gradle index e522b17..1cd395a 100644 --- a/feature_transaction/build.gradle +++ b/feature_transaction/build.gradle @@ -72,6 +72,12 @@ dependencies { // retrofit - for network call implementation "com.squareup.retrofit2:retrofit:$retrofit_version" + // room - for storing data locally + implementation "androidx.room:room-ktx:$room_version" + implementation "androidx.room:room-runtime:$room_version" + annotationProcessor "androidx.room:room-compiler:$room_version" + kapt "androidx.room:room-compiler:$room_version" + // junit4 testImplementation "junit:junit:$junit_version" From 0229b63e72c1e2e10adfcdfc89641c6efd596961 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 10:53:10 +0300 Subject: [PATCH 106/201] implement transaction db --- .../core/di/TransactionDatabaseModule.kt | 35 +++++++++++++++++++ .../data/data_source/local/TransactionDao.kt | 18 ++++++++++ .../data_source/local/TransactionDatabase.kt | 17 +++++++++ .../dto/transaction_dto/TransactionDto.kt | 16 +++++++++ .../dto/transaction_dto/TransactionType.kt | 6 ++++ 5 files changed, 92 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionDatabaseModule.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDatabase.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionDto.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionType.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionDatabaseModule.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionDatabaseModule.kt new file mode 100644 index 0000000..f05560d --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionDatabaseModule.kt @@ -0,0 +1,35 @@ +package com.ryankoech.krypto.feature_transaction.core.di + +import android.content.Context +import androidx.room.Room +import androidx.room.RoomDatabase +import com.ryankoech.krypto.feature_transaction.data.data_source.local.NAME_DATABASE_TRANSACTION +import com.ryankoech.krypto.feature_transaction.data.data_source.local.TransactionDao +import com.ryankoech.krypto.feature_transaction.data.data_source.local.TransactionDatabase +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object TransactionDatabaseModule { + + @Provides + @Singleton + fun getTransactionDatabase(@ApplicationContext context : Context) : TransactionDatabase = + Room.databaseBuilder( + context, + TransactionDatabase::class.java, + NAME_DATABASE_TRANSACTION, + ) + .fallbackToDestructiveMigration() + .build() + + + @Provides + @Singleton + fun getTransactionDao(transactionDatabase: TransactionDatabase) : TransactionDao = transactionDatabase.getTransactionDao() +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt new file mode 100644 index 0000000..a272abf --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt @@ -0,0 +1,18 @@ +package com.ryankoech.krypto.feature_transaction.data.data_source.local + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TABLE_NAME_TRANSACTION +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto + +@Dao +interface TransactionDao { + + @Insert + fun insertTransaction(transactionDto: TransactionDto) + + @Query("SELECT * FROM `$TABLE_NAME_TRANSACTION` WHERE coinId = :coinId ORDER by date DESC") + fun getCoinTransactions(coinId : String) : List + +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDatabase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDatabase.kt new file mode 100644 index 0000000..380c32b --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDatabase.kt @@ -0,0 +1,17 @@ +package com.ryankoech.krypto.feature_transaction.data.data_source.local + +import androidx.room.Database +import androidx.room.RoomDatabase + +const val NAME_DATABASE_TRANSACTION = "transaction db" + +@Database( + entities = [TransactionDao::class], + version = 1, + exportSchema = false, +) +abstract class TransactionDatabase : RoomDatabase() { + + abstract fun getTransactionDao() : TransactionDao + +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionDto.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionDto.kt new file mode 100644 index 0000000..0218835 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionDto.kt @@ -0,0 +1,16 @@ +package com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto + +import androidx.room.Entity +import androidx.room.PrimaryKey + +const val TABLE_NAME_TRANSACTION = "table name transaction" + +@Entity(tableName = TABLE_NAME_TRANSACTION) +data class TransactionDto( + @PrimaryKey + val date : Long, + val coinId : String, + val transactionType : TransactionType, + val currentPrice : Double, + val amount : Float, +) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionType.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionType.kt new file mode 100644 index 0000000..1ce345c --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionType.kt @@ -0,0 +1,6 @@ +package com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto + +enum class TransactionType { + BUY, + SELL +} From 6f016a627dfc2a04ec385168850326bc3f709244 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 10:54:13 +0300 Subject: [PATCH 107/201] implement repository --- .../core/di/TransactionRepositoryModule.kt | 36 +++++++++++++++++ .../repository/FakeTransactionRepository.kt | 40 +++++++++++++++++++ .../repository/TransactionRepositoryImpl.kt | 16 ++++++++ .../repository/TransactionRepository.kt | 10 +++++ 4 files changed, 102 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionRepositoryModule.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionRepositoryModule.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionRepositoryModule.kt new file mode 100644 index 0000000..4d52802 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionRepositoryModule.kt @@ -0,0 +1,36 @@ +package com.ryankoech.krypto.feature_transaction.core.di + +import com.ryankoech.krypto.feature_transaction.data.repository.FakeTransactionRepository +import com.ryankoech.krypto.feature_transaction.data.repository.TransactionRepositoryImpl +import com.ryankoech.krypto.feature_transaction.domain.repository.TransactionRepository +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Named +import javax.inject.Singleton + +const val HILT_NAMED_REPO_FAKE = "FakeRepo" +const val HILT_NAMED_REPO = "Repo" +const val HILT_NAME_REPO_FOR_ALL = HILT_NAMED_REPO_FAKE + +@Module +@InstallIn(SingletonComponent::class) +abstract class TransactionRepositoryModule { + + @Binds + @Singleton + @Named(HILT_NAMED_REPO) + abstract fun getTrasnactionRepository( + repository: TransactionRepositoryImpl + ) : TransactionRepository + + @Binds + @Singleton + @Named(HILT_NAMED_REPO_FAKE) + abstract fun getFakeTransactionRepository( + repository : FakeTransactionRepository + ) : TransactionRepository + +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt new file mode 100644 index 0000000..9a6e832 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt @@ -0,0 +1,40 @@ +package com.ryankoech.krypto.feature_transaction.data.repository + +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType +import com.ryankoech.krypto.feature_transaction.domain.repository.TransactionRepository +import timber.log.Timber +import javax.inject.Inject + +val bitCoinTransaction = listOf( + TransactionDto( + date = 1675655596952, + coinId = "bitcoin", + currentPrice = 20000.00, + amount = 1.5F, + transactionType = TransactionType.BUY + ), + TransactionDto( + date = 1675655696952, + coinId = "bitcoin", + currentPrice = 24000.00, + amount = 0.5F, + transactionType = TransactionType.SELL + ), +) + +class FakeTransactionRepository @Inject constructor() : TransactionRepository { + override fun addTransaction(transaction: TransactionDto) { + Timber.d("Added transaction.") + Timber.d(transaction.toString()) + } + + override fun getCoinTransactions(coinId: String): List { + return if(coinId == bitCoinTransaction.first().coinId){ + bitCoinTransaction + } else { + listOf() + } + + } +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt new file mode 100644 index 0000000..0310465 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt @@ -0,0 +1,16 @@ +package com.ryankoech.krypto.feature_transaction.data.repository + +import com.ryankoech.krypto.feature_transaction.data.data_source.local.TransactionDao +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.domain.repository.TransactionRepository +import javax.inject.Inject + +class TransactionRepositoryImpl @Inject constructor( + private val dao: TransactionDao +) : TransactionRepository { + + override fun addTransaction(transaction: TransactionDto) = dao.insertTransaction(transaction) + + override fun getCoinTransactions(coinId: String): List = dao.getCoinTransactions(coinId) + +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt new file mode 100644 index 0000000..8a1e681 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt @@ -0,0 +1,10 @@ +package com.ryankoech.krypto.feature_transaction.domain.repository + +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto + +interface TransactionRepository { + + fun addTransaction(transaction : TransactionDto) + + fun getCoinTransactions(coinId : String) : List +} \ No newline at end of file From 2490cf69042432f707d99f747c6d6508c5656e79 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 10:55:05 +0300 Subject: [PATCH 108/201] implement usecases --- .../usecase/GetCoinTransactionsUseCase.kt | 27 +++++++++++++++++++ .../usecase/SaveCoinTransactionUseCase.kt | 25 +++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinTransactionsUseCase.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/SaveCoinTransactionUseCase.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinTransactionsUseCase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinTransactionsUseCase.kt new file mode 100644 index 0000000..8b2c633 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/GetCoinTransactionsUseCase.kt @@ -0,0 +1,27 @@ +package com.ryankoech.krypto.feature_transaction.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_transaction.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.domain.repository.TransactionRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import javax.inject.Inject +import javax.inject.Named + +class GetCoinTransactionsUseCase @Inject constructor( + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: TransactionRepository +) { + + operator fun invoke(coinId : String) = flow>> { + emit(Resource.Success(repository.getCoinTransactions(coinId))) + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + emit(Resource.Error( + e.localizedMessage?: "An unknown error occurred" + )) + } + +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/SaveCoinTransactionUseCase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/SaveCoinTransactionUseCase.kt new file mode 100644 index 0000000..ee0f900 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/SaveCoinTransactionUseCase.kt @@ -0,0 +1,25 @@ +package com.ryankoech.krypto.feature_transaction.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_transaction.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.domain.repository.TransactionRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import javax.inject.Inject +import javax.inject.Named + +class SaveCoinTransactionUseCase @Inject constructor( + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: TransactionRepository +) { + + operator fun invoke(transaction: TransactionDto) = flow> { + emit(Resource.Success(repository.addTransaction(transaction))) + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + emit(Resource.Error(e.localizedMessage ?: "An unknown error occurred" )) + } + +} \ No newline at end of file From 4128c869bd82b99d4a25c4532023ba4c71a686d2 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 11:50:04 +0300 Subject: [PATCH 109/201] fix wrong entity class --- .../data/data_source/local/TransactionDatabase.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDatabase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDatabase.kt index 380c32b..1c06797 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDatabase.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDatabase.kt @@ -2,11 +2,12 @@ package com.ryankoech.krypto.feature_transaction.data.data_source.local import androidx.room.Database import androidx.room.RoomDatabase +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto const val NAME_DATABASE_TRANSACTION = "transaction db" @Database( - entities = [TransactionDao::class], + entities = [TransactionDto::class], version = 1, exportSchema = false, ) From 0f7aeb52a4eec9d750e33afee143e703ae983e5f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 11:50:36 +0300 Subject: [PATCH 110/201] utilize modifier parameter --- .../presentation/choose_asset/ChooseAssetScreen.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt index 64422fa..b9f3c90 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt @@ -27,10 +27,11 @@ fun ChooseAssetScreen( when(viewState.screenState){ ScreenState.LOADING -> { - ChooseAssetScreenLoading() + ChooseAssetScreenLoading(modifier) } ScreenState.ERROR -> { ChooseAssetScreenError( + modifier = modifier, onRetryButtonClick = { viewModel.getCoinList(searchValue) } @@ -39,6 +40,7 @@ fun ChooseAssetScreen( ScreenState.SUCCESS -> { ChooseAssetScreenSuccess( + modifier = modifier, onChooseAssetItemClick = {}, coins = viewState.coins, searchValue = searchValue, From b1b8c09bfc674ffeffc6c3c3c7c53b6b588a3884 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 11:51:20 +0300 Subject: [PATCH 111/201] add color flexibility --- .../krypto/common/presentation/components/KryptoButton.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/KryptoButton.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/KryptoButton.kt index f31b4fd..ac25d95 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/KryptoButton.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/KryptoButton.kt @@ -7,6 +7,7 @@ import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.theme.Green200 @@ -15,13 +16,14 @@ import com.ryankoech.krypto.common.presentation.theme.Green200 fun KryptoButton( modifier: Modifier = Modifier, text : String, + color : Color = Green200, onClick : () -> Unit ) { Button( modifier = modifier, colors = ButtonDefaults.buttonColors( - backgroundColor = Green200 + backgroundColor = color ), shape = MaterialTheme.shapes.medium, elevation = ButtonDefaults.elevation( From 6bddd4b7b4329ffd346313be97118f4a777b5afb Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 12 Feb 2023 11:52:39 +0300 Subject: [PATCH 112/201] implement transaction screen UI --- .../transaction/TransactionScreen.kt | 117 ++++++++++++++++ .../components/BuyTransactionScreen.kt | 125 ++++++++++++++++++ .../components/SellTransactionScreen.kt | 123 +++++++++++++++++ .../transaction/util/TabRowItem.kt | 8 ++ .../src/main/res/drawable/icon_exchange.xml | 7 + 5 files changed, 380 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/util/TabRowItem.kt create mode 100644 feature_transaction/src/main/res/drawable/icon_exchange.xml diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt new file mode 100644 index 0000000..ff09652 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt @@ -0,0 +1,117 @@ +package com.ryankoech.krypto.feature_transaction.presentation.transaction + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.text.toUpperCase +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.google.accompanist.pager.ExperimentalPagerApi +import com.google.accompanist.pager.HorizontalPager +import com.google.accompanist.pager.pagerTabIndicatorOffset +import com.google.accompanist.pager.rememberPagerState +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin +import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity +import com.ryankoech.krypto.feature_transaction.presentation.transaction.components.BuyTransactionScreen +import com.ryankoech.krypto.feature_transaction.presentation.transaction.components.SellTransactionScreen +import com.ryankoech.krypto.feature_transaction.presentation.transaction.util.TabRowItem +import kotlinx.coroutines.launch +import java.util.* + +@OptIn(ExperimentalPagerApi::class) +@Composable +fun TransactionScreen( + coin : Coin, + modifier: Modifier = Modifier +) { + + val tabRowItems = listOf( + TabRowItem( + title = "Buy", + screen = { + BuyTransactionScreen( + coin + ) + }, + ), + TabRowItem( + title = "SELL", + screen = { + SellTransactionScreen( + coin + ) + }, + ), + ) + + val pagerState = rememberPagerState() + val coroutineScope = rememberCoroutineScope() + + Column( + modifier = modifier + ) { + TabRow( + modifier = Modifier + .shadow( + elevation = 4.dp + ), + selectedTabIndex = pagerState.currentPage, + indicator = { tabPositions -> + TabRowDefaults.Indicator( + Modifier.pagerTabIndicatorOffset(pagerState, tabPositions), + color = Color(0xff1975d8) + ) + }, + ) { + tabRowItems.forEachIndexed { index, item -> + Tab( + modifier = Modifier + .background( + color = Color.White + ), + selected = pagerState.currentPage == index, + onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } }, + text = { + Text( + text = item.title.uppercase(Locale.ROOT), + maxLines = 2, + overflow = TextOverflow.Ellipsis, + style = MaterialTheme.typography.body1, + color = if (pagerState.currentPage == index) Color.Black else Color.LightGray + ) + } + ) + } + } + HorizontalPager( + count = tabRowItems.size, + state = pagerState, + ) { + tabRowItems[pagerState.currentPage].screen() + } + } + +} + +@Preview +@Composable +fun TransactionScreenPreview() { + + KryptoTheme { + Surface { + TransactionScreen( + FAKE_COIN_LIST.toCoinEntity().first(), + ) + } + } + +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt new file mode 100644 index 0000000..6c0a56e --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt @@ -0,0 +1,125 @@ +package com.ryankoech.krypto.feature_transaction.presentation.transaction.components + +import android.widget.EditText +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.currentCompositionLocalContext +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.toUpperCase +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.ryankoech.krypto.common.presentation.components.KryptoButton +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.DisplayCurrency +import com.ryankoech.krypto.common.presentation.util.getFormattedBalance +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_transaction.R +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin +import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity +import java.util.* + +@Composable +fun BuyTransactionScreen( + coin : Coin, + modifier : Modifier = Modifier +) { + + val context = LocalContext.current + val textFieldTextStyle = MaterialTheme.typography.caption.copy( + fontSize = 64.sp, + textAlign = TextAlign.Center + ) + val spacing = 24.dp + + Column( + modifier = modifier + .padding(12.dp) + .fillMaxHeight() + ) { + + Column( + modifier = modifier + .weight(1.0f), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + + Row { + Icon( + painter = painterResource(R.drawable.icon_exchange), + contentDescription = null + ) + Text( + text = coin.symbol.uppercase(Locale.ROOT), + style = MaterialTheme.typography.body1.copy( + fontSize = 20.sp + ) + ) + } + + + Spacer(Modifier.height(spacing)) + + TextField( + value = "", + onValueChange = {}, + textStyle = textFieldTextStyle, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + placeholder = { + Text( + modifier = Modifier + .fillMaxWidth() + .alpha(0.4f), + text = "Quantity", + style = textFieldTextStyle, + color = Color.Black + ) + }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = Color.Unspecified, + unfocusedIndicatorColor = Color.Unspecified, + backgroundColor = Color.White + ), + ) + + Spacer(Modifier.height(spacing)) + + Text( + text = "${getFormattedBalance(context, coin.price, DisplayCurrency.USD)} per coin.", + style = MaterialTheme.typography.caption, + ) + } + + KryptoButton( + modifier = Modifier + .fillMaxWidth(), + text = "Buy " + coin.name, + onClick = {} + ) + + } + +} + +@Preview +@Composable +fun BuyTransactionScreenPreview() { + KryptoTheme { + Surface { + BuyTransactionScreen( + FAKE_COIN_LIST.toCoinEntity().first() + ) + } + } +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt new file mode 100644 index 0000000..c4eb382 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -0,0 +1,123 @@ +package com.ryankoech.krypto.feature_transaction.presentation.transaction.components + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.ryankoech.krypto.common.presentation.components.KryptoButton +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.theme.Red200 +import com.ryankoech.krypto.common.presentation.util.DisplayCurrency +import com.ryankoech.krypto.common.presentation.util.getFormattedBalance +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_transaction.R +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin +import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity +import java.util.* + +@Composable +fun SellTransactionScreen( + coin : Coin, + modifier: Modifier = Modifier +) { + + val context = LocalContext.current + val textFieldTextStyle = MaterialTheme.typography.caption.copy( + fontSize = 64.sp, + textAlign = TextAlign.Center + ) + val spacing = 24.dp + + Column( + modifier = modifier + .padding(12.dp) + .fillMaxHeight() + ) { + + Column( + modifier = modifier + .weight(1.0f), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + + Row { + Icon( + painter = painterResource(R.drawable.icon_exchange), + contentDescription = null + ) + Text( + text = coin.symbol.uppercase(Locale.ROOT), + style = MaterialTheme.typography.body1.copy( + fontSize = 20.sp + ) + ) + } + + + Spacer(Modifier.height(spacing)) + + TextField( + value = "", + onValueChange = {}, + textStyle = textFieldTextStyle, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + placeholder = { + Text( + modifier = Modifier + .fillMaxWidth() + .alpha(0.4f), + text = "Quantity", + style = textFieldTextStyle, + color = Color.Black + ) + }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = Color.Unspecified, + unfocusedIndicatorColor = Color.Unspecified, + backgroundColor = Color.White + ), + ) + + Spacer(Modifier.height(spacing)) + + Text( + text = "${getFormattedBalance(context, coin.price, DisplayCurrency.USD)} per coin.", + style = MaterialTheme.typography.caption, + ) + } + + KryptoButton( + modifier = Modifier + .fillMaxWidth(), + text = "Sell " + coin.name, + color = Red200, + onClick = {} + ) + + } + +} + +@Preview +@Composable +fun SellTransactionScreenPreview() { + KryptoTheme { + Surface { + SellTransactionScreen( + FAKE_COIN_LIST.toCoinEntity().first() + ) + } + } +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/util/TabRowItem.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/util/TabRowItem.kt new file mode 100644 index 0000000..64f83dc --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/util/TabRowItem.kt @@ -0,0 +1,8 @@ +package com.ryankoech.krypto.feature_transaction.presentation.transaction.util + +import androidx.compose.runtime.Composable + +data class TabRowItem( + val title: String, + val screen: @Composable () -> Unit, +) \ No newline at end of file diff --git a/feature_transaction/src/main/res/drawable/icon_exchange.xml b/feature_transaction/src/main/res/drawable/icon_exchange.xml new file mode 100644 index 0000000..bd77a8c --- /dev/null +++ b/feature_transaction/src/main/res/drawable/icon_exchange.xml @@ -0,0 +1,7 @@ + + + From e449941d251705ecbd9bd30d6a14d33198155d77 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 12:12:45 +0300 Subject: [PATCH 113/201] implement dao repo usecase to get single owned coin --- .../data_source/local/db/OwnedCoinsDao.kt | 3 ++ .../FakeOwnedCoinsRepositoryImpl.kt | 4 +++ .../repository/OwnedCoinsRepositoryImpl.kt | 7 +++++ .../domain/repository/OwnedCoinsRepository.kt | 2 ++ .../domain/usecase/GetOwnedCoinUseCase.kt | 30 +++++++++++++++++++ 5 files changed, 46 insertions(+) create mode 100644 feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/GetOwnedCoinUseCase.kt diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt index 0b4174a..e4c2884 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt @@ -15,4 +15,7 @@ interface OwnedCoinsDao { @Query("SELECT * FROM $OWNED_COIN_DTO_TABLENAME") suspend fun getOwnedCoins() : List + + @Query("SELECT * FROM $OWNED_COIN_DTO_TABLENAME WHERE id = :coinId") + suspend fun getOwnedCoin(coinId : String) : OwnedCoinDto } \ No newline at end of file diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/FakeOwnedCoinsRepositoryImpl.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/FakeOwnedCoinsRepositoryImpl.kt index 8a6189c..2f325d3 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/FakeOwnedCoinsRepositoryImpl.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/FakeOwnedCoinsRepositoryImpl.kt @@ -78,6 +78,10 @@ class FakeOwnedCoinsRepositoryImpl @Inject constructor() : OwnedCoinsRepository } } + override suspend fun getOwnedCoin(coinId: String): OwnedCoinDto { + return FakeOwnedCoins.first() + } + override suspend fun getOwnedCoins(): List { return coroutineScope { withContext(Dispatchers.IO) { diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt index e573863..cfb5ec2 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt @@ -23,6 +23,13 @@ class OwnedCoinsRepositoryImpl @Inject constructor( } } + override suspend fun getOwnedCoin(coinId: String): OwnedCoinDto { + return coroutineScope { + coinsDao.getOwnedCoin(coinId) + } + } + + override suspend fun getOwnedCoins(): List { return coroutineScope { coinsDao.getOwnedCoins() diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt index e12029b..9f21d93 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt @@ -8,6 +8,8 @@ interface OwnedCoinsRepository { suspend fun saveOwnedCoin(coin : OwnedCoinDto) : String + suspend fun getOwnedCoin(coinId : String) : OwnedCoinDto + suspend fun getOwnedCoins() : List suspend fun saveDisplayCurrencyData(displayCurrencyDataMap : HashMap) diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/GetOwnedCoinUseCase.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/GetOwnedCoinUseCase.kt new file mode 100644 index 0000000..1e1e0c8 --- /dev/null +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/GetOwnedCoinUseCase.kt @@ -0,0 +1,30 @@ +package com.ryankoech.krypto.feature_home.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_home.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto +import com.ryankoech.krypto.feature_home.domain.repository.OwnedCoinsRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onStart +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Named + +class GetOwnedCoinUseCase @Inject constructor( + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: OwnedCoinsRepository +) { + + operator fun invoke(coinId : String) = flow> { + Timber.d("GetOwnedCoinUseCase") + emit(Resource.Success(repository.getOwnedCoin(coinId))) + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + Timber.e(e) + emit(Resource.Error(e.localizedMessage ?: "An Unknown Error Occured")) + }.flowOn(Dispatchers.IO) + +} \ No newline at end of file From f6e61bbccf58679cade74083da51694266af5a15 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 12:13:20 +0300 Subject: [PATCH 114/201] fix usecase to return flow --- .../domain/usecase/SaveOwnedCoinUseCase.kt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/SaveOwnedCoinUseCase.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/SaveOwnedCoinUseCase.kt index 3e10c99..fa41edc 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/SaveOwnedCoinUseCase.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/SaveOwnedCoinUseCase.kt @@ -5,6 +5,8 @@ import com.ryankoech.krypto.feature_home.core.di.HILT_NAME_REPO_FOR_ALL import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto import com.ryankoech.krypto.feature_home.domain.repository.OwnedCoinsRepository import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject @@ -14,14 +16,11 @@ class SaveOwnedCoinUseCase @Inject constructor( @Named(HILT_NAME_REPO_FOR_ALL) private val repository : OwnedCoinsRepository ) { - suspend operator fun invoke(coin : OwnedCoinDto) : Resource = - try { - val id = repository.saveOwnedCoin(coin) - Resource.Success( - data = id - ) - }catch (e : Exception) { - Timber.e(e) - Resource.Error(e.message?: "Unexpected Error Occurred" ) - } + operator fun invoke(coin : OwnedCoinDto) = flow> { + val id = repository.saveOwnedCoin(coin) + emit(Resource.Success(id)) + }.catch { e -> + Timber.e(e) + emit(Resource.Error(e.message?: "Unexpected Error Occurred" )) + } } \ No newline at end of file From 242358af4c4f4ab4b93b0dd61ee4d72a6f589603 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 12:14:20 +0300 Subject: [PATCH 115/201] add enable parameter and preview --- .../presentation/components/KryptoButton.kt | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/KryptoButton.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/KryptoButton.kt index ac25d95..7905a72 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/KryptoButton.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/KryptoButton.kt @@ -1,15 +1,14 @@ package com.ryankoech.krypto.common.presentation.components import androidx.compose.foundation.layout.padding -import androidx.compose.material.Button -import androidx.compose.material.ButtonDefaults -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text +import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.theme.Green200 +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme @Composable @@ -17,6 +16,7 @@ fun KryptoButton( modifier: Modifier = Modifier, text : String, color : Color = Green200, + enabled : Boolean = true, onClick : () -> Unit ) { @@ -25,6 +25,7 @@ fun KryptoButton( colors = ButtonDefaults.buttonColors( backgroundColor = color ), + enabled = enabled, shape = MaterialTheme.shapes.medium, elevation = ButtonDefaults.elevation( defaultElevation = 0.dp @@ -40,3 +41,15 @@ fun KryptoButton( } } + +@Preview +@Composable +fun KryptoButtonPreview(){ + + KryptoTheme { + Surface { + KryptoButton(text = "Button") {} + } + } + +} \ No newline at end of file From 542bbe1f6845ae0c658d268d7cdcd3196c96a600 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 12:16:14 +0300 Subject: [PATCH 116/201] update type to double --- .../data/dto/transaction_dto/TransactionDto.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionDto.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionDto.kt index 0218835..bb6b1e7 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionDto.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/dto/transaction_dto/TransactionDto.kt @@ -12,5 +12,5 @@ data class TransactionDto( val coinId : String, val transactionType : TransactionType, val currentPrice : Double, - val amount : Float, + val amount : Double, ) From b40eca8148d86e7e1b5bb2b8f46dbfdde6f0e7cf Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 12:19:39 +0300 Subject: [PATCH 117/201] add home module dependency --- feature_transaction/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/feature_transaction/build.gradle b/feature_transaction/build.gradle index 1cd395a..1dd915c 100644 --- a/feature_transaction/build.gradle +++ b/feature_transaction/build.gradle @@ -56,6 +56,7 @@ dependencies { implementation "com.google.dagger:hilt-android:$hilt_android_version" implementation "androidx.hilt:hilt-navigation-compose:$hilt_navigation_compose_version" implementation project(path: ':feature_coin_list') + implementation project(path: ':feature_home') kapt "com.google.dagger:hilt-android-compiler:$hilt_android_compile_version" kapt "androidx.hilt:hilt-compiler:$hilt_compile_version" From 95ff2daf6b627104379f2fc96e4d8c184c9a4984 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 12:20:44 +0300 Subject: [PATCH 118/201] update to match new double type --- .../data/repository/FakeTransactionRepository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt index 9a6e832..46976b2 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt @@ -11,14 +11,14 @@ val bitCoinTransaction = listOf( date = 1675655596952, coinId = "bitcoin", currentPrice = 20000.00, - amount = 1.5F, + amount = 1.5, transactionType = TransactionType.BUY ), TransactionDto( date = 1675655696952, coinId = "bitcoin", currentPrice = 24000.00, - amount = 0.5F, + amount = 0.5, transactionType = TransactionType.SELL ), ) From aca9a482f6970921109ea884ea69db49482a3036 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 12:22:02 +0300 Subject: [PATCH 119/201] implement viewmodel --- .../viewmodel/TransactionScreenViewModel.kt | 117 ++++++++++++++++++ .../viewstate/TransactionScreenViewState.kt | 9 ++ 2 files changed, 126 insertions(+) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewstate/TransactionScreenViewState.kt diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt new file mode 100644 index 0000000..3f5f33b --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt @@ -0,0 +1,117 @@ +package com.ryankoech.krypto.feature_transaction.presentation.transaction.viewmodel + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_home.domain.usecase.GetOwnedCoinUseCase +import com.ryankoech.krypto.feature_home.domain.usecase.SaveOwnedCoinUseCase +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType +import com.ryankoech.krypto.feature_transaction.domain.usecase.SaveCoinTransactionUseCase +import com.ryankoech.krypto.feature_transaction.presentation.transaction.viewstate.TransactionScreenViewState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import timber.log.Timber +import javax.inject.Inject + +@HiltViewModel +class TransactionScreenViewModel @Inject constructor( + private val saveCoinTransactionUseCase: SaveCoinTransactionUseCase, + private val getOwnedCoinUseCase : GetOwnedCoinUseCase, + private val saveOwnedCoinUseCase: SaveOwnedCoinUseCase +) : ViewModel() { + + private val _viewState = mutableStateOf(TransactionScreenViewState()) + val viewState : State = _viewState + + fun getCoinAmount(coinId : String) { + Timber.d("getCoinAmount") + + getOwnedCoinUseCase(coinId) + .onEach { res -> + when(res) { + is Resource.Error -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + is Resource.Loading -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING + ) + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS, + ownedCoin = res.data!! + ) + + } + } + }.launchIn(viewModelScope) + } + + fun saveCoinTransaction (transaction : TransactionDto) { + + val newOwnedCoin = _viewState.value.ownedCoin.copy( + amount = if( transaction.transactionType == TransactionType.BUY) { + _viewState.value.ownedCoin.amount + transaction.amount + }else { + _viewState.value.ownedCoin.amount - transaction.amount + } + ) + + saveOwnedCoinUseCase(newOwnedCoin) + .onEach { res -> + when(res) { + is Resource.Error -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS + ) + insertTransaction(transaction) + } + else -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + } + } + + } + + private fun insertTransaction(transaction : TransactionDto) { + + saveCoinTransactionUseCase(transaction) + .onEach { res -> + when(res) { + is Resource.Error -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + is Resource.Loading -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING + ) + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS + ) + } + } + } + + } + +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewstate/TransactionScreenViewState.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewstate/TransactionScreenViewState.kt new file mode 100644 index 0000000..93bc574 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewstate/TransactionScreenViewState.kt @@ -0,0 +1,9 @@ +package com.ryankoech.krypto.feature_transaction.presentation.transaction.viewstate + +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto + +data class TransactionScreenViewState( + val screenState: ScreenState = ScreenState.LOADING, + val ownedCoin : OwnedCoinDto = OwnedCoinDto("", "", 0.0, 0.0F, 0.0, "") +) From a476a3e45878a1bd9afad75412987c74f04435b4 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 12:23:50 +0300 Subject: [PATCH 120/201] implement ui logic --- .../transaction/TransactionScreen.kt | 26 ++++++- .../components/BuyTransactionScreen.kt | 57 +++++++++++--- .../components/SellTransactionScreen.kt | 76 +++++++++++++++++-- 3 files changed, 140 insertions(+), 19 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt index ff09652..431e2cb 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt @@ -2,28 +2,30 @@ package com.ryankoech.krypto.feature_transaction.presentation.transaction import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding import androidx.compose.material.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.text.toUpperCase import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.pagerTabIndicatorOffset import com.google.accompanist.pager.rememberPagerState import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto import com.ryankoech.krypto.feature_transaction.domain.entity.Coin import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity import com.ryankoech.krypto.feature_transaction.presentation.transaction.components.BuyTransactionScreen import com.ryankoech.krypto.feature_transaction.presentation.transaction.components.SellTransactionScreen import com.ryankoech.krypto.feature_transaction.presentation.transaction.util.TabRowItem +import com.ryankoech.krypto.feature_transaction.presentation.transaction.viewmodel.TransactionScreenViewModel import kotlinx.coroutines.launch import java.util.* @@ -31,15 +33,28 @@ import java.util.* @Composable fun TransactionScreen( coin : Coin, + viewModel : TransactionScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { + val viewState = viewModel.viewState.value + + LaunchedEffect(key1 = Unit){ + viewModel.getCoinAmount(coin.id) + } + + val onTransactionButtonClick = { transaction : TransactionDto -> + viewModel.saveCoinTransaction(transaction) + } + val tabRowItems = listOf( TabRowItem( title = "Buy", screen = { BuyTransactionScreen( - coin + coin = coin, + onTransactionButtonClick = onTransactionButtonClick, + screenState = viewState.screenState ) }, ), @@ -47,7 +62,10 @@ fun TransactionScreen( title = "SELL", screen = { SellTransactionScreen( - coin + coin = coin, + onTransactionButtonClick = onTransactionButtonClick, + ownedCoinDto = viewState.ownedCoin, + screenState = viewState.screenState ) }, ), diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt index 6c0a56e..b706076 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt @@ -1,12 +1,9 @@ package com.ryankoech.krypto.feature_transaction.presentation.transaction.components -import android.widget.EditText import androidx.compose.foundation.layout.* -import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.currentCompositionLocalContext +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -15,16 +12,20 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.toUpperCase import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.ryankoech.krypto.common.presentation.components.KryptoButton import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.DisplayCurrency +import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto +import com.ryankoech.krypto.feature_home.data.repository.FakeOwnedCoins import com.ryankoech.krypto.feature_transaction.R +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType import com.ryankoech.krypto.feature_transaction.domain.entity.Coin import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity import java.util.* @@ -32,6 +33,8 @@ import java.util.* @Composable fun BuyTransactionScreen( coin : Coin, + onTransactionButtonClick : (TransactionDto) -> Unit, + screenState : ScreenState, modifier : Modifier = Modifier ) { @@ -42,6 +45,24 @@ fun BuyTransactionScreen( ) val spacing = 24.dp + var enteredQuantity by remember { + mutableStateOf("") + } + + val onEnteredQuantityChange = onEnteredQuantityChange@{ text : String -> + if(text.isEmpty()){ + enteredQuantity = text + return@onEnteredQuantityChange + } + + try { + enteredQuantity = text + }catch(_ : Throwable) { + return@onEnteredQuantityChange + } + + } + Column( modifier = modifier .padding(12.dp) @@ -72,8 +93,8 @@ fun BuyTransactionScreen( Spacer(Modifier.height(spacing)) TextField( - value = "", - onValueChange = {}, + value = enteredQuantity, + onValueChange = onEnteredQuantityChange, textStyle = textFieldTextStyle, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), placeholder = { @@ -105,7 +126,23 @@ fun BuyTransactionScreen( modifier = Modifier .fillMaxWidth(), text = "Buy " + coin.name, - onClick = {} + enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null, + onClick = onClick@{ + + if(enteredQuantity.toDoubleOrNull() == null){ + return@onClick + } + + val transaction = TransactionDto( + date = Calendar.getInstance().timeInMillis, + coinId = coin.id, + transactionType = TransactionType.BUY, + currentPrice = coin.price, + amount = enteredQuantity.toDouble() + ) + + onTransactionButtonClick(transaction) + } ) } @@ -118,7 +155,9 @@ fun BuyTransactionScreenPreview() { KryptoTheme { Surface { BuyTransactionScreen( - FAKE_COIN_LIST.toCoinEntity().first() + FAKE_COIN_LIST.toCoinEntity().first(), + {}, + ScreenState.SUCCESS ) } } diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt index c4eb382..2908da0 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -3,7 +3,7 @@ package com.ryankoech.krypto.feature_transaction.presentation.transaction.compon import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.* -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -18,10 +18,16 @@ import androidx.compose.ui.unit.sp import com.ryankoech.krypto.common.presentation.components.KryptoButton import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.theme.Red200 +import com.ryankoech.krypto.common.presentation.theme.Red400 import com.ryankoech.krypto.common.presentation.util.DisplayCurrency +import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto +import com.ryankoech.krypto.feature_home.data.repository.FakeOwnedCoins import com.ryankoech.krypto.feature_transaction.R +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType import com.ryankoech.krypto.feature_transaction.domain.entity.Coin import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity import java.util.* @@ -29,7 +35,10 @@ import java.util.* @Composable fun SellTransactionScreen( coin : Coin, - modifier: Modifier = Modifier + onTransactionButtonClick : (TransactionDto) -> Unit, + ownedCoinDto: OwnedCoinDto, + screenState : ScreenState, + modifier: Modifier = Modifier, ) { val context = LocalContext.current @@ -38,6 +47,32 @@ fun SellTransactionScreen( textAlign = TextAlign.Center ) val spacing = 24.dp + var enteredQuanity by remember { + mutableStateOf("") + } + var enterQuantityError by remember { + mutableStateOf(false) + } + + val onEnteredQuantityChange = onEnteredQuantityChange@{ text : String -> + if(text.isEmpty()){ + enteredQuanity = text + return@onEnteredQuantityChange + } + + try { + if (text.toDouble() > ownedCoinDto.amount) { + enteredQuanity = ownedCoinDto.amount.toString() + enterQuantityError = true + } else { + enteredQuanity = text + enterQuantityError = false + } + }catch(_ : Throwable) { + return@onEnteredQuantityChange + } + + } Column( modifier = modifier @@ -69,8 +104,8 @@ fun SellTransactionScreen( Spacer(Modifier.height(spacing)) TextField( - value = "", - onValueChange = {}, + value = enteredQuanity, + onValueChange = onEnteredQuantityChange, textStyle = textFieldTextStyle, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), placeholder = { @@ -92,6 +127,16 @@ fun SellTransactionScreen( Spacer(Modifier.height(spacing)) + if(enterQuantityError){ + Text( + text = "You can not exceed your " + coin.name + " balance.", + style = MaterialTheme.typography.caption, + color = Red400 + ) + + Spacer(Modifier.height(spacing / 2)) + } + Text( text = "${getFormattedBalance(context, coin.price, DisplayCurrency.USD)} per coin.", style = MaterialTheme.typography.caption, @@ -103,7 +148,23 @@ fun SellTransactionScreen( .fillMaxWidth(), text = "Sell " + coin.name, color = Red200, - onClick = {} + enabled = screenState == ScreenState.SUCCESS && enteredQuanity.toDoubleOrNull() != null, + onClick = onClick@{ + + if(enteredQuanity.toDoubleOrNull() == null){ + return@onClick + } + + val transaction = TransactionDto( + date = Calendar.getInstance().timeInMillis, + coinId = coin.id, + transactionType = TransactionType.SELL, + currentPrice = coin.price, + amount = enteredQuanity.toDouble() + ) + + onTransactionButtonClick(transaction) + } ) } @@ -116,7 +177,10 @@ fun SellTransactionScreenPreview() { KryptoTheme { Surface { SellTransactionScreen( - FAKE_COIN_LIST.toCoinEntity().first() + FAKE_COIN_LIST.toCoinEntity().first(), + {}, + FakeOwnedCoins.first(), + ScreenState.SUCCESS ) } } From a26ecbbf1bec823d7a9a88bccddb699142304321 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 13:26:52 +0300 Subject: [PATCH 121/201] implement null check extension functions --- .../java/com/ryankoech/krypto/common/core/ktx/Any.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 common/src/main/java/com/ryankoech/krypto/common/core/ktx/Any.kt diff --git a/common/src/main/java/com/ryankoech/krypto/common/core/ktx/Any.kt b/common/src/main/java/com/ryankoech/krypto/common/core/ktx/Any.kt new file mode 100644 index 0000000..15524cd --- /dev/null +++ b/common/src/main/java/com/ryankoech/krypto/common/core/ktx/Any.kt @@ -0,0 +1,9 @@ +package com.ryankoech.krypto.common.core.ktx + +fun Any?.isNull() : Boolean { + return this == null +} + +fun Any?.isNotNull() : Boolean { + return this != null +} \ No newline at end of file From 7685e78fdace30f1aa0bd907f680a9700a1bdca5 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 13:27:30 +0300 Subject: [PATCH 122/201] add nullable return type --- .../feature_coin_list/data/data_source/local/db/CoinDao.kt | 2 +- .../feature_coin_list/data/repository/CoinRepositoryImpl.kt | 2 +- .../feature_coin_list/domain/repository/CoinRepository.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt index f4cac38..485fdca 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/data_source/local/db/CoinDao.kt @@ -16,6 +16,6 @@ interface CoinDao { suspend fun getCoins() : List @Query("SELECT * FROM $TANLENAME_COIN_DTO WHERE id = :coinId") - suspend fun getCoin(coinId : String) : CoinLocalDto + suspend fun getCoin(coinId : String) : CoinLocalDto? } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt index 1536968..ceff42e 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/repository/CoinRepositoryImpl.kt @@ -21,7 +21,7 @@ class CoinRepositoryImpl @Inject constructor( dao.insertCoins(coins) } - override suspend fun getCoin(coinId: String): CoinLocalDto = dao.getCoin(coinId) + override suspend fun getCoin(coinId: String): CoinLocalDto? = dao.getCoin(coinId) } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt index 7f61d12..a46acc6 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/repository/CoinRepository.kt @@ -12,5 +12,5 @@ interface CoinRepository { suspend fun saveCoins(coins : List) - suspend fun getCoin(coinId : String) : CoinLocalDto + suspend fun getCoin(coinId : String) : CoinLocalDto? } \ No newline at end of file From 49a8a8034db9961e6516b2fb75b478734af30ff6 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 13 Feb 2023 13:31:10 +0300 Subject: [PATCH 123/201] implement to account for nullable types from db --- feature_home/build.gradle | 1 + .../data_source/local/db/OwnedCoinsDao.kt | 2 +- .../repository/OwnedCoinsRepositoryImpl.kt | 2 +- .../domain/repository/OwnedCoinsRepository.kt | 2 +- .../domain/usecase/GetOwnedCoinUseCase.kt | 30 ++++++++++++++++--- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/feature_home/build.gradle b/feature_home/build.gradle index 4662e46..8557516 100644 --- a/feature_home/build.gradle +++ b/feature_home/build.gradle @@ -51,6 +51,7 @@ dependencies { // local modules implementation project(":common") + implementation project(path: ':feature_coin_list') //Compose implementation "androidx.compose.ui:ui:$compose_version" diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt index e4c2884..9f30726 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt @@ -17,5 +17,5 @@ interface OwnedCoinsDao { suspend fun getOwnedCoins() : List @Query("SELECT * FROM $OWNED_COIN_DTO_TABLENAME WHERE id = :coinId") - suspend fun getOwnedCoin(coinId : String) : OwnedCoinDto + suspend fun getOwnedCoin(coinId : String) : OwnedCoinDto? } \ No newline at end of file diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt index cfb5ec2..f076521 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt @@ -23,7 +23,7 @@ class OwnedCoinsRepositoryImpl @Inject constructor( } } - override suspend fun getOwnedCoin(coinId: String): OwnedCoinDto { + override suspend fun getOwnedCoin(coinId: String): OwnedCoinDto? { return coroutineScope { coinsDao.getOwnedCoin(coinId) } diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt index 9f21d93..a9f5532 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt @@ -8,7 +8,7 @@ interface OwnedCoinsRepository { suspend fun saveOwnedCoin(coin : OwnedCoinDto) : String - suspend fun getOwnedCoin(coinId : String) : OwnedCoinDto + suspend fun getOwnedCoin(coinId : String) : OwnedCoinDto? suspend fun getOwnedCoins() : List diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/GetOwnedCoinUseCase.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/GetOwnedCoinUseCase.kt index 1e1e0c8..246e2e2 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/GetOwnedCoinUseCase.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/GetOwnedCoinUseCase.kt @@ -1,7 +1,10 @@ package com.ryankoech.krypto.feature_home.domain.usecase +import com.ryankoech.krypto.common.core.ktx.isNull import com.ryankoech.krypto.common.core.util.Resource -import com.ryankoech.krypto.feature_home.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL as HILT_NAME_REPO_FOR_ALL_COIN_LIST +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import com.ryankoech.krypto.feature_home.core.di.HILT_NAME_REPO_FOR_ALL as HILT_NAME_REPO_FOR_ALL_HOME import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto import com.ryankoech.krypto.feature_home.domain.repository.OwnedCoinsRepository import kotlinx.coroutines.Dispatchers @@ -14,12 +17,31 @@ import javax.inject.Inject import javax.inject.Named class GetOwnedCoinUseCase @Inject constructor( - @Named(HILT_NAME_REPO_FOR_ALL) private val repository: OwnedCoinsRepository + @Named(HILT_NAME_REPO_FOR_ALL_HOME) private val repository: OwnedCoinsRepository, + @Named(HILT_NAME_REPO_FOR_ALL_COIN_LIST) private val coinRepository: CoinRepository, ) { operator fun invoke(coinId : String) = flow> { - Timber.d("GetOwnedCoinUseCase") - emit(Resource.Success(repository.getOwnedCoin(coinId))) + val ownedCoin = repository.getOwnedCoin(coinId) + if(ownedCoin.isNull()){ + val coinLocal = coinRepository.getCoin(coinId) + + if(coinLocal.isNull()){ + throw Exception("No Corresponding Local Coin Found.") + } + val ownedCoinFromLocalCoin = OwnedCoinDto( + id = coinLocal!!.id, + symbol = coinLocal.symbol, + value = coinLocal.price, + change = coinLocal.change, + amount = 0.0, + icon = coinLocal.image + ) + emit(Resource.Success(ownedCoinFromLocalCoin)) + return@flow + } + + emit(Resource.Success(ownedCoin!!)) }.onStart { emit(Resource.Loading()) }.catch { e -> From a1d05762d44b4051f43f8bece813385f5a8d1c10 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 10:36:01 +0300 Subject: [PATCH 124/201] fix functions to suspend functions --- .../data/data_source/local/TransactionDao.kt | 7 ++++--- .../data/repository/FakeTransactionRepository.kt | 4 ++-- .../data/repository/TransactionRepositoryImpl.kt | 10 ++++++++-- .../domain/repository/TransactionRepository.kt | 4 ++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt index a272abf..3d9941a 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt @@ -2,6 +2,7 @@ package com.ryankoech.krypto.feature_transaction.data.data_source.local import androidx.room.Dao import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TABLE_NAME_TRANSACTION import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto @@ -9,10 +10,10 @@ import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.Transac @Dao interface TransactionDao { - @Insert - fun insertTransaction(transactionDto: TransactionDto) + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertTransaction(transactionDto: TransactionDto) @Query("SELECT * FROM `$TABLE_NAME_TRANSACTION` WHERE coinId = :coinId ORDER by date DESC") - fun getCoinTransactions(coinId : String) : List + suspend fun getCoinTransactions(coinId : String) : List } \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt index 46976b2..29950fb 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt @@ -24,12 +24,12 @@ val bitCoinTransaction = listOf( ) class FakeTransactionRepository @Inject constructor() : TransactionRepository { - override fun addTransaction(transaction: TransactionDto) { + override suspend fun addTransaction(transaction: TransactionDto) { Timber.d("Added transaction.") Timber.d(transaction.toString()) } - override fun getCoinTransactions(coinId: String): List { + override suspend fun getCoinTransactions(coinId: String): List { return if(coinId == bitCoinTransaction.first().coinId){ bitCoinTransaction } else { diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt index 0310465..24618dc 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt @@ -3,14 +3,20 @@ package com.ryankoech.krypto.feature_transaction.data.repository import com.ryankoech.krypto.feature_transaction.data.data_source.local.TransactionDao import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto import com.ryankoech.krypto.feature_transaction.domain.repository.TransactionRepository +import kotlinx.coroutines.coroutineScope +import timber.log.Timber import javax.inject.Inject class TransactionRepositoryImpl @Inject constructor( private val dao: TransactionDao ) : TransactionRepository { - override fun addTransaction(transaction: TransactionDto) = dao.insertTransaction(transaction) + override suspend fun addTransaction(transaction: TransactionDto) { + return coroutineScope { + dao.insertTransaction(transaction) + } + } - override fun getCoinTransactions(coinId: String): List = dao.getCoinTransactions(coinId) + override suspend fun getCoinTransactions(coinId: String): List = dao.getCoinTransactions(coinId) } \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt index 8a1e681..9e39da5 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt @@ -4,7 +4,7 @@ import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.Transac interface TransactionRepository { - fun addTransaction(transaction : TransactionDto) + suspend fun addTransaction(transaction : TransactionDto) - fun getCoinTransactions(coinId : String) : List + suspend fun getCoinTransactions(coinId : String) : List } \ No newline at end of file From b495a7492bb816cdd554a057476e2f796cbaccd5 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 10:43:04 +0300 Subject: [PATCH 125/201] add coroutine scope, remove loggers, update ownedcoin update logic --- .../viewmodel/TransactionScreenViewModel.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt index 3f5f33b..dcaabeb 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt @@ -29,7 +29,6 @@ class TransactionScreenViewModel @Inject constructor( val viewState : State = _viewState fun getCoinAmount(coinId : String) { - Timber.d("getCoinAmount") getOwnedCoinUseCase(coinId) .onEach { res -> @@ -57,15 +56,17 @@ class TransactionScreenViewModel @Inject constructor( fun saveCoinTransaction (transaction : TransactionDto) { - val newOwnedCoin = _viewState.value.ownedCoin.copy( - amount = if( transaction.transactionType == TransactionType.BUY) { - _viewState.value.ownedCoin.amount + transaction.amount - }else { - _viewState.value.ownedCoin.amount - transaction.amount - } + _viewState.value = _viewState.value.copy( + ownedCoin = _viewState.value.ownedCoin.copy( + amount = if( transaction.transactionType == TransactionType.BUY) { + _viewState.value.ownedCoin.amount + transaction.amount + }else { + _viewState.value.ownedCoin.amount - transaction.amount + } + ) ) - saveOwnedCoinUseCase(newOwnedCoin) + saveOwnedCoinUseCase(_viewState.value.ownedCoin) .onEach { res -> when(res) { is Resource.Error -> { @@ -85,12 +86,11 @@ class TransactionScreenViewModel @Inject constructor( ) } } - } + }.launchIn(viewModelScope) } private fun insertTransaction(transaction : TransactionDto) { - saveCoinTransactionUseCase(transaction) .onEach { res -> when(res) { @@ -110,7 +110,7 @@ class TransactionScreenViewModel @Inject constructor( ) } } - } + }.launchIn(viewModelScope) } From ba8b74efa3858f92c8bcd4c999fb1aeca1f51fb9 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 10:48:25 +0300 Subject: [PATCH 126/201] minor improvment --- .../transaction/components/BuyTransactionScreen.kt | 5 ++--- .../transaction/components/SellTransactionScreen.kt | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt index b706076..1cb33e4 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt @@ -15,14 +15,13 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.ryankoech.krypto.common.core.ktx.isNull import com.ryankoech.krypto.common.presentation.components.KryptoButton import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.DisplayCurrency import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST -import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto -import com.ryankoech.krypto.feature_home.data.repository.FakeOwnedCoins import com.ryankoech.krypto.feature_transaction.R import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType @@ -129,7 +128,7 @@ fun BuyTransactionScreen( enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null, onClick = onClick@{ - if(enteredQuantity.toDoubleOrNull() == null){ + if(enteredQuantity.toDoubleOrNull().isNull()){ return@onClick } diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt index 2908da0..79886cd 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.ryankoech.krypto.common.core.ktx.isNull import com.ryankoech.krypto.common.presentation.components.KryptoButton import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.theme.Red200 @@ -151,7 +152,7 @@ fun SellTransactionScreen( enabled = screenState == ScreenState.SUCCESS && enteredQuanity.toDoubleOrNull() != null, onClick = onClick@{ - if(enteredQuanity.toDoubleOrNull() == null){ + if(enteredQuanity.toDoubleOrNull().isNull()){ return@onClick } From 3d15419703ef0dc50562587657e33873b0900ab4 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 12:19:45 +0300 Subject: [PATCH 127/201] update balance formatting logic, extract string resources --- .../krypto/common/presentation/util/Utils.kt | 36 +++++++++++++++---- common/src/main/res/values/strings.xml | 7 +++- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt index 780debf..ae86a28 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt @@ -18,10 +18,32 @@ fun getFormattedChange(context: Context, change : Float) : String { } fun getFormattedBalance(context : Context, balance : Double, displayCurrency: DisplayCurrency) : String { + val million = 1_000_000 + val billion = 1_000_000_000 + val trillion = 1_000_000_000_000 + val quadrillion = 1_000_000_000_000_000 + val quintillion = 1_000_000_000_000_000_000 + + val extension : String = if(balance < million) { + "" + }else if(balance < billion){ + context.getString(R.string.symbol_million) + }else if(balance < trillion){ + context.getString(R.string.symbol_billion) + }else if(balance < quadrillion){ + context.getString(R.string.symbol_trillion) + }else if(balance < quintillion){ + context.getString(R.string.symbol_quadrillion) + }else { + return when (displayCurrency) { + DisplayCurrency.USD -> context.getString(R.string.symbol_quintillion_fallback, "$") + else -> context.getString(R.string.symbol_quintillion_fallback, "$displayCurrency ") + } + } val roundOffBalance = getInTwoDecimalPlaces(balance) return when (displayCurrency) { - DisplayCurrency.USD -> context.getString(R.string.coin_amount_balance, "$", roundOffBalance) - else -> context.getString(R.string.coin_amount_balance, "$displayCurrency ", roundOffBalance) + DisplayCurrency.USD -> context.getString(R.string.coin_amount_balance, "$", roundOffBalance, extension) + else -> context.getString(R.string.coin_amount_balance, "$displayCurrency ", roundOffBalance, extension) } } @@ -47,28 +69,28 @@ fun getFormattedMarketCap(context: Context, value : Long) : String { context.getString( R.string.coin_market_cap, getInFourDecimalPlaces(value.toDouble() / million.toDouble()), - "M" + context.getString(R.string.symbol_million) ) }else if(value < trillion){ context.getString( R.string.coin_market_cap, getInFourDecimalPlaces(value.toDouble() / billion.toDouble()), - "Bn" + context.getString(R.string.symbol_billion) ) }else if(value < quadrillion){ context.getString( R.string.coin_market_cap, getInFourDecimalPlaces(value.toDouble() / trillion.toDouble()), - "Tr" + context.getString(R.string.symbol_trillion) ) }else if(value < quintillion){ context.getString( R.string.coin_market_cap, getInFourDecimalPlaces(value.toDouble() / quadrillion.toDouble()), - "Tr" + context.getString(R.string.symbol_quadrillion) ) }else { - "Over $1 Qnt" + context.getString(R.string.symbol_quintillion_fallback, "$") } } diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index fad1980..e25142a 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -2,6 +2,11 @@ %s Image %s%s%% - %s%s + %s%s %s MCap $%s %s + M + Bn + Tr + Qdr + Over %s1 Qnt \ No newline at end of file From c68dbf42c332961b7c73bfbd43d612db7d521588 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 12:22:28 +0300 Subject: [PATCH 128/201] update owned coin update logic --- .../transaction/viewmodel/TransactionScreenViewModel.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt index dcaabeb..3207e47 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt @@ -62,7 +62,9 @@ class TransactionScreenViewModel @Inject constructor( _viewState.value.ownedCoin.amount + transaction.amount }else { _viewState.value.ownedCoin.amount - transaction.amount - } + }, + value = transaction.currentPrice, + change = (transaction.currentPrice - _viewState.value.ownedCoin.value / _viewState.value.ownedCoin.value * 100).toFloat() ) ) From c4f657bffbc15c0b958782a9db758ad1d11f9101 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 12:23:17 +0300 Subject: [PATCH 129/201] add amount tag --- .../transaction/TransactionScreen.kt | 2 +- .../components/BuyTransactionScreen.kt | 31 +++++++++++ .../components/SellTransactionScreen.kt | 52 +++++++++++++++---- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt index 431e2cb..e3d04c3 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt @@ -64,7 +64,7 @@ fun TransactionScreen( SellTransactionScreen( coin = coin, onTransactionButtonClick = onTransactionButtonClick, - ownedCoinDto = viewState.ownedCoin, + ownedCoin = viewState.ownedCoin, screenState = viewState.screenState ) }, diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt index 1cb33e4..48c546c 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt @@ -1,5 +1,6 @@ package com.ryankoech.krypto.feature_transaction.presentation.transaction.components +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.* @@ -15,8 +16,10 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.ryankoech.krypto.common.core.ktx.isNotNull import com.ryankoech.krypto.common.core.ktx.isNull import com.ryankoech.krypto.common.presentation.components.KryptoButton +import com.ryankoech.krypto.common.presentation.theme.Green200 import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.DisplayCurrency import com.ryankoech.krypto.common.presentation.util.ScreenState @@ -119,6 +122,34 @@ fun BuyTransactionScreen( text = "${getFormattedBalance(context, coin.price, DisplayCurrency.USD)} per coin.", style = MaterialTheme.typography.caption, ) + + if(enteredQuantity.toDoubleOrNull().isNotNull() && enteredQuantity.toDouble() > 0) { + + Spacer(Modifier.height(spacing)) + + Box( + modifier = Modifier + .background( + color = Green200.copy( + alpha = 0.8F + ), + shape = MaterialTheme.shapes.small + ), + ){ + Text( + modifier = Modifier + .padding( + vertical = 4.dp, + horizontal = 6.dp + ), + text = getFormattedBalance(context, enteredQuantity.toDouble() * coin.price, DisplayCurrency.USD), + style = MaterialTheme.typography.caption.copy( + fontSize = 12.sp + ) + ) + } + + } } KryptoButton( diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt index 79886cd..19f5a19 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -1,5 +1,6 @@ package com.ryankoech.krypto.feature_transaction.presentation.transaction.components +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.* @@ -15,8 +16,10 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.ryankoech.krypto.common.core.ktx.isNotNull import com.ryankoech.krypto.common.core.ktx.isNull import com.ryankoech.krypto.common.presentation.components.KryptoButton +import com.ryankoech.krypto.common.presentation.theme.Green200 import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.theme.Red200 import com.ryankoech.krypto.common.presentation.theme.Red400 @@ -37,7 +40,7 @@ import java.util.* fun SellTransactionScreen( coin : Coin, onTransactionButtonClick : (TransactionDto) -> Unit, - ownedCoinDto: OwnedCoinDto, + ownedCoin: OwnedCoinDto, screenState : ScreenState, modifier: Modifier = Modifier, ) { @@ -48,7 +51,7 @@ fun SellTransactionScreen( textAlign = TextAlign.Center ) val spacing = 24.dp - var enteredQuanity by remember { + var enteredQuantity by remember { mutableStateOf("") } var enterQuantityError by remember { @@ -57,16 +60,16 @@ fun SellTransactionScreen( val onEnteredQuantityChange = onEnteredQuantityChange@{ text : String -> if(text.isEmpty()){ - enteredQuanity = text + enteredQuantity = text return@onEnteredQuantityChange } try { - if (text.toDouble() > ownedCoinDto.amount) { - enteredQuanity = ownedCoinDto.amount.toString() + if (text.toDouble() > ownedCoin.amount) { + enteredQuantity = ownedCoin.amount.toString() enterQuantityError = true } else { - enteredQuanity = text + enteredQuantity = text enterQuantityError = false } }catch(_ : Throwable) { @@ -105,7 +108,7 @@ fun SellTransactionScreen( Spacer(Modifier.height(spacing)) TextField( - value = enteredQuanity, + value = enteredQuantity, onValueChange = onEnteredQuantityChange, textStyle = textFieldTextStyle, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), @@ -142,6 +145,35 @@ fun SellTransactionScreen( text = "${getFormattedBalance(context, coin.price, DisplayCurrency.USD)} per coin.", style = MaterialTheme.typography.caption, ) + + if(enteredQuantity.toDoubleOrNull().isNotNull() && enteredQuantity.toDouble() > 0) { + + Spacer(Modifier.height(spacing)) + + Box( + modifier = Modifier + .background( + color = Green200.copy( + alpha = 0.8F + ), + shape = MaterialTheme.shapes.small + ), + ){ + Text( + modifier = Modifier + .padding( + vertical = 4.dp, + horizontal = 6.dp + ), + text = getFormattedBalance(context, enteredQuantity.toDouble() * ownedCoin.value, DisplayCurrency.USD), + style = MaterialTheme.typography.caption.copy( + fontSize = 12.sp + ) + ) + } + + } + } KryptoButton( @@ -149,10 +181,10 @@ fun SellTransactionScreen( .fillMaxWidth(), text = "Sell " + coin.name, color = Red200, - enabled = screenState == ScreenState.SUCCESS && enteredQuanity.toDoubleOrNull() != null, + enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null, onClick = onClick@{ - if(enteredQuanity.toDoubleOrNull().isNull()){ + if(enteredQuantity.toDoubleOrNull().isNull()){ return@onClick } @@ -161,7 +193,7 @@ fun SellTransactionScreen( coinId = coin.id, transactionType = TransactionType.SELL, currentPrice = coin.price, - amount = enteredQuanity.toDouble() + amount = enteredQuantity.toDouble() ) onTransactionButtonClick(transaction) From 1cb73eeb5d2dd93bb05ddee926a3d32b47e6f113 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 12:39:45 +0300 Subject: [PATCH 130/201] extract string resources --- .../presentation/transaction/TransactionScreen.kt | 6 ++++-- .../transaction/components/BuyTransactionScreen.kt | 9 +++++---- .../transaction/components/SellTransactionScreen.kt | 11 ++++++----- feature_transaction/src/main/res/values/strings.xml | 12 ++++++++++++ 4 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 feature_transaction/src/main/res/values/strings.xml diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt index e3d04c3..d5a8e38 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -19,6 +20,7 @@ import com.google.accompanist.pager.pagerTabIndicatorOffset import com.google.accompanist.pager.rememberPagerState import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_transaction.R import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto import com.ryankoech.krypto.feature_transaction.domain.entity.Coin import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity @@ -49,7 +51,7 @@ fun TransactionScreen( val tabRowItems = listOf( TabRowItem( - title = "Buy", + title = stringResource(R.string.tab_title_buy), screen = { BuyTransactionScreen( coin = coin, @@ -59,7 +61,7 @@ fun TransactionScreen( }, ), TabRowItem( - title = "SELL", + title = stringResource(R.string.tab_title_sell), screen = { SellTransactionScreen( coin = coin, diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt index 48c546c..ef8011f 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -104,7 +105,7 @@ fun BuyTransactionScreen( modifier = Modifier .fillMaxWidth() .alpha(0.4f), - text = "Quantity", + text = stringResource(R.string.placeholder_transaction_amount), style = textFieldTextStyle, color = Color.Black ) @@ -119,7 +120,7 @@ fun BuyTransactionScreen( Spacer(Modifier.height(spacing)) Text( - text = "${getFormattedBalance(context, coin.price, DisplayCurrency.USD)} per coin.", + text = stringResource(R.string.price_coin, getFormattedBalance(context, coin.price, DisplayCurrency.USD)), style = MaterialTheme.typography.caption, ) @@ -142,7 +143,7 @@ fun BuyTransactionScreen( vertical = 4.dp, horizontal = 6.dp ), - text = getFormattedBalance(context, enteredQuantity.toDouble() * coin.price, DisplayCurrency.USD), + text = stringResource(R.string.amount_tag_buying, getFormattedBalance(context, enteredQuantity.toDouble() * coin.price, DisplayCurrency.USD)), style = MaterialTheme.typography.caption.copy( fontSize = 12.sp ) @@ -155,7 +156,7 @@ fun BuyTransactionScreen( KryptoButton( modifier = Modifier .fillMaxWidth(), - text = "Buy " + coin.name, + text = stringResource(R.string.button_label_buy, coin.name), enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null, onClick = onClick@{ diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt index 19f5a19..e439047 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -117,7 +118,7 @@ fun SellTransactionScreen( modifier = Modifier .fillMaxWidth() .alpha(0.4f), - text = "Quantity", + text = stringResource(R.string.placeholder_transaction_amount), style = textFieldTextStyle, color = Color.Black ) @@ -133,7 +134,7 @@ fun SellTransactionScreen( if(enterQuantityError){ Text( - text = "You can not exceed your " + coin.name + " balance.", + text = stringResource(R.string.error_max_balance, coin.name), style = MaterialTheme.typography.caption, color = Red400 ) @@ -142,7 +143,7 @@ fun SellTransactionScreen( } Text( - text = "${getFormattedBalance(context, coin.price, DisplayCurrency.USD)} per coin.", + text = stringResource(R.string.price_coin, getFormattedBalance(context, coin.price, DisplayCurrency.USD)), style = MaterialTheme.typography.caption, ) @@ -165,7 +166,7 @@ fun SellTransactionScreen( vertical = 4.dp, horizontal = 6.dp ), - text = getFormattedBalance(context, enteredQuantity.toDouble() * ownedCoin.value, DisplayCurrency.USD), + text = stringResource(R.string.amount_tag_selling, getFormattedBalance(context, enteredQuantity.toDouble() * ownedCoin.value, DisplayCurrency.USD)), style = MaterialTheme.typography.caption.copy( fontSize = 12.sp ) @@ -179,7 +180,7 @@ fun SellTransactionScreen( KryptoButton( modifier = Modifier .fillMaxWidth(), - text = "Sell " + coin.name, + text = stringResource(R.string.button_label_sell, coin.name), color = Red200, enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null, onClick = onClick@{ diff --git a/feature_transaction/src/main/res/values/strings.xml b/feature_transaction/src/main/res/values/strings.xml new file mode 100644 index 0000000..c3c4ee9 --- /dev/null +++ b/feature_transaction/src/main/res/values/strings.xml @@ -0,0 +1,12 @@ + + + Quantity + %s per coin. + Buy %s + You\'ll pay %s + Sell %s + You\'ll receive % + You can not exceed your %s balance. + Buy + Sell + \ No newline at end of file From d66e17286260cf7e3056cd60bec1d5cd8ea40809 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 13:08:05 +0300 Subject: [PATCH 131/201] minor fix --- feature_transaction/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature_transaction/src/main/res/values/strings.xml b/feature_transaction/src/main/res/values/strings.xml index c3c4ee9..a7b4544 100644 --- a/feature_transaction/src/main/res/values/strings.xml +++ b/feature_transaction/src/main/res/values/strings.xml @@ -5,7 +5,7 @@ Buy %s You\'ll pay %s Sell %s - You\'ll receive % + You\'ll receive %s You can not exceed your %s balance. Buy Sell From 210e179eaa5e0f48bc03c1ed674f560f8bccc46b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 13:08:25 +0300 Subject: [PATCH 132/201] set singleline --- .../presentation/transaction/components/BuyTransactionScreen.kt | 1 + .../presentation/transaction/components/SellTransactionScreen.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt index ef8011f..d649dd0 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt @@ -99,6 +99,7 @@ fun BuyTransactionScreen( value = enteredQuantity, onValueChange = onEnteredQuantityChange, textStyle = textFieldTextStyle, + singleLine = true, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), placeholder = { Text( diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt index e439047..34eb935 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -112,6 +112,7 @@ fun SellTransactionScreen( value = enteredQuantity, onValueChange = onEnteredQuantityChange, textStyle = textFieldTextStyle, + singleLine = true, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), placeholder = { Text( From 06c37f33500618fda2bd3c864291d30440b42304 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 13:09:03 +0300 Subject: [PATCH 133/201] update name variable --- .../feature_transaction/core/di/TransactionRepositoryModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionRepositoryModule.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionRepositoryModule.kt index 4d52802..7b95902 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionRepositoryModule.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/core/di/TransactionRepositoryModule.kt @@ -13,7 +13,7 @@ import javax.inject.Singleton const val HILT_NAMED_REPO_FAKE = "FakeRepo" const val HILT_NAMED_REPO = "Repo" -const val HILT_NAME_REPO_FOR_ALL = HILT_NAMED_REPO_FAKE +const val HILT_NAME_REPO_FOR_ALL = HILT_NAMED_REPO @Module @InstallIn(SingletonComponent::class) From 2f610924c223ee47aa1b7a6d3d7f74406cc8ebde Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 13:33:23 +0300 Subject: [PATCH 134/201] implement navigation condition and logic --- .../transaction/TransactionScreen.kt | 19 +++++++++++++++++++ .../components/SellTransactionScreen.kt | 1 + .../viewmodel/TransactionScreenViewModel.kt | 3 ++- .../viewstate/TransactionScreenViewState.kt | 3 ++- .../src/main/res/values/strings.xml | 1 + 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt index d5a8e38..b4be06f 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt @@ -1,5 +1,6 @@ package com.ryankoech.krypto.feature_transaction.presentation.transaction +import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.material.* @@ -9,6 +10,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -19,6 +21,7 @@ import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.pagerTabIndicatorOffset import com.google.accompanist.pager.rememberPagerState import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_transaction.R import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto @@ -35,16 +38,31 @@ import java.util.* @Composable fun TransactionScreen( coin : Coin, + navigateBackToHomeScreen : () -> Unit, viewModel : TransactionScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { + val context = LocalContext.current val viewState = viewModel.viewState.value LaunchedEffect(key1 = Unit){ viewModel.getCoinAmount(coin.id) } + val errorMessage = stringResource(R.string.error_message) + LaunchedEffect(key1 = viewState.screenState){ + if(viewState.screenState == ScreenState.ERROR){ + Toast.makeText(context, errorMessage, Toast.LENGTH_SHORT).show() + } + } + + LaunchedEffect(key1 = viewState.backToHome){ + if(viewState.backToHome){ + navigateBackToHomeScreen() + } + } + val onTransactionButtonClick = { transaction : TransactionDto -> viewModel.saveCoinTransaction(transaction) } @@ -130,6 +148,7 @@ fun TransactionScreenPreview() { Surface { TransactionScreen( FAKE_COIN_LIST.toCoinEntity().first(), + {} ) } } diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt index 34eb935..c43a030 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -198,6 +198,7 @@ fun SellTransactionScreen( amount = enteredQuantity.toDouble() ) + enteredQuantity = "" onTransactionButtonClick(transaction) } ) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt index 3207e47..47e75a2 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt @@ -108,7 +108,8 @@ class TransactionScreenViewModel @Inject constructor( } is Resource.Success -> { _viewState.value = _viewState.value.copy( - screenState = ScreenState.SUCCESS + screenState = ScreenState.SUCCESS, + backToHome = true, ) } } diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewstate/TransactionScreenViewState.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewstate/TransactionScreenViewState.kt index 93bc574..d0cd46e 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewstate/TransactionScreenViewState.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewstate/TransactionScreenViewState.kt @@ -5,5 +5,6 @@ import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto data class TransactionScreenViewState( val screenState: ScreenState = ScreenState.LOADING, - val ownedCoin : OwnedCoinDto = OwnedCoinDto("", "", 0.0, 0.0F, 0.0, "") + val ownedCoin : OwnedCoinDto = OwnedCoinDto("", "", 0.0, 0.0F, 0.0, ""), + val backToHome : Boolean = false, ) diff --git a/feature_transaction/src/main/res/values/strings.xml b/feature_transaction/src/main/res/values/strings.xml index a7b4544..61f0381 100644 --- a/feature_transaction/src/main/res/values/strings.xml +++ b/feature_transaction/src/main/res/values/strings.xml @@ -9,4 +9,5 @@ You can not exceed your %s balance. Buy Sell + Something went wrong. Try again later. \ No newline at end of file From 25f15beb8780d5feefc044366bc1d6f302f289b4 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 14 Feb 2023 13:35:48 +0300 Subject: [PATCH 135/201] amount check --- .../transaction/components/SellTransactionScreen.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt index c43a030..c7dd0ed 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -190,6 +190,10 @@ fun SellTransactionScreen( return@onClick } + if(enteredQuantity.toDouble() > ownedCoin.amount){ + return@onClick + } + val transaction = TransactionDto( date = Calendar.getInstance().timeInMillis, coinId = coin.id, From ea580d7507f7b61b22606af0fab605f893e4b8b6 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 15 Feb 2023 12:09:39 +0300 Subject: [PATCH 136/201] add feature module --- feature_coin_details/.gitignore | 1 + feature_coin_details/build.gradle | 41 +++++++++++++++++++ feature_coin_details/consumer-rules.pro | 0 feature_coin_details/proguard-rules.pro | 21 ++++++++++ .../mylibrary/ExampleInstrumentedTest.kt | 24 +++++++++++ .../src/main/AndroidManifest.xml | 4 ++ .../krypto/mylibrary/ExampleUnitTest.kt | 17 ++++++++ settings.gradle | 1 + 8 files changed, 109 insertions(+) create mode 100644 feature_coin_details/.gitignore create mode 100644 feature_coin_details/build.gradle create mode 100644 feature_coin_details/consumer-rules.pro create mode 100644 feature_coin_details/proguard-rules.pro create mode 100644 feature_coin_details/src/androidTest/java/com/ryankoech/krypto/mylibrary/ExampleInstrumentedTest.kt create mode 100644 feature_coin_details/src/main/AndroidManifest.xml create mode 100644 feature_coin_details/src/test/java/com/ryankoech/krypto/mylibrary/ExampleUnitTest.kt diff --git a/feature_coin_details/.gitignore b/feature_coin_details/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/feature_coin_details/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle new file mode 100644 index 0000000..9a81dd1 --- /dev/null +++ b/feature_coin_details/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.ryankoech.krypto.mylibrary' + compileSdk 32 + + defaultConfig { + minSdk 21 + targetSdk 32 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.8.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} \ No newline at end of file diff --git a/feature_coin_details/consumer-rules.pro b/feature_coin_details/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/feature_coin_details/proguard-rules.pro b/feature_coin_details/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/feature_coin_details/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature_coin_details/src/androidTest/java/com/ryankoech/krypto/mylibrary/ExampleInstrumentedTest.kt b/feature_coin_details/src/androidTest/java/com/ryankoech/krypto/mylibrary/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..993d009 --- /dev/null +++ b/feature_coin_details/src/androidTest/java/com/ryankoech/krypto/mylibrary/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.ryankoech.krypto.mylibrary + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.ryankoech.krypto.mylibrary.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/feature_coin_details/src/main/AndroidManifest.xml b/feature_coin_details/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/feature_coin_details/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/feature_coin_details/src/test/java/com/ryankoech/krypto/mylibrary/ExampleUnitTest.kt b/feature_coin_details/src/test/java/com/ryankoech/krypto/mylibrary/ExampleUnitTest.kt new file mode 100644 index 0000000..7f2a57f --- /dev/null +++ b/feature_coin_details/src/test/java/com/ryankoech/krypto/mylibrary/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.ryankoech.krypto.mylibrary + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index d721631..39512df 100644 --- a/settings.gradle +++ b/settings.gradle @@ -18,3 +18,4 @@ include ':feature_home' include ':common' include ':feature_coin_list' include ':feature_transaction' +include ':feature_coin_details' From 649e1d38c44b63dae7bfdf7e238c3a258959a9f2 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 15 Feb 2023 12:18:47 +0300 Subject: [PATCH 137/201] add missing color --- .../com/ryankoech/krypto/common/presentation/theme/Color.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Color.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Color.kt index c2201e5..03ef447 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Color.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Color.kt @@ -8,4 +8,5 @@ val Purple700 = Color(0xFF3700B3) val Teal200 = Color(0xFF03DAC5) val Green500 = Color(0xff39b23f) val Green200 = Color(0xffa1f5b9) -val Red400 = Color(0xfffc4e51) \ No newline at end of file +val Red400 = Color(0xfffc4e51) +val Red200 = Color(0xfff79a9c) \ No newline at end of file From 770a2eb377b09f9a4231772280d84f6125fd440c Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 15 Feb 2023 12:28:56 +0300 Subject: [PATCH 138/201] fix wrong package name --- feature_coin_details/build.gradle | 6 +++--- .../ExampleInstrumentedTest.kt | 4 ++-- .../{mylibrary => feature_coin_details}/ExampleUnitTest.kt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename feature_coin_details/src/androidTest/java/com/ryankoech/krypto/{mylibrary => feature_coin_details}/ExampleInstrumentedTest.kt (79%) rename feature_coin_details/src/test/java/com/ryankoech/krypto/{mylibrary => feature_coin_details}/ExampleUnitTest.kt (86%) diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle index 9a81dd1..f9b6a8c 100644 --- a/feature_coin_details/build.gradle +++ b/feature_coin_details/build.gradle @@ -4,12 +4,12 @@ plugins { } android { - namespace 'com.ryankoech.krypto.mylibrary' - compileSdk 32 + namespace 'com.ryankoech.krypto.feature_coin_details' + compileSdk 33 defaultConfig { minSdk 21 - targetSdk 32 + targetSdk 33 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" diff --git a/feature_coin_details/src/androidTest/java/com/ryankoech/krypto/mylibrary/ExampleInstrumentedTest.kt b/feature_coin_details/src/androidTest/java/com/ryankoech/krypto/feature_coin_details/ExampleInstrumentedTest.kt similarity index 79% rename from feature_coin_details/src/androidTest/java/com/ryankoech/krypto/mylibrary/ExampleInstrumentedTest.kt rename to feature_coin_details/src/androidTest/java/com/ryankoech/krypto/feature_coin_details/ExampleInstrumentedTest.kt index 993d009..e958964 100644 --- a/feature_coin_details/src/androidTest/java/com/ryankoech/krypto/mylibrary/ExampleInstrumentedTest.kt +++ b/feature_coin_details/src/androidTest/java/com/ryankoech/krypto/feature_coin_details/ExampleInstrumentedTest.kt @@ -1,4 +1,4 @@ -package com.ryankoech.krypto.mylibrary +package com.ryankoech.krypto.feature_coin_details import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -19,6 +19,6 @@ class ExampleInstrumentedTest { fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.ryankoech.krypto.mylibrary.test", appContext.packageName) + assertEquals("com.ryankoech.krypto.feature_coin_details.test", appContext.packageName) } } \ No newline at end of file diff --git a/feature_coin_details/src/test/java/com/ryankoech/krypto/mylibrary/ExampleUnitTest.kt b/feature_coin_details/src/test/java/com/ryankoech/krypto/feature_coin_details/ExampleUnitTest.kt similarity index 86% rename from feature_coin_details/src/test/java/com/ryankoech/krypto/mylibrary/ExampleUnitTest.kt rename to feature_coin_details/src/test/java/com/ryankoech/krypto/feature_coin_details/ExampleUnitTest.kt index 7f2a57f..7ba94c9 100644 --- a/feature_coin_details/src/test/java/com/ryankoech/krypto/mylibrary/ExampleUnitTest.kt +++ b/feature_coin_details/src/test/java/com/ryankoech/krypto/feature_coin_details/ExampleUnitTest.kt @@ -1,4 +1,4 @@ -package com.ryankoech.krypto.mylibrary +package com.ryankoech.krypto.feature_coin_details import org.junit.Test From d769f464c19184838a23411ab879c4e29209a457 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 15 Feb 2023 12:34:05 +0300 Subject: [PATCH 139/201] use gradle variables --- feature_coin_details/build.gradle | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle index f9b6a8c..efd1389 100644 --- a/feature_coin_details/build.gradle +++ b/feature_coin_details/build.gradle @@ -32,10 +32,17 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.8.0' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + // core android + implementation "androidx.core:core-ktx:$ktx_core_version" + implementation "androidx.appcompat:appcompat:$app_compat_version" + implementation "com.google.android.material:material:$material_version" + + // junit4 + testImplementation "junit:junit:$junit_version" + + // junit4 + androidTestImplementation "androidx.test.ext:junit:$junit_ext_version" + + // espresso + androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" } \ No newline at end of file From f7c96cc9c70634e94ac5927e7a9878fc25f3b3a3 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 15 Feb 2023 12:47:44 +0300 Subject: [PATCH 140/201] add retrofit2, okhttp dependencies --- feature_coin_details/build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle index efd1389..78b12c3 100644 --- a/feature_coin_details/build.gradle +++ b/feature_coin_details/build.gradle @@ -37,6 +37,13 @@ dependencies { implementation "androidx.appcompat:appcompat:$app_compat_version" implementation "com.google.android.material:material:$material_version" + // retrofit - for network call + implementation "com.squareup.retrofit2:retrofit:$retrofit_version" + implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" + + // okhttp logging interceptor + implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_logging_interceptor_version" + // junit4 testImplementation "junit:junit:$junit_version" From f7d8cb8436703762236800f8b080b6bdf761a9bf Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 15 Feb 2023 12:48:30 +0300 Subject: [PATCH 141/201] implement api serivce with dto --- .../data/data_source/remote/CoinServiceApi.kt | 18 ++++++++++++++++++ .../dto/market_chart_dto/MarketChartDto.kt | 12 ++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinServiceApi.kt create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/dto/market_chart_dto/MarketChartDto.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinServiceApi.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinServiceApi.kt new file mode 100644 index 0000000..e999fbd --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinServiceApi.kt @@ -0,0 +1,18 @@ +package com.ryankoech.krypto.feature_coin_details.data.data_source.remote + +import com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto.MarketChartDto +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface CoinServiceApi { + + @GET("/coins/{id}/market_chart") + suspend fun getCoinMarketChart( + @Path(value = "id", encoded = true) coinId : String, + @Query("days") days : Int, + @Query("vs_currency") currency : String = "usd", + ) : Response + +} \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/dto/market_chart_dto/MarketChartDto.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/dto/market_chart_dto/MarketChartDto.kt new file mode 100644 index 0000000..eb92bd5 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/dto/market_chart_dto/MarketChartDto.kt @@ -0,0 +1,12 @@ +package com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto + +import com.google.gson.annotations.SerializedName + +data class MarketChartDto( + @SerializedName("market_caps") + val marketCaps: List>, + @SerializedName("prices") + val prices: List>, + @SerializedName("total_volumes") + val totalVolumes: List> +) \ No newline at end of file From ea2ace1c7863da25bdbf1460d067c72ced35b91b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 15 Feb 2023 12:59:10 +0300 Subject: [PATCH 142/201] add hilt dependencies --- feature_coin_details/build.gradle | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle index 78b12c3..3abceb7 100644 --- a/feature_coin_details/build.gradle +++ b/feature_coin_details/build.gradle @@ -1,6 +1,8 @@ plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'dagger.hilt.android.plugin' + id 'kotlin-kapt' } android { @@ -44,6 +46,12 @@ dependencies { // okhttp logging interceptor implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_logging_interceptor_version" + // dagger-hilt - for dependency injection + implementation "com.google.dagger:hilt-android:$hilt_android_version" + implementation "androidx.hilt:hilt-navigation-compose:$hilt_navigation_compose_version" + kapt "com.google.dagger:hilt-android-compiler:$hilt_android_compile_version" + kapt "androidx.hilt:hilt-compiler:$hilt_compile_version" + // junit4 testImplementation "junit:junit:$junit_version" From 6e8fcf1c72a0ff39e8fb3dbc21687468d5cd7c9d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 15 Feb 2023 12:59:51 +0300 Subject: [PATCH 143/201] implement api service provider module --- .../core/di/ApiServiceModule.kt | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/ApiServiceModule.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/ApiServiceModule.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/ApiServiceModule.kt new file mode 100644 index 0000000..fa4209f --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/ApiServiceModule.kt @@ -0,0 +1,53 @@ +package com.ryankoech.krypto.feature_coin_details.core.di + +import com.ryankoech.krypto.feature_coin_details.BuildConfig +import com.ryankoech.krypto.feature_coin_details.data.data_source.remote.CoinServiceApi +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +private const val BASE_URL = "https://api.coingecko.com/api/v3/" + +@Module +@InstallIn(SingletonComponent::class) +object ApiServiceModule { + + @Singleton + @Provides + fun provideLoggingInterceptor() : OkHttpClient { + + val loggingInterceptor = HttpLoggingInterceptor() + loggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY + else HttpLoggingInterceptor.Level.NONE + + return OkHttpClient.Builder() + .readTimeout(120, TimeUnit.SECONDS) + .connectTimeout(120, TimeUnit.SECONDS) + .addInterceptor(loggingInterceptor) + .build() + } + + @Singleton + @Provides + fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { + return Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .client(okHttpClient) + .build() + } + + @Singleton + @Provides + fun provideCoinServiceApi(retrofit: Retrofit) : CoinServiceApi = + retrofit.create(CoinServiceApi::class.java) + + +} \ No newline at end of file From 258f30314fa6695c01e7e683fd18af52d784a5b1 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 18 Feb 2023 11:08:17 +0300 Subject: [PATCH 144/201] implement repository --- .../core/di/RepositoryModule.kt | 35 ++++++++++++++ .../repository/CoinDetailsRepositoryImpl.kt | 32 +++++++++++++ .../repository/FakeCoinDetailsRepository.kt | 48 +++++++++++++++++++ .../repository/CoinDetailsRepository.kt | 15 ++++++ 4 files changed, 130 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/RepositoryModule.kt create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/CoinDetailsRepositoryImpl.kt create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/FakeCoinDetailsRepository.kt create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/repository/CoinDetailsRepository.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/RepositoryModule.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/RepositoryModule.kt new file mode 100644 index 0000000..2844553 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/RepositoryModule.kt @@ -0,0 +1,35 @@ +package com.ryankoech.krypto.feature_coin_details.core.di + +import com.ryankoech.krypto.feature_coin_details.data.repository.CoinDetailsRepositoryImpl +import com.ryankoech.krypto.feature_coin_details.data.repository.FakeCoinDetailsRepository +import com.ryankoech.krypto.feature_coin_details.domain.repository.CoinDetailsRepository +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Named +import javax.inject.Singleton + +const val HILT_NAMED_REPO_FAKE = "FakeRepo" +const val HILT_NAMED_REPO = "Repo" +const val HILT_NAME_REPO_FOR_ALL = HILT_NAMED_REPO + +@Module +@InstallIn(SingletonComponent::class) +abstract class RepositoryModule { + + @Binds + @Singleton + @Named(HILT_NAMED_REPO) + abstract fun provideCoinDetailRepository( + repository: CoinDetailsRepositoryImpl + ) : CoinDetailsRepository + + @Binds + @Singleton + @Named(HILT_NAMED_REPO_FAKE) + abstract fun provideFakeCoinDetailRepository( + repository: FakeCoinDetailsRepository + ) : CoinDetailsRepository + +} \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/CoinDetailsRepositoryImpl.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/CoinDetailsRepositoryImpl.kt new file mode 100644 index 0000000..8761e29 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/CoinDetailsRepositoryImpl.kt @@ -0,0 +1,32 @@ +package com.ryankoech.krypto.feature_coin_details.data.repository + +import com.ryankoech.krypto.feature_coin_details.data.data_source.remote.CoinServiceApi +import com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto.MarketChartDto +import com.ryankoech.krypto.feature_coin_details.domain.repository.CoinDetailsRepository +import kotlinx.coroutines.coroutineScope +import retrofit2.Response +import javax.inject.Inject + +class CoinDetailsRepositoryImpl @Inject constructor( + private val apiService : CoinServiceApi +) : CoinDetailsRepository { + + override suspend fun getDayMarketChart(coinId : String): Response { + return coroutineScope { + apiService.getCoinMarketChart(coinId, 1) + } + } + + override suspend fun getThreeMonthsMarketChart(coinId : String): Response { + return coroutineScope { + apiService.getCoinMarketChart(coinId, 90) + } + } + + override suspend fun getYearMarketChart(coinId : String): Response { + return coroutineScope { + apiService.getCoinMarketChart(coinId, 365) + } + } + +} \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/FakeCoinDetailsRepository.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/FakeCoinDetailsRepository.kt new file mode 100644 index 0000000..f50339e --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/FakeCoinDetailsRepository.kt @@ -0,0 +1,48 @@ +package com.ryankoech.krypto.feature_coin_details.data.repository + +import com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto.MarketChartDto +import com.ryankoech.krypto.feature_coin_details.domain.repository.CoinDetailsRepository +import retrofit2.Response +import javax.inject.Inject + +val FAKE_MARKET_CHART_DTO = MarketChartDto( + prices = listOf( + listOf( 0.0, 21719.94377889883), + listOf( 0.0, 21726.012694376623), + listOf( 0.0, 21754.081777271844), + listOf( 0.0, 21787.54913559603), + listOf( 0.0, 21750.230221882968), + listOf( 0.0, 21719.94377889883), + listOf( 0.0, 21751.645292836954), + listOf( 0.0, 21825.36877917646), + listOf( 0.0, 21821.486652083513), + listOf( 0.0, 21804.720442422582), + ), + marketCaps = listOf(), + totalVolumes = listOf(), +) + +class FakeCoinDetailsRepository @Inject constructor() : CoinDetailsRepository { + + override suspend fun getDayMarketChart(coinId: String): Response { + return Response.success( + FAKE_MARKET_CHART_DTO.copy( + prices = FAKE_MARKET_CHART_DTO.prices.subList(0, (FAKE_MARKET_CHART_DTO.prices.size-1)/3) + ) + ) + } + + override suspend fun getThreeMonthsMarketChart(coinId: String): Response { + return Response.success( + FAKE_MARKET_CHART_DTO.copy( + prices = FAKE_MARKET_CHART_DTO.prices.subList(0,FAKE_MARKET_CHART_DTO.prices.size/2) + ) + ) + } + + override suspend fun getYearMarketChart(coinId: String): Response { + return Response.success( + FAKE_MARKET_CHART_DTO + ) + } +} \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/repository/CoinDetailsRepository.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/repository/CoinDetailsRepository.kt new file mode 100644 index 0000000..9633ed3 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/repository/CoinDetailsRepository.kt @@ -0,0 +1,15 @@ +package com.ryankoech.krypto.feature_coin_details.domain.repository + +import com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto.MarketChartDto +import com.ryankoech.krypto.feature_coin_details.domain.entity.MarketChartEntity +import retrofit2.Response + +interface CoinDetailsRepository { + + suspend fun getDayMarketChart(coinId : String) : Response + + suspend fun getThreeMonthsMarketChart(coinId : String) : Response + + suspend fun getYearMarketChart(coinId : String) : Response + +} \ No newline at end of file From c02ee5697737a672d0b4f876752f77d031746c0f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 18 Feb 2023 11:09:22 +0300 Subject: [PATCH 145/201] add timber dependency --- feature_coin_details/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle index 3abceb7..47cee6a 100644 --- a/feature_coin_details/build.gradle +++ b/feature_coin_details/build.gradle @@ -39,6 +39,9 @@ dependencies { implementation "androidx.appcompat:appcompat:$app_compat_version" implementation "com.google.android.material:material:$material_version" + // local modules + implementation project(":common") + // retrofit - for network call implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" @@ -52,6 +55,9 @@ dependencies { kapt "com.google.dagger:hilt-android-compiler:$hilt_android_compile_version" kapt "androidx.hilt:hilt-compiler:$hilt_compile_version" + // timber + implementation "com.jakewharton.timber:timber:$timber_version" + // junit4 testImplementation "junit:junit:$junit_version" From 406a17f2c6573dfed923317735acb6e03ca23ad9 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sat, 18 Feb 2023 11:11:25 +0300 Subject: [PATCH 146/201] implement usecase, list type convertor --- .../dto/market_chart_dto/MarketChartDto.kt | 11 ++++- .../domain/entity/MarketChartEntity.kt | 6 +++ .../domain/usecase/GetCoinMarketChart.kt | 49 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/MarketChartEntity.kt create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChart.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/dto/market_chart_dto/MarketChartDto.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/dto/market_chart_dto/MarketChartDto.kt index eb92bd5..8232fc3 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/dto/market_chart_dto/MarketChartDto.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/dto/market_chart_dto/MarketChartDto.kt @@ -1,6 +1,7 @@ package com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto import com.google.gson.annotations.SerializedName +import com.ryankoech.krypto.feature_coin_details.domain.entity.MarketChartEntity data class MarketChartDto( @SerializedName("market_caps") @@ -9,4 +10,12 @@ data class MarketChartDto( val prices: List>, @SerializedName("total_volumes") val totalVolumes: List> -) \ No newline at end of file +) + +fun MarketChartDto.toMarketChartEntityList() : List { + return this.prices.map { + MarketChartEntity( + price = it[1] + ) + } +} \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/MarketChartEntity.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/MarketChartEntity.kt new file mode 100644 index 0000000..6e66b4a --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/MarketChartEntity.kt @@ -0,0 +1,6 @@ +package com.ryankoech.krypto.feature_coin_details.domain.entity + +data class MarketChartEntity( + val price : Double +) + diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChart.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChart.kt new file mode 100644 index 0000000..d7dabef --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChart.kt @@ -0,0 +1,49 @@ +package com.ryankoech.krypto.feature_coin_details.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_coin_details.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto.toMarketChartEntityList +import com.ryankoech.krypto.feature_coin_details.domain.entity.MarketChartEntity +import com.ryankoech.krypto.feature_coin_details.domain.repository.CoinDetailsRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Named + +class GetCoinMarketChart @Inject constructor( + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinDetailsRepository +) { + + operator fun invoke(coinId : String) = flow>>> { + + val dayMarketChartResponse = repository.getDayMarketChart(coinId) + val threeMonthMarketChartResponse = repository.getThreeMonthsMarketChart(coinId) + val yearMarketChartResponse = repository.getYearMarketChart(coinId) + + if(dayMarketChartResponse.isSuccessful && threeMonthMarketChartResponse.isSuccessful && yearMarketChartResponse.isSuccessful) { + + val dayMarketChartEntity = dayMarketChartResponse.body()!!.toMarketChartEntityList() + val threeMonthMarketChartEntity = threeMonthMarketChartResponse.body()!!.toMarketChartEntityList() + val yearMarketChartEntity = yearMarketChartResponse.body()!!.toMarketChartEntityList() + + emit(Resource.Success( + listOf( + dayMarketChartEntity, + threeMonthMarketChartEntity, + yearMarketChartEntity + ) + )) + } else { + throw Exception("Response not Successful.") + } + + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + Timber.e(e) + emit(Resource.Error( e.localizedMessage ?: "Unexpected Error Occurred.")) + } + +} \ No newline at end of file From c332598b39fa545654d6aaa4c325aa35d0249165 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 19 Feb 2023 14:12:35 +0300 Subject: [PATCH 147/201] rename file --- .../{GetCoinMarketChart.kt => GetCoinMarketChartUseCase.kt} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/{GetCoinMarketChart.kt => GetCoinMarketChartUseCase.kt} (97%) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChart.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChartUseCase.kt similarity index 97% rename from feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChart.kt rename to feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChartUseCase.kt index d7dabef..3f107d4 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChart.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChartUseCase.kt @@ -12,7 +12,7 @@ import timber.log.Timber import javax.inject.Inject import javax.inject.Named -class GetCoinMarketChart @Inject constructor( +class GetCoinMarketChartUseCase @Inject constructor( @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinDetailsRepository ) { From 9230ba22f828b87efa896250ec6b31c741bbc847 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 19 Feb 2023 14:15:43 +0300 Subject: [PATCH 148/201] implement header info ui --- .../components/success/CoinDetailsHeader.kt | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinDetailsHeader.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinDetailsHeader.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinDetailsHeader.kt new file mode 100644 index 0000000..5998c97 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinDetailsHeader.kt @@ -0,0 +1,155 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.components.success + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.CoinImage +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.* +import java.util.* + +@Composable +fun CoinDetailsHeader( + modifier: Modifier = Modifier +) { + + val context = LocalContext.current + val coinImage = "https://assets.coingecko.com/coins/images/1/large/bitcoin.png?1547033579" + val coinChange = 2.3F + val coinId = "bitcoin" + val coinPrice = 12345F + val coinName = "Bitcoin" + val coinMktCapRank = 1 + val coinSymbol = "btc" + + + Row( + modifier = modifier + .fillMaxWidth() + .height(IntrinsicSize.Min) + .background( + color = Color.White, + shape = RoundedCornerShape(10.dp) + ), + ) { + CoinImage( + coinImage, + coinId, + backgroundColor = MaterialTheme.colors.surface, + ) + + Spacer(modifier = Modifier.width(8.dp)) + + Column( + modifier = Modifier + .padding(4.dp) + .fillMaxHeight() + .weight(1.0f), + verticalArrangement = Arrangement.SpaceBetween + ) { + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + modifier = Modifier + .padding(end = 2.dp), + text = coinName, + style = MaterialTheme.typography.h3, + ) + Text( + text = getFormattedBalance( + context = context, + balance = coinPrice.toDouble(), + displayCurrency = DisplayCurrency.USD + ), + style = MaterialTheme.typography.h4 + ) + } + + Row( + modifier = Modifier + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .padding( + end = 4.dp + ) + .background( + color = Color.LightGray, + shape = RoundedCornerShape(3.dp) + ), + + ){ + Text( + modifier = Modifier + .padding( + vertical = 0.dp, + horizontal = 3.dp + ), + text = coinMktCapRank.toString(), + style = MaterialTheme.typography.h4, + color = Color.White + ) + } + Text( + modifier = Modifier + .padding(end = 2.dp) + .alpha(0.6f), + text = coinSymbol.uppercase(Locale.ROOT), + style = MaterialTheme.typography.h3, + ) + Spacer(modifier = Modifier.weight(1.0f)) + Icon( + modifier = Modifier + .size(32.dp) + .rotate(if (coinChange < 0f) 0f else 180f), + imageVector = Icons.Filled.ArrowDropDown, + tint = getChangeColor(coinChange), + contentDescription = null, + ) + Text( + text = getFormattedChange(context, coinChange), + style = MaterialTheme.typography.caption, + color = getChangeColor(coinChange) + ) + } + } + } + +} + +@Preview(showBackground = true) +@Composable +fun CoinDetailsHeaderPreview() { + KryptoTheme { + Surface( + modifier = Modifier + .fillMaxSize() + ) { + Column { + CoinDetailsHeader( + ) + } + } + } +} \ No newline at end of file From 014a06e6a4fb4237d6609b8d2c2339c242631129 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 19 Feb 2023 14:16:35 +0300 Subject: [PATCH 149/201] implement viewmodel --- .../viewmodel/CoinDetailsScreenViewModel.kt | 51 +++++++++++++++++++ .../viewstate/CoinDetailsScreenViewState.kt | 11 ++++ 2 files changed, 62 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt new file mode 100644 index 0000000..02a81a6 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt @@ -0,0 +1,51 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.viewmodel + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_details.domain.usecase.GetCoinMarketChartUseCase +import com.ryankoech.krypto.feature_coin_details.presentation.viewstate.CoinDetailsScreenViewState +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject + +class CoinDetailsScreenViewModel @Inject constructor( + private val getCoinMarketChartUseCase: GetCoinMarketChartUseCase +) : ViewModel(){ + + private val _viewState = mutableStateOf(CoinDetailsScreenViewState()) + private val viewState : State = _viewState + + fun getCoinDetails(coinId :String) { + + getCoinMarketChartUseCase(coinId) + .onEach { res -> + when(res){ + is Resource.Error -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR, + ) + } + is Resource.Loading -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING, + ) + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS, + dayMarketChart = res.data!![0], + threeMonthMarketChart = res.data!![1], + yearMarketChart = res.data!![2] + ) + } + } + + }.launchIn(viewModelScope) + + } + +} \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt new file mode 100644 index 0000000..7df3a1f --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt @@ -0,0 +1,11 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.viewstate + +import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_details.domain.entity.MarketChartEntity + +data class CoinDetailsScreenViewState( + private val screenState: ScreenState = ScreenState.LOADING, + private val dayMarketChart : List = listOf(), + private val threeMonthMarketChart : List = listOf(), + private val yearMarketChart : List = listOf(), +) From 3d4c0b792dcd4efbf5d90d803b93d9a093144287 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 19 Feb 2023 14:17:34 +0300 Subject: [PATCH 150/201] implement line chart component --- .../components/success/LineChart.kt | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt new file mode 100644 index 0000000..195dc1a --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt @@ -0,0 +1,129 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.components.success + +import android.graphics.Paint +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import kotlin.math.roundToInt + +@Composable +fun LineChart( + data: List> = emptyList(), + modifier: Modifier = Modifier +) { + val spacing = 0f + val graphColor = Color.Red + val transparentGraphColor = remember { graphColor.copy(alpha = 0.5f) } + val upperValue = remember { (data.maxOfOrNull { it.second }?.plus(1))?.roundToInt() ?: 0 } + val lowerValue = remember { (data.minOfOrNull { it.second }?.toInt() ?: 0) } + val density = LocalDensity.current + + val textPaint = remember(density) { + Paint().apply { + color = android.graphics.Color.WHITE + textAlign = Paint.Align.CENTER + textSize = density.run { 12.sp.toPx() } + } + } + + Canvas(modifier = modifier) { + val spacePerHour = (size.width - spacing) / data.size + + var medX: Float + var medY: Float + val strokePath = Path().apply { + val height = size.height + data.indices.forEach { i -> + val nextInfo = data.getOrNull(i + 1) ?: data.last() + val firstRatio = (data[i].second - lowerValue) / (upperValue - lowerValue) + val secondRatio = (nextInfo.second - lowerValue) / (upperValue - lowerValue) + + val x1 = spacing + i * spacePerHour + val y1 = height - spacing - (firstRatio * height).toFloat() + val x2 = spacing + (i + 1) * spacePerHour + val y2 = height - spacing - (secondRatio * height).toFloat() + if (i == 0) { + moveTo(x1, y1) + } else { + medX = (x1 + x2) / 2f + medY = (y1 + y2) / 2f + quadraticBezierTo(x1 = x1, y1 = y1, x2 = medX, y2 = medY) + } + } + } + + drawPath( + path = strokePath, + color = Color.Red, + style = Stroke( + width = 3.dp.toPx(), + cap = StrokeCap.Round + ) + ) + + val fillPath = android.graphics.Path(strokePath.asAndroidPath()).asComposePath().apply { + lineTo(size.width - spacePerHour, size.height - spacing) + lineTo(spacing, size.height - spacing) + close() + } + + drawPath( + path = fillPath, + brush = Brush.verticalGradient( + colors = listOf( + transparentGraphColor, + Color.Transparent + ), + endY = size.height - spacing + ) + ) + + } +} + +@Preview +@Composable +fun LineChartPreview() { + val data = listOf( + Pair(6, 111.45), + Pair(7, 111.0), + Pair(8, 113.45), + Pair(9, 112.25), + Pair(10, 116.45), + Pair(11, 113.35), + Pair(12, 118.65), + Pair(13, 110.15), + Pair(14, 113.05), + Pair(15, 114.25), + Pair(16, 116.35), + Pair(17, 117.45), + Pair(18, 112.65), + Pair(19, 115.45), + Pair(20, 111.85) + ) + KryptoTheme { + Surface ( + modifier = Modifier.background(color = Color.Black) + ) { + LineChart( + data = data, + modifier = Modifier + .fillMaxWidth() + .height(300.dp) + .background(color = Color.Black) + ) + } + } +} \ No newline at end of file From 24eb55d800ce00873d085340ace0d9d305a63fbe Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Sun, 19 Feb 2023 14:34:49 +0300 Subject: [PATCH 151/201] add compose dependencies --- feature_coin_details/build.gradle | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle index 47cee6a..fd94fb5 100644 --- a/feature_coin_details/build.gradle +++ b/feature_coin_details/build.gradle @@ -30,6 +30,12 @@ android { kotlinOptions { jvmTarget = '1.8' } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion compose_version + } } dependencies { @@ -58,6 +64,12 @@ dependencies { // timber implementation "com.jakewharton.timber:timber:$timber_version" + //Compose + implementation "androidx.compose.ui:ui:$compose_version" + implementation "androidx.compose.material:material:$compose_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" + implementation "androidx.activity:activity-compose:$compose_activity_version" + // junit4 testImplementation "junit:junit:$junit_version" From 1a7e2c884644705ecb544be31bc6a43b7810b931 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 20 Feb 2023 11:01:21 +0300 Subject: [PATCH 152/201] add module dependency --- feature_coin_details/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle index fd94fb5..7fb9a49 100644 --- a/feature_coin_details/build.gradle +++ b/feature_coin_details/build.gradle @@ -47,6 +47,7 @@ dependencies { // local modules implementation project(":common") + implementation project(":feature_coin_list") // retrofit - for network call implementation "com.squareup.retrofit2:retrofit:$retrofit_version" From 8d633e048547af5f7926d8fd38a6bf6df8466f01 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 20 Feb 2023 11:03:18 +0300 Subject: [PATCH 153/201] refactored api service class name --- .../remote/{CoinServiceApi.kt => CoinDetailsServiceApi.kt} | 2 +- .../data/repository/CoinDetailsRepositoryImpl.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/{CoinServiceApi.kt => CoinDetailsServiceApi.kt} (94%) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinServiceApi.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinDetailsServiceApi.kt similarity index 94% rename from feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinServiceApi.kt rename to feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinDetailsServiceApi.kt index e999fbd..5bf4cc5 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinServiceApi.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinDetailsServiceApi.kt @@ -6,7 +6,7 @@ import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query -interface CoinServiceApi { +interface CoinDetailsServiceApi { @GET("/coins/{id}/market_chart") suspend fun getCoinMarketChart( diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/CoinDetailsRepositoryImpl.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/CoinDetailsRepositoryImpl.kt index 8761e29..a69260d 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/CoinDetailsRepositoryImpl.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/repository/CoinDetailsRepositoryImpl.kt @@ -1,6 +1,6 @@ package com.ryankoech.krypto.feature_coin_details.data.repository -import com.ryankoech.krypto.feature_coin_details.data.data_source.remote.CoinServiceApi +import com.ryankoech.krypto.feature_coin_details.data.data_source.remote.CoinDetailsServiceApi import com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto.MarketChartDto import com.ryankoech.krypto.feature_coin_details.domain.repository.CoinDetailsRepository import kotlinx.coroutines.coroutineScope @@ -8,7 +8,7 @@ import retrofit2.Response import javax.inject.Inject class CoinDetailsRepositoryImpl @Inject constructor( - private val apiService : CoinServiceApi + private val apiService : CoinDetailsServiceApi ) : CoinDetailsRepository { override suspend fun getDayMarketChart(coinId : String): Response { From 28fe66d17a55b3a3eb6c2eb42acf2969eace452b Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 20 Feb 2023 11:04:13 +0300 Subject: [PATCH 154/201] add hilt retrofit okhttp dependencies --- common/build.gradle | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/common/build.gradle b/common/build.gradle index 23a70df..cd66b57 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,6 +1,8 @@ plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'dagger.hilt.android.plugin' + id 'kotlin-kapt' } android { @@ -49,10 +51,23 @@ dependencies { implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation "androidx.activity:activity-compose:$compose_activity_version" + // dagger-hilt - for dependency injection + implementation "com.google.dagger:hilt-android:$hilt_android_version" + implementation "androidx.hilt:hilt-navigation-compose:$hilt_navigation_compose_version" + kapt "com.google.dagger:hilt-android-compiler:$hilt_android_compile_version" + kapt "androidx.hilt:hilt-compiler:$hilt_compile_version" + // coil compose implementation "io.coil-kt:coil-compose:$coil_compose" implementation "io.coil-kt:coil-gif:$coil_compose" + // retrofit - for network call + implementation "com.squareup.retrofit2:retrofit:$retrofit_version" + implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" + + // okhttp logging interceptor + implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_logging_interceptor_version" + // junit4 testImplementation "junit:junit:$junit_version" From 686cc0df56a23d01c6635e2459f502683b489536 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 20 Feb 2023 11:06:22 +0300 Subject: [PATCH 155/201] refactor providers to common --- .../krypto/common/core/di/ApiServiceModule.kt | 47 +++++++++++++++++++ .../core/di/ApiServiceModule.kt | 38 ++------------- .../core/di/ApiServiceModule.kt | 32 ------------- 3 files changed, 50 insertions(+), 67 deletions(-) create mode 100644 common/src/main/java/com/ryankoech/krypto/common/core/di/ApiServiceModule.kt diff --git a/common/src/main/java/com/ryankoech/krypto/common/core/di/ApiServiceModule.kt b/common/src/main/java/com/ryankoech/krypto/common/core/di/ApiServiceModule.kt new file mode 100644 index 0000000..2051c6d --- /dev/null +++ b/common/src/main/java/com/ryankoech/krypto/common/core/di/ApiServiceModule.kt @@ -0,0 +1,47 @@ +package com.ryankoech.krypto.common.core.di + +import com.ryankoech.krypto.common.BuildConfig +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +private const val BASE_URL = "https://api.coingecko.com/api/v3/" + +@Module +@InstallIn(SingletonComponent::class) +object ApiServiceModule { + + @Singleton + @Provides + fun provideLoggingInterceptor() : OkHttpClient { + + val loggingInterceptor = HttpLoggingInterceptor() + loggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY + else HttpLoggingInterceptor.Level.NONE + + return OkHttpClient.Builder() + .readTimeout(120, TimeUnit.SECONDS) + .connectTimeout(120, TimeUnit.SECONDS) + .addInterceptor(loggingInterceptor) + .build() + } + + @Singleton + @Provides + fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { + return Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .client(okHttpClient) + .build() + } + + +} \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/ApiServiceModule.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/ApiServiceModule.kt index fa4209f..529add6 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/ApiServiceModule.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/core/di/ApiServiceModule.kt @@ -1,53 +1,21 @@ package com.ryankoech.krypto.feature_coin_details.core.di -import com.ryankoech.krypto.feature_coin_details.BuildConfig -import com.ryankoech.krypto.feature_coin_details.data.data_source.remote.CoinServiceApi +import com.ryankoech.krypto.feature_coin_details.data.data_source.remote.CoinDetailsServiceApi import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import java.util.concurrent.TimeUnit import javax.inject.Singleton -private const val BASE_URL = "https://api.coingecko.com/api/v3/" - @Module @InstallIn(SingletonComponent::class) object ApiServiceModule { @Singleton @Provides - fun provideLoggingInterceptor() : OkHttpClient { - - val loggingInterceptor = HttpLoggingInterceptor() - loggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY - else HttpLoggingInterceptor.Level.NONE - - return OkHttpClient.Builder() - .readTimeout(120, TimeUnit.SECONDS) - .connectTimeout(120, TimeUnit.SECONDS) - .addInterceptor(loggingInterceptor) - .build() - } - - @Singleton - @Provides - fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { - return Retrofit.Builder() - .baseUrl(BASE_URL) - .addConverterFactory(GsonConverterFactory.create()) - .client(okHttpClient) - .build() - } - - @Singleton - @Provides - fun provideCoinServiceApi(retrofit: Retrofit) : CoinServiceApi = - retrofit.create(CoinServiceApi::class.java) + fun provideCoinServiceApi(retrofit: Retrofit) : CoinDetailsServiceApi = + retrofit.create(CoinDetailsServiceApi::class.java) } \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt index 4a99e6b..0fd084b 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/core/di/ApiServiceModule.kt @@ -1,49 +1,17 @@ package com.ryankoech.krypto.feature_coin_list.core.di -import com.ryankoech.krypto.feature_coin_list.BuildConfig import com.ryankoech.krypto.feature_coin_list.data.data_source.remote.CoinServiceApi import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import java.util.concurrent.TimeUnit import javax.inject.Singleton -private const val BASE_URL = "https://api.coingecko.com/api/v3/" - @Module @InstallIn(SingletonComponent::class) object ApiServiceModule { - @Singleton - @Provides - fun provideLoggingInterceptor() : OkHttpClient { - - val loggingInterceptor = HttpLoggingInterceptor() - loggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY - else HttpLoggingInterceptor.Level.NONE - - return OkHttpClient.Builder() - .readTimeout(120, TimeUnit.SECONDS) - .connectTimeout(120, TimeUnit.SECONDS) - .addInterceptor(loggingInterceptor) - .build() - } - - @Singleton - @Provides - fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { - return Retrofit.Builder() - .baseUrl(BASE_URL) - .addConverterFactory(GsonConverterFactory.create()) - .client(okHttpClient) - .build() - } - @Singleton @Provides fun provideCoinServiceApi(retrofit: Retrofit) : CoinServiceApi = From 36ca8a3bcc7ce06185f1d4f2e78c0e5b0f6b1375 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 20 Feb 2023 11:07:32 +0300 Subject: [PATCH 156/201] add hilt annotation --- .../presentation/viewmodel/CoinDetailsScreenViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt index 02a81a6..db400e7 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt @@ -8,10 +8,12 @@ import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_details.domain.usecase.GetCoinMarketChartUseCase import com.ryankoech.krypto.feature_coin_details.presentation.viewstate.CoinDetailsScreenViewState +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import javax.inject.Inject +@HiltViewModel class CoinDetailsScreenViewModel @Inject constructor( private val getCoinMarketChartUseCase: GetCoinMarketChartUseCase ) : ViewModel(){ From 0035d65c7df55ef079b06e62c6834235bea2d883 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 23 Feb 2023 12:47:04 +0300 Subject: [PATCH 157/201] add coin object --- .../components/success/CoinDetailsHeader.kt | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinDetailsHeader.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinDetailsHeader.kt index 5998c97..55acf30 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinDetailsHeader.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinDetailsHeader.kt @@ -21,22 +21,18 @@ import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.components.CoinImage import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.* +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import java.util.* @Composable fun CoinDetailsHeader( + coin : Coin, modifier: Modifier = Modifier ) { val context = LocalContext.current - val coinImage = "https://assets.coingecko.com/coins/images/1/large/bitcoin.png?1547033579" - val coinChange = 2.3F - val coinId = "bitcoin" - val coinPrice = 12345F - val coinName = "Bitcoin" - val coinMktCapRank = 1 - val coinSymbol = "btc" - Row( modifier = modifier @@ -48,8 +44,8 @@ fun CoinDetailsHeader( ), ) { CoinImage( - coinImage, - coinId, + coin.image, + coin.id, backgroundColor = MaterialTheme.colors.surface, ) @@ -71,13 +67,13 @@ fun CoinDetailsHeader( Text( modifier = Modifier .padding(end = 2.dp), - text = coinName, + text = coin.name, style = MaterialTheme.typography.h3, ) Text( text = getFormattedBalance( context = context, - balance = coinPrice.toDouble(), + balance = coin.price, displayCurrency = DisplayCurrency.USD ), style = MaterialTheme.typography.h4 @@ -106,7 +102,7 @@ fun CoinDetailsHeader( vertical = 0.dp, horizontal = 3.dp ), - text = coinMktCapRank.toString(), + text = coin.marketCapRank.toString(), style = MaterialTheme.typography.h4, color = Color.White ) @@ -115,22 +111,22 @@ fun CoinDetailsHeader( modifier = Modifier .padding(end = 2.dp) .alpha(0.6f), - text = coinSymbol.uppercase(Locale.ROOT), + text = coin.symbol.uppercase(Locale.ROOT), style = MaterialTheme.typography.h3, ) Spacer(modifier = Modifier.weight(1.0f)) Icon( modifier = Modifier .size(32.dp) - .rotate(if (coinChange < 0f) 0f else 180f), + .rotate(if (coin.change < 0f) 0f else 180f), imageVector = Icons.Filled.ArrowDropDown, - tint = getChangeColor(coinChange), + tint = getChangeColor(coin.change), contentDescription = null, ) Text( - text = getFormattedChange(context, coinChange), + text = getFormattedChange(context, coin.change), style = MaterialTheme.typography.caption, - color = getChangeColor(coinChange) + color = getChangeColor(coin.change) ) } } @@ -148,6 +144,7 @@ fun CoinDetailsHeaderPreview() { ) { Column { CoinDetailsHeader( + FAKE_COIN_LIST.toCoinEntity().first() ) } } From da1874ad07719c1cb2c69bb3abb20da655ad5865 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 23 Feb 2023 12:48:44 +0300 Subject: [PATCH 158/201] update graph color --- .../presentation/components/success/LineChart.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt index 195dc1a..79ffd93 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt @@ -24,7 +24,7 @@ fun LineChart( modifier: Modifier = Modifier ) { val spacing = 0f - val graphColor = Color.Red + val graphColor = Color(0xff39b23f) val transparentGraphColor = remember { graphColor.copy(alpha = 0.5f) } val upperValue = remember { (data.maxOfOrNull { it.second }?.plus(1))?.roundToInt() ?: 0 } val lowerValue = remember { (data.minOfOrNull { it.second }?.toInt() ?: 0) } @@ -66,7 +66,7 @@ fun LineChart( drawPath( path = strokePath, - color = Color.Red, + color = transparentGraphColor, style = Stroke( width = 3.dp.toPx(), cap = StrokeCap.Round @@ -84,7 +84,12 @@ fun LineChart( brush = Brush.verticalGradient( colors = listOf( transparentGraphColor, - Color.Transparent + transparentGraphColor.copy( + alpha = 0.8F + ), + transparentGraphColor.copy( + alpha = 0.1F + ) ), endY = size.height - spacing ) @@ -122,7 +127,6 @@ fun LineChartPreview() { modifier = Modifier .fillMaxWidth() .height(300.dp) - .background(color = Color.Black) ) } } From 3dde62ff27db746906aaa90fccecf181a9caacaa Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 23 Feb 2023 12:49:33 +0300 Subject: [PATCH 159/201] implement component --- .../components/success/MarketRangeButton.kt | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/MarketRangeButton.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/MarketRangeButton.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/MarketRangeButton.kt new file mode 100644 index 0000000..f205e5e --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/MarketRangeButton.kt @@ -0,0 +1,61 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.components.success + +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme + +@Composable +fun MarketRangeButton( + onClick : () -> Unit, + text : String, + selected : Boolean, + modifier: Modifier = Modifier +) { + + val colorDark = Color(0xff35343a) + + Button( + modifier = modifier + .defaultMinSize(minWidth = 1.dp, minHeight = 1.dp), + onClick = onClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = if(selected) colorDark else Color.White + ), + shape = MaterialTheme.shapes.small, + // shape = RoundedCornerShape(0.dp), + elevation = ButtonDefaults.elevation( + defaultElevation = 0.dp + ), + ){ + Text( + text = text, + style = MaterialTheme.typography.button.copy( + color = if(selected) Color.White else colorDark + ) + ) + } + +} + +@Preview +@Composable +fun MarketRangeButtonPreview() { + + KryptoTheme { + Surface { + MarketRangeButton( + onClick = {}, + text = "1h", + selected = true + ) + } + } + +} \ No newline at end of file From 3aeec14a3d264bd1e1882c9239fa55797f07b548 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 23 Feb 2023 12:50:13 +0300 Subject: [PATCH 160/201] implement component --- .../components/success/CoinStatisticsCard.kt | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinStatisticsCard.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinStatisticsCard.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinStatisticsCard.kt new file mode 100644 index 0000000..df2eb8b --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/CoinStatisticsCard.kt @@ -0,0 +1,96 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.components.success + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CornerSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_coin_details.R + +@Composable +fun CoinStatisticsCard( + @DrawableRes resId : Int, + title : String, + body : String, + modifier: Modifier = Modifier +) { + + Card( + modifier = modifier, + backgroundColor = Color(0xfff2f2f2), + shape = RoundedCornerShape(50F), + elevation = 0.dp + ) { + + Row( + modifier = Modifier + .padding( + horizontal = 20.dp, + vertical = 24.dp, + ), + verticalAlignment = Alignment.CenterVertically + ) { + + Icon( + modifier = Modifier + .size(32.dp), + painter = painterResource(resId), + contentDescription = title + ) + + Column( + modifier = Modifier + .weight(1.0f), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = title, + style = MaterialTheme.typography.h4, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + + Spacer( + modifier = Modifier + .height(4.dp) + ) + + Text( + text = body, + style = MaterialTheme.typography.caption, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + + } + + } + +} + +@Preview +@Composable +fun CoinStatisticsCardPreview() { + + KryptoTheme { + Surface { + CoinStatisticsCard( + R.drawable.icon_line_graph, + "Total Volume", + "1.2111M" + ) + } + } + +} \ No newline at end of file From 667a7ce7e1f01fc13985a663a017e11a983fdfff Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 23 Feb 2023 12:51:01 +0300 Subject: [PATCH 161/201] implement coin detail screen to coin statistics --- .../presentation/CoinDetailsScreen.kt | 189 ++++++++++++++++++ .../presentation/util/CoinStatistic.kt | 9 + .../presentation/util/MarketChartRange.kt | 10 + .../src/main/res/drawable/icon_line_graph.xml | 7 + .../src/main/res/drawable/icon_pie_chart.xml | 5 + .../src/main/res/drawable/icon_rocket.xml | 11 + .../src/main/res/drawable/iconi_trophie.xml | 6 + 7 files changed, 237 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/util/CoinStatistic.kt create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/util/MarketChartRange.kt create mode 100644 feature_coin_details/src/main/res/drawable/icon_line_graph.xml create mode 100644 feature_coin_details/src/main/res/drawable/icon_pie_chart.xml create mode 100644 feature_coin_details/src/main/res/drawable/icon_rocket.xml create mode 100644 feature_coin_details/src/main/res/drawable/iconi_trophie.xml diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt new file mode 100644 index 0000000..cb66392 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -0,0 +1,189 @@ +package com.ryankoech.krypto.feature_coin_details.presentation + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap +import com.ryankoech.krypto.feature_coin_details.R +import com.ryankoech.krypto.feature_coin_details.presentation.components.success.CoinDetailsHeader +import com.ryankoech.krypto.feature_coin_details.presentation.components.success.CoinStatisticsCard +import com.ryankoech.krypto.feature_coin_details.presentation.components.success.LineChart +import com.ryankoech.krypto.feature_coin_details.presentation.components.success.MarketRangeButton +import com.ryankoech.krypto.feature_coin_details.presentation.util.CoinStatistic +import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRange +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin + +val MarketChartRangeText = listOf( + Pair(MarketChartRange.ONE_HOUR, "1h"), + Pair(MarketChartRange.ONE_DAY ,"1d"), + Pair(MarketChartRange.ONE_WEEK ,"7d"), + Pair(MarketChartRange.ONE_MONTH ,"30d"), + Pair(MarketChartRange.THREE_MONTH ,"90d"), + Pair(MarketChartRange.ONE_YEAR ,"1y"), +) + +@Composable +fun CoinDetailsScreen( + // viewModel : CoinDetailsScreenViewModel = hiltViewModel(), + coin : Coin, + modifier: Modifier = Modifier +) { + + val context = LocalContext.current + + var currentMarketChartRange by remember { + mutableStateOf(MarketChartRange.ONE_DAY) + } + + LazyColumn( + modifier = modifier + .fillMaxSize(), + contentPadding = PaddingValues(vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ){ + + item{ + CoinDetailsHeader( + coin = coin, + modifier = Modifier + .padding(horizontal = 12.dp) + ) + } + + item { + val data = listOf( + Pair(6, 111.45), + Pair(7, 111.0), + Pair(8, 113.45), + Pair(9, 112.25), + Pair(10, 116.45), + Pair(11, 113.35), + Pair(12, 118.65), + Pair(13, 110.15), + Pair(14, 113.05), + Pair(15, 114.25), + Pair(16, 116.35), + Pair(17, 117.45), + Pair(18, 112.65), + Pair(19, 115.45), + Pair(20, 111.85) + ) + LineChart( + data = data, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp) + .height(300.dp) + .background(color = Color.White) + ) + } + + + item{ + + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp), + horizontalArrangement = Arrangement.SpaceBetween, + ){ + + items(MarketChartRangeText.size){ counter -> + MarketRangeButton( + onClick = { /*TODO*/ }, + text = MarketChartRangeText[counter].second, + selected = MarketChartRangeText[counter].first == currentMarketChartRange + ) + + } + + } + + } + + item{ + Divider( + modifier = Modifier.fillMaxWidth(), + color = Color(0xfff2f2f2) + ) + } + + item{ + Text( + modifier = Modifier + .padding(horizontal = 12.dp), + text = "Coin Statistics", + style = MaterialTheme.typography.h2, + ) + } + + + item{ + + val coinStatistics = listOf( + CoinStatistic("Market Cap", "$352.1234 Bn", R.drawable.icon_pie_chart), + CoinStatistic("All Time High", "$352.1234 Bn", R.drawable.icon_pie_chart), + CoinStatistic("24hr High", "$352.1234 Bn", R.drawable.icon_pie_chart), + CoinStatistic("Total Volume", "$352.1234 Bn", R.drawable.icon_pie_chart), + ) + + LazyVerticalGrid( + modifier = Modifier + .fillMaxWidth() + .height(216.dp), + contentPadding = PaddingValues(horizontal = 12.dp), + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(20.dp), + verticalArrangement = Arrangement.SpaceAround, + userScrollEnabled = false, + ) { + + items(coinStatistics) { coinStatistic -> + CoinStatisticsCard( + resId = coinStatistic.icon, + title = coinStatistic.title , + body = coinStatistic.message + ) + } + + } + + } + + + + + } + +} + +@Preview +@Composable +fun CoinDetailsScreenPreview() { + + KryptoTheme { + Surface( + modifier = Modifier + .fillMaxSize() + ) { + CoinDetailsScreen( + coin = FAKE_COIN_LIST.toCoinEntity().first(), + ) + } + } + +} \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/util/CoinStatistic.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/util/CoinStatistic.kt new file mode 100644 index 0000000..fa722bb --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/util/CoinStatistic.kt @@ -0,0 +1,9 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.util + +import androidx.annotation.DrawableRes + +data class CoinStatistic( + val title : String, + val message : String, + @DrawableRes val icon : Int, +) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/util/MarketChartRange.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/util/MarketChartRange.kt new file mode 100644 index 0000000..e225be7 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/util/MarketChartRange.kt @@ -0,0 +1,10 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.util + +enum class MarketChartRange { + ONE_HOUR, + ONE_DAY, + ONE_WEEK, + ONE_MONTH, + THREE_MONTH, + ONE_YEAR +} \ No newline at end of file diff --git a/feature_coin_details/src/main/res/drawable/icon_line_graph.xml b/feature_coin_details/src/main/res/drawable/icon_line_graph.xml new file mode 100644 index 0000000..66ecbb3 --- /dev/null +++ b/feature_coin_details/src/main/res/drawable/icon_line_graph.xml @@ -0,0 +1,7 @@ + + + diff --git a/feature_coin_details/src/main/res/drawable/icon_pie_chart.xml b/feature_coin_details/src/main/res/drawable/icon_pie_chart.xml new file mode 100644 index 0000000..05a1c7b --- /dev/null +++ b/feature_coin_details/src/main/res/drawable/icon_pie_chart.xml @@ -0,0 +1,5 @@ + + + + diff --git a/feature_coin_details/src/main/res/drawable/icon_rocket.xml b/feature_coin_details/src/main/res/drawable/icon_rocket.xml new file mode 100644 index 0000000..0351a18 --- /dev/null +++ b/feature_coin_details/src/main/res/drawable/icon_rocket.xml @@ -0,0 +1,11 @@ + + + + diff --git a/feature_coin_details/src/main/res/drawable/iconi_trophie.xml b/feature_coin_details/src/main/res/drawable/iconi_trophie.xml new file mode 100644 index 0000000..a4f9213 --- /dev/null +++ b/feature_coin_details/src/main/res/drawable/iconi_trophie.xml @@ -0,0 +1,6 @@ + + + + + From aa7155294520ba13aaab93b387a0a894bbfbda8c Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 23 Feb 2023 13:07:24 +0300 Subject: [PATCH 162/201] fix coin statistics body --- .../krypto/common/presentation/util/Utils.kt | 44 ++++++++++++++++++- common/src/main/res/values/strings.xml | 3 +- .../presentation/CoinDetailsScreen.kt | 10 +++-- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt index ae86a28..a85b662 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/util/Utils.kt @@ -17,7 +17,7 @@ fun getFormattedChange(context: Context, change : Float) : String { context.getString(R.string.coin_value_change, "+",roundOffChange) } -fun getFormattedBalance(context : Context, balance : Double, displayCurrency: DisplayCurrency) : String { +fun getFormattedBalance(context : Context, balance : Double, displayCurrency: DisplayCurrency = DisplayCurrency.USD) : String { val million = 1_000_000 val billion = 1_000_000_000 val trillion = 1_000_000_000_000 @@ -55,6 +55,7 @@ fun getInTwoDecimalPlaces(value : Double) : String{ val df = DecimalFormat("#,##0.00") return df.format(value) } + fun getFormattedMarketCap(context: Context, value : Long) : String { val million = 1_000_000 val billion = 1_000_000_000 @@ -94,6 +95,47 @@ fun getFormattedMarketCap(context: Context, value : Long) : String { } } + +fun getFormattedTotalVolume(context: Context, value : Long) : String { + val million = 1_000_000 + val billion = 1_000_000_000 + val trillion = 1_000_000_000_000 + val quadrillion = 1_000_000_000_000_000 + val quintillion = 1_000_000_000_000_000_000 + + return if(value < million) { + val df = DecimalFormat("#,###.##") + context.getString(R.string.coin_total_volume, df.format(value), "") + }else if(value < billion){ + context.getString( + R.string.coin_total_volume, + getInFourDecimalPlaces(value.toDouble() / million.toDouble()), + context.getString(R.string.symbol_million) + ) + }else if(value < trillion){ + context.getString( + R.string.coin_total_volume, + getInFourDecimalPlaces(value.toDouble() / billion.toDouble()), + context.getString(R.string.symbol_billion) + ) + }else if(value < quadrillion){ + context.getString( + R.string.coin_total_volume, + getInFourDecimalPlaces(value.toDouble() / trillion.toDouble()), + context.getString(R.string.symbol_trillion) + ) + }else if(value < quintillion){ + context.getString( + R.string.coin_total_volume, + getInFourDecimalPlaces(value.toDouble() / quadrillion.toDouble()), + context.getString(R.string.symbol_quadrillion) + ) + }else { + context.getString(R.string.symbol_quintillion_fallback, "") + } +} + + fun getInFourDecimalPlaces(value : Double) : String{ val df = DecimalFormat("#,##0.0000") return df.format(value) diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index e25142a..cc73f56 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -3,7 +3,8 @@ %s Image %s%s%% %s%s %s - MCap $%s %s + $%s %s + %s %s M Bn Tr diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index cb66392..35782c3 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -15,7 +15,9 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap +import com.ryankoech.krypto.common.presentation.util.getFormattedTotalVolume import com.ryankoech.krypto.feature_coin_details.R import com.ryankoech.krypto.feature_coin_details.presentation.components.success.CoinDetailsHeader import com.ryankoech.krypto.feature_coin_details.presentation.components.success.CoinStatisticsCard @@ -135,10 +137,10 @@ fun CoinDetailsScreen( item{ val coinStatistics = listOf( - CoinStatistic("Market Cap", "$352.1234 Bn", R.drawable.icon_pie_chart), - CoinStatistic("All Time High", "$352.1234 Bn", R.drawable.icon_pie_chart), - CoinStatistic("24hr High", "$352.1234 Bn", R.drawable.icon_pie_chart), - CoinStatistic("Total Volume", "$352.1234 Bn", R.drawable.icon_pie_chart), + CoinStatistic("Market Cap", getFormattedMarketCap(context, coin.marketCap), R.drawable.icon_pie_chart), + CoinStatistic("All Time High", getFormattedBalance(context, coin.allTimeHigh), R.drawable.icon_pie_chart), + CoinStatistic("24hr High", getFormattedBalance(context, coin.high24Hr), R.drawable.icon_pie_chart), + CoinStatistic("Total Volume", getFormattedTotalVolume(context, coin.totalVolume.toLong()), R.drawable.icon_pie_chart), ) LazyVerticalGrid( From 597999d13ad4c1ed7cc4162db527ee4ddfa156ea Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 23 Feb 2023 20:05:34 +0300 Subject: [PATCH 163/201] add module dependency --- feature_coin_details/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/feature_coin_details/build.gradle b/feature_coin_details/build.gradle index 7fb9a49..6f13b70 100644 --- a/feature_coin_details/build.gradle +++ b/feature_coin_details/build.gradle @@ -48,6 +48,7 @@ dependencies { // local modules implementation project(":common") implementation project(":feature_coin_list") + implementation project(":feature_transaction") // retrofit - for network call implementation "com.squareup.retrofit2:retrofit:$retrofit_version" From 6cb418d5c31e8aeff1519ea86a53e045598f0e6f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 23 Feb 2023 20:18:23 +0300 Subject: [PATCH 164/201] implement composable --- .../components/success/TransactionItem.kt | 152 ++++++++++++++++++ .../src/main/res/drawable/icon_delete.xml | 6 + .../main/res/drawable/icon_graphline_up.xml | 4 + 3 files changed, 162 insertions(+) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt create mode 100644 feature_coin_details/src/main/res/drawable/icon_delete.xml create mode 100644 feature_coin_details/src/main/res/drawable/icon_graphline_up.xml diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt new file mode 100644 index 0000000..6fc25ec --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt @@ -0,0 +1,152 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.components.success + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.foundation.layout.* +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.theme.Green500 +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.theme.Red400 +import com.ryankoech.krypto.common.presentation.util.getFormattedBalance +import com.ryankoech.krypto.feature_coin_details.R +import com.ryankoech.krypto.feature_transaction.core.ktx.bottomBorder +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType +import com.ryankoech.krypto.feature_transaction.data.repository.bitCoinTransaction +import java.text.SimpleDateFormat +import java.util.* + +// @RequiresApi(Build.VERSION_CODES.N) +fun convertLongToTime(time: Long): String { + val date = Date(time) + val format = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + SimpleDateFormat("MMMM dd YYYY hh:mm:ss aa") + } else { + SimpleDateFormat("MM-dd-yyyy") + } + return format.format(date) +} + +@Composable +fun TransactionItem( + modifier: Modifier = Modifier, + transaction: TransactionDto, +) { + + val context = LocalContext.current + val isBuyingTransaction = transaction.transactionType == TransactionType.BUY + + Box( + modifier = modifier + .bottomBorder( + strokeWidth = 1.dp, + color = Color(0xfff2f2f2), + ), + ) { + Row( + modifier = Modifier + .padding( + vertical = 8.dp, + horizontal = 4.dp, + ), + verticalAlignment = Alignment.CenterVertically + ) { + + Column( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + ) { + + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + + Text( + text = "${ + getFormattedBalance( + context, + transaction.currentPrice * transaction.amount + ) + } bought", + style = MaterialTheme.typography.h3, + ) + Text( + modifier = Modifier + .alpha(0.6f), + text = "${if (isBuyingTransaction) "+" else "-"}${transaction.amount} BTC", + style = MaterialTheme.typography.body1, + ) + + } + + Spacer(modifier = Modifier.height(4.dp)) + + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + + Text( + modifier = Modifier + .alpha(0.6f), + text = convertLongToTime(transaction.date), + style = MaterialTheme.typography.caption, + ) + Icon( + modifier = Modifier + .scale( + scaleX = 1f, + scaleY = if (isBuyingTransaction) -1f else 1f + ), + painter = painterResource(R.drawable.icon_graphline_up), + contentDescription = null, + tint = if (isBuyingTransaction) Green500 else Red400, + ) + + } + } + + Spacer(modifier = Modifier.width(12.dp)) + + Icon( + modifier = Modifier + .size(36.dp), + painter = painterResource(R.drawable.icon_delete), + contentDescription = null, + ) + + } + } + +} + +@Preview +@Composable +fun TransactionItemPreview() { + + KryptoTheme { + Surface { + TransactionItem( + transaction = bitCoinTransaction.first() + ) + } + } + +} \ No newline at end of file diff --git a/feature_coin_details/src/main/res/drawable/icon_delete.xml b/feature_coin_details/src/main/res/drawable/icon_delete.xml new file mode 100644 index 0000000..806cc88 --- /dev/null +++ b/feature_coin_details/src/main/res/drawable/icon_delete.xml @@ -0,0 +1,6 @@ + + + diff --git a/feature_coin_details/src/main/res/drawable/icon_graphline_up.xml b/feature_coin_details/src/main/res/drawable/icon_graphline_up.xml new file mode 100644 index 0000000..76f2f9f --- /dev/null +++ b/feature_coin_details/src/main/res/drawable/icon_graphline_up.xml @@ -0,0 +1,4 @@ + + + From 3b9eba4ced209279c1c6f971d0d7cea704f22a5f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 28 Feb 2023 12:47:06 +0300 Subject: [PATCH 165/201] implement logic to get transactions --- .../viewmodel/CoinDetailsScreenViewModel.kt | 34 +++++++++++++++++-- .../viewstate/CoinDetailsScreenViewState.kt | 2 ++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt index db400e7..2748f26 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt @@ -8,18 +8,24 @@ import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_details.domain.usecase.GetCoinMarketChartUseCase import com.ryankoech.krypto.feature_coin_details.presentation.viewstate.CoinDetailsScreenViewState +import com.ryankoech.krypto.feature_transaction.domain.usecase.GetCoinTransactionsUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import javax.inject.Inject @HiltViewModel class CoinDetailsScreenViewModel @Inject constructor( - private val getCoinMarketChartUseCase: GetCoinMarketChartUseCase + private val getCoinMarketChartUseCase: GetCoinMarketChartUseCase, + private val getCoinTransactionsUseCase: GetCoinTransactionsUseCase, ) : ViewModel(){ private val _viewState = mutableStateOf(CoinDetailsScreenViewState()) - private val viewState : State = _viewState + val viewState : State = _viewState + private val _message = MutableSharedFlow() + val message : SharedFlow get() = _message fun getCoinDetails(coinId :String) { @@ -50,4 +56,28 @@ class CoinDetailsScreenViewModel @Inject constructor( } + fun getTransactions(coinId: String) { + + getCoinTransactionsUseCase(coinId) + .onEach { res -> + + when(res){ + is Resource.Error -> { + _message.emit("An error occurred while fetching transactions.") + } + is Resource.Loading -> { + // Do nothing + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + transactions = res.data!! + ) + } + } + + + }.launchIn(viewModelScope) + + } + } \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt index 7df3a1f..9f39edd 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt @@ -2,10 +2,12 @@ package com.ryankoech.krypto.feature_coin_details.presentation.viewstate import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_details.domain.entity.MarketChartEntity +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto data class CoinDetailsScreenViewState( private val screenState: ScreenState = ScreenState.LOADING, private val dayMarketChart : List = listOf(), private val threeMonthMarketChart : List = listOf(), private val yearMarketChart : List = listOf(), + private val transactions : List = listOf(), ) From 00e5106cde86f023436ec49cbc8e4580f59e5d15 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 28 Feb 2023 12:56:14 +0300 Subject: [PATCH 166/201] implement transactions section --- .../presentation/CoinDetailsScreen.kt | 48 +++++++++++++++++-- .../viewstate/CoinDetailsScreenViewState.kt | 10 ++-- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 35782c3..2e5aebf 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -1,5 +1,6 @@ package com.ryankoech.krypto.feature_coin_details.presentation +import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -7,6 +8,7 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.items import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier @@ -14,20 +16,22 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.util.collectAsEffect import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap import com.ryankoech.krypto.common.presentation.util.getFormattedTotalVolume import com.ryankoech.krypto.feature_coin_details.R -import com.ryankoech.krypto.feature_coin_details.presentation.components.success.CoinDetailsHeader -import com.ryankoech.krypto.feature_coin_details.presentation.components.success.CoinStatisticsCard -import com.ryankoech.krypto.feature_coin_details.presentation.components.success.LineChart -import com.ryankoech.krypto.feature_coin_details.presentation.components.success.MarketRangeButton +import com.ryankoech.krypto.feature_coin_details.presentation.components.success.* import com.ryankoech.krypto.feature_coin_details.presentation.util.CoinStatistic import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRange +import com.ryankoech.krypto.feature_coin_details.presentation.viewmodel.CoinDetailsScreenViewModel import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.data.repository.bitCoinTransaction val MarketChartRangeText = listOf( Pair(MarketChartRange.ONE_HOUR, "1h"), @@ -40,12 +44,19 @@ val MarketChartRangeText = listOf( @Composable fun CoinDetailsScreen( - // viewModel : CoinDetailsScreenViewModel = hiltViewModel(), + viewModel : CoinDetailsScreenViewModel = hiltViewModel(), coin : Coin, modifier: Modifier = Modifier ) { val context = LocalContext.current + val viewState = viewModel.viewState.value + + viewModel.message.collectAsEffect { toastMessage -> + if(toastMessage.isNotEmpty()){ + Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show() + } + } var currentMarketChartRange by remember { mutableStateOf(MarketChartRange.ONE_DAY) @@ -166,8 +177,35 @@ fun CoinDetailsScreen( } + item{ + Divider( + modifier = Modifier.fillMaxWidth(), + color = Color(0xfff2f2f2) + ) + } + item{ + Text( + modifier = Modifier + .padding(horizontal = 12.dp), + text = "Transaction History", + style = MaterialTheme.typography.h2, + ) + } + + + items(viewState.transactions){ transaction -> + + TransactionItem( + modifier = Modifier + .padding( + horizontal = 12.dp, + ), + transaction = transaction + ) + + } } diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt index 9f39edd..1310c48 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt @@ -5,9 +5,9 @@ import com.ryankoech.krypto.feature_coin_details.domain.entity.MarketChartEntity import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto data class CoinDetailsScreenViewState( - private val screenState: ScreenState = ScreenState.LOADING, - private val dayMarketChart : List = listOf(), - private val threeMonthMarketChart : List = listOf(), - private val yearMarketChart : List = listOf(), - private val transactions : List = listOf(), + val screenState: ScreenState = ScreenState.LOADING, + val dayMarketChart : List = listOf(), + val threeMonthMarketChart : List = listOf(), + val yearMarketChart : List = listOf(), + val transactions : List = listOf(), ) From 6928f1d61e57829a703dc40bf871c385032d58f2 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Tue, 28 Feb 2023 12:56:32 +0300 Subject: [PATCH 167/201] fix structure --- .../presentation/components/success/TransactionItem.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt index 6fc25ec..ff184fd 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt @@ -78,12 +78,12 @@ fun TransactionItem( ) { Text( - text = "${ + text = "${if(isBuyingTransaction) "" else "-"}${ getFormattedBalance( context, transaction.currentPrice * transaction.amount ) - } bought", + } ${if(isBuyingTransaction) "bought" else "sold"}", style = MaterialTheme.typography.h3, ) Text( @@ -111,6 +111,7 @@ fun TransactionItem( ) Icon( modifier = Modifier + .size(16.dp) .scale( scaleX = 1f, scaleY = if (isBuyingTransaction) -1f else 1f @@ -123,11 +124,11 @@ fun TransactionItem( } } - Spacer(modifier = Modifier.width(12.dp)) + Spacer(modifier = Modifier.width(16.dp)) Icon( modifier = Modifier - .size(36.dp), + .size(28.dp), painter = painterResource(R.drawable.icon_delete), contentDescription = null, ) From d7d1378d3135f04f9ba361ba25f8a7d09c913103 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 1 Mar 2023 12:12:23 +0300 Subject: [PATCH 168/201] fix endpoint --- .../data/data_source/remote/CoinDetailsServiceApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinDetailsServiceApi.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinDetailsServiceApi.kt index 5bf4cc5..b3546a1 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinDetailsServiceApi.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/data/data_source/remote/CoinDetailsServiceApi.kt @@ -8,7 +8,7 @@ import retrofit2.http.Query interface CoinDetailsServiceApi { - @GET("/coins/{id}/market_chart") + @GET("coins/{id}/market_chart") suspend fun getCoinMarketChart( @Path(value = "id", encoded = true) coinId : String, @Query("days") days : Int, From c7e110ae0b197a0dad772e6aeb06cb6664baf939 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 1 Mar 2023 12:13:01 +0300 Subject: [PATCH 169/201] implement type convertor --- .../feature_coin_details/domain/entity/MarketChartEntity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/MarketChartEntity.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/MarketChartEntity.kt index 6e66b4a..1af3b27 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/MarketChartEntity.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/MarketChartEntity.kt @@ -4,3 +4,6 @@ data class MarketChartEntity( val price : Double ) +fun List.toPairList() : List> = mapIndexed{ index, marketEntity -> + Pair(index, marketEntity.price) +} From 63489dde5a5297633cde90b4f5f7cf60519e7a87 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 1 Mar 2023 12:15:06 +0300 Subject: [PATCH 170/201] polish component --- .../components/success/LineChart.kt | 43 ++++++++----------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt index 79ffd93..4a2ea8f 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt @@ -1,44 +1,35 @@ package com.ryankoech.krypto.feature_coin_details.presentation.components.success -import android.graphics.Paint import androidx.compose.foundation.Canvas import androidx.compose.foundation.background import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import kotlin.math.roundToInt @Composable fun LineChart( + modifier: Modifier = Modifier, data: List> = emptyList(), - modifier: Modifier = Modifier ) { val spacing = 0f val graphColor = Color(0xff39b23f) - val transparentGraphColor = remember { graphColor.copy(alpha = 0.5f) } - val upperValue = remember { (data.maxOfOrNull { it.second }?.plus(1))?.roundToInt() ?: 0 } - val lowerValue = remember { (data.minOfOrNull { it.second }?.toInt() ?: 0) } - val density = LocalDensity.current + val upperValue = (data.maxOfOrNull { it.second }?.plus(1))?.roundToInt() ?: 0 + val lowerValue = (data.minOfOrNull { it.second }?.toInt() ?: 0) - val textPaint = remember(density) { - Paint().apply { - color = android.graphics.Color.WHITE - textAlign = Paint.Align.CENTER - textSize = density.run { 12.sp.toPx() } - } - } - - Canvas(modifier = modifier) { + Canvas( + modifier = modifier + .background( + color = Color(0xfff2f2f2) + ) + ) { val spacePerHour = (size.width - spacing) / data.size var medX: Float @@ -66,10 +57,10 @@ fun LineChart( drawPath( path = strokePath, - color = transparentGraphColor, + color = graphColor, style = Stroke( - width = 3.dp.toPx(), - cap = StrokeCap.Round + width = 2.dp.toPx(), + cap = StrokeCap.Square ) ) @@ -83,12 +74,12 @@ fun LineChart( path = fillPath, brush = Brush.verticalGradient( colors = listOf( - transparentGraphColor, - transparentGraphColor.copy( - alpha = 0.8F + graphColor, + graphColor.copy( + alpha = 0.9F ), - transparentGraphColor.copy( - alpha = 0.1F + graphColor.copy( + alpha = 0.3F ) ), endY = size.height - spacing From 952557c57d8a7c3a11b65997ae932a127714af6f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 1 Mar 2023 12:19:04 +0300 Subject: [PATCH 171/201] implement logic to toggle market chart graph data --- .../presentation/CoinDetailsScreen.kt | 79 ++++++++++++++----- 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 2e5aebf..335902f 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -23,6 +23,7 @@ import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap import com.ryankoech.krypto.common.presentation.util.getFormattedTotalVolume import com.ryankoech.krypto.feature_coin_details.R +import com.ryankoech.krypto.feature_coin_details.domain.entity.toPairList import com.ryankoech.krypto.feature_coin_details.presentation.components.success.* import com.ryankoech.krypto.feature_coin_details.presentation.util.CoinStatistic import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRange @@ -30,8 +31,7 @@ import com.ryankoech.krypto.feature_coin_details.presentation.viewmodel.CoinDeta import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin -import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto -import com.ryankoech.krypto.feature_transaction.data.repository.bitCoinTransaction +import timber.log.Timber val MarketChartRangeText = listOf( Pair(MarketChartRange.ONE_HOUR, "1h"), @@ -49,6 +49,11 @@ fun CoinDetailsScreen( modifier: Modifier = Modifier ) { + LaunchedEffect(key1 = Unit){ + viewModel.getCoinDetails(coin.id) + // viewModel.getTransactions(coin.id) + } + val context = LocalContext.current val viewState = viewModel.viewState.value @@ -62,6 +67,55 @@ fun CoinDetailsScreen( mutableStateOf(MarketChartRange.ONE_DAY) } + val marketChartButtonOnClick = { marketChartRange : MarketChartRange -> + currentMarketChartRange = marketChartRange + } + + var marketChartData by remember { + mutableStateOf(listOf>()) + } + + LaunchedEffect(key1 = currentMarketChartRange, key2 = viewState){ + marketChartData = when(currentMarketChartRange){ + MarketChartRange.ONE_HOUR -> { + // Every 5 min hence first 12 = 1 hour + try { + viewState.dayMarketChart.toPairList().subList(0, 11) + } catch (e : Throwable){ + Timber.d(e.localizedMessage) + viewState.dayMarketChart.toPairList() + } + } + MarketChartRange.ONE_DAY -> { + viewState.dayMarketChart.toPairList() + } + MarketChartRange.ONE_WEEK -> { + // Every 1 hour hence first (24 hours per day * 7 days) hours + try { + viewState.threeMonthMarketChart.toPairList().subList(0, 167) + } catch (e : Throwable){ + Timber.d(e.localizedMessage) + viewState.threeMonthMarketChart.toPairList() + } + } + MarketChartRange.ONE_MONTH -> { + // Every 1 hour hence first (24 hours per day * 30 days) hours + try { + viewState.threeMonthMarketChart.toPairList().subList(0, 719) + } catch (e : Throwable){ + Timber.d(e.localizedMessage) + viewState.threeMonthMarketChart.toPairList() + } + } + MarketChartRange.THREE_MONTH -> { + viewState.threeMonthMarketChart.toPairList() + } + MarketChartRange.ONE_YEAR -> { + viewState.yearMarketChart.toPairList() + } + } + } + LazyColumn( modifier = modifier .fillMaxSize(), @@ -78,25 +132,8 @@ fun CoinDetailsScreen( } item { - val data = listOf( - Pair(6, 111.45), - Pair(7, 111.0), - Pair(8, 113.45), - Pair(9, 112.25), - Pair(10, 116.45), - Pair(11, 113.35), - Pair(12, 118.65), - Pair(13, 110.15), - Pair(14, 113.05), - Pair(15, 114.25), - Pair(16, 116.35), - Pair(17, 117.45), - Pair(18, 112.65), - Pair(19, 115.45), - Pair(20, 111.85) - ) LineChart( - data = data, + data = marketChartData, modifier = Modifier .fillMaxWidth() .padding(horizontal = 12.dp) @@ -117,7 +154,7 @@ fun CoinDetailsScreen( items(MarketChartRangeText.size){ counter -> MarketRangeButton( - onClick = { /*TODO*/ }, + onClick = { marketChartButtonOnClick(MarketChartRangeText[counter].first) }, text = MarketChartRangeText[counter].second, selected = MarketChartRangeText[counter].first == currentMarketChartRange ) From 09cf5a086e37c1c7a94ff7f923f73a3e1c208f7a Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 1 Mar 2023 12:25:01 +0300 Subject: [PATCH 172/201] fix incorrect icons --- .../feature_coin_details/presentation/CoinDetailsScreen.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 335902f..2d8a048 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -186,9 +186,9 @@ fun CoinDetailsScreen( val coinStatistics = listOf( CoinStatistic("Market Cap", getFormattedMarketCap(context, coin.marketCap), R.drawable.icon_pie_chart), - CoinStatistic("All Time High", getFormattedBalance(context, coin.allTimeHigh), R.drawable.icon_pie_chart), - CoinStatistic("24hr High", getFormattedBalance(context, coin.high24Hr), R.drawable.icon_pie_chart), - CoinStatistic("Total Volume", getFormattedTotalVolume(context, coin.totalVolume.toLong()), R.drawable.icon_pie_chart), + CoinStatistic("All Time High", getFormattedBalance(context, coin.allTimeHigh), R.drawable.icon_rocket), + CoinStatistic("24hr High", getFormattedBalance(context, coin.high24Hr), R.drawable.iconi_trophie), + CoinStatistic("Total Volume", getFormattedTotalVolume(context, coin.totalVolume.toLong()), R.drawable.icon_line_graph), ) LazyVerticalGrid( From db12e798bbadfa9b6b455ef847334c7009c16cb8 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 1 Mar 2023 13:15:20 +0300 Subject: [PATCH 173/201] implement no transactions fallback --- .../presentation/CoinDetailsScreen.kt | 37 +++++++++++++----- .../src/main/res/drawable/no_transaction.gif | Bin 0 -> 842232 bytes 2 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 feature_transaction/src/main/res/drawable/no_transaction.gif diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 2d8a048..e65f0fe 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import com.ryankoech.krypto.common.presentation.ErrorScreen import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.collectAsEffect import com.ryankoech.krypto.common.presentation.util.getFormattedBalance @@ -51,7 +52,7 @@ fun CoinDetailsScreen( LaunchedEffect(key1 = Unit){ viewModel.getCoinDetails(coin.id) - // viewModel.getTransactions(coin.id) + viewModel.getTransactions(coin.id) } val context = LocalContext.current @@ -230,18 +231,34 @@ fun CoinDetailsScreen( style = MaterialTheme.typography.h2, ) } + + if(viewState.transactions.isEmpty()) { + + item{ + ErrorScreen( + modifier = Modifier + .padding( + vertical = 40.dp, + ), + messageText = "Whoops, looks like a ghost town here.", + res = com.ryankoech.krypto.feature_transaction.R.drawable.no_transaction, + showButton = false, + ) + } + + }else { + items(viewState.transactions){ transaction -> - items(viewState.transactions){ transaction -> - - TransactionItem( - modifier = Modifier - .padding( - horizontal = 12.dp, - ), - transaction = transaction - ) + TransactionItem( + modifier = Modifier + .padding( + horizontal = 12.dp, + ), + transaction = transaction + ) + } } } diff --git a/feature_transaction/src/main/res/drawable/no_transaction.gif b/feature_transaction/src/main/res/drawable/no_transaction.gif new file mode 100644 index 0000000000000000000000000000000000000000..9d4d68b4dae1850b03ebcf18b51228f7f82b8d29 GIT binary patch literal 842232 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

cO}jG8T3hB~BvekV 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

PLrlfI!~n-C1l^uE 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 4sBXY@B1?HcSMAp$6K|m zuEK0!PS*^VQte7}AQL$)2kSa1lfq2tNK`gPdz+mc#*^4lgm+^uD4w@f&sN3Z|OwM}Um_s`kk0|w*u!No2w z9{b9ct*Ye`xCEU#zRojOaZe^L_Zi&%*3*Wb)`xxd3gJ0qN{R%CINCzyTXi%P_NW#?5vG&E$7zw%)S zdV`1`8lWcYcm2+X|HnkkMfPedI)1_sWnM(71xp$3yG#x{x={-j53@&j{ne7F4VT$! zNq8Z=s4a$GM7)i|+c><9!`nFg|3@4qF{mh>WcR&sQfS$@;^c1y z&3L)44j+;TeYn#P>T`L?9jsh4frFT3Ld&M4OmbUkAD&;_rHFuVf828f`b0d_xSYg3 zU>2#;A^aRkCST z2xs#*inz58<~i{|sY20$eHS;0m7$kG0_gj`SdUV?`kH(C$WT;6z@9xk>S+<+wVZfk zQYPqG%w9n#h$cNeLDhM!=B(vi;?no$$&d^6U2INKhSxJeGQAN8Z|`lZK19!OS!%Asp2eXrM`f z?0!ROQrLN@H}AK4+9Xj&M{stg>$QOEm@_g)y~SwfpBJlGMhztQvM1#0^TJT?Oigdc znK+-V``KctQ`f~_BKx9PU3)!Nmn@S!SaBOZYw^yomDTz*K*m-A?*YUO{nXGo-z-pX zOaiBjtH~VX`kt?0UozrghFYC@20BEzkmSJaq&8ZkxJMBP6gN$AwCK6=# z&He4SZ|+XVCJ?#S%kIbk^@*qh2ZN88dhP>AJ!EAP;?)BZ;%+}@}1l-P&l_6tab z>?JdseL*cr6X?kSWa?xZ^vO_EeY7K=WnjBRSD^$N2SFj3jbsr z?R`tqTspXy&U^jwH`i;MXL2Qo!pYqD!?@M5-F+$A=StDxURT?x^$B?kg|GUfA2Pbt z4mHnE)_?g!I%RF%Ei{Xpyr%#8_4N&qSGidFwN+3+1DM0vk6C=8#P+rJZnKJ#oS^m! zF^H*EzmwIn;M6KvuD#vN7Z=6j%hw9#R%!LkZ|@;gyalXhtxh)ghKFoBBl=U~pgT#K zw5EJ$W)x_$?;gQd-M_-|SUr6@?reK7;mxq)Pn{=9!F^Ia9b;Gc0tZ5VWySS6B41V! z5l!c`UJ%`)+n%MCPLHbrSux>h)h*G<`*?OM*g4O-ftzg3^_c5poB$cWT^|C%V(X*l zVwacep6b{{Iw&(&tJ`W!mB-ub?az`bFNCnQ%sG-u4vQ|#vO*fzj(MBRn$ymIQ%9)C z+_~^K7ki=k`PI{v_S5^L=Ka7+rzH?`5W@uezr1HjXn82YsU1CgpLTZw#Hthp!~M~l zIFDAaz-1|6zm%ek@qZ{G7BKowI75Gy!^vUZ64a!afGI(SowNuONcIMjV$J(uhw;>; zn1EU2jJRMCwo#q1$O~sC|CJPbL9v_FiOdM*2ChTvC@6}IL7%`YP?O>rznO%iecgRq+_oGXq>Q##skneb08^3#(myEWBK?^(L-6x3>A%kEXPMO@S;Eo zjQ|=W6E0KH7}^!Z6bYk=OmJSNB*kp>=eYmt0kLJ0Ni3IDEvh;>mH>Z5Ibzk0+{Pva$iGf$&U@Q4^%n_O<}I zM%-V__#7l6skZVhGrs8Mk+|b2jU!oQi&=Gnz*ws+{FR_GEmRx@zbyxYv;{4!n-FnH zlKYbFgm0uAk*gZ=7(R2H`#wJQD#n(VIaQDS0t1ay%=|5*$y|BO-AO1FyG+_?zJ0en z*p_!i3SSZu)lf78Nqy9DEV0!FtJofU^B~@J$J!B-159lR^Wl8;4RHREU2?-E-00mT3 zKm}Ap6ogQeDn&txC{cG1VbT&Ly(Uml#XSlPRpE%Jha&_-yn?x5N!kE^PBN>^k>Htv>K z&iDyZb9jr3oB*?w67G_6rI!euB%#*J;**t9hcnv5Co_`;&S;IPiP?Zgbku}yzQK6O zYsyL?njXp1mKe1YdpzhAfZ_>*gOuWla(baG*@ql!O=%E3nm&2{f$!*5?3jpf;{A`Q z{Hj&5A$h5+6_>;f2cM^bu5Hw85u{z&lPf>#W;+cTodVcccH0xhD`-8bOG1K#hbwp4 z7?C~j_~K1jKq7v1*}mbCYXGlb8OKIbBBY}+FA!_Tc?o1sxwpGLVoi|#IKd!j7a%T$ zbpCz{#4WYbcI(YjVvojsL@}1!VX++`rgGo%AX_6;_|8`^pkqR?edyhQdk~=+2x#^9-x^pNOZ}70~@; zqMF{meZ|G9qn&s38V?!HF`k1f>wK4hEAvPug#kc(>z1HVnNxx!SE7QiI`-y)W;UZx zPdRXegpH?s(L2QkyRW7~U1_cSz~_e(=??|Dh@ixXr|&6Q@==ucqp+q05g<$c(riS` zK!LbY-uZ4>eXYHF!Ca&Rl)ocdR8E8g#QZ%<0P$XY$ZsF z=>4J(&?`|xHm!N_0r@mI>{Ng<=)%i`(HO`gnn+k*d$MzI_t;1L_&Ruw)u;1paD^7T zVK+Szd^S*Rx{!0PDA<3LsaUKhNsv|&ut*RrhHV<#uihUNnATlLtuuONJpxR*N(^o( z5YzC<4QbT1UA=rsXv=_v#(DFvq5T|2RC%lQ-NcUCw`(qRWq^rcu&Mb)6|u+x5?uIk z6q*wN!HQO1;hM#NpP2r#*Z>F@4SPZ5oxOUh zm7li8Ji(q(Z{zznAy;7dxivqns|~NBe{5(&& zEB*>4JU$DY*cF)A{|b-qhhiU;C_DthW0vG!;qkrPWFS0_*mR<-wSiK0U5Yk*%CSAU zIHh+tJobyf>y>&1AmrXXLY_29J57;`(`NVN;=cxdH&d43nA1yMWOaf)%RV%c&0XDA5(tekv`-hPK5b_^F z{zJ(BPZKgxE?8kAP97lMc%ijOAM@b~*j``AJ08)`hSWw1BQi}h4I{Tje5nkKS?Q2$ zTtZ(&$0URb(Of!ATOi$W@xHjnw9;BFpY@D_z;gaHT>@*OpC{^GKM>sN(hZKN2bYNp zH2++_Hz;HK_H5M4F>MhH9ztGqj#Ga^!%Bz1)yo;5C^jRQ&L^3m_k!g1Gf5`5!S{&W z#+r0vnB!YjYH2^f4t9^tB};pVuP8Nb!N^dPFEze|LfyqaEJVuXQ5H}aK>)qW;U1`S zqw)&v;@hDpxk|sh{?y{(5#V;W%}Eo1)!Yb%?F0hZUHj~AL*7PS8~4Of-A5jpLEKr zkZgU}+&J@2hkIvtK4|!oi2O0FcWI_b_vTf{gRw~HOUpot zVxiVRA>_lEFO#YijrE~i%je8|JYsU;7VE;6AXTl z`b?AC&FITl>SlqWVWfG#>#3omz#ZPG(cCFu@1syqNIv5Gt3d1}xRR9D&XPta_o$4w zJenRg5&Wp-bp}!SS-YAU_iE^1{kKBk4v#(fjJ(df(cn7urTENi+fx$c9_6~vI-j&A z1JAAHO87RNAFw-dO+v-FS#mDeFXQCnSL@LM(}t?ae$Ub%y%INko%ip}7*CWNM9*_Z zLnktFu{4f0RL6<;1uIaY3k37PhXEM4n#;zk*|#hAeD}>!k8aJ`6U=zIb%qa(NzZpg z`_l&&z|}i7^87J=M<2_+V>#Z!d=!Ow?*O7cG?qG=ej{izdZU_RTR2{4y2-JKy+*p7iUAHC>1g$@;*}WCwG+!*Elcr zn14_)G(m2cikoRe)MF@6+?%kU%&i`~`MY@{vE*-5%pRYyOT`mMu8`b*QSq(K*gGW( z#Q+r(ek&D)+!QJf_^Wt=NIXF46b3Hs)N#AT6YaSvM|aBBoVb&ExD$cmiMJ#^W1vAt!KPYysyTi@i8+n z)8*4O_G&(X*9VSLl|$IeD_1 zUf2xw)o?56*0a+>3oDLyCTN(q-uSvO8W{eZczck1m-+vtXLpB#A7NQ_@-c|By;v2K zLZ>E7D$B$SJ5f#rUx+;fH(>=PNM(2NQPuW@() zH+=f+cP*aWtGnxNeR+zh%-l?qiVOF~yfXI4$QYpLwtdUB_r2K)J zdM#ahQ}YsuHww7x+f(yadKB#f|1Hczq_~CLA?yBp3UmS_;+NT}hn&mG+UFsp7Tiq}XH*Fd4=LvvMX zIirsq`r6VujUcR?CY2`Rcb_S3P}3dC?PQQLt40*J+clp$_0Rj`9`N`gCbgYr zyh(SxsO|_9x7SlV>!_AG7h2cs8+cxy@c-iI338}V6gE$qHCq2Nlv;KZ`+N*0l3vu(zUwMU*V9OC%)2CN8u zHu(x_Zmze``ZJ`cuo$lHzg4=0roVdfxX^DoSow;TkDO@GU4P~; zf$J~douF%cO8yekP!^7RMjCh+yYHeBl=F{; zkn`FnBFI?!H-}@U+U3OA(MF3g9C=^u}M9iI*q&e106`FO^`n zgU^O0^7xJfpIv+=v*BY&(f{D*TX>Vd_&I}nCsg)JJj|`0my7!qD&HbH{|=Qa67B=| zTz(D+l`FWNe&O@eTwFtmLKA?`3Ms!r<$7WYfX^v^;dB2kK4Vkg&&2KG^SF9ig+8UX zEsU5vOH2ard2tt?ozpjF;sJdA-jTkG&y-QPo%)FhTLJ~25gGexDEQ2!kp|#1pERC= z&x;wY+?nu#3?Vz1ga&JdvnzeoUuSo_$+66@f|ek12etrcxti+L?BPtyhEuUL z&sx4b)%lp}_IJKnxvaydDQA8~1bbS!{I;kutN;wI$9U$+`?^=S$2o?)`V^8DxflRb zm_Pcp2|~Ahsm^Q@<8QNkYT(P8Jc_`qB*nOTZzBPJ;VxU%kUX%4_e5S#j;l?|aeHSH z1gcFjGlhf|2;4&=aNn1EhVisD={7+mHR_Mu z=VHcAi7e9V2Y$a<5eyp_GM8iH1vN=+C?-R?oQX-XfVG@&MUs>3h~f^=eC08^B@jjp zo8cF}upb-!iS)<{r6236KcVa^OMXepx6DY@uE{=?OJLjAe0iixTzZ3)@%TDtUUiDH zzFEL=wl=V`hgSZuI2+s@OAYe_&8OW68uiMg zHzb{9wOlb8HE|fSP+9L`Rit_VY&;tg!&n=C)^dpP1@nPaTCL2gMTVz7psKHRjmtfE zv3CeC$;FJce*tqVghQXuNA_ce`D900XJgx*x7{5r3)GGdc*TlCQ1$RhISU5w_bPvO zA_u5~)9bA_X&*S^WMZDD%O=VGkWC5&JR+j4Lwji_a$eKe&)itL<(}~MpHvpe|z6UoM@b>8_-3=A~o`0rc9(a`;_a@jcy=30{IBl%+wza}jz=`IG zLGU#jn6?Xrph@vD->T)r10(InG~L?6KfR^WS&E`K8Tn`FOZ4Wa(b6cb;}VYc0muH; zbs@JITk!f~%xetOW_XHtgjM5z!e=NJz-O=5Xr@gQA^iDv8(p=(vGajkoISwKGcjh| z@j+RCV`oyF!)9DNBHl$^Qv-;e0d_8rKi?6r0QUui3@2CulL?yAZ-K4AtR%YB4lLj3K{&;v4U4v zxH>ap)iVKQSu!|M>Rsl)#S8KO7N7qJ8Gp$64>|uK=l>ZwH-A>7*HgzFFq&y{Pg9_p z;F!K(vTDXVquM5ODI?K*xPX{>TVGlULRBq_=2!EBlHlNflk@EkO0Epz0vut_CZ?$2 zNlx?(21bVf^GG$Ng|5;L=Mq|1FE6D8w;1uZ$BBvDX%WC#+USHYYDx}Z9lm!M>x^NT z&MGuRsX9QcN>E@Q;x|O&|AJ^JulmZB-jpJh0%<5KM?TH+vBL!FutH{hzQ`l=?;KnlAC^UbGg!VyDd&Y1ydf`LdCwN-vFt@Z zeXx&$=}uLKU5Q-=^@$UY0n<5jZeVq(n1=%$&XeMyL-NNklrnps^ny5d?s^<@oJ9(D z!Y3&nM?WEt+7|IV%5RO4Y7^s2y!5V{{0diK?p*8@w%e7#=^(5tmH@A1>whvYg@*UC zTX$1em42sR@VVc+1JNG{!}ehR;YiXXfkjDF@jTF#5n7dHl3cO zrpOxuYBymWAjx4)n@(ZdXDe&>7(6-0WxP~rJ{jq=0iAOi-rhD})cHhlS;)sKN9_ze)Se7~6?XD-hM)(sr1t z!f7R0CVkT}%q?Mov&zRryOY+gVW6pFW_6E1VrD{@qLkwfzXT2fC03qq?k{yt@8Q6t z;i%yUj95^h{sRtG6S00n#`4C)p1?uiK)rsjdqkOBs0a1hXOH9bC;RMY#!MHryC#-m z1y(Am%H=Z_ggFqSG&to4c3p>z*b5|-QL*dWjD80Jy&2vWEXF?s4ZD@fiaY>u={s62 z(&1cSMCKL@ByW60S0`Ua$bmvQ;}^WO_E8Z=t{@!Sp^OQ2YA2nQ%tUVJDBIY_0Y!5C zIj>glOy{-orsJCEQ8@jEWOl#Ek?N?j5{5uMxM~5IUH7_*v{2N`xq#}nX;kds8j{8O z=JPaZyE?|j_vZsAn_H|-QN2mYQ1cAYc>m`4CuDKK!oxbWas|NC3NFwmZkYJaSM4Ih zViT8`wd+pWZ6ZaRX_ft&#MBV6JljZGwj$)h=Yn^r=8{_9N-&kIte*G`#d zkBXEC1~cE-en5$%JAgQvrGDWJr_6|P?8fXHy#*;mfJU9NlSb2afalHa?pp#v{XpMa zTft4o_GX{CEb@20y$QVzo1e==am>L$@O(RJpFHknZ0(01LEeq*sw@tRl7~jsVh+9C z-%JA|&}e0zi4uR#{(R#QG2e#)Vb3B~5H zFpddb+`ekTbcZos|MR893l}5kFO$E~EtAC}@W4mdzTiQ%V{B9ckl{i2CPl8jU2tY7zjVroBtpO{0JHy)CL|0BN)=b*5M+3`nEJdD4M2TADVIl1BGt z_HSmwF_{PKU@C`zI2z^2o1LZme;PbnXk50myKEhH+4joiQ#F_E-(7b6_9u-N{=?LN znEDS>|7L1GcM^*sEBPvdN{j)cK6rI}(YvE{wJX-sbYfgPdQ&c#158zM%K@wef(i^f zA22*w=-ZD}Q?hPKF~?0XJ-;l*`Lj3ap_?A_Xd_++>K zGCV!u(qkIVcOP+sea`#l`rCCrWiXu`(`Pe~LPND1a}e8ol74Q@Y_HE8R(a3Jb&j7a z6Mu;*WWR;Onv_1+7IY*SI8xgzNzf+sl^s-5Ecm(tyGN_wdjXH3 zd`0C**wic)3BfA4t9u-Zn4s7m?IPm^ILM6o8R&r$?cSv%2ny|#<1dBqSdQgk>c6oz z)xT3kXO@vPk2HkIp_nVYhIi_Exy<{|ClXD((8WCUA8mSokMyPK^gE5s z`dN2WFW<1&|9Bd(J!%TOIWlqqL1WS2>8o2AhipG_TvZ@d0H6qrn3!I^YiiwVd4wzS z)>P#STA9&h!FeepZEwq+ZgOz21nWhJ&XJe9a&+$uvz>4a4@Z7rS+}u{1rl5g$*#b0 zzGPWfJ2h(ERBb*tL^r1htkjKN-X_uLj-t?ylq%?|05=+`b@aBKWx|Sr^N&}3BlPGH zp>JbUS}t!NcK>XwIMBJ^l+kv_5>5~}b6Qxg_IsbrXSaPYLQ^TCRa^=oTq}R}u20|0 zXawbY5FwAOCY=iTaU?+84;Yj4^D}Uk8pm4 zHY?})ZCzc2W&?@`#}_|};=yv#zXK?{TWdURK`ZH_aS~8GZr>mJSReX=qIgV2Gzy=; zOlFl8Jm*R4Js=~c_w=R_#Aqbh^Qhgo7nBw_ONLP=8BBBS34R>V=`5L?UHw!qQ1dN= zV~6=GVuynmeEZyhX2b!wV!nT&ld8wr+mk((_KQ>fD70WbTeI{cV`24kDna$|<_ej$ zs{&fOTTJij^c;m5>GG+HMNX+%c~zQv=1-eDF?2UitZl9;PMLrTL5P`II+yMb9wOK1 z^&1zmx*1+e11E#tKMU?j=6KkgDHr5|7nSC8eqee9ya5(feT%x%z8#5(Tqy|_OF4~$ zz6B0WdohDDbOkCb08^`17H)JWM^^wP8|?2CsJ@H{dPSV0kw=!&mP#qDe}XHKrMy|= zjfcoq!ykZ+KD<-ARov_(+nd8U|FgjSc4*`6bct^{*G#kUfE+EKBQH7HxLTz3boR70 zw>9j>k#y=Ihl<8RsN*z-DMGVvtcsQ~ckFEK65l6T$DD`v8R3&YkKh-z`}dEIQQ=PJ zL!MwUgIU3k5(cMWMyS+I2cM;wGk%khYE`D_FFhQ{0ysy>_2!LN<1+Of60GE{cdr>8 zg9i>Sy=^mKO;W(}!G&k+d-WEk7Dj6v9OvEBRpjVy28X<9=}$alm*7BC$C&Tf`Qru9 zw?R1XcpJL##FtA;J>$D)*!87{vY$s!4ANY8kJbQ6HkLGQZinY#iCM3s$O#4I<|Of& zHHC_7bFW^i(fOv$j^ocdkk*f%8axXQTo30Z0sV8RjUUS`QOm|kuc|}t(P)*1Xa=>g zw*V;Z=L1nk&soI0ZjX3a0TyTz2gHu~9kHWC0z+qjc})`qLs0Qhc0&G*(yF1@f~>Qe z2C)$|u#64OZwV?XpcDW0qOn*MfYL44^=k9*>5H3zf9un*z@AW#FHnwysYiKr{H=L; z1?O%O?-|N)HaC8cqZ@G*h=c(31a+@aK#IO_G2!fv)nRHPpGKC#2ku$X33y`2KR6ni zi2948bBG~3R&=5{w|XJ>Z;rl8`Wr{H;~!C^=<@(a*O0=0adZoJ-18EJc8V1J+v;fM zrf_uTUmQ)^lcH0{)b}`gI(N_Nh~ZB8%1zp(IM%FNk06%@OIk+{MlbS2ZOJd>T3R_)V8gIk^`;!r&TD7>@Ep$4=tHd?3T5^5 z!vMr6XL#%vMVm$LQ8a1-nVY-Re%#{YL)|qvIu52*%mp(7Wg6#zQ^B{F^uYM?a@Sc=p^fr(?O{y&VIL5! zA>PbCfYQMscg5qM9USYO@SCK^$ zM;v5MhEb~O0E*6+dA|ryG+=1wZI0{K@-pYifIU&p6lXfC^3{RDlF0j+!@@R|z!rzR zRHMkoDQ0t)M(U*d%@m5hMWJZ!&n_9ANx3q!v4>jQr)2W2o=#u|xk!z+ohFvA$ZXaU zj29u=>F;(a8n}A9BV3~aRM9=WG^GCbZvYg1 zUoQ?+QTr}fB40qfU+f;R`d1#km75pB19ps_0U)`fskG}mcIL5I_1tOs91CG&aNdPD z>jfY4xw>?ll+_@hpYDQ_l7n2n|I-x?=Yh?o_~>VH(6F_<$Oih+sId@g6TbWGX@s4n zzoVscfqTUpr1~Orqy050BGu2B+V;oaAHxZaWy805W#hjCvnCgaMOn#))^jhJ%c;RF zbyonr1CcE}6RZ(7&jk%6cLDX%?jrJ73W7!p7meUEqbyjg`nv`e( zXcZ<8mqUNNtp|o13(EMOi94e-$xy$7SF%3+-5{9Xvh#lDsx6iU$|b6&rsVlprT@{i z^gY!V>Y!Cwqobp@Q#l9fTp-MBPn{00=<|B`c>f@3X&739sLt!=-_aR+V#CMRr*x&M zc(!P2bj;4Sw#@0~t;j(U(+p~u*TIv*?ni|YoSn`-(ph~cn3aJAyc~Rhn8^1@Xs|l$ zyA{U;&Nq6iBH$}KqBPgSRzc06pcERx)PaY1Bm185Twpz?1Qqv^|L|S4Vzo$3$-IP* z1zcVAVX+3I);>f!Gu6!Mjw0=t9%R>mRx1*exq*pAB)PJdmDP>~7wT>mDNs-UbU=pt ziUecNja-{iIY5-2F*&Z;e^*i|xa4%ep%SDuPoIX&sXlP|YrTRiw!W09zpk=tFTR<1 z1naEN;u~k@?8m5XZ-9mzO@UMxg%cjUN>6Wmp4HM|h&+33-ot6I;Y=Ei$F?z;XR(nn z{@(ha18DqtTM(zCdsckHbssmikf?VVUy6_UaNlLYu~d%mu@3l9oeo)>@?XAqcrtbd zbH=7bTPQKhg`3U+H^OMqb0@EH3|?hUGv+2Aan@G*MOC|k?s=OK_0zfZ=-$MS6ukrP zw9?v6BVQnv>dCo9{Ul1_HV|!jwHNR}@V?xvh zz2HyV_=qQ1*VFCn4FEhNeSS>Gd~K({YeU6>(z>0X0>Jb14m{s!L%+!ix6g+@5rx=V z!x%jNSw^=KtH7;kRjn*OiLpn7XeM~b8kqi@oY{Arj+0nHIIJiH++FSX4|tx4Jwl2r zsK9}|urU1JoQ|0|M|eEobWE!K!|6~YMQ`^;`N9+8swe?8;6ulkBzW(F^Kt^3OmzGQ zIb(nO(CK)WodlZVLtp)y4_$y)`C9^=a2Fuwd6IIUV0pA)PQ_u!LEf0L0JiJjp=(%ykyKv*4E@{WgQvC4=iotO#Yn z&kYkwS>*e-(;@cXQS_e)zdzvo2b}+Z2hJZ3(j!@1sI_g6SvV?Ct!k9VTpTiJq$;^h zS0pMVYssxe&Ldz*PhWx09nqs+wQ3n3Ure060_)D5Y6+w2bC{QErX24bGnwQExLBCj z3#IQsoj0S{9aU{Im5NCx=P7naGeW5luaX;AyXv1F)(92o&yAB5Yocc9jq{5i5+eI- z9+D340g~u;N)ipU%%;x){_>&=b9hIKz)UEc3b;rCjyL6QEjeLhIN94zDio1tAhe=&4bXSYxI%C(UcFf&~* zHjeX{&{i*pmrJYZmBxcFSzR8`9Dtbto2DAz>Wh{l+&&pGxDQx^)#c~toM?2N(37$pWJXzTK}hMW4_CQh~6CZa&8 z6ZqDWIoTKrO^{i4~kzE~_W&@DP# zOtfkE_=b@yZxK2I#LuxGDe?1tW+zr5IzfH#(QSuM%c^JZkN0!Lg0NM~6ozKL3^4Sj zCyLx8EBHA?&-wK8xGQQ$$C^?y@=H{X^YC4IyeuYL;LIGVR^u^Jn%rj}Ck<-qyuEh8 z_h*-9UR21ltk>cm{yY;xh8kTd`}7&sOQ&+o07aT*Rjm5h2m00Jq&493EmD-Ed$XE` z04UPtBcIyeGQXrdtPjpp=wz8|Jb&Vg84J)@r<;>g8?!I_A#(>UEV&Yt0-xAVSC09t z&#teZn`l(9e~i2Y5m@tE;T(6lUoc{v)v^zs@JLX7^2bEmrHeYyUMpO+kMO@@A8 z)3A-SCv3P>xxukFfnK-_L4^n{TfmkU?mY56q%pZmF3R-!XI}Jm`l@$pgD0G+MdL=` zN6Yw(bnHLgv%A$G`z*Ms;u!B+>qY*wF$hz=4^#v=6*Qrbb8G%WtSz2~7HBWBR5ZQFcrFA}eltytQqAGqlN`ix zWBtp$1TD#&2&NYH;QcIH0WWg0@Q1Y4+h}x_2M?x)X(w~(CqT%sbH)LWUNbW94gw}j z2*rHorE2JnLut`T39r0;pU7A=6#eb2(9h2nO83>=%U@r(($3xturu0+OoN6H!}(BJ zNo_6wIDfW*X$CRfqej1}0Kl1Ql13}i=ET434T=oSZmqR~zF&MS*d{W4{zKh3fTzgNM@jnyx#R5#zrp$NUo!L+8`!NZ_LGZn19kfI#CUHw z7E&zNkFfCz-I1XcC^B@!ZyA~!&;QT0zr@hrGBp3r+F!OUMTR!{n+$E@_IvCvd`E_U zwj)D3PX0Ca*OF}VONLgL-5dM+ONQQCzXp~|cG!6^H`RW(pbnZg0gt3qIHMD4@oDz} zc3#|L=QXb#cFs@#zRS)8!rm<*Pa2g*{Apn*>k$e&b4pX#nTKbmhod(Gx}HIc$>6br zi2>$@pPPQpe*tI7{|=miTf#qwgn!ui4?F*_WoPH1a8%yy`msod2@T*(+FU{0&M`NnsnOlPMUTw15mb7{bdI$J>uX09Z zQP;kCL>Dq3!iAM86MImOPaz_~qrDo@^H8BRe1cZnTB-}$mGz`8{WwGQp`QzjF{f8= zut<9_D?FBk!xlknq$lZ-!!2g3xis3neGDfNv9Qc}z?b%WzB;0q9^CR=aL<>%VL7Os z2eiZuOgen;P0&?|V~*$*6)c^iVx?m_c0H1Cez)O{+5wWW+i-`(23%dqn=zf%Z~@_5 z1p{5$PD$u~0etDmNlqOpB$GFY%$wJd4=)-j68KSl&2lQ$c?OV1yb|i-H7h|}#73!$ z*84p^wFs^t+hz4p=$6$Apua<3yyA$35sxJvsPB*jTHu5@(5!3srF33rB%zo*;jJ~D z^Z|H5%)}l>uNo;l7G=YiplNJ#O(VNR1psk{rAQ%{L~<`So4I@Z7e==WwI?ul3Xk70 z^8Tz1G$}Baw9)2$V=xKZQaToZ0qUT+g%%X88y=~!DN8kKUAdPY(TdGA&L85)Q|G$s zY;|93;ilXgfYGa*7uIs^VYVz?7Voj_Ohj-O_fS)A#~2)iC{eBGq$>dOXXi`tQ=b$% zoXNcXcexhP&?8z|1WmpCj1fjzG*ALv!jTe_1c=xm_>jbkpfaMd^j_m>N>Rr>hXW(= zKv4&$Vuj~{#{J&sJ0hoEpHI2odG>swN^B7XzoIY(?orgpNz19<0^k~=`CjPKTk&TO zP7yV$JM3(<-8S_q+-dq526VLJ3kRXsHg|rtI?UTw55`UDvMZo;*>SAfd@Q_N|9u7% zRM8HT3Q~cOHWfN?sAW&*YRju8r~v4+|^#_VXdvcJJu^6%(kwbVaR&tQkr6& z19M6SQgG!fm>V9~M@;C?57O+ve|Z{(F|8;U+%MJ0T%WBAr!A;Xm8&?{1GICLhTXAF zqf&IpKilvzkec_cAP$dY=Q&@ov!$Icun<&Tnah6tlnx;`)7YH8b#^#*G&w96LjPTOGMV>-y<)>5JK5VAgL8 zay+Gr-6RMJR%MyHeb={-?#yP;>lMFm0TYZS$7}nu%$GuDTR46mZe{k2#)yQv7FH~_ z^0i4}-Z#}v5AnvDc{So(B@cXL8Ch72UwAUg)}pFPnM5n}NP@ znduPkA38P1{0iVAi%2@pMX2!NC+a74jSp%@4n3n8nGcq&9cxlguPXlT{%D`xf;Q9o z(@ETX#b>A-bc6;uUqL9p=BGnWpCa zU;PX*+t>o=8BGIVY@X_gq!n+Kl4jh$cK{_wSOAt~@G-$Qe*co3MQ5-mZcSupB)e_g zZ^^j@dxAUeWGI7`ZTOy?LBLjw#W`-qNf5*O(Kc?j;gk|*0(Lbs!Dn-C>BLn%;n6=S zIf8_pCYLKO_3qC@;2-T^GM40bM(k{2$Cs9*<^h<@ zl2*SHF;C;uoPdbAF>PTNlgrb$N$Ec~(?J@k>qN>XHZ+Wa$ut_2x;lD|9ZX&%aC2wC z3kb}1uzeK4*-fW91Mxp;aAx}_JO9DtKbZUnlmEA3vc0W1yf1;<4-LXcuR;t_< zj%D|@fPKU?G1MlrA_&(R^vbiDt-awhfzIU5RS9TX)DccoV_mZS=1wmLjEH3Cb}2lj z4PgyLLTL0CW9hvZ6IzA}_Pti7zp5yWUqKYsm4jn}`ZrdZTQu7J{%O7{P_7~(l`wuR zmg^EI)OII$ZkJijNOq(uBxVlii^z#2qHPCtm;KYjd))+={fsr6{TWa!uGCcJg~wMD zZXDS6FnN?-WhNF-)4j>DCrC>jBum?o?O(vHmG%rAo)7+DC zTbW?6xB!$Q8h@rN}nrI5IX!&`SA z41X-qO`F*5VG6WxNUaWB8+A8AT@Gq0G%us#GAXKE$1n$zS;k-r&AS3iKBS&{X%E38qk?3=dSwud=6?4)hty^j zex+NQB3yNjF24m*@_WP{-FW&}^~U9Ki_f+J=06lddGtU6+u1$<8{5W@4Sf`=VLoQw zUi1E%USxfBg}I3zGoAB$Sy>Euhrdm(Iw}B7&}QbJ#0?`cUD=NX&lxE>6oYUg)!$ys z`e*0*XFJ>1Z#?uREW|$;wym|&gDc`!^7>Yk6po1sgqcfdjq=fwWZuM4a%B!lFS2R@ zO+1h*YwLXK6zuK#YIKMGXw4^~?ZN&!+GbNvg)`1Q@9ml&U!=~^suAMO#$Ufs9@i&| zyMkNo`1z4B7Z5U(ax8=*qJ3%UP&fvqLJ*(2%KcPEVUb?LS0DBZ%99iid7LSK_|*tU z)8TMPQtZUY<9HsNqhS`0lwQPgk=hlYx$gR-*nte0GAzVD=WcbL!S>97^D0idk_?O&y)vrM@DFlIzv_Fe0kQ}Joi zQ=Rp2?YsfW+JtBm#rKt#;sYru2zqVsrQfJ^m38SI{9xC<7BM% zPPg+~G1bPIi~F)8RsYtmAwr^H@*ydVOb3j{%jGvISNtO7m_1TPV=F-M&fM|hUX+53 zV5|7GYKn}ZZXzEEPjK0lG4$hux&LV~lP43j|I(P_xOX(>a=a$DI)Q}U%nxV;NZBuO z_HU%@yGbGCDu9$-lTv@RYe18Aq>||jD5PBVirqq>8nVSFPW^n!!lYzRrKQhK2QvO5A z|657f(pKjl0V`Vi90G+GJbN|xght{3<5~O|)iq1KFlPnqf@=c15<-im7X&xphA_#E zVYp1tUX*N^{I_s<8Qc=`<`(>+Ta(BXCe<=*A}I%9$o_V@3c-|)cizpG#b4b@{L&mx zLx;rLEgA@|6M($<;9Wm{C`ZN^geztlBEKcU7zB0aq>?_YByqz2NVp681`18D;0k2G zG`jCsCBnO)g0qCfGTeR8-g(2A8Cticwiz99ix+}k_Ji8@0QyCxJ7f&B7cFAaBL+k% zeHK!AW1V@8skBa}HxaaF)$F+g>`g>0G>0>eUW{^M;v_c8j>PSc>R1+B#T%>JDkeCN zPQk?X3hlVr6L$;kpuEJD>x(JH+T*jaDqhH|Ub5Ny7Zl0NLG^`Mqos)qNzR%9)crAa zM~p_{@k~9AMmk7G;TJlL5`Aqi6gX?Ok?;7pF$cA&Ikugrj{OX`SPs2RD9r>pGr5^GkiH zMgW^B)~APM_yI4&U{X!OCKh67#L3RgV) zZe)F5$wDfyT(W5N$}B({9zjD;z|3pxPr@0ewfPeePljZXcLR@rJY{6Vk5|r$?|pMQpfS>x*d!>6A}qrI5< za^Wgh{HwxFdIonre5VlPmsAi2)=N3g@-X5_or`rGS0At$*z33y>he_uDAmxqZ!F%$ zXr@|p+NFZ!0Thk!hC(f9mGe94lN7X9{qBx#kbQEzj&!}desFLYA6n+j<3Ag`Mhq6^ zR`1^zwTK(!{kZnAl`r0WwUGVC1YLy2^PVkDUUkfjPJYvz6aw>}HgfEE8Kj;<%7{82 zWV@P00pp5FS0kiqa-1O_fqQ=lF{wB( z*d#ZtIo&@T@$+JBT+~-ye(HDN5Boz5#v#_gW*}W!R@o3Q7bDmAuy=|KG&jA+E+mW$ zjXcd$nWCaLE%O=F9|me4)@cG2pD=6uGtXziROm=f{m!FZhQ=EQW9Cw_y?~MY7etjZSj*%=U3(2*b{ajv| z-|B4Fo-a$Qv|gI}X60-+?R;+CSZOmM>Iu7d`KN!k&g~1u6uj0r85lj213co;j>;+@ zaR1JZxi@2h?3f=945u9CXpDL0@{h)5PB_+(TT>|%El@%=RDIw#7f;3-+2V{t83ag} zJuWWao6F{w3I`HoI}(PHAeYCkF311g%Fd04{e=~NkbPk;W-6@@mCX-?@%6Nre zqD4Ml(DS!w;U-1l;u?U93lnL6CCCOz3SLQcSjtxRy`#}K_(=da#JMb z2JRHY-2@q%@?v)hkR`qlo|*}8vESYj;K)oWWh)zzHo42iEPI0|>$xfOz*hE>(>GE& zWeIRB{RME|hajBYIq##cNrES`fX@=FdI{_q#;8v&Y+)I{`ZWZ<{m%krsz2v_f57+; z82^7CjOPsg)8YxB8;3h%7<-Kl@F9@T{{t9bg)!10LHkUp^`$IhnQZg3S?e$Cq{)Ae zlbwMyd3EffVQ8H8jXMQ4xrJ;=CM^ue$t*6Af2aY2Tezp5vV^$5plQ&ctR~O|5M(a2 zk!!3yHqIn^N0h%i7bf|M1uFNYHQ9cJQc~9;!x50;VF;wjtNPp%SQZ!&B>MIVbJW^8O(p31Vc>TC7B210A9aGmn5M0Tb-#@@WtBGM|#3vy@s9I-?)FsoDvzUE2*WINjkGpj zM1|IzfoVPzPJ+Wl?%>_eFHK&+C=qf}WxLIfqV&!uDp$8j38rWC(0qPPw8rQ;)2Sqt zOqsn1xyquG6B&YzbJK<+Vn>j|kD$O79W`sV*&@6ErV;Q#;snPC|FzJ%+}R9DyadVSA%y+6NQ z=QQ&-%sKbxeQuB2z4LJBG(eMcWmG8JW8S~NM>AvW8`m6}c}?oWz%E~daR<$CPX&w; zCY>uFr4P~ztZzZK$W^v6e0^EQj}{Y{#Aw}y#KLn0m|V-0ec#sHaK1h6olezhIPeV(I>h};GIbjS9@Uv8gLm9M!VXu=? zZb?z60*|S%Ht1+c^Fr=oqKUph{Dx%NN+6QJ?pAcV^=tjrd% z=rc6@YC}tLtDADo>4%XXr0ceb%db*7k3mi@waj)6n3)zskG$yia?QD3WO9Me{GV!`*LLjHKZArDl@S7eU7s1AhP7Kmd@;K#tBZ*sUjP+0=J zZs?p{x7v=bb+8CPIBhmqW{PQoI1&$Yvj1GrRyXfJgZ_K^=%#et#Ss57HWWuwKmP8A zj4NOJ%+SzTClp?E3B#}jy%i32ML3Q}M%lWCQt^uIL#Y!>$_veX5;GB(FEVKn*Jp^# zc;Rz)bJa$n?g#cQqzM@8#7oz=v@3^%T6`Lj&8i2(MyFgpl+VN8)cMTTullSOi>(nD z8f65~UZ5eCs?h3XNaMNw_$t`^`#dgSmmbIp8e(Q7?^m{FF|!CQuP&g&SO{||!+$7k z5K~dtN0Sc{7v70Te-Ajeu>CTlKtpKc{E+R<%FDzMJ$CfnAVd7N1rLt;&Torba@JFf zu)x`|v@v{JmGL~;wTYa2VX@)O*Gd)P5CKT^z*Q2%`ChOONM2dbee=CCnHT~QaJ$yV z^UNM@62x9uA0_=X%6>Jf&K*7Wk69DiR<=srj&GsC{BWI?T^eow5s$Ybsc417WMnnZ znbZ@1%f>=x_&tK!ySgy;4Z`L%r@3&1g0E;8!IOyNwaWE49BOa6Dp&PV(j1$CT0~0i8@wfui#*_rE z-{P@{Cp8{dgLpia*zzkLE_G|Lf!Nn~Dxj z1`>(EMbXFk(}i{M!Fc<|YNwC;81>6SP_d8N7~tX<1d|mMhD2=_6309TNtuaSAy-h~ zh35>y{AxgjOph=`((k1p0?X0H*&EsfoInZ$4LW4{pA~YCtM(!mRLFQncq2)8z%3ok z+if<9wo_1k5-*A=msK$vTgdBrK=aLIj_F>Vyne`m2r;f;+`W>K9x+^M;Zpz*3@&yT zG>k(HS!y}Zwew9G)+fEnQ2I5ZQ!YtyuV#mv-ntc*#Scd%ishC|b><(b1Xx}CLfpRjeNSh>4rgpRT;0SD<^(SKjr*d?`8ef z{EY(wWuuI6bo(0VMQ2!<6yFZ3;}+C;!8)GIU-NG4p^_||Ze+s)5L{07zla$+*g9$%ii}wi+cY}B* zc1cQXrj>mUC&u8yjc%*jPRo&ni(4izM>EM8-Rs3h0bX(#o}1mBVMXmQVL#xxu+F-6 z{(5l>a!;p{SNhGg$5$ZB+qN!aIl`8R5GM?bds3UHdF0vIfngxR7`4Cm%pHg@P`jS- z^@Kxk5JR)sV|ZqsEh1266XywS$BaWVXE<{Q@_?eb#<6c>jH+^j#t>EQ2bzp8S)waW z0Y$T1xsm9O`|ozi*h5}F%So^9+U|>f=#W?DfA-2&AHF02B98_HWO(|Vd3Gs%vIpWZ zSe)opn0PDK&|j2cR$QN?IP!76R1}`qy50!X6l*y$B0(p3a4Gd`qIM(g7j(?5Y%3ATGLRQsNX+)x*Wz8;6 z#lhgGE{}ESai7(aZ@h8fam2&QyT`Xo;Ml>HU&_QjSq)E^?@G;=n_otvTN3m)1az%* zzOkb<11X7YH4mdcFMt0sjf-B&R*fWkMUiY>=??g9>~`||@@+x(?32*Y8oZC-a|PXu zC|ip0g!riid%dv+;Nj6R@r(XX3Rx0~qc+J>m?tOwt8K8LNtXW)3R$|58kOY)qn^s1 z(LVXNs4UTiw-nUYM?`YvIVh1`{;H8n@dwso4x(9Y8iP0Q^)!(zE|alG&2W9PY+*a& zw$RuLO*0iVIqs+#hy0MzF}Zlbzf;KJjkJ)w0Vrfhf*_4Tj?2SiYZG)6IQCD3w=Xbc z{%*Nwk1GI{3oEMSqU1NrMP(QMT7_yg)pC*i%W`owFBw=aB7gefNMvE^a*2CN*W{1U z?8kzsEwts5Q+Y{471Yt}k;cvClC*bg)X{7}SZsQh*YeWW8>t|2KQi5k#5VyaObLSJ z5<&@exrD$)OUSHRuI%}ojEMwWRcb<3-*ZOre~-s(zX*#z3HeV#{*#dZ{Rx?qo|T%A z)d?r|PZn$pGM4DKv_-v3I;y=OQAc;TQZxl{vj`M~t%k_7!^{A#K!P!GQqD}w2*I;* z;xrsM@fHI_UG2%%5GF}FcnykYqvlD9Zm|MiGR2VD98z$;#T7AG_={2&0+e$2TB{%! z)=24(*LyFKjwZEl^)!yx@EBz>>?bDbgh>v$?z;bd*^OVr-I{-*^?t~d5jP)5c+;)v zQIm9HYmKIbFO50E8plQ2A#hHpITX|E}t!Ymn+Y?DH3%+ zaDz^0?b8Ja8`%Aw#%Ul+AbJ%S6h0bogf1Ae^Vhtih2`b+xaPNpKeo7I8dvNB}-NHq;^|^*OfnL`&(xf3Rb~^zgC?pzaSh8+fYd3v$Ex8jAcsicILbECS}%k zYUOZVlX1BvqUua&dy*mu%Q}4TX$(b~o%4~c$}vQe{rJtdiC-$OovG}1y1blvb+B$e zcr}AVh?l52Y+>b{u4+*>r_N_z6c3G9lkK)$ZJHj456NPP6+?&0bU9y$x*cE3Yl^*}ULt&#jDlwP$Q++nvu}H?tjRp|iS&9`G~e z@~Zr*l?5wMZdEn>rpMUfkm=x)2QgdLJepC2#QmS)CAYslc5GHqbM{xeZ3fhAkZmw% zlIn;!38f@jek6PD6{FJS@eQXh@5X{;SMg6>R$;G2RCg;sc~{AupS%n<9Oc+{EU_9eMDKb0@TF2} z5T|xsV2+5mf}gb;cL`*-RnZEPDONxE#6WG6VCAUNOVP~whm00-0$b*=oQjs?~GxPh4vHT}!6V8+~#-o(p}FtOuUi^RGomV8({@LQaWJ>=M78^VY`J{Jrh2^S`DZSqxHU701gm?vjB7YCPgTX8x_+ea zgyn+o82;ff|1-%TRXQ#-ihhSH=b2cm=7UmtUUo@f6fmnhxz_n9OCjU1OsIMSD0)@R zZeN5Q~s1ta!epDJ+NksJ2i9{ubh>R1hU!3gw*}wd-4`1qiT~^HO4c{D`pN*V~VX&Y)5)H2o zqexk;ot^l+F|)_-3zf1MeSP<9^oOWm1FA?9(P$0W%etESKUG`~fhycd- z&JzV)Y?Q5)$;85`If2NQh0qoWSY0Vy;eB}aKWgMpSaEP-ClEoIz?3rTXx2Cy{Wqh9 zL>@IBe_IW`We*vvckBxNO`<%8)h5T3wBuzaF-{P8xxlf%5;7idIT>SxX0=`m{Q+87 z{W#SFrSyQRgZo-2wMn-6=c!)b-$Qal-fyRReVeCxXzHn+_Ak%^mALX7fV_FCcb|5u zSNID+9#7K#zntn>{5sVm(`;}xf1T%h{3j;=`(v`15d#AX($qqvqZdCs-1L6;vOxt$wcpX(W4Y{+W^_Vj<~cXh0~mXV>}E&Ps|k1VzR3h-eQcXtB+_4VFG*43n;OTHvbg+vNqo6 zu^4IIgK&OoPb>&qS0LYOnv-ya9pYwunvpJgcSb}7SgMx%!9iTRS&Me3X2C~h%OwMb z1A}{cZ!^>?tWO^bT{ z(W?9CUTZkQEz4!o9fyx;qsc}=N-%o3D}6Iq(Tnn97E7$6RmL{GC7C;clX-UX-hpX< zr!iQ$-q*(KZpN_etC99M4>Mg2?*jLEBs%4jU~=14J*sG_?6u#=hd(B_)t;T`6$3)x zXm_wn0w%6|+n7{(yIGDobcQQjW%j0c$UOz8S~UCuQGsGK@5iwZ!o9$vhl3x=4ycAF zUEv%_c$zxyTdAAMZ34|4XCfytzsKB~EFqCHNH;3+B9YBxzm1YH`Hfyw)|0d(?!0yJ za(x9ZCKMPPjCS(UjWfX44IfWy9`=;|wwlxlwb>gbU9Kht7Pb9wd0)EX^#*Pvz=kOd zyqC&(v#t*Q>XZ$7)~DP9#1}|NwnUCF*KycZWSdif*7MwtzM9ld`Bol##I4}SiM-(h z6FnSJWIE9uawtARjs1;X*s3kdVw#MV(xDA^D6Z>ufYO~pKBhAc5i}LD7!BM)EMEWWz|2k-zmbPY+0Spks6cHF5L%n z8&dE4aPl(7it#qcbOyJr&pwp-nwh-y4s8*VZ5FVXI|z?|_Vc3=5=}gVS5Q z)(T=6nn?N~x5!SM=wX*Otq)AOf1QO3o1IjanGfLF_X`negwo> z^E|#>5R;!vx|N%`@7N_*cjAEytXrlLCDGZP21|hSJ2AJNbE|Y3LA-o~bib)V*zZP6 z%VKzONi8={oNo8&wG-Ysd$gG!IcP~~r6{dP$}&Uf?t4{dSxxTPFYi2c=-%gAm!hk0 zIS*o4%6MZ!FF~rid*Kp*zBpT6n0->l(+#TAr(5g?O-Y?)u_7Wgig!&Xpez(B!%DpY zi%jVycSvqwdbMkD5IK6rFImt-r9g$d?TnX8jeGRaij*Qjgh?8aNwBFj<)}aNA>z{> zD~)_Cx6kVjXWM}d&Ztm-zkwg>oa-w~NNrmU*TB#ys$*_Y}~=X)tGLU*@u$LqX)+voG3nni4ae6Tie9{ch&Wh7V; zW;twm#;Jdp8k3*y``&bEM9K0a5_Z6tGyeiE zkmMMPwU|x_mh&fYu@lMSOpbMt!}WJ^3~)LeL(q6+T1-AO8N1XU{D?a)aMJH@!sOa` zEpVf^!Nc*WjR`yHM>QtB9Me1W92=*AHyc*Sg9)taWJFh0gie8B`_@{XS|`4%!=xxP{~8)C2-lfmeRXO`sa zLqMf0wRJ!hF5zt@qP6F5G1+18n0EMNyRWz*A;on_f2kz>!05Q>a)N1#5 zO>@8JWY7XS3Lu}ubgGG};mu#Zg{xPAHaWJKry!>Wbf`sn!GZ(jT)0vPw$PQf3GP$ z5d&+178zuBsww+HJqM1b?X^915B(%1kfgGAR{R|_Oem4MoJSdq*CQXal|-B<`c<&eGA1SqU0Axwdv6|5(69(sQV>)3*`Ykq3CVN2pSrZZ0? znIU+-Jt5oFkuYB6>B8qX+pd_8i6b|76E!v*_-@5@#Ot=1X?8Vzl2J*xVtukn*v?gL z>tfdxOWBjJDsds%E0pa5<&+~W>~3eP&YT%Y0lWn?P_*~Xb|1VsgoDV=Y-&c>Z@tf= z%vpoa0c7JSgiH5Mfrhx=_@Gd_Sh275GOZvR4?mPyqh{kT^KT^&LL@1W9HZ)6^S*)Ft2yOEdIRz!z8%!>m#UXYuDQ7WO zdAblwMLij==__-2dGZ8A)^Z-NJMrkHLJOkK%=64gbZgq@?XS{fQ#I5KDC5P?O0V)d zG}MJk$rbdHx{?Y*?>teuGxa%jD@)EWr-Btk={&oDwg5s_O^xob{Tb* zmUz7lU`mF3Tu3m5aqd8j!NV6A*uuuxEd5&NVpRRqgkMq+zSp|vUjMZ=GSLuTp*41e zg6s1)g$k01AywNJ>T9ThSfV#rIJ{A;>bfr>B0zQ=#~GuF2h-Jvg!iypZlQRr>?8A? zVFp}>O1ph76wR_cWz;!;e#I`7Hw5>*>EeP*79L;hbL^hxi;v*;K;ty!I^LQ2uycbX zrDKL_d;89gF3$F*SP@Zk=(JnW@4%fNLQe&zvocUSvqU!peXey^*l4oj<3ldJIT;T0 zFh}Hkb!9~5r%OCS8d%MUJiRApe0RH$i&^5&I*%RD1PC&u`AP24jkzn2Yabrn{i*s@ zQp{XjBuUj%0th6Q{*LLNTuc zwuH`J$LMTGd?e%K&i~pS^OLDZdO}D)6Jj{;!fBWBh~IND&m_)JP+Jv=8EO#r>-=iIXV=Kp|VDZff3Mb*0(>3K^0%x=A4~q%8>2 z?)1nrn{p`f(!}G8?PrBz4lq}*Z*Lv5WPS=`i(y)NixNCJFhs3@%b1OMo43F z<{|zKN3JJ@-Y8|PrZeEVN?$X@cQE4T&<_)4N z7RHL@8R+LxDfn3GL6PLk<)r8GBxeb*LZgIOU0<(os?sUQ$4qs_bAq#T7Yq?1nrEUv zE5U&#Nr^5dxa$sQr1`P7^CS?VoJH;|~H$P$WC&c~{#kSb38v<>+s`$vlmne*!$$l-@DnaPoaA9y~A z=rt0GAfQaKd+FU4c?iw&@`Cp-aRe6_2FS>v^f(=DLVL$x0_3S()d`{*nVI`&qa#6G zC)$hxFkp0K@N-vq86E*grC6*x*jBE1B+|&_8$Ixwh5<%$5ZS@*^eBpvXf=4vyoc?- zde=M8i2{~J;>;rkgCp1ShFQ<`*hf#ci_QWRJ�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 Date: Thu, 2 Mar 2023 09:57:45 +0300 Subject: [PATCH 174/201] implement transfer ctas --- .../presentation/CoinDetailsScreen.kt | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index e65f0fe..4dcbc48 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -18,7 +18,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.ryankoech.krypto.common.presentation.ErrorScreen +import com.ryankoech.krypto.common.presentation.components.KryptoButton import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.theme.Red100 import com.ryankoech.krypto.common.presentation.util.collectAsEffect import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap @@ -47,6 +49,8 @@ val MarketChartRangeText = listOf( fun CoinDetailsScreen( viewModel : CoinDetailsScreenViewModel = hiltViewModel(), coin : Coin, + navigateToBuyTransactionScreen : (String) -> Unit, + navigateToSellTransactionScreen : (String) -> Unit, modifier: Modifier = Modifier ) { @@ -253,7 +257,10 @@ fun CoinDetailsScreen( TransactionItem( modifier = Modifier .padding( - horizontal = 12.dp, + start = 12.dp, + end = 12.dp, + bottom = 12.dp, + ), transaction = transaction ) @@ -261,6 +268,41 @@ fun CoinDetailsScreen( } } + item { + + Row( + modifier = Modifier + .padding( + horizontal = 12.dp, + ) + .fillMaxWidth(), + ) { + + KryptoButton( + modifier = Modifier + .weight(1.0f), + text = "Transfer In", + onClick = { + navigateToBuyTransactionScreen(coin.id) + } + ) + + Spacer(modifier = Modifier.width(24.dp)) + + KryptoButton( + modifier = Modifier + .weight(1.0f), + text = "Transfer Out", + onClick = { + navigateToSellTransactionScreen(coin.id) + }, + color = Red100 + ) + + } + + } + } } @@ -276,6 +318,8 @@ fun CoinDetailsScreenPreview() { ) { CoinDetailsScreen( coin = FAKE_COIN_LIST.toCoinEntity().first(), + navigateToBuyTransactionScreen = {}, + navigateToSellTransactionScreen = {}, ) } } From 2b73cee488357c35c2748ab66a20a3878a18254a Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 09:58:24 +0300 Subject: [PATCH 175/201] add color resource --- .../com/ryankoech/krypto/common/presentation/theme/Color.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Color.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Color.kt index 03ef447..4fa73f8 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Color.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/theme/Color.kt @@ -9,4 +9,5 @@ val Teal200 = Color(0xFF03DAC5) val Green500 = Color(0xff39b23f) val Green200 = Color(0xffa1f5b9) val Red400 = Color(0xfffc4e51) -val Red200 = Color(0xfff79a9c) \ No newline at end of file +val Red200 = Color(0xfff79a9c) +val Red100 = Color(0xffffcdd4) \ No newline at end of file From 66e4ffcfb458f292df441d67aa5c55801549666a Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 10:18:55 +0300 Subject: [PATCH 176/201] make test data public --- .../components/success/LineChart.kt | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt index 4a2ea8f..65b41d5 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/LineChart.kt @@ -14,6 +14,24 @@ import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import kotlin.math.roundToInt +val FAKE_LINECHART_DATA = listOf( + Pair(6, 111.45), + Pair(7, 111.0), + Pair(8, 113.45), + Pair(9, 112.25), + Pair(10, 116.45), + Pair(11, 113.35), + Pair(12, 118.65), + Pair(13, 110.15), + Pair(14, 113.05), + Pair(15, 114.25), + Pair(16, 116.35), + Pair(17, 117.45), + Pair(18, 112.65), + Pair(19, 115.45), + Pair(20, 111.85) +) + @Composable fun LineChart( modifier: Modifier = Modifier, @@ -92,29 +110,13 @@ fun LineChart( @Preview @Composable fun LineChartPreview() { - val data = listOf( - Pair(6, 111.45), - Pair(7, 111.0), - Pair(8, 113.45), - Pair(9, 112.25), - Pair(10, 116.45), - Pair(11, 113.35), - Pair(12, 118.65), - Pair(13, 110.15), - Pair(14, 113.05), - Pair(15, 114.25), - Pair(16, 116.35), - Pair(17, 117.45), - Pair(18, 112.65), - Pair(19, 115.45), - Pair(20, 111.85) - ) + KryptoTheme { Surface ( modifier = Modifier.background(color = Color.Black) ) { LineChart( - data = data, + data = FAKE_LINECHART_DATA, modifier = Modifier .fillMaxWidth() .height(300.dp) From 1d785eee02194a3164337ded49033ba3d0781513 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 10:20:02 +0300 Subject: [PATCH 177/201] refactor out success screen and add conditional loading screens logic --- .../presentation/CoinDetailsScreen.kt | 192 +------------ .../viewstate/CoinDetailsScreenSuccess.kt | 257 ++++++++++++++++++ 2 files changed, 271 insertions(+), 178 deletions(-) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenSuccess.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 4dcbc48..06d5d0c 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -21,16 +21,14 @@ import com.ryankoech.krypto.common.presentation.ErrorScreen import com.ryankoech.krypto.common.presentation.components.KryptoButton import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.theme.Red100 -import com.ryankoech.krypto.common.presentation.util.collectAsEffect -import com.ryankoech.krypto.common.presentation.util.getFormattedBalance -import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap -import com.ryankoech.krypto.common.presentation.util.getFormattedTotalVolume +import com.ryankoech.krypto.common.presentation.util.* import com.ryankoech.krypto.feature_coin_details.R import com.ryankoech.krypto.feature_coin_details.domain.entity.toPairList import com.ryankoech.krypto.feature_coin_details.presentation.components.success.* import com.ryankoech.krypto.feature_coin_details.presentation.util.CoinStatistic import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRange import com.ryankoech.krypto.feature_coin_details.presentation.viewmodel.CoinDetailsScreenViewModel +import com.ryankoech.krypto.feature_coin_details.presentation.viewstate.CoinDetailsScreenSuccess import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin @@ -121,188 +119,26 @@ fun CoinDetailsScreen( } } - LazyColumn( - modifier = modifier - .fillMaxSize(), - contentPadding = PaddingValues(vertical = 12.dp), - verticalArrangement = Arrangement.spacedBy(12.dp) - ){ - - item{ - CoinDetailsHeader( - coin = coin, - modifier = Modifier - .padding(horizontal = 12.dp) - ) - } - - item { - LineChart( - data = marketChartData, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 12.dp) - .height(300.dp) - .background(color = Color.White) - ) - } - - - item{ - - LazyRow( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 12.dp), - horizontalArrangement = Arrangement.SpaceBetween, - ){ - - items(MarketChartRangeText.size){ counter -> - MarketRangeButton( - onClick = { marketChartButtonOnClick(MarketChartRangeText[counter].first) }, - text = MarketChartRangeText[counter].second, - selected = MarketChartRangeText[counter].first == currentMarketChartRange - ) - - } - - } - - } - - item{ - Divider( - modifier = Modifier.fillMaxWidth(), - color = Color(0xfff2f2f2) - ) - } - - item{ - Text( - modifier = Modifier - .padding(horizontal = 12.dp), - text = "Coin Statistics", - style = MaterialTheme.typography.h2, - ) - } - - - item{ - - val coinStatistics = listOf( - CoinStatistic("Market Cap", getFormattedMarketCap(context, coin.marketCap), R.drawable.icon_pie_chart), - CoinStatistic("All Time High", getFormattedBalance(context, coin.allTimeHigh), R.drawable.icon_rocket), - CoinStatistic("24hr High", getFormattedBalance(context, coin.high24Hr), R.drawable.iconi_trophie), - CoinStatistic("Total Volume", getFormattedTotalVolume(context, coin.totalVolume.toLong()), R.drawable.icon_line_graph), - ) - - LazyVerticalGrid( - modifier = Modifier - .fillMaxWidth() - .height(216.dp), - contentPadding = PaddingValues(horizontal = 12.dp), - columns = GridCells.Fixed(2), - horizontalArrangement = Arrangement.spacedBy(20.dp), - verticalArrangement = Arrangement.SpaceAround, - userScrollEnabled = false, - ) { - - items(coinStatistics) { coinStatistic -> - CoinStatisticsCard( - resId = coinStatistic.icon, - title = coinStatistic.title , - body = coinStatistic.message - ) - } - - } + when(viewState.screenState){ + ScreenState.LOADING -> { } + ScreenState.ERROR -> { - item{ - Divider( - modifier = Modifier.fillMaxWidth(), - color = Color(0xfff2f2f2) - ) } + ScreenState.SUCCESS -> { - - item{ - Text( - modifier = Modifier - .padding(horizontal = 12.dp), - text = "Transaction History", - style = MaterialTheme.typography.h2, + CoinDetailsScreenSuccess( + coin = coin, + transactions = viewState.transactions, + navigateToBuyTransactionScreen = navigateToBuyTransactionScreen, + navigateToSellTransactionScreen = navigateToSellTransactionScreen, + marketChartData = marketChartData, + marketChartButtonOnClick = marketChartButtonOnClick, + currentMarketChartRange = currentMarketChartRange ) - } - - if(viewState.transactions.isEmpty()) { - - item{ - ErrorScreen( - modifier = Modifier - .padding( - vertical = 40.dp, - ), - messageText = "Whoops, looks like a ghost town here.", - res = com.ryankoech.krypto.feature_transaction.R.drawable.no_transaction, - showButton = false, - ) - } - - }else { - - items(viewState.transactions){ transaction -> - TransactionItem( - modifier = Modifier - .padding( - start = 12.dp, - end = 12.dp, - bottom = 12.dp, - - ), - transaction = transaction - ) - - } } - - item { - - Row( - modifier = Modifier - .padding( - horizontal = 12.dp, - ) - .fillMaxWidth(), - ) { - - KryptoButton( - modifier = Modifier - .weight(1.0f), - text = "Transfer In", - onClick = { - navigateToBuyTransactionScreen(coin.id) - } - ) - - Spacer(modifier = Modifier.width(24.dp)) - - KryptoButton( - modifier = Modifier - .weight(1.0f), - text = "Transfer Out", - onClick = { - navigateToSellTransactionScreen(coin.id) - }, - color = Red100 - ) - - } - - } - } } diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenSuccess.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenSuccess.kt new file mode 100644 index 0000000..5eb7975 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenSuccess.kt @@ -0,0 +1,257 @@ +package com.ryankoech.krypto.feature_coin_details.presentation.viewstate + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Divider +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.ErrorScreen +import com.ryankoech.krypto.common.presentation.components.KryptoButton +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.common.presentation.theme.Red100 +import com.ryankoech.krypto.common.presentation.util.getFormattedBalance +import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap +import com.ryankoech.krypto.common.presentation.util.getFormattedTotalVolume +import com.ryankoech.krypto.feature_coin_details.R +import com.ryankoech.krypto.feature_coin_details.presentation.MarketChartRangeText +import com.ryankoech.krypto.feature_coin_details.presentation.components.success.* +import com.ryankoech.krypto.feature_coin_details.presentation.util.CoinStatistic +import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRange +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.data.repository.bitCoinTransaction + +@Composable +fun CoinDetailsScreenSuccess( + modifier : Modifier = Modifier, + coin : Coin, + transactions : List, + navigateToBuyTransactionScreen : (String) -> Unit, + navigateToSellTransactionScreen : (String) -> Unit, + marketChartData : List>, + marketChartButtonOnClick : (MarketChartRange) -> Unit, + currentMarketChartRange : MarketChartRange, +) { + + val context = LocalContext.current + + LazyColumn( + modifier = modifier + .fillMaxSize(), + contentPadding = PaddingValues(vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ){ + + item{ + CoinDetailsHeader( + coin = coin, + modifier = Modifier + .padding(horizontal = 12.dp) + ) + } + + item { + LineChart( + data = marketChartData, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp) + .height(300.dp) + .background(color = Color.White) + ) + } + + + item{ + + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp), + horizontalArrangement = Arrangement.SpaceBetween, + ){ + + items(MarketChartRangeText.size){ counter -> + MarketRangeButton( + onClick = { marketChartButtonOnClick(MarketChartRangeText[counter].first) }, + text = MarketChartRangeText[counter].second, + selected = MarketChartRangeText[counter].first == currentMarketChartRange + ) + + } + + } + + } + + item{ + Divider( + modifier = Modifier.fillMaxWidth(), + color = Color(0xfff2f2f2) + ) + } + + item{ + Text( + modifier = Modifier + .padding(horizontal = 12.dp), + text = "Coin Statistics", + style = MaterialTheme.typography.h2, + ) + } + + + item{ + + val coinStatistics = listOf( + CoinStatistic("Market Cap", getFormattedMarketCap(context, coin.marketCap), R.drawable.icon_pie_chart), + CoinStatistic("All Time High", getFormattedBalance(context, coin.allTimeHigh), R.drawable.icon_rocket), + CoinStatistic("24hr High", getFormattedBalance(context, coin.high24Hr), R.drawable.iconi_trophie), + CoinStatistic("Total Volume", getFormattedTotalVolume(context, coin.totalVolume.toLong()), R.drawable.icon_line_graph), + ) + + LazyVerticalGrid( + modifier = Modifier + .fillMaxWidth() + .height(216.dp), + contentPadding = PaddingValues(horizontal = 12.dp), + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(20.dp), + verticalArrangement = Arrangement.SpaceAround, + userScrollEnabled = false, + ) { + + items(coinStatistics) { coinStatistic -> + CoinStatisticsCard( + resId = coinStatistic.icon, + title = coinStatistic.title , + body = coinStatistic.message + ) + } + + } + + } + + item{ + Divider( + modifier = Modifier.fillMaxWidth(), + color = Color(0xfff2f2f2) + ) + } + + + item{ + Text( + modifier = Modifier + .padding(horizontal = 12.dp), + text = "Transaction History", + style = MaterialTheme.typography.h2, + ) + } + + if(transactions.isEmpty()) { + + item{ + ErrorScreen( + modifier = Modifier + .padding( + vertical = 40.dp, + ), + messageText = "Whoops, looks like a ghost town here.", + res = com.ryankoech.krypto.feature_transaction.R.drawable.no_transaction, + showButton = false, + ) + } + + }else { + + items(transactions){ transaction -> + + TransactionItem( + modifier = Modifier + .padding( + start = 12.dp, + end = 12.dp, + bottom = 12.dp, + + ), + transaction = transaction + ) + + } + } + + item { + + Row( + modifier = Modifier + .padding( + horizontal = 12.dp, + ) + .fillMaxWidth(), + ) { + + KryptoButton( + modifier = Modifier + .weight(1.0f), + text = "Transfer In", + onClick = { + navigateToBuyTransactionScreen(coin.id) + } + ) + + Spacer(modifier = Modifier.width(24.dp)) + + KryptoButton( + modifier = Modifier + .weight(1.0f), + text = "Transfer Out", + onClick = { + navigateToSellTransactionScreen(coin.id) + }, + color = Red100 + ) + + } + + } + + } + +} + +@Preview +@Composable +fun CoinDetailsScreenSuccessPreview() { + + KryptoTheme { + Surface { + CoinDetailsScreenSuccess( + coin = FAKE_COIN_LIST.toCoinEntity().first(), + navigateToBuyTransactionScreen = {}, + navigateToSellTransactionScreen = {}, + currentMarketChartRange = MarketChartRange.ONE_DAY, + marketChartButtonOnClick = {}, + marketChartData = FAKE_LINECHART_DATA, + transactions = bitCoinTransaction, + ) + } + } + +} \ No newline at end of file From ed9a85b1e16dd7a62ddac87561eebe00e3cb6bed Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 10:22:04 +0300 Subject: [PATCH 178/201] refactor file location --- .../presentation/CoinDetailsScreen.kt | 16 ---------------- .../{viewstate => }/CoinDetailsScreenSuccess.kt | 3 +-- 2 files changed, 1 insertion(+), 18 deletions(-) rename feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/{viewstate => }/CoinDetailsScreenSuccess.kt (98%) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 06d5d0c..523c8e0 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -1,34 +1,18 @@ package com.ryankoech.krypto.feature_coin_details.presentation import android.widget.Toast -import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.grid.GridCells -import androidx.compose.foundation.lazy.grid.LazyVerticalGrid -import androidx.compose.foundation.lazy.grid.items -import androidx.compose.foundation.lazy.items import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import com.ryankoech.krypto.common.presentation.ErrorScreen -import com.ryankoech.krypto.common.presentation.components.KryptoButton import com.ryankoech.krypto.common.presentation.theme.KryptoTheme -import com.ryankoech.krypto.common.presentation.theme.Red100 import com.ryankoech.krypto.common.presentation.util.* -import com.ryankoech.krypto.feature_coin_details.R import com.ryankoech.krypto.feature_coin_details.domain.entity.toPairList -import com.ryankoech.krypto.feature_coin_details.presentation.components.success.* -import com.ryankoech.krypto.feature_coin_details.presentation.util.CoinStatistic import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRange import com.ryankoech.krypto.feature_coin_details.presentation.viewmodel.CoinDetailsScreenViewModel -import com.ryankoech.krypto.feature_coin_details.presentation.viewstate.CoinDetailsScreenSuccess import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenSuccess.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt similarity index 98% rename from feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenSuccess.kt rename to feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt index 5eb7975..7f4545d 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenSuccess.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt @@ -1,4 +1,4 @@ -package com.ryankoech.krypto.feature_coin_details.presentation.viewstate +package com.ryankoech.krypto.feature_coin_details.presentation import androidx.compose.foundation.background import androidx.compose.foundation.layout.* @@ -26,7 +26,6 @@ import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap import com.ryankoech.krypto.common.presentation.util.getFormattedTotalVolume import com.ryankoech.krypto.feature_coin_details.R -import com.ryankoech.krypto.feature_coin_details.presentation.MarketChartRangeText import com.ryankoech.krypto.feature_coin_details.presentation.components.success.* import com.ryankoech.krypto.feature_coin_details.presentation.util.CoinStatistic import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRange From c9a9e70f7688a9ea1bd7352ed9a54b4569c47eed Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 10:31:54 +0300 Subject: [PATCH 179/201] refactor out component --- .../presentation/components/loading/BigCardLoading.kt | 10 ++++------ .../feature_home/presentation/HomeScreenLoading.kt | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) rename feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/loading/CreditCardLoading.kt => common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/BigCardLoading.kt (76%) diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/loading/CreditCardLoading.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/BigCardLoading.kt similarity index 76% rename from feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/loading/CreditCardLoading.kt rename to common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/BigCardLoading.kt index 6ec5f51..6ebf70e 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/loading/CreditCardLoading.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/BigCardLoading.kt @@ -1,4 +1,4 @@ -package com.ryankoech.krypto.feature_home.presentation.components.loading +package com.ryankoech.krypto.common.presentation.components.loading import androidx.compose.foundation.background import androidx.compose.foundation.layout.* @@ -7,15 +7,13 @@ import androidx.compose.material.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.ryankoech.krypto.common.presentation.components.loading.loadingEffect import com.ryankoech.krypto.common.presentation.theme.KryptoTheme @Composable -fun CreditCardLoading( +fun BigCardLoading( brush: Brush, modifier: Modifier = Modifier, ){ @@ -34,13 +32,13 @@ fun CreditCardLoading( @Preview @Composable -fun CreditCardLoadingPreview(){ +fun BigCardLoadingPreview(){ KryptoTheme { Surface(modifier = Modifier.fillMaxSize()) { val brush = loadingEffect() - Column{ CreditCardLoading(brush) } + Column{ BigCardLoading(brush) } } } diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenLoading.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenLoading.kt index f0d34fd..713b3c3 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenLoading.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenLoading.kt @@ -10,7 +10,7 @@ import com.ryankoech.krypto.common.presentation.components.loading.CoinCardLoadi import com.ryankoech.krypto.common.presentation.components.loading.loadingEffect import com.ryankoech.krypto.common.presentation.components.loading.LoadingText import com.ryankoech.krypto.common.presentation.theme.KryptoTheme -import com.ryankoech.krypto.feature_home.presentation.components.loading.CreditCardLoading +import com.ryankoech.krypto.common.presentation.components.loading.BigCardLoading import com.ryankoech.krypto.feature_home.presentation.components.loading.HomeScreenActionsLoading const val TEST_TAG_HOME_SCREEN_LOADING = "test_tag_home_screen_loading" @@ -28,7 +28,7 @@ fun HomeScreenLoading( val brush = loadingEffect() - CreditCardLoading(brush) + BigCardLoading(brush) Spacer(modifier = Modifier.height(32.dp)) From 3664fed38c271ec551a1f215a5770c3cb055737f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 10:57:03 +0300 Subject: [PATCH 180/201] refactor component name --- .../loading/{BigCardLoading.kt => CardLoading.kt} | 6 +++--- .../krypto/feature_home/presentation/HomeScreenLoading.kt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/{BigCardLoading.kt => CardLoading.kt} (91%) diff --git a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/BigCardLoading.kt b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/CardLoading.kt similarity index 91% rename from common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/BigCardLoading.kt rename to common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/CardLoading.kt index 6ebf70e..ecd13a1 100644 --- a/common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/BigCardLoading.kt +++ b/common/src/main/java/com/ryankoech/krypto/common/presentation/components/loading/CardLoading.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.theme.KryptoTheme @Composable -fun BigCardLoading( +fun CardLoading( brush: Brush, modifier: Modifier = Modifier, ){ @@ -32,13 +32,13 @@ fun BigCardLoading( @Preview @Composable -fun BigCardLoadingPreview(){ +fun CardLoadingPreview(){ KryptoTheme { Surface(modifier = Modifier.fillMaxSize()) { val brush = loadingEffect() - Column{ BigCardLoading(brush) } + Column{ CardLoading(brush) } } } diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenLoading.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenLoading.kt index 713b3c3..0969573 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenLoading.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenLoading.kt @@ -10,7 +10,7 @@ import com.ryankoech.krypto.common.presentation.components.loading.CoinCardLoadi import com.ryankoech.krypto.common.presentation.components.loading.loadingEffect import com.ryankoech.krypto.common.presentation.components.loading.LoadingText import com.ryankoech.krypto.common.presentation.theme.KryptoTheme -import com.ryankoech.krypto.common.presentation.components.loading.BigCardLoading +import com.ryankoech.krypto.common.presentation.components.loading.CardLoading import com.ryankoech.krypto.feature_home.presentation.components.loading.HomeScreenActionsLoading const val TEST_TAG_HOME_SCREEN_LOADING = "test_tag_home_screen_loading" @@ -28,7 +28,7 @@ fun HomeScreenLoading( val brush = loadingEffect() - BigCardLoading(brush) + CardLoading(brush) Spacer(modifier = Modifier.height(32.dp)) From 1ca2c9ab095792503c8524904e3b15f659b5cd05 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 10:58:26 +0300 Subject: [PATCH 181/201] pass modifier parameter --- .../feature_coin_details/presentation/CoinDetailsScreen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 523c8e0..e163be6 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -113,6 +113,7 @@ fun CoinDetailsScreen( ScreenState.SUCCESS -> { CoinDetailsScreenSuccess( + modifier = modifier, coin = coin, transactions = viewState.transactions, navigateToBuyTransactionScreen = navigateToBuyTransactionScreen, From 3fa3093dd6707d773d21794bf39f8a11a004c7aa Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 11:06:31 +0300 Subject: [PATCH 182/201] implement loading screen --- .../presentation/CoinDetailsScreen.kt | 4 +- .../presentation/CoinDetailsScreenLoading.kt | 114 ++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenLoading.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index e163be6..455a0c5 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -105,7 +105,9 @@ fun CoinDetailsScreen( when(viewState.screenState){ ScreenState.LOADING -> { - + CoinDetailsScreenLoading( + modifier = modifier, + ) } ScreenState.ERROR -> { diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenLoading.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenLoading.kt new file mode 100644 index 0000000..8060d18 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenLoading.kt @@ -0,0 +1,114 @@ +package com.ryankoech.krypto.feature_coin_details.presentation + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ryankoech.krypto.common.presentation.components.loading.CardLoading +import com.ryankoech.krypto.common.presentation.components.loading.CoinCardLoading +import com.ryankoech.krypto.common.presentation.components.loading.loadingEffect +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme + +@Composable +fun CoinDetailsScreenLoading( + modifier: Modifier = Modifier, +) { + + val brush = loadingEffect() + + LazyColumn( + modifier = modifier + .padding(top = 12.dp, start = 12.dp, end = 12.dp) + .fillMaxSize() + ){ + + item{ + CoinCardLoading( + brush = brush, + ) + } + + item{ Spacer(modifier = Modifier.height(32.dp)) } + + item{ + CardLoading( + modifier = Modifier + .height(280.dp), + brush = brush, + ) + } + + item{ Spacer(modifier = Modifier.height(24.dp)) } + + item { + LazyRow( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + + items((1..5).toList()){ + CardLoading( + modifier = Modifier + .height(28.dp) + .width(36.dp), + brush = brush, + ) + } + + } + } + + item{ Spacer(modifier = Modifier.height(24.dp)) } + + item{ + + LazyVerticalGrid( + modifier = Modifier + .fillMaxWidth() + .height(216.dp), + contentPadding = PaddingValues(horizontal = 12.dp), + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(20.dp), + verticalArrangement = Arrangement.SpaceAround, + userScrollEnabled = false, + ) { + + items((1..4).toList()) { + CardLoading( + modifier = Modifier + .height(80.dp), + brush = brush + ) + } + + } + + } + + + + } + + +} + +@Preview +@Composable +fun CoinDetailsScreenLoadingPreview() { + + KryptoTheme { + Surface { + CoinDetailsScreenLoading() + } + } + +} \ No newline at end of file From bc80e6e3caddd9d24cde944a74b940f306290a8a Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 2 Mar 2023 11:38:16 +0300 Subject: [PATCH 183/201] implement fallback error screen --- .../presentation/CoinDetailsScreen.kt | 6 +++- .../presentation/CoinDetailsScreenError.kt | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenError.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 455a0c5..86a5c74 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -110,7 +110,11 @@ fun CoinDetailsScreen( ) } ScreenState.ERROR -> { - + CoinDetailsScreenError( + onButtonClick = { + viewModel.getCoinDetails(coin.id) + } + ) } ScreenState.SUCCESS -> { diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenError.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenError.kt new file mode 100644 index 0000000..c4bc3c1 --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenError.kt @@ -0,0 +1,31 @@ +package com.ryankoech.krypto.feature_coin_details.presentation + +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.ryankoech.krypto.common.R +import com.ryankoech.krypto.common.presentation.ErrorScreen +import com.ryankoech.krypto.common.presentation.theme.KryptoTheme + +@Composable +fun CoinDetailsScreenError( + onButtonClick: () -> Unit, + modifier: Modifier = Modifier, +){ + + ErrorScreen(modifier = modifier, onButtonClick = onButtonClick, messageText = "Jeez, something's amiss", buttonText = "Retry", res = R.drawable.icon_gif_search) + +} + +@Preview +@Composable +fun CoinDetailsScreenErrorPreview (){ + KryptoTheme { + Surface { + CoinDetailsScreenError( + onButtonClick = { /*TODO*/ } + ) + } + } +} \ No newline at end of file From 69ed8bd1ab2d6ce70bd00022f4bdef6c01b2aa21 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 3 Mar 2023 09:16:54 +0300 Subject: [PATCH 184/201] extract string resources --- .../presentation/CoinDetailsScreen.kt | 9 ----- .../presentation/CoinDetailsScreenError.kt | 3 +- .../presentation/CoinDetailsScreenSuccess.kt | 39 ++++++++++++------- .../components/success/TransactionItem.kt | 25 +++++++----- .../src/main/res/values/strings.xml | 24 ++++++++++++ 5 files changed, 67 insertions(+), 33 deletions(-) create mode 100644 feature_coin_details/src/main/res/values/strings.xml diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 86a5c74..9fa769c 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -18,15 +18,6 @@ import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import timber.log.Timber -val MarketChartRangeText = listOf( - Pair(MarketChartRange.ONE_HOUR, "1h"), - Pair(MarketChartRange.ONE_DAY ,"1d"), - Pair(MarketChartRange.ONE_WEEK ,"7d"), - Pair(MarketChartRange.ONE_MONTH ,"30d"), - Pair(MarketChartRange.THREE_MONTH ,"90d"), - Pair(MarketChartRange.ONE_YEAR ,"1y"), -) - @Composable fun CoinDetailsScreen( viewModel : CoinDetailsScreenViewModel = hiltViewModel(), diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenError.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenError.kt index c4bc3c1..4f70dd1 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenError.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenError.kt @@ -3,6 +3,7 @@ package com.ryankoech.krypto.feature_coin_details.presentation import androidx.compose.material.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.ryankoech.krypto.common.R import com.ryankoech.krypto.common.presentation.ErrorScreen @@ -14,7 +15,7 @@ fun CoinDetailsScreenError( modifier: Modifier = Modifier, ){ - ErrorScreen(modifier = modifier, onButtonClick = onButtonClick, messageText = "Jeez, something's amiss", buttonText = "Retry", res = R.drawable.icon_gif_search) + ErrorScreen(modifier = modifier, onButtonClick = onButtonClick, messageText = stringResource(com.ryankoech.krypto.feature_coin_details.R.string.message_error_screen), buttonText = stringResource(com.ryankoech.krypto.feature_coin_details.R.string.button_retry), res = R.drawable.icon_gif_search) } diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt index 7f4545d..d6dc8b6 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt @@ -16,6 +16,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.ErrorScreen @@ -49,6 +50,15 @@ fun CoinDetailsScreenSuccess( val context = LocalContext.current + val marketChartRangeText = listOf( + Pair(MarketChartRange.ONE_HOUR, context.getString(R.string.button_market_chart_hour)), + Pair(MarketChartRange.ONE_DAY ,context.getString(R.string.button_market_chart_day)), + Pair(MarketChartRange.ONE_WEEK ,context.getString(R.string.button_market_chart_week)), + Pair(MarketChartRange.ONE_MONTH ,context.getString(R.string.button_market_chart_month)), + Pair(MarketChartRange.THREE_MONTH ,context.getString(R.string.button_market_chart_three_months)), + Pair(MarketChartRange.ONE_YEAR ,context.getString(R.string.button_market_chart_year)), + ) + LazyColumn( modifier = modifier .fillMaxSize(), @@ -85,11 +95,11 @@ fun CoinDetailsScreenSuccess( horizontalArrangement = Arrangement.SpaceBetween, ){ - items(MarketChartRangeText.size){ counter -> + items(marketChartRangeText.size){ counter -> MarketRangeButton( - onClick = { marketChartButtonOnClick(MarketChartRangeText[counter].first) }, - text = MarketChartRangeText[counter].second, - selected = MarketChartRangeText[counter].first == currentMarketChartRange + onClick = { marketChartButtonOnClick(marketChartRangeText[counter].first) }, + text = marketChartRangeText[counter].second, + selected = marketChartRangeText[counter].first == currentMarketChartRange ) } @@ -109,7 +119,7 @@ fun CoinDetailsScreenSuccess( Text( modifier = Modifier .padding(horizontal = 12.dp), - text = "Coin Statistics", + text = stringResource(R.string.heading_coin_statistics), style = MaterialTheme.typography.h2, ) } @@ -118,10 +128,10 @@ fun CoinDetailsScreenSuccess( item{ val coinStatistics = listOf( - CoinStatistic("Market Cap", getFormattedMarketCap(context, coin.marketCap), R.drawable.icon_pie_chart), - CoinStatistic("All Time High", getFormattedBalance(context, coin.allTimeHigh), R.drawable.icon_rocket), - CoinStatistic("24hr High", getFormattedBalance(context, coin.high24Hr), R.drawable.iconi_trophie), - CoinStatistic("Total Volume", getFormattedTotalVolume(context, coin.totalVolume.toLong()), R.drawable.icon_line_graph), + CoinStatistic(stringResource(R.string.card_heading_market_cap), getFormattedMarketCap(context, coin.marketCap), R.drawable.icon_pie_chart), + CoinStatistic(stringResource(R.string.card_heading_all_time_high), getFormattedBalance(context, coin.allTimeHigh), R.drawable.icon_rocket), + CoinStatistic(stringResource(R.string.card_heading_24hr_high), getFormattedBalance(context, coin.high24Hr), R.drawable.iconi_trophie), + CoinStatistic(stringResource(R.string.card_heading_total_volume), getFormattedTotalVolume(context, coin.totalVolume.toLong()), R.drawable.icon_line_graph), ) LazyVerticalGrid( @@ -159,7 +169,7 @@ fun CoinDetailsScreenSuccess( Text( modifier = Modifier .padding(horizontal = 12.dp), - text = "Transaction History", + text = stringResource(R.string.heading_transaction_history), style = MaterialTheme.typography.h2, ) } @@ -172,7 +182,7 @@ fun CoinDetailsScreenSuccess( .padding( vertical = 40.dp, ), - messageText = "Whoops, looks like a ghost town here.", + messageText = stringResource(R.string.message_no_transactions), res = com.ryankoech.krypto.feature_transaction.R.drawable.no_transaction, showButton = false, ) @@ -190,7 +200,8 @@ fun CoinDetailsScreenSuccess( bottom = 12.dp, ), - transaction = transaction + transaction = transaction, + symbol = coin.symbol ) } @@ -209,7 +220,7 @@ fun CoinDetailsScreenSuccess( KryptoButton( modifier = Modifier .weight(1.0f), - text = "Transfer In", + text = stringResource(R.string.button_transfer_in), onClick = { navigateToBuyTransactionScreen(coin.id) } @@ -220,7 +231,7 @@ fun CoinDetailsScreenSuccess( KryptoButton( modifier = Modifier .weight(1.0f), - text = "Transfer Out", + text = stringResource(R.string.button_transfer_out), onClick = { navigateToSellTransactionScreen(coin.id) }, diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt index ff184fd..e36b1c6 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt @@ -1,7 +1,6 @@ package com.ryankoech.krypto.feature_coin_details.presentation.components.success import android.os.Build -import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.* import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme @@ -15,6 +14,7 @@ import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ryankoech.krypto.common.presentation.theme.Green500 @@ -44,6 +44,7 @@ fun convertLongToTime(time: Long): String { fun TransactionItem( modifier: Modifier = Modifier, transaction: TransactionDto, + symbol : String, ) { val context = LocalContext.current @@ -78,18 +79,23 @@ fun TransactionItem( ) { Text( - text = "${if(isBuyingTransaction) "" else "-"}${ - getFormattedBalance( - context, - transaction.currentPrice * transaction.amount - ) - } ${if(isBuyingTransaction) "bought" else "sold"}", + text = stringResource( + R.string.item_transaction_expenditure, + if(isBuyingTransaction) "" else "-", + getFormattedBalance(context,transaction.currentPrice * transaction.amount), + if(isBuyingTransaction) stringResource(R.string.transaction_type_buy) else stringResource(R.string.transaction_type_sell) + ), style = MaterialTheme.typography.h3, ) Text( modifier = Modifier .alpha(0.6f), - text = "${if (isBuyingTransaction) "+" else "-"}${transaction.amount} BTC", + text = stringResource( + R.string.item_transaction_amount, + if (isBuyingTransaction) "+" else "-", + transaction.amount.toString(), + symbol + ), style = MaterialTheme.typography.body1, ) @@ -145,7 +151,8 @@ fun TransactionItemPreview() { KryptoTheme { Surface { TransactionItem( - transaction = bitCoinTransaction.first() + transaction = bitCoinTransaction.first(), + symbol = "BTC" ) } } diff --git a/feature_coin_details/src/main/res/values/strings.xml b/feature_coin_details/src/main/res/values/strings.xml new file mode 100644 index 0000000..3b6cbae --- /dev/null +++ b/feature_coin_details/src/main/res/values/strings.xml @@ -0,0 +1,24 @@ + + + Coin Statistics + Market Cap + All Time High + 24hr High + Total Volume + Transaction History + Whoops, looks like a ghost town here. + Transfer In + Transfer Out + Jeez, something\'s amiss + Retry + 1h + 1d + 7d + 30d + 90d + 1y + %s%s %s + %s%s %s + bought + sold + \ No newline at end of file From 4b8f53c25e9d041ddfe61d1f7eccfe65adeb8081 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 3 Mar 2023 10:34:18 +0300 Subject: [PATCH 185/201] implement delete transaction --- .../presentation/CoinDetailsScreen.kt | 5 +++- .../presentation/CoinDetailsScreenSuccess.kt | 5 +++- .../components/success/TransactionItem.kt | 30 +++++++++++-------- .../viewmodel/CoinDetailsScreenViewModel.kt | 23 ++++++++++++++ .../data/data_source/local/TransactionDao.kt | 3 ++ .../repository/FakeTransactionRepository.kt | 4 +++ .../repository/TransactionRepositoryImpl.kt | 6 ++++ .../repository/TransactionRepository.kt | 2 ++ .../usecase/DeleteCoinTransactionUseCase.kt | 23 ++++++++++++++ 9 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/DeleteCoinTransactionUseCase.kt diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 9fa769c..227be11 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -117,7 +117,10 @@ fun CoinDetailsScreen( navigateToSellTransactionScreen = navigateToSellTransactionScreen, marketChartData = marketChartData, marketChartButtonOnClick = marketChartButtonOnClick, - currentMarketChartRange = currentMarketChartRange + currentMarketChartRange = currentMarketChartRange, + onDeleteTransactionClick = { date -> + viewModel.deleteCoinTransaction(date) + } ) } diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt index d6dc8b6..0f43ef0 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt @@ -46,6 +46,7 @@ fun CoinDetailsScreenSuccess( marketChartData : List>, marketChartButtonOnClick : (MarketChartRange) -> Unit, currentMarketChartRange : MarketChartRange, + onDeleteTransactionClick : (Long) -> Unit, ) { val context = LocalContext.current @@ -201,7 +202,8 @@ fun CoinDetailsScreenSuccess( ), transaction = transaction, - symbol = coin.symbol + symbol = coin.symbol, + onDeleteTransactionClick = onDeleteTransactionClick ) } @@ -260,6 +262,7 @@ fun CoinDetailsScreenSuccessPreview() { marketChartButtonOnClick = {}, marketChartData = FAKE_LINECHART_DATA, transactions = bitCoinTransaction, + onDeleteTransactionClick = {} ) } } diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt index e36b1c6..dd0d0a4 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt @@ -1,11 +1,9 @@ package com.ryankoech.krypto.feature_coin_details.presentation.components.success import android.os.Build +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface -import androidx.compose.material.Text +import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -45,6 +43,7 @@ fun TransactionItem( modifier: Modifier = Modifier, transaction: TransactionDto, symbol : String, + onDeleteTransactionClick : (Long) -> Unit, ) { val context = LocalContext.current @@ -130,14 +129,20 @@ fun TransactionItem( } } - Spacer(modifier = Modifier.width(16.dp)) + Spacer(modifier = Modifier.width(8.dp)) - Icon( - modifier = Modifier - .size(28.dp), - painter = painterResource(R.drawable.icon_delete), - contentDescription = null, - ) + IconButton( + onClick = { + onDeleteTransactionClick(transaction.date) + } + ) { + Icon( + modifier = Modifier + .size(28.dp), + painter = painterResource(R.drawable.icon_delete), + contentDescription = null, + ) + } } } @@ -152,7 +157,8 @@ fun TransactionItemPreview() { Surface { TransactionItem( transaction = bitCoinTransaction.first(), - symbol = "BTC" + symbol = "BTC", + onDeleteTransactionClick = {} ) } } diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt index 2748f26..d3d0703 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt @@ -8,6 +8,7 @@ import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_details.domain.usecase.GetCoinMarketChartUseCase import com.ryankoech.krypto.feature_coin_details.presentation.viewstate.CoinDetailsScreenViewState +import com.ryankoech.krypto.feature_transaction.domain.usecase.DeleteCoinTransactionUseCase import com.ryankoech.krypto.feature_transaction.domain.usecase.GetCoinTransactionsUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow @@ -20,6 +21,7 @@ import javax.inject.Inject class CoinDetailsScreenViewModel @Inject constructor( private val getCoinMarketChartUseCase: GetCoinMarketChartUseCase, private val getCoinTransactionsUseCase: GetCoinTransactionsUseCase, + private val deleteCoinTransactionUseCase: DeleteCoinTransactionUseCase, ) : ViewModel(){ private val _viewState = mutableStateOf(CoinDetailsScreenViewState()) @@ -80,4 +82,25 @@ class CoinDetailsScreenViewModel @Inject constructor( } + fun deleteCoinTransaction(date : Long) { + + deleteCoinTransactionUseCase(date) + .onEach { res -> + when(res){ + is Resource.Error -> { + _message.emit("An error occurred while deleting the transaction.") + } + is Resource.Loading -> { + // Do nothing + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + transactions = _viewState.value.transactions.filter { it.date != date } + ) + } + } + } + + } + } \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt index 3d9941a..2665715 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/data_source/local/TransactionDao.kt @@ -16,4 +16,7 @@ interface TransactionDao { @Query("SELECT * FROM `$TABLE_NAME_TRANSACTION` WHERE coinId = :coinId ORDER by date DESC") suspend fun getCoinTransactions(coinId : String) : List + @Query("DELETE FROM `$TABLE_NAME_TRANSACTION` WHERE date = :date") + suspend fun deleteTransaction(date : Long) + } \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt index 29950fb..8bf7b16 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/FakeTransactionRepository.kt @@ -37,4 +37,8 @@ class FakeTransactionRepository @Inject constructor() : TransactionRepository { } } + + override suspend fun deleteCoinTransaction(date: Long) { + Timber.d("Deleted transaction: $date") + } } \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt index 24618dc..08e098b 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/data/repository/TransactionRepositoryImpl.kt @@ -19,4 +19,10 @@ class TransactionRepositoryImpl @Inject constructor( override suspend fun getCoinTransactions(coinId: String): List = dao.getCoinTransactions(coinId) + override suspend fun deleteCoinTransaction(date: Long) { + return coroutineScope { + dao.deleteTransaction(date) + } + } + } \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt index 9e39da5..601f3b8 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/repository/TransactionRepository.kt @@ -7,4 +7,6 @@ interface TransactionRepository { suspend fun addTransaction(transaction : TransactionDto) suspend fun getCoinTransactions(coinId : String) : List + + suspend fun deleteCoinTransaction(date : Long) } \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/DeleteCoinTransactionUseCase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/DeleteCoinTransactionUseCase.kt new file mode 100644 index 0000000..6480a84 --- /dev/null +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/DeleteCoinTransactionUseCase.kt @@ -0,0 +1,23 @@ +package com.ryankoech.krypto.feature_transaction.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_transaction.domain.repository.TransactionRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import javax.inject.Inject + +class DeleteCoinTransactionUseCase @Inject constructor( + private val repository: TransactionRepository +) { + operator fun invoke(date : Long) = flow> { + emit( + Resource.Success(repository.deleteCoinTransaction(date)) + ) + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + emit(Resource.Error(e.localizedMessage ?: "An Unknown Error Occurred")) + } + +} \ No newline at end of file From b97f5850ca440e69f6eb6246607bf6d5b84c4b13 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 3 Mar 2023 10:38:19 +0300 Subject: [PATCH 186/201] fix format warnings --- .../presentation/components/success/TransactionItem.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt index dd0d0a4..30f2002 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/components/success/TransactionItem.kt @@ -31,9 +31,9 @@ import java.util.* fun convertLongToTime(time: Long): String { val date = Date(time) val format = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - SimpleDateFormat("MMMM dd YYYY hh:mm:ss aa") + SimpleDateFormat("MMMM dd yyyy hh:mm:ss aa", Locale.ROOT) } else { - SimpleDateFormat("MM-dd-yyyy") + SimpleDateFormat("MM-dd-yyyy", Locale.ROOT) } return format.format(date) } From 832be7c15b0498027d9cc76a94b13ae25d305b1f Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Fri, 3 Mar 2023 11:01:02 +0300 Subject: [PATCH 187/201] minor fixes --- .../presentation/viewmodel/CoinDetailsScreenViewModel.kt | 2 +- .../domain/usecase/DeleteCoinTransactionUseCase.kt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt index d3d0703..d3bf478 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt @@ -99,7 +99,7 @@ class CoinDetailsScreenViewModel @Inject constructor( ) } } - } + }.launchIn(viewModelScope) } diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/DeleteCoinTransactionUseCase.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/DeleteCoinTransactionUseCase.kt index 6480a84..bd744cf 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/DeleteCoinTransactionUseCase.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/domain/usecase/DeleteCoinTransactionUseCase.kt @@ -1,14 +1,16 @@ package com.ryankoech.krypto.feature_transaction.domain.usecase import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL import com.ryankoech.krypto.feature_transaction.domain.repository.TransactionRepository import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.onStart import javax.inject.Inject +import javax.inject.Named class DeleteCoinTransactionUseCase @Inject constructor( - private val repository: TransactionRepository + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: TransactionRepository ) { operator fun invoke(date : Long) = flow> { emit( From e9ae4bdd1a8895dd49304d3b74ced26472dce96c Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Mon, 6 Mar 2023 11:10:54 +0300 Subject: [PATCH 188/201] implement navigation flow along with bottom navigation --- app/build.gradle | 11 + .../krypto/core/logging/CrashAndLog.kt | 2 +- .../krypto/presentation/MainActivity.kt | 204 +++++++++++++++++- .../krypto/presentation/utils/Screens.kt | 18 ++ .../presentation/viewmodel/MainViewModel.kt | 26 +++ app/src/main/res/drawable/icon_bar_graph.xml | 15 ++ app/src/main/res/drawable/icon_home.xml | 14 ++ app/src/main/res/drawable/icon_settings.xml | 10 + app/src/main/res/values/strings.xml | 6 + build.gradle | 1 + .../domain/entity/Util.kt | 13 ++ .../presentation/CoinDetailsScreen.kt | 9 +- .../presentation/CoinDetailsScreenSuccess.kt | 14 +- .../presentation/CoinListScreen.kt | 3 +- .../presentation/CoinListScreenSuccess.kt | 2 +- .../components/success/CoinItem.kt | 4 +- .../choose_asset/ChooseAssetScreen.kt | 13 +- .../choose_asset/ChooseAssetScreenSuccess.kt | 2 +- .../components/success/ChooseAssetItem.kt | 4 +- .../transaction/TransactionScreen.kt | 9 +- 20 files changed, 351 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/ryankoech/krypto/presentation/utils/Screens.kt create mode 100644 app/src/main/java/com/ryankoech/krypto/presentation/viewmodel/MainViewModel.kt create mode 100644 app/src/main/res/drawable/icon_bar_graph.xml create mode 100644 app/src/main/res/drawable/icon_home.xml create mode 100644 app/src/main/res/drawable/icon_settings.xml create mode 100644 feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/Util.kt diff --git a/app/build.gradle b/app/build.gradle index 09c3372..9cfc03a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,9 +58,20 @@ dependencies { implementation "androidx.compose.material:material:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation "androidx.activity:activity-compose:$compose_activity_version" + implementation "androidx.navigation:navigation-compose:$navigation_compose_version" // local modules implementation project(":common") + implementation project(":feature_transaction") + implementation project(":feature_coin_list") + implementation project(":feature_coin_details") + implementation project(":feature_home") + + // dagger-hilt - for dependency injection + implementation "com.google.dagger:hilt-android:$hilt_android_version" + implementation "androidx.hilt:hilt-navigation-compose:$hilt_navigation_compose_version" + kapt "com.google.dagger:hilt-android-compiler:$hilt_android_compile_version" + kapt "androidx.hilt:hilt-compiler:$hilt_compile_version" // dagger-hilt - for dependency injection implementation "com.google.dagger:hilt-android:$hilt_android_version" diff --git a/app/src/main/java/com/ryankoech/krypto/core/logging/CrashAndLog.kt b/app/src/main/java/com/ryankoech/krypto/core/logging/CrashAndLog.kt index 6fb49f7..5f68198 100644 --- a/app/src/main/java/com/ryankoech/krypto/core/logging/CrashAndLog.kt +++ b/app/src/main/java/com/ryankoech/krypto/core/logging/CrashAndLog.kt @@ -8,7 +8,7 @@ object CrashAndLog { if (BuildConfig.DEBUG) { Timber.plant(object : Timber.DebugTree() { override fun createStackElementTag(element: StackTraceElement): String? { - return "(${element.fileName}:${element.lineNumber})#${element.methodName}" + return "Timber: (${element.fileName}:${element.lineNumber})#${element.methodName}" } }) } else { diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt index d5d0afd..7641576 100644 --- a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt +++ b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt @@ -4,13 +4,34 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface -import androidx.compose.material.Text +import androidx.compose.foundation.layout.padding +import androidx.compose.material.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavDestination.Companion.hierarchy +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument import com.ryankoech.krypto.common.presentation.theme.KryptoTheme +import com.ryankoech.krypto.feature_coin_details.presentation.CoinDetailsScreen +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin as CoinListCoin +import com.ryankoech.krypto.feature_coin_list.presentation.CoinListScreen +import com.ryankoech.krypto.feature_home.presentation.HomeScreen +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin as TransactionCoin +import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.ChooseAssetScreen +import com.ryankoech.krypto.feature_transaction.presentation.transaction.TransactionScreen +import com.ryankoech.krypto.presentation.utils.Screens +import com.ryankoech.krypto.presentation.viewmodel.MainViewModel import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -18,13 +39,182 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { + val viewModel = hiltViewModel() + val navController = rememberNavController() + + val items = listOf( + Screens.Home, + Screens.CoinList, + Screens.Settings + ) + + fun navigateToTransactionScreen(coin : TransactionCoin, transactionType: String) { + viewModel.addTransactionCoin(coin) + navController.navigate(Screens.Transaction.route + "/$transactionType"){ + launchSingleTop = true + } + } + + fun navigateToChooseAssetScreen(transactionType: String) { + navController.navigate(Screens.ChooseAsset.route + "/$transactionType"){ + launchSingleTop = true + } + } + + fun navigateToHomeScreen() { + navController.navigate(Screens.Home.route) { + // Pop up to the start destination of the graph to + // avoid building up a large stack of destinations + // on the back stack as users select items + popUpTo(navController.graph.findStartDestination().id) { + saveState = true + } + // Avoid multiple copies of the same destination when + // reselecting the same item + launchSingleTop = true + // Restore state when reselecting a previously selected item + restoreState = true + } + } + + fun navigateToCoinDetails(coin : CoinListCoin) { + viewModel.addCoinListCoin(coin) + navController.navigate(Screens.CoinDetails.route){ + launchSingleTop = true + } + } + + KryptoTheme { // A surface container using the 'background' color from the theme - Surface( + Scaffold( modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colors.background - ) { - Greeting("Android") + bottomBar = { + BottomNavigation { + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentDestination = navBackStackEntry?.destination + items.forEach { screen -> + BottomNavigationItem( + icon = { Icon(painterResource(screen.iconResId), contentDescription = null) }, + label = { Text(stringResource(screen.labelResId)) }, + selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true, + onClick = { + navController.navigate(screen.route) { + // Pop up to the start destination of the graph to + // avoid building up a large stack of destinations + // on the back stack as users select items + popUpTo(navController.graph.findStartDestination().id) { + saveState = true + } + // Avoid multiple copies of the same destination when + // reselecting the same item + launchSingleTop = true + // Restore state when reselecting a previously selected item + restoreState = true + } + } + ) + } + } + } + + ) { innerPadding -> + Surface( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding), + color = MaterialTheme.colors.background + ) { + + NavHost(navController = navController, startDestination = "home") { + + composable(Screens.Home.route) { + HomeScreen( + onTransferInClick = { + navigateToChooseAssetScreen(TransactionType.BUY.toString()) + }, + onTransferOutClick = { + navigateToChooseAssetScreen(TransactionType.SELL.toString()) + } + ) + } + + composable( + Screens.ChooseAsset.route + "/{transactionType}", + arguments = listOf( + navArgument("transactionType") { + type = NavType.StringType + defaultValue = TransactionType.BUY.toString() + } + ) + ) { backStackEntry -> + ChooseAssetScreen( + toTransactionScreen = ::navigateToTransactionScreen, + toTransactionType = backStackEntry.arguments?.getString("transactionType")!! + ) + } + + composable( + Screens.Transaction.route + "/{transactionType}", + arguments = listOf( + navArgument("transactionType") { + type = NavType.StringType + defaultValue = TransactionType.BUY.toString() + } + ) + ) { backStackEntry -> + + val coin = viewModel.transactionCoin + + coin?.apply { + TransactionScreen( + coin = coin, + navigateBackToHomeScreen = ::navigateToHomeScreen, + transactionType = backStackEntry.arguments?.getString("transactionType")!! + ) + return@composable + } + + // Fall back error screen + } + + composable(Screens.CoinList.route){ + CoinListScreen( + coinItemOnClick = ::navigateToCoinDetails + ) + } + + composable(Screens.CoinDetails.route){ + + val coin = viewModel.coinListCoin + + coin?.apply { + CoinDetailsScreen( + coin = coin, + navigateToBuyTransactionScreen = { transactionCoin -> + navigateToTransactionScreen(transactionCoin, TransactionType.BUY.toString()) + }, + navigateToSellTransactionScreen = { transactionCoin -> + navigateToTransactionScreen(transactionCoin, TransactionType.SELL.toString()) + } + ) + return@composable + } + + // Fallback error screen + + } + + + composable(Screens.Settings.route){ + Text( + text = "Settings" + ) + } + + + } + } } } } diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/utils/Screens.kt b/app/src/main/java/com/ryankoech/krypto/presentation/utils/Screens.kt new file mode 100644 index 0000000..3f18e50 --- /dev/null +++ b/app/src/main/java/com/ryankoech/krypto/presentation/utils/Screens.kt @@ -0,0 +1,18 @@ +package com.ryankoech.krypto.presentation.utils + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import com.ryankoech.krypto.R + +sealed class Screens( + val route : String, + @StringRes val labelResId : Int, + @DrawableRes val iconResId : Int = R.drawable.icon_home +) { + object Home : Screens("home", R.string.screen_label_home, R.drawable.icon_home) + object ChooseAsset : Screens("choose-asset", R.string.screen_label_choose_asset) + object Transaction : Screens("transaction", R.string.screen_label_transaction) + object CoinList : Screens("coin-list", R.string.screen_label_coin_list, R.drawable.icon_bar_graph) + object CoinDetails : Screens("coin-details", R.string.screen_label_coin_details) + object Settings : Screens("settings", R.string.screen_label_settings, R.drawable.icon_settings) +} diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/viewmodel/MainViewModel.kt b/app/src/main/java/com/ryankoech/krypto/presentation/viewmodel/MainViewModel.kt new file mode 100644 index 0000000..7941366 --- /dev/null +++ b/app/src/main/java/com/ryankoech/krypto/presentation/viewmodel/MainViewModel.kt @@ -0,0 +1,26 @@ +package com.ryankoech.krypto.presentation.viewmodel + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin as TransactionCoin +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin as CoinListCoin +import javax.inject.Inject + +class MainViewModel @Inject constructor() : ViewModel(){ + + var coinListCoin by mutableStateOf(null) + private set + + var transactionCoin by mutableStateOf(null) + private set + + fun addCoinListCoin(coin : CoinListCoin) { + coinListCoin = coin + } + + fun addTransactionCoin(coin: TransactionCoin){ + transactionCoin = coin + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_bar_graph.xml b/app/src/main/res/drawable/icon_bar_graph.xml new file mode 100644 index 0000000..97c62b8 --- /dev/null +++ b/app/src/main/res/drawable/icon_bar_graph.xml @@ -0,0 +1,15 @@ + + + + + + diff --git a/app/src/main/res/drawable/icon_home.xml b/app/src/main/res/drawable/icon_home.xml new file mode 100644 index 0000000..445eff2 --- /dev/null +++ b/app/src/main/res/drawable/icon_home.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/app/src/main/res/drawable/icon_settings.xml b/app/src/main/res/drawable/icon_settings.xml new file mode 100644 index 0000000..61ab0b9 --- /dev/null +++ b/app/src/main/res/drawable/icon_settings.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 18ae2a2..75aa1e1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,9 @@ Krypto + Home + ChooseAsset + Transaction + CoinList + CoinDetails + Settings \ No newline at end of file diff --git a/build.gradle b/build.gradle index 39115a3..a3c74ec 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ buildscript { okhttp_logging_interceptor_version = '5.0.0-alpha.9' retrofit_version = '2.9.0' accompanist_version = '0.28.0' + navigation_compose_version = '2.5.3' } dependencies { classpath "com.google.dagger:hilt-android-gradle-plugin:2.42" diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/Util.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/Util.kt new file mode 100644 index 0000000..ec9679a --- /dev/null +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/entity/Util.kt @@ -0,0 +1,13 @@ +package com.ryankoech.krypto.feature_coin_details.domain.entity + +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin as TransactionCoin +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin as CoinListCoin + +fun CoinListCoin.toTransactionCoin() : TransactionCoin = + TransactionCoin( + id = id, + symbol = symbol, + name = name, + image = image, + price = price + ) \ No newline at end of file diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 227be11..098be2a 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -15,15 +15,16 @@ import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRa import com.ryankoech.krypto.feature_coin_details.presentation.viewmodel.CoinDetailsScreenViewModel import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST -import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin as TransactionCoin +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin as CoinListCoin import timber.log.Timber @Composable fun CoinDetailsScreen( viewModel : CoinDetailsScreenViewModel = hiltViewModel(), - coin : Coin, - navigateToBuyTransactionScreen : (String) -> Unit, - navigateToSellTransactionScreen : (String) -> Unit, + coin : CoinListCoin, + navigateToBuyTransactionScreen : (TransactionCoin) -> Unit, + navigateToSellTransactionScreen : (TransactionCoin) -> Unit, modifier: Modifier = Modifier ) { diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt index 0f43ef0..8f771c8 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreenSuccess.kt @@ -27,22 +27,24 @@ import com.ryankoech.krypto.common.presentation.util.getFormattedBalance import com.ryankoech.krypto.common.presentation.util.getFormattedMarketCap import com.ryankoech.krypto.common.presentation.util.getFormattedTotalVolume import com.ryankoech.krypto.feature_coin_details.R +import com.ryankoech.krypto.feature_coin_details.domain.entity.toTransactionCoin import com.ryankoech.krypto.feature_coin_details.presentation.components.success.* import com.ryankoech.krypto.feature_coin_details.presentation.util.CoinStatistic import com.ryankoech.krypto.feature_coin_details.presentation.util.MarketChartRange import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST -import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin as CoinListCoin import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto import com.ryankoech.krypto.feature_transaction.data.repository.bitCoinTransaction +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin as TransactionCoin @Composable fun CoinDetailsScreenSuccess( modifier : Modifier = Modifier, - coin : Coin, + coin : CoinListCoin, transactions : List, - navigateToBuyTransactionScreen : (String) -> Unit, - navigateToSellTransactionScreen : (String) -> Unit, + navigateToBuyTransactionScreen : (TransactionCoin) -> Unit, + navigateToSellTransactionScreen : (TransactionCoin) -> Unit, marketChartData : List>, marketChartButtonOnClick : (MarketChartRange) -> Unit, currentMarketChartRange : MarketChartRange, @@ -224,7 +226,7 @@ fun CoinDetailsScreenSuccess( .weight(1.0f), text = stringResource(R.string.button_transfer_in), onClick = { - navigateToBuyTransactionScreen(coin.id) + navigateToBuyTransactionScreen(coin.toTransactionCoin()) } ) @@ -235,7 +237,7 @@ fun CoinDetailsScreenSuccess( .weight(1.0f), text = stringResource(R.string.button_transfer_out), onClick = { - navigateToSellTransactionScreen(coin.id) + navigateToSellTransactionScreen(coin.toTransactionCoin()) }, color = Red100 ) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index fbc2501..4d31c9d 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import com.ryankoech.krypto.feature_coin_list.domain.entity.Order import com.ryankoech.krypto.feature_coin_list.domain.entity.SortCoinBy import com.ryankoech.krypto.feature_coin_list.domain.entity.SortInfo @@ -26,7 +27,7 @@ import timber.log.Timber @OptIn(ExperimentalMaterialApi::class) @Composable fun CoinListScreen( - coinItemOnClick : (String) -> Unit, + coinItemOnClick : (Coin) -> Unit, viewModel: CoinListScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index 86e5bdc..4871b7e 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -26,7 +26,7 @@ const val TEST_TAG_COIN_LIST_SCREEN_SUCCESS_COINS_LAZY_COLUMN = "test tag coin l @Composable fun CoinListScreenSuccess( - coinItemOnClick : (String) -> Unit, + coinItemOnClick : (Coin) -> Unit, screenState : ScreenState, editSortInfo : (SortCoinBy) -> Unit, sortInfoState : SortInfo, diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt index 23f408f..9cf3702 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt @@ -29,7 +29,7 @@ import com.ryankoech.krypto.feature_coin_list.presentation.theme.black200 @Composable fun CoinItem( - onClick : (String) -> Unit, + onClick : (Coin) -> Unit, coin: Coin, modifier: Modifier = Modifier ) { @@ -45,7 +45,7 @@ fun CoinItem( shape = RoundedCornerShape(10.dp) ) .clickable { - onClick(coin.id) + onClick(coin) }, ) { CoinImage(coin.image, coin.id) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt index b9f3c90..cfd5a46 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreen.kt @@ -7,10 +7,14 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType +import com.ryankoech.krypto.feature_transaction.domain.entity.Coin import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.viewmodel.ChooseAssetScreenViewModel @Composable fun ChooseAssetScreen( + toTransactionScreen : (Coin, String) -> Unit, + toTransactionType: String, viewModel : ChooseAssetScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { @@ -41,7 +45,9 @@ fun ChooseAssetScreen( ChooseAssetScreenSuccess( modifier = modifier, - onChooseAssetItemClick = {}, + onChooseAssetItemClick = { coin -> + toTransactionScreen(coin, toTransactionType) + }, coins = viewState.coins, searchValue = searchValue, onSearchValueChange = ::editSearchValueState @@ -58,7 +64,10 @@ fun PreviewChooseAssetScreen() { KryptoTheme { Surface { - ChooseAssetScreen() + ChooseAssetScreen( + { _, _ -> }, + TransactionType.BUY.toString(), + ) } } diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenSuccess.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenSuccess.kt index 1ad65fd..1d05b09 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenSuccess.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/ChooseAssetScreenSuccess.kt @@ -21,7 +21,7 @@ import com.ryankoech.krypto.feature_transaction.presentation.choose_asset.compon @Composable fun ChooseAssetScreenSuccess( - onChooseAssetItemClick : (String) -> Unit, + onChooseAssetItemClick : (Coin) -> Unit, coins : List, searchValue : String, onSearchValueChange : (String) -> Unit, diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt index 5ed6d31..a6b0daf 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/choose_asset/components/success/ChooseAssetItem.kt @@ -21,7 +21,7 @@ import com.ryankoech.krypto.feature_transaction.domain.entity.Coin @Composable fun ChooseAssetItem( - onClick : (String) -> Unit, + onClick : (Coin) -> Unit, coin: Coin, modifier: Modifier = Modifier ) { @@ -34,7 +34,7 @@ fun ChooseAssetItem( Color(0xfff6f6f6) ) .clickable { - onClick(coin.id) + onClick(coin) }, verticalAlignment = Alignment.CenterVertically, ) { diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt index b4be06f..434ed5b 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/TransactionScreen.kt @@ -25,6 +25,7 @@ import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_transaction.R import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto +import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType import com.ryankoech.krypto.feature_transaction.domain.entity.Coin import com.ryankoech.krypto.feature_transaction.domain.entity.toCoinEntity import com.ryankoech.krypto.feature_transaction.presentation.transaction.components.BuyTransactionScreen @@ -39,6 +40,7 @@ import java.util.* fun TransactionScreen( coin : Coin, navigateBackToHomeScreen : () -> Unit, + transactionType: String, viewModel : TransactionScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { @@ -91,7 +93,9 @@ fun TransactionScreen( ), ) - val pagerState = rememberPagerState() + val pagerState = rememberPagerState( + if(transactionType == TransactionType.BUY.toString()) 0 else 1 + ) val coroutineScope = rememberCoroutineScope() Column( @@ -148,7 +152,8 @@ fun TransactionScreenPreview() { Surface { TransactionScreen( FAKE_COIN_LIST.toCoinEntity().first(), - {} + {}, + TransactionType.SELL.toString() ) } } From aa211727ce6b21fa9f724a56291deb078eb7f30e Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 8 Mar 2023 12:43:47 +0300 Subject: [PATCH 189/201] implement top app bar --- .../krypto/presentation/MainActivity.kt | 46 ++++++++++++++++--- .../krypto/presentation/utils/Screens.kt | 42 ++++++++++++++--- app/src/main/res/drawable/icon_arrow_left.xml | 10 ++++ app/src/main/res/values/strings.xml | 8 +++- 4 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 app/src/main/res/drawable/icon_arrow_left.xml diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt index 7641576..99cece6 100644 --- a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt +++ b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt @@ -6,8 +6,7 @@ import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -21,6 +20,7 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument +import com.ryankoech.krypto.R import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.feature_coin_details.presentation.CoinDetailsScreen import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin as CoinListCoin @@ -42,7 +42,14 @@ class MainActivity : ComponentActivity() { val viewModel = hiltViewModel() val navController = rememberNavController() - val items = listOf( + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentDestination = navBackStackEntry?.destination + + var topBarTitle by remember { + mutableStateOf("") + } + + val bottomNavigationItems = listOf( Screens.Home, Screens.CoinList, Screens.Settings @@ -89,11 +96,32 @@ class MainActivity : ComponentActivity() { // A surface container using the 'background' color from the theme Scaffold( modifier = Modifier.fillMaxSize(), + topBar = { + TopAppBar( + title = { + Text( + text = topBarTitle, + style = MaterialTheme.typography.h1 + ) + }, + navigationIcon = + if (bottomNavigationItems.none { it.route == currentDestination?.route }) { + { + IconButton(onClick = { + navController.popBackStack() + }) { + Icon( + painter = painterResource(R.drawable.icon_arrow_left), + contentDescription = "Go back" + ) + } + } + } else null, + ) + }, bottomBar = { BottomNavigation { - val navBackStackEntry by navController.currentBackStackEntryAsState() - val currentDestination = navBackStackEntry?.destination - items.forEach { screen -> + bottomNavigationItems.forEach { screen -> BottomNavigationItem( icon = { Icon(painterResource(screen.iconResId), contentDescription = null) }, label = { Text(stringResource(screen.labelResId)) }, @@ -129,6 +157,7 @@ class MainActivity : ComponentActivity() { NavHost(navController = navController, startDestination = "home") { composable(Screens.Home.route) { + topBarTitle = stringResource(Screens.Home.titleResId) HomeScreen( onTransferInClick = { navigateToChooseAssetScreen(TransactionType.BUY.toString()) @@ -148,6 +177,7 @@ class MainActivity : ComponentActivity() { } ) ) { backStackEntry -> + topBarTitle = stringResource(Screens.ChooseAsset.titleResId) ChooseAssetScreen( toTransactionScreen = ::navigateToTransactionScreen, toTransactionType = backStackEntry.arguments?.getString("transactionType")!! @@ -163,6 +193,7 @@ class MainActivity : ComponentActivity() { } ) ) { backStackEntry -> + topBarTitle = stringResource(Screens.Transaction.titleResId) val coin = viewModel.transactionCoin @@ -179,12 +210,14 @@ class MainActivity : ComponentActivity() { } composable(Screens.CoinList.route){ + topBarTitle = stringResource(Screens.CoinList.titleResId) CoinListScreen( coinItemOnClick = ::navigateToCoinDetails ) } composable(Screens.CoinDetails.route){ + topBarTitle = stringResource(Screens.CoinDetails.titleResId) val coin = viewModel.coinListCoin @@ -207,6 +240,7 @@ class MainActivity : ComponentActivity() { composable(Screens.Settings.route){ + topBarTitle = stringResource(Screens.Settings.titleResId) Text( text = "Settings" ) diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/utils/Screens.kt b/app/src/main/java/com/ryankoech/krypto/presentation/utils/Screens.kt index 3f18e50..7c3fbcc 100644 --- a/app/src/main/java/com/ryankoech/krypto/presentation/utils/Screens.kt +++ b/app/src/main/java/com/ryankoech/krypto/presentation/utils/Screens.kt @@ -7,12 +7,40 @@ import com.ryankoech.krypto.R sealed class Screens( val route : String, @StringRes val labelResId : Int, - @DrawableRes val iconResId : Int = R.drawable.icon_home + @DrawableRes val iconResId : Int = R.drawable.icon_home, + @StringRes val titleResId : Int = R.string.app_name, ) { - object Home : Screens("home", R.string.screen_label_home, R.drawable.icon_home) - object ChooseAsset : Screens("choose-asset", R.string.screen_label_choose_asset) - object Transaction : Screens("transaction", R.string.screen_label_transaction) - object CoinList : Screens("coin-list", R.string.screen_label_coin_list, R.drawable.icon_bar_graph) - object CoinDetails : Screens("coin-details", R.string.screen_label_coin_details) - object Settings : Screens("settings", R.string.screen_label_settings, R.drawable.icon_settings) + object Home : Screens( + route = "home", + labelResId = R.string.screen_label_home, + iconResId = R.drawable.icon_home, + titleResId = R.string.screen_title_home + ) + object ChooseAsset : Screens( + route = "choose-asset", + labelResId = R.string.screen_label_choose_asset, + titleResId = R.string.screen_title_choose_asset + ) + object Transaction : Screens( + route = "transaction", + labelResId = R.string.screen_label_transaction, + titleResId = R.string.screen_title_transaction + ) + object CoinList : Screens( + route = "coin-list", + labelResId = R.string.screen_label_coin_list, + iconResId = R.drawable.icon_bar_graph, + titleResId = R.string.screen_title_coin_list + ) + object CoinDetails : Screens( + route = "coin-details", + labelResId = R.string.screen_label_coin_details, + titleResId = R.string.screen_title_coin_details + ) + object Settings : Screens( + route = "settings", + labelResId = R.string.screen_label_settings, + iconResId = R.drawable.icon_settings, + titleResId = R.string.screen_title_settings + ) } diff --git a/app/src/main/res/drawable/icon_arrow_left.xml b/app/src/main/res/drawable/icon_arrow_left.xml new file mode 100644 index 0000000..12332a4 --- /dev/null +++ b/app/src/main/res/drawable/icon_arrow_left.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 75aa1e1..ae70760 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,7 +3,13 @@ Home ChooseAsset Transaction - CoinList + Assets CoinDetails Settings + Home + Choose an Asset + Transaction + Cryptoassets + Asset Overview + Settings \ No newline at end of file From 26a1abe100cf54d67e72b7cfa1092fbbd8286bc5 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 8 Mar 2023 12:48:14 +0300 Subject: [PATCH 190/201] fix navigation bug --- .../com/ryankoech/krypto/presentation/MainActivity.kt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt index 99cece6..35f6ef5 100644 --- a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt +++ b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt @@ -70,17 +70,10 @@ class MainActivity : ComponentActivity() { fun navigateToHomeScreen() { navController.navigate(Screens.Home.route) { - // Pop up to the start destination of the graph to - // avoid building up a large stack of destinations - // on the back stack as users select items popUpTo(navController.graph.findStartDestination().id) { - saveState = true + inclusive = true } - // Avoid multiple copies of the same destination when - // reselecting the same item launchSingleTop = true - // Restore state when reselecting a previously selected item - restoreState = true } } From 5608649a3440b29ff8e0cbdd5adea7ff1c29475d Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Wed, 8 Mar 2023 13:00:33 +0300 Subject: [PATCH 191/201] remove redundant clickable --- .../presentation/components/success/HomeScreenActions.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenActions.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenActions.kt index fb57d46..71d1d87 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenActions.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenActions.kt @@ -79,9 +79,6 @@ fun HomeScreenActionItem( shape = MaterialTheme.shapes.small, color = color ) - .clickable { - onClick() - } ) { IconButton( From 3c217939b82145545f768525945497aa54c029a2 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 10:31:04 +0300 Subject: [PATCH 192/201] add check for zero amount --- .../presentation/transaction/components/BuyTransactionScreen.kt | 2 +- .../transaction/components/SellTransactionScreen.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt index d649dd0..1a8b65b 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/BuyTransactionScreen.kt @@ -158,7 +158,7 @@ fun BuyTransactionScreen( modifier = Modifier .fillMaxWidth(), text = stringResource(R.string.button_label_buy, coin.name), - enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null, + enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null && enteredQuantity.toDouble() > 0, onClick = onClick@{ if(enteredQuantity.toDoubleOrNull().isNull()){ diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt index c7dd0ed..13fc4ad 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/components/SellTransactionScreen.kt @@ -183,7 +183,7 @@ fun SellTransactionScreen( .fillMaxWidth(), text = stringResource(R.string.button_label_sell, coin.name), color = Red200, - enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null, + enabled = screenState == ScreenState.SUCCESS && enteredQuantity.toDoubleOrNull() != null && enteredQuantity.toDouble() > 0, onClick = onClick@{ if(enteredQuantity.toDoubleOrNull().isNull()){ From 3c6129a7d66ac458d3ca9cc9724f7c673eef059e Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 10:31:44 +0300 Subject: [PATCH 193/201] fix zero amount owned coins bug --- .../data_source/local/db/OwnedCoinsDao.kt | 3 ++ .../FakeOwnedCoinsRepositoryImpl.kt | 4 +++ .../repository/OwnedCoinsRepositoryImpl.kt | 6 ++++ .../domain/repository/OwnedCoinsRepository.kt | 2 ++ .../domain/usecase/DeleteOwnedCoinUseCase.kt | 24 ++++++++++++++ .../viewmodel/TransactionScreenViewModel.kt | 32 ++++++++++++++++++- 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/DeleteOwnedCoinUseCase.kt diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt index 9f30726..b3832ee 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/data_source/local/db/OwnedCoinsDao.kt @@ -18,4 +18,7 @@ interface OwnedCoinsDao { @Query("SELECT * FROM $OWNED_COIN_DTO_TABLENAME WHERE id = :coinId") suspend fun getOwnedCoin(coinId : String) : OwnedCoinDto? + + @Query("DELETE FROM $OWNED_COIN_DTO_TABLENAME WHERE id = :coinId") + suspend fun deleteOwnedCoin(coinId: String) } \ No newline at end of file diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/FakeOwnedCoinsRepositoryImpl.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/FakeOwnedCoinsRepositoryImpl.kt index 2f325d3..86f197f 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/FakeOwnedCoinsRepositoryImpl.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/FakeOwnedCoinsRepositoryImpl.kt @@ -102,4 +102,8 @@ class FakeOwnedCoinsRepositoryImpl @Inject constructor() : OwnedCoinsRepository Timber.d("Database cleared") } + override suspend fun deleteOwnedCoin(coinId: String) { + Timber.d("Coin : $coinId has been deleted") + } + } \ No newline at end of file diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt index f076521..eb480f2 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt @@ -55,4 +55,10 @@ class OwnedCoinsRepositoryImpl @Inject constructor( } } + override suspend fun deleteOwnedCoin(coinId: String) { + return coroutineScope { + coinsDao.deleteOwnedCoin(coinId) + } + } + } \ No newline at end of file diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt index a9f5532..5ec5023 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/repository/OwnedCoinsRepository.kt @@ -17,4 +17,6 @@ interface OwnedCoinsRepository { suspend fun getDisplayCurrencyData() : List? suspend fun wipeDatabase() + + suspend fun deleteOwnedCoin(coinId : String) } \ No newline at end of file diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/DeleteOwnedCoinUseCase.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/DeleteOwnedCoinUseCase.kt new file mode 100644 index 0000000..e9f689b --- /dev/null +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/domain/usecase/DeleteOwnedCoinUseCase.kt @@ -0,0 +1,24 @@ +package com.ryankoech.krypto.feature_home.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_home.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_home.domain.repository.OwnedCoinsRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import javax.inject.Inject +import javax.inject.Named + +class DeleteOwnedCoinUseCase @Inject constructor( + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: OwnedCoinsRepository, +){ + + operator fun invoke(coinId : String) = flow>{ + emit(Resource.Success(repository.deleteOwnedCoin(coinId))) + }.onStart { + emit(Resource.Loading()) + }.catch {e -> + emit(Resource.Error(e.localizedMessage ?: "An Unknown Error Occurred")) + } + +} \ No newline at end of file diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt index 47e75a2..2c398a1 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_home.domain.usecase.DeleteOwnedCoinUseCase import com.ryankoech.krypto.feature_home.domain.usecase.GetOwnedCoinUseCase import com.ryankoech.krypto.feature_home.domain.usecase.SaveOwnedCoinUseCase import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto @@ -22,7 +23,8 @@ import javax.inject.Inject class TransactionScreenViewModel @Inject constructor( private val saveCoinTransactionUseCase: SaveCoinTransactionUseCase, private val getOwnedCoinUseCase : GetOwnedCoinUseCase, - private val saveOwnedCoinUseCase: SaveOwnedCoinUseCase + private val saveOwnedCoinUseCase: SaveOwnedCoinUseCase, + private val deleteOwnedCoinUseCase: DeleteOwnedCoinUseCase, ) : ViewModel() { private val _viewState = mutableStateOf(TransactionScreenViewState()) @@ -68,6 +70,34 @@ class TransactionScreenViewModel @Inject constructor( ) ) + if(_viewState.value.ownedCoin.amount <= 0) { + + deleteOwnedCoinUseCase(_viewState.value.ownedCoin.id) + .onEach { res -> + when(res) { + is Resource.Error -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR + ) + } + is Resource.Loading -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING + ) + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.SUCCESS + ) + insertTransaction(transaction) + } + } + }.launchIn(viewModelScope) + + return + + } + saveOwnedCoinUseCase(_viewState.value.ownedCoin) .onEach { res -> when(res) { From 1344e06823edd233ed8d03d754b253275f23e289 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 11:18:07 +0300 Subject: [PATCH 194/201] fix coin change calculation --- .../transaction/viewmodel/TransactionScreenViewModel.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt index 2c398a1..ff5048a 100644 --- a/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt +++ b/feature_transaction/src/main/java/com/ryankoech/krypto/feature_transaction/presentation/transaction/viewmodel/TransactionScreenViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.common.presentation.util.ScreenState +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import com.ryankoech.krypto.feature_home.domain.usecase.DeleteOwnedCoinUseCase import com.ryankoech.krypto.feature_home.domain.usecase.GetOwnedCoinUseCase import com.ryankoech.krypto.feature_home.domain.usecase.SaveOwnedCoinUseCase @@ -58,6 +59,10 @@ class TransactionScreenViewModel @Inject constructor( fun saveCoinTransaction (transaction : TransactionDto) { + Timber.d(transaction.currentPrice.toString()) + Timber.d(_viewState.value.ownedCoin.value.toString()) + Timber.d(((transaction.currentPrice - _viewState.value.ownedCoin.value) / (_viewState.value.ownedCoin.value) * 100).toFloat().toString()) + _viewState.value = _viewState.value.copy( ownedCoin = _viewState.value.ownedCoin.copy( amount = if( transaction.transactionType == TransactionType.BUY) { @@ -66,7 +71,7 @@ class TransactionScreenViewModel @Inject constructor( _viewState.value.ownedCoin.amount - transaction.amount }, value = transaction.currentPrice, - change = (transaction.currentPrice - _viewState.value.ownedCoin.value / _viewState.value.ownedCoin.value * 100).toFloat() + change = ((transaction.currentPrice - _viewState.value.ownedCoin.value) / (_viewState.value.ownedCoin.value) * 100 ).toFloat() ) ) From 2a77a73be38f6ca285dfb236236d591795a99be8 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 13:29:13 +0300 Subject: [PATCH 195/201] implement cache in use case --- .../usecase/GetCoinMarketChartUseCase.kt | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChartUseCase.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChartUseCase.kt index 3f107d4..ab0b83b 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChartUseCase.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/domain/usecase/GetCoinMarketChartUseCase.kt @@ -1,5 +1,6 @@ package com.ryankoech.krypto.feature_coin_details.domain.usecase +import com.ryankoech.krypto.common.core.ktx.isNotNull import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.feature_coin_details.core.di.HILT_NAME_REPO_FOR_ALL import com.ryankoech.krypto.feature_coin_details.data.dto.market_chart_dto.toMarketChartEntityList @@ -9,15 +10,25 @@ import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.onStart import timber.log.Timber +import java.util.* import javax.inject.Inject import javax.inject.Named class GetCoinMarketChartUseCase @Inject constructor( @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinDetailsRepository ) { + private var cacheCoinId : String? = null + private var cacheChartEntities : List>? = null operator fun invoke(coinId : String) = flow>>> { + if(cacheCoinId.isNotNull() && cacheCoinId == coinId && !cacheChartEntities.isNullOrEmpty()){ + emit(Resource.Success( + cacheChartEntities!! + )) + return@flow + } + val dayMarketChartResponse = repository.getDayMarketChart(coinId) val threeMonthMarketChartResponse = repository.getThreeMonthsMarketChart(coinId) val yearMarketChartResponse = repository.getYearMarketChart(coinId) @@ -28,12 +39,23 @@ class GetCoinMarketChartUseCase @Inject constructor( val threeMonthMarketChartEntity = threeMonthMarketChartResponse.body()!!.toMarketChartEntityList() val yearMarketChartEntity = yearMarketChartResponse.body()!!.toMarketChartEntityList() + // Clear cache after 1 minute + Timer().schedule(object : TimerTask() { + override fun run() { + cacheChartEntities = null + cacheCoinId = null + } + }, 60_000) + + cacheChartEntities = listOf( + dayMarketChartEntity, + threeMonthMarketChartEntity, + yearMarketChartEntity + ) + cacheCoinId = coinId + emit(Resource.Success( - listOf( - dayMarketChartEntity, - threeMonthMarketChartEntity, - yearMarketChartEntity - ) + cacheChartEntities!! )) } else { throw Exception("Response not Successful.") From 39cb9ccf21da91288f8ce89672962e0fcc33cf49 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 14:05:52 +0300 Subject: [PATCH 196/201] refactored passing coin to passing coinId coin details screen --- .../krypto/presentation/MainActivity.kt | 41 +++++++++---------- .../presentation/viewmodel/MainViewModel.kt | 7 ---- .../presentation/CoinDetailsScreen.kt | 12 +++--- .../viewmodel/CoinDetailsScreenViewModel.kt | 33 ++++++++++++++- .../viewstate/CoinDetailsScreenViewState.kt | 2 + .../data/dto/CoinLocalDto.kt | 18 +++++++- .../domain/usecase/GetLocalCoinUseCase.kt | 29 +++++++++++++ .../presentation/CoinListScreen.kt | 2 +- .../presentation/CoinListScreenSuccess.kt | 2 +- .../components/success/CoinItem.kt | 4 +- 10 files changed, 109 insertions(+), 41 deletions(-) create mode 100644 feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinUseCase.kt diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt index 35f6ef5..fc35973 100644 --- a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt +++ b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt @@ -23,7 +23,6 @@ import androidx.navigation.navArgument import com.ryankoech.krypto.R import com.ryankoech.krypto.common.presentation.theme.KryptoTheme import com.ryankoech.krypto.feature_coin_details.presentation.CoinDetailsScreen -import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin as CoinListCoin import com.ryankoech.krypto.feature_coin_list.presentation.CoinListScreen import com.ryankoech.krypto.feature_home.presentation.HomeScreen import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionType @@ -77,9 +76,8 @@ class MainActivity : ComponentActivity() { } } - fun navigateToCoinDetails(coin : CoinListCoin) { - viewModel.addCoinListCoin(coin) - navController.navigate(Screens.CoinDetails.route){ + fun navigateToCoinDetails(coinId : String) { + navController.navigate(Screens.CoinDetails.route + "/$coinId"){ launchSingleTop = true } } @@ -209,25 +207,26 @@ class MainActivity : ComponentActivity() { ) } - composable(Screens.CoinDetails.route){ + composable( + Screens.CoinDetails.route + "/{coinId}", + arguments = listOf( + navArgument("coinId") { + type = NavType.StringType + defaultValue = "bitcoin" + } + ) + ){ backStackEntry -> topBarTitle = stringResource(Screens.CoinDetails.titleResId) - val coin = viewModel.coinListCoin - - coin?.apply { - CoinDetailsScreen( - coin = coin, - navigateToBuyTransactionScreen = { transactionCoin -> - navigateToTransactionScreen(transactionCoin, TransactionType.BUY.toString()) - }, - navigateToSellTransactionScreen = { transactionCoin -> - navigateToTransactionScreen(transactionCoin, TransactionType.SELL.toString()) - } - ) - return@composable - } - - // Fallback error screen + CoinDetailsScreen( + coinId = backStackEntry.arguments?.getString("coinId")!!, + navigateToBuyTransactionScreen = { transactionCoin -> + navigateToTransactionScreen(transactionCoin, TransactionType.BUY.toString()) + }, + navigateToSellTransactionScreen = { transactionCoin -> + navigateToTransactionScreen(transactionCoin, TransactionType.SELL.toString()) + } + ) } diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/viewmodel/MainViewModel.kt b/app/src/main/java/com/ryankoech/krypto/presentation/viewmodel/MainViewModel.kt index 7941366..20fb05f 100644 --- a/app/src/main/java/com/ryankoech/krypto/presentation/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/ryankoech/krypto/presentation/viewmodel/MainViewModel.kt @@ -10,16 +10,9 @@ import javax.inject.Inject class MainViewModel @Inject constructor() : ViewModel(){ - var coinListCoin by mutableStateOf(null) - private set - var transactionCoin by mutableStateOf(null) private set - fun addCoinListCoin(coin : CoinListCoin) { - coinListCoin = coin - } - fun addTransactionCoin(coin: TransactionCoin){ transactionCoin = coin } diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt index 098be2a..df4db98 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/CoinDetailsScreen.kt @@ -16,21 +16,19 @@ import com.ryankoech.krypto.feature_coin_details.presentation.viewmodel.CoinDeta import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity import com.ryankoech.krypto.feature_coin_list.data.repository.FAKE_COIN_LIST import com.ryankoech.krypto.feature_transaction.domain.entity.Coin as TransactionCoin -import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin as CoinListCoin import timber.log.Timber @Composable fun CoinDetailsScreen( viewModel : CoinDetailsScreenViewModel = hiltViewModel(), - coin : CoinListCoin, + coinId : String, navigateToBuyTransactionScreen : (TransactionCoin) -> Unit, navigateToSellTransactionScreen : (TransactionCoin) -> Unit, modifier: Modifier = Modifier ) { LaunchedEffect(key1 = Unit){ - viewModel.getCoinDetails(coin.id) - viewModel.getTransactions(coin.id) + viewModel.getCoin(coinId) } val context = LocalContext.current @@ -104,7 +102,7 @@ fun CoinDetailsScreen( ScreenState.ERROR -> { CoinDetailsScreenError( onButtonClick = { - viewModel.getCoinDetails(coin.id) + viewModel.getCoinDetails(coinId) } ) } @@ -112,7 +110,7 @@ fun CoinDetailsScreen( CoinDetailsScreenSuccess( modifier = modifier, - coin = coin, + coin = viewState.coin, transactions = viewState.transactions, navigateToBuyTransactionScreen = navigateToBuyTransactionScreen, navigateToSellTransactionScreen = navigateToSellTransactionScreen, @@ -139,7 +137,7 @@ fun CoinDetailsScreenPreview() { .fillMaxSize() ) { CoinDetailsScreen( - coin = FAKE_COIN_LIST.toCoinEntity().first(), + coinId = "bitcoin", navigateToBuyTransactionScreen = {}, navigateToSellTransactionScreen = {}, ) diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt index d3bf478..789281e 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewmodel/CoinDetailsScreenViewModel.kt @@ -8,6 +8,8 @@ import com.ryankoech.krypto.common.core.util.Resource import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_details.domain.usecase.GetCoinMarketChartUseCase import com.ryankoech.krypto.feature_coin_details.presentation.viewstate.CoinDetailsScreenViewState +import com.ryankoech.krypto.feature_coin_list.data.dto.toCoinEntity +import com.ryankoech.krypto.feature_coin_list.domain.usecase.GetLocalCoinUseCase import com.ryankoech.krypto.feature_transaction.domain.usecase.DeleteCoinTransactionUseCase import com.ryankoech.krypto.feature_transaction.domain.usecase.GetCoinTransactionsUseCase import dagger.hilt.android.lifecycle.HiltViewModel @@ -22,6 +24,7 @@ class CoinDetailsScreenViewModel @Inject constructor( private val getCoinMarketChartUseCase: GetCoinMarketChartUseCase, private val getCoinTransactionsUseCase: GetCoinTransactionsUseCase, private val deleteCoinTransactionUseCase: DeleteCoinTransactionUseCase, + private val getLocalCoinUseCase: GetLocalCoinUseCase, ) : ViewModel(){ private val _viewState = mutableStateOf(CoinDetailsScreenViewState()) @@ -29,6 +32,34 @@ class CoinDetailsScreenViewModel @Inject constructor( private val _message = MutableSharedFlow() val message : SharedFlow get() = _message + + fun getCoin(coinId :String) { + getLocalCoinUseCase(coinId) + .onEach { res -> + when(res){ + is Resource.Error -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.ERROR, + ) + } + is Resource.Loading -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING, + ) + } + is Resource.Success -> { + _viewState.value = _viewState.value.copy( + screenState = ScreenState.LOADING, + coin = res.data!!.toCoinEntity() + ) + getCoinDetails(coinId) + getTransactions(coinId) + } + } + + }.launchIn(viewModelScope) + } + fun getCoinDetails(coinId :String) { getCoinMarketChartUseCase(coinId) @@ -58,7 +89,7 @@ class CoinDetailsScreenViewModel @Inject constructor( } - fun getTransactions(coinId: String) { + private fun getTransactions(coinId: String) { getCoinTransactionsUseCase(coinId) .onEach { res -> diff --git a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt index 1310c48..5f14e74 100644 --- a/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt +++ b/feature_coin_details/src/main/java/com/ryankoech/krypto/feature_coin_details/presentation/viewstate/CoinDetailsScreenViewState.kt @@ -2,6 +2,7 @@ package com.ryankoech.krypto.feature_coin_details.presentation.viewstate import com.ryankoech.krypto.common.presentation.util.ScreenState import com.ryankoech.krypto.feature_coin_details.domain.entity.MarketChartEntity +import com.ryankoech.krypto.feature_coin_list.domain.entity.Coin import com.ryankoech.krypto.feature_transaction.data.dto.transaction_dto.TransactionDto data class CoinDetailsScreenViewState( @@ -10,4 +11,5 @@ data class CoinDetailsScreenViewState( val threeMonthMarketChart : List = listOf(), val yearMarketChart : List = listOf(), val transactions : List = listOf(), + val coin : Coin = Coin("", "", "", 0, "", 0F, 0.0, 0, 0.0, 0.0, 0.0), ) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinLocalDto.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinLocalDto.kt index f542b3b..5b69f1c 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinLocalDto.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/data/dto/CoinLocalDto.kt @@ -37,4 +37,20 @@ fun List.toCoinEntity() : List = map { high24Hr = it.high24Hr, totalVolume = it.totalVolume ) -} \ No newline at end of file +} + + +fun CoinLocalDto.toCoinEntity() : Coin = + Coin( + id = this.id, + name = this.name, + symbol = this.symbol, + price = this.price, + marketCapRank = this.marketCapRank, + image = this.image, + change = this.change, + marketCap = this.marketCap, + allTimeHigh = this.allTimeHigh, + high24Hr = this.high24Hr, + totalVolume = this.totalVolume + ) diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinUseCase.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinUseCase.kt new file mode 100644 index 0000000..6f82c7f --- /dev/null +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/domain/usecase/GetLocalCoinUseCase.kt @@ -0,0 +1,29 @@ +package com.ryankoech.krypto.feature_coin_list.domain.usecase + +import com.ryankoech.krypto.common.core.util.Resource +import com.ryankoech.krypto.feature_coin_list.core.di.HILT_NAME_REPO_FOR_ALL +import com.ryankoech.krypto.feature_coin_list.data.dto.CoinLocalDto +import com.ryankoech.krypto.feature_coin_list.domain.repository.CoinRepository +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart +import javax.inject.Inject +import javax.inject.Named + +class GetLocalCoinUseCase @Inject constructor( + @Named(HILT_NAME_REPO_FOR_ALL) private val repository: CoinRepository +){ + operator fun invoke(coinId : String) = flow> { + + repository.getCoin(coinId)?.apply { + emit(Resource.Success(this)) + return@flow + } + throw Exception("No such coin found") + }.onStart { + emit(Resource.Loading()) + }.catch { e -> + emit(Resource.Error(e.localizedMessage ?: "An Unknown Error Occurred")) + } + +} \ No newline at end of file diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt index 4d31c9d..2725f09 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreen.kt @@ -27,7 +27,7 @@ import timber.log.Timber @OptIn(ExperimentalMaterialApi::class) @Composable fun CoinListScreen( - coinItemOnClick : (Coin) -> Unit, + coinItemOnClick : (String) -> Unit, viewModel: CoinListScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt index 4871b7e..86e5bdc 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/CoinListScreenSuccess.kt @@ -26,7 +26,7 @@ const val TEST_TAG_COIN_LIST_SCREEN_SUCCESS_COINS_LAZY_COLUMN = "test tag coin l @Composable fun CoinListScreenSuccess( - coinItemOnClick : (Coin) -> Unit, + coinItemOnClick : (String) -> Unit, screenState : ScreenState, editSortInfo : (SortCoinBy) -> Unit, sortInfoState : SortInfo, diff --git a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt index 9cf3702..23f408f 100644 --- a/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt +++ b/feature_coin_list/src/main/java/com/ryankoech/krypto/feature_coin_list/presentation/components/success/CoinItem.kt @@ -29,7 +29,7 @@ import com.ryankoech.krypto.feature_coin_list.presentation.theme.black200 @Composable fun CoinItem( - onClick : (Coin) -> Unit, + onClick : (String) -> Unit, coin: Coin, modifier: Modifier = Modifier ) { @@ -45,7 +45,7 @@ fun CoinItem( shape = RoundedCornerShape(10.dp) ) .clickable { - onClick(coin) + onClick(coin.id) }, ) { CoinImage(coin.image, coin.id) From 07c7a9fa6b452f859cf16d19358490c41c022cc9 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 14:18:05 +0300 Subject: [PATCH 197/201] add navigate to home screen callback --- .../java/com/ryankoech/krypto/presentation/MainActivity.kt | 3 ++- .../krypto/feature_home/presentation/HomeScreen.kt | 4 +++- .../krypto/feature_home/presentation/HomeScreenSuccess.kt | 4 +++- .../components/success/HomeScreenSuccessWithData.kt | 7 +++++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt index fc35973..3955c1d 100644 --- a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt +++ b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt @@ -155,7 +155,8 @@ class MainActivity : ComponentActivity() { }, onTransferOutClick = { navigateToChooseAssetScreen(TransactionType.SELL.toString()) - } + }, + navigateToCoinDetails = ::navigateToCoinDetails ) } diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreen.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreen.kt index 04f9eb2..b5e8a14 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreen.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreen.kt @@ -18,6 +18,7 @@ import com.ryankoech.krypto.feature_home.presentation.viewmodel.HomeScreenViewMo fun HomeScreen( onTransferInClick : () -> Unit, onTransferOutClick : () -> Unit, + navigateToCoinDetails : (String) -> Unit, viewModel: HomeScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { @@ -53,6 +54,7 @@ fun HomeScreen( displayCurrencies = viewState.displayCurrencies, onTransferInClick = onTransferInClick, onTransferOutClick = onTransferOutClick, + navigateToCoinDetails = navigateToCoinDetails, onWipeWalletClick = { viewModel.wipeOwnedCoinsDatabase() } ) } @@ -64,6 +66,6 @@ fun HomeScreen( @Composable fun HomeScreenPreview() { KryptoTheme { - HomeScreen({}, {}) + HomeScreen({}, {}, {}) } } \ No newline at end of file diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenSuccess.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenSuccess.kt index 6c8319c..94e11ec 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenSuccess.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenSuccess.kt @@ -22,6 +22,7 @@ fun HomeScreenSuccess( onTransferInClick : () -> Unit, onTransferOutClick : () -> Unit, onWipeWalletClick : () -> Unit, + navigateToCoinDetails : (String) -> Unit, modifier: Modifier = Modifier ) { @@ -36,6 +37,7 @@ fun HomeScreenSuccess( onTransferInClick = onTransferInClick, onTransferOutClick = onTransferOutClick, onWipeWalletClick = onWipeWalletClick, + navigateToCoinDetails = navigateToCoinDetails, modifier = modifier.testTag(TEST_TAG_HOME_SCREEN_SUCCESS_WITH_DATA) ) } @@ -49,7 +51,7 @@ fun HomeScreenSuccessPreview() { KryptoTheme { Surface(modifier = Modifier.fillMaxSize()) { - HomeScreenSuccess(FakeOwnedCoins, FakeDisplayCurrencies, {}, {}, {}) + HomeScreenSuccess(FakeOwnedCoins, FakeDisplayCurrencies, {}, {}, {}, {}) } } diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenSuccessWithData.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenSuccessWithData.kt index 2e0c44a..b3d3499 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenSuccessWithData.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenSuccessWithData.kt @@ -32,6 +32,7 @@ fun HomeScreenSuccessWithData( onTransferInClick : () -> Unit, onTransferOutClick : () -> Unit, onWipeWalletClick : () -> Unit, + navigateToCoinDetails : (String) -> Unit, modifier: Modifier = Modifier, ) { @@ -107,7 +108,9 @@ fun HomeScreenSuccessWithData( item{ Spacer(modifier = Modifier.height(24.dp)) } items(items = ownedCoins){ ownedCoin -> - OwnedCoinItem({},ownedCoin) + OwnedCoinItem({ + navigateToCoinDetails(ownedCoin.id) + },ownedCoin) Spacer(modifier = Modifier.height(16.dp)) } @@ -125,7 +128,7 @@ fun HomeScreenSuccessWithDataPreview() { Surface( modifier = Modifier.fillMaxSize() ) { - HomeScreenSuccessWithData(FakeOwnedCoins, FakeDisplayCurrencies, {}, {}, {}) + HomeScreenSuccessWithData(FakeOwnedCoins, FakeDisplayCurrencies, {}, {}, {}, {}) } } From 7dca756e9e7793f017b8cbcf83cc99daf88a3bec Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 15:15:16 +0300 Subject: [PATCH 198/201] change status bar color --- app/src/main/res/values/themes.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 3cc60d9..ab34125 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -2,6 +2,6 @@ \ No newline at end of file From 2fa71e99f5fe1e14196e7d1ef68ed46bd57a18a7 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 15:16:29 +0300 Subject: [PATCH 199/201] run function in coroutine scope --- .../data/repository/OwnedCoinsRepositoryImpl.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt index eb480f2..de08570 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/data/repository/OwnedCoinsRepositoryImpl.kt @@ -7,7 +7,10 @@ import com.ryankoech.krypto.feature_home.data.data_source.local.shared_pref.Home import com.ryankoech.krypto.feature_home.data.dto.display_currency.DisplayCurrencyDto import com.ryankoech.krypto.feature_home.data.dto.owned_coin.OwnedCoinDto import com.ryankoech.krypto.feature_home.domain.repository.OwnedCoinsRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch import javax.inject.Inject class OwnedCoinsRepositoryImpl @Inject constructor( @@ -50,8 +53,10 @@ class OwnedCoinsRepositoryImpl @Inject constructor( } override suspend fun wipeDatabase() { - return coroutineScope{ - ownedCoinsDatabase.clearAllTables() + return coroutineScope { + CoroutineScope(Dispatchers.IO).launch { + ownedCoinsDatabase.clearAllTables() + } } } From f1f55d340d322f0e26b1111f9b6c0f6647901772 Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 15:17:21 +0300 Subject: [PATCH 200/201] fix bar stylings --- .../krypto/presentation/MainActivity.kt | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt index 3955c1d..eee3607 100644 --- a/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt +++ b/app/src/main/java/com/ryankoech/krypto/presentation/MainActivity.kt @@ -4,13 +4,16 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavGraph.Companion.findStartDestination @@ -89,6 +92,9 @@ class MainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), topBar = { TopAppBar( + backgroundColor = MaterialTheme.colors.surface, + contentColor = MaterialTheme.colors.onSurface, + elevation = 0.dp, title = { Text( text = topBarTitle, @@ -111,11 +117,28 @@ class MainActivity : ComponentActivity() { ) }, bottomBar = { - BottomNavigation { + BottomNavigation( + modifier = Modifier + .padding(bottom = 12.dp) + .height(64.dp), + backgroundColor = Color(0xfff2f2f2), + contentColor = MaterialTheme.colors.onSurface, + ) { bottomNavigationItems.forEach { screen -> BottomNavigationItem( - icon = { Icon(painterResource(screen.iconResId), contentDescription = null) }, - label = { Text(stringResource(screen.labelResId)) }, + icon = { + Icon( + modifier = Modifier + .padding(bottom = 4.dp), + painter = painterResource(screen.iconResId), + contentDescription = null + ) + }, + label = { + Text( + text = stringResource(screen.labelResId) + ) + }, selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true, onClick = { navController.navigate(screen.route) { From 73054b7980939399d52289fc2950861f3cd733bb Mon Sep 17 00:00:00 2001 From: RyanKoech Date: Thu, 9 Mar 2023 15:17:34 +0300 Subject: [PATCH 201/201] passed callback --- .../krypto/feature_home/presentation/HomeScreenSuccess.kt | 3 ++- .../components/success/HomeScreenSuccessNoData.kt | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenSuccess.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenSuccess.kt index 94e11ec..cd93357 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenSuccess.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/HomeScreenSuccess.kt @@ -28,7 +28,8 @@ fun HomeScreenSuccess( if(ownedCoins.isEmpty()){ HomeScreenSuccessNoData( - modifier.testTag(TEST_TAG_HOME_SCREEN_SUCCESS_NO_DATA) + modifier.testTag(TEST_TAG_HOME_SCREEN_SUCCESS_NO_DATA), + navigateToChooseAsset = onTransferInClick, ) }else{ HomeScreenSuccessWithData( diff --git a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenSuccessNoData.kt b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenSuccessNoData.kt index ff027c3..ae0e6ac 100644 --- a/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenSuccessNoData.kt +++ b/feature_home/src/main/java/com/ryankoech/krypto/feature_home/presentation/components/success/HomeScreenSuccessNoData.kt @@ -14,11 +14,12 @@ const val TEST_TAG_HOME_SCREEN_SUCCESS_NO_DATA = "test_tag_home_screen_success_n @Composable fun HomeScreenSuccessNoData( - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + navigateToChooseAsset : () -> Unit ){ ErrorScreen( modifier = modifier, - onButtonClick = {}, + onButtonClick = navigateToChooseAsset, messageText = stringResource(R.string.home_screen_success_not_data_message), buttonText = stringResource(R.string.home_screen_success_no_data_action), res = R.drawable.astronaut @@ -34,7 +35,7 @@ fun HomeScreenSuccessNoDataPreview() { modifier = Modifier.fillMaxSize() ) { - HomeScreenSuccessNoData() + HomeScreenSuccessNoData(Modifier, {}) } }