Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
444f0aa
feat(PlaceMap): 장소 카테고리 라벨 컴포저블 추가
oungsi2000 Dec 5, 2025
36c48ae
feat(PlaceList): 드래그 가능한 BottomSheet 컴포저블 추가
oungsi2000 Dec 6, 2025
7dbef25
feat(PlaceList): 장소 목록 UI를 Compose로 구현
oungsi2000 Dec 6, 2025
add6924
feat(PlaceCategory): 카테고리별 라벨 색상 정의 함수 추가
oungsi2000 Dec 6, 2025
a33a814
feat(PlaceMap): 학교로 돌아가기, 현위치 버튼 Compose 마이그레이션
oungsi2000 Dec 14, 2025
cf83cf9
refactor(PlaceList): ViewModel, Fragment Compose 마이그레이션
oungsi2000 Dec 14, 2025
6e5cb56
refactor(PlaceList): 같은 카테고리 클릭 시 깜빡이는 현상 제거
oungsi2000 Dec 14, 2025
cf328e6
refactor(PlaceList): 데이터 로딩 로직 및 UI 상태 처리 개선
oungsi2000 Dec 14, 2025
bd76738
refactor(PlaceList): BottomSheet 및 RecyclerView 관련 View 시스템 코드 제거
oungsi2000 Dec 14, 2025
b387fd2
refactor(PlaceList): BottomSheet를 Compose로 완전히 전환하고 XML 의존성 제거
oungsi2000 Dec 14, 2025
f2713c9
refactor: AnchordState 추상화
oungsi2000 Dec 14, 2025
d07a626
refactor(ViewModel): 테스트 코드에서 불필요한 테스트와 `getOrAwaitValue` 사용 제거
oungsi2000 Dec 16, 2025
390a72c
feat: 이미지 URL 변환 유틸리티 함수 추가 및 전역 예외 처리기 활성화
oungsi2000 Dec 17, 2025
db24df3
fix: 타임 태그별로 필터링이 되지 않는 버그 해결
oungsi2000 Dec 17, 2025
fe726a2
refactor: 에러 스낵바 노출, hide 상태일 때는 onMapDrag 미수신, 빈 리스트일 때 아무것도 출력하지 않는…
oungsi2000 Dec 17, 2025
115ed91
fix(PlaceList): OffsetDependentLayout 빈 컨텐츠 크래시 수정
oungsi2000 Dec 19, 2025
ee2bcd5
feat(CoilImage): 이미지 URL 변환 로직 통합
oungsi2000 Dec 19, 2025
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
Expand Up @@ -8,7 +8,6 @@ import com.daedan.festabook.di.viewmodel.MetroViewModelFactory
import com.daedan.festabook.logging.DefaultFirebaseLogger
import com.daedan.festabook.presentation.main.MainActivity
import com.daedan.festabook.presentation.placeDetail.PlaceDetailActivity
import com.daedan.festabook.presentation.placeMap.placeList.behavior.PlaceListBottomSheetBehavior
import com.daedan.festabook.presentation.schedule.ScheduleViewModel
import com.daedan.festabook.presentation.splash.SplashActivity
import com.google.android.play.core.appupdate.AppUpdateManager
Expand All @@ -34,8 +33,6 @@ interface FestaBookAppGraph {

fun inject(activity: PlaceDetailActivity)

fun inject(placeListBottomSheetBehavior: PlaceListBottomSheetBehavior<*>)

// splashActivity
@Provides
fun provideAppUpdateManager(application: Application): AppUpdateManager = AppUpdateManagerFactory.create(application)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import android.os.Parcelable
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import com.daedan.festabook.R
import com.daedan.festabook.data.util.ApiResultException
import com.daedan.festabook.presentation.placeMap.placeList.behavior.PlaceListBottomSheetFollowBehavior
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import java.io.Serializable
Expand Down Expand Up @@ -128,8 +126,3 @@ fun Activity.showSnackBar(msg: String) {
}.setActionTextColor(getColor(R.color.blue400))
snackBar.show()
}

fun View.placeListBottomSheetFollowBehavior(): PlaceListBottomSheetFollowBehavior? {
val params = layoutParams as? CoordinatorLayout.LayoutParams
return params?.behavior as? PlaceListBottomSheetFollowBehavior
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade
import com.daedan.festabook.R
import com.daedan.festabook.presentation.common.convertImageUrl

@Composable
fun CoilImage(
Expand All @@ -26,7 +27,7 @@ fun CoilImage(
ImageRequest
.Builder(LocalContext.current)
.apply(builder)
.data(url)
.data(url.convertImageUrl())
.crossfade(true)
.build(),
contentDescription = contentDescription,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.daedan.festabook.presentation.placeMap.model.toUiModel
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesIntoMap
import dev.zacsweers.metro.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
Expand Down Expand Up @@ -67,6 +68,15 @@ class PlaceMapViewModel(
private val _isExceededMaxLength: MutableLiveData<Boolean> = MutableLiveData()
val isExceededMaxLength: LiveData<Boolean> = _isExceededMaxLength

val isExceededMaxLengthFlow: StateFlow<Boolean> =
_isExceededMaxLength
.asFlow()
.stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = false,
)

private val _backToInitialPositionClicked: MutableLiveData<Event<Unit>> = MutableLiveData()
val backToInitialPositionClicked: LiveData<Event<Unit>> = _backToInitialPositionClicked

Expand All @@ -76,6 +86,10 @@ class PlaceMapViewModel(
private val _onMapViewClick: MutableLiveData<Event<Unit>> = MutableLiveData()
val onMapViewClick: LiveData<Event<Unit>> = _onMapViewClick

val onMapViewClickFlow: Flow<Event<Unit>> =
_onMapViewClick
.asFlow()

init {
loadOrganizationGeography()
loadTimeTags()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.daedan.festabook.presentation.placeMap.component

import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Card
import androidx.compose.material3.CardColors
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.daedan.festabook.presentation.placeMap.model.PlaceCategoryUiModel
import com.daedan.festabook.presentation.placeMap.model.getIconId
import com.daedan.festabook.presentation.placeMap.model.getLabelColor
import com.daedan.festabook.presentation.placeMap.model.getTextId
import com.daedan.festabook.presentation.theme.festabookShapes
import kotlin.math.roundToInt

@Composable
fun PlaceCategoryLabel(
category: PlaceCategoryUiModel,
modifier: Modifier = Modifier,
iconColor: Color = category.getLabelColor(),
) {
Card(
shape = festabookShapes.radius1,
colors =
CardColors(
containerColor = getBackgroundColor(iconColor),
contentColor = Color.Unspecified,
disabledContainerColor = getBackgroundColor(iconColor),
disabledContentColor = Color.Unspecified,
),
modifier = modifier,
) {
Row(
modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(category.getIconId()),
contentDescription = stringResource(category.getTextId()),
tint = iconColor,
modifier = Modifier.size(12.dp),
)
Text(
modifier = Modifier.padding(start = 4.dp),
text = stringResource(category.getTextId()),
style = MaterialTheme.typography.labelMedium,
)
}
}
}

private fun getBackgroundColor(color: Color): Color {
// 10% 투명도를 가지게 변경
val alpha = (MAX_ALPHA * ALPHA_RATIO).roundToInt()
return color.copy(alpha = alpha / MAX_ALPHA.toFloat())
}

private const val MAX_ALPHA = 255
private const val ALPHA_RATIO = 0.10f

@Preview(showBackground = true)
@Composable
private fun PlaceCategoryLabelPreview() {
val category = PlaceCategoryUiModel.FOOD_TRUCK
PlaceCategoryLabel(
category = category,
iconColor = Color(0xFF00AB40),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,41 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.daedan.festabook.domain.model.TimeTag
import com.daedan.festabook.presentation.placeMap.model.PlaceCategoryUiModel
import com.daedan.festabook.presentation.placeMap.model.PlaceUiModel
import com.daedan.festabook.presentation.placeMap.placeCategory.component.PlaceCategoryScreen
import com.daedan.festabook.presentation.placeMap.timeTagSpinner.component.TimeTagMenu
import com.daedan.festabook.presentation.theme.FestabookColor
import com.daedan.festabook.presentation.theme.FestabookTheme
import com.naver.maps.map.NaverMap

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PlaceMapScreen(
timeTagTitle: String,
timeTags: List<TimeTag>,
places: List<PlaceUiModel>,
modifier: Modifier = Modifier,
onMapReady: (NaverMap) -> Unit = {},
onPlaceClick: (PlaceUiModel) -> Unit = {},
onTimeTagClick: (TimeTag) -> Unit = {},
Comment on lines +25 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlaceMapScreen에서는 PlaceMapContent를 호출만 하고 있는데 screen이랑 content랑 따로 분리하신 이유가 있으실까용?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlaceMapScreen은 추후 하위 Fragment를 제거한 후 사용될 컴포저블 함수입니다 !
지금은 크게 와닿지 않을 수 있지만 컴포저블 함수를 통합할 때, stateFlow 등으로 복잡해질 것 같아요.

해당 부분은 나중에 PlaceMapScreen을 사용하게 될 때 구조가 변경될 가능성이 높아, 가볍게만 봐주셔도 좋을 것 같습니다 !

) {
PlaceMapContent(
title = timeTagTitle,
timeTags = timeTags,
onMapReady = onMapReady,
onTimeTagClick = onTimeTagClick,
)
}

@Composable
private fun PlaceMapContent(
timeTags: List<TimeTag>,
title: String,
onMapReady: (NaverMap) -> Unit,
Expand Down Expand Up @@ -42,6 +67,35 @@ fun PlaceMapScreen(
).padding(horizontal = 24.dp),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나중에 지도 전용 spacing을 만드는 것도 나쁘지 않을 것 같아용

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlaceMapScreen에 통합할 때 만들겠습니다 !

)
}
PlaceCategoryScreen()
}
}
}

@Preview(showBackground = true)
@Composable
private fun PlaceMapScreenPreview() {
FestabookTheme {
PlaceMapScreen(
timeTagTitle = "테스트",
timeTags =
listOf(
TimeTag(1, "테스트1"),
TimeTag(2, "테스트2"),
),
places =
(0..100).map {
PlaceUiModel(
id = it.toLong(),
imageUrl = null,
title = "테스트테스트테스트테스트테스트테스트테스트테스트테스트테스트",
description = "테스트테스트테스트테스트테스트테스트테스트테스트테스트테스트테스트",
location = "테스트테스트테스트테스트테스트테스트테스트테스트테스트",
category = PlaceCategoryUiModel.BAR,
isBookmarked = true,
timeTagId = listOf(1),
)
},
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.daedan.festabook.presentation.placeMap.model

import androidx.compose.ui.graphics.Color
import com.daedan.festabook.R
import com.daedan.festabook.domain.model.PlaceCategory
import com.daedan.festabook.presentation.placeMap.mapManager.internal.OverlayImageManager
Expand Down Expand Up @@ -65,6 +66,14 @@ val PlaceCategoryUiModel.Companion.iconResources: List<Int>
R.drawable.ic_extra_selected,
)

fun PlaceCategoryUiModel.getLabelColor() =
when (this) {
PlaceCategoryUiModel.BOOTH -> Color(0xFF0094FF)
PlaceCategoryUiModel.FOOD_TRUCK -> Color(0xFF00AB40)
PlaceCategoryUiModel.BAR -> Color(0xFFFF9D00)
else -> Color.Unspecified
Comment on lines +71 to +74
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하드 코딩 해치워주세요..!!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도 추후 전용 spacing을 만들 때 함께 해치우겠습니다..!

}

fun OverlayImageManager.getNormalIcon(category: PlaceCategoryUiModel): OverlayImage? =
when (category) {
PlaceCategoryUiModel.BOOTH -> getImage(R.drawable.ic_booth)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,4 @@ sealed interface PlaceListUiState<T> {
data class Error<T>(
val throwable: Throwable,
) : PlaceListUiState<T>

class Complete<T> : PlaceListUiState<T>
}

This file was deleted.

Loading