Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
989fed4
feat: 소식화면 StateFlow 적용
parkjiminnnn Nov 25, 2025
1ff88a5
feat: FAQ화면 StateFlow 적용
parkjiminnnn Nov 25, 2025
8a5b801
feat: 분실물 화면 StateFlow 적용
parkjiminnnn Nov 25, 2025
94124c6
refactor: 함수명 변경
parkjiminnnn Nov 25, 2025
06f9348
refactor: 프로퍼티 위치 변경
parkjiminnnn Nov 25, 2025
d70bf78
feat: Festabook Compose Shape 추가
parkjiminnnn Nov 26, 2025
c2664cc
refactor: newsClickListener제거
parkjiminnnn Nov 26, 2025
94c1993
feat: 공통 헤더 구현
parkjiminnnn Nov 26, 2025
faa8ed5
feat: 소식 화면 viewPager, tabLayout Compose마이그레이션
parkjiminnnn Nov 26, 2025
86cc75b
feat: Header 컴포저블 프리뷰 구현
parkjiminnnn Nov 26, 2025
c452e41
refactor: 위임으로 변경
parkjiminnnn Nov 26, 2025
0803163
feat: 알림 클릭시 화면 이동 기능 구현
parkjiminnnn Nov 26, 2025
5a82554
chore: 사용하지 않는 파일 제거
parkjiminnnn Nov 26, 2025
e50328f
refactor: 사용하지 않는 코드 제거
parkjiminnnn Nov 26, 2025
42beb6e
feat: 초기로딩 뷰 추가
parkjiminnnn Nov 26, 2025
fce5b7f
refactor: loadAllFAQs 호출 시 초기 로딩 상태 명시적 전달
parkjiminnnn Nov 26, 2025
74a5036
refactor: 소식 화면 컴포저블 구조 분리 및 개선
parkjiminnnn Nov 27, 2025
62ab991
feat: 프리뷰 구현
parkjiminnnn Nov 27, 2025
2c57ef5
refactor: modifier 선택인자 추가
parkjiminnnn Nov 27, 2025
839cf20
fix: 분실물 화면 새로고침 상태 확인 로직 수정
parkjiminnnn Nov 27, 2025
ba5df24
feat: 공통 spacing 적용
parkjiminnnn Nov 27, 2025
dde92db
feat: 공통 Shape 적용
parkjiminnnn Nov 27, 2025
134a09e
refactor: NewsViewModelTest 수정
parkjiminnnn Nov 28, 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 @@ -38,8 +38,7 @@ interface FestaBookAppGraph {

// splashActivity
@Provides
fun provideAppUpdateManager(application: Application): AppUpdateManager =
AppUpdateManagerFactory.create(application)
fun provideAppUpdateManager(application: Application): AppUpdateManager = AppUpdateManagerFactory.create(application)

// logger
val defaultFirebaseLogger: DefaultFirebaseLogger
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,42 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.daedan.festabook.presentation.theme.FestabookColor
import com.daedan.festabook.presentation.theme.FestabookTheme
import com.daedan.festabook.presentation.theme.festabookShapes

@Composable
fun Modifier.cardBackground(
backgroundColor: Color = FestabookColor.gray100,
borderStroke: Dp = 1.dp,
borderColor: Color = FestabookColor.gray200,
roundedCornerShape: Dp = 16.dp,
shape: Shape = festabookShapes.radius3,
): Modifier =
background(
color = backgroundColor,
shape = RoundedCornerShape(roundedCornerShape),
shape = shape,
).border(
width = borderStroke,
color = borderColor,
shape = RoundedCornerShape(roundedCornerShape),
shape = shape,
)

@Composable
@Preview(showBackground = true)
private fun CardBackgroundPreview() {
Box(
modifier =
Modifier
.cardBackground()
.size(120.dp),
)
FestabookTheme {
Box(
modifier =
Modifier
.cardBackground()
.size(120.dp),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.daedan.festabook.presentation.common.component

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import com.daedan.festabook.presentation.theme.FestabookTypography
import com.daedan.festabook.presentation.theme.festabookSpacing

@Composable
fun Header(
title: String,
modifier: Modifier = Modifier,
style: TextStyle = FestabookTypography.displayLarge,
) {
Text(
text = title,
style = style,
modifier =
modifier
.padding(
top = festabookSpacing.paddingTitleHorizontal,
bottom = festabookSpacing.paddingBody4,
start = festabookSpacing.paddingScreenGutter,
end = festabookSpacing.paddingScreenGutter,
).fillMaxWidth(),
)
}

@Composable
@Preview(showBackground = true)
private fun HeaderPreview() {
Header(title = "FestaBook")
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.daedan.festabook.presentation.common.showToast
import com.daedan.festabook.presentation.home.HomeFragment
import com.daedan.festabook.presentation.home.HomeViewModel
import com.daedan.festabook.presentation.news.NewsFragment
import com.daedan.festabook.presentation.news.NewsViewModel
import com.daedan.festabook.presentation.placeMap.PlaceMapFragment
import com.daedan.festabook.presentation.schedule.ScheduleFragment
import com.daedan.festabook.presentation.setting.SettingFragment
Expand All @@ -44,7 +45,6 @@ import timber.log.Timber
class MainActivity :
AppCompatActivity(),
NotificationPermissionRequester {

@Inject
override lateinit var defaultViewModelProviderFactory: ViewModelProvider.Factory

Expand All @@ -59,6 +59,7 @@ class MainActivity :

private val mainViewModel: MainViewModel by viewModels()
private val homeViewModel: HomeViewModel by viewModels()
private val newsViewModel: NewsViewModel by viewModels()
private val settingViewModel: SettingViewModel by viewModels()

private val notificationPermissionManager by lazy {
Expand Down Expand Up @@ -116,25 +117,24 @@ class MainActivity :
) {
grantResults.forEachIndexed { index, result ->
val text = permissions[index]
when(text) {
when (text) {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION -> {
Manifest.permission.ACCESS_COARSE_LOCATION,
-> {
if (!result.isGranted()) {
showNotificationDeniedSnackbar(
binding.root,
this,
getString(R.string.map_request_location_permission_message)
getString(R.string.map_request_location_permission_message),
)
}
}
}

}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

override fun shouldShowPermissionRationale(permission: String): Boolean =
shouldShowRequestPermissionRationale(permission)
override fun shouldShowPermissionRationale(permission: String): Boolean = shouldShowRequestPermissionRationale(permission)

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
Expand All @@ -145,7 +145,7 @@ class MainActivity :
val canNavigateToNewsScreen =
intent.getBooleanExtra(KEY_CAN_NAVIGATE_TO_NEWS, false)
val noticeIdToExpand = intent.getLongExtra(KEY_NOTICE_ID_TO_EXPAND, INITIALIZED_ID)
if (noticeIdToExpand != INITIALIZED_ID) mainViewModel.expandNoticeItem(noticeIdToExpand)
if (noticeIdToExpand != INITIALIZED_ID) newsViewModel.expandNotice(noticeIdToExpand)

if (canNavigateToNewsScreen) {
binding.bnvMenu.selectedItemId = R.id.item_menu_news
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.daedan.festabook.di.viewmodel.ViewModelKey
import com.daedan.festabook.di.viewmodel.ViewModelScope
import com.daedan.festabook.domain.repository.DeviceRepository
import com.daedan.festabook.domain.repository.FestivalRepository
import com.daedan.festabook.presentation.common.Event
Expand All @@ -25,13 +24,8 @@ class MainViewModel @Inject constructor(
private val _backPressEvent: MutableLiveData<Event<Boolean>> = MutableLiveData()
val backPressEvent: LiveData<Event<Boolean>> get() = _backPressEvent

private val _noticeIdToExpand: MutableLiveData<Long> = MutableLiveData()
val noticeIdToExpand: LiveData<Long> = _noticeIdToExpand

private val _isFirstVisit =
MutableLiveData(
festivalRepository.getIsFirstVisit().getOrDefault(true),
)
MutableLiveData(festivalRepository.getIsFirstVisit().getOrDefault(true))
val isFirstVisit: LiveData<Boolean> get() = _isFirstVisit

private var lastBackPressedTime: Long = 0
Expand Down Expand Up @@ -90,10 +84,6 @@ class MainViewModel @Inject constructor(
}
}

fun expandNoticeItem(announcementId: Long) {
_noticeIdToExpand.value = announcementId
}

companion object {
private const val BACK_PRESS_INTERVAL: Long = 2000L
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package com.daedan.festabook.presentation.news

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider
import com.daedan.festabook.R
import com.daedan.festabook.databinding.FragmentNewsBinding
import com.daedan.festabook.di.fragment.FragmentKey
import com.daedan.festabook.presentation.common.BaseFragment
import com.daedan.festabook.presentation.main.MainViewModel
import com.daedan.festabook.presentation.news.adapter.NewsPagerAdapter
import com.daedan.festabook.presentation.news.faq.model.FAQItemUiModel
import com.daedan.festabook.presentation.news.lost.model.LostUiModel
import com.daedan.festabook.presentation.news.notice.adapter.NewsClickListener
import com.daedan.festabook.presentation.news.notice.model.NoticeUiModel
import com.google.android.material.tabs.TabLayoutMediator
import com.daedan.festabook.presentation.news.component.NewsScreen
import com.daedan.festabook.presentation.theme.FestabookTheme
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesIntoMap
import dev.zacsweers.metro.Inject
Expand All @@ -27,53 +26,25 @@ import dev.zacsweers.metro.binding
)
@FragmentKey(NewsFragment::class)
@Inject
class NewsFragment :
BaseFragment<FragmentNewsBinding>(),
NewsClickListener {
class NewsFragment : BaseFragment<FragmentNewsBinding>() {
override val layoutId: Int = R.layout.fragment_news

@Inject
override lateinit var defaultViewModelProviderFactory: ViewModelProvider.Factory

override val layoutId: Int = R.layout.fragment_news
private val newsViewModel: NewsViewModel by viewModels({ requireActivity() })

private val newsPagerAdapter by lazy {
NewsPagerAdapter(this)
}
private val newsViewModel: NewsViewModel by viewModels()
private val mainViewModel: MainViewModel by viewModels({ requireActivity() })

override fun onViewCreated(
view: View,
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
) {
super.onViewCreated(view, savedInstanceState)
binding.lifecycleOwner = viewLifecycleOwner
setupNewsTabLayout()
mainViewModel.noticeIdToExpand.observe(viewLifecycleOwner) {
binding.vpNews.currentItem = NOTICE_TAB_INDEX
): View =
ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
FestabookTheme {
NewsScreen(newsViewModel = newsViewModel)
}
}
}
}

override fun onNoticeClick(notice: NoticeUiModel) {
newsViewModel.toggleNoticeExpanded(notice)
}

override fun onFAQClick(faqItem: FAQItemUiModel) {
newsViewModel.toggleFAQExpanded(faqItem)
}

override fun onLostGuideItemClick() {
newsViewModel.toggleLostGuideExpanded()
}

private fun setupNewsTabLayout() {
binding.vpNews.adapter = newsPagerAdapter
TabLayoutMediator(binding.tlNews, binding.vpNews) { tab, position ->
val tabNameRes = NewsTab.entries[position].tabNameRes
tab.text = getString(tabNameRes)
}.attach()
}

companion object {
private const val NOTICE_TAB_INDEX: Int = 0
}
}
Loading
Loading