-
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
15 changed files
with
406 additions
and
6 deletions.
There are no files selected for viewing
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
91 changes: 91 additions & 0 deletions
91
app/src/main/java/com/polzzak_android/presentation/feature/myPage/notice/MyNoticeFragment.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,91 @@ | ||
package com.polzzak_android.presentation.feature.myPage.notice | ||
|
||
import androidx.fragment.app.viewModels | ||
import androidx.navigation.fragment.findNavController | ||
import androidx.recyclerview.widget.LinearLayoutManager | ||
import androidx.recyclerview.widget.RecyclerView | ||
import com.polzzak_android.R | ||
import com.polzzak_android.databinding.FragmentMyNoticeBinding | ||
import com.polzzak_android.presentation.common.base.BaseFragment | ||
import com.polzzak_android.presentation.common.item.FullLoadingItem | ||
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 | ||
import com.polzzak_android.presentation.common.util.toPx | ||
import com.polzzak_android.presentation.component.toolbar.ToolbarData | ||
import com.polzzak_android.presentation.component.toolbar.ToolbarHelper | ||
import com.polzzak_android.presentation.feature.myPage.notice.item.MyNoticeEmptyItem | ||
import com.polzzak_android.presentation.feature.myPage.notice.item.MyNoticeItem | ||
import com.polzzak_android.presentation.feature.myPage.notice.model.MyNoticesModel | ||
|
||
//TODO 바텀네비 invisible | ||
class MyNoticeFragment : BaseFragment<FragmentMyNoticeBinding>() { | ||
override val layoutResId: Int = R.layout.fragment_my_notice | ||
|
||
private val noticeViewModel by viewModels<MyNoticeViewModel>() | ||
|
||
override fun initView() { | ||
super.initView() | ||
initToolbar() | ||
initRecyclerView() | ||
} | ||
|
||
private fun initToolbar() { | ||
with(binding) { | ||
ToolbarHelper( | ||
data = ToolbarData( | ||
popStack = findNavController(), | ||
titleText = getString(R.string.common_notice) | ||
), | ||
toolbar = inToolbar | ||
).set() | ||
} | ||
} | ||
|
||
private fun initRecyclerView() { | ||
val context = binding.root.context ?: return | ||
with(binding.rvNotices) { | ||
layoutManager = LinearLayoutManager(context) | ||
adapter = BindableItemAdapter() | ||
val marginPx = ITEM_MARGIN_DP.toPx(context) | ||
addItemDecoration(MyNoticeItemDecoration(marginPx = marginPx)) | ||
addOnScrollListener(object : RecyclerView.OnScrollListener() { | ||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { | ||
super.onScrolled(recyclerView, dx, dy) | ||
if (!recyclerView.canScrollVertically(1) && noticeViewModel.noticesLiveData.value is ModelState.Success) noticeViewModel.requestMoreNotices() | ||
} | ||
}) | ||
} | ||
} | ||
|
||
override fun initObserver() { | ||
super.initObserver() | ||
noticeViewModel.noticesLiveData.observe(viewLifecycleOwner) { | ||
val adapter = (binding.rvNotices.adapter as? BindableItemAdapter) ?: return@observe | ||
val noticeItem = createNoticeItem(it.data ?: MyNoticesModel()) | ||
val items = mutableListOf<BindableItem<*>>() | ||
when (it) { | ||
is ModelState.Loading -> { | ||
if (it.data?.notices.isNullOrEmpty()) items.add(FullLoadingItem()) | ||
else items.addAll(noticeItem + LoadMoreLoadingSpinnerItem()) | ||
} | ||
|
||
is ModelState.Success -> items.addAll(noticeItem) | ||
is ModelState.Error -> { | ||
//TODO error handling | ||
} | ||
} | ||
adapter.updateItem(item = items) | ||
} | ||
} | ||
|
||
private fun createNoticeItem(model: MyNoticesModel) = model.notices.map { | ||
MyNoticeItem(model = it) | ||
}.ifEmpty { listOf(MyNoticeEmptyItem()) } | ||
|
||
companion object { | ||
private const val ITEM_MARGIN_DP = 16 | ||
} | ||
|
||
} |
25 changes: 25 additions & 0 deletions
25
...ain/java/com/polzzak_android/presentation/feature/myPage/notice/MyNoticeItemDecoration.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,25 @@ | ||
package com.polzzak_android.presentation.feature.myPage.notice | ||
|
||
import android.graphics.Rect | ||
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.myPage.notice.item.MyNoticeItem | ||
|
||
class MyNoticeItemDecoration(@Px private val marginPx: 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) | ||
val adapter = (parent.adapter as? BindableItemAdapter) ?: return | ||
if (adapter.currentList.getOrNull(position) !is MyNoticeItem) return | ||
outRect.top = marginPx | ||
outRect.bottom = if (position == adapter.currentList.lastIndex) marginPx else 0 | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
...src/main/java/com/polzzak_android/presentation/feature/myPage/notice/MyNoticeViewModel.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,78 @@ | ||
package com.polzzak_android.presentation.feature.myPage.notice | ||
|
||
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.common.util.toLocalDate | ||
import com.polzzak_android.presentation.feature.myPage.notice.model.MyNoticeModel | ||
import com.polzzak_android.presentation.feature.myPage.notice.model.MyNoticesModel | ||
import kotlinx.coroutines.Job | ||
import kotlinx.coroutines.delay | ||
import kotlinx.coroutines.launch | ||
import java.time.LocalDate | ||
|
||
//TODO api 연동 | ||
class MyNoticeViewModel : ViewModel() { | ||
private val _noticesLiveData = MutableLiveData<ModelState<MyNoticesModel>>() | ||
val noticesLiveData: LiveData<ModelState<MyNoticesModel>> = _noticesLiveData | ||
|
||
private var requestNoticesJob: Job? = null | ||
|
||
init { | ||
initNotices() | ||
} | ||
|
||
private fun initNotices() { | ||
requestNoticesJob?.cancel() | ||
requestNoticesJob = viewModelScope.launch { | ||
_noticesLiveData.value = ModelState.Loading(MyNoticesModel()) | ||
requestNotices() | ||
} | ||
} | ||
|
||
fun requestMoreNotices() { | ||
if (noticesLiveData.value?.data?.hasNextPage == false) return | ||
if (requestNoticesJob?.isCompleted == false) return | ||
requestNoticesJob = viewModelScope.launch { | ||
_noticesLiveData.value = | ||
ModelState.Loading(_noticesLiveData.value?.data ?: MyNoticesModel()) | ||
requestNotices() | ||
} | ||
} | ||
|
||
private suspend fun requestNotices() { | ||
val prevData = noticesLiveData.value?.data ?: MyNoticesModel() | ||
delay(2000) | ||
//TODO api 연동 | ||
//on Success | ||
val nextData = getMockNotices(nextId = prevData.nextId, pageSize = PAGE_SIZE) | ||
val updatedData = nextData.copy(notices = prevData.notices + nextData.notices) | ||
_noticesLiveData.value = ModelState.Success(updatedData) | ||
} | ||
|
||
companion object { | ||
private const val PAGE_SIZE = 10 | ||
} | ||
} | ||
|
||
private fun getMockNotices(nextId: Int?, pageSize: Int): MyNoticesModel { | ||
val startIdx = nextId ?: 0 | ||
val nextIdx = minOf(mockNotices.size, startIdx + pageSize) | ||
val nId = mockNotices.getOrNull(nextIdx)?.id | ||
return MyNoticesModel( | ||
notices = mockNotices.subList(startIdx, nextIdx), | ||
nextId = nId, | ||
hasNextPage = (nId != null) | ||
) | ||
} | ||
|
||
private val mockNotices = List(27) { | ||
MyNoticeModel( | ||
id = it, | ||
title = "title$it".repeat((it % 12) + 1), | ||
date = "2023-06-04T20:08:23.745393551".toLocalDate() ?: (LocalDate.now()), | ||
content = "content \n\n\n content1 \n\n content \n" | ||
) | ||
} |
17 changes: 17 additions & 0 deletions
17
...ain/java/com/polzzak_android/presentation/feature/myPage/notice/item/MyNoticeEmptyItem.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,17 @@ | ||
package com.polzzak_android.presentation.feature.myPage.notice.item | ||
|
||
import com.polzzak_android.R | ||
import com.polzzak_android.databinding.ItemMyNoticieEmptyBinding | ||
import com.polzzak_android.presentation.common.util.BindableItem | ||
|
||
class MyNoticeEmptyItem : BindableItem<ItemMyNoticieEmptyBinding>() { | ||
override val layoutRes: Int = R.layout.item_my_noticie_empty | ||
override fun areItemsTheSame(other: BindableItem<*>): Boolean = other is MyNoticeEmptyItem | ||
|
||
override fun areContentsTheSame(other: BindableItem<*>): Boolean = other is MyNoticeEmptyItem | ||
|
||
override fun bind(binding: ItemMyNoticieEmptyBinding, position: Int) { | ||
//do nothing | ||
} | ||
|
||
} |
24 changes: 24 additions & 0 deletions
24
...src/main/java/com/polzzak_android/presentation/feature/myPage/notice/item/MyNoticeItem.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,24 @@ | ||
package com.polzzak_android.presentation.feature.myPage.notice.item | ||
|
||
import com.polzzak_android.R | ||
import com.polzzak_android.databinding.ItemMyNoticeBinding | ||
import com.polzzak_android.presentation.common.util.BindableItem | ||
import com.polzzak_android.presentation.common.util.toDateString | ||
import com.polzzak_android.presentation.feature.myPage.notice.model.MyNoticeModel | ||
|
||
class MyNoticeItem(private val model: MyNoticeModel) : BindableItem<ItemMyNoticeBinding>() { | ||
override val layoutRes: Int = R.layout.item_my_notice | ||
override fun areItemsTheSame(other: BindableItem<*>): Boolean = | ||
other is MyNoticeItem && this.model.id == other.model.id | ||
|
||
override fun areContentsTheSame(other: BindableItem<*>): Boolean = | ||
other is MyNoticeItem && this.model == other.model | ||
|
||
override fun bind(binding: ItemMyNoticeBinding, position: Int) { | ||
with(binding) { | ||
tvTitle.text = model.title | ||
tvDate.text = model.date.toDateString() | ||
tvContent.text = model.content.replace(Regex("(\\r\\n|\\r|\\n)+"), " ") | ||
} | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
...c/main/java/com/polzzak_android/presentation/feature/myPage/notice/model/MyNoticeModel.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,10 @@ | ||
package com.polzzak_android.presentation.feature.myPage.notice.model | ||
|
||
import java.time.LocalDate | ||
|
||
data class MyNoticeModel( | ||
val id: Int, | ||
val title: String, | ||
val date: LocalDate, | ||
val content: String | ||
) |
7 changes: 7 additions & 0 deletions
7
.../main/java/com/polzzak_android/presentation/feature/myPage/notice/model/MyNoticesModel.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,7 @@ | ||
package com.polzzak_android.presentation.feature.myPage.notice.model | ||
|
||
data class MyNoticesModel( | ||
val notices: List<MyNoticeModel> = emptyList(), | ||
val nextId: Int? = null, | ||
val hasNextPage: Boolean = true | ||
) |
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
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,30 @@ | ||
<?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" | ||
xmlns:tools="http://schemas.android.com/tools"> | ||
|
||
<androidx.constraintlayout.widget.ConstraintLayout | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent"> | ||
|
||
<include | ||
android:id="@+id/inToolbar" | ||
layout="@layout/layout_toolbar" | ||
app:layout_constraintEnd_toEndOf="parent" | ||
app:layout_constraintStart_toStartOf="parent" | ||
app:layout_constraintTop_toTopOf="parent" /> | ||
|
||
<androidx.recyclerview.widget.RecyclerView | ||
android:id="@+id/rvNotices" | ||
android:layout_width="0dp" | ||
android:layout_height="0dp" | ||
android:background="@color/gray_200" | ||
android:paddingHorizontal="16dp" | ||
app:layout_constraintBottom_toBottomOf="parent" | ||
app:layout_constraintEnd_toEndOf="parent" | ||
app:layout_constraintStart_toStartOf="parent" | ||
app:layout_constraintTop_toBottomOf="@id/inToolbar" | ||
tools:itemCount="5" | ||
tools:listitem="@layout/item_my_notice" /> | ||
</androidx.constraintlayout.widget.ConstraintLayout> | ||
</layout> |
Oops, something went wrong.