feat: sort subscriptions in groups (#443)

This commit is contained in:
ibo 2024-06-25 07:01:04 +02:00 committed by GitHub
parent 2180086573
commit ae95b61298
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 184 additions and 25 deletions

View file

@ -9,31 +9,25 @@ import ani.dantotsu.loadImage
import ani.dantotsu.media.MediaDetailsActivity import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.notifications.subscription.SubscriptionHelper import ani.dantotsu.notifications.subscription.SubscriptionHelper
import com.xwray.groupie.GroupieAdapter import com.xwray.groupie.GroupieAdapter
import com.xwray.groupie.Item
import com.xwray.groupie.viewbinding.BindableItem import com.xwray.groupie.viewbinding.BindableItem
class SubscriptionItem( class SubscriptionItem(
val id: Int, val id: Int,
private val media: SubscriptionHelper.Companion.SubscribeMedia, private val media: SubscriptionHelper.Companion.SubscribeMedia,
private val adapter: GroupieAdapter private val adapter: GroupieAdapter,
private val onItemRemoved: (Int) -> Unit
) : BindableItem<ItemSubscriptionBinding>() { ) : BindableItem<ItemSubscriptionBinding>() {
private lateinit var binding: ItemSubscriptionBinding private lateinit var binding: ItemSubscriptionBinding
override fun bind(p0: ItemSubscriptionBinding, p1: Int) {
val context = p0.root.context override fun bind(viewBinding: ItemSubscriptionBinding, position: Int) {
binding = p0 binding = viewBinding
val parserName = if (media.isAnime) val context = binding.root.context
SubscriptionHelper.getAnimeParser(media.id).name
else binding.subscriptionName.text = media.name
SubscriptionHelper.getMangaParser(media.id).name
val mediaName = media.name
val showName = "$mediaName ($parserName)"
binding.subscriptionName.text = showName
binding.root.setOnClickListener { binding.root.setOnClickListener {
ContextCompat.startActivity( ContextCompat.startActivity(
context, context,
Intent(context, MediaDetailsActivity::class.java).putExtra( Intent(context, MediaDetailsActivity::class.java).putExtra("mediaId", media.id),
"mediaId", media.id
),
null null
) )
} }
@ -41,14 +35,11 @@ class SubscriptionItem(
binding.deleteSubscription.setOnClickListener { binding.deleteSubscription.setOnClickListener {
SubscriptionHelper.deleteSubscription(id, true) SubscriptionHelper.deleteSubscription(id, true)
adapter.remove(this) adapter.remove(this)
onItemRemoved(id)
} }
} }
override fun getLayout(): Int { override fun getLayout(): Int = R.layout.item_subscription
return R.layout.item_subscription
}
override fun initializeViewBinding(p0: View): ItemSubscriptionBinding { override fun initializeViewBinding(view: View): ItemSubscriptionBinding = ItemSubscriptionBinding.bind(view)
return ItemSubscriptionBinding.bind(p0)
}
} }

View file

@ -0,0 +1,113 @@
package ani.dantotsu.settings
import android.app.AlertDialog
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
import ani.dantotsu.R
import ani.dantotsu.databinding.ItemExtensionBinding
import ani.dantotsu.notifications.subscription.SubscriptionHelper
import com.xwray.groupie.GroupieAdapter
import com.xwray.groupie.viewbinding.BindableItem
class SubscriptionSource(
private val parserName: String,
private val subscriptions: MutableList<SubscriptionHelper.Companion.SubscribeMedia>,
private val adapter: GroupieAdapter,
private var parserIcon: Drawable? = null,
private val onGroupRemoved: (SubscriptionSource) -> Unit
) : BindableItem<ItemExtensionBinding>() {
private lateinit var binding: ItemExtensionBinding
private var isExpanded = false
override fun bind(viewBinding: ItemExtensionBinding, position: Int) {
binding = viewBinding
binding.extensionNameTextView.text = parserName
updateSubscriptionCount()
binding.extensionSubscriptions.visibility = View.VISIBLE
binding.extensionSubscriptions.setOnClickListener(null)
binding.root.setOnClickListener {
isExpanded = !isExpanded
toggleSubscriptions()
}
binding.subscriptionCount.setOnClickListener {
showRemoveAllSubscriptionsDialog(it.context)
}
binding.extensionIconImageView.visibility = View.VISIBLE
val layoutParams = binding.extensionIconImageView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.leftMargin = 28
binding.extensionIconImageView.layoutParams = layoutParams
parserIcon?.let {
binding.extensionIconImageView.setImageDrawable(it)
} ?: run {
binding.extensionIconImageView.setImageResource(R.drawable.control_background_40dp)
}
binding.extensionPinImageView.visibility = View.GONE
binding.extensionVersionTextView.visibility = View.GONE
binding.closeTextView.visibility = View.GONE
binding.settingsImageView.visibility = View.GONE
}
private fun updateSubscriptionCount() {
binding.subscriptionCount.text = subscriptions.size.toString()
binding.subscriptionCount.visibility = if (subscriptions.isEmpty()) View.GONE else View.VISIBLE
}
private fun showRemoveAllSubscriptionsDialog(context: Context) {
AlertDialog.Builder(context, R.style.MyPopup)
.setTitle(R.string.remove_all_subscriptions)
.setMessage(context.getString(R.string.remove_all_subscriptions_desc, parserName))
.setPositiveButton(R.string.apply) { _, _ ->
removeAllSubscriptions()
}
.setNegativeButton(R.string.cancel, null)
.show()
}
private fun removeAllSubscriptions() {
subscriptions.forEach { subscription ->
SubscriptionHelper.deleteSubscription(subscription.id, false)
}
if (isExpanded) {
val startPosition = adapter.getAdapterPosition(this) + 1
repeat(subscriptions.size) {
adapter.removeGroupAtAdapterPosition(startPosition)
}
}
subscriptions.clear()
onGroupRemoved(this)
}
private fun removeSubscription(id: Any?) {
subscriptions.removeAll { it.id == id }
updateSubscriptionCount()
if (subscriptions.isEmpty()) {
onGroupRemoved(this)
} else {
adapter.notifyItemChanged(adapter.getAdapterPosition(this))
}
}
private fun toggleSubscriptions() {
val startPosition = adapter.getAdapterPosition(this) + 1
if (isExpanded) {
subscriptions.forEachIndexed { index, subscribeMedia ->
adapter.add(startPosition + index, SubscriptionItem(subscribeMedia.id, subscribeMedia, adapter) { removedId ->
removeSubscription(removedId)
})
}
} else {
repeat(subscriptions.size) {
adapter.removeGroupAtAdapterPosition(startPosition)
}
}
}
override fun getLayout(): Int = R.layout.item_extension
override fun initializeViewBinding(view: View): ItemExtensionBinding = ItemExtensionBinding.bind(view)
}

View file

@ -1,5 +1,6 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -9,13 +10,21 @@ import ani.dantotsu.BottomSheetDialogFragment
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.databinding.BottomSheetRecyclerBinding import ani.dantotsu.databinding.BottomSheetRecyclerBinding
import ani.dantotsu.notifications.subscription.SubscriptionHelper import ani.dantotsu.notifications.subscription.SubscriptionHelper
import ani.dantotsu.parsers.novel.NovelExtensionManager
import com.xwray.groupie.GroupieAdapter import com.xwray.groupie.GroupieAdapter
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class SubscriptionsBottomDialog : BottomSheetDialogFragment() { class SubscriptionsBottomDialog : BottomSheetDialogFragment() {
private var _binding: BottomSheetRecyclerBinding? = null private var _binding: BottomSheetRecyclerBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private val adapter: GroupieAdapter = GroupieAdapter() private val adapter: GroupieAdapter = GroupieAdapter()
private var subscriptions: Map<Int, SubscriptionHelper.Companion.SubscribeMedia> = mapOf() private var subscriptions: Map<Int, SubscriptionHelper.Companion.SubscribeMedia> = mapOf()
private val animeExtension: AnimeExtensionManager = Injekt.get()
private val mangaExtensions: MangaExtensionManager = Injekt.get()
private val novelExtensions: NovelExtensionManager = Injekt.get()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -36,8 +45,33 @@ class SubscriptionsBottomDialog : BottomSheetDialogFragment() {
val context = requireContext() val context = requireContext()
binding.title.text = context.getString(R.string.subscriptions) binding.title.text = context.getString(R.string.subscriptions)
binding.replyButton.visibility = View.GONE binding.replyButton.visibility = View.GONE
subscriptions.forEach { (id, media) ->
adapter.add(SubscriptionItem(id, media, adapter)) val groupedSubscriptions = subscriptions.values.groupBy {
if (it.isAnime) SubscriptionHelper.getAnimeParser(it.id).name
else SubscriptionHelper.getMangaParser(it.id).name
}
groupedSubscriptions.forEach { (parserName, mediaList) ->
adapter.add(SubscriptionSource(
parserName,
mediaList.toMutableList(),
adapter,
getParserIcon(parserName)
) { group ->
adapter.remove(group)
})
}
}
private fun getParserIcon(parserName: String): Drawable? {
return when {
animeExtension.installedExtensionsFlow.value.any { it.name == parserName } ->
animeExtension.installedExtensionsFlow.value.find { it.name == parserName }?.icon
mangaExtensions.installedExtensionsFlow.value.any { it.name == parserName } ->
mangaExtensions.installedExtensionsFlow.value.find { it.name == parserName }?.icon
novelExtensions.installedExtensionsFlow.value.any { it.name == parserName } ->
novelExtensions.installedExtensionsFlow.value.find { it.name == parserName }?.icon
else -> null
} }
} }

View file

@ -25,7 +25,7 @@
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginEnd="3dp" android:layout_marginEnd="9dp"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
<LinearLayout <LinearLayout
@ -53,6 +53,26 @@
tools:ignore="SmallSp" /> tools:ignore="SmallSp" />
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/subscriptionCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="12dp"
android:fontFamily="@font/poppins_bold"
android:visibility="gone"/>
<ImageView
android:id="@+id/extensionSubscriptions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0"
android:src="@drawable/ui_bg"
android:visibility="gone"
app:tint="?attr/colorOnBackground"
tools:ignore="ContentDescription"/>
<ImageView <ImageView
android:id="@+id/closeTextView" android:id="@+id/closeTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -4,7 +4,6 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:layout_marginHorizontal="8dp" android:layout_marginHorizontal="8dp"
android:orientation="horizontal" android:orientation="horizontal"
tools:ignore="UseCompoundDrawables"> tools:ignore="UseCompoundDrawables">

View file

@ -417,6 +417,8 @@
<string name="use_alarm_manager_reliable">Use Alarm Manager for reliable Notifications</string> <string name="use_alarm_manager_reliable">Use Alarm Manager for reliable Notifications</string>
<string name="use_alarm_manager_confirm">Using Alarm Manger can help fight against battery optimization, but may consume more battery. It also requires the Alarm Manager permission.</string> <string name="use_alarm_manager_confirm">Using Alarm Manger can help fight against battery optimization, but may consume more battery. It also requires the Alarm Manager permission.</string>
<string name="use">Use</string> <string name="use">Use</string>
<string name="remove_all_subscriptions">Remove All Subscriptions</string>
<string name="remove_all_subscriptions_desc">Are you sure you want to remove all subscriptions for %1$s?</string>
<string name="checking_subscriptions">Notification for Checking Subscriptions</string> <string name="checking_subscriptions">Notification for Checking Subscriptions</string>
<string name="subscriptions_checking_time_s">Subscriptions Update Frequency : %1$s</string> <string name="subscriptions_checking_time_s">Subscriptions Update Frequency : %1$s</string>
<string name="subscriptions_checking_time">Subscriptions Update Frequency</string> <string name="subscriptions_checking_time">Subscriptions Update Frequency</string>