diff --git a/conferences-app/src/commonMain/composeResources/values/strings.xml b/conferences-app/src/commonMain/composeResources/values/strings.xml index bd92b09cf..0baa99b31 100644 --- a/conferences-app/src/commonMain/composeResources/values/strings.xml +++ b/conferences-app/src/commonMain/composeResources/values/strings.xml @@ -1,9 +1,8 @@ - Conferences - Upcoming - Profile - Events + Conferences + Upcoming Events + Past Events Call for Papers (Until %1$s) Online Only diff --git a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/events/EventsTopBar.kt b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/events/EventsTopBar.kt new file mode 100644 index 000000000..b986570b3 --- /dev/null +++ b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/events/EventsTopBar.kt @@ -0,0 +1,35 @@ +package io.ashdavies.party.events + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.stringResource + +@Composable +@ExperimentalMaterial3Api +internal fun EventsTopBar( + title: StringResource, + actions: @Composable RowScope.() -> Unit, + modifier: Modifier = Modifier, +) { + CenterAlignedTopAppBar( + title = { + Text( + text = stringResource(title), + color = MaterialTheme.colorScheme.onBackground, + style = MaterialTheme.typography.titleLarge, + ) + }, + modifier = modifier, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MaterialTheme.colorScheme.background, + ), + actions = actions, + ) +} diff --git a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/gallery/GallerySheet.kt b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/gallery/GallerySheet.kt index 15cd9f241..03c44b635 100644 --- a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/gallery/GallerySheet.kt +++ b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/gallery/GallerySheet.kt @@ -9,7 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import io.ashdavies.analytics.OnClick -import io.ashdavies.material.BottomSheetItem +import io.ashdavies.party.material.BottomSheetItem import io.ashdavies.party.past.GalleryScreen @Composable diff --git a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/home/HomeScreen.kt b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/home/HomeScreen.kt index aa2a4a091..dce73a132 100644 --- a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/home/HomeScreen.kt +++ b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/home/HomeScreen.kt @@ -1,24 +1,17 @@ package io.ashdavies.party.home import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.exclude import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Warning import androidx.compose.material3.BottomAppBar -import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text +import androidx.compose.material3.ScaffoldDefaults import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarDefaults.enterAlwaysScrollBehavior -import androidx.compose.material3.TopAppBarScrollBehavior -import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -31,18 +24,14 @@ import com.slack.circuit.foundation.NavEvent import com.slack.circuit.runtime.CircuitUiEvent import com.slack.circuit.runtime.CircuitUiState import com.slack.circuit.runtime.screen.Screen -import io.ashdavies.analytics.OnClick import io.ashdavies.identity.IdentityState import io.ashdavies.parcelable.Parcelable import io.ashdavies.parcelable.Parcelize import io.ashdavies.party.animation.FadeVisibility import io.ashdavies.party.config.booleanConfigAsState -import io.ashdavies.party.config.isProfileEnabled -import io.ashdavies.party.config.showPastEvents import io.ashdavies.party.material.icons.EventList import io.ashdavies.party.material.icons.EventUpcoming import io.ashdavies.party.past.GalleryScreen -import io.ashdavies.party.profile.ProfileActionButton import io.ashdavies.party.upcoming.UpcomingEventsScreen @Parcelize @@ -68,30 +57,11 @@ internal fun HomeScreen( modifier: Modifier = Modifier, reportFullyDrawn: () -> Unit, ) { - val isProfileEnabled by booleanConfigAsState { isProfileEnabled() } - val showPastEvents by booleanConfigAsState { showPastEvents() } + val showPastEvents by booleanConfigAsState { true } val eventSink = state.eventSink Scaffold( modifier = modifier, - topBar = { - HomeTopBar( - actions = { - FadeVisibility(isProfileEnabled) { - ProfileActionButton( - identityState = state.identityState, - onClick = OnClick("profile_login") { - eventSink(HomeScreen.Event.Login) - }, - ) - } - - IconButton(onClick = { error("Crashlytics") }) { - Icon(Icons.Default.Warning, contentDescription = null) - } - }, - ) - }, bottomBar = { FadeVisibility(showPastEvents) { HomeBottomBar { screen -> @@ -100,6 +70,9 @@ internal fun HomeScreen( } }, floatingActionButton = { }, + contentWindowInsets = ScaffoldDefaults.contentWindowInsets.exclude( + insets = TopAppBarDefaults.windowInsets, + ), ) { contentPadding -> CircuitContent( screen = state.screen, @@ -117,31 +90,6 @@ internal fun HomeScreen( } } -@Composable -@ExperimentalMaterial3Api -internal fun HomeTopBar( - modifier: Modifier = Modifier, - title: String = "Upcoming Events", - actions: @Composable RowScope.() -> Unit = { }, - scrollBehavior: TopAppBarScrollBehavior = enterAlwaysScrollBehavior(rememberTopAppBarState()), -) { - CenterAlignedTopAppBar( - title = { - Text( - text = title, - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.onBackground, - ) - }, - modifier = modifier, - colors = TopAppBarDefaults.centerAlignedTopAppBarColors( - containerColor = MaterialTheme.colorScheme.background, - ), - actions = actions, - scrollBehavior = scrollBehavior, - ) -} - @Composable internal fun HomeBottomBar( modifier: Modifier = Modifier, diff --git a/compose-material/src/commonMain/kotlin/io/ashdavies/material/BottomSheet.kt b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/material/BottomSheet.kt similarity index 97% rename from compose-material/src/commonMain/kotlin/io/ashdavies/material/BottomSheet.kt rename to conferences-app/src/commonMain/kotlin/io/ashdavies/party/material/BottomSheet.kt index 5cfde2073..1dd06d0b8 100644 --- a/compose-material/src/commonMain/kotlin/io/ashdavies/material/BottomSheet.kt +++ b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/material/BottomSheet.kt @@ -1,4 +1,4 @@ -package io.ashdavies.material +package io.ashdavies.party.material import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope @@ -25,7 +25,7 @@ import androidx.compose.ui.unit.dp @Composable @ExperimentalMaterial3Api -public fun BottomSheetScaffold( +internal fun BottomSheetScaffold( sheetContent: @Composable ColumnScope.() -> Unit, modifier: Modifier = Modifier, topBar: @Composable () -> Unit = { }, diff --git a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/past/PastEventsScreen.kt b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/past/PastEventsScreen.kt index 676b80259..58824d847 100644 --- a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/past/PastEventsScreen.kt +++ b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/past/PastEventsScreen.kt @@ -61,20 +61,23 @@ import com.slack.circuit.runtime.CircuitUiEvent import com.slack.circuit.runtime.CircuitUiState import com.slack.circuit.runtime.screen.Screen import io.ashdavies.analytics.OnClick -import io.ashdavies.material.BottomSheetScaffold import io.ashdavies.parcelable.Parcelable import io.ashdavies.parcelable.Parcelize import io.ashdavies.party.animation.FadeVisibility import io.ashdavies.party.config.booleanConfigAsState import io.ashdavies.party.config.galleryCapture +import io.ashdavies.party.events.EventsTopBar import io.ashdavies.party.gallery.File import io.ashdavies.party.gallery.GallerySheetContent import io.ashdavies.party.gallery.ImageCapture import io.ashdavies.party.gallery.StorageManager import io.ashdavies.party.gallery.SyncIndicator import io.ashdavies.party.gallery.SyncState +import io.ashdavies.party.material.BottomSheetScaffold import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList +import playground.conferences_app.generated.resources.Res +import playground.conferences_app.generated.resources.past_events private const val DEFAULT_COLUMN_COUNT = 4 @@ -136,9 +139,9 @@ internal fun PastEventListScreen( val eventSink = state.eventSink BottomSheetScaffold( - sheetContent = { - GallerySheetContent(eventSink) - }, + sheetContent = { GallerySheetContent(eventSink) }, + modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { EventsTopBar(Res.string.past_events, actions = { }) }, floatingActionButton = { FadeVisibility(isGalleryCaptureEnabled) { GalleryActionButton( @@ -150,7 +153,6 @@ internal fun PastEventListScreen( } }, showDragHandle = false, - modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), ) { paddingValues -> when { state.itemList.isEmpty() -> { diff --git a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/upcoming/UpcomingEventsList.kt b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/upcoming/UpcomingEventsList.kt index 22b1f9c81..da13d4c33 100644 --- a/conferences-app/src/commonMain/kotlin/io/ashdavies/party/upcoming/UpcomingEventsList.kt +++ b/conferences-app/src/commonMain/kotlin/io/ashdavies/party/upcoming/UpcomingEventsList.kt @@ -12,12 +12,17 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Warning import androidx.compose.material3.Card import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.SuggestionChip import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -43,6 +48,7 @@ import coil3.compose.AsyncImage import io.ashdavies.analytics.OnClick import io.ashdavies.paging.LazyPagingItems import io.ashdavies.party.events.Event +import io.ashdavies.party.events.EventsTopBar import io.ashdavies.party.events.paging.errorMessage import io.ashdavies.party.events.paging.isRefreshing import io.ashdavies.placeholder.PlaceholderHighlight @@ -58,6 +64,7 @@ import org.jetbrains.compose.resources.stringResource import playground.conferences_app.generated.resources.Res import playground.conferences_app.generated.resources.call_for_papers import playground.conferences_app.generated.resources.online_only +import playground.conferences_app.generated.resources.upcoming_events private const val PLACEHOLDER_COUNT = 8 private const val EMPTY_STRING = "" @@ -75,39 +82,53 @@ internal fun UpcomingEventsList( ) { val isRefreshing = state.pagingItems.loadState.isRefreshing - PullToRefreshBox( - isRefreshing = isRefreshing, - onRefresh = OnClick("events_refresh") { state.pagingItems.refresh() }, + Scaffold( modifier = modifier, - ) { - if (state.pagingItems.loadState.hasError) { - EventFailure(state.pagingItems.loadState.errorMessage ?: "Unknown Error") - } - - LazyColumn(Modifier.fillMaxSize()) { - val itemCount = when { - isRefreshing -> state.pagingItems.itemCount.coerceAtLeast(PLACEHOLDER_COUNT) - else -> state.pagingItems.itemCount + topBar = { + EventsTopBar( + title = Res.string.upcoming_events, + actions = { + IconButton(onClick = { error("Crashlytics") }) { + Icon(Icons.Default.Warning, contentDescription = null) + } + }, + ) + }, + ) { contentPadding -> + PullToRefreshBox( + isRefreshing = isRefreshing, + onRefresh = OnClick("events_refresh") { state.pagingItems.refresh() }, + modifier = Modifier.padding(contentPadding), + ) { + if (state.pagingItems.loadState.hasError) { + EventFailure(state.pagingItems.loadState.errorMessage ?: "Unknown Error") } - items(itemCount) { index -> - val event = state.pagingItems.rememberItemOrNull(index, isRefreshing) + LazyColumn(Modifier.fillMaxSize()) { + val itemCount = when { + isRefreshing -> state.pagingItems.itemCount.coerceAtLeast(PLACEHOLDER_COUNT) + else -> state.pagingItems.itemCount + } - EventItemContent( - modifier = Modifier - .fillMaxWidth() - .padding( - horizontal = 16.dp, - vertical = 8.dp, - ) - .clickable( - enabled = event != null, - onClickLabel = event?.name, - onClick = { onClick(event!!) }, - ) - .animateItem(), - event = event, - ) + items(itemCount) { index -> + val event = state.pagingItems.rememberItemOrNull(index, isRefreshing) + + EventItemContent( + modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = 16.dp, + vertical = 8.dp, + ) + .clickable( + enabled = event != null, + onClickLabel = event?.name, + onClick = { onClick(event!!) }, + ) + .animateItem(), + event = event, + ) + } } } }