some more account authentication stuff and title bar fixes

This commit is contained in:
Owen LeJeune
2022-06-28 15:27:02 -04:00
parent 58b740cfb0
commit 24f75f0211
14 changed files with 256 additions and 120 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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())
}
}

View File

@@ -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")

View File

@@ -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>
}

View File

@@ -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")
// }
//
// }
}

View File

@@ -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")

View File

@@ -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)
}
}
}

View File

@@ -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
}
}
}
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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
}
)
}

View File

@@ -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()
}
)
}
}

View File

@@ -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) {