Make swtichbar an item of rv (#1817)

This commit is contained in:
LoveSy 2022-04-06 22:54:45 +08:00 committed by GitHub
parent 2cb973656d
commit 81e2b5cfb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 38 deletions

View File

@ -67,6 +67,7 @@ import org.lsposed.manager.App;
import org.lsposed.manager.BuildConfig; import org.lsposed.manager.BuildConfig;
import org.lsposed.manager.ConfigManager; import org.lsposed.manager.ConfigManager;
import org.lsposed.manager.R; import org.lsposed.manager.R;
import org.lsposed.manager.databinding.ItemMasterSwitchBinding;
import org.lsposed.manager.databinding.ItemModuleBinding; import org.lsposed.manager.databinding.ItemModuleBinding;
import org.lsposed.manager.ui.dialog.BlurBehindDialogBuilder; import org.lsposed.manager.ui.dialog.BlurBehindDialogBuilder;
import org.lsposed.manager.ui.fragment.AppListFragment; import org.lsposed.manager.ui.fragment.AppListFragment;
@ -86,6 +87,7 @@ import java.util.stream.Collectors;
import rikka.core.util.ResourceUtils; import rikka.core.util.ResourceUtils;
import rikka.material.app.LocaleDelegate; import rikka.material.app.LocaleDelegate;
import rikka.widget.mainswitchbar.MainSwitchBar;
import rikka.widget.mainswitchbar.OnMainSwitchChangeListener; import rikka.widget.mainswitchbar.OnMainSwitchChangeListener;
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
@ -105,18 +107,43 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter<Scope
private List<AppInfo> showList = new ArrayList<>(); private List<AppInfo> showList = new ArrayList<>();
private List<String> denyList = new ArrayList<>(); private List<String> denyList = new ArrayList<>();
public RecyclerView.Adapter<RecyclerView.ViewHolder> switchAdaptor = new RecyclerView.Adapter<>() {
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new RecyclerView.ViewHolder(ItemMasterSwitchBinding.inflate(activity.getLayoutInflater(), parent, false).masterSwitch) {
};
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
var mainSwitchBar = (MainSwitchBar) holder.itemView;
mainSwitchBar.setChecked(enabled);
mainSwitchBar.addOnSwitchChangeListener(switchBarOnCheckedChangeListener);
// bug of MainSwitchBar, force set the checkedChangeListener
fragment.runOnUiThread(mainSwitchBar::show);
}
@Override
public int getItemCount() {
return 1;
}
};
private final OnMainSwitchChangeListener switchBarOnCheckedChangeListener = new OnMainSwitchChangeListener() { private final OnMainSwitchChangeListener switchBarOnCheckedChangeListener = new OnMainSwitchChangeListener() {
@Override @Override
public void onSwitchChanged(Switch view, boolean isChecked) { public void onSwitchChanged(Switch view, boolean isChecked) {
enabled = isChecked;
if (!moduleUtil.setModuleEnabled(module.packageName, isChecked)) { if (!moduleUtil.setModuleEnabled(module.packageName, isChecked)) {
view.setChecked(!isChecked); view.setChecked(!isChecked);
enabled = !isChecked;
} }
var tmpChkList = new HashSet<>(checkedList); var tmpChkList = new HashSet<>(checkedList);
if (isChecked && !tmpChkList.isEmpty() && !ConfigManager.setModuleScope(module.packageName, tmpChkList)) { if (isChecked && !tmpChkList.isEmpty() && !ConfigManager.setModuleScope(module.packageName, tmpChkList)) {
view.setChecked(false); view.setChecked(false);
enabled = false;
} }
enabled = isChecked; fragment.runOnUiThread(ScopeAdapter.this::notifyDataSetChanged);
notifyDataSetChanged();
} }
}; };
@ -205,7 +232,7 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter<Scope
} }
private void checkRecommended() { private void checkRecommended() {
if (!fragment.binding.masterSwitch.isChecked()) { if (!enabled) {
fragment.showHint(R.string.module_is_not_activated_yet, false); fragment.showHint(R.string.module_is_not_activated_yet, false);
return; return;
} }
@ -359,7 +386,9 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter<Scope
@Override @Override
public void onViewRecycled(@NonNull ViewHolder holder) { public void onViewRecycled(@NonNull ViewHolder holder) {
holder.checkbox.setOnCheckedChangeListener(null); if (holder.checkbox != null) {
holder.checkbox.setOnCheckedChangeListener(null);
}
super.onViewRecycled(holder); super.onViewRecycled(holder);
} }
@ -480,9 +509,6 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter<Scope
public void refresh(boolean force) { public void refresh(boolean force) {
setLoaded(null, false); setLoaded(null, false);
enabled = moduleUtil.isModuleEnabled(module.packageName); enabled = moduleUtil.isModuleEnabled(module.packageName);
fragment.binding.masterSwitch.addOnSwitchChangeListener(null);
fragment.binding.masterSwitch.setChecked(enabled);
fragment.binding.masterSwitch.addOnSwitchChangeListener(switchBarOnCheckedChangeListener);
fragment.runAsync(() -> { fragment.runAsync(() -> {
List<PackageInfo> appList = AppHelper.getAppList(force); List<PackageInfo> appList = AppHelper.getAppList(force);
denyList = AppHelper.getDenyList(force); denyList = AppHelper.getDenyList(force);
@ -640,7 +666,7 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter<Scope
public void onBackPressed() { public void onBackPressed() {
fragment.searchView.clearFocus(); fragment.searchView.clearFocus();
if (isLoaded && fragment.binding.masterSwitch.isChecked() && checkedList.isEmpty()) { if (isLoaded && enabled && checkedList.isEmpty()) {
var builder = new BlurBehindDialogBuilder(activity); var builder = new BlurBehindDialogBuilder(activity);
builder.setMessage(!recommendedList.isEmpty() ? R.string.no_scope_selected_has_recommended : R.string.no_scope_selected); builder.setMessage(!recommendedList.isEmpty() ? R.string.no_scope_selected_has_recommended : R.string.no_scope_selected);
if (!recommendedList.isEmpty()) { if (!recommendedList.isEmpty()) {

View File

@ -33,6 +33,7 @@ import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.SearchView;
import androidx.recyclerview.widget.ConcatAdapter;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -87,7 +88,10 @@ public class AppListFragment extends BaseFragment {
scopeAdapter = new ScopeAdapter(this, module); scopeAdapter = new ScopeAdapter(this, module);
scopeAdapter.setHasStableIds(true); scopeAdapter.setHasStableIds(true);
scopeAdapter.registerAdapterDataObserver(observer); scopeAdapter.registerAdapterDataObserver(observer);
binding.recyclerView.setAdapter(scopeAdapter); var concatAdapter = new ConcatAdapter();
concatAdapter.addAdapter(scopeAdapter.switchAdaptor);
concatAdapter.addAdapter(scopeAdapter);
binding.recyclerView.setAdapter(concatAdapter);
binding.recyclerView.setHasFixedSize(true); binding.recyclerView.setHasFixedSize(true);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(requireActivity())); binding.recyclerView.setLayoutManager(new LinearLayoutManager(requireActivity()));
binding.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setLifted(!top)); binding.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setLifted(!top));

View File

@ -29,6 +29,7 @@ import android.util.AttributeSet;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.recyclerview.widget.ConcatAdapter;
import org.lsposed.manager.R; import org.lsposed.manager.R;
import org.lsposed.manager.util.SimpleStatefulAdaptor; import org.lsposed.manager.util.SimpleStatefulAdaptor;
@ -61,6 +62,14 @@ public class EmptyStateRecyclerView extends StatefulRecyclerView {
protected void dispatchDraw(Canvas canvas) { protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas); super.dispatchDraw(canvas);
var adapter = getAdapter(); var adapter = getAdapter();
if (adapter instanceof ConcatAdapter) {
for (var a : ((ConcatAdapter) adapter).getAdapters()) {
if (a instanceof EmptyStateAdapter) {
adapter = a;
break;
}
}
}
if (adapter instanceof EmptyStateAdapter && ((EmptyStateAdapter<?>) adapter).isLoaded() && adapter.getItemCount() == 0) { if (adapter instanceof EmptyStateAdapter && ((EmptyStateAdapter<?>) adapter).isLoaded() && adapter.getItemCount() == 0) {
final int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); final int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
final int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); final int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();

View File

@ -74,41 +74,29 @@
app:layout_fitsSystemWindowsInsets="@integer/internal_fragment_bottom_insets" app:layout_fitsSystemWindowsInsets="@integer/internal_fragment_bottom_insets"
app:tint="?attr/colorOnPrimary" /> app:tint="?attr/colorOnPrimary" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <LinearLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.core.widget.NestedScrollView <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <org.lsposed.manager.ui.widget.EmptyStateRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:orientation="vertical"> android:clipToPadding="false"
android:fadeScrollbars="true"
<rikka.widget.mainswitchbar.MainSwitchBar android:scrollbarStyle="insideOverlay"
android:id="@+id/master_switch" android:scrollbars="vertical"
android:layout_width="match_parent" app:borderBottomVisibility="never"
android:layout_height="wrap_content" app:borderTopDrawable="@null"
android:fillViewport="true" app:borderTopVisibility="whenTop"
android:text="@string/enable_module" /> app:fitsSystemWindowsInsets="@integer/internal_fragment_bottom_insets" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<org.lsposed.manager.ui.widget.EmptyStateRecyclerView </LinearLayout>
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:fadeScrollbars="true"
android:scrollbarStyle="insideOverlay"
android:scrollbars="vertical"
app:borderBottomVisibility="never"
app:borderTopDrawable="@null"
app:borderTopVisibility="whenTop"
app:fitsSystemWindowsInsets="@integer/internal_fragment_bottom_insets" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<rikka.widget.mainswitchbar.MainSwitchBar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/master_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/enable_module" />