wait for configuration details and use them for image loading

This commit is contained in:
Owen LeJeune
2023-06-14 16:50:35 -04:00
parent 76cfd18bb5
commit 7941200b13
6 changed files with 80 additions and 78 deletions

View File

@@ -2,9 +2,13 @@ package com.owenlejeune.tvtime
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.owenlejeune.tvtime.extensions.launchActivity import com.owenlejeune.tvtime.extensions.launchActivity
import com.owenlejeune.tvtime.preferences.AppPreferences 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.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.getViewModel
class AppRoutingActivity: AppCompatActivity() { class AppRoutingActivity: AppCompatActivity() {
@@ -13,11 +17,17 @@ class AppRoutingActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
lifecycleScope.launchWhenCreated {
val configurationViewModel = getViewModel<ConfigurationViewModel>()
configurationViewModel.getConfigurations()
TmdbUtils.setup(configurationViewModel)
if (preferences.firstLaunchTesting || preferences.firstLaunch) { if (preferences.firstLaunchTesting || preferences.firstLaunch) {
launchActivity(OnboardingActivity::class.java) launchActivity(OnboardingActivity::class.java)
} else { } else {
launchActivity(MainActivity::class.java) launchActivity(MainActivity::class.java)
} }
} }
}
} }

View File

@@ -36,9 +36,6 @@ class MainActivity : MonetCompatActivity() {
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
monet.awaitMonetReady() monet.awaitMonetReady()
setContent { setContent {
val configurationViewModel = viewModel<ConfigurationViewModel>()
configurationViewModel.getConfigurations()
AppKeyboardFocusManager() AppKeyboardFocusManager()
TVTimeTheme(monetCompat = monet) { TVTimeTheme(monetCompat = monet) {
val windowSize = rememberWindowSizeClass() val windowSize = rememberWindowSizeClass()

View File

@@ -10,7 +10,6 @@ import androidx.compose.animation.core.tween
import androidx.compose.foundation.* import androidx.compose.foundation.*
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons 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.filled.Send
import androidx.compose.material.icons.outlined.ExpandMore import androidx.compose.material.icons.outlined.ExpandMore
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.material.TabRow
import androidx.compose.material.icons.filled.Bookmark import androidx.compose.material.icons.filled.Bookmark
import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.List 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.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight 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.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastForEachIndexed
import androidx.navigation.NavController import androidx.navigation.NavController
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.google.accompanist.flowlayout.FlowRow import com.google.accompanist.flowlayout.FlowRow
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.PagerState import com.google.accompanist.pager.PagerState
import com.google.accompanist.pager.pagerTabIndicatorOffset
import com.google.accompanist.pager.rememberPagerState import com.google.accompanist.pager.rememberPagerState
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.owenlejeune.tvtime.R 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.RatingSelected
import com.owenlejeune.tvtime.ui.theme.WatchlistSelected import com.owenlejeune.tvtime.ui.theme.WatchlistSelected
import com.owenlejeune.tvtime.ui.theme.actionButtonColor 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.SessionManager
import com.owenlejeune.tvtime.utils.TmdbUtils import com.owenlejeune.tvtime.utils.TmdbUtils
import kotlinx.coroutines.* import kotlinx.coroutines.*
import okhttp3.internal.notify
import org.json.JSONObject import org.json.JSONObject
import org.koin.androidx.compose.koinViewModel
import org.koin.java.KoinJavaComponent.get import org.koin.java.KoinJavaComponent.get
import java.text.DecimalFormat import java.text.DecimalFormat
@@ -1425,7 +1417,7 @@ private fun WatchProviderContainer(
} }
) { ) {
AsyncImage( AsyncImage(
model = TmdbUtils.fullImagePath(item.logoPath), model = TmdbUtils.fullLogoPath(item.logoPath),
contentDescription = null, contentDescription = null,
modifier = Modifier modifier = Modifier
.size(48.dp) .size(48.dp)

View File

@@ -23,16 +23,25 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
private const val TAG = "ConfigurationViewModel" private const val TAG = "ConfigurationViewModel"
} }
private val service: ConfigurationApi by inject() private object Backer {
val detailsConfiguration = mutableStateOf(ConfigurationDetails.Empty) val detailsConfiguration = mutableStateOf(ConfigurationDetails.Empty)
val countriesConfiguration = mutableStateListOf<ConfigurationCountry>() val countriesConfiguration = mutableStateListOf<ConfigurationCountry>()
val jobsConfiguration = mutableStateListOf<ConfigurationJob>() val jobsConfiguration = mutableStateListOf<ConfigurationJob>()
val languagesConfiguration = mutableStateListOf<ConfigurationLanguage>() val languagesConfiguration = mutableStateListOf<ConfigurationLanguage>()
val primaryTranslationsConfiguration = mutableStateListOf<String>() val primaryTranslationsConfiguration = mutableStateListOf<String>()
val timezonesConfiguration = mutableStateListOf<ConfigurationTimezone>() val timezonesConfiguration = mutableStateListOf<ConfigurationTimezone>()
}
fun getConfigurations() { private val service: ConfigurationApi by inject()
val detailsConfiguration = Backer.detailsConfiguration
val countriesConfiguration = Backer.countriesConfiguration
val jobsConfiguration = Backer.jobsConfiguration
val languagesConfiguration = Backer.languagesConfiguration
val primaryTranslationsConfiguration = Backer.primaryTranslationsConfiguration
val timezonesConfiguration = Backer.timezonesConfiguration
suspend fun getConfigurations() {
getDetailsConfiguration() getDetailsConfiguration()
getCountriesConfiguration() getCountriesConfiguration()
getJobsConfiguration() getJobsConfiguration()
@@ -41,14 +50,14 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
getTimezonesConfiguration() getTimezonesConfiguration()
} }
fun getDetailsConfiguration() { suspend fun getDetailsConfiguration() {
getConfiguration( getConfiguration(
{ service.getDetailsConfiguration() }, { service.getDetailsConfiguration() },
{ detailsConfiguration.value = it } { detailsConfiguration.value = it }
) )
} }
fun getCountriesConfiguration() { suspend fun getCountriesConfiguration() {
getConfiguration( getConfiguration(
{ service.getCountriesConfiguration() }, { service.getCountriesConfiguration() },
{ {
@@ -58,7 +67,7 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
) )
} }
fun getJobsConfiguration() { suspend fun getJobsConfiguration() {
getConfiguration( getConfiguration(
{ service.getJobsConfiguration() }, { service.getJobsConfiguration() },
{ {
@@ -68,7 +77,7 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
) )
} }
fun getLanguagesConfiguration() { suspend fun getLanguagesConfiguration() {
getConfiguration( getConfiguration(
{ service.getLanguagesConfiguration() }, { service.getLanguagesConfiguration() },
{ {
@@ -78,7 +87,7 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
) )
} }
fun getPrimaryTranslationsConfiguration() { suspend fun getPrimaryTranslationsConfiguration() {
getConfiguration( getConfiguration(
{ service.getPrimaryTranslationsConfiguration() }, { service.getPrimaryTranslationsConfiguration() },
{ {
@@ -88,7 +97,7 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
) )
} }
fun getTimezonesConfiguration() { suspend fun getTimezonesConfiguration() {
getConfiguration( getConfiguration(
{ service.getTimezonesConfiguration() }, { service.getTimezonesConfiguration() },
{ {
@@ -98,11 +107,10 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
) )
} }
private fun <T> getConfiguration( private suspend fun <T> getConfiguration(
fetcher: suspend () -> Response<T>, fetcher: suspend () -> Response<T>,
bodyHandler: (T) -> Unit bodyHandler: (T) -> Unit
) { ) {
CoroutineScope(Dispatchers.IO).launch {
val response = fetcher() val response = fetcher()
if (response.isSuccessful) { if (response.isSuccessful) {
response.body()?.let { response.body()?.let {
@@ -113,6 +121,5 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
Log.e(TAG, "Issue getting configuration") Log.e(TAG, "Issue getting configuration")
} }
} }
}
} }

View File

@@ -7,41 +7,34 @@ import kotlinx.coroutines.flow.asStateFlow
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
class SettingsViewModel: ViewModel(), KoinComponent { class SettingsViewModel: ViewModel() {
private companion object Backer: KoinComponent {
private val preferences: AppPreferences by inject() private val preferences: AppPreferences by inject()
private val _showSearchBar = MutableStateFlow(preferences.showSearchBar) private val _showSearchBar = MutableStateFlow(preferences.showSearchBar)
val showSearchBar = _showSearchBar.asStateFlow()
private val _useMultiSearch = MutableStateFlow(preferences.multiSearch) private val _useMultiSearch = MutableStateFlow(preferences.multiSearch)
val useMultiSearch = _useMultiSearch.asStateFlow()
private val _useWallpaperColor = MutableStateFlow(preferences.useWallpaperColors) private val _useWallpaperColor = MutableStateFlow(preferences.useWallpaperColors)
val useWallpaperColors = _useWallpaperColor.asStateFlow()
private val _darkTheme = MutableStateFlow(preferences.darkTheme) private val _darkTheme = MutableStateFlow(preferences.darkTheme)
val darkTheme = _darkTheme.asStateFlow()
private val _useSystemColors = MutableStateFlow(preferences.useSystemColors) private val _useSystemColors = MutableStateFlow(preferences.useSystemColors)
val useSystemColors = _useSystemColors.asStateFlow()
private val _chromaMultiplier = MutableStateFlow(preferences.chromaMultiplier) private val _chromaMultiplier = MutableStateFlow(preferences.chromaMultiplier)
val chromaMultiplier = _chromaMultiplier.asStateFlow()
private val _selectedColor = MutableStateFlow(preferences.selectedColor) private val _selectedColor = MutableStateFlow(preferences.selectedColor)
val selectedColor = _selectedColor.asStateFlow()
private val _showBottomTabLabels = MutableStateFlow(preferences.showBottomTabLabels) private val _showBottomTabLabels = MutableStateFlow(preferences.showBottomTabLabels)
val showBottomTabLabels = _showBottomTabLabels.asStateFlow()
private val _showPosterTitles = MutableStateFlow(preferences.showPosterTitles) private val _showPosterTitles = MutableStateFlow(preferences.showPosterTitles)
val showPosterTitles = _showPosterTitles.asStateFlow()
private val _firstLaunchTesting = MutableStateFlow(preferences.firstLaunchTesting) private val _firstLaunchTesting = MutableStateFlow(preferences.firstLaunchTesting)
val firstLaunchTesting = _firstLaunchTesting.asStateFlow()
private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery) private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery)
}
val showSearchBar = _showSearchBar.asStateFlow()
val useMultiSearch = _useMultiSearch.asStateFlow()
val useWallpaperColors = _useWallpaperColor.asStateFlow()
val darkTheme = _darkTheme.asStateFlow()
val useSystemColors = _useSystemColors.asStateFlow()
val chromaMultiplier = _chromaMultiplier.asStateFlow()
val selectedColor = _selectedColor.asStateFlow()
val showBottomTabLabels = _showBottomTabLabels.asStateFlow()
val showPosterTitles = _showPosterTitles.asStateFlow()
val firstLaunchTesting = _firstLaunchTesting.asStateFlow()
val showBackdropGallery = _showBackdropGallery.asStateFlow() val showBackdropGallery = _showBackdropGallery.asStateFlow()
fun toggleShowSearchBar() { fun toggleShowSearchBar() {

View File

@@ -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.TmdbItem
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TvContentRatings import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TvContentRatings
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Video import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Video
import com.owenlejeune.tvtime.ui.viewmodel.ConfigurationViewModel
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
object TmdbUtils { 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 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" 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? { fun getFullPosterPath(posterPath: String?): String? {
return posterPath?.let { 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? { fun getFullBackdropPath(backdropPath: String?): String? {
return backdropPath?.let { 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? { 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? { fun getFullPersonImagePath(person: Person): String? {
@@ -74,7 +77,7 @@ object TmdbUtils {
if (path.contains("http")) { if (path.contains("http")) {
return path.substring(startIndex = 1) 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? { fun getFullEpisodeStillPath(path: String?): String? {
return path?.let { return path?.let {
"${STILL_BASE}${path}" IMAGE_BASE.plus(STILL_SIZE).plus(path)
} }
} }
@@ -211,7 +214,7 @@ object TmdbUtils {
fun getAccountAvatarUrl(accountDetails: AccountDetails): String { fun getAccountAvatarUrl(accountDetails: AccountDetails): String {
val path = accountDetails.avatar.tmdb?.avatarPath val path = accountDetails.avatar.tmdb?.avatarPath
return "${AVATAR_BASE}${path}" return IMAGE_BASE.plus(LOGO_SIZE).plus(path)
} }
fun releaseYearFromData(releaseDate: String): String { fun releaseYearFromData(releaseDate: String): String {