Skip to content

Commit 900cc8e

Browse files
committed
Refactor flor for getting single result with no replies
1 parent 1594990 commit 900cc8e

File tree

7 files changed

+133
-27
lines changed

7 files changed

+133
-27
lines changed

app/src/main/java/st/slex/csplashscreen/data/core/DataResult.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package st.slex.csplashscreen.data.core
22

33
sealed interface DataResult<D> {
4+
45
fun <U> map(mapper: Mapper.DataToUI<D, U>): U
5-
class Success<T>(val data: T) : DataResult<T> {
6+
7+
class Success<T>(private val data: T) : DataResult<T> {
68
override fun <U> map(mapper: Mapper.DataToUI<T, U>) = mapper.map(data)
79
}
810

9-
class Failure<T>(val exception: Exception) : DataResult<T> {
11+
class Failure<T>(private val exception: Exception) : DataResult<T> {
1012
override fun <U> map(mapper: Mapper.DataToUI<T, U>): U =
1113
mapper.map(exception)
1214
}

app/src/main/java/st/slex/csplashscreen/di/module/RetrofitModule.kt

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import okhttp3.logging.HttpLoggingInterceptor
1010
import retrofit2.Retrofit
1111
import retrofit2.converter.gson.GsonConverterFactory
1212
import st.slex.csplashscreen.utiles.BASE_URL
13+
import javax.inject.Singleton
1314

1415
@Module
1516
class RetrofitModule {
@@ -22,17 +23,17 @@ class RetrofitModule {
2223
.addConverterFactory(GsonConverterFactory.create())
2324
.build()
2425

26+
@Singleton
2527
@Provides
2628
fun providesRetrofitClient(
2729
mLoggingInterceptor: HttpLoggingInterceptor,
28-
interceptor: Interceptor,
30+
onlineInterceptor: Interceptor,
2931
application: Application
30-
): OkHttpClient =
31-
OkHttpClient.Builder()
32-
.addInterceptor(mLoggingInterceptor)
33-
.addInterceptor(interceptor)
34-
.cache(Cache(application.cacheDir, 10 * 1024 * 1024 * 8L))
35-
.build()
32+
): OkHttpClient = OkHttpClient.Builder()
33+
.addInterceptor(mLoggingInterceptor)
34+
.addInterceptor(onlineInterceptor)
35+
.cache(Cache(application.cacheDir, 10 * 1024 * 1024 * 8L))
36+
.build()
3637

3738
@Provides
3839
fun providesLoggingInterceptor(): HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
@@ -48,4 +49,18 @@ class RetrofitModule {
4849
.removeHeader("Pragma")
4950
.build()
5051
}
52+
53+
/* @OfflineScope
54+
@Provides
55+
fun providesOfflineInterceptor(): Interceptor = Interceptor { chain ->
56+
var request: Request = chain.request()
57+
val maxStale = 60 * 60 * 3
58+
request = request.newBuilder()
59+
.header("Cache-Control", "public, only-if-cached, max-stale=$maxStale")
60+
.removeHeader("Pragma")
61+
.build()
62+
63+
chain.proceed(request)
64+
}*/
65+
5166
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package st.slex.csplashscreen.di.scopes
2+
3+
import javax.inject.Scope
4+
5+
@Scope
6+
@Retention(value = AnnotationRetention.RUNTIME)
7+
annotation class OfflineScope
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package st.slex.csplashscreen.di.scopes
2+
3+
import javax.inject.Scope
4+
5+
@Scope
6+
@Retention(value = AnnotationRetention.BINARY)
7+
annotation class OnlineScope

app/src/main/java/st/slex/csplashscreen/ui/MainViewModel.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,16 @@ class MainViewModel @Inject constructor(
3131
) : ViewModel() {
3232

3333

34-
private val _currentPhoto = MutableStateFlow<UIResult<ImageModel>>(UIResult.Loading)
35-
val currentPhoto: StateFlow<UIResult<ImageModel>>
36-
get() = _currentPhoto.asStateFlow()
34+
private val _currentPhoto = MutableSharedFlow<UIResult<ImageModel>>(replay = 0)
35+
val currentPhoto: SharedFlow<UIResult<ImageModel>>
36+
get() = _currentPhoto
3737

3838
fun getCurrentPhoto(id: String) = viewModelScope.launch {
3939
repository.getCurrentPhoto(id).collect {
40-
_currentPhoto.value = it.map(mapper = photoMapper)
40+
_currentPhoto.emit(it.map(mapper = photoMapper))
4141
}
4242
}
4343

44-
4544
suspend fun downloadPhoto(id: String): StateFlow<UIResult<DownloadModel>> =
4645
response.getAndMap(repository.downloadPhoto(id), downloadMapper).stateIn(
4746
scope = viewModelScope,
Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
package st.slex.csplashscreen.ui.detail
22

3-
import android.util.Log
43
import androidx.compose.foundation.Image
54
import androidx.compose.foundation.clickable
65
import androidx.compose.foundation.layout.Column
76
import androidx.compose.foundation.layout.fillMaxWidth
87
import androidx.compose.foundation.layout.height
98
import androidx.compose.runtime.Composable
109
import androidx.compose.runtime.collectAsState
10+
import androidx.compose.runtime.rememberCoroutineScope
1111
import androidx.compose.ui.Modifier
12+
import androidx.compose.ui.graphics.Color
13+
import androidx.compose.ui.platform.LocalContext
1214
import androidx.compose.ui.unit.dp
1315
import androidx.navigation.NavController
1416
import coil.annotation.ExperimentalCoilApi
1517
import coil.compose.rememberImagePainter
18+
import coil.transform.BlurTransformation
1619
import coil.transform.RoundedCornersTransformation
20+
import com.google.accompanist.placeholder.PlaceholderHighlight
21+
import com.google.accompanist.placeholder.fade
22+
import com.google.accompanist.placeholder.placeholder
1723
import kotlinx.coroutines.ExperimentalCoroutinesApi
18-
import kotlinx.coroutines.flow.StateFlow
24+
import kotlinx.coroutines.flow.SharedFlow
25+
import st.slex.csplashscreen.R
1926
import st.slex.csplashscreen.data.model.ui.image.ImageModel
2027
import st.slex.csplashscreen.ui.core.UIResult
2128
import java.net.URLEncoder
@@ -27,40 +34,93 @@ import java.nio.charset.StandardCharsets
2734
fun ImageDetailScreen(
2835
url: String,
2936
navController: NavController,
30-
imageFlow: () -> StateFlow<UIResult<ImageModel>>
37+
imageFlow: () -> SharedFlow<UIResult<ImageModel>>
3138
) {
32-
val imageModel = imageFlow().collectAsState().value
39+
val imageModel = imageFlow().collectAsState(
40+
initial = UIResult.Loading,
41+
context = rememberCoroutineScope().coroutineContext
42+
).value
3343

3444
when (imageModel) {
35-
is UIResult.Success -> {
36-
BindImage(navController, url, imageModel.data)
37-
}
45+
is UIResult.Success -> BindImage(navController, imageModel.data)
46+
is UIResult.Loading -> BindImageLoading(url = url)
47+
is UIResult.Failure -> BindImageFailure(url = url)
3848
}
39-
40-
Log.i("imageModel", imageModel.toString())
4149
}
4250

51+
@ExperimentalCoilApi
4352
@Composable
44-
fun BindImage(navController: NavController, url: String, imageModel: ImageModel) {
53+
private fun BindImage(navController: NavController, imageModel: ImageModel) {
4554
Column {
4655
Image(
4756
modifier = Modifier
4857
.fillMaxWidth()
4958
.height(300.dp)
5059
.clickable {
5160
val encodedUrl =
52-
URLEncoder.encode(url, StandardCharsets.UTF_8.toString())
61+
URLEncoder.encode(
62+
imageModel.urls.regular,
63+
StandardCharsets.UTF_8.toString()
64+
)
5365
navController.navigate("raw_image/$encodedUrl")
5466
},
5567
painter = rememberImagePainter(
5668
data = imageModel.urls.regular,
5769
builder = {
5870
transformations(RoundedCornersTransformation())
5971
allowHardware(false)
60-
crossfade(500)
6172
}
6273
),
6374
contentDescription = "TestImage"
6475
)
6576
}
66-
}
77+
}
78+
79+
@ExperimentalCoilApi
80+
@Composable
81+
private fun BindImageLoading(url: String) {
82+
androidx.compose.material.Surface(
83+
modifier = Modifier
84+
.height(300.dp)
85+
.fillMaxWidth()
86+
.placeholder(
87+
visible = true,
88+
highlight = PlaceholderHighlight.fade(highlightColor = Color.LightGray),
89+
color = Color.Gray
90+
)
91+
) {}
92+
93+
}
94+
95+
@ExperimentalCoilApi
96+
@Composable
97+
private fun BindImageFailure(url: String) {
98+
99+
Image(
100+
modifier = Modifier
101+
.fillMaxWidth()
102+
.height(300.dp),
103+
painter = rememberImagePainter(
104+
data = url,
105+
builder = {
106+
transformations(
107+
RoundedCornersTransformation(),
108+
BlurTransformation(LocalContext.current)
109+
)
110+
allowHardware(false)
111+
crossfade(500)
112+
}
113+
),
114+
contentDescription = "TestImage"
115+
)
116+
Image(
117+
modifier = Modifier
118+
.fillMaxWidth()
119+
.height(300.dp),
120+
painter = rememberImagePainter(
121+
data = R.drawable.ic_baseline_sentiment_very_dissatisfied_24
122+
),
123+
contentDescription = "TestImage"
124+
)
125+
}
126+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:tint="?attr/colorControlNormal"
5+
android:viewportWidth="24"
6+
android:viewportHeight="24">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M15.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
10+
<path
11+
android:fillColor="@android:color/white"
12+
android:pathData="M8.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
13+
<path
14+
android:fillColor="@android:color/white"
15+
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12,14c-2.33,0 -4.32,1.45 -5.12,3.5h1.67c0.69,-1.19 1.97,-2 3.45,-2s2.75,0.81 3.45,2h1.67c-0.8,-2.05 -2.79,-3.5 -5.12,-3.5z" />
16+
</vector>

0 commit comments

Comments
 (0)