Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AN] 마이페이지 수정 및 보기 기능 개선 #602

Merged
merged 25 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c493caa
refactor: 간단 소개 multiLine 지정 및 autoLink 설정
inseonyun Nov 2, 2023
fa1efb2
refactor: 필수 투두 -> Must Do
inseonyun Nov 2, 2023
264c137
refactor: profile, nickname StateFlow로 변경
inseonyun Nov 2, 2023
5c8b837
refactor: ProfileType StateFlow로 변경
inseonyun Nov 2, 2023
dd7a23a
refactor: NicknameState StateFlow로 변경
inseonyun Nov 2, 2023
829d605
refactor: Introduction StateFlow로 변경
inseonyun Nov 2, 2023
3c4dfb9
refactor: modifyProfileState StateFlow로 변경
inseonyun Nov 2, 2023
8110519
refactor: MyPageEvent 구현
inseonyun Nov 2, 2023
6c38e2b
refactor: DataBinding -> ViewBinding
inseonyun Nov 2, 2023
7fd38b9
refactor: 누군가 파놓은 Profile 중복 옵저빙 제거
inseonyun Nov 2, 2023
b181627
refactor: 불필요한 함수 제거 및 함수 분리
inseonyun Nov 2, 2023
39db7ee
refactor: 닉네임 검증 입력 반응 0.7초간 없을 경우 수행
inseonyun Nov 2, 2023
88fc692
refactor: 프로필 수정 취소 리셋 함수 수정
inseonyun Nov 2, 2023
1be2271
refactor: 프로필 수정 상태 시 nickname EditText 언더 라인 및 drawable 표시
inseonyun Nov 2, 2023
cc6016b
refactor: 프로필 수정 상태 시 introduction EditText 보더 라인 컬러 변경
inseonyun Nov 2, 2023
dba6c67
refactor: State enum class로 관리
inseonyun Nov 7, 2023
0ef0bef
refactor: strings 오탈자 수정
inseonyun Nov 7, 2023
71c2000
refactor: set function prefix 수정
inseonyun Nov 7, 2023
fca93bf
chore: conflict 해결
inseonyun Nov 7, 2023
8d3920e
refactor: BindingViewFragment 사용
inseonyun Nov 7, 2023
c582543
refactor: MyPage 스터디 성공률 및 Must Do 성공률 커스텀 뷰 작성
inseonyun Nov 7, 2023
4803819
refactor: 프로필 수정 액티비티 추가
inseonyun Nov 8, 2023
058d484
refactor: 프로필 수정 뷰 Dialog로 변경
inseonyun Nov 9, 2023
24ce134
refactor: layout 태그 제거
inseonyun Nov 9, 2023
e97f2b7
refactor: back 버튼 클릭 시 dismiss 하도록 수정
inseonyun Nov 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,32 +1,46 @@
package com.created.team201.presentation.myPage

import android.content.res.ColorStateList
import android.os.Bundle
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.GridLayout
import android.widget.ImageView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.view.forEach
import androidx.core.view.setMargins
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import androidx.fragment.app.viewModels
import com.bumptech.glide.Glide
import com.created.team201.R
import com.created.team201.databinding.FragmentMyPageBinding
import com.created.team201.presentation.common.BindingFragment
import com.created.team201.presentation.myPage.MyPageViewModel.State.FAIL
import com.created.team201.presentation.myPage.MyPageViewModel.State.IDLE
import com.created.team201.presentation.myPage.MyPageViewModel.State.SUCCESS
import com.created.team201.presentation.myPage.MyPageViewModel.Event.EnableModify
import com.created.team201.presentation.myPage.MyPageViewModel.Event.ModifyMyPage
import com.created.team201.presentation.myPage.MyPageViewModel.Event.ShowDialog
import com.created.team201.presentation.myPage.MyPageViewModel.Event.ShowToast
import com.created.team201.presentation.myPage.MyPageViewModel.State.Fail
import com.created.team201.presentation.myPage.MyPageViewModel.State.Loading
import com.created.team201.presentation.myPage.MyPageViewModel.State.Success
import com.created.team201.presentation.myPage.model.ProfileType
import com.created.team201.presentation.myPage.model.TierProgress
import com.created.team201.presentation.setting.SettingActivity
import com.created.team201.presentation.studyDetail.model.Tier
import com.created.team201.util.FirebaseLogUtil
import com.created.team201.util.FirebaseLogUtil.SCREEN_MY_PAGE
import com.created.team201.util.collectOnStarted
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MyPageFragment : BindingFragment<FragmentMyPageBinding>(R.layout.fragment_my_page) {
class MyPageFragment : Fragment() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

새로운 ViewBinding BaseClass 만들어두었습니다! HomeFragement참고

private val myPageViewModel: MyPageViewModel by viewModels()
private var _binding: FragmentMyPageBinding? = null
private val binding: FragmentMyPageBinding get() = _binding!!
Copy link
Collaborator

Choose a reason for hiding this comment

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

오래동안 안써서 까먹을 법도 한데 세심하게 잘 처리해주셨네요!


override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
Expand All @@ -43,21 +57,39 @@ class MyPageFragment : BindingFragment<FragmentMyPageBinding>(R.layout.fragment_
FirebaseLogUtil.logScreenEvent(SCREEN_MY_PAGE, [email protected])
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentMyPageBinding.inflate(layoutInflater)
return binding.root
}

override fun onDestroyView() {
super.onDestroyView()

_binding = null
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

initBinding()
setActionBar()
initMyProfile()
setNicknameValidate()
setMyPageObserve()
setActionBar()
setOnProfileModifyClick()
observeProfile()
setEditTextChangeListener()
collectMyProfileInformation()
collectMyProfileType()
collectModifyProfileState()
collectNicknameState()
collectMyProfile()
collectMyPageEvent()
}

private fun initBinding() {
binding.lifecycleOwner = viewLifecycleOwner
binding.viewModel = myPageViewModel
private fun initMyProfile() {
myPageViewModel.loadProfile()
myPageViewModel.setProfileType(ProfileType.VIEW)
}

private fun setActionBar() {
Expand All @@ -77,58 +109,167 @@ class MyPageFragment : BindingFragment<FragmentMyPageBinding>(R.layout.fragment_
startActivity(SettingActivity.getIntent(requireContext()))
}

private fun initMyProfile() {
myPageViewModel.loadProfile()
myPageViewModel.setProfileType(ProfileType.VIEW)
private fun setOnProfileModifyClick() {
binding.tvMyPageBtnModifyProfile.setOnClickListener {
when (myPageViewModel.profileType.value) {
ProfileType.VIEW -> {
myPageViewModel.switchProfileType()
}

ProfileType.MODIFY -> {
myPageViewModel.changeMyPageEvent(ShowDialog)
}
}
}
}

private fun setProfileView(enabled: Boolean) {
setNicknameReadWriteMode(enabled)
setIntroductionReadWriteMode(enabled)
binding.etMyPageProfileNickname.requestFocus(View.FOCUS_UP)
binding.tvMyPageNicknameValidateIntroduction.visibility =
if (enabled) View.VISIBLE else View.GONE
binding.tbMyPage.menu.forEach { item ->
item.isVisible = !enabled
}
binding.tvMyPageBtnModifyProfile.text =
if (enabled) getString(R.string.myPage_button_save_profile) else getString(R.string.myPage_button_modify_profile)
}

private fun setNicknameValidate() {
binding.etMyPageProfileNickname.setOnFocusChangeListener { _, focus ->
if (focus) return@setOnFocusChangeListener
myPageViewModel.checkAvailableNickname()
private fun setNicknameReadWriteMode(enabled: Boolean) {
with(binding.etMyPageProfileNickname) {
isEnabled = enabled
when (enabled) {
true -> {
backgroundTintList =
ColorStateList.valueOf(requireContext().getColor(R.color.green02_E639D353))
setCompoundDrawablesWithIntrinsicBounds(
null,
null,
ContextCompat.getDrawable(requireContext(), R.drawable.ic_edit_16),
null,
)
}

false -> {
backgroundTintList =
ColorStateList.valueOf(requireContext().getColor(R.color.transparent))
setCompoundDrawables(null, null, null, null)
}
}
}
}

private fun setMyPageObserve() {
myPageViewModel.profileType.observe(viewLifecycleOwner) { profileType ->
private fun setIntroductionReadWriteMode(enabled: Boolean) {
with(binding.etMyPageProfileIntroduction) {
when (enabled) {
true -> {
background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_stroke_fill_color_5dp)
linksClickable = enabled.not()
isCursorVisible = enabled
keyListener = EditText(requireContext()).keyListener
}

false -> {
background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_rectangle_radius_5dp)
linksClickable = enabled.not()
isCursorVisible = enabled
keyListener = null
}
}
}
}

private fun setEditTextChangeListener() {
binding.etMyPageProfileNickname.filters = myPageViewModel.getInputFilter()
binding.etMyPageProfileNickname.doOnTextChanged { text, start, before, count ->
myPageViewModel.setNickname(text.toString())
}
binding.etMyPageProfileIntroduction.doOnTextChanged { text, _, _, _ ->
myPageViewModel.setIntroduction(text.toString())
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

함수 파라미터가 없기 때문에 prefix를 set 대신 setup으로 변경하시는게 좋을 것 같네요


private fun collectMyProfileInformation() {
myPageViewModel.nickname.collectOnStarted(viewLifecycleOwner) { nickname ->
if (binding.etMyPageProfileNickname.text.toString() == nickname) return@collectOnStarted
binding.etMyPageProfileNickname.setText(nickname)
}

myPageViewModel.introduction.collectOnStarted(viewLifecycleOwner) { introduction ->
if (binding.etMyPageProfileIntroduction.text.toString() == introduction) return@collectOnStarted
binding.etMyPageProfileIntroduction.setText(introduction)
}
}

private fun collectMyProfileType() {
myPageViewModel.profileType.collectOnStarted(viewLifecycleOwner) { profileType ->
when (profileType) {
ProfileType.VIEW -> setProfileView(false)
ProfileType.MODIFY -> setProfileView(true)
else -> Unit
}
}
myPageViewModel.modifyProfileState.observe(viewLifecycleOwner) { modifyProfileState ->
}

private fun collectModifyProfileState() {

myPageViewModel.modifyProfileState.collectOnStarted(viewLifecycleOwner) { modifyProfileState ->
when (modifyProfileState) {
SUCCESS -> {
Toast.makeText(
requireContext(),
getString(R.string.myPage_toast_modify_profile_success),
Toast.LENGTH_SHORT,
).show()
Loading -> Unit
Success -> {
myPageViewModel.changeMyPageEvent(
ShowToast(getString(R.string.myPage_toast_modify_profile_success))
)
}

FAIL -> {
Toast.makeText(
requireContext(),
getString(R.string.myPage_toast_modify_profile_failed),
Toast.LENGTH_SHORT,
).show()
myPageViewModel.resetModifyProfile()
Fail -> {
myPageViewModel.changeMyPageEvent(
ShowToast(getString(R.string.myPage_toast_modify_profile_failed))
)
}
}
}
}

IDLE -> throw IllegalStateException()
private fun collectNicknameState() {
myPageViewModel.nicknameState.collectOnStarted(viewLifecycleOwner) { state ->
with(binding.tvMyPageNicknameValidateIntroduction) {
text = getString(state.introduction)
setTextColor(requireContext().getColor(state.color))
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

wow.

}
}

private fun setOnProfileModifyClick() {
binding.tvMyPageBtnModifyProfile.setOnClickListener {
when (myPageViewModel.profileType.value) {
ProfileType.VIEW -> {
myPageViewModel.switchProfileType()
}
private fun collectMyProfile() {
myPageViewModel.profile.collectOnStarted(viewLifecycleOwner) { profile ->
binding.ivMyPageProfile.loadImageUrl(profile.profileImageUrl)
binding.tvMyPageProfileId.text = profile.githubId
binding.etMyPageProfileNickname.setText(profile.profileInformation.nickname.nickname)
binding.etMyPageProfileIntroduction.setText(profile.profileInformation.introduction)
binding.layoutMyPageStudySuccessRate.result =
getString(R.string.profile_success_rate_format, profile.successRate)
binding.layoutMyPageTodoSuccessRate.result =
getString(R.string.profile_todo_success_rate_format, profile.successfulRoundCount)
setupTierProgress(
TierProgress.of(
Tier.of(profile.tier),
profile.tierProgress,
).getTierProgressTable(),
)
}
}

ProfileType.MODIFY -> {
private fun ImageView.loadImageUrl(imageUrl: String?) {
Glide.with(requireContext())
.load(imageUrl)
.into(this)
}

private fun collectMyPageEvent() {
myPageViewModel.myPageEvent.collectOnStarted(viewLifecycleOwner) { event ->
when (event) {
is ShowToast -> showToast(event.message)
ShowDialog -> {
removeDialog()
showDialog(
getString(R.string.myPage_dialog_modify_profile_title),
Expand All @@ -137,40 +278,18 @@ class MyPageFragment : BindingFragment<FragmentMyPageBinding>(R.layout.fragment_
)
}

else -> throw IllegalStateException()
ModifyMyPage -> myPageViewModel.patchMyProfile()
is EnableModify -> binding.tvMyPageBtnModifyProfile.isEnabled = event.isEnable
}
}
}

private fun onModifySaveClick(): MyPageDialogClickListener =
object : MyPageDialogClickListener {
override fun onCancelClick() {
myPageViewModel.resetModifyProfile()
Toast.makeText(
requireContext(),
getString(R.string.myPage_toast_modify_profile_cancel),
Toast.LENGTH_SHORT,
).show()
myPageViewModel.switchProfileType()
}

override fun onOkClick() {
myPageViewModel.patchMyProfile()
myPageViewModel.switchProfileType()
private fun removeDialog() {
childFragmentManager.findFragmentByTag(TAG_DIALOG_MODIFY_PROFILE)?.let {
childFragmentManager.commit {
remove(it)
}
}

private fun setProfileView(enabled: Boolean) {
binding.etMyPageProfileNickname.isEnabled = enabled
binding.etMyPageProfileIntroduction.isEnabled = enabled
binding.etMyPageProfileNickname.requestFocus(View.FOCUS_UP)
binding.tvMyPageNicknameValidateIntroduction.visibility =
if (enabled) View.VISIBLE else View.GONE
binding.tbMyPage.menu.forEach { item ->
item.isVisible = !enabled
}
binding.tvMyPageBtnModifyProfile.text =
if (enabled) getString(R.string.myPage_button_save_profile) else getString(R.string.myPage_button_modify_profile)
}

private fun showDialog(
Expand All @@ -184,21 +303,21 @@ class MyPageFragment : BindingFragment<FragmentMyPageBinding>(R.layout.fragment_
)
}

private fun removeDialog() {
childFragmentManager.findFragmentByTag(TAG_DIALOG_MODIFY_PROFILE)?.let {
childFragmentManager.commit {
remove(it)
private fun onModifySaveClick(): MyPageDialogClickListener =
object : MyPageDialogClickListener {
override fun onCancelClick() {
myPageViewModel.changeMyPageEvent(
ShowToast(getString(R.string.myPage_toast_modify_profile_cancel))
)
myPageViewModel.resetModifyProfile()
myPageViewModel.switchProfileType()
}
}
}

private fun observeProfile() {
myPageViewModel.profile.observe(viewLifecycleOwner) { profile ->
val tierProgress =
TierProgress.of(Tier.of(profile.tier), profile.tierProgress).getTierProgressTable()
setupTierProgress(tierProgress)
override fun onOkClick() {
myPageViewModel.changeMyPageEvent(ModifyMyPage)
myPageViewModel.switchProfileType()
}
}
}

private fun setupTierProgress(tierProgress: List<Int>) {
binding.glMyPageTierProgress.removeAllViews()
Expand Down Expand Up @@ -228,6 +347,9 @@ class MyPageFragment : BindingFragment<FragmentMyPageBinding>(R.layout.fragment_
requireContext().resources.displayMetrics,
).toInt()

private fun showToast(message: String) =
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()

companion object {
private const val TAG_DIALOG_MODIFY_PROFILE = "TAG_DIALOG_MODIFY_PROFILE"
private const val TOTAL_BLOCK_COUNT = 20
Expand Down
Loading