Skip to content

Commit

Permalink
[FEAT] 더 불러오기 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
kim0hoon committed Aug 20, 2023
1 parent 535de08 commit 02adbd0
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.polzzak_android.presentation.common.item

import android.view.animation.Animation
import android.view.animation.LinearInterpolator
import android.view.animation.RotateAnimation
import androidx.constraintlayout.widget.ConstraintLayout
import com.polzzak_android.R
import com.polzzak_android.databinding.ItemLoadMoreLoadingBinding
import com.polzzak_android.presentation.common.util.BindableItem
import com.polzzak_android.presentation.common.util.toPx

class LoadMoreLoadingSpinnerItem(
private val marginTopDp: Int = DEFAULT_VERTICAL_MARGIN_DP,
private val marginBottomDp: Int = DEFAULT_VERTICAL_MARGIN_DP
) :
BindableItem<ItemLoadMoreLoadingBinding>() {
override val layoutRes: Int = R.layout.item_load_more_loading

override fun areItemsTheSame(other: BindableItem<*>): Boolean =
other is LoadMoreLoadingSpinnerItem

override fun areContentsTheSame(other: BindableItem<*>): Boolean =
other is LoadMoreLoadingSpinnerItem && this.marginTopDp == other.marginTopDp &&
this.marginBottomDp == other.marginBottomDp

override fun bind(binding: ItemLoadMoreLoadingBinding, position: Int) {
val context = binding.root.context
(binding.ivSpinner.layoutParams as? ConstraintLayout.LayoutParams)?.let { lp ->
binding.ivSpinner.layoutParams = lp.apply {
topMargin = marginTopDp.toPx(context)
bottomMargin = marginBottomDp.toPx(context)
}
}
val rotateAnimation = RotateAnimation(
0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
).apply {
duration = 1000
interpolator = LinearInterpolator()
repeatCount = Animation.INFINITE
}
binding.ivSpinner.startAnimation(rotateAnimation)

}

companion object {
private const val DEFAULT_VERTICAL_MARGIN_DP = 24
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import android.view.View
import androidx.annotation.Px
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
import com.polzzak_android.presentation.common.util.BindableItemAdapter
import com.polzzak_android.presentation.feature.notification.item.NotificationItem
import com.polzzak_android.presentation.feature.notification.item.NotificationSkeletonLoadingItem

class NotificationItemDecoration(
@Px private val paddingPx: Int,
@Px private val betweenMarginPx: Int,
private val offset: Int = 0
) : ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
Expand All @@ -18,11 +20,20 @@ class NotificationItemDecoration(
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
val adapter = (parent.adapter as? BindableItemAdapter) ?: return
val position = parent.getChildAdapterPosition(view)
if (position < offset) return
outRect.top = if (position == offset) paddingPx else 0
val currentItem = adapter.currentList.getOrNull(position)
if (!isContentItem(currentItem)) return
val prevItem = adapter.currentList.getOrNull(position - 1)
val nextItem = adapter.currentList.getOrNull(position + 1)
outRect.top =
if (isContentItem(prevItem)) 0 else paddingPx
outRect.left = paddingPx
outRect.right = paddingPx
outRect.bottom = if (position == parent.childCount - 1) paddingPx else betweenMarginPx
outRect.bottom =
if (isContentItem(nextItem)) betweenMarginPx else paddingPx
}

private fun isContentItem(item: Any?): Boolean =
item is NotificationItem || item is NotificationSkeletonLoadingItem
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class NotificationViewModel @Inject constructor() : ViewModel() {

//TODO test용 delay를 위해 suspend 붙여줌(제거 필요)
private suspend fun requestNotifications() {
val prevData = notificationLiveData.value?.data ?: NotificationsModel()
val prevData =
notificationLiveData.value?.data.takeIf { !isRefreshed } ?: NotificationsModel()
//TODO api 연동(현재 mock data)
//onSuccess
delay(2000)
Expand Down Expand Up @@ -106,7 +107,7 @@ class NotificationViewModel @Inject constructor() : ViewModel() {

private fun getMockData(nextOffset: Int, pageSize: Int): NotificationsModel {
return NotificationsModel(
hasNextPage = nextOffset + pageSize >= mockNotification.size,
hasNextPage = nextOffset + pageSize < mockNotification.size,
nextOffset = nextOffset + pageSize,
items = mockNotification.subList(
nextOffset,
Expand All @@ -118,23 +119,27 @@ private fun getMockData(nextOffset: Int, pageSize: Int): NotificationsModel {
private val mockNotification = List(187) {
when (it % 4) {
0 -> NotificationModel.CompleteLink(
id = it,
date = "${it}일 전",
content = SpannableString("연동 완료"),
nickName = "닉네임${it}",
profileImageUrl = "https://picsum.photos/id/${it + 1}/200/300"
)

1 -> NotificationModel.LevelDown(
id = it,
date = "${it}일 전",
content = SpannableString("레벨 감소"),
)

2 -> NotificationModel.LevelUp(
id = it,
date = "${it}일 전",
content = SpannableString("레벨 업")
)

else -> NotificationModel.RequestLink(
id = it,
date = "${it}일 전",
content = SpannableString("연동 요청"),
nickName = "닉네임${it}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.polzzak_android.R
import com.polzzak_android.databinding.FragmentNotificationBinding
import com.polzzak_android.presentation.common.base.BaseFragment
import com.polzzak_android.presentation.common.item.LoadMoreLoadingSpinnerItem
import com.polzzak_android.presentation.common.model.ModelState
import com.polzzak_android.presentation.common.util.BindableItem
import com.polzzak_android.presentation.common.util.BindableItemAdapter
Expand Down Expand Up @@ -53,8 +54,7 @@ abstract class BaseNotificationFragment : BaseFragment<FragmentNotificationBindi
val betweenMarginPx = NOTIFICATIONS_BETWEEN_MARGIN_DP.toPx(context)
val itemDecoration = NotificationItemDecoration(
paddingPx = paddingPx,
betweenMarginPx = betweenMarginPx,
offset = 1
betweenMarginPx = betweenMarginPx
)
addItemDecoration(itemDecoration)
adapter = BindableItemAdapter()
Expand Down Expand Up @@ -116,21 +116,18 @@ abstract class BaseNotificationFragment : BaseFragment<FragmentNotificationBindi
is ModelState.Loading -> {
if (it.data?.items == null) {
items.addAll(createSkeletonLoadingItems())
} else if (it.data?.items?.isEmpty() == true) {
items.add(NotificationEmptyItem())
} else items.addAll(
createNotificationItems(
data = it.data?.items ?: emptyList()
} else {
items.addAll(createNotificationItems(data = it.data?.items))
if (!notificationViewModel.isRefreshed) items.add(
LoadMoreLoadingSpinnerItem(
marginTopDp = 8
)
)
)
}
}

is ModelState.Success -> {
if (it.data.items.isNullOrEmpty()) {
items.add(NotificationEmptyItem())
} else {
items.addAll(createNotificationItems(data = it.data.items))
}
items.addAll(createNotificationItems(data = it.data.items))
if (notificationViewModel.isRefreshed) {
updateCallback = {
layoutManager.scrollToPositionWithOffset(1, 0)
Expand All @@ -151,8 +148,12 @@ abstract class BaseNotificationFragment : BaseFragment<FragmentNotificationBindi
NotificationSkeletonLoadingItem()
}

private fun createNotificationItems(data: List<NotificationModel>): List<NotificationItem> {
return data.map { NotificationItem(model = it) }
private fun createNotificationItems(data: List<NotificationModel>?): List<BindableItem<*>> {
return if (data.isNullOrEmpty()) listOf(NotificationEmptyItem()) else data.map {
NotificationItem(
model = it
)
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import com.polzzak_android.presentation.feature.notification.model.NotificationM
class NotificationItem(private val model: NotificationModel) :
BindableItem<ItemNotificationBinding>() {
override val layoutRes: Int = R.layout.item_notification
override fun areItemsTheSame(other: BindableItem<*>): Boolean = other is NotificationItem
override fun areItemsTheSame(other: BindableItem<*>): Boolean =
other is NotificationItem && this.model.id == other.model.id

override fun areContentsTheSame(other: BindableItem<*>): Boolean =
other is NotificationItem && this.model == other.model
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.polzzak_android.R

//TODO api response 확인 후 알림타입추가
sealed interface NotificationModel {
val id: Int

@get:StringRes
val emojiStringRes: Int

Expand All @@ -22,6 +24,7 @@ sealed interface NotificationModel {
)

class RequestLink(
override val id: Int,
override val date: String,
override val content: Spannable,
nickName: String,
Expand All @@ -35,6 +38,7 @@ sealed interface NotificationModel {
}

class CompleteLink(
override val id: Int,
override val date: String,
override val content: Spannable,
nickName: String,
Expand All @@ -48,6 +52,7 @@ sealed interface NotificationModel {
}

class LevelUp(
override val id: Int,
override val date: String,
override val content: Spannable
) : NotificationModel {
Expand All @@ -58,6 +63,7 @@ sealed interface NotificationModel {
}

class LevelDown(
override val id: Int,
override val date: String,
override val content: Spannable
) : NotificationModel {
Expand Down
19 changes: 19 additions & 0 deletions app/src/main/res/layout/item_load_more_loading.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/ivSpinner"
android:layout_width="36dp"
android:layout_height="36dp"
android:src="@drawable/ic_refresh_loading_spinner"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

0 comments on commit 02adbd0

Please sign in to comment.