Skip to content

Commit

Permalink
[feature/myPage] myPage 진행상황 공유 (#57)
Browse files Browse the repository at this point in the history
* [feat/store]: del legacy code

* [feat/store]: feat MyFage

* [feat/store]: add fake Repository

* [feat/store]: refactor approve code review

* [feat/store]: add background store text

* [feat/store]: UI albumPhotoCount

* [feat/mypage]: UI photoCount

* [feat/mypage]: add getMyPageEmtpyInfo

* [feat/mypage]: UI EmtpyImage

* [feat/mypage]: move GridSpacingItemDecoration to core/common

* [feat/mypage]: approve code review

* [feat/mypage]: add DiffUtil at MyPageAdapter super

* [feat/mypage]: add listener at iv_setting

* [feat/mypage]: refactor to MultiViewType Rv

* [feat/mypage]: refactor Any Class

* [feat/store]: UI title logo margin edit

* [feat/mypage]: chore black del

* [feat/mypage]: fix responsenamig

* [feat/mypage]: fix bug
  • Loading branch information
librarywon authored Jul 4, 2023
1 parent 6df9e25 commit 8d3f365
Show file tree
Hide file tree
Showing 22 changed files with 692 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.teampophory.pophory.data.repository

import com.teampophory.pophory.network.model.MyPageResponse

interface MyPageInfoRepository {
suspend fun getMyPageInfo(): Result<MyPageResponse>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.teampophory.pophory.data.repository.fake

import com.teampophory.pophory.data.repository.MyPageInfoRepository
import com.teampophory.pophory.network.model.MyPageResponse
import kotlinx.coroutines.delay

class FakeMyPageInfoRepository : MyPageInfoRepository {
private val fakeImageUrl =
"https://images.unsplash.com/photo-1687023956422-117d5c47029d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3432&q=80"

override suspend fun getMyPageInfo(): Result<MyPageResponse> {
delay(300)
return runCatching {
MyPageResponse(
"한수아",
"HANSUAH",
"",
5,
listOf(

)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.teampophory.pophory.feature.home.mypage

sealed class MyPageDisplayItem {
data class Profile(
val realName: String,
val nickname: String,
val photoCount: Int
) : MyPageDisplayItem()

data class Photo(val photo: MyPageInfo.Photo) : MyPageDisplayItem()
}

data class MyPageInfo(
val realName: String,
val nickname: String,
val photoCount: Int,
val photos: List<Photo>
) {
data class Photo(
val photoId: Long,
val photoUrl: String
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,108 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.teampophory.pophory.R
import com.teampophory.pophory.common.fragment.toast
import com.teampophory.pophory.common.view.GridSpacingItemDecoration
import com.teampophory.pophory.common.view.viewBinding
import com.teampophory.pophory.databinding.FragmentMyPageBinding
import com.teampophory.pophory.databinding.FragmentMypageBinding
import com.teampophory.pophory.feature.home.mypage.adapter.MyPageAdapter
import com.teampophory.pophory.feature.home.mypage.adapter.MyPageAdapter.Companion.VIEW_TYPE_PHOTO
import com.teampophory.pophory.feature.home.mypage.adapter.MyPageAdapter.Companion.VIEW_TYPE_PROFILE

class MyPageFragment : Fragment() {
private val binding by viewBinding(FragmentMyPageBinding::bind)
private val binding by viewBinding(FragmentMypageBinding::bind)

private var myPageAdapter: MyPageAdapter? = null

private val viewModel by viewModels<MyPageViewModel>()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_my_page, container, false)
return inflater.inflate(R.layout.fragment_mypage, container, false)
}

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

override fun onDestroyView() {
super.onDestroyView()
myPageAdapter = null
}

private fun initObserver() {
viewModel.myPageInfo.observe(viewLifecycleOwner) { myPageInfoState ->
when (myPageInfoState) {
is MyPageInfoState.Uninitialized -> {
viewModel.getMyPageInfo()
initRecyclerView()
}

is MyPageInfoState.Loading -> {}

is MyPageInfoState.SuccessMyPageInfo -> {
val photoItems =
myPageInfoState.data.filterIsInstance<MyPageDisplayItem.Photo>()
val isEmpty = photoItems.isEmpty()
val myPageInfoData = myPageInfoState.data
val profileItem =
myPageInfoState.data.firstOrNull { it is MyPageDisplayItem.Profile } as? MyPageDisplayItem.Profile

with(binding) {
tvMypageToolbarNickname.text = "@${profileItem?.nickname}"
myPageAdapter?.submitList(myPageInfoData)
ivMypageFeedEmpty.isVisible = isEmpty
tvMypageFeedEmpty.isVisible = isEmpty
}
}

is MyPageInfoState.Error -> {}
}
}
}

private fun initRecyclerView() {
val gridLayoutManager =
GridLayoutManager(requireContext(), 3, GridLayoutManager.VERTICAL, false)

myPageAdapter = MyPageAdapter { photos ->
val photoList = viewModel.myPageInfo.value
if (photoList is MyPageInfoState.SuccessMyPageInfo) {
toast(photos.photo.photoId.toString());
//TODO intent photo_detail activity
}
}

gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return when (position) {
VIEW_TYPE_PROFILE -> 3
VIEW_TYPE_PHOTO -> 1
else -> 1
}
}
}

binding.rvMypage.apply {
layoutManager = gridLayoutManager
adapter = myPageAdapter
isNestedScrollingEnabled = false
}.addItemDecoration(GridSpacingItemDecoration(3, 2, false))
}

private fun setOnClickListener() {
binding.ivToolbarSetting.setOnClickListener {
//TODO intent to setting
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.teampophory.pophory.feature.home.mypage

sealed class MyPageInfoState {
object Uninitialized : MyPageInfoState()
object Loading : MyPageInfoState()
data class SuccessMyPageInfo(val data: List<MyPageDisplayItem>) : MyPageInfoState()
data class Error(val error: Throwable) : MyPageInfoState()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.teampophory.pophory.feature.home.mypage

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.teampophory.pophory.data.repository.MyPageInfoRepository
import com.teampophory.pophory.data.repository.fake.FakeMyPageInfoRepository
import kotlinx.coroutines.launch


class MyPageViewModel : ViewModel() {

private val myPageInfoRepository: MyPageInfoRepository = FakeMyPageInfoRepository()

private val _myPageUserInfo = MutableLiveData<MyPageInfoState>(MyPageInfoState.Uninitialized)
val myPageInfo: LiveData<MyPageInfoState> get() = _myPageUserInfo

fun getMyPageInfo() {
viewModelScope.launch {
_myPageUserInfo.value = MyPageInfoState.Loading

myPageInfoRepository.getMyPageInfo()
.onSuccess {
_myPageUserInfo.value =
MyPageInfoState.SuccessMyPageInfo(it.toItems())
}.onFailure {
_myPageUserInfo.value = MyPageInfoState.Error(it)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.teampophory.pophory.feature.home.mypage.adapter

import android.content.Context
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import coil.load
import com.teampophory.pophory.R
import com.teampophory.pophory.common.view.ItemDiffCallback
import com.teampophory.pophory.databinding.ItemMypageFeedBinding
import com.teampophory.pophory.databinding.ItemMypageProfileBinding
import com.teampophory.pophory.feature.home.mypage.MyPageDisplayItem

class MyPageAdapter(
private val onItemClicked: (MyPageDisplayItem.Photo) -> Unit
) : ListAdapter<MyPageDisplayItem, RecyclerView.ViewHolder>(
ItemDiffCallback<MyPageDisplayItem>(
onItemsTheSame = { old, new -> old == new },
onContentsTheSame = { old, new -> old == new }
)
) {
companion object {
const val VIEW_TYPE_PROFILE = 0
const val VIEW_TYPE_PHOTO = 1
}

override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is MyPageDisplayItem.Profile -> VIEW_TYPE_PROFILE
is MyPageDisplayItem.Photo -> VIEW_TYPE_PHOTO
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val context = parent.context
return when (viewType) {
VIEW_TYPE_PROFILE -> {
val binding =
ItemMypageProfileBinding.inflate(LayoutInflater.from(context), parent, false)
ProfileViewHolder(binding, context)
}

VIEW_TYPE_PHOTO -> {
val binding =
ItemMypageFeedBinding.inflate(LayoutInflater.from(context), parent, false)
PhotoViewHolder(binding, onItemClicked)
}

else -> throw IllegalArgumentException("Invalid view type")
}
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = getItem(position)) {
is MyPageDisplayItem.Profile -> {
(holder as ProfileViewHolder).bind(item)
}

is MyPageDisplayItem.Photo -> {
(holder as PhotoViewHolder).bind(item)
}
}
}

class PhotoViewHolder(
private val binding: ItemMypageFeedBinding,
private val onItemClicked: (MyPageDisplayItem.Photo) -> Unit
) : RecyclerView.ViewHolder(binding.root) {
fun bind(photo: MyPageDisplayItem.Photo) {
binding.ivMypageFeedItem.load(photo.photo.photoUrl)
itemView.setOnClickListener {
onItemClicked(photo)
}
}
}

class ProfileViewHolder(
private val binding: ItemMypageProfileBinding,
private val context: Context
) : RecyclerView.ViewHolder(binding.root) {
fun bind(profileInfo: MyPageDisplayItem.Profile) {
with(binding) {
tvMypageName.text = profileInfo.realName
tvMypagePictureCount.text = setSpannableString(profileInfo.photoCount)
}
}

private fun setSpannableString(myPageInfoDataPhotoCount: Int): SpannableStringBuilder {
val fullText =
context.getString(R.string.mypage_picture_count, myPageInfoDataPhotoCount)
val coloredText = myPageInfoDataPhotoCount.toString()

val spannableStringBuilder = SpannableStringBuilder(fullText)
val start = fullText.indexOf(coloredText)
val end = start + coloredText.length

if (start != -1) {
spannableStringBuilder.setSpan(
ForegroundColorSpan(
ContextCompat.getColor(
context,
R.color.pophory_purple
)
),
start,
end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
return spannableStringBuilder
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.teampophory.pophory.R
import com.teampophory.pophory.common.view.ItemDiffCallback
import com.teampophory.pophory.common.view.viewBinding
Expand Down Expand Up @@ -53,18 +52,14 @@ class StoreFragment : Fragment() {

binding.viewpagerStore.adapter = adapter

viewModel.albumList.observe(viewLifecycleOwner) { list ->
adapter?.submitList(list)
}

//1차 스프린트용 입력 방지
binding.viewpagerStore.isUserInputEnabled = false
}

private fun observeAlbumList() {
viewModel.albumList.observe(viewLifecycleOwner, Observer { list ->
viewModel.albumList.observe(viewLifecycleOwner) { list ->
adapter?.submitList(list)
})
}
}

private fun setSpannableString() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.teampophory.pophory.network

import com.teampophory.pophory.network.model.MyPageResponse

interface MyPageInfoNetworkDataSource {
suspend fun getMyPageInfo(): MyPageResponse
}
Loading

0 comments on commit 8d3f365

Please sign in to comment.