mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-12-29 10:51:20 -05:00
add Game of Thrones quotes
This commit is contained in:
@@ -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
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.owenlejeune.tvtime.api
|
package com.owenlejeune.tvtime.api.common
|
||||||
|
|
||||||
import retrofit2.Converter
|
import retrofit2.Converter
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.owenlejeune.tvtime.api
|
package com.owenlejeune.tvtime.api.common
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.owenlejeune.tvtime.api
|
package com.owenlejeune.tvtime.api.common
|
||||||
|
|
||||||
enum class LoadingState {
|
enum class LoadingState {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.owenlejeune.tvtime.api
|
package com.owenlejeune.tvtime.api.common
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
|
||||||
@@ -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) {
|
||||||
|
|
||||||
@@ -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) {
|
||||||
@@ -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>>
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
)
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user