add Game of Thrones quotes

This commit is contained in:
Owen LeJeune
2023-08-02 15:05:14 -04:00
parent 6fe0b9f1dd
commit abd6e4ddee
34 changed files with 291 additions and 48 deletions

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
import okhttp3.Interceptor import okhttp3.Interceptor
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
import retrofit2.Converter import retrofit2.Converter

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor

View File

@@ -1,8 +1,6 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializer
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
import retrofit2.Converter import retrofit2.Converter

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
import okhttp3.OkHttpClient import okhttp3.OkHttpClient

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
enum class LoadingState { enum class LoadingState {

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
import okhttp3.OkHttpClient import okhttp3.OkHttpClient

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
class QueryParam(val key: String, val param: String) { class QueryParam(val key: String, val param: String) {

View File

@@ -1,7 +1,6 @@
package com.owenlejeune.tvtime.api package com.owenlejeune.tvtime.api.common
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import kotlinx.coroutines.delay
import retrofit2.Response import retrofit2.Response
infix fun <T> Response<T>.storedIn(body: (T) -> Unit) { infix fun <T> Response<T>.storedIn(body: (T) -> Unit) {

View File

@@ -0,0 +1,12 @@
package com.owenlejeune.tvtime.api.gotquotes
import com.owenlejeune.tvtime.api.gotquotes.model.GotQuote
import retrofit2.Response
import retrofit2.http.GET
interface GotQuotesApi {
@GET("random/5")
suspend fun getRandomQuotes(): Response<List<GotQuote>>
}

View File

@@ -0,0 +1,20 @@
package com.owenlejeune.tvtime.api.gotquotes
import com.owenlejeune.tvtime.api.common.Client
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.parameter.parametersOf
class GotQuotesClient: KoinComponent {
companion object {
private const val BASE_URL = "https://api.gameofthronesquotes.xyz/v1/"
}
private val client: Client by inject { parametersOf(BASE_URL) }
fun createQuotesApi(): GotQuotesApi {
return client.create(GotQuotesApi::class.java)
}
}

View File

@@ -0,0 +1,24 @@
package com.owenlejeune.tvtime.api.gotquotes
import androidx.compose.runtime.mutableStateListOf
import com.owenlejeune.tvtime.api.gotquotes.model.GotQuote
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class GotQuotesService: KoinComponent {
private val api: GotQuotesApi by inject()
val quotes = mutableStateListOf<GotQuote>()
suspend fun getRandomQuotes() {
quotes.clear()
val response = api.getRandomQuotes()
if (response.isSuccessful) {
response.body()?.let {
quotes.addAll(it)
}
}
}
}

View File

@@ -0,0 +1,19 @@
package com.owenlejeune.tvtime.api.gotquotes.model
import com.google.gson.annotations.SerializedName
class GotQuote(
@SerializedName("sentence") val quote: String,
@SerializedName("character") val character: GotCharacter
)
class GotCharacter(
@SerializedName("name") val name: String,
@SerializedName("slug") val slug: String,
@SerializedName("house") val house: GotHouse
)
class GotHouse(
@SerializedName("name") val name: String,
@SerializedName("slug") val slug: String
)

View File

@@ -1,6 +1,6 @@
package com.owenlejeune.tvtime.api.nextmcu package com.owenlejeune.tvtime.api.nextmcu
import com.owenlejeune.tvtime.api.Client import com.owenlejeune.tvtime.api.common.Client
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
import org.koin.core.parameter.parametersOf import org.koin.core.parameter.parametersOf

View File

@@ -1,7 +1,7 @@
package com.owenlejeune.tvtime.api.nextmcu package com.owenlejeune.tvtime.api.nextmcu
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import com.owenlejeune.tvtime.api.LoadingState import com.owenlejeune.tvtime.api.common.LoadingState
import com.owenlejeune.tvtime.api.nextmcu.model.NextMCU import com.owenlejeune.tvtime.api.nextmcu.model.NextMCU
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject

View File

@@ -2,10 +2,9 @@ package com.owenlejeune.tvtime.api.tmdb
import android.annotation.SuppressLint import android.annotation.SuppressLint
import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.intl.Locale
import androidx.lifecycle.viewmodel.viewModelFactory
import com.owenlejeune.tvtime.BuildConfig import com.owenlejeune.tvtime.BuildConfig
import com.owenlejeune.tvtime.api.Client import com.owenlejeune.tvtime.api.common.Client
import com.owenlejeune.tvtime.api.QueryParam import com.owenlejeune.tvtime.api.common.QueryParam
import com.owenlejeune.tvtime.api.tmdb.api.v3.AccountApi import com.owenlejeune.tvtime.api.tmdb.api.v3.AccountApi
import com.owenlejeune.tvtime.api.tmdb.api.v3.AuthenticationApi import com.owenlejeune.tvtime.api.tmdb.api.v3.AuthenticationApi
import com.owenlejeune.tvtime.api.tmdb.api.v3.ConfigurationApi import com.owenlejeune.tvtime.api.tmdb.api.v3.ConfigurationApi
@@ -18,7 +17,6 @@ import com.owenlejeune.tvtime.api.tmdb.api.v4.AccountV4Api
import com.owenlejeune.tvtime.api.tmdb.api.v4.AuthenticationV4Api import com.owenlejeune.tvtime.api.tmdb.api.v4.AuthenticationV4Api
import com.owenlejeune.tvtime.api.tmdb.api.v4.ListV4Api import com.owenlejeune.tvtime.api.tmdb.api.v4.ListV4Api
import com.owenlejeune.tvtime.extensions.addQueryParams import com.owenlejeune.tvtime.extensions.addQueryParams
import com.owenlejeune.tvtime.preferences.AppPreferences
import com.owenlejeune.tvtime.ui.viewmodel.ConfigurationViewModel import com.owenlejeune.tvtime.ui.viewmodel.ConfigurationViewModel
import com.owenlejeune.tvtime.utils.SessionManager import com.owenlejeune.tvtime.utils.SessionManager
import okhttp3.Interceptor import okhttp3.Interceptor

View File

@@ -4,8 +4,8 @@ import android.util.Log
import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.paging.PagingData import androidx.paging.PagingData
import com.owenlejeune.tvtime.api.LoadingState import com.owenlejeune.tvtime.api.common.LoadingState
import com.owenlejeune.tvtime.api.loadRemoteData import com.owenlejeune.tvtime.api.common.loadRemoteData
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.AccountStates import com.owenlejeune.tvtime.api.tmdb.api.v3.model.AccountStates
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CastMember import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CastMember
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CrewMember import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CrewMember

View File

@@ -2,8 +2,8 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3
import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import com.owenlejeune.tvtime.api.LoadingState import com.owenlejeune.tvtime.api.common.LoadingState
import com.owenlejeune.tvtime.api.loadRemoteData import com.owenlejeune.tvtime.api.common.loadRemoteData
import com.owenlejeune.tvtime.api.tmdb.TmdbClient import com.owenlejeune.tvtime.api.tmdb.TmdbClient
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailCast import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailCast
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailCrew import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailCrew

View File

@@ -4,8 +4,8 @@ import android.util.Log
import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.paging.PagingData import androidx.paging.PagingData
import com.owenlejeune.tvtime.api.LoadingState import com.owenlejeune.tvtime.api.common.LoadingState
import com.owenlejeune.tvtime.api.loadRemoteData import com.owenlejeune.tvtime.api.common.loadRemoteData
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.AccountStates import com.owenlejeune.tvtime.api.tmdb.api.v3.model.AccountStates
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CastMember import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CastMember
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CrewMember import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CrewMember

View File

@@ -2,7 +2,14 @@ package com.owenlejeune.tvtime.di.modules
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.owenlejeune.tvtime.BuildConfig import com.owenlejeune.tvtime.BuildConfig
import com.owenlejeune.tvtime.api.* import com.owenlejeune.tvtime.api.common.Client
import com.owenlejeune.tvtime.api.common.ConverterFactoryFactory
import com.owenlejeune.tvtime.api.common.DateTypeAdapter
import com.owenlejeune.tvtime.api.common.DebugHttpClient
import com.owenlejeune.tvtime.api.common.GsonConverter
import com.owenlejeune.tvtime.api.common.ProdHttpClient
import com.owenlejeune.tvtime.api.gotquotes.GotQuotesClient
import com.owenlejeune.tvtime.api.gotquotes.GotQuotesService
import com.owenlejeune.tvtime.api.nextmcu.NextMCUClient import com.owenlejeune.tvtime.api.nextmcu.NextMCUClient
import com.owenlejeune.tvtime.api.nextmcu.NextMCUService import com.owenlejeune.tvtime.api.nextmcu.NextMCUService
import com.owenlejeune.tvtime.api.tmdb.TmdbClient import com.owenlejeune.tvtime.api.tmdb.TmdbClient
@@ -76,6 +83,10 @@ val networkModule = module {
single { get<NextMCUClient>().createNextMcuService() } single { get<NextMCUClient>().createNextMcuService() }
single { NextMCUService() } single { NextMCUService() }
single { GotQuotesClient() }
single { get<GotQuotesClient>().createQuotesApi() }
single { GotQuotesService() }
single<Map<Class<*>, Any>> { single<Map<Class<*>, Any>> {
mapOf( mapOf(
ListItem::class.java to ListItemDeserializer(), ListItem::class.java to ListItemDeserializer(),

View File

@@ -1,8 +1,7 @@
package com.owenlejeune.tvtime.extensions package com.owenlejeune.tvtime.extensions
import com.owenlejeune.tvtime.api.QueryParam import com.owenlejeune.tvtime.api.common.QueryParam
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request
fun HttpUrl.Builder.addQueryParams(vararg queryParams: QueryParam?): HttpUrl.Builder { fun HttpUrl.Builder.addQueryParams(vararg queryParams: QueryParam?): HttpUrl.Builder {
return apply { return apply {

View File

@@ -39,6 +39,7 @@ class AppPreferences(context: Context) {
private val STORED_TEST_ROUTE = "stored_test_route" private val STORED_TEST_ROUTE = "stored_test_route"
private val FLOATING_BOTTOM_BAR = "floating_bottom_bar" private val FLOATING_BOTTOM_BAR = "floating_bottom_bar"
private val RECENT_SEARCHES = "recent_searches" private val RECENT_SEARCHES = "recent_searches"
private val SHOW_GOT_QUOTES = "show_got_quotes"
} }
private val preferences: SharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE) private val preferences: SharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE)
@@ -138,17 +139,22 @@ class AppPreferences(context: Context) {
get() = preferences.getBoolean(SHOW_BACKDROP_GALLERY, showBackdropGalleryDefault) get() = preferences.getBoolean(SHOW_BACKDROP_GALLERY, showBackdropGalleryDefault)
set(value) { preferences.put(SHOW_BACKDROP_GALLERY, value) } set(value) { preferences.put(SHOW_BACKDROP_GALLERY, value) }
/******** Special Features Preferences ********/
val showNextMcuProductionDefault: Boolean = false
var showNextMcuProduction: Boolean
get() = preferences.getBoolean(SHOW_NEXT_MCU, showNextMcuProductionDefault)
set(value) { preferences.put(SHOW_NEXT_MCU, value) }
val storedTestRouteDefault: String = "" val storedTestRouteDefault: String = ""
var storedTestRoute: String var storedTestRoute: String
get() = preferences.getString(STORED_TEST_ROUTE, storedTestRouteDefault) ?: storedTestRouteDefault get() = preferences.getString(STORED_TEST_ROUTE, storedTestRouteDefault) ?: storedTestRouteDefault
set(value) { preferences.put(STORED_TEST_ROUTE, value) } set(value) { preferences.put(STORED_TEST_ROUTE, value) }
/******** Special Features Preferences ********/
val showNextMcuProductionDefault: Boolean = true
var showNextMcuProduction: Boolean
get() = preferences.getBoolean(SHOW_NEXT_MCU, showNextMcuProductionDefault)
set(value) { preferences.put(SHOW_NEXT_MCU, value) }
val showGotQuotesDefault: Boolean = true
var showGotQuotes: Boolean
get() = preferences.getBoolean(SHOW_GOT_QUOTES, showGotQuotesDefault)
set(value) { preferences.put(SHOW_GOT_QUOTES, value) }
/******** General Storage ********/ /******** General Storage ********/
var recentSearches: MutableList<String> var recentSearches: MutableList<String>
get() = preferences.getStringSet(RECENT_SEARCHES, emptySet())?.toMutableList() ?: emptySet<String>().toMutableList() get() = preferences.getStringSet(RECENT_SEARCHES, emptySet())?.toMutableList() ?: emptySet<String>().toMutableList()

View File

@@ -29,14 +29,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.owenlejeune.tvtime.api.LoadingState
import com.owenlejeune.tvtime.extensions.isIn
import com.owenlejeune.tvtime.extensions.shimmerBackground
import com.owenlejeune.tvtime.ui.theme.FavoriteSelected 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.viewmodel.AccountViewModel import com.owenlejeune.tvtime.ui.viewmodel.AccountViewModel
import com.owenlejeune.tvtime.ui.viewmodel.ApplicationViewModel
import com.owenlejeune.tvtime.ui.viewmodel.MainViewModel import com.owenlejeune.tvtime.ui.viewmodel.MainViewModel
import com.owenlejeune.tvtime.utils.types.MediaViewType import com.owenlejeune.tvtime.utils.types.MediaViewType
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View File

@@ -62,6 +62,28 @@ fun ContentCard(
} }
} }
@Composable
fun ContentCard(
modifier: Modifier = Modifier,
heading: (@Composable () -> Unit)? = null,
backgroundColor: Color = MaterialTheme.colorScheme.surfaceVariant,
content: @Composable () -> Unit = {}
) {
Card(
modifier = modifier
.fillMaxWidth()
.wrapContentHeight(),
shape = RoundedCornerShape(10.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp),
colors = CardDefaults.cardColors(containerColor = backgroundColor)
) {
Column(modifier = Modifier.fillMaxSize()) {
heading?.invoke()
content()
}
}
}
@Composable @Composable
fun ExpandableContentCard( fun ExpandableContentCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,

View File

@@ -52,7 +52,7 @@ import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.PagerState import com.google.accompanist.pager.PagerState
import com.google.accompanist.pager.rememberPagerState import com.google.accompanist.pager.rememberPagerState
import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.api.LoadingState import com.owenlejeune.tvtime.api.common.LoadingState
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Episode import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Episode
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.EpisodeCastMember import com.owenlejeune.tvtime.api.tmdb.api.v3.model.EpisodeCastMember
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.EpisodeCrewMember import com.owenlejeune.tvtime.api.tmdb.api.v3.model.EpisodeCrewMember

View File

@@ -37,7 +37,6 @@ import androidx.paging.compose.LazyPagingItems
import coil.compose.AsyncImage import coil.compose.AsyncImage
import coil.request.CachePolicy import coil.request.CachePolicy
import coil.request.ImageRequest import coil.request.ImageRequest
import com.owenlejeune.tvtime.api.LoadingState
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.HomePagePerson import com.owenlejeune.tvtime.api.tmdb.api.v3.model.HomePagePerson
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TmdbItem import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TmdbItem
import com.owenlejeune.tvtime.extensions.header import com.owenlejeune.tvtime.extensions.header

View File

@@ -70,7 +70,7 @@ import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.PagerState import com.google.accompanist.pager.PagerState
import com.google.accompanist.pager.rememberPagerState import com.google.accompanist.pager.rememberPagerState
import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.api.LoadingState import com.owenlejeune.tvtime.api.common.LoadingState
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedItem import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedItem
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedMovie import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedMovie
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedTv import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedTv
@@ -92,7 +92,6 @@ import com.owenlejeune.tvtime.ui.components.AdditionalDetailItem
import com.owenlejeune.tvtime.ui.components.AvatarImage import com.owenlejeune.tvtime.ui.components.AvatarImage
import com.owenlejeune.tvtime.ui.components.BackButton import com.owenlejeune.tvtime.ui.components.BackButton
import com.owenlejeune.tvtime.ui.components.CastCard import com.owenlejeune.tvtime.ui.components.CastCard
import com.owenlejeune.tvtime.ui.components.CastCrewCard
import com.owenlejeune.tvtime.ui.components.ChipDefaults import com.owenlejeune.tvtime.ui.components.ChipDefaults
import com.owenlejeune.tvtime.ui.components.ChipGroup import com.owenlejeune.tvtime.ui.components.ChipGroup
import com.owenlejeune.tvtime.ui.components.ChipInfo import com.owenlejeune.tvtime.ui.components.ChipInfo
@@ -118,6 +117,7 @@ import com.owenlejeune.tvtime.ui.theme.Typography
import com.owenlejeune.tvtime.ui.viewmodel.ApplicationViewModel import com.owenlejeune.tvtime.ui.viewmodel.ApplicationViewModel
import com.owenlejeune.tvtime.ui.viewmodel.MainViewModel import com.owenlejeune.tvtime.ui.viewmodel.MainViewModel
import com.owenlejeune.tvtime.ui.viewmodel.SpecialFeaturesViewModel import com.owenlejeune.tvtime.ui.viewmodel.SpecialFeaturesViewModel
import com.owenlejeune.tvtime.ui.views.extras.SpecialFeaturesViews
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 com.owenlejeune.tvtime.utils.types.MediaViewType import com.owenlejeune.tvtime.utils.types.MediaViewType
@@ -386,6 +386,8 @@ fun MediaViewContent(
NextMcuProjectCard(itemId = itemId, appNavController = appNavController) NextMcuProjectCard(itemId = itemId, appNavController = appNavController)
} }
SpecialFeaturesViews.viewsMap[itemId]?.invoke()
if (windowSize != WindowSizeClass.Expanded) { if (windowSize != WindowSizeClass.Expanded) {
ReviewsCard(itemId = itemId, type = type, mainViewModel = mainViewModel, windowSize = windowSize) ReviewsCard(itemId = itemId, type = type, mainViewModel = mainViewModel, windowSize = windowSize)
} }

View File

@@ -458,6 +458,15 @@ fun SpecialFeaturePreferences() {
settingsViewModel.toggleShowNextMcuProduction() settingsViewModel.toggleShowNextMcuProduction()
} }
) )
SwitchPreference(
titleText = "Show Game of Thrones Quotes",
subtitleText = "Show random quotes from Game of Thrones on the show",
checkState = settingsViewModel.showGotQuotes.collectAsState(),
onCheckedChange = {
settingsViewModel.toggleShowGotQuotes()
}
)
} }
} }

View File

@@ -3,11 +3,10 @@ package com.owenlejeune.tvtime.ui.viewmodel
import android.annotation.SuppressLint import android.annotation.SuppressLint
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.paging.PagingData import androidx.paging.PagingData
import com.owenlejeune.tvtime.api.LoadingState import com.owenlejeune.tvtime.api.common.LoadingState
import com.owenlejeune.tvtime.api.tmdb.api.createPagingFlow import com.owenlejeune.tvtime.api.tmdb.api.createPagingFlow
import com.owenlejeune.tvtime.api.tmdb.api.v3.MoviesService import com.owenlejeune.tvtime.api.tmdb.api.v3.MoviesService
import com.owenlejeune.tvtime.api.tmdb.api.v3.PeopleService import com.owenlejeune.tvtime.api.tmdb.api.v3.PeopleService
@@ -16,7 +15,6 @@ import com.owenlejeune.tvtime.api.tmdb.api.v3.model.AccountStates
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CastMember import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CastMember
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CrewMember import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CrewMember
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedItem import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedItem
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Episode
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ExternalIds import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ExternalIds
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ImageCollection import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ImageCollection
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Keyword import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Keyword
@@ -31,7 +29,6 @@ import com.owenlejeune.tvtime.utils.types.MediaViewType
import com.owenlejeune.tvtime.utils.types.TimeWindow import com.owenlejeune.tvtime.utils.types.TimeWindow
import com.owenlejeune.tvtime.utils.types.ViewableMediaTypeException import com.owenlejeune.tvtime.utils.types.ViewableMediaTypeException
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.cancellable
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject

View File

@@ -20,11 +20,12 @@ class SettingsViewModel: ViewModel() {
private val _chromaMultiplier = MutableStateFlow(preferences.chromaMultiplier) private val _chromaMultiplier = MutableStateFlow(preferences.chromaMultiplier)
private val _selectedColor = MutableStateFlow(preferences.selectedColor) private val _selectedColor = MutableStateFlow(preferences.selectedColor)
private val _showBottomTabLabels = MutableStateFlow(preferences.showBottomTabLabels) private val _showBottomTabLabels = MutableStateFlow(preferences.showBottomTabLabels)
private val _showFloatingBottomBar = MutableStateFlow(preferences.floatingBottomBar)
private val _showPosterTitles = MutableStateFlow(preferences.showPosterTitles) private val _showPosterTitles = MutableStateFlow(preferences.showPosterTitles)
private val _firstLaunchTesting = MutableStateFlow(preferences.firstLaunchTesting) private val _firstLaunchTesting = MutableStateFlow(preferences.firstLaunchTesting)
private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery) private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery)
private val _showNextMcuProduction = MutableStateFlow(preferences.showNextMcuProduction) private val _showNextMcuProduction = MutableStateFlow(preferences.showNextMcuProduction)
private val _showFloatingBottomBar = MutableStateFlow(preferences.floatingBottomBar) private val _showGotQuotes = MutableStateFlow(preferences.showGotQuotes)
} }
val showSearchBar = _showSearchBar.asStateFlow() val showSearchBar = _showSearchBar.asStateFlow()
@@ -34,12 +35,13 @@ class SettingsViewModel: ViewModel() {
val useSystemColors = _useSystemColors.asStateFlow() val useSystemColors = _useSystemColors.asStateFlow()
val chromaMultiplier = _chromaMultiplier.asStateFlow() val chromaMultiplier = _chromaMultiplier.asStateFlow()
val selectedColor = _selectedColor.asStateFlow() val selectedColor = _selectedColor.asStateFlow()
val showFloatingBottomBar = _showFloatingBottomBar.asStateFlow()
val showBottomTabLabels = _showBottomTabLabels.asStateFlow() val showBottomTabLabels = _showBottomTabLabels.asStateFlow()
val showPosterTitles = _showPosterTitles.asStateFlow() val showPosterTitles = _showPosterTitles.asStateFlow()
val firstLaunchTesting = _firstLaunchTesting.asStateFlow() val firstLaunchTesting = _firstLaunchTesting.asStateFlow()
val showBackdropGallery = _showBackdropGallery.asStateFlow() val showBackdropGallery = _showBackdropGallery.asStateFlow()
val showNextMcuProduction = _showNextMcuProduction.asStateFlow() val showNextMcuProduction = _showNextMcuProduction.asStateFlow()
val showFloatingBottomBar = _showFloatingBottomBar.asStateFlow() val showGotQuotes = _showGotQuotes.asStateFlow()
fun toggleShowSearchBar() { fun toggleShowSearchBar() {
_showSearchBar.value = _showSearchBar.value.not() _showSearchBar.value = _showSearchBar.value.not()
@@ -156,4 +158,14 @@ class SettingsViewModel: ViewModel() {
preferences.floatingBottomBar = value preferences.floatingBottomBar = value
} }
fun toggleShowGotQuotes() {
_showGotQuotes.value = _showGotQuotes.value.not()
preferences.showGotQuotes = _showGotQuotes.value
}
fun setShowGotQuotes(value: Boolean) {
_showGotQuotes.value = value
preferences.showGotQuotes = value
}
} }

View File

@@ -1,6 +1,7 @@
package com.owenlejeune.tvtime.ui.viewmodel package com.owenlejeune.tvtime.ui.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.owenlejeune.tvtime.api.gotquotes.GotQuotesService
import com.owenlejeune.tvtime.api.nextmcu.NextMCUService import com.owenlejeune.tvtime.api.nextmcu.NextMCUService
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@@ -8,8 +9,10 @@ import org.koin.core.component.inject
class SpecialFeaturesViewModel: ViewModel(), KoinComponent { class SpecialFeaturesViewModel: ViewModel(), KoinComponent {
private val mcuService: NextMCUService by inject() private val mcuService: NextMCUService by inject()
private val gotQuotesService: GotQuotesService by inject()
val nextMcuProject = mcuService.nextMcuProject val nextMcuProject = mcuService.nextMcuProject
val gotQuotes = gotQuotesService.quotes
suspend fun getNextMcuProject(force: Boolean = false) { suspend fun getNextMcuProject(force: Boolean = false) {
if (nextMcuProject.value == null || force) { if (nextMcuProject.value == null || force) {
@@ -17,4 +20,8 @@ class SpecialFeaturesViewModel: ViewModel(), KoinComponent {
} }
} }
suspend fun getGotQuotes() {
gotQuotesService.getRandomQuotes()
}
} }

View File

@@ -0,0 +1,112 @@
package com.owenlejeune.tvtime.ui.views.extras
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Refresh
import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.preferences.AppPreferences
import com.owenlejeune.tvtime.ui.components.ContentCard
import com.owenlejeune.tvtime.ui.viewmodel.SpecialFeaturesViewModel
import kotlinx.coroutines.launch
import org.koin.java.KoinJavaComponent.get
object SpecialFeaturesViews {
val viewsMap: Map<Int, @Composable () -> Unit> = mapOf(
206584 to { GotQuotesView() },
1399 to { GotQuotesView() }
)
}
@Composable
fun GotQuotesView(
appPreferences: AppPreferences = get(AppPreferences::class.java)
) {
if (appPreferences.showGotQuotes) {
val scope = rememberCoroutineScope()
val viewModel = viewModel<SpecialFeaturesViewModel>()
LaunchedEffect(Unit) {
viewModel.getGotQuotes()
}
val quotes = remember { viewModel.gotQuotes }
if (quotes.isNotEmpty()) {
ContentCard(
heading = {
Row(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)
) {
Text(
text = stringResource(R.string.quotes_title),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.weight(1f))
IconButton(
modifier = Modifier.offset(x = 8.dp, y = (-8).dp),
onClick = {
scope.launch { viewModel.getGotQuotes() }
}
) {
Icon(
imageVector = Icons.Outlined.Refresh,
contentDescription = null
)
}
}
}
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
.padding(horizontal = 16.dp)
.offset(y = (-12).dp)
) {
quotes.forEachIndexed { index, quote ->
Column {
Text(
text = quote.quote,
color = MaterialTheme.colorScheme.primary
)
Text(
text = " - ${quote.character.name}",
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontStyle = FontStyle.Italic
)
}
if (index != quotes.size - 1) {
Divider(
modifier = Modifier.padding(vertical = 8.dp),
color = MaterialTheme.colorScheme.surface
)
}
}
Spacer(modifier = Modifier.height(1.dp))
}
}
}
}
}

View File

@@ -267,4 +267,5 @@
<string name="your_rating">Your rating: %1$d/10</string> <string name="your_rating">Your rating: %1$d/10</string>
<string name="uncredited">Uncredited</string> <string name="uncredited">Uncredited</string>
<string name="clear_search_query">Clear search query</string> <string name="clear_search_query">Clear search query</string>
<string name="quotes_title">Quotes</string>
</resources> </resources>