add items to about page and add attribution

This commit is contained in:
Owen LeJeune
2023-06-09 13:45:30 -04:00
parent 8e27b26cc6
commit a473171559
15 changed files with 342 additions and 242 deletions

View File

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

View File

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

View File

@@ -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<Any?>,
modifier: Modifier = Modifier,
contentDescriptions: List<String> = 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)
// )
// }
// }
}
}

View File

@@ -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 ?: {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<DetailPerson?>(null) }
personId?.let {
if (person.value == null) {

View File

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

View File

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

View File

@@ -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<Boolean>) -> Unit = { a, e -> }
val additionalContent: @Composable ColumnScope.(AppCompatActivity, MutableState<Boolean>) -> 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(

View File

@@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="185.04dp"
android:height="133.4dp"
android:viewportWidth="185.04"
android:viewportHeight="133.4">
<path
android:pathData="M51.06,66.7h0A17.67,17.67 0,0 1,68.73 49h-0.1A17.67,17.67 0,0 1,86.3 66.7h0A17.67,17.67 0,0 1,68.63 84.37h0.1A17.67,17.67 0,0 1,51.06 66.7ZM133.73,35.37h32.9A17.67,17.67 0,0 0,184.3 17.7h0A17.67,17.67 0,0 0,166.63 0h-32.9A17.67,17.67 0,0 0,116.06 17.7h0A17.67,17.67 0,0 0,133.73 35.37ZM20.73,133.37h63.9A17.67,17.67 0,0 0,102.3 115.7h0A17.67,17.67 0,0 0,84.63 98L20.73,98A17.67,17.67 0,0 0,3.06 115.7h0A17.67,17.67 0,0 0,20.73 133.37ZM104.65,84.37h6.25L125.5,49h-8.35l-8.9,23.2h-0.1L99.4,49L90.5,49ZM137.1,84.37h7.8L144.9,49h-7.8ZM159.3,84.37h24.95L184.25,77.2L167.1,77.2L167.1,70h15.35L182.45,62.8L167.1,62.8L167.1,56.2h16.25L183.35,49h-24ZM10.1,35.4h7.8L17.9,6.9L28,6.9L28,0L0,0L0,6.9L10.1,6.9ZM39,35.4h7.8L46.8,20.1L61.9,20.1L61.9,35.4h7.8L69.7,0L61.9,0L61.9,13.2L46.75,13.2L46.75,0L39,0ZM80.25,35.4h25L105.25,28.2L88,28.2L88,21h15.35L103.35,13.8L88,13.8L88,7.2h16.25L104.25,0h-24ZM1.25,84.4L9,84.4L9,57.25h0.1l9,27.15L24,84.4l9.3,-27.15h0.1L33.4,84.4h7.8L41.2,49L29.45,49l-8.2,23.1h-0.1L13,49L1.2,49ZM113.34,133.4L126,133.4a24.59,24.59 0,0 0,7.56 -1.15,19.52 19.52,0 0,0 6.35,-3.37 16.37,16.37 0,0 0,4.37 -5.5A16.91,16.91 0,0 0,146 115.8a18.5,18.5 0,0 0,-1.68 -8.25,15.1 15.1,0 0,0 -4.52,-5.53A18.55,18.55 0,0 0,133.07 99,33.54 33.54,0 0,0 125,98L113.29,98ZM121.15,105.2h4.6a17.43,17.43 0,0 1,4.67 0.62,11.68 11.68,0 0,1 3.88,1.88 9,9 0,0 1,2.62 3.18,9.87 9.87,0 0,1 1,4.52 11.92,11.92 0,0 1,-1 5.08,8.69 8.69,0 0,1 -2.67,3.34 10.87,10.87 0,0 1,-4 1.83,21.57 21.57,0 0,1 -5,0.55L121.1,126.2ZM157.29,133.4h14.5a23.11,23.11 0,0 0,4.73 -0.5,13.38 13.38,0 0,0 4.27,-1.65 9.42,9.42 0,0 0,3.1 -3,8.52 8.52,0 0,0 1.2,-4.68 9.16,9.16 0,0 0,-0.55 -3.2,7.79 7.79,0 0,0 -1.57,-2.62 8.38,8.38 0,0 0,-2.45 -1.85,10 10,0 0,0 -3.18,-1v-0.1a9.28,9.28 0,0 0,4.43 -2.82,7.42 7.42,0 0,0 1.67,-5 8.34,8.34 0,0 0,-1.15 -4.65,7.88 7.88,0 0,0 -3,-2.73 12.9,12.9 0,0 0,-4.17 -1.3,34.42 34.42,0 0,0 -4.63,-0.32h-13.2ZM165.09,104.6h5.3a10.79,10.79 0,0 1,1.85 0.17,5.77 5.77,0 0,1 1.7,0.58 3.33,3.33 0,0 1,1.23 1.13,3.22 3.22,0 0,1 0.47,1.82 3.63,3.63 0,0 1,-0.42 1.8,3.34 3.34,0 0,1 -1.13,1.2 4.78,4.78 0,0 1,-1.57 0.65,8.16 8.16,0 0,1 -1.78,0.2L165,112.15ZM165.09,118.75h5.9a15.12,15.12 0,0 1,2.05 0.15,7.83 7.83,0 0,1 2,0.55 4,4 0,0 1,1.58 1.17,3.13 3.13,0 0,1 0.62,2 3.71,3.71 0,0 1,-0.47 1.95,4 4,0 0,1 -1.23,1.3 4.78,4.78 0,0 1,-1.67 0.7,8.91 8.91,0 0,1 -1.83,0.2h-7Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="0"
android:startY="66.7"
android:endX="185.04"
android:endY="66.7"
android:type="linear">
<item android:offset="0" android:color="#FF90CEA1"/>
<item android:offset="0.56" android:color="#FF3CBEC9"/>
<item android:offset="1" android:color="#FF00B3E5"/>
</gradient>
</aapt:attr>
</path>
</vector>

View File

@@ -215,4 +215,10 @@
<string name="recommended_tv_title">Recommended TV</string>
<string name="no_recommended_tv">No Recommended TV</string>
<string name="no_result_found">No more results found</string>
<string name="attribution_text">This product uses the TMDB API but is not endorsed or certified by TMDB.</string>
<string name="tmdb_home_page">"https://www.themoviedb.org"</string>
<string name="app_info_label">App Info</string>
<string name="changelog_label">Changelog</string>
<string name="powered_by_tmdb">Powered by TMDB</string>
</resources>