Fix grid span count calculation; remove duplicate methods

This commit is contained in:
Stypox 2021-07-19 20:47:50 +02:00
parent b795c5f017
commit a7dd3af4e5
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
5 changed files with 52 additions and 84 deletions

View File

@ -1,7 +1,6 @@
package org.schabi.newpipe.local; package org.schabi.newpipe.local;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
@ -26,6 +25,7 @@ import org.schabi.newpipe.fragments.list.ListViewContract;
import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling; import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
/** /**
* This fragment is design to be used with persistent data such as * This fragment is design to be used with persistent data such as
@ -77,7 +77,7 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
super.onResume(); super.onResume();
if (updateFlags != 0) { if (updateFlags != 0) {
if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) { if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
final boolean useGrid = isGridLayout(); final boolean useGrid = shouldUseGridLayout(requireContext());
itemsList.setLayoutManager( itemsList.setLayoutManager(
useGrid ? getGridLayoutManager() : getListLayoutManager()); useGrid ? getGridLayoutManager() : getListLayoutManager());
itemListAdapter.setUseGridVariant(useGrid); itemListAdapter.setUseGridVariant(useGrid);
@ -121,7 +121,7 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
itemListAdapter = new LocalItemListAdapter(activity); itemListAdapter = new LocalItemListAdapter(activity);
final boolean useGrid = isGridLayout(); final boolean useGrid = shouldUseGridLayout(requireContext());
itemsList = rootView.findViewById(R.id.items_list); itemsList = rootView.findViewById(R.id.items_list);
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager()); itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
@ -260,17 +260,4 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
updateFlags |= LIST_MODE_UPDATE_FLAG; updateFlags |= LIST_MODE_UPDATE_FLAG;
} }
} }
protected boolean isGridLayout() {
final String listMode = PreferenceManager.getDefaultSharedPreferences(activity)
.getString(getString(R.string.list_view_mode_key),
getString(R.string.list_view_mode_value));
if ("auto".equals(listMode)) {
final Configuration configuration = getResources().getConfiguration();
return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
&& configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
} else {
return "grid".equals(listMode);
}
}
} }

View File

@ -23,7 +23,6 @@ import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.LayoutInflater import android.view.LayoutInflater
@ -74,10 +73,10 @@ import org.schabi.newpipe.player.helper.PlayerHolder
import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.NavigationHelper import org.schabi.newpipe.util.NavigationHelper
import org.schabi.newpipe.util.StreamDialogEntry import org.schabi.newpipe.util.StreamDialogEntry
import org.schabi.newpipe.util.ThemeHelper.getGridSpanCount
import org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout
import java.time.OffsetDateTime import java.time.OffsetDateTime
import java.util.ArrayList import java.util.ArrayList
import kotlin.math.floor
import kotlin.math.max
class FeedFragment : BaseStateFragment<FeedState>() { class FeedFragment : BaseStateFragment<FeedState>() {
private var _feedBinding: FragmentFeedBinding? = null private var _feedBinding: FragmentFeedBinding? = null
@ -161,7 +160,7 @@ class FeedFragment : BaseStateFragment<FeedState>() {
fun setupListViewMode() { fun setupListViewMode() {
// does everything needed to setup the layouts for grid or list modes // does everything needed to setup the layouts for grid or list modes
groupAdapter.spanCount = if (shouldUseGridLayout()) getGridSpanCount() else 1 groupAdapter.spanCount = if (shouldUseGridLayout(context)) getGridSpanCount(context) else 1
feedBinding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply { feedBinding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply {
spanSizeLookup = groupAdapter.spanSizeLookup spanSizeLookup = groupAdapter.spanSizeLookup
} }
@ -384,7 +383,7 @@ class FeedFragment : BaseStateFragment<FeedState>() {
@SuppressLint("StringFormatMatches") @SuppressLint("StringFormatMatches")
private fun handleLoadedState(loadedState: FeedState.LoadedState) { private fun handleLoadedState(loadedState: FeedState.LoadedState) {
val itemVersion = if (shouldUseGridLayout()) { val itemVersion = if (shouldUseGridLayout(context)) {
StreamItem.ItemVersion.GRID StreamItem.ItemVersion.GRID
} else { } else {
StreamItem.ItemVersion.NORMAL StreamItem.ItemVersion.NORMAL
@ -528,35 +527,6 @@ class FeedFragment : BaseStateFragment<FeedState>() {
listState = null listState = null
} }
// /////////////////////////////////////////////////////////////////////////
// Grid Mode
// /////////////////////////////////////////////////////////////////////////
// TODO: Move these out of this class, as it can be reused
private fun shouldUseGridLayout(): Boolean {
val listMode = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value))
return when (listMode) {
getString(R.string.list_view_mode_auto_key) -> {
val configuration = resources.configuration
(
configuration.orientation == Configuration.ORIENTATION_LANDSCAPE &&
configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)
)
}
getString(R.string.list_view_mode_grid_key) -> true
else -> false
}
}
private fun getGridSpanCount(): Int {
val minWidth = resources.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width)
return max(1, floor(resources.displayMetrics.widthPixels / minWidth.toDouble()).toInt())
}
companion object { companion object {
const val KEY_GROUP_ID = "ARG_GROUP_ID" const val KEY_GROUP_ID = "ARG_GROUP_ID"
const val KEY_GROUP_NAME = "ARG_GROUP_NAME" const val KEY_GROUP_NAME = "ARG_GROUP_NAME"

View File

@ -68,6 +68,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> { public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> {
// Save the list 10 seconds after the last change occurred // Save the list 10 seconds after the last change occurred
@ -678,7 +679,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
private ItemTouchHelper.SimpleCallback getItemTouchCallback() { private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
int directions = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int directions = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
if (isGridLayout()) { if (shouldUseGridLayout(requireContext())) {
directions |= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; directions |= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
} }
return new ItemTouchHelper.SimpleCallback(directions, return new ItemTouchHelper.SimpleCallback(directions,

View File

@ -6,7 +6,6 @@ import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.LayoutInflater import android.view.LayoutInflater
@ -20,7 +19,6 @@ import androidx.activity.result.contract.ActivityResultContracts.StartActivityFo
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.xwray.groupie.Group import com.xwray.groupie.Group
import com.xwray.groupie.GroupAdapter import com.xwray.groupie.GroupAdapter
@ -60,12 +58,12 @@ import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService
import org.schabi.newpipe.streams.io.StoredFileHelper import org.schabi.newpipe.streams.io.StoredFileHelper
import org.schabi.newpipe.util.NavigationHelper import org.schabi.newpipe.util.NavigationHelper
import org.schabi.newpipe.util.OnClickGesture import org.schabi.newpipe.util.OnClickGesture
import org.schabi.newpipe.util.ThemeHelper.getGridSpanCount
import org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout
import org.schabi.newpipe.util.external_communication.ShareUtils import org.schabi.newpipe.util.external_communication.ShareUtils
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import kotlin.math.floor
import kotlin.math.max
class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
private var _binding: FragmentSubscriptionBinding? = null private var _binding: FragmentSubscriptionBinding? = null
@ -279,8 +277,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
super.initViews(rootView, savedInstanceState) super.initViews(rootView, savedInstanceState)
_binding = FragmentSubscriptionBinding.bind(rootView) _binding = FragmentSubscriptionBinding.bind(rootView)
val shouldUseGridLayout = shouldUseGridLayout() groupAdapter.spanCount = if (shouldUseGridLayout(context)) getGridSpanCount(context) else 1
groupAdapter.spanCount = if (shouldUseGridLayout) getGridSpanCount() else 1
binding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply { binding.itemsList.layoutManager = GridLayoutManager(requireContext(), groupAdapter.spanCount).apply {
spanSizeLookup = groupAdapter.spanSizeLookup spanSizeLookup = groupAdapter.spanSizeLookup
} }
@ -359,7 +356,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
override fun handleResult(result: SubscriptionState) { override fun handleResult(result: SubscriptionState) {
super.handleResult(result) super.handleResult(result)
val shouldUseGridLayout = shouldUseGridLayout() val shouldUseGridLayout = shouldUseGridLayout(context)
when (result) { when (result) {
is SubscriptionState.LoadedState -> { is SubscriptionState.LoadedState -> {
result.subscriptions.forEach { result.subscriptions.forEach {
@ -420,30 +417,4 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
super.hideLoading() super.hideLoading()
binding.itemsList.animate(true, 200) binding.itemsList.animate(true, 200)
} }
// /////////////////////////////////////////////////////////////////////////
// Grid Mode
// /////////////////////////////////////////////////////////////////////////
// TODO: Move these out of this class, as it can be reused
private fun shouldUseGridLayout(): Boolean {
val listMode = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value))
return when (listMode) {
getString(R.string.list_view_mode_auto_key) -> {
val configuration = resources.configuration
configuration.orientation == Configuration.ORIENTATION_LANDSCAPE &&
configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)
}
getString(R.string.list_view_mode_grid_key) -> true
else -> false
}
}
private fun getGridSpanCount(): Int {
val minWidth = resources.getDimensionPixelSize(R.dimen.channel_item_grid_min_width)
return max(1, floor(resources.displayMetrics.widthPixels / minWidth.toDouble()).toInt())
}
} }

View File

@ -298,4 +298,43 @@ public final class ThemeHelper {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
} }
} }
/**
* Returns whether the grid layout or the list layout should be used. If the user set "auto"
* mode in settings, decides based on screen orientation (landscape) and size.
*
* @param context the context to use
* @return true:use grid layout, false:use list layout
*/
public static boolean shouldUseGridLayout(final Context context) {
final String listMode = PreferenceManager.getDefaultSharedPreferences(context)
.getString(context.getString(R.string.list_view_mode_key),
context.getString(R.string.list_view_mode_value));
if (listMode.equals(context.getString(R.string.list_view_mode_list_key))) {
return false;
} else if (listMode.equals(context.getString(R.string.list_view_mode_grid_key))) {
return true;
} else {
final Configuration configuration = context.getResources().getConfiguration();
return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
&& configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
}
}
/**
* Calculates the number of grid items that can fit horizontally on the screen. The width of a
* grid item is obtained from the thumbnail width plus the right and left paddings.
*
* @param context the context to use
* @return the span count of grid list items
*/
public static int getGridSpanCount(final Context context) {
final Resources res = context.getResources();
final int minWidth
= res.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width)
+ res.getDimensionPixelSize(R.dimen.video_item_search_padding) * 2;
return Math.max(1, res.getDisplayMetrics().widthPixels / minWidth);
}
} }