UI improvements

This commit is contained in:
tehcneko 2021-01-30 17:20:55 +08:00
parent 9379ffbca5
commit 32136b62d7
12 changed files with 253 additions and 312 deletions

View File

@ -1,20 +1,12 @@
package io.github.lsposed.manager.adapters;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.content.pm.ResolveInfo;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.PopupMenu;
import androidx.fragment.app.FragmentManager;
import java.io.IOException;
import java.nio.file.Files;
@ -28,62 +20,34 @@ import java.util.List;
import io.github.lsposed.manager.Constants;
import io.github.lsposed.manager.R;
import io.github.lsposed.manager.util.CompileUtil;
import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
public class AppHelper {
public static final String SETTINGS_CATEGORY = "de.robv.android.xposed.category.MODULE_SETTINGS";
private static final String BASE_PATH = Constants.getBaseDir();
private static final String SCOPE_LIST_PATH = "conf/%s.conf";
private static final HashMap<String, List<String>> scopeList = new HashMap<>();
public static void showMenu(@NonNull Context context,
@NonNull FragmentManager fragmentManager,
@NonNull View anchor,
@NonNull ApplicationInfo info) {
PopupMenu appMenu = new PopupMenu(context, anchor);
appMenu.inflate(R.menu.menu_app_item);
appMenu.setOnMenuItemClickListener(menuItem -> {
int itemId = menuItem.getItemId();
if (itemId == R.id.app_menu_launch) {
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(info.packageName);
if (launchIntent != null) {
context.startActivity(launchIntent);
} else {
Toast.makeText(context, context.getString(R.string.module_no_ui), Toast.LENGTH_LONG).show();
}
} else if (itemId == R.id.app_menu_stop) {
try {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
manager.killBackgroundProcesses(info.packageName);
} catch (Exception e) {
e.printStackTrace();
}
} else if (itemId == R.id.app_menu_compile_speed) {
CompileUtil.compileSpeed(context, fragmentManager, info);
} else if (itemId == R.id.app_menu_compile_dexopt) {
CompileUtil.compileDexopt(context, fragmentManager, info);
} else if (itemId == R.id.app_menu_compile_reset) {
CompileUtil.reset(context, fragmentManager, info);
} else if (itemId == R.id.app_menu_store) {
Uri uri = Uri.parse("market://details?id=" + info.packageName);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
} else if (itemId == R.id.app_menu_info) {
context.startActivity(new Intent(ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", info.packageName, null)));
} else if (itemId == R.id.app_menu_uninstall) {
context.startActivity(new Intent(Intent.ACTION_UNINSTALL_PACKAGE, Uri.fromParts("package", info.packageName, null)));
}
return true;
});
appMenu.show();
public static Intent getSettingsIntent(String packageName, PackageManager packageManager) {
// taken from
// ApplicationPackageManager.getLaunchIntentForPackage(String)
// first looks for an Xposed-specific category, falls back to
// getLaunchIntentForPackage
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.addCategory(SETTINGS_CATEGORY);
intentToResolve.setPackage(packageName);
List<ResolveInfo> ris = packageManager.queryIntentActivities(intentToResolve, 0);
if (ris.size() <= 0) {
return packageManager.getLaunchIntentForPackage(packageName);
}
Intent intent = new Intent(intentToResolve);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName(ris.get(0).activityInfo.packageName, ris.get(0).activityInfo.name);
return intent;
}
public static boolean onOptionsItemSelected(MenuItem item, SharedPreferences preferences) {
@ -122,17 +86,17 @@ public class AppHelper {
ApplicationInfo.DisplayNameComparator displayNameComparator = new ApplicationInfo.DisplayNameComparator(pm);
switch (sort) {
case 7:
return Collections.reverseOrder((PackageInfo a, PackageInfo b) -> Long.compare(a.lastUpdateTime, b.lastUpdateTime));
return Collections.reverseOrder(Comparator.comparingLong((PackageInfo a) -> a.lastUpdateTime));
case 6:
return (PackageInfo a, PackageInfo b) -> Long.compare(a.lastUpdateTime, b.lastUpdateTime);
return Comparator.comparingLong((PackageInfo a) -> a.lastUpdateTime);
case 5:
return Collections.reverseOrder((PackageInfo a, PackageInfo b) -> Long.compare(a.firstInstallTime, b.firstInstallTime));
return Collections.reverseOrder(Comparator.comparingLong((PackageInfo a) -> a.firstInstallTime));
case 4:
return (PackageInfo a, PackageInfo b) -> Long.compare(a.firstInstallTime, b.firstInstallTime);
return Comparator.comparingLong((PackageInfo a) -> a.firstInstallTime);
case 3:
return Collections.reverseOrder((a, b) -> a.packageName.compareTo(b.packageName));
return Collections.reverseOrder(Comparator.comparing(a -> a.packageName));
case 2:
return (a, b) -> a.packageName.compareTo(b.packageName);
return Comparator.comparing(a -> a.packageName);
case 1:
return Collections.reverseOrder((PackageInfo a, PackageInfo b) -> displayNameComparator.compare(a.applicationInfo, b.applicationInfo));
case 0:

View File

@ -1,12 +1,17 @@
package io.github.lsposed.manager.adapters;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -21,33 +26,31 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.google.android.material.checkbox.MaterialCheckBox;
import com.google.android.material.snackbar.Snackbar;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import io.github.lsposed.manager.App;
import io.github.lsposed.manager.R;
import io.github.lsposed.manager.ui.activity.AppListActivity;
import io.github.lsposed.manager.ui.widget.MasterSwitch;
import io.github.lsposed.manager.util.CompileUtil;
import io.github.lsposed.manager.util.GlideApp;
import io.github.lsposed.manager.util.ModuleUtil;
import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder> implements Filterable {
private final AppListActivity activity;
private final DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
private final PackageManager pm;
private final ApplicationFilter filter;
private final SharedPreferences preferences;
@ -56,6 +59,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
private List<PackageInfo> fullList, showList;
private List<String> checkedList;
private boolean enabled = true;
private ApplicationInfo selectedInfo;
public ScopeAdapter(AppListActivity activity, String modulePackageName, MasterSwitch masterSwitch) {
this.activity = activity;
@ -74,6 +78,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
notifyDataSetChanged();
}
});
enabled = ModuleUtil.getInstance().isModuleEnabled(modulePackageName);
refresh();
}
@ -85,7 +90,6 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
}
private void loadApps() {
enabled = ModuleUtil.getInstance().isModuleEnabled(modulePackageName);
activity.runOnUiThread(() -> masterSwitch.setChecked(enabled));
checkedList = AppHelper.getScopeList(modulePackageName);
fullList = pm.getInstalledPackages(PackageManager.GET_META_DATA);
@ -161,6 +165,13 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
} else if (itemId == R.id.item_show_modules) {
item.setChecked(!item.isChecked());
preferences.edit().putBoolean("show_modules", item.isChecked()).apply();
} else if (itemId == R.id.menu_launch) {
Intent launchIntent = pm.getLaunchIntentForPackage(modulePackageName);
if (launchIntent != null) {
activity.startActivity(launchIntent);
} else {
activity.makeSnackBar(R.string.module_no_ui, Snackbar.LENGTH_LONG);
}
} else if (!AppHelper.onOptionsItemSelected(item, preferences)) {
return false;
}
@ -168,8 +179,57 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
return true;
}
public boolean onContextItemSelected(@NonNull MenuItem item) {
ApplicationInfo info = selectedInfo;
if (info == null) {
return false;
}
int itemId = item.getItemId();
if (itemId == R.id.app_menu_launch) {
Intent launchIntent = pm.getLaunchIntentForPackage(info.packageName);
if (launchIntent != null) {
activity.startActivity(launchIntent);
} else {
activity.makeSnackBar(R.string.module_no_ui, Snackbar.LENGTH_LONG);
}
} else if (itemId == R.id.app_menu_stop) {
try {
ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
manager.killBackgroundProcesses(info.packageName);
} catch (Exception e) {
e.printStackTrace();
}
} else if (itemId == R.id.app_menu_compile_speed) {
CompileUtil.compileSpeed(activity, activity.getSupportFragmentManager(), info);
} else if (itemId == R.id.app_menu_compile_dexopt) {
CompileUtil.compileDexopt(activity, activity.getSupportFragmentManager(), info);
} else if (itemId == R.id.app_menu_compile_reset) {
CompileUtil.reset(activity, activity.getSupportFragmentManager(), info);
} else if (itemId == R.id.app_menu_store) {
Uri uri = Uri.parse("market://details?id=" + info.packageName);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
} else if (itemId == R.id.app_menu_info) {
activity.startActivity(new Intent(ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", info.packageName, null)));
} else if (itemId == R.id.app_menu_uninstall) {
activity.startActivity(new Intent(Intent.ACTION_UNINSTALL_PACKAGE, Uri.fromParts("package", info.packageName, null)));
} else {
return false;
}
return true;
}
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
inflater.inflate(R.menu.menu_app_list, menu);
Intent intent = AppHelper.getSettingsIntent(modulePackageName, pm);
if (intent == null) {
menu.removeItem(R.id.menu_launch);
}
menu.findItem(R.id.item_show_system).setChecked(preferences.getBoolean("show_system_apps", false));
menu.findItem(R.id.item_show_games).setChecked(preferences.getBoolean("show_games", false));
menu.findItem(R.id.item_show_modules).setChecked(preferences.getBoolean("show_modules", false));
@ -203,6 +263,8 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Log.e("Test", enabled + "");
holder.root.setAlpha(enabled ? 1.0f : .5f);
PackageInfo info = showList.get(position);
holder.appName.setText(getAppLabel(info.applicationInfo, pm));
GlideApp.with(holder.appIcon)
@ -218,20 +280,21 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
}
});
holder.appVersion.setText(info.versionName);
holder.appVersion.setSelected(true);
String creationDate = dateformat.format(new Date(info.firstInstallTime));
String updateDate = dateformat.format(new Date(info.lastUpdateTime));
holder.timestamps.setText(holder.itemView.getContext().getString(R.string.install_timestamps, creationDate, updateDate));
holder.appPackage.setText(info.packageName);
holder.appDescription.setText(activity.getString(R.string.app_description, info.packageName, info.versionName));
holder.mSwitch.setOnCheckedChangeListener(null);
holder.mSwitch.setChecked(checkedList.contains(info.packageName));
holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> activity.getMenuInflater().inflate(R.menu.menu_app_item, menu));
holder.mSwitch.setEnabled(((ScopeAdapter) this).enabled);
holder.mSwitch.setOnCheckedChangeListener((v, isChecked) ->
onCheckedChange(v, isChecked, info.packageName));
holder.itemView.setOnClickListener(v -> AppHelper.showMenu(activity, activity.getSupportFragmentManager(), v, info.applicationInfo));
holder.checkbox.setOnCheckedChangeListener(null);
holder.checkbox.setChecked(checkedList.contains(info.packageName));
holder.checkbox.setOnCheckedChangeListener((v, isChecked) -> onCheckedChange(v, isChecked, info.packageName));
holder.itemView.setOnClickListener(v -> {
if (enabled) holder.checkbox.toggle();
});
holder.itemView.setOnLongClickListener(v -> {
selectedInfo = info.applicationInfo;
return false;
});
}
@Override
@ -254,7 +317,6 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
}
public void refresh() {
//noinspection deprecation
AsyncTask.THREAD_POOL_EXECUTOR.execute(this::loadApps);
}
@ -277,21 +339,20 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
static class ViewHolder extends RecyclerView.ViewHolder {
View root;
ImageView appIcon;
TextView appName;
TextView appPackage;
TextView appVersion;
TextView timestamps;
SwitchCompat mSwitch;
TextView appDescription;
MaterialCheckBox checkbox;
ViewHolder(View itemView) {
super(itemView);
root = itemView.findViewById(R.id.item_root);
appIcon = itemView.findViewById(R.id.app_icon);
appName = itemView.findViewById(R.id.app_name);
appPackage = itemView.findViewById(R.id.package_name);
appVersion = itemView.findViewById(R.id.version_name);
timestamps = itemView.findViewById(R.id.timestamps);
mSwitch = itemView.findViewById(R.id.checkbox);
appDescription = itemView.findViewById(R.id.description);
checkbox = itemView.findViewById(R.id.checkbox);
checkbox.setVisibility(View.VISIBLE);
}
}

View File

@ -52,8 +52,8 @@ public class AppListActivity extends BaseActivity {
ActionBar bar = getSupportActionBar();
assert bar != null;
bar.setDisplayHomeAsUpEnabled(true);
bar.setTitle(R.string.menu_scope);
bar.setSubtitle(moduleName);
bar.setTitle(moduleName);
bar.setSubtitle(modulePackageName);
scopeAdapter = new ScopeAdapter(this, modulePackageName, binding.masterSwitch);
scopeAdapter.setHasStableIds(true);
binding.recyclerView.setAdapter(scopeAdapter);
@ -87,10 +87,10 @@ public class AppListActivity extends BaseActivity {
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (!scopeAdapter.onOptionsItemSelected(item)) {
return super.onOptionsItemSelected(item);
if (scopeAdapter.onOptionsItemSelected(item)) {
return true;
}
return true;
return super.onOptionsItemSelected(item);
}
@Override
@ -108,6 +108,14 @@ public class AppListActivity extends BaseActivity {
runOnUiThread(() -> scopeAdapter.getFilter().filter(queryStr));
}
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
if (scopeAdapter.onContextItemSelected(item)) {
return true;
}
return super.onContextItemSelected(item);
}
@Override
public void onBackPressed() {
if (searchView.isIconified()) {

View File

@ -3,7 +3,6 @@ package io.github.lsposed.manager.ui.activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
@ -19,7 +18,6 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.RecyclerView;
@ -30,18 +28,12 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import io.github.lsposed.manager.BuildConfig;
import io.github.lsposed.manager.Constants;
import io.github.lsposed.manager.R;
import io.github.lsposed.manager.adapters.AppHelper;
@ -56,14 +48,12 @@ import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleListener {
public static final String SETTINGS_CATEGORY = "de.robv.android.xposed.category.MODULE_SETTINGS";
ActivityModulesBinding binding;
private int installedXposedVersion;
private ApplicationFilter filter;
private SearchView searchView;
private SearchView.OnQueryTextListener mSearchListener;
private PackageManager pm;
private final DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
private ModuleUtil moduleUtil;
private ModuleAdapter adapter = null;
private final Runnable reloadModules = new Runnable() {
@ -293,7 +283,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
if (packageName == null) {
return false;
}
Intent intent = getSettingsIntent(packageName);
Intent intent = AppHelper.getSettingsIntent(packageName, pm);
if (intent != null) {
startActivity(intent);
} else {
@ -316,38 +306,10 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
} else if (itemId == R.id.menu_uninstall) {
startActivity(new Intent(Intent.ACTION_UNINSTALL_PACKAGE, Uri.fromParts("package", module.packageName, null)));
return true;
} else if (itemId == R.id.menu_scope) {
Intent intent = new Intent(this, AppListActivity.class);
intent.putExtra("modulePackageName", module.packageName);
intent.putExtra("moduleName", module.getAppName());
startActivity(intent);
return true;
}
return super.onContextItemSelected(item);
}
private Intent getSettingsIntent(String packageName) {
// taken from
// ApplicationPackageManager.getLaunchIntentForPackage(String)
// first looks for an Xposed-specific category, falls back to
// getLaunchIntentForPackage
PackageManager pm = getPackageManager();
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.addCategory(SETTINGS_CATEGORY);
intentToResolve.setPackage(packageName);
List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
if (ris.size() <= 0) {
return pm.getLaunchIntentForPackage(packageName);
}
Intent intent = new Intent(intentToResolve);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName(ris.get(0).activityInfo.packageName, ris.get(0).activityInfo.name);
return intent;
}
private boolean lowercaseContains(String s, CharSequence filter) {
return !TextUtils.isEmpty(s) && s.toLowerCase().contains(filter);
}
@ -374,17 +336,12 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ModuleUtil.InstalledModule item = items.get(position);
boolean enabled = moduleUtil.isModuleEnabled(item.packageName);
holder.itemView.setOnClickListener(v -> {
String packageName = item.packageName;
if (packageName == null || packageName.equals(BuildConfig.APPLICATION_ID)) {
return;
}
Intent launchIntent = getSettingsIntent(packageName);
if (launchIntent != null) {
startActivity(launchIntent);
} else {
Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show();
}
Intent intent = new Intent(ModulesActivity.this, AppListActivity.class);
intent.putExtra("modulePackageName", item.packageName);
intent.putExtra("moduleName", item.getAppName());
startActivity(intent);
});
holder.itemView.setOnLongClickListener(v -> {
@ -392,20 +349,21 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
return false;
});
holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> getMenuInflater().inflate(R.menu.context_menu_modules, menu));
holder.root.setAlpha(enabled ? 1.0f : .5f);
holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> {
getMenuInflater().inflate(R.menu.context_menu_modules, menu);
Intent intent = AppHelper.getSettingsIntent(item.packageName, pm);
if (intent == null) {
menu.removeItem(R.id.menu_launch);
}
});
holder.appName.setText(item.getAppName());
TextView version = holder.appVersion;
version.setText(Objects.requireNonNull(item).versionName);
version.setSelected(true);
TextView packageTv = holder.appPackage;
packageTv.setText(item.packageName);
String creationDate = dateformat.format(new Date(item.installTime));
String updateDate = dateformat.format(new Date(item.updateTime));
holder.timestamps.setText(getString(R.string.install_timestamps, creationDate, updateDate));
GlideApp.with(holder.appIcon)
.load(item.getPackageInfo())
.into(holder.appIcon);
@ -418,59 +376,24 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
descriptionText.setText(getString(R.string.module_empty_description));
descriptionText.setTextColor(ContextCompat.getColor(ModulesActivity.this, R.color.warning));
}
SwitchCompat mSwitch = holder.mSwitch;
mSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
String packageName = item.packageName;
boolean changed = moduleUtil.isModuleEnabled(packageName) ^ isChecked;
if (changed) {
if (isChecked && AppHelper.getScopeList(packageName).isEmpty()) {
moduleUtil.setModuleEnabled(packageName, true);
Intent intent = new Intent(ModulesActivity.this, AppListActivity.class);
intent.putExtra("modulePackageName", packageName);
intent.putExtra("moduleName", item.getAppName());
startActivity(intent);
return;
}
moduleUtil.setModuleEnabled(packageName, isChecked);
moduleUtil.updateModulesList(true, binding.snackbar);
}
});
mSwitch.setChecked(moduleUtil.isModuleEnabled(item.packageName));
TextView warningText = holder.warningText;
if (item.minVersion == 0) {
if (!preferences.getBoolean("skip_xposedminversion_check", false)) {
mSwitch.setEnabled(false);
}
warningText.setText(getString(R.string.no_min_version_specified));
warningText.setVisibility(View.VISIBLE);
} else if (installedXposedVersion > 0 && item.minVersion > installedXposedVersion) {
if (!preferences.getBoolean("skip_xposedminversion_check", false)) {
mSwitch.setEnabled(false);
}
warningText.setText(String.format(getString(R.string.warning_xposed_min_version), item.minVersion));
warningText.setVisibility(View.VISIBLE);
} else if (item.minVersion < ModuleUtil.MIN_MODULE_VERSION) {
if (!preferences.getBoolean("skip_xposedminversion_check", false)) {
mSwitch.setEnabled(false);
}
warningText.setText(String.format(getString(R.string.warning_min_version_too_low), item.minVersion, ModuleUtil.MIN_MODULE_VERSION));
warningText.setVisibility(View.VISIBLE);
} else if (item.isInstalledOnExternalStorage()) {
if (!preferences.getBoolean("skip_xposedminversion_check", false)) {
mSwitch.setEnabled(false);
}
warningText.setText(getString(R.string.warning_installed_on_external_storage));
warningText.setVisibility(View.VISIBLE);
} else if (installedXposedVersion == 0 || (installedXposedVersion == -1)) {
if (!preferences.getBoolean("skip_xposedminversion_check", false)) {
mSwitch.setEnabled(false);
}
warningText.setText(getString(R.string.not_installed_no_lollipop));
warningText.setVisibility(View.VISIBLE);
} else {
mSwitch.setEnabled(true);
warningText.setVisibility(View.GONE);
}
}
@ -495,25 +418,22 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
}
class ViewHolder extends RecyclerView.ViewHolder {
View root;
ImageView appIcon;
TextView appName;
TextView appPackage;
TextView appDescription;
TextView appVersion;
TextView timestamps;
TextView warningText;
SwitchCompat mSwitch;
ViewHolder(View itemView) {
super(itemView);
root = itemView.findViewById(R.id.item_root);
appIcon = itemView.findViewById(R.id.app_icon);
appName = itemView.findViewById(R.id.app_name);
appDescription = itemView.findViewById(R.id.description);
appPackage = itemView.findViewById(R.id.package_name);
appVersion = itemView.findViewById(R.id.version_name);
timestamps = itemView.findViewById(R.id.timestamps);
appVersion.setVisibility(View.VISIBLE);
warningText = itemView.findViewById(R.id.warning);
mSwitch = itemView.findViewById(R.id.checkbox);
}
}
}

View File

@ -11,12 +11,6 @@ import androidx.core.content.ContextCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import io.github.lsposed.manager.App;
import io.github.lsposed.manager.BuildConfig;
import io.github.lsposed.manager.Constants;
import io.github.lsposed.manager.R;
import io.github.lsposed.manager.databinding.StatusInstallerBinding;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@ -25,6 +19,11 @@ import java.lang.reflect.Method;
import java.util.Locale;
import dalvik.system.VMRuntime;
import io.github.lsposed.manager.App;
import io.github.lsposed.manager.BuildConfig;
import io.github.lsposed.manager.Constants;
import io.github.lsposed.manager.R;
import io.github.lsposed.manager.databinding.StatusInstallerBinding;
@SuppressLint("StaticFieldLeak")
public class StatusDialogBuilder extends MaterialAlertDialogBuilder {

View File

@ -9,11 +9,11 @@ import com.takisoft.preferencex.ColorPickerPreference;
import com.takisoft.preferencex.ColorPickerPreferenceDialogFragmentCompat;
import com.takisoft.preferencex.PreferenceFragmentCompat;
import java.util.Objects;
import io.github.lsposed.manager.util.CustomThemeColor;
import io.github.lsposed.manager.util.CustomThemeColors;
import java.util.Objects;
public class ThemeColorPreference extends ColorPickerPreference {
static {

View File

@ -3,6 +3,7 @@ package io.github.lsposed.manager.util;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.graphics.Bitmap;
import android.graphics.drawable.AdaptiveIconDrawable;
import androidx.annotation.NonNull;
@ -21,7 +22,7 @@ public class IconLoader extends AppGlideModule {
public void registerComponents(Context context, @NonNull Glide glide, Registry registry) {
int iconSize = context.getResources().getDimensionPixelSize(R.dimen.app_icon_size);
registry.prepend(PackageInfo.class, Bitmap.class, new AppIconModelLoader.Factory(iconSize,
false, context));
context.getApplicationInfo().loadIcon(context.getPackageManager()) instanceof AdaptiveIconDrawable, context));
}
}

View File

@ -1,4 +1,4 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout 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"
android:layout_width="match_parent"
@ -7,110 +7,98 @@
android:clickable="true"
android:focusable="true"
android:minHeight="?attr/listPreferredItemHeight"
android:paddingVertical="8dp"
android:paddingStart="8dp"
android:paddingEnd="?modulesHorizontalPadding"
tools:ignore="RtlSymmetry">
android:paddingVertical="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<ImageView
android:id="@+id/app_icon"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:srcCompat="@tools:sample/backgrounds/scenic" />
<TextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/item_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:singleLine="false"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false"
app:layout_constraintStart_toEndOf="@id/app_icon"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/first_names" />
tools:ignore="RtlSymmetry">
<TextView
android:id="@+id/version_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:maxWidth="100dp"
android:singleLine="true"
android:textAlignment="viewEnd"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textIsSelectable="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/app_name"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlHardcoded"
tools:text="@tools:sample/last_names" />
<ImageView
android:id="@+id/app_icon"
android:layout_width="36dp"
android:layout_height="36dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:srcCompat="@tools:sample/backgrounds/scenic" />
<TextView
android:id="@+id/package_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textIsSelectable="false"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="@+id/checkbox"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="@+id/app_name"
app:layout_constraintTop_toBottomOf="@+id/app_name"
tools:text="@tools:sample/cities" />
<TextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:singleLine="false"
android:textAppearance="?android:attr/textAppearance"
android:textSize="16sp"
android:textIsSelectable="false"
app:layout_constraintStart_toEndOf="@id/app_icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/description"
tools:text="@tools:sample/first_names" />
<TextView
android:id="@+id/timestamps"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
app:layout_constraintStart_toStartOf="@+id/package_name"
app:layout_constraintTop_toBottomOf="@+id/package_name"
tools:text="@tools:sample/cities" />
<TextView
android:id="@+id/description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/checkbox"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/app_name"
app:layout_constraintTop_toBottomOf="@id/app_name"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="gone"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="@+id/checkbox"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="@+id/timestamps"
app:layout_constraintTop_toBottomOf="@+id/timestamps"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/version_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:maxWidth="100dp"
android:singleLine="true"
android:textAlignment="viewEnd"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textIsSelectable="false"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/app_name"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlHardcoded"
tools:text="@tools:sample/last_names" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:focusable="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:focusable="false"
android:clickable="false"
android:visibility="gone"
android:minHeight="0dp"
android:minWidth="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/warning"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@+id/description"
app:layout_constraintTop_toBottomOf="@+id/description"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/warning"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@+id/description"
app:layout_constraintTop_toBottomOf="@+id/description"
tools:text="@tools:sample/lorem" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -16,6 +16,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="16dp"
android:paddingStart="54dp"
android:paddingBottom="16dp">
<TextView

View File

@ -3,16 +3,7 @@
<item
android:id="@+id/menu_launch"
android:title="@string/module_launch" />
<item
android:id="@+id/menu_scope"
android:title="@string/menu_scope" />
<!-- <item
android:id="@+id/menu_download_updates"
android:title="@string/module_download_updates" />
<item
android:id="@+id/menu_support"
android:title="@string/module_support" />-->
android:title="@string/module_settings" />
<item
android:id="@+id/menu_app_store"
android:title="@string/modules_app_store" />

View File

@ -8,6 +8,12 @@
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_launch"
android:title="@string/module_settings"
android:icon="@drawable/ic_settings"
app:showAsAction="ifRoom" />
<item
android:id="@+id/item_show_games"
android:checkable="true"

View File

@ -160,4 +160,6 @@
<string name="menu_show_games">Games</string>
<string name="menu_show_modules">Modules</string>
<string name="failed_to_save_scope_list">Failed save scope list</string>
<string name="module_settings">Module settings</string>
<string name="app_description">%s\nVersion: %s</string>
</resources>