mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-22 11:40:54 -05:00
custom dropdown menu + setup account api service
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.*
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.*
|
||||
|
||||
interface AccountApi {
|
||||
|
||||
@GET("account")
|
||||
suspend fun getAccountDetails(): Response<AccountDetails>
|
||||
|
||||
@GET("account/{id}/lists")
|
||||
suspend fun getLists(
|
||||
@Path("id") id: Int,
|
||||
@Query("page") page: Int
|
||||
): Response<AccountListResponse>
|
||||
|
||||
@GET("account/{id}/favorite/movies")
|
||||
suspend fun getFavoriteMovies(
|
||||
@Path("id") id: Int,
|
||||
@Query("page") page: Int
|
||||
): Response<FavoriteMediaResponse<FavoriteMovie>>
|
||||
|
||||
@GET("account/{id}/favorite/tv")
|
||||
suspend fun getFavoriteTvShows(
|
||||
@Path("id") id: Int,
|
||||
@Query("page") page: Int
|
||||
): Response<FavoriteMediaResponse<FavoriteTvSeries>>
|
||||
|
||||
// @Headers("Content-Type: application/json;charset=utf-8")
|
||||
@POST("account/{id}/favorite")
|
||||
suspend fun markAsFavorite(
|
||||
@Path("id") id: Int,
|
||||
@Body body: MarkAsFavoriteBody
|
||||
): Response<StatusResponse>
|
||||
|
||||
@GET("account/{id}/rated/movies")
|
||||
suspend fun getRatedMovies(
|
||||
@Path("id") id: Int,
|
||||
@Query("page") page: Int
|
||||
): Response<RatedMediaResponse<RatedMovie>>
|
||||
|
||||
@GET("account/{id}/rated/tv")
|
||||
suspend fun getRatedTvShows(
|
||||
@Path("id") id: Int,
|
||||
@Query("page") page: Int
|
||||
): Response<RatedMediaResponse<RatedTv>>
|
||||
|
||||
@GET("account/{id}/rated/tv/episodes")
|
||||
suspend fun getRatedTvEpisodes(
|
||||
@Path("id") id: Int,
|
||||
@Query("page") page: Int
|
||||
): Response<RatedMediaResponse<RatedEpisode>>
|
||||
|
||||
@GET("account/{id}/watchlist/movies")
|
||||
suspend fun getMovieWatchlist(
|
||||
@Path("id") id: Int,
|
||||
@Query("page") page: Int
|
||||
): Response<WatchlistResponse<WatchlistMovie>>
|
||||
|
||||
@GET("account/{id}/watchlist/tv")
|
||||
suspend fun getTvWatchlist(
|
||||
@Path("id") id: Int,
|
||||
@Query("page") page: Int
|
||||
): Response<WatchlistResponse<WatchlistTvSeries>>
|
||||
|
||||
// @Headers("Content-Type: application/json;charset=utf-8")
|
||||
@POST("account/{id}/watchlist")
|
||||
suspend fun addToWatchlist(
|
||||
@Path("id") id: Int,
|
||||
@Body body: WatchlistBody
|
||||
): Response<StatusResponse>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.*
|
||||
import retrofit2.Response
|
||||
|
||||
class AccountService {
|
||||
|
||||
private val accountService by lazy { TmdbClient().createAccountService() }
|
||||
|
||||
suspend fun getAccountDetails(): Response<AccountDetails> {
|
||||
return accountService.getAccountDetails()
|
||||
}
|
||||
|
||||
suspend fun getFavoriteMovies(accountId: Int, page: Int = 1): Response<FavoriteMediaResponse<FavoriteMovie>> {
|
||||
return accountService.getFavoriteMovies(accountId, page)
|
||||
}
|
||||
|
||||
suspend fun getFavoriteTvShows(accountId: Int, page: Int = 1): Response<FavoriteMediaResponse<FavoriteTvSeries>> {
|
||||
return accountService.getFavoriteTvShows(accountId, page)
|
||||
}
|
||||
|
||||
suspend fun markAsFavorite(accountId: Int, body: MarkAsFavoriteBody): Response<StatusResponse> {
|
||||
return accountService.markAsFavorite(accountId, body)
|
||||
}
|
||||
|
||||
suspend fun getRatedMovies(accountId: Int, page: Int = 1): Response<RatedMediaResponse<RatedMovie>> {
|
||||
return accountService.getRatedMovies(accountId, page)
|
||||
}
|
||||
|
||||
suspend fun getRatedTvShows(accountId: Int, page: Int = 1): Response<RatedMediaResponse<RatedTv>> {
|
||||
return accountService.getRatedTvShows(accountId, page)
|
||||
}
|
||||
|
||||
suspend fun getRatedTvEpisodes(accountId: Int, page: Int = 1): Response<RatedMediaResponse<RatedEpisode>> {
|
||||
return accountService.getRatedTvEpisodes(accountId, page)
|
||||
}
|
||||
|
||||
suspend fun getMovieWatchlist(accountId: Int, page: Int = 1): Response<WatchlistResponse<WatchlistMovie>> {
|
||||
return accountService.getMovieWatchlist(accountId, page)
|
||||
}
|
||||
|
||||
suspend fun getTvWatchlist(accountId: Int, page: Int = 1): Response<WatchlistResponse<WatchlistTvSeries>> {
|
||||
return accountService.getTvWatchlist(accountId, page)
|
||||
}
|
||||
|
||||
suspend fun addToWatchlist(accountId: Int, body: WatchlistBody): Response<StatusResponse> {
|
||||
return accountService.addToWatchlist(accountId, body)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,9 +17,9 @@ interface DetailService {
|
||||
|
||||
suspend fun getReviews(id: Int): Response<ReviewResponse>
|
||||
|
||||
suspend fun postRating(id: Int, ratingBody: RatingBody): Response<RatingResponse>
|
||||
suspend fun postRating(id: Int, ratingBody: RatingBody): Response<StatusResponse>
|
||||
|
||||
suspend fun deleteRating(id: Int): Response<RatingResponse>
|
||||
suspend fun deleteRating(id: Int): Response<StatusResponse>
|
||||
|
||||
suspend fun getKeywords(id: Int): Response<KeywordsResponse>
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class MarkAsFavoriteBody(
|
||||
@SerializedName("media_type") val mediaType: String, // media type
|
||||
@SerializedName("media_id") val mediaId: Int,
|
||||
@SerializedName("favorite") val isFavorite: Boolean
|
||||
)
|
||||
@@ -47,25 +47,25 @@ interface MoviesApi {
|
||||
@Path("id") id: Int,
|
||||
@Query("guest_session_id") guestSessionId: String,
|
||||
@Body ratingBody: RatingBody
|
||||
): Response<RatingResponse>
|
||||
): Response<StatusResponse>
|
||||
|
||||
@POST("movie/{id}/rating")
|
||||
suspend fun postMovieRatingAsUser(
|
||||
@Path("id") id: Int,
|
||||
@Query("session_id") sessionId: String,
|
||||
@Body ratingBody: RatingBody
|
||||
): Response<RatingResponse>
|
||||
): Response<StatusResponse>
|
||||
|
||||
@DELETE("movie/{id}/rating")
|
||||
suspend fun deleteMovieReviewAsGuest(
|
||||
@Path("id") id: Int,
|
||||
@Query("guest_session_id") guestSessionId: String
|
||||
): Response<RatingResponse>
|
||||
): Response<StatusResponse>
|
||||
|
||||
@DELETE("movie/{id}/rating")
|
||||
suspend fun deleteMovieReviewAsUser(
|
||||
@Path("id") id: Int,
|
||||
@Query("session_id") sessionId: String
|
||||
): Response<RatingResponse>
|
||||
): Response<StatusResponse>
|
||||
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class MoviesService: KoinComponent, DetailService, HomePageService {
|
||||
return movieService.getReviews(id)
|
||||
}
|
||||
|
||||
override suspend fun postRating(id: Int, rating: RatingBody): Response<RatingResponse> {
|
||||
override suspend fun postRating(id: Int, rating: RatingBody): Response<StatusResponse> {
|
||||
val session = SessionManager.currentSession ?: throw Exception("Session must not be null")
|
||||
return if (!session.isAuthorized) {
|
||||
movieService.postMovieRatingAsGuest(id, session.sessionId, rating)
|
||||
@@ -62,7 +62,7 @@ class MoviesService: KoinComponent, DetailService, HomePageService {
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteRating(id: Int): Response<RatingResponse> {
|
||||
override suspend fun deleteRating(id: Int): Response<StatusResponse> {
|
||||
val session = SessionManager.currentSession ?: throw Exception("Session must not be null")
|
||||
return if (!session.isAuthorized) {
|
||||
movieService.deleteMovieReviewAsGuest(id, session.sessionId)
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.owenlejeune.tvtime.BuildConfig
|
||||
import com.owenlejeune.tvtime.api.Client
|
||||
import com.owenlejeune.tvtime.api.QueryParam
|
||||
import com.owenlejeune.tvtime.extensions.addQueryParams
|
||||
import com.owenlejeune.tvtime.utils.SessionManager
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import org.koin.core.component.KoinComponent
|
||||
@@ -43,6 +44,10 @@ class TmdbClient: KoinComponent {
|
||||
return client.create(GuestSessionApi::class.java)
|
||||
}
|
||||
|
||||
fun createAccountService(): AccountApi {
|
||||
return client.create(AccountApi::class.java)
|
||||
}
|
||||
|
||||
private inner class TmdbInterceptor: Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val apiParam = QueryParam("api_key", BuildConfig.TMDB_ApiKey)
|
||||
@@ -51,7 +56,13 @@ class TmdbClient: KoinComponent {
|
||||
val languageCode = "${locale.language}-${locale.region}"
|
||||
val languageParam = QueryParam("language", languageCode)
|
||||
|
||||
val request = chain.addQueryParams(apiParam, languageParam)
|
||||
var sessionIdParam: QueryParam? = null
|
||||
val segments = chain.request().url().encodedPathSegments()
|
||||
if (segments.size > 1 && segments[1].equals("account") && SessionManager.currentSession?.isAuthorized == true) {
|
||||
sessionIdParam = QueryParam("session_id", SessionManager.currentSession!!.sessionId)
|
||||
}
|
||||
|
||||
val request = chain.addQueryParams(apiParam, languageParam, sessionIdParam)
|
||||
|
||||
return chain.proceed(request)
|
||||
}
|
||||
|
||||
@@ -47,25 +47,25 @@ interface TvApi {
|
||||
@Path("id") id: Int,
|
||||
@Query("guest_session_id") guestSessionId: String,
|
||||
@Body ratingBody: RatingBody
|
||||
): Response<RatingResponse>
|
||||
): Response<StatusResponse>
|
||||
|
||||
@POST("tv/{id}/rating")
|
||||
suspend fun postTvRatingAsUser(
|
||||
@Path("id") id: Int,
|
||||
@Query("session_id") sessionId: String,
|
||||
@Body ratingBody: RatingBody
|
||||
): Response<RatingResponse>
|
||||
): Response<StatusResponse>
|
||||
|
||||
@DELETE("tv/{id}/rating")
|
||||
suspend fun deleteTvReviewAsGuest(
|
||||
@Path("id") id: Int,
|
||||
@Query("guest_session_id") guestSessionId: String
|
||||
): Response<RatingResponse>
|
||||
): Response<StatusResponse>
|
||||
|
||||
@DELETE("tv/{id}/rating")
|
||||
suspend fun deleteTvReviewAsUser(
|
||||
@Path("id") id: Int,
|
||||
@Query("session_id") sessionId: String
|
||||
): Response<RatingResponse>
|
||||
): Response<StatusResponse>
|
||||
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class TvService: KoinComponent, DetailService, HomePageService {
|
||||
return service.getReviews(id)
|
||||
}
|
||||
|
||||
override suspend fun postRating(id: Int, rating: RatingBody): Response<RatingResponse> {
|
||||
override suspend fun postRating(id: Int, rating: RatingBody): Response<StatusResponse> {
|
||||
val session = SessionManager.currentSession ?: throw Exception("Session must not be null")
|
||||
return if (!session.isAuthorized) {
|
||||
service.postTvRatingAsGuest(id, session.sessionId, rating)
|
||||
@@ -62,7 +62,7 @@ class TvService: KoinComponent, DetailService, HomePageService {
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteRating(id: Int): Response<RatingResponse> {
|
||||
override suspend fun deleteRating(id: Int): Response<StatusResponse> {
|
||||
val session = SessionManager.currentSession ?: throw Exception("Session must not be null")
|
||||
return if (!session.isAuthorized) {
|
||||
service.deleteTvReviewAsGuest(id, session.sessionId)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class AccountDetails(
|
||||
@SerializedName("avatar") val avatar: Avatar,
|
||||
@SerializedName("id") val id: Int,
|
||||
@SerializedName("iso_639_1") val languageCode: String,
|
||||
@SerializedName("iso_3166_1") val countryCode: String,
|
||||
@SerializedName("name") val name: String,
|
||||
@SerializedName("include_adult") val includeAdult: Boolean,
|
||||
@SerializedName("username") val username: String
|
||||
)
|
||||
|
||||
class Avatar(
|
||||
@SerializedName("gravatar") val gravatar: Gravatar
|
||||
)
|
||||
|
||||
class Gravatar(
|
||||
@SerializedName("hash") val hash: String
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class AccountList(
|
||||
@SerializedName("description") val description: String,
|
||||
@SerializedName("favorite_count") val favoriteCount: Int,
|
||||
@SerializedName("id") val id: Int,
|
||||
@SerializedName("item_count") val itemCount: Int,
|
||||
@SerializedName("iso_639_1") val languageCode: String,
|
||||
@SerializedName("list_type") val listType: String, // media type
|
||||
@SerializedName("name") val name: String
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class AccountListResponse(
|
||||
@SerializedName("page") val page: Int,
|
||||
@SerializedName("total_pages") val totalPages: Int,
|
||||
@SerializedName("total_results") val totalResults: Int,
|
||||
@SerializedName("results") val results: List<AccountList>
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
abstract class FavoriteMedia(
|
||||
@SerializedName("poster_path") val posterPath: String?,
|
||||
@SerializedName("popularity") val popularity: Float,
|
||||
@SerializedName("id") val id: Int,
|
||||
@SerializedName("backdrop_path") val backdropPath: String?,
|
||||
@SerializedName("vote_average") val voteAverage: Float,
|
||||
@SerializedName("overview") val overview: String,
|
||||
@SerializedName("release_date", alternate = ["first_air_date"]) val releaseDate: String,
|
||||
@SerializedName("genre_ids") val genreIds: List<Int>,
|
||||
@SerializedName("original_language") val originalLanguage: String,
|
||||
@SerializedName("vote_count") val voteCount: Int,
|
||||
@SerializedName("title", alternate = ["name"]) val title: String,
|
||||
@SerializedName("original_title", alternate = ["original_name"]) val originalTitle: String
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class FavoriteMediaResponse<T: FavoriteMedia>(
|
||||
@SerializedName("page") val page: Int,
|
||||
@SerializedName("results") val results: List<T>,
|
||||
@SerializedName("total_pages") val totalPages: Int,
|
||||
@SerializedName("total_results") val totalResults: Int
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class FavoriteMovie(
|
||||
posterPath: String?,
|
||||
popularity: Float,
|
||||
id: Int,
|
||||
backdropPath: String?,
|
||||
voteAverage: Float,
|
||||
overview: String,
|
||||
releaseDate: String,
|
||||
genreIds: List<Int>,
|
||||
originalLanguage: String,
|
||||
voteCount: Int,
|
||||
title: String,
|
||||
originalTitle: String,
|
||||
@SerializedName("adult") val isAdult: Boolean,
|
||||
@SerializedName("video") val isVideo: Boolean,
|
||||
): FavoriteMedia(
|
||||
posterPath, popularity, id, backdropPath, voteAverage, overview, releaseDate,
|
||||
genreIds, originalLanguage, voteCount, title, originalTitle
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class FavoriteTvSeries(
|
||||
posterPath: String?,
|
||||
popularity: Float,
|
||||
id: Int,
|
||||
backdropPath: String?,
|
||||
voteAverage: Float,
|
||||
overview: String,
|
||||
releaseDate: String,
|
||||
genreIds: List<Int>,
|
||||
originalLanguage: String,
|
||||
voteCount: Int,
|
||||
title: String,
|
||||
originalTitle: String,
|
||||
@SerializedName("origin_country") val originCountry: List<String>
|
||||
): FavoriteMedia(
|
||||
posterPath, popularity, id, backdropPath, voteAverage, overview, releaseDate,
|
||||
genreIds, originalLanguage, voteCount, title, originalTitle
|
||||
)
|
||||
@@ -2,7 +2,7 @@ package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class RatingResponse(
|
||||
class StatusResponse(
|
||||
@SerializedName("status_code") val statusCode: Int,
|
||||
@SerializedName("status_message") val statusMessage: String
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class WatchlistBody(
|
||||
@SerializedName("media_type") val mediaType: String, // media type
|
||||
@SerializedName("media_id") val mediaId: Int,
|
||||
@SerializedName("watchlist") val onWatchlist: Boolean
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
abstract class WatchlistMedia(
|
||||
@SerializedName("poster_path") val posterPath: String?,
|
||||
@SerializedName("popularity") val popularity: Float,
|
||||
@SerializedName("id") val id: Int,
|
||||
@SerializedName("backdrop_path") val backdropPath: String?,
|
||||
@SerializedName("vote_average") val voteAverage: Float,
|
||||
@SerializedName("overview") val overview: String,
|
||||
@SerializedName("release_date", alternate = ["first_air_date"]) val releaseDate: String,
|
||||
@SerializedName("genre_ids") val genreIds: List<Int>,
|
||||
@SerializedName("original_language") val originalLanguage: String,
|
||||
@SerializedName("vote_count") val voteCount: Int,
|
||||
@SerializedName("title", alternate = ["name"]) val title: String,
|
||||
@SerializedName("original_title", alternate = ["original_name"]) val originalTitle: String
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class WatchlistMovie(
|
||||
posterPath: String?,
|
||||
popularity: Float,
|
||||
id: Int,
|
||||
backdropPath: String?,
|
||||
voteAverage: Float,
|
||||
overview: String,
|
||||
releaseDate: String,
|
||||
genreIds: List<Int>,
|
||||
originalLanguage: String,
|
||||
voteCount: Int,
|
||||
title: String,
|
||||
originalTitle: String,
|
||||
@SerializedName("adult") val isAdult: Boolean,
|
||||
@SerializedName("video") val isVideo: Boolean,
|
||||
): WatchlistMedia(
|
||||
posterPath, popularity, id, backdropPath, voteAverage, overview, releaseDate,
|
||||
genreIds, originalLanguage, voteCount, title, originalTitle
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class WatchlistResponse<T: WatchlistMedia>(
|
||||
@SerializedName("page") val page: Int,
|
||||
@SerializedName("results") val results: List<T>,
|
||||
@SerializedName("total_pages") val totalPages: Int,
|
||||
@SerializedName("total_results") val totalResults: Int
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class WatchlistTvSeries(
|
||||
posterPath: String?,
|
||||
popularity: Float,
|
||||
id: Int,
|
||||
backdropPath: String?,
|
||||
voteAverage: Float,
|
||||
overview: String,
|
||||
releaseDate: String,
|
||||
genreIds: List<Int>,
|
||||
originalLanguage: String,
|
||||
voteCount: Int,
|
||||
title: String,
|
||||
originalTitle: String,
|
||||
@SerializedName("origin_country") val originCountry: List<String>
|
||||
): WatchlistMedia(
|
||||
posterPath, popularity, id, backdropPath, voteAverage, overview, releaseDate,
|
||||
genreIds, originalLanguage, voteCount, title, originalTitle
|
||||
)
|
||||
@@ -1,19 +1,26 @@
|
||||
package com.owenlejeune.tvtime.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.AlertDialog
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.DropdownMenu
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
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.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.compose.ui.window.Dialog
|
||||
|
||||
@Composable
|
||||
@@ -36,7 +43,7 @@ fun TopAppBarDropdownMenu(
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
modifier = Modifier.background(color = MaterialTheme.colorScheme.surfaceVariant),
|
||||
modifier = Modifier.background(color = MaterialTheme.colorScheme.background),
|
||||
expanded = expanded.value,
|
||||
onDismissRequest = { expanded.value = false }
|
||||
) {
|
||||
@@ -44,6 +51,59 @@ fun TopAppBarDropdownMenu(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomTopAppBarDropdownMenu(
|
||||
icon: @Composable () -> Unit = {},
|
||||
content: @Composable ColumnScope.(expanded: MutableState<Boolean>) -> Unit = {}
|
||||
) {
|
||||
val expanded = remember { mutableStateOf(false) }
|
||||
|
||||
Box(modifier = Modifier.wrapContentSize(Alignment.TopEnd)) {
|
||||
IconButton(onClick = { expanded.value = true }) {
|
||||
icon()
|
||||
}
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = expanded.value,
|
||||
onDismissRequest = { expanded.value = false},
|
||||
modifier = Modifier
|
||||
.background(color = MaterialTheme.colorScheme.background)
|
||||
.shadow(elevation = 0.dp),
|
||||
offset = DpOffset(16.dp, 0.dp)
|
||||
) {
|
||||
content(this, expanded)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomMenuItem(
|
||||
text: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(30.dp))
|
||||
.fillMaxWidth()
|
||||
.background(color = MaterialTheme.colorScheme.primary)
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
color = MaterialTheme.colorScheme.background,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 15.dp, vertical = 10.dp)
|
||||
.clickable(onClick = onClick)
|
||||
.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomMenuDivider() {
|
||||
Divider(color = Color.Transparent, modifier = Modifier.padding(vertical = 2.dp))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TopAppBarDialogMenu(
|
||||
icon: @Composable () -> Unit = {},
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package com.owenlejeune.tvtime.ui.screens.tabs.bottom
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AccountCircle
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
@@ -31,9 +28,7 @@ import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.RatedMovie
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.RatedTopLevelMedia
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.RatedTv
|
||||
import com.owenlejeune.tvtime.ui.components.RoundedLetterImage
|
||||
import com.owenlejeune.tvtime.ui.components.SignInDialog
|
||||
import com.owenlejeune.tvtime.ui.components.TopAppBarDropdownMenu
|
||||
import com.owenlejeune.tvtime.ui.components.*
|
||||
import com.owenlejeune.tvtime.ui.navigation.AccountTabNavItem
|
||||
import com.owenlejeune.tvtime.ui.navigation.ListFetchFun
|
||||
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
|
||||
@@ -175,7 +170,7 @@ private fun AccountDropdownMenu(
|
||||
session: SessionManager.Session?,
|
||||
lastSelectedOption: MutableState<String>
|
||||
) {
|
||||
TopAppBarDropdownMenu(
|
||||
CustomTopAppBarDropdownMenu(
|
||||
icon = {
|
||||
when(session?.isAuthorized) {
|
||||
true -> { }
|
||||
@@ -198,14 +193,14 @@ private fun NoSessionMenuItems(
|
||||
lastSelectedOption: MutableState<String>
|
||||
) {
|
||||
val showSignInDialog = remember { mutableStateOf(false) }
|
||||
DropdownMenuItem(
|
||||
CustomMenuItem(
|
||||
text = stringResource(id = R.string.action_sign_in),
|
||||
onClick = {
|
||||
showSignInDialog.value = true
|
||||
},
|
||||
modifier = Modifier.background(color = MaterialTheme.colorScheme.surfaceVariant)
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_sign_in), color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
CustomMenuDivider()
|
||||
|
||||
if (showSignInDialog.value) {
|
||||
SignInDialog(showDialog = showSignInDialog) { success ->
|
||||
@@ -216,16 +211,13 @@ private fun NoSessionMenuItems(
|
||||
}
|
||||
}
|
||||
|
||||
Divider(color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(horizontal = 12.dp))
|
||||
|
||||
DropdownMenuItem(
|
||||
CustomMenuItem(
|
||||
text = stringResource(R.string.action_sign_in_as_guest),
|
||||
onClick = {
|
||||
createGuestSession(lastSelectedOption)
|
||||
expanded.value = false
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_sign_in_as_guest), color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -246,14 +238,10 @@ private fun GuestSessionMenuItems(
|
||||
lastSelectedOption: MutableState<String>
|
||||
) {
|
||||
val showSignInDialog = remember { mutableStateOf(false) }
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
showSignInDialog.value = true
|
||||
},
|
||||
modifier = Modifier.background(color = MaterialTheme.colorScheme.surfaceVariant)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.action_sign_in), color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
}
|
||||
CustomMenuItem(
|
||||
text = stringResource(id = R.string.action_sign_in),
|
||||
onClick = { showSignInDialog.value = true }
|
||||
)
|
||||
|
||||
if (showSignInDialog.value) {
|
||||
SignInDialog(showDialog = showSignInDialog) { success ->
|
||||
@@ -264,16 +252,15 @@ private fun GuestSessionMenuItems(
|
||||
}
|
||||
}
|
||||
|
||||
Divider(color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(horizontal = 12.dp))
|
||||
CustomMenuDivider()
|
||||
|
||||
DropdownMenuItem(
|
||||
CustomMenuItem(
|
||||
text = stringResource(id = R.string.action_sign_out),
|
||||
onClick = {
|
||||
signOut(lastSelectedOption)
|
||||
expanded.value = false
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.action_sign_out), color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -287,14 +274,13 @@ private fun AuthorizedSessionMenuItems(
|
||||
expanded: MutableState<Boolean>,
|
||||
lastSelectedOption: MutableState<String>
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
CustomMenuItem(
|
||||
text = stringResource(id = R.string.action_sign_out),
|
||||
onClick = {
|
||||
lastSelectedOption.value = ACCOUNT_SIGN_OUT
|
||||
expanded.value = false
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.action_sign_out), color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun createGuestSession(lastSelectedOption: MutableState<String>) {
|
||||
|
||||
Reference in New Issue
Block a user