From 2dd13c918ff83880253523f5affdd117aa7db85c Mon Sep 17 00:00:00 2001 From: eshc123 <> Date: Thu, 19 Dec 2024 12:34:36 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EB=B7=B0=EC=96=B4=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - background black - 이미지 배율 유지한 채로 중앙 배치 --- .../core/designsystem/util/StatusBarUtil.kt | 20 ++++ .../feature/board/screen/UserStroyScreen.kt | 46 ++++++--- .../board/screen/VerificationPreviewScreen.kt | 93 ++++++++++++------- .../core/main/component/MainNavHost.kt | 21 ++++- .../core/main/component/MainNavigator.kt | 7 +- 5 files changed, 139 insertions(+), 48 deletions(-) create mode 100644 core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/util/StatusBarUtil.kt diff --git a/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/util/StatusBarUtil.kt b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/util/StatusBarUtil.kt new file mode 100644 index 00000000..62cf9fca --- /dev/null +++ b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/util/StatusBarUtil.kt @@ -0,0 +1,20 @@ +package com.goalpanzi.mission_mate.core.designsystem.util + +import android.app.Activity +import android.content.Context +import androidx.core.view.WindowCompat + +fun isLightStatusBars(context: Activity): Boolean { + val window = context.window + val insetsController = WindowCompat.getInsetsController(window, window.decorView) + return insetsController.isAppearanceLightStatusBars +} + +fun setStatusBar(context: Context, isLight: Boolean) { + if (context is Activity) { + val window = context.window + val insetsController = WindowCompat.getInsetsController(window, window.decorView) + if (insetsController.isAppearanceLightStatusBars != isLight) + insetsController.isAppearanceLightStatusBars = isLight + } +} diff --git a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/UserStroyScreen.kt b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/UserStroyScreen.kt index 01f0298f..7d5b743b 100644 --- a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/UserStroyScreen.kt +++ b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/UserStroyScreen.kt @@ -1,15 +1,20 @@ package com.goalpanzi.mission_mate.feature.board.screen +import android.app.Activity import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box 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.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentWidth @@ -18,10 +23,12 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.paint -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale @@ -33,6 +40,7 @@ import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import coil.request.ImageRequest import com.goalpanzi.mission_mate.core.designsystem.component.StableImage +import com.goalpanzi.mission_mate.core.designsystem.ext.clickableWithoutRipple import com.goalpanzi.mission_mate.core.designsystem.theme.ColorBlack_FF000000 import com.goalpanzi.mission_mate.core.designsystem.theme.ColorWhite_FFFFFFFF import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography @@ -53,16 +61,18 @@ fun UserStoryScreen( ) { val dateTime = LocalDateTime.parse(verifiedAt) val formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") + val statusBarPaddingValue = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + var isVisibleSpacer by remember { mutableStateOf(true) } Box( modifier = Modifier .fillMaxSize() - .background(ColorWhite_FFFFFFFF) .navigationBarsPadding() ) { Box( modifier = Modifier .fillMaxSize() + .background(ColorBlack_FF000000) .statusBarsPadding() ) { AsyncImage( @@ -70,22 +80,27 @@ fun UserStoryScreen( .data(URLDecoder.decode(imageUrl, StandardCharsets.UTF_8.toString())) .build(), contentDescription = null, - modifier = Modifier.fillMaxSize(), - contentScale = ContentScale.FillBounds, + modifier = Modifier + .fillMaxSize() + .clickableWithoutRipple { + isVisibleSpacer = !isVisibleSpacer + }, + contentScale = ContentScale.Fit, filterQuality = FilterQuality.None ) + } + if (isVisibleSpacer) { + Spacer( + modifier = Modifier + .fillMaxWidth() + .height(statusBarPaddingValue + 80.dp) + .background(ColorBlack_FF000000.copy(alpha = 0.7f)) + ) Row( modifier = Modifier .fillMaxWidth() - .background( - brush = Brush.verticalGradient( - colors = listOf( - ColorBlack_FF000000.copy(alpha = 0.4f), - Color.Transparent - ) - ) - ) + .statusBarsPadding() .height(93.dp) .padding(horizontal = 24.dp, vertical = 14.dp) ) { @@ -123,7 +138,10 @@ fun UserStoryScreen( ) IconButton( - onClick = onClickClose, + onClick = { + onClickClose() + //setStatusBar(context, true) + }, modifier = Modifier.wrapContentSize() ) { Icon( diff --git a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt index f87aea43..9420a9d7 100644 --- a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt +++ b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt @@ -1,16 +1,19 @@ package com.goalpanzi.mission_mate.feature.board.screen -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box 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.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentWidth @@ -23,6 +26,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -47,6 +51,7 @@ import coil.request.ImageRequest import com.goalpanzi.mission_mate.core.designsystem.component.MissionMateButton import com.goalpanzi.mission_mate.core.designsystem.component.MissionMateButtonType import com.goalpanzi.mission_mate.core.designsystem.component.StableImage +import com.goalpanzi.mission_mate.core.designsystem.ext.clickableWithoutRipple import com.goalpanzi.mission_mate.core.designsystem.theme.ColorBlack_FF000000 import com.goalpanzi.mission_mate.core.designsystem.theme.ColorWhite_FFFFFFFF import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography @@ -105,31 +110,67 @@ fun VerificationPreviewScreen( val context = LocalContext.current val dateTime = LocalDateTime.now() val formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") + val statusBarPaddingValue = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + var isVisibleSpacer by remember { mutableStateOf(true) } Box( modifier = Modifier .fillMaxSize() - .background(ColorWhite_FFFFFFFF) .navigationBarsPadding() ) { - Box( - modifier = Modifier - .fillMaxSize() - .statusBarsPadding() - ) { - when (uiState) { - VerificationPreviewUiState.Loading -> VerificationPreviewLoading() - is VerificationPreviewUiState.Success -> { + when (uiState) { + VerificationPreviewUiState.Loading -> VerificationPreviewLoading() + is VerificationPreviewUiState.Success -> { + Box( + modifier = Modifier + .fillMaxSize() + .background(ColorBlack_FF000000) + .statusBarsPadding() + ) { + AsyncImage( model = ImageRequest.Builder(context) .data(uiState.imageUrl) .build(), contentDescription = null, - modifier = Modifier.fillMaxSize(), - contentScale = ContentScale.FillBounds, + modifier = Modifier.fillMaxSize().clickableWithoutRipple { + isVisibleSpacer = !isVisibleSpacer + }, + contentScale = ContentScale.Fit, filterQuality = FilterQuality.None ) + + + MissionMateButton( + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(horizontal = 24.dp, vertical = 36.dp) + .fillMaxWidth() + .navigationBarsPadding(), + buttonType = MissionMateButtonType.ACTIVE, + onClick = { + val file = ImageCompressor.getCompressedImage( + context, + uiState.imageUrl.toUri() + ) + onClickUpload(file) + } + ) { + Text( + text = stringResource(id = R.string.upload), + style = MissionMateTypography.body_xl_bold, + color = ColorWhite_FFFFFFFF + ) + } + } + if (isVisibleSpacer) { + Spacer( + modifier = Modifier + .fillMaxWidth() + .height(statusBarPaddingValue + 80.dp) + .background(ColorBlack_FF000000.copy(alpha = 0.7f)) + ) Row( modifier = Modifier .fillMaxWidth() @@ -141,6 +182,7 @@ fun VerificationPreviewScreen( ) ) ) + .statusBarsPadding() .height(93.dp) .padding(horizontal = 24.dp, vertical = 14.dp) ) { @@ -178,7 +220,10 @@ fun VerificationPreviewScreen( ) IconButton( - onClick = onClickClose, + onClick = { + onClickClose() + //setStatusBar(context, true) + }, modifier = Modifier.wrapContentSize() ) { Icon( @@ -188,28 +233,11 @@ fun VerificationPreviewScreen( ) } } - - MissionMateButton( - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(horizontal = 24.dp, vertical = 36.dp) - .fillMaxWidth() - .navigationBarsPadding(), - buttonType = MissionMateButtonType.ACTIVE, - onClick = { - val file = ImageCompressor.getCompressedImage(context, uiState.imageUrl.toUri()) - onClickUpload(file) - } - ) { - Text( - text = stringResource(id = R.string.upload), - style = MissionMateTypography.body_xl_bold, - color = ColorWhite_FFFFFFFF - ) - } + } } } + } } @@ -231,6 +259,7 @@ fun VerificationPreviewLoading() { fun ProgressBar() { Box( modifier = Modifier + .fillMaxSize() .statusBarsPadding() .navigationBarsPadding() ) { diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt index 4a52ef9d..3f2054d5 100644 --- a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt +++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt @@ -1,13 +1,20 @@ package com.goalpanzi.mission_mate.core.main.component +import android.app.Activity import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.navigation.compose.NavHost +import androidx.navigation.compose.currentBackStackEntryAsState import com.goalpanzi.mission_mate.core.designsystem.theme.ColorWhite_FFFFFFFF +import com.goalpanzi.mission_mate.core.designsystem.util.isLightStatusBars +import com.goalpanzi.mission_mate.core.designsystem.util.setStatusBar import com.goalpanzi.mission_mate.feature.board.boardDetailNavGraph import com.goalpanzi.mission_mate.feature.board.boardFinishNavGraph import com.goalpanzi.mission_mate.feature.board.boardNavGraph @@ -30,6 +37,18 @@ internal fun MainNavHost( startDestination: String, padding: PaddingValues ) { + val context = LocalContext.current + val currentBackStackEntry by navigator.navController.currentBackStackEntryAsState() + val currentRoute = currentBackStackEntry?.destination?.route + + LaunchedEffect(currentRoute) { + if (navigator.isDarkStatusBarScreen(currentRoute)) { + setStatusBar(context, false) + } else if(!isLightStatusBars(context as Activity)){ + setStatusBar(context, true) + } + } + Box( modifier = modifier .fillMaxSize() @@ -142,4 +161,4 @@ internal fun MainNavHost( ) } } -} \ No newline at end of file +} diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt index c3413fe0..e166d049 100644 --- a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt +++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt @@ -91,6 +91,11 @@ class MainNavigator( fun navigationToVerificationPreview(missionId: Long, imageUrl : Uri) { navController.navigateToVerificationPreview(missionId, imageUrl) } + + fun isDarkStatusBarScreen(currentRoute: String?): Boolean { + return currentRoute?.contains("RouteModel.VerificationPreview") == true + || currentRoute?.contains("RouteModel.UserStory") == true + } } @Composable @@ -98,4 +103,4 @@ internal fun rememberMainNavigator( navController: NavHostController = rememberNavController() ) : MainNavigator = remember(navController) { MainNavigator(navController) -} \ No newline at end of file +} From b00001df683190141061cb65215d3ca8acfa33e5 Mon Sep 17 00:00:00 2001 From: eshc123 <> Date: Fri, 20 Dec 2024 20:45:08 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EC=97=85=EB=A1=9C=EB=93=9C=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EB=A1=9C=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../board/screen/VerificationPreviewScreen.kt | 55 +++++++------------ .../screen/VerificationPreviewViewModel.kt | 2 + 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt index 18746ddc..6ac9a458 100644 --- a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt +++ b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt @@ -88,7 +88,6 @@ fun VerificationPreviewRoute( showProgress = true } UploadEvent.Success -> { - showProgress = false onUploadSuccess() } UploadEvent.Error -> { @@ -99,18 +98,16 @@ fun VerificationPreviewRoute( } VerificationPreviewScreen( + isUploading = showProgress, onClickClose = onClickClose, uiState = uiState, onClickUpload = viewModel::uploadImage ) - - if (showProgress) { - ProgressBar() - } } @Composable fun VerificationPreviewScreen( + isUploading: Boolean, onClickClose: () -> Unit, uiState: VerificationPreviewUiState, onClickUpload: (File) -> Unit @@ -147,30 +144,6 @@ fun VerificationPreviewScreen( contentScale = ContentScale.Fit, filterQuality = FilterQuality.None ) - - - - MissionMateButton( - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(horizontal = 24.dp, vertical = 36.dp) - .fillMaxWidth() - .navigationBarsPadding(), - buttonType = MissionMateButtonType.ACTIVE, - onClick = { - val file = ImageCompressor.getCompressedImage( - context, - uiState.imageUrl.toUri() - ) - onClickUpload(file) - } - ) { - Text( - text = stringResource(id = R.string.upload), - style = MissionMateTypography.body_xl_bold, - color = ColorWhite_FFFFFFFF - ) - } } if (isVisibleSpacer) { Spacer( @@ -245,6 +218,7 @@ fun VerificationPreviewScreen( UploadButton( context = context, filePath = uiState.imageUrl.toUri(), + isUploading = isUploading, onClickUpload = onClickUpload ) } @@ -257,6 +231,7 @@ fun VerificationPreviewScreen( fun BoxScope.UploadButton( context: Context, filePath: Uri, + isUploading: Boolean, onClickUpload: (File) -> Unit ) { val multipleEventsCutter = remember { MultipleEventsCutter.get() } @@ -266,7 +241,7 @@ fun BoxScope.UploadButton( .padding(horizontal = 24.dp, vertical = 36.dp) .fillMaxWidth() .navigationBarsPadding(), - buttonType = MissionMateButtonType.ACTIVE, + buttonType = if(isUploading) MissionMateButtonType.DISABLED else MissionMateButtonType.ACTIVE, onClick = { multipleEventsCutter.processEvent { val file = ImageCompressor.getCompressedImage(context, filePath) @@ -274,11 +249,19 @@ fun BoxScope.UploadButton( } } ) { - Text( - text = stringResource(id = R.string.upload), - style = MissionMateTypography.body_xl_bold, - color = ColorWhite_FFFFFFFF - ) + if(isUploading){ + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + color = ColorWhite_FFFFFFFF, + strokeWidth = 3.dp + ) + }else { + Text( + text = stringResource(id = R.string.upload), + style = MissionMateTypography.body_lg_bold, + color = ColorWhite_FFFFFFFF + ) + } } } @@ -317,6 +300,7 @@ fun ProgressBar() { @Composable fun VerificationPreviewScreenPreview() { VerificationPreviewScreen( + isUploading = false, onClickClose = {}, uiState = VerificationPreviewUiState.Success( characterUiModel = CharacterUiModel.RABBIT, @@ -331,6 +315,7 @@ fun VerificationPreviewScreenPreview() { @Composable fun VerificationPreviewScreenLoadingPreview() { VerificationPreviewScreen( + isUploading = false, onClickClose = {}, uiState = VerificationPreviewUiState.Loading, onClickUpload = {} diff --git a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewViewModel.kt b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewViewModel.kt index 87d36f46..2d477db0 100644 --- a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewViewModel.kt +++ b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewViewModel.kt @@ -1,5 +1,6 @@ package com.goalpanzi.mission_mate.feature.board.screen +import android.util.Log import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -87,3 +88,4 @@ sealed interface UploadEvent { data object Success : UploadEvent data object Error : UploadEvent } +