-
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
[FEAT/#212] 여행 정보 수정 뷰 / UI 구현 #215
Conversation
…into feat/#212-edit-trip-info
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.
조폼미~~~
근데 화면에 버튼 없는건 저 페이지 담당자한테 맡기는 건가욤?
글구 화면이 뭔가뭔가 많이 확대돼있는거 같은데 폰 설정 손봐져있는건가욤
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() | ||
} | ||
} |
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.
묘하게 viewModel이 자주 나오지 않나요?
with로 묶어도 됩니다!
하지만, viewModel의 값을 acivity나 fragment에서 직접 조작하는 것 보다는 viewModel 내부 함수를 활용한다면 더욱 좋겠죠?
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.
아하 viewModel도 with로 묶을 수 있군요!
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.
오호! 좋은 답변 감사합니다! 뷰모델 내부에서 함수 작성하도록 수정했씁니다!
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 |
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.
요기두 with로 묶을 수 있을듯~~~
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.
그리고 두번 반복되는 구조가 같다보니까 함수로도 만들 수 있을 것 같네요!
아래는 제가 생각하는 예시~~~~ 다르게 구현해도 너무 조음!!
val endDate = getCalendarTime(viewModel.endYear.value?:0, ...)
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.
앗 답변 감사합니다!
코드 다시 보다보니 이제 시작일과 종료일을 계산해서 비교할 필요가 없어져서 이 부분 코드는 지워도 될 것 같아서 이렇게 수정하였습니다!
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" |
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.
?!?!?!?!?!!?!?!??!?!!?!?!?!?!?
우리 앱에 이런 색이 있었나요!!
<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" /> |
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.
이 복잡한 코드... 복붙하느라 고생 많으셨습니다!
복붙... 불편하지 않으셨나요? 그런당신을 위해 CustomView가 준비되어 있답니다 ㅎㅎㅎㅎ
수정하십쇼!
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)) | ||
} |
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.
이런 복잡한것들을 customView를 사용하면 안써도 된답니당~
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:text="@string/edit_trip_info_slash" | ||
android:textColor="@color/black_000" |
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.
요기두~ black_000은 없서욤
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 | ||
} |
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.
조세연 폼 미쳤다~~~~
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.
조폼미,,,,👍
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.
갓세연은 데이트피커를 찢어,,,👍👍👍
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 | ||
} |
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.
조폼미,,,,👍
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}" |
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.
데바의 장인이 되셨군여,,
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() | ||
} | ||
} |
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.
아하 viewModel도 with로 묶을 수 있군요!
val isNameAvailable = MutableLiveData(NameState.Empty) | ||
private val isTripAvailable = MutableLiveData(false) | ||
var isCheckTripAvailable = MutableLiveData(false) |
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.
isTripAvailable
만 private인 거는 이 친구만 다른 곳에서 안 써줘서 그런 건가용...?
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.
넵 isTripAvailable
은 해당 뷰모델에서만 사용해서 private로 해주었습니다!!
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.
이제 지인짜 야무지네요... 말안됨
지금처럼 쭉쭉 성장하는 개발자가 될 수 있길,,, 포항가서도 응원하겟슴다 ^__^
class BottomSheetEditDateFragment(val viewModel: EditTripInfoViewModel, val isStart: Boolean) : | ||
BaseBottomSheet<FragmentBottomSheetEditDateTripBinding>(R.layout.fragment_bottom_sheet_edit_date_trip) { |
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.
뷰모델을 파라미터로 보내게 된다면 종속성이 생기게 됩니다 !!
다른 프래그먼트에서 하는 것처럼, 바텀시트 내부에서 선언해주세요 ~~ 다른 바텀시트들도 수정해주세요
그리고 네이밍 저는 EditDateBottomSheet처럼 바텀시트가 뒤로 가게 통일하는건 어떨까요~ 프래그먼트까지 쓰면 너무 길어지길래 .. ㅎㅎ
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.
네엡 수정하겠습니다!
val currentStartYear = calendar.get(Calendar.YEAR) | ||
val currentStartMonth = calendar.get(Calendar.MONTH) | ||
val currentStartDay = calendar.get(Calendar.DAY_OF_MONTH) |
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.
요 친구들은 맨 아래에 datePicker.updateDate(currentStartYear, currentStartMonth, currentStartDay)
에서만 사용되는 것 같은데, 불필요한 변수 선언 대신 스코프 함수로 처리해보는건 어떨까요! (get때문에 안돌아갈수도 있긴 함)
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) | |
) | |
} |
이런 느낌으로요!
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.
좋은 지적 감사합니다!!! 이렇게 스코프로 수정했습니다!
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 | ||
} |
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.
이 부분에서 calendar set이 바뀌고 두번 적용되는 것 같은데, 아예 객체를 따로 가져가는건 어떨까요?
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 | |
} |
요런 느낌..?
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.
넵 객체 두개로 가져가도록 수정하겠습니다!
private lateinit var startBottomSheetDialog: BottomSheetEditDateFragment | ||
private lateinit var endBottomSheetDialog: BottomSheetEditDateFragment | ||
private var quitDialog: TripQuitDialogFragment? = null |
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.
다이얼로그, 바텀시트, 어댑터와 같이 액티비티에 종속되지만 생명주기를 감지할 수 없는 요소들은,
미처 종료를 하지 않아주게 되면 이 액티비티가 종료가 되었을 때에도 혼자서 살아있어 메모리 누수를 유발할 수 있습니다!
20번째 줄에서의 quitDialog 설정해둔 것 처럼, 초기값을 null로 설정해둔 후 onDestroy에서 다시 null로 바꿔주면서 생명주기에 끼워맞추는 작업을 해주신다면 더 좋은 코드를 만드실 수 있어요 ~
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.
넵 메모리 누수! 체크하겠씁니다!
|
||
<import type="android.view.View" /> | ||
|
||
<import type="com.going.domain.entity.NameState" /> |
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.
요친구 사용이 없는 것 같습니다 !
app:layout_constraintStart_toStartOf="parent" | ||
app:layout_constraintTop_toBottomOf="@id/tv_edit_trip_info_on_line_info_title"> | ||
|
||
<TextView |
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.
여기 텍스트들에 폰트 적용이 안되어있는 것 같습니다!
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.
이제 어엿한 개발자로 성장했군요... 이만 하산해도 좋습니다... 큼
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.
좋아용~~~~~~
private lateinit var startBottomSheetDialog: DateContentBottomSheet | ||
private lateinit var endBottomSheetDialog: DateContentBottomSheet |
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.
여기 뷰 다이얼로그들도 생명주기 따라 해제되도록 해제해주면 더 좋을 것 같아요 !
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.
엇 이걸 놓쳤네욥,,ㅠ 수정하겠습니다!
⛳️ Work Description
📸 Screenshot
1.mp4
📢 To Reviewers