diff --git a/app/build.gradle b/app/build.gradle index 6e4061b..596db7f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,8 +33,8 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } kotlinOptions { jvmTarget = '1.8' @@ -118,7 +118,7 @@ dependencies { implementation "io.insert-koin:koin-android:$koin" // coil - def coil = "2.0.0-rc01" + def coil = "2.2.2" implementation "io.coil-kt:coil-compose:$coil" //Coroutines @@ -135,9 +135,11 @@ dependencies { def markdown = "0.2.1" implementation "org.jetbrains:markdown:$markdown" - implementation 'de.charlex.compose:revealswipe:1.0.0' + def revealSwipe = "1.0.0" + implementation "de.charlex.compose:revealswipe:$revealSwipe" - implementation 'com.github.jeziellago:compose-markdown:0.3.3' + def compose_markdown = "0.3.3" + implementation "com.github.jeziellago:compose-markdown:$compose_markdown" // testing def junit = "4.13.2" diff --git a/app/src/main/java/com/owenlejeune/tvtime/OnboardingActivity.kt b/app/src/main/java/com/owenlejeune/tvtime/OnboardingActivity.kt index cfa424e..f0a0866 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/OnboardingActivity.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/OnboardingActivity.kt @@ -1,6 +1,8 @@ package com.owenlejeune.tvtime import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent import android.os.Bundle import android.window.OnBackInvokedDispatcher import androidx.activity.OnBackPressedCallback @@ -40,6 +42,14 @@ import org.koin.android.ext.android.inject @OptIn(ExperimentalPagerApi::class) class OnboardingActivity: MonetCompatActivity() { + companion object { + fun showActivity(sourceActivity: Context) { + val intent = Intent(sourceActivity, OnboardingActivity::class.java) +// intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK + sourceActivity.startActivity(intent) + } + } + private val preferences: AppPreferences by inject() private lateinit var pagerState: PagerState @@ -104,53 +114,56 @@ class OnboardingActivity: MonetCompatActivity() { } } - Box( + Column( modifier = Modifier .fillMaxWidth() .padding(all = 12.dp) ) { - Button( - modifier = Modifier.align(Alignment.CenterStart), - enabled = true, - onClick = { - preferences.firstLaunch = false - launchActivity(MainActivity::class.java) - } + OnboardingPage[pagerState.currentPage].footer.invoke(this@Column) + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxWidth() ) { - val skipText = if (preferences.firstLaunchTesting) - stringResource(id = R.string.action_skip_testing) - else - stringResource(id = R.string.action_skip) - Text(text = skipText) - } - - HorizontalPagerIndicator( - pagerState = pagerState, - modifier = Modifier - .align(Alignment.Center) - .padding(16.dp), - activeColor = MaterialTheme.colorScheme.secondary - ) - - Button( - modifier = Modifier.align(Alignment.CenterEnd), - shape = CircleShape, - enabled = nextButtonEnabled.value, - onClick = { - if (isLastPage) { + Button( + enabled = true, + onClick = { preferences.firstLaunch = false launchActivity(MainActivity::class.java) - } else { - coroutineScope.launch { - pagerState.animateScrollToPage(pagerState.currentPage + 1) + } + ) { + val skipText = if (preferences.firstLaunchTesting) + stringResource(id = R.string.action_skip_testing) + else + stringResource(id = R.string.action_skip) + Text(text = skipText) + } + + HorizontalPagerIndicator( + pagerState = pagerState, + modifier = Modifier + .padding(16.dp), + activeColor = MaterialTheme.colorScheme.secondary + ) + + Button( + shape = CircleShape, + enabled = nextButtonEnabled.value, + 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) + ) { + if (!isLastPage) { + Text(stringResource(id = R.string.get_started)) + } else { + Icon(imageVector = Icons.Filled.ArrowForward, contentDescription = null) + } } } } @@ -185,7 +198,7 @@ class OnboardingActivity: MonetCompatActivity() { color = MaterialTheme.colorScheme.onBackground ) Spacer(modifier = Modifier.height(50.dp)) - page.additionalContent(this@OnboardingActivity, nextButtonEnabled) + page.additionalContent(this@Column, this@OnboardingActivity, nextButtonEnabled) } } diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Gallery.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Gallery.kt index 660c52c..46f8416 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Gallery.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Gallery.kt @@ -45,27 +45,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlin.time.Duration.Companion.seconds -@OptIn(ExperimentalPagerApi::class) -@Composable -fun Gallery( - pagerState: PagerState, - models: List, - modifier: Modifier = Modifier, - contentDescriptions: List = emptyList() -) { - HorizontalPager( - count = models.size, - state = pagerState, - modifier = modifier - ) { page -> - AsyncImage( - model = models[page], - contentDescription = contentDescriptions[page], - contentScale = ContentScale.FillWidth - ) - } -} - @OptIn(ExperimentalPagerApi::class) @Composable fun TapGallery( @@ -145,7 +124,7 @@ fun TapGallery( imageVector = Icons.Outlined.ChevronLeft, contentDescription = null, modifier = Modifier.align(Alignment.Center), - tint = MaterialTheme.colorScheme.surface + tint = Color.White ) } @@ -160,114 +139,10 @@ fun TapGallery( imageVector = Icons.Outlined.ChevronRight, contentDescription = null, modifier = Modifier.align(Alignment.Center), - tint = MaterialTheme.colorScheme.surface + tint = Color.White ) } -// Box( -// modifier = Modifier -// .background(brush = leftGradient) -// .height(height = sizeImage.value.height.toDp()) -// .width((sizeImage.value.width/2).toDp()) -// .align(Alignment.CenterStart) -// .onGloballyPositioned { leftSizeImage.value = it.size } -// .clickable { -// val target = -// if (pagerState.currentPage == 0) models.size - 1 else pagerState.currentPage - 1 -// scope.launch { pagerState.animateScrollToPage(target) } -// } -// ) { -// Icon( -// imageVector = Icons.Outlined.ChevronLeft, -// contentDescription = null, -// modifier = Modifier -// .size(48.dp) -// .padding(start = 24.dp) -// .align(Alignment.CenterStart), -// tint = MaterialTheme.colorScheme.surface -// ) -// } -// Box( -// modifier = Modifier -// .background(brush = rightGradient) -// .height(height = sizeImage.value.height.toDp()) -// .width((sizeImage.value.width/2).toDp()) -// .align(Alignment.CenterEnd) -// .onGloballyPositioned { rightSizeImage.value = it.size } -// .clickable { -// val target = -// if (pagerState.currentPage == models.size - 1) 0 else pagerState.currentPage + 1 -// scope.launch { pagerState.animateScrollToPage(target) } -// } -// ) { -// Icon( -// imageVector = Icons.Outlined.ChevronRight, -// contentDescription = null, -// modifier = Modifier -// .size(48.dp) -// .padding(end = 24.dp) -// .align(Alignment.CenterEnd), -// tint = MaterialTheme.colorScheme.surface -// ) -// } } } - -// AnimatedVisibility( -// visible = showControls.value, -// enter = fadeIn(), -// exit = fadeOut() -// ) { -// val leftSizeImage = remember { mutableStateOf(IntSize.Zero) } -// val leftGradient = Brush.horizontalGradient( -// colors = listOf(Color.Black, Color.Transparent), -// startX = 0f, -// endX = leftSizeImage.value.width.toFloat() -// ) -// Box( -// modifier = Modifier -// .background(brush = leftGradient) -// .fillMaxHeight() -// .width(100.dp) -// .align(Alignment.CenterStart) -// .onGloballyPositioned { leftSizeImage.value = it.size } -// .clickable { -// val target = -// if (pagerState.currentPage == 0) models.size - 1 else pagerState.currentPage + 1 -// scope.launch { pagerState.animateScrollToPage(target) } -// } -// ) { -// Icon( -// imageVector = Icons.Outlined.ChevronLeft, -// contentDescription = null, -// modifier = Modifier.size(48.dp) -// ) -// } -// -// val rightSizeImage = remember { mutableStateOf(IntSize.Zero) } -// val rightGradient = Brush.horizontalGradient( -// colors = listOf(Color.Black, Color.Transparent), -// startX = leftSizeImage.value.width.toFloat(), -// endX = 0f -// ) -// Box( -// modifier = Modifier -// .background(brush = rightGradient) -// .fillMaxHeight() -// .width(100.dp) -// .align(Alignment.CenterEnd) -// .onGloballyPositioned { rightSizeImage.value = it.size } -// .clickable { -// val target = -// if (pagerState.currentPage == models.size - 1) 0 else pagerState.currentPage - 1 -// scope.launch { pagerState.animateScrollToPage(target) } -// } -// ) { -// Icon( -// imageVector = Icons.Outlined.ChevronRight, -// contentDescription = null, -// modifier = Modifier.size(48.dp) -// ) -// } -// } } } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Menus.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Menus.kt index 4df45c4..39f9bd5 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Menus.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Menus.kt @@ -12,7 +12,9 @@ import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Login @@ -30,9 +32,11 @@ import androidx.compose.runtime.Composable 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.graphics.Color import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.platform.LocalContext +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 @@ -213,12 +217,27 @@ fun ProfileMenuOverlay( MenuDivider() - Text( - text = "${stringResource(id = R.string.app_name)} v${BuildConfig.VERSION_NAME}", - fontSize = 10.sp, - textAlign = TextAlign.Center, - modifier = Modifier.fillMaxWidth() - ) + Row( + modifier = Modifier.align(Alignment.CenterHorizontally), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "${stringResource(id = R.string.app_name)} v${BuildConfig.VERSION_NAME}", + fontSize = 10.sp + ) + Text(text = "•") + Icon( + painter = painterResource(id = R.drawable.tmdb_logo), + tint = Color.Unspecified, + contentDescription = null, + modifier = Modifier.size(16.dp) + ) + Text( + text = stringResource(R.string.powered_by_tmdb), + fontSize = 10.sp + ) + } } } } @@ -237,6 +256,8 @@ private fun ProfileMenuItem( ) { Box( modifier = Modifier + .clip(RoundedCornerShape(10.dp)) + .padding(horizontal = 4.dp) .clickable( enabled = onClick != null, onClick = onClick ?: {} diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SearchScreen.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SearchScreen.kt index 7ea3193..37180c2 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SearchScreen.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SearchScreen.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavHostController import coil.compose.AsyncImage +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.DetailService import com.owenlejeune.tvtime.api.tmdb.api.v3.MoviesService @@ -47,6 +48,10 @@ fun SearchScreen( title: String, mediaViewType: MediaViewType ) { + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background) + systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background) + Column( modifier = Modifier .fillMaxSize() diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AboutView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AboutView.kt index 76bb03a..307a12a 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AboutView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AboutView.kt @@ -8,10 +8,16 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.outlined.Description @@ -34,13 +40,17 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue 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.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.owenlejeune.tvtime.BuildConfig import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.utils.FileUtils @@ -51,6 +61,10 @@ import dev.jeziellago.compose.markdowntext.MarkdownText fun AboutView( appNavController: NavController ) { + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background) + systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background) + val context = LocalContext.current val decayAnimationSpec = rememberSplineBasedDecay() @@ -78,11 +92,10 @@ fun AboutView( ) { Box(modifier = Modifier.padding(it)) { Column( - verticalArrangement = Arrangement.spacedBy(24.dp), - modifier = Modifier.padding(horizontal = 24.dp) + modifier = Modifier.padding(horizontal = 12.dp) ) { AboutItem( - title = "App Info", + title = stringResource(R.string.app_info_label), subtitle = "v${BuildConfig.VERSION_NAME}", icon = Icons.Outlined.Info, onClick = { @@ -96,7 +109,7 @@ fun AboutView( var showChangeLog by remember { mutableStateOf(false) } AboutItem( - title = "Changelog", + title = stringResource(R.string.changelog_label), icon = Icons.Outlined.Description, onClick = { showChangeLog = true } ) @@ -104,6 +117,18 @@ fun AboutView( visible = showChangeLog, onDismissRequest = { showChangeLog = false } ) + + AboutItem( + title = "Privacy Policy", + onClick = {} + ) + + AboutItem( + title = "Terms of Use", + onClick = {} + ) + + AttributionSection() } } } @@ -113,29 +138,34 @@ fun AboutView( private fun AboutItem( title: String, subtitle: String? = null, - icon: ImageVector, + icon: ImageVector? = null, onClick: (() -> Unit)? = null ) { Row( modifier = Modifier .fillMaxWidth() .wrapContentHeight() + .clip(RoundedCornerShape(10.dp)) .clickable( onClick = onClick ?: {}, enabled = onClick != null - ), - horizontalArrangement = Arrangement.spacedBy(24.dp) + ) ) { - Icon( - imageVector = icon, - contentDescription = subtitle, - modifier = Modifier.align(Alignment.CenterVertically), - tint = MaterialTheme.colorScheme.primary - ) + icon?.let { + Icon( + imageVector = icon, + contentDescription = subtitle, + modifier = Modifier + .align(Alignment.CenterVertically) + .padding(all = 12.dp), + tint = MaterialTheme.colorScheme.primary + ) + } Column( modifier = Modifier .align(Alignment.CenterVertically) .weight(1f) + .padding(all = 12.dp) ) { val titleColor = MaterialTheme.colorScheme.onBackground val subtitleColor = MaterialTheme.colorScheme.onSurfaceVariant @@ -161,12 +191,54 @@ private fun ChangeLogDialog( Button( onClick = onDismissRequest ) { - Text(text = "Close") + Text(text = stringResource(id = R.string.action_dismiss)) } }, text = { - MarkdownText(markdown = changeLog) + MarkdownText( + markdown = changeLog, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) } ) } +} + +@Composable +private fun ColumnScope.AttributionSection() { + val context = LocalContext.current + + Spacer(modifier = Modifier.weight(1f)) + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .clip(RoundedCornerShape(10.dp)) + .clickable( + onClick = { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.tmdb_home_page))) + context.startActivity(intent) + } + ) + ) { + Spacer(modifier = Modifier.height(12.dp)) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Spacer(modifier = Modifier.width(12.dp)) + Icon( + painter = painterResource(id = R.drawable.tmdb_logo), + contentDescription = null, + modifier = Modifier.size(32.dp), + tint = Color.Unspecified + ) + Text( + text = stringResource(id = R.string.attribution_text), + fontSize = 12.sp + ) + Spacer(modifier = Modifier.width(12.dp)) + } + Spacer(modifier = Modifier.height(12.dp)) + } } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AccountView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AccountView.kt index 57a19a7..2efe011 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AccountView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/AccountView.kt @@ -8,9 +8,11 @@ import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll @@ -24,6 +26,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.google.accompanist.systemuicontroller.rememberSystemUiController import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.model.* import com.owenlejeune.tvtime.api.tmdb.api.v4.model.V4AccountList @@ -48,59 +51,67 @@ fun AccountView( appNavController: NavHostController, doSignInPartTwo: Boolean = false ) { + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background) + systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background) + val currentSessionState = remember { SessionManager.currentSession } val currentSession = currentSessionState.value - val showProfileMenuOverlay = remember { mutableStateOf(false) } - - ProfileMenuContainer( - appNavController = appNavController, - visible = showProfileMenuOverlay.value, - onDismissRequest = { showProfileMenuOverlay.value = false } - ) { - val decayAnimationSpec = rememberSplineBasedDecay() - val topAppBarScrollState = rememberTopAppBarScrollState() - val scrollBehavior = remember(decayAnimationSpec) { - TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec, topAppBarScrollState) - } - Scaffold( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), - topBar = { - LargeTopAppBar( - scrollBehavior = scrollBehavior, - navigationIcon = { - IconButton( - onClick = { appNavController.popBackStack() } - ) { - Icon( - Icons.Filled.ArrowBack, - contentDescription = null - ) - } - }, - title = { - if (currentSession?.isAuthorized == false) { - Text(text = stringResource(id = R.string.account_not_logged_in)) - } else { - val accountDetails = remember { currentSession!!.accountDetails } - Text(text = getAccountName(accountDetails.value)) - } - }, - colors = TopAppBarDefaults.largeTopAppBarColors(scrolledContainerColor = MaterialTheme.colorScheme.background), - actions = { - AccountIcon( - modifier = Modifier.padding(start = 12.dp), - size = 32.dp, - onClick = { showProfileMenuOverlay.value = true } + val decayAnimationSpec = rememberSplineBasedDecay() + val topAppBarScrollState = rememberTopAppBarScrollState() + val scrollBehavior = remember(decayAnimationSpec) { + TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec, topAppBarScrollState) + } + Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { + LargeTopAppBar( + scrollBehavior = scrollBehavior, + navigationIcon = { + IconButton( + onClick = { appNavController.popBackStack() } + ) { + Icon( + Icons.Filled.ArrowBack, + contentDescription = null ) - Spacer(modifier = Modifier.width(8.dp)) } - ) - } - ) { - Box(modifier = Modifier.padding(it)) { - AccountViewContent(appNavController = appNavController, doSignInPartTwo = doSignInPartTwo) - } + }, + title = { + if (currentSession?.isAuthorized == false) { + Text(text = stringResource(id = R.string.account_not_logged_in)) + } else { + val accountDetails = remember { currentSession!!.accountDetails } + Text(text = getAccountName(accountDetails.value)) + } + }, + colors = TopAppBarDefaults.largeTopAppBarColors(scrolledContainerColor = MaterialTheme.colorScheme.background), + actions = { + var showDropDownMenu by remember { mutableStateOf(false) } + AccountIcon( + modifier = Modifier.padding(end = 8.dp), + size = 32.dp, + onClick = { showDropDownMenu = true } + ) + DropdownMenu( + expanded = showDropDownMenu, + onDismissRequest = { showDropDownMenu = false} + ) { + DropdownMenuItem( + text = { Text(text = stringResource(id = R.string.action_sign_out)) }, + onClick = { + SessionManager.clearSession() + appNavController.popBackStack() + } + ) + } + } + ) + } + ) { + Box(modifier = Modifier.padding(it)) { + AccountViewContent(appNavController = appNavController, doSignInPartTwo = doSignInPartTwo) } } } diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/ListDetailView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/ListDetailView.kt index 714629c..bcb6497 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/ListDetailView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/ListDetailView.kt @@ -33,6 +33,7 @@ import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.Dimension import androidx.navigation.NavController import coil.compose.AsyncImage +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.AccountService import com.owenlejeune.tvtime.api.tmdb.api.v3.model.MarkAsFavoriteBody @@ -65,6 +66,10 @@ fun ListDetailView( windowSize: WindowSizeClass, preferences: AppPreferences = KoinJavaComponent.get(AppPreferences::class.java) ) { + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background) + systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background) + val service = ListV4Service() val parentList = remember { mutableStateOf(null) } diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt index 4915c42..a753163 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt @@ -37,6 +37,7 @@ import com.google.accompanist.flowlayout.FlowRow import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.PagerState import com.google.accompanist.pager.rememberPagerState +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.AccountService import com.owenlejeune.tvtime.api.tmdb.api.v3.DetailService @@ -69,6 +70,10 @@ fun MediaDetailView( windowSize: WindowSizeClass, preferences: AppPreferences = get(AppPreferences::class.java) ) { + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background) + systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background) + val service = when (type) { MediaViewType.MOVIE -> MoviesService() MediaViewType.TV -> TvService() diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt index 6c02fb6..6fbab81 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.google.accompanist.pager.ExperimentalPagerApi +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.PeopleService import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailPerson @@ -40,6 +41,10 @@ fun PersonDetailView( appNavController: NavController, personId: Int? ) { + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background) + systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background) + val person = remember { mutableStateOf(null) } personId?.let { if (person.value == null) { 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 index beab561..5cc00e7 100644 --- 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 @@ -30,8 +30,10 @@ import androidx.navigation.NavController import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.kieronquinn.monetcompat.core.MonetCompat import com.owenlejeune.tvtime.BuildConfig +import com.owenlejeune.tvtime.OnboardingActivity import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.preferences.AppPreferences import com.owenlejeune.tvtime.ui.components.* @@ -53,6 +55,10 @@ fun SettingsTab( route: String? = null, preferences: AppPreferences = get(AppPreferences::class.java) ) { + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background) + systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background) + val decayAnimationSpec = rememberSplineBasedDecay() val topAppBarScrollState = rememberTopAppBarScrollState() val scrollBehavior = remember(decayAnimationSpec) { @@ -445,6 +451,15 @@ private fun DevPreferences( preferences.firstLaunchTesting = isChecked } ) + Text( + text = "Show onboarding UI", + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier + .padding(horizontal = 8.dp, vertical = 12.dp) + .clickable { + OnboardingActivity.showActivity(context) + } + ) val shouldShowPalette = remember { mutableStateOf(false) } Text( diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/WebLinkView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/WebLinkView.kt index b94146f..5614c5b 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/WebLinkView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/WebLinkView.kt @@ -14,11 +14,13 @@ import androidx.compose.material.icons.filled.Close import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SmallTopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.navigation.NavController +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.web.AccompanistWebViewClient import com.google.accompanist.web.WebView import com.google.accompanist.web.rememberWebViewState @@ -32,6 +34,10 @@ fun WebLinkView( url: String, appNavController: NavController ) { + val systemUiController = rememberSystemUiController() + systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background) + systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background) + Scaffold( topBar = { SmallTopAppBar( 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 index 8a4570b..4267744 100644 --- 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 @@ -4,8 +4,16 @@ import android.os.Build import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Brightness6 import androidx.compose.material.icons.filled.Search @@ -13,13 +21,19 @@ import androidx.compose.material.icons.outlined.DarkMode import androidx.compose.material.icons.outlined.LightMode import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon +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.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.kieronquinn.monetcompat.core.MonetCompat import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.preferences.AppPreferences @@ -34,7 +48,8 @@ sealed class OnboardingPage( @StringRes val title: Int, @StringRes val description: Int, @DrawableRes val image: Int? = null, - val additionalContent: @Composable (AppCompatActivity, MutableState) -> Unit = { a, e -> } + val additionalContent: @Composable ColumnScope.(AppCompatActivity, MutableState) -> Unit = { _, _ -> }, + val footer: @Composable ColumnScope.() -> Unit = {} ) { companion object: KoinComponent { @@ -49,7 +64,29 @@ sealed class OnboardingPage( order = 0, title = R.string.app_name, description = R.string.intro_page_desc, - image = R.drawable.ic_launcher_foreground + image = R.drawable.ic_launcher_foreground, + footer = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(12.dp), + modifier = Modifier + .align(Alignment.CenterHorizontally) + .wrapContentWidth() + .padding(all = 24.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.tmdb_logo), + contentDescription = null, + modifier = Modifier.size(32.dp), + tint = Color.Unspecified + ) + Text( + text = stringResource(id = R.string.attribution_text), + fontSize = 12.sp, + textAlign = TextAlign.Center + ) + } + } ) object SignInPage: OnboardingPage( diff --git a/app/src/main/res/drawable/tmdb_logo.xml b/app/src/main/res/drawable/tmdb_logo.xml new file mode 100644 index 0000000..5805929 --- /dev/null +++ b/app/src/main/res/drawable/tmdb_logo.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b9508d7..6d275c1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -215,4 +215,10 @@ Recommended TV No Recommended TV No more results found + + This product uses the TMDB API but is not endorsed or certified by TMDB. + "https://www.themoviedb.org" + App Info + Changelog + Powered by TMDB \ No newline at end of file