-
Notifications
You must be signed in to change notification settings - Fork 2
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
refactor : EventDetail 코드 리팩토링 #282
The head ref may contain hidden characters: "Feature/#277-\uC2A4\uCE87_\uCF54\uB4DC_\uB9AC\uD329\uD1A0\uB9C1"
Changes from all commits
35a1998
194191d
b4c4b40
7bf4d1c
bbd4406
811782f
0e92d64
111d9dc
9a1b092
5087a0a
6fbb8b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,17 @@ | ||
package com.emmsale.data.eventdetail | ||
|
||
import java.time.LocalDateTime | ||
|
||
data class EventDetail( | ||
val id: Long, | ||
val name: String, | ||
val status: String, | ||
val location: String, | ||
val startDate: String, | ||
val endDate: String, | ||
val startDate: LocalDateTime, | ||
val endDate: LocalDateTime, | ||
val informationUrl: String, | ||
val tags: List<String>, | ||
val imageUrl: String?, | ||
val postImageUrl: String?, | ||
val remainingDays: Int, | ||
val type: String, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.emmsale.data.eventdetail.mapper | ||
|
||
import com.emmsale.data.eventdetail.EventDetail | ||
import com.emmsale.data.eventdetail.dto.EventDetailApiModel | ||
import java.time.LocalDateTime | ||
import java.time.format.DateTimeFormatter | ||
|
||
fun EventDetailApiModel.toData(): EventDetail = EventDetail( | ||
id = id, | ||
name = name, | ||
status = status, | ||
location = location, | ||
startDate = startDate.toLocalDateTime(), | ||
endDate = endDate.toLocalDateTime(), | ||
informationUrl = informationUrl, | ||
tags = tags, | ||
postImageUrl = imageUrl, | ||
remainingDays = remainingDays, | ||
type = type, | ||
) | ||
|
||
private fun String.toLocalDateTime(): LocalDateTime { | ||
val format = DateTimeFormatter.ofPattern("yyyy:MM:dd:HH:mm:ss") | ||
return LocalDateTime.parse(this, format) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,72 @@ | ||
package com.emmsale.presentation.eventdetail | ||
package com.emmsale.presentation.ui.eventdetail | ||
|
||
import android.content.Context | ||
import android.content.Intent | ||
import android.os.Bundle | ||
import androidx.activity.viewModels | ||
import androidx.appcompat.app.AppCompatActivity | ||
import com.emmsale.R | ||
import com.emmsale.databinding.ActivityEventDetailBinding | ||
import com.emmsale.presentation.common.extension.showToast | ||
import com.emmsale.presentation.ui.eventdetail.EventDetailFragmentStateAdpater | ||
import com.emmsale.presentation.ui.eventdetail.EventDetailViewModel | ||
import com.emmsale.presentation.ui.eventdetail.EventTag | ||
import com.emmsale.presentation.ui.eventdetail.uistate.EventDetailUiState | ||
import com.google.android.material.tabs.TabLayoutMediator | ||
|
||
class EventDetailActivity : AppCompatActivity() { | ||
private lateinit var binding: ActivityEventDetailBinding | ||
private val viewModel: EventDetailViewModel by viewModels { EventDetailViewModel.factory } | ||
private val eventId: Long by lazy { | ||
intent.getLongExtra(EVENT_ID_KEY, DEFAULT_EVENT_ID) | ||
} | ||
|
||
private val viewModel: EventDetailViewModel by viewModels { EventDetailViewModel.factory(eventId) } | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setUpBinding() | ||
setUpEventDetail() | ||
setBackPress() | ||
viewModel.fetchEventDetail(eventId) | ||
initBackPressButtonClickListener() | ||
} | ||
|
||
private fun setUpBinding() { | ||
binding = ActivityEventDetailBinding.inflate(layoutInflater) | ||
setContentView(binding.root) | ||
binding.lifecycleOwner = this | ||
binding.vm = viewModel | ||
Comment on lines
+29
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 코드는 setContentView 이후에 호출해주는 것도 좋을 것 같아요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 확인이요 |
||
} | ||
|
||
private fun setUpEventDetail() { | ||
viewModel.eventDetail.observe(this) { eventDetailUiState -> | ||
when (eventDetailUiState) { | ||
is EventDetailUiState.Success -> { | ||
binding.eventDetail = eventDetailUiState | ||
addTag(eventDetailUiState.tags) | ||
initFragmentStateAdapter( | ||
eventDetailUiState.informationUrl, | ||
eventDetailUiState.imageUrl, | ||
) | ||
} | ||
|
||
else -> showToast("행사 받아오기 실패") | ||
if (eventDetailUiState.isError) { | ||
showToast(getString(R.string.eventdetail_fetch_eventdetail_error_message)) | ||
} else { | ||
addEventTag(eventDetailUiState.tags) | ||
initFragmentStateAdapter( | ||
eventDetailUiState.informationUrl, | ||
eventDetailUiState.imageUrl, | ||
) | ||
} | ||
} | ||
} | ||
|
||
private fun initFragmentStateAdapter(informationUrl: String, imageUrl: String?) { | ||
binding.vpEventdetail.adapter = | ||
EventDetailFragmentStateAdpater(this, eventId, informationUrl, imageUrl) | ||
TabLayoutMediator(binding.tablayoutEventdetail, binding.vpEventdetail) { tab, position -> | ||
when (position) { | ||
INFORMATION_TAB_POSITION -> tab.text = "상세 정보" | ||
COMMENT_TAB_POSITION -> tab.text = "댓글" | ||
RECRUITMENT_TAB_POSITION -> tab.text = "같이가요" | ||
} | ||
val tabNames = listOf( | ||
getString(R.string.eventdetail_tab_infromation), | ||
getString(R.string.eventdetail_tab_comment), | ||
getString(R.string.eventdetail_tab_recruitment), | ||
) | ||
TabLayoutMediator(binding.tablayoutEventdetail, binding.vpEventdetail) { _, _ -> | ||
tabNames | ||
}.attach() | ||
binding.vpEventdetail.isUserInputEnabled = false | ||
} | ||
|
||
private fun addTag(tags: List<String>) { | ||
tags.forEach { binding.chipgroupEvendetailTags.addView(createTag(it)) } | ||
private fun addEventTag(tags: List<String>) { | ||
tags.forEach { binding.chipgroupEvendetailTags.addView(createEventTag(it)) } | ||
} | ||
|
||
private fun createTag(tag: String) = EventTag(this).apply { | ||
private fun createEventTag(tag: String) = EventTag(this).apply { | ||
text = tag | ||
} | ||
|
||
private fun setBackPress() { | ||
private fun initBackPressButtonClickListener() { | ||
binding.ivEventdetailBackpress.setOnClickListener { | ||
finish() | ||
} | ||
|
@@ -80,10 +75,6 @@ class EventDetailActivity : AppCompatActivity() { | |
companion object { | ||
private const val EVENT_ID_KEY = "EVENT_ID_KEY" | ||
private const val DEFAULT_EVENT_ID = 1L | ||
private const val INFORMATION_TAB_POSITION = 0 | ||
private const val COMMENT_TAB_POSITION = 1 | ||
private const val RECRUITMENT_TAB_POSITION = 2 | ||
|
||
fun startActivity(context: Context, eventId: Long) { | ||
val intent = Intent(context, EventDetailActivity::class.java) | ||
intent.putExtra(EVENT_ID_KEY, eventId) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,63 @@ | ||
package com.emmsale.presentation.ui.eventdetail | ||
|
||
import androidx.lifecycle.LiveData | ||
import androidx.lifecycle.MutableLiveData | ||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.viewModelScope | ||
import com.emmsale.data.common.ApiError | ||
import com.emmsale.data.common.ApiException | ||
import com.emmsale.data.common.ApiSuccess | ||
import com.emmsale.data.eventdetail.EventDetail | ||
import com.emmsale.data.eventdetail.EventDetailRepository | ||
import com.emmsale.data.member.MemberRepository | ||
import com.emmsale.presentation.KerdyApplication | ||
import com.emmsale.presentation.common.ViewModelFactory | ||
import com.emmsale.presentation.common.livedata.NotNullLiveData | ||
import com.emmsale.presentation.common.livedata.NotNullMutableLiveData | ||
import com.emmsale.presentation.ui.eventdetail.uistate.EventDetailUiState | ||
import kotlinx.coroutines.launch | ||
|
||
class EventDetailViewModel( | ||
private val eventId: Long, | ||
private val eventDetailRepository: EventDetailRepository, | ||
private val memberRepository: MemberRepository, | ||
) : ViewModel() { | ||
|
||
private val _eventDetail: MutableLiveData<EventDetailUiState> = | ||
MutableLiveData<EventDetailUiState>() | ||
val eventDetail: LiveData<EventDetailUiState> | ||
get() = _eventDetail | ||
private val _eventDetail: NotNullMutableLiveData<EventDetailUiState> = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. _eventDetail의 타입을 명시해주지 않으면 한 줄에 깔끔하게 작성할 수 있어요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 무조건 타입을 명시해야 한다고 생각합니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 어떤 타입인지 명확하게 적는 것이 실수를 방지한다고 생각해요 |
||
NotNullMutableLiveData(EventDetailUiState()) | ||
val eventDetail: NotNullLiveData<EventDetailUiState> = _eventDetail | ||
|
||
fun fetchEventDetail(id: Long) { | ||
viewModelScope.launch { | ||
when (val result = eventDetailRepository.fetchEventDetail(id)) { | ||
is ApiSuccess -> _eventDetail.postValue( | ||
EventDetailUiState.from(result.data), | ||
) | ||
init { | ||
fetchEventDetail(eventId) | ||
} | ||
|
||
is ApiError -> _eventDetail.postValue(EventDetailUiState.Error) | ||
is ApiException -> _eventDetail.postValue(EventDetailUiState.Error) | ||
private fun fetchEventDetail(id: Long) { | ||
setLoadingState(true) | ||
viewModelScope.launch { | ||
when (val result = eventDetailRepository.getEventDetail(id)) { | ||
is ApiSuccess -> fetchSuccessEventDetail(result.data) | ||
is ApiError -> changeToErrorState() | ||
is ApiException -> changeToErrorState() | ||
} | ||
} | ||
} | ||
|
||
private fun setLoadingState(state: Boolean) { | ||
_eventDetail.value = _eventDetail.value.copy(isLoading = state) | ||
} | ||
|
||
private fun fetchSuccessEventDetail(eventDetail: EventDetail) { | ||
_eventDetail.value = EventDetailUiState.from(eventDetail) | ||
} | ||
|
||
private fun changeToErrorState() { | ||
_eventDetail.value = _eventDetail.value.copy( | ||
isError = true, | ||
isLoading = false, | ||
) | ||
} | ||
|
||
companion object { | ||
val factory = ViewModelFactory { | ||
fun factory(eventId: Long) = ViewModelFactory { | ||
EventDetailViewModel( | ||
eventId, | ||
eventDetailRepository = KerdyApplication.repositoryContainer.eventDetailRepository, | ||
memberRepository = KerdyApplication.repositoryContainer.memberRepository, | ||
) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
데이터 모델에서 날짜 표현을 위해 String에서 LocalDateTime으로 타입을 바꾼 것 좋네요 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
감사요