From e67f9d72a09fbe2089b2e683a579afd840c90829 Mon Sep 17 00:00:00 2001 From: Dongmin Date: Wed, 17 Jan 2024 03:40:41 +0900 Subject: [PATCH 1/7] =?UTF-8?q?[FIX/#149]=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 9 +-- .../onboarding/splash/SplashActivity.kt | 2 - .../going/presentation/util/ActivityExt.kt | 69 +++++++++++-------- presentation/src/main/res/values/strings.xml | 3 +- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 310c0ae4..4c29b984 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,9 +4,7 @@ - + - diff --git a/presentation/src/main/java/com/going/presentation/onboarding/splash/SplashActivity.kt b/presentation/src/main/java/com/going/presentation/onboarding/splash/SplashActivity.kt index 2d314a1b..e6a57847 100644 --- a/presentation/src/main/java/com/going/presentation/onboarding/splash/SplashActivity.kt +++ b/presentation/src/main/java/com/going/presentation/onboarding/splash/SplashActivity.kt @@ -30,7 +30,6 @@ class SplashActivity : BaseActivity(R.layout.activity_spl setStatusBarColor() checkConnectedNetwork() observeUserState() - } private fun setStatusBarColor() { @@ -105,5 +104,4 @@ class SplashActivity : BaseActivity(R.layout.activity_spl } finish() } - } diff --git a/presentation/src/main/java/com/going/presentation/util/ActivityExt.kt b/presentation/src/main/java/com/going/presentation/util/ActivityExt.kt index a8ba1ec9..ebf7e59c 100644 --- a/presentation/src/main/java/com/going/presentation/util/ActivityExt.kt +++ b/presentation/src/main/java/com/going/presentation/util/ActivityExt.kt @@ -1,38 +1,42 @@ package com.going.presentation.util -import android.Manifest import android.app.Activity -import android.content.pm.PackageManager +import android.app.AlertDialog +import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory import android.media.MediaScannerConnection import android.os.Build import android.os.Environment +import android.os.Environment.DIRECTORY_DOWNLOADS +import android.provider.Settings import androidx.activity.ComponentActivity import androidx.activity.OnBackPressedCallback -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat import com.going.presentation.R -import com.going.presentation.tendency.result.TendencyResultActivity import com.going.presentation.tendency.result.UserTendencyResultList import com.going.ui.extension.toast import java.io.File import java.io.FileOutputStream fun Activity.downloadImage(number: Int) { - val downloadPath = "/Download/" val downloadImageName = "img_tendency_result%s.png" - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission( - this, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - ) != PackageManager.PERMISSION_GRANTED - ) { - ActivityCompat.requestPermissions( - this, - arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), - TendencyResultActivity.PERMISSION_REQUEST_CODE, - ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { + AlertDialog.Builder(this) + .setTitle(R.string.notice) + .setMessage(R.string.profile_image_permission_error) + .setCancelable(false) + .setPositiveButton( + R.string.okay, + ) { _, _ -> + val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) + this.startActivity(intent) + } + .setNegativeButton( + R.string.setting_logout_negative, + ) { _, _ -> } + .create() + .show() } else { val imageBitmap: Bitmap = BitmapFactory.decodeResource( resources, @@ -41,26 +45,31 @@ fun Activity.downloadImage(number: Int) { val imageFileName = downloadImageName.replace("%s", number.toString()) - val uploadFolder = Environment.getExternalStoragePublicDirectory(downloadPath) + val uploadFolder = + Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS) + if (!uploadFolder.exists()) { uploadFolder.mkdirs() } - val imageFile = File(uploadFolder, imageFileName) + val imageFile = File(uploadFolder.toString(), imageFileName) - val outputStream = FileOutputStream(imageFile) - imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) - outputStream.flush() - outputStream.close() + try { + val outputStream = FileOutputStream(imageFile) + imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) + outputStream.flush() + outputStream.close() - MediaScannerConnection.scanFile( - this, - arrayOf(imageFile.absolutePath), - arrayOf("image/jpeg"), - null, - ) - - toast(getString(R.string.profile_image_download_success)) + MediaScannerConnection.scanFile( + this, + arrayOf(imageFile.absolutePath), + arrayOf("image/jpeg"), + null, + ) + toast(getString(R.string.profile_image_download_success)) + } catch (e: Exception) { + toast(getString(R.string.profile_image_download_error)) + } } } diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index e175cbc7..ac2534f1 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -162,8 +162,9 @@ 나는 두릅이 좋다. 다시 해볼래요 존재하지 않는 여행입니다. - 이미지가 저장되었어요\n친구에게 내 캐릭터를 공유해 보세요 + 이미지가 저장되었어요.\n친구들에게 공유해보세요! 저장할 수 없습니다\ndoorip에 사진에 대한 엑세스 권한이 없습니다 + "사진 접근 권한이 없습니다.\n설정으로 이동하여 권한 설정을 해주세요" 여행 입장하기 From e5f7f82f853466ecd61953c604951b0742fcda0e Mon Sep 17 00:00:00 2001 From: Dongmin Date: Wed, 17 Jan 2024 04:13:25 +0900 Subject: [PATCH 2/7] =?UTF-8?q?[FIX/#149]=20kakao=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EB=B2=84=ED=8A=BC=20=EC=BB=A4=EC=8A=A4=ED=85=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_kakao.xml | 11 +++++ .../shape_kakao_yellow_fill_8_rect.xml | 6 +++ .../src/main/res/layout/activity_signin.xml | 41 +++++++++++++++---- presentation/src/main/res/values/strings.xml | 1 + 4 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 presentation/src/main/res/drawable/ic_kakao.xml create mode 100644 presentation/src/main/res/drawable/shape_kakao_yellow_fill_8_rect.xml diff --git a/presentation/src/main/res/drawable/ic_kakao.xml b/presentation/src/main/res/drawable/ic_kakao.xml new file mode 100644 index 00000000..beecf8a0 --- /dev/null +++ b/presentation/src/main/res/drawable/ic_kakao.xml @@ -0,0 +1,11 @@ + + + diff --git a/presentation/src/main/res/drawable/shape_kakao_yellow_fill_8_rect.xml b/presentation/src/main/res/drawable/shape_kakao_yellow_fill_8_rect.xml new file mode 100644 index 00000000..fe492bfa --- /dev/null +++ b/presentation/src/main/res/drawable/shape_kakao_yellow_fill_8_rect.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/presentation/src/main/res/layout/activity_signin.xml b/presentation/src/main/res/layout/activity_signin.xml index 5075e3d5..740c8c72 100644 --- a/presentation/src/main/res/layout/activity_signin.xml +++ b/presentation/src/main/res/layout/activity_signin.xml @@ -32,17 +32,42 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintBottom_toTopOf="@id/btn_terms"> + + + + + + + + app:layout_constraintStart_toEndOf="@id/tv_sign_in_terms_icon" /> 해당 기능은 추후 업데이트 예정이에요 :) 여행을 시작해보세요 + 카카오 로그인 개인정보처리방침 버튼을 한번 더 누르면 종료됩니다. From 29d4e20a12eda866a14821891f7adf1dd69887f9 Mon Sep 17 00:00:00 2001 From: Dongmin Date: Wed, 17 Jan 2024 05:51:12 +0900 Subject: [PATCH 3/7] =?UTF-8?q?[FIX/#149]=20=EA=B8=80=EC=9E=90=EC=A0=9C?= =?UTF-8?q?=ED=95=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/going/domain/entity/NameState.kt | 2 +- .../OnboardingProfileSettingActivity.kt | 83 +++++-------------- .../OnboardingProfileSettingViewModel.kt | 13 +-- .../activity_onboarding_profile_setting.xml | 18 +++- presentation/src/main/res/values/strings.xml | 2 + 5 files changed, 46 insertions(+), 72 deletions(-) diff --git a/domain/src/main/kotlin/com/going/domain/entity/NameState.kt b/domain/src/main/kotlin/com/going/domain/entity/NameState.kt index 413b375a..765922df 100644 --- a/domain/src/main/kotlin/com/going/domain/entity/NameState.kt +++ b/domain/src/main/kotlin/com/going/domain/entity/NameState.kt @@ -1,5 +1,5 @@ package com.going.domain.entity enum class NameState { - Empty, Success, Blank + Empty, Success, Blank, OVER } diff --git a/presentation/src/main/java/com/going/presentation/onboarding/signup/OnboardingProfileSettingActivity.kt b/presentation/src/main/java/com/going/presentation/onboarding/signup/OnboardingProfileSettingActivity.kt index a9798d0e..24f18f38 100644 --- a/presentation/src/main/java/com/going/presentation/onboarding/signup/OnboardingProfileSettingActivity.kt +++ b/presentation/src/main/java/com/going/presentation/onboarding/signup/OnboardingProfileSettingActivity.kt @@ -33,10 +33,9 @@ class OnboardingProfileSettingActivity : initBindingViewModel() initOnLineInfoEditorActionListener() - initSetOnFocusChangeListener() initSignUpBtnClickListener() observeIsNameAvailable() - observeTextLength() + observeIsInfoAvailable() observeIsSignUpState() initOnBackPressedListener() } @@ -52,12 +51,17 @@ class OnboardingProfileSettingActivity : } } - private fun initSetOnFocusChangeListener() { - binding.etOnboardingProfileSettingName.setOnFocusChangeListener { _, hasFocus -> + private fun initSignUpBtnClickListener() { + binding.btnOnboardingProfileSettingFinish.setOnSingleClickListener { + viewModel.startSignUp() + } + } + + private fun observeIsNameAvailable() { + viewModel.isNameAvailable.observe(this) { state -> setColors( - hasFocus, - viewModel.nowNameLength.value ?: 0, binding.tvNameCounter, + state, ) { background -> binding.etOnboardingProfileSettingName.background = ResourcesCompat.getDrawable( this.resources, @@ -66,12 +70,13 @@ class OnboardingProfileSettingActivity : ) } } + } - binding.etOnboardingProfileSettingInfo.setOnFocusChangeListener { _, hasFocus -> + private fun observeIsInfoAvailable() { + viewModel.isInfoAvailable.observe(this) { state -> setColors( - hasFocus, - viewModel.nowInfoLength.value ?: 0, binding.tvInfoCounter, + state, ) { background -> binding.etOnboardingProfileSettingInfo.background = ResourcesCompat.getDrawable( this.resources, @@ -82,39 +87,16 @@ class OnboardingProfileSettingActivity : } } - private fun initSignUpBtnClickListener() { - binding.btnOnboardingProfileSettingFinish.setOnSingleClickListener { - viewModel.startSignUp() - } - } - - private fun observeIsNameAvailable() { - viewModel.isNameAvailable.observe(this) { state -> - setColors( - false, - viewModel.nowNameLength.value ?: 0, - binding.tvNameCounter, - ) { background -> - binding.etOnboardingProfileSettingName.background = ResourcesCompat.getDrawable( - this.resources, - background, - theme, - ) - } - } - } - private fun setColors( - hasFocus: Boolean, - length: Int, counter: TextView, + state: NameState, setBackground: (Int) -> Unit, ) { - val (color, background) = when { - viewModel.isNameAvailable.value != NameState.Blank && hasFocus -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line - length == 0 -> R.color.gray_200 to R.drawable.shape_rect_4_gray200_line - viewModel.isNameAvailable.value == NameState.Blank && counter == binding.tvNameCounter -> R.color.red_500 to R.drawable.shape_rect_4_red500_line - else -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line + 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) @@ -125,31 +107,6 @@ class OnboardingProfileSettingActivity : counter.setTextColor(getColor(color)) } - // 커스텀 글자수 제한 함수 - private fun observeTextLength() { - viewModel.nowNameLength.observe(this) { length -> - val maxNameLength = viewModel.getMaxNameLen() - - if (length > maxNameLength) { - binding.etOnboardingProfileSettingName.apply { - setText(text?.subSequence(0, maxNameLength)) - setSelection(maxNameLength) - } - } - } - - viewModel.nowInfoLength.observe(this) { length -> - val maxInfoLength = viewModel.getMaxInfoLen() - - if (length > maxInfoLength) { - binding.etOnboardingProfileSettingInfo.apply { - setText(text?.subSequence(0, maxInfoLength)) - setSelection(maxInfoLength) - } - } - } - } - private fun observeIsSignUpState() { viewModel.isSignUpState.flowWithLifecycle(lifecycle).onEach { state -> when (state) { diff --git a/presentation/src/main/java/com/going/presentation/onboarding/signup/OnboardingProfileSettingViewModel.kt b/presentation/src/main/java/com/going/presentation/onboarding/signup/OnboardingProfileSettingViewModel.kt index fdaf97c9..02c39836 100644 --- a/presentation/src/main/java/com/going/presentation/onboarding/signup/OnboardingProfileSettingViewModel.kt +++ b/presentation/src/main/java/com/going/presentation/onboarding/signup/OnboardingProfileSettingViewModel.kt @@ -30,14 +30,12 @@ class OnboardingProfileSettingViewModel @Inject constructor( val nowInfoLength = MutableLiveData(0) val isNameAvailable = MutableLiveData(NameState.Empty) + val isInfoAvailable = MutableLiveData(NameState.Empty) val isProfileAvailable = MutableLiveData(false) private val _isSignUpState = MutableStateFlow(AuthState.LOADING) val isSignUpState: StateFlow = _isSignUpState - fun getMaxNameLen() = MAX_NAME_LEN - fun getMaxInfoLen() = MAX_INFO_LEN - fun checkProfileAvailable() { nowNameLength.value = name.value.getGraphemeLength() nowInfoLength.value = info.value.getGraphemeLength() @@ -45,13 +43,18 @@ class OnboardingProfileSettingViewModel @Inject constructor( isNameAvailable.value = when { nowNameLength.value == 0 -> NameState.Empty name.value.isBlank() -> NameState.Blank + (nowNameLength.value ?: 0) > 3 -> NameState.OVER else -> NameState.Success } - val isInfoAvailable = nowInfoLength.value in 1..MAX_INFO_LEN + isInfoAvailable.value = when { + nowInfoLength.value == 0 -> NameState.Empty + (nowInfoLength.value ?: 0) > MAX_INFO_LEN -> NameState.OVER + else -> NameState.Success + } isProfileAvailable.value = - (isNameAvailable.value == NameState.Success) && isInfoAvailable + (isNameAvailable.value == NameState.Success) && (isInfoAvailable.value == NameState.Success) } fun startSignUp() { diff --git a/presentation/src/main/res/layout/activity_onboarding_profile_setting.xml b/presentation/src/main/res/layout/activity_onboarding_profile_setting.xml index 24c3aacd..3fbfe9f8 100644 --- a/presentation/src/main/res/layout/activity_onboarding_profile_setting.xml +++ b/presentation/src/main/res/layout/activity_onboarding_profile_setting.xml @@ -68,9 +68,9 @@ android:layout_height="wrap_content" android:layout_marginStart="4dp" android:layout_marginTop="4dp" - android:text="@string/name_blank_error" - android:textColor="@{viewModel.isNameAvailable() == NameState.Blank ? @color/red_500 : @color/gray_700}" - android:visibility="@{viewModel.isNameAvailable() == NameState.Blank ? View.VISIBLE : View.GONE}" + android:text="@{viewModel.isNameAvailable() == NameState.Blank ? @string/name_blank_error : @string/name_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_onboarding_profile_setting_name" app:layout_constraintTop_toBottomOf="@id/et_onboarding_profile_setting_name" /> @@ -114,6 +114,18 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_onboarding_profile_setting_on_line_info_title" /> + + 서버 통신에 실패했습니다. 이름에는 공백만 입력할 수 없어요 + 이름은 3자 이하여야 합니다 + 자기소개는 20자 이하여야 합니다 해당 기능은 추후 업데이트 예정이에요 :) From 630805acb6c300ab8e58894e67519c47a2f4fc7c Mon Sep 17 00:00:00 2001 From: Dongmin Date: Wed, 17 Jan 2024 06:09:33 +0900 Subject: [PATCH 4/7] =?UTF-8?q?[FIX/#149]=20=EC=97=AC=ED=96=89=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EA=B8=80=EC=9E=90=20=EC=A0=9C=ED=95=9C=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../choosedate/CreateTripActivity.kt | 31 +++++-------------- .../choosedate/CreateTripViewModel.kt | 4 +-- .../main/res/layout/activity_create_trip.xml | 6 ++-- presentation/src/main/res/values/strings.xml | 1 + 4 files changed, 13 insertions(+), 29 deletions(-) diff --git a/presentation/src/main/java/com/going/presentation/entertrip/createtrip/choosedate/CreateTripActivity.kt b/presentation/src/main/java/com/going/presentation/entertrip/createtrip/choosedate/CreateTripActivity.kt index 31b5c0b0..1eb96960 100644 --- a/presentation/src/main/java/com/going/presentation/entertrip/createtrip/choosedate/CreateTripActivity.kt +++ b/presentation/src/main/java/com/going/presentation/entertrip/createtrip/choosedate/CreateTripActivity.kt @@ -23,7 +23,6 @@ class CreateTripActivity : super.onCreate(savedInstanceState) initBindingViewModel() - observeTextLength() observeIsNameAvailable() observeCheckStartDateAvailable() observeCheckEndDateAvailable() @@ -37,24 +36,10 @@ class CreateTripActivity : binding.viewModel = viewModel } - private fun observeTextLength() { - viewModel.nameLength.observe(this) { length -> - val maxNameLength = viewModel.getMaxNameLen() - - if (length > maxNameLength) { - binding.etCreateTripName.apply { - setText(text?.subSequence(0, maxNameLength)) - setSelection(maxNameLength) - } - } - } - } - private fun observeIsNameAvailable() { viewModel.isNameAvailable.observe(this) { state -> setColors( - false, - viewModel.nameLength.value ?: 0, + state, binding.tvNameCounter, ) { background -> binding.etCreateTripName.background = ResourcesCompat.getDrawable( @@ -99,17 +84,17 @@ class CreateTripActivity : } private fun setColors( - hasFocus: Boolean, - length: Int, + state: NameState, counter: TextView, setBackground: (Int) -> Unit, ) { - val (color, background) = when { - viewModel.isNameAvailable.value != NameState.Blank && hasFocus -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line - length == 0 -> R.color.gray_200 to R.drawable.shape_rect_4_gray200_line - viewModel.isNameAvailable.value == NameState.Blank && counter == binding.tvNameCounter -> R.color.red_500 to R.drawable.shape_rect_4_red500_line - else -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line + 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) } diff --git a/presentation/src/main/java/com/going/presentation/entertrip/createtrip/choosedate/CreateTripViewModel.kt b/presentation/src/main/java/com/going/presentation/entertrip/createtrip/choosedate/CreateTripViewModel.kt index 80485bfc..0b8cbe63 100644 --- a/presentation/src/main/java/com/going/presentation/entertrip/createtrip/choosedate/CreateTripViewModel.kt +++ b/presentation/src/main/java/com/going/presentation/entertrip/createtrip/choosedate/CreateTripViewModel.kt @@ -24,13 +24,12 @@ class CreateTripViewModel : ViewModel() { val isTripAvailable = MutableLiveData(false) var isCheckTripAvailable = MutableLiveData(false) - fun getMaxNameLen() = MAX_TRIP_LEN - fun checkNameAvailable() { nameLength.value = name.value?.getGraphemeLength() isNameAvailable.value = when { nameLength.value == 0 -> NameState.Empty + (nameLength.value ?: 0) > MAX_TRIP_LEN -> NameState.OVER name.value.isNullOrBlank() -> NameState.Blank else -> NameState.Success } @@ -60,7 +59,6 @@ class CreateTripViewModel : ViewModel() { } else { isEndDateAvailable.value = false checkTripAvailable() - } } diff --git a/presentation/src/main/res/layout/activity_create_trip.xml b/presentation/src/main/res/layout/activity_create_trip.xml index 2d6b3cea..840395bf 100644 --- a/presentation/src/main/res/layout/activity_create_trip.xml +++ b/presentation/src/main/res/layout/activity_create_trip.xml @@ -87,9 +87,9 @@ android:layout_height="wrap_content" android:layout_marginStart="4dp" android:layout_marginTop="4dp" - android:text="@string/name_blank_error" - android:textColor="@{viewModel.isNameAvailable() == NameState.Blank ? @color/red_500 : @color/gray_700}" - android:visibility="@{viewModel.isNameAvailable() == NameState.Blank ? View.VISIBLE : View.GONE}" + 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_create_trip_name" app:layout_constraintTop_toBottomOf="@id/et_create_trip_name" /> diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 9028d1d5..f3f121ea 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -10,6 +10,7 @@ 이름에는 공백만 입력할 수 없어요 이름은 3자 이하여야 합니다 자기소개는 20자 이하여야 합니다 + 여행이름은 15자 이하여야 합니다 해당 기능은 추후 업데이트 예정이에요 :) From 0ce039e2cafd75cc90c3c492a0b3e9266db21d42 Mon Sep 17 00:00:00 2001 From: Dongmin Date: Wed, 17 Jan 2024 06:40:43 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[FIX/#149]=20our=20todo=20create=20?= =?UTF-8?q?=EC=97=AC=ED=96=89=EC=83=9D=EC=84=B1=20=EA=B8=80=EC=9E=90=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourtodo/create/OurTodoCreateActivity.kt | 70 ++++--------------- .../ourtodo/create/OurTodoCreateViewModel.kt | 23 ++++-- .../res/layout/activity_our_todo_create.xml | 29 +++++++- presentation/src/main/res/values/strings.xml | 2 + 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateActivity.kt b/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateActivity.kt index 86d0a192..a4dbaefb 100644 --- a/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateActivity.kt +++ b/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateActivity.kt @@ -7,6 +7,7 @@ import androidx.activity.viewModels import androidx.core.content.res.ResourcesCompat import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope +import com.going.domain.entity.NameState import com.going.domain.entity.response.TripParticipantModel import com.going.presentation.R import com.going.presentation.databinding.ActivityOurTodoCreateBinding @@ -36,8 +37,6 @@ class OurTodoCreateActivity : initViewModel() initNameListAdapter() - initTodoFocusListener() - initMemoFocusListener() initDateClickListener() initFinishBtnListener() initBackBtnListener() @@ -62,30 +61,6 @@ class OurTodoCreateActivity : binding.rvOurTodoCreatePerson.adapter = adapter } - private fun initTodoFocusListener() { - binding.etOurTodoCreateTodo.setOnFocusChangeListener { _, hasFocus -> - setColors( - hasFocus, - viewModel.nowTodoLength.value ?: 0, - binding.tvOurTodoTodoCounter, - ) { background -> - binding.etOurTodoCreateTodo.background = setBackgroundColor(background) - } - } - } - - private fun initMemoFocusListener() { - binding.etOurTodoCreateMemo.setOnFocusChangeListener { _, hasFocus -> - setColors( - hasFocus, - viewModel.nowMemoLength.value ?: 0, - binding.tvOurTodoMemoCounter, - ) { background -> - binding.etOurTodoCreateMemo.background = setBackgroundColor(background) - } - } - } - private fun initDateClickListener() { binding.etOurTodoCreateDate.setOnSingleClickListener { ourTodoCreateBottomSheet = OurTodoCreateBottomSheet() @@ -107,7 +82,7 @@ class OurTodoCreateActivity : } private fun getTripId() { - viewModel.tripId = intent.getLongExtra(EXTRA_TRIP_ID,0) + viewModel.tripId = intent.getLongExtra(EXTRA_TRIP_ID, 0) } private fun setParticipantList() { @@ -140,18 +115,9 @@ class OurTodoCreateActivity : } private fun observeTextLength() { - viewModel.nowTodoLength.observe(this) { length -> - val maxTodoLen = viewModel.getMaxTodoLen() - - if (length > maxTodoLen) { - binding.etOurTodoCreateTodo.apply { - setText(text?.subSequence(0, maxTodoLen)) - setSelection(maxTodoLen) - } - } + viewModel.isTodoAvailable.observe(this) { state -> setColors( - false, - viewModel.nowTodoLength.value ?: 0, + state, binding.tvOurTodoTodoCounter, ) { background -> binding.etOurTodoCreateTodo.background = setBackgroundColor(background) @@ -160,17 +126,9 @@ class OurTodoCreateActivity : } private fun observeMemoLength() { - viewModel.nowMemoLength.observe(this) { length -> - val maxMemoLen = viewModel.getMaxMemoLen() - if (length > maxMemoLen) { - binding.etOurTodoCreateTodo.apply { - setText(text?.subSequence(0, maxMemoLen)) - setSelection(maxMemoLen) - } - } + viewModel.isMemoAvailable.observe(this) { state -> setColors( - false, - viewModel.nowMemoLength.value ?: 0, + state, binding.tvOurTodoMemoCounter, ) { background -> binding.etOurTodoCreateMemo.background = setBackgroundColor(background) @@ -189,16 +147,17 @@ class OurTodoCreateActivity : } private fun setColors( - hasFocus: Boolean, - length: Int, + state: NameState, counter: TextView, setBackground: (Int) -> Unit, ) { - val (color, background) = when { - hasFocus || viewModel.nowTodoLength.value != 0 -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line - length == 0 -> R.color.gray_200 to R.drawable.shape_rect_4_gray200_line - else -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line + 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) } @@ -228,5 +187,4 @@ class OurTodoCreateActivity : const val EXTRA_NAME = "EXTRA_NAME" const val EXTRA_RESULT = "EXTRA_RESULT" } - -} \ No newline at end of file +} diff --git a/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateViewModel.kt b/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateViewModel.kt index d9103cbf..6fdf6fd1 100644 --- a/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateViewModel.kt +++ b/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateViewModel.kt @@ -1,8 +1,10 @@ package com.going.presentation.todo.ourtodo.create +import android.util.Log import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.going.domain.entity.NameState import com.going.domain.entity.request.TodoCreateRequestModel import com.going.domain.entity.response.TripParticipantModel import com.going.domain.repository.TodoRepository @@ -12,7 +14,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import java.text.BreakIterator import javax.inject.Inject @HiltViewModel @@ -21,11 +22,13 @@ class OurTodoCreateViewModel @Inject constructor( ) : ViewModel() { val todo = MutableLiveData("") + val isTodoAvailable = MutableLiveData(NameState.Empty) val nowTodoLength = MutableLiveData(0) val endDate = MutableLiveData("") val memo = MutableLiveData("") + val isMemoAvailable = MutableLiveData(NameState.Empty) val nowMemoLength = MutableLiveData(0) val isFinishAvailable = MutableLiveData(false) @@ -38,13 +41,23 @@ class OurTodoCreateViewModel @Inject constructor( var tripId: Long = 0 - fun getMaxTodoLen() = MAX_TODO_LEN - - fun getMaxMemoLen() = MAX_MEMO_LEN - fun checkIsFinishAvailable() { nowTodoLength.value = todo.value?.getGraphemeLength() + isTodoAvailable.value = when { + nowTodoLength.value == 0 -> NameState.Empty + (nowTodoLength.value ?: 0) > MAX_TODO_LEN -> NameState.OVER + todo.value.isNullOrBlank() -> NameState.Blank + else -> NameState.Success + } + nowMemoLength.value = memo.value?.getGraphemeLength() + isMemoAvailable.value = when { + nowMemoLength.value == 0 -> NameState.Empty + (nowMemoLength.value ?: 0) > MAX_MEMO_LEN -> NameState.OVER + memo.value.isNullOrBlank() -> NameState.Blank + else -> NameState.Success + } + isFinishAvailable.value = todo.value?.isNotEmpty() == true && endDate.value?.isNotEmpty() == true && participantList.any { it.isSelected } } diff --git a/presentation/src/main/res/layout/activity_our_todo_create.xml b/presentation/src/main/res/layout/activity_our_todo_create.xml index 35e98b77..111836fb 100644 --- a/presentation/src/main/res/layout/activity_our_todo_create.xml +++ b/presentation/src/main/res/layout/activity_our_todo_create.xml @@ -7,6 +7,8 @@ + + @@ -106,6 +108,19 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_our_todo_create_todo_title" /> + + + + + - \ No newline at end of file + diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index f3f121ea..4407fed6 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -11,6 +11,8 @@ 이름은 3자 이하여야 합니다 자기소개는 20자 이하여야 합니다 여행이름은 15자 이하여야 합니다 + 할일은 15자 이하여야 합니다 + 메모는 1000자 이하여야 합니다 해당 기능은 추후 업데이트 예정이에요 :) From e209e37d8e2c39a3d49b895cc9fafb38271558a8 Mon Sep 17 00:00:00 2001 From: Dongmin Date: Wed, 17 Jan 2024 14:06:16 +0900 Subject: [PATCH 6/7] =?UTF-8?q?[FIX/#149]=20my=20todo=20create=20=EC=97=AC?= =?UTF-8?q?=ED=96=89=EC=83=9D=EC=84=B1=20=EA=B8=80=EC=9E=90=20=EC=A0=9C?= =?UTF-8?q?=ED=95=9C=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mytodo/create/MyTodoCreateActivity.kt | 72 ++++--------------- .../mytodo/create/MyTodoCreateViewModel.kt | 25 +++++-- .../ourtodo/create/OurTodoCreateViewModel.kt | 3 +- .../res/layout/activity_my_todo_create.xml | 30 +++++++- .../res/layout/activity_our_todo_create.xml | 2 +- 5 files changed, 64 insertions(+), 68 deletions(-) diff --git a/presentation/src/main/java/com/going/presentation/todo/mytodo/create/MyTodoCreateActivity.kt b/presentation/src/main/java/com/going/presentation/todo/mytodo/create/MyTodoCreateActivity.kt index 15d0e0f8..26039134 100644 --- a/presentation/src/main/java/com/going/presentation/todo/mytodo/create/MyTodoCreateActivity.kt +++ b/presentation/src/main/java/com/going/presentation/todo/mytodo/create/MyTodoCreateActivity.kt @@ -7,9 +7,9 @@ import androidx.activity.viewModels import androidx.core.content.res.ResourcesCompat import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope +import com.going.domain.entity.NameState import com.going.presentation.R import com.going.presentation.databinding.ActivityMyTodoCreateBinding -import com.going.presentation.todo.TodoActivity import com.going.presentation.todo.TodoActivity.Companion.EXTRA_TRIP_ID import com.going.presentation.todo.ourtodo.create.OurTodoCreateActivity.Companion.EXTRA_PARTICIPANT_ID import com.going.ui.base.BaseActivity @@ -32,8 +32,6 @@ class MyTodoCreateActivity : super.onCreate(savedInstanceState) initViewModel() - initTodoFocusListener() - initMemoFocusListener() initDateClickListener() initFinishBtnListener() initBackBtnListener() @@ -48,30 +46,6 @@ class MyTodoCreateActivity : binding.vm = viewModel } - private fun initTodoFocusListener() { - binding.etMyTodoCreateTodo.setOnFocusChangeListener { _, hasFocus -> - setColors( - hasFocus, - viewModel.nowTodoLength.value ?: 0, - binding.tvMyTodoTodoCounter, - ) { background -> - binding.etMyTodoCreateTodo.background = setBackgroundColor(background) - } - } - } - - private fun initMemoFocusListener() { - binding.etMyTodoCreateMemo.setOnFocusChangeListener { _, hasFocus -> - setColors( - hasFocus, - viewModel.nowMemoLength.value ?: 0, - binding.tvMyTodoMemoCounter, - ) { background -> - binding.etMyTodoCreateMemo.background = setBackgroundColor(background) - } - } - } - private fun initDateClickListener() { binding.etMyTodoCreateDate.setOnSingleClickListener { myTodoCreateBottomSheet = MyTodoCreateBottomSheet() @@ -92,8 +66,8 @@ class MyTodoCreateActivity : } private fun getId() { - viewModel.tripId = intent.getLongExtra(EXTRA_TRIP_ID,0) - viewModel.participantId = intent.getLongExtra(EXTRA_PARTICIPANT_ID,0) + viewModel.tripId = intent.getLongExtra(EXTRA_TRIP_ID, 0) + viewModel.participantId = intent.getLongExtra(EXTRA_PARTICIPANT_ID, 0) } private fun observeTodoCreateState() { @@ -114,18 +88,9 @@ class MyTodoCreateActivity : } private fun observeTextLength() { - viewModel.nowTodoLength.observe(this) { length -> - val maxTodoLen = viewModel.getMaxTodoLen() - - if (length > maxTodoLen) { - binding.etMyTodoCreateTodo.apply { - setText(text?.subSequence(0, maxTodoLen)) - setSelection(maxTodoLen) - } - } + viewModel.isTodoAvailable.observe(this) { state -> setColors( - false, - viewModel.nowTodoLength.value ?: 0, + state, binding.tvMyTodoTodoCounter, ) { background -> binding.etMyTodoCreateTodo.background = setBackgroundColor(background) @@ -134,17 +99,9 @@ class MyTodoCreateActivity : } private fun observeMemoLength() { - viewModel.nowMemoLength.observe(this) { length -> - val maxMemoLen = viewModel.getMaxMemoLen() - if (length > maxMemoLen) { - binding.etMyTodoCreateTodo.apply { - setText(text?.subSequence(0, maxMemoLen)) - setSelection(maxMemoLen) - } - } + viewModel.isMemoAvailable.observe(this) { state -> setColors( - false, - viewModel.nowMemoLength.value ?: 0, + state, binding.tvMyTodoMemoCounter, ) { background -> binding.etMyTodoCreateMemo.background = setBackgroundColor(background) @@ -163,16 +120,17 @@ class MyTodoCreateActivity : } private fun setColors( - hasFocus: Boolean, - length: Int, + state: NameState, counter: TextView, setBackground: (Int) -> Unit, ) { - val (color, background) = when { - hasFocus || viewModel.nowTodoLength.value != 0 -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line - length == 0 -> R.color.gray_200 to R.drawable.shape_rect_4_gray200_line - else -> R.color.gray_700 to R.drawable.shape_rect_4_gray700_line + 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) } @@ -197,4 +155,4 @@ class MyTodoCreateActivity : companion object { private const val DATE_BOTTOM_SHEET = "DATE_BOTTOM_SHEET" } -} \ No newline at end of file +} diff --git a/presentation/src/main/java/com/going/presentation/todo/mytodo/create/MyTodoCreateViewModel.kt b/presentation/src/main/java/com/going/presentation/todo/mytodo/create/MyTodoCreateViewModel.kt index 634ce1d5..edcf9a9a 100644 --- a/presentation/src/main/java/com/going/presentation/todo/mytodo/create/MyTodoCreateViewModel.kt +++ b/presentation/src/main/java/com/going/presentation/todo/mytodo/create/MyTodoCreateViewModel.kt @@ -3,8 +3,10 @@ package com.going.presentation.todo.mytodo.create import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.going.domain.entity.NameState import com.going.domain.entity.request.TodoCreateRequestModel import com.going.domain.repository.TodoRepository +import com.going.presentation.todo.ourtodo.create.OurTodoCreateViewModel import com.going.ui.extension.UiState import com.going.ui.extension.getGraphemeLength import dagger.hilt.android.lifecycle.HiltViewModel @@ -19,11 +21,13 @@ class MyTodoCreateViewModel @Inject constructor( ) : ViewModel() { val todo = MutableLiveData("") + val isTodoAvailable = MutableLiveData(NameState.Empty) val nowTodoLength = MutableLiveData(0) val endDate = MutableLiveData("") val memo = MutableLiveData("") + val isMemoAvailable = MutableLiveData(NameState.Empty) val nowMemoLength = MutableLiveData(0) val isFinishAvailable = MutableLiveData(false) @@ -34,15 +38,25 @@ class MyTodoCreateViewModel @Inject constructor( var tripId: Long = 0 var participantId: Long = 0 - fun getMaxTodoLen() = MAX_TODO_LEN - - fun getMaxMemoLen() = MAX_MEMO_LEN - fun checkIsFinishAvailable() { nowTodoLength.value = todo.value?.getGraphemeLength() + isTodoAvailable.value = when { + nowTodoLength.value == 0 -> NameState.Empty + (nowTodoLength.value ?: 0) > MAX_TODO_LEN -> NameState.OVER + todo.value.isNullOrBlank() -> NameState.Blank + else -> NameState.Success + } + nowMemoLength.value = memo.value?.getGraphemeLength() + isMemoAvailable.value = when { + nowMemoLength.value == 0 -> NameState.Empty + (nowMemoLength.value ?: 0) > MAX_MEMO_LEN -> NameState.OVER + memo.value.isNullOrBlank() -> NameState.Blank + else -> NameState.Success + } + isFinishAvailable.value = - todo.value?.isNotEmpty() == true && endDate.value?.isNotEmpty() == true + todo.value?.isNotEmpty() == true && endDate.value?.isNotEmpty() == true && isTodoAvailable.value == NameState.Success && isMemoAvailable.value != NameState.OVER } fun postToCreateTodoFromServer() { @@ -71,5 +85,4 @@ class MyTodoCreateViewModel @Inject constructor( const val MAX_TODO_LEN = 15 const val MAX_MEMO_LEN = 1000 } - } diff --git a/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateViewModel.kt b/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateViewModel.kt index 6fdf6fd1..237dcfcd 100644 --- a/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateViewModel.kt +++ b/presentation/src/main/java/com/going/presentation/todo/ourtodo/create/OurTodoCreateViewModel.kt @@ -54,12 +54,11 @@ class OurTodoCreateViewModel @Inject constructor( isMemoAvailable.value = when { nowMemoLength.value == 0 -> NameState.Empty (nowMemoLength.value ?: 0) > MAX_MEMO_LEN -> NameState.OVER - memo.value.isNullOrBlank() -> NameState.Blank else -> NameState.Success } isFinishAvailable.value = - todo.value?.isNotEmpty() == true && endDate.value?.isNotEmpty() == true && participantList.any { it.isSelected } + todo.value?.isNotEmpty() == true && endDate.value?.isNotEmpty() == true && participantList.any { it.isSelected } && isTodoAvailable.value == NameState.Success && isMemoAvailable.value != NameState.OVER } fun postToCreateTodoFromServer() { diff --git a/presentation/src/main/res/layout/activity_my_todo_create.xml b/presentation/src/main/res/layout/activity_my_todo_create.xml index 0c1d2acd..0f1dc0e1 100644 --- a/presentation/src/main/res/layout/activity_my_todo_create.xml +++ b/presentation/src/main/res/layout/activity_my_todo_create.xml @@ -7,6 +7,8 @@ + + @@ -96,7 +98,7 @@ android:includeFontPadding="false" android:inputType="text" android:afterTextChanged="@{(text) -> vm.checkIsFinishAvailable()}" - android:maxLines="1" + android:maxLines="5" android:paddingHorizontal="12dp" android:paddingVertical="19dp" android:text="@={vm.todo}" @@ -106,6 +108,18 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_my_todo_create_todo_title" /> + + + + - \ No newline at end of file + diff --git a/presentation/src/main/res/layout/activity_our_todo_create.xml b/presentation/src/main/res/layout/activity_our_todo_create.xml index 111836fb..5b7191fe 100644 --- a/presentation/src/main/res/layout/activity_our_todo_create.xml +++ b/presentation/src/main/res/layout/activity_our_todo_create.xml @@ -253,7 +253,7 @@ android:layout_marginTop="4dp" android:text="@string/memo_over_error" android:textColor="@color/red_500" - android:visibility="@{(vm.isMemoAvailable() == NameState.Blank) || (vm.isMemoAvailable() == NameState.OVER) ? View.VISIBLE : View.GONE}" + android:visibility="@{vm.isMemoAvailable() == NameState.OVER ? View.VISIBLE : View.GONE}" app:layout_constraintStart_toStartOf="@id/et_our_todo_create_memo" app:layout_constraintTop_toBottomOf="@id/et_our_todo_create_memo" /> From c894d86e2c64364c5a888389081764016e33ccbf Mon Sep 17 00:00:00 2001 From: Dongmin Date: Wed, 17 Jan 2024 14:23:41 +0900 Subject: [PATCH 7/7] =?UTF-8?q?[ADD/#149]=20=EB=88=84=EB=9D=BD=EB=90=9C=20?= =?UTF-8?q?string=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EC=B6=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- presentation/src/main/res/values/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index add47417..747036ec 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -180,6 +180,8 @@ 잘못된 초대코드예요. 초대코드 확인하기 존재하지 않는 여행입니다 + 존재하지 않는 여행입니다. + 입장할 수 있는 최대 인원은 6명입니다. 초대받은 여행이 맞는지\n 확인해 주세요