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

마이페이지 #74

Merged
merged 5 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -0,0 +1,5 @@
package com.woowacourse.friendogly.presentation.ui.mypage

interface MyPageActionHandler {
fun navigateToDogDetail()
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,43 @@
package com.woowacourse.friendogly.presentation.ui.mypage

import androidx.fragment.app.viewModels
import com.woowacourse.friendogly.R
import com.woowacourse.friendogly.databinding.FragmentMyPageBinding
import com.woowacourse.friendogly.presentation.base.BaseFragment
import com.woowacourse.friendogly.presentation.base.observeEvent
import com.woowacourse.friendogly.presentation.ui.mypage.adapter.DogProfileAdapter

class MyPageFragment : BaseFragment<FragmentMyPageBinding>(R.layout.fragment_my_page) {
override fun initViewCreated() {}
private val viewModel: MyPageViewModel by viewModels()

private val adapter: DogProfileAdapter by lazy { DogProfileAdapter(viewModel) }

override fun initViewCreated() {
initDataBinding()
initAdapter()
initObserve()
}

private fun initDataBinding() {
binding.vm = viewModel
}

private fun initAdapter() {
binding.rvDogProfile.adapter = adapter
}

private fun initObserve() {
viewModel.navigateAction.observeEvent(this) { action ->
when (action) {
is MyPageNavigationAction.NavigateToSetting -> TODO()
is MyPageNavigationAction.NavigateToDogDetail -> TODO()
is MyPageNavigationAction.NavigateToDogRegister -> TODO()
is MyPageNavigationAction.NavigateToProfileEdit -> TODO()
}
}

viewModel.uiState.observe(viewLifecycleOwner) { uiState ->
adapter.submitList(uiState.dogs)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.woowacourse.friendogly.presentation.ui.mypage

sealed interface MyPageNavigationAction {
data object NavigateToProfileEdit : MyPageNavigationAction

data object NavigateToSetting : MyPageNavigationAction

data object NavigateToDogRegister : MyPageNavigationAction

data object NavigateToDogDetail : MyPageNavigationAction
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.woowacourse.friendogly.presentation.ui.mypage

import java.time.LocalDate

data class MyPageUiState(
val nickname: String = "",
val email: String = "",
val profilePath: String? = null,
val dogs: List<Dog> = emptyList(),
)
Comment on lines +5 to +10
Copy link
Contributor

Choose a reason for hiding this comment

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

nickname, email에 default-value 가 있는 다른 이유가 있나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

닉네임과 이메일에 null값이 들어와도 화면에는 보이도록 하기 위해서 위와 같이 구현했는데, 이건 다같이 의논해봐도 좋을 것 같아요!!


// TODO 더미 데이터 모델
data class Dog(
Copy link
Contributor

Choose a reason for hiding this comment

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

ui model인가요?
패키지 분리하거나 나중에 수정할 코드라면 TODO로 명시해도 좋습니다 !!

Copy link
Member Author

Choose a reason for hiding this comment

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

val name: String,
val description: String,
val birthDate: LocalDate,
val sizeType: String,
val gender: String,
val isNeutered: Boolean,
val image: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.woowacourse.friendogly.presentation.ui.mypage

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.woowacourse.friendogly.presentation.base.BaseViewModel
import com.woowacourse.friendogly.presentation.base.Event
import com.woowacourse.friendogly.presentation.base.emit
import java.time.LocalDate

class MyPageViewModel : BaseViewModel(), MyPageActionHandler {
private val _uiState: MutableLiveData<MyPageUiState> = MutableLiveData(MyPageUiState())
val uiState: LiveData<MyPageUiState> get() = _uiState

private val _navigateAction: MutableLiveData<Event<MyPageNavigationAction>> =
MutableLiveData(null)
val navigateAction: LiveData<Event<MyPageNavigationAction>> get() = _navigateAction

init {
fetchDummy()
}

private fun fetchDummy() {
Copy link
Contributor

Choose a reason for hiding this comment

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

fetchDummy에 실패할 경우 or 리스트가 없는 경우에 대한 케이스도 구상되어 있을까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

에러 처리에 대한 이야기를 더 자세히 나눠야할 것 같아 구현하지 않았습니다!!

val state = _uiState.value ?: return

_uiState.value =
state.copy(
nickname = "손흥민",
email = "[email protected]",
dogs = dogs,
)
}

fun navigateToDogRegister() {
_navigateAction.emit(MyPageNavigationAction.NavigateToDogRegister)
}

override fun navigateToDogDetail() {
_navigateAction.emit(MyPageNavigationAction.NavigateToDogDetail)
}

companion object {
val dog =
Dog(
name = "땡이",
description = "강인해요",
birthDate = LocalDate.now(),
sizeType = "",
gender = "",
isNeutered = true,
image = "https://github.com/user-attachments/assets/9329234e-e47d-4fc5-b4b5-9f2a827b60b1",
)
val dogs =
listOf<Dog>(
dog,
dog.copy(
name = "초코",
image = "https://github.com/user-attachments/assets/a344d355-8b00-4e08-a33f-08db58010b07",
),
dog.copy(
name = "도토리",
image = "https://petsstore.co.kr/web/product/big/202401/dc7c18de083f0ab58060b4ec82321028.jpg",
),
dog.copy(
name = "도토리",
image = "https://petsstore.co.kr/web/product/big/202401/dc7c18de083f0ab58060b4ec82321028.jpg",
),
dog.copy(
name = "도토리",
image = "https://petsstore.co.kr/web/product/big/202401/dc7c18de083f0ab58060b4ec82321028.jpg",
),
dog.copy(
name = "도토리",
image = "https://petsstore.co.kr/web/product/big/202401/dc7c18de083f0ab58060b4ec82321028.jpg",
),
dog.copy(
name = "도토리",
image = "https://petsstore.co.kr/web/product/big/202401/dc7c18de083f0ab58060b4ec82321028.jpg",
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.woowacourse.friendogly.presentation.ui.mypage.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.woowacourse.friendogly.databinding.ItemDogBinding
import com.woowacourse.friendogly.presentation.ui.mypage.Dog
import com.woowacourse.friendogly.presentation.ui.mypage.MyPageActionHandler

class DogProfileAdapter(
private val actionHandler: MyPageActionHandler,
) : ListAdapter<Dog, DogProfileAdapter.ViewHolder>(DogItemDiffCallback) {
init {
setHasStableIds(true)
}

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ItemDogBinding.inflate(inflater, parent, false)
binding.actionHandler = actionHandler
return ViewHolder(binding)
}

override fun onBindViewHolder(
holder: ViewHolder,
position: Int,
) {
holder.bind(getItem(position))
}

class ViewHolder(private val binding: ItemDogBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: Dog) {
binding.dog = item
}
}

internal object DogItemDiffCallback : DiffUtil.ItemCallback<Dog>() {
override fun areItemsTheSame(
oldItem: Dog,
Comment on lines +42 to +44
Copy link
Member

Choose a reason for hiding this comment

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

혹시 internal companion object 대신 internal object를 쓰는 이유가 있을까요..? 다들 companion object를 많이 쓰던데 object로 두신 이유가 궁금해요!

Copy link
Member Author

Choose a reason for hiding this comment

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

멀티모듈이 아닌 시점에서는 수정해야할 것 같습니다!!

newItem: Dog,
): Boolean = oldItem.name == newItem.name

override fun areContentsTheSame(
oldItem: Dog,
newItem: Dog,
): Boolean = oldItem == newItem
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,27 @@ fun ImageView.bindProfile1000(bitmap: Bitmap?) {
.transform(CenterCrop(), RoundedCorners(1000))
.into(this)
}

@BindingAdapter("glideProfile1000")
Copy link
Contributor

Choose a reason for hiding this comment

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

공용 파일 분리👍

fun ImageView.bindProfile1000(profilePath: String?) {
if (profilePath == null) {
this.setImageResource(R.drawable.img_dog)
return
}

Glide.with(context)
.asBitmap()
.load(profilePath)
.transform(CenterCrop(), RoundedCorners(1000))
.into(this)
}

@BindingAdapter("urlToImage")
fun ImageView.bindUrlToImage(imageUrl: String?) {
imageUrl?.let { url ->
Glide.with(context)
.load(url)
.centerCrop()
.into(this)
}
}
11 changes: 11 additions & 0 deletions android/app/src/main/res/drawable/rect_black_gradient_fill.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<gradient
android:angle="90"
android:centerColor="#70000000"
android:endColor="#00000000"
android:startColor="#80000000"
android:type="linear" />
</shape>
6 changes: 6 additions & 0 deletions android/app/src/main/res/drawable/rect_gray01_fill_16.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="16dp" />
<solid android:color="@color/gray03" />
</shape>
Loading
Loading