Skip to content

Commit

Permalink
feat(schedule): support adaptive layout.
Browse files Browse the repository at this point in the history
  • Loading branch information
GerardPaligot committed Jan 18, 2024
1 parent 70ade8d commit 2372919
Show file tree
Hide file tree
Showing 27 changed files with 263 additions and 252 deletions.
1 change: 1 addition & 0 deletions androidApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ dependencies {
implementation(libs.androidx.browser)

implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.material3.windowsizeclass)
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.activity)
implementation(libs.androidx.compose.navigation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val openfeedbackFirebaseConfig = (application as MainApplication).openFeedbackConfig

val workManager = WorkManager.getInstance(this)
setContent {
val inDarkTheme = isSystemInDarkTheme()
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-compose-material3-windowsizeclass = { group = "androidx.compose.material3", name = "material3-window-size-class" }
androidx-compose-material3-adaptive = { group = "androidx.compose.material3", name = "material3-adaptive", version = "1.0.0-alpha03" }
androidx-compose-material3-adaptive = { group = "androidx.compose.material3", name = "material3-adaptive", version = "1.0.0-alpha04" }
androidx-compose-material3-adaptive-navigation-suite = { group = "androidx.compose.material3", name = "material3-adaptive-navigation-suite", version = "1.0.0-alpha02" }
androidx-compose-icons = { group = "androidx.compose.material", name = "material-icons-extended" }
androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime-livedata" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.gdglille.devfest.android.theme

import android.content.res.Configuration

val Configuration.isPortrait: Boolean
get() = orientation == Configuration.ORIENTATION_PORTRAIT
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package org.gdglille.devfest.android.theme

import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.adaptive.navigation.suite.ExperimentalMaterial3AdaptiveNavigationSuiteApi
import androidx.compose.material3.adaptive.navigation.suite.NavigationSuiteScaffold
import androidx.compose.material3.adaptive.navigation.suite.NavigationSuiteScaffoldDefaults
import androidx.compose.material3.adaptive.navigation.suite.NavigationSuiteType
import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.SavedStateHandle
import androidx.navigation.NavGraph.Companion.findStartDestination
Expand All @@ -27,8 +26,6 @@ import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import androidx.navigation.navDeepLink
import io.openfeedback.android.viewmodels.OpenFeedbackFirebaseConfig
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import org.gdglille.devfest.android.theme.m3.events.feature.EventListVM
import org.gdglille.devfest.android.theme.m3.infos.feature.InfoCompactVM
import org.gdglille.devfest.android.theme.m3.infos.feature.TicketQrCodeScanner
Expand All @@ -38,9 +35,9 @@ 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.schedules.feature.AgendaFiltersVM
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.ScheduleListCompactVM
import org.gdglille.devfest.android.theme.m3.schedules.feature.ScheduleGridAdaptive
import org.gdglille.devfest.android.theme.m3.speakers.feature.SpeakerDetailOrientableVM
import org.gdglille.devfest.android.theme.m3.speakers.feature.SpeakersListCompactVM
import org.gdglille.devfest.android.theme.m3.style.appbars.iconColor
Expand All @@ -51,8 +48,7 @@ import org.koin.androidx.compose.koinViewModel

@Suppress("LongMethod")
@OptIn(
ExperimentalMaterial3AdaptiveNavigationSuiteApi::class, ExperimentalCoroutinesApi::class,
FlowPreview::class, ExperimentalMaterial3AdaptiveApi::class
ExperimentalMaterial3AdaptiveNavigationSuiteApi::class, ExperimentalMaterial3AdaptiveApi::class
)
@Composable
fun MainNavigation(
Expand Down Expand Up @@ -87,15 +83,14 @@ fun MainNavigation(
}
}
val rootUri = "c4h://event"
val config = LocalConfiguration.current
val uiState = viewModel.uiState.collectAsState()
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
val route = currentDestination?.route ?: Screen.ScheduleList.route
val adaptiveInfo = currentWindowAdaptiveInfo()
val heightCompact =
adaptiveInfo.windowSizeClass.heightSizeClass == WindowHeightSizeClass.Compact
val isTablet = adaptiveInfo.windowPosture.isTabletop
val layoutType = if (heightCompact && isTablet.not()) {
val heightCompact = adaptiveInfo.windowSizeClass.heightSizeClass.isCompat
val layoutType = if (heightCompact) {
NavigationSuiteType.NavigationRail
} else {
NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
Expand All @@ -119,7 +114,6 @@ fun MainNavigation(
tint = iconColor(selected = selected)
)
},
label = { Text(stringResource(id = action.label)) },
onClick = {
navController.navigate(action.route) {
popUpTo(navController.graph.findStartDestination().id) {
Expand All @@ -128,8 +122,7 @@ fun MainNavigation(
launchSingleTop = true
restoreState = true
}
},
alwaysShowLabel = false
}
)
}
}
Expand All @@ -154,15 +147,28 @@ fun MainNavigation(
)
}
composable(Screen.ScheduleList.route) {
ScheduleListCompactVM(
val showFilterIcon = adaptiveInfo.windowSizeClass.widthSizeClass.isCompat
|| (adaptiveInfo.windowSizeClass.widthSizeClass.isMedium && config.isPortrait)
val columnCount = when {
adaptiveInfo.windowSizeClass.widthSizeClass.isExpanded
&& adaptiveInfo.windowSizeClass.heightSizeClass.isCompat -> 1

adaptiveInfo.windowSizeClass.widthSizeClass.isExpanded -> 2
else -> 1
}
val isSmallSize = adaptiveInfo.windowSizeClass.heightSizeClass.isCompat
ScheduleGridAdaptive(
onScheduleStarted = onScheduleStarted,
onFilterClicked = { navController.navigate(Screen.ScheduleFilters.route) },
onTalkClicked = { navController.navigate(Screen.Schedule.route(it)) }
onTalkClicked = { navController.navigate(Screen.Schedule.route(it)) },
showFilterIcon = showFilterIcon,
columnCount = columnCount,
isSmallSize = isSmallSize
)
}
composable(route = Screen.ScheduleFilters.route) {
AgendaFiltersVM(
onBackClicked = { navController.popBackStack() }
AgendaFiltersCompactVM(
navigationIcon = { Back { navController.popBackStack() } }
)
}
composable(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.gdglille.devfest.android.theme

import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass

val WindowWidthSizeClass.isCompat: Boolean
get() = this == WindowWidthSizeClass.Compact

val WindowWidthSizeClass.isMedium: Boolean
get() = this == WindowWidthSizeClass.Medium

val WindowWidthSizeClass.isExpanded: Boolean
get() = this == WindowWidthSizeClass.Expanded

val WindowHeightSizeClass.isCompat: Boolean
get() = this == WindowHeightSizeClass.Compact

val WindowHeightSizeClass.isMedium: Boolean
get() = this == WindowHeightSizeClass.Medium
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import org.gdglille.devfest.android.theme.m3.schedules.feature.AgendaFiltersViewModel
import org.gdglille.devfest.android.theme.m3.schedules.feature.ScheduleDetailViewModel
import org.gdglille.devfest.android.theme.m3.schedules.feature.ScheduleListViewModel
import org.gdglille.devfest.android.theme.m3.schedules.feature.ScheduleGridViewModel
import org.gdglille.devfest.repositoriesModule
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
Expand All @@ -14,5 +14,5 @@ val scheduleModule = module {
includes(repositoriesModule)
viewModel { AgendaFiltersViewModel(get()) }
viewModel { parameters -> ScheduleDetailViewModel(parameters.get(), get()) }
viewModel { ScheduleListViewModel(get(), get()) }
viewModel { ScheduleGridViewModel(get(), get()) }
}
2 changes: 2 additions & 0 deletions theme-m3/schedules/schedules-feature/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ dependencies {

implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material3.adaptive)
implementation(libs.androidx.compose.material3.adaptive.navigation.suite)
implementation(libs.androidx.compose.tooling)
implementation(libs.androidx.compose.lifecycle)
implementation(libs.androidx.lifecycle.vm)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package org.gdglille.devfest.android.theme.m3.schedules.feature

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import org.gdglille.devfest.android.theme.m3.schedules.screens.AgendaFiltersScreen
import org.gdglille.devfest.android.theme.m3.style.R
import org.gdglille.devfest.android.theme.m3.style.appbars.AppBarIcons
import org.koin.androidx.compose.koinViewModel

@Composable
fun AgendaFiltersVM(
onBackClicked: () -> Unit,
fun AgendaFiltersCompactVM(
modifier: Modifier = Modifier,
containerColor: Color = MaterialTheme.colorScheme.background,
navigationIcon: @Composable() (AppBarIcons.() -> Unit)? = null,
viewModel: AgendaFiltersViewModel = koinViewModel()
) {
val uiState = viewModel.uiState.collectAsState()
Expand All @@ -26,8 +30,9 @@ fun AgendaFiltersVM(
onFavoriteClick = viewModel::applyFavoriteFilter,
onCategoryClick = viewModel::applyCategoryFilter,
onFormatClick = viewModel::applyFormatFilter,
onBack = onBackClicked,
modifier = modifier
modifier = modifier,
containerColor = containerColor,
navigationIcon = navigationIcon
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.gdglille.devfest.android.theme.m3.schedules.feature

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.SupportingPaneScaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview

@OptIn(
ExperimentalMaterial3AdaptiveApi::class,
ExperimentalCoroutinesApi::class,
FlowPreview::class
)
@Composable
fun ScheduleGridAdaptive(
onScheduleStarted: () -> Unit,
onFilterClicked: () -> Unit,
onTalkClicked: (id: String) -> Unit,
showFilterIcon: Boolean,
modifier: Modifier = Modifier,
columnCount: Int = 1,
isSmallSize: Boolean = false,
) {
SupportingPaneScaffold(
modifier = modifier,
mainPane = {
ScheduleGridVM(
onScheduleStarted = onScheduleStarted,
onFilterClicked = onFilterClicked,
onTalkClicked = onTalkClicked,
showFilterIcon = showFilterIcon,
columnCount = columnCount,
isSmallSize = isSmallSize
)
},
supportingPane = {
AgendaFiltersCompactVM(
containerColor = if (showFilterIcon) MaterialTheme.colorScheme.background
else MaterialTheme.colorScheme.surfaceContainerHigh
)
}
)
}
Loading

0 comments on commit 2372919

Please sign in to comment.