Add master switch for scope list
This commit is contained in:
parent
ec08cc85e6
commit
840d54cccf
|
|
@ -16,14 +16,14 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import org.meowcat.edxposed.manager.adapters.AppAdapter;
|
import org.meowcat.edxposed.manager.adapters.AppAdapter;
|
||||||
import org.meowcat.edxposed.manager.adapters.AppHelper;
|
import org.meowcat.edxposed.manager.adapters.AppHelper;
|
||||||
import org.meowcat.edxposed.manager.adapters.ScopeAdapter;
|
import org.meowcat.edxposed.manager.adapters.ScopeAdapter;
|
||||||
import org.meowcat.edxposed.manager.databinding.ActivityBlackListBinding;
|
import org.meowcat.edxposed.manager.databinding.ActivityScopeListBinding;
|
||||||
|
|
||||||
public class ModuleScopeActivity extends BaseActivity implements AppAdapter.Callback {
|
public class ModuleScopeActivity extends BaseActivity implements AppAdapter.Callback {
|
||||||
private SearchView searchView;
|
private SearchView searchView;
|
||||||
private AppAdapter appAdapter;
|
private ScopeAdapter appAdapter;
|
||||||
|
|
||||||
private SearchView.OnQueryTextListener searchListener;
|
private SearchView.OnQueryTextListener searchListener;
|
||||||
private ActivityBlackListBinding binding;
|
private ActivityScopeListBinding binding;
|
||||||
private final Runnable runnable = new Runnable() {
|
private final Runnable runnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
@ -37,7 +37,7 @@ public class ModuleScopeActivity extends BaseActivity implements AppAdapter.Call
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
String modulePackageName = getIntent().getStringExtra("modulePackageName");
|
String modulePackageName = getIntent().getStringExtra("modulePackageName");
|
||||||
String moduleName = getIntent().getStringExtra("moduleName");
|
String moduleName = getIntent().getStringExtra("moduleName");
|
||||||
binding = ActivityBlackListBinding.inflate(getLayoutInflater());
|
binding = ActivityScopeListBinding.inflate(getLayoutInflater());
|
||||||
setContentView(binding.getRoot());
|
setContentView(binding.getRoot());
|
||||||
setSupportActionBar(binding.toolbar);
|
setSupportActionBar(binding.toolbar);
|
||||||
binding.toolbar.setNavigationOnClickListener(view -> finish());
|
binding.toolbar.setNavigationOnClickListener(view -> finish());
|
||||||
|
|
@ -47,7 +47,7 @@ public class ModuleScopeActivity extends BaseActivity implements AppAdapter.Call
|
||||||
bar.setSubtitle(moduleName);
|
bar.setSubtitle(moduleName);
|
||||||
}
|
}
|
||||||
setupWindowInsets(binding.snackbar, binding.recyclerView);
|
setupWindowInsets(binding.snackbar, binding.recyclerView);
|
||||||
appAdapter = new ScopeAdapter(this, modulePackageName);
|
appAdapter = new ScopeAdapter(this, modulePackageName, binding.masterSwitch);
|
||||||
appAdapter.setHasStableIds(true);
|
appAdapter.setHasStableIds(true);
|
||||||
binding.recyclerView.setAdapter(appAdapter);
|
binding.recyclerView.setAdapter(appAdapter);
|
||||||
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,11 @@ public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> impl
|
||||||
|
|
||||||
holder.mSwitch.setOnCheckedChangeListener(null);
|
holder.mSwitch.setOnCheckedChangeListener(null);
|
||||||
holder.mSwitch.setChecked(checkedList.contains(info.packageName));
|
holder.mSwitch.setChecked(checkedList.contains(info.packageName));
|
||||||
|
if (this instanceof ScopeAdapter) {
|
||||||
|
holder.mSwitch.setEnabled(((ScopeAdapter) this).enabled);
|
||||||
|
} else {
|
||||||
|
holder.mSwitch.setEnabled(true);
|
||||||
|
}
|
||||||
holder.mSwitch.setOnCheckedChangeListener((v, isChecked) ->
|
holder.mSwitch.setOnCheckedChangeListener((v, isChecked) ->
|
||||||
onCheckedChange(v, isChecked, info));
|
onCheckedChange(v, isChecked, info));
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,7 @@ public class AppHelper {
|
||||||
static boolean saveScopeList(String modulePackageName, List<String> list) {
|
static boolean saveScopeList(String modulePackageName, List<String> list) {
|
||||||
File file = new File(BASE_PATH + String.format(SCOPE_LIST_PATH, modulePackageName));
|
File file = new File(BASE_PATH + String.format(SCOPE_LIST_PATH, modulePackageName));
|
||||||
if (list.size() == 0) {
|
if (list.size() == 0) {
|
||||||
|
scopeList.put(modulePackageName, list);
|
||||||
return file.delete();
|
return file.delete();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
package org.meowcat.edxposed.manager.adapters;
|
package org.meowcat.edxposed.manager.adapters;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.R;
|
import org.meowcat.edxposed.manager.R;
|
||||||
import org.meowcat.edxposed.manager.util.ToastUtil;
|
import org.meowcat.edxposed.manager.util.ToastUtil;
|
||||||
|
import org.meowcat.edxposed.manager.widget.MasterSwitch;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -13,11 +15,23 @@ import java.util.List;
|
||||||
public class ScopeAdapter extends AppAdapter {
|
public class ScopeAdapter extends AppAdapter {
|
||||||
|
|
||||||
protected final String modulePackageName;
|
protected final String modulePackageName;
|
||||||
|
protected boolean enabled = true;
|
||||||
private List<String> checkedList;
|
private List<String> checkedList;
|
||||||
|
private final MasterSwitch masterSwitch;
|
||||||
|
|
||||||
public ScopeAdapter(Context context, String modulePackageName) {
|
public ScopeAdapter(Context context, String modulePackageName, MasterSwitch masterSwitch) {
|
||||||
super(context);
|
super(context);
|
||||||
this.modulePackageName = modulePackageName;
|
this.modulePackageName = modulePackageName;
|
||||||
|
this.masterSwitch = masterSwitch;
|
||||||
|
masterSwitch.setTitle(context.getString(R.string.enable_scope));
|
||||||
|
masterSwitch.setOnCheckedChangedListener(new MasterSwitch.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(boolean checked) {
|
||||||
|
enabled = checked;
|
||||||
|
AppHelper.saveScopeList(modulePackageName, enabled ? checkedList : new ArrayList<>());
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -30,6 +44,8 @@ public class ScopeAdapter extends AppAdapter {
|
||||||
}
|
}
|
||||||
scopeList.retainAll(list);
|
scopeList.retainAll(list);
|
||||||
checkedList = scopeList;
|
checkedList = scopeList;
|
||||||
|
enabled = checkedList.size() != 0;
|
||||||
|
((Activity) context).runOnUiThread(() -> masterSwitch.setChecked(enabled));
|
||||||
return checkedList;
|
return checkedList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
package org.meowcat.edxposed.manager.widget;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.graphics.drawable.StateListDrawable;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Checkable;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.widget.SwitchCompat;
|
||||||
|
|
||||||
|
import org.meowcat.edxposed.manager.R;
|
||||||
|
|
||||||
|
public class MasterSwitch extends FrameLayout implements View.OnClickListener, Checkable {
|
||||||
|
|
||||||
|
private TextView masterTitle;
|
||||||
|
private SwitchCompat switchCompat;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private OnCheckedChangeListener listener;
|
||||||
|
|
||||||
|
private boolean isChecked;
|
||||||
|
|
||||||
|
public MasterSwitch(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
init(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MasterSwitch(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
init(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MasterSwitch(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
init(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(Context context, AttributeSet attrs) {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||||
|
inflater.inflate(R.layout.master_switch, this, true);
|
||||||
|
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MasterSwitch);
|
||||||
|
int colorOn = a.getColor(R.styleable.MasterSwitch_masterSwitchBackgroundOn, 0);
|
||||||
|
int colorOff = a.getColor(R.styleable.MasterSwitch_masterSwitchBackgroundOff, 0);
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
|
StateListDrawable drawable = new StateListDrawable();
|
||||||
|
drawable.addState(new int[]{android.R.attr.state_selected}, new ColorDrawable(colorOn));
|
||||||
|
drawable.addState(new int[]{}, new ColorDrawable(colorOff));
|
||||||
|
setBackground(drawable);
|
||||||
|
|
||||||
|
masterTitle = findViewById(android.R.id.title);
|
||||||
|
switchCompat = findViewById(R.id.switchWidget);
|
||||||
|
|
||||||
|
setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
masterTitle.setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateViews() {
|
||||||
|
if (switchCompat != null) {
|
||||||
|
setSelected(isChecked);
|
||||||
|
switchCompat.setChecked(isChecked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChecked() {
|
||||||
|
return isChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toggle() {
|
||||||
|
setChecked(!isChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChecked(boolean checked) {
|
||||||
|
final boolean changed = isChecked != checked;
|
||||||
|
if (changed) {
|
||||||
|
isChecked = checked;
|
||||||
|
updateViews();
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onCheckedChanged(checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnCheckedChangedListener(OnCheckedChangeListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class OnCheckedChangeListener {
|
||||||
|
public abstract void onCheckedChanged(boolean checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/snackbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="?actionBarTheme"
|
||||||
|
app:elevation="4dp">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?colorActionBar"
|
||||||
|
app:popupTheme="?actionBarPopupTheme" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<org.meowcat.edxposed.manager.widget.MasterSwitch
|
||||||
|
android:id="@+id/master_switch"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:theme="@style/MasterSwitch"
|
||||||
|
android:foreground="?selectableItemBackground" />
|
||||||
|
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/swipeRefreshLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false" />
|
||||||
|
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/master_switch_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@android:id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?masterSwitchTextAppearance" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@android:id/widget_frame"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="end|center_vertical"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="0dp">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/switchWidget"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="false"
|
||||||
|
android:focusable="false" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</merge>
|
||||||
|
|
@ -311,4 +311,5 @@
|
||||||
<string name="settings_title_disable_hidden_api_bypass">禁用绕过隐藏 API 的限制</string>
|
<string name="settings_title_disable_hidden_api_bypass">禁用绕过隐藏 API 的限制</string>
|
||||||
<string name="settings_summary_disable_hidden_api_bypass">禁用绕过隐藏 API 的限制将会通过某些检测(如Snapchat)\n<b>警告:</b> 启用此选项可能会使某些功能无法正常工作,或出现一些其他问题</string>
|
<string name="settings_summary_disable_hidden_api_bypass">禁用绕过隐藏 API 的限制将会通过某些检测(如Snapchat)\n<b>警告:</b> 启用此选项可能会使某些功能无法正常工作,或出现一些其他问题</string>
|
||||||
<string name="menu_scope">作用域</string>
|
<string name="menu_scope">作用域</string>
|
||||||
|
<string name="enable_scope">启用作用域</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,11 @@
|
||||||
<attr name="downloadVerticalPadding" format="dimension" />
|
<attr name="downloadVerticalPadding" format="dimension" />
|
||||||
<attr name="actionBarPopupTheme" format="reference" />
|
<attr name="actionBarPopupTheme" format="reference" />
|
||||||
<attr name="tabLayoutTheme" format="reference" />
|
<attr name="tabLayoutTheme" format="reference" />
|
||||||
|
|
||||||
|
<declare-styleable name="MasterSwitch">
|
||||||
|
<attr name="masterSwitchTextAppearance" format="reference" />
|
||||||
|
<attr name="masterSwitchBackgroundOn" format="color" />
|
||||||
|
<attr name="masterSwitchBackgroundOff" format="color" />
|
||||||
|
<attr name="masterSwitchForeground" format="color" />
|
||||||
|
</declare-styleable>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -342,4 +342,5 @@
|
||||||
<string name="settings_title_disable_hidden_api_bypass">Disable hidden API restrictions bypass</string>
|
<string name="settings_title_disable_hidden_api_bypass">Disable hidden API restrictions bypass</string>
|
||||||
<string name="settings_summary_disable_hidden_api_bypass">Disable hidden API restrictions bypass will pass some detection (eg Snapchat), these APIs are disabled by default\n<b>WARNING:</b> Enable this option may cause some features do not work properly, or some other problems</string>
|
<string name="settings_summary_disable_hidden_api_bypass">Disable hidden API restrictions bypass will pass some detection (eg Snapchat), these APIs are disabled by default\n<b>WARNING:</b> Enable this option may cause some features do not work properly, or some other problems</string>
|
||||||
<string name="menu_scope">Scope</string>
|
<string name="menu_scope">Scope</string>
|
||||||
|
<string name="enable_scope">Enable scope</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,24 @@
|
||||||
|
|
||||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.MaterialComponents.Light" />
|
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.MaterialComponents.Light" />
|
||||||
|
|
||||||
|
<style name="MasterSwitch">
|
||||||
|
<item name="masterSwitchBackgroundOff">#80868b</item>
|
||||||
|
<item name="masterSwitchBackgroundOn">?colorAccent</item>
|
||||||
|
<item name="masterSwitchTextAppearance">@style/MasterSwitch.TextAppearance</item>
|
||||||
|
<item name="switchStyle">@style/MasterSwitch.Switch</item>
|
||||||
|
<item name="android:theme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="MasterSwitch.Switch" parent="@style/Widget.AppCompat.CompoundButton.Switch">
|
||||||
|
<item name="trackTint">#33ffffff</item>
|
||||||
|
<item name="thumbTint">@android:color/white</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="MasterSwitch.TextAppearance" parent="@style/TextAppearance.AppCompat.Body2">
|
||||||
|
<item name="android:textSize">18sp</item>
|
||||||
|
<item name="android:textColor">@android:color/white</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="ThemeOverlay" />
|
<style name="ThemeOverlay" />
|
||||||
|
|
||||||
<style name="ThemeOverlay.Md2">
|
<style name="ThemeOverlay.Md2">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue