Extract LatestLayoutPolicy class from LatestAdapter

The policy class decides which item view types to show.

See issue #2650.
This commit is contained in:
Henrik Tunedal
2023-07-12 01:20:57 +02:00
committed by Torsten Grote
parent e97a0c0f70
commit c2cd43a822
3 changed files with 110 additions and 82 deletions

View File

@@ -1,20 +1,12 @@
package org.fdroid.fdroid.views.main;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.fdroid.database.AppOverviewItem;
import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.categories.AppCardController;
@@ -24,11 +16,15 @@ public class LatestAdapter extends RecyclerView.Adapter<AppCardController> {
private List<AppOverviewItem> apps;
private final AppCompatActivity activity;
private final LatestLayoutPolicy layoutPolicy;
private final RecyclerView.ItemDecoration appListDecorator;
private final GridLayoutManager.SpanSizeLookup spanSizeLookup;
LatestAdapter(AppCompatActivity activity) {
this.activity = activity;
appListDecorator = new LatestAdapter.ItemDecorator(activity);
layoutPolicy = new LatestLayoutPolicy(activity);
appListDecorator = layoutPolicy.getItemDecoration();
spanSizeLookup = new SpanSizeLookup(layoutPolicy);
}
@Override
@@ -66,33 +62,7 @@ public class LatestAdapter extends RecyclerView.Adapter<AppCardController> {
@Override
public int getItemViewType(int position) {
int relativePositionInCycle = position % 5;
if (BuildConfig.FLAVOR.startsWith("basic")) {
if (relativePositionInCycle > 0) {
return R.id.latest_small_tile;
} else {
return R.id.latest_regular_list;
}
}
if (position == 0) {
return R.id.latest_regular_list;
} else {
switch (relativePositionInCycle) {
case 1:
case 2:
return R.id.latest_large_tile;
case 3:
case 4:
return R.id.latest_small_tile;
case 0:
default:
return R.id.latest_regular_list;
}
}
return layoutPolicy.getItemViewType(position);
}
@Override
@@ -115,57 +85,20 @@ public class LatestAdapter extends RecyclerView.Adapter<AppCardController> {
notifyDataSetChanged();
}
public static class SpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
@Override
public int getSpanSize(int position) {
int relativePositionInCycle = position % 5;
if (relativePositionInCycle == 0) {
return 2;
} else {
return 1;
}
}
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup() {
return spanSizeLookup;
}
/**
* Applies padding to items, ensuring that the spacing on the left, centre, and right all match.
* The vertical padding is slightly shorter than the horizontal padding also.
*
* @see org.fdroid.fdroid.R.dimen#latest__padding__app_card__horizontal
* @see org.fdroid.fdroid.R.dimen#latest__padding__app_card__vertical
*/
private static class ItemDecorator extends RecyclerView.ItemDecoration {
private final Context context;
private static final class SpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
private final LatestLayoutPolicy layoutPolicy;
ItemDecorator(Context context) {
this.context = context.getApplicationContext();
private SpanSizeLookup(LatestLayoutPolicy layoutPolicy) {
this.layoutPolicy = layoutPolicy;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, RecyclerView parent,
@NonNull RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
Resources resources = context.getResources();
int horizontalPadding = (int) resources.getDimension(R.dimen.latest__padding__app_card__horizontal);
int verticalPadding = (int) resources.getDimension(R.dimen.latest__padding__app_card__vertical);
int relativePositionInCycle = position % 5;
if (position == 0) {
outRect.set(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
} else if (relativePositionInCycle != 0) {
// The item on the left will have both left and right padding. The item on the right
// will only have padding on the right. This will allow the same amount of padding
// on the left, centre, and right of the grid, rather than double the padding in the
// middle (which would happen if both left and right padding was set for both items).
boolean isLtr = ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_LTR;
boolean isAtStart = relativePositionInCycle == 1 || relativePositionInCycle == 3;
int paddingStart = isAtStart ? horizontalPadding : 0;
int paddingLeft = isLtr ? paddingStart : horizontalPadding;
int paddingRight = isLtr ? horizontalPadding : paddingStart;
outRect.set(paddingLeft, 0, paddingRight, verticalPadding);
} else {
outRect.set(horizontalPadding, 0, horizontalPadding, verticalPadding);
}
public int getSpanSize(int position) {
return layoutPolicy.getSpanSize(position);
}
}
}

View File

@@ -0,0 +1,95 @@
package org.fdroid.fdroid.views.main;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import org.fdroid.fdroid.R;
public class LatestLayoutPolicy {
private final Context context;
public LatestLayoutPolicy(Context context) {
this.context = context.getApplicationContext();
}
public RecyclerView.ItemDecoration getItemDecoration() {
return new ItemDecorator(context);
}
public int getItemViewType(int position) {
int relativePositionInCycle = position % 5;
if (position == 0) {
return R.id.latest_regular_list;
} else {
switch (relativePositionInCycle) {
case 1:
case 2:
return R.id.latest_large_tile;
case 3:
case 4:
return R.id.latest_small_tile;
case 0:
default:
return R.id.latest_regular_list;
}
}
}
public int getSpanSize(int position) {
int relativePositionInCycle = position % 5;
if (relativePositionInCycle == 0) {
return 2;
} else {
return 1;
}
}
/**
* Applies padding to items, ensuring that the spacing on the left, centre, and right all match.
* The vertical padding is slightly shorter than the horizontal padding also.
*
* @see org.fdroid.fdroid.R.dimen#latest__padding__app_card__horizontal
* @see org.fdroid.fdroid.R.dimen#latest__padding__app_card__vertical
*/
private static class ItemDecorator extends RecyclerView.ItemDecoration {
private final Context context;
ItemDecorator(Context context) {
this.context = context.getApplicationContext();
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, RecyclerView parent,
@NonNull RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
Resources resources = context.getResources();
int horizontalPadding = (int) resources.getDimension(R.dimen.latest__padding__app_card__horizontal);
int verticalPadding = (int) resources.getDimension(R.dimen.latest__padding__app_card__vertical);
int relativePositionInCycle = position % 5;
if (position == 0) {
outRect.set(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
} else if (relativePositionInCycle != 0) {
// The item on the left will have both left and right padding. The item on the right
// will only have padding on the right. This will allow the same amount of padding
// on the left, centre, and right of the grid, rather than double the padding in the
// middle (which would happen if both left and right padding was set for both items).
boolean isLtr = ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_LTR;
boolean isAtStart = relativePositionInCycle == 1 || relativePositionInCycle == 3;
int paddingStart = isAtStart ? horizontalPadding : 0;
int paddingLeft = isLtr ? paddingStart : horizontalPadding;
int paddingRight = isLtr ? horizontalPadding : paddingStart;
outRect.set(paddingLeft, 0, paddingRight, verticalPadding);
} else {
outRect.set(horizontalPadding, 0, horizontalPadding, verticalPadding);
}
}
}
}

View File

@@ -72,7 +72,7 @@ class LatestViewBinder implements Observer<List<AppOverviewItem>>, ChangeListene
latestAdapter = new LatestAdapter(activity);
GridLayoutManager layoutManager = new GridLayoutManager(activity, 2);
layoutManager.setSpanSizeLookup(new LatestAdapter.SpanSizeLookup());
layoutManager.setSpanSizeLookup(latestAdapter.getSpanSizeLookup());
emptyState = latestView.findViewById(R.id.empty_state);