From 58b740cfb0e985d4ca39f06861867b913f11c3c8 Mon Sep 17 00:00:00 2001 From: Owen LeJeune Date: Wed, 22 Jun 2022 14:51:51 -0400 Subject: [PATCH] add basis for onboarding flow and some more theming options --- app/src/main/AndroidManifest.xml | 18 +- .../owenlejeune/tvtime/AppRoutingActivity.kt | 23 ++ .../com/owenlejeune/tvtime/MainActivity.kt | 7 +- .../owenlejeune/tvtime/OnboardingActivity.kt | 156 +++++++++ .../owenlejeune/tvtime/TvTimeApplication.kt | 11 + .../v3/deserializer/KnownForDeserializer.kt | 2 +- .../api/tmdb/api/v3/model/DetailCast.kt | 2 +- .../api/tmdb/api/v3/model/DetailCrew.kt | 2 +- .../tvtime/api/tmdb/api/v3/model/KnowForTv.kt | 2 +- .../tvtime/api/tmdb/api/v3/model/KnownFor.kt | 2 +- .../api/tmdb/api/v3/model/KnownForMovie.kt | 2 +- .../tmdb/api/v3/model/MarkAsFavoriteBody.kt | 2 +- .../api/tmdb/api/v3/model/WatchlistBody.kt | 2 +- .../v4/deserializer/ListItemDeserializer.kt | 2 +- .../tmdb/api/v4/model/AddToListBodyItem.kt | 2 +- .../tmdb/api/v4/model/DeleteListItemsBody.kt | 2 +- .../tvtime/api/tmdb/api/v4/model/ListItem.kt | 2 +- .../api/v4/model/ListItemStatusResponse.kt | 2 +- .../tvtime/api/tmdb/api/v4/model/ListMovie.kt | 2 +- .../tvtime/api/tmdb/api/v4/model/ListTv.kt | 2 +- .../tmdb/api/v4/model/UpdateListItemBody.kt | 2 +- .../tvtime/extensions/ActivityExtensions.kt | 7 + .../tvtime/preferences/AppPreferences.kt | 31 ++ .../tvtime/ui/components/PreferenceWidgets.kt | 41 ++- .../tvtime/ui/components/Widgets.kt | 42 ++- .../tvtime/ui/navigation/AccountTabNavItem.kt | 4 +- .../tvtime/ui/navigation/MediaTabNavItem.kt | 4 +- .../tvtime/ui/navigation/Routes.kt | 8 +- .../{tabs/bottom => main}/AccountTab.kt | 6 +- .../ui/screens/{ => main}/DetailViewCommon.kt | 2 +- .../{tabs/bottom => main}/FavouritesTab.kt | 2 +- .../tvtime/ui/screens/{ => main}/MainView.kt | 2 +- .../ui/screens/{ => main}/MediaDetailView.kt | 7 +- .../screens/{tabs/bottom => main}/MediaTab.kt | 5 +- .../ui/screens/{ => main}/MediaViewType.kt | 2 +- .../ui/screens/{ => main}/PeopleDetailView.kt | 2 +- .../{tabs/bottom => main}/PeopleTab.kt | 3 +- .../tvtime/ui/screens/main/SettingsTab.kt | 296 ++++++++++++++++++ .../screens/{tabs => main}/top/TabsCommon.kt | 2 +- .../ui/screens/onboarding/OnboardingPage.kt | 28 ++ .../ui/screens/tabs/bottom/SettingsTab.kt | 145 --------- app/src/main/res/values/strings.xml | 10 + 42 files changed, 692 insertions(+), 204 deletions(-) create mode 100644 app/src/main/java/com/owenlejeune/tvtime/AppRoutingActivity.kt create mode 100644 app/src/main/java/com/owenlejeune/tvtime/OnboardingActivity.kt rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{tabs/bottom => main}/AccountTab.kt (98%) rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{ => main}/DetailViewCommon.kt (99%) rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{tabs/bottom => main}/FavouritesTab.kt (92%) rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{ => main}/MainView.kt (99%) rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{ => main}/MediaDetailView.kt (99%) rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{tabs/bottom => main}/MediaTab.kt (95%) rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{ => main}/MediaViewType.kt (79%) rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{ => main}/PeopleDetailView.kt (99%) rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{tabs/bottom => main}/PeopleTab.kt (94%) create mode 100644 app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/SettingsTab.kt rename app/src/main/java/com/owenlejeune/tvtime/ui/screens/{tabs => main}/top/TabsCommon.kt (98%) create mode 100644 app/src/main/java/com/owenlejeune/tvtime/ui/screens/onboarding/OnboardingPage.kt delete mode 100644 app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/SettingsTab.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 32e4374..ceef3fe 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,15 +13,25 @@ android:supportsRtl="true" android:theme="@style/Theme.TVTime" android:usesCleartextTraffic="true"> + + + + + + + + + + - - - - diff --git a/app/src/main/java/com/owenlejeune/tvtime/AppRoutingActivity.kt b/app/src/main/java/com/owenlejeune/tvtime/AppRoutingActivity.kt new file mode 100644 index 0000000..13f91a4 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/AppRoutingActivity.kt @@ -0,0 +1,23 @@ +package com.owenlejeune.tvtime + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.owenlejeune.tvtime.extensions.launchActivity +import com.owenlejeune.tvtime.preferences.AppPreferences +import org.koin.android.ext.android.inject + +class AppRoutingActivity: AppCompatActivity() { + + private val preferences: AppPreferences by inject() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (preferences.firstLaunch) { + launchActivity(OnboardingActivity::class.java) + } else { + launchActivity(MainActivity::class.java) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/MainActivity.kt b/app/src/main/java/com/owenlejeune/tvtime/MainActivity.kt index 0c7645b..c86e510 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/MainActivity.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/MainActivity.kt @@ -1,7 +1,6 @@ package com.owenlejeune.tvtime import android.os.Bundle -import android.widget.Toast import androidx.activity.compose.setContent import androidx.compose.animation.rememberSplineBasedDecay import androidx.compose.foundation.Image @@ -37,9 +36,9 @@ import com.owenlejeune.tvtime.ui.components.SearchFab import com.owenlejeune.tvtime.ui.navigation.BottomNavItem import com.owenlejeune.tvtime.ui.navigation.MainNavGraph import com.owenlejeune.tvtime.ui.navigation.MainNavItem -import com.owenlejeune.tvtime.ui.screens.MediaDetailView -import com.owenlejeune.tvtime.ui.screens.MediaViewType -import com.owenlejeune.tvtime.ui.screens.PersonDetailView +import com.owenlejeune.tvtime.ui.screens.main.MediaDetailView +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.PersonDetailView import com.owenlejeune.tvtime.ui.theme.TVTimeTheme import com.owenlejeune.tvtime.utils.KeyboardManager import com.owenlejeune.tvtime.utils.SessionManager diff --git a/app/src/main/java/com/owenlejeune/tvtime/OnboardingActivity.kt b/app/src/main/java/com/owenlejeune/tvtime/OnboardingActivity.kt new file mode 100644 index 0000000..56dcf46 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/OnboardingActivity.kt @@ -0,0 +1,156 @@ +package com.owenlejeune.tvtime + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowForward +import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.lifecycleScope +import com.google.accompanist.pager.* +import com.kieronquinn.monetcompat.app.MonetCompatActivity +import com.owenlejeune.tvtime.extensions.launchActivity +import com.owenlejeune.tvtime.preferences.AppPreferences +import com.owenlejeune.tvtime.ui.screens.onboarding.OnboardingPage +import com.owenlejeune.tvtime.ui.theme.TVTimeTheme +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.koin.android.ext.android.inject + +@OptIn(ExperimentalPagerApi::class) +class OnboardingActivity: MonetCompatActivity() { + + private val preferences: AppPreferences by inject() + + private lateinit var pagerState: PagerState + private lateinit var coroutineScope: CoroutineScope + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + lifecycleScope.launchWhenCreated { + monet.awaitMonetReady() + setContent { + TVTimeTheme(monetCompat = monet) { + OnboardingUi() + } + } + } + } + + @Composable + fun OnboardingUi() { + pagerState = rememberPagerState() + coroutineScope = rememberCoroutineScope() + + Column( + modifier = Modifier.background(color = MaterialTheme.colorScheme.background) + ) { + HorizontalPager( + state = pagerState, + modifier = Modifier + .fillMaxWidth() + .weight(1f), +// .background(MaterialTheme.colorScheme.primary), + count = OnboardingPage.values().size, + userScrollEnabled = false + ) { page -> + OnboardingPageUi(page = OnboardingPage[page]) + } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(all = 12.dp) + ) { + HorizontalPagerIndicator( + pagerState = pagerState, + modifier = Modifier + .align(Alignment.Center) + .padding(16.dp), + activeColor = MaterialTheme.colorScheme.secondary + ) + + val isLastPage = pagerState.currentPage == OnboardingPage.values().size - 1 + Button( + modifier = Modifier.align(Alignment.CenterEnd), + shape = CircleShape, + onClick = { + if (isLastPage) { + preferences.firstLaunch = false + launchActivity(MainActivity::class.java) + } else { + coroutineScope.launch { + pagerState.animateScrollToPage(pagerState.currentPage + 1) + } + } + } + ) { + if (isLastPage) { + Text(stringResource(id = R.string.get_started)) + } else { + Icon(imageVector = Icons.Filled.ArrowForward, contentDescription = null) + } + } + } + } + } + + @Composable + fun OnboardingPageUi(page: OnboardingPage) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + page.image?.let { + Image( + painter = painterResource(id = it), + contentDescription = null, + modifier = Modifier.size(200.dp), + colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.secondary) + ) + Spacer(modifier = Modifier.height(20.dp)) + } + Text( + text = stringResource(id = page.title), + fontSize = 28.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onBackground + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = stringResource(id = page.description), + textAlign = TextAlign.Center, + fontSize = 14.sp, + color = MaterialTheme.colorScheme.onBackground + ) + Spacer(modifier = Modifier.height(12.dp)) + page.additionalContent(this@OnboardingActivity) + } + } + + override fun onBackPressed() { + if (pagerState.currentPage == 0) { + finish() + } else { + coroutineScope.launch { + pagerState.animateScrollToPage(pagerState.currentPage - 1) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/TvTimeApplication.kt b/app/src/main/java/com/owenlejeune/tvtime/TvTimeApplication.kt index 864b286..f61a824 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/TvTimeApplication.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/TvTimeApplication.kt @@ -6,6 +6,9 @@ import com.kieronquinn.monetcompat.core.MonetCompat import com.owenlejeune.tvtime.di.modules.appModule import com.owenlejeune.tvtime.di.modules.networkModule import com.owenlejeune.tvtime.di.modules.preferencesModule +import com.owenlejeune.tvtime.preferences.AppPreferences +import dev.kdrag0n.monet.factory.ColorSchemeFactory +import org.koin.android.ext.android.inject import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin @@ -13,6 +16,8 @@ import org.koin.core.logger.Level class TvTimeApplication: Application() { + private val preferences: AppPreferences by inject() + override fun onCreate() { super.onCreate() @@ -30,6 +35,12 @@ class TvTimeApplication: Application() { } MonetCompat.enablePaletteCompat() + MonetCompat.chromaMultiplier = preferences.chromaMultiplier + + MonetCompat.wallpaperColorPicker = { + val userPickedColor = preferences.selectedColor + it?.firstOrNull { color -> color == userPickedColor } ?: it?.firstOrNull() + } if (BuildConfig.DEBUG) { Stetho.initializeWithDefaults(this) diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/deserializer/KnownForDeserializer.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/deserializer/KnownForDeserializer.kt index cb6da5d..bd00477 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/deserializer/KnownForDeserializer.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/deserializer/KnownForDeserializer.kt @@ -2,7 +2,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer import com.google.gson.* import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownFor -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType import java.lang.reflect.Type class KnownForDeserializer: JsonDeserializer { diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailCast.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailCast.kt index 9d171ee..04f84ff 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailCast.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailCast.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class DetailCast( @SerializedName("id") val id: Int, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailCrew.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailCrew.kt index d0a41c7..93762d3 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailCrew.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailCrew.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class DetailCrew( @SerializedName("id") val id: Int, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnowForTv.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnowForTv.kt index fb17ccb..ce4762d 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnowForTv.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnowForTv.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class KnowForTv( backdropPath: String?, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnownFor.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnownFor.kt index 37cbb6c..f83f5e9 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnownFor.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnownFor.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType abstract class KnownFor( @SerializedName("backdrop_path") val backdropPath: String?, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnownForMovie.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnownForMovie.kt index 8f49e17..cc77622 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnownForMovie.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/KnownForMovie.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class KnownForMovie( backdropPath: String?, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/MarkAsFavoriteBody.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/MarkAsFavoriteBody.kt index 42b2e3b..8a3be6c 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/MarkAsFavoriteBody.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/MarkAsFavoriteBody.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class MarkAsFavoriteBody( @SerializedName("media_type") val mediaType: MediaViewType, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/WatchlistBody.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/WatchlistBody.kt index 21d4947..e434fdd 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/WatchlistBody.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/WatchlistBody.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class WatchlistBody( @SerializedName("media_type") val mediaType: MediaViewType, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/deserializer/ListItemDeserializer.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/deserializer/ListItemDeserializer.kt index f7eac33..c8d4c07 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/deserializer/ListItemDeserializer.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/deserializer/ListItemDeserializer.kt @@ -4,7 +4,7 @@ import com.google.gson.* import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListItem import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListMovie import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListTv -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType import java.lang.reflect.Type class ListItemDeserializer: JsonDeserializer { diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/AddToListBodyItem.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/AddToListBodyItem.kt index 9844173..253e2c2 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/AddToListBodyItem.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/AddToListBodyItem.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v4.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class AddToListBody( @SerializedName("items") val items: List diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/DeleteListItemsBody.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/DeleteListItemsBody.kt index cc0707f..215d460 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/DeleteListItemsBody.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/DeleteListItemsBody.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v4.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class DeleteListItemsBody( @SerializedName("media_id") val id: Int, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListItem.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListItem.kt index fb31713..942ad2d 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListItem.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListItem.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v4.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType abstract class ListItem( @SerializedName("backdrop_path") val backdropPath: String?, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListItemStatusResponse.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListItemStatusResponse.kt index e997d08..8167bef 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListItemStatusResponse.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListItemStatusResponse.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v4.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class ListItemStatusResponse( statusMessage: String, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListMovie.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListMovie.kt index e6fa6e8..bdf91eb 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListMovie.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListMovie.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v4.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class ListMovie( backdropPath: String?, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListTv.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListTv.kt index c267e68..713203f 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListTv.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/ListTv.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v4.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class ListTv( backdropPath: String?, diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/UpdateListItemBody.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/UpdateListItemBody.kt index b751210..b2df822 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/UpdateListItemBody.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v4/model/UpdateListItemBody.kt @@ -1,7 +1,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v4.model import com.google.gson.annotations.SerializedName -import com.owenlejeune.tvtime.ui.screens.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType class UpdateListItemBody( @SerializedName("items") val items: List diff --git a/app/src/main/java/com/owenlejeune/tvtime/extensions/ActivityExtensions.kt b/app/src/main/java/com/owenlejeune/tvtime/extensions/ActivityExtensions.kt index 1fa2829..94022cd 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/extensions/ActivityExtensions.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/extensions/ActivityExtensions.kt @@ -1,6 +1,7 @@ package com.owenlejeune.tvtime.extensions import android.app.Activity +import android.content.Intent import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.geometry.Size @@ -39,4 +40,10 @@ private fun getWindowSizeClass(windowDpSize: DpSize): WindowSizeClass = when { windowDpSize.width < 600.dp -> WindowSizeClass.Compact windowDpSize.width < 840.dp -> WindowSizeClass.Medium else -> WindowSizeClass.Expanded +} + +fun Activity.launchActivity(activity: Class) { + val intent = Intent(this, activity) + startActivity(intent) + finish() } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/preferences/AppPreferences.kt b/app/src/main/java/com/owenlejeune/tvtime/preferences/AppPreferences.kt index 49b1cac..88f4c3a 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/preferences/AppPreferences.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/preferences/AppPreferences.kt @@ -2,6 +2,8 @@ package com.owenlejeune.tvtime.preferences import android.content.Context import android.content.SharedPreferences +import com.kieronquinn.monetcompat.core.MonetCompat +import com.owenlejeune.tvtime.BuildConfig class AppPreferences(context: Context) { @@ -13,6 +15,11 @@ 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 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 preferences: SharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE) @@ -37,6 +44,26 @@ class AppPreferences(context: Context) { // get() = preferences.getBoolean(USE_PREFERENCES, false) // set(value) { preferences.put(USE_PREFERENCES, value) } + var firstLaunchTesting: Boolean + get() = preferences.getBoolean(FIRST_LAUNCH_TESTING, false) + set(value) { preferences.put(FIRST_LAUNCH_TESTING, value) } + + var firstLaunch: Boolean + get() = if (BuildConfig.DEBUG) firstLaunchTesting else preferences.getBoolean(FIRST_LAUNCH, true) + set(value) { preferences.put(FIRST_LAUNCH, value) } + + var useSystemColors: Boolean + get() = preferences.getBoolean(USE_SYSTEM_COLORS, true) + set(value) { preferences.put(USE_SYSTEM_COLORS, value) } + + var chromaMultiplier: Double + get() = preferences.getFloat(CHROMA_MULTIPLIER, MonetCompat.chromaMultiplier.toFloat()).toDouble() + set(value) { preferences.put(CHROMA_MULTIPLIER, value) } + + var selectedColor: Int + get() = preferences.getInt(SELECTED_COLOR, Int.MAX_VALUE) + set(value) { preferences.put(SELECTED_COLOR, value) } + private fun SharedPreferences.put(key: String, value: Any?) { edit().apply { when (value) { @@ -44,12 +71,16 @@ class AppPreferences(context: Context) { is Int -> putInt(key, value) is Long -> putLong(key, value) is Float -> putFloat(key, value) + is Double -> putFloat(key, value.toFloat()) is String -> putString(key, value) + else -> throw UnsupportedTypeError() } apply() } } + class UnsupportedTypeError: Exception() + // private fun SharedPreferences.get(key: String, java: Class): T { // // } diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/PreferenceWidgets.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/PreferenceWidgets.kt index 835c28e..0c42a2c 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/components/PreferenceWidgets.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/PreferenceWidgets.kt @@ -1,9 +1,11 @@ package com.owenlejeune.tvtime.ui.components import androidx.compose.foundation.layout.* +import androidx.compose.material3.SliderDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Slider import androidx.compose.material3.Text -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -73,4 +75,41 @@ fun SwitchPreference( @Composable private fun SwitchPreferencePreview() { SwitchPreference("Title", true, subtitleText = "Subtitle") +} + +@Composable +fun SliderPreference( + modifier: Modifier = Modifier, + titleText: String, + value: Float, + onValueChangeFinished: (Float) -> Unit , + titleTextColor: Color = MaterialTheme.colorScheme.onBackground, + disabledTextColor: Color = MaterialTheme.colorScheme.outline, + enabled: Boolean = true +) { + Column( + modifier = modifier + .wrapContentHeight() + .padding(all = 8.dp) + ) { + val titleColor = if (enabled) titleTextColor else disabledTextColor + Text(text = titleText, style = MaterialTheme.typography.titleLarge, color = titleColor, fontSize = 20.sp) + + var sliderValue by remember { mutableStateOf(value) } + + Slider( + modifier = Modifier.fillMaxWidth().padding(start = 8.dp), + value = sliderValue, + onValueChange = { sliderValue = it }, + enabled = enabled, + valueRange = 0f..100f, + onValueChangeFinished = { + onValueChangeFinished(sliderValue) + }, + colors = SliderDefaults.colors( + thumbColor = MaterialTheme.colorScheme.primary, + activeTrackColor = MaterialTheme.colorScheme.primary + ) + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Widgets.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Widgets.kt index 9df7452..7aefd89 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Widgets.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Widgets.kt @@ -20,10 +20,7 @@ import androidx.compose.material.Card import androidx.compose.material.OutlinedTextField import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Error -import androidx.compose.material.icons.filled.Search -import androidx.compose.material.icons.filled.Visibility -import androidx.compose.material.icons.filled.VisibilityOff +import androidx.compose.material.icons.filled.* import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable @@ -65,6 +62,7 @@ import androidx.core.text.HtmlCompat import coil.compose.AsyncImage import coil.compose.rememberAsyncImagePainter import com.google.accompanist.flowlayout.FlowRow +import com.kieronquinn.monetcompat.core.MonetCompat import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.model.AuthorDetails import com.owenlejeune.tvtime.ui.theme.RatingSelected @@ -924,4 +922,40 @@ fun TimeoutSnackbar( onDismiss() } } +} + +@Composable +fun CenteredIconCircle( + size: Dp, + backgroundColor: Color, + iconTint: Color, + icon: ImageVector, + contentDescription: String?, + showIcon: Boolean = true, + onClick: () -> Unit = {} +) { + Box( + modifier = Modifier + .size(size) + .clip(CircleShape) + .background(color = backgroundColor) + .clickable { + onClick() + } + ) { + if (showIcon) { + Column( + modifier = Modifier.size(size), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + imageVector = icon, + contentDescription = contentDescription, + modifier = Modifier.size(size / 2), + tint = iconTint + ) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/AccountTabNavItem.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/AccountTabNavItem.kt index 7161d2a..6a5aa1e 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/AccountTabNavItem.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/AccountTabNavItem.kt @@ -4,8 +4,8 @@ import androidx.compose.runtime.Composable import androidx.navigation.NavHostController import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.model.* -import com.owenlejeune.tvtime.ui.screens.MediaViewType -import com.owenlejeune.tvtime.ui.screens.tabs.bottom.AccountTabContent +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.AccountTabContent import com.owenlejeune.tvtime.utils.ResourceUtils import com.owenlejeune.tvtime.utils.SessionManager import org.koin.core.component.inject diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/MediaTabNavItem.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/MediaTabNavItem.kt index 0d9a23d..61e9c22 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/MediaTabNavItem.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/MediaTabNavItem.kt @@ -5,8 +5,8 @@ import androidx.navigation.NavHostController import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.HomePageService import com.owenlejeune.tvtime.api.tmdb.api.v3.model.HomePageResponse -import com.owenlejeune.tvtime.ui.screens.MediaViewType -import com.owenlejeune.tvtime.ui.screens.tabs.bottom.MediaTabContent +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.MediaTabContent import com.owenlejeune.tvtime.utils.ResourceUtils import org.koin.core.component.inject import retrofit2.Response diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/Routes.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/Routes.kt index 0049745..a37cea0 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/Routes.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/navigation/Routes.kt @@ -9,11 +9,9 @@ import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.navArgument -import com.owenlejeune.tvtime.ui.screens.MediaDetailView -import com.owenlejeune.tvtime.ui.screens.MainAppView -import com.owenlejeune.tvtime.ui.screens.MediaViewType -import com.owenlejeune.tvtime.ui.screens.PersonDetailView -import com.owenlejeune.tvtime.ui.screens.tabs.bottom.* +import com.owenlejeune.tvtime.ui.screens.main.MediaDetailView +import com.owenlejeune.tvtime.ui.screens.main.MediaViewType +import com.owenlejeune.tvtime.ui.screens.main.* object NavConstants { const val ID_KEY = "id_key" diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/AccountTab.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AccountTab.kt similarity index 98% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/AccountTab.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AccountTab.kt index 50d21e5..568a511 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/AccountTab.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AccountTab.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens.tabs.bottom +package com.owenlejeune.tvtime.ui.screens.main import android.content.Context import androidx.compose.foundation.clickable @@ -12,7 +12,6 @@ import androidx.compose.runtime.* 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 @@ -29,8 +28,7 @@ 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 -import com.owenlejeune.tvtime.ui.screens.MediaViewType -import com.owenlejeune.tvtime.ui.screens.tabs.top.ScrollableTabs +import com.owenlejeune.tvtime.ui.screens.main.tabs.top.ScrollableTabs import com.owenlejeune.tvtime.utils.SessionManager import com.owenlejeune.tvtime.utils.TmdbUtils import kotlinx.coroutines.CoroutineScope diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/DetailViewCommon.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/DetailViewCommon.kt similarity index 99% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/DetailViewCommon.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/DetailViewCommon.kt index c89a1e5..a84c779 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/DetailViewCommon.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/DetailViewCommon.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens +package com.owenlejeune.tvtime.ui.screens.main import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/FavouritesTab.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/FavouritesTab.kt similarity index 92% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/FavouritesTab.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/FavouritesTab.kt index 0f771c7..279e30c 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/FavouritesTab.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/FavouritesTab.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens.tabs.bottom +package com.owenlejeune.tvtime.ui.screens.main import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MainView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MainView.kt similarity index 99% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/MainView.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MainView.kt index 0c260b8..e7a7798 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MainView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MainView.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens +package com.owenlejeune.tvtime.ui.screens.main import androidx.compose.animation.rememberSplineBasedDecay import androidx.compose.foundation.Image diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt similarity index 99% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailView.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt index 494ac1e..7590974 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt @@ -1,17 +1,13 @@ -package com.owenlejeune.tvtime.ui.screens +package com.owenlejeune.tvtime.ui.screens.main import android.content.Context import android.widget.Toast import androidx.compose.animation.* -import androidx.compose.animation.core.LinearOutSlowInEasing -import androidx.compose.animation.core.keyframes -import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Send @@ -29,7 +25,6 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/MediaTab.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaTab.kt similarity index 95% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/MediaTab.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaTab.kt index 141ab0b..48a6b4d 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/MediaTab.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaTab.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens.tabs.bottom +package com.owenlejeune.tvtime.ui.screens.main import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable @@ -16,8 +16,7 @@ import com.owenlejeune.tvtime.ui.components.PosterGrid import com.owenlejeune.tvtime.ui.navigation.MainNavItem import com.owenlejeune.tvtime.ui.navigation.MediaFetchFun import com.owenlejeune.tvtime.ui.navigation.MediaTabNavItem -import com.owenlejeune.tvtime.ui.screens.MediaViewType -import com.owenlejeune.tvtime.ui.screens.tabs.top.Tabs +import com.owenlejeune.tvtime.ui.screens.main.tabs.top.Tabs import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaViewType.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaViewType.kt similarity index 79% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaViewType.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaViewType.kt index 0454549..d4ede70 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaViewType.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaViewType.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens +package com.owenlejeune.tvtime.ui.screens.main import com.google.gson.annotations.SerializedName diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/PeopleDetailView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt similarity index 99% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/PeopleDetailView.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt index 411e6eb..54b41ef 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/PeopleDetailView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens +package com.owenlejeune.tvtime.ui.screens.main import androidx.compose.foundation.background import androidx.compose.foundation.layout.* diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/PeopleTab.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleTab.kt similarity index 94% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/PeopleTab.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleTab.kt index 409b4ad..4447fa3 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/PeopleTab.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleTab.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens.tabs.bottom +package com.owenlejeune.tvtime.ui.screens.main import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding @@ -14,7 +14,6 @@ import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.PeopleService import com.owenlejeune.tvtime.ui.components.PeoplePosterGrid import com.owenlejeune.tvtime.ui.navigation.MainNavItem -import com.owenlejeune.tvtime.ui.screens.MediaViewType import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/SettingsTab.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/SettingsTab.kt new file mode 100644 index 0000000..f10ee90 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/SettingsTab.kt @@ -0,0 +1,296 @@ +package com.owenlejeune.tvtime.ui.screens.main + +import android.os.Build +import android.widget.Toast +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.* +import androidx.compose.material.TextButton +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.ResetTv +import androidx.compose.material.icons.filled.RestartAlt +import androidx.compose.material3.* +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Divider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.Icon +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.kieronquinn.monetcompat.core.MonetCompat +import com.owenlejeune.tvtime.BuildConfig +import com.owenlejeune.tvtime.R +import com.owenlejeune.tvtime.preferences.AppPreferences +import com.owenlejeune.tvtime.ui.components.* +import com.owenlejeune.tvtime.utils.SessionManager +import dev.kdrag0n.monet.factory.ColorSchemeFactory +import kotlinx.coroutines.launch +import org.koin.java.KoinJavaComponent.get + +@Composable +fun SettingsTab(preferences: AppPreferences = get(AppPreferences::class.java)) { + val scrollState = rememberScrollState() + + Column( + modifier = Modifier + .fillMaxSize() + .padding(start = 8.dp, top = 8.dp, bottom = 8.dp, end = 24.dp) + .verticalScroll(scrollState) + ) { +// val usePreferences = remember { mutableStateOf(preferences.usePreferences) } +// TopLevelSwitch( +// text = "Enable Preferences", +// checkedState = usePreferences, +// onCheckChanged = { isChecked -> +// usePreferences.value = isChecked +// preferences.usePreferences = isChecked +// } +// ) +// +// Column( +// modifier = Modifier +// .fillMaxWidth() +// .wrapContentHeight() +// .padding(start = 8.dp, top = 8.dp, bottom = 8.dp, end = 24.dp) +// .verticalScroll() +// ) { + PreferenceHeading(text = stringResource(R.string.preference_heading_search)) + + val persistentSearch = remember { mutableStateOf(preferences.persistentSearch) } + SwitchPreference( + titleText = stringResource(R.string.preferences_persistent_search_title), + subtitleText = stringResource(R.string.preferences_persistent_search_subtitle), + checkState = persistentSearch.value, + onCheckedChange = { isChecked -> + persistentSearch.value = isChecked + preferences.persistentSearch = isChecked + } + ) + + val hideTitle = remember { mutableStateOf(preferences.hideTitle) } + SwitchPreference( + titleText = stringResource(R.string.preferences_hide_heading_title), + subtitleText = stringResource(R.string.preferences_hide_heading_subtitle), + checkState = hideTitle.value, + onCheckedChange = { isChecked -> + hideTitle.value = isChecked + preferences.hideTitle = isChecked + }, + enabled = persistentSearch.value + ) + + PreferenceHeading(text = stringResource(id = R.string.preference_heading_design)) + + val isSystemColorsSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + if (isSystemColorsSupported) { + val useSystemColors = remember { mutableStateOf(preferences.useSystemColors) } + SwitchPreference( + titleText = stringResource(id = R.string.preference_system_colors_heading), + checkState = useSystemColors.value, + onCheckedChange = { isChecked -> + useSystemColors.value = isChecked + preferences.useSystemColors = isChecked + MonetCompat.useSystemColorsOnAndroid12 = isChecked + MonetCompat.getInstance().updateMonetColors() + } + ) + } + + SliderPreference( + titleText = stringResource(id = R.string.preference_chroma_factor_heading), + value = preferences.chromaMultiplier.toFloat() * 50f, + onValueChangeFinished = { value -> + with((value / 50f).toDouble()) { + preferences.chromaMultiplier = this + MonetCompat.chromaMultiplier = this + } + MonetCompat.getInstance().updateMonetColors() + }, + enabled = if (isSystemColorsSupported) !preferences.useSystemColors else true + ) + + val showWallpaperPicker = remember { mutableStateOf(false) } + val wallpaperPickerModifier = if (isSystemColorsSupported && preferences.useSystemColors) { + Modifier + } else { + Modifier.clickable { showWallpaperPicker.value = true } + } + Text( + text = stringResource(id = R.string.preference_wallpaper_color_heading), + style = MaterialTheme.typography.titleLarge, + fontSize = 20.sp, + color = if (isSystemColorsSupported && preferences.useSystemColors) { + MaterialTheme.colorScheme.outline + } else { + MaterialTheme.colorScheme.onBackground + }, + modifier = wallpaperPickerModifier + .padding(start = 8.dp) + ) + if (showWallpaperPicker.value) { + WallpaperPicker(showPopup = showWallpaperPicker) + } + + if (BuildConfig.DEBUG) { + Divider(modifier = Modifier.padding(start = 8.dp, top = 20.dp)) + Text( + modifier = Modifier.padding(start = 8.dp, top = 20.dp), + text = stringResource(R.string.preferences_debug_title), + style = MaterialTheme.typography.headlineMedium, + color = MaterialTheme.colorScheme.primary + ) + DebugOptions() + } + } +} + +@Composable +private fun WallpaperPicker( + showPopup: MutableState, + preference: AppPreferences = get(AppPreferences::class.java) +) { + val context = LocalContext.current + + val wallpaperColors = remember { mutableStateOf>(emptyList()) } + val selectedWallpaperColor = remember { mutableStateOf(0) } + LaunchedEffect(true) { + val colors = MonetCompat.getInstance().getAvailableWallpaperColors() ?: emptyList() + if (colors.isEmpty()) { + Toast.makeText(context, context.getString(R.string.preference_no_wallpaper_colors), Toast.LENGTH_SHORT).show() + showPopup.value = false + + } + wallpaperColors.value = colors + selectedWallpaperColor.value = MonetCompat.getInstance().getSelectedWallpaperColor() ?: 0 + } + + if (wallpaperColors.value.isNotEmpty() && selectedWallpaperColor.value != 0) { + val colorCircleSize = 50.dp + AlertDialog( + modifier = Modifier.padding(12.dp), + title = { Text(text = stringResource(id = R.string.preference_wallpaper_color_heading)) }, + text = { + Row( + modifier = Modifier + .height(colorCircleSize) + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + wallpaperColors.value.forEach { + CenteredIconCircle( + size = colorCircleSize, + backgroundColor = Color(it), + iconTint = Color.White, + icon = Icons.Filled.Check, + contentDescription = null, + showIcon = it == selectedWallpaperColor.value, + onClick = { + if (it != selectedWallpaperColor.value) { + preference.selectedColor = it + MonetCompat + .getInstance() + .updateMonetColors() + } + } + ) + } + + CenteredIconCircle( + size = colorCircleSize, + backgroundColor = MaterialTheme.colorScheme.secondaryContainer, + iconTint = MaterialTheme.colorScheme.onSecondaryContainer, + icon = Icons.Filled.RestartAlt, + contentDescription = null, + onClick = { + if (preference.selectedColor != Int.MAX_VALUE) { + preference.selectedColor = Int.MAX_VALUE + MonetCompat.getInstance().updateMonetColors() + } else { + Toast.makeText(context, context.getString(R.string.preference_wallpaper_color_default_selected), Toast.LENGTH_SHORT).show() + } + } + ) + } + }, + dismissButton = { + TextButton(onClick = { showPopup.value = false }) { + Text(text = stringResource(id = R.string.action_cancel)) + } + }, + confirmButton = {}, + onDismissRequest = { showPopup.value = false } + ) + } +} + +@Composable +private fun DebugOptions(preferences: AppPreferences = get(AppPreferences::class.java)) { + val context = LocalContext.current + + val firstLaunchTesting = remember { mutableStateOf(preferences.firstLaunchTesting) } + SwitchPreference( + titleText = "Always show onboarding flow", + subtitleText = "Show onboarding flow on each launch", + checkState = firstLaunchTesting.value, + onCheckedChange = { isChecked -> + firstLaunchTesting.value = isChecked + preferences.firstLaunchTesting = isChecked + } + ) + + val shouldShowPalette = remember { mutableStateOf(false) } + Text( + text = "Show material palette", + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier + .padding(horizontal = 8.dp, vertical = 12.dp) + .clickable( + onClick = { + shouldShowPalette.value = true + } + ) + ) + if (shouldShowPalette.value) { + AlertDialog( + modifier = Modifier.padding(12.dp), + title = { Text(text = "Palette") }, + text = { PaletteView() }, + dismissButton = { + TextButton(onClick = { shouldShowPalette.value = false }) { + Text("Dismiss") + } + }, + confirmButton = {}, + onDismissRequest = { shouldShowPalette.value = false } + ) + } + + Text( + text = "Clear session", + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier + .padding(horizontal = 8.dp, vertical = 12.dp) + .clickable( + onClick = { + preferences.guestSessionId = "" + SessionManager.clearSession { + Toast + .makeText(context, "Cleared session: $it", Toast.LENGTH_SHORT) + .show() + } + } + ) + ) +} diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/top/TabsCommon.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/top/TabsCommon.kt similarity index 98% rename from app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/top/TabsCommon.kt rename to app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/top/TabsCommon.kt index 1fa24f0..64ee517 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/top/TabsCommon.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/top/TabsCommon.kt @@ -1,4 +1,4 @@ -package com.owenlejeune.tvtime.ui.screens.tabs.top +package com.owenlejeune.tvtime.ui.screens.main.tabs.top import androidx.compose.foundation.background import androidx.compose.foundation.layout.Spacer diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/onboarding/OnboardingPage.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/onboarding/OnboardingPage.kt new file mode 100644 index 0000000..c5f8cb4 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/onboarding/OnboardingPage.kt @@ -0,0 +1,28 @@ +package com.owenlejeune.tvtime.ui.screens.onboarding + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.runtime.Composable +import com.owenlejeune.tvtime.R + +sealed class OnboardingPage( + @StringRes val title: Int, + @StringRes val description: Int, + @DrawableRes val image: Int? = null, + val additionalContent: @Composable (AppCompatActivity) -> Unit = {} +) { + + companion object { + fun values() = listOf(ExamplePage) + + operator fun get(i: Int) = values()[i] + } + + object ExamplePage: OnboardingPage( + R.string.app_name, + R.string.example_page_desc, + R.drawable.ic_launcher_foreground + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/SettingsTab.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/SettingsTab.kt deleted file mode 100644 index fbc1a19..0000000 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/tabs/bottom/SettingsTab.kt +++ /dev/null @@ -1,145 +0,0 @@ -package com.owenlejeune.tvtime.ui.screens.tabs.bottom - -import android.widget.Toast -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Switch -import androidx.compose.material.TextButton -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -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.graphics.Color -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.unit.dp -import com.owenlejeune.tvtime.BuildConfig -import com.owenlejeune.tvtime.R -import com.owenlejeune.tvtime.di.modules.preferencesModule -import com.owenlejeune.tvtime.preferences.AppPreferences -import com.owenlejeune.tvtime.ui.components.* -import com.owenlejeune.tvtime.utils.SessionManager -import org.koin.java.KoinJavaComponent.get - -@Composable -fun SettingsTab(preferences: AppPreferences = get(AppPreferences::class.java)) { - val scrollState = rememberScrollState() - - Column(modifier = Modifier - .fillMaxSize() - .padding(start = 8.dp, top = 8.dp, bottom = 8.dp, end = 24.dp) - .verticalScroll(scrollState) - ) { -// val usePreferences = remember { mutableStateOf(preferences.usePreferences) } -// TopLevelSwitch( -// text = "Enable Preferences", -// checkedState = usePreferences, -// onCheckChanged = { isChecked -> -// usePreferences.value = isChecked -// preferences.usePreferences = isChecked -// } -// ) -// -// Column( -// modifier = Modifier -// .fillMaxWidth() -// .wrapContentHeight() -// .padding(start = 8.dp, top = 8.dp, bottom = 8.dp, end = 24.dp) -// .verticalScroll() -// ) { - PreferenceHeading(text = stringResource(R.string.preference_heading_search)) - - val persistentSearch = remember { mutableStateOf(preferences.persistentSearch) } - SwitchPreference( - titleText = stringResource(R.string.preferences_persistent_search_title), - subtitleText = stringResource(R.string.preferences_persistent_search_subtitle), - checkState = persistentSearch.value, - onCheckedChange = { isChecked -> - persistentSearch.value = isChecked - preferences.persistentSearch = isChecked - } - ) - - val hideTitle = remember { mutableStateOf(preferences.hideTitle) } - SwitchPreference( - titleText = stringResource(R.string.preferences_hide_heading_title), - subtitleText = stringResource(R.string.preferences_hide_heading_subtitle), - checkState = hideTitle.value, - onCheckedChange = { isChecked -> - hideTitle.value = isChecked - preferences.hideTitle = isChecked - }, - enabled = persistentSearch.value - ) - - if (BuildConfig.DEBUG) { - Text( - modifier = Modifier.padding(start = 8.dp, top = 20.dp), - text = stringResource(R.string.preferences_debug_title), - style = MaterialTheme.typography.headlineSmall, - color = MaterialTheme.colorScheme.onBackground - ) - DebugOptions() - } - } -} - -@Composable -private fun DebugOptions(preferences: AppPreferences = get(AppPreferences::class.java)) { - val context = LocalContext.current - val shouldShowPalette = remember { mutableStateOf(false) } - Text( - text = "Show material palette", - color = MaterialTheme.colorScheme.onBackground, - modifier = Modifier - .padding(horizontal = 8.dp, vertical = 12.dp) - .clickable( - onClick = { - shouldShowPalette.value = true - } - ) - ) - if (shouldShowPalette.value) { - PaletteDialog(shouldShowPalette) - } - - Text( - text = "Clear session", - color = MaterialTheme.colorScheme.onBackground, - modifier = Modifier - .padding(horizontal = 8.dp, vertical = 12.dp) - .clickable( - onClick = { - preferences.guestSessionId = "" - SessionManager.clearSession { - Toast.makeText(context, "Cleared session: $it", Toast.LENGTH_SHORT).show() - } - } - ) - ) -} - -@Composable -private fun PaletteDialog(showDialog: MutableState) { - AlertDialog( - modifier = Modifier.padding(12.dp), - title = { Text(text = "Palette") }, - text = { PaletteView() }, - dismissButton = { - TextButton(onClick = { showDialog.value = false }) { - Text("Dismiss") - } - }, - confirmButton = {}, - onDismissRequest = { showDialog.value = false } - ) -} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0606b8b..42d6988 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -54,6 +54,12 @@ Expanded search bar Keep search bar expanded at all times Developer options + Design + Use system colors + Saturation + Wallpaper Color Picker + Unavailable for the current wallpaper or your current settings + Wallpaper color already set to default Clips @@ -104,4 +110,8 @@ tvtime.auth.return + + + Get started + This is an example \ No newline at end of file