@@ -22,7 +22,6 @@ import androidx.lifecycle.ViewModelProvider
2222import androidx.recyclerview.widget.GridLayoutManager
2323import com.xwray.groupie.Group
2424import com.xwray.groupie.GroupAdapter
25- import com.xwray.groupie.Item
2625import com.xwray.groupie.Section
2726import com.xwray.groupie.viewbinding.GroupieViewHolder
2827import icepick.State
@@ -43,11 +42,13 @@ import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog
4342import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialog
4443import org.schabi.newpipe.local.subscription.item.ChannelItem
4544import org.schabi.newpipe.local.subscription.item.EmptyPlaceholderItem
46- import org.schabi.newpipe.local.subscription.item.FeedGroupAddItem
45+ import org.schabi.newpipe.local.subscription.item.FeedGroupAddNewGridItem
46+ import org.schabi.newpipe.local.subscription.item.FeedGroupAddNewItem
47+ import org.schabi.newpipe.local.subscription.item.FeedGroupCardGridItem
4748import org.schabi.newpipe.local.subscription.item.FeedGroupCardItem
4849import org.schabi.newpipe.local.subscription.item.FeedGroupCarouselItem
49- import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem
50- import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem.Companion.PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM
50+ import org.schabi.newpipe.local.subscription.item.GroupsHeader
51+ import org.schabi.newpipe.local.subscription.item.Header
5152import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService
5253import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService
5354import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_MODE
@@ -74,9 +75,9 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
7475 private val disposables: CompositeDisposable = CompositeDisposable ()
7576
7677 private val groupAdapter = GroupAdapter <GroupieViewHolder <FeedItemCarouselBinding >>()
77- private val feedGroupsSection = Section ()
78- private var feedGroupsCarousel: FeedGroupCarouselItem ? = null
79- private lateinit var feedGroupsSortMenuItem: HeaderWithMenuItem
78+ private lateinit var carouselAdapter : GroupAdapter < GroupieViewHolder < FeedItemCarouselBinding >>
79+ private lateinit var feedGroupsCarousel: FeedGroupCarouselItem
80+ private lateinit var feedGroupsSortMenuItem: GroupsHeader
8081 private val subscriptionsSection = Section ()
8182
8283 private val requestExportLauncher =
@@ -90,7 +91,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
9091
9192 @State
9293 @JvmField
93- var feedGroupsListState : Parcelable ? = null
94+ var feedGroupsCarouselState : Parcelable ? = null
9495
9596 init {
9697 setHasOptionsMenu(true )
@@ -100,11 +101,6 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
100101 // Fragment LifeCycle
101102 // /////////////////////////////////////////////////////////////////////////
102103
103- override fun onCreate (savedInstanceState : Bundle ? ) {
104- super .onCreate(savedInstanceState)
105- setupInitialLayout()
106- }
107-
108104 override fun onAttach (context : Context ) {
109105 super .onAttach(context)
110106 subscriptionManager = SubscriptionManager (requireContext())
@@ -117,7 +113,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
117113 override fun onPause () {
118114 super .onPause()
119115 itemsListState = binding.itemsList.layoutManager?.onSaveInstanceState()
120- feedGroupsListState = feedGroupsCarousel? .onSaveInstanceState()
116+ feedGroupsCarouselState = feedGroupsCarousel.onSaveInstanceState()
121117 }
122118
123119 override fun onDestroy () {
@@ -184,7 +180,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
184180 menuItem : MenuItem ,
185181 onClick : Runnable
186182 ): MenuItem {
187- menuItem.setOnMenuItemClickListener { _ ->
183+ menuItem.setOnMenuItemClickListener {
188184 onClick.run ()
189185 true
190186 }
@@ -245,35 +241,76 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
245241 // Fragment Views
246242 // ////////////////////////////////////////////////////////////////////////
247243
244+ override fun initViews (rootView : View , savedInstanceState : Bundle ? ) {
245+ super .initViews(rootView, savedInstanceState)
246+ _binding = FragmentSubscriptionBinding .bind(rootView)
247+
248+ groupAdapter.spanCount = if (shouldUseGridLayout(context)) getGridSpanCountChannels(context) else 1
249+ binding.itemsList.layoutManager = GridLayoutManager (requireContext(), groupAdapter.spanCount).apply {
250+ spanSizeLookup = groupAdapter.spanSizeLookup
251+ }
252+ binding.itemsList.adapter = groupAdapter
253+ binding.itemsList.itemAnimator = null
254+
255+ viewModel = ViewModelProvider (this )[SubscriptionViewModel ::class .java]
256+ viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let (this ::handleResult) }
257+ viewModel.feedGroupsLiveData.observe(viewLifecycleOwner) { it?.let (this ::handleFeedGroups) }
258+
259+ setupInitialLayout()
260+ }
261+
248262 private fun setupInitialLayout () {
249263 Section ().apply {
250- val carouselAdapter = GroupAdapter <GroupieViewHolder <FeedItemCarouselBinding >>()
251-
252- carouselAdapter.add(FeedGroupCardItem (- 1 , getString(R .string.all), FeedGroupIcon .RSS ))
253- carouselAdapter.add(feedGroupsSection)
254- carouselAdapter.add(FeedGroupAddItem ())
264+ carouselAdapter = GroupAdapter <GroupieViewHolder <FeedItemCarouselBinding >>()
255265
256266 carouselAdapter.setOnItemClickListener { item, _ ->
257- listenerFeedGroups.selected(item)
267+ when (item) {
268+ is FeedGroupCardItem ->
269+ NavigationHelper .openFeedFragment(fm, item.groupId, item.name)
270+ is FeedGroupCardGridItem ->
271+ NavigationHelper .openFeedFragment(fm, item.groupId, item.name)
272+ is FeedGroupAddNewItem ->
273+ FeedGroupDialog .newInstance().show(fm, null )
274+ is FeedGroupAddNewGridItem ->
275+ FeedGroupDialog .newInstance().show(fm, null )
276+ }
258277 }
259278 carouselAdapter.setOnItemLongClickListener { item, _ ->
260- if (item is FeedGroupCardItem ) {
261- if (item.groupId == FeedGroupEntity .GROUP_ALL_ID ) {
262- return @setOnItemLongClickListener false
263- }
279+ if ((
280+ item is FeedGroupCardItem &&
281+ item.groupId == FeedGroupEntity .GROUP_ALL_ID
282+ ) ||
283+ (
284+ item is FeedGroupCardGridItem &&
285+ item.groupId == FeedGroupEntity .GROUP_ALL_ID
286+ )
287+ ) {
288+ return @setOnItemLongClickListener false
289+ }
290+
291+ when (item) {
292+ is FeedGroupCardItem ->
293+ FeedGroupDialog .newInstance(item.groupId).show(fm, null )
294+ is FeedGroupCardGridItem ->
295+ FeedGroupDialog .newInstance(item.groupId).show(fm, null )
264296 }
265- listenerFeedGroups.held(item)
266297 return @setOnItemLongClickListener true
267298 }
268299
269- feedGroupsCarousel = FeedGroupCarouselItem (requireContext(), carouselAdapter)
270- feedGroupsSortMenuItem = HeaderWithMenuItem (
271- getString(R .string.feed_groups_header_title),
272- R .drawable.ic_sort,
273- menuItemOnClickListener = ::openReorderDialog
300+ feedGroupsCarousel = FeedGroupCarouselItem (
301+ carouselAdapter = carouselAdapter,
302+ listViewMode = viewModel.getListViewMode()
303+ )
304+
305+ feedGroupsSortMenuItem = GroupsHeader (
306+ title = getString(R .string.feed_groups_header_title),
307+ onSortClicked = ::openReorderDialog,
308+ onToggleListViewModeClicked = ::toggleListViewMode,
309+ listViewMode = viewModel.getListViewMode(),
274310 )
275- add(Section (feedGroupsSortMenuItem, listOf (feedGroupsCarousel)))
276311
312+ add(Section (feedGroupsSortMenuItem, listOf (feedGroupsCarousel)))
313+ groupAdapter.clear()
277314 groupAdapter.add(this )
278315 }
279316
@@ -282,27 +319,14 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
282319
283320 groupAdapter.add(
284321 Section (
285- HeaderWithMenuItem (
286- getString(R .string.tab_subscriptions)
287- ),
322+ Header (getString(R .string.tab_subscriptions)),
288323 listOf (subscriptionsSection)
289324 )
290325 )
291326 }
292327
293- override fun initViews (rootView : View , savedInstanceState : Bundle ? ) {
294- super .initViews(rootView, savedInstanceState)
295- _binding = FragmentSubscriptionBinding .bind(rootView)
296-
297- groupAdapter.spanCount = if (shouldUseGridLayout(context)) getGridSpanCountChannels(context) else 1
298- binding.itemsList.layoutManager = GridLayoutManager (requireContext(), groupAdapter.spanCount).apply {
299- spanSizeLookup = groupAdapter.spanSizeLookup
300- }
301- binding.itemsList.adapter = groupAdapter
302-
303- viewModel = ViewModelProvider (this ).get(SubscriptionViewModel ::class .java)
304- viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let (this ::handleResult) }
305- viewModel.feedGroupsLiveData.observe(viewLifecycleOwner) { it?.let (this ::handleFeedGroups) }
328+ private fun toggleListViewMode () {
329+ viewModel.setListViewMode(! viewModel.getListViewMode())
306330 }
307331
308332 private fun showLongTapDialog (selectedItem : ChannelInfoItem ) {
@@ -346,21 +370,6 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
346370 override fun doInitialLoadLogic () = Unit
347371 override fun startLoading (forceLoad : Boolean ) = Unit
348372
349- private val listenerFeedGroups = object : OnClickGesture <Item <* >> {
350- override fun selected (selectedItem : Item <* >? ) {
351- when (selectedItem) {
352- is FeedGroupCardItem -> NavigationHelper .openFeedFragment(fm, selectedItem.groupId, selectedItem.name)
353- is FeedGroupAddItem -> FeedGroupDialog .newInstance().show(fm, null )
354- }
355- }
356-
357- override fun held (selectedItem : Item <* >? ) {
358- when (selectedItem) {
359- is FeedGroupCardItem -> FeedGroupDialog .newInstance(selectedItem.groupId).show(fm, null )
360- }
361- }
362- }
363-
364373 private val listenerChannelItem = object : OnClickGesture <ChannelInfoItem > {
365374 override fun selected (selectedItem : ChannelInfoItem ) = NavigationHelper .openChannelFragment(
366375 fm,
@@ -403,15 +412,39 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
403412 }
404413
405414 private fun handleFeedGroups (groups : List <Group >) {
406- feedGroupsSection.update(groups )
415+ val listViewMode = viewModel.getListViewMode( )
407416
408- if (feedGroupsListState != null ) {
409- feedGroupsCarousel? .onRestoreInstanceState(feedGroupsListState )
410- feedGroupsListState = null
417+ if (feedGroupsCarouselState != null ) {
418+ feedGroupsCarousel.onRestoreInstanceState(feedGroupsCarouselState )
419+ feedGroupsCarouselState = null
411420 }
412421
413- feedGroupsSortMenuItem.showMenuItem = groups.size > 1
414- binding.itemsList.post { feedGroupsSortMenuItem.notifyChanged(PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM ) }
422+ feedGroupsCarousel.listViewMode = listViewMode
423+ feedGroupsSortMenuItem.showSortButton = groups.size > 1
424+ feedGroupsSortMenuItem.listViewMode = listViewMode
425+ binding.itemsList.post {
426+ if (context == null ) {
427+ // since this part was posted to the next UI cycle, the fragment might have been
428+ // removed in the meantime
429+ return @post
430+ }
431+
432+ feedGroupsCarousel.notifyChanged(FeedGroupCarouselItem .PAYLOAD_UPDATE_LIST_VIEW_MODE )
433+ feedGroupsSortMenuItem.notifyChanged(GroupsHeader .PAYLOAD_UPDATE_ICONS )
434+
435+ // update items here to prevent flickering
436+ carouselAdapter.apply {
437+ clear()
438+ if (listViewMode) {
439+ add(FeedGroupAddNewItem ())
440+ add(FeedGroupCardItem (- 1 , getString(R .string.all), FeedGroupIcon .RSS ))
441+ } else {
442+ add(FeedGroupAddNewGridItem ())
443+ add(FeedGroupCardGridItem (- 1 , getString(R .string.all), FeedGroupIcon .RSS ))
444+ }
445+ addAll(groups)
446+ }
447+ }
415448 }
416449
417450 // /////////////////////////////////////////////////////////////////////////
0 commit comments