Skip to content

Commit

Permalink
feat: Improve home screen when no packs (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
octera authored Aug 14, 2024
1 parent 86bc482 commit 73460ee
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
Expand All @@ -23,6 +24,7 @@ import androidx.compose.material3.Card
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -33,13 +35,17 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
import coil.compose.rememberAsyncImagePainter
import info.octera.droidstorybox.R
import info.octera.droidstorybox.domain.model.pack.PackMetadata
import info.octera.droidstorybox.presentation.PreviewFakeData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
Expand All @@ -59,6 +65,20 @@ fun PreviewHomeScreeen() {
)
}

@Preview(
showSystemUi = true,
showBackground = true,
)
@Composable
fun PreviewHomeScreeen_EmptyPack() {
HomeScreen(
packs = listOf(),
onSettingsClicked = {},
onPackFocused = {},
onPackSelected = {}
)
}

@OptIn(FlowPreview::class)
@Composable
fun HomeScreen(
Expand All @@ -70,16 +90,6 @@ fun HomeScreen(
val pagerState = rememberPagerState { packs.count() }
val coroutineScope = rememberCoroutineScope()

if(packs.isNotEmpty()) {
LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }
.debounce(500)
.collect { page ->
onPackFocused(packs[page])
}
}
}

Scaffold(
modifier = Modifier
.fillMaxSize(),
Expand All @@ -98,113 +108,145 @@ fun HomeScreen(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
HorizontalPager(
state = pagerState,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.5F),
contentPadding = PaddingValues(horizontal = 32.dp),
pageSpacing = 8.dp
) { page ->
val item = packs[page]
Card(
modifier = Modifier
.graphicsLayer {
// Calculate the absolute offset for the current page from the
// scroll position. We use the absolute value which allows us to mirror
// any effects for both directions
val pageOffset = (
(pagerState.currentPage - page) + pagerState
.currentPageOffsetFraction
).absoluteValue
verticalArrangement = Arrangement.Center,
)
{
if (packs.isEmpty()) {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.displayLarge.copy(fontWeight = FontWeight.Bold),
text= stringResource(R.string.please_add_pack_in_settings_menu)
)
} else {
PackSelector(pagerState, packs, coroutineScope, onPackFocused, onPackSelected)
}

// We animate the alpha, between 50% and 100%
alpha = lerp(
start = 0.5f,
stop = 1f,
fraction = 1f - pageOffset.coerceIn(0f, 1f)
)
}
}
}

) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
modifier = Modifier
.height(205.dp),
painter = rememberAsyncImagePainter(model = item.thumbsnail),
contentDescription = item.title,
contentScale = ContentScale.Crop
)
}
Text(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.padding(8.dp),
textAlign = TextAlign.Center,
text = item.description
)
}
}

@OptIn(FlowPreview::class)
@Composable
private fun PackSelector(
pagerState: PagerState,
packs: List<PackMetadata>,
coroutineScope: CoroutineScope,
onPackFocused: (PackMetadata) -> Unit,
onPackSelected: (PackMetadata) -> Unit
) {
LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }
.debounce(500)
.collect { page ->
onPackFocused(packs[page])
}
Row(modifier = Modifier
.padding(8.dp, 64.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceAround) {
FilledIconButton(
modifier = Modifier.size(64.dp),
enabled = pagerState.canScrollBackward,
onClick = {
coroutineScope.launch {
if (pagerState.canScrollBackward) {
pagerState.animateScrollToPage(pagerState.currentPage - 1)
}
}
},
)
{
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
"",
modifier = Modifier.fillMaxSize()
)
}
FilledIconButton(
modifier = Modifier.size(64.dp),
onClick = { onPackSelected(packs[pagerState.currentPage]) },
) {
Icon(
Icons.Filled.PlayArrow,
"",
modifier = Modifier.fillMaxSize()
}

HorizontalPager(
state = pagerState,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.5F),
contentPadding = PaddingValues(horizontal = 32.dp),
pageSpacing = 8.dp
) { page ->
val item = packs[page]
Card(
modifier = Modifier
.graphicsLayer {
// Calculate the absolute offset for the current page from the
// scroll position. We use the absolute value which allows us to mirror
// any effects for both directions
val pageOffset = (
(pagerState.currentPage - page) + pagerState
.currentPageOffsetFraction
).absoluteValue

// We animate the alpha, between 50% and 100%
alpha = lerp(
start = 0.5f,
stop = 1f,
fraction = 1f - pageOffset.coerceIn(0f, 1f)
)
}
FilledIconButton(
modifier = Modifier.size(64.dp),
enabled = pagerState.canScrollForward,
onClick = {
coroutineScope.launch {
if (pagerState.canScrollForward) {
pagerState.animateScrollToPage(pagerState.currentPage + 1)
}
}
},

) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
modifier = Modifier
.height(205.dp),
painter = rememberAsyncImagePainter(model = item.thumbsnail),
contentDescription = item.title,
contentScale = ContentScale.Crop
)
{
Icon(
Icons.AutoMirrored.Filled.ArrowForward,
"",
modifier = Modifier.fillMaxSize()
)
}
}
Text(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.padding(8.dp),
textAlign = TextAlign.Center,
text = item.description
)
}

}

Row(
modifier = Modifier
.padding(8.dp, 64.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceAround
) {
FilledIconButton(
modifier = Modifier.size(64.dp),
enabled = pagerState.canScrollBackward,
onClick = {
coroutineScope.launch {
if (pagerState.canScrollBackward) {
pagerState.animateScrollToPage(pagerState.currentPage - 1)
}
}
},
)
{
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
"",
modifier = Modifier.fillMaxSize()
)
}
FilledIconButton(
modifier = Modifier.size(64.dp),
onClick = { onPackSelected(packs[pagerState.currentPage]) },
) {
Icon(
Icons.Filled.PlayArrow,
"",
modifier = Modifier.fillMaxSize()
)
}
FilledIconButton(
modifier = Modifier.size(64.dp),
enabled = pagerState.canScrollForward,
onClick = {
coroutineScope.launch {
if (pagerState.canScrollForward) {
pagerState.animateScrollToPage(pagerState.currentPage + 1)
}
}
},
)
{
Icon(
Icons.AutoMirrored.Filled.ArrowForward,
"",
modifier = Modifier.fillMaxSize()
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import info.octera.droidstorybox.R
import info.octera.droidstorybox.domain.model.pack.PackMetadata
import info.octera.droidstorybox.presentation.PreviewFakeData
import info.octera.droidstorybox.presentation.common.LocalPackList
Expand Down Expand Up @@ -92,7 +94,7 @@ fun LocalPacksScreen(
.padding(20.dp)
)
Text(
text = "Please add pack",
text = stringResource(R.string.please_add_pack),
style = MaterialTheme.typography.headlineLarge.copy(),
textAlign = TextAlign.Center

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package info.octera.droidstorybox.settings_appinfo
package info.octera.droidstorybox.presentation.settings_appinfo

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
Expand All @@ -36,7 +37,7 @@ import info.octera.droidstorybox.presentation.remote_pack.RemotePackScreen
import info.octera.droidstorybox.presentation.remote_pack.RemotePackViewModel
import info.octera.droidstorybox.presentation.settings_navigation.components.BottomNavigation
import info.octera.droidstorybox.presentation.settings_navigation.components.BottomNavigationItem
import info.octera.droidstorybox.settings_appinfo.AppInfoScreen
import info.octera.droidstorybox.presentation.settings_appinfo.AppInfoScreen

@OptIn(ExperimentalMaterial3Api::class)
@Composable
Expand Down Expand Up @@ -87,7 +88,7 @@ fun SettingsNavigator() {
titleContentColor = MaterialTheme.colorScheme.primary,
),*/
title = {
Text("Settings")
Text(stringResource(R.string.settings))
}
)
},
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@
</string-array>
<string name="onboarding_page3_title">Ajout des histoires</string>
<string name="onboarding_page3_desc">Ensuite, vous pourrez télécharger des packs puis les ajouter dans l\'application depuis le bouton \"+\" depuis l\'onglet Pack. Les packs doivent être au format ZIP</string>
<string name="please_add_pack_in_settings_menu">Merci d\'ajouter des packs dans les paramètres</string>
<string name="settings">Paramètres</string>
<string name="please_add_pack">Merci d\'ajouter des packs</string>
</resources>
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@
</string-array>
<string name="onboarding_page3_title">Add story</string>
<string name="onboarding_page3_desc">After that, you can download packs and add them to the app using the "+" button in the Pack tab. The packs must be in ZIP format.</string>
<string name="please_add_pack_in_settings_menu">Please add pack in settings menu</string>
<string name="settings">Settings</string>
<string name="please_add_pack">Please add pack</string>
</resources>

0 comments on commit 73460ee

Please sign in to comment.