From 7941200b13513df31be76767deea43c701a27150 Mon Sep 17 00:00:00 2001 From: Owen LeJeune Date: Wed, 14 Jun 2023 16:50:35 -0400 Subject: [PATCH] wait for configuration details and use them for image loading --- .../owenlejeune/tvtime/AppRoutingActivity.kt | 18 +++++-- .../com/owenlejeune/tvtime/MainActivity.kt | 3 -- .../tvtime/ui/screens/MediaDetailScreen.kt | 10 +--- .../ui/viewmodel/ConfigurationViewModel.kt | 53 +++++++++++-------- .../tvtime/ui/viewmodel/SettingsViewModel.kt | 39 ++++++-------- .../com/owenlejeune/tvtime/utils/TmdbUtils.kt | 35 ++++++------ 6 files changed, 80 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/com/owenlejeune/tvtime/AppRoutingActivity.kt b/app/src/main/java/com/owenlejeune/tvtime/AppRoutingActivity.kt index fae515a..e147cfb 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/AppRoutingActivity.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/AppRoutingActivity.kt @@ -2,9 +2,13 @@ package com.owenlejeune.tvtime import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope import com.owenlejeune.tvtime.extensions.launchActivity import com.owenlejeune.tvtime.preferences.AppPreferences +import com.owenlejeune.tvtime.ui.viewmodel.ConfigurationViewModel +import com.owenlejeune.tvtime.utils.TmdbUtils import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.getViewModel class AppRoutingActivity: AppCompatActivity() { @@ -13,10 +17,16 @@ class AppRoutingActivity: AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (preferences.firstLaunchTesting || preferences.firstLaunch) { - launchActivity(OnboardingActivity::class.java) - } else { - launchActivity(MainActivity::class.java) + lifecycleScope.launchWhenCreated { + val configurationViewModel = getViewModel() + configurationViewModel.getConfigurations() + TmdbUtils.setup(configurationViewModel) + + if (preferences.firstLaunchTesting || preferences.firstLaunch) { + launchActivity(OnboardingActivity::class.java) + } else { + launchActivity(MainActivity::class.java) + } } } diff --git a/app/src/main/java/com/owenlejeune/tvtime/MainActivity.kt b/app/src/main/java/com/owenlejeune/tvtime/MainActivity.kt index 3bb5ed6..830320b 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/MainActivity.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/MainActivity.kt @@ -36,9 +36,6 @@ class MainActivity : MonetCompatActivity() { lifecycleScope.launchWhenCreated { monet.awaitMonetReady() setContent { - val configurationViewModel = viewModel() - configurationViewModel.getConfigurations() - AppKeyboardFocusManager() TVTimeTheme(monetCompat = monet) { val windowSize = rememberWindowSizeClass() diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt index 11c2df3..27fb280 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt @@ -10,7 +10,6 @@ import androidx.compose.animation.core.tween import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -19,7 +18,6 @@ import androidx.compose.material.icons.filled.Movie import androidx.compose.material.icons.filled.Send import androidx.compose.material.icons.outlined.ExpandMore import androidx.compose.material3.* -import androidx.compose.material.TabRow import androidx.compose.material.icons.filled.Bookmark import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.List @@ -35,7 +33,6 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight @@ -44,14 +41,12 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.util.fastForEachIndexed import androidx.navigation.NavController import coil.compose.AsyncImage import com.google.accompanist.flowlayout.FlowRow import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.PagerState -import com.google.accompanist.pager.pagerTabIndicatorOffset import com.google.accompanist.pager.rememberPagerState import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.owenlejeune.tvtime.R @@ -73,13 +68,10 @@ import com.owenlejeune.tvtime.ui.theme.FavoriteSelected import com.owenlejeune.tvtime.ui.theme.RatingSelected import com.owenlejeune.tvtime.ui.theme.WatchlistSelected import com.owenlejeune.tvtime.ui.theme.actionButtonColor -import com.owenlejeune.tvtime.ui.viewmodel.ConfigurationViewModel import com.owenlejeune.tvtime.utils.SessionManager import com.owenlejeune.tvtime.utils.TmdbUtils import kotlinx.coroutines.* -import okhttp3.internal.notify import org.json.JSONObject -import org.koin.androidx.compose.koinViewModel import org.koin.java.KoinJavaComponent.get import java.text.DecimalFormat @@ -1425,7 +1417,7 @@ private fun WatchProviderContainer( } ) { AsyncImage( - model = TmdbUtils.fullImagePath(item.logoPath), + model = TmdbUtils.fullLogoPath(item.logoPath), contentDescription = null, modifier = Modifier .size(48.dp) diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/viewmodel/ConfigurationViewModel.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/viewmodel/ConfigurationViewModel.kt index 26c8688..b4c5903 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/viewmodel/ConfigurationViewModel.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/viewmodel/ConfigurationViewModel.kt @@ -23,16 +23,25 @@ class ConfigurationViewModel: ViewModel(), KoinComponent { private const val TAG = "ConfigurationViewModel" } + private object Backer { + val detailsConfiguration = mutableStateOf(ConfigurationDetails.Empty) + val countriesConfiguration = mutableStateListOf() + val jobsConfiguration = mutableStateListOf() + val languagesConfiguration = mutableStateListOf() + val primaryTranslationsConfiguration = mutableStateListOf() + val timezonesConfiguration = mutableStateListOf() + } + private val service: ConfigurationApi by inject() - val detailsConfiguration = mutableStateOf(ConfigurationDetails.Empty) - val countriesConfiguration = mutableStateListOf() - val jobsConfiguration = mutableStateListOf() - val languagesConfiguration = mutableStateListOf() - val primaryTranslationsConfiguration = mutableStateListOf() - val timezonesConfiguration = mutableStateListOf() + val detailsConfiguration = Backer.detailsConfiguration + val countriesConfiguration = Backer.countriesConfiguration + val jobsConfiguration = Backer.jobsConfiguration + val languagesConfiguration = Backer.languagesConfiguration + val primaryTranslationsConfiguration = Backer.primaryTranslationsConfiguration + val timezonesConfiguration = Backer.timezonesConfiguration - fun getConfigurations() { + suspend fun getConfigurations() { getDetailsConfiguration() getCountriesConfiguration() getJobsConfiguration() @@ -41,14 +50,14 @@ class ConfigurationViewModel: ViewModel(), KoinComponent { getTimezonesConfiguration() } - fun getDetailsConfiguration() { + suspend fun getDetailsConfiguration() { getConfiguration( { service.getDetailsConfiguration() }, { detailsConfiguration.value = it } ) } - fun getCountriesConfiguration() { + suspend fun getCountriesConfiguration() { getConfiguration( { service.getCountriesConfiguration() }, { @@ -58,7 +67,7 @@ class ConfigurationViewModel: ViewModel(), KoinComponent { ) } - fun getJobsConfiguration() { + suspend fun getJobsConfiguration() { getConfiguration( { service.getJobsConfiguration() }, { @@ -68,7 +77,7 @@ class ConfigurationViewModel: ViewModel(), KoinComponent { ) } - fun getLanguagesConfiguration() { + suspend fun getLanguagesConfiguration() { getConfiguration( { service.getLanguagesConfiguration() }, { @@ -78,7 +87,7 @@ class ConfigurationViewModel: ViewModel(), KoinComponent { ) } - fun getPrimaryTranslationsConfiguration() { + suspend fun getPrimaryTranslationsConfiguration() { getConfiguration( { service.getPrimaryTranslationsConfiguration() }, { @@ -88,7 +97,7 @@ class ConfigurationViewModel: ViewModel(), KoinComponent { ) } - fun getTimezonesConfiguration() { + suspend fun getTimezonesConfiguration() { getConfiguration( { service.getTimezonesConfiguration() }, { @@ -98,20 +107,18 @@ class ConfigurationViewModel: ViewModel(), KoinComponent { ) } - private fun getConfiguration( + private suspend fun getConfiguration( fetcher: suspend () -> Response, bodyHandler: (T) -> Unit ) { - CoroutineScope(Dispatchers.IO).launch { - val response = fetcher() - if (response.isSuccessful) { - response.body()?.let { - Log.d(TAG, "Successfully got configuration: $it") - bodyHandler(it) - } - } else { - Log.e(TAG, "Issue getting configuration") + val response = fetcher() + if (response.isSuccessful) { + response.body()?.let { + Log.d(TAG, "Successfully got configuration: $it") + bodyHandler(it) } + } else { + Log.e(TAG, "Issue getting configuration") } } diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/viewmodel/SettingsViewModel.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/viewmodel/SettingsViewModel.kt index d0bb34c..19a1a73 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/viewmodel/SettingsViewModel.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/viewmodel/SettingsViewModel.kt @@ -7,41 +7,34 @@ import kotlinx.coroutines.flow.asStateFlow import org.koin.core.component.KoinComponent import org.koin.core.component.inject -class SettingsViewModel: ViewModel(), KoinComponent { +class SettingsViewModel: ViewModel() { - private val preferences: AppPreferences by inject() + private companion object Backer: KoinComponent { + private val preferences: AppPreferences by inject() + + private val _showSearchBar = MutableStateFlow(preferences.showSearchBar) + private val _useMultiSearch = MutableStateFlow(preferences.multiSearch) + private val _useWallpaperColor = MutableStateFlow(preferences.useWallpaperColors) + private val _darkTheme = MutableStateFlow(preferences.darkTheme) + private val _useSystemColors = MutableStateFlow(preferences.useSystemColors) + private val _chromaMultiplier = MutableStateFlow(preferences.chromaMultiplier) + private val _selectedColor = MutableStateFlow(preferences.selectedColor) + private val _showBottomTabLabels = MutableStateFlow(preferences.showBottomTabLabels) + private val _showPosterTitles = MutableStateFlow(preferences.showPosterTitles) + private val _firstLaunchTesting = MutableStateFlow(preferences.firstLaunchTesting) + private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery) + } - private val _showSearchBar = MutableStateFlow(preferences.showSearchBar) val showSearchBar = _showSearchBar.asStateFlow() - - private val _useMultiSearch = MutableStateFlow(preferences.multiSearch) val useMultiSearch = _useMultiSearch.asStateFlow() - - private val _useWallpaperColor = MutableStateFlow(preferences.useWallpaperColors) val useWallpaperColors = _useWallpaperColor.asStateFlow() - - private val _darkTheme = MutableStateFlow(preferences.darkTheme) val darkTheme = _darkTheme.asStateFlow() - - private val _useSystemColors = MutableStateFlow(preferences.useSystemColors) val useSystemColors = _useSystemColors.asStateFlow() - - private val _chromaMultiplier = MutableStateFlow(preferences.chromaMultiplier) val chromaMultiplier = _chromaMultiplier.asStateFlow() - - private val _selectedColor = MutableStateFlow(preferences.selectedColor) val selectedColor = _selectedColor.asStateFlow() - - private val _showBottomTabLabels = MutableStateFlow(preferences.showBottomTabLabels) val showBottomTabLabels = _showBottomTabLabels.asStateFlow() - - private val _showPosterTitles = MutableStateFlow(preferences.showPosterTitles) val showPosterTitles = _showPosterTitles.asStateFlow() - - private val _firstLaunchTesting = MutableStateFlow(preferences.firstLaunchTesting) val firstLaunchTesting = _firstLaunchTesting.asStateFlow() - - private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery) val showBackdropGallery = _showBackdropGallery.asStateFlow() fun toggleShowSearchBar() { diff --git a/app/src/main/java/com/owenlejeune/tvtime/utils/TmdbUtils.kt b/app/src/main/java/com/owenlejeune/tvtime/utils/TmdbUtils.kt index 42d4946..d739440 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/utils/TmdbUtils.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/utils/TmdbUtils.kt @@ -14,28 +14,31 @@ import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Status import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TmdbItem import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TvContentRatings import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Video +import com.owenlejeune.tvtime.ui.viewmodel.ConfigurationViewModel import java.text.SimpleDateFormat object TmdbUtils { - private const val POSTER_BASE = "https://image.tmdb.org/t/p/original" -// private const val BACKDROP_BASE = "https://www.themoviedb.org/t/p/original" -// private const val PERSON_BASE = "https://www.themoviedb.org/t/p/w600_and_h900_bestv2" private const val GRAVATAR_BASE = "https://www.gravatar.com/avatar/" -// private const val AVATAR_BASE = "https://www.themoviedb.org/t/p/w150_and_h150_face" -// private const val STILL_BASE = "https://www.themoviedb.org/t/p/w454_and_h254_bestv2/" - private const val BACKDROP_BASE = POSTER_BASE - private const val PERSON_BASE = POSTER_BASE - private const val AVATAR_BASE = POSTER_BASE - private const val STILL_BASE = POSTER_BASE private const val DEF_REGION = "US" - fun fullImagePath(sourcePath: String) = POSTER_BASE.plus(sourcePath) + private var IMAGE_BASE = "" + private var BACKDROP_SIZE = "original" + private var LOGO_SIZE = "original" + private var POSTER_SIZE = "original" + private var PROFILE_SIZE = "original" + private var STILL_SIZE = "original" + + fun setup(configurationViewModel: ConfigurationViewModel) { + IMAGE_BASE = configurationViewModel.detailsConfiguration.value.images.secureBaseUrl + } + + fun fullLogoPath(sourcePath: String) = IMAGE_BASE.plus(LOGO_SIZE).plus(sourcePath) fun getFullPosterPath(posterPath: String?): String? { return posterPath?.let { - if (posterPath.isEmpty()) null else "${POSTER_BASE}${posterPath}" + if (posterPath.isEmpty()) null else IMAGE_BASE.plus(POSTER_SIZE).plus(posterPath) } } @@ -49,7 +52,7 @@ object TmdbUtils { fun getFullBackdropPath(backdropPath: String?): String? { return backdropPath?.let { - if (backdropPath.isEmpty()) null else "${BACKDROP_BASE}${backdropPath}" + if (backdropPath.isEmpty()) null else IMAGE_BASE.plus(BACKDROP_SIZE).plus(backdropPath) } } @@ -62,7 +65,7 @@ object TmdbUtils { } fun getFullPersonImagePath(path: String?): String? { - return path?.let { "${PERSON_BASE}${path}" } + return path?.let { IMAGE_BASE.plus(PROFILE_SIZE).plus(it) } } fun getFullPersonImagePath(person: Person): String? { @@ -74,7 +77,7 @@ object TmdbUtils { if (path.contains("http")) { return path.substring(startIndex = 1) } - "${AVATAR_BASE}${path}" + IMAGE_BASE.plus(LOGO_SIZE).plus(path) } } @@ -84,7 +87,7 @@ object TmdbUtils { fun getFullEpisodeStillPath(path: String?): String? { return path?.let { - "${STILL_BASE}${path}" + IMAGE_BASE.plus(STILL_SIZE).plus(path) } } @@ -211,7 +214,7 @@ object TmdbUtils { fun getAccountAvatarUrl(accountDetails: AccountDetails): String { val path = accountDetails.avatar.tmdb?.avatarPath - return "${AVATAR_BASE}${path}" + return IMAGE_BASE.plus(LOGO_SIZE).plus(path) } fun releaseYearFromData(releaseDate: String): String {