-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
371 additions
and
12 deletions.
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
.../java/com/polzzak_android/presentation/feature/notification/NotificationItemDecoration.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.polzzak_android.presentation.feature.notification | ||
|
||
import android.graphics.Rect | ||
import android.view.View | ||
import androidx.annotation.Px | ||
import androidx.recyclerview.widget.RecyclerView | ||
import androidx.recyclerview.widget.RecyclerView.ItemDecoration | ||
|
||
class NotificationItemDecoration( | ||
@Px private val paddingPx: Int, | ||
@Px private val betweenMarginPx: Int | ||
) : ItemDecoration() { | ||
override fun getItemOffsets( | ||
outRect: Rect, | ||
view: View, | ||
parent: RecyclerView, | ||
state: RecyclerView.State | ||
) { | ||
super.getItemOffsets(outRect, view, parent, state) | ||
val position = parent.getChildAdapterPosition(view) | ||
outRect.top = if (position == 0) paddingPx else 0 | ||
outRect.left = paddingPx | ||
outRect.right = paddingPx | ||
outRect.bottom = if (position == parent.childCount - 1) paddingPx else betweenMarginPx | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
.../main/java/com/polzzak_android/presentation/feature/notification/NotificationViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package com.polzzak_android.presentation.feature.notification | ||
|
||
import android.text.SpannableString | ||
import androidx.lifecycle.LiveData | ||
import androidx.lifecycle.MutableLiveData | ||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.viewModelScope | ||
import com.polzzak_android.presentation.common.model.ModelState | ||
import com.polzzak_android.presentation.feature.notification.model.NotificationModel | ||
import com.polzzak_android.presentation.feature.notification.model.NotificationsModel | ||
import dagger.hilt.android.lifecycle.HiltViewModel | ||
import kotlinx.coroutines.Job | ||
import kotlinx.coroutines.delay | ||
import kotlinx.coroutines.launch | ||
import javax.inject.Inject | ||
|
||
@HiltViewModel | ||
class NotificationViewModel @Inject constructor() : ViewModel() { | ||
private val _notificationLiveData = MutableLiveData<ModelState<NotificationsModel>>() | ||
val notificationLiveData: LiveData<ModelState<NotificationsModel>> = _notificationLiveData | ||
private var requestNotificationJob: Job? = null | ||
|
||
init { | ||
requestNotifications(hasPriority = true) | ||
} | ||
|
||
fun requestMoreNotifications() { | ||
requestNotifications(hasPriority = false) | ||
} | ||
|
||
private fun requestNotifications(hasPriority: Boolean) { | ||
if (hasPriority) requestNotificationJob?.cancel() | ||
else if (requestNotificationJob?.isCompleted == false) return | ||
requestNotificationJob = viewModelScope.launch { | ||
val prevData = notificationLiveData.value?.data ?: NotificationsModel() | ||
_notificationLiveData.value = ModelState.Loading(prevData) | ||
//TODO api 호출 | ||
delay(2000) | ||
val nextData = getMockData(prevData.nextOffset, NOTIFICATION_PAGE_SIZE) | ||
_notificationLiveData.value = | ||
ModelState.Success(nextData.copy(items = prevData.items + nextData.items)) | ||
} | ||
|
||
} | ||
|
||
companion object { | ||
const val NOTIFICATION_PAGE_SIZE = 10 | ||
} | ||
} | ||
|
||
private fun getMockData(nextOffset: Int, pageSize: Int): NotificationsModel { | ||
return NotificationsModel( | ||
hasNextPage = nextOffset + pageSize >= mockNotification.size, | ||
nextOffset = nextOffset + pageSize, | ||
items = mockNotification.subList( | ||
nextOffset, | ||
minOf(mockNotification.size, nextOffset + pageSize) | ||
) | ||
) | ||
} | ||
|
||
private val mockNotification = List(187) { | ||
when (it % 4) { | ||
0 -> NotificationModel.CompleteLink( | ||
date = "${it}일 전", | ||
content = SpannableString("연동 완료"), | ||
nickName = "닉네임${it}", | ||
profileImageUrl = "https://picsum.photos/id/${it + 1}/200/300" | ||
) | ||
|
||
1 -> NotificationModel.LevelDown( | ||
date = "${it}일 전", | ||
content = SpannableString("레벨 감소"), | ||
) | ||
|
||
2 -> NotificationModel.LevelUp( | ||
date = "${it}일 전", | ||
content = SpannableString("레벨 업") | ||
) | ||
|
||
else -> NotificationModel.RequestLink( | ||
date = "${it}일 전", | ||
content = SpannableString("연동 요청"), | ||
nickName = "닉네임${it}", | ||
profileImageUrl = "https://picsum.photos/id/${it + 1}/200/300" | ||
) | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
...va/com/polzzak_android/presentation/feature/notification/base/BaseNotificationFragment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,90 @@ | ||
package com.polzzak_android.presentation.feature.notification.base | ||
|
||
import androidx.fragment.app.viewModels | ||
import androidx.recyclerview.widget.LinearLayoutManager | ||
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.model.ModelState | ||
import com.polzzak_android.presentation.common.util.BindableItem | ||
import com.polzzak_android.presentation.common.util.BindableItemAdapter | ||
import com.polzzak_android.presentation.common.util.toPx | ||
import com.polzzak_android.presentation.feature.notification.NotificationItemDecoration | ||
import com.polzzak_android.presentation.feature.notification.NotificationViewModel | ||
import com.polzzak_android.presentation.feature.notification.item.NotificationItem | ||
import com.polzzak_android.presentation.feature.notification.item.NotificationSkeletonLoadingItem | ||
import com.polzzak_android.presentation.feature.notification.model.NotificationModel | ||
|
||
abstract class BaseNotificationFragment : BaseFragment<FragmentNotificationBinding>() { | ||
override val layoutResId: Int = R.layout.fragment_notification | ||
private val notificationViewModel by viewModels<NotificationViewModel>() | ||
|
||
override fun initView() { | ||
super.initView() | ||
initRecyclerView() | ||
//TODO refresh | ||
binding.ivBtnSetting.setOnClickListener { | ||
//TODO move to setting page | ||
} | ||
} | ||
|
||
private fun initRecyclerView() { | ||
with(binding.rvNotifications) { | ||
layoutManager = LinearLayoutManager(context) | ||
val paddingPx = NOTIFICATIONS_PADDING_DP.toPx(context) | ||
val betweenMarginPx = NOTIFICATIONS_BETWEEN_MARGIN_DP.toPx(context) | ||
val itemDecoration = NotificationItemDecoration( | ||
paddingPx = paddingPx, | ||
betweenMarginPx = betweenMarginPx | ||
) | ||
addItemDecoration(itemDecoration) | ||
adapter = BindableItemAdapter() | ||
addOnScrollListener(object : RecyclerView.OnScrollListener() { | ||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { | ||
super.onScrolled(recyclerView, dx, dy) | ||
//TODO 무한스크롤 | ||
} | ||
}) | ||
} | ||
} | ||
|
||
override fun initObserver() { | ||
super.initObserver() | ||
notificationViewModel.notificationLiveData.observe(viewLifecycleOwner) { | ||
val items = mutableListOf<BindableItem<*>>() | ||
val adapter = | ||
(binding.rvNotifications.adapter as? BindableItemAdapter) ?: return@observe | ||
when (it) { | ||
is ModelState.Loading -> { | ||
if (it.data?.items.isNullOrEmpty()) items.addAll(createSkeletonLoadingItems()) | ||
else items.addAll(createNotificationItems(data = it.data?.items ?: emptyList())) | ||
} | ||
|
||
is ModelState.Success -> { | ||
//TODO 비어있는경우 대응 | ||
items.addAll(createNotificationItems(data = it.data.items)) | ||
} | ||
|
||
is ModelState.Error -> { | ||
|
||
} | ||
} | ||
adapter.updateItem(item = items) | ||
} | ||
} | ||
|
||
private fun createSkeletonLoadingItems() = List(LOADING_SKELETON_ITEM_COUNT) { | ||
NotificationSkeletonLoadingItem() | ||
} | ||
|
||
private fun createNotificationItems(data: List<NotificationModel>): List<NotificationItem> { | ||
return data.map { NotificationItem(model = it) } | ||
} | ||
|
||
companion object { | ||
private const val LOADING_SKELETON_ITEM_COUNT = 5 | ||
private const val NOTIFICATIONS_PADDING_DP = 16 | ||
private const val NOTIFICATIONS_BETWEEN_MARGIN_DP = 8 | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
.../main/java/com/polzzak_android/presentation/feature/notification/item/NotificationItem.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.polzzak_android.presentation.feature.notification.item | ||
|
||
import androidx.core.view.isVisible | ||
import com.polzzak_android.R | ||
import com.polzzak_android.databinding.ItemNotificationBinding | ||
import com.polzzak_android.presentation.common.util.BindableItem | ||
import com.polzzak_android.presentation.common.util.loadCircleImageUrl | ||
import com.polzzak_android.presentation.feature.notification.model.NotificationModel | ||
|
||
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 areContentsTheSame(other: BindableItem<*>): Boolean = | ||
other is NotificationItem && this.model == other.model | ||
|
||
override fun bind(binding: ItemNotificationBinding, position: Int) { | ||
with(binding) { | ||
val context = root.context | ||
tvEmoji.text = context.getString(model.emojiStringRes) | ||
tvTitle.text = context.getString(model.titleStringRes) | ||
tvDate.text = model.date | ||
tvContent.text = model.content | ||
bindBtnLayout(binding = binding) | ||
bindProfile(binding = binding) | ||
} | ||
} | ||
|
||
private fun bindBtnLayout(binding: ItemNotificationBinding) { | ||
with(binding) { | ||
clBtnLayout.isVisible = model.isButtonVisible | ||
tvBtnAccept.setOnClickListener { | ||
//TODO 수락 버튼 클릭 | ||
} | ||
tvBtnReject.setOnClickListener { | ||
//TODO 거절 버튼 클릭 | ||
} | ||
} | ||
|
||
} | ||
|
||
private fun bindProfile(binding: ItemNotificationBinding) { | ||
with(binding) { | ||
clProfile.isVisible = (model.userInfo != null) | ||
ivProfileImage.loadCircleImageUrl(imageUrl = model.userInfo?.profileImageUrl) | ||
tvNickName.text = model.userInfo?.nickName | ||
} | ||
} | ||
|
||
} |
18 changes: 18 additions & 0 deletions
18
...polzzak_android/presentation/feature/notification/item/NotificationSkeletonLoadingItem.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.polzzak_android.presentation.feature.notification.item | ||
|
||
import com.polzzak_android.R | ||
import com.polzzak_android.databinding.ItemNotificationLoadingSkeletonBinding | ||
import com.polzzak_android.presentation.common.util.BindableItem | ||
|
||
class NotificationSkeletonLoadingItem : BindableItem<ItemNotificationLoadingSkeletonBinding>() { | ||
override val layoutRes: Int = R.layout.item_notification_loading_skeleton | ||
override fun areItemsTheSame(other: BindableItem<*>): Boolean = | ||
other is NotificationSkeletonLoadingItem | ||
|
||
override fun areContentsTheSame(other: BindableItem<*>): Boolean = | ||
other is NotificationSkeletonLoadingItem | ||
|
||
override fun bind(binding: ItemNotificationLoadingSkeletonBinding, position: Int) { | ||
//do nothing | ||
} | ||
} |
7 changes: 2 additions & 5 deletions
7
...java/com/polzzak_android/presentation/feature/notification/kid/KidNotificationFragment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,7 @@ | ||
package com.polzzak_android.presentation.feature.notification.kid | ||
|
||
import com.polzzak_android.R | ||
import com.polzzak_android.presentation.common.base.BaseFragment | ||
import com.polzzak_android.databinding.FragmentKidNotificationBinding | ||
import com.polzzak_android.presentation.feature.notification.base.BaseNotificationFragment | ||
|
||
class KidNotificationFragment : BaseFragment<FragmentKidNotificationBinding>() { | ||
override val layoutResId: Int = R.layout.fragment_kid_notification | ||
class KidNotificationFragment:BaseNotificationFragment(){ | ||
|
||
} |
69 changes: 69 additions & 0 deletions
69
...ain/java/com/polzzak_android/presentation/feature/notification/model/NotificationModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package com.polzzak_android.presentation.feature.notification.model | ||
|
||
import android.text.Spannable | ||
import androidx.annotation.StringRes | ||
import com.polzzak_android.R | ||
|
||
//TODO api response 확인 후 알림타입추가 | ||
sealed interface NotificationModel { | ||
@get:StringRes | ||
val emojiStringRes: Int | ||
|
||
@get:StringRes | ||
val titleStringRes: Int | ||
val date: String | ||
val content: Spannable | ||
val isButtonVisible: Boolean | ||
val userInfo: NotificationUserModel? | ||
|
||
data class NotificationUserModel( | ||
val profileImageUrl: String, | ||
val nickName: String | ||
) | ||
|
||
class RequestLink( | ||
override val date: String, | ||
override val content: Spannable, | ||
nickName: String, | ||
profileImageUrl: String, | ||
) : NotificationModel { | ||
override val emojiStringRes: Int = R.string.notification_request_link_emoji | ||
override val titleStringRes: Int = R.string.notification_request_link_title | ||
override val isButtonVisible = true | ||
override val userInfo = | ||
NotificationUserModel(profileImageUrl = profileImageUrl, nickName = nickName) | ||
} | ||
|
||
class CompleteLink( | ||
override val date: String, | ||
override val content: Spannable, | ||
nickName: String, | ||
profileImageUrl: String, | ||
) : NotificationModel { | ||
override val emojiStringRes: Int = R.string.notification_complete_link_emoji | ||
override val titleStringRes: Int = R.string.notification_complete_link_title | ||
override val isButtonVisible = false | ||
override val userInfo = | ||
NotificationUserModel(profileImageUrl = profileImageUrl, nickName = nickName) | ||
} | ||
|
||
class LevelUp( | ||
override val date: String, | ||
override val content: Spannable | ||
) : NotificationModel { | ||
override val emojiStringRes: Int = R.string.notification_level_up_emoji | ||
override val titleStringRes: Int = R.string.notification_level_up_title | ||
override val isButtonVisible = false | ||
override val userInfo = null | ||
} | ||
|
||
class LevelDown( | ||
override val date: String, | ||
override val content: Spannable | ||
) : NotificationModel { | ||
override val emojiStringRes: Int = R.string.notification_level_down_emoji | ||
override val titleStringRes: Int = R.string.notification_level_down_title | ||
override val isButtonVisible = false | ||
override val userInfo = null | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
...in/java/com/polzzak_android/presentation/feature/notification/model/NotificationsModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.polzzak_android.presentation.feature.notification.model | ||
|
||
//TODO API 모델 확인 후 수정 필요 | ||
data class NotificationsModel( | ||
val hasNextPage: Boolean = true, | ||
val nextOffset: Int = 0, | ||
val items: List<NotificationModel> = emptyList() | ||
) |
8 changes: 3 additions & 5 deletions
8
...zzak_android/presentation/feature/notification/protector/ProtectorNotificationFragment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,7 @@ | ||
package com.polzzak_android.presentation.feature.notification.protector | ||
|
||
import com.polzzak_android.R | ||
import com.polzzak_android.presentation.common.base.BaseFragment | ||
import com.polzzak_android.databinding.FragmentProtectorNotificationBinding | ||
import com.polzzak_android.presentation.feature.notification.base.BaseNotificationFragment | ||
|
||
class ProtectorNotificationFragment : BaseNotificationFragment() { | ||
|
||
class ProtectorNotificationFragment : BaseFragment<FragmentProtectorNotificationBinding>() { | ||
override val layoutResId: Int = R.layout.fragment_protector_notification | ||
} |
Oops, something went wrong.