Merge pull request #8841 from Isira-Seneviratne/Notification_mode_ListAdapter

Use ListAdapter in NotificationModeConfigAdapter.
pull/9598/merge
Stypox 2023-01-02 14:47:25 +01:00 zatwierdzone przez GitHub
commit b6488fe342
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
2 zmienionych plików z 79 dodań i 119 usunięć

Wyświetl plik

@ -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
)

Wyświetl plik

@ -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 disposables = 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,28 +46,34 @@ 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.
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()
} }
override fun onDestroy() { override fun onDestroy() {
updaters.dispose() disposables.dispose()
super.onDestroy() super.onDestroy()
} }
@ -79,41 +92,20 @@ 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()) adapter.currentList.forEach { updateNotificationMode(it, newMode) }
updaters.add( }
CompositeDisposable(
subscriptions.map { item -> private fun updateNotificationMode(item: SubscriptionItem, @NotificationMode mode: Int) {
subscriptionManager.updateNotificationMode( disposables.add(
serviceId = item.serviceId, subscriptionManager.updateNotificationMode(item.serviceId, item.url, mode)
url = item.url, .subscribeOn(Schedulers.io())
mode = newMode .subscribe()
).subscribeOn(Schedulers.io())
.subscribe()
}
)
) )
} }
} }