Use ListAdapter in NotificationModeConfigAdapter.

This commit is contained in:
Isira Seneviratne 2022-08-18 20:42:29 +05:30
parent 231e677b16
commit fb1360b72a
2 changed files with 81 additions and 119 deletions

View file

@ -1,15 +1,13 @@
package org.schabi.newpipe.settings.notifications package org.schabi.newpipe.settings.notifications
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.CheckedTextView
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.schabi.newpipe.R
import org.schabi.newpipe.database.subscription.NotificationMode import org.schabi.newpipe.database.subscription.NotificationMode
import org.schabi.newpipe.database.subscription.SubscriptionEntity import org.schabi.newpipe.database.subscription.SubscriptionEntity
import org.schabi.newpipe.databinding.ItemNotificationConfigBinding
import org.schabi.newpipe.settings.notifications.NotificationModeConfigAdapter.SubscriptionHolder import org.schabi.newpipe.settings.notifications.NotificationModeConfigAdapter.SubscriptionHolder
/** /**
@ -19,85 +17,46 @@ import org.schabi.newpipe.settings.notifications.NotificationModeConfigAdapter.S
*/ */
class NotificationModeConfigAdapter( class NotificationModeConfigAdapter(
private val listener: ModeToggleListener private val listener: ModeToggleListener
) : RecyclerView.Adapter<SubscriptionHolder>() { ) : ListAdapter<SubscriptionItem, SubscriptionHolder>(DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, i: Int): SubscriptionHolder {
private val differ = AsyncListDiffer(this, DiffCallback()) return SubscriptionHolder(
ItemNotificationConfigBinding
init { .inflate(LayoutInflater.from(parent.context), parent, false)
setHasStableIds(true)
}
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): SubscriptionHolder {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.item_notification_config, viewGroup, false)
return SubscriptionHolder(view, listener)
}
override fun onBindViewHolder(subscriptionHolder: SubscriptionHolder, i: Int) {
subscriptionHolder.bind(differ.currentList[i])
}
fun getItem(position: Int): SubscriptionItem = differ.currentList[position]
override fun getItemCount() = differ.currentList.size
override fun getItemId(position: Int): Long {
return differ.currentList[position].id
}
fun getCurrentList(): List<SubscriptionItem> = differ.currentList
fun update(newData: List<SubscriptionEntity>) {
differ.submitList(
newData.map {
SubscriptionItem(
id = it.uid,
title = it.name,
notificationMode = it.notificationMode,
serviceId = it.serviceId,
url = it.url
)
}
) )
} }
data class SubscriptionItem( override fun onBindViewHolder(holder: SubscriptionHolder, position: Int) {
val id: Long, holder.bind(currentList[position])
val title: String, }
@NotificationMode
val notificationMode: Int,
val serviceId: Int,
val url: String
)
class SubscriptionHolder( fun update(newData: List<SubscriptionEntity>) {
itemView: View, val items = newData.map {
private val listener: ModeToggleListener SubscriptionItem(it.uid, it.name, it.notificationMode, it.serviceId, it.url)
) : RecyclerView.ViewHolder(itemView), View.OnClickListener { }
submitList(items)
private val checkedTextView = itemView as CheckedTextView }
inner class SubscriptionHolder(
private val itemBinding: ItemNotificationConfigBinding
) : RecyclerView.ViewHolder(itemBinding.root) {
init { init {
itemView.setOnClickListener(this) itemView.setOnClickListener {
val mode = if (itemBinding.root.isChecked) {
NotificationMode.DISABLED
} else {
NotificationMode.ENABLED
}
listener.onModeChange(bindingAdapterPosition, mode)
}
} }
fun bind(data: SubscriptionItem) { fun bind(data: SubscriptionItem) {
checkedTextView.text = data.title itemBinding.root.text = data.title
checkedTextView.isChecked = data.notificationMode != NotificationMode.DISABLED itemBinding.root.isChecked = data.notificationMode != NotificationMode.DISABLED
}
override fun onClick(v: View) {
val mode = if (checkedTextView.isChecked) {
NotificationMode.DISABLED
} else {
NotificationMode.ENABLED
}
listener.onModeChange(bindingAdapterPosition, mode)
} }
} }
private class DiffCallback : DiffUtil.ItemCallback<SubscriptionItem>() { private object DiffCallback : DiffUtil.ItemCallback<SubscriptionItem>() {
override fun areItemsTheSame(oldItem: SubscriptionItem, newItem: SubscriptionItem): Boolean { override fun areItemsTheSame(oldItem: SubscriptionItem, newItem: SubscriptionItem): Boolean {
return oldItem.id == newItem.id return oldItem.id == newItem.id
} }
@ -107,18 +66,27 @@ class NotificationModeConfigAdapter(
} }
override fun getChangePayload(oldItem: SubscriptionItem, newItem: SubscriptionItem): Any? { override fun getChangePayload(oldItem: SubscriptionItem, newItem: SubscriptionItem): Any? {
if (oldItem.notificationMode != newItem.notificationMode) { return if (oldItem.notificationMode != newItem.notificationMode) {
return newItem.notificationMode newItem.notificationMode
} else { } else {
return super.getChangePayload(oldItem, newItem) super.getChangePayload(oldItem, newItem)
} }
} }
} }
interface ModeToggleListener { fun interface ModeToggleListener {
/** /**
* Triggered when the UI representation of a notification mode is changed. * Triggered when the UI representation of a notification mode is changed.
*/ */
fun onModeChange(position: Int, @NotificationMode mode: Int) fun onModeChange(position: Int, @NotificationMode mode: Int)
} }
} }
data class SubscriptionItem(
val id: Long,
val title: String,
@NotificationMode
val notificationMode: Int,
val serviceId: Int,
val url: String
)

View file

@ -1,5 +1,6 @@
package org.schabi.newpipe.settings.notifications package org.schabi.newpipe.settings.notifications
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
@ -8,30 +9,36 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.subscription.NotificationMode import org.schabi.newpipe.database.subscription.NotificationMode
import org.schabi.newpipe.databinding.FragmentChannelsNotificationsBinding
import org.schabi.newpipe.local.subscription.SubscriptionManager import org.schabi.newpipe.local.subscription.SubscriptionManager
import org.schabi.newpipe.settings.notifications.NotificationModeConfigAdapter.ModeToggleListener
/** /**
* [NotificationModeConfigFragment] is a settings fragment * [NotificationModeConfigFragment] is a settings fragment
* which allows changing the [NotificationMode] of all subscribed channels. * which allows changing the [NotificationMode] of all subscribed channels.
* The [NotificationMode] can either be changed one by one or toggled for all channels. * The [NotificationMode] can either be changed one by one or toggled for all channels.
*/ */
class NotificationModeConfigFragment : Fragment(), ModeToggleListener { class NotificationModeConfigFragment : Fragment() {
private var _binding: FragmentChannelsNotificationsBinding? = null
private val binding get() = _binding!!
private lateinit var updaters: CompositeDisposable private val updaters = CompositeDisposable()
private var loader: Disposable? = null private var loader: Disposable? = null
private var adapter: NotificationModeConfigAdapter? = null private lateinit var adapter: NotificationModeConfigAdapter
private lateinit var subscriptionManager: SubscriptionManager
override fun onAttach(context: Context) {
super.onAttach(context)
subscriptionManager = SubscriptionManager(context)
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
updaters = CompositeDisposable()
setHasOptionsMenu(true) setHasOptionsMenu(true)
} }
@ -39,23 +46,29 @@ class NotificationModeConfigFragment : Fragment(), ModeToggleListener {
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle?, savedInstanceState: Bundle?,
): View = inflater.inflate(R.layout.fragment_channels_notifications, container, false) ): View {
_binding = FragmentChannelsNotificationsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val recyclerView: RecyclerView = view.findViewById(R.id.recycler_view) adapter = NotificationModeConfigAdapter { position, mode ->
adapter = NotificationModeConfigAdapter(this) // Notification mode has been changed via the UI.
recyclerView.adapter = adapter // Now change it in the database.
updaters.add(updateNotificationMode(adapter.currentList[position], mode))
}
binding.recyclerView.adapter = adapter
loader?.dispose() loader?.dispose()
loader = SubscriptionManager(requireContext()) loader = subscriptionManager.subscriptions()
.subscriptions()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { newData -> adapter?.update(newData) } .subscribe(adapter::update)
} }
override fun onDestroyView() { override fun onDestroyView() {
loader?.dispose() loader?.dispose()
loader = null loader = null
_binding = null
super.onDestroyView() super.onDestroyView()
} }
@ -79,41 +92,22 @@ class NotificationModeConfigFragment : Fragment(), ModeToggleListener {
} }
} }
override fun onModeChange(position: Int, @NotificationMode mode: Int) {
// Notification mode has been changed via the UI.
// Now change it in the database.
val subscription = adapter?.getItem(position) ?: return
updaters.add(
SubscriptionManager(requireContext())
.updateNotificationMode(
subscription.serviceId,
subscription.url,
mode
)
.subscribeOn(Schedulers.io())
.subscribe()
)
}
private fun toggleAll() { private fun toggleAll() {
val subscriptions = adapter?.getCurrentList() ?: return val mode = adapter.currentList.firstOrNull()?.notificationMode ?: return
val mode = subscriptions.firstOrNull()?.notificationMode ?: return
val newMode = when (mode) { val newMode = when (mode) {
NotificationMode.DISABLED -> NotificationMode.ENABLED NotificationMode.DISABLED -> NotificationMode.ENABLED
else -> NotificationMode.DISABLED else -> NotificationMode.DISABLED
} }
val subscriptionManager = SubscriptionManager(requireContext()) val disposables = adapter.currentList.map { updateNotificationMode(it, newMode) }
updaters.add( updaters.add(CompositeDisposable(disposables))
CompositeDisposable( }
subscriptions.map { item ->
subscriptionManager.updateNotificationMode( private fun updateNotificationMode(
serviceId = item.serviceId, item: SubscriptionItem,
url = item.url, @NotificationMode mode: Int
mode = newMode ): Disposable {
).subscribeOn(Schedulers.io()) return subscriptionManager.updateNotificationMode(item.serviceId, item.url, mode)
.subscribe() .subscribeOn(Schedulers.io())
} .subscribe()
)
)
} }
} }