mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-15 08:12:45 -05:00
wait for configuration details and use them for image loading
This commit is contained in:
@@ -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>()
|
||||
configurationViewModel.getConfigurations()
|
||||
TmdbUtils.setup(configurationViewModel)
|
||||
|
||||
if (preferences.firstLaunchTesting || preferences.firstLaunch) {
|
||||
launchActivity(OnboardingActivity::class.java)
|
||||
} else {
|
||||
launchActivity(MainActivity::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,6 @@ class MainActivity : MonetCompatActivity() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
monet.awaitMonetReady()
|
||||
setContent {
|
||||
val configurationViewModel = viewModel<ConfigurationViewModel>()
|
||||
configurationViewModel.getConfigurations()
|
||||
|
||||
AppKeyboardFocusManager()
|
||||
TVTimeTheme(monetCompat = monet) {
|
||||
val windowSize = rememberWindowSizeClass()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -23,16 +23,25 @@ class ConfigurationViewModel: ViewModel(), KoinComponent {
|
||||
private const val TAG = "ConfigurationViewModel"
|
||||
}
|
||||
|
||||
private object Backer {
|
||||
val detailsConfiguration = mutableStateOf(ConfigurationDetails.Empty)
|
||||
val countriesConfiguration = mutableStateListOf<ConfigurationCountry>()
|
||||
val jobsConfiguration = mutableStateListOf<ConfigurationJob>()
|
||||
val languagesConfiguration = mutableStateListOf<ConfigurationLanguage>()
|
||||
val primaryTranslationsConfiguration = mutableStateListOf<String>()
|
||||
val timezonesConfiguration = mutableStateListOf<ConfigurationTimezone>()
|
||||
}
|
||||
|
||||
private val service: ConfigurationApi by inject()
|
||||
|
||||
val detailsConfiguration = mutableStateOf(ConfigurationDetails.Empty)
|
||||
val countriesConfiguration = mutableStateListOf<ConfigurationCountry>()
|
||||
val jobsConfiguration = mutableStateListOf<ConfigurationJob>()
|
||||
val languagesConfiguration = mutableStateListOf<ConfigurationLanguage>()
|
||||
val primaryTranslationsConfiguration = mutableStateListOf<String>()
|
||||
val timezonesConfiguration = mutableStateListOf<ConfigurationTimezone>()
|
||||
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 <T> getConfiguration(
|
||||
private suspend fun <T> getConfiguration(
|
||||
fetcher: suspend () -> Response<T>,
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user