diff --git a/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/PreferenceStoreDatabase.kt b/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/PreferenceStoreDatabase.kt new file mode 100644 index 0000000..81095b8 --- /dev/null +++ b/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/PreferenceStoreDatabase.kt @@ -0,0 +1,22 @@ +package com.developersbreach.composeactors.data.datasource.database + +import android.content.Context +import com.developersbreach.composeactors.utils.PreferenceConstants +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PreferenceStoreDatabase @Inject constructor(@ApplicationContext context: Context){ + + private val sharedPreferences = + context.applicationContext.getSharedPreferences("compose_actors", Context.MODE_PRIVATE) + + fun getRegion(): String? { + return sharedPreferences.getString(PreferenceConstants.USER_REGION, null) + } + + fun setString(key: String, value: String) { + sharedPreferences.edit().putString(key, value).apply() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/dao/UserRegionDao.kt b/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/dao/UserRegionDao.kt new file mode 100644 index 0000000..66a1e53 --- /dev/null +++ b/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/dao/UserRegionDao.kt @@ -0,0 +1,18 @@ +package com.developersbreach.composeactors.data.datasource.database.dao + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update +import com.developersbreach.composeactors.data.datasource.database.entity.UserRegionEntity + +@Dao +interface UserRegionDao { + + @Update(onConflict = OnConflictStrategy.REPLACE) + fun editUserRegion(userRegionEntity: UserRegionEntity) + + @Query("SELECT * FROM user_region_table") + fun getSavedUserRegion(): LiveData +} \ No newline at end of file diff --git a/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/entity/UserRegionEntity.kt b/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/entity/UserRegionEntity.kt new file mode 100644 index 0000000..91d169d --- /dev/null +++ b/app/src/main/java/com/developersbreach/composeactors/data/datasource/database/entity/UserRegionEntity.kt @@ -0,0 +1,16 @@ +package com.developersbreach.composeactors.data.datasource.database.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "user_region_table") +data class UserRegionEntity( + + @PrimaryKey + @ColumnInfo(name = "user_region_country_code") + val countryCode: Int, + + @ColumnInfo(name = "user_region_country_name") + val countryName: String +) \ No newline at end of file diff --git a/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/JsonRemoteData.kt b/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/JsonRemoteData.kt index 7cb47da..a94d0de 100644 --- a/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/JsonRemoteData.kt +++ b/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/JsonRemoteData.kt @@ -258,8 +258,12 @@ class JsonRemoteData @Inject constructor( val movieList: MutableList = ArrayList() val baseJsonArray = JSONObject(response) val moviesJsonArray = baseJsonArray.getJSONArray("results") - - for (notI: Int in 0 until 5) { + val upcomingMovieCount = if (moviesJsonArray.length() >= 5) { + 5 + } else { + moviesJsonArray.length() + } + for (notI: Int in 0 until upcomingMovieCount) { val jsonObject = moviesJsonArray.getJSONObject(notI) val movieId = jsonObject.getInt("id") val originalTitle = jsonObject.getString("original_title") diff --git a/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/NetworkDataSource.kt b/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/NetworkDataSource.kt index 2f05086..89d49c9 100644 --- a/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/NetworkDataSource.kt +++ b/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/NetworkDataSource.kt @@ -29,15 +29,15 @@ class NetworkDataSource @Inject constructor( ) { /*** @return the result of latest list of all popular actors fetched from the network.*/ - suspend fun getPopularActorsData(): List = withContext(Dispatchers.IO) { - val requestUrl = requestUrls.getPopularActorsUrl() + suspend fun getPopularActorsData(region: String?): List = withContext(Dispatchers.IO) { + val requestUrl = requestUrls.getPopularActorsUrl(region) val response: String = queryUtils.getResponseFromHttpUrl(requestUrl) jsonData.fetchActorsJsonData(response) } /** @return the result of latest list of all trending actors fetched from the network. */ - suspend fun getTrendingActorsData(): List = withContext(Dispatchers.IO) { - val requestUrl = requestUrls.getTrendingActorsUrl() + suspend fun getTrendingActorsData(region: String?): List = withContext(Dispatchers.IO) { + val requestUrl = requestUrls.getTrendingActorsUrl(region) val response = queryUtils.getResponseFromHttpUrl(requestUrl) jsonData.fetchActorsJsonData(response) } @@ -79,9 +79,10 @@ class NetworkDataSource @Inject constructor( * @return the result of list of movies which are based on current movie id. */ suspend fun getSimilarMoviesByIdData( - movieId: Int + movieId: Int, + region: String? ): List = withContext(Dispatchers.IO) { - val requestUrl = requestUrls.getSimilarMoviesUrl(movieId) + val requestUrl = requestUrls.getSimilarMoviesUrl(movieId, region = region) val response = queryUtils.getResponseFromHttpUrl(requestUrl) jsonData.fetchSimilarAndRecommendedMoviesJsonData(response) } @@ -91,9 +92,10 @@ class NetworkDataSource @Inject constructor( * @return the result of list of movies which are based on current movie id. */ suspend fun getRecommendedMoviesByIdData( - movieId: Int + movieId: Int, + region: String? ): List = withContext(Dispatchers.IO) { - val requestUrl = requestUrls.getRecommendedMoviesUrl(movieId) + val requestUrl = requestUrls.getRecommendedMoviesUrl(movieId, region = region) val response = queryUtils.getResponseFromHttpUrl(requestUrl) jsonData.fetchSimilarAndRecommendedMoviesJsonData(response) } @@ -110,8 +112,8 @@ class NetworkDataSource @Inject constructor( jsonData.fetchMovieCastByIdJsonData(response) } - suspend fun getUpcomingMoviesData(): List = withContext(Dispatchers.IO) { - val requestUrl = requestUrls.getUpcomingMoviesUrl() + suspend fun getUpcomingMoviesData(region: String?): List = withContext(Dispatchers.IO) { + val requestUrl = requestUrls.getUpcomingMoviesUrl(region = region) val response = queryUtils.getResponseFromHttpUrl(requestUrl) jsonData.fetchUpcomingMoviesJsonData(response) } @@ -125,9 +127,10 @@ class NetworkDataSource @Inject constructor( } suspend fun getNowPlayingMoviesData( - page: Int + page: Int, + region: String? ): PagedResponse = withContext(Dispatchers.IO) { - val requestUrl = requestUrls.getNowPlayingMoviesUrl(page) + val requestUrl = requestUrls.getNowPlayingMoviesUrl(page, region) val response = queryUtils.getResponseFromHttpUrl(requestUrl) jsonData.fetchNowPlayingMoviesJsonData(response) } diff --git a/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/RequestUrls.kt b/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/RequestUrls.kt index 1efdd12..211210e 100644 --- a/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/RequestUrls.kt +++ b/app/src/main/java/com/developersbreach/composeactors/data/datasource/network/RequestUrls.kt @@ -12,13 +12,13 @@ import javax.inject.Singleton class RequestUrls @Inject constructor() { // https://api.themoviedb.org/3/person/popular?api_key=API_KEY - fun getPopularActorsUrl(): URL { - return URL("${BASE_URL}person/popular?$API_KEY") + fun getPopularActorsUrl(region: String?): URL { + return URL("${BASE_URL}person/popular?$API_KEY®ion=$region") } // https://api.themoviedb.org/3/trending/person/week?api_key=API_KEY - fun getTrendingActorsUrl(): URL { - return URL("${BASE_URL}trending/person/week?$API_KEY") + fun getTrendingActorsUrl(region: String?): URL { + return URL("${BASE_URL}trending/person/week?$API_KEY®ion=$region") } // https://api.themoviedb.org/3/person/3233?api_key=API_KEY @@ -59,17 +59,19 @@ class RequestUrls @Inject constructor() { // https://api.themoviedb.org/3/movie/{movie_id}/recommendations?api_key=API_KEY&page=1 fun getRecommendedMoviesUrl( movieId: Int, - page: Int = 1 + page: Int = 1, + region: String? ): URL { - return URL("${BASE_URL}movie/$movieId/recommendations?$API_KEY&page=$page") + return URL("${BASE_URL}movie/$movieId/recommendations?$API_KEY&page=$page®ion=$region") } // https://api.themoviedb.org/3/movie/{movie_id}/similar?api_key=API_KEY&page=1 fun getSimilarMoviesUrl( movieId: Int, - page: Int = 1 + page: Int = 1, + region: String? ): URL { - return URL("${BASE_URL}movie/$movieId/similar?$API_KEY&page=$page") + return URL("${BASE_URL}movie/$movieId/similar?$API_KEY&page=$page®ion=$region") } // 299536 @@ -97,9 +99,10 @@ class RequestUrls @Inject constructor() { // https://api.themoviedb.org/3/movie/upcoming?api_key=API_KEY&page=1 fun getUpcomingMoviesUrl( - page: Int = 1 + page: Int = 1, + region: String? ): URL { - return URL("${BASE_URL}movie/upcoming?$API_KEY&page=$page") + return URL("${BASE_URL}movie/upcoming?$API_KEY&page=$page®ion=$region") } // https://api.themoviedb.org/3/movie/{movie_id}/watch/providers?api_key @@ -111,9 +114,10 @@ class RequestUrls @Inject constructor() { // https://api.themoviedb.org/3/movie/now_playing?api_key=API_KEY&page=1 fun getNowPlayingMoviesUrl( - page: Int + page: Int, + region: String? ): URL { - return URL("${BASE_URL}movie/now_playing?$API_KEY&page=$page") + return URL("${BASE_URL}movie/now_playing?$API_KEY&page=$page®ion=${region}") } companion object { diff --git a/app/src/main/java/com/developersbreach/composeactors/data/model/HomeOptionItems.kt b/app/src/main/java/com/developersbreach/composeactors/data/model/HomeOptionItems.kt index 4348c72..2805e1a 100644 --- a/app/src/main/java/com/developersbreach/composeactors/data/model/HomeOptionItems.kt +++ b/app/src/main/java/com/developersbreach/composeactors/data/model/HomeOptionItems.kt @@ -28,6 +28,11 @@ data class HomeOptionItems( id = 4, title = "About", icon = R.drawable.ic_about + ), + HomeOptionItems( + id = 5, + title = "Region preference", + icon = R.drawable.ic_edit_location ) ) } diff --git a/app/src/main/java/com/developersbreach/composeactors/data/repository/actor/ActorRepository.kt b/app/src/main/java/com/developersbreach/composeactors/data/repository/actor/ActorRepository.kt index 160ef48..ac9d702 100644 --- a/app/src/main/java/com/developersbreach/composeactors/data/repository/actor/ActorRepository.kt +++ b/app/src/main/java/com/developersbreach/composeactors/data/repository/actor/ActorRepository.kt @@ -7,24 +7,26 @@ import com.developersbreach.composeactors.data.model.Actor import com.developersbreach.composeactors.data.model.ActorDetail import com.developersbreach.composeactors.data.model.FavoriteActor import com.developersbreach.composeactors.data.model.Movie +import com.developersbreach.composeactors.data.repository.user.UserRepository import javax.inject.Inject import javax.inject.Singleton @Singleton class ActorRepository @Inject constructor( private val networkDataSource: NetworkDataSource, - private val databaseDataSource: DatabaseDataSource + private val databaseDataSource: DatabaseDataSource, + private val userRepository: UserRepository ) { suspend fun getPopularActorsData(): List { - return networkDataSource.getPopularActorsData() + return networkDataSource.getPopularActorsData(userRepository.getRegion()) } suspend fun getTrendingActorsData(): List { - return networkDataSource.getTrendingActorsData() + return networkDataSource.getTrendingActorsData(userRepository.getRegion()) } suspend fun getUpcomingMoviesData(): List { - return networkDataSource.getUpcomingMoviesData() + return networkDataSource.getUpcomingMoviesData(userRepository.getRegion()) } suspend fun getSelectedActorData(actorInt: Int): ActorDetail { diff --git a/app/src/main/java/com/developersbreach/composeactors/data/repository/movie/MovieRepository.kt b/app/src/main/java/com/developersbreach/composeactors/data/repository/movie/MovieRepository.kt index a2c0e9b..ca93dea 100644 --- a/app/src/main/java/com/developersbreach/composeactors/data/repository/movie/MovieRepository.kt +++ b/app/src/main/java/com/developersbreach/composeactors/data/repository/movie/MovieRepository.kt @@ -8,17 +8,19 @@ import com.developersbreach.composeactors.data.model.Cast import com.developersbreach.composeactors.data.model.Movie import com.developersbreach.composeactors.data.model.MovieDetail import com.developersbreach.composeactors.data.model.MovieProvider +import com.developersbreach.composeactors.data.repository.user.UserRepository import javax.inject.Inject import javax.inject.Singleton @Singleton class MovieRepository @Inject constructor( private val networkDataSource: NetworkDataSource, - private val databaseDataSource: DatabaseDataSource + private val databaseDataSource: DatabaseDataSource, + private val userRepository: UserRepository ) { suspend fun getNowPlayingMoviesData(page: Int): PagedResponse { - return networkDataSource.getNowPlayingMoviesData(page) + return networkDataSource.getNowPlayingMoviesData(page, userRepository.getRegion()) } suspend fun getSelectedMovieData(movieId: Int): MovieDetail { @@ -26,11 +28,11 @@ class MovieRepository @Inject constructor( } suspend fun getSimilarMoviesByIdData(movieId: Int): List { - return networkDataSource.getSimilarMoviesByIdData(movieId) + return networkDataSource.getSimilarMoviesByIdData(movieId, userRepository.getRegion()) } suspend fun getRecommendedMoviesByIdData(movieId: Int): List { - return networkDataSource.getRecommendedMoviesByIdData(movieId) + return networkDataSource.getRecommendedMoviesByIdData(movieId, userRepository.getRegion()) } suspend fun getMovieCastByIdData(movieId: Int): List { diff --git a/app/src/main/java/com/developersbreach/composeactors/data/repository/user/UserRepository.kt b/app/src/main/java/com/developersbreach/composeactors/data/repository/user/UserRepository.kt new file mode 100644 index 0000000..e7b922f --- /dev/null +++ b/app/src/main/java/com/developersbreach/composeactors/data/repository/user/UserRepository.kt @@ -0,0 +1,36 @@ +package com.developersbreach.composeactors.data.repository.user + +import androidx.compose.runtime.MutableState +import com.developersbreach.composeactors.data.datasource.database.PreferenceStoreDatabase +import com.developersbreach.composeactors.utils.PreferenceConstants +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class UserRepository @Inject constructor(private val preferenceStoreDatabase: PreferenceStoreDatabase) { + + fun setRegion(countryCode: String, setRegionSuccessesCallBack: MutableState): Boolean { + return if (countryCode != getRegion()) { + preferenceStoreDatabase.setString( + PreferenceConstants.USER_REGION, + countryCode + ) + setRegionSuccessesCallBack.value = true + true + } else false + } + + fun setDefaultRegion() { + if (getRegion() == null) { + preferenceStoreDatabase.setString( + PreferenceConstants.USER_REGION, + Locale.getDefault().country + ) + } + } + + fun getRegion(): String? { + return preferenceStoreDatabase.getRegion() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/developersbreach/composeactors/di/PreferenceStoreModule.kt b/app/src/main/java/com/developersbreach/composeactors/di/PreferenceStoreModule.kt new file mode 100644 index 0000000..d372ff1 --- /dev/null +++ b/app/src/main/java/com/developersbreach/composeactors/di/PreferenceStoreModule.kt @@ -0,0 +1,20 @@ +package com.developersbreach.composeactors.di + +import android.content.Context +import com.developersbreach.composeactors.data.datasource.database.PreferenceStoreDatabase +import com.google.android.datatransport.runtime.dagger.Provides +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object PreferenceStoreModule { + @Provides + @Singleton + fun providePreferenceStore(@ApplicationContext context: Context): PreferenceStoreDatabase { + return PreferenceStoreDatabase(context = context.applicationContext) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/developersbreach/composeactors/ui/components/RegionEditDialog.kt b/app/src/main/java/com/developersbreach/composeactors/ui/components/RegionEditDialog.kt new file mode 100644 index 0000000..d37e568 --- /dev/null +++ b/app/src/main/java/com/developersbreach/composeactors/ui/components/RegionEditDialog.kt @@ -0,0 +1,141 @@ +package com.developersbreach.composeactors.ui.components + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Close +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Popup +import com.developersbreach.composeactors.R +import com.developersbreach.composeactors.utils.getCountryListWithCode + +@Composable +fun RegionEditDialog( + popupState: MutableState, + onRegionSelect: (String, String) -> Unit +) { + if (popupState.value) { + val regions = getCountryListWithCode() + Popup(alignment = Alignment.Center, onDismissRequest = { popupState.value = false }) { + Column( + modifier = Modifier + .fillMaxWidth() + .height(300.dp) + .padding(horizontal = 50.dp) + .clip(shape = RoundedCornerShape(16.dp)) + ) { + DropdownMenu( + regionList = regions, + modifier = Modifier, + onRegionSelect = onRegionSelect, + popupState = popupState + ) + } + } + } +} + +@Composable +fun DropdownMenu( + regionList: List, + modifier: Modifier = Modifier, + onRegionSelect: (String, String) -> Unit, + popupState: MutableState +) { + Column( + Modifier + .fillMaxWidth() + .fillMaxHeight() + .background(MaterialTheme.colors.surface) + .padding(horizontal = 16.dp) + ) { + + Header(popupState) + + LazyColumn(modifier = Modifier.fillMaxWidth()) { + items(regionList) { region -> + val countryCodeAndName = region.split(",") + DropdownMenuItem( + text = countryCodeAndName[1], + onClick = { onRegionSelect(countryCodeAndName[0], countryCodeAndName[1]) }, + popupState = popupState + ) + } + } + } +} + +@Composable +fun Header(popupState: MutableState) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier + .padding(8.dp) + .padding(vertical = 8.dp) + .fillMaxWidth() + ) { + Text( + stringResource(R.string.choose_region), + style = MaterialTheme.typography.subtitle1 + ) + Image( + imageVector = Icons.Rounded.Close, + contentDescription = stringResource(R.string.close_pop_up_icon), + modifier = Modifier.clickable { + popupState.value = false + } + ) + } +} + +@Composable +fun DropdownMenuItem( + text: String, + onClick: () -> Unit, + popupState: MutableState +) { + Box( + modifier = Modifier + .clickable { + onClick() + popupState.value = false + } + .background(MaterialTheme.colors.surface) + .padding(horizontal = 24.dp) + .padding(8.dp) + ) { + Text(text, style = MaterialTheme.typography.subtitle2) + } +} + +@Preview +@Composable +private fun RegionEditDialogPreview() { + RegionEditDialog( + popupState = remember { mutableStateOf(true) }, + onRegionSelect = { _: String, _: String -> } + ) +} diff --git a/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeScreen.kt b/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeScreen.kt index 46e3761..bece090 100644 --- a/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeScreen.kt +++ b/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeScreen.kt @@ -1,11 +1,17 @@ package com.developersbreach.composeactors.ui.screens.home -import androidx.compose.material.* +import android.widget.Toast +import androidx.compose.material.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel +import com.developersbreach.composeactors.R import com.developersbreach.composeactors.ui.screens.search.SearchType /** @@ -29,6 +35,28 @@ fun HomeScreen( ) { val navigateToSearchBySearchType by viewModel.updateHomeSearchType.observeAsState(SearchType.Actors) + val setRegionSuccessesCallBack = remember { mutableStateOf(false) } + val selectedCountryName = remember { mutableStateOf("") } + + if (setRegionSuccessesCallBack.value) { + if (selectedCountryName.value.isNotEmpty()) { + Toast.makeText( + LocalContext.current, + stringResource(R.string.region_successfully_changed_to, selectedCountryName.value), + Toast.LENGTH_LONG + ).show() + } + setRegionSuccessesCallBack.value = false + } + + val onRegionSelect: (String, String) -> Unit = { countryCode, countryName -> + selectedCountryName.value = countryName + viewModel.setRegion( + countryCode = countryCode, + setRegionSuccessesCallBack = setRegionSuccessesCallBack + ) + } + HomeScreenUI( modifier = Modifier, navigateToFavorite = navigateToFavorite, @@ -37,6 +65,7 @@ fun HomeScreen( navigateToSearchBySearchType = navigateToSearchBySearchType, navigateToSelectedActor = navigateToSelectedActor, navigateToSelectedMovie = navigateToSelectedMovie, + onRegionSelect = onRegionSelect, uiState = viewModel.uiState, sheetUiState = viewModel.sheetUiState, updateHomeSearchType = { searchType: SearchType -> diff --git a/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeScreenUI.kt b/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeScreenUI.kt index d1e2cc0..da34a72 100644 --- a/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeScreenUI.kt +++ b/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeScreenUI.kt @@ -20,6 +20,9 @@ import androidx.compose.material.Surface import androidx.compose.material.rememberModalBottomSheetState import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag @@ -31,6 +34,7 @@ import com.developersbreach.composeactors.data.datasource.fake.fakeMovieList import com.developersbreach.composeactors.ui.components.ApiKeyMissingShowSnackbar import com.developersbreach.composeactors.ui.components.AppDivider import com.developersbreach.composeactors.ui.components.IfOfflineShowSnackbar +import com.developersbreach.composeactors.ui.components.RegionEditDialog import com.developersbreach.composeactors.ui.components.TabItem import com.developersbreach.composeactors.ui.components.TabsContainer import com.developersbreach.composeactors.ui.screens.home.tabs.ActorsTabContent @@ -51,6 +55,7 @@ fun HomeScreenUI( navigateToSearchBySearchType: SearchType, navigateToSelectedActor: (Int) -> Unit, navigateToSelectedMovie: (Int) -> Unit, + onRegionSelect: (String, String) -> Unit, uiState: HomeUIState, sheetUiState: HomeSheetUIState, updateHomeSearchType: (SearchType) -> Unit @@ -62,6 +67,19 @@ fun HomeScreenUI( animationSpec = tween(durationMillis = 500), skipHalfExpanded = true ) + val popupState = remember { mutableStateOf(false) } + + val regionBtnClick = { + popupState.value = true + } + + RegionEditDialog(popupState = popupState, onRegionSelect = onRegionSelect) + + if (popupState.value) { + LaunchedEffect(popupState) { + modalSheetState.hide() + } + } Surface( color = MaterialTheme.colors.background, @@ -79,7 +97,8 @@ fun HomeScreenUI( navigateToFavorite = navigateToFavorite, navigateToSearch = { navigateToSearch(SearchType.Movies) }, navigateToProfile = { }, - navigateToAbout = navigateToAbout + navigateToAbout = navigateToAbout, + regionBtnClick = regionBtnClick ) }, ) { diff --git a/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeViewModel.kt b/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeViewModel.kt index e337ebf..c91d99f 100644 --- a/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeViewModel.kt +++ b/app/src/main/java/com/developersbreach/composeactors/ui/screens/home/HomeViewModel.kt @@ -1,5 +1,6 @@ package com.developersbreach.composeactors.ui.screens.home +import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -8,10 +9,10 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.developersbreach.composeactors.data.repository.actor.ActorRepository +import com.developersbreach.composeactors.data.repository.user.UserRepository import com.developersbreach.composeactors.domain.GetPagedMovies import com.developersbreach.composeactors.ui.screens.search.SearchType import dagger.hilt.android.lifecycle.HiltViewModel -import java.io.IOException import javax.inject.Inject import kotlinx.coroutines.launch import timber.log.Timber @@ -22,7 +23,8 @@ import timber.log.Timber @HiltViewModel class HomeViewModel @Inject constructor( private val actorRepository: ActorRepository, - private val getPagedMovies: GetPagedMovies + private val getPagedMovies: GetPagedMovies, + private val userRepository: UserRepository ) : ViewModel() { var uiState by mutableStateOf(HomeUIState()) @@ -35,15 +37,27 @@ class HomeViewModel @Inject constructor( val updateHomeSearchType: LiveData = _updateHomeSearchType init { + setData() + } + + private fun setData() { viewModelScope.launch { try { + userRepository.setDefaultRegion() startFetchingActors() - } catch (e: IOException) { + } catch (e: Exception) { Timber.e("$e") } } } + fun setRegion(countryCode: String, setRegionSuccessesCallBack: MutableState) { + val success = userRepository.setRegion(countryCode, setRegionSuccessesCallBack) + if (success) { + setData() + } + } + private suspend fun startFetchingActors() { uiState = HomeUIState(isFetchingActors = true) uiState = HomeUIState( diff --git a/app/src/main/java/com/developersbreach/composeactors/ui/screens/modalSheets/OptionsModalSheetContent.kt b/app/src/main/java/com/developersbreach/composeactors/ui/screens/modalSheets/OptionsModalSheetContent.kt index 085bad2..3c42191 100644 --- a/app/src/main/java/com/developersbreach/composeactors/ui/screens/modalSheets/OptionsModalSheetContent.kt +++ b/app/src/main/java/com/developersbreach/composeactors/ui/screens/modalSheets/OptionsModalSheetContent.kt @@ -44,10 +44,11 @@ import kotlinx.coroutines.launch fun OptionsModalSheetContent( modalSheetSheet: ModalBottomSheetState, coroutineScope: CoroutineScope = rememberCoroutineScope(), - navigateToFavorite:() -> Unit, + navigateToFavorite: () -> Unit, navigateToSearch: () -> Unit, navigateToProfile: () -> Unit, - navigateToAbout: () -> Unit + navigateToAbout: () -> Unit, + regionBtnClick: () -> Unit ) { Column( modifier = Modifier @@ -100,7 +101,8 @@ fun OptionsModalSheetContent( navigateToFavorite = navigateToFavorite, navigateToSearch = navigateToSearch, navigateToProfile = navigateToProfile, - navigateToAbout = navigateToAbout + navigateToAbout = navigateToAbout, + regionBtnClick = regionBtnClick ) } } @@ -113,7 +115,8 @@ private fun ItemOptionRow( navigateToFavorite: () -> Unit, navigateToSearch: () -> Unit, navigateToProfile: () -> Unit, - navigateToAbout: () -> Unit + navigateToAbout: () -> Unit, + regionBtnClick: () -> Unit ) { Row( verticalAlignment = Alignment.CenterVertically, @@ -126,6 +129,7 @@ private fun ItemOptionRow( 2 -> navigateToSearch() 3 -> navigateToProfile() 4 -> navigateToAbout() + 5 -> regionBtnClick() } } .padding(top = 8.dp, start = 20.dp, end = 20.dp, bottom = 8.dp) @@ -156,7 +160,8 @@ private fun OptionsModalSheetContentLightPreview() { navigateToFavorite = {}, navigateToSearch = {}, navigateToProfile = {}, - navigateToAbout = {} + navigateToAbout = {}, + regionBtnClick = {} ) } } @@ -171,7 +176,8 @@ private fun OptionsModalSheetContentDarkPreview() { navigateToFavorite = {}, navigateToSearch = {}, navigateToProfile = {}, - navigateToAbout = {} + navigateToAbout = {}, + regionBtnClick = {} ) } } \ No newline at end of file diff --git a/app/src/main/java/com/developersbreach/composeactors/utils/PreferenceConstants.kt b/app/src/main/java/com/developersbreach/composeactors/utils/PreferenceConstants.kt new file mode 100644 index 0000000..bf1abe4 --- /dev/null +++ b/app/src/main/java/com/developersbreach/composeactors/utils/PreferenceConstants.kt @@ -0,0 +1,5 @@ +package com.developersbreach.composeactors.utils + +object PreferenceConstants { + const val USER_REGION = "user_region" +} \ No newline at end of file diff --git a/app/src/main/java/com/developersbreach/composeactors/utils/Utilities.kt b/app/src/main/java/com/developersbreach/composeactors/utils/Utilities.kt index 0a95d5f..3774688 100644 --- a/app/src/main/java/com/developersbreach/composeactors/utils/Utilities.kt +++ b/app/src/main/java/com/developersbreach/composeactors/utils/Utilities.kt @@ -59,4 +59,15 @@ fun getMovieRuntimeFormatted( val hours: Int? = runtime?.div(60) val minutes: Int? = runtime?.rem(60) return "${hours}h:${minutes}m" +} + +fun getCountryListWithCode(): List { + val region = arrayListOf() + val isoCountryCodes: Array = Locale.getISOCountries() + for (countryCode in isoCountryCodes) { + val locale = Locale("", countryCode) + val countryName: String = locale.displayCountry + region.add("$countryCode,$countryName") + } + return region } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_edit_location.xml b/app/src/main/res/drawable/ic_edit_location.xml new file mode 100644 index 0000000..88a515e --- /dev/null +++ b/app/src/main/res/drawable/ic_edit_location.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dd92b31..b2fbe06 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,11 +33,14 @@ Movie Providers Watch providers No watch options available! - + Logo of TMDB Api The data and images displayed in this app are sourced from TMDB Api, a comprehensive movie and TV show database. + Choose region: + close pop up icon + Region successfully changed to %1$s \ No newline at end of file