From 065082aa63e330c08c534de88a77e434cbf1eb12 Mon Sep 17 00:00:00 2001 From: domonkosadam Date: Fri, 7 Nov 2025 13:00:37 +0100 Subject: [PATCH 1/5] Implement edge-to-edge display with proper status bar padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enable edge-to-edge mode in HorizonActivity - Configure Scaffolds to not consume window insets automatically - Add proper status bar inset padding to all screen headers: - Dashboard HomeScreenTopBar - LearnScreen - AccountScreen - InboxListScreen - ModuleItemSequenceScreen - SkillspaceScreen - NotificationScreen (via HorizonScaffold) - Ensure all content is clickable and visible while maintaining modern edge-to-edge experience 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../instructure/horizon/HorizonActivity.kt | 7 ++-- .../horizon/features/account/AccountScreen.kt | 6 ++- .../features/dashboard/DashboardScreen.kt | 20 ++++++---- .../horizon/features/home/HomeScreen.kt | 40 +++++++++++-------- .../compose/HorizonInboxComposeScreen.kt | 11 +---- .../inbox/list/HorizonInboxListScreen.kt | 18 ++++----- .../horizon/features/learn/LearnScreen.kt | 19 +++++---- .../ModuleItemSequenceScreen.kt | 16 +++++--- .../notebook/addedit/AddEditNoteScreen.kt | 13 ++---- .../notification/NotificationScreen.kt | 8 ---- .../features/skillspace/SkillspaceScreen.kt | 9 ++++- .../organisms/scaffolds/HorizonScaffold.kt | 2 + .../organisms/topappbar/HorizonTopAppBar.kt | 3 ++ .../horizon/navigation/HorizonNavigation.kt | 2 + libs/horizon/src/main/res/values/styles.xml | 3 ++ 15 files changed, 97 insertions(+), 80 deletions(-) diff --git a/libs/horizon/src/main/java/com/instructure/horizon/HorizonActivity.kt b/libs/horizon/src/main/java/com/instructure/horizon/HorizonActivity.kt index 9d8dbf869c..5ccdf69d7c 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/HorizonActivity.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/HorizonActivity.kt @@ -44,11 +44,10 @@ import com.instructure.pandautils.receivers.PushExternalReceiver import com.instructure.pandautils.utils.AppTheme import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.Const +import com.instructure.pandautils.utils.EdgeToEdgeHelper import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.Utils -import com.instructure.pandautils.utils.ViewStyler import com.instructure.pandautils.utils.WebViewAuthenticator -import com.instructure.pandautils.utils.getActivityOrNull import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -62,6 +61,8 @@ class HorizonActivity : BaseCanvasActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + EdgeToEdgeHelper.enableEdgeToEdge(this, lightStatusBar = true, lightNavigationBar = true) + val manager = getSystemService(ShortcutManager::class.java) manager?.removeAllDynamicShortcuts() if (ThemePrefs.appTheme != AppTheme.LIGHT.ordinal) { @@ -71,8 +72,6 @@ class HorizonActivity : BaseCanvasActivity() { setContent { navController = rememberNavController() - val activity = LocalContext.current.getActivityOrNull() - if (activity != null) ViewStyler.setStatusBarColor(activity, ContextCompat.getColor(activity, R.color.surface_pagePrimary)) HorizonTheme { HorizonNavigation(navController) } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt index 7bbb49ab1c..5f6151cd33 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt @@ -21,10 +21,14 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.add +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api @@ -82,7 +86,7 @@ fun AccountScreen( @Composable private fun AccountContentScreen(state: AccountUiState, navController: NavController, onLogout: () -> Unit, switchExperience: () -> Unit) { LazyColumn( - contentPadding = PaddingValues(24.dp) + contentPadding = WindowInsets.statusBars.add(WindowInsets(24.dp, 24.dp, 24.dp, 24.dp)).asPaddingValues() ) { item { Column { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt index 57b515c1d0..e43e9dd27d 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt @@ -26,9 +26,12 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -155,12 +158,14 @@ fun DashboardScreen(uiState: DashboardUiState, mainNavController: NavHostControl modifier = Modifier.padding(paddingValues), headerContent = { Column( - modifier = Modifier.conditional(scrollState.canScrollBackward) { - shadow( - elevation = HorizonElevation.level3, - spotColor = Color.Transparent, - ) - } + modifier = Modifier + .windowInsetsPadding(WindowInsets.statusBars) + .conditional(scrollState.canScrollBackward) { + shadow( + elevation = HorizonElevation.level3, + spotColor = Color.Transparent, + ) + } ) { HomeScreenTopBar( uiState, @@ -245,7 +250,8 @@ private fun HomeScreenTopBar(uiState: DashboardUiState, mainNavController: NavCo ) { Row( verticalAlignment = Alignment.Bottom, - modifier = modifier.padding(horizontal = 24.dp) + modifier = modifier + .padding(horizontal = 24.dp) ) { GlideImage( model = uiState.logoUrl, diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/home/HomeScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/home/HomeScreen.kt index 8c3e4be2a5..7150767f21 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/home/HomeScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/home/HomeScreen.kt @@ -20,9 +20,12 @@ package com.instructure.horizon.features.home import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredSize +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.NavigationBar import androidx.compose.material3.Scaffold @@ -36,7 +39,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.NavDestination @@ -54,7 +56,6 @@ import com.instructure.horizon.horizonui.molecules.IconButtonColor import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.horizonui.organisms.navelements.SelectableNavigationItem import com.instructure.pandautils.utils.ThemePrefs -import com.instructure.pandautils.utils.ViewStyler import com.instructure.pandautils.utils.getActivityOrNull data class BottomNavItem( @@ -84,26 +85,30 @@ fun HomeScreen(parentNavController: NavHostController, viewModel: HomeViewModel) val navBackStackEntry by navController.currentBackStackEntryAsState() val currentDestination = navBackStackEntry?.destination val activity = LocalContext.current.getActivityOrNull() - if (activity != null) ViewStyler.setStatusBarColor(activity, ContextCompat.getColor(activity, R.color.surface_pagePrimary)) LaunchedEffect(key1 = uiState.theme) { val theme = uiState.theme if (theme != null && activity != null && !ThemePrefs.isThemeApplied) ThemePrefs.applyCanvasTheme(theme, activity) } - Scaffold(content = { padding -> - if (uiState.initialDataLoading) { - val spinnerColor = - if (ThemePrefs.isThemeApplied) HorizonColors.Surface.institution() else HorizonColors.Surface.inverseSecondary() - Spinner(modifier = Modifier.fillMaxSize(), color = spinnerColor) - } else { - if (uiState.showAiAssist) { - AiAssistantScreen({ uiState.updateShowAiAssist(false) }) + Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), + content = { padding -> + if (uiState.initialDataLoading) { + val spinnerColor = + if (ThemePrefs.isThemeApplied) HorizonColors.Surface.institution() else HorizonColors.Surface.inverseSecondary() + Spinner(modifier = Modifier.fillMaxSize(), color = spinnerColor) + } else { + if (uiState.showAiAssist) { + AiAssistantScreen({ uiState.updateShowAiAssist(false) }) + } + HomeNavigation(navController, parentNavController, Modifier.padding(padding)) } - HomeNavigation(navController, parentNavController, Modifier.padding(padding)) + }, + containerColor = HorizonColors.Surface.pagePrimary(), + bottomBar = { + BottomNavigationBar(navController, currentDestination, !uiState.initialDataLoading, { uiState.updateShowAiAssist(it) }) } - }, containerColor = HorizonColors.Surface.pagePrimary(), bottomBar = { - BottomNavigationBar(navController, currentDestination, !uiState.initialDataLoading, { uiState.updateShowAiAssist(it) }) - }) + ) } @Composable @@ -115,7 +120,10 @@ private fun BottomNavigationBar( modifier: Modifier = Modifier ) { Surface(shadowElevation = HorizonElevation.level5) { - NavigationBar(containerColor = HorizonColors.Surface.pageSecondary(), modifier = modifier) { + NavigationBar( + containerColor = HorizonColors.Surface.pageSecondary(), + modifier = modifier.windowInsetsPadding(WindowInsets.navigationBars) + ) { bottomNavItems.forEach { item -> val selected = currentDestination?.hierarchy?.any { it.route == item.route } == true if (item.route == null) { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt index 47fc1f97e3..9408c9c274 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt @@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -51,7 +52,6 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.instructure.canvasapi2.utils.ContextKeeper @@ -90,8 +90,6 @@ import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextAreaState import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextField import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextFieldInputSize import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextFieldState -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.getActivityOrNull @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -109,14 +107,9 @@ fun HorizonInboxComposeScreen( } } } - val activity = LocalContext.current.getActivityOrNull() - LaunchedEffect(Unit) { - if (activity != null) { - ViewStyler.setStatusBarColor(activity, ContextCompat.getColor(activity, R.color.surface_pageSecondary)) - } - } Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, containerColor = HorizonColors.Surface.pageSecondary(), topBar = { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt index ce3e5977c6..0e9b3848a5 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt @@ -20,12 +20,16 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items @@ -53,7 +57,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.instructure.canvasapi2.utils.ContextKeeper @@ -82,8 +85,6 @@ import com.instructure.horizon.horizonui.organisms.inputs.multiselectsearch.Mult import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelect import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelectInputSize import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelectState -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.getActivityOrNull import com.instructure.pandautils.utils.localisedFormat import java.util.Date @@ -101,14 +102,9 @@ fun HorizonInboxListScreen( } } } - val activity = LocalContext.current.getActivityOrNull() - LaunchedEffect(Unit) { - if (activity != null) { - ViewStyler.setStatusBarColor(activity, ContextCompat.getColor(activity, R.color.surface_pagePrimary)) - } - } Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, containerColor = HorizonColors.Surface.pagePrimary(), ) { padding -> @@ -145,7 +141,9 @@ private fun InboxStateWrapper( ) }, content = { - LazyColumn { + LazyColumn( + contentPadding = WindowInsets.statusBars.asPaddingValues() + ) { inboxHeader(state, navController) if (state.loadingState.isLoading) { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt index 89c4de046d..94ff38a0bf 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt @@ -25,10 +25,13 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api @@ -61,7 +64,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController @@ -83,18 +85,10 @@ import com.instructure.horizon.horizonui.organisms.inputs.common.InputDropDownPo import com.instructure.horizon.horizonui.platform.LoadingState import com.instructure.horizon.horizonui.platform.LoadingStateWrapper import com.instructure.pandautils.compose.modifiers.conditional -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.getActivityOrNull import kotlinx.coroutines.delay @Composable fun LearnScreen(state: LearnUiState, mainNavController: NavHostController) { - - val activity = LocalContext.current.getActivityOrNull() - LaunchedEffect(Unit) { - if (activity != null) ViewStyler.setStatusBarColor(activity, ContextCompat.getColor(activity, R.color.surface_pagePrimary)) - } - val snackbarHostState: SnackbarHostState = remember { SnackbarHostState() } LaunchedEffect(state.screenState.snackbarMessage) { @@ -107,6 +101,7 @@ fun LearnScreen(state: LearnUiState, mainNavController: NavHostController) { } Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), containerColor = HorizonColors.Surface.pagePrimary(), snackbarHost = { SnackbarHost(snackbarHostState) } ) { padding -> @@ -186,7 +181,11 @@ private fun LearnScreenWrapper( modifier = modifier .fillMaxSize() ) { - Column(modifier = Modifier.padding(top = 16.dp)) { + Column( + modifier = Modifier + .windowInsetsPadding(WindowInsets.statusBars) + .padding(top = 16.dp) + ) { val selectedLearningItem = state.selectedLearningItem AnimatedContent(selectedLearningItem) { selectedItem -> selectedItem?.parentItem?.let { parentItem -> diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt index a526ca2f46..8f9b1106cc 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt @@ -29,10 +29,14 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PageSize @@ -126,21 +130,18 @@ import com.instructure.horizon.navigation.MainNavigationRoute import com.instructure.pandautils.compose.modifiers.conditional import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ThemePrefs -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.getActivityOrNull import com.instructure.pandautils.utils.orDefault import kotlinx.coroutines.launch import kotlin.math.abs @Composable fun ModuleItemSequenceScreen(mainNavController: NavHostController, uiState: ModuleItemSequenceUiState) { - val activity = LocalContext.current.getActivityOrNull() - if (activity != null) ViewStyler.setStatusBarColor(activity, ThemePrefs.brandColor, true) if (uiState.progressScreenState.visible) ProgressScreen(uiState.progressScreenState, uiState.loadingState) val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), containerColor = HorizonColors.Surface.institution(), snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, bottomBar = { @@ -271,6 +272,7 @@ private fun ModuleItemSequenceContent( ModuleHeaderContainer( uiState = uiState, modifier = Modifier + .windowInsetsPadding(WindowInsets.statusBars) .padding(start = 24.dp, end = 24.dp, top = 16.dp, bottom = 24.dp) .wrapContentHeight(), onBackPressed = onBackPressed @@ -546,7 +548,11 @@ private fun ModuleItemSequenceBottomBar( onNotebookClick: () -> Unit = {}, hasUnreadComments: Boolean = false ) { - Surface(shadowElevation = HorizonElevation.level4, color = HorizonColors.Surface.pagePrimary()) { + Surface( + shadowElevation = HorizonElevation.level4, + color = HorizonColors.Surface.pagePrimary(), + modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars) + ) { Box( modifier = modifier .fillMaxWidth() diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/addedit/AddEditNoteScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/addedit/AddEditNoteScreen.kt index 4efc360ecf..3a2b1cba69 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/addedit/AddEditNoteScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/addedit/AddEditNoteScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState @@ -35,8 +36,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController import com.instructure.canvasapi2.managers.graphql.horizon.redwood.NoteHighlightedData import com.instructure.canvasapi2.managers.graphql.horizon.redwood.NoteHighlightedDataRange import com.instructure.canvasapi2.managers.graphql.horizon.redwood.NoteHighlightedDataTextPosition @@ -59,8 +60,6 @@ import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.horizonui.organisms.inputs.common.InputLabelRequired import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextArea import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextAreaState -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.getActivityOrNull @Composable fun AddEditNoteScreen( @@ -68,16 +67,12 @@ fun AddEditNoteScreen( state: AddEditNoteUiState, onShowSnackbar: (String?, () -> Unit) -> Unit ) { - val activity = LocalContext.current.getActivityOrNull() - LaunchedEffect(Unit) { - if (activity != null) ViewStyler.setStatusBarColor(activity, ContextCompat.getColor(activity, R.color.surface_pagePrimary)) - } - LaunchedEffect(state.snackbarMessage) { onShowSnackbar(state.snackbarMessage, state.onSnackbarDismiss) } Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), containerColor = HorizonColors.Surface.pagePrimary(), topBar = { NotebookAppBar(navigateBack = { navController.popBackStack() }) }, ) { padding -> @@ -212,7 +207,7 @@ private fun AddEditNoteScreenPreview() { ) AddEditNoteScreen( - navController = NavHostController(LocalContext.current), + navController = rememberNavController(), state = state, onShowSnackbar = { _, _ -> } ) diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/notification/NotificationScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/notification/NotificationScreen.kt index 8c27503c8a..555c21adef 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/notification/NotificationScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/notification/NotificationScreen.kt @@ -33,7 +33,6 @@ import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment @@ -44,7 +43,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat import androidx.core.net.toUri import androidx.navigation.NavDeepLinkRequest import androidx.navigation.NavHostController @@ -66,8 +64,6 @@ import com.instructure.horizon.horizonui.molecules.StatusChipState import com.instructure.horizon.horizonui.organisms.scaffolds.HorizonScaffold import com.instructure.horizon.horizonui.platform.LoadingState import com.instructure.horizon.horizonui.platform.LoadingStateWrapper -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.getActivityOrNull import com.instructure.pandautils.utils.isPreviousDay import com.instructure.pandautils.utils.isSameDay import com.instructure.pandautils.utils.isSameWeek @@ -81,12 +77,8 @@ import java.util.Locale @OptIn(ExperimentalMaterial3Api::class) @Composable fun NotificationScreen(state: NotificationUiState, mainNavController: NavHostController) { - val activity = LocalContext.current.getActivityOrNull() val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() - LaunchedEffect(Unit) { - if (activity != null) ViewStyler.setStatusBarColor(activity, ContextCompat.getColor(activity, R.color.surface_pagePrimary)) - } HorizonScaffold( title = stringResource(R.string.notificationsTitle), diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/skillspace/SkillspaceScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/skillspace/SkillspaceScreen.kt index 8bd034e0f9..4d82d6fc59 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/skillspace/SkillspaceScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/skillspace/SkillspaceScreen.kt @@ -21,7 +21,10 @@ import android.view.ViewGroup import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -52,7 +55,11 @@ fun SkillspaceScreen(state: SkillspaceUiState) { webView?.handleOnActivityResult(request, result.resultCode, result.data) } - Box(modifier = Modifier.fillMaxSize()) { + Box( + modifier = Modifier + .fillMaxSize() + .windowInsetsPadding(WindowInsets.statusBars) + ) { LoadingStateWrapper(state.loadingState) { state.webviewUrl?.let { ComposeCanvasWebView( diff --git a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt index 814f47b373..670f0a5ce1 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt @@ -19,6 +19,7 @@ package com.instructure.horizon.horizonui.organisms.scaffolds import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold @@ -40,6 +41,7 @@ fun HorizonScaffold( content: @Composable (Modifier) -> Unit, ) { Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), topBar = { HorizonTopAppBar(title, onBackPressed) }, snackbarHost = snackbarHost, contentColor = HorizonColors.Surface.pagePrimary() diff --git a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/topappbar/HorizonTopAppBar.kt b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/topappbar/HorizonTopAppBar.kt index ba3f194914..8cf8cdbe57 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/topappbar/HorizonTopAppBar.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/topappbar/HorizonTopAppBar.kt @@ -18,8 +18,10 @@ package com.instructure.horizon.horizonui.organisms.topappbar import androidx.compose.foundation.background import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -71,6 +73,7 @@ fun HorizonTopAppBar( titleContentColor = HorizonColors.Text.title(), navigationIconContentColor = HorizonColors.Icon.default() ), + windowInsets = WindowInsets.statusBars, ) } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt b/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt index b573a35e8d..7a08d20180 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt @@ -15,6 +15,7 @@ */ package com.instructure.horizon.navigation +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost @@ -87,6 +88,7 @@ fun HorizonNavigation(navController: NavHostController, modifier: Modifier = Mod val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ) { innerPadding -> NavHost( diff --git a/libs/horizon/src/main/res/values/styles.xml b/libs/horizon/src/main/res/values/styles.xml index b4a36a96cf..74718e8c64 100644 --- a/libs/horizon/src/main/res/values/styles.xml +++ b/libs/horizon/src/main/res/values/styles.xml @@ -17,5 +17,8 @@ --> \ No newline at end of file From 3de6ef5ca00ff0765d6b809f4703f64ec7131c2b Mon Sep 17 00:00:00 2001 From: domonkosadam Date: Fri, 7 Nov 2025 16:01:12 +0100 Subject: [PATCH 2/5] Fix edge to edge --- .../horizon/features/account/AccountScreen.kt | 5 +- .../features/aiassistant/AiAssistantScreen.kt | 3 ++ .../features/dashboard/DashboardScreen.kt | 17 +++--- .../horizon/features/home/HomeScreen.kt | 9 +++- .../compose/HorizonInboxComposeScreen.kt | 3 +- .../details/HorizonInboxDetailsScreen.kt | 20 +++++-- .../inbox/list/HorizonInboxListScreen.kt | 9 ++-- .../horizon/features/learn/LearnScreen.kt | 6 +-- .../learn/course/CourseDetailsScreen.kt | 2 + .../ModuleItemSequenceScreen.kt | 7 ++- .../features/notebook/NotebookScreen.kt | 9 +++- .../features/skillspace/SkillspaceScreen.kt | 4 +- .../organisms/scaffolds/HorizonScaffold.kt | 3 +- .../organisms/topappbar/HorizonTopAppBar.kt | 3 -- .../horizonui/platform/LoadingStateWrapper.kt | 8 ++- .../horizon/navigation/HorizonNavigation.kt | 3 +- .../horizon/util/HorizonEdgeToEdgeHelper.kt | 52 +++++++++++++++++++ 17 files changed, 117 insertions(+), 46 deletions(-) create mode 100644 libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt index 5f6151cd33..fc0dd75f0c 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt @@ -18,7 +18,6 @@ package com.instructure.horizon.features.account import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets @@ -27,8 +26,8 @@ import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api @@ -86,7 +85,7 @@ fun AccountScreen( @Composable private fun AccountContentScreen(state: AccountUiState, navController: NavController, onLogout: () -> Unit, switchExperience: () -> Unit) { LazyColumn( - contentPadding = WindowInsets.statusBars.add(WindowInsets(24.dp, 24.dp, 24.dp, 24.dp)).asPaddingValues() + contentPadding = WindowInsets.safeDrawing.add(WindowInsets(24.dp, 24.dp, 24.dp, 24.dp)).asPaddingValues() ) { item { Column { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/AiAssistantScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/AiAssistantScreen.kt index a02b39286f..5274c0535a 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/AiAssistantScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/AiAssistantScreen.kt @@ -17,6 +17,7 @@ package com.instructure.horizon.features.aiassistant import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet @@ -28,6 +29,7 @@ import androidx.navigation.compose.rememberNavController import com.instructure.horizon.R import com.instructure.horizon.features.aiassistant.navigation.AiAssistNavigation import com.instructure.horizon.horizonui.foundation.HorizonColors +import com.instructure.horizon.util.zeroScreenInsets @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -41,6 +43,7 @@ fun AiAssistantScreen( onDismissRequest = { onDismiss() }, dragHandle = null, sheetState = bottomSheetState, + contentWindowInsets = { WindowInsets.zeroScreenInsets } ) { Box( modifier = Modifier diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt index e43e9dd27d..14ac4062fd 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt @@ -30,7 +30,6 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.rememberScrollState @@ -53,8 +52,6 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -87,7 +84,9 @@ import com.instructure.horizon.horizonui.molecules.IconButtonColor import com.instructure.horizon.horizonui.organisms.AnimatedHorizontalPager import com.instructure.horizon.horizonui.organisms.CollapsableHeaderScreen import com.instructure.horizon.navigation.MainNavigationRoute -import com.instructure.pandautils.compose.modifiers.conditional +import com.instructure.horizon.util.horizontalSafeDrawing +import com.instructure.horizon.util.verticalSafeDrawing +import com.instructure.horizon.util.zeroScreenInsets import kotlinx.coroutines.flow.MutableStateFlow @Composable @@ -132,6 +131,7 @@ fun DashboardScreen(uiState: DashboardUiState, mainNavController: NavHostControl } Scaffold( + contentWindowInsets = WindowInsets.zeroScreenInsets, containerColor = HorizonColors.Surface.pagePrimary(), snackbarHost = { SnackbarHost(snackbarHostState) } ) { paddingValues -> @@ -159,13 +159,7 @@ fun DashboardScreen(uiState: DashboardUiState, mainNavController: NavHostControl headerContent = { Column( modifier = Modifier - .windowInsetsPadding(WindowInsets.statusBars) - .conditional(scrollState.canScrollBackward) { - shadow( - elevation = HorizonElevation.level3, - spotColor = Color.Transparent, - ) - } + .windowInsetsPadding(WindowInsets.verticalSafeDrawing) ) { HomeScreenTopBar( uiState, @@ -180,6 +174,7 @@ fun DashboardScreen(uiState: DashboardUiState, mainNavController: NavHostControl Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier + .windowInsetsPadding(WindowInsets.horizontalSafeDrawing) .verticalScroll(scrollState) ) { HorizonSpace(SpaceSize.SPACE_12) diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/home/HomeScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/home/HomeScreen.kt index 7150767f21..f0a51f7b25 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/home/HomeScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/home/HomeScreen.kt @@ -55,6 +55,7 @@ import com.instructure.horizon.horizonui.molecules.IconButton import com.instructure.horizon.horizonui.molecules.IconButtonColor import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.horizonui.organisms.navelements.SelectableNavigationItem +import com.instructure.horizon.util.zeroScreenInsets import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.getActivityOrNull @@ -91,7 +92,7 @@ fun HomeScreen(parentNavController: NavHostController, viewModel: HomeViewModel) if (theme != null && activity != null && !ThemePrefs.isThemeApplied) ThemePrefs.applyCanvasTheme(theme, activity) } Scaffold( - contentWindowInsets = WindowInsets(0, 0, 0, 0), + contentWindowInsets = WindowInsets.zeroScreenInsets, content = { padding -> if (uiState.initialDataLoading) { val spinnerColor = @@ -119,8 +120,12 @@ private fun BottomNavigationBar( updateShowAiAssist: (Boolean) -> Unit, modifier: Modifier = Modifier ) { - Surface(shadowElevation = HorizonElevation.level5) { + Surface( + shadowElevation = HorizonElevation.level5, + color = HorizonColors.Surface.pageSecondary() + ) { NavigationBar( + windowInsets = WindowInsets.zeroScreenInsets, containerColor = HorizonColors.Surface.pageSecondary(), modifier = modifier.windowInsetsPadding(WindowInsets.navigationBars) ) { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt index 9408c9c274..97d9e8cff5 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt @@ -90,6 +90,7 @@ import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextAreaState import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextField import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextFieldInputSize import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextFieldState +import com.instructure.horizon.util.topBarScreenInsets @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -109,7 +110,7 @@ fun HorizonInboxComposeScreen( } Scaffold( - contentWindowInsets = WindowInsets(0, 0, 0, 0), + contentWindowInsets = WindowInsets.topBarScreenInsets, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, containerColor = HorizonColors.Surface.pageSecondary(), topBar = { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/details/HorizonInboxDetailsScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/details/HorizonInboxDetailsScreen.kt index b0af64c093..9b8186276f 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/details/HorizonInboxDetailsScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/details/HorizonInboxDetailsScreen.kt @@ -23,9 +23,10 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -81,6 +82,8 @@ import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextArea import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextAreaState import com.instructure.horizon.horizonui.platform.LoadingState import com.instructure.horizon.horizonui.platform.LoadingStateWrapper +import com.instructure.horizon.util.topBarScreenInsets +import com.instructure.horizon.util.zeroScreenInsets import com.instructure.pandautils.compose.composables.ComposeCanvasWebViewWrapper import com.instructure.pandautils.compose.composables.ComposeEmbeddedWebViewCallbacks import com.instructure.pandautils.room.appdatabase.entities.FileDownloadProgressState @@ -98,10 +101,13 @@ fun HorizonInboxDetailsScreen( navController: NavHostController ) { Scaffold( + contentWindowInsets = WindowInsets.zeroScreenInsets, containerColor = HorizonColors.Surface.pagePrimary(), topBar = { HorizonInboxDetailsHeader(state.title, state.titleIcon, state, navController) }, ) { innerPadding -> - LoadingStateWrapper(state.loadingState, modifier = Modifier.padding(innerPadding)) { + LoadingStateWrapper( + state.loadingState, + ) { BackHandler { onExit(state, navController) } state.replyState?.let { replyState -> @@ -131,7 +137,11 @@ fun HorizonInboxDetailsScreen( } } - HorizonInboxDetailsContent(state) + HorizonInboxDetailsContent( + state, + Modifier + .padding(innerPadding) + ) } } } @@ -182,7 +192,7 @@ private fun HorizonInboxDetailsHeader( containerColor = HorizonColors.Surface.pagePrimary(), titleContentColor = HorizonColors.Text.title(), navigationIconContentColor = HorizonColors.Icon.default() - ) + ), ) } @@ -195,6 +205,7 @@ private fun HorizonInboxDetailsContent( Column( modifier = modifier .fillMaxSize() + .padding(WindowInsets.topBarScreenInsets.asPaddingValues()) .clip(HorizonCornerRadius.level4Top) .background(HorizonColors.Surface.pageSecondary()) ) { @@ -203,7 +214,6 @@ private fun HorizonInboxDetailsContent( .fillMaxSize() .background(HorizonColors.Surface.pageSecondary()), reverseLayout = state.bottomLayout, - contentPadding = PaddingValues(top = 16.dp) ) { if (state.replyState != null) { stickyHeader { HorizonInboxReplyContent(state.replyState) } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt index 0e9b3848a5..4e4aa8d49d 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt @@ -20,7 +20,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets @@ -29,7 +28,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items @@ -45,7 +43,6 @@ import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults.Indicator import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -85,6 +82,8 @@ import com.instructure.horizon.horizonui.organisms.inputs.multiselectsearch.Mult import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelect import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelectInputSize import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelectState +import com.instructure.horizon.util.fullScreenInsets +import com.instructure.horizon.util.zeroScreenInsets import com.instructure.pandautils.utils.localisedFormat import java.util.Date @@ -104,7 +103,7 @@ fun HorizonInboxListScreen( } Scaffold( - contentWindowInsets = WindowInsets(0, 0, 0, 0), + contentWindowInsets = WindowInsets.zeroScreenInsets, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, containerColor = HorizonColors.Surface.pagePrimary(), ) { padding -> @@ -142,7 +141,7 @@ private fun InboxStateWrapper( }, content = { LazyColumn( - contentPadding = WindowInsets.statusBars.asPaddingValues() + contentPadding = WindowInsets.fullScreenInsets.asPaddingValues() ) { inboxHeader(state, navController) diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt index 94ff38a0bf..fc622fed0b 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt @@ -30,8 +30,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBars -import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api @@ -84,6 +82,7 @@ import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.horizonui.organisms.inputs.common.InputDropDownPopup import com.instructure.horizon.horizonui.platform.LoadingState import com.instructure.horizon.horizonui.platform.LoadingStateWrapper +import com.instructure.horizon.util.bottomNavigationScreenInsets import com.instructure.pandautils.compose.modifiers.conditional import kotlinx.coroutines.delay @@ -101,7 +100,7 @@ fun LearnScreen(state: LearnUiState, mainNavController: NavHostController) { } Scaffold( - contentWindowInsets = WindowInsets(0, 0, 0, 0), + contentWindowInsets = WindowInsets.bottomNavigationScreenInsets, containerColor = HorizonColors.Surface.pagePrimary(), snackbarHost = { SnackbarHost(snackbarHostState) } ) { padding -> @@ -183,7 +182,6 @@ private fun LearnScreenWrapper( ) { Column( modifier = Modifier - .windowInsetsPadding(WindowInsets.statusBars) .padding(top = 16.dp) ) { val selectedLearningItem = state.selectedLearningItem diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/learn/course/CourseDetailsScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/learn/course/CourseDetailsScreen.kt index 62ed59915a..c693f2ee50 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/learn/course/CourseDetailsScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/learn/course/CourseDetailsScreen.kt @@ -19,6 +19,7 @@ import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager @@ -61,6 +62,7 @@ fun CourseDetailsScreen( val coroutineScope = rememberCoroutineScope() Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), containerColor = HorizonColors.Surface.pagePrimary(), ) { padding -> Column(modifier = Modifier.padding(padding)) { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt index 8f9b1106cc..6a4e0a1724 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt @@ -126,10 +126,9 @@ import com.instructure.horizon.horizonui.molecules.PillType import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.horizonui.molecules.SpinnerSize import com.instructure.horizon.horizonui.platform.LoadingStateWrapper -import com.instructure.horizon.navigation.MainNavigationRoute +import com.instructure.horizon.util.horizontalSafeDrawing import com.instructure.pandautils.compose.modifiers.conditional import com.instructure.pandautils.utils.Const -import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.orDefault import kotlinx.coroutines.launch import kotlin.math.abs @@ -141,7 +140,7 @@ fun ModuleItemSequenceScreen(mainNavController: NavHostController, uiState: Modu val snackbarHostState = remember { SnackbarHostState() } Scaffold( - contentWindowInsets = WindowInsets(0, 0, 0, 0), + contentWindowInsets = WindowInsets.horizontalSafeDrawing, containerColor = HorizonColors.Surface.institution(), snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, bottomBar = { @@ -551,11 +550,11 @@ private fun ModuleItemSequenceBottomBar( Surface( shadowElevation = HorizonElevation.level4, color = HorizonColors.Surface.pagePrimary(), - modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars) ) { Box( modifier = modifier .fillMaxWidth() + .windowInsetsPadding(WindowInsets.navigationBars) .padding(horizontal = 24.dp, vertical = 16.dp) ) { if (showPreviousButton) IconButton( diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/NotebookScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/NotebookScreen.kt index fdf3723dae..79602787ca 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/NotebookScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/NotebookScreen.kt @@ -21,8 +21,10 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.add +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -63,6 +65,8 @@ import com.instructure.horizon.horizonui.molecules.IconButtonColor import com.instructure.horizon.horizonui.molecules.IconButtonSize import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.navigation.MainNavigationRoute +import com.instructure.horizon.util.topBarScreenInsets +import com.instructure.horizon.util.zeroScreenInsets import com.instructure.pandautils.compose.modifiers.conditional import com.instructure.pandautils.utils.localisedFormat import java.util.Date @@ -76,6 +80,7 @@ fun NotebookScreen( ) { val scrollState = rememberLazyListState() Scaffold( + contentWindowInsets = WindowInsets.zeroScreenInsets, containerColor = HorizonColors.Surface.pagePrimary(), topBar = { if (state.showTopBar) { @@ -103,7 +108,7 @@ fun NotebookScreen( state = scrollState, modifier = Modifier .padding(padding), - contentPadding = PaddingValues(24.dp) + contentPadding = WindowInsets.topBarScreenInsets.add(WindowInsets(24.dp, 24.dp, 24.dp, 24.dp)).asPaddingValues() ) { if (state.showFilters && state.notes.isNotEmpty()) { item { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/skillspace/SkillspaceScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/skillspace/SkillspaceScreen.kt index 4d82d6fc59..3cd68af335 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/skillspace/SkillspaceScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/skillspace/SkillspaceScreen.kt @@ -23,7 +23,6 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable @@ -35,6 +34,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import com.instructure.horizon.horizonui.platform.LoadingStateWrapper +import com.instructure.horizon.util.bottomNavigationScreenInsets import com.instructure.pandautils.compose.composables.ComposeCanvasWebView import com.instructure.pandautils.compose.composables.ComposeEmbeddedWebViewCallbacks import com.instructure.pandautils.utils.ThemePrefs @@ -58,7 +58,7 @@ fun SkillspaceScreen(state: SkillspaceUiState) { Box( modifier = Modifier .fillMaxSize() - .windowInsetsPadding(WindowInsets.statusBars) + .windowInsetsPadding(WindowInsets.bottomNavigationScreenInsets) ) { LoadingStateWrapper(state.loadingState) { state.webviewUrl?.let { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt index 670f0a5ce1..6127f2336a 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt @@ -19,7 +19,6 @@ package com.instructure.horizon.horizonui.organisms.scaffolds import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold @@ -41,7 +40,7 @@ fun HorizonScaffold( content: @Composable (Modifier) -> Unit, ) { Scaffold( - contentWindowInsets = WindowInsets(0, 0, 0, 0), +// contentWindowInsets = WindowInsets.safeDrawing, topBar = { HorizonTopAppBar(title, onBackPressed) }, snackbarHost = snackbarHost, contentColor = HorizonColors.Surface.pagePrimary() diff --git a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/topappbar/HorizonTopAppBar.kt b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/topappbar/HorizonTopAppBar.kt index 8cf8cdbe57..ba3f194914 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/topappbar/HorizonTopAppBar.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/topappbar/HorizonTopAppBar.kt @@ -18,10 +18,8 @@ package com.instructure.horizon.horizonui.organisms.topappbar import androidx.compose.foundation.background import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBars import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -73,7 +71,6 @@ fun HorizonTopAppBar( titleContentColor = HorizonColors.Text.title(), navigationIconContentColor = HorizonColors.Icon.default() ), - windowInsets = WindowInsets.statusBars, ) } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/platform/LoadingStateWrapper.kt b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/platform/LoadingStateWrapper.kt index 5796539765..6c1572c007 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/platform/LoadingStateWrapper.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/platform/LoadingStateWrapper.kt @@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState @@ -77,7 +78,12 @@ fun LoadingStateWrapper( } } - Scaffold(containerColor = containerColor, snackbarHost = { SnackbarHost(snackbarHostState) }, modifier = modifier) { paddingValues -> + Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), + containerColor = containerColor, + snackbarHost = { SnackbarHost(snackbarHostState) }, + modifier = modifier + ) { paddingValues -> if (loadingState.isPullToRefreshEnabled) { PullToRefreshBox( isRefreshing = loadingState.isRefreshing, diff --git a/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt b/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt index 7a08d20180..9444fdc9e7 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt @@ -52,6 +52,7 @@ import com.instructure.horizon.navigation.MainNavigationRoute.Companion.ASSIGNME import com.instructure.horizon.navigation.MainNavigationRoute.Companion.COURSE_ID import com.instructure.horizon.navigation.MainNavigationRoute.Companion.PAGE_ID import com.instructure.horizon.navigation.MainNavigationRoute.Companion.QUIZ_ID +import com.instructure.horizon.util.zeroScreenInsets import kotlinx.coroutines.launch import kotlinx.serialization.Serializable @@ -88,7 +89,7 @@ fun HorizonNavigation(navController: NavHostController, modifier: Modifier = Mod val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } Scaffold( - contentWindowInsets = WindowInsets(0, 0, 0, 0), + contentWindowInsets = WindowInsets.zeroScreenInsets, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ) { innerPadding -> NavHost( diff --git a/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt b/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt new file mode 100644 index 0000000000..3006b0db1f --- /dev/null +++ b/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2025 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.horizon.util + +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.runtime.Composable + +val WindowInsetsSides.Companion.BottomHorizontalSides: WindowInsetsSides + get() = WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + +val WindowInsetsSides.Companion.TopHorizontalSides: WindowInsetsSides + get() = WindowInsetsSides.Horizontal + WindowInsetsSides.Top + +val WindowInsets.Companion.zeroScreenInsets: WindowInsets + get() = WindowInsets(0, 0, 0, 0) + +val WindowInsets.Companion.bottomNavigationScreenInsets: WindowInsets + @Composable + get() = WindowInsets.safeDrawing.only(WindowInsetsSides.TopHorizontalSides) + +val WindowInsets.Companion.topBarScreenInsets: WindowInsets + @Composable + get() = WindowInsets.safeDrawing.only(WindowInsetsSides.BottomHorizontalSides) + +val WindowInsets.Companion.horizontalSafeDrawing: WindowInsets + @Composable + get() = WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal) + +val WindowInsets.Companion.verticalSafeDrawing: WindowInsets + @Composable + get() = WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical) + +val WindowInsets.Companion.fullScreenInsets: WindowInsets + @Composable + get() = WindowInsets.safeDrawing From e07d253978436dc639dbcf6a63fd94a83e5d9fd7 Mon Sep 17 00:00:00 2001 From: domonkosadam Date: Fri, 7 Nov 2025 16:16:57 +0100 Subject: [PATCH 3/5] Fixes --- .../features/aiassistant/AiAssistantScreen.kt | 6 +++--- .../horizon/features/dashboard/DashboardScreen.kt | 4 ++-- .../horizon/util/HorizonEdgeToEdgeHelper.kt | 12 ++++++++++-- libs/horizon/src/main/res/values/styles.xml | 3 --- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/AiAssistantScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/AiAssistantScreen.kt index 5274c0535a..534e157109 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/AiAssistantScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/AiAssistantScreen.kt @@ -29,7 +29,7 @@ import androidx.navigation.compose.rememberNavController import com.instructure.horizon.R import com.instructure.horizon.features.aiassistant.navigation.AiAssistNavigation import com.instructure.horizon.horizonui.foundation.HorizonColors -import com.instructure.horizon.util.zeroScreenInsets +import com.instructure.horizon.util.bottomSafeDrawing @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -39,11 +39,11 @@ fun AiAssistantScreen( val navController = rememberNavController() val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) ModalBottomSheet( - containerColor = colorResource(R.color.ai_gradient_start), + containerColor = colorResource(R.color.ai_gradient_end), onDismissRequest = { onDismiss() }, dragHandle = null, sheetState = bottomSheetState, - contentWindowInsets = { WindowInsets.zeroScreenInsets } + contentWindowInsets = { WindowInsets.bottomSafeDrawing } ) { Box( modifier = Modifier diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt index 14ac4062fd..a03f0a70ea 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt @@ -85,7 +85,7 @@ import com.instructure.horizon.horizonui.organisms.AnimatedHorizontalPager import com.instructure.horizon.horizonui.organisms.CollapsableHeaderScreen import com.instructure.horizon.navigation.MainNavigationRoute import com.instructure.horizon.util.horizontalSafeDrawing -import com.instructure.horizon.util.verticalSafeDrawing +import com.instructure.horizon.util.topSafeDrawing import com.instructure.horizon.util.zeroScreenInsets import kotlinx.coroutines.flow.MutableStateFlow @@ -159,7 +159,7 @@ fun DashboardScreen(uiState: DashboardUiState, mainNavController: NavHostControl headerContent = { Column( modifier = Modifier - .windowInsetsPadding(WindowInsets.verticalSafeDrawing) + .windowInsetsPadding(WindowInsets.topSafeDrawing) ) { HomeScreenTopBar( uiState, diff --git a/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt b/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt index 3006b0db1f..a7b929542f 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt @@ -22,10 +22,10 @@ import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.safeDrawing import androidx.compose.runtime.Composable -val WindowInsetsSides.Companion.BottomHorizontalSides: WindowInsetsSides +private val WindowInsetsSides.Companion.BottomHorizontalSides: WindowInsetsSides get() = WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom -val WindowInsetsSides.Companion.TopHorizontalSides: WindowInsetsSides +private val WindowInsetsSides.Companion.TopHorizontalSides: WindowInsetsSides get() = WindowInsetsSides.Horizontal + WindowInsetsSides.Top val WindowInsets.Companion.zeroScreenInsets: WindowInsets @@ -47,6 +47,14 @@ val WindowInsets.Companion.verticalSafeDrawing: WindowInsets @Composable get() = WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical) +val WindowInsets.Companion.topSafeDrawing: WindowInsets + @Composable + get() = WindowInsets.safeDrawing.only(WindowInsetsSides.Top) + +val WindowInsets.Companion.bottomSafeDrawing: WindowInsets + @Composable + get() = WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom) + val WindowInsets.Companion.fullScreenInsets: WindowInsets @Composable get() = WindowInsets.safeDrawing diff --git a/libs/horizon/src/main/res/values/styles.xml b/libs/horizon/src/main/res/values/styles.xml index 74718e8c64..b4a36a96cf 100644 --- a/libs/horizon/src/main/res/values/styles.xml +++ b/libs/horizon/src/main/res/values/styles.xml @@ -17,8 +17,5 @@ --> \ No newline at end of file From 47a8af373a47e76d03a37d664d44ad0eec6767a4 Mon Sep 17 00:00:00 2001 From: domonkosadam Date: Mon, 10 Nov 2025 09:59:41 +0100 Subject: [PATCH 4/5] Fix system bar colors --- .../instructure/horizon/HorizonActivity.kt | 13 +- .../horizon/features/account/AccountScreen.kt | 7 +- .../features/dashboard/DashboardScreen.kt | 206 +++++++++--------- .../compose/HorizonInboxComposeScreen.kt | 71 +++--- .../details/HorizonInboxDetailsScreen.kt | 88 ++++---- .../inbox/list/HorizonInboxListScreen.kt | 26 ++- .../horizon/features/learn/LearnScreen.kt | 45 ++-- .../ModuleItemSequenceScreen.kt | 109 +++++---- .../features/notebook/NotebookScreen.kt | 169 +++++++------- .../notification/NotificationScreen.kt | 34 +-- .../organisms/scaffolds/HorizonScaffold.kt | 1 - .../horizon/navigation/HorizonNavigation.kt | 23 +- .../horizon/util/HorizonEdgeToEdgeHelper.kt | 43 ++++ 13 files changed, 482 insertions(+), 353 deletions(-) diff --git a/libs/horizon/src/main/java/com/instructure/horizon/HorizonActivity.kt b/libs/horizon/src/main/java/com/instructure/horizon/HorizonActivity.kt index 5ccdf69d7c..27c30c27f3 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/HorizonActivity.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/HorizonActivity.kt @@ -19,15 +19,17 @@ import android.content.Intent import android.content.pm.ShortcutManager import android.content.res.Configuration import android.os.Bundle +import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatDelegate import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.LocalContext -import androidx.core.content.ContextCompat +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb import androidx.core.net.toUri import androidx.lifecycle.lifecycleScope import androidx.navigation.NavDeepLinkRequest @@ -44,7 +46,6 @@ import com.instructure.pandautils.receivers.PushExternalReceiver import com.instructure.pandautils.utils.AppTheme import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.Const -import com.instructure.pandautils.utils.EdgeToEdgeHelper import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.Utils import com.instructure.pandautils.utils.WebViewAuthenticator @@ -61,13 +62,15 @@ class HorizonActivity : BaseCanvasActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - EdgeToEdgeHelper.enableEdgeToEdge(this, lightStatusBar = true, lightNavigationBar = true) - val manager = getSystemService(ShortcutManager::class.java) manager?.removeAllDynamicShortcuts() if (ThemePrefs.appTheme != AppTheme.LIGHT.ordinal) { setLightTheme() // Force the light theme for Horizon experience to avoid any glitches. } + enableEdgeToEdge( + statusBarStyle = SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb()), + navigationBarStyle = SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb()) + ) setContent { navController = rememberNavController() diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt index fc0dd75f0c..b4813820a3 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/account/AccountScreen.kt @@ -51,6 +51,7 @@ import com.instructure.horizon.horizonui.foundation.HorizonTypography import com.instructure.horizon.horizonui.foundation.SpaceSize import com.instructure.horizon.horizonui.molecules.HorizonDivider import com.instructure.horizon.horizonui.platform.LoadingStateWrapper +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars import com.instructure.pandautils.utils.LocaleUtils import com.instructure.pandautils.utils.getActivityOrNull @@ -78,7 +79,11 @@ fun AccountScreen( } LoadingStateWrapper(state.screenState) { - AccountContentScreen(state, navController, state.performLogout, state.switchExperience) + HorizonEdgeToEdgeSystemBars( + statusBarColor = HorizonColors.Surface.pagePrimary(), + ) { + AccountContentScreen(state, navController, state.performLogout, state.switchExperience) + } } } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt index a03f0a70ea..77cf3f5022 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/dashboard/DashboardScreen.kt @@ -84,8 +84,9 @@ import com.instructure.horizon.horizonui.molecules.IconButtonColor import com.instructure.horizon.horizonui.organisms.AnimatedHorizontalPager import com.instructure.horizon.horizonui.organisms.CollapsableHeaderScreen import com.instructure.horizon.navigation.MainNavigationRoute +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars +import com.instructure.horizon.util.bottomNavigationScreenInsets import com.instructure.horizon.util.horizontalSafeDrawing -import com.instructure.horizon.util.topSafeDrawing import com.instructure.horizon.util.zeroScreenInsets import kotlinx.coroutines.flow.MutableStateFlow @@ -130,112 +131,117 @@ fun DashboardScreen(uiState: DashboardUiState, mainNavController: NavHostControl } } - Scaffold( - contentWindowInsets = WindowInsets.zeroScreenInsets, - containerColor = HorizonColors.Surface.pagePrimary(), - snackbarHost = { SnackbarHost(snackbarHostState) } - ) { paddingValues -> - val pullToRefreshState = rememberPullToRefreshState() - val isRefreshing = refreshState.any { it } - PullToRefreshBox( - isRefreshing = isRefreshing, - onRefresh = { shouldRefresh = true }, - state = pullToRefreshState, - indicator = { - Indicator( - modifier = Modifier - .align(Alignment.TopCenter) - .padding(top = 56.dp), - isRefreshing = isRefreshing, - containerColor = HorizonColors.Surface.pageSecondary(), - color = HorizonColors.Surface.institution(), - state = pullToRefreshState - ) - } - ){ - val scrollState = rememberScrollState() - CollapsableHeaderScreen( - modifier = Modifier.padding(paddingValues), - headerContent = { - Column( + HorizonEdgeToEdgeSystemBars { + Scaffold( + contentWindowInsets = WindowInsets.zeroScreenInsets, + containerColor = HorizonColors.Surface.pagePrimary(), + snackbarHost = { SnackbarHost(snackbarHostState) } + ) { paddingValues -> + val pullToRefreshState = rememberPullToRefreshState() + val isRefreshing = refreshState.any { it } + PullToRefreshBox( + isRefreshing = isRefreshing, + onRefresh = { shouldRefresh = true }, + state = pullToRefreshState, + indicator = { + Indicator( modifier = Modifier - .windowInsetsPadding(WindowInsets.topSafeDrawing) - ) { - HomeScreenTopBar( - uiState, - mainNavController, + .align(Alignment.TopCenter) + .padding(top = 56.dp), + isRefreshing = isRefreshing, + containerColor = HorizonColors.Surface.pageSecondary(), + color = HorizonColors.Surface.institution(), + state = pullToRefreshState + ) + } + ) { + val scrollState = rememberScrollState() + CollapsableHeaderScreen( + modifier = Modifier.padding(paddingValues), + headerContent = { + Column( modifier = Modifier - .height(56.dp) - .padding(bottom = 12.dp) - ) - } - }, - bodyContent = { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .windowInsetsPadding(WindowInsets.horizontalSafeDrawing) - .verticalScroll(scrollState) - ) { - HorizonSpace(SpaceSize.SPACE_12) - DashboardAnnouncementBannerWidget( - mainNavController, - homeNavController, - shouldRefresh, - refreshStateFlow - ) - DashboardCourseSection( - mainNavController, - homeNavController, - shouldRefresh, - refreshStateFlow - ) - HorizonSpace(SpaceSize.SPACE_16) - val pagerState = rememberPagerState{ 3 } - AnimatedHorizontalPager( - pagerState, - sizeAnimationRange = 0f, - contentPadding = PaddingValues(horizontal = 24.dp), - pageSpacing = 12.dp, - verticalAlignment = Alignment.CenterVertically, - ) { index, modifier -> - when (index) { - 0 -> { - DashboardMyProgressWidget( - shouldRefresh, - refreshStateFlow, - modifier.padding(bottom = 16.dp) - ) - } - 1 -> { - DashboardTimeSpentWidget( - shouldRefresh, - refreshStateFlow, - modifier.padding(bottom = 16.dp) - ) - } - 2 -> { - DashboardSkillOverviewWidget( - homeNavController, - shouldRefresh, - refreshStateFlow, - modifier.padding(bottom = 16.dp) - ) - } - else -> { + .windowInsetsPadding(WindowInsets.bottomNavigationScreenInsets) + ) { + HomeScreenTopBar( + uiState, + mainNavController, + modifier = Modifier + .height(56.dp) + .padding(bottom = 12.dp) + ) + } + }, + bodyContent = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .windowInsetsPadding(WindowInsets.horizontalSafeDrawing) + .verticalScroll(scrollState) + ) { + HorizonSpace(SpaceSize.SPACE_12) + DashboardAnnouncementBannerWidget( + mainNavController, + homeNavController, + shouldRefresh, + refreshStateFlow + ) + DashboardCourseSection( + mainNavController, + homeNavController, + shouldRefresh, + refreshStateFlow + ) + HorizonSpace(SpaceSize.SPACE_16) + val pagerState = rememberPagerState { 3 } + AnimatedHorizontalPager( + pagerState, + sizeAnimationRange = 0f, + contentPadding = PaddingValues(horizontal = 24.dp), + pageSpacing = 12.dp, + verticalAlignment = Alignment.CenterVertically, + ) { index, modifier -> + when (index) { + 0 -> { + DashboardMyProgressWidget( + shouldRefresh, + refreshStateFlow, + modifier.padding(bottom = 16.dp) + ) + } + + 1 -> { + DashboardTimeSpentWidget( + shouldRefresh, + refreshStateFlow, + modifier.padding(bottom = 16.dp) + ) + } + + 2 -> { + DashboardSkillOverviewWidget( + homeNavController, + shouldRefresh, + refreshStateFlow, + modifier.padding(bottom = 16.dp) + ) + } + + else -> { + } } } + DashboardSkillHighlightsWidget( + homeNavController, + shouldRefresh, + refreshStateFlow + ) + HorizonSpace(SpaceSize.SPACE_24) } - DashboardSkillHighlightsWidget( - homeNavController, - shouldRefresh, - refreshStateFlow - ) - HorizonSpace(SpaceSize.SPACE_24) } - } - ) + ) + } } } } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt index 97d9e8cff5..43364ebf86 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/compose/HorizonInboxComposeScreen.kt @@ -90,6 +90,7 @@ import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextAreaState import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextField import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextFieldInputSize import com.instructure.horizon.horizonui.organisms.inputs.textfield.TextFieldState +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars import com.instructure.horizon.util.topBarScreenInsets @OptIn(ExperimentalMaterial3Api::class) @@ -109,44 +110,46 @@ fun HorizonInboxComposeScreen( } } - Scaffold( - contentWindowInsets = WindowInsets.topBarScreenInsets, - snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, - containerColor = HorizonColors.Surface.pageSecondary(), - topBar = { - HorizonInboxComposeTopBar(state, navController) - } - ) { innerPadding -> - BackHandler { onExit(state, navController) } - - HorizonInboxAttachmentPicker( - showBottomSheet = state.showAttachmentPicker, - onDismissBottomSheet = { state.onShowAttachmentPickerChanged(false) }, - state = pickerState, - onFilesChanged = state.onAttachmentsChanged - ) + HorizonEdgeToEdgeSystemBars(null, null) { + Scaffold( + contentWindowInsets = WindowInsets.topBarScreenInsets, + snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, + containerColor = HorizonColors.Surface.pageSecondary(), + topBar = { + HorizonInboxComposeTopBar(state, navController) + } + ) { innerPadding -> + BackHandler { onExit(state, navController) } + + HorizonInboxAttachmentPicker( + showBottomSheet = state.showAttachmentPicker, + onDismissBottomSheet = { state.onShowAttachmentPickerChanged(false) }, + state = pickerState, + onFilesChanged = state.onAttachmentsChanged + ) - if (state.showExitConfirmationDialog) { - Modal( - dialogState = ModalDialogState( - title = stringResource(R.string.exitConfirmationTitle), - message = stringResource(R.string.exitConfirmationMessage), - primaryButtonTitle = stringResource(R.string.exitConfirmationExitButtonLabel), - secondaryButtonTitle = stringResource(R.string.exitConfirmationCancelButtonLabel), - primaryButtonClick = { - state.updateShowExitConfirmationDialog(false) - navController.popBackStack() - }, - secondaryButtonClick = { state.updateShowExitConfirmationDialog(false) } + if (state.showExitConfirmationDialog) { + Modal( + dialogState = ModalDialogState( + title = stringResource(R.string.exitConfirmationTitle), + message = stringResource(R.string.exitConfirmationMessage), + primaryButtonTitle = stringResource(R.string.exitConfirmationExitButtonLabel), + secondaryButtonTitle = stringResource(R.string.exitConfirmationCancelButtonLabel), + primaryButtonClick = { + state.updateShowExitConfirmationDialog(false) + navController.popBackStack() + }, + secondaryButtonClick = { state.updateShowExitConfirmationDialog(false) } + ) ) + } + + HorizonInboxComposeContent( + state, + navController, + Modifier.padding(innerPadding) ) } - - HorizonInboxComposeContent( - state, - navController, - Modifier.padding(innerPadding) - ) } } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/details/HorizonInboxDetailsScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/details/HorizonInboxDetailsScreen.kt index 9b8186276f..ac0fdef3aa 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/details/HorizonInboxDetailsScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/details/HorizonInboxDetailsScreen.kt @@ -82,6 +82,7 @@ import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextArea import com.instructure.horizon.horizonui.organisms.inputs.textarea.TextAreaState import com.instructure.horizon.horizonui.platform.LoadingState import com.instructure.horizon.horizonui.platform.LoadingStateWrapper +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars import com.instructure.horizon.util.topBarScreenInsets import com.instructure.horizon.util.zeroScreenInsets import com.instructure.pandautils.compose.composables.ComposeCanvasWebViewWrapper @@ -100,48 +101,61 @@ fun HorizonInboxDetailsScreen( state: HorizonInboxDetailsUiState, navController: NavHostController ) { - Scaffold( - contentWindowInsets = WindowInsets.zeroScreenInsets, - containerColor = HorizonColors.Surface.pagePrimary(), - topBar = { HorizonInboxDetailsHeader(state.title, state.titleIcon, state, navController) }, - ) { innerPadding -> - LoadingStateWrapper( - state.loadingState, - ) { - BackHandler { onExit(state, navController) } - - state.replyState?.let { replyState -> - val viewModel: HorizonInboxAttachmentPickerViewModel = hiltViewModel() - val pickerState by viewModel.uiState.collectAsState() - HorizonInboxAttachmentPicker( - showBottomSheet = replyState.showAttachmentPicker, - onDismissBottomSheet = { replyState.onShowAttachmentPickerChanged(false) }, - state = pickerState, - onFilesChanged = replyState.onAttachmentsChanged + HorizonEdgeToEdgeSystemBars(null, null) { + Scaffold( + contentWindowInsets = WindowInsets.zeroScreenInsets, + containerColor = HorizonColors.Surface.pagePrimary(), + topBar = { + HorizonInboxDetailsHeader( + state.title, + state.titleIcon, + state, + navController ) + }, + ) { innerPadding -> + LoadingStateWrapper( + state.loadingState, + ) { + BackHandler { onExit(state, navController) } + + state.replyState?.let { replyState -> + val viewModel: HorizonInboxAttachmentPickerViewModel = hiltViewModel() + val pickerState by viewModel.uiState.collectAsState() + HorizonInboxAttachmentPicker( + showBottomSheet = replyState.showAttachmentPicker, + onDismissBottomSheet = { replyState.onShowAttachmentPickerChanged(false) }, + state = pickerState, + onFilesChanged = replyState.onAttachmentsChanged + ) - if (replyState.showExitConfirmationDialog) { - Modal( - dialogState = ModalDialogState( - title = stringResource(R.string.exitConfirmationTitle), - message = stringResource(R.string.exitConfirmationMessage), - primaryButtonTitle = stringResource(R.string.exitConfirmationExitButtonLabel), - secondaryButtonTitle = stringResource(R.string.exitConfirmationCancelButtonLabel), - primaryButtonClick = { - replyState.updateShowExitConfirmationDialog(false) - navController.popBackStack() - }, - secondaryButtonClick = { replyState.updateShowExitConfirmationDialog(false) } + if (replyState.showExitConfirmationDialog) { + Modal( + dialogState = ModalDialogState( + title = stringResource(R.string.exitConfirmationTitle), + message = stringResource(R.string.exitConfirmationMessage), + primaryButtonTitle = stringResource(R.string.exitConfirmationExitButtonLabel), + secondaryButtonTitle = stringResource(R.string.exitConfirmationCancelButtonLabel), + primaryButtonClick = { + replyState.updateShowExitConfirmationDialog(false) + navController.popBackStack() + }, + secondaryButtonClick = { + replyState.updateShowExitConfirmationDialog( + false + ) + } + ) ) - ) + } } - } - HorizonInboxDetailsContent( - state, - Modifier - .padding(innerPadding) - ) + HorizonInboxDetailsContent( + state, + Modifier + .padding(innerPadding) + ) + } } } } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt index 4e4aa8d49d..c2171be8e0 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/inbox/list/HorizonInboxListScreen.kt @@ -82,6 +82,7 @@ import com.instructure.horizon.horizonui.organisms.inputs.multiselectsearch.Mult import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelect import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelectInputSize import com.instructure.horizon.horizonui.organisms.inputs.singleselect.SingleSelectState +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars import com.instructure.horizon.util.fullScreenInsets import com.instructure.horizon.util.zeroScreenInsets import com.instructure.pandautils.utils.localisedFormat @@ -102,16 +103,21 @@ fun HorizonInboxListScreen( } } - Scaffold( - contentWindowInsets = WindowInsets.zeroScreenInsets, - snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, - containerColor = HorizonColors.Surface.pagePrimary(), - ) { padding -> - InboxStateWrapper( - state, - navController, - Modifier.padding(padding) - ) + HorizonEdgeToEdgeSystemBars( + statusBarColor = HorizonColors.Surface.pagePrimary(), + navigationBarColor = HorizonColors.Surface.cardPrimary(), + ) { + Scaffold( + contentWindowInsets = WindowInsets.zeroScreenInsets, + snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, + containerColor = HorizonColors.Surface.pagePrimary(), + ) { padding -> + InboxStateWrapper( + state, + navController, + Modifier.padding(padding) + ) + } } } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt index fc622fed0b..5412e46ec7 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/learn/LearnScreen.kt @@ -82,6 +82,7 @@ import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.horizonui.organisms.inputs.common.InputDropDownPopup import com.instructure.horizon.horizonui.platform.LoadingState import com.instructure.horizon.horizonui.platform.LoadingStateWrapper +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars import com.instructure.horizon.util.bottomNavigationScreenInsets import com.instructure.pandautils.compose.modifiers.conditional import kotlinx.coroutines.delay @@ -99,25 +100,31 @@ fun LearnScreen(state: LearnUiState, mainNavController: NavHostController) { } } - Scaffold( - contentWindowInsets = WindowInsets.bottomNavigationScreenInsets, - containerColor = HorizonColors.Surface.pagePrimary(), - snackbarHost = { SnackbarHost(snackbarHostState) } - ) { padding -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(padding), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - when { - state.screenState.isError -> ErrorContent(state.screenState, state.screenState.errorMessage.orEmpty()) - state.screenState.isLoading -> LoadingContent() - else -> if (state.learningItems.isEmpty()) { - LearnScreenEmptyContent(state) - } else { - LearnScreenWrapper(state, mainNavController, Modifier.fillMaxSize()) + HorizonEdgeToEdgeSystemBars(null, null) { + Scaffold( + contentWindowInsets = WindowInsets.bottomNavigationScreenInsets, + containerColor = HorizonColors.Surface.pagePrimary(), + snackbarHost = { SnackbarHost(snackbarHostState) } + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + when { + state.screenState.isError -> ErrorContent( + state.screenState, + state.screenState.errorMessage.orEmpty() + ) + + state.screenState.isLoading -> LoadingContent() + else -> if (state.learningItems.isEmpty()) { + LearnScreenEmptyContent(state) + } else { + LearnScreenWrapper(state, mainNavController, Modifier.fillMaxSize()) + } } } } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt index 6a4e0a1724..c4aca64804 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt @@ -126,6 +126,7 @@ import com.instructure.horizon.horizonui.molecules.PillType import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.horizonui.molecules.SpinnerSize import com.instructure.horizon.horizonui.platform.LoadingStateWrapper +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars import com.instructure.horizon.util.horizontalSafeDrawing import com.instructure.pandautils.compose.modifiers.conditional import com.instructure.pandautils.utils.Const @@ -139,55 +140,64 @@ fun ModuleItemSequenceScreen(mainNavController: NavHostController, uiState: Modu val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } - Scaffold( - contentWindowInsets = WindowInsets.horizontalSafeDrawing, - containerColor = HorizonColors.Surface.institution(), - snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, - bottomBar = { - ModuleItemSequenceBottomBar( - showNextButton = uiState.currentPosition < uiState.items.size - 1, - showPreviousButton = uiState.currentPosition > 0, - showNotebookButton = uiState.currentItem?.moduleItemContent is ModuleItemContent.Page, - showAssignmentToolsButton = uiState.currentItem?.moduleItemContent is ModuleItemContent.Assignment, - onNextClick = uiState.onNextClick, - onPreviousClick = uiState.onPreviousClick, - onAssignmentToolsClick = uiState.onAssignmentToolsClick, - onAiAssistClick = { uiState.updateShowAiAssist(true) }, - onNotebookClick = { uiState.updateShowNotebook(true) }, - notebookEnabled = uiState.notebookButtonEnabled, - aiAssistEnabled = uiState.aiAssistButtonEnabled, - hasUnreadComments = uiState.hasUnreadComments - ) - } - ) { contentPadding -> - Box(modifier = Modifier.padding(contentPadding)) { - if (uiState.showAiAssist) { - AiAssistantScreen( - onDismiss = { uiState.updateShowAiAssist(false) }, + HorizonEdgeToEdgeSystemBars( + statusBarColor = HorizonColors.Surface.institution(), + navigationBarColor = HorizonColors.Surface.pagePrimary() + ){ + Scaffold( + contentWindowInsets = WindowInsets.horizontalSafeDrawing, + containerColor = HorizonColors.Surface.institution(), + snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, + bottomBar = { + ModuleItemSequenceBottomBar( + showNextButton = uiState.currentPosition < uiState.items.size - 1, + showPreviousButton = uiState.currentPosition > 0, + showNotebookButton = uiState.currentItem?.moduleItemContent is ModuleItemContent.Page, + showAssignmentToolsButton = uiState.currentItem?.moduleItemContent is ModuleItemContent.Assignment, + onNextClick = uiState.onNextClick, + onPreviousClick = uiState.onPreviousClick, + onAssignmentToolsClick = uiState.onAssignmentToolsClick, + onAiAssistClick = { uiState.updateShowAiAssist(true) }, + onNotebookClick = { uiState.updateShowNotebook(true) }, + notebookEnabled = uiState.notebookButtonEnabled, + aiAssistEnabled = uiState.aiAssistButtonEnabled, + hasUnreadComments = uiState.hasUnreadComments ) } - if (uiState.showNotebook) { - NotebookBottomDialog( - uiState.courseId, - uiState.objectTypeAndId, - { snackbarMessage, onDismiss -> - scope.launch { - if (snackbarMessage != null) { - val result = snackbarHostState.showSnackbar(snackbarMessage) - if (result == SnackbarResult.Dismissed) { - onDismiss() + ) { contentPadding -> + Box(modifier = Modifier.padding(contentPadding)) { + if (uiState.showAiAssist) { + AiAssistantScreen( + onDismiss = { uiState.updateShowAiAssist(false) }, + ) + } + if (uiState.showNotebook) { + NotebookBottomDialog( + uiState.courseId, + uiState.objectTypeAndId, + { snackbarMessage, onDismiss -> + scope.launch { + if (snackbarMessage != null) { + val result = snackbarHostState.showSnackbar(snackbarMessage) + if (result == SnackbarResult.Dismissed) { + onDismiss() + } } } - } }, - { uiState.updateShowNotebook(false) } - ) - } - ModuleItemSequenceContent(uiState = uiState, mainNavController = mainNavController, onBackPressed = { - mainNavController.popBackStack() - }) - val markAsDoneState = uiState.currentItem?.markAsDoneUiState - if (markAsDoneState != null && !uiState.currentItem.isLoading) { - MarkAsDoneButton(markAsDoneState) + }, + { uiState.updateShowNotebook(false) } + ) + } + ModuleItemSequenceContent( + uiState = uiState, + mainNavController = mainNavController, + onBackPressed = { + mainNavController.popBackStack() + }) + val markAsDoneState = uiState.currentItem?.markAsDoneUiState + if (markAsDoneState != null && !uiState.currentItem.isLoading) { + MarkAsDoneButton(markAsDoneState) + } } } } @@ -264,7 +274,9 @@ private fun ModuleItemSequenceContent( moduleHeaderHeight = coordinates.size.height val temp = nestedScrollConnection.appBarOffset nestedScrollConnection = - CollapsingAppBarNestedScrollConnection(moduleHeaderHeight).apply { appBarOffset = temp } + CollapsingAppBarNestedScrollConnection(moduleHeaderHeight).apply { + appBarOffset = temp + } } } ) { @@ -283,7 +295,10 @@ private fun ModuleItemSequenceContent( containerColor = Color.Transparent, modifier = Modifier .conditional(uiState.loadingState.isLoading || uiState.loadingState.isError) { - background(color = HorizonColors.Surface.pageSecondary(), shape = HorizonCornerRadius.level5) + background( + color = HorizonColors.Surface.pageSecondary(), + shape = HorizonCornerRadius.level5 + ) } .padding(top = moduleHeaderHeight) ) { diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/NotebookScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/NotebookScreen.kt index 79602787ca..fce27f6323 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/NotebookScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/notebook/NotebookScreen.kt @@ -65,6 +65,7 @@ import com.instructure.horizon.horizonui.molecules.IconButtonColor import com.instructure.horizon.horizonui.molecules.IconButtonSize import com.instructure.horizon.horizonui.molecules.Spinner import com.instructure.horizon.navigation.MainNavigationRoute +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars import com.instructure.horizon.util.topBarScreenInsets import com.instructure.horizon.util.zeroScreenInsets import com.instructure.pandautils.compose.modifiers.conditional @@ -79,98 +80,110 @@ fun NotebookScreen( onNoteSelected: ((Note) -> Unit)? = null, ) { val scrollState = rememberLazyListState() - Scaffold( - contentWindowInsets = WindowInsets.zeroScreenInsets, - containerColor = HorizonColors.Surface.pagePrimary(), - topBar = { - if (state.showTopBar) { - NotebookAppBar( - navigateBack = { mainNavController.popBackStack() }, - modifier = Modifier.conditional(scrollState.canScrollBackward) { - horizonShadow( - elevation = HorizonElevation.level2, - ) - } - ) - } else if (onDismiss != null) { - NotebookAppBar( - onClose = { onDismiss() }, - modifier = Modifier.conditional(scrollState.canScrollBackward) { - horizonShadow( - elevation = HorizonElevation.level2, - ) - } - ) - } - }, - ) { padding -> - LazyColumn( - state = scrollState, - modifier = Modifier - .padding(padding), - contentPadding = WindowInsets.topBarScreenInsets.add(WindowInsets(24.dp, 24.dp, 24.dp, 24.dp)).asPaddingValues() - ) { - if (state.showFilters && state.notes.isNotEmpty()) { - item { - FilterContent( - state.selectedFilter, - state.onFilterSelected + HorizonEdgeToEdgeSystemBars( + null, + HorizonColors.Surface.pagePrimary() + ){ + Scaffold( + contentWindowInsets = WindowInsets.zeroScreenInsets, + containerColor = HorizonColors.Surface.pagePrimary(), + topBar = { + if (state.showTopBar) { + NotebookAppBar( + navigateBack = { mainNavController.popBackStack() }, + modifier = Modifier.conditional(scrollState.canScrollBackward) { + horizonShadow( + elevation = HorizonElevation.level2, + ) + } + ) + } else if (onDismiss != null) { + NotebookAppBar( + onClose = { onDismiss() }, + modifier = Modifier.conditional(scrollState.canScrollBackward) { + horizonShadow( + elevation = HorizonElevation.level2, + ) + } ) } - } - - if (state.notes.isNotEmpty()){ - item { - Column { - Text( - text = stringResource(R.string.notebookNotesLabel), - style = HorizonTypography.labelLargeBold, - color = HorizonColors.Text.title() + }, + ) { padding -> + LazyColumn( + state = scrollState, + modifier = Modifier + .padding(padding), + contentPadding = WindowInsets.topBarScreenInsets.add( + WindowInsets( + 24.dp, + 24.dp, + 24.dp, + 24.dp + ) + ).asPaddingValues() + ) { + if (state.showFilters && state.notes.isNotEmpty()) { + item { + FilterContent( + state.selectedFilter, + state.onFilterSelected ) - - HorizonSpace(SpaceSize.SPACE_12) } } - } - if (state.isLoading) { - item { - LoadingContent() - } - } else if (state.notes.isEmpty()) { - item { - EmptyContent() - } - } else { - items(state.notes) { note -> - Column { - NoteContent(note) { - onNoteSelected?.invoke(note) ?: mainNavController.navigate( - MainNavigationRoute.ModuleItemSequence( - courseId = note.courseId, - moduleItemAssetType = note.objectType.value, - moduleItemAssetId = note.objectId, - ) + if (state.notes.isNotEmpty()) { + item { + Column { + Text( + text = stringResource(R.string.notebookNotesLabel), + style = HorizonTypography.labelLargeBold, + color = HorizonColors.Text.title() ) - } - if (state.notes.lastOrNull() != note) { HorizonSpace(SpaceSize.SPACE_12) } } } - item { - Column { - HorizonSpace(SpaceSize.SPACE_24) + if (state.isLoading) { + item { + LoadingContent() + } + } else if (state.notes.isEmpty()) { + item { + EmptyContent() + } + } else { + items(state.notes) { note -> + Column { + NoteContent(note) { + onNoteSelected?.invoke(note) ?: mainNavController.navigate( + MainNavigationRoute.ModuleItemSequence( + courseId = note.courseId, + moduleItemAssetType = note.objectType.value, + moduleItemAssetId = note.objectId, + ) + ) + } + + if (state.notes.lastOrNull() != note) { + HorizonSpace(SpaceSize.SPACE_12) + } + } + } + + item { + Column { + HorizonSpace(SpaceSize.SPACE_24) - NotesPager( - canNavigateBack = state.hasPreviousPage, - canNavigateForward = state.hasNextPage, - isLoading = state.isLoading, - onNavigateBack = state.loadPreviousPage, - onNavigateForward = state.loadNextPage - ) + NotesPager( + canNavigateBack = state.hasPreviousPage, + canNavigateForward = state.hasNextPage, + isLoading = state.isLoading, + onNavigateBack = state.loadPreviousPage, + onNavigateForward = state.loadNextPage + ) + } } } } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/notification/NotificationScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/notification/NotificationScreen.kt index 555c21adef..fee9c239b5 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/notification/NotificationScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/notification/NotificationScreen.kt @@ -64,6 +64,7 @@ import com.instructure.horizon.horizonui.molecules.StatusChipState import com.instructure.horizon.horizonui.organisms.scaffolds.HorizonScaffold import com.instructure.horizon.horizonui.platform.LoadingState import com.instructure.horizon.horizonui.platform.LoadingStateWrapper +import com.instructure.horizon.util.HorizonEdgeToEdgeSystemBars import com.instructure.pandautils.utils.isPreviousDay import com.instructure.pandautils.utils.isSameDay import com.instructure.pandautils.utils.isSameWeek @@ -80,20 +81,25 @@ fun NotificationScreen(state: NotificationUiState, mainNavController: NavHostCon val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() - HorizonScaffold( - title = stringResource(R.string.notificationsTitle), - snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, - onBackPressed = { mainNavController.popBackStack() }, - ) { modifier -> - LoadingStateWrapper(state.screenState) { - NotificationContent( - mainNavController, - state, - showSnackbar = { message -> - scope.launch { snackbarHostState.showSnackbar(message) } - }, - modifier - ) + HorizonEdgeToEdgeSystemBars( + null, + HorizonColors.Surface.cardPrimary() + ){ + HorizonScaffold( + title = stringResource(R.string.notificationsTitle), + snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, + onBackPressed = { mainNavController.popBackStack() }, + ) { modifier -> + LoadingStateWrapper(state.screenState) { + NotificationContent( + mainNavController, + state, + showSnackbar = { message -> + scope.launch { snackbarHostState.showSnackbar(message) } + }, + modifier + ) + } } } } diff --git a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt index 6127f2336a..814f47b373 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/horizonui/organisms/scaffolds/HorizonScaffold.kt @@ -40,7 +40,6 @@ fun HorizonScaffold( content: @Composable (Modifier) -> Unit, ) { Scaffold( -// contentWindowInsets = WindowInsets.safeDrawing, topBar = { HorizonTopAppBar(title, onBackPressed) }, snackbarHost = snackbarHost, contentColor = HorizonColors.Surface.pagePrimary() diff --git a/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt b/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt index 9444fdc9e7..2ab274f820 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/navigation/HorizonNavigation.kt @@ -139,7 +139,8 @@ fun HorizonNavigation(navController: NavHostController, modifier: Modifier = Mod ), deepLinks = listOf( navDeepLink { - uriPattern = "${ApiPrefs.fullDomain}/courses/{${COURSE_ID}}/assignments/{${ASSIGNMENT_ID}}" + uriPattern = + "${ApiPrefs.fullDomain}/courses/{${COURSE_ID}}/assignments/{${ASSIGNMENT_ID}}" } ) ) { backStackEntry -> @@ -158,7 +159,9 @@ fun HorizonNavigation(navController: NavHostController, modifier: Modifier = Mod moduleItemAssetId = assignmentId?.toString() ) ) { - popUpTo(MainNavigationRoute.AssignmentDetailsDeepLink.route) { inclusive = true } + popUpTo(MainNavigationRoute.AssignmentDetailsDeepLink.route) { + inclusive = true + } } } } @@ -176,7 +179,8 @@ fun HorizonNavigation(navController: NavHostController, modifier: Modifier = Mod ), deepLinks = listOf( navDeepLink { - uriPattern = "${ApiPrefs.fullDomain}/courses/{${COURSE_ID}}/quizzes/{${QUIZ_ID}}" + uriPattern = + "${ApiPrefs.fullDomain}/courses/{${COURSE_ID}}/quizzes/{${QUIZ_ID}}" } ) ) { backStackEntry -> @@ -195,7 +199,9 @@ fun HorizonNavigation(navController: NavHostController, modifier: Modifier = Mod moduleItemAssetId = quizId?.toString() ) ) { - popUpTo(MainNavigationRoute.QuizDetailsDeepLink.route) { inclusive = true } + popUpTo(MainNavigationRoute.QuizDetailsDeepLink.route) { + inclusive = true + } } } } @@ -213,7 +219,8 @@ fun HorizonNavigation(navController: NavHostController, modifier: Modifier = Mod ), deepLinks = listOf( navDeepLink { - uriPattern = "${ApiPrefs.fullDomain}/courses/{${COURSE_ID}}/pages/{${PAGE_ID}}" + uriPattern = + "${ApiPrefs.fullDomain}/courses/{${COURSE_ID}}/pages/{${PAGE_ID}}" } ) ) { backStackEntry -> @@ -230,10 +237,12 @@ fun HorizonNavigation(navController: NavHostController, modifier: Modifier = Mod moduleItemAssetId = pageId ) ) { - popUpTo(MainNavigationRoute.PageDetailsDeepLink.route) { inclusive = true } + popUpTo(MainNavigationRoute.PageDetailsDeepLink.route) { + inclusive = true + } } } } } } -} \ No newline at end of file +} diff --git a/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt b/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt index a7b929542f..e3eebec259 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt @@ -16,11 +16,54 @@ */ package com.instructure.horizon.util +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsBottomHeight +import androidx.compose.foundation.layout.windowInsetsTopHeight import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import com.instructure.horizon.horizonui.foundation.HorizonColors + +@Composable +fun HorizonEdgeToEdgeSystemBars( + statusBarColor: Color? = HorizonColors.Surface.pagePrimary(), + navigationBarColor: Color? = null, + statusBarAlpha: Float = 0.8f, + navigationBarAlpha: Float = 0.8f, + content: @Composable () -> Unit +) { + Box { + content() + statusBarColor?.let { + Box( + modifier = Modifier + .align(Alignment.TopCenter) + .fillMaxWidth() + .windowInsetsTopHeight(WindowInsets.statusBars) + .background(statusBarColor.copy(alpha = statusBarAlpha)) + ) + } + + navigationBarColor?.let { + Box( + modifier = Modifier + .align(Alignment.BottomCenter) + .fillMaxWidth() + .windowInsetsBottomHeight(WindowInsets.navigationBars) + .background(navigationBarColor.copy(alpha = navigationBarAlpha)) + ) + } + } +} private val WindowInsetsSides.Companion.BottomHorizontalSides: WindowInsetsSides get() = WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom From f6130198b596e067bfaa36f55230f40fb6a9bf11 Mon Sep 17 00:00:00 2001 From: domonkosadam Date: Mon, 10 Nov 2025 11:44:40 +0100 Subject: [PATCH 5/5] Fix moduleitemsequence --- .../ModuleItemSequenceScreen.kt | 9 ++++--- .../horizon/util/HorizonEdgeToEdgeHelper.kt | 26 +++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt b/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt index c4aca64804..2565170f51 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/features/moduleitemsequence/ModuleItemSequenceScreen.kt @@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars @@ -142,11 +143,12 @@ fun ModuleItemSequenceScreen(mainNavController: NavHostController, uiState: Modu HorizonEdgeToEdgeSystemBars( statusBarColor = HorizonColors.Surface.institution(), - navigationBarColor = HorizonColors.Surface.pagePrimary() + navigationBarColor = HorizonColors.Surface.pagePrimary(), + modifier = Modifier.padding(WindowInsets.horizontalSafeDrawing.asPaddingValues()) ){ Scaffold( contentWindowInsets = WindowInsets.horizontalSafeDrawing, - containerColor = HorizonColors.Surface.institution(), + containerColor = HorizonColors.Surface.pagePrimary(), snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, bottomBar = { ModuleItemSequenceBottomBar( @@ -283,6 +285,7 @@ private fun ModuleItemSequenceContent( ModuleHeaderContainer( uiState = uiState, modifier = Modifier + .background(HorizonColors.Surface.institution()) .windowInsetsPadding(WindowInsets.statusBars) .padding(start = 24.dp, end = 24.dp, top = 16.dp, bottom = 24.dp) .wrapContentHeight(), @@ -401,7 +404,7 @@ private fun ModuleItemPager(pagerState: PagerState, modifier: Modifier = Modifie state = pagerState, beyondViewportPageCount = 0, pageSize = PageSize.Fill, - modifier = modifier, + modifier = modifier.background(HorizonColors.Surface.institution()), userScrollEnabled = false ) { page -> Column( diff --git a/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt b/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt index e3eebec259..ffdf77c328 100644 --- a/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt +++ b/libs/horizon/src/main/java/com/instructure/horizon/util/HorizonEdgeToEdgeHelper.kt @@ -28,24 +28,46 @@ import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.windowInsetsBottomHeight import androidx.compose.foundation.layout.windowInsetsTopHeight import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.luminance +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat import com.instructure.horizon.horizonui.foundation.HorizonColors @Composable fun HorizonEdgeToEdgeSystemBars( statusBarColor: Color? = HorizonColors.Surface.pagePrimary(), navigationBarColor: Color? = null, + modifier: Modifier = Modifier, statusBarAlpha: Float = 0.8f, navigationBarAlpha: Float = 0.8f, content: @Composable () -> Unit ) { + val view = LocalView.current + + SideEffect { + val window = (view.context as? android.app.Activity)?.window ?: return@SideEffect + val insetsController = WindowCompat.getInsetsController(window, view) + + statusBarColor?.let { color -> + val isLight = color.luminance() > 0.5f + insetsController.isAppearanceLightStatusBars = isLight + } + + navigationBarColor?.let { color -> + val isLight = color.luminance() > 0.5f + insetsController.isAppearanceLightNavigationBars = isLight + } + } + Box { content() statusBarColor?.let { Box( - modifier = Modifier + modifier = modifier .align(Alignment.TopCenter) .fillMaxWidth() .windowInsetsTopHeight(WindowInsets.statusBars) @@ -55,7 +77,7 @@ fun HorizonEdgeToEdgeSystemBars( navigationBarColor?.let { Box( - modifier = Modifier + modifier = modifier .align(Alignment.BottomCenter) .fillMaxWidth() .windowInsetsBottomHeight(WindowInsets.navigationBars)