diff --git a/Picon/app/build.gradle b/Picon/app/build.gradle index a7c7e1e..bec0944 100644 --- a/Picon/app/build.gradle +++ b/Picon/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.yapp.picon" minSdkVersion 22 targetSdkVersion 29 - versionCode 1 - versionName "1.0" + versionCode 3 + versionName "1.2.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/Picon/app/src/main/AndroidManifest.xml b/Picon/app/src/main/AndroidManifest.xml index e4af199..033ae3f 100644 --- a/Picon/app/src/main/AndroidManifest.xml +++ b/Picon/app/src/main/AndroidManifest.xml @@ -1,9 +1,7 @@ + package="com.yapp.picon"> @@ -13,7 +11,7 @@ @@ -22,6 +23,9 @@ val networkModule = module { single { OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) .addNetworkInterceptor( HttpLoggingInterceptor().also { it.level = HttpLoggingInterceptor.Level.BODY diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectActivity.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectActivity.kt index 1b353aa..61e29af 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectActivity.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectActivity.kt @@ -2,6 +2,7 @@ package com.yapp.picon.presentation.collect import android.content.Intent import android.os.Bundle +import android.util.Log import androidx.lifecycle.Observer import androidx.recyclerview.widget.GridLayoutManager import com.yapp.picon.BR @@ -11,6 +12,7 @@ import com.yapp.picon.databinding.CollectItemBinding import com.yapp.picon.presentation.base.BaseActivity import com.yapp.picon.presentation.model.Pin import com.yapp.picon.presentation.model.Post +import com.yapp.picon.presentation.nav.repository.EmotionDatabaseRepository import com.yapp.picon.presentation.postdetail.PostDetailActivity import org.koin.androidx.viewmodel.ext.android.viewModel @@ -28,6 +30,8 @@ class CollectActivity : BaseActivity( { item: Pin -> itemClicked(item) } ) {} + private val collectBottomSheetDialog = CollectBottomSheetDialog() + private fun itemClicked(item: Pin) { clickItem(item) } @@ -56,6 +60,7 @@ class CollectActivity : BaseActivity( setAdapter() setListeners() setPosts() + setEmotions() } private fun setAdapter() { @@ -65,16 +70,17 @@ class CollectActivity : BaseActivity( private fun setListeners() { binding.collectIbBack.setOnClickListener { finish() } - binding.collectIbFilter.setOnClickListener { - //todo 필터 구현하기 - showToast("필터는 현재 구현 중에 있습니다.") - } + binding.collectIbFilter.setOnClickListener { vm.toggleShowFilterYN() } } private fun setPosts() { vm.setPosts() } + private fun setEmotions() { + EmotionDatabaseRepository(application).getAll().observe(this, { vm.setEmotions(it) }) + } + override fun initViewModel() { binding.setVariable(BR.collectVM, vm) @@ -82,6 +88,23 @@ class CollectActivity : BaseActivity( showToast(it) } vm.toastMsg.observe(this, toastMsgObserver) + + val showFilterYNObserver = Observer { + Log.e(TAG, "showFilterYNObserver : $it") + + if (it) { + collectBottomSheetDialog.show(supportFragmentManager, "CollectBottomSheetDialog") + } else { + if (collectBottomSheetDialog.isVisible) { + collectBottomSheetDialog.dismiss() + } + } + } + vm.showFilterYN.observe(this, showFilterYNObserver) + } + + companion object { + private const val TAG = "CollectActivity" } } \ No newline at end of file diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectBottomSheetDialog.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectBottomSheetDialog.kt new file mode 100644 index 0000000..f9786dc --- /dev/null +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectBottomSheetDialog.kt @@ -0,0 +1,121 @@ +package com.yapp.picon.presentation.collect + +import android.graphics.Typeface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.core.content.res.ResourcesCompat +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Observer +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.yapp.picon.BR +import com.yapp.picon.R +import com.yapp.picon.databinding.CollectBottomSheetBinding +import org.koin.androidx.viewmodel.ext.android.sharedViewModel + +class CollectBottomSheetDialog : BottomSheetDialogFragment() { + + private lateinit var binding: CollectBottomSheetBinding + private val vm: CollectViewModel by sharedViewModel() + + private fun initViewModel() { + binding.setVariable(BR.collectVM, vm) + + val emotion1ClickedYNObserver = Observer { + if (it) { + selectedEmotion(binding.collectMbsTvEmotion1, binding.collectMbsIvEmotion1) + } else { + unselectedEmotion(binding.collectMbsTvEmotion1, binding.collectMbsIvEmotion1) + } + } + vm.emotion1ClickedYN.observe(this, emotion1ClickedYNObserver) + + val emotion2ClickedYNObserver = Observer { + if (it) { + selectedEmotion(binding.collectMbsTvEmotion2, binding.collectMbsIvEmotion2) + } else { + unselectedEmotion(binding.collectMbsTvEmotion2, binding.collectMbsIvEmotion2) + } + } + vm.emotion2ClickedYN.observe(this, emotion2ClickedYNObserver) + + val emotion3ClickedYNObserver = Observer { + if (it) { + selectedEmotion(binding.collectMbsTvEmotion3, binding.collectMbsIvEmotion3) + } else { + unselectedEmotion(binding.collectMbsTvEmotion3, binding.collectMbsIvEmotion3) + } + } + vm.emotion3ClickedYN.observe(this, emotion3ClickedYNObserver) + + val emotion4ClickedYNObserver = Observer { + if (it) { + selectedEmotion(binding.collectMbsTvEmotion4, binding.collectMbsIvEmotion4) + } else { + unselectedEmotion(binding.collectMbsTvEmotion4, binding.collectMbsIvEmotion4) + } + } + vm.emotion4ClickedYN.observe(this, emotion4ClickedYNObserver) + + val emotion5ClickedYNObserver = Observer { + if (it) { + selectedEmotion(binding.collectMbsTvEmotion5, binding.collectMbsIvEmotion5) + } else { + unselectedEmotion(binding.collectMbsTvEmotion5, binding.collectMbsIvEmotion5) + } + } + vm.emotion5ClickedYN.observe(this, emotion5ClickedYNObserver) + } + + private fun selectedEmotion(textView: TextView, imageView: ImageView) { + textView.apply { + setTypeface(null, Typeface.BOLD) + setTextColor(ResourcesCompat.getColor(resources, R.color.pale_grey, null)) + } + imageView.visibility = View.VISIBLE + } + + private fun unselectedEmotion(textView: TextView, imageView: ImageView) { + textView.apply { + setTypeface(null, Typeface.NORMAL) + setTextColor(ResourcesCompat.getColor(resources, R.color.brown_grey, null)) + } + imageView.visibility = View.GONE + } + + private fun setListeners() { + binding.collectMbsLiEmotion1.setOnClickListener { vm.toggleEmotion1ClickedYN() } + binding.collectMbsLiEmotion2.setOnClickListener { vm.toggleEmotion2ClickedYN() } + binding.collectMbsLiEmotion3.setOnClickListener { vm.toggleEmotion3ClickedYN() } + binding.collectMbsLiEmotion4.setOnClickListener { vm.toggleEmotion4ClickedYN() } + binding.collectMbsLiEmotion5.setOnClickListener { vm.toggleEmotion5ClickedYN() } + + binding.collectMbsTvApply.setOnClickListener { + vm.applyFilter() + vm.toggleShowFilterYN() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NORMAL, R.style.TransparentStyle) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = + DataBindingUtil.inflate(inflater, R.layout.collect_bottom_sheet, container, false) + + initViewModel() + setListeners() + + return binding.root + } + +} \ No newline at end of file diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectViewModel.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectViewModel.kt index 15f599e..01b0a47 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectViewModel.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/collect/CollectViewModel.kt @@ -1,12 +1,15 @@ package com.yapp.picon.presentation.collect +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.yapp.picon.domain.usecase.RequestPostsUseCase import com.yapp.picon.presentation.base.BaseViewModel +import com.yapp.picon.presentation.model.EmotionEntity import com.yapp.picon.presentation.model.Pin import com.yapp.picon.presentation.model.Post +import com.yapp.picon.presentation.util.TextViewCode import com.yapp.picon.presentation.util.toPresentation import kotlinx.coroutines.launch @@ -25,13 +28,49 @@ class CollectViewModel( private val _emotionCount = MutableLiveData() val emotionCount: LiveData get() = _emotionCount - private val _toastMsg = MutableLiveData() val toastMsg: LiveData get() = _toastMsg + private val _textViewCodeEmotion = MutableLiveData() + val textViewCodeEmotion: LiveData get() = _textViewCodeEmotion + + private val _textViewCodeLocation = MutableLiveData() + val textViewCodeLocation: LiveData get() = _textViewCodeLocation + + private val _emotions = MutableLiveData>>() + val emotions: LiveData>> get() = _emotions + + private val _showFilterYN = MutableLiveData() + val showFilterYN: LiveData get() = _showFilterYN + + private val _emotion1ClickedYN = MutableLiveData() + val emotion1ClickedYN: LiveData get() = _emotion1ClickedYN + + private val _emotion2ClickedYN = MutableLiveData() + val emotion2ClickedYN: LiveData get() = _emotion2ClickedYN + + private val _emotion3ClickedYN = MutableLiveData() + val emotion3ClickedYN: LiveData get() = _emotion3ClickedYN + + private val _emotion4ClickedYN = MutableLiveData() + val emotion4ClickedYN: LiveData get() = _emotion4ClickedYN + + private val _emotion5ClickedYN = MutableLiveData() + val emotion5ClickedYN: LiveData get() = _emotion5ClickedYN + init { _items.value = mutableListOf() _posts.value = mutableListOf() + _textViewCodeEmotion.value = TextViewCode.COLLECT_MBS_EMOTION.code + _textViewCodeLocation.value = TextViewCode.COLLECT_MBS_LOCATION.code + _emotions.value = mutableListOf() + _showFilterYN.value = false + + _emotion1ClickedYN.value = false + _emotion2ClickedYN.value = false + _emotion3ClickedYN.value = false + _emotion4ClickedYN.value = false + _emotion5ClickedYN.value = false } private fun showToast(msg: String) { @@ -73,4 +112,91 @@ class CollectViewModel( } } + fun toBoolean(value: String?): Boolean = value.toBoolean() + + fun setEmotions(list: List) { + _emotions.value = list.map { + mutableMapOf( + "color" to it.color, + "text" to it.emotion, + "clickedYN" to "false" + ) + } + } + + fun toggleShowFilterYN() { + _showFilterYN.value = _showFilterYN.value?.let { !it } + } + + fun toggleEmotion1ClickedYN() { + _emotion1ClickedYN.value = _emotion1ClickedYN.value?.let { !it } + } + + fun toggleEmotion2ClickedYN() { + _emotion2ClickedYN.value = _emotion2ClickedYN.value?.let { !it } + } + + fun toggleEmotion3ClickedYN() { + _emotion3ClickedYN.value = _emotion3ClickedYN.value?.let { !it } + } + + fun toggleEmotion4ClickedYN() { + _emotion4ClickedYN.value = _emotion4ClickedYN.value?.let { !it } + } + + fun toggleEmotion5ClickedYN() { + _emotion5ClickedYN.value = _emotion5ClickedYN.value?.let { !it } + } + + fun applyFilter() { + val filterEmotionList = arrayListOf() + + filterEmotionList.add(_emotion1ClickedYN.value ?: false) + filterEmotionList.add(_emotion2ClickedYN.value ?: false) + filterEmotionList.add(_emotion3ClickedYN.value ?: false) + filterEmotionList.add(_emotion4ClickedYN.value ?: false) + filterEmotionList.add(_emotion5ClickedYN.value ?: false) + + filterEmotionList.let { + val lastIndex = it.size - 1 + _emotions.value = _emotions.value?.apply { + for (i in 0..lastIndex) { + this[i]["clickedYN"] = it[i].toString() + } + } + Log.e(TAG, "Emotions Value : ${_emotions.value.toString()}") + } + + val emotionFilter = _emotions.value?.filter { + it["clickedYN"] == "true" + }?.mapNotNull { it["color"] } + + emotionFilter?.let { + _items.value = _posts.value?.filter { post -> + post.emotion?.name in emotionFilter + }?.let { posts -> + _locationCount.value = "위치(${posts.groupBy { it.address.addrGu }.keys.size})" + _emotionCount.value = "감정(${posts.groupBy { it.emotion }.keys.size})" + + posts.map { + val size = it.imageUrls?.size ?: 0 + val showManyYN = size > 1 + + Pin( + it.id, + it.imageUrls?.get(0), + it.emotion?.rgb, + showManyYN = showManyYN, + showCbYN = false, + checkYN = false + ) + } + } + } + } + + companion object { + private const val TAG = "CollectViewModel" + } + } \ No newline at end of file diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/login/LoginActivity.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/login/LoginActivity.kt index 7a7aa16..1d7bbd3 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/login/LoginActivity.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/login/LoginActivity.kt @@ -28,6 +28,8 @@ class LoginActivity : BaseActivity( private fun setListeners() { binding.loginBtnLogin.setOnClickListener { vm.login() } binding.loginTvSimpleJoin.setOnClickListener { startSimpleJoinActivity() } + binding.loginIbNaver.setOnClickListener { showToast(getString(R.string.update_plan_guide_text)) } + binding.loginIbKakao.setOnClickListener { showToast(getString(R.string.update_plan_guide_text)) } } private fun startSimpleJoinActivity() { diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/map/MapActivity.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/map/MapActivity.kt index d37b6ba..444a96e 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/map/MapActivity.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/map/MapActivity.kt @@ -4,12 +4,14 @@ import android.Manifest import android.app.Activity import android.content.Context import android.content.Intent -import android.net.Uri +import android.content.pm.PackageManager +import android.location.Location import android.os.Bundle import android.util.Log import android.util.TypedValue import android.view.MenuItem import android.view.View +import android.widget.Toast import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.GravityCompat import androidx.recyclerview.widget.GridLayoutManager @@ -114,7 +116,7 @@ class MapActivity : BaseMapActivity( dpToPx(this, 60f).toInt(), dpToPx(this, 60f).toInt() ) - locationLayoutParams.setMargins(0,0,18,0) + locationLayoutParams.setMargins(0, 0, 18, 0) locationLayoutParams.endToEnd = R.id.map_constraint_layout locationLayoutParams.topToTop = R.id.map_shared_button locationLayoutParams.bottomToBottom = R.id.map_shared_button @@ -173,6 +175,9 @@ class MapActivity : BaseMapActivity( private fun setSharedButton() { binding.mapSharedButton.setOnClickListener { + showToast(getString(R.string.update_plan_guide_text)) + /* + //todo share map Image vm.setToggleShowBtnYN(false) vm.setSharedMenuButton(false) @@ -180,6 +185,7 @@ class MapActivity : BaseMapActivity( getBitmapFromFile()?.let { imageFile -> shareTheScreenShot(imageFile) } + */ } } @@ -294,24 +300,26 @@ class MapActivity : BaseMapActivity( } } - private fun setCurrentLocation() { - LocationHelper(this).requestLocationPermissions()?.let { - val cameraUpdate = CameraUpdate.scrollAndZoomTo( - LatLng(it.latitude, it.longitude), - NaverCamera.DEFAULT_ZOOM - ) - .animate(CameraAnimation.Fly, NaverCamera.DEFAULT_ANIMATION_TIME) - naverMap.moveCamera(cameraUpdate) - - currentLocationMarker.map = null - currentLocationMarker.run { - icon = OverlayImage.fromResource(R.drawable.ic_map_now) - position = LatLng(it.latitude, it.longitude) - this.map = naverMap - } + private fun setCurrentLocationMarker(location: Location) { + val cameraUpdate = CameraUpdate.scrollAndZoomTo( + LatLng(location.latitude, location.longitude), + NaverCamera.DEFAULT_ZOOM + ) + .animate(CameraAnimation.Fly, NaverCamera.DEFAULT_ANIMATION_TIME) + naverMap.moveCamera(cameraUpdate) + + currentLocationMarker.map = null + currentLocationMarker.run { + icon = OverlayImage.fromResource(R.drawable.ic_map_now) + position = LatLng(location.latitude, location.longitude) + this.map = naverMap } } + private fun setCurrentLocation() { + LocationHelper(this).requestLocationPermissions()?.let { setCurrentLocationMarker(it) } + } + private fun checkStoragePermission() { val storagePermissionListener: PermissionListener = object : PermissionListener { override fun onPermissionGranted() { @@ -556,4 +564,25 @@ class MapActivity : BaseMapActivity( return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics) } + private fun showRejectLocation() { + Toast.makeText(this, "권한이 거절되어 현재 위치 찾기가 불가합니다.", Toast.LENGTH_SHORT).show() + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + when (requestCode) { + RequestCodeSet.LOCATION_REQUEST_CODE.code -> { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + setCurrentLocation() + } else { + showRejectLocation() + } + } + } + } + } \ No newline at end of file diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/nav/manageFriend/ManageFriendActivity.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/nav/manageFriend/ManageFriendActivity.kt index 26404a1..15e1664 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/nav/manageFriend/ManageFriendActivity.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/nav/manageFriend/ManageFriendActivity.kt @@ -41,7 +41,8 @@ class ManageFriendActivity : BaseActivity if (str.isEmpty()) { - changeToMainFragment() +// QA 후 PM 요청으로 기능 제거 +// changeToMainFragment() } else { if (binding.manageFriendSearchDeleteButton.visibility == View.GONE) { changeToSearchFragment() diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/profile/MyProfileActivity.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/profile/MyProfileActivity.kt index c33481e..8096b2a 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/profile/MyProfileActivity.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/profile/MyProfileActivity.kt @@ -7,6 +7,7 @@ import android.graphics.Color import android.net.Uri import android.os.Bundle import android.view.View +import android.view.WindowManager import androidx.core.content.res.ResourcesCompat import androidx.recyclerview.widget.GridLayoutManager import com.bumptech.glide.Glide @@ -152,6 +153,25 @@ class MyProfileActivity : BaseActivity(Define.INTENT_PATH)?.let { - vm.setProfileNewImageUri(it[0]) + changeProfileImage(it[0]) } } } diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/profile/MyProfileViewModel.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/profile/MyProfileViewModel.kt index ba2e700..0126eea 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/profile/MyProfileViewModel.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/profile/MyProfileViewModel.kt @@ -73,6 +73,7 @@ class MyProfileViewModel( fun requestUserInfo() { viewModelScope.launch { try { + //HTTP 504 발생 Gateway Time Out getUserInfoUseCase().memberDetailDto.let { _myProfileTitle.value = it.member.nickName _profileImageUrl.value = it.member.profileImageUrl ?: "" diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/simplejoin/SimpleJoinActivity.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/simplejoin/SimpleJoinActivity.kt index 08f4a24..c5338b4 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/simplejoin/SimpleJoinActivity.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/simplejoin/SimpleJoinActivity.kt @@ -3,6 +3,9 @@ package com.yapp.picon.presentation.simplejoin import android.app.Activity import android.content.Intent import android.os.Bundle +import android.view.View +import android.view.WindowManager +import android.widget.EditText import androidx.lifecycle.Observer import com.yapp.picon.BR import com.yapp.picon.R @@ -23,7 +26,61 @@ class SimpleJoinActivity : BaseActivity + if (!hasFocus) { + if ((view as EditText).text.isNullOrBlank()) { + showTextEssential(view.id) + } else { + hideTextEssential(view.id) + } + } + }.let { + binding.run { + simpleJoinEtId.onFocusChangeListener = it + simpleJoinEtPw.onFocusChangeListener = it + simpleJoinEtPwRe.onFocusChangeListener = it + simpleJoinEtNic.onFocusChangeListener = it + } + } + } + + private fun joinMembership() { + startLoading() + vm.joinMembership() + stopLoading() + } + + private fun startLoading() { + binding.simpleJoinProgressBar.visibility = View.VISIBLE + window.setFlags( + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + ) + } + + private fun stopLoading() { + window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) + binding.simpleJoinProgressBar.visibility = View.GONE + } + + private fun showTextEssential(viewId: Int) { + when (viewId) { + binding.simpleJoinEtId.id -> vm.showIdIsBlank() + binding.simpleJoinEtPw.id -> vm.showPwIsBlank() + binding.simpleJoinEtPwRe.id -> vm.showPwReIsBlank() + binding.simpleJoinEtNic.id -> vm.showNicIsBlank() + } + } + + private fun hideTextEssential(viewId: Int) { + when (viewId) { + binding.simpleJoinEtId.id -> vm.hideIdIsBlank() + binding.simpleJoinEtPw.id -> vm.hidePwIsBlank() + binding.simpleJoinEtPwRe.id -> vm.hidePwReIsBlank() + binding.simpleJoinEtNic.id -> vm.hideNicIsBlank() + } } override fun initViewModel() { diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/simplejoin/SimpleJoinViewModel.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/simplejoin/SimpleJoinViewModel.kt index a8857c9..789be14 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/simplejoin/SimpleJoinViewModel.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/simplejoin/SimpleJoinViewModel.kt @@ -23,56 +23,172 @@ class SimpleJoinViewModel( var pwRe = MutableLiveData() var nic = MutableLiveData() + private val _idIsBlank = MutableLiveData() + val idIsBlank: LiveData get() = _idIsBlank + private val _idIsError = MutableLiveData() + val idIsError: LiveData get() = _idIsError + + private val _pwIsBlank = MutableLiveData() + val pwIsBlank: LiveData get() = _pwIsBlank + private val _pwIsError = MutableLiveData() + val pwIsError: LiveData get() = _pwIsError + + private val _pwReIsBlank = MutableLiveData() + val pwReIsBlank: LiveData get() = _pwReIsBlank + private val _pwReIsError = MutableLiveData() + val pwReIsError: LiveData get() = _pwReIsError + + private val _nicIsBlank = MutableLiveData() + val nicIsBlank: LiveData get() = _nicIsBlank + private val _nicIsError = MutableLiveData() + val nicIsError: LiveData get() = _nicIsError + init { _joinYN.value = false + + _idIsBlank.value = false + _idIsError.value = false + _pwIsBlank.value = false + _pwIsError.value = false + _pwReIsBlank.value = false + _pwReIsError.value = false + _nicIsBlank.value = false + _nicIsError.value = false } private fun showToast(msg: String) { _toastMsg.value = msg } + private fun showError(error: String) { + when (error) { + "nickName" -> { + hideNicIsBlank() + _nicIsError.value = true + } + "password" -> { + hidePwIsBlank() + _pwIsError.value = true + } + } + } + + private fun hideErrors() { + _idIsError.value = false + _pwIsError.value = false + _pwReIsError.value = false + _nicIsError.value = false + } + //todo 유효성 검사 가입 완료 후 fun joinMembership() { viewModelScope.launch { + hideErrors() val loginId = id.value if (loginId.isNullOrEmpty()) { - showToast("아이디를 입력해주세요.") + showIdIsBlank() return@launch + } else { + hideIdIsBlank() } val loginPw = pw.value if (loginPw.isNullOrEmpty()) { - showToast("비밀번호를 입력해주세요.") + showPwIsBlank() return@launch + } else { + hidePwIsBlank() } val loginPwRe = pwRe.value if (loginPwRe.isNullOrEmpty()) { - showToast("비밀번호를 재입력해주세요.") + showPwReIsBlank() return@launch + } else { + hidePwReIsBlank() } - if(loginPw != loginPwRe) { - showToast("비밀번호가 일치하지 않습니다.") + if (loginPw != loginPwRe) { + hidePwReIsBlank() + _pwReIsError.value = true return@launch + } else { + _pwReIsError.value = false } val loginNic = nic.value if (loginNic.isNullOrEmpty()) { - showToast("닉네임을 재입력해주세요.") + showNicIsBlank() return@launch + } else { + hideNicIsBlank() } simpleJoinUseCase(loginId, loginPw, loginNic).let { - Log.e("aa12", "joinMembership : $it") + Log.e(TAG, "joinMembership : $it") + if (it.status == 200) { showToast("회원가입이 완료되었습니다!") _joinYN.value = true } else { - showToast(it.errorMessage) + if (it.status == 409) { + _idIsError.value = true + } else { + it.errors.split(",").let { errors -> + Log.e(TAG, errors.size.toString()) + Log.e(TAG, errors.toString()) + + for (error in errors) { + val startIndex = error.indexOf("error field:") + 12 + val endIndex = error.indexOf("message:") + if ((startIndex == -1) or (endIndex == -1)) { + break + } + Log.e(TAG, "startIndex : $startIndex , endIndex : $endIndex") + val errorField = error.substring(startIndex, endIndex).trim() + showError(errorField) + } + } + } } } } } + fun showIdIsBlank() { + _idIsBlank.value = true + } + + fun hideIdIsBlank() { + _idIsBlank.value = false + } + + fun showPwIsBlank() { + _pwIsBlank.value = true + } + + fun hidePwIsBlank() { + _pwIsBlank.value = false + } + + fun showPwReIsBlank() { + _pwReIsBlank.value = true + } + + fun hidePwReIsBlank() { + _pwReIsBlank.value = false + } + + fun showNicIsBlank() { + _nicIsBlank.value = true + } + + fun hideNicIsBlank() { + _nicIsBlank.value = false + } + + companion object { + private const val TAG = "SimpleJoinViewModel" + } + } \ No newline at end of file diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/splash/SplashViewModel.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/splash/SplashViewModel.kt index 88a5b13..86a7d32 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/splash/SplashViewModel.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/splash/SplashViewModel.kt @@ -34,25 +34,34 @@ class SplashViewModel( fun check() { viewModelScope.launch { loadFirstUseCase().let { - Log.e("aa12", "loadFirstUseCase : $it") + Log.e(TAG, "loadFirstUseCase : $it") _firstYN.value = it } - loadAccessTokenUseCase().let { - Log.e("aa12", "loadAccessTokenUseCase : $it") - _loginYN.value = it.isNotEmpty() + // AccessToken 이 있지만 인증이 안될 경우 try catch 로 처리합니다. + try { + loadAccessTokenUseCase().let { + Log.e(TAG, "loadAccessTokenUseCase : $it") + _loginYN.value = it.isNotEmpty() + } + } catch (e: Exception) { + Log.e(TAG, "Error loadAccessTokenUseCase : ${e.message}") + return@launch } - Log.e("aa12", "_checkYN CHANGE") + Log.e(TAG, "_checkYN CHANGE") _checkYN.value = true } } fun saveFirstYN(firstYN: Boolean) { viewModelScope.launch { - Log.e("aa12", "saveFirstYN") + Log.e(TAG, "saveFirstYN") saveFirstUseCase(firstYN) } } + companion object { + private const val TAG = "SplashViewModel" + } } \ No newline at end of file diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/util/LocationHelper.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/util/LocationHelper.kt index c78fffc..09992a1 100644 --- a/Picon/app/src/main/java/com/yapp/picon/presentation/util/LocationHelper.kt +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/util/LocationHelper.kt @@ -6,12 +6,11 @@ import android.content.Context import android.content.pm.PackageManager import android.location.Location import android.location.LocationManager -import android.widget.Toast import androidx.core.app.ActivityCompat class LocationHelper(private val context: Context) { - private val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager - private var location: Location? = null + private val locationManager = + context.getSystemService(Context.LOCATION_SERVICE) as LocationManager private fun checkPermission(): Boolean { return ActivityCompat.checkSelfPermission( @@ -23,19 +22,29 @@ class LocationHelper(private val context: Context) { ) == PackageManager.PERMISSION_GRANTED } - fun locationPermissionResult(): Location? { - if (checkPermission()) { - location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) - return location + private fun getLocation(): Location? { + val isGPSEnabled: Boolean = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) + val isNetworkEnabled: Boolean = + locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) + + return if (checkPermission()) { + when { + isNetworkEnabled -> { + locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) + } + isGPSEnabled -> { + locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) + } + else -> null + } + } else { + null } - Toast.makeText(context, "권한이 거절되어 현재 위치 찾기가 불가합니다.", Toast.LENGTH_SHORT).show() - return null } fun requestLocationPermissions(): Location? { - if (checkPermission()) { - location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) - return location + getLocation()?.let { + return it } ActivityCompat.requestPermissions( context as Activity, @@ -44,6 +53,7 @@ class LocationHelper(private val context: Context) { Manifest.permission.ACCESS_COARSE_LOCATION ), RequestCodeSet.LOCATION_REQUEST_CODE.code ) - return location + return null } + } \ No newline at end of file diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/util/TextViewCode.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/util/TextViewCode.kt new file mode 100644 index 0000000..3888376 --- /dev/null +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/util/TextViewCode.kt @@ -0,0 +1,6 @@ +package com.yapp.picon.presentation.util + +enum class TextViewCode(val code: Int) { + COLLECT_MBS_EMOTION(2000), + COLLECT_MBS_LOCATION(2001) +} \ No newline at end of file diff --git a/Picon/app/src/main/java/com/yapp/picon/presentation/util/TextViewExt.kt b/Picon/app/src/main/java/com/yapp/picon/presentation/util/TextViewExt.kt new file mode 100644 index 0000000..5f20ae7 --- /dev/null +++ b/Picon/app/src/main/java/com/yapp/picon/presentation/util/TextViewExt.kt @@ -0,0 +1,31 @@ +package com.yapp.picon.presentation.util + +import android.graphics.Typeface +import android.widget.TextView +import androidx.core.content.res.ResourcesCompat +import androidx.databinding.BindingAdapter +import com.yapp.picon.R + +@BindingAdapter("isClicked", "textViewCode") +fun TextView.isClicked(isClicked: Boolean, textViewCode: Int) { + when (textViewCode) { + TextViewCode.COLLECT_MBS_EMOTION.code -> { + if (isClicked) { + setTypeface(null, Typeface.BOLD) + setTextColor(ResourcesCompat.getColor(resources, R.color.pale_grey, null)) + } else { + setTypeface(null, Typeface.NORMAL) + setTextColor(ResourcesCompat.getColor(resources, R.color.brown_grey, null)) + } + } + TextViewCode.COLLECT_MBS_LOCATION.code -> { + if (isClicked) { + setTypeface(null, Typeface.BOLD) + setTextColor(ResourcesCompat.getColor(resources, R.color.pale_grey, null)) + } else { + setTypeface(null, Typeface.NORMAL) + setTextColor(ResourcesCompat.getColor(resources, R.color.brown_grey_two, null)) + } + } + } +} \ No newline at end of file diff --git a/Picon/app/src/main/res/drawable-hdpi/ic_collect_mbs_check.png b/Picon/app/src/main/res/drawable-hdpi/ic_collect_mbs_check.png new file mode 100644 index 0000000..1d45740 Binary files /dev/null and b/Picon/app/src/main/res/drawable-hdpi/ic_collect_mbs_check.png differ diff --git a/Picon/app/src/main/res/drawable-mdpi/ic_collect_mbs_check.png b/Picon/app/src/main/res/drawable-mdpi/ic_collect_mbs_check.png new file mode 100644 index 0000000..16af853 Binary files /dev/null and b/Picon/app/src/main/res/drawable-mdpi/ic_collect_mbs_check.png differ diff --git a/Picon/app/src/main/res/drawable-xhdpi/ic_collect_mbs_check.png b/Picon/app/src/main/res/drawable-xhdpi/ic_collect_mbs_check.png new file mode 100644 index 0000000..9028272 Binary files /dev/null and b/Picon/app/src/main/res/drawable-xhdpi/ic_collect_mbs_check.png differ diff --git a/Picon/app/src/main/res/drawable-xxhdpi/ic_collect_mbs_check.png b/Picon/app/src/main/res/drawable-xxhdpi/ic_collect_mbs_check.png new file mode 100644 index 0000000..9f34e5c Binary files /dev/null and b/Picon/app/src/main/res/drawable-xxhdpi/ic_collect_mbs_check.png differ diff --git a/Picon/app/src/main/res/drawable-xxxhdpi/ic_collect_mbs_check.png b/Picon/app/src/main/res/drawable-xxxhdpi/ic_collect_mbs_check.png new file mode 100644 index 0000000..c5924e1 Binary files /dev/null and b/Picon/app/src/main/res/drawable-xxxhdpi/ic_collect_mbs_check.png differ diff --git a/Picon/app/src/main/res/drawable/bg_collect_bottom_sheet.xml b/Picon/app/src/main/res/drawable/bg_collect_bottom_sheet.xml new file mode 100644 index 0000000..45667b4 --- /dev/null +++ b/Picon/app/src/main/res/drawable/bg_collect_bottom_sheet.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/Picon/app/src/main/res/layout/collect_bottom_sheet.xml b/Picon/app/src/main/res/layout/collect_bottom_sheet.xml new file mode 100644 index 0000000..0f09cf3 --- /dev/null +++ b/Picon/app/src/main/res/layout/collect_bottom_sheet.xml @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +