Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

인증 & 스토리에서 이미지 뷰어 화면 개선 #83

Merged
merged 3 commits into from
Dec 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -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,39 +61,46 @@ 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(
model = ImageRequest.Builder(LocalContext.current)
.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(
Original file line number Diff line number Diff line change
@@ -10,12 +10,16 @@ import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
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
@@ -53,6 +57,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
@@ -83,7 +88,6 @@ fun VerificationPreviewRoute(
showProgress = true
}
UploadEvent.Success -> {
showProgress = false
onUploadSuccess()
}
UploadEvent.Error -> {
@@ -94,50 +98,60 @@ 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
) {
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
)

}
if (isVisibleSpacer) {
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(statusBarPaddingValue + 80.dp)
.background(ColorBlack_FF000000.copy(alpha = 0.7f))
)
Row(
modifier = Modifier
.fillMaxWidth()
@@ -149,6 +163,7 @@ fun VerificationPreviewScreen(
)
)
)
.statusBarsPadding()
.height(93.dp)
.padding(horizontal = 24.dp, vertical = 14.dp)
) {
@@ -186,7 +201,10 @@ fun VerificationPreviewScreen(
)

IconButton(
onClick = onClickClose,
onClick = {
onClickClose()
//setStatusBar(context, true)
},
modifier = Modifier.wrapContentSize()
) {
Icon(
@@ -196,9 +214,11 @@ fun VerificationPreviewScreen(
)
}
}

UploadButton(
context = context,
filePath = uiState.imageUrl.toUri(),
isUploading = isUploading,
onClickUpload = onClickUpload
)
}
@@ -211,6 +231,7 @@ fun VerificationPreviewScreen(
fun BoxScope.UploadButton(
context: Context,
filePath: Uri,
isUploading: Boolean,
onClickUpload: (File) -> Unit
) {
val multipleEventsCutter = remember { MultipleEventsCutter.get() }
@@ -220,19 +241,27 @@ 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)
onClickUpload(file)
}
}
) {
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
)
}
}
}

@@ -257,6 +286,7 @@ fun VerificationPreviewLoading() {
fun ProgressBar() {
Box(
modifier = Modifier
.fillMaxSize()
.statusBarsPadding()
.navigationBarsPadding()
) {
@@ -270,6 +300,7 @@ fun ProgressBar() {
@Composable
fun VerificationPreviewScreenPreview() {
VerificationPreviewScreen(
isUploading = false,
onClickClose = {},
uiState = VerificationPreviewUiState.Success(
characterUiModel = CharacterUiModel.RABBIT,
@@ -284,6 +315,7 @@ fun VerificationPreviewScreenPreview() {
@Composable
fun VerificationPreviewScreenLoadingPreview() {
VerificationPreviewScreen(
isUploading = false,
onClickClose = {},
uiState = VerificationPreviewUiState.Loading,
onClickUpload = {}
Original file line number Diff line number Diff line change
@@ -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
}

Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package com.goalpanzi.mission_mate.feature.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(
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -91,11 +91,16 @@ 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
internal fun rememberMainNavigator(
navController: NavHostController = rememberNavController()
) : MainNavigator = remember(navController) {
MainNavigator(navController)
}
}