Add master switch for scope list

This commit is contained in:
NekoInverter 2020-11-22 13:19:11 +08:00
parent ec08cc85e6
commit 840d54cccf
No known key found for this signature in database
GPG Key ID: 280D6CCCF95715F9
11 changed files with 273 additions and 6 deletions

View File

@ -16,14 +16,14 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import org.meowcat.edxposed.manager.adapters.AppAdapter;
import org.meowcat.edxposed.manager.adapters.AppHelper;
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 {
private SearchView searchView;
private AppAdapter appAdapter;
private ScopeAdapter appAdapter;
private SearchView.OnQueryTextListener searchListener;
private ActivityBlackListBinding binding;
private ActivityScopeListBinding binding;
private final Runnable runnable = new Runnable() {
@Override
public void run() {
@ -37,7 +37,7 @@ public class ModuleScopeActivity extends BaseActivity implements AppAdapter.Call
super.onCreate(savedInstanceState);
String modulePackageName = getIntent().getStringExtra("modulePackageName");
String moduleName = getIntent().getStringExtra("moduleName");
binding = ActivityBlackListBinding.inflate(getLayoutInflater());
binding = ActivityScopeListBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
binding.toolbar.setNavigationOnClickListener(view -> finish());
@ -47,7 +47,7 @@ public class ModuleScopeActivity extends BaseActivity implements AppAdapter.Call
bar.setSubtitle(moduleName);
}
setupWindowInsets(binding.snackbar, binding.recyclerView);
appAdapter = new ScopeAdapter(this, modulePackageName);
appAdapter = new ScopeAdapter(this, modulePackageName, binding.masterSwitch);
appAdapter.setHasStableIds(true);
binding.recyclerView.setAdapter(appAdapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));

View File

@ -205,6 +205,11 @@ public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> impl
holder.mSwitch.setOnCheckedChangeListener(null);
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) ->
onCheckedChange(v, isChecked, info));
holder.itemView.setOnClickListener(v -> {

View File

@ -354,6 +354,7 @@ public class AppHelper {
static boolean saveScopeList(String modulePackageName, List<String> list) {
File file = new File(BASE_PATH + String.format(SCOPE_LIST_PATH, modulePackageName));
if (list.size() == 0) {
scopeList.put(modulePackageName, list);
return file.delete();
}
try {

View File

@ -1,11 +1,13 @@
package org.meowcat.edxposed.manager.adapters;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.widget.CompoundButton;
import org.meowcat.edxposed.manager.R;
import org.meowcat.edxposed.manager.util.ToastUtil;
import org.meowcat.edxposed.manager.widget.MasterSwitch;
import java.util.ArrayList;
import java.util.List;
@ -13,11 +15,23 @@ import java.util.List;
public class ScopeAdapter extends AppAdapter {
protected final String modulePackageName;
protected boolean enabled = true;
private List<String> checkedList;
private final MasterSwitch masterSwitch;
public ScopeAdapter(Context context, String modulePackageName) {
public ScopeAdapter(Context context, String modulePackageName, MasterSwitch masterSwitch) {
super(context);
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
@ -30,6 +44,8 @@ public class ScopeAdapter extends AppAdapter {
}
scopeList.retainAll(list);
checkedList = scopeList;
enabled = checkedList.size() != 0;
((Activity) context).runOnUiThread(() -> masterSwitch.setChecked(enabled));
return checkedList;
}

View File

@ -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();
}
}

View File

@ -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>

View File

@ -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>

View File

@ -311,4 +311,5 @@
<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="menu_scope">作用域</string>
<string name="enable_scope">启用作用域</string>
</resources>

View File

@ -9,4 +9,11 @@
<attr name="downloadVerticalPadding" format="dimension" />
<attr name="actionBarPopupTheme" 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>

View File

@ -342,4 +342,5 @@
<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="menu_scope">Scope</string>
<string name="enable_scope">Enable scope</string>
</resources>

View File

@ -33,6 +33,24 @@
<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.Md2">