diff --git a/theme-m3/event-list/event-list-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/events/feature/EventListVM.kt b/theme-m3/event-list/event-list-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/events/feature/EventListVM.kt index 6b0d175c1..85bfb6da3 100644 --- a/theme-m3/event-list/event-list-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/events/feature/EventListVM.kt +++ b/theme-m3/event-list/event-list-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/events/feature/EventListVM.kt @@ -14,10 +14,9 @@ fun EventListVM( modifier: Modifier = Modifier, viewModel: EventListViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is EventListUiState.Loading -> EventList( - events = (uiState.value as EventListUiState.Loading).events, + events = uiState.events, onEventClicked = {}, modifier = modifier, isLoading = true @@ -25,7 +24,7 @@ fun EventListVM( is EventListUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is EventListUiState.Success -> EventList( - events = (uiState.value as EventListUiState.Success).events, + events = uiState.events, onEventClicked = { viewModel.savedEventId(it) onEventClicked() diff --git a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/CoCVM.kt b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/CoCVM.kt index 92fbd58a4..2328aa49c 100644 --- a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/CoCVM.kt +++ b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/CoCVM.kt @@ -15,12 +15,11 @@ fun CoCVM( modifier: Modifier = Modifier, viewModel: CoCViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is CoCUiState.Loading -> Text(text = stringResource(R.string.text_loading)) is CoCUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is CoCUiState.Success -> CoC( - coc = (uiState.value as CoCUiState.Success).coc, + coc = uiState.coc, modifier = modifier, onReportByPhoneClicked = onReportByPhoneClicked, onReportByEmailClicked = onReportByEmailClicked diff --git a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/EventVM.kt b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/EventVM.kt index 154b4ae4e..13644c5fb 100644 --- a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/EventVM.kt +++ b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/EventVM.kt @@ -15,10 +15,9 @@ fun EventVM( modifier: Modifier = Modifier, viewModel: EventViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is EventUiState.Loading -> Event( - event = (uiState.value as EventUiState.Loading).event, + event = uiState.event, modifier = modifier, isLoading = true, onLinkClicked = onLinkClicked, @@ -27,7 +26,7 @@ fun EventVM( is EventUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is EventUiState.Success -> Event( - event = (uiState.value as EventUiState.Success).event, + event = uiState.event, modifier = modifier, onLinkClicked = onLinkClicked, onItineraryClicked = onItineraryClicked diff --git a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/InfoCompactVM.kt b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/InfoCompactVM.kt index a8e2d0fe9..706fdae43 100644 --- a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/InfoCompactVM.kt +++ b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/InfoCompactVM.kt @@ -29,9 +29,8 @@ fun InfoCompactVM( modifier: Modifier = Modifier, viewModel: InfoViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() val title = stringResource(id = R.string.screen_info) - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is InfoUiState.Loading -> Scaffold(title = title, modifier = modifier) { EventVM( onLinkClicked = onLinkClicked, @@ -41,18 +40,18 @@ fun InfoCompactVM( } is InfoUiState.Success -> { - val uiModel = uiState.value as InfoUiState.Success - val pagerState = - rememberPagerState(pageCount = { uiModel.tabActionsUi.actions.count() }) + val pagerState = rememberPagerState( + pageCount = { uiState.tabActionsUi.actions.count() } + ) LaunchedEffect(pagerState.currentPage) { - viewModel.innerScreenConfig(uiModel.tabActionsUi.actions[pagerState.currentPage].route) + viewModel.innerScreenConfig(uiState.tabActionsUi.actions[pagerState.currentPage].route) } Scaffold( title = title, modifier = modifier, - topActions = uiModel.topActionsUi, - tabActions = uiModel.tabActionsUi, - fabAction = uiModel.fabAction, + topActions = uiState.topActionsUi, + tabActions = uiState.tabActionsUi, + fabAction = uiState.fabAction, onActionClicked = { when (it.id) { ActionIds.DISCONNECT -> { @@ -76,7 +75,7 @@ fun InfoCompactVM( state = pagerState, modifier = Modifier.padding(it) ) { page -> - when (uiModel.tabActionsUi.actions[page].route) { + when (uiState.tabActionsUi.actions[page].route) { TabActions.event.route -> EventVM( onLinkClicked = onLinkClicked, onItineraryClicked = onItineraryClicked, diff --git a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/MenusVM.kt b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/MenusVM.kt index 0bbc1e395..eac278101 100644 --- a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/MenusVM.kt +++ b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/MenusVM.kt @@ -15,17 +15,16 @@ fun MenusVM( modifier: Modifier = Modifier, viewModel: MenusViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is MenusUiState.Loading -> Menus( - menuItems = (uiState.value as MenusUiState.Loading).menus, + menuItems = uiState.menus, modifier = modifier, isLoading = true ) is MenusUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is MenusUiState.Success -> Menus( - menuItems = (uiState.value as MenusUiState.Success).menus, + menuItems = uiState.menus, modifier = modifier, isLoading = false ) diff --git a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/QAndAListVM.kt b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/QAndAListVM.kt index 4aeadfb7c..1c99274c8 100644 --- a/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/QAndAListVM.kt +++ b/theme-m3/infos/infos-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/infos/feature/QAndAListVM.kt @@ -14,10 +14,9 @@ fun QAndAListVM( modifier: Modifier = Modifier, viewModel: QAndAListViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is QAndAUiState.Loading -> QAndAList( - qAndA = (uiState.value as QAndAUiState.Loading).qanda, + qAndA = uiState.qanda, modifier = modifier, isLoading = true, onExpandedClicked = {}, @@ -26,12 +25,10 @@ fun QAndAListVM( is QAndAUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is QAndAUiState.Success -> QAndAList( - qAndA = (uiState.value as QAndAUiState.Success).qanda, + qAndA = uiState.qanda, modifier = modifier, isLoading = false, - onExpandedClicked = { - viewModel.expanded(it) - }, + onExpandedClicked = { viewModel.expanded(it) }, onLinkClicked = onLinkClicked ) } diff --git a/theme-m3/main/main/src/main/kotlin/org/gdglille/devfest/android/theme/MainNavigation.kt b/theme-m3/main/main/src/main/kotlin/org/gdglille/devfest/android/theme/MainNavigation.kt index c68bead53..14b5aacf1 100644 --- a/theme-m3/main/main/src/main/kotlin/org/gdglille/devfest/android/theme/MainNavigation.kt +++ b/theme-m3/main/main/src/main/kotlin/org/gdglille/devfest/android/theme/MainNavigation.kt @@ -34,8 +34,8 @@ import org.gdglille.devfest.android.theme.m3.navigation.Screen import org.gdglille.devfest.android.theme.m3.networking.feature.NetworkingCompactVM import org.gdglille.devfest.android.theme.m3.networking.feature.ProfileInputVM import org.gdglille.devfest.android.theme.m3.networking.feature.VCardQrCodeScanner -import org.gdglille.devfest.android.theme.m3.partners.feature.PartnerDetailOrientableVM -import org.gdglille.devfest.android.theme.m3.partners.feature.PartnersListCompactVM +import org.gdglille.devfest.android.theme.m3.partners.feature.PartnerDetailVM +import org.gdglille.devfest.android.theme.m3.partners.feature.PartnersGridVM import org.gdglille.devfest.android.theme.m3.schedules.feature.AgendaFiltersCompactVM import org.gdglille.devfest.android.theme.m3.schedules.feature.ScheduleDetailOrientableVM import org.gdglille.devfest.android.theme.m3.schedules.feature.ScheduleGridAdaptive @@ -208,7 +208,7 @@ fun MainNavigation( ) } composable(Screen.PartnerList.route) { - PartnersListCompactVM( + PartnersGridVM( onPartnerClick = { navController.navigate(Screen.Partner.route(it)) } ) } @@ -219,7 +219,7 @@ fun MainNavigation( uriPattern = "$rootUri/${Screen.Partner.route}" }) ) { - PartnerDetailOrientableVM( + PartnerDetailVM( partnerId = it.arguments?.getString("partnerId")!!, onLinkClicked = { launchUrl(it) }, onItineraryClicked = onItineraryClicked, diff --git a/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/ContactsCompactVM.kt b/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/ContactsCompactVM.kt index 5ca3317cf..f7e112b51 100644 --- a/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/ContactsCompactVM.kt +++ b/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/ContactsCompactVM.kt @@ -14,14 +14,12 @@ fun ContactsCompactVM( modifier: Modifier = Modifier, viewModel: ContactsViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is ContactsUiState.Loading -> Text(text = stringResource(id = R.string.text_loading)) is ContactsUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is ContactsUiState.Success -> { - val usersUi = (uiState.value as ContactsUiState.Success).users ContactsScreen( - users = usersUi, + users = uiState.users, modifier = modifier, onNetworkDeleted = viewModel::deleteNetworking ) diff --git a/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/MyProfileCompactVM.kt b/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/MyProfileCompactVM.kt index dbad3870a..b1d375932 100644 --- a/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/MyProfileCompactVM.kt +++ b/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/MyProfileCompactVM.kt @@ -16,12 +16,11 @@ fun MyProfileCompactVM( modifier: Modifier = Modifier, viewModel: MyProfileViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is MyProfileUiState.Loading -> Text(text = stringResource(id = R.string.text_loading)) is MyProfileUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is MyProfileUiState.Success -> { - val profileUi = (uiState.value as MyProfileUiState.Success).profile + val profileUi = uiState.profile if (profileUi.qrCode == null) { EmptyNetworkingScreen(modifier = modifier) } else { diff --git a/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/NetworkingCompactVM.kt b/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/NetworkingCompactVM.kt index aad4bf341..ceec7cd7e 100644 --- a/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/NetworkingCompactVM.kt +++ b/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/NetworkingCompactVM.kt @@ -28,29 +28,27 @@ fun NetworkingCompactVM( modifier: Modifier = Modifier, viewModel: NetworkingViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() val exportPath = viewModel.exportPath.collectAsState(null) LaunchedEffect(exportPath.value) { exportPath.value?.let(onContactExportClicked) } val title = stringResource(id = R.string.screen_networking) - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is NetworkingUiState.Loading -> Scaffold(title = title, modifier = modifier) { EmptyNetworkingScreen() } is NetworkingUiState.Success -> { - val uiModel = uiState.value as NetworkingUiState.Success val pagerState: PagerState = - rememberPagerState(pageCount = { uiModel.tabActionsUi.actions.count() }) + rememberPagerState(pageCount = { uiState.tabActionsUi.actions.count() }) LaunchedEffect(pagerState.currentPage) { - viewModel.innerScreenConfig(uiModel.tabActionsUi.actions[pagerState.currentPage].route) + viewModel.innerScreenConfig(uiState.tabActionsUi.actions[pagerState.currentPage].route) } Scaffold( title = title, - topActions = uiModel.topActionsUi, - tabActions = uiModel.tabActionsUi, - fabAction = uiModel.fabAction, + topActions = uiState.topActionsUi, + tabActions = uiState.tabActionsUi, + fabAction = uiState.fabAction, onActionClicked = { when (it.id) { ActionIds.EXPORT -> { @@ -77,7 +75,7 @@ fun NetworkingCompactVM( state = pagerState, modifier = Modifier.padding(it) ) { page -> - when (uiModel.tabActionsUi.actions[page].route) { + when (uiState.tabActionsUi.actions[page].route) { TabActions.myProfile.route -> MyProfileCompactVM( onEditInformation = onCreateProfileClicked ) diff --git a/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/ProfileInputVM.kt b/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/ProfileInputVM.kt index 88eb79b52..706725668 100644 --- a/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/ProfileInputVM.kt +++ b/theme-m3/networking/networking-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/networking/feature/ProfileInputVM.kt @@ -17,12 +17,11 @@ fun ProfileInputVM( modifier: Modifier = Modifier, viewModel: ProfileInputViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is ProfileInputUiState.Loading -> Text(text = stringResource(id = R.string.text_loading)) is ProfileInputUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is ProfileInputUiState.Success -> ProfileInputScreen( - profile = (uiState.value as ProfileInputUiState.Success).profile, + profile = uiState.profile, modifier = modifier, onBackClicked = onBackClicked, onValueChanged = viewModel::fieldChanged, diff --git a/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnerDetailOrientableVM.kt b/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnerDetailOrientableVM.kt deleted file mode 100644 index cfc73c653..000000000 --- a/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnerDetailOrientableVM.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.gdglille.devfest.android.theme.m3.partners.feature - -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberTopAppBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.res.stringResource -import org.gdglille.devfest.android.theme.m3.partners.screens.PartnerDetailOrientable -import org.gdglille.devfest.android.theme.m3.style.R -import org.gdglille.devfest.android.theme.m3.style.appbars.TopAppBar -import org.koin.androidx.compose.koinViewModel -import org.koin.core.parameter.parametersOf - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun PartnerDetailOrientableVM( - partnerId: String, - onLinkClicked: (url: String) -> Unit, - onItineraryClicked: (lat: Double, lng: Double) -> Unit, - onBackClicked: () -> Unit, - modifier: Modifier = Modifier, - viewModel: PartnerDetailViewModel = koinViewModel(parameters = { parametersOf(partnerId) }) -) { - val uiState = viewModel.uiState.collectAsState() - val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) - Scaffold( - modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), - topBar = { - TopAppBar( - title = stringResource(id = R.string.screen_partners_detail), - navigationIcon = { Back(onClick = onBackClicked) }, - scrollBehavior = scrollBehavior - ) - }, - content = { - when (uiState.value) { - is PartnerUiState.Loading -> PartnerDetailOrientable( - partnerItemUi = (uiState.value as PartnerUiState.Loading).partner, - onLinkClicked = {}, - onItineraryClicked = { _, _ -> }, - contentPadding = it, - isLoading = true - ) - - is PartnerUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) - is PartnerUiState.Success -> PartnerDetailOrientable( - partnerItemUi = (uiState.value as PartnerUiState.Success).partner, - onLinkClicked = onLinkClicked, - onItineraryClicked = onItineraryClicked, - contentPadding = it - ) - } - } - ) -} diff --git a/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnerDetailVM.kt b/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnerDetailVM.kt new file mode 100644 index 000000000..8adb0c714 --- /dev/null +++ b/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnerDetailVM.kt @@ -0,0 +1,41 @@ +package org.gdglille.devfest.android.theme.m3.partners.feature + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import org.gdglille.devfest.android.theme.m3.partners.screens.PartnerDetailOrientable +import org.gdglille.devfest.android.theme.m3.style.R +import org.koin.androidx.compose.koinViewModel +import org.koin.core.parameter.parametersOf + +@Composable +fun PartnerDetailVM( + partnerId: String, + onLinkClicked: (url: String) -> Unit, + onItineraryClicked: (lat: Double, lng: Double) -> Unit, + onBackClicked: () -> Unit, + modifier: Modifier = Modifier, + viewModel: PartnerDetailViewModel = koinViewModel(parameters = { parametersOf(partnerId) }) +) { + when (val uiState = viewModel.uiState.collectAsState().value) { + is PartnerUiState.Loading -> PartnerDetailOrientable( + partnerItemUi = uiState.partner, + onLinkClicked = {}, + onItineraryClicked = { _, _ -> }, + onBackClicked = onBackClicked, + modifier = modifier, + isLoading = true + ) + + is PartnerUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) + is PartnerUiState.Success -> PartnerDetailOrientable( + partnerItemUi = uiState.partner, + onLinkClicked = onLinkClicked, + onItineraryClicked = onItineraryClicked, + onBackClicked = onBackClicked, + modifier = modifier + ) + } +} diff --git a/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnersGridVM.kt b/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnersGridVM.kt new file mode 100644 index 000000000..b8ded00e3 --- /dev/null +++ b/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnersGridVM.kt @@ -0,0 +1,37 @@ +package org.gdglille.devfest.android.theme.m3.partners.feature + +import androidx.compose.foundation.lazy.grid.rememberLazyGridState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import org.gdglille.devfest.android.theme.m3.partners.screens.PartnersGridScreen +import org.gdglille.devfest.android.theme.m3.style.R +import org.koin.androidx.compose.koinViewModel + +@Composable +fun PartnersGridVM( + onPartnerClick: (id: String) -> Unit, + modifier: Modifier = Modifier, + viewModel: PartnersViewModel = koinViewModel() +) { + val state = rememberLazyGridState() + when (val uiState = viewModel.uiState.collectAsState().value) { + is PartnersUiState.Loading -> PartnersGridScreen( + partners = uiState.partners, + state = state, + isLoading = true, + onPartnerClick = {}, + modifier = modifier + ) + + is PartnersUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) + is PartnersUiState.Success -> PartnersGridScreen( + partners = uiState.partners, + state = state, + onPartnerClick = onPartnerClick, + modifier = modifier + ) + } +} diff --git a/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnersListCompactVM.kt b/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnersListCompactVM.kt deleted file mode 100644 index 8f843463e..000000000 --- a/theme-m3/partners/partners-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/feature/PartnersListCompactVM.kt +++ /dev/null @@ -1,58 +0,0 @@ -package org.gdglille.devfest.android.theme.m3.partners.feature - -import android.content.res.Configuration -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.grid.rememberLazyGridState -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.res.stringResource -import org.gdglille.devfest.android.theme.m3.partners.screens.PartnersListScreen -import org.gdglille.devfest.android.theme.m3.style.R -import org.gdglille.devfest.android.theme.m3.style.Scaffold -import org.koin.androidx.compose.koinViewModel - -private const val ColumnCountLandscape = 6 -private const val ColumnCountPortrait = 3 - -@OptIn(ExperimentalFoundationApi::class) -@Composable -fun PartnersListCompactVM( - onPartnerClick: (id: String) -> Unit, - modifier: Modifier = Modifier, - viewModel: PartnersViewModel = koinViewModel() -) { - val configuration = LocalConfiguration.current - val state = rememberLazyGridState() - val columnCount = - if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) ColumnCountLandscape - else ColumnCountPortrait - val uiState = viewModel.uiState.collectAsState() - Scaffold( - title = stringResource(id = R.string.screen_partners), - modifier = modifier - ) { - when (uiState.value) { - is PartnersUiState.Loading -> PartnersListScreen( - partners = (uiState.value as PartnersUiState.Loading).partners, - columnCount = columnCount, - state = state, - isLoading = true, - onPartnerClick = {}, - modifier = Modifier.padding(it) - ) - - is PartnersUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) - is PartnersUiState.Success -> PartnersListScreen( - partners = (uiState.value as PartnersUiState.Success).partners, - columnCount = columnCount, - state = state, - onPartnerClick = onPartnerClick, - modifier = Modifier.padding(it) - ) - } - } -} diff --git a/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnerDetailOrientable.kt b/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnerDetailOrientable.kt index 346fc2596..e3058bff3 100644 --- a/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnerDetailOrientable.kt +++ b/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnerDetailOrientable.kt @@ -1,57 +1,76 @@ package org.gdglille.devfest.android.theme.m3.partners.screens import android.content.res.Configuration -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.unit.dp +import androidx.compose.ui.res.stringResource +import org.gdglille.devfest.android.theme.m3.style.R +import org.gdglille.devfest.android.theme.m3.style.appbars.TopAppBar import org.gdglille.devfest.models.ui.PartnerItemUi +@OptIn(ExperimentalMaterial3Api::class) @Composable fun PartnerDetailOrientable( partnerItemUi: PartnerItemUi, onLinkClicked: (url: String) -> Unit, onItineraryClicked: (lat: Double, lng: Double) -> Unit, + onBackClicked: () -> Unit, modifier: Modifier = Modifier, - contentPadding: PaddingValues = PaddingValues(0.dp), isLoading: Boolean = false, ) { val state = rememberLazyListState() val orientation = LocalConfiguration.current - if (orientation.orientation == Configuration.ORIENTATION_LANDSCAPE) { - Row( - verticalAlignment = Alignment.Top, - modifier = modifier.padding(contentPadding) - ) { - PartnerImageScreen( - url = partnerItemUi.logoUrl, - isLoading = isLoading, - modifier = Modifier.weight(1f) - ) - PartnerDetailVerticalScreen( - partnerItemUi = partnerItemUi, - onLinkClicked = onLinkClicked, - onItineraryClicked = onItineraryClicked, - modifier = Modifier.weight(1f), - state = state, - isLoading = isLoading, - displayAvatar = false + val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) + Scaffold( + modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { + TopAppBar( + title = stringResource(id = R.string.screen_partners_detail), + navigationIcon = { Back(onClick = onBackClicked) }, + scrollBehavior = scrollBehavior ) + }, + content = { + if (orientation.orientation == Configuration.ORIENTATION_LANDSCAPE) { + Row( + verticalAlignment = Alignment.Top, + modifier = Modifier.padding(it) + ) { + PartnerImageScreen( + url = partnerItemUi.logoUrl, + isLoading = isLoading, + modifier = Modifier.weight(1f) + ) + PartnerDetailVerticalScreen( + partnerItemUi = partnerItemUi, + onLinkClicked = onLinkClicked, + onItineraryClicked = onItineraryClicked, + modifier = Modifier.weight(1f), + state = state, + isLoading = isLoading, + displayAvatar = false + ) + } + } else { + PartnerDetailVerticalScreen( + partnerItemUi = partnerItemUi, + onLinkClicked = onLinkClicked, + onItineraryClicked = onItineraryClicked, + contentPadding = it, + state = state, + isLoading = isLoading + ) + } } - } else { - PartnerDetailVerticalScreen( - partnerItemUi = partnerItemUi, - onLinkClicked = onLinkClicked, - onItineraryClicked = onItineraryClicked, - contentPadding = contentPadding, - state = state, - isLoading = isLoading - ) - } + ) } diff --git a/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnersGridScreen.kt b/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnersGridScreen.kt new file mode 100644 index 000000000..cd32c0898 --- /dev/null +++ b/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnersGridScreen.kt @@ -0,0 +1,91 @@ +package org.gdglille.devfest.android.theme.m3.partners.screens + +import android.annotation.SuppressLint +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.grid.rememberLazyGridState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import kotlin.math.floor +import org.gdglille.devfest.android.theme.m3.partners.ui.partners.PartnerDivider +import org.gdglille.devfest.android.theme.m3.style.Conferences4HallTheme +import org.gdglille.devfest.android.theme.m3.style.R +import org.gdglille.devfest.android.theme.m3.style.Scaffold +import org.gdglille.devfest.android.theme.m3.style.SpacingTokens +import org.gdglille.devfest.android.theme.m3.style.partners.items.PartnerItem +import org.gdglille.devfest.android.theme.m3.style.placeholder +import org.gdglille.devfest.android.theme.m3.style.toDp +import org.gdglille.devfest.models.ui.PartnerGroupsUi + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun PartnersGridScreen( + partners: PartnerGroupsUi, + modifier: Modifier = Modifier, + state: LazyGridState = rememberLazyGridState(), + isLoading: Boolean = false, + onPartnerClick: (id: String) -> Unit +) { + Scaffold( + title = stringResource(id = R.string.screen_partners), + modifier = modifier + ) { + BoxWithConstraints(modifier = Modifier.padding(it)) { + val minSize = 100.dp + val mediumSpacing = SpacingTokens.MediumSpacing.toDp() + val count = floor((this.maxWidth - mediumSpacing * 2) / minSize).toInt() + LazyVerticalGrid( + columns = GridCells.Adaptive(minSize = minSize), + horizontalArrangement = Arrangement.spacedBy(mediumSpacing), + verticalArrangement = Arrangement.spacedBy(mediumSpacing), + contentPadding = PaddingValues( + vertical = SpacingTokens.LargeSpacing.toDp(), + horizontal = mediumSpacing + ), + state = state, + ) { + partners.groups.forEach { + item(span = { GridItemSpan(currentLineSpan = count) }) { + PartnerDivider(title = it.type) + } + items(it.partners) { + PartnerItem( + url = it.logoUrl, + contentDescription = it.name, + modifier = Modifier + .fillMaxWidth() + .aspectRatio(1f) + .placeholder(visible = isLoading), + onClick = { onPartnerClick(it.id) } + ) + } + } + } + } + } +} + +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@Preview +@Composable +private fun PartnersGridScreenPreview() { + Conferences4HallTheme { + PartnersGridScreen( + partners = PartnerGroupsUi.fake, + onPartnerClick = {} + ) + } +} diff --git a/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnersListScreen.kt b/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnersListScreen.kt deleted file mode 100644 index bbbe796fe..000000000 --- a/theme-m3/partners/partners-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/partners/screens/PartnersListScreen.kt +++ /dev/null @@ -1,73 +0,0 @@ -package org.gdglille.devfest.android.theme.m3.partners.screens - -import android.annotation.SuppressLint -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.lazy.grid.GridCells -import androidx.compose.foundation.lazy.grid.GridItemSpan -import androidx.compose.foundation.lazy.grid.LazyGridState -import androidx.compose.foundation.lazy.grid.LazyVerticalGrid -import androidx.compose.foundation.lazy.grid.items -import androidx.compose.foundation.lazy.grid.rememberLazyGridState -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import org.gdglille.devfest.android.theme.m3.partners.ui.partners.PartnerDivider -import org.gdglille.devfest.android.theme.m3.style.Conferences4HallTheme -import org.gdglille.devfest.android.theme.m3.style.partners.items.PartnerItem -import org.gdglille.devfest.android.theme.m3.style.placeholder -import org.gdglille.devfest.models.ui.PartnerGroupsUi - -@Composable -fun PartnersListScreen( - partners: PartnerGroupsUi, - modifier: Modifier = Modifier, - state: LazyGridState = rememberLazyGridState(), - isLoading: Boolean = false, - columnCount: Int = 3, - onPartnerClick: (id: String) -> Unit -) { - LazyVerticalGrid( - columns = GridCells.Fixed(columnCount), - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - contentPadding = PaddingValues(vertical = 16.dp), - state = state, - modifier = modifier - ) { - partners.groups.forEach { - item(span = { GridItemSpan(currentLineSpan = columnCount) }) { - PartnerDivider(title = it.type) - } - items(it.partners) { - PartnerItem( - url = it.logoUrl, - contentDescription = it.name, - modifier = Modifier - .fillMaxWidth() - .aspectRatio(1f) - .placeholder(visible = isLoading), - onClick = { onPartnerClick(it.id) } - ) - } - } - } -} - -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") -@Preview -@Composable -private fun PartnersListScreenPreview() { - Conferences4HallTheme { - Scaffold { - PartnersListScreen( - partners = PartnerGroupsUi.fake, - onPartnerClick = {} - ) - } - } -} diff --git a/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/AgendaFiltersCompactVM.kt b/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/AgendaFiltersCompactVM.kt index 63cc4c24a..4abeab228 100644 --- a/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/AgendaFiltersCompactVM.kt +++ b/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/AgendaFiltersCompactVM.kt @@ -19,14 +19,12 @@ fun AgendaFiltersCompactVM( navigationIcon: @Composable() (AppBarIcons.() -> Unit)? = null, viewModel: AgendaFiltersViewModel = koinViewModel() ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is AgendaFiltersUiState.Loading -> Text(text = stringResource(id = R.string.text_loading)) is AgendaFiltersUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is AgendaFiltersUiState.Success -> { - val filtersUi = (uiState.value as AgendaFiltersUiState.Success).filters AgendaFiltersScreen( - filtersUi = filtersUi, + filtersUi = uiState.filters, onFavoriteClick = viewModel::applyFavoriteFilter, onCategoryClick = viewModel::applyCategoryFilter, onFormatClick = viewModel::applyFormatFilter, diff --git a/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/ScheduleDetailOrientableVM.kt b/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/ScheduleDetailOrientableVM.kt index b6c766bb5..2cde132f2 100644 --- a/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/ScheduleDetailOrientableVM.kt +++ b/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/ScheduleDetailOrientableVM.kt @@ -23,12 +23,11 @@ fun ScheduleDetailOrientableVM( modifier: Modifier = Modifier, viewModel: ScheduleDetailViewModel = koinViewModel(parameters = { parametersOf(scheduleId) }) ) { - val uiState = viewModel.uiState.collectAsState() - when (uiState.value) { + when (val uiState = viewModel.uiState.collectAsState().value) { is ScheduleUiState.Loading -> Text(text = stringResource(id = R.string.text_loading)) is ScheduleUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) is ScheduleUiState.Success -> ScheduleDetailOrientableScreen( - talk = (uiState.value as ScheduleUiState.Success).talk, + talk = uiState.talk, openFeedbackFirebaseConfig = openfeedbackFirebaseConfig, modifier = modifier, onBackClicked = onBackClicked, diff --git a/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/ScheduleGridVM.kt b/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/ScheduleGridVM.kt index bc830d872..b750d9f7d 100644 --- a/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/ScheduleGridVM.kt +++ b/theme-m3/schedules/schedules-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/feature/ScheduleGridVM.kt @@ -1,8 +1,6 @@ package org.gdglille.devfest.android.theme.m3.schedules.feature import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -12,10 +10,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview -import org.gdglille.devfest.android.theme.m3.navigation.ActionIds import org.gdglille.devfest.android.theme.m3.schedules.screens.ScheduleGridPager import org.gdglille.devfest.android.theme.m3.style.R -import org.gdglille.devfest.android.theme.m3.style.Scaffold import org.gdglille.devfest.android.theme.m3.style.actions.TopActionsUi import org.koin.androidx.compose.koinViewModel @@ -33,53 +29,31 @@ fun ScheduleGridVM( viewModel: ScheduleGridViewModel = koinViewModel() ) { val context = LocalContext.current - val title = stringResource(id = R.string.screen_agenda) LaunchedEffect(key1 = Unit) { onScheduleStarted() } when (val uiState = viewModel.uiState.collectAsState().value) { - is ScheduleGridUiState.Loading -> Scaffold( - title = title, - modifier = modifier - ) { - ScheduleGridPager( - agendas = uiState.agenda, - onTalkClicked = {}, - onFavoriteClicked = {}, - isLoading = true - ) - } + is ScheduleGridUiState.Loading -> ScheduleGridPager( + agendas = uiState.agenda, + onTalkClicked = {}, + onFilterClicked = {}, + onFavoriteClicked = {}, + isLoading = true + ) is ScheduleGridUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) - is ScheduleGridUiState.Success -> { - val count = uiState.scheduleUi.tabActionsUi.actions.count() - val pagerState = rememberPagerState(pageCount = { count }) - Scaffold( - title = title, - modifier = modifier, - topActions = if (!showFilterIcon) TopActionsUi() else uiState.scheduleUi.topActionsUi, - tabActions = uiState.scheduleUi.tabActionsUi, - hasScrollBehavior = false, - onActionClicked = { - when (it.id) { - ActionIds.FILTERS -> { - onFilterClicked() - } - } - } - ) { - ScheduleGridPager( - agendas = uiState.scheduleUi.schedules, - onTalkClicked = onTalkClicked, - onFavoriteClicked = { talkItem -> - viewModel.markAsFavorite(context, talkItem) - }, - modifier = Modifier.padding(top = it.calculateTopPadding()), - pagerState = pagerState, - isSmallSize = isSmallSize, - isLoading = false - ) - } - } + is ScheduleGridUiState.Success -> ScheduleGridPager( + agendas = uiState.scheduleUi.schedules, + topActionsUi = if (!showFilterIcon) TopActionsUi() else uiState.scheduleUi.topActionsUi, + tabActionsUi = uiState.scheduleUi.tabActionsUi, + onTalkClicked = onTalkClicked, + onFilterClicked = onFilterClicked, + onFavoriteClicked = { talkItem -> + viewModel.markAsFavorite(context, talkItem) + }, + modifier = modifier, + isSmallSize = isSmallSize, + isLoading = false + ) } } diff --git a/theme-m3/schedules/schedules-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/screens/ScheduleGridPager.kt b/theme-m3/schedules/schedules-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/screens/ScheduleGridPager.kt index 93d1bf8bb..3474c5bb2 100644 --- a/theme-m3/schedules/schedules-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/screens/ScheduleGridPager.kt +++ b/theme-m3/schedules/schedules-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/schedules/screens/ScheduleGridPager.kt @@ -2,13 +2,20 @@ package org.gdglille.devfest.android.theme.m3.schedules.screens import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import kotlinx.collections.immutable.ImmutableList +import org.gdglille.devfest.android.theme.m3.navigation.ActionIds +import org.gdglille.devfest.android.theme.m3.style.R +import org.gdglille.devfest.android.theme.m3.style.Scaffold +import org.gdglille.devfest.android.theme.m3.style.actions.TabActionsUi +import org.gdglille.devfest.android.theme.m3.style.actions.TopActionsUi import org.gdglille.devfest.models.ui.AgendaUi import org.gdglille.devfest.models.ui.TalkItemUi @@ -17,24 +24,43 @@ import org.gdglille.devfest.models.ui.TalkItemUi fun ScheduleGridPager( agendas: ImmutableList, onTalkClicked: (id: String) -> Unit, + onFilterClicked: () -> Unit, onFavoriteClicked: (TalkItemUi) -> Unit, modifier: Modifier = Modifier, - pagerState: PagerState = rememberPagerState(pageCount = { 0 }), + topActionsUi: TopActionsUi = TopActionsUi(), + tabActionsUi: TabActionsUi = TabActionsUi(), + pagerState: PagerState = rememberPagerState(pageCount = { tabActionsUi.actions.count() }), isSmallSize: Boolean = false, isLoading: Boolean = false, ) { - HorizontalPager( - state = pagerState, - modifier = Modifier.fillMaxSize(), - verticalAlignment = Alignment.Top - ) { page -> - ScheduleGridScreen( - agenda = agendas[page], - onTalkClicked = onTalkClicked, - onFavoriteClicked = onFavoriteClicked, - modifier = modifier, - isSmallSize = isSmallSize, - isLoading = isLoading - ) + Scaffold( + title = stringResource(id = R.string.screen_agenda), + modifier = modifier, + topActions = topActionsUi, + tabActions = tabActionsUi, + hasScrollBehavior = false, + onActionClicked = { + when (it.id) { + ActionIds.FILTERS -> { + onFilterClicked() + } + } + } + ) { + HorizontalPager( + state = pagerState, + modifier = Modifier + .padding(top = it.calculateTopPadding()) + .fillMaxSize(), + verticalAlignment = Alignment.Top + ) { page -> + ScheduleGridScreen( + agenda = agendas[page], + onTalkClicked = onTalkClicked, + onFavoriteClicked = onFavoriteClicked, + isSmallSize = isSmallSize, + isLoading = isLoading + ) + } } } diff --git a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailOrientableVM.kt b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailOrientableVM.kt index 0a4203eb2..7ecc8d9d1 100644 --- a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailOrientableVM.kt +++ b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailOrientableVM.kt @@ -1,6 +1,5 @@ package org.gdglille.devfest.android.theme.m3.speakers.feature -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -9,12 +8,10 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import org.gdglille.devfest.android.theme.m3.speakers.screens.SpeakerDetailOrientable import org.gdglille.devfest.android.theme.m3.style.R -import org.gdglille.devfest.android.theme.m3.style.Scaffold import org.gdglille.devfest.android.theme.m3.style.appbars.AppBarIcons import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf -@OptIn(ExperimentalFoundationApi::class) @Composable fun SpeakerDetailOrientableVM( speakerId: String, @@ -26,33 +23,28 @@ fun SpeakerDetailOrientableVM( viewModel: SpeakerDetailViewModel = koinViewModel(key = speakerId, parameters = { parametersOf(speakerId) }) ) { val context = LocalContext.current - val uiState = viewModel.uiState.collectAsState() - Scaffold( - title = stringResource(id = R.string.screen_speaker_detail), - navigationIcon = navigationIcon, - modifier = modifier - ) { - when (uiState.value) { - is SpeakerUiState.Loading -> SpeakerDetailOrientable( - speaker = (uiState.value as SpeakerUiState.Loading).speaker, - contentPadding = it, - onTalkClicked = {}, - onFavoriteClicked = {}, - onLinkClicked = {}, - isLandscape = isLandscape - ) + when (val uiState = viewModel.uiState.collectAsState().value) { + is SpeakerUiState.Loading -> SpeakerDetailOrientable( + speaker = uiState.speaker, + onTalkClicked = {}, + onFavoriteClicked = {}, + onLinkClicked = {}, + modifier = modifier, + navigationIcon = navigationIcon, + isLandscape = isLandscape, + ) - is SpeakerUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) - is SpeakerUiState.Success -> SpeakerDetailOrientable( - speaker = (uiState.value as SpeakerUiState.Success).speaker, - contentPadding = it, - onTalkClicked = onTalkClicked, - onFavoriteClicked = { - viewModel.markAsFavorite(context, it) - }, - onLinkClicked = onLinkClicked, - isLandscape = isLandscape - ) - } + is SpeakerUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) + is SpeakerUiState.Success -> SpeakerDetailOrientable( + speaker = uiState.speaker, + onTalkClicked = onTalkClicked, + onFavoriteClicked = { + viewModel.markAsFavorite(context, it) + }, + onLinkClicked = onLinkClicked, + modifier = modifier, + navigationIcon = navigationIcon, + isLandscape = isLandscape + ) } } diff --git a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakersListCompactVM.kt b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakersListCompactVM.kt index bbb7e2446..f52fe7c4d 100644 --- a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakersListCompactVM.kt +++ b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakersListCompactVM.kt @@ -1,19 +1,15 @@ package org.gdglille.devfest.android.theme.m3.speakers.feature -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import org.gdglille.devfest.android.theme.m3.speakers.screens.SpeakersListScreen +import org.gdglille.devfest.android.theme.m3.speakers.screens.SpeakersGridScreen import org.gdglille.devfest.android.theme.m3.style.R -import org.gdglille.devfest.android.theme.m3.style.Scaffold import org.koin.androidx.compose.koinViewModel -@OptIn(ExperimentalFoundationApi::class) @Composable fun SpeakersListCompactVM( onSpeakerClicked: (id: String) -> Unit, @@ -21,31 +17,22 @@ fun SpeakersListCompactVM( viewModel: SpeakersListViewModel = koinViewModel() ) { val state = rememberLazyGridState() - val uiState = viewModel.uiState.collectAsState() - Scaffold( - title = stringResource(id = R.string.screen_speakers), - modifier = modifier, - hasScrollBehavior = false - ) { - when (uiState.value) { - is SpeakersUiState.Loading -> SpeakersListScreen( - speakers = (uiState.value as SpeakersUiState.Loading).speakers, - onSpeakerClicked = onSpeakerClicked, - modifier = Modifier.padding(it), - state = state, - isLoading = true - ) + when (val uiState = viewModel.uiState.collectAsState().value) { + is SpeakersUiState.Loading -> SpeakersGridScreen( + speakers = uiState.speakers, + onSpeakerClicked = onSpeakerClicked, + modifier = modifier, + state = state, + isLoading = true + ) - is SpeakersUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) - is SpeakersUiState.Success -> { - SpeakersListScreen( - speakers = (uiState.value as SpeakersUiState.Success).speakers, - onSpeakerClicked = onSpeakerClicked, - modifier = Modifier.padding(top = it.calculateTopPadding()), - state = state, - isLoading = false - ) - } - } + is SpeakersUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) + is SpeakersUiState.Success -> SpeakersGridScreen( + speakers = uiState.speakers, + onSpeakerClicked = onSpeakerClicked, + modifier = modifier, + state = state, + isLoading = false + ) } } diff --git a/theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakerDetailOrientable.kt b/theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakerDetailOrientable.kt index 3162b136a..9d99c7709 100644 --- a/theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakerDetailOrientable.kt +++ b/theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakerDetailOrientable.kt @@ -1,16 +1,20 @@ package org.gdglille.devfest.android.theme.m3.speakers.screens -import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import androidx.compose.ui.res.stringResource +import org.gdglille.devfest.android.theme.m3.style.R +import org.gdglille.devfest.android.theme.m3.style.Scaffold +import org.gdglille.devfest.android.theme.m3.style.appbars.AppBarIcons import org.gdglille.devfest.models.ui.SpeakerUi import org.gdglille.devfest.models.ui.TalkItemUi +@OptIn(ExperimentalFoundationApi::class) @Composable fun SpeakerDetailOrientable( speaker: SpeakerUi, @@ -18,42 +22,47 @@ fun SpeakerDetailOrientable( onFavoriteClicked: (TalkItemUi) -> Unit, onLinkClicked: (url: String) -> Unit, modifier: Modifier = Modifier, - contentPadding: PaddingValues = PaddingValues(0.dp), + navigationIcon: @Composable (AppBarIcons.() -> Unit)? = null, isLandscape: Boolean = false, isLoading: Boolean = false ) { val state = rememberLazyListState() - if (isLandscape) { - Row( - verticalAlignment = Alignment.Top, - modifier = modifier.padding(contentPadding) - ) { - SpeakerAvatarScreen( - url = speaker.url, - isLoading = isLoading, - modifier = Modifier.weight(1f) - ) + Scaffold( + title = stringResource(id = R.string.screen_speaker_detail), + navigationIcon = navigationIcon, + modifier = modifier + ) { + if (isLandscape) { + Row( + verticalAlignment = Alignment.Top, + modifier = Modifier.padding(it) + ) { + SpeakerAvatarScreen( + url = speaker.url, + isLoading = isLoading, + modifier = Modifier.weight(1f) + ) + SpeakerDetailScreen( + speaker = speaker, + onTalkClicked = onTalkClicked, + onFavoriteClicked = onFavoriteClicked, + onLinkClicked = onLinkClicked, + modifier = Modifier.weight(1f), + state = state, + isLoading = isLoading, + displayAvatar = false + ) + } + } else { SpeakerDetailScreen( speaker = speaker, onTalkClicked = onTalkClicked, onFavoriteClicked = onFavoriteClicked, onLinkClicked = onLinkClicked, - modifier = Modifier.weight(1f), state = state, - isLoading = isLoading, - displayAvatar = false + contentPadding = it, + isLoading = isLoading ) } - } else { - SpeakerDetailScreen( - speaker = speaker, - onTalkClicked = onTalkClicked, - onFavoriteClicked = onFavoriteClicked, - onLinkClicked = onLinkClicked, - modifier = modifier, - state = state, - contentPadding = contentPadding, - isLoading = isLoading - ) } } diff --git a/theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakersListScreen.kt b/theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakersGridScreen.kt similarity index 54% rename from theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakersListScreen.kt rename to theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakersGridScreen.kt index d959c3720..0032fb979 100644 --- a/theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakersListScreen.kt +++ b/theme-m3/speakers/speakers-screens/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/screens/SpeakersGridScreen.kt @@ -1,8 +1,10 @@ package org.gdglille.devfest.android.theme.m3.speakers.screens +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.LazyVerticalGrid @@ -10,51 +12,63 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import org.gdglille.devfest.android.theme.m3.style.Conferences4HallTheme +import org.gdglille.devfest.android.theme.m3.style.R +import org.gdglille.devfest.android.theme.m3.style.Scaffold import org.gdglille.devfest.android.theme.m3.style.SpacingTokens import org.gdglille.devfest.android.theme.m3.style.placeholder import org.gdglille.devfest.android.theme.m3.style.speakers.items.LargeSpeakerItem import org.gdglille.devfest.android.theme.m3.style.toDp import org.gdglille.devfest.models.ui.SpeakerItemUi +@OptIn(ExperimentalFoundationApi::class) @Composable -fun SpeakersListScreen( +fun SpeakersGridScreen( speakers: ImmutableList, onSpeakerClicked: (id: String) -> Unit, modifier: Modifier = Modifier, state: LazyGridState = rememberLazyGridState(), isLoading: Boolean = false, ) { - LazyVerticalGrid( - columns = GridCells.Adaptive(minSize = 150.dp), - modifier = modifier.fillMaxWidth(), - state = state, - verticalArrangement = Arrangement.spacedBy(SpacingTokens.MediumSpacing.toDp()), - horizontalArrangement = Arrangement.spacedBy(SpacingTokens.MediumSpacing.toDp()), - contentPadding = PaddingValues(vertical = SpacingTokens.ExtraLargeSpacing.toDp()), - content = { - items(speakers.toList(), key = { it.id }) { - LargeSpeakerItem( - name = it.name, - description = it.company, - url = it.url, - onClick = { onSpeakerClicked(it.id) }, - modifier = Modifier.placeholder(isLoading) - ) + Scaffold( + title = stringResource(id = R.string.screen_speakers), + modifier = modifier, + hasScrollBehavior = false + ) { + LazyVerticalGrid( + columns = GridCells.Adaptive(minSize = 150.dp), + modifier = Modifier + .padding(top = it.calculateTopPadding()) + .fillMaxWidth(), + state = state, + verticalArrangement = Arrangement.spacedBy(SpacingTokens.MediumSpacing.toDp()), + horizontalArrangement = Arrangement.spacedBy(SpacingTokens.MediumSpacing.toDp()), + contentPadding = PaddingValues(vertical = SpacingTokens.ExtraLargeSpacing.toDp()), + content = { + items(speakers.toList(), key = { it.id }) { + LargeSpeakerItem( + name = it.name, + description = it.company, + url = it.url, + onClick = { onSpeakerClicked(it.id) }, + modifier = Modifier.placeholder(isLoading) + ) + } } - } - ) + ) + } } @Preview @Composable -private fun SpeakersListPreview() { +private fun SpeakersGridPreview() { Conferences4HallTheme { - SpeakersListScreen( + SpeakersGridScreen( speakers = persistentListOf( SpeakerItemUi.fake.copy(id = "1"), SpeakerItemUi.fake.copy(id = "2"),