This commit is contained in:
@@ -13,10 +13,12 @@ import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
@@ -62,6 +64,23 @@ private fun toGroupedList(notifications: List<AppNotification>): List<NotifListI
|
||||
return result
|
||||
}
|
||||
|
||||
private class NotifDiff(
|
||||
private val old: List<NotifListItem>,
|
||||
private val new: List<NotifListItem>
|
||||
) : DiffUtil.Callback() {
|
||||
override fun getOldListSize() = old.size
|
||||
override fun getNewListSize() = new.size
|
||||
override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean {
|
||||
val o = old[oldPos]; val n = new[newPos]
|
||||
return when {
|
||||
o is NotifListItem.Header && n is NotifListItem.Header -> o.label == n.label
|
||||
o is NotifListItem.Entry && n is NotifListItem.Entry -> o.n.id == n.n.id
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
override fun areContentsTheSame(oldPos: Int, newPos: Int) = old[oldPos] == new[newPos]
|
||||
}
|
||||
|
||||
class NotificationsSheetFragment : BottomSheetDialogFragment() {
|
||||
|
||||
var onUnreadCountChanged: ((hasUnread: Boolean) -> Unit)? = null
|
||||
@@ -148,11 +167,16 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setSpinner(show: Boolean) {
|
||||
tabAdapters.forEach { it?.showLoadingSpinner = show }
|
||||
}
|
||||
|
||||
private fun refreshFromNetwork() {
|
||||
val bmlSessions = app.bmlSessions.toMap()
|
||||
val mibSessions = app.mibSessions.toMap()
|
||||
|
||||
lifecycleScope.launch {
|
||||
setSpinner(true)
|
||||
val bmlClient = BmlNotificationsClient()
|
||||
bmlSessions.forEach { (loginId, session) ->
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
@@ -196,6 +220,8 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() {
|
||||
mibDone[loginId] = hasOverlap || result.nextStart > result.totalCount
|
||||
}
|
||||
}
|
||||
|
||||
if (isAdded) setSpinner(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +234,7 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() {
|
||||
if (!anyLeft) return
|
||||
|
||||
isLoadingMore = true
|
||||
setSpinner(true)
|
||||
lifecycleScope.launch {
|
||||
val bmlClient = BmlNotificationsClient()
|
||||
bmlSessions.forEach { (loginId, session) ->
|
||||
@@ -255,7 +282,10 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() {
|
||||
}
|
||||
|
||||
isLoadingMore = false
|
||||
if (isAdded) refreshAdapters()
|
||||
if (isAdded) {
|
||||
setSpinner(false)
|
||||
refreshAdapters()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,16 +389,35 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() {
|
||||
|
||||
private val displayItems = mutableListOf<NotifListItem>()
|
||||
|
||||
var showLoadingSpinner: Boolean = false
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
field = value
|
||||
if (displayItems.isEmpty()) {
|
||||
notifyItemChanged(0)
|
||||
} else if (value) {
|
||||
notifyItemInserted(displayItems.size)
|
||||
} else {
|
||||
notifyItemRemoved(displayItems.size)
|
||||
}
|
||||
}
|
||||
|
||||
fun update(filtered: List<AppNotification>) {
|
||||
val newItems = toGroupedList(filtered)
|
||||
val diff = DiffUtil.calculateDiff(NotifDiff(displayItems.toList(), newItems))
|
||||
displayItems.clear()
|
||||
displayItems.addAll(toGroupedList(filtered))
|
||||
notifyDataSetChanged()
|
||||
displayItems.addAll(newItems)
|
||||
diff.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
override fun getItemCount() = if (displayItems.isEmpty()) 1 else displayItems.size
|
||||
override fun getItemCount(): Int {
|
||||
if (displayItems.isEmpty()) return 1
|
||||
return displayItems.size + if (showLoadingSpinner) 1 else 0
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (displayItems.isEmpty()) return 2 // empty
|
||||
if (displayItems.isEmpty()) return if (showLoadingSpinner) 3 else 2
|
||||
if (showLoadingSpinner && position == displayItems.size) return 3
|
||||
return when (displayItems[position]) {
|
||||
is NotifListItem.Header -> 0
|
||||
is NotifListItem.Entry -> 1
|
||||
@@ -379,6 +428,7 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() {
|
||||
when (viewType) {
|
||||
0 -> HeaderVH(buildHeaderView(parent.context))
|
||||
1 -> ItemVH(buildRowView(parent.context))
|
||||
3 -> SpinnerVH(buildSpinnerView(parent.context))
|
||||
else -> EmptyVH(buildEmptyView(parent.context))
|
||||
}
|
||||
|
||||
@@ -439,6 +489,28 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Loading spinner ───────────────────────────────────────────────────────
|
||||
|
||||
inner class SpinnerVH(v: View) : RecyclerView.ViewHolder(v)
|
||||
|
||||
private fun buildSpinnerView(ctx: android.content.Context): View {
|
||||
val dp = ctx.resources.displayMetrics.density
|
||||
val pad = (16 * dp).toInt()
|
||||
val size = (28 * dp).toInt()
|
||||
return LinearLayout(ctx).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
gravity = Gravity.CENTER
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
setPadding(pad, pad, pad, pad)
|
||||
addView(ProgressBar(ctx).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(size, size)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ── Notification row ──────────────────────────────────────────────────────
|
||||
|
||||
inner class ItemVH(v: View) : RecyclerView.ViewHolder(v) {
|
||||
|
||||
Reference in New Issue
Block a user