From f37d869ea2c2474985a1386af9fbed67abf092ef Mon Sep 17 00:00:00 2001 From: Samuel Wu Date: Mon, 24 Oct 2022 23:01:02 +1100 Subject: [PATCH] Button can be toggled but not all strings have been fed --- .../5.json | 26 +++-- .../database/feed/model/FeedGroupEntity.kt | 2 +- .../subscription/SubscriptionFragment.kt | 101 ++++++++++++++++-- .../subscription/item/FeedGroupCardItem.kt | 4 +- .../item/FeedGroupCardVerticalItem.kt | 32 ++++++ .../item/FeedGroupCarouselItem.kt | 6 +- ....xml => feed_group_card_vertical_item.xml} | 7 +- 7 files changed, 155 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCardVerticalItem.kt rename app/src/main/res/layout/{feed_group_list_item.xml => feed_group_card_vertical_item.xml} (92%) diff --git a/app/schemas/org.schabi.newpipe.database.AppDatabase/5.json b/app/schemas/org.schabi.newpipe.database.AppDatabase/5.json index 9a1c62995..eeebdeb49 100644 --- a/app/schemas/org.schabi.newpipe.database.AppDatabase/5.json +++ b/app/schemas/org.schabi.newpipe.database.AppDatabase/5.json @@ -71,6 +71,7 @@ "service_id", "url" ], + "orders": [], "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_subscriptions_service_id_url` ON `${TABLE_NAME}` (`service_id`, `url`)" } ], @@ -78,14 +79,8 @@ }, { "tableName": "search_history", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `creation_date` INTEGER, `service_id` INTEGER NOT NULL, `search` TEXT)", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`creation_date` INTEGER, `service_id` INTEGER NOT NULL, `search` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, { "fieldPath": "creationDate", "columnName": "creation_date", @@ -103,6 +98,12 @@ "columnName": "search", "affinity": "TEXT", "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true } ], "primaryKey": { @@ -118,6 +119,7 @@ "columnNames": [ "search" ], + "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_search_history_search` ON `${TABLE_NAME}` (`search`)" } ], @@ -220,6 +222,7 @@ "service_id", "url" ], + "orders": [], "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_streams_service_id_url` ON `${TABLE_NAME}` (`service_id`, `url`)" } ], @@ -262,6 +265,7 @@ "columnNames": [ "stream_id" ], + "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_stream_history_stream_id` ON `${TABLE_NAME}` (`stream_id`)" } ], @@ -353,6 +357,7 @@ "columnNames": [ "name" ], + "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_playlists_name` ON `${TABLE_NAME}` (`name`)" } ], @@ -396,6 +401,7 @@ "playlist_id", "join_index" ], + "orders": [], "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_playlist_stream_join_playlist_id_join_index` ON `${TABLE_NAME}` (`playlist_id`, `join_index`)" }, { @@ -404,6 +410,7 @@ "columnNames": [ "stream_id" ], + "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_playlist_stream_join_stream_id` ON `${TABLE_NAME}` (`stream_id`)" } ], @@ -492,6 +499,7 @@ "columnNames": [ "name" ], + "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_remote_playlists_name` ON `${TABLE_NAME}` (`name`)" }, { @@ -501,6 +509,7 @@ "service_id", "url" ], + "orders": [], "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_remote_playlists_service_id_url` ON `${TABLE_NAME}` (`service_id`, `url`)" } ], @@ -537,6 +546,7 @@ "columnNames": [ "subscription_id" ], + "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_feed_subscription_id` ON `${TABLE_NAME}` (`subscription_id`)" } ], @@ -607,6 +617,7 @@ "columnNames": [ "sort_order" ], + "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_feed_group_sort_order` ON `${TABLE_NAME}` (`sort_order`)" } ], @@ -643,6 +654,7 @@ "columnNames": [ "subscription_id" ], + "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_feed_group_subscription_join_subscription_id` ON `${TABLE_NAME}` (`subscription_id`)" } ], diff --git a/app/src/main/java/org/schabi/newpipe/database/feed/model/FeedGroupEntity.kt b/app/src/main/java/org/schabi/newpipe/database/feed/model/FeedGroupEntity.kt index 1dd26946a..c7415ace0 100644 --- a/app/src/main/java/org/schabi/newpipe/database/feed/model/FeedGroupEntity.kt +++ b/app/src/main/java/org/schabi/newpipe/database/feed/model/FeedGroupEntity.kt @@ -24,7 +24,7 @@ data class FeedGroupEntity( var icon: FeedGroupIcon, @ColumnInfo(name = SORT_ORDER) - var sortOrder: Long = -1 + var sortOrder: Long = -1, ) { companion object { const val FEED_GROUP_TABLE = "feed_group" diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt index bf4941e8e..659187ffa 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt @@ -20,6 +20,7 @@ import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.xwray.groupie.Group import com.xwray.groupie.GroupAdapter import com.xwray.groupie.Item @@ -45,6 +46,7 @@ import org.schabi.newpipe.local.subscription.item.ChannelItem import org.schabi.newpipe.local.subscription.item.EmptyPlaceholderItem import org.schabi.newpipe.local.subscription.item.FeedGroupAddItem import org.schabi.newpipe.local.subscription.item.FeedGroupCardItem +import org.schabi.newpipe.local.subscription.item.FeedGroupCardVerticalItem import org.schabi.newpipe.local.subscription.item.FeedGroupCarouselItem import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem.Companion.PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM @@ -76,6 +78,7 @@ class SubscriptionFragment : BaseStateFragment() { private val groupAdapter = GroupAdapter>() private val feedGroupsSection = Section() private var feedGroupsCarousel: FeedGroupCarouselItem? = null + private var feedGroupsCarouselVertical: FeedGroupCarouselItem? = feedGroupsCarousel private lateinit var feedGroupsSortMenuItem: HeaderWithMenuItem private val subscriptionsSection = Section() @@ -92,6 +95,10 @@ class SubscriptionFragment : BaseStateFragment() { @JvmField var feedGroupsListState: Parcelable? = null + @State + @JvmField + var feedGroupsListVerticalState: Parcelable? = null + init { setHasOptionsMenu(true) } @@ -118,6 +125,7 @@ class SubscriptionFragment : BaseStateFragment() { super.onPause() itemsListState = binding.itemsList.layoutManager?.onSaveInstanceState() feedGroupsListState = feedGroupsCarousel?.onSaveInstanceState() + feedGroupsListVerticalState = feedGroupsCarouselVertical?.onSaveInstanceState() } override fun onDestroy() { @@ -221,10 +229,6 @@ class SubscriptionFragment : BaseStateFragment() { FeedGroupReorderDialog().show(parentFragmentManager, null) } - private fun temp() { - println("This button is clicked") - } - private fun requestExportResult(result: ActivityResult) { if (result.data != null && result.resultCode == Activity.RESULT_OK) { activity.startService( @@ -270,16 +274,16 @@ class SubscriptionFragment : BaseStateFragment() { return@setOnItemLongClickListener true } - feedGroupsCarousel = FeedGroupCarouselItem(requireContext(), carouselAdapter) + feedGroupsCarousel = FeedGroupCarouselItem(requireContext(), carouselAdapter, RecyclerView.HORIZONTAL) feedGroupsSortMenuItem = HeaderWithMenuItem( getString(R.string.feed_groups_header_title), R.drawable.ic_list, R.drawable.ic_sort, - listViewOnClickListener = ::temp, + listViewOnClickListener = ::changeLayout, menuItemOnClickListener = ::openReorderDialog ) add(Section(feedGroupsSortMenuItem, listOf(feedGroupsCarousel))) - + groupAdapter.clear() groupAdapter.add(this) } @@ -296,6 +300,62 @@ class SubscriptionFragment : BaseStateFragment() { ) } + private fun changeLayout() { + Section().apply { + val carouselAdapter = GroupAdapter>() + + carouselAdapter.add(FeedGroupCardVerticalItem(-1, getString(R.string.all), FeedGroupIcon.RSS)) + carouselAdapter.add(feedGroupsSection) + carouselAdapter.add(FeedGroupAddItem()) // change this button later + carouselAdapter.setOnItemClickListener { item, _ -> + listenerFeedVerticalGroups.selected(item) + } + carouselAdapter.setOnItemLongClickListener { item, _ -> + if (item is FeedGroupCardVerticalItem) { + if (item.groupId == FeedGroupEntity.GROUP_ALL_ID) { + return@setOnItemLongClickListener false + } + } + listenerFeedVerticalGroups.held(item) + return@setOnItemLongClickListener true + } + + feedGroupsCarouselVertical = FeedGroupCarouselItem(requireContext(), carouselAdapter, RecyclerView.VERTICAL) + feedGroupsSortMenuItem = HeaderWithMenuItem( + getString(R.string.feed_groups_header_title), + R.drawable.ic_apps, + R.drawable.ic_sort, + listViewOnClickListener = ::setupInitialLayout, + menuItemOnClickListener = ::openReorderDialog + ) + add(Section(feedGroupsSortMenuItem, listOf(feedGroupsCarouselVertical))) + groupAdapter.clear() + groupAdapter.add(this) + } + subscriptionsSection.setPlaceholder(EmptyPlaceholderItem()) + subscriptionsSection.setHideWhenEmpty(true) + + groupAdapter.add( + Section( + HeaderWithMenuItem( + getString(R.string.tab_subscriptions) + ), + listOf(subscriptionsSection) + ) + ) + + // TODO: remove this + groupAdapter.spanCount = if (shouldUseGridLayout(context)) getGridSpanCountChannels(context) else 1 + binding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply { + spanSizeLookup = groupAdapter.spanSizeLookup + } + binding.itemsList.adapter = groupAdapter + + viewModel = ViewModelProvider(this).get(SubscriptionViewModel::class.java) + viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(this::handleResult) } + viewModel.feedGroupsLiveData.observe(viewLifecycleOwner) { it?.let(this::handleFeedVerticalGroups) } + } + override fun initViews(rootView: View, savedInstanceState: Bundle?) { super.initViews(rootView, savedInstanceState) _binding = FragmentSubscriptionBinding.bind(rootView) @@ -367,6 +427,21 @@ class SubscriptionFragment : BaseStateFragment() { } } + private val listenerFeedVerticalGroups = object : OnClickGesture> { + override fun selected(selectedItem: Item<*>?) { + when (selectedItem) { + is FeedGroupCardVerticalItem -> NavigationHelper.openFeedFragment(fm, selectedItem.groupId, selectedItem.name) + is FeedGroupAddItem -> FeedGroupDialog.newInstance().show(fm, null) + } + } + + override fun held(selectedItem: Item<*>?) { + when (selectedItem) { + is FeedGroupCardVerticalItem -> FeedGroupDialog.newInstance(selectedItem.groupId).show(fm, null) + } + } + } + private val listenerChannelItem = object : OnClickGesture { override fun selected(selectedItem: ChannelInfoItem) = NavigationHelper.openChannelFragment( fm, @@ -420,6 +495,18 @@ class SubscriptionFragment : BaseStateFragment() { binding.itemsList.post { feedGroupsSortMenuItem.notifyChanged(PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM) } } + private fun handleFeedVerticalGroups(groups: List) { + feedGroupsSection.update(groups) + + if (feedGroupsListState != null) { + feedGroupsCarouselVertical?.onRestoreInstanceState(feedGroupsListVerticalState) + feedGroupsListVerticalState = null + } + + feedGroupsSortMenuItem.showMenuItem = groups.size > 1 + binding.itemsList.post { feedGroupsSortMenuItem.notifyChanged(PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM) } + } + // ///////////////////////////////////////////////////////////////////////// // Contract // ///////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCardItem.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCardItem.kt index fd8a75da1..a4fa84798 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCardItem.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCardItem.kt @@ -10,7 +10,7 @@ import org.schabi.newpipe.local.subscription.FeedGroupIcon data class FeedGroupCardItem( val groupId: Long = FeedGroupEntity.GROUP_ALL_ID, val name: String, - val icon: FeedGroupIcon + val icon: FeedGroupIcon, ) : BindableItem() { constructor (feedGroupEntity: FeedGroupEntity) : this(feedGroupEntity.uid, feedGroupEntity.name, feedGroupEntity.icon) @@ -21,7 +21,7 @@ data class FeedGroupCardItem( } } - override fun getLayout(): Int = R.layout.feed_group_list_item + override fun getLayout(): Int = R.layout.feed_group_card_item override fun bind(viewBinding: FeedGroupCardItemBinding, position: Int) { viewBinding.title.text = name diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCardVerticalItem.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCardVerticalItem.kt new file mode 100644 index 000000000..9750da7b4 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCardVerticalItem.kt @@ -0,0 +1,32 @@ +package org.schabi.newpipe.local.subscription.item + +import android.view.View +import com.xwray.groupie.viewbinding.BindableItem +import org.schabi.newpipe.R +import org.schabi.newpipe.database.feed.model.FeedGroupEntity +import org.schabi.newpipe.databinding.FeedGroupCardVerticalItemBinding +import org.schabi.newpipe.local.subscription.FeedGroupIcon + +data class FeedGroupCardVerticalItem( + val groupId: Long = FeedGroupEntity.GROUP_ALL_ID, + val name: String, + val icon: FeedGroupIcon +) : BindableItem() { + constructor (feedGroupEntity: FeedGroupEntity) : this(feedGroupEntity.uid, feedGroupEntity.name, feedGroupEntity.icon) + + override fun getId(): Long { + return when (groupId) { + FeedGroupEntity.GROUP_ALL_ID -> super.getId() + else -> groupId + } + } + + override fun getLayout(): Int = R.layout.feed_group_card_vertical_item + + override fun bind(viewBinding: FeedGroupCardVerticalItemBinding, position: Int) { + viewBinding.title.text = name + viewBinding.icon.setImageResource(icon.getDrawableRes()) + } + + override fun initializeViewBinding(view: View) = FeedGroupCardVerticalItemBinding.bind(view) +} diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCarouselItem.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCarouselItem.kt index 031eb9b18..a574fa01b 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCarouselItem.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedGroupCarouselItem.kt @@ -4,7 +4,6 @@ import android.content.Context import android.os.Parcelable import android.view.View import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import com.xwray.groupie.GroupAdapter import com.xwray.groupie.viewbinding.BindableItem import com.xwray.groupie.viewbinding.GroupieViewHolder @@ -14,7 +13,8 @@ import org.schabi.newpipe.local.subscription.decoration.FeedGroupCarouselDecorat class FeedGroupCarouselItem( context: Context, - private val carouselAdapter: GroupAdapter> + private val carouselAdapter: GroupAdapter>, + private var listView: Int ) : BindableItem() { private val feedGroupCarouselDecoration = FeedGroupCarouselDecoration(context) @@ -36,7 +36,7 @@ class FeedGroupCarouselItem( override fun initializeViewBinding(view: View): FeedItemCarouselBinding { val viewHolder = FeedItemCarouselBinding.bind(view) - linearLayoutManager = LinearLayoutManager(view.context, RecyclerView.VERTICAL, false) + linearLayoutManager = LinearLayoutManager(view.context, listView, false) viewHolder.recyclerView.apply { layoutManager = linearLayoutManager diff --git a/app/src/main/res/layout/feed_group_list_item.xml b/app/src/main/res/layout/feed_group_card_vertical_item.xml similarity index 92% rename from app/src/main/res/layout/feed_group_list_item.xml rename to app/src/main/res/layout/feed_group_card_vertical_item.xml index c49da1eab..aadfc95a8 100644 --- a/app/src/main/res/layout/feed_group_list_item.xml +++ b/app/src/main/res/layout/feed_group_card_vertical_item.xml @@ -2,7 +2,7 @@ +