[app] Refactored to use AndroidX Navigation (#697)
This commit is contained in:
parent
a694d2bc73
commit
ba545bafec
|
|
@ -197,12 +197,15 @@ dependencies {
|
||||||
val glideVersion = "4.12.0"
|
val glideVersion = "4.12.0"
|
||||||
val markwonVersion = "4.6.2"
|
val markwonVersion = "4.6.2"
|
||||||
val okhttpVersion = "4.9.1"
|
val okhttpVersion = "4.9.1"
|
||||||
|
val navVersion = "2.3.5"
|
||||||
annotationProcessor("com.github.bumptech.glide:compiler:$glideVersion")
|
annotationProcessor("com.github.bumptech.glide:compiler:$glideVersion")
|
||||||
implementation("androidx.activity:activity:1.2.3")
|
implementation("androidx.activity:activity:1.2.3")
|
||||||
implementation("androidx.browser:browser:1.3.0")
|
implementation("androidx.browser:browser:1.3.0")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
|
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
|
||||||
implementation("androidx.core:core:1.5.0")
|
implementation("androidx.core:core:1.5.0")
|
||||||
implementation("androidx.fragment:fragment:1.3.4")
|
implementation("androidx.fragment:fragment:1.3.4")
|
||||||
|
implementation("androidx.navigation:navigation-fragment:$navVersion")
|
||||||
|
implementation("androidx.navigation:navigation-ui:$navVersion")
|
||||||
implementation("androidx.recyclerview:recyclerview:1.2.0")
|
implementation("androidx.recyclerview:recyclerview:1.2.0")
|
||||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||||
implementation("com.caverock:androidsvg-aar:1.4")
|
implementation("com.caverock:androidsvg-aar:1.4")
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.INTERACT_ACROSS_USERS"
|
android:name="android.permission.INTERACT_ACROSS_USERS"
|
||||||
tools:ignore="ProtectedPermissions" />
|
tools:ignore="ProtectedPermissions" />
|
||||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_SECURE_SETTINGS"
|
||||||
tools:ignore="ProtectedPermissions" />
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
|
|
@ -45,45 +46,24 @@
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning"
|
tools:ignore="AllowBackup,GoogleAppIndexingWarning"
|
||||||
tools:targetApi="q">
|
tools:targetApi="q">
|
||||||
<activity
|
|
||||||
android:name=".ui.activity.CrashReportActivity"
|
|
||||||
android:process=":error_activity" />
|
|
||||||
<activity
|
|
||||||
android:name=".ui.activity.LogsActivity"
|
|
||||||
android:label="@string/Logs" />
|
|
||||||
<activity android:name=".ui.activity.AppListActivity" />
|
|
||||||
<activity
|
|
||||||
android:name=".ui.activity.RepoActivity"
|
|
||||||
android:label="@string/module_repo" />
|
|
||||||
<activity android:name=".ui.activity.RepoItemActivity" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.activity.MainActivity"
|
android:name=".ui.activity.MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleInstance"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.app.shortcuts"
|
android:name="android.app.shortcuts"
|
||||||
android:resource="@xml/shortcuts" />
|
android:resource="@xml/shortcuts" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.activity.ModulesActivity"
|
android:name=".ui.activity.CrashReportActivity"
|
||||||
android:label="@string/Modules" />
|
android:process=":error_activity" />
|
||||||
<activity
|
|
||||||
android:name=".ui.activity.SettingsActivity"
|
|
||||||
android:label="@string/Settings"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".receivers.ServiceReceiver"
|
android:name=".receivers.ServiceReceiver"
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ package org.lsposed.manager.adapters;
|
||||||
import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
|
import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
|
|
@ -72,7 +73,7 @@ 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.ItemModuleBinding;
|
import org.lsposed.manager.databinding.ItemModuleBinding;
|
||||||
import org.lsposed.manager.ui.activity.AppListActivity;
|
import org.lsposed.manager.ui.fragment.AppListFragment;
|
||||||
import org.lsposed.manager.ui.fragment.CompileDialogFragment;
|
import org.lsposed.manager.ui.fragment.CompileDialogFragment;
|
||||||
import org.lsposed.manager.util.GlideApp;
|
import org.lsposed.manager.util.GlideApp;
|
||||||
import org.lsposed.manager.util.ModuleUtil;
|
import org.lsposed.manager.util.ModuleUtil;
|
||||||
|
|
@ -93,7 +94,8 @@ import rikka.widget.switchbar.SwitchBar;
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder> implements Filterable, Handler.Callback {
|
public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder> implements Filterable, Handler.Callback {
|
||||||
|
|
||||||
private final AppListActivity activity;
|
private final Activity activity;
|
||||||
|
private final AppListFragment fragment;
|
||||||
private final PackageManager pm;
|
private final PackageManager pm;
|
||||||
private final SharedPreferences preferences;
|
private final SharedPreferences preferences;
|
||||||
private final Handler loadAppListHandler;
|
private final Handler loadAppListHandler;
|
||||||
|
|
@ -121,9 +123,9 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
activity.binding.progress.setIndeterminate(false);
|
fragment.binding.progress.setIndeterminate(false);
|
||||||
activity.binding.swipeRefreshLayout.setRefreshing(false);
|
fragment.binding.swipeRefreshLayout.setRefreshing(false);
|
||||||
String queryStr = activity.searchView != null ? activity.searchView.getQuery().toString() : "";
|
String queryStr = fragment.searchView != null ? fragment.searchView.getQuery().toString() : "";
|
||||||
getFilter().filter(queryStr);
|
getFilter().filter(queryStr);
|
||||||
this.notify();
|
this.notify();
|
||||||
}
|
}
|
||||||
|
|
@ -134,8 +136,9 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
private boolean refreshing = false;
|
private boolean refreshing = false;
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
|
|
||||||
public ScopeAdapter(AppListActivity activity, ModuleUtil.InstalledModule module) {
|
public ScopeAdapter(AppListFragment fragment, ModuleUtil.InstalledModule module) {
|
||||||
this.activity = activity;
|
this.fragment = fragment;
|
||||||
|
this.activity = fragment.requireActivity();
|
||||||
this.module = module;
|
this.module = module;
|
||||||
moduleUtil = ModuleUtil.getInstance();
|
moduleUtil = ModuleUtil.getInstance();
|
||||||
HandlerThread handlerThread = new HandlerThread("appList");
|
HandlerThread handlerThread = new HandlerThread("appList");
|
||||||
|
|
@ -250,12 +253,12 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
if (launchIntent != null) {
|
if (launchIntent != null) {
|
||||||
ConfigManager.startActivityAsUserWithFeature(launchIntent, module.userId);
|
ConfigManager.startActivityAsUserWithFeature(launchIntent, module.userId);
|
||||||
} else {
|
} else {
|
||||||
activity.makeSnackBar(R.string.module_no_ui, Snackbar.LENGTH_LONG);
|
fragment.makeSnackBar(R.string.module_no_ui, Snackbar.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.backup) {
|
} else if (itemId == R.id.backup) {
|
||||||
Calendar now = Calendar.getInstance();
|
Calendar now = Calendar.getInstance();
|
||||||
activity.backupLauncher.launch(String.format(Locale.US,
|
fragment.backupLauncher.launch(String.format(Locale.US,
|
||||||
"%s_%04d%02d%02d_%02d%02d%02d.lsp",
|
"%s_%04d%02d%02d_%02d%02d%02d.lsp",
|
||||||
module.getAppName(),
|
module.getAppName(),
|
||||||
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||||
|
|
@ -263,7 +266,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND)));
|
now.get(Calendar.MINUTE), now.get(Calendar.SECOND)));
|
||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.restore) {
|
} else if (itemId == R.id.restore) {
|
||||||
activity.restoreLauncher.launch(new String[]{"*/*"});
|
fragment.restoreLauncher.launch(new String[]{"*/*"});
|
||||||
return true;
|
return true;
|
||||||
} else if (!AppHelper.onOptionsItemSelected(item, preferences)) {
|
} else if (!AppHelper.onOptionsItemSelected(item, preferences)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -284,7 +287,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
ConfigManager.startActivityAsUserWithFeature(launchIntent, module.userId);
|
ConfigManager.startActivityAsUserWithFeature(launchIntent, module.userId);
|
||||||
}
|
}
|
||||||
} else if (itemId == R.id.menu_compile_speed) {
|
} else if (itemId == R.id.menu_compile_speed) {
|
||||||
CompileDialogFragment.speed(activity.getSupportFragmentManager(), info);
|
CompileDialogFragment.speed(fragment.getChildFragmentManager(), info);
|
||||||
} else if (itemId == R.id.menu_other_app) {
|
} else if (itemId == R.id.menu_other_app) {
|
||||||
var intent = new Intent(Intent.ACTION_SHOW_APP_INFO);
|
var intent = new Intent(Intent.ACTION_SHOW_APP_INFO);
|
||||||
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, module.packageName);
|
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, module.packageName);
|
||||||
|
|
@ -309,8 +312,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
public void onPrepareOptionsMenu(@NonNull Menu menu) {
|
||||||
inflater.inflate(R.menu.menu_app_list, menu);
|
|
||||||
Intent intent = AppHelper.getSettingsIntent(module.packageName, module.userId);
|
Intent intent = AppHelper.getSettingsIntent(module.packageName, module.userId);
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
menu.removeItem(R.id.menu_launch);
|
menu.removeItem(R.id.menu_launch);
|
||||||
|
|
@ -448,14 +450,14 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
}
|
}
|
||||||
loadAppListHandler.removeMessages(0);
|
loadAppListHandler.removeMessages(0);
|
||||||
if (!force) {
|
if (!force) {
|
||||||
activity.binding.progress.setVisibility(View.INVISIBLE);
|
fragment.binding.progress.setVisibility(View.INVISIBLE);
|
||||||
activity.binding.progress.setIndeterminate(true);
|
fragment.binding.progress.setIndeterminate(true);
|
||||||
activity.binding.progress.setVisibility(View.VISIBLE);
|
fragment.binding.progress.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
enabled = moduleUtil.isModuleEnabled(module.packageName);
|
enabled = moduleUtil.isModuleEnabled(module.packageName);
|
||||||
activity.binding.masterSwitch.setOnCheckedChangeListener(null);
|
fragment.binding.masterSwitch.setOnCheckedChangeListener(null);
|
||||||
activity.binding.masterSwitch.setChecked(enabled);
|
fragment.binding.masterSwitch.setChecked(enabled);
|
||||||
activity.binding.masterSwitch.setOnCheckedChangeListener(switchBarOnCheckedChangeListener);
|
fragment.binding.masterSwitch.setOnCheckedChangeListener(switchBarOnCheckedChangeListener);
|
||||||
loadAppListHandler.sendMessage(Message.obtain(loadAppListHandler, 0, force));
|
loadAppListHandler.sendMessage(Message.obtain(loadAppListHandler, 0, force));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -466,7 +468,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
checkedList.remove(appInfo.application);
|
checkedList.remove(appInfo.application);
|
||||||
}
|
}
|
||||||
if (!ConfigManager.setModuleScope(module.packageName, checkedList)) {
|
if (!ConfigManager.setModuleScope(module.packageName, checkedList)) {
|
||||||
activity.makeSnackBar(R.string.failed_to_save_scope_list, Snackbar.LENGTH_SHORT);
|
fragment.makeSnackBar(R.string.failed_to_save_scope_list, Snackbar.LENGTH_SHORT);
|
||||||
if (!isChecked) {
|
if (!isChecked) {
|
||||||
checkedList.add(appInfo.application);
|
checkedList.add(appInfo.application);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -474,7 +476,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
}
|
}
|
||||||
buttonView.setChecked(!isChecked);
|
buttonView.setChecked(!isChecked);
|
||||||
} else if (appInfo.packageName.equals("android")) {
|
} else if (appInfo.packageName.equals("android")) {
|
||||||
Snackbar.make(activity.binding.snackbar, R.string.reboot_required, Snackbar.LENGTH_SHORT)
|
Snackbar.make(fragment.binding.snackbar, R.string.reboot_required, Snackbar.LENGTH_SHORT)
|
||||||
.setAction(R.string.reboot, v -> ConfigManager.reboot(false, null, false))
|
.setAction(R.string.reboot, v -> ConfigManager.reboot(false, null, false))
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
@ -619,7 +621,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onBackPressed() {
|
public boolean onBackPressed() {
|
||||||
if (!refreshing && activity.binding.masterSwitch.isChecked() && checkedList.isEmpty()) {
|
if (!refreshing && fragment.binding.masterSwitch.isChecked() && checkedList.isEmpty()) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(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()) {
|
||||||
|
|
|
||||||
|
|
@ -1,157 +1,126 @@
|
||||||
/*
|
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.lsposed.manager.ui.activity;
|
package org.lsposed.manager.ui.activity;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import androidx.core.text.HtmlCompat;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.navigation.NavController;
|
||||||
|
import androidx.navigation.Navigation;
|
||||||
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
|
|
||||||
import org.lsposed.manager.BuildConfig;
|
|
||||||
import org.lsposed.manager.ConfigManager;
|
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.databinding.ActivityMainBinding;
|
import org.lsposed.manager.databinding.ActivityMainBinding;
|
||||||
import org.lsposed.manager.databinding.DialogAboutBinding;
|
|
||||||
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
||||||
import org.lsposed.manager.ui.dialog.BlurBehindDialogBuilder;
|
|
||||||
import org.lsposed.manager.ui.dialog.InfoDialogBuilder;
|
|
||||||
import org.lsposed.manager.util.GlideHelper;
|
|
||||||
import org.lsposed.manager.util.ModuleUtil;
|
|
||||||
import org.lsposed.manager.util.NavUtil;
|
|
||||||
import org.lsposed.manager.util.chrome.LinkTransformationMethod;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import rikka.core.res.ResourcesKt;
|
|
||||||
|
|
||||||
public class MainActivity extends BaseActivity {
|
public class MainActivity extends BaseActivity {
|
||||||
ActivityMainBinding binding;
|
private static final String KEY_PREFIX = MainActivity.class.getName() + '.';
|
||||||
|
private static final String EXTRA_SAVED_INSTANCE_STATE = KEY_PREFIX + "SAVED_INSTANCE_STATE";
|
||||||
|
private boolean restarting;
|
||||||
|
private ActivityMainBinding binding;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static Intent newIntent(@NonNull Context context) {
|
||||||
|
return new Intent(context, MainActivity.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static Intent newIntent(@NonNull Bundle savedInstanceState, @NonNull Context context) {
|
||||||
|
return newIntent(context)
|
||||||
|
.putExtra(EXTRA_SAVED_INSTANCE_STATE, savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
savedInstanceState = getIntent().getBundleExtra(EXTRA_SAVED_INSTANCE_STATE);
|
||||||
|
}
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||||
setContentView(binding.getRoot());
|
setContentView(binding.getRoot());
|
||||||
binding.status.setOnClickListener(v -> {
|
|
||||||
if (ConfigManager.getXposedApiVersion() != -1) {
|
if (savedInstanceState == null) {
|
||||||
new InfoDialogBuilder(this)
|
handleIntent(getIntent());
|
||||||
.setTitle(R.string.info)
|
|
||||||
.show();
|
|
||||||
} else {
|
|
||||||
NavUtil.startURL(this, getString(R.string.about_source));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
binding.modules.setOnClickListener(new StartActivityListener(ModulesActivity.class, true));
|
|
||||||
binding.download.setOnClickListener(new StartActivityListener(RepoActivity.class, false));
|
|
||||||
binding.logs.setOnClickListener(new StartActivityListener(LogsActivity.class, true));
|
|
||||||
binding.settings.setOnClickListener(new StartActivityListener(SettingsActivity.class, false));
|
|
||||||
binding.about.setOnClickListener(v -> {
|
|
||||||
DialogAboutBinding binding = DialogAboutBinding.inflate(LayoutInflater.from(this), null, false);
|
|
||||||
binding.sourceCode.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
binding.sourceCode.setTransformationMethod(new LinkTransformationMethod(this));
|
|
||||||
binding.sourceCode.setText(HtmlCompat.fromHtml(getString(
|
|
||||||
R.string.about_view_source_code,
|
|
||||||
"<b><a href=\"https://github.com/LSPosed/LSPosed\">GitHub</a></b>",
|
|
||||||
"<b><a href=\"https://t.me/LSPosed\">Telegram</a></b>"), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
|
||||||
binding.translators.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
binding.translators.setTransformationMethod(new LinkTransformationMethod(this));
|
|
||||||
binding.translators.setText(HtmlCompat.fromHtml(getString(R.string.about_translators, getString(R.string.translators)), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
|
||||||
binding.version.setText(String.format(Locale.US, "%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
|
|
||||||
new BlurBehindDialogBuilder(this)
|
|
||||||
.setView(binding.getRoot())
|
|
||||||
.show();
|
|
||||||
});
|
|
||||||
Glide.with(binding.appIcon)
|
|
||||||
.load(GlideHelper.wrapApplicationInfoForIconLoader(getApplicationInfo()))
|
|
||||||
.into(binding.appIcon);
|
|
||||||
String installXposedVersion = ConfigManager.getXposedVersionName();
|
|
||||||
int cardBackgroundColor;
|
|
||||||
if (installXposedVersion != null) {
|
|
||||||
if (!ConfigManager.isSepolicyLoaded()) {
|
|
||||||
binding.statusTitle.setText(R.string.partial_activated);
|
|
||||||
cardBackgroundColor = ResourcesKt.resolveColor(getTheme(), R.attr.colorWarning);
|
|
||||||
binding.statusIcon.setImageResource(R.drawable.ic_warning);
|
|
||||||
binding.statusSummary.setText(R.string.selinux_policy_not_loaded_summary);
|
|
||||||
} else if (!ConfigManager.systemServerRequested()) {
|
|
||||||
binding.statusTitle.setText(R.string.partial_activated);
|
|
||||||
cardBackgroundColor = ResourcesKt.resolveColor(getTheme(), R.attr.colorWarning);
|
|
||||||
binding.statusIcon.setImageResource(R.drawable.ic_warning);
|
|
||||||
binding.statusSummary.setText(R.string.system_inject_fail_summary);
|
|
||||||
} else {
|
|
||||||
binding.statusTitle.setText(R.string.activated);
|
|
||||||
cardBackgroundColor = ResourcesKt.resolveColor(getTheme(), R.attr.colorNormal);
|
|
||||||
binding.statusIcon.setImageResource(R.drawable.ic_check_circle);
|
|
||||||
binding.statusSummary.setText(String.format(Locale.US, "%s (%d)", installXposedVersion, ConfigManager.getXposedVersionCode()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cardBackgroundColor = ResourcesKt.resolveColor(getTheme(), R.attr.colorInstall);
|
|
||||||
boolean isMagiskInstalled = ConfigManager.isMagiskInstalled();
|
|
||||||
binding.statusTitle.setText(isMagiskInstalled ? R.string.Install : R.string.NotInstall);
|
|
||||||
binding.statusSummary.setText(isMagiskInstalled ? R.string.InstallDetail : R.string.NotInstallDetail);
|
|
||||||
if (!isMagiskInstalled) {
|
|
||||||
binding.status.setOnClickListener(null);
|
|
||||||
binding.download.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
binding.statusIcon.setImageResource(R.drawable.ic_error);
|
|
||||||
Snackbar.make(binding.snackbar, R.string.lsposed_not_active, Snackbar.LENGTH_INDEFINITE).show();
|
|
||||||
}
|
|
||||||
binding.status.setCardBackgroundColor(cardBackgroundColor);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
||||||
binding.status.setOutlineSpotShadowColor(cardBackgroundColor);
|
|
||||||
binding.status.setOutlineAmbientShadowColor(cardBackgroundColor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StartActivityListener implements View.OnClickListener {
|
@Override
|
||||||
boolean requireInstalled;
|
protected void onNewIntent(Intent intent) {
|
||||||
Class<?> clazz;
|
super.onNewIntent(intent);
|
||||||
|
handleIntent(intent);
|
||||||
|
}
|
||||||
|
|
||||||
StartActivityListener(Class<?> clazz, boolean requireInstalled) {
|
private void handleIntent(Intent intent) {
|
||||||
this.clazz = clazz;
|
if (intent == null) {
|
||||||
this.requireInstalled = requireInstalled;
|
return;
|
||||||
}
|
}
|
||||||
|
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
|
||||||
@Override
|
NavController navController = navHostFragment.getNavController();
|
||||||
public void onClick(View v) {
|
if (intent.getAction().equals("android.intent.action.APPLICATION_PREFERENCES")) {
|
||||||
if (requireInstalled && ConfigManager.getXposedVersionName() == null) {
|
navController.navigate(R.id.settings_fragment);
|
||||||
Snackbar.make(binding.snackbar, R.string.lsposed_not_active, Snackbar.LENGTH_LONG).show();
|
} else if (intent.hasExtra("modulePackageName")) {
|
||||||
} else {
|
Bundle bundle = new Bundle();
|
||||||
Intent intent = new Intent();
|
bundle.putString("modulePackageName", intent.getStringExtra("modulePackageName"));
|
||||||
intent.setClass(MainActivity.this, clazz);
|
bundle.putInt("moduleUserId", intent.getIntExtra("moduleUserId", -1));
|
||||||
startActivity(intent);
|
navController.navigate(R.id.app_list_fragment, bundle);
|
||||||
|
} else if (!TextUtils.isEmpty(intent.getDataString())) {
|
||||||
|
switch (intent.getDataString()) {
|
||||||
|
case "modules":
|
||||||
|
navController.navigate(R.id.modules_fragment);
|
||||||
|
break;
|
||||||
|
case "logs":
|
||||||
|
navController.navigate(R.id.logs_fragment);
|
||||||
|
break;
|
||||||
|
case "repo":
|
||||||
|
navController.navigate(R.id.repo_fragment);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
public boolean onSupportNavigateUp() {
|
||||||
super.onResume();
|
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
|
||||||
int moduleCount = ModuleUtil.getInstance().getEnabledModulesCount();
|
return navController.navigateUp() || super.onSupportNavigateUp();
|
||||||
binding.modulesSummary.setText(getResources().getQuantityString(R.plurals.modules_enabled_count, moduleCount, moduleCount));
|
}
|
||||||
|
|
||||||
|
public void restart() {
|
||||||
|
Bundle savedInstanceState = new Bundle();
|
||||||
|
onSaveInstanceState(savedInstanceState);
|
||||||
|
finish();
|
||||||
|
startActivity(newIntent(savedInstanceState, this));
|
||||||
|
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
|
||||||
|
restarting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchKeyEvent(@NonNull KeyEvent event) {
|
||||||
|
return restarting || super.dispatchKeyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
|
@Override
|
||||||
|
public boolean dispatchKeyShortcutEvent(@NonNull KeyEvent event) {
|
||||||
|
return restarting || super.dispatchKeyShortcutEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchTouchEvent(@NonNull MotionEvent event) {
|
||||||
|
return restarting || super.dispatchTouchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchTrackballEvent(@NonNull MotionEvent event) {
|
||||||
|
return restarting || super.dispatchTrackballEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchGenericMotionEvent(@NonNull MotionEvent event) {
|
||||||
|
return restarting || super.dispatchGenericMotionEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ import com.takisoft.preferencex.PreferenceFragmentCompat;
|
||||||
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.ActivitySettingsBinding;
|
import org.lsposed.manager.databinding.FragmentSettingsBinding;
|
||||||
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
||||||
import org.lsposed.manager.util.BackupUtils;
|
import org.lsposed.manager.util.BackupUtils;
|
||||||
import org.lsposed.manager.util.theme.ThemeUtil;
|
import org.lsposed.manager.util.theme.ThemeUtil;
|
||||||
|
|
@ -67,7 +67,7 @@ import rikka.widget.borderview.BorderRecyclerView;
|
||||||
public class SettingsActivity extends BaseActivity {
|
public class SettingsActivity extends BaseActivity {
|
||||||
private static final String KEY_PREFIX = SettingsActivity.class.getName() + '.';
|
private static final String KEY_PREFIX = SettingsActivity.class.getName() + '.';
|
||||||
private static final String EXTRA_SAVED_INSTANCE_STATE = KEY_PREFIX + "SAVED_INSTANCE_STATE";
|
private static final String EXTRA_SAVED_INSTANCE_STATE = KEY_PREFIX + "SAVED_INSTANCE_STATE";
|
||||||
ActivitySettingsBinding binding;
|
FragmentSettingsBinding binding;
|
||||||
private boolean restarting;
|
private boolean restarting;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|
@ -87,7 +87,7 @@ public class SettingsActivity extends BaseActivity {
|
||||||
savedInstanceState = getIntent().getBundleExtra(EXTRA_SAVED_INSTANCE_STATE);
|
savedInstanceState = getIntent().getBundleExtra(EXTRA_SAVED_INSTANCE_STATE);
|
||||||
}
|
}
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
binding = ActivitySettingsBinding.inflate(getLayoutInflater());
|
binding = FragmentSettingsBinding.inflate(getLayoutInflater());
|
||||||
setContentView(binding.getRoot());
|
setContentView(binding.getRoot());
|
||||||
setAppBar(binding.appBar, binding.toolbar);
|
setAppBar(binding.appBar, binding.toolbar);
|
||||||
binding.getRoot().bringChildToFront(binding.appBar);
|
binding.getRoot().bringChildToFront(binding.appBar);
|
||||||
|
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.lsposed.manager.ui.activity.base;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Filterable;
|
|
||||||
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.appcompat.widget.SearchView;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import org.lsposed.manager.R;
|
|
||||||
import org.lsposed.manager.databinding.ActivityListBinding;
|
|
||||||
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
|
||||||
|
|
||||||
import rikka.recyclerview.RecyclerViewKt;
|
|
||||||
|
|
||||||
public abstract class ListActivity extends BaseActivity {
|
|
||||||
|
|
||||||
protected ActivityListBinding binding;
|
|
||||||
protected SearchView searchView;
|
|
||||||
private SearchView.OnQueryTextListener mSearchListener;
|
|
||||||
private BaseAdapter<?> adapter = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
binding = ActivityListBinding.inflate(getLayoutInflater());
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
setAppBar(binding.appBar, binding.toolbar);
|
|
||||||
binding.getRoot().bringChildToFront(binding.appBar);
|
|
||||||
binding.toolbar.setNavigationOnClickListener(view -> onBackPressed());
|
|
||||||
binding.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
|
||||||
ActionBar bar = getSupportActionBar();
|
|
||||||
if (bar != null) {
|
|
||||||
bar.setDisplayHomeAsUpEnabled(true);
|
|
||||||
}
|
|
||||||
adapter = createAdapter();
|
|
||||||
adapter.setHasStableIds(true);
|
|
||||||
binding.recyclerView.setAdapter(adapter);
|
|
||||||
binding.recyclerView.setHasFixedSize(true);
|
|
||||||
binding.recyclerView.setLayoutManager(new LinearLayoutManagerFix(this));
|
|
||||||
RecyclerViewKt.addFastScroller(binding.recyclerView, binding.recyclerView);
|
|
||||||
RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true);
|
|
||||||
binding.progress.setVisibilityAfterHide(View.GONE);
|
|
||||||
mSearchListener = new SearchView.OnQueryTextListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onQueryTextSubmit(String query) {
|
|
||||||
adapter.getFilter().filter(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onQueryTextChange(String newText) {
|
|
||||||
adapter.getFilter().filter(newText);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
|
||||||
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
|
||||||
searchView.setOnQueryTextListener(mSearchListener);
|
|
||||||
return super.onPrepareOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
if (searchView.isIconified()) {
|
|
||||||
super.onBackPressed();
|
|
||||||
} else {
|
|
||||||
searchView.setIconified(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract static class BaseAdapter<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> implements Filterable {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract BaseAdapter<?> createAdapter();
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +1,19 @@
|
||||||
/*
|
package org.lsposed.manager.ui.fragment;
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.lsposed.manager.ui.activity;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.widget.SearchView;
|
import androidx.appcompat.widget.SearchView;
|
||||||
|
|
||||||
|
|
@ -40,8 +22,7 @@ import com.google.android.material.snackbar.Snackbar;
|
||||||
import org.lsposed.manager.BuildConfig;
|
import org.lsposed.manager.BuildConfig;
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.adapters.ScopeAdapter;
|
import org.lsposed.manager.adapters.ScopeAdapter;
|
||||||
import org.lsposed.manager.databinding.ActivityAppListBinding;
|
import org.lsposed.manager.databinding.FragmentAppListBinding;
|
||||||
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
|
||||||
import org.lsposed.manager.util.BackupUtils;
|
import org.lsposed.manager.util.BackupUtils;
|
||||||
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
||||||
import org.lsposed.manager.util.ModuleUtil;
|
import org.lsposed.manager.util.ModuleUtil;
|
||||||
|
|
@ -50,68 +31,74 @@ import java.util.Locale;
|
||||||
|
|
||||||
import rikka.recyclerview.RecyclerViewKt;
|
import rikka.recyclerview.RecyclerViewKt;
|
||||||
|
|
||||||
public class AppListActivity extends BaseActivity {
|
public class AppListFragment extends BaseFragment {
|
||||||
|
|
||||||
public SearchView searchView;
|
public SearchView searchView;
|
||||||
private ScopeAdapter scopeAdapter;
|
private ScopeAdapter scopeAdapter;
|
||||||
|
private ModuleUtil.InstalledModule module;
|
||||||
|
|
||||||
private SearchView.OnQueryTextListener searchListener;
|
private SearchView.OnQueryTextListener searchListener;
|
||||||
public ActivityAppListBinding binding;
|
public FragmentAppListBinding binding;
|
||||||
public ActivityResultLauncher<String> backupLauncher;
|
public ActivityResultLauncher<String> backupLauncher;
|
||||||
public ActivityResultLauncher<String[]> restoreLauncher;
|
public ActivityResultLauncher<String[]> restoreLauncher;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
binding = FragmentAppListBinding.inflate(getLayoutInflater(), container, false);
|
||||||
String modulePackageName = getIntent().getStringExtra("modulePackageName");
|
|
||||||
int moduleUserId = getIntent().getIntExtra("moduleUserId", -1);
|
|
||||||
binding = ActivityAppListBinding.inflate(getLayoutInflater());
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
setAppBar(binding.appBar, binding.toolbar);
|
|
||||||
binding.appBar.setRaised(true);
|
binding.appBar.setRaised(true);
|
||||||
binding.toolbar.setNavigationOnClickListener(view -> onBackPressed());
|
String title;
|
||||||
ModuleUtil.InstalledModule module = ModuleUtil.getInstance().getModule(modulePackageName, moduleUserId);
|
if (module.userId != 0) {
|
||||||
if (module == null) {
|
title = String.format(Locale.US, "%s (%d)", module.getAppName(), module.userId);
|
||||||
finish();
|
} else {
|
||||||
return;
|
title = module.getAppName();
|
||||||
}
|
|
||||||
ActionBar bar = getSupportActionBar();
|
|
||||||
if (bar != null) {
|
|
||||||
bar.setDisplayHomeAsUpEnabled(true);
|
|
||||||
if (module.userId != 0) {
|
|
||||||
bar.setTitle(String.format(Locale.US, "%s (%d)", module.getAppName(), module.userId));
|
|
||||||
} else {
|
|
||||||
bar.setTitle(module.getAppName());
|
|
||||||
}
|
|
||||||
bar.setSubtitle(module.packageName);
|
|
||||||
}
|
}
|
||||||
|
binding.toolbar.setSubtitle(module.packageName);
|
||||||
|
|
||||||
scopeAdapter = new ScopeAdapter(this, module);
|
scopeAdapter = new ScopeAdapter(this, module);
|
||||||
scopeAdapter.setHasStableIds(true);
|
scopeAdapter.setHasStableIds(true);
|
||||||
binding.recyclerView.setAdapter(scopeAdapter);
|
binding.recyclerView.setAdapter(scopeAdapter);
|
||||||
binding.recyclerView.setHasFixedSize(true);
|
binding.recyclerView.setHasFixedSize(true);
|
||||||
binding.recyclerView.setLayoutManager(new LinearLayoutManagerFix(this));
|
binding.recyclerView.setLayoutManager(new LinearLayoutManagerFix(requireActivity()));
|
||||||
RecyclerViewKt.addFastScroller(binding.recyclerView, binding.recyclerView);
|
RecyclerViewKt.addFastScroller(binding.recyclerView, binding.recyclerView);
|
||||||
RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true);
|
RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true);
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener(() -> scopeAdapter.refresh(true));
|
binding.swipeRefreshLayout.setOnRefreshListener(() -> scopeAdapter.refresh(true));
|
||||||
|
|
||||||
searchListener = scopeAdapter.getSearchListener();
|
searchListener = scopeAdapter.getSearchListener();
|
||||||
|
|
||||||
|
setupToolbar(binding.toolbar, title, R.menu.menu_app_list);
|
||||||
|
return binding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
String modulePackageName = getArguments().getString("modulePackageName");
|
||||||
|
int moduleUserId = getArguments().getInt("moduleUserId", -1);
|
||||||
|
|
||||||
|
module = ModuleUtil.getInstance().getModule(modulePackageName, moduleUserId);
|
||||||
|
if (module == null) {
|
||||||
|
getNavController().navigateUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
backupLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
backupLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
||||||
uri -> {
|
uri -> {
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
try {
|
try {
|
||||||
// grantUriPermission might throw RemoteException on MIUI
|
// grantUriPermission might throw RemoteException on MIUI
|
||||||
grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
requireActivity().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
AlertDialog alertDialog = new AlertDialog.Builder(this)
|
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.setMessage(R.string.settings_backuping)
|
.setMessage(R.string.settings_backuping)
|
||||||
.show();
|
.show();
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
boolean success = BackupUtils.backup(this, uri, modulePackageName);
|
boolean success = BackupUtils.backup(requireActivity(), uri, modulePackageName);
|
||||||
try {
|
try {
|
||||||
runOnUiThread(() -> {
|
requireActivity().runOnUiThread(() -> {
|
||||||
alertDialog.dismiss();
|
alertDialog.dismiss();
|
||||||
makeSnackBar(success ? R.string.settings_backup_success : R.string.settings_backup_failed, Snackbar.LENGTH_SHORT);
|
makeSnackBar(success ? R.string.settings_backup_success : R.string.settings_backup_failed, Snackbar.LENGTH_SHORT);
|
||||||
});
|
});
|
||||||
|
|
@ -126,18 +113,18 @@ public class AppListActivity extends BaseActivity {
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
try {
|
try {
|
||||||
// grantUriPermission might throw RemoteException on MIUI
|
// grantUriPermission might throw RemoteException on MIUI
|
||||||
grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
requireActivity().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
AlertDialog alertDialog = new AlertDialog.Builder(this)
|
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.setMessage(R.string.settings_restoring)
|
.setMessage(R.string.settings_restoring)
|
||||||
.show();
|
.show();
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
boolean success = BackupUtils.restore(this, uri, modulePackageName);
|
boolean success = BackupUtils.restore(requireActivity(), uri, modulePackageName);
|
||||||
try {
|
try {
|
||||||
runOnUiThread(() -> {
|
requireActivity().runOnUiThread(() -> {
|
||||||
alertDialog.dismiss();
|
alertDialog.dismiss();
|
||||||
makeSnackBar(success ? R.string.settings_restore_success : R.string.settings_restore_failed, Snackbar.LENGTH_SHORT);
|
makeSnackBar(success ? R.string.settings_restore_success : R.string.settings_restore_failed, Snackbar.LENGTH_SHORT);
|
||||||
scopeAdapter.refresh(false);
|
scopeAdapter.refresh(false);
|
||||||
|
|
@ -151,7 +138,7 @@ public class AppListActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
scopeAdapter.refresh(false);
|
scopeAdapter.refresh(false);
|
||||||
}
|
}
|
||||||
|
|
@ -165,11 +152,11 @@ public class AppListActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
|
public void onPrepareOptionsMenu(@NonNull Menu menu) {
|
||||||
scopeAdapter.onCreateOptionsMenu(menu, getMenuInflater());
|
super.onPrepareOptionsMenu(menu);
|
||||||
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||||
searchView.setOnQueryTextListener(searchListener);
|
searchView.setOnQueryTextListener(searchListener);
|
||||||
return super.onCreateOptionsMenu(menu);
|
scopeAdapter.onPrepareOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -180,17 +167,6 @@ public class AppListActivity extends BaseActivity {
|
||||||
return super.onContextItemSelected(item);
|
return super.onContextItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
if (searchView.isIconified()) {
|
|
||||||
if (scopeAdapter.onBackPressed()) {
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
searchView.setIconified(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void makeSnackBar(String text, @Snackbar.Duration int duration) {
|
public void makeSnackBar(String text, @Snackbar.Duration int duration) {
|
||||||
Snackbar.make(binding.snackbar, text, duration).show();
|
Snackbar.make(binding.snackbar, text, duration).show();
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package org.lsposed.manager.ui.fragment;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.navigation.NavController;
|
||||||
|
import androidx.navigation.NavOptions;
|
||||||
|
import androidx.navigation.Navigation;
|
||||||
|
|
||||||
|
import org.lsposed.manager.R;
|
||||||
|
|
||||||
|
public class BaseFragment extends Fragment {
|
||||||
|
public void navigateUp() {
|
||||||
|
getNavController().navigateUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavController getNavController() {
|
||||||
|
View view = getView();
|
||||||
|
if (view == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
View tabletFragmentContainer = view.findViewById(R.id.tablet_nav_container);
|
||||||
|
if (tabletFragmentContainer != null) {
|
||||||
|
return Navigation.findNavController(tabletFragmentContainer);
|
||||||
|
} else {
|
||||||
|
return Navigation.findNavController(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupToolbar(Toolbar toolbar, int title) {
|
||||||
|
setupToolbar(toolbar, getString(title), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupToolbar(Toolbar toolbar, int title, int menu) {
|
||||||
|
setupToolbar(toolbar, getString(title), menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupToolbar(Toolbar toolbar, String title, int menu) {
|
||||||
|
toolbar.setNavigationOnClickListener(v -> navigateUp());
|
||||||
|
toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24);
|
||||||
|
toolbar.setTitle(title);
|
||||||
|
if (menu != -1) {
|
||||||
|
toolbar.inflateMenu(menu);
|
||||||
|
toolbar.setOnMenuItemClickListener(this::onOptionsItemSelected);
|
||||||
|
onPrepareOptionsMenu(toolbar.getMenu());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavOptions getNavOptions() {
|
||||||
|
return new NavOptions.Builder()
|
||||||
|
.setEnterAnim(R.anim.nav_default_enter_anim)
|
||||||
|
.setExitAnim(R.anim.nav_default_exit_anim)
|
||||||
|
.setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
|
||||||
|
.setPopExitAnim(R.anim.nav_default_pop_exit_anim)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,7 +41,6 @@ import com.google.android.material.snackbar.Snackbar;
|
||||||
import org.lsposed.manager.App;
|
import org.lsposed.manager.App;
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.databinding.FragmentCompileDialogBinding;
|
import org.lsposed.manager.databinding.FragmentCompileDialogBinding;
|
||||||
import org.lsposed.manager.ui.activity.AppListActivity;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
@ -156,9 +155,9 @@ public class CompileDialogFragment extends AppCompatDialogFragment {
|
||||||
CompileDialogFragment fragment = outerRef.get();
|
CompileDialogFragment fragment = outerRef.get();
|
||||||
if (fragment != null) {
|
if (fragment != null) {
|
||||||
fragment.dismissAllowingStateLoss();
|
fragment.dismissAllowingStateLoss();
|
||||||
AppListActivity activity = (AppListActivity) fragment.getActivity();
|
AppListFragment appListFragment = (AppListFragment) fragment.getParentFragment();
|
||||||
if (activity != null && activity.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
if (appListFragment != null && appListFragment.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
||||||
activity.makeSnackBar(text, Snackbar.LENGTH_LONG);
|
appListFragment.makeSnackBar(text, Snackbar.LENGTH_LONG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
package org.lsposed.manager.ui.fragment;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.text.HtmlCompat;
|
||||||
|
import androidx.navigation.NavOptions;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
import org.lsposed.manager.BuildConfig;
|
||||||
|
import org.lsposed.manager.ConfigManager;
|
||||||
|
import org.lsposed.manager.R;
|
||||||
|
import org.lsposed.manager.databinding.DialogAboutBinding;
|
||||||
|
import org.lsposed.manager.databinding.FragmentHomeBinding;
|
||||||
|
import org.lsposed.manager.databinding.FragmentMainBinding;
|
||||||
|
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
||||||
|
import org.lsposed.manager.ui.dialog.BlurBehindDialogBuilder;
|
||||||
|
import org.lsposed.manager.ui.dialog.InfoDialogBuilder;
|
||||||
|
import org.lsposed.manager.util.GlideHelper;
|
||||||
|
import org.lsposed.manager.util.ModuleUtil;
|
||||||
|
import org.lsposed.manager.util.NavUtil;
|
||||||
|
import org.lsposed.manager.util.chrome.LinkTransformationMethod;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import rikka.core.res.ResourcesKt;
|
||||||
|
|
||||||
|
public class HomeFragment extends BaseFragment {
|
||||||
|
|
||||||
|
private FragmentHomeBinding binding;
|
||||||
|
private View snackbar;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
FragmentMainBinding mainBinding = FragmentMainBinding.inflate(inflater, container, false);
|
||||||
|
snackbar = mainBinding.snackbar;
|
||||||
|
binding = FragmentHomeBinding.bind(mainBinding.snackbar);
|
||||||
|
return mainBinding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
|
BaseActivity activity = (BaseActivity) requireActivity();
|
||||||
|
binding.status.setOnClickListener(v -> {
|
||||||
|
if (ConfigManager.getXposedApiVersion() != -1) {
|
||||||
|
new InfoDialogBuilder(activity)
|
||||||
|
.setTitle(R.string.info)
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
NavUtil.startURL(activity, getString(R.string.about_source));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.modules.setOnClickListener(new StartFragmentListener(R.id.action_main_fragment_to_modules_fragment, true));
|
||||||
|
binding.download.setOnClickListener(new StartFragmentListener(R.id.action_main_fragment_to_repo_fragment, false));
|
||||||
|
binding.logs.setOnClickListener(new StartFragmentListener(R.id.action_main_fragment_to_logs_fragment, true));
|
||||||
|
binding.settings.setOnClickListener(new StartFragmentListener(R.id.action_main_fragment_to_settings_fragment, false));
|
||||||
|
binding.about.setOnClickListener(v -> {
|
||||||
|
DialogAboutBinding binding = DialogAboutBinding.inflate(LayoutInflater.from(requireActivity()), null, false);
|
||||||
|
binding.sourceCode.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
binding.sourceCode.setTransformationMethod(new LinkTransformationMethod(activity));
|
||||||
|
binding.sourceCode.setText(HtmlCompat.fromHtml(getString(
|
||||||
|
R.string.about_view_source_code,
|
||||||
|
"<b><a href=\"https://github.com/LSPosed/LSPosed\">GitHub</a></b>",
|
||||||
|
"<b><a href=\"https://t.me/LSPosed\">Telegram</a></b>"), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
||||||
|
binding.translators.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
binding.translators.setTransformationMethod(new LinkTransformationMethod(activity));
|
||||||
|
binding.translators.setText(HtmlCompat.fromHtml(getString(R.string.about_translators, getString(R.string.translators)), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
||||||
|
binding.version.setText(String.format(Locale.US, "%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
|
||||||
|
new BlurBehindDialogBuilder(activity)
|
||||||
|
.setView(binding.getRoot())
|
||||||
|
.show();
|
||||||
|
});
|
||||||
|
Glide.with(binding.appIcon)
|
||||||
|
.load(GlideHelper.wrapApplicationInfoForIconLoader(activity.getApplicationInfo()))
|
||||||
|
.into(binding.appIcon);
|
||||||
|
String installXposedVersion = ConfigManager.getXposedVersionName();
|
||||||
|
int cardBackgroundColor;
|
||||||
|
if (installXposedVersion != null) {
|
||||||
|
if (!ConfigManager.isSepolicyLoaded()) {
|
||||||
|
binding.statusTitle.setText(R.string.partial_activated);
|
||||||
|
cardBackgroundColor = ResourcesKt.resolveColor(activity.getTheme(), R.attr.colorWarning);
|
||||||
|
binding.statusIcon.setImageResource(R.drawable.ic_warning);
|
||||||
|
binding.statusSummary.setText(R.string.selinux_policy_not_loaded_summary);
|
||||||
|
} else if (!ConfigManager.systemServerRequested()) {
|
||||||
|
binding.statusTitle.setText(R.string.partial_activated);
|
||||||
|
cardBackgroundColor = ResourcesKt.resolveColor(activity.getTheme(), R.attr.colorWarning);
|
||||||
|
binding.statusIcon.setImageResource(R.drawable.ic_warning);
|
||||||
|
binding.statusSummary.setText(R.string.system_inject_fail_summary);
|
||||||
|
} else {
|
||||||
|
binding.statusTitle.setText(R.string.activated);
|
||||||
|
cardBackgroundColor = ResourcesKt.resolveColor(activity.getTheme(), R.attr.colorNormal);
|
||||||
|
binding.statusIcon.setImageResource(R.drawable.ic_check_circle);
|
||||||
|
binding.statusSummary.setText(String.format(Locale.US, "%s (%d)", installXposedVersion, ConfigManager.getXposedVersionCode()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cardBackgroundColor = ResourcesKt.resolveColor(activity.getTheme(), R.attr.colorInstall);
|
||||||
|
boolean isMagiskInstalled = ConfigManager.isMagiskInstalled();
|
||||||
|
binding.statusTitle.setText(isMagiskInstalled ? R.string.Install : R.string.NotInstall);
|
||||||
|
binding.statusSummary.setText(isMagiskInstalled ? R.string.InstallDetail : R.string.NotInstallDetail);
|
||||||
|
if (!isMagiskInstalled) {
|
||||||
|
binding.status.setOnClickListener(null);
|
||||||
|
binding.download.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
binding.statusIcon.setImageResource(R.drawable.ic_error);
|
||||||
|
Snackbar.make(snackbar, R.string.lsposed_not_active, Snackbar.LENGTH_INDEFINITE).show();
|
||||||
|
}
|
||||||
|
binding.status.setCardBackgroundColor(cardBackgroundColor);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
binding.status.setOutlineSpotShadowColor(cardBackgroundColor);
|
||||||
|
binding.status.setOutlineAmbientShadowColor(cardBackgroundColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StartFragmentListener implements View.OnClickListener {
|
||||||
|
boolean requireInstalled;
|
||||||
|
int fragment;
|
||||||
|
|
||||||
|
StartFragmentListener(int fragment, boolean requireInstalled) {
|
||||||
|
this.fragment = fragment;
|
||||||
|
this.requireInstalled = requireInstalled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (requireInstalled && ConfigManager.getXposedVersionName() == null) {
|
||||||
|
Snackbar.make(snackbar, R.string.lsposed_not_active, Snackbar.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
getNavController().navigate(fragment, null, getNavOptions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
int moduleCount = ModuleUtil.getInstance().getEnabledModulesCount();
|
||||||
|
binding.modulesSummary.setText(getResources().getQuantityString(R.plurals.modules_enabled_count, moduleCount, moduleCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
binding = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
* Copyright (C) 2021 LSPosed Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.lsposed.manager.ui.activity;
|
package org.lsposed.manager.ui.fragment;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
@ -29,7 +29,6 @@ import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
@ -39,7 +38,6 @@ import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
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.app.ActionBar;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
@ -47,13 +45,13 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.google.android.material.tabs.TabLayout;
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
|
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.ActivityLogsBinding;
|
|
||||||
import org.lsposed.manager.databinding.DialogInstallWarningBinding;
|
import org.lsposed.manager.databinding.DialogInstallWarningBinding;
|
||||||
|
import org.lsposed.manager.databinding.FragmentLogsBinding;
|
||||||
import org.lsposed.manager.databinding.ItemLogBinding;
|
import org.lsposed.manager.databinding.ItemLogBinding;
|
||||||
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
|
||||||
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
|
@ -76,23 +74,23 @@ import rikka.insets.WindowInsetsHelperKt;
|
||||||
import rikka.recyclerview.RecyclerViewKt;
|
import rikka.recyclerview.RecyclerViewKt;
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
public class LogsActivity extends BaseActivity {
|
public class LogsFragment extends BaseFragment {
|
||||||
private boolean verbose = false;
|
private boolean verbose = false;
|
||||||
private LogsAdapter adapter;
|
private LogsAdapter adapter;
|
||||||
private final Handler handler = new Handler(Looper.getMainLooper());
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
private ActivityLogsBinding binding;
|
private FragmentLogsBinding binding;
|
||||||
private LinearLayoutManagerFix layoutManager;
|
private LinearLayoutManagerFix layoutManager;
|
||||||
ActivityResultLauncher<String> saveLogsLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
ActivityResultLauncher<String> saveLogsLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
||||||
uri -> {
|
uri -> {
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
try {
|
try {
|
||||||
// grantUriPermission might throw RemoteException on MIUI
|
// grantUriPermission might throw RemoteException on MIUI
|
||||||
grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
requireContext().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
try (var os = getContentResolver().openOutputStream(uri)) {
|
try (var os = requireContext().getContentResolver().openOutputStream(uri)) {
|
||||||
ParcelFileDescriptor parcelFileDescriptor = ConfigManager.getLogs(verbose);
|
ParcelFileDescriptor parcelFileDescriptor = ConfigManager.getLogs(verbose);
|
||||||
if (parcelFileDescriptor == null) {
|
if (parcelFileDescriptor == null) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -107,59 +105,65 @@ public class LogsActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
binding = FragmentLogsBinding.inflate(inflater, container, false);
|
||||||
binding = ActivityLogsBinding.inflate(getLayoutInflater());
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
setAppBar(binding.appBar, binding.toolbar);
|
|
||||||
binding.getRoot().bringChildToFront(binding.appBar);
|
binding.getRoot().bringChildToFront(binding.appBar);
|
||||||
binding.toolbar.setNavigationOnClickListener(view -> onBackPressed());
|
setupToolbar(binding.toolbar, R.string.Logs, R.menu.menu_logs);
|
||||||
binding.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
binding.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
||||||
ActionBar bar = getSupportActionBar();
|
|
||||||
if (bar != null) {
|
|
||||||
bar.setDisplayHomeAsUpEnabled(true);
|
if (!ConfigManager.isVerboseLogEnabled()) {
|
||||||
|
WindowInsetsHelperKt.setInitialPadding(binding.recyclerView, 0, ResourcesKt.resolveDimensionPixelOffset(requireActivity().getTheme(), R.attr.actionBarSize, 0), 0, 0);
|
||||||
|
binding.slidingTabs.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
binding.slidingTabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onTabSelected(TabLayout.Tab tab) {
|
||||||
|
verbose = tab.getPosition() == 1;
|
||||||
|
reloadErrorLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabUnselected(TabLayout.Tab tab) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabReselected(TabLayout.Tab tab) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (!preferences.getBoolean("hide_logcat_warning", false)) {
|
|
||||||
|
adapter = new LogsAdapter();
|
||||||
|
RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true);
|
||||||
|
binding.recyclerView.setAdapter(adapter);
|
||||||
|
layoutManager = new LinearLayoutManagerFix(requireActivity());
|
||||||
|
binding.recyclerView.setLayoutManager(layoutManager);
|
||||||
|
return binding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
|
if (!App.getPreferences().getBoolean("hide_logcat_warning", false)) {
|
||||||
DialogInstallWarningBinding binding = DialogInstallWarningBinding.inflate(getLayoutInflater());
|
DialogInstallWarningBinding binding = DialogInstallWarningBinding.inflate(getLayoutInflater());
|
||||||
binding.getRoot().setOnClickListener(v -> binding.checkbox.toggle());
|
binding.getRoot().setOnClickListener(v -> binding.checkbox.toggle());
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(requireActivity())
|
||||||
.setMessage(R.string.not_logcat_2)
|
.setMessage(R.string.not_logcat_2)
|
||||||
.setView(binding.getRoot())
|
.setView(binding.getRoot())
|
||||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||||
if (binding.checkbox.isChecked()) {
|
if (binding.checkbox.isChecked()) {
|
||||||
preferences.edit().putBoolean("hide_logcat_warning", true).apply();
|
App.getPreferences().edit().putBoolean("hide_logcat_warning", true).apply();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
if (!ConfigManager.isVerboseLogEnabled()) {
|
|
||||||
WindowInsetsHelperKt.setInitialPadding(binding.recyclerView, 0, ResourcesKt.resolveDimensionPixelOffset(getTheme(), R.attr.actionBarSize, 0), 0, 0);
|
|
||||||
binding.slidingTabs.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
adapter = new LogsAdapter();
|
|
||||||
RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true);
|
|
||||||
binding.recyclerView.setAdapter(adapter);
|
|
||||||
layoutManager = new LinearLayoutManagerFix(this);
|
|
||||||
binding.recyclerView.setLayoutManager(layoutManager);
|
|
||||||
binding.slidingTabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
|
||||||
@Override
|
|
||||||
public void onTabSelected(TabLayout.Tab tab) {
|
|
||||||
verbose = tab.getPosition() == 1;
|
|
||||||
reloadErrorLog();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTabUnselected(TabLayout.Tab tab) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTabReselected(TabLayout.Tab tab) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -168,12 +172,6 @@ public class LogsActivity extends BaseActivity {
|
||||||
reloadErrorLog();
|
reloadErrorLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.menu_logs, menu);
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
int itemId = item.getItemId();
|
int itemId = item.getItemId();
|
||||||
|
|
@ -216,7 +214,7 @@ public class LogsActivity extends BaseActivity {
|
||||||
new LogsReader().execute(parcelFileDescriptor.getFileDescriptor());
|
new LogsReader().execute(parcelFileDescriptor.getFileDescriptor());
|
||||||
} else {
|
} else {
|
||||||
binding.slidingTabs.selectTab(binding.slidingTabs.getTabAt(0));
|
binding.slidingTabs.selectTab(binding.slidingTabs.getTabAt(0));
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(requireActivity())
|
||||||
.setMessage(R.string.verbose_log_not_avaliable)
|
.setMessage(R.string.verbose_log_not_avaliable)
|
||||||
.setPositiveButton(android.R.string.ok, null)
|
.setPositiveButton(android.R.string.ok, null)
|
||||||
.show();
|
.show();
|
||||||
|
|
@ -244,7 +242,7 @@ public class LogsActivity extends BaseActivity {
|
||||||
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||||
File cacheFile = new File(getCacheDir(), filename);
|
File cacheFile = new File(requireActivity().getCacheDir(), filename);
|
||||||
try (var os = new FileOutputStream(cacheFile); var is = new FileInputStream(parcelFileDescriptor.getFileDescriptor())) {
|
try (var os = new FileOutputStream(cacheFile); var is = new FileInputStream(parcelFileDescriptor.getFileDescriptor())) {
|
||||||
FileUtils.copy(is, os);
|
FileUtils.copy(is, os);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
@ -252,7 +250,7 @@ public class LogsActivity extends BaseActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uri uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", cacheFile);
|
Uri uri = FileProvider.getUriForFile(requireActivity(), BuildConfig.APPLICATION_ID + ".fileprovider", cacheFile);
|
||||||
Intent sendIntent = new Intent();
|
Intent sendIntent = new Intent();
|
||||||
sendIntent.setAction(Intent.ACTION_SEND);
|
sendIntent.setAction(Intent.ACTION_SEND);
|
||||||
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||||
|
|
@ -279,7 +277,7 @@ public class LogsActivity extends BaseActivity {
|
||||||
private final Runnable mRunnable = new Runnable() {
|
private final Runnable mRunnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!isFinishing()) {
|
if (!requireActivity().isFinishing()) {
|
||||||
mProgressDialog.show();
|
mProgressDialog.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +285,7 @@ public class LogsActivity extends BaseActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
mProgressDialog = new AlertDialog.Builder(LogsActivity.this).create();
|
mProgressDialog = new AlertDialog.Builder(requireActivity()).create();
|
||||||
mProgressDialog.setMessage(getString(R.string.loading));
|
mProgressDialog.setMessage(getString(R.string.loading));
|
||||||
mProgressDialog.setCancelable(false);
|
mProgressDialog.setCancelable(false);
|
||||||
handler.postDelayed(mRunnable, 300);
|
handler.postDelayed(mRunnable, 300);
|
||||||
|
|
@ -305,7 +303,7 @@ public class LogsActivity extends BaseActivity {
|
||||||
logs.add(line);
|
logs.add(line);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logs.add(LogsActivity.this.getResources().getString(R.string.logs_cannot_read));
|
logs.add(requireActivity().getResources().getString(R.string.logs_cannot_read));
|
||||||
if (e.getMessage() != null) {
|
if (e.getMessage() != null) {
|
||||||
logs.addAll(Arrays.asList(e.getMessage().split("\n")));
|
logs.addAll(Arrays.asList(e.getMessage().split("\n")));
|
||||||
}
|
}
|
||||||
|
|
@ -368,6 +366,4 @@ public class LogsActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,24 +1,4 @@
|
||||||
/*
|
package org.lsposed.manager.ui.fragment;
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.lsposed.manager.ui.activity;
|
|
||||||
|
|
||||||
import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
|
import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
|
||||||
|
|
||||||
|
|
@ -39,6 +19,7 @@ import android.text.TextUtils;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.text.style.TypefaceSpan;
|
import android.text.style.TypefaceSpan;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
@ -51,7 +32,6 @@ import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.widget.SearchView;
|
import androidx.appcompat.widget.SearchView;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
|
@ -70,12 +50,11 @@ import org.lsposed.lspd.models.UserInfo;
|
||||||
import org.lsposed.manager.ConfigManager;
|
import org.lsposed.manager.ConfigManager;
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.adapters.AppHelper;
|
import org.lsposed.manager.adapters.AppHelper;
|
||||||
import org.lsposed.manager.databinding.ActivityModuleDetailBinding;
|
|
||||||
import org.lsposed.manager.databinding.DialogRecyclerviewBinding;
|
import org.lsposed.manager.databinding.DialogRecyclerviewBinding;
|
||||||
|
import org.lsposed.manager.databinding.FragmentPagerBinding;
|
||||||
import org.lsposed.manager.databinding.ItemModuleBinding;
|
import org.lsposed.manager.databinding.ItemModuleBinding;
|
||||||
import org.lsposed.manager.databinding.ItemRepoRecyclerviewBinding;
|
import org.lsposed.manager.databinding.ItemRepoRecyclerviewBinding;
|
||||||
import org.lsposed.manager.repo.RepoLoader;
|
import org.lsposed.manager.repo.RepoLoader;
|
||||||
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
|
||||||
import org.lsposed.manager.ui.widget.EmptyStateRecyclerView;
|
import org.lsposed.manager.ui.widget.EmptyStateRecyclerView;
|
||||||
import org.lsposed.manager.util.GlideApp;
|
import org.lsposed.manager.util.GlideApp;
|
||||||
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
||||||
|
|
@ -93,13 +72,14 @@ import rikka.insets.WindowInsetsHelperKt;
|
||||||
import rikka.recyclerview.RecyclerViewKt;
|
import rikka.recyclerview.RecyclerViewKt;
|
||||||
import rikka.widget.borderview.BorderRecyclerView;
|
import rikka.widget.borderview.BorderRecyclerView;
|
||||||
|
|
||||||
public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleListener {
|
public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleListener {
|
||||||
|
|
||||||
protected ActivityModuleDetailBinding binding;
|
protected FragmentPagerBinding binding;
|
||||||
protected SearchView searchView;
|
protected SearchView searchView;
|
||||||
private SearchView.OnQueryTextListener mSearchListener;
|
private SearchView.OnQueryTextListener mSearchListener;
|
||||||
private final PagerAdapter pagerAdapter = new PagerAdapter();
|
private final PagerAdapter pagerAdapter = new PagerAdapter();
|
||||||
private final ArrayList<ModuleAdapter> adapters = new ArrayList<>();
|
private final ArrayList<ModuleAdapter> adapters = new ArrayList<>();
|
||||||
|
private final ArrayList<String> titles = new ArrayList<>();
|
||||||
|
|
||||||
private Handler workHandler;
|
private Handler workHandler;
|
||||||
private PackageManager pm;
|
private PackageManager pm;
|
||||||
|
|
@ -107,23 +87,36 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
private ModuleUtil.InstalledModule selectedModule;
|
private ModuleUtil.InstalledModule selectedModule;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
HandlerThread workThread = new HandlerThread("ModulesActivity WorkHandler");
|
HandlerThread workThread = new HandlerThread("ModulesActivity WorkHandler");
|
||||||
workThread.start();
|
workThread.start();
|
||||||
workHandler = new Handler(workThread.getLooper());
|
workHandler = new Handler(workThread.getLooper());
|
||||||
moduleUtil = ModuleUtil.getInstance();
|
moduleUtil = ModuleUtil.getInstance();
|
||||||
pm = getPackageManager();
|
pm = requireContext().getPackageManager();
|
||||||
moduleUtil.addListener(this);
|
moduleUtil.addListener(this);
|
||||||
super.onCreate(savedInstanceState);
|
mSearchListener = new SearchView.OnQueryTextListener() {
|
||||||
binding = ActivityModuleDetailBinding.inflate(getLayoutInflater());
|
@Override
|
||||||
setContentView(binding.getRoot());
|
public boolean onQueryTextSubmit(String query) {
|
||||||
setAppBar(binding.appBar, binding.toolbar);
|
adapters.forEach(adapter -> adapter.getFilter().filter(query));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextChange(String newText) {
|
||||||
|
adapters.forEach(adapter -> adapter.getFilter().filter(newText));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
binding = FragmentPagerBinding.inflate(inflater, container, false);
|
||||||
|
|
||||||
binding.getRoot().bringChildToFront(binding.appBar);
|
binding.getRoot().bringChildToFront(binding.appBar);
|
||||||
binding.toolbar.setNavigationOnClickListener(view -> onBackPressed());
|
setupToolbar(binding.toolbar, R.string.Modules, R.menu.menu_modules);
|
||||||
ActionBar bar = getSupportActionBar();
|
|
||||||
if (bar != null) {
|
|
||||||
bar.setDisplayHomeAsUpEnabled(true);
|
|
||||||
}
|
|
||||||
binding.viewPager.setAdapter(new PagerAdapter());
|
binding.viewPager.setAdapter(new PagerAdapter());
|
||||||
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -138,19 +131,19 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
binding.fab.setOnClickListener(view -> {
|
binding.fab.setOnClickListener(v -> {
|
||||||
var pickAdaptor = new ModuleAdapter(null, true);
|
var pickAdaptor = new ModuleAdapter(null, true);
|
||||||
var position = binding.viewPager.getCurrentItem();
|
var position = binding.viewPager.getCurrentItem();
|
||||||
var snapshot = adapters.get(position).snapshot().stream().map(m -> m.packageName).collect(Collectors.toSet());
|
var snapshot = adapters.get(position).snapshot().stream().map(m -> m.packageName).collect(Collectors.toSet());
|
||||||
var user = adapters.get(position).getUser();
|
var user = adapters.get(position).getUser();
|
||||||
pickAdaptor.setFilter(m -> !snapshot.contains(m.packageName));
|
pickAdaptor.setFilter(m -> !snapshot.contains(m.packageName));
|
||||||
pickAdaptor.refresh();
|
pickAdaptor.refresh();
|
||||||
var v = DialogRecyclerviewBinding.inflate(getLayoutInflater()).getRoot();
|
var rv = DialogRecyclerviewBinding.inflate(getLayoutInflater()).getRoot();
|
||||||
v.setAdapter(pickAdaptor);
|
rv.setAdapter(pickAdaptor);
|
||||||
v.setLayoutManager(new LinearLayoutManagerFix(ModulesActivity.this));
|
rv.setLayoutManager(new LinearLayoutManagerFix(requireActivity()));
|
||||||
var dialog = new AlertDialog.Builder(ModulesActivity.this)
|
var dialog = new AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(getString(R.string.install_to_user, user.name))
|
.setTitle(getString(R.string.install_to_user, user.name))
|
||||||
.setView(v)
|
.setView(rv)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.show();
|
.show();
|
||||||
pickAdaptor.setOnPickListener(picked -> {
|
pickAdaptor.setOnPickListener(picked -> {
|
||||||
|
|
@ -160,43 +153,26 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
mSearchListener = new SearchView.OnQueryTextListener() {
|
return binding.getRoot();
|
||||||
@Override
|
}
|
||||||
public boolean onQueryTextSubmit(String query) {
|
|
||||||
adapters.forEach(adapter -> adapter.getFilter().filter(query));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextChange(String newText) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
adapters.forEach(adapter -> adapter.getFilter().filter(newText));
|
super.onCreate(savedInstanceState);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (ConfigManager.getXposedVersionName() == null) {
|
if (ConfigManager.getXposedVersionName() == null) {
|
||||||
Toast.makeText(this, R.string.lsposed_not_active, Toast.LENGTH_LONG).show();
|
Toast.makeText(requireContext(), R.string.lsposed_not_active, Toast.LENGTH_LONG).show();
|
||||||
finish();
|
getNavController().navigateUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public void onPrepareOptionsMenu(Menu menu) {
|
||||||
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||||
searchView.setOnQueryTextListener(mSearchListener);
|
searchView.setOnQueryTextListener(mSearchListener);
|
||||||
return super.onPrepareOptionsMenu(menu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onResume() {
|
||||||
if (searchView.isIconified()) {
|
|
||||||
super.onBackPressed();
|
|
||||||
} else {
|
|
||||||
searchView.setIconified(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
super.onResume();
|
||||||
var users = ConfigManager.getUsers();
|
var users = ConfigManager.getUsers();
|
||||||
if (users != null) {
|
if (users != null) {
|
||||||
|
|
@ -204,14 +180,12 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
adapters.clear();
|
adapters.clear();
|
||||||
if (users.size() != 1) {
|
if (users.size() != 1) {
|
||||||
binding.viewPager.setUserInputEnabled(true);
|
binding.viewPager.setUserInputEnabled(true);
|
||||||
ArrayList<String> titles = new ArrayList<>();
|
|
||||||
for (var user : users) {
|
for (var user : users) {
|
||||||
var adapter = new ModuleAdapter(user);
|
var adapter = new ModuleAdapter(user);
|
||||||
adapter.setHasStableIds(true);
|
adapter.setHasStableIds(true);
|
||||||
adapters.add(adapter);
|
adapters.add(adapter);
|
||||||
titles.add(user.name);
|
titles.add(user.name);
|
||||||
}
|
}
|
||||||
new TabLayoutMediator(binding.tabLayout, binding.viewPager, (tab, position) -> tab.setText(titles.get(position))).attach();
|
|
||||||
binding.tabLayout.setVisibility(View.VISIBLE);
|
binding.tabLayout.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
binding.viewPager.setUserInputEnabled(false);
|
binding.viewPager.setUserInputEnabled(false);
|
||||||
|
|
@ -222,16 +196,13 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
}
|
}
|
||||||
pagerAdapter.notifyDataSetChanged();
|
pagerAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
if (users.size() != 1) {
|
||||||
|
new TabLayoutMediator(binding.tabLayout, binding.viewPager, (tab, position) -> tab.setText(titles.get(position))).attach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
adapters.forEach(ModuleAdapter::refresh);
|
adapters.forEach(ModuleAdapter::refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.menu_modules, menu);
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
@ -253,18 +224,18 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installModuleToUser(ModuleUtil.InstalledModule module, UserInfo user) {
|
private void installModuleToUser(ModuleUtil.InstalledModule module, UserInfo user) {
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(getString(R.string.install_to_user, user.name))
|
.setTitle(getString(R.string.install_to_user, user.name))
|
||||||
.setMessage(getString(R.string.install_to_user_message, module.getAppName(), user.name))
|
.setMessage(getString(R.string.install_to_user_message, module.getAppName(), user.name))
|
||||||
.setPositiveButton(android.R.string.ok, (dialog, which) ->
|
.setPositiveButton(android.R.string.ok, (dialog, which) ->
|
||||||
workHandler.post(() -> {
|
workHandler.post(() -> {
|
||||||
var success = ConfigManager.installExistingPackageAsUser(module.packageName, user.id);
|
var success = ConfigManager.installExistingPackageAsUser(module.packageName, user.id);
|
||||||
runOnUiThread(() -> {
|
requireActivity().runOnUiThread(() -> {
|
||||||
String text = success ? getString(R.string.module_installed, module.getAppName(), user.name) : getString(R.string.module_install_failed);
|
String text = success ? getString(R.string.module_installed, module.getAppName(), user.name) : getString(R.string.module_install_failed);
|
||||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
||||||
Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_SHORT).show();
|
Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(ModulesActivity.this, text, Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireActivity(), text, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (success)
|
if (success)
|
||||||
|
|
@ -302,18 +273,18 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
ConfigManager.startActivityAsUserWithFeature(new Intent(ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", selectedModule.packageName, null)), selectedModule.userId);
|
ConfigManager.startActivityAsUserWithFeature(new Intent(ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", selectedModule.packageName, null)), selectedModule.userId);
|
||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.menu_uninstall) {
|
} else if (itemId == R.id.menu_uninstall) {
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(selectedModule.getAppName())
|
.setTitle(selectedModule.getAppName())
|
||||||
.setMessage(R.string.module_uninstall_message)
|
.setMessage(R.string.module_uninstall_message)
|
||||||
.setPositiveButton(android.R.string.ok, (dialog, which) ->
|
.setPositiveButton(android.R.string.ok, (dialog, which) ->
|
||||||
workHandler.post(() -> {
|
workHandler.post(() -> {
|
||||||
boolean success = ConfigManager.uninstallPackage(selectedModule.packageName, selectedModule.userId);
|
boolean success = ConfigManager.uninstallPackage(selectedModule.packageName, selectedModule.userId);
|
||||||
runOnUiThread(() -> {
|
requireActivity().runOnUiThread(() -> {
|
||||||
String text = success ? getString(R.string.module_uninstalled, selectedModule.getAppName()) : getString(R.string.module_uninstall_failed);
|
String text = success ? getString(R.string.module_uninstalled, selectedModule.getAppName()) : getString(R.string.module_uninstall_failed);
|
||||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
||||||
Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_SHORT).show();
|
Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(ModulesActivity.this, text, Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireActivity(), text, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (success)
|
if (success)
|
||||||
|
|
@ -323,11 +294,10 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
.show();
|
.show();
|
||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.menu_repo) {
|
} else if (itemId == R.id.menu_repo) {
|
||||||
Intent intent = new Intent();
|
Bundle bundle = new Bundle();
|
||||||
intent.setClass(this, RepoItemActivity.class);
|
bundle.putString("modulePackageName", selectedModule.packageName);
|
||||||
intent.putExtra("modulePackageName", selectedModule.packageName);
|
bundle.putString("moduleName", selectedModule.getAppName());
|
||||||
intent.putExtra("moduleName", selectedModule.getAppName());
|
getNavController().navigate(R.id.action_modules_fragment_to_repo_item_fragment, bundle, getNavOptions());
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.onContextItemSelected(item);
|
return super.onContextItemSelected(item);
|
||||||
|
|
@ -344,11 +314,11 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull PagerAdapter.ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull PagerAdapter.ViewHolder holder, int position) {
|
||||||
if (getItemCount() == 1) {
|
if (getItemCount() == 1) {
|
||||||
WindowInsetsHelperKt.setInitialPadding(holder.recyclerView, 0, ResourcesKt.resolveDimensionPixelOffset(getTheme(), R.attr.actionBarSize, 0), 0, 0);
|
WindowInsetsHelperKt.setInitialPadding(holder.recyclerView, 0, ResourcesKt.resolveDimensionPixelOffset(requireActivity().getTheme(), R.attr.actionBarSize, 0), 0, 0);
|
||||||
}
|
}
|
||||||
holder.recyclerView.setTag(position);
|
holder.recyclerView.setTag(position);
|
||||||
holder.recyclerView.setAdapter(adapters.get(position));
|
holder.recyclerView.setAdapter(adapters.get(position));
|
||||||
holder.recyclerView.setLayoutManager(new LinearLayoutManagerFix(ModulesActivity.this));
|
holder.recyclerView.setLayoutManager(new LinearLayoutManagerFix(requireActivity()));
|
||||||
holder.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
holder.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
||||||
holder.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
holder.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -403,12 +373,12 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ModuleAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
return new ViewHolder(ItemModuleBinding.inflate(getLayoutInflater(), parent, false));
|
return new ModuleAdapter.ViewHolder(ItemModuleBinding.inflate(getLayoutInflater(), parent, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ModuleAdapter.ViewHolder holder, int position) {
|
||||||
ModuleUtil.InstalledModule item = showList.get(position);
|
ModuleUtil.InstalledModule item = showList.get(position);
|
||||||
String appName;
|
String appName;
|
||||||
if (item.userId != 0) {
|
if (item.userId != 0) {
|
||||||
|
|
@ -451,7 +421,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
if (warningText != null) {
|
if (warningText != null) {
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
sb.append(warningText);
|
sb.append(warningText);
|
||||||
final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(ContextCompat.getColor(ModulesActivity.this, R.color.material_red_500));
|
final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(ContextCompat.getColor(requireActivity(), R.color.material_red_500));
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
final TypefaceSpan typefaceSpan = new TypefaceSpan(Typeface.create("sans-serif-medium", Typeface.NORMAL));
|
final TypefaceSpan typefaceSpan = new TypefaceSpan(Typeface.create("sans-serif-medium", Typeface.NORMAL));
|
||||||
sb.setSpan(typefaceSpan, sb.length() - warningText.length(), sb.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
sb.setSpan(typefaceSpan, sb.length() - warningText.length(), sb.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||||
|
|
@ -466,17 +436,17 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
if (!isPick) {
|
if (!isPick) {
|
||||||
holder.root.setAlpha(moduleUtil.isModuleEnabled(item.packageName) ? 1.0f : .5f);
|
holder.root.setAlpha(moduleUtil.isModuleEnabled(item.packageName) ? 1.0f : .5f);
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
Intent intent = new Intent(ModulesActivity.this, AppListActivity.class);
|
Bundle bundle = new Bundle();
|
||||||
intent.putExtra("modulePackageName", item.packageName);
|
bundle.putString("modulePackageName", item.packageName);
|
||||||
intent.putExtra("moduleUserId", item.userId);
|
bundle.putInt("moduleUserId", item.userId);
|
||||||
startActivity(intent);
|
getNavController().navigate(R.id.action_modules_fragment_to_app_list_fragment, bundle, getNavOptions());
|
||||||
});
|
});
|
||||||
holder.itemView.setOnLongClickListener(v -> {
|
holder.itemView.setOnLongClickListener(v -> {
|
||||||
selectedModule = item;
|
selectedModule = item;
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> {
|
holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> {
|
||||||
getMenuInflater().inflate(R.menu.context_menu_modules, menu);
|
requireActivity().getMenuInflater().inflate(R.menu.context_menu_modules, menu);
|
||||||
menu.setHeaderTitle(item.getAppName());
|
menu.setHeaderTitle(item.getAppName());
|
||||||
Intent intent = AppHelper.getSettingsIntent(item.packageName, item.userId);
|
Intent intent = AppHelper.getSettingsIntent(item.packageName, item.userId);
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
|
|
@ -523,7 +493,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Filter getFilter() {
|
public Filter getFilter() {
|
||||||
return new ApplicationFilter();
|
return new ModuleAdapter.ApplicationFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFilter(@NonNull Predicate<ModuleUtil.InstalledModule> filter) {
|
public void setFilter(@NonNull Predicate<ModuleUtil.InstalledModule> filter) {
|
||||||
|
|
@ -544,7 +514,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
|
|
||||||
public void refresh(boolean force) {
|
public void refresh(boolean force) {
|
||||||
if (force) moduleUtil.reloadInstalledModules();
|
if (force) moduleUtil.reloadInstalledModules();
|
||||||
runOnUiThread(reloadModules);
|
requireActivity().runOnUiThread(reloadModules);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Runnable reloadModules = new Runnable() {
|
private final Runnable reloadModules = new Runnable() {
|
||||||
|
|
@ -565,7 +535,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
searchList.clear();
|
searchList.clear();
|
||||||
searchList.addAll(tmpList);
|
searchList.addAll(tmpList);
|
||||||
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
|
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
|
||||||
runOnUiThread(() -> getFilter().filter(queryStr));
|
requireActivity().runOnUiThread(() -> getFilter().filter(queryStr));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1,50 +1,35 @@
|
||||||
/*
|
package org.lsposed.manager.ui.fragment;
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.lsposed.manager.ui.activity;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Filter;
|
import android.widget.Filter;
|
||||||
|
import android.widget.Filterable;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.widget.SearchView;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
import org.lsposed.manager.App;
|
||||||
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.FragmentRepoBinding;
|
||||||
import org.lsposed.manager.databinding.ItemOnlinemoduleBinding;
|
import org.lsposed.manager.databinding.ItemOnlinemoduleBinding;
|
||||||
import org.lsposed.manager.repo.RepoLoader;
|
import org.lsposed.manager.repo.RepoLoader;
|
||||||
import org.lsposed.manager.repo.model.OnlineModule;
|
import org.lsposed.manager.repo.model.OnlineModule;
|
||||||
import org.lsposed.manager.ui.activity.base.ListActivity;
|
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -55,41 +40,89 @@ import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import rikka.core.util.LabelComparator;
|
import rikka.core.util.LabelComparator;
|
||||||
|
import rikka.recyclerview.RecyclerViewKt;
|
||||||
|
|
||||||
|
public class RepoFragment extends BaseFragment implements RepoLoader.Listener {
|
||||||
|
protected FragmentRepoBinding binding;
|
||||||
|
protected SearchView searchView;
|
||||||
|
private SearchView.OnQueryTextListener mSearchListener;
|
||||||
|
|
||||||
public class RepoActivity extends ListActivity implements RepoLoader.Listener {
|
|
||||||
private final RepoLoader repoLoader = RepoLoader.getInstance();
|
private final RepoLoader repoLoader = RepoLoader.getInstance();
|
||||||
private RepoAdapter adapter;
|
private RepoAdapter adapter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
repoLoader.addListener(this);
|
repoLoader.addListener(this);
|
||||||
|
mSearchListener = new SearchView.OnQueryTextListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextSubmit(String query) {
|
||||||
|
adapter.getFilter().filter(query);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextChange(String newText) {
|
||||||
|
adapter.getFilter().filter(newText);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
binding = FragmentRepoBinding.inflate(getLayoutInflater(), container, false);
|
||||||
|
binding.getRoot().bringChildToFront(binding.appBar);
|
||||||
|
setupToolbar(binding.toolbar, R.string.module_repo, R.menu.menu_repo);
|
||||||
|
binding.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
||||||
|
adapter = new RepoAdapter();
|
||||||
|
adapter.setHasStableIds(true);
|
||||||
|
binding.recyclerView.setAdapter(adapter);
|
||||||
|
binding.recyclerView.setHasFixedSize(true);
|
||||||
|
binding.recyclerView.setLayoutManager(new LinearLayoutManagerFix(requireActivity()));
|
||||||
|
RecyclerViewKt.addFastScroller(binding.recyclerView, binding.recyclerView);
|
||||||
|
RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true);
|
||||||
|
binding.progress.setVisibilityAfterHide(View.GONE);
|
||||||
|
return binding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
if (ConfigManager.getXposedVersionName() == null && !ConfigManager.isMagiskInstalled()) {
|
if (ConfigManager.getXposedVersionName() == null && !ConfigManager.isMagiskInstalled()) {
|
||||||
Toast.makeText(this, R.string.lsposed_not_active, Toast.LENGTH_LONG).show();
|
Toast.makeText(requireActivity(), R.string.lsposed_not_active, Toast.LENGTH_LONG).show();
|
||||||
finish();
|
getNavController().navigateUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BaseAdapter<?> createAdapter() {
|
public void onPrepareOptionsMenu(Menu menu) {
|
||||||
return adapter = new RepoAdapter();
|
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||||
|
searchView.setOnQueryTextListener(mSearchListener);
|
||||||
|
int sort = App.getPreferences().getInt("repo_sort", 0);
|
||||||
|
if (sort == 0) {
|
||||||
|
menu.findItem(R.id.item_sort_by_name).setChecked(true);
|
||||||
|
} else if (sort == 1) {
|
||||||
|
menu.findItem(R.id.item_sort_by_update_time).setChecked(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
repoLoader.removeListener(this);
|
repoLoader.removeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
adapter.initData();
|
adapter.initData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void repoLoaded() {
|
public void repoLoaded() {
|
||||||
runOnUiThread(() -> {
|
requireActivity().runOnUiThread(() -> {
|
||||||
binding.progress.hide();
|
binding.progress.hide();
|
||||||
adapter.setData(repoLoader.getOnlineModules());
|
adapter.setData(repoLoader.getOnlineModules());
|
||||||
});
|
});
|
||||||
|
|
@ -115,29 +148,17 @@ public class RepoActivity extends ListActivity implements RepoLoader.Listener {
|
||||||
repoLoader.loadRemoteData();
|
repoLoader.loadRemoteData();
|
||||||
} else if (itemId == R.id.item_sort_by_name) {
|
} else if (itemId == R.id.item_sort_by_name) {
|
||||||
item.setChecked(true);
|
item.setChecked(true);
|
||||||
preferences.edit().putInt("repo_sort", 0).apply();
|
App.getPreferences().edit().putInt("repo_sort", 0).apply();
|
||||||
adapter.setData(repoLoader.getOnlineModules());
|
adapter.setData(repoLoader.getOnlineModules());
|
||||||
} else if (itemId == R.id.item_sort_by_update_time) {
|
} else if (itemId == R.id.item_sort_by_update_time) {
|
||||||
item.setChecked(true);
|
item.setChecked(true);
|
||||||
preferences.edit().putInt("repo_sort", 1).apply();
|
App.getPreferences().edit().putInt("repo_sort", 1).apply();
|
||||||
adapter.setData(repoLoader.getOnlineModules());
|
adapter.setData(repoLoader.getOnlineModules());
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private class RepoAdapter extends RecyclerView.Adapter<RepoAdapter.ViewHolder> implements Filterable {
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.menu_repo, menu);
|
|
||||||
int sort = preferences.getInt("repo_sort", 0);
|
|
||||||
if (sort == 0) {
|
|
||||||
menu.findItem(R.id.item_sort_by_name).setChecked(true);
|
|
||||||
} else if (sort == 1) {
|
|
||||||
menu.findItem(R.id.item_sort_by_update_time).setChecked(true);
|
|
||||||
}
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RepoAdapter extends BaseAdapter<RepoAdapter.ViewHolder> {
|
|
||||||
private List<OnlineModule> fullList, showList;
|
private List<OnlineModule> fullList, showList;
|
||||||
private final LabelComparator labelComparator = new LabelComparator();
|
private final LabelComparator labelComparator = new LabelComparator();
|
||||||
|
|
||||||
|
|
@ -147,12 +168,12 @@ public class RepoActivity extends ListActivity implements RepoLoader.Listener {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public RepoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
return new ViewHolder(ItemOnlinemoduleBinding.inflate(getLayoutInflater(), parent, false));
|
return new RepoAdapter.ViewHolder(ItemOnlinemoduleBinding.inflate(getLayoutInflater(), parent, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull RepoAdapter.ViewHolder holder, int position) {
|
||||||
OnlineModule module = showList.get(position);
|
OnlineModule module = showList.get(position);
|
||||||
holder.appName.setText(module.getDescription());
|
holder.appName.setText(module.getDescription());
|
||||||
SpannableStringBuilder sb = new SpannableStringBuilder(module.getName());
|
SpannableStringBuilder sb = new SpannableStringBuilder(module.getName());
|
||||||
|
|
@ -163,11 +184,10 @@ public class RepoActivity extends ListActivity implements RepoLoader.Listener {
|
||||||
}
|
}
|
||||||
holder.appDescription.setText(sb);
|
holder.appDescription.setText(sb);
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
Intent intent = new Intent();
|
Bundle bundle = new Bundle();
|
||||||
intent.setClass(RepoActivity.this, RepoItemActivity.class);
|
bundle.putString("modulePackageName", module.getName());
|
||||||
intent.putExtra("modulePackageName", module.getName());
|
bundle.putString("moduleName", module.getDescription());
|
||||||
intent.putExtra("moduleName", module.getDescription());
|
getNavController().navigate(R.id.action_repo_fragment_to_repo_item_fragment, bundle, getNavOptions());
|
||||||
startActivity(intent);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,14 +199,14 @@ public class RepoActivity extends ListActivity implements RepoLoader.Listener {
|
||||||
public void setData(Collection<OnlineModule> modules) {
|
public void setData(Collection<OnlineModule> modules) {
|
||||||
fullList = new ArrayList<>(modules);
|
fullList = new ArrayList<>(modules);
|
||||||
fullList = fullList.stream().filter((onlineModule -> !onlineModule.isHide())).collect(Collectors.toList());
|
fullList = fullList.stream().filter((onlineModule -> !onlineModule.isHide())).collect(Collectors.toList());
|
||||||
int sort = preferences.getInt("repo_sort", 0);
|
int sort = App.getPreferences().getInt("repo_sort", 0);
|
||||||
if (sort == 0) {
|
if (sort == 0) {
|
||||||
fullList.sort((o1, o2) -> labelComparator.compare(o1.getDescription(), o2.getDescription()));
|
fullList.sort((o1, o2) -> labelComparator.compare(o1.getDescription(), o2.getDescription()));
|
||||||
} else if (sort == 1) {
|
} else if (sort == 1) {
|
||||||
fullList.sort(Collections.reverseOrder(Comparator.comparing(o -> Instant.parse(o.getReleases().get(0).getUpdatedAt()))));
|
fullList.sort(Collections.reverseOrder(Comparator.comparing(o -> Instant.parse(o.getReleases().get(0).getUpdatedAt()))));
|
||||||
}
|
}
|
||||||
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
|
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
|
||||||
runOnUiThread(() -> getFilter().filter(queryStr));
|
requireActivity().runOnUiThread(() -> getFilter().filter(queryStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initData() {
|
public void initData() {
|
||||||
|
|
@ -206,7 +226,7 @@ public class RepoActivity extends ListActivity implements RepoLoader.Listener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Filter getFilter() {
|
public Filter getFilter() {
|
||||||
return new ModuleFilter();
|
return new RepoAdapter.ModuleFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder extends RecyclerView.ViewHolder {
|
class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
@ -1,24 +1,4 @@
|
||||||
/*
|
package org.lsposed.manager.ui.fragment;
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.lsposed.manager.ui.activity;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
|
|
@ -26,7 +6,7 @@ import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.ClickableSpan;
|
import android.text.style.ClickableSpan;
|
||||||
import android.text.util.Linkify;
|
import android.text.util.Linkify;
|
||||||
import android.view.Menu;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
@ -34,7 +14,6 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
@ -46,7 +25,7 @@ import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.google.android.material.tabs.TabLayoutMediator;
|
import com.google.android.material.tabs.TabLayoutMediator;
|
||||||
|
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.databinding.ActivityModuleDetailBinding;
|
import org.lsposed.manager.databinding.FragmentPagerBinding;
|
||||||
import org.lsposed.manager.databinding.ItemRepoLoadmoreBinding;
|
import org.lsposed.manager.databinding.ItemRepoLoadmoreBinding;
|
||||||
import org.lsposed.manager.databinding.ItemRepoReadmeBinding;
|
import org.lsposed.manager.databinding.ItemRepoReadmeBinding;
|
||||||
import org.lsposed.manager.databinding.ItemRepoRecyclerviewBinding;
|
import org.lsposed.manager.databinding.ItemRepoRecyclerviewBinding;
|
||||||
|
|
@ -57,7 +36,6 @@ import org.lsposed.manager.repo.model.Collaborator;
|
||||||
import org.lsposed.manager.repo.model.OnlineModule;
|
import org.lsposed.manager.repo.model.OnlineModule;
|
||||||
import org.lsposed.manager.repo.model.Release;
|
import org.lsposed.manager.repo.model.Release;
|
||||||
import org.lsposed.manager.repo.model.ReleaseAsset;
|
import org.lsposed.manager.repo.model.ReleaseAsset;
|
||||||
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
|
||||||
import org.lsposed.manager.ui.widget.LinkifyTextView;
|
import org.lsposed.manager.ui.widget.LinkifyTextView;
|
||||||
import org.lsposed.manager.util.GlideApp;
|
import org.lsposed.manager.util.GlideApp;
|
||||||
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
||||||
|
|
@ -83,38 +61,21 @@ import rikka.widget.borderview.BorderNestedScrollView;
|
||||||
import rikka.widget.borderview.BorderRecyclerView;
|
import rikka.widget.borderview.BorderRecyclerView;
|
||||||
import rikka.widget.borderview.BorderView;
|
import rikka.widget.borderview.BorderView;
|
||||||
|
|
||||||
public class RepoItemActivity extends BaseActivity implements RepoLoader.Listener {
|
public class RepoItemFragment extends BaseFragment implements RepoLoader.Listener {
|
||||||
ActivityModuleDetailBinding binding;
|
FragmentPagerBinding binding;
|
||||||
private Markwon markwon;
|
private Markwon markwon;
|
||||||
private OnlineModule module;
|
private OnlineModule module;
|
||||||
private ReleaseAdapter releaseAdapter;
|
private ReleaseAdapter releaseAdapter;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
RepoLoader.getInstance().addListener(this);
|
binding = FragmentPagerBinding.inflate(getLayoutInflater(), container, false);
|
||||||
super.onCreate(savedInstanceState);
|
String modulePackageName = getArguments().getString("modulePackageName");
|
||||||
binding = ActivityModuleDetailBinding.inflate(getLayoutInflater());
|
String moduleName = getArguments().getString("moduleName");
|
||||||
String modulePackageName = getIntent().getStringExtra("modulePackageName");
|
|
||||||
String moduleName = getIntent().getStringExtra("moduleName");
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
setAppBar(binding.appBar, binding.toolbar);
|
|
||||||
binding.getRoot().bringChildToFront(binding.appBar);
|
binding.getRoot().bringChildToFront(binding.appBar);
|
||||||
binding.toolbar.setNavigationOnClickListener(view -> onBackPressed());
|
setupToolbar(binding.toolbar, moduleName, R.menu.menu_repo_item);
|
||||||
ActionBar bar = getSupportActionBar();
|
binding.toolbar.setSubtitle(modulePackageName);
|
||||||
assert bar != null;
|
|
||||||
bar.setTitle(moduleName);
|
|
||||||
bar.setSubtitle(modulePackageName);
|
|
||||||
bar.setDisplayHomeAsUpEnabled(true);
|
|
||||||
markwon = Markwon.builder(this)
|
|
||||||
.usePlugin(StrikethroughPlugin.create())
|
|
||||||
.usePlugin(TablePlugin.create(this))
|
|
||||||
.usePlugin(TaskListPlugin.create(this))
|
|
||||||
.usePlugin(HtmlPlugin.create())
|
|
||||||
.usePlugin(GlideImagesPlugin.create(GlideApp.with(this)))
|
|
||||||
.usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS, true))
|
|
||||||
.usePlugin(SoftBreakAddsNewLinePlugin.create())
|
|
||||||
.build();
|
|
||||||
module = RepoLoader.getInstance().getOnlineModule(modulePackageName);
|
|
||||||
binding.viewPager.setAdapter(new PagerAdapter());
|
binding.viewPager.setAdapter(new PagerAdapter());
|
||||||
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -128,19 +89,38 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
});
|
});
|
||||||
int[] titles = new int[]{R.string.module_readme, R.string.module_releases, R.string.module_information};
|
int[] titles = new int[]{R.string.module_readme, R.string.module_releases, R.string.module_information};
|
||||||
new TabLayoutMediator(binding.tabLayout, binding.viewPager, (tab, position) -> tab.setText(titles[position])).attach();
|
new TabLayoutMediator(binding.tabLayout, binding.viewPager, (tab, position) -> tab.setText(titles[position])).attach();
|
||||||
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
getMenuInflater().inflate(R.menu.menu_repo_item, menu);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
return super.onCreateOptionsMenu(menu);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
RepoLoader.getInstance().addListener(this);
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
markwon = Markwon.builder(requireActivity())
|
||||||
|
.usePlugin(StrikethroughPlugin.create())
|
||||||
|
.usePlugin(TablePlugin.create(requireActivity()))
|
||||||
|
.usePlugin(TaskListPlugin.create(requireActivity()))
|
||||||
|
.usePlugin(HtmlPlugin.create())
|
||||||
|
.usePlugin(GlideImagesPlugin.create(GlideApp.with(this)))
|
||||||
|
.usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS, true))
|
||||||
|
.usePlugin(SoftBreakAddsNewLinePlugin.create())
|
||||||
|
.build();
|
||||||
|
String modulePackageName = getArguments().getString("modulePackageName");
|
||||||
|
module = RepoLoader.getInstance().getOnlineModule(modulePackageName);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
int id = item.getItemId();
|
int id = item.getItemId();
|
||||||
if (id == R.id.menu_open_in_browser) {
|
if (id == R.id.menu_open_in_browser) {
|
||||||
NavUtil.startURL(this, "https://modules.lsposed.org/module/" + module.getName());
|
NavUtil.startURL(requireActivity(), "https://modules.lsposed.org/module/" + module.getName());
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +134,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
public void moduleReleasesLoaded(OnlineModule module) {
|
public void moduleReleasesLoaded(OnlineModule module) {
|
||||||
this.module = module;
|
this.module = module;
|
||||||
if (releaseAdapter != null) {
|
if (releaseAdapter != null) {
|
||||||
runOnUiThread(() -> releaseAdapter.loadItems());
|
requireActivity().runOnUiThread(() -> releaseAdapter.loadItems());
|
||||||
if (module.getReleases().size() == 1) {
|
if (module.getReleases().size() == 1) {
|
||||||
Snackbar.make(binding.snackbar, R.string.module_release_no_more, Snackbar.LENGTH_SHORT).show();
|
Snackbar.make(binding.snackbar, R.string.module_release_no_more, Snackbar.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +144,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
@Override
|
@Override
|
||||||
public void onThrowable(Throwable t) {
|
public void onThrowable(Throwable t) {
|
||||||
if (releaseAdapter != null) {
|
if (releaseAdapter != null) {
|
||||||
runOnUiThread(() -> releaseAdapter.loadItems());
|
requireActivity().runOnUiThread(() -> releaseAdapter.loadItems());
|
||||||
}
|
}
|
||||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
||||||
Snackbar.make(binding.snackbar, getString(R.string.repo_load_failed, t.getLocalizedMessage()), Snackbar.LENGTH_SHORT).show();
|
Snackbar.make(binding.snackbar, getString(R.string.repo_load_failed, t.getLocalizedMessage()), Snackbar.LENGTH_SHORT).show();
|
||||||
|
|
@ -172,7 +152,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
RepoLoader.getInstance().removeListener(this);
|
RepoLoader.getInstance().removeListener(this);
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +198,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
Collaborator collaborator = iterator.next();
|
Collaborator collaborator = iterator.next();
|
||||||
String name = collaborator.getName() == null ? collaborator.getLogin() : collaborator.getName();
|
String name = collaborator.getName() == null ? collaborator.getLogin() : collaborator.getName();
|
||||||
sb.append(name);
|
sb.append(name);
|
||||||
CustomTabsURLSpan span = new CustomTabsURLSpan(RepoItemActivity.this, String.format("https://github.com/%s", collaborator.getLogin()));
|
CustomTabsURLSpan span = new CustomTabsURLSpan(requireActivity(), String.format("https://github.com/%s", collaborator.getLogin()));
|
||||||
sb.setSpan(span, sb.length() - name.length(), sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
sb.setSpan(span, sb.length() - name.length(), sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
if (iterator.hasNext()) {
|
if (iterator.hasNext()) {
|
||||||
sb.append(", ");
|
sb.append(", ");
|
||||||
|
|
@ -231,7 +211,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
}
|
}
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
if (position == homepageRow) {
|
if (position == homepageRow) {
|
||||||
NavUtil.startURL(RepoItemActivity.this, module.getHomepageUrl());
|
NavUtil.startURL(requireActivity(), module.getHomepageUrl());
|
||||||
} else if (position == collaboratorsRow) {
|
} else if (position == collaboratorsRow) {
|
||||||
ClickableSpan span = holder.description.getCurrentSpan();
|
ClickableSpan span = holder.description.getCurrentSpan();
|
||||||
holder.description.clearCurrentSpan();
|
holder.description.clearCurrentSpan();
|
||||||
|
|
@ -240,7 +220,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
span.onClick(v);
|
span.onClick(v);
|
||||||
}
|
}
|
||||||
} else if (position == sourceUrlRow) {
|
} else if (position == sourceUrlRow) {
|
||||||
NavUtil.startURL(RepoItemActivity.this, module.getSourceUrl());
|
NavUtil.startURL(requireActivity(), module.getSourceUrl());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -277,16 +257,16 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ReleaseAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
if (viewType == 0) {
|
if (viewType == 0) {
|
||||||
return new ReleaseViewHolder(ItemRepoReleaseBinding.inflate(getLayoutInflater(), parent, false));
|
return new ReleaseAdapter.ReleaseViewHolder(ItemRepoReleaseBinding.inflate(getLayoutInflater(), parent, false));
|
||||||
} else {
|
} else {
|
||||||
return new LoadmoreViewHolder(ItemRepoLoadmoreBinding.inflate(getLayoutInflater(), parent, false));
|
return new ReleaseAdapter.LoadmoreViewHolder(ItemRepoLoadmoreBinding.inflate(getLayoutInflater(), parent, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ReleaseAdapter.ViewHolder holder, int position) {
|
||||||
if (position == items.size()) {
|
if (position == items.size()) {
|
||||||
holder.progress.setVisibility(View.GONE);
|
holder.progress.setVisibility(View.GONE);
|
||||||
holder.title.setVisibility(View.VISIBLE);
|
holder.title.setVisibility(View.VISIBLE);
|
||||||
|
|
@ -300,18 +280,18 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
} else {
|
} else {
|
||||||
Release release = items.get(position);
|
Release release = items.get(position);
|
||||||
holder.title.setText(release.getName());
|
holder.title.setText(release.getName());
|
||||||
holder.description.setTransformationMethod(new LinkTransformationMethod(RepoItemActivity.this));
|
holder.description.setTransformationMethod(new LinkTransformationMethod(requireActivity()));
|
||||||
holder.description.setSpannableFactory(NoCopySpannableFactory.getInstance());
|
holder.description.setSpannableFactory(NoCopySpannableFactory.getInstance());
|
||||||
markwon.setMarkdown(holder.description, release.getDescription());
|
markwon.setMarkdown(holder.description, release.getDescription());
|
||||||
holder.description.setMovementMethod(null);
|
holder.description.setMovementMethod(null);
|
||||||
holder.openInBrowser.setOnClickListener(v -> NavUtil.startURL(RepoItemActivity.this, release.getUrl()));
|
holder.openInBrowser.setOnClickListener(v -> NavUtil.startURL(requireActivity(), release.getUrl()));
|
||||||
List<ReleaseAsset> assets = release.getReleaseAssets();
|
List<ReleaseAsset> assets = release.getReleaseAssets();
|
||||||
if (assets != null && !assets.isEmpty()) {
|
if (assets != null && !assets.isEmpty()) {
|
||||||
holder.viewAssets.setOnClickListener(v -> {
|
holder.viewAssets.setOnClickListener(v -> {
|
||||||
ArrayList<String> names = new ArrayList<>();
|
ArrayList<String> names = new ArrayList<>();
|
||||||
assets.forEach(releaseAsset -> names.add(releaseAsset.getName()));
|
assets.forEach(releaseAsset -> names.add(releaseAsset.getName()));
|
||||||
new AlertDialog.Builder(RepoItemActivity.this)
|
new AlertDialog.Builder(requireActivity())
|
||||||
.setItems(names.toArray(new String[0]), (dialog, which) -> NavUtil.startURL(RepoItemActivity.this, assets.get(which).getDownloadUrl()))
|
.setItems(names.toArray(new String[0]), (dialog, which) -> NavUtil.startURL(requireActivity(), assets.get(which).getDownloadUrl()))
|
||||||
.show();
|
.show();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -350,7 +330,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReleaseViewHolder extends ViewHolder {
|
class ReleaseViewHolder extends ReleaseAdapter.ViewHolder {
|
||||||
public ReleaseViewHolder(ItemRepoReleaseBinding binding) {
|
public ReleaseViewHolder(ItemRepoReleaseBinding binding) {
|
||||||
super(binding.getRoot());
|
super(binding.getRoot());
|
||||||
title = binding.title;
|
title = binding.title;
|
||||||
|
|
@ -360,7 +340,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LoadmoreViewHolder extends ViewHolder {
|
class LoadmoreViewHolder extends ReleaseAdapter.ViewHolder {
|
||||||
public LoadmoreViewHolder(ItemRepoLoadmoreBinding binding) {
|
public LoadmoreViewHolder(ItemRepoLoadmoreBinding binding) {
|
||||||
super(binding.getRoot());
|
super(binding.getRoot());
|
||||||
title = binding.title;
|
title = binding.title;
|
||||||
|
|
@ -375,17 +355,17 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
@Override
|
@Override
|
||||||
public PagerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public PagerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
if (viewType == 0) {
|
if (viewType == 0) {
|
||||||
return new ReadmeViewHolder(ItemRepoReadmeBinding.inflate(getLayoutInflater(), parent, false));
|
return new PagerAdapter.ReadmeViewHolder(ItemRepoReadmeBinding.inflate(getLayoutInflater(), parent, false));
|
||||||
} else {
|
} else {
|
||||||
return new RecyclerviewBinding(ItemRepoRecyclerviewBinding.inflate(getLayoutInflater(), parent, false));
|
return new PagerAdapter.RecyclerviewBinding(ItemRepoRecyclerviewBinding.inflate(getLayoutInflater(), parent, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull PagerAdapter.ViewHolder holder, int position) {
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 0:
|
case 0:
|
||||||
holder.textView.setTransformationMethod(new LinkTransformationMethod(RepoItemActivity.this));
|
holder.textView.setTransformationMethod(new LinkTransformationMethod(requireActivity()));
|
||||||
holder.scrollView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
holder.scrollView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
||||||
holder.scrollView.setTag(position);
|
holder.scrollView.setTag(position);
|
||||||
markwon.setMarkdown(holder.textView, module.getReadme());
|
markwon.setMarkdown(holder.textView, module.getReadme());
|
||||||
|
|
@ -398,7 +378,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
holder.recyclerView.setAdapter(new InformationAdapter(module));
|
holder.recyclerView.setAdapter(new InformationAdapter(module));
|
||||||
}
|
}
|
||||||
holder.recyclerView.setTag(position);
|
holder.recyclerView.setTag(position);
|
||||||
holder.recyclerView.setLayoutManager(new LinearLayoutManagerFix(RepoItemActivity.this));
|
holder.recyclerView.setLayoutManager(new LinearLayoutManagerFix(requireActivity()));
|
||||||
holder.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
holder.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top));
|
||||||
RecyclerViewKt.fixEdgeEffect(holder.recyclerView, false, true);
|
RecyclerViewKt.fixEdgeEffect(holder.recyclerView, false, true);
|
||||||
RecyclerViewKt.addFastScroller(holder.recyclerView, holder.itemView);
|
RecyclerViewKt.addFastScroller(holder.recyclerView, holder.itemView);
|
||||||
|
|
@ -426,7 +406,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReadmeViewHolder extends ViewHolder {
|
class ReadmeViewHolder extends PagerAdapter.ViewHolder {
|
||||||
public ReadmeViewHolder(ItemRepoReadmeBinding binding) {
|
public ReadmeViewHolder(ItemRepoReadmeBinding binding) {
|
||||||
super(binding.getRoot());
|
super(binding.getRoot());
|
||||||
textView = binding.readme;
|
textView = binding.readme;
|
||||||
|
|
@ -434,7 +414,7 @@ public class RepoItemActivity extends BaseActivity implements RepoLoader.Listene
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RecyclerviewBinding extends ViewHolder {
|
class RecyclerviewBinding extends PagerAdapter.ViewHolder {
|
||||||
public RecyclerviewBinding(ItemRepoRecyclerviewBinding binding) {
|
public RecyclerviewBinding(ItemRepoRecyclerviewBinding binding) {
|
||||||
super(binding.getRoot());
|
super(binding.getRoot());
|
||||||
recyclerView = binding.recyclerView;
|
recyclerView = binding.recyclerView;
|
||||||
|
|
@ -0,0 +1,262 @@
|
||||||
|
package org.lsposed.manager.ui.fragment;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import com.takisoft.preferencex.PreferenceCategory;
|
||||||
|
import com.takisoft.preferencex.PreferenceFragmentCompat;
|
||||||
|
|
||||||
|
import org.lsposed.manager.App;
|
||||||
|
import org.lsposed.manager.BuildConfig;
|
||||||
|
import org.lsposed.manager.ConfigManager;
|
||||||
|
import org.lsposed.manager.R;
|
||||||
|
import org.lsposed.manager.databinding.FragmentSettingsBinding;
|
||||||
|
import org.lsposed.manager.ui.activity.MainActivity;
|
||||||
|
import org.lsposed.manager.util.BackupUtils;
|
||||||
|
import org.lsposed.manager.util.theme.ThemeUtil;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import rikka.core.util.ResourceUtils;
|
||||||
|
import rikka.material.app.DayNightDelegate;
|
||||||
|
import rikka.recyclerview.RecyclerViewKt;
|
||||||
|
import rikka.widget.borderview.BorderRecyclerView;
|
||||||
|
|
||||||
|
public class SettingsFragment extends BaseFragment {
|
||||||
|
FragmentSettingsBinding binding;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
binding = FragmentSettingsBinding.inflate(inflater, container, false);
|
||||||
|
binding.getRoot().bringChildToFront(binding.appBar);
|
||||||
|
setupToolbar(binding.toolbar, R.string.Settings);
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
getChildFragmentManager().beginTransaction()
|
||||||
|
.add(R.id.container, new PreferenceFragment()).commit();
|
||||||
|
}
|
||||||
|
return binding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
if (ConfigManager.getXposedVersionName() == null) {
|
||||||
|
Snackbar.make(binding.snackbar, R.string.lsposed_not_active, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class PreferenceFragment extends PreferenceFragmentCompat {
|
||||||
|
ActivityResultLauncher<String> backupLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
||||||
|
uri -> {
|
||||||
|
if (uri != null) {
|
||||||
|
try {
|
||||||
|
// grantUriPermission might throw RemoteException on MIUI
|
||||||
|
requireActivity().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
||||||
|
.setCancelable(false)
|
||||||
|
.setMessage(R.string.settings_backuping)
|
||||||
|
.show();
|
||||||
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
|
boolean success = BackupUtils.backup(requireContext(), uri);
|
||||||
|
try {
|
||||||
|
SettingsFragment fragment = (SettingsFragment) getParentFragment();
|
||||||
|
requireActivity().runOnUiThread(() -> {
|
||||||
|
alertDialog.dismiss();
|
||||||
|
fragment.makeSnackBar(success ? R.string.settings_backup_success : R.string.settings_backup_failed, Snackbar.LENGTH_SHORT);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ActivityResultLauncher<String[]> restoreLauncher = registerForActivityResult(new ActivityResultContracts.OpenDocument(),
|
||||||
|
uri -> {
|
||||||
|
if (uri != null) {
|
||||||
|
try {
|
||||||
|
// grantUriPermission might throw RemoteException on MIUI
|
||||||
|
requireActivity().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
||||||
|
.setCancelable(false)
|
||||||
|
.setMessage(R.string.settings_restoring)
|
||||||
|
.show();
|
||||||
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
|
boolean success = BackupUtils.restore(requireContext(), uri);
|
||||||
|
try {
|
||||||
|
SettingsFragment fragment = (SettingsFragment) getParentFragment();
|
||||||
|
requireActivity().runOnUiThread(() -> {
|
||||||
|
alertDialog.dismiss();
|
||||||
|
fragment.makeSnackBar(success ? R.string.settings_restore_success : R.string.settings_restore_failed, Snackbar.LENGTH_SHORT);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreatePreferencesFix(Bundle savedInstanceState, String rootKey) {
|
||||||
|
addPreferencesFromResource(R.xml.prefs);
|
||||||
|
|
||||||
|
boolean installed = ConfigManager.getXposedVersionName() != null;
|
||||||
|
SwitchPreference prefVerboseLogs = findPreference("disable_verbose_log");
|
||||||
|
if (prefVerboseLogs != null) {
|
||||||
|
if (requireActivity().getApplicationInfo().uid / 100000 != 0) {
|
||||||
|
prefVerboseLogs.setVisible(false);
|
||||||
|
} else {
|
||||||
|
prefVerboseLogs.setEnabled(installed);
|
||||||
|
prefVerboseLogs.setChecked(!ConfigManager.isVerboseLogEnabled());
|
||||||
|
prefVerboseLogs.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
boolean result = ConfigManager.setVerboseLogEnabled(!(boolean) newValue);
|
||||||
|
SettingsFragment fragment = (SettingsFragment) getParentFragment();
|
||||||
|
if (result && fragment != null) {
|
||||||
|
Snackbar.make(fragment.binding.snackbar, R.string.reboot_required, Snackbar.LENGTH_SHORT)
|
||||||
|
.setAction(R.string.reboot, v -> ConfigManager.reboot(false, null, false))
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchPreference prefEnableResources = findPreference("enable_resources");
|
||||||
|
if (prefEnableResources != null) {
|
||||||
|
prefEnableResources.setEnabled(installed);
|
||||||
|
prefEnableResources.setChecked(ConfigManager.isResourceHookEnabled());
|
||||||
|
prefEnableResources.setOnPreferenceChangeListener((preference, newValue) -> ConfigManager.setResourceHookEnabled((boolean) newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
Preference backup = findPreference("backup");
|
||||||
|
if (backup != null) {
|
||||||
|
backup.setEnabled(installed);
|
||||||
|
backup.setOnPreferenceClickListener(preference -> {
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
backupLauncher.launch(String.format(Locale.US,
|
||||||
|
"LSPosed_%04d%02d%02d_%02d%02d%02d.lsp",
|
||||||
|
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||||
|
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||||
|
now.get(Calendar.MINUTE), now.get(Calendar.SECOND)));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Preference restore = findPreference("restore");
|
||||||
|
if (restore != null) {
|
||||||
|
restore.setEnabled(installed);
|
||||||
|
restore.setOnPreferenceClickListener(preference -> {
|
||||||
|
restoreLauncher.launch(new String[]{"*/*"});
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Preference theme = findPreference("dark_theme");
|
||||||
|
if (theme != null) {
|
||||||
|
theme.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
if (!App.getPreferences().getString("dark_theme", ThemeUtil.MODE_NIGHT_FOLLOW_SYSTEM).equals(newValue)) {
|
||||||
|
DayNightDelegate.setDefaultNightMode(ThemeUtil.getDarkTheme((String) newValue));
|
||||||
|
MainActivity activity = (MainActivity) getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Preference black_dark_theme = findPreference("black_dark_theme");
|
||||||
|
if (black_dark_theme != null) {
|
||||||
|
black_dark_theme.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
MainActivity activity = (MainActivity) getActivity();
|
||||||
|
if (activity != null && ResourceUtils.isNightMode(getResources().getConfiguration())) {
|
||||||
|
activity.restart();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Preference primary_color = findPreference("theme_color");
|
||||||
|
if (primary_color != null) {
|
||||||
|
primary_color.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
MainActivity activity = (MainActivity) getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.restart();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferenceCategory prefGroupSystem = findPreference("settings_group_system");
|
||||||
|
SwitchPreference prefShowHiddenIcons = findPreference("show_hidden_icon_apps_enabled");
|
||||||
|
if (prefGroupSystem != null && prefShowHiddenIcons != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
||||||
|
&& requireActivity().checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
prefGroupSystem.setVisible(true);
|
||||||
|
prefShowHiddenIcons.setVisible(true);
|
||||||
|
prefShowHiddenIcons.setChecked(Settings.Global.getInt(
|
||||||
|
requireActivity().getContentResolver(), "show_hidden_icon_apps_enabled", 1) != 0);
|
||||||
|
prefShowHiddenIcons.setOnPreferenceChangeListener((preference, newValue) -> Settings.Global.putInt(requireActivity().getContentResolver(),
|
||||||
|
"show_hidden_icon_apps_enabled", (boolean) newValue ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchPreference prefFollowSystemAccent = findPreference("follow_system_accent");
|
||||||
|
if (prefFollowSystemAccent != null && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S || Build.VERSION.SDK_INT == Build.VERSION_CODES.R && Build.VERSION.PREVIEW_SDK_INT != 0)) {
|
||||||
|
if (primary_color != null) {
|
||||||
|
primary_color.setVisible(!prefFollowSystemAccent.isChecked());
|
||||||
|
}
|
||||||
|
prefFollowSystemAccent.setVisible(true);
|
||||||
|
prefFollowSystemAccent.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
MainActivity activity = (MainActivity) getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.restart();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
|
||||||
|
BorderRecyclerView recyclerView = (BorderRecyclerView) super.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||||
|
RecyclerViewKt.fixEdgeEffect(recyclerView, false, true);
|
||||||
|
recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> {
|
||||||
|
SettingsFragment fragment = (SettingsFragment) getParentFragment();
|
||||||
|
if (fragment != null) {
|
||||||
|
fragment.binding.appBar.setRaised(!top);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return recyclerView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void makeSnackBar(@StringRes int text, @Snackbar.Duration int duration) {
|
||||||
|
Snackbar.make(binding.snackbar, text, duration).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
package org.lsposed.manager.util;
|
package org.lsposed.manager.util;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.browser.customtabs.CustomTabColorSchemeParams;
|
import androidx.browser.customtabs.CustomTabColorSchemeParams;
|
||||||
|
|
@ -32,7 +33,7 @@ import rikka.core.util.ResourceUtils;
|
||||||
|
|
||||||
public final class NavUtil {
|
public final class NavUtil {
|
||||||
|
|
||||||
public static void startURL(BaseActivity activity, Uri uri) {
|
public static void startURL(Activity activity, Uri uri) {
|
||||||
CustomTabsIntent.Builder customTabsIntent = new CustomTabsIntent.Builder();
|
CustomTabsIntent.Builder customTabsIntent = new CustomTabsIntent.Builder();
|
||||||
customTabsIntent.setShowTitle(true);
|
customTabsIntent.setShowTitle(true);
|
||||||
CustomTabColorSchemeParams params = new CustomTabColorSchemeParams.Builder()
|
CustomTabColorSchemeParams params = new CustomTabColorSchemeParams.Builder()
|
||||||
|
|
@ -46,7 +47,7 @@ public final class NavUtil {
|
||||||
customTabsIntent.build().launchUrl(activity, uri);
|
customTabsIntent.build().launchUrl(activity, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void startURL(BaseActivity activity, String url) {
|
public static void startURL(Activity activity, String url) {
|
||||||
startURL(activity, Uri.parse(url));
|
startURL(activity, Uri.parse(url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import android.content.Intent;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.ui.activity.AppListActivity;
|
import org.lsposed.manager.ui.activity.MainActivity;
|
||||||
|
|
||||||
public final class NotificationUtil {
|
public final class NotificationUtil {
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ public final class NotificationUtil {
|
||||||
String title = context.getString(enabled ? R.string.xposed_module_updated_notification_title : R.string.module_is_not_activated_yet);
|
String title = context.getString(enabled ? R.string.xposed_module_updated_notification_title : R.string.module_is_not_activated_yet);
|
||||||
String content = context.getString(enabled ? R.string.xposed_module_updated_notification_content : R.string.module_is_not_activated_yet_detailed, moduleName);
|
String content = context.getString(enabled ? R.string.xposed_module_updated_notification_content : R.string.module_is_not_activated_yet_detailed, moduleName);
|
||||||
|
|
||||||
Intent intent = new Intent(context, AppListActivity.class)
|
Intent intent = new Intent(context, MainActivity.class)
|
||||||
.putExtra("modulePackageName", modulePackageName)
|
.putExtra("modulePackageName", modulePackageName)
|
||||||
.putExtra("moduleUserId", moduleUserId)
|
.putExtra("moduleUserId", moduleUserId)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
package org.lsposed.manager.util.chrome;
|
package org.lsposed.manager.util.chrome;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.text.style.URLSpan;
|
import android.text.style.URLSpan;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
|
@ -28,9 +29,9 @@ import org.lsposed.manager.util.NavUtil;
|
||||||
|
|
||||||
public class CustomTabsURLSpan extends URLSpan {
|
public class CustomTabsURLSpan extends URLSpan {
|
||||||
|
|
||||||
private final BaseActivity activity;
|
private final Activity activity;
|
||||||
|
|
||||||
public CustomTabsURLSpan(BaseActivity activity, String url) {
|
public CustomTabsURLSpan(Activity activity, String url) {
|
||||||
super(url);
|
super(url);
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
package org.lsposed.manager.util.chrome;
|
package org.lsposed.manager.util.chrome;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
|
@ -32,9 +33,9 @@ import org.lsposed.manager.ui.activity.base.BaseActivity;
|
||||||
|
|
||||||
public class LinkTransformationMethod implements TransformationMethod {
|
public class LinkTransformationMethod implements TransformationMethod {
|
||||||
|
|
||||||
private final BaseActivity activity;
|
private final Activity activity;
|
||||||
|
|
||||||
public LinkTransformationMethod(BaseActivity activity) {
|
public LinkTransformationMethod(Activity activity) {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:autoMirrored="true">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" />
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:consumeSystemWindowsInsets="start|end"
|
||||||
|
app:edgeToEdge="true"
|
||||||
|
app:fitsSystemWindowsInsets="start|end">
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/snackbar"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<include layout="@layout/fragment_home" />
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/guideline"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintGuide_begin="@dimen/item_width" />
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/tablet_nav_container"
|
||||||
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/container_margin"
|
||||||
|
app:defaultNavHost="false"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:navGraph="@navigation/sub_nav_graph" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -1,321 +1,21 @@
|
||||||
<!--
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
~ This file is part of LSPosed.
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
~
|
|
||||||
~ LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
~ it under the terms of the GNU General Public License as published by
|
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
|
||||||
~ (at your option) any later version.
|
|
||||||
~
|
|
||||||
~ LSPosed is distributed in the hope that it will be useful,
|
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
~ GNU General Public License for more details.
|
|
||||||
~
|
|
||||||
~ You should have received a copy of the GNU General Public License
|
|
||||||
~ along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
~
|
|
||||||
~ Copyright (C) 2020 EdXposed Contributors
|
|
||||||
~ Copyright (C) 2021 LSPosed Contributors
|
|
||||||
-->
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/snackbar"
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
app:consumeSystemWindowsInsets="start|end"
|
|
||||||
app:edgeToEdge="true"
|
|
||||||
app:fitsSystemWindowsInsets="start|end">
|
|
||||||
|
|
||||||
<FrameLayout
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
android:id="@+id/nav_host_fragment"
|
||||||
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
app:defaultNavHost="true"
|
||||||
android:clipChildren="false"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:fitsSystemWindowsInsets="top|bottom"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
tools:ignore="MissingPrefix">
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:navGraph="@navigation/nav_graph" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
android:id="@+id/nestedScrollView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:scrollbars="none">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
android:orientation="vertical"
|
|
||||||
tools:context=".ui.activity.MainActivity">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="72dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:clipChildren="false"
|
|
||||||
android:clipToPadding="false">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/app_icon"
|
|
||||||
android:layout_width="42dp"
|
|
||||||
android:layout_height="42dp"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:contentDescription="@string/app_name" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:layout_toEndOf="@id/app_icon"
|
|
||||||
android:contentDescription="@string/app_name"
|
|
||||||
android:text="@string/app_name"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Title"
|
|
||||||
android:textSize="20sp"
|
|
||||||
tools:ignore="RelativeOverlap" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/status"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:foreground="?attr/selectableItemBackground"
|
|
||||||
app:cardBackgroundColor="#4CAF50"
|
|
||||||
app:cardCornerRadius="8dp"
|
|
||||||
app:cardElevation="4dp"
|
|
||||||
app:cardPreventCornerOverlap="false">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="18dp"
|
|
||||||
android:paddingTop="20dp"
|
|
||||||
android:paddingEnd="18dp"
|
|
||||||
android:paddingBottom="20dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/status_icon"
|
|
||||||
android:layout_width="28dp"
|
|
||||||
android:layout_height="28dp"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
app:srcCompat="@drawable/ic_check_circle"
|
|
||||||
app:tint="?android:attr/textColorPrimaryInverse" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/status_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="25dp"
|
|
||||||
android:layout_toEndOf="@id/status_icon"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
|
||||||
android:textColor="?android:attr/textColorPrimaryInverse" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/status_summary"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/status_title"
|
|
||||||
android:layout_alignStart="@id/status_title"
|
|
||||||
android:layout_marginTop="5dp"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
|
||||||
android:textColor="?android:attr/textColorPrimaryInverse" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/modules"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:foreground="?attr/selectableItemBackground"
|
|
||||||
android:outlineAmbientShadowColor="#3A000000"
|
|
||||||
android:outlineSpotShadowColor="#3A000000"
|
|
||||||
app:cardCornerRadius="8dp"
|
|
||||||
app:cardElevation="4dp"
|
|
||||||
app:cardPreventCornerOverlap="false">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="18dp"
|
|
||||||
android:paddingTop="16dp"
|
|
||||||
android:paddingEnd="18dp"
|
|
||||||
android:paddingBottom="16dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/modules_icon"
|
|
||||||
android:layout_width="28dp"
|
|
||||||
android:layout_height="28dp"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:contentDescription="@string/Modules"
|
|
||||||
app:srcCompat="@drawable/ic_extension" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/modules_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="25dp"
|
|
||||||
android:layout_toEndOf="@id/modules_icon"
|
|
||||||
android:text="@string/Modules"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/modules_summary"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/modules_title"
|
|
||||||
android:layout_alignStart="@id/modules_title"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
|
||||||
android:textColor="@android:color/darker_gray" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/download"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:foreground="?attr/selectableItemBackground"
|
|
||||||
android:outlineAmbientShadowColor="#3A000000"
|
|
||||||
android:outlineSpotShadowColor="#3A000000"
|
|
||||||
app:cardCornerRadius="8dp"
|
|
||||||
app:cardElevation="4dp"
|
|
||||||
app:cardPreventCornerOverlap="false">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="18dp"
|
|
||||||
android:paddingTop="16dp"
|
|
||||||
android:paddingEnd="18dp"
|
|
||||||
android:paddingBottom="16dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/download_icon"
|
|
||||||
android:layout_width="28dp"
|
|
||||||
android:layout_height="28dp"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:contentDescription="@string/module_repo"
|
|
||||||
app:srcCompat="@drawable/ic_get_app" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/download_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="25dp"
|
|
||||||
android:layout_toEndOf="@id/download_icon"
|
|
||||||
android:text="@string/module_repo"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/download_summary"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/download_title"
|
|
||||||
android:layout_alignStart="@id/download_title"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:text="@string/module_repo_summary"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
|
||||||
android:textColor="@android:color/darker_gray" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/logs"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:background="@drawable/item_background_round_nopadding"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="18dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="28dp"
|
|
||||||
android:layout_height="28dp"
|
|
||||||
android:contentDescription="@string/Logs"
|
|
||||||
app:srcCompat="@drawable/ic_assignment" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="25dp"
|
|
||||||
android:text="@string/Logs"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/settings"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:background="@drawable/item_background_round_nopadding"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="18dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="28dp"
|
|
||||||
android:layout_height="28dp"
|
|
||||||
android:contentDescription="@string/Settings"
|
|
||||||
app:srcCompat="@drawable/ic_settings" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="25dp"
|
|
||||||
android:text="@string/Settings"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/about"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:background="@drawable/item_background_round_nopadding"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="18dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="28dp"
|
|
||||||
android:layout_height="28dp"
|
|
||||||
android:contentDescription="@string/About"
|
|
||||||
app:srcCompat="@drawable/ic_info" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="25dp"
|
|
||||||
android:text="@string/About"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
</FrameLayout>
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,325 @@
|
||||||
|
<!--
|
||||||
|
~ This file is part of LSPosed.
|
||||||
|
~
|
||||||
|
~ LSPosed is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ LSPosed is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
~
|
||||||
|
~ Copyright (C) 2020 EdXposed Contributors
|
||||||
|
~ Copyright (C) 2021 LSPosed Contributors
|
||||||
|
-->
|
||||||
|
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:clipChildren="false"
|
||||||
|
app:fitsSystemWindowsInsets="top|bottom"
|
||||||
|
tools:ignore="MissingPrefix">
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/nestedScrollView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:context=".ui.activity.MainActivity">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/app_icon"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:contentDescription="@string/app_name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_toEndOf="@id/app_icon"
|
||||||
|
android:contentDescription="@string/app_name"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Title"
|
||||||
|
android:textSize="20sp"
|
||||||
|
tools:ignore="RelativeOverlap" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="86dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
app:cardBackgroundColor="#4CAF50"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="4dp"
|
||||||
|
app:cardPreventCornerOverlap="false">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/holiday_header"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="18dp"
|
||||||
|
android:paddingTop="20dp"
|
||||||
|
android:paddingEnd="18dp"
|
||||||
|
android:paddingBottom="20dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/status_icon"
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
app:srcCompat="@drawable/ic_check_circle"
|
||||||
|
app:tint="?android:attr/textColorPrimaryInverse" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="25dp"
|
||||||
|
android:layout_toEndOf="@id/status_icon"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:textColor="?android:attr/textColorPrimaryInverse" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status_summary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/status_title"
|
||||||
|
android:layout_alignStart="@id/status_title"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
android:textColor="?android:attr/textColorPrimaryInverse" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/modules"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:outlineAmbientShadowColor="#3A000000"
|
||||||
|
android:outlineSpotShadowColor="#3A000000"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="4dp"
|
||||||
|
app:cardPreventCornerOverlap="false">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="18dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingEnd="18dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/modules_icon"
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:contentDescription="@string/Modules"
|
||||||
|
app:srcCompat="@drawable/ic_extension" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/modules_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="25dp"
|
||||||
|
android:layout_toEndOf="@id/modules_icon"
|
||||||
|
android:text="@string/Modules"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/modules_summary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/modules_title"
|
||||||
|
android:layout_alignStart="@id/modules_title"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
android:textColor="@android:color/darker_gray" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/download"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:outlineAmbientShadowColor="#3A000000"
|
||||||
|
android:outlineSpotShadowColor="#3A000000"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="4dp"
|
||||||
|
app:cardPreventCornerOverlap="false">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="18dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingEnd="18dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/download_icon"
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:contentDescription="@string/module_repo"
|
||||||
|
app:srcCompat="@drawable/ic_get_app" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/download_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="25dp"
|
||||||
|
android:layout_toEndOf="@id/download_icon"
|
||||||
|
android:text="@string/module_repo"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/download_summary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/download_title"
|
||||||
|
android:layout_alignStart="@id/download_title"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:text="@string/module_repo_summary"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
android:textColor="@android:color/darker_gray" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/logs"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:background="@drawable/item_background_round_nopadding"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="18dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:contentDescription="@string/Logs"
|
||||||
|
app:srcCompat="@drawable/ic_assignment" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="25dp"
|
||||||
|
android:text="@string/Logs"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/settings"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:background="@drawable/item_background_round_nopadding"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="18dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:contentDescription="@string/Settings"
|
||||||
|
app:srcCompat="@drawable/ic_settings" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="25dp"
|
||||||
|
android:text="@string/Settings"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/about"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:background="@drawable/item_background_round_nopadding"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="18dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:contentDescription="@string/About"
|
||||||
|
app:srcCompat="@drawable/ic_info" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="25dp"
|
||||||
|
android:text="@string/About"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
</FrameLayout>
|
||||||
|
</merge>
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Adding the same root's ID for view binding as other layout configurations -->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:consumeSystemWindowsInsets="start|end"
|
||||||
|
app:edgeToEdge="true"
|
||||||
|
app:fitsSystemWindowsInsets="start|end">
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/snackbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<include layout="@layout/fragment_home" />
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/nav_graph"
|
||||||
|
app:startDestination="@id/main_fragment">
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/main_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.HomeFragment"
|
||||||
|
android:label="MainFragment" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_main_fragment_to_settings_fragment"
|
||||||
|
app:destination="@id/settings_fragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_main_fragment_to_logs_fragment"
|
||||||
|
app:destination="@id/logs_fragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_main_fragment_to_repo_fragment"
|
||||||
|
app:destination="@id/repo_fragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_main_fragment_to_modules_fragment"
|
||||||
|
app:destination="@id/modules_fragment" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/logs_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.LogsFragment"
|
||||||
|
android:label="logs" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/modules_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.ModulesFragment"
|
||||||
|
android:label="modules" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_modules_fragment_to_app_list_fragment"
|
||||||
|
app:destination="@id/app_list_fragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_modules_fragment_to_repo_item_fragment"
|
||||||
|
app:destination="@id/repo_item_fragment" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/settings_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.SettingsFragment"
|
||||||
|
android:label="settings" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/app_list_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.AppListFragment"
|
||||||
|
android:label="app_list" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/repo_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.RepoFragment"
|
||||||
|
android:label="repo" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_repo_fragment_to_repo_item_fragment"
|
||||||
|
app:destination="@id/repo_item_fragment" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/repo_item_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.RepoItemFragment"
|
||||||
|
android:label="repo_item" />
|
||||||
|
</navigation>
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/nav_graph_details"
|
||||||
|
app:startDestination="@id/modules_fragment">
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/logs_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.LogsFragment"
|
||||||
|
android:label="logs" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/modules_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.ModulesFragment"
|
||||||
|
android:label="modules" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_modules_fragment_to_app_list_fragment"
|
||||||
|
app:destination="@id/app_list_fragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_modules_fragment_to_repo_item_fragment"
|
||||||
|
app:destination="@id/repo_item_fragment" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/settings_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.SettingsFragment"
|
||||||
|
android:label="settings" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/app_list_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.AppListFragment"
|
||||||
|
android:label="app_list" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/repo_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.RepoFragment"
|
||||||
|
android:label="repo" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_repo_fragment_to_repo_item_fragment"
|
||||||
|
app:destination="@id/repo_item_fragment" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/repo_item_fragment"
|
||||||
|
android:name="org.lsposed.manager.ui.fragment.RepoItemFragment"
|
||||||
|
android:label="repo_item" />
|
||||||
|
</navigation>
|
||||||
|
|
@ -22,4 +22,6 @@
|
||||||
<dimen name="app_icon_size">48dp</dimen>
|
<dimen name="app_icon_size">48dp</dimen>
|
||||||
<dimen name="tab_layout_height">48dp</dimen>
|
<dimen name="tab_layout_height">48dp</dimen>
|
||||||
<dimen name="colorpickerpreference_widget_size">32dp</dimen>
|
<dimen name="colorpickerpreference_widget_size">32dp</dimen>
|
||||||
</resources>
|
<dimen name="item_width">400dp</dimen>
|
||||||
|
<dimen name="container_margin">8dp</dimen>
|
||||||
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -28,29 +28,32 @@
|
||||||
android:shortcutShortLabel="@string/Modules">
|
android:shortcutShortLabel="@string/Modules">
|
||||||
<intent
|
<intent
|
||||||
android:action="android.intent.action.MAIN"
|
android:action="android.intent.action.MAIN"
|
||||||
android:targetClass="org.lsposed.manager.ui.activity.ModulesActivity"
|
android:targetClass="org.lsposed.manager.ui.activity.MainActivity"
|
||||||
|
android:data="modules"
|
||||||
android:targetPackage="org.lsposed.manager" />
|
android:targetPackage="org.lsposed.manager" />
|
||||||
</shortcut>
|
</shortcut>
|
||||||
<shortcut
|
<shortcut
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:icon="@drawable/shortcut_ic_logs"
|
android:icon="@drawable/shortcut_ic_logs"
|
||||||
android:shortcutId="log"
|
android:shortcutId="logs"
|
||||||
android:shortcutLongLabel="@string/Logs"
|
android:shortcutLongLabel="@string/Logs"
|
||||||
android:shortcutShortLabel="@string/Logs">
|
android:shortcutShortLabel="@string/Logs">
|
||||||
<intent
|
<intent
|
||||||
android:action="android.intent.action.MAIN"
|
android:action="android.intent.action.MAIN"
|
||||||
android:targetClass="org.lsposed.manager.ui.activity.LogsActivity"
|
android:targetClass="org.lsposed.manager.ui.activity.MainActivity"
|
||||||
|
android:data="logs"
|
||||||
android:targetPackage="org.lsposed.manager" />
|
android:targetPackage="org.lsposed.manager" />
|
||||||
</shortcut>
|
</shortcut>
|
||||||
<shortcut
|
<shortcut
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:icon="@drawable/shortcut_ic_repo"
|
android:icon="@drawable/shortcut_ic_repo"
|
||||||
android:shortcutId="Repo"
|
android:shortcutId="repo"
|
||||||
android:shortcutLongLabel="@string/module_repo"
|
android:shortcutLongLabel="@string/module_repo"
|
||||||
android:shortcutShortLabel="@string/module_repo">
|
android:shortcutShortLabel="@string/module_repo">
|
||||||
<intent
|
<intent
|
||||||
android:action="android.intent.action.MAIN"
|
android:action="android.intent.action.MAIN"
|
||||||
android:targetClass="org.lsposed.manager.ui.activity.RepoActivity"
|
android:targetClass="org.lsposed.manager.ui.activity.MainActivity"
|
||||||
|
android:data="repo"
|
||||||
android:targetPackage="org.lsposed.manager" />
|
android:targetPackage="org.lsposed.manager" />
|
||||||
</shortcut>
|
</shortcut>
|
||||||
</shortcuts>
|
</shortcuts>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue