Skip to content
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

[FEAT/#212] 여행 정보 수정 뷰 / UI 구현 #215

Merged
merged 12 commits into from
Mar 4, 2024

Conversation

crownjoe
Copy link
Contributor

@crownjoe crownjoe commented Feb 28, 2024

⛳️ Work Description

  • 여행 정보 수정 뷰 UI 구현
  • 데이트 피커 오류 있었던 것 해결
  • 종료일 먼저 클릭하고 시작일 입력하려고 하면 시작일 max 값이 종료일 됨 ㅋㅋ!! 드디어!!!!!!!!
  • 여행 나가기 누르면 다이얼로그 띄움

📸 Screenshot

1.mp4

📢 To Reviewers

  • 원래 종료일의 시작부분만 했어서 조금 마음에 걸렸는데 드디어 해결했수다 ㅋㅅㅋ~~~야호!!
  • 아 그리고, 플로우 상 여행 투두 뷰에서 오른쪽 상단 위 아이콘 누르면 여행 수정할 수 있길래 todo 패키지에 넣어놓았습니당!
  • 서버 나오면 붙이면서 인텐트 작업 야무지게 할게요!

@crownjoe crownjoe added this to the 2차 스프린트 milestone Feb 28, 2024
@crownjoe crownjoe self-assigned this Feb 28, 2024
@crownjoe crownjoe changed the title [FEAT/#212] 여행 정보 수정 뷰 [FEAT/#212] 여행 정보 수정 뷰 / UI 구현 Feb 28, 2024
@crownjoe crownjoe added 세연 🤤 FEAT ✨ 새로운 기능 구현 UI 💐 UI 작업 labels Feb 28, 2024
Copy link
Member

@chattymin chattymin left a comment

Choose a reason for hiding this comment

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

조폼미~~~

근데 화면에 버튼 없는건 저 페이지 담당자한테 맡기는 건가욤?
글구 화면이 뭔가뭔가 많이 확대돼있는거 같은데 폰 설정 손봐져있는건가욤

Comment on lines 69 to 83
private fun sendDateInfo() {
if (isStart) {
viewModel.startYear.value = binding.dpEditTripDate.year
viewModel.startMonth.value = binding.dpEditTripDate.month + 1
viewModel.startDay.value = binding.dpEditTripDate.dayOfMonth
viewModel.checkStartDateAvailable()

} else {
customEndDate()
viewModel.endYear.value = binding.dpEditTripDate.year
viewModel.endMonth.value = binding.dpEditTripDate.month + 1
viewModel.endDay.value = binding.dpEditTripDate.dayOfMonth
viewModel.checkEndDateAvailable()
}
}
Copy link
Member

Choose a reason for hiding this comment

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

묘하게 viewModel이 자주 나오지 않나요?
with로 묶어도 됩니다!

하지만, viewModel의 값을 acivity나 fragment에서 직접 조작하는 것 보다는 viewModel 내부 함수를 활용한다면 더욱 좋겠죠?

Copy link
Member

Choose a reason for hiding this comment

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

아하 viewModel도 with로 묶을 수 있군요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오호! 좋은 답변 감사합니다! 뷰모델 내부에서 함수 작성하도록 수정했씁니다!

Comment on lines 92 to 100
calendar.set(Calendar.YEAR, viewModel.startYear.value ?: 0)
calendar.set(Calendar.MONTH, viewModel.startMonth.value ?: 0)
calendar.set(Calendar.DAY_OF_MONTH, viewModel.startDay.value ?: 0)
val startDate = calendar.time

calendar.set(Calendar.YEAR, viewModel.endYear.value ?: 0)
calendar.set(Calendar.MONTH, viewModel.endMonth.value ?: 0)
calendar.set(Calendar.DAY_OF_MONTH, viewModel.endDay.value ?: 0)
val endDate = calendar.time
Copy link
Member

Choose a reason for hiding this comment

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

요기두 with로 묶을 수 있을듯~~~

Copy link
Member

Choose a reason for hiding this comment

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

그리고 두번 반복되는 구조가 같다보니까 함수로도 만들 수 있을 것 같네요!
아래는 제가 생각하는 예시~~~~ 다르게 구현해도 너무 조음!!
val endDate = getCalendarTime(viewModel.endYear.value?:0, ...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

앗 답변 감사합니다!
코드 다시 보다보니 이제 시작일과 종료일을 계산해서 비교할 필요가 없어져서 이 부분 코드는 지워도 될 것 같아서 이렇게 수정하였습니다!

android:layout_height="wrap_content"
android:layout_marginTop="37dp"
android:text="@string/edit_trip_info_one_line_info_tv_title"
android:textColor="@color/black_000"
Copy link
Member

Choose a reason for hiding this comment

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

?!?!?!?!?!!?!?!??!?!!?!?!?!?!?
우리 앱에 이런 색이 있었나요!!

Comment on lines 55 to 116
<TextView
android:id="@+id/tv_edit_trip_info_name_title"
style="@style/TextAppearance.Doorip.Body3.Bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="40dp"
android:text="@string/edit_trip_info_tv_title"
app:layout_constraintStart_toStartOf="@id/tb_edit_trip_info"
app:layout_constraintTop_toBottomOf="@id/tb_edit_trip_info" />

<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/et_edit_trip_info_name"
style="@style/edit_text_style"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="8dp"
android:afterTextChanged="@{(text) -> viewModel.checkNameAvailable()}"
android:background="@drawable/shape_rect_4_gray700_line"
android:hint="@string/edit_trip_info_et_name_hint"
android:imeOptions="actionDone"
android:inputType="text"
android:maxLines="3"
android:text="@={viewModel.name}"
android:textAppearance="@style/TextAppearance.Doorip.Detail1.Regular"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_edit_trip_info_name_title" />

<TextView
style="@style/TextAppearance.Doorip.Detail3.Regular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
android:text="@{viewModel.isNameAvailable() == NameState.Blank ? @string/name_blank_error : @string/trip_over_error}"
android:textColor="@color/red_500"
android:visibility="@{(viewModel.isNameAvailable() == NameState.Blank) || (viewModel.isNameAvailable() == NameState.OVER) ? View.VISIBLE : View.GONE}"
app:layout_constraintStart_toStartOf="@id/et_edit_trip_info_name"
app:layout_constraintTop_toBottomOf="@id/et_edit_trip_info_name" />

<TextView
android:id="@+id/tv_name_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@{@string/counter(viewModel.nameLength, viewModel.MAX_TRIP_LEN)}"
android:textColor="@color/gray_200"
app:layout_constraintEnd_toEndOf="@id/et_edit_trip_info_name"
app:layout_constraintTop_toBottomOf="@id/et_edit_trip_info_name" />

<TextView
android:id="@+id/tv_edit_trip_info_on_line_info_title"
style="@style/TextAppearance.Doorip.Body3.Bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="37dp"
android:text="@string/edit_trip_info_one_line_info_tv_title"
android:textColor="@color/black_000"
app:layout_constraintStart_toStartOf="@id/et_edit_trip_info_name"
app:layout_constraintTop_toBottomOf="@id/et_edit_trip_info_name" />
Copy link
Member

Choose a reason for hiding this comment

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

이 복잡한 코드... 복붙하느라 고생 많으셨습니다!

복붙... 불편하지 않으셨나요? 그런당신을 위해 CustomView가 준비되어 있답니다 ㅎㅎㅎㅎ
수정하십쇼!

Comment on lines 40 to 73
private fun observeIsNameAvailable() {
viewModel.isNameAvailable.observe(this) { state ->
setColors(
state,
binding.tvNameCounter,
) { background ->
binding.etEditTripInfoName.background = ResourcesCompat.getDrawable(
this.resources,
background,
theme,
)
}
}
}

private fun setColors(
state: NameState,
counter: TextView,
setBackground: (Int) -> Unit,
) {
val (color, background) = when (state) {
NameState.Empty -> R.color.gray_200 to R.drawable.shape_rect_4_gray200_line
NameState.Success -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line
NameState.Blank -> R.color.red_500 to R.drawable.shape_rect_4_red500_line
NameState.OVER -> R.color.red_500 to R.drawable.shape_rect_4_red500_line
}

setCounterColor(counter, color)
setBackground(background)
}

private fun setCounterColor(counter: TextView, color: Int) {
counter.setTextColor(getColor(color))
}
Copy link
Member

Choose a reason for hiding this comment

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

이런 복잡한것들을 customView를 사용하면 안써도 된답니당~

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit_trip_info_slash"
android:textColor="@color/black_000"
Copy link
Member

Choose a reason for hiding this comment

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

요기두~ black_000은 없서욤

Comment on lines 54 to 67
private fun customEndDate() {
val datePicker = binding.dpEditTripDate
val calendar = Calendar.getInstance()

val currentEndYear = viewModel.startYear.value ?: 0
val currentEndMonth = viewModel.startMonth.value ?: 0
val currentEndDay = viewModel.startDay.value ?: 0

calendar.set(currentEndYear, currentEndMonth - 1, currentEndDay)
datePicker.minDate = calendar.timeInMillis

calendar.set(2100, 0, 1)
datePicker.maxDate = calendar.timeInMillis
}
Copy link
Member

Choose a reason for hiding this comment

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

조세연 폼 미쳤다~~~~

Copy link
Member

Choose a reason for hiding this comment

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

조폼미,,,,👍

Copy link
Member

@leeeyubin leeeyubin left a comment

Choose a reason for hiding this comment

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

갓세연은 데이트피커를 찢어,,,👍👍👍

Comment on lines 54 to 67
private fun customEndDate() {
val datePicker = binding.dpEditTripDate
val calendar = Calendar.getInstance()

val currentEndYear = viewModel.startYear.value ?: 0
val currentEndMonth = viewModel.startMonth.value ?: 0
val currentEndDay = viewModel.startDay.value ?: 0

calendar.set(currentEndYear, currentEndMonth - 1, currentEndDay)
datePicker.minDate = calendar.timeInMillis

calendar.set(2100, 0, 1)
datePicker.maxDate = calendar.timeInMillis
}
Copy link
Member

Choose a reason for hiding this comment

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

조폼미,,,,👍

android:layout_marginTop="4dp"
android:text="@{viewModel.isNameAvailable() == NameState.Blank ? @string/name_blank_error : @string/trip_over_error}"
android:textColor="@color/red_500"
android:visibility="@{(viewModel.isNameAvailable() == NameState.Blank) || (viewModel.isNameAvailable() == NameState.OVER) ? View.VISIBLE : View.GONE}"
Copy link
Member

Choose a reason for hiding this comment

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

데바의 장인이 되셨군여,,

Comment on lines 69 to 83
private fun sendDateInfo() {
if (isStart) {
viewModel.startYear.value = binding.dpEditTripDate.year
viewModel.startMonth.value = binding.dpEditTripDate.month + 1
viewModel.startDay.value = binding.dpEditTripDate.dayOfMonth
viewModel.checkStartDateAvailable()

} else {
customEndDate()
viewModel.endYear.value = binding.dpEditTripDate.year
viewModel.endMonth.value = binding.dpEditTripDate.month + 1
viewModel.endDay.value = binding.dpEditTripDate.dayOfMonth
viewModel.checkEndDateAvailable()
}
}
Copy link
Member

Choose a reason for hiding this comment

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

아하 viewModel도 with로 묶을 수 있군요!

Comment on lines 23 to 25
val isNameAvailable = MutableLiveData(NameState.Empty)
private val isTripAvailable = MutableLiveData(false)
var isCheckTripAvailable = MutableLiveData(false)
Copy link
Member

Choose a reason for hiding this comment

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

isTripAvailable만 private인 거는 이 친구만 다른 곳에서 안 써줘서 그런 건가용...?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

isTripAvailable 은 해당 뷰모델에서만 사용해서 private로 해주었습니다!!

Copy link
Member

@Marchbreeze Marchbreeze left a comment

Choose a reason for hiding this comment

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

이제 지인짜 야무지네요... 말안됨
지금처럼 쭉쭉 성장하는 개발자가 될 수 있길,,, 포항가서도 응원하겟슴다 ^__^

Comment on lines 11 to 12
class BottomSheetEditDateFragment(val viewModel: EditTripInfoViewModel, val isStart: Boolean) :
BaseBottomSheet<FragmentBottomSheetEditDateTripBinding>(R.layout.fragment_bottom_sheet_edit_date_trip) {
Copy link
Member

Choose a reason for hiding this comment

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

뷰모델을 파라미터로 보내게 된다면 종속성이 생기게 됩니다 !!
다른 프래그먼트에서 하는 것처럼, 바텀시트 내부에서 선언해주세요 ~~ 다른 바텀시트들도 수정해주세요

그리고 네이밍 저는 EditDateBottomSheet처럼 바텀시트가 뒤로 가게 통일하는건 어떨까요~ 프래그먼트까지 쓰면 너무 길어지길래 .. ㅎㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네엡 수정하겠습니다!

Comment on lines 32 to 34
val currentStartYear = calendar.get(Calendar.YEAR)
val currentStartMonth = calendar.get(Calendar.MONTH)
val currentStartDay = calendar.get(Calendar.DAY_OF_MONTH)
Copy link
Member

Choose a reason for hiding this comment

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

요 친구들은 맨 아래에 datePicker.updateDate(currentStartYear, currentStartMonth, currentStartDay) 에서만 사용되는 것 같은데, 불필요한 변수 선언 대신 스코프 함수로 처리해보는건 어떨까요! (get때문에 안돌아갈수도 있긴 함)

Suggested change
val currentStartYear = calendar.get(Calendar.YEAR)
val currentStartMonth = calendar.get(Calendar.MONTH)
val currentStartDay = calendar.get(Calendar.DAY_OF_MONTH)
val calendar = Calendar.getInstance()
val datePicker = binding.dpEditTripDate.apply {
updateDate(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
)
}

이런 느낌으로요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

좋은 지적 감사합니다!!! 이렇게 스코프로 수정했습니다!

Comment on lines 54 to 67
private fun customEndDate() {
val datePicker = binding.dpEditTripDate
val calendar = Calendar.getInstance()

val currentEndYear = viewModel.startYear.value ?: 0
val currentEndMonth = viewModel.startMonth.value ?: 0
val currentEndDay = viewModel.startDay.value ?: 0

calendar.set(currentEndYear, currentEndMonth - 1, currentEndDay)
datePicker.minDate = calendar.timeInMillis

calendar.set(2100, 0, 1)
datePicker.maxDate = calendar.timeInMillis
}
Copy link
Member

Choose a reason for hiding this comment

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

이 부분에서 calendar set이 바뀌고 두번 적용되는 것 같은데, 아예 객체를 따로 가져가는건 어떨까요?

Suggested change
private fun customEndDate() {
val datePicker = binding.dpEditTripDate
val calendar = Calendar.getInstance()
val currentEndYear = viewModel.startYear.value ?: 0
val currentEndMonth = viewModel.startMonth.value ?: 0
val currentEndDay = viewModel.startDay.value ?: 0
calendar.set(currentEndYear, currentEndMonth - 1, currentEndDay)
datePicker.minDate = calendar.timeInMillis
calendar.set(2100, 0, 1)
datePicker.maxDate = calendar.timeInMillis
}
binding.dpEditTripDate.apply{
minDate = Calendar.getInstance().apply{
set(
viewModel.startYear.value ?: 0
viewModel.startMonth.value ?: 0
viewModel.startDay.value ?: 0
)
}.timeInMillis
maxDate = Calendar.getInstance().apply{
set(2100,0,1)
}.timeInMillis
}

요런 느낌..?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 객체 두개로 가져가도록 수정하겠습니다!

Comment on lines 18 to 20
private lateinit var startBottomSheetDialog: BottomSheetEditDateFragment
private lateinit var endBottomSheetDialog: BottomSheetEditDateFragment
private var quitDialog: TripQuitDialogFragment? = null
Copy link
Member

Choose a reason for hiding this comment

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

다이얼로그, 바텀시트, 어댑터와 같이 액티비티에 종속되지만 생명주기를 감지할 수 없는 요소들은,
미처 종료를 하지 않아주게 되면 이 액티비티가 종료가 되었을 때에도 혼자서 살아있어 메모리 누수를 유발할 수 있습니다!

20번째 줄에서의 quitDialog 설정해둔 것 처럼, 초기값을 null로 설정해둔 후 onDestroy에서 다시 null로 바꿔주면서 생명주기에 끼워맞추는 작업을 해주신다면 더 좋은 코드를 만드실 수 있어요 ~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 메모리 누수! 체크하겠씁니다!


<import type="android.view.View" />

<import type="com.going.domain.entity.NameState" />
Copy link
Member

Choose a reason for hiding this comment

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

요친구 사용이 없는 것 같습니다 !

app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_edit_trip_info_on_line_info_title">

<TextView
Copy link
Member

Choose a reason for hiding this comment

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

여기 텍스트들에 폰트 적용이 안되어있는 것 같습니다!

Copy link
Member

@chattymin chattymin left a comment

Choose a reason for hiding this comment

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

이제 어엿한 개발자로 성장했군요... 이만 하산해도 좋습니다... 큼

Copy link
Member

@Marchbreeze Marchbreeze left a comment

Choose a reason for hiding this comment

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

좋아용~~~~~~

Comment on lines 18 to 19
private lateinit var startBottomSheetDialog: DateContentBottomSheet
private lateinit var endBottomSheetDialog: DateContentBottomSheet
Copy link
Member

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.

엇 이걸 놓쳤네욥,,ㅠ 수정하겠습니다!

@crownjoe crownjoe merged commit 2137e52 into develop Mar 4, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FEAT ✨ 새로운 기능 구현 UI 💐 UI 작업 세연 🤤
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEAT] 여행 정보 수정 뷰 / UI 구현
4 participants