Skip to content

Commit b533fc8

Browse files
Merge pull request #131 from Newyork-Squad/refactor/enhancement-explore-screen
Refactor/enhancement explore screen
2 parents 3793c2f + 918b0cb commit b533fc8

File tree

14 files changed

+106
-50
lines changed

14 files changed

+106
-50
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.karrar.movieapp.data.util
2+
3+
import android.content.Context
4+
import com.karrar.movieapp.domain.util.ResourceProvider
5+
import dagger.hilt.android.qualifiers.ApplicationContext
6+
import javax.inject.Inject
7+
8+
class ResourceProviderImpl @Inject constructor(
9+
@ApplicationContext private val context: Context
10+
) : ResourceProvider {
11+
override fun getString(resId: Int): String = context.getString(resId)
12+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.karrar.movieapp.di
2+
3+
import com.karrar.movieapp.data.util.ResourceProviderImpl
4+
import com.karrar.movieapp.domain.util.ResourceProvider
5+
import dagger.Binds
6+
import dagger.Module
7+
import dagger.hilt.InstallIn
8+
import dagger.hilt.components.SingletonComponent
9+
import javax.inject.Singleton
10+
11+
@Module
12+
@InstallIn(SingletonComponent::class)
13+
abstract class ResourceModule {
14+
15+
@Singleton
16+
@Binds
17+
abstract fun bindResourceProvider(
18+
impl: ResourceProviderImpl
19+
): ResourceProvider
20+
}

app/src/main/java/com/karrar/movieapp/domain/usecases/GetGenreListUseCase.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package com.karrar.movieapp.domain.usecases
22

3+
import com.karrar.movieapp.R
34
import com.karrar.movieapp.data.remote.response.genre.GenreDto
45
import com.karrar.movieapp.data.repository.MovieRepository
56
import com.karrar.movieapp.data.repository.SeriesRepository
67
import com.karrar.movieapp.domain.mappers.GenreMapper
78
import com.karrar.movieapp.domain.mappers.ListMapper
89
import com.karrar.movieapp.domain.models.Genre
10+
import com.karrar.movieapp.domain.util.ResourceProvider
911
import com.karrar.movieapp.utilities.Constants
1012
import javax.inject.Inject
1113

1214
class GetGenreListUseCase @Inject constructor(
15+
private val resourceProvider: ResourceProvider,
1316
private val movieRepository: MovieRepository,
1417
private val seriesRepository: SeriesRepository,
1518
private val genreMapper: GenreMapper
@@ -29,7 +32,8 @@ class GetGenreListUseCase @Inject constructor(
2932

3033
private fun setGenre(genre: List<Genre>): List<Genre> {
3134
val allGenre = mutableListOf<Genre>()
32-
allGenre.add(Genre(Constants.FIRST_CATEGORY_ID, Constants.ALL))
35+
allGenre.add(Genre(Constants.FIRST_CATEGORY_ID,
36+
resourceProvider.getString(R.string.txt_all)))
3337
allGenre.addAll(genre)
3438
return allGenre.toList()
3539
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.karrar.movieapp.domain.util
2+
3+
interface ResourceProvider {
4+
fun getString(resId: Int) : String
5+
}

app/src/main/java/com/karrar/movieapp/ui/explore/ExploringFragment.kt

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class ExploringFragment : BaseFragment<FragmentExploringBinding>() {
6565

6666
override fun onResume() {
6767
super.onResume()
68-
viewModel.refreshData()
68+
viewModel.getData()
6969
}
7070

7171
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -81,34 +81,9 @@ class ExploringFragment : BaseFragment<FragmentExploringBinding>() {
8181
}
8282

8383
private fun setupToggle() {
84-
val toggleRoot = binding.viewToggle
85-
86-
toggleRoot.ivGrid.setOnClickListener { viewModel.setGridMode(true) }
87-
toggleRoot.ivList.setOnClickListener { viewModel.setGridMode(false) }
88-
toggleRoot.indicator.setOnClickListener { viewModel.toggleGridMode() }
89-
90-
viewLifecycleOwner.lifecycleScope.launch {
91-
viewModel.isGrid.collect { isGrid ->
92-
if (isGrid) toggleRoot.toggleMotion.transitionToStart() else toggleRoot.toggleMotion.transitionToEnd()
93-
94-
allMediaAdapter.setGridMode(isGrid)
95-
96-
val lm = binding.recyclerMedia.layoutManager as? GridLayoutManager
97-
lm?.let {
98-
val firstPos = it.findFirstVisibleItemPosition()
99-
it.spanCount = if (isGrid) 2 else 1
100-
101-
binding.recyclerMedia.post {
102-
it.requestLayout()
103-
if (firstPos != RecyclerView.NO_POSITION) binding.recyclerMedia.scrollToPosition(firstPos)
104-
}
105-
}
106-
val gridIcon = if (isGrid) R.drawable.ic_grid_selected else R.drawable.ic_grid_unselected
107-
val listIcon = if (!isGrid) R.drawable.ic_row_vertical_selected else R.drawable.ic_row_vertical_unselected
108-
toggleRoot.ivGrid.setImageResource(gridIcon)
109-
toggleRoot.ivList.setImageResource(listIcon)
110-
}
111-
}
84+
binding.viewToggle.ivGrid.setOnClickListener { viewModel.setGridMode(true) }
85+
binding.viewToggle.ivList.setOnClickListener { viewModel.setGridMode(false) }
86+
binding.viewToggle.indicator.setOnClickListener { viewModel.toggleGridMode() }
11287
}
11388

11489
private fun initTabLayout() {
@@ -148,9 +123,14 @@ class ExploringFragment : BaseFragment<FragmentExploringBinding>() {
148123
private fun collectData() {
149124
viewLifecycleOwner.lifecycleScope.launch {
150125
viewModel.uiState.collect { state ->
126+
allMediaAdapter.setGridMode(state.isGrid)
127+
val gridIcon = if (state.isGrid) R.drawable.ic_grid_selected else R.drawable.ic_grid_unselected
128+
val listIcon = if (!state.isGrid) R.drawable.ic_row_vertical_selected else R.drawable.ic_row_vertical_unselected
129+
binding.viewToggle.ivGrid.setImageResource(gridIcon)
130+
binding.viewToggle.ivList.setImageResource(listIcon)
131+
151132
genreAdapter.setItems(state.genre)
152133
genreAdapter.setSelectedGenre(state.selectedCategoryID)
153-
154134
val desiredTab = if (state.selectedMediaId == Constants.TV_CATEGORIES_ID) 1 else 0
155135
if (binding.tabExplore.selectedTabPosition != desiredTab) {
156136
ignoreTabChanges = true

app/src/main/java/com/karrar/movieapp/ui/explore/ExploringViewModel.kt

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,10 @@ class ExploringViewModel @Inject constructor(
3939
private val _exploringUIEvent: MutableStateFlow<Event<ExploringUIEvent>?> = MutableStateFlow(null)
4040
val exploringUIEvent= _exploringUIEvent.asStateFlow()
4141

42-
private val _isGrid = MutableStateFlow(true)
43-
val isGrid: StateFlow<Boolean> = _isGrid.asStateFlow()
44-
4542
init {
4643
setMediaType(Constants.MOVIE_CATEGORIES_ID)
4744
}
4845

49-
fun refreshData() {
50-
getData()
51-
}
52-
5346
override fun getData() {
5447
val mediaId = _uiState.value.selectedMediaId
5548
val catId = _uiState.value.selectedCategoryID
@@ -71,10 +64,10 @@ class ExploringViewModel @Inject constructor(
7164
}
7265

7366
fun setGridMode(grid: Boolean) {
74-
_isGrid.value = grid
67+
_uiState.update { it.copy(isGrid = grid) }
7568
}
7669

77-
fun toggleGridMode() = setGridMode(!_isGrid.value)
70+
fun toggleGridMode() = setGridMode(!_uiState.value.isGrid)
7871

7972
private fun loadGenres(mediaId: Int) {
8073
viewModelScope.launch {
@@ -103,7 +96,13 @@ class ExploringViewModel @Inject constructor(
10396

10497
_uiState.update { it.copy(isLoading = false, media = paging, error = emptyList()) }
10598
} catch (t: Throwable) {
106-
_uiState.update { it.copy(isLoading = false, error = listOf(ErrorUIState(-1, t.message.orEmpty()))) }
99+
_uiState.update {
100+
it.copy(
101+
isLoading = false,
102+
error = listOf(ErrorUIState(-1, t.message.orEmpty())
103+
)
104+
)
105+
}
107106
}
108107
}
109108
}
@@ -127,17 +126,20 @@ class ExploringViewModel @Inject constructor(
127126
when (combinedLoadStates.refresh) {
128127
is LoadState.NotLoading -> {
129128
_uiState.update {
130-
it.copy(isLoading = false, error = emptyList())
129+
it.copy(isLoading = false,
130+
error = emptyList())
131131
}
132132
}
133133
LoadState.Loading -> {
134134
_uiState.update {
135-
it.copy(isLoading = false, error = emptyList())
135+
it.copy(isLoading = false,
136+
error = emptyList())
136137
}
137138
}
138139
is LoadState.Error -> {
139140
_uiState.update {
140-
it.copy(isLoading = false, error = listOf(ErrorUIState(404, "Error")))
141+
it.copy(isLoading = false,
142+
error = listOf(ErrorUIState(404, "Error")))
141143
}
142144
}
143145
}

app/src/main/java/com/karrar/movieapp/ui/explore/exploreUIState/ExploreUIState.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ data class ExploreUIState(
1414
val media: Flow<PagingData<MediaUIState>> = emptyFlow(),
1515
val selectedMediaId: Int = Constants.MOVIE_CATEGORIES_ID,
1616
val selectedGenreId: Int? = null,
17+
val isGrid: Boolean = true,
1718
val isLoading: Boolean = false,
1819
val error: List<ErrorUIState> = emptyList()
1920
)

app/src/main/java/com/karrar/movieapp/utilities/BindingAdapter.kt

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import android.widget.LinearLayout
1010
import android.widget.RatingBar
1111
import android.widget.TextView
1212
import androidx.cardview.widget.CardView
13+
import androidx.constraintlayout.motion.widget.MotionLayout
1314
import androidx.core.content.ContextCompat
1415
import androidx.core.view.isVisible
1516
import androidx.databinding.BindingAdapter
17+
import androidx.recyclerview.widget.GridLayoutManager
1618
import androidx.recyclerview.widget.PagerSnapHelper
1719
import androidx.recyclerview.widget.RecyclerView
1820
import coil.imageLoader
@@ -281,10 +283,28 @@ fun loadMediaPoster(image: ImageView, imageURL: String?) {
281283
}
282284
}
283285

286+
@BindingAdapter("app:transitionToSelect")
287+
fun transitionToSelect(motionLayout: MotionLayout, isSelect: Boolean) {
288+
if (isSelect) {
289+
motionLayout.transitionToStart()
290+
} else {
291+
motionLayout.transitionToEnd()
292+
}
293+
}
284294

295+
@BindingAdapter("app:isRecyclerViewGrid")
296+
fun isRecyclerViewGrid(recyclerView: RecyclerView, isGrid: Boolean) {
297+
val lm = recyclerView.layoutManager as? GridLayoutManager ?: return
298+
val firstPos = lm.findFirstVisibleItemPosition()
299+
lm.spanCount = if (isGrid) 2 else 1
285300

286-
287-
301+
recyclerView.post {
302+
lm.requestLayout()
303+
if (firstPos != RecyclerView.NO_POSITION) {
304+
recyclerView.scrollToPosition(firstPos)
305+
}
306+
}
307+
}
288308

289309
@BindingAdapter("app:showProfileWhenSuccess")
290310
fun showWhenProfileSuccess(view: View, userName: String) {
@@ -487,6 +507,7 @@ fun setOneDecimal(textView: TextView, number: Double?) {
487507
textView.text = String.format("%.1f", it)
488508
}
489509
}
510+
490511
@BindingAdapter("srcCompatSafe")
491512
fun ImageView.setSrcCompatSafe(resId: Int?) {
492513
if (resId != null && resId != 0) {

app/src/main/res/drawable/media_place_holder.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
<group android:translateX="80" android:translateY="80">
88
<path
99
android:pathData="M80,75.999V4.174C80,0.612 75.696,-1.173 73.175,1.342L1.183,73.167C-1.341,75.686 0.442,79.999 4.008,79.999H76C78.209,79.999 80,78.208 80,75.999ZM68.424,72.76C68.424,71.655 69.319,70.76 70.424,70.76H74.527C75.631,70.76 76.527,71.655 76.527,72.76V74.534C76.527,75.639 75.631,76.534 74.527,76.534H70.424C69.319,76.534 68.424,75.639 68.424,74.534V72.76ZM70.424,61.52C69.319,61.52 68.424,62.416 68.424,63.52V65.294C68.424,66.399 69.319,67.294 70.424,67.294H74.527C75.631,67.294 76.527,66.399 76.527,65.294V63.52C76.527,62.416 75.631,61.52 74.527,61.52H70.424ZM68.424,54.281C68.424,53.176 69.319,52.281 70.424,52.281H74.527C75.631,52.281 76.527,53.176 76.527,54.281V56.055C76.527,57.16 75.631,58.055 74.527,58.055H70.424C69.319,58.055 68.424,57.16 68.424,56.055V54.281ZM70.424,43.041C69.319,43.041 68.424,43.937 68.424,45.041V46.815C68.424,47.92 69.319,48.815 70.424,48.815H74.527C75.631,48.815 76.527,47.92 76.527,46.815V45.041C76.527,43.937 75.631,43.041 74.527,43.041H70.424ZM68.424,35.802C68.424,34.697 69.319,33.802 70.424,33.802H74.527C75.631,33.802 76.527,34.697 76.527,35.802V37.576C76.527,38.681 75.631,39.576 74.527,39.576H70.424C69.319,39.576 68.424,38.681 68.424,37.576V35.802ZM70.424,24.562C69.319,24.562 68.424,25.458 68.424,26.562V28.336C68.424,29.441 69.319,30.336 70.424,30.336H74.527C75.631,30.336 76.527,29.441 76.527,28.336V26.562C76.527,25.458 75.631,24.562 74.527,24.562H70.424ZM68.424,17.322C68.424,16.218 69.319,15.322 70.424,15.322H74.527C75.631,15.322 76.527,16.218 76.527,17.322V19.097C76.527,20.201 75.631,21.097 74.527,21.097H70.424C69.319,21.097 68.424,20.201 68.424,19.097V17.322ZM70.424,6.082C69.319,6.082 68.424,6.978 68.424,8.082V9.857C68.424,10.961 69.319,11.857 70.424,11.857H74.527C75.631,11.857 76.527,10.961 76.527,9.857V8.082C76.527,6.978 75.631,6.082 74.527,6.082H70.424Z"
10-
android:fillColor="@color/shade_ternary_color"
10+
android:fillColor="@color/shade_tertiary"
1111
android:fillType="evenOdd"/>
1212
<path
1313
android:pathData="M33.215,34.813L6.777,60.114C4.231,62.55 0,60.749 0,57.229L0,4.002C-0,0.388 4.427,-1.368 6.915,1.26L33.353,29.186C34.864,30.782 34.802,33.294 33.215,34.813ZM5.09,45.351C3.985,45.351 3.09,46.246 3.09,47.351V49.125C3.09,50.23 3.985,51.125 5.09,51.125H9.193C10.297,51.125 11.193,50.23 11.193,49.125V47.351C11.193,46.246 10.297,45.351 9.193,45.351H5.09ZM3.09,38.111C3.09,37.007 3.985,36.111 5.09,36.111H9.193C10.297,36.111 11.193,37.007 11.193,38.111V39.886C11.193,40.99 10.297,41.886 9.193,41.886H5.09C3.985,41.886 3.09,40.99 3.09,39.886V38.111ZM5.09,26.872C3.985,26.872 3.09,27.767 3.09,28.872V30.646C3.09,31.751 3.985,32.646 5.09,32.646H9.193C10.297,32.646 11.193,31.751 11.193,30.646V28.872C11.193,27.767 10.297,26.872 9.193,26.872H5.09ZM3.09,19.632C3.09,18.528 3.985,17.632 5.09,17.632H9.193C10.297,17.632 11.193,18.528 11.193,19.632V21.407C11.193,22.511 10.297,23.407 9.193,23.407H5.09C3.985,23.407 3.09,22.511 3.09,21.407V19.632ZM5.09,8.392C3.985,8.392 3.09,9.288 3.09,10.392V12.166C3.09,13.271 3.985,14.166 5.09,14.166H9.193C10.297,14.166 11.193,13.271 11.193,12.166V10.392C11.193,9.288 10.297,8.392 9.193,8.392H5.09Z"
14-
android:fillColor="@color/shade_ternary_color"
14+
android:fillColor="@color/shade_tertiary"
1515
android:fillType="evenOdd"/>
1616
</group>
1717

app/src/main/res/layout/fragment_exploring.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@
182182
android:clipToPadding="false"
183183
app:doneLoading="@{viewModel.uiState.loading}"
184184
app:errorNotEmpty="@{viewModel.uiState.error}"
185+
app:isRecyclerViewGrid="@{viewModel.uiState.isGrid}"
185186
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
186187
app:layout_constraintBottom_toBottomOf="parent"
187188
app:layout_constraintEnd_toEndOf="parent"
@@ -195,6 +196,7 @@
195196
android:layout_height="40dp"
196197
android:layout_marginEnd="@dimen/spacing_medium"
197198
app:isVisible="@{true}"
199+
app:isGrid="@{viewModel.uiState.isGrid}"
198200
android:elevation="@dimen/spacing_xSmall"
199201
android:layout_marginBottom="@dimen/spacing_medium"
200202
app:layout_constraintBottom_toBottomOf="parent"

0 commit comments

Comments
 (0)