diff --git a/presentation/src/main/java/com/going/presentation/designsystem/edittext/EmojiCounterEditText.kt b/presentation/src/main/java/com/going/presentation/designsystem/edittext/EmojiCounterEditText.kt index 2ed5a129..4dd8d26a 100644 --- a/presentation/src/main/java/com/going/presentation/designsystem/edittext/EmojiCounterEditText.kt +++ b/presentation/src/main/java/com/going/presentation/designsystem/edittext/EmojiCounterEditText.kt @@ -2,6 +2,7 @@ package com.going.presentation.designsystem.edittext import android.content.Context import android.content.res.TypedArray +import android.text.InputType import android.text.method.ScrollingMovementMethod import android.util.AttributeSet import android.view.LayoutInflater diff --git a/presentation/src/main/java/com/going/presentation/designsystem/edittext/EmojiCounterEditTextMultiLine.kt b/presentation/src/main/java/com/going/presentation/designsystem/edittext/EmojiCounterEditTextMultiLine.kt new file mode 100644 index 00000000..25166983 --- /dev/null +++ b/presentation/src/main/java/com/going/presentation/designsystem/edittext/EmojiCounterEditTextMultiLine.kt @@ -0,0 +1,152 @@ +package com.going.presentation.designsystem.edittext + +import android.content.Context +import android.content.res.TypedArray +import android.text.method.ScrollingMovementMethod +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View.OnFocusChangeListener +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.res.ResourcesCompat +import androidx.core.view.isVisible +import androidx.core.widget.doAfterTextChanged +import com.going.presentation.R +import com.going.presentation.databinding.ViewEmojiCounterEdittextMultilineBinding +import com.going.ui.extension.colorOf +import com.going.ui.extension.getGraphemeLength +import com.going.ui.extension.setOnSingleClickListener + +class EmojiCounterEditTextMultiLine(context: Context, attrs: AttributeSet) : + ConstraintLayout(context, attrs) { + + private val binding: ViewEmojiCounterEdittextMultilineBinding + + private var maxLen: Int = 0 + private var canBlankError: Boolean = false + lateinit var overWarning: String + var blankWarning: String = "" + + private val editTextStateMap by lazy { + mapOf( + EditTextState.SUCCESS to Triple( + R.color.gray_700, + R.drawable.shape_rect_4_gray700_line, + "" + ), + EditTextState.EMPTY to Triple( + R.color.gray_200, + R.drawable.shape_rect_4_gray200_line, + "" + ), + EditTextState.BLANK to Triple( + R.color.red_500, + R.drawable.shape_rect_4_red500_line, + blankWarning + ), + EditTextState.OVER to Triple( + R.color.red_500, + R.drawable.shape_rect_4_red500_line, + overWarning + ), + ) + } + + val editText + get() = binding.etEmojiCounterEtContent + + var state: EditTextState = EditTextState.EMPTY + set(value) { + field = value + + binding.run { + btnDeleteText.isVisible = + (value != EditTextState.EMPTY) && etEmojiCounterEtContent.hasFocus() + } + + editTextStateMap[field]?.let { setEditTextState(it) } + } + + init { + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.EmojiCounterEditText) + binding = ViewEmojiCounterEdittextMultilineBinding.inflate( + LayoutInflater.from(context), + this, + true, + ) + + initDeleteBtnClickListener() + setBindingContent(typedArray) + initEtFocusChangeListener() + + typedArray.recycle() + + checkTextAvailable() + } + + private fun initDeleteBtnClickListener() = with(binding) { + btnDeleteText.setOnSingleClickListener { + etEmojiCounterEtContent.text = null + } + } + + private fun setBindingContent(typedArray: TypedArray) { + with(binding) { + tvEmojiCounterEtTitle.text = + typedArray.getString(R.styleable.EmojiCounterEditText_title) + etEmojiCounterEtContent.hint = + typedArray.getString(R.styleable.EmojiCounterEditText_hint) + etEmojiCounterEtContent.minLines = + typedArray.getInt(R.styleable.EmojiCounterEditText_minLines, 1) + etEmojiCounterEtContent.maxLines = + typedArray.getInt(R.styleable.EmojiCounterEditText_minLines, 2) + etEmojiCounterEtContent.movementMethod = ScrollingMovementMethod() + tvEmojiCounterEtNameCounter.text = context.getString(R.string.counter, 0, maxLen) + } + canBlankError = typedArray.getBoolean(R.styleable.EmojiCounterEditText_canBlankError, false) + } + + private fun initEtFocusChangeListener() { + binding.etEmojiCounterEtContent.onFocusChangeListener = + OnFocusChangeListener { _, hasFocus -> + binding.btnDeleteText.isVisible = hasFocus && (state != EditTextState.EMPTY) + } + } + + private fun checkTextAvailable() { + binding.etEmojiCounterEtContent.doAfterTextChanged { text -> + val len = text.toString().getGraphemeLength() + + state = when { + text.toString().isBlank() && len != 0 && canBlankError -> EditTextState.BLANK + len > maxLen -> EditTextState.OVER + len > 0 -> EditTextState.SUCCESS + else -> EditTextState.EMPTY + } + + binding.tvEmojiCounterEtNameCounter.text = + context.getString(R.string.counter, len, maxLen) + } + } + + fun setMaxLen(len: Int) { + maxLen = len + binding.tvEmojiCounterEtNameCounter.text = context.getString(R.string.counter, 0, maxLen) + } + + private fun setEditTextState(info: Triple) { + val color = info.first + val background = info.second + val text = info.third + + with(binding) { + tvEmojiCounterEtWarningMessage.isVisible = color == R.color.red_500 + tvEmojiCounterEtNameCounter.setTextColor(context.colorOf(color)) + etEmojiCounterEtContent.background = ResourcesCompat.getDrawable( + this@EmojiCounterEditTextMultiLine.resources, + background, + context.theme, + ) + tvEmojiCounterEtWarningMessage.text = text + } + } +} diff --git a/presentation/src/main/java/com/going/presentation/profile/edit/ProfileEditActivity.kt b/presentation/src/main/java/com/going/presentation/profile/edit/ProfileEditActivity.kt index d1422875..17336779 100644 --- a/presentation/src/main/java/com/going/presentation/profile/edit/ProfileEditActivity.kt +++ b/presentation/src/main/java/com/going/presentation/profile/edit/ProfileEditActivity.kt @@ -53,13 +53,13 @@ class ProfileEditActivity : private fun observeNameTextChanged() { binding.etProfileEditNickname.editText.doAfterTextChanged { name -> - viewModel.checkIsNameChanged(name.toString()) + viewModel.checkIsNameChanged(name.toString(), binding.etProfileEditNickname.state, binding.etProfileEditInfo.state) } } private fun observeInfoTextChanged() { binding.etProfileEditInfo.editText.doAfterTextChanged { info -> - viewModel.checkIsInfoChanged(info.toString()) + viewModel.checkIsInfoChanged(info.toString(), binding.etProfileEditNickname.state, binding.etProfileEditInfo.state) } } diff --git a/presentation/src/main/java/com/going/presentation/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/going/presentation/profile/edit/ProfileEditViewModel.kt index 5735bff2..a7a9cb97 100644 --- a/presentation/src/main/java/com/going/presentation/profile/edit/ProfileEditViewModel.kt +++ b/presentation/src/main/java/com/going/presentation/profile/edit/ProfileEditViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.going.domain.entity.request.UserProfileRequestModel import com.going.domain.repository.ProfileRepository +import com.going.presentation.designsystem.edittext.EditTextState import com.going.presentation.onboarding.signup.SignUpViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow @@ -40,23 +41,23 @@ class ProfileEditViewModel @Inject constructor( defaultInfo = info } - fun checkIsNameChanged(name: String) { + fun checkIsNameChanged(name: String, nameState: EditTextState, infoState: EditTextState) { nowName = name isNameChanged = name != defaultName - checkIsValueChanged() + checkIsValueChanged(nameState, infoState) } - fun checkIsInfoChanged(info: String) { + fun checkIsInfoChanged(info: String, nameState: EditTextState, infoState: EditTextState) { nowInfo = info isInfoChanged = info != defaultInfo - checkIsValueChanged() + checkIsValueChanged(nameState, infoState) } - private fun checkIsValueChanged() { + private fun checkIsValueChanged(nameState: EditTextState, infoState: EditTextState) { _isValueChanged.value = - nowName.isNotBlank() && nowName.length <= getMaxNameLen() && nowInfo.isNotBlank() && nowInfo.length <= getMaxInfoLen() && (isInfoChanged || isNameChanged) + nowName.isNotBlank() && nameState == EditTextState.SUCCESS && nowInfo.isNotBlank() && infoState == EditTextState.SUCCESS && (isInfoChanged || isNameChanged) } fun patchUserInfo() { diff --git a/presentation/src/main/java/com/going/presentation/profile/participant/ParticipantProfileActivity.kt b/presentation/src/main/java/com/going/presentation/profile/participant/ParticipantProfileActivity.kt index 9c10e4ba..ff889a19 100644 --- a/presentation/src/main/java/com/going/presentation/profile/participant/ParticipantProfileActivity.kt +++ b/presentation/src/main/java/com/going/presentation/profile/participant/ParticipantProfileActivity.kt @@ -88,6 +88,8 @@ class ParticipantProfileActivity : } } + setFragmentHeight(profile.result == -1) + tvProfileName.text = profile.name tvProfileOneLine.text = profile.intro @@ -149,7 +151,7 @@ class ParticipantProfileActivity : setFragmentHeight() } - private fun setFragmentHeight(temp: Boolean = true) { + private fun setFragmentHeight(isEmpty: Boolean = true) { val displayHeight = getWindowHeight() val toolbarHeight = binding.tbTripProfile.height val appBarHeight = binding.appbarTripProfile.totalScrollRange @@ -157,7 +159,7 @@ class ParticipantProfileActivity : binding.vpTripProfile.layoutParams = binding.vpTripProfile.layoutParams.also { it.height = - if (temp) displayHeight - toolbarHeight - appBarHeight - tabHeight else displayHeight - toolbarHeight - tabHeight + if (isEmpty) displayHeight - toolbarHeight - appBarHeight - tabHeight else displayHeight - toolbarHeight - tabHeight } } diff --git a/presentation/src/main/java/com/going/presentation/todo/detail/TodoDetailActivity.kt b/presentation/src/main/java/com/going/presentation/todo/detail/TodoDetailActivity.kt index 59d17ed7..293e5e8a 100644 --- a/presentation/src/main/java/com/going/presentation/todo/detail/TodoDetailActivity.kt +++ b/presentation/src/main/java/com/going/presentation/todo/detail/TodoDetailActivity.kt @@ -118,7 +118,6 @@ class TodoDetailActivity : with(binding) { tvTodoCreateMemoTitle.isVisible = true etTodoCreateMemo.isVisible = true - tvTodoMemoCounter.isVisible = true } if (state.data.memo.isBlank()) { @@ -127,7 +126,6 @@ class TodoDetailActivity : drawableOf(R.drawable.shape_rect_4_gray200_line) etTodoCreateMemo.text = stringOf(R.string.my_todo_create_tv_memo_hint) etTodoCreateMemo.setTextColor(colorOf(R.color.gray_200)) - tvTodoMemoCounter.isVisible = false } } } diff --git a/presentation/src/main/java/com/going/presentation/todo/detail/TodoDetailViewModel.kt b/presentation/src/main/java/com/going/presentation/todo/detail/TodoDetailViewModel.kt index 8e5b783b..17c21df3 100644 --- a/presentation/src/main/java/com/going/presentation/todo/detail/TodoDetailViewModel.kt +++ b/presentation/src/main/java/com/going/presentation/todo/detail/TodoDetailViewModel.kt @@ -60,10 +60,4 @@ class TodoDetailViewModel @Inject constructor( } } } - - companion object { - const val MAX_TODO_LEN = 15 - const val MAX_MEMO_LEN = 1000 - } - } \ No newline at end of file diff --git a/presentation/src/main/java/com/going/presentation/todo/edittrip/edit/EditTripActivity.kt b/presentation/src/main/java/com/going/presentation/todo/edittrip/edit/EditTripActivity.kt index ab33a6ba..95192468 100644 --- a/presentation/src/main/java/com/going/presentation/todo/edittrip/edit/EditTripActivity.kt +++ b/presentation/src/main/java/com/going/presentation/todo/edittrip/edit/EditTripActivity.kt @@ -37,7 +37,7 @@ class EditTripActivity : } private fun initBindingViewModel() { - binding.viewModel = viewModel + binding.vm = viewModel } private fun getIntentData() { @@ -50,10 +50,9 @@ class EditTripActivity : when (state) { is UiState.Success -> { with(binding) { - tvEditTripName.text = viewModel?.title - tvEditTripInfoStartDate.text = viewModel?.startDate - tvEditTripInfoEndDate.text = viewModel?.endDate - viewModel?.gettitleLength() + tvEditTripName.text = viewModel.title + tvEditTripInfoStartDate.text = viewModel.startDate + tvEditTripInfoEndDate.text = viewModel.endDate } } diff --git a/presentation/src/main/java/com/going/presentation/todo/edittrip/edit/EditTripViewModel.kt b/presentation/src/main/java/com/going/presentation/todo/edittrip/edit/EditTripViewModel.kt index 7e3fd8e9..3443e6a8 100644 --- a/presentation/src/main/java/com/going/presentation/todo/edittrip/edit/EditTripViewModel.kt +++ b/presentation/src/main/java/com/going/presentation/todo/edittrip/edit/EditTripViewModel.kt @@ -19,7 +19,6 @@ import javax.inject.Inject class EditTripViewModel @Inject constructor( private val editTripRepository: EditTripRepository ) : ViewModel() { - val titleLength = MutableLiveData(0) val startYear = MutableLiveData() val startMonth = MutableLiveData() @@ -41,10 +40,6 @@ class EditTripViewModel @Inject constructor( private val _quittripState = MutableSharedFlow() val quittripState: SharedFlow = _quittripState - fun gettitleLength(){ - titleLength.value = title.getGraphemeLength() - } - fun getTripInfoFromServer(tripId: Long) { _tripInfoState.value = UiState.Loading viewModelScope.launch { @@ -74,9 +69,4 @@ class EditTripViewModel @Inject constructor( } } } - - companion object { - const val MAX_TRIP_LEN = 15 - } - } diff --git a/presentation/src/main/res/drawable/shape_line_gray100_fill_dash_5_vertical.xml b/presentation/src/main/res/drawable/shape_line_gray100_fill_dash_5_vertical.xml index c69c0986..1ae92cfb 100644 --- a/presentation/src/main/res/drawable/shape_line_gray100_fill_dash_5_vertical.xml +++ b/presentation/src/main/res/drawable/shape_line_gray100_fill_dash_5_vertical.xml @@ -1,5 +1,11 @@ - + + + + + \ No newline at end of file diff --git a/presentation/src/main/res/layout/activity_edit_trip.xml b/presentation/src/main/res/layout/activity_edit_trip.xml index aa694c43..47566efd 100644 --- a/presentation/src/main/res/layout/activity_edit_trip.xml +++ b/presentation/src/main/res/layout/activity_edit_trip.xml @@ -6,7 +6,7 @@ @@ -61,16 +61,17 @@ @@ -80,13 +81,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="4dp" - android:textAppearance="@style/TextAppearance.Doorip.Detail3.Regular" - android:text="@{@string/counter(viewModel.titleLength, viewModel.MAX_TRIP_LEN)}" - android:textColor="@color/gray_400" + android:text="@string/empty_string" + style="@style/TextAppearance.Doorip.Detail3.Regular" + android:textColor="@color/white_000" app:layout_constraintEnd_toEndOf="@id/tv_edit_trip_name" app:layout_constraintTop_toBottomOf="@id/tv_edit_trip_name" /> - diff --git a/presentation/src/main/res/layout/activity_profile.xml b/presentation/src/main/res/layout/activity_profile.xml index db7a617d..4ae1208d 100644 --- a/presentation/src/main/res/layout/activity_profile.xml +++ b/presentation/src/main/res/layout/activity_profile.xml @@ -106,11 +106,12 @@ diff --git a/presentation/src/main/res/layout/activity_todo_change.xml b/presentation/src/main/res/layout/activity_todo_change.xml index c671d460..1453cb20 100644 --- a/presentation/src/main/res/layout/activity_todo_change.xml +++ b/presentation/src/main/res/layout/activity_todo_change.xml @@ -229,7 +229,7 @@ - - + app:layout_constraintTop_toBottomOf="@id/et_todo_detail_todo" /> - - diff --git a/presentation/src/main/res/layout/fragment_my_todo.xml b/presentation/src/main/res/layout/fragment_my_todo.xml index 57cd69e2..72c8ade2 100644 --- a/presentation/src/main/res/layout/fragment_my_todo.xml +++ b/presentation/src/main/res/layout/fragment_my_todo.xml @@ -38,7 +38,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="18dp" - android:layout_marginEnd="10dp" + android:layout_marginEnd="12dp" android:layout_marginBottom="4dp" android:src="@drawable/ic_trip_info" app:layout_constraintBottom_toBottomOf="parent" diff --git a/presentation/src/main/res/layout/view_chart_textview.xml b/presentation/src/main/res/layout/view_chart_textview.xml index 459a578f..a405dbaa 100644 --- a/presentation/src/main/res/layout/view_chart_textview.xml +++ b/presentation/src/main/res/layout/view_chart_textview.xml @@ -15,20 +15,21 @@ android:layout_height="wrap_content" android:gravity="center" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@id/linear_layout_chart_description" - app:layout_constraintHorizontal_weight="2" + app:layout_constraintEnd_toStartOf="@id/img_chart_dash_vertical" + app:layout_constraintHorizontal_weight="2.6" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -36,12 +37,11 @@ android:id="@+id/linear_layout_chart_description" android:layout_width="0dp" android:layout_height="match_parent" - android:layout_marginStart="26dp" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_weight="7" - app:layout_constraintStart_toEndOf="@id/tv_chart_title" + app:layout_constraintHorizontal_weight="6.8" + app:layout_constraintStart_toEndOf="@id/img_chart_dash_vertical" app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + + + + + diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index ca019eef..81ece3ce 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -5,6 +5,7 @@ Adapter is not initialized %s Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + 서버 통신에 실패했어요 닉네임에는 공백만 입력할 수 없어요