Skip to content

Commit 4f38bb1

Browse files
author
eshc123
committed
feat: 스토리 화면 HorizontalPager 적용
1 parent 41566b7 commit 4f38bb1

File tree

2 files changed

+105
-81
lines changed
  • core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/model/image
  • feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen

2 files changed

+105
-81
lines changed

core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/model/image/MissionMateImage.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import android.os.Build
44
import android.os.Bundle
55
import android.os.Parcelable
66
import androidx.navigation.NavType
7-
import com.goalpanzi.mission_mate.core.navigation.model.MainTabDataModel
87
import kotlinx.parcelize.Parcelize
98
import kotlinx.serialization.Serializable
109
import kotlinx.serialization.encodeToString
1110
import kotlinx.serialization.json.Json
11+
import java.time.LocalDateTime
12+
import java.time.format.DateTimeFormatter
1213

1314
@Serializable
1415
@Parcelize
@@ -23,7 +24,14 @@ class MissionMateImage(
2324
val nickname : String,
2425
val verifiedAt : String,
2526
val imageUrl : String
26-
) : Parcelable
27+
) : Parcelable {
28+
29+
fun formattedVerifiedAt() : String {
30+
val dateTime = LocalDateTime.parse(verifiedAt)
31+
val formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd")
32+
return dateTime.format(formatter)
33+
}
34+
}
2735

2836
val MissionMateImagesModelType = object : NavType<MissionMateImages>(
2937
isNullableAllowed = false

feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/UserStroyScreen.kt

Lines changed: 95 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import androidx.compose.foundation.layout.statusBars
1717
import androidx.compose.foundation.layout.statusBarsPadding
1818
import androidx.compose.foundation.layout.wrapContentSize
1919
import androidx.compose.foundation.layout.wrapContentWidth
20+
import androidx.compose.foundation.pager.HorizontalPager
21+
import androidx.compose.foundation.pager.rememberPagerState
2022
import androidx.compose.foundation.shape.CircleShape
2123
import androidx.compose.material3.Icon
2224
import androidx.compose.material3.IconButton
@@ -48,112 +50,126 @@ import com.goalpanzi.mission_mate.core.navigation.model.image.MissionMateImages
4850
import com.goalpanzi.mission_mate.feature.board.model.CharacterUiModel
4951
import java.net.URLDecoder
5052
import java.nio.charset.StandardCharsets
51-
import java.time.LocalDateTime
52-
import java.time.format.DateTimeFormatter
5353

5454
@Composable
5555
fun UserStoryScreen(
5656
images: MissionMateImages,
5757
onClickClose: () -> Unit
5858
) {
59-
if(images.isEmpty()) return
59+
if (images.isEmpty()) return
6060

61-
val characterUiModel = images[0].userCharacter.let { CharacterUiModel.valueOf(it) }
62-
val verifiedAt = images[0].verifiedAt
63-
val imageUrl = images[0].imageUrl
64-
val nickname = images[0].nickname
65-
66-
val dateTime = LocalDateTime.parse(verifiedAt)
67-
val formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd")
68-
val statusBarPaddingValue = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
61+
val verifiedImages = images.filter { it.verifiedAt.isNotEmpty() }
62+
val pagerState = rememberPagerState { verifiedImages.size }
63+
val image = verifiedImages[pagerState.currentPage ]
6964
var isVisibleSpacer by remember { mutableStateOf(true) }
65+
val statusBarPaddingValue = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
7066

7167
Box(
7268
modifier = Modifier
7369
.fillMaxSize()
7470
.navigationBarsPadding()
7571
) {
76-
Box(
77-
modifier = Modifier
78-
.fillMaxSize()
79-
.background(ColorBlack_FF000000)
80-
.statusBarsPadding()
81-
) {
82-
AsyncImage(
83-
model = ImageRequest.Builder(LocalContext.current)
84-
.data(URLDecoder.decode(imageUrl, StandardCharsets.UTF_8.toString()))
85-
.build(),
86-
contentDescription = null,
72+
HorizontalPager(
73+
pagerState
74+
) { page ->
75+
val imageUrl = verifiedImages[page].imageUrl
76+
Box(
8777
modifier = Modifier
8878
.fillMaxSize()
89-
.clickableWithoutRipple {
90-
isVisibleSpacer = !isVisibleSpacer
91-
},
92-
contentScale = ContentScale.Fit,
93-
filterQuality = FilterQuality.None
94-
)
79+
.background(ColorBlack_FF000000)
80+
.statusBarsPadding()
81+
) {
82+
AsyncImage(
83+
model = ImageRequest.Builder(LocalContext.current)
84+
.data(URLDecoder.decode(imageUrl, StandardCharsets.UTF_8.toString()))
85+
.build(),
86+
contentDescription = null,
87+
modifier = Modifier
88+
.fillMaxSize()
89+
.clickableWithoutRipple {
90+
isVisibleSpacer = !isVisibleSpacer
91+
},
92+
contentScale = ContentScale.Fit,
93+
filterQuality = FilterQuality.None
94+
)
95+
}
9596
}
96-
9797
if (isVisibleSpacer) {
9898
Spacer(
9999
modifier = Modifier
100100
.fillMaxWidth()
101101
.height(statusBarPaddingValue + 80.dp)
102102
.background(ColorBlack_FF000000.copy(alpha = 0.7f))
103103
)
104-
Row(
105-
modifier = Modifier
106-
.fillMaxWidth()
107-
.statusBarsPadding()
108-
.height(93.dp)
109-
.padding(horizontal = 24.dp, vertical = 14.dp)
110-
) {
111-
StableImage(
112-
modifier = Modifier
113-
.padding(top = 6.dp)
114-
.size(28.dp)
115-
.border(1.dp, ColorWhite_FFFFFFFF, CircleShape)
116-
.paint(
117-
painter = painterResource(characterUiModel.backgroundId),
118-
contentScale = ContentScale.FillWidth
119-
)
120-
.padding(5.dp),
121-
drawableResId = characterUiModel.imageId,
122-
description = ""
123-
)
124-
Text(
125-
text = nickname,
126-
style = MissionMateTypography.body_xl_bold,
127-
color = ColorWhite_FFFFFFFF,
128-
modifier = Modifier
129-
.padding(start = 8.dp)
130-
.wrapContentWidth()
131-
.padding(top = 6.dp)
132-
)
104+
StoryImageDetail(
105+
characterUiModel = image.userCharacter.let { CharacterUiModel.valueOf(it) },
106+
nickname = image.nickname,
107+
dateTime = image.formattedVerifiedAt(),
108+
onClickClose = onClickClose
109+
)
110+
}
111+
}
112+
}
133113

134-
Text(
135-
text = dateTime.format(formatter),
136-
style = MissionMateTypography.body_xl_regular,
137-
color = ColorWhite_FFFFFFFF,
138-
modifier = Modifier
139-
.padding(start = 8.dp)
140-
.weight(1f)
141-
.padding(top = 6.dp)
114+
@Composable
115+
fun StoryImageDetail(
116+
characterUiModel: CharacterUiModel,
117+
nickname: String,
118+
dateTime: String,
119+
onClickClose: () -> Unit,
120+
modifier: Modifier = Modifier
121+
) {
122+
Row(
123+
modifier = modifier
124+
.fillMaxWidth()
125+
.statusBarsPadding()
126+
.height(93.dp)
127+
.padding(horizontal = 24.dp, vertical = 14.dp)
128+
) {
129+
StableImage(
130+
modifier = Modifier
131+
.padding(top = 6.dp)
132+
.size(28.dp)
133+
.border(1.dp, ColorWhite_FFFFFFFF, CircleShape)
134+
.paint(
135+
painter = painterResource(characterUiModel.backgroundId),
136+
contentScale = ContentScale.FillWidth
142137
)
138+
.padding(5.dp),
139+
drawableResId = characterUiModel.imageId,
140+
description = ""
141+
)
142+
Text(
143+
text = nickname,
144+
style = MissionMateTypography.body_xl_bold,
145+
color = ColorWhite_FFFFFFFF,
146+
modifier = Modifier
147+
.padding(start = 8.dp)
148+
.wrapContentWidth()
149+
.padding(top = 6.dp)
150+
)
143151

144-
IconButton(
145-
onClick = {
146-
onClickClose()
147-
},
148-
modifier = Modifier.wrapContentSize()
149-
) {
150-
Icon(
151-
imageVector = ImageVector.vectorResource(id = com.goalpanzi.mission_mate.core.designsystem.R.drawable.ic_close),
152-
contentDescription = "",
153-
tint = ColorWhite_FFFFFFFF
154-
)
155-
}
156-
}
152+
Text(
153+
text = dateTime,
154+
style = MissionMateTypography.body_xl_regular,
155+
color = ColorWhite_FFFFFFFF,
156+
modifier = Modifier
157+
.padding(start = 8.dp)
158+
.weight(1f)
159+
.padding(top = 6.dp)
160+
)
161+
162+
IconButton(
163+
onClick = {
164+
onClickClose()
165+
},
166+
modifier = Modifier.wrapContentSize()
167+
) {
168+
Icon(
169+
imageVector = ImageVector.vectorResource(id = com.goalpanzi.mission_mate.core.designsystem.R.drawable.ic_close),
170+
contentDescription = "",
171+
tint = ColorWhite_FFFFFFFF
172+
)
157173
}
158174
}
159175
}

0 commit comments

Comments
 (0)