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
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckedTextView
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.schabi.newpipe.R
import org.schabi.newpipe.database.subscription.NotificationMode
import org.schabi.newpipe.database.subscription.SubscriptionEntity
import org.schabi.newpipe.databinding.ItemNotificationConfigBinding
import org.schabi.newpipe.settings.notifications.NotificationModeConfigAdapter.SubscriptionHolder
/**
@ -19,85 +17,46 @@ import org.schabi.newpipe.settings.notifications.NotificationModeConfigAdapter.S
*/
class NotificationModeConfigAdapter(
private val listener: ModeToggleListener
) : RecyclerView.Adapter<SubscriptionHolder>() {
private val differ = AsyncListDiffer(this, DiffCallback())
init {
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
)
}
) : ListAdapter<SubscriptionItem, SubscriptionHolder>(DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, i: Int): SubscriptionHolder {
return SubscriptionHolder(
ItemNotificationConfigBinding
.inflate(LayoutInflater.from(parent.context), parent, false)
)
}
data class SubscriptionItem(
val id: Long,
val title: String,
@NotificationMode
val notificationMode: Int,
val serviceId: Int,
val url: String
)
override fun onBindViewHolder(holder: SubscriptionHolder, position: Int) {
holder.bind(currentList[position])
}
class SubscriptionHolder(
itemView: View,
private val listener: ModeToggleListener
) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
private val checkedTextView = itemView as CheckedTextView
fun update(newData: List<SubscriptionEntity>) {
val items = newData.map {
SubscriptionItem(it.uid, it.name, it.notificationMode, it.serviceId, it.url)
}
submitList(items)
}
inner class SubscriptionHolder(
private val itemBinding: ItemNotificationConfigBinding
) : RecyclerView.ViewHolder(itemBinding.root) {
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) {
checkedTextView.text = data.title
checkedTextView.isChecked = data.notificationMode != NotificationMode.DISABLED
}
override fun onClick(v: View) {
val mode = if (checkedTextView.isChecked) {
NotificationMode.DISABLED
} else {
NotificationMode.ENABLED
}
listener.onModeChange(bindingAdapterPosition, mode)
itemBinding.root.text = data.title
itemBinding.root.isChecked = data.notificationMode != NotificationMode.DISABLED
}
}
private class DiffCallback : DiffUtil.ItemCallback<SubscriptionItem>() {
private object DiffCallback : DiffUtil.ItemCallback<SubscriptionItem>() {
override fun areItemsTheSame(oldItem: SubscriptionItem, newItem: SubscriptionItem): Boolean {
return oldItem.id == newItem.id
}
@ -107,18 +66,27 @@ class NotificationModeConfigAdapter(
}
override fun getChangePayload(oldItem: SubscriptionItem, newItem: SubscriptionItem): Any? {
if (oldItem.notificationMode != newItem.notificationMode) {
return newItem.notificationMode
return if (oldItem.notificationMode != newItem.notificationMode) {
newItem.notificationMode
} 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.
*/
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
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
@ -8,30 +9,36 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import org.schabi.newpipe.R
import org.schabi.newpipe.database.subscription.NotificationMode
import org.schabi.newpipe.databinding.FragmentChannelsNotificationsBinding
import org.schabi.newpipe.local.subscription.SubscriptionManager
import org.schabi.newpipe.settings.notifications.NotificationModeConfigAdapter.ModeToggleListener
/**
* [NotificationModeConfigFragment] is a settings fragment
* which allows changing the [NotificationMode] of all subscribed 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 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?) {
super.onCreate(savedInstanceState)
updaters = CompositeDisposable()
setHasOptionsMenu(true)
}
@ -39,23 +46,29 @@ class NotificationModeConfigFragment : Fragment(), ModeToggleListener {
inflater: LayoutInflater,
container: ViewGroup?,
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?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView: RecyclerView = view.findViewById(R.id.recycler_view)
adapter = NotificationModeConfigAdapter(this)
recyclerView.adapter = adapter
adapter = NotificationModeConfigAdapter { position, mode ->
// Notification mode has been changed via the UI.
// Now change it in the database.
updaters.add(updateNotificationMode(adapter.currentList[position], mode))
}
binding.recyclerView.adapter = adapter
loader?.dispose()
loader = SubscriptionManager(requireContext())
.subscriptions()
loader = subscriptionManager.subscriptions()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newData -> adapter?.update(newData) }
.subscribe(adapter::update)
}
override fun onDestroyView() {
loader?.dispose()
loader = null
_binding = null
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() {
val subscriptions = adapter?.getCurrentList() ?: return
val mode = subscriptions.firstOrNull()?.notificationMode ?: return
val mode = adapter.currentList.firstOrNull()?.notificationMode ?: return
val newMode = when (mode) {
NotificationMode.DISABLED -> NotificationMode.ENABLED
else -> NotificationMode.DISABLED
}
val subscriptionManager = SubscriptionManager(requireContext())
updaters.add(
CompositeDisposable(
subscriptions.map { item ->
subscriptionManager.updateNotificationMode(
serviceId = item.serviceId,
url = item.url,
mode = newMode
).subscribeOn(Schedulers.io())
.subscribe()
}
)
)
val disposables = adapter.currentList.map { updateNotificationMode(it, newMode) }
updaters.add(CompositeDisposable(disposables))
}
private fun updateNotificationMode(
item: SubscriptionItem,
@NotificationMode mode: Int
): Disposable {
return subscriptionManager.updateNotificationMode(item.serviceId, item.url, mode)
.subscribeOn(Schedulers.io())
.subscribe()
}
}