Skip to content

Commit

Permalink
Merge pull request #33 from Nexters/feature/implement-board
Browse files Browse the repository at this point in the history
Feature/implement board
  • Loading branch information
eshc123 authored Aug 17, 2024
2 parents 1fed30c + 33dd7a7 commit f677727
Show file tree
Hide file tree
Showing 45 changed files with 1,354 additions and 263 deletions.
2 changes: 2 additions & 0 deletions core/designsystem/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ dependencies {
androidTestImplementation(platform(libs.androidx.compose.bom))
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)

implementation(libs.lottie.compose)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.goalpanzi.mission_mate.core.designsystem.component

import androidx.annotation.RawRes
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition

@Composable
fun LottieImage(
@RawRes lottieRes : Int,
modifier: Modifier = Modifier
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(lottieRes))
val progress by animateLottieCompositionAsState(composition)
LottieAnimation(
modifier = modifier,
composition = composition,
progress = { progress },
)
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import kotlinx.serialization.Serializable
data class MissionBoardResponse(
val number : Int,
val reward : BoardReward = BoardReward.NONE,
val isMyPosition : Boolean = false,
val missionBoardMembers : List<MissionBoardMembersResponse>
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,16 @@ import kotlinx.serialization.Serializable

@Serializable
data class MissionBoardsResponse(
val missionBoards : List<MissionBoardResponse>
)
val missionBoards : List<MissionBoardResponse>,
val progressCount : Int,
val rank : Int
){
val boardRewardList : List<MissionBoardResponse> by lazy {
missionBoards.filter { it.reward != BoardReward.NONE }
}

val passedCountByMe : Int
get() {
return missionBoards.find { it.isMyPosition }?.number ?: 0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ data class MissionDetailResponse(
LocalDate.parse(missionStartDate, formatter)
}

val missionEndLocalDateTime : LocalDateTime by lazy {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime.parse(missionEndDate, formatter)
}

val missionPeriod : String by lazy {
try {
val inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
Expand All @@ -39,7 +44,7 @@ data class MissionDetailResponse(
}
}

val missionDaysOfWeek : List<String> by lazy {
val missionDaysOfWeekTextLocale : List<String> by lazy {
try {
missionDays.map {
DayOfWeek.valueOf(it).getDisplayName(TextStyle.SHORT, Locale.getDefault())
Expand All @@ -49,6 +54,16 @@ data class MissionDetailResponse(
}
}

val missionDaysOfWeek : List<DayOfWeek> by lazy {
try {
missionDays.map {
DayOfWeek.valueOf(it)
}
}catch (e: Exception){
emptyList()
}
}

fun isStartedMission() : Boolean {
val currentDate = LocalDate.now()
return currentDate.isEqual(missionStartLocalDate) || currentDate.isAfter(missionStartLocalDate)
Expand Down
2 changes: 2 additions & 0 deletions feature/board/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ dependencies {
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)

implementation(libs.balloon)

implementation(project(":core:designsystem"))
implementation(project(":core:navigation"))
implementation(project(":core:domain"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import com.goalpanzi.mission_mate.feature.onboarding.component.StableImage
fun Block(
index: Int,
type: BlockType,
eventType: BlockEventType,
eventType: BlockEventType?,
numberOfColumns: Int,
modifier: Modifier = Modifier,
isPassed: Boolean = false,
Expand All @@ -41,7 +41,7 @@ fun Block(
if (type == BlockType.START) R.drawable.img_board_start
else if (isStartedMission && isPassed) {
if (eventType is BlockEventType.Item) {
eventType.boardEventItem.eventType.imageId
eventType.boardEventItem.eventType?.imageId ?: 0
} else {
when (type) {
BlockType.CENTER -> R.drawable.img_board_center_jeju
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
package com.goalpanzi.mission_mate.feature.board.component

import android.annotation.SuppressLint
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.drawscope.clipRect
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.goalpanzi.mission_mate.core.designsystem.theme.ColorGray1_FF404249
import com.goalpanzi.mission_mate.core.designsystem.theme.ColorGray2_FF4F505C
import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography
import com.goalpanzi.mission_mate.feature.board.R
import com.goalpanzi.mission_mate.feature.board.model.BoardEventItem
import com.goalpanzi.mission_mate.feature.board.model.MissionState
import com.goalpanzi.mission_mate.feature.board.model.toCharacter
import com.goalpanzi.mission_mate.feature.board.model.toEventType
import com.goalpanzi.mission_mate.feature.board.util.BoardGenerator
import com.luckyoct.core.model.response.MissionBoardsResponse
import com.luckyoct.core.model.response.MissionVerificationResponse
import kotlin.math.absoluteValue


@Composable
fun Board(
scrollState: ScrollState,
boardCount: Int,
passedCount: Int,
startDateText: String,
missionBoards: MissionBoardsResponse,
numberOfColumns: Int,
profile: MissionVerificationResponse,
missionState: MissionState,
modifier: Modifier = Modifier,
) {
val statusBar = WindowInsets.statusBars
val navigationBar = WindowInsets.navigationBars
val localDensity = LocalDensity.current
val statusBarHeight = remember { (statusBar.getTop(localDensity) - statusBar.getBottom(localDensity)).absoluteValue }
val navigationBarHeight = remember { (navigationBar.getTop(localDensity) - navigationBar.getBottom(localDensity)).absoluteValue }
Box(
modifier = modifier
.fillMaxSize()
) {
Column(
modifier = modifier.modifierWithClipRect(
scrollState = scrollState,
missionState = missionState,
innerModifier = Modifier
.drawWithContent {
clipRect(bottom = statusBarHeight + 178.dp.toPx()) {
this@drawWithContent.drawContent()
}
}
.blur(10.dp, 10.dp),
)
) {
BoardContent(
boardCount,
passedCount,
startDateText,
missionBoards,
numberOfColumns,
profile,
missionState,
modifier
)
}
Column(
modifier = modifier.modifierWithClipRect(
scrollState = scrollState,
missionState = missionState,
innerModifier = Modifier
.drawWithContent {
clipRect(
top = statusBarHeight + 178.dp.toPx() - 1,
bottom = size.height + navigationBarHeight - (if (missionState.isVisiblePiece()) 188.dp else 46.dp).toPx()
) {
this@drawWithContent.drawContent()
}
}
)
) {
BoardContent(
boardCount,
passedCount,
startDateText,
missionBoards,
numberOfColumns,
profile,
missionState,
modifier
)
}

Column(
modifier = modifier.modifierWithClipRect(
scrollState = scrollState,
missionState = missionState,
innerModifier = Modifier
.drawWithContent {
clipRect(top = (size.height + navigationBarHeight - (if (missionState.isVisiblePiece()) 188.dp else 46.dp).toPx())) {
this@drawWithContent.drawContent()
}
}.blur(10.dp,10.dp)
)
) {
BoardContent(
boardCount,
passedCount,
startDateText,
missionBoards,
numberOfColumns,
profile,
missionState,
modifier
)
}


}

}

@Composable
fun ColumnScope.BoardContent(
boardCount: Int,
passedCount: Int,
startDateText: String,
missionBoards: MissionBoardsResponse,
numberOfColumns: Int,
profile: MissionVerificationResponse,
missionState: MissionState,
modifier: Modifier = Modifier,
) {
Text(
modifier = Modifier.padding(top = 28.dp),
text = startDateText,
style = MissionMateTypography.heading_md_bold,
color = ColorGray1_FF404249
)
Text(
modifier = Modifier.padding(top = 2.dp, bottom = 20.dp),
text = stringResource(id = R.string.board_before_start_description),
style = MissionMateTypography.body_lg_bold,
color = ColorGray2_FF4F505C
)
BoxWithConstraints {
val width = maxWidth
Column {
BoardGenerator.getBlockListByBoardCount(
boardCount,
numberOfColumns,
passedCount,
missionBoards.boardRewardList.map {
BoardEventItem(
index = it.number,
eventType = it.reward.toEventType()
)
}
).chunked(numberOfColumns).forEach {
Row() {
it.forEach {
Block(
index = it.index,
eventType = it.blockEventType,
type = it.blockType, modifier = Modifier
.weight(1f)
.aspectRatio(1f),
numberOfColumns = numberOfColumns,
isPassed = it.isPassed,
isStartedMission = missionState.isVisiblePiece()
)
}
}
}
}
if (missionState.isVisiblePiece()) {
missionBoards.missionBoards.forEach { block ->
if (block.missionBoardMembers.isNotEmpty()) {
Piece(
index = block.number,
count = block.missionBoardMembers.size,
nickname = if (block.isMyPosition) profile.nickname else block.missionBoardMembers.first().nickname,
sizePerBlock = width / numberOfColumns,
numberOfColumn = numberOfColumns,
isMe = block.isMyPosition,
imageId = if (block.isMyPosition) profile.characterType.toCharacter().imageId else block.missionBoardMembers.first().characterType.toCharacter().imageId,
imageIdForCount = if (block.isMyPosition) profile.characterType.toCharacter().imageId else block.missionBoardMembers.first().characterType.toCharacter().imageId
)
}
}
}
}
}

@SuppressLint("ModifierFactoryUnreferencedReceiver")
fun Modifier.modifierWithClipRect(
scrollState: ScrollState,
missionState: MissionState,
innerModifier: Modifier,
modifier: Modifier = Modifier,
): Modifier {
return modifier
.fillMaxSize()
.navigationBarsPadding()
.then(innerModifier)
.verticalScroll(scrollState)
.statusBarsPadding()
.padding(
top = 180.dp,
start = 24.dp,
end = 24.dp,
bottom = if (missionState.isVisiblePiece()) 188.dp else 46.dp
)
}
Loading

0 comments on commit f677727

Please sign in to comment.