Separate ExpandableViewHolder

This commit is contained in:
topjohnwu 2019-01-28 14:51:29 -05:00
parent 18ab6b51fd
commit 976c299657
5 changed files with 113 additions and 142 deletions

View File

@ -15,7 +15,7 @@ import com.topjohnwu.core.container.Policy;
import com.topjohnwu.core.database.MagiskDB; import com.topjohnwu.core.database.MagiskDB;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.CustomAlertDialog; import com.topjohnwu.magisk.components.CustomAlertDialog;
import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.ExpandableViewHolder;
import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.FingerprintHelper; import com.topjohnwu.magisk.utils.FingerprintHelper;
@ -51,13 +51,13 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
public void onBindViewHolder(ViewHolder holder, int position) { public void onBindViewHolder(ViewHolder holder, int position) {
Policy policy = policyList.get(position); Policy policy = policyList.get(position);
holder.setExpanded(expandList[position]); holder.settings.setExpanded(expandList[position]);
holder.trigger.setOnClickListener(view -> { holder.trigger.setOnClickListener(view -> {
if (holder.isExpanded()) { if (holder.settings.isExpanded()) {
holder.collapse(); holder.settings.collapse();
expandList[position] = false; expandList[position] = false;
} else { } else {
holder.expand(); holder.settings.expand();
expandList[position] = true; expandList[position] = true;
} }
}); });
@ -136,7 +136,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
return policyList.size(); return policyList.size();
} }
static class ViewHolder extends RecyclerView.ViewHolder implements ExpandableView { static class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.app_name) TextView appName; @BindView(R.id.app_name) TextView appName;
@BindView(R.id.package_name) TextView packageName; @BindView(R.id.package_name) TextView packageName;
@ -150,24 +150,32 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
@BindView(R.id.delete) ImageView delete; @BindView(R.id.delete) ImageView delete;
@BindView(R.id.more_info) ImageView moreInfo; @BindView(R.id.more_info) ImageView moreInfo;
private Container container = new Container(); ExpandableViewHolder settings;
public ViewHolder(View itemView) { public ViewHolder(View itemView) {
super(itemView); super(itemView);
new PolicyAdapter$ViewHolder_ViewBinding(this, itemView); new PolicyAdapter$ViewHolder_ViewBinding(this, itemView);
container.expandLayout = expandLayout; settings = new ExpandableViewHolder(expandLayout) {
setupExpandable(); @Override
} public void setExpanded(boolean expanded) {
super.setExpanded(expanded);
arrow.setRotation(expanded ? 180 : 0);
}
@Override @Override
public Container getContainer() { public void expand() {
return container; super.expand();
} setRotate(new RotateAnimation(0, 180,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f));
}
@Override @Override
public void setExpanded(boolean expanded) { public void collapse() {
ExpandableView.super.setExpanded(expanded); super.collapse();
arrow.setRotation(expanded ? 180 : 0); setRotate(new RotateAnimation(180, 0,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f));
}
};
} }
private void setRotate(RotateAnimation rotate) { private void setRotate(RotateAnimation rotate) {
@ -175,19 +183,5 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
rotate.setFillAfter(true); rotate.setFillAfter(true);
arrow.startAnimation(rotate); arrow.startAnimation(rotate);
} }
@Override
public void expand() {
ExpandableView.super.expand();
setRotate(new RotateAnimation(0, 180,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f));
}
@Override
public void collapse() {
ExpandableView.super.collapse();
setRotate(new RotateAnimation(180, 0,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f));
}
} }
} }

View File

@ -12,7 +12,7 @@ import android.widget.TextView;
import com.topjohnwu.core.container.SuLogEntry; import com.topjohnwu.core.container.SuLogEntry;
import com.topjohnwu.core.database.MagiskDB; import com.topjohnwu.core.database.MagiskDB;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.ExpandableViewHolder;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@ -84,13 +84,13 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
public void onBindItemViewHolder(LogViewHolder holder, int section, int position) { public void onBindItemViewHolder(LogViewHolder holder, int section, int position) {
SuLogEntry entry = logEntries.get(section).get(position); SuLogEntry entry = logEntries.get(section).get(position);
int realIdx = getItemPosition(section, position); int realIdx = getItemPosition(section, position);
holder.setExpanded(itemExpanded.contains(realIdx)); holder.expandable.setExpanded(itemExpanded.contains(realIdx));
holder.itemView.setOnClickListener(view -> { holder.itemView.setOnClickListener(view -> {
if (holder.isExpanded()) { if (holder.expandable.isExpanded()) {
holder.collapse(); holder.expandable.collapse();
itemExpanded.remove(realIdx); itemExpanded.remove(realIdx);
} else { } else {
holder.expand(); holder.expandable.expand();
itemExpanded.add(realIdx); itemExpanded.add(realIdx);
} }
}); });
@ -122,7 +122,7 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
} }
} }
static class LogViewHolder extends RecyclerView.ViewHolder implements ExpandableView { static class LogViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.app_name) TextView appName; @BindView(R.id.app_name) TextView appName;
@BindView(R.id.action) TextView action; @BindView(R.id.action) TextView action;
@ -132,18 +132,12 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
@BindView(R.id.cmd) TextView command; @BindView(R.id.cmd) TextView command;
@BindView(R.id.expand_layout) ViewGroup expandLayout; @BindView(R.id.expand_layout) ViewGroup expandLayout;
private Container container = new Container(); ExpandableViewHolder expandable;
LogViewHolder(View itemView) { LogViewHolder(View itemView) {
super(itemView); super(itemView);
new SuLogAdapter$LogViewHolder_ViewBinding(this, itemView); new SuLogAdapter$LogViewHolder_ViewBinding(this, itemView);
container.expandLayout = expandLayout; expandable = new ExpandableViewHolder(expandLayout);
setupExpandable();
}
@Override
public Container getContainer() {
return container;
} }
} }
} }

View File

@ -1,83 +0,0 @@
package com.topjohnwu.magisk.components;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
public interface ExpandableView {
class Container {
public ViewGroup expandLayout;
ValueAnimator expandAnimator, collapseAnimator;
boolean mExpanded = false;
int expandHeight = 0;
}
// Provide state info
Container getContainer();
default void setupExpandable() {
Container container = getContainer();
setExpanded(false);
container.expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (container.expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
container.expandLayout.measure(widthSpec, heightSpec);
container.expandHeight = container.expandLayout.getMeasuredHeight();
}
container.expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
container.expandAnimator = slideAnimator(0, container.expandHeight);
container.collapseAnimator = slideAnimator(container.expandHeight, 0);
return true;
}
});
}
default boolean isExpanded() {
return getContainer().mExpanded;
}
default void setExpanded(boolean expanded) {
Container container = getContainer();
container.mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = container.expandLayout.getLayoutParams();
layoutParams.height = expanded ? container.expandHeight : 0;
container.expandLayout.setLayoutParams(layoutParams);
}
default void expand() {
Container container = getContainer();
if (container.mExpanded) return;
container.expandLayout.setVisibility(View.VISIBLE);
container.expandAnimator.start();
container.mExpanded = true;
}
default void collapse() {
Container container = getContainer();
if (!container.mExpanded) return;
container.collapseAnimator.start();
container.mExpanded = false;
}
default ValueAnimator slideAnimator(int start, int end) {
Container container = getContainer();
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = container.expandLayout.getLayoutParams();
layoutParams.height = value;
container.expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
}

View File

@ -0,0 +1,72 @@
package com.topjohnwu.magisk.components;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
public class ExpandableViewHolder {
private ViewGroup expandLayout;
private ValueAnimator expandAnimator, collapseAnimator;
private boolean mExpanded = false;
private int expandHeight = 0;
public ExpandableViewHolder(ViewGroup viewGroup) {
expandLayout = viewGroup;
setExpanded(false);
expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
expandLayout.measure(0, 0);
expandHeight = expandLayout.getMeasuredHeight();
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
expandAnimator = slideAnimator(0, expandHeight);
collapseAnimator = slideAnimator(expandHeight, 0);
return true;
}
});
}
public boolean isExpanded() {
return mExpanded;
}
public void setExpanded(boolean expanded) {
mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = expanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
}
public void expand() {
if (mExpanded) return;
expandLayout.setVisibility(View.VISIBLE);
expandAnimator.start();
mExpanded = true;
}
public void collapse() {
if (!mExpanded) return;
collapseAnimator.start();
mExpanded = false;
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
}

View File

@ -24,7 +24,7 @@ import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.components.BaseFragment; import com.topjohnwu.magisk.components.BaseFragment;
import com.topjohnwu.magisk.components.CustomAlertDialog; import com.topjohnwu.magisk.components.CustomAlertDialog;
import com.topjohnwu.magisk.components.EnvFixDialog; import com.topjohnwu.magisk.components.EnvFixDialog;
import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.ExpandableViewHolder;
import com.topjohnwu.magisk.components.MagiskInstallDialog; import com.topjohnwu.magisk.components.MagiskInstallDialog;
import com.topjohnwu.magisk.components.ManagerInstallDialog; import com.topjohnwu.magisk.components.ManagerInstallDialog;
import com.topjohnwu.magisk.components.UninstallDialog; import com.topjohnwu.magisk.components.UninstallDialog;
@ -50,9 +50,8 @@ import butterknife.BindView;
import butterknife.OnClick; import butterknife.OnClick;
public class MagiskFragment extends BaseFragment public class MagiskFragment extends BaseFragment
implements SwipeRefreshLayout.OnRefreshListener, ExpandableView, Topic.Subscriber { implements SwipeRefreshLayout.OnRefreshListener, Topic.Subscriber {
private Container expandableContainer = new Container();
private static boolean shownDialog = false; private static boolean shownDialog = false;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@ -83,6 +82,7 @@ public class MagiskFragment extends BaseFragment
private UpdateCardHolder magisk; private UpdateCardHolder magisk;
private UpdateCardHolder manager; private UpdateCardHolder manager;
private ExpandableViewHolder snExpandableHolder;
private Transition transition; private Transition transition;
@OnClick(R.id.safetyNet_title) @OnClick(R.id.safetyNet_title)
@ -92,7 +92,7 @@ public class MagiskFragment extends BaseFragment
safetyNetRefreshIcon.setVisibility(View.GONE); safetyNetRefreshIcon.setVisibility(View.GONE);
safetyNetStatusText.setText(R.string.checking_safetyNet_status); safetyNetStatusText.setText(R.string.checking_safetyNet_status);
SafetyNet.check(requireActivity()); SafetyNet.check(requireActivity());
collapse(); snExpandableHolder.collapse();
}; };
if (!SafetyNet.EXT_APK.exists()) { if (!SafetyNet.EXT_APK.exists()) {
// Show dialog // Show dialog
@ -134,8 +134,7 @@ public class MagiskFragment extends BaseFragment
unbinder = new MagiskFragment_ViewBinding(this, v); unbinder = new MagiskFragment_ViewBinding(this, v);
requireActivity().setTitle(R.string.magisk); requireActivity().setTitle(R.string.magisk);
expandableContainer.expandLayout = expandLayout; snExpandableHolder = new ExpandableViewHolder(expandLayout);
setupExpandable();
magisk = new UpdateCardHolder(inflater, root); magisk = new UpdateCardHolder(inflater, root);
manager = new UpdateCardHolder(inflater, root); manager = new UpdateCardHolder(inflater, root);
@ -168,7 +167,7 @@ public class MagiskFragment extends BaseFragment
@Override @Override
public void onRefresh() { public void onRefresh() {
safetyNetStatusText.setText(R.string.safetyNet_check_text); safetyNetStatusText.setText(R.string.safetyNet_check_text);
setExpanded(false); snExpandableHolder.setExpanded(false);
mSwipeRefreshLayout.setRefreshing(false); mSwipeRefreshLayout.setRefreshing(false);
TransitionManager.beginDelayedTransition(root, transition); TransitionManager.beginDelayedTransition(root, transition);
@ -207,11 +206,6 @@ public class MagiskFragment extends BaseFragment
} }
} }
@Override
public Container getContainer() {
return expandableContainer;
}
private boolean hasGms() { private boolean hasGms() {
PackageManager pm = app.getPackageManager(); PackageManager pm = app.getPackageManager();
PackageInfo info; PackageInfo info;
@ -352,7 +346,7 @@ public class MagiskFragment extends BaseFragment
basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel); basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
basicStatusIcon.setColorFilter(b ? colorOK : colorBad); basicStatusIcon.setColorFilter(b ? colorOK : colorBad);
expand(); snExpandableHolder.expand();
} else { } else {
@StringRes int resid; @StringRes int resid;
switch (response) { switch (response) {