mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-18 17:50:56 -05:00
some more account authentication stuff and title bar fixes
This commit is contained in:
@@ -4,12 +4,15 @@ import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.rememberSplineBasedDecay
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@@ -27,6 +30,7 @@ import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.kieronquinn.monetcompat.app.MonetCompatActivity
|
||||
import com.owenlejeune.tvtime.extensions.WindowSizeClass
|
||||
import com.owenlejeune.tvtime.extensions.rememberWindowSizeClass
|
||||
@@ -171,6 +175,9 @@ class MainActivity : MonetCompatActivity() {
|
||||
NavigationBar {
|
||||
BottomNavItem.Items.forEach { item ->
|
||||
NavigationBarItem(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.clip(RoundedCornerShape(24.dp)),
|
||||
icon = { Icon(painter = painterResource(id = item.icon), contentDescription = null) },
|
||||
label = { Text(item.name) },
|
||||
selected = currentRoute == item.route,
|
||||
@@ -191,8 +198,8 @@ class MainActivity : MonetCompatActivity() {
|
||||
appBarTitle: MutableState<String>,
|
||||
item: BottomNavItem
|
||||
) {
|
||||
appBarTitle.value = item.name
|
||||
navigateToRoute(navController, item.route)
|
||||
appBarTitle.value = item.name
|
||||
}
|
||||
|
||||
private fun navigateToRoute(navController: NavController, route: String) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.accompanist.pager.*
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.kieronquinn.monetcompat.app.MonetCompatActivity
|
||||
import com.owenlejeune.tvtime.extensions.launchActivity
|
||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||
|
||||
@@ -99,6 +99,9 @@ class TmdbClient: KoinComponent {
|
||||
sessionIdParam = QueryParam("session_id", SessionManager.currentSession!!.sessionId)
|
||||
} else if (preferences.authorizedSessionId.isNotEmpty()) {
|
||||
sessionIdParam = QueryParam("session_id", preferences.authorizedSessionId)
|
||||
} else if (preferences.authorizedSessionValues != null) {
|
||||
val sessionId = preferences.authorizedSessionValues!!.sessionId
|
||||
sessionIdParam = QueryParam("session_id", sessionId)
|
||||
}
|
||||
}
|
||||
return sessionIdParam
|
||||
@@ -113,16 +116,15 @@ class TmdbClient: KoinComponent {
|
||||
builder.header("Authorization", "Bearer ${BuildConfig.TMDB_Api_v4Key}")
|
||||
} else {
|
||||
builder.header("Authorization", "Bearer ${SessionManager.currentSession!!.accessToken}")
|
||||
val locale = Locale.current
|
||||
val languageCode = "${locale.language}-${locale.region}"
|
||||
val languageParam = QueryParam("language", languageCode)
|
||||
|
||||
val newUrl = url.newBuilder().addQueryParams(languageParam).build()
|
||||
builder.url(newUrl)
|
||||
}
|
||||
}
|
||||
|
||||
val locale = Locale.current
|
||||
val languageCode = "${locale.language}-${locale.region}"
|
||||
val languageParam = QueryParam("language", languageCode)
|
||||
|
||||
val url = chain.request().url.newBuilder().addQueryParams(languageParam).build()
|
||||
builder.url(url)
|
||||
|
||||
return chain.proceed(builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,28 +12,28 @@ import retrofit2.http.Path
|
||||
|
||||
interface AccountV4Api {
|
||||
|
||||
@GET("/account/{account_id}/lists")
|
||||
@GET("account/{account_id}/lists")
|
||||
suspend fun getLists(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<V4AccountList>>
|
||||
|
||||
@GET("/account/{account_id}/movie/favorites")
|
||||
@GET("account/{account_id}/movie/favorites")
|
||||
suspend fun getFavoriteMovies(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
|
||||
@GET("/account/{account_id}/tv/favorites")
|
||||
@GET("account/{account_id}/tv/favorites")
|
||||
suspend fun getFavoriteTvShows(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
|
||||
@GET("/account/{account_id}/movie/recommendations")
|
||||
@GET("account/{account_id}/movie/recommendations")
|
||||
suspend fun getMovieRecommendations(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
|
||||
@GET("/account/{account_id}/tv/recommendations")
|
||||
@GET("account/{account_id}/tv/recommendations")
|
||||
suspend fun getTvShowRecommendations(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
|
||||
@GET("/account/{account_id}/movie/watchlist")
|
||||
@GET("account/{account_id}/movie/watchlist")
|
||||
suspend fun getMovieWatchlist(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
|
||||
@GET("/account/{account_id}/tv/watchlist")
|
||||
@GET("account/{account_id}/tv/watchlist")
|
||||
suspend fun getTvShowWatchlist(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
|
||||
@GET("/account/{account_id}/movie/rated")
|
||||
@GET("account/{account_id}/movie/rated")
|
||||
suspend fun getRatedMovies(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<V4RatedMovie>>
|
||||
|
||||
@GET("account/{account_id}/tv/rated")
|
||||
|
||||
@@ -3,18 +3,21 @@ package com.owenlejeune.tvtime.api.tmdb.api.v4
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.StatusResponse
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.*
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.DELETE
|
||||
import retrofit2.http.HTTP
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface AuthenticationV4Api {
|
||||
|
||||
@POST("auth/request_token")
|
||||
suspend fun createRequestToken(body: AuthRequestBody): Response<AuthResponse>
|
||||
suspend fun createRequestToken(@Body body: AuthRequestBody): Response<AuthResponse>
|
||||
|
||||
@POST("auth/access_token")
|
||||
suspend fun createAccessToken(body: AuthAccessBody): Response<AccessResponse>
|
||||
suspend fun createAccessToken(@Body body: AuthAccessBody): Response<AccessResponse>
|
||||
|
||||
@DELETE("auth/access_token")
|
||||
suspend fun deleteAccessToken(body: AuthDeleteBody): Response<StatusResponse>
|
||||
// @DELETE("auth/access_token")
|
||||
@HTTP(method = "DELETE", path = "auth/access_token", hasBody = true)
|
||||
suspend fun deleteAccessToken(@Body body: AuthDeleteBody): Response<StatusResponse>
|
||||
|
||||
}
|
||||
@@ -2,8 +2,10 @@ package com.owenlejeune.tvtime.preferences
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.google.gson.Gson
|
||||
import com.kieronquinn.monetcompat.core.MonetCompat
|
||||
import com.owenlejeune.tvtime.BuildConfig
|
||||
import com.owenlejeune.tvtime.utils.SessionManager
|
||||
|
||||
class AppPreferences(context: Context) {
|
||||
|
||||
@@ -15,11 +17,13 @@ class AppPreferences(context: Context) {
|
||||
private val HIDE_TITLE = "hide_title"
|
||||
private val GUEST_SESSION = "guest_session_id"
|
||||
private val AUTHORIZED_SESSION = "authorized_session_id"
|
||||
private val AUTHORIZED_SESSION_VALUES = "authorized_session_values"
|
||||
private val FIRST_LAUNCH = "first_launch"
|
||||
private val FIRST_LAUNCH_TESTING = "first_launch_testing"
|
||||
private val CHROMA_MULTIPLIER = "chroma_multiplier"
|
||||
private val USE_SYSTEM_COLORS = "use_system_colors"
|
||||
private val SELECTED_COLOR = "selected_color"
|
||||
private val USE_V4_API = "use_v4_api"
|
||||
}
|
||||
|
||||
private val preferences: SharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE)
|
||||
@@ -36,6 +40,12 @@ class AppPreferences(context: Context) {
|
||||
get() = preferences.getString(GUEST_SESSION, "") ?: ""
|
||||
set(value) { preferences.put(GUEST_SESSION, value) }
|
||||
|
||||
var authorizedSessionValues: SessionManager.AuthorizedSessionValues?
|
||||
get() = preferences.getString(AUTHORIZED_SESSION_VALUES, null)?.let {
|
||||
Gson().fromJson(it, SessionManager.AuthorizedSessionValues::class.java)
|
||||
}
|
||||
set(value) { preferences.putNullableString(AUTHORIZED_SESSION_VALUES, value?.let { Gson().toJson(value) }) }
|
||||
|
||||
var authorizedSessionId: String
|
||||
get() = preferences.getString(AUTHORIZED_SESSION, "") ?: ""
|
||||
set(value) { preferences.put(AUTHORIZED_SESSION, value) }
|
||||
@@ -64,6 +74,10 @@ class AppPreferences(context: Context) {
|
||||
get() = preferences.getInt(SELECTED_COLOR, Int.MAX_VALUE)
|
||||
set(value) { preferences.put(SELECTED_COLOR, value) }
|
||||
|
||||
var useV4Api: Boolean
|
||||
get() = preferences.getBoolean(USE_V4_API, true)
|
||||
set(value) { preferences.put(USE_V4_API, value) }
|
||||
|
||||
private fun SharedPreferences.put(key: String, value: Any?) {
|
||||
edit().apply {
|
||||
when (value) {
|
||||
@@ -79,25 +93,10 @@ class AppPreferences(context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.putNullableString(key: String, value: String?) {
|
||||
edit().putString(key, value).apply()
|
||||
}
|
||||
|
||||
class UnsupportedTypeError: Exception()
|
||||
|
||||
// private fun <T> SharedPreferences.get(key: String, java: Class<T>): T {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// inner class PrefsMutableState<T>(val key: String): MutableState<T> {
|
||||
// override var value: T
|
||||
// get() = preferences.get(key, T::class.java)
|
||||
// set(value) { preferences.put(key, value) }
|
||||
//
|
||||
// override fun component1(): T {
|
||||
// TODO("Not yet implemented")
|
||||
// }
|
||||
//
|
||||
// override fun component2(): (T) -> Unit {
|
||||
// TODO("Not yet implemented")
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ sealed class BottomNavItem(stringRes: Int, val icon: Int, val route: String): Ko
|
||||
Movies.route -> Movies
|
||||
TV.route -> TV
|
||||
Account.route -> Account
|
||||
Favourites.route -> Favourites
|
||||
// Favourites.route -> Favourites
|
||||
Settings.route -> Settings
|
||||
else -> null
|
||||
}
|
||||
@@ -30,7 +30,7 @@ sealed class BottomNavItem(stringRes: Int, val icon: Int, val route: String): Ko
|
||||
object Movies: BottomNavItem(R.string.nav_movies_title, R.drawable.ic_movie, "movies_route")
|
||||
object TV: BottomNavItem(R.string.nav_tv_title, R.drawable.ic_tv, "tv_route")
|
||||
object Account: BottomNavItem(R.string.nav_account_title, R.drawable.ic_person, "account_route")
|
||||
object Favourites: BottomNavItem(R.string.nav_favourites_title, R.drawable.ic_favorite, "favourites_route")
|
||||
// object Favourites: BottomNavItem(R.string.nav_favourites_title, R.drawable.ic_favorite, "favourites_route")
|
||||
object Settings: BottomNavItem(R.string.nav_settings_title, R.drawable.ic_settings, "settings_route")
|
||||
object People: BottomNavItem(R.string.nav_people_title, R.drawable.ic_face, "people_route")
|
||||
|
||||
|
||||
@@ -63,26 +63,26 @@ fun MainNavGraph(
|
||||
NavHost(navController = navController, startDestination = startDestination) {
|
||||
composable(BottomNavItem.Movies.route) {
|
||||
appBarActions.value = {}
|
||||
MediaTab(appNavController = appNavController, mediaType = MediaViewType.MOVIE)
|
||||
MediaTab(appBarTitle = appBarTitle, appNavController = appNavController, mediaType = MediaViewType.MOVIE)
|
||||
}
|
||||
composable(BottomNavItem.TV.route) {
|
||||
appBarActions.value = {}
|
||||
MediaTab(appNavController = appNavController, mediaType = MediaViewType.TV)
|
||||
MediaTab(appBarTitle = appBarTitle, appNavController = appNavController, mediaType = MediaViewType.TV)
|
||||
}
|
||||
composable(BottomNavItem.Account.route) {
|
||||
AccountTab(appBarTitle = appBarTitle, appNavController = appNavController, appBarActions = appBarActions)
|
||||
}
|
||||
composable(BottomNavItem.People.route) {
|
||||
appBarActions.value = {}
|
||||
PeopleTab(appBarTitle, appNavController = appNavController)
|
||||
}
|
||||
composable(BottomNavItem.Favourites.route) {
|
||||
appBarActions.value = {}
|
||||
FavouritesTab()
|
||||
PeopleTab(appBarTitle = appBarTitle, appNavController = appNavController)
|
||||
}
|
||||
// composable(BottomNavItem.Favourites.route) {
|
||||
// appBarActions.value = {}
|
||||
// FavouritesTab()
|
||||
// }
|
||||
composable(BottomNavItem.Settings.route) {
|
||||
appBarActions.value = {}
|
||||
SettingsTab()
|
||||
SettingsTab(appBarTitle = appBarTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,15 @@ import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -24,7 +29,9 @@ import com.google.accompanist.pager.PagerState
|
||||
import com.google.accompanist.pager.rememberPagerState
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.*
|
||||
import com.owenlejeune.tvtime.ui.components.*
|
||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||
import com.owenlejeune.tvtime.ui.components.RoundedLetterImage
|
||||
import com.owenlejeune.tvtime.ui.components.SignInDialog
|
||||
import com.owenlejeune.tvtime.ui.navigation.AccountTabNavItem
|
||||
import com.owenlejeune.tvtime.ui.navigation.ListFetchFun
|
||||
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
|
||||
@@ -35,6 +42,8 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.java.KoinJavaComponent
|
||||
import org.koin.java.KoinJavaComponent.get
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private const val GUEST_SIGN_IN = "guest_sign_in"
|
||||
@@ -51,11 +60,12 @@ fun AccountTab(
|
||||
) {
|
||||
val lastSelectedOption = remember { mutableStateOf("") }
|
||||
|
||||
val lso = lastSelectedOption.value
|
||||
if (SessionManager.isV4SignInInProgress) {
|
||||
appBarTitle.value = stringResource(id = R.string.account_not_logged_in)
|
||||
AccountLoadingView()
|
||||
v4SignInPart2(lastSelectedOption)
|
||||
}
|
||||
|
||||
if (appBarTitle.value == stringResource(id = R.string.nav_account_title)) {
|
||||
} else {
|
||||
when (SessionManager.currentSession?.isAuthorized) {
|
||||
false -> {
|
||||
appBarTitle.value =
|
||||
@@ -75,33 +85,54 @@ fun AccountTab(
|
||||
appBarTitle.value = stringResource(id = R.string.account_not_logged_in)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appBarActions.value = {
|
||||
AccountDropdownMenu(session = SessionManager.currentSession, lastSelectedOption = lastSelectedOption)
|
||||
}
|
||||
|
||||
SessionManager.currentSession?.let { session ->
|
||||
val tabs = if (session.isAuthorized) {
|
||||
AccountTabNavItem.AuthorizedItems
|
||||
} else {
|
||||
AccountTabNavItem.GuestItems
|
||||
}
|
||||
|
||||
Column {
|
||||
when(session.isAuthorized) {
|
||||
true -> { AuthorizedSessionIcon() }
|
||||
false -> { GuestSessionIcon() }
|
||||
}
|
||||
|
||||
val pagerState = rememberPagerState()
|
||||
ScrollableTabs(tabs = tabs, pagerState = pagerState)
|
||||
AccountTabs(
|
||||
appNavController = appNavController,
|
||||
tabs = tabs,
|
||||
pagerState = pagerState
|
||||
appBarActions.value = {
|
||||
AccountDropdownMenu(
|
||||
session = SessionManager.currentSession,
|
||||
lastSelectedOption = lastSelectedOption
|
||||
)
|
||||
}
|
||||
|
||||
if (!SessionManager.isV4SignInInProgress) {
|
||||
SessionManager.currentSession?.let { session ->
|
||||
val tabs = if (session.isAuthorized) {
|
||||
AccountTabNavItem.AuthorizedItems
|
||||
} else {
|
||||
AccountTabNavItem.GuestItems
|
||||
}
|
||||
|
||||
Column {
|
||||
when (session.isAuthorized) {
|
||||
true -> {
|
||||
AuthorizedSessionIcon()
|
||||
}
|
||||
false -> {
|
||||
GuestSessionIcon()
|
||||
}
|
||||
}
|
||||
|
||||
val pagerState = rememberPagerState()
|
||||
ScrollableTabs(tabs = tabs, pagerState = pagerState)
|
||||
AccountTabs(
|
||||
appNavController = appNavController,
|
||||
tabs = tabs,
|
||||
pagerState = pagerState
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AccountLoadingView() {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(200.dp),
|
||||
color = MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,12 +307,17 @@ private fun AccountDropdownMenu(
|
||||
@Composable
|
||||
private fun AuthorizedSessionMenuItems(
|
||||
expanded: MutableState<Boolean>,
|
||||
lastSelectedOption: MutableState<String>
|
||||
lastSelectedOption: MutableState<String>,
|
||||
preferences: AppPreferences = get(AppPreferences::class.java)
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(id = R.string.action_sign_out)) },
|
||||
onClick = {
|
||||
signOut(lastSelectedOption)
|
||||
if (preferences.useV4Api) {
|
||||
signOutV4(lastSelectedOption)
|
||||
} else {
|
||||
signOut(lastSelectedOption)
|
||||
}
|
||||
expanded.value = false
|
||||
}
|
||||
)
|
||||
@@ -320,7 +356,8 @@ private fun GuestSessionMenuItems(
|
||||
@Composable
|
||||
private fun NoSessionMenuItems(
|
||||
expanded: MutableState<Boolean>,
|
||||
lastSelectedOption: MutableState<String>
|
||||
lastSelectedOption: MutableState<String>,
|
||||
preferences: AppPreferences = get(AppPreferences::class.java)
|
||||
) {
|
||||
val showSignInDialog = remember { mutableStateOf(false) }
|
||||
|
||||
@@ -333,15 +370,18 @@ private fun NoSessionMenuItems(
|
||||
}
|
||||
}
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(id = R.string.action_sign_in)) },
|
||||
onClick = { showSignInDialog.value = true }
|
||||
)
|
||||
// val context = LocalContext.current
|
||||
// DropdownMenuItem(
|
||||
// text = { Text(text = stringResource(id = R.string.action_sign_in)) },
|
||||
// onClick = { v4SignInPart1(context) }
|
||||
// )
|
||||
if (!preferences.useV4Api) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(id = R.string.action_sign_in)) },
|
||||
onClick = { showSignInDialog.value = true }
|
||||
)
|
||||
} else {
|
||||
val context = LocalContext.current
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(id = R.string.action_sign_in)) },
|
||||
onClick = { v4SignInPart1(context) }
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(id = R.string.action_sign_in_as_guest)) },
|
||||
@@ -362,7 +402,9 @@ private fun v4SignInPart2(lastSelectedOption: MutableState<String>) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val signIn = SessionManager.signInWithV4Part2()
|
||||
if (signIn) {
|
||||
lastSelectedOption.value = NO_SESSION_SIGN_IN
|
||||
withContext(Dispatchers.Main) {
|
||||
lastSelectedOption.value = NO_SESSION_SIGN_IN
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,9 +461,21 @@ private fun createGuestSession(lastSelectedOption: MutableState<String>) {
|
||||
}
|
||||
|
||||
private fun signOut(lastSelectedOption: MutableState<String>) {
|
||||
SessionManager.clearSession { isSuccessful ->
|
||||
if (isSuccessful) {
|
||||
lastSelectedOption.value = SIGN_OUT
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
SessionManager.clearSession { isSuccessful ->
|
||||
if (isSuccessful) {
|
||||
lastSelectedOption.value = SIGN_OUT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun signOutV4(lastSelectedOption: MutableState<String>) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
SessionManager.clearSessionV4 { isSuccessful ->
|
||||
if (isSuccessful) {
|
||||
lastSelectedOption.value = SIGN_OUT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.owenlejeune.tvtime.ui.screens.main
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
@@ -9,6 +11,7 @@ import com.google.accompanist.pager.ExperimentalPagerApi
|
||||
import com.google.accompanist.pager.HorizontalPager
|
||||
import com.google.accompanist.pager.PagerState
|
||||
import com.google.accompanist.pager.rememberPagerState
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.HomePageService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.MoviesService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.TvService
|
||||
@@ -24,7 +27,17 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
@OptIn(ExperimentalPagerApi::class)
|
||||
@Composable
|
||||
fun MediaTab(appNavController: NavHostController, mediaType: MediaViewType) {
|
||||
fun MediaTab(
|
||||
appBarTitle: MutableState<String>,
|
||||
appNavController: NavHostController,
|
||||
mediaType: MediaViewType
|
||||
) {
|
||||
appBarTitle.value = when (mediaType) {
|
||||
MediaViewType.MOVIE -> stringResource(id = R.string.nav_movies_title)
|
||||
MediaViewType.TV -> stringResource(id = R.string.nav_tv_title)
|
||||
else -> ""
|
||||
}
|
||||
|
||||
Column {
|
||||
val tabs = when (mediaType) {
|
||||
MediaViewType.MOVIE -> MediaTabNavItem.MovieItems
|
||||
|
||||
@@ -24,7 +24,7 @@ fun PeopleTab(
|
||||
appBarTitle: MutableState<String>,
|
||||
appNavController: NavHostController
|
||||
) {
|
||||
// appBarTitle.value = stringResource(id = R.string.nav_people_title)
|
||||
appBarTitle.value = stringResource(id = R.string.nav_people_title)
|
||||
|
||||
val service = PeopleService()
|
||||
|
||||
|
||||
@@ -40,7 +40,12 @@ import kotlinx.coroutines.launch
|
||||
import org.koin.java.KoinJavaComponent.get
|
||||
|
||||
@Composable
|
||||
fun SettingsTab(preferences: AppPreferences = get(AppPreferences::class.java)) {
|
||||
fun SettingsTab(
|
||||
appBarTitle: MutableState<String>,
|
||||
preferences: AppPreferences = get(AppPreferences::class.java)
|
||||
) {
|
||||
appBarTitle.value = stringResource(id = R.string.nav_settings_title)
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
Column(
|
||||
@@ -238,6 +243,7 @@ private fun WallpaperPicker(
|
||||
@Composable
|
||||
private fun DebugOptions(preferences: AppPreferences = get(AppPreferences::class.java)) {
|
||||
val context = LocalContext.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val firstLaunchTesting = remember { mutableStateOf(preferences.firstLaunchTesting) }
|
||||
SwitchPreference(
|
||||
@@ -285,12 +291,29 @@ private fun DebugOptions(preferences: AppPreferences = get(AppPreferences::class
|
||||
.clickable(
|
||||
onClick = {
|
||||
preferences.guestSessionId = ""
|
||||
SessionManager.clearSession {
|
||||
Toast
|
||||
.makeText(context, "Cleared session: $it", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
coroutineScope.launch {
|
||||
SessionManager.clearSession {
|
||||
Toast
|
||||
.makeText(context, "Cleared session: $it", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
SessionManager.clearSessionV4 {
|
||||
Toast
|
||||
.makeText(context, "Cleared session v4: $it", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
val useV4Api = remember { mutableStateOf(preferences.useV4Api) }
|
||||
SwitchPreference(
|
||||
titleText = "Use v4 API",
|
||||
checkState = useV4Api.value,
|
||||
onCheckedChange = { isChecked ->
|
||||
useV4Api.value = isChecked
|
||||
preferences.useV4Api = isChecked
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.kieronquinn.monetcompat.core.MonetCompat
|
||||
|
||||
private val DarkColorPalette = darkColorScheme(
|
||||
@@ -127,7 +128,12 @@ fun TVTimeTheme(
|
||||
isLight = !isDarkTheme
|
||||
),
|
||||
shapes = Shapes,
|
||||
content = content
|
||||
content = {
|
||||
val systemUiController = rememberSystemUiController()
|
||||
systemUiController.setSystemBarsColor(color = androidx.compose.material3.MaterialTheme.colorScheme.background)
|
||||
|
||||
content()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.owenlejeune.tvtime.utils
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.AccountService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.AuthenticationService
|
||||
@@ -34,7 +36,13 @@ object SessionManager: KoinComponent {
|
||||
private val authenticationService by lazy { TmdbClient().createAuthenticationService() }
|
||||
private val authenticationV4Service by lazy { TmdbClient().createV4AuthenticationService() }
|
||||
|
||||
fun clearSession(onResponse: (isSuccessful: Boolean) -> Unit) {
|
||||
class AuthorizedSessionValues(
|
||||
@SerializedName("session_id") val sessionId: String,
|
||||
@SerializedName("access_token") val accessToken: String,
|
||||
@SerializedName("account_id") val accountId: String
|
||||
)
|
||||
|
||||
suspend fun clearSession(onResponse: (isSuccessful: Boolean) -> Unit) {
|
||||
currentSession?.let { session ->
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val deleteResponse = authenticationService.deleteSession(SessionBody(session.sessionId))
|
||||
@@ -42,7 +50,8 @@ object SessionManager: KoinComponent {
|
||||
if (deleteResponse.isSuccessful) {
|
||||
_currentSession = null
|
||||
preferences.guestSessionId = ""
|
||||
preferences.authorizedSessionId = ""
|
||||
preferences.authorizedSessionValues = null
|
||||
// preferences.authorizedSessionId = ""
|
||||
}
|
||||
onResponse(deleteResponse.isSuccessful)
|
||||
}
|
||||
@@ -53,12 +62,13 @@ object SessionManager: KoinComponent {
|
||||
fun clearSessionV4(onResponse: (isSuccessful: Boolean) -> Unit) {
|
||||
currentSession?.let { session ->
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val deleteResponse = authenticationV4Service.deleteAccessToken(AuthDeleteBody(session.sessionId))
|
||||
val deleteResponse = authenticationV4Service.deleteAccessToken(AuthDeleteBody(session.accessToken))
|
||||
withContext(Dispatchers.Main) {
|
||||
if (deleteResponse.isSuccessful) {
|
||||
_currentSession = null
|
||||
preferences.guestSessionId = ""
|
||||
preferences.authorizedSessionId = ""
|
||||
preferences.authorizedSessionValues = null
|
||||
// preferences.authorizedSessionId = ""
|
||||
}
|
||||
onResponse(deleteResponse.isSuccessful)
|
||||
}
|
||||
@@ -75,6 +85,16 @@ object SessionManager: KoinComponent {
|
||||
val session = AuthorizedSession()
|
||||
session.initialize()
|
||||
_currentSession = session
|
||||
} else {
|
||||
preferences.authorizedSessionValues?.let { values ->
|
||||
val session = AuthorizedSession(
|
||||
sessionId = values.sessionId,
|
||||
accessToken = values.accessToken,
|
||||
accountId = values.accountId
|
||||
)
|
||||
session.initialize()
|
||||
_currentSession = session
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +124,7 @@ object SessionManager: KoinComponent {
|
||||
if (sr.isSuccess) {
|
||||
preferences.authorizedSessionId = sr.sessionId
|
||||
preferences.guestSessionId = ""
|
||||
preferences.authorizedSessionValues = null
|
||||
_currentSession = AuthorizedSession()
|
||||
_currentSession?.initialize()
|
||||
return true
|
||||
@@ -122,7 +143,7 @@ object SessionManager: KoinComponent {
|
||||
isV4SignInInProgress = true
|
||||
|
||||
val service = AuthenticationV4Service()
|
||||
val requestTokenResponse = service.createRequestToken(AuthRequestBody(redirect = ""))
|
||||
val requestTokenResponse = service.createRequestToken(AuthRequestBody(redirect = "app://tvtime.auth.return"))
|
||||
if (requestTokenResponse.isSuccessful) {
|
||||
requestTokenResponse.body()?.let { ctr ->
|
||||
_currentSession = InProgressSession(ctr.requestToken)
|
||||
@@ -147,20 +168,23 @@ object SessionManager: KoinComponent {
|
||||
val sessionResponse = authenticationService.createSessionFromV4Token(V4TokenBody(ar.accessToken))
|
||||
if (sessionResponse.isSuccessful) {
|
||||
sessionResponse.body()?.let { sr ->
|
||||
preferences.authorizedSessionId = sr.sessionId
|
||||
preferences.authorizedSessionValues = AuthorizedSessionValues(
|
||||
sessionId = sr.sessionId,
|
||||
accountId = ar.accountId,
|
||||
accessToken = ar.accessToken
|
||||
)
|
||||
preferences.authorizedSessionId = ""
|
||||
preferences.guestSessionId = ""
|
||||
_currentSession = AuthorizedSession(accessToken = ar.accessToken, accountId = ar.accountId)
|
||||
_currentSession = AuthorizedSession(
|
||||
sessionId = sr.sessionId,
|
||||
accessToken = ar.accessToken,
|
||||
accountId = ar.accountId
|
||||
)
|
||||
_currentSession?.initialize()
|
||||
isV4SignInInProgress = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
// preferences.authorizedSessionId = ar.accessToken
|
||||
// preferences.guestSessionId = ""
|
||||
// _currentSession = AuthorizedSession()
|
||||
// _currentSession?.initialize()
|
||||
// isV4SignInInProgress = false
|
||||
// return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,7 +299,11 @@ object SessionManager: KoinComponent {
|
||||
|
||||
}
|
||||
|
||||
private class AuthorizedSession(accessToken: String = "", accountId: String = ""): Session(preferences.authorizedSessionId, true, accessToken, accountId) {
|
||||
private class AuthorizedSession(
|
||||
sessionId: String = preferences.authorizedSessionId,
|
||||
accessToken: String = "",
|
||||
accountId: String = ""
|
||||
): Session(sessionId, true, accessToken, accountId) {
|
||||
private val service by lazy { AccountService() }
|
||||
|
||||
override suspend fun initialize() {
|
||||
@@ -286,14 +314,14 @@ object SessionManager: KoinComponent {
|
||||
if (changed.contains(Changed.AccountDetails)) {
|
||||
service.getAccountDetails().apply {
|
||||
if (isSuccessful) {
|
||||
withContext(Dispatchers.Main) {
|
||||
// withContext(Dispatchers.Main) {
|
||||
_accountDetails = body() ?: _accountDetails
|
||||
accountDetails?.let {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// CoroutineScope(Dispatchers.IO).launch {
|
||||
refreshWithAccountId(it.id, changed)
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
} else if (accountDetails != null) {
|
||||
|
||||
Reference in New Issue
Block a user