Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement content language change support #224

Merged
merged 1 commit into from
Nov 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2022 Maximillian Leonov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.maximillianleonov.cinemax.di

import android.content.Context
import androidx.datastore.preferences.preferencesDataStore
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 DataStoreModule {
@Provides
@Singleton
fun providePreferencesDataStore(@ApplicationContext context: Context) =
context.preferencesDataStore
}

private const val PREFERENCES_NAME = "preferences"
private val Context.preferencesDataStore by preferencesDataStore(name = PREFERENCES_NAME)
2 changes: 2 additions & 0 deletions app/src/main/res/values-night/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@
<item name="android:navigationBarColor">@color/primaryDark</item>
<item name="android:windowLightStatusBar" tools:targetApi="23">false</item>
<item name="android:windowLightNavigationBar" tools:targetApi="27">false</item>
<item name="android:dialogTheme">@style/Theme.Cinemax.Dialog</item>
</style>

</resources>
6 changes: 6 additions & 0 deletions app/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@
<item name="android:navigationBarColor">@color/primaryLight</item>
<item name="android:windowLightStatusBar" tools:targetApi="23">true</item>
<item name="android:windowLightNavigationBar" tools:targetApi="27">true</item>
<item name="android:dialogTheme">@style/Theme.Cinemax.Dialog</item>
</style>

<style name="Theme.Cinemax.Splash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/primaryDark</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_splash</item>
<item name="postSplashScreenTheme">@style/Theme.Cinemax</item>
</style>

<style name="Theme.Cinemax.Dialog" parent="android:Theme.Material.Light.Dialog">
<item name="android:backgroundDimEnabled">false</item>
</style>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ import com.maximillianleonov.cinemax.core.database.model.common.MediaType
import com.maximillianleonov.cinemax.core.database.model.movie.MovieEntity
import com.maximillianleonov.cinemax.core.database.model.movie.MovieRemoteKeyEntity
import com.maximillianleonov.cinemax.core.database.source.MovieDatabaseDataSource
import com.maximillianleonov.cinemax.core.datastore.PreferencesDataStoreDataSource
import com.maximillianleonov.cinemax.core.network.source.MovieNetworkDataSource
import kotlinx.coroutines.flow.first
import java.io.IOException

@OptIn(ExperimentalPagingApi::class)
class MovieRemoteMediator(
private val databaseDataSource: MovieDatabaseDataSource,
private val networkDataSource: MovieNetworkDataSource,
private val preferencesDataStoreDataSource: PreferencesDataStoreDataSource,
private val mediaType: MediaType.Movie
) : RemoteMediator<Int, MovieEntity>() {
@Suppress("ReturnCount")
Expand Down Expand Up @@ -71,6 +74,7 @@ class MovieRemoteMediator(

val response = networkDataSource.getByMediaType(
mediaType = mediaType.asNetworkMediaType(),
language = preferencesDataStoreDataSource.getContentLanguage().first(),
page = currentPage
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@ import com.maximillianleonov.cinemax.core.common.result.isFailure
import com.maximillianleonov.cinemax.core.common.result.isSuccess
import com.maximillianleonov.cinemax.core.data.mapper.asMovieModel
import com.maximillianleonov.cinemax.core.data.util.Constants
import com.maximillianleonov.cinemax.core.datastore.PreferencesDataStoreDataSource
import com.maximillianleonov.cinemax.core.domain.model.MovieModel
import com.maximillianleonov.cinemax.core.network.model.movie.NetworkMovie
import com.maximillianleonov.cinemax.core.network.source.MovieNetworkDataSource
import com.maximillianleonov.cinemax.core.network.util.DEFAULT_PAGE
import kotlinx.coroutines.flow.first
import java.io.IOException

class SearchMoviePagingSource(
private val query: String,
private val networkDataSource: MovieNetworkDataSource
private val networkDataSource: MovieNetworkDataSource,
private val preferencesDataStoreDataSource: PreferencesDataStoreDataSource
) : PagingSource<Int, MovieModel>() {

override fun getRefreshKey(state: PagingState<Int, MovieModel>) = state.anchorPosition
Expand All @@ -40,7 +43,11 @@ class SearchMoviePagingSource(
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MovieModel> {
return try {
val currentPage = params.key ?: DEFAULT_PAGE
val response = networkDataSource.search(query = query, page = currentPage)
val response = networkDataSource.search(
query = query,
language = preferencesDataStoreDataSource.getContentLanguage().first(),
page = currentPage
)

when {
response.isSuccess() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@ import com.maximillianleonov.cinemax.core.common.result.isFailure
import com.maximillianleonov.cinemax.core.common.result.isSuccess
import com.maximillianleonov.cinemax.core.data.mapper.asTvShowModel
import com.maximillianleonov.cinemax.core.data.util.Constants
import com.maximillianleonov.cinemax.core.datastore.PreferencesDataStoreDataSource
import com.maximillianleonov.cinemax.core.domain.model.TvShowModel
import com.maximillianleonov.cinemax.core.network.model.tvshow.NetworkTvShow
import com.maximillianleonov.cinemax.core.network.source.TvShowNetworkDataSource
import com.maximillianleonov.cinemax.core.network.util.DEFAULT_PAGE
import kotlinx.coroutines.flow.first
import java.io.IOException

class SearchTvShowPagingSource(
private val query: String,
private val networkDataSource: TvShowNetworkDataSource
private val networkDataSource: TvShowNetworkDataSource,
private val preferencesDataStoreDataSource: PreferencesDataStoreDataSource
) : PagingSource<Int, TvShowModel>() {

override fun getRefreshKey(state: PagingState<Int, TvShowModel>) = state.anchorPosition
Expand All @@ -40,7 +43,11 @@ class SearchTvShowPagingSource(
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TvShowModel> {
return try {
val currentPage = params.key ?: DEFAULT_PAGE
val response = networkDataSource.search(query = query, page = currentPage)
val response = networkDataSource.search(
query = query,
language = preferencesDataStoreDataSource.getContentLanguage().first(),
page = currentPage
)

when {
response.isSuccess() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ import com.maximillianleonov.cinemax.core.database.model.common.MediaType
import com.maximillianleonov.cinemax.core.database.model.tvshow.TvShowEntity
import com.maximillianleonov.cinemax.core.database.model.tvshow.TvShowRemoteKeyEntity
import com.maximillianleonov.cinemax.core.database.source.TvShowDatabaseDataSource
import com.maximillianleonov.cinemax.core.datastore.PreferencesDataStoreDataSource
import com.maximillianleonov.cinemax.core.network.source.TvShowNetworkDataSource
import kotlinx.coroutines.flow.first
import java.io.IOException

@OptIn(ExperimentalPagingApi::class)
class TvShowRemoteMediator(
private val databaseDataSource: TvShowDatabaseDataSource,
private val networkDataSource: TvShowNetworkDataSource,
private val preferencesDataStoreDataSource: PreferencesDataStoreDataSource,
private val mediaType: MediaType.TvShow
) : RemoteMediator<Int, TvShowEntity>() {
@Suppress("ReturnCount")
Expand Down Expand Up @@ -71,6 +74,7 @@ class TvShowRemoteMediator(

val response = networkDataSource.getByMediaType(
mediaType = mediaType.asNetworkMediaType(),
language = preferencesDataStoreDataSource.getContentLanguage().first(),
page = currentPage
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,22 @@ import com.maximillianleonov.cinemax.core.data.mapper.asMovieDetailsModel
import com.maximillianleonov.cinemax.core.data.mapper.listMap
import com.maximillianleonov.cinemax.core.database.source.MovieDetailsDatabaseDataSource
import com.maximillianleonov.cinemax.core.database.source.WishlistDatabaseDataSource
import com.maximillianleonov.cinemax.core.datastore.PreferencesDataStoreDataSource
import com.maximillianleonov.cinemax.core.domain.model.MovieDetailsModel
import com.maximillianleonov.cinemax.core.domain.repository.MovieDetailsRepository
import com.maximillianleonov.cinemax.core.network.common.networkBoundResource
import com.maximillianleonov.cinemax.core.network.model.movie.NetworkMovieDetails
import com.maximillianleonov.cinemax.core.network.source.MovieDetailsNetworkDataSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class MovieDetailsRepositoryImpl @Inject constructor(
private val databaseDataSource: MovieDetailsDatabaseDataSource,
private val networkDataSource: MovieDetailsNetworkDataSource,
private val wishlistDatabaseDataSource: WishlistDatabaseDataSource
private val wishlistDatabaseDataSource: WishlistDatabaseDataSource,
private val preferencesDataStoreDataSource: PreferencesDataStoreDataSource
) : MovieDetailsRepository {
override fun getById(id: Int): Flow<CinemaxResult<MovieDetailsModel?>> = networkBoundResource(
query = {
Expand All @@ -44,7 +47,12 @@ class MovieDetailsRepositoryImpl @Inject constructor(
)
}
},
fetch = { networkDataSource.getById(id) },
fetch = {
networkDataSource.getById(
id = id,
language = preferencesDataStoreDataSource.getContentLanguage().first()
)
},
saveFetchResult = { response ->
databaseDataSource.deleteAndInsert(response.asMovieDetailsEntity())
}
Expand All @@ -59,7 +67,12 @@ class MovieDetailsRepositoryImpl @Inject constructor(
)
}
},
fetch = { networkDataSource.getByIds(ids) },
fetch = {
networkDataSource.getByIds(
ids = ids,
language = preferencesDataStoreDataSource.getContentLanguage().first()
)
},
saveFetchResult = { response ->
databaseDataSource.deleteAndInsertAll(
response.map(NetworkMovieDetails::asMovieDetailsEntity)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,21 @@ import com.maximillianleonov.cinemax.core.data.paging.SearchMoviePagingSource
import com.maximillianleonov.cinemax.core.data.util.defaultPagingConfig
import com.maximillianleonov.cinemax.core.database.model.movie.MovieEntity
import com.maximillianleonov.cinemax.core.database.source.MovieDatabaseDataSource
import com.maximillianleonov.cinemax.core.datastore.PreferencesDataStoreDataSource
import com.maximillianleonov.cinemax.core.domain.model.MediaTypeModel
import com.maximillianleonov.cinemax.core.domain.model.MovieModel
import com.maximillianleonov.cinemax.core.domain.repository.MovieRepository
import com.maximillianleonov.cinemax.core.network.common.networkBoundResource
import com.maximillianleonov.cinemax.core.network.source.MovieNetworkDataSource
import com.maximillianleonov.cinemax.core.network.util.PAGE_SIZE
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import javax.inject.Inject

class MovieRepositoryImpl @Inject constructor(
private val databaseDataSource: MovieDatabaseDataSource,
private val networkDataSource: MovieNetworkDataSource
private val networkDataSource: MovieNetworkDataSource,
private val preferencesDataStoreDataSource: PreferencesDataStoreDataSource
) : MovieRepository {
override fun getByMediaType(
mediaTypeModel: MediaTypeModel.Movie
Expand All @@ -55,7 +58,12 @@ class MovieRepositoryImpl @Inject constructor(
pageSize = PAGE_SIZE
).listMap(MovieEntity::asMovieModel)
},
fetch = { networkDataSource.getByMediaType(mediaType.asNetworkMediaType()) },
fetch = {
networkDataSource.getByMediaType(
mediaType = mediaType.asNetworkMediaType(),
language = preferencesDataStoreDataSource.getContentLanguage().first()
)
},
saveFetchResult = { response ->
databaseDataSource.deleteByMediaTypeAndInsertAll(
mediaType = mediaType,
Expand All @@ -72,13 +80,24 @@ class MovieRepositoryImpl @Inject constructor(
val mediaType = mediaTypeModel.asMediaType()
return Pager(
config = defaultPagingConfig,
remoteMediator = MovieRemoteMediator(databaseDataSource, networkDataSource, mediaType),
remoteMediator = MovieRemoteMediator(
databaseDataSource = databaseDataSource,
networkDataSource = networkDataSource,
preferencesDataStoreDataSource = preferencesDataStoreDataSource,
mediaType = mediaType
),
pagingSourceFactory = { databaseDataSource.getPagingByMediaType(mediaType) }
).flow.pagingMap(MovieEntity::asMovieModel)
}

override fun search(query: String): Flow<PagingData<MovieModel>> = Pager(
config = defaultPagingConfig,
pagingSourceFactory = { SearchMoviePagingSource(query, networkDataSource) }
pagingSourceFactory = {
SearchMoviePagingSource(
query = query,
networkDataSource = networkDataSource,
preferencesDataStoreDataSource = preferencesDataStoreDataSource
)
}
).flow
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,33 @@

package com.maximillianleonov.cinemax.core.data.repository

import com.maximillianleonov.cinemax.core.data.util.titlecase
import com.maximillianleonov.cinemax.core.database.source.SettingsDatabaseDataSource
import com.maximillianleonov.cinemax.core.datastore.PreferencesDataStoreDataSource
import com.maximillianleonov.cinemax.core.domain.repository.SettingsRepository
import java.util.Locale
import javax.inject.Inject

class SettingsRepositoryImpl @Inject constructor(
databaseDataSource: SettingsDatabaseDataSource
databaseDataSource: SettingsDatabaseDataSource,
private val preferencesDataStoreDataSource: PreferencesDataStoreDataSource
) : SettingsRepository {
override val repoUrl = databaseDataSource.repoUrl
override val privacyPolicyUrl = databaseDataSource.privacyPolicyUrl
override val version = databaseDataSource.version

override fun getAvailableLanguages(): Map<String, String> {
val languages = mutableMapOf<String, String>()
Locale.getAvailableLocales()
.sortedBy(Locale::getDisplayLanguage)
.forEach { locale ->
languages[locale.language] = locale.displayLanguage.titlecase()
}
return languages
}

override fun getContentLanguage() = preferencesDataStoreDataSource.getContentLanguage()
override suspend fun setContentLanguage(contentLanguage: String) {
preferencesDataStoreDataSource.setContentLanguage(contentLanguage)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,22 @@ import com.maximillianleonov.cinemax.core.data.mapper.asTvShowDetailsModel
import com.maximillianleonov.cinemax.core.data.mapper.listMap
import com.maximillianleonov.cinemax.core.database.source.TvShowDetailsDatabaseDataSource
import com.maximillianleonov.cinemax.core.database.source.WishlistDatabaseDataSource
import com.maximillianleonov.cinemax.core.datastore.PreferencesDataStoreDataSource
import com.maximillianleonov.cinemax.core.domain.model.TvShowDetailsModel
import com.maximillianleonov.cinemax.core.domain.repository.TvShowDetailsRepository
import com.maximillianleonov.cinemax.core.network.common.networkBoundResource
import com.maximillianleonov.cinemax.core.network.model.tvshow.NetworkTvShowDetails
import com.maximillianleonov.cinemax.core.network.source.TvShowDetailsNetworkDataSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class TvShowDetailsRepositoryImpl @Inject constructor(
private val databaseDataSource: TvShowDetailsDatabaseDataSource,
private val networkDataSource: TvShowDetailsNetworkDataSource,
private val wishlistDatabaseDataSource: WishlistDatabaseDataSource
private val wishlistDatabaseDataSource: WishlistDatabaseDataSource,
private val preferencesDataStoreDataSource: PreferencesDataStoreDataSource
) : TvShowDetailsRepository {
override fun getById(id: Int): Flow<CinemaxResult<TvShowDetailsModel?>> = networkBoundResource(
query = {
Expand All @@ -44,7 +47,12 @@ class TvShowDetailsRepositoryImpl @Inject constructor(
)
}
},
fetch = { networkDataSource.getById(id) },
fetch = {
networkDataSource.getById(
id = id,
language = preferencesDataStoreDataSource.getContentLanguage().first()
)
},
saveFetchResult = { response ->
databaseDataSource.deleteAndInsert(response.asTvShowDetailsEntity())
}
Expand All @@ -59,7 +67,12 @@ class TvShowDetailsRepositoryImpl @Inject constructor(
)
}
},
fetch = { networkDataSource.getByIds(ids) },
fetch = {
networkDataSource.getByIds(
ids = ids,
language = preferencesDataStoreDataSource.getContentLanguage().first()
)
},
saveFetchResult = { response ->
databaseDataSource.deleteAndInsertAll(
response.map(NetworkTvShowDetails::asTvShowDetailsEntity)
Expand Down
Loading