Merge pull request #192 from Androidacy/master

Reworks Androidacy support
pull/193/head
Fox2Code 2 years ago committed by GitHub
commit 05931a3a36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,8 +2,7 @@
## Fox Module contest
[NoStorageRestrict](https://github.com/Magisk-Modules-Alt-Repo/NoStorageRestrict)
by [@DanGLES3](https://github.com/DanGLES3) won via vote in community telegram server.
[NoStorageRestrict](https://github.com/Magisk-Modules-Alt-Repo/NoStorageRestrict) by [@DanGLES3](https://github.com/DanGLES3) won via vote in community telegram server.
Module description: Removes the restriction when selecting folders (Downloads/Android) through the file manager on Android 11 and higher
@ -19,12 +18,11 @@ Main activity:
## What is this?
The official Magisk is dropping support to download online modules...
So I made my own app to do that! :3
The official Magisk has dropped support to download online modules, so I made Fox's Magisk Module Manager to help you download and install Magisk modules.
**This app is not officially supported by Magisk or its developers**
**The modules shown in this app are not affiliated with this app**
**The modules shown in this app are not affiliated with this app or Magisk**
(Please contact repo owners instead)
## Requirements

@ -34,6 +34,7 @@ android {
"default" {
dimension "type"
buildConfigField "boolean", "ENABLE_AUTO_UPDATER", "true"
buildConfigField "boolean", "DEFAULT_ENABLE_CRASH_REPORTING", "true"
buildConfigField(
"java.util.List<String>",
"ENABLED_REPOS",
@ -50,6 +51,9 @@ android {
// with our keys, so the APK wouldn't install anyways).
buildConfigField "boolean", "ENABLE_AUTO_UPDATER", "false"
// Disable crash reporting for F-Droid flavor by default
buildConfigField "boolean", "DEFAULT_ENABLE_CRASH_REPORTING", "false"
// Repo with ads or tracking feature are disabled by default for the
// F-Droid flavor.
buildConfigField(
@ -79,6 +83,8 @@ configurations {
}
dependencies {
// Error reporting
implementation 'io.sentry:sentry-android:6.4.0'
// UI
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'androidx.emoji2:emoji2:1.2.0'
@ -87,7 +93,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.webkit:webkit:1.4.0'
implementation 'androidx.webkit:webkit:1.5.0'
implementation 'com.google.android.material:material:1.6.1'
implementation "com.mikepenz:aboutlibraries:${latestAboutLibsRelease}"
implementation "dev.rikka.rikkax.layoutinflater:layoutinflater:1.2.0"

@ -5,7 +5,9 @@
tools:ignore="QueryAllPackagesPermission">
<!-- Wifi is not the only way to get an internet connection -->
<uses-feature android:name="android.hardware.wifi" android:required="false" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<!-- Retrieve online modules -->
<uses-permission android:name="android.permission.INTERNET" />
@ -16,7 +18,8 @@
<!-- Open config apps for applications -->
<uses-permission-sdk-23 android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- Supposed to fix bugs with old firmware, only requested on pre Marshmallow -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="22" />
<!-- Post background notifications -->
<uses-permission-sdk-23 android:name="android.permission.POST_NOTIFICATIONS" />
@ -24,30 +27,32 @@
<application
android:name=".MainApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/full_backup_content"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="@bool/lang_support_rtl"
android:testOnly="false"
android:theme="@style/Theme.MagiskModuleManager"
android:fullBackupContent="@xml/full_backup_content"
android:dataExtractionRules="@xml/data_extraction_rules"
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="false"
tools:targetApi="s"
tools:ignore="ManifestResource"
tools:replace="android:supportsRtl"
tools:ignore="ManifestResource">
<receiver android:name="com.fox2code.mmm.background.BackgroundBootListener"
tools:targetApi="s">
<receiver
android:name="com.fox2code.mmm.background.BackgroundBootListener"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name=".settings.SettingsActivity"
android:parentActivityName=".MainActivity"
android:exported="true"
android:label="@string/title_activity_settings">
android:label="@string/title_activity_settings"
android:parentActivityName=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
</intent-filter>
@ -55,8 +60,8 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask"
android:label="@string/app_name_short">
android:label="@string/app_name_short"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@ -64,10 +69,10 @@
</activity>
<activity
android:name=".installer.InstallerActivity"
android:parentActivityName=".MainActivity"
android:exported="false"
android:screenOrientation="portrait"
android:launchMode="singleTop"
android:parentActivityName=".MainActivity"
android:screenOrientation="portrait"
tools:ignore="LockedOrientationActivity">
<intent-filter>
<action android:name="${applicationId}.intent.action.INSTALL_MODULE_INTERNAL" />
@ -75,30 +80,45 @@
</activity>
<activity
android:name=".markdown.MarkdownActivity"
android:parentActivityName=".MainActivity"
android:exported="false"
android:theme="@style/Theme.MagiskModuleManager">
</activity>
android:parentActivityName=".MainActivity"
android:theme="@style/Theme.MagiskModuleManager"></activity>
<activity
android:name=".androidacy.AndroidacyActivity"
android:parentActivityName=".MainActivity"
android:exported="false"
android:parentActivityName=".MainActivity"
android:theme="@style/Theme.MagiskModuleManager">
<intent-filter>
<action android:name="${applicationId}.intent.action.OPEN_ANDROIDACY_INTERNAL" />
</intent-filter>
</activity>
<activity android:name="com.mikepenz.aboutlibraries.ui.LibsActivity"
tools:node="remove"/>
<activity
android:name="com.mikepenz.aboutlibraries.ui.LibsActivity"
tools:node="remove" />
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer"
<meta-data
android:name="androidx.emoji2.text.EmojiCompatInitializer"
tools:node="remove" />
<meta-data android:name="androidx.work.WorkManagerInitializer"
<meta-data
android:name="androidx.work.WorkManagerInitializer"
tools:node="remove" />
</provider>
<meta-data
android:name="io.sentry.dsn"
android:value="https://ba5cb5ef513b423cbd54a2a8457113b1@sentry.androidacy.com/7" />
<!-- Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
We recommend adjusting this value in production. -->
<meta-data
android:name="io.sentry.traces.sample-rate"
android:value="1.0" />
<!-- Enable user interaction tracing to capture transactions for various UI events (such as clicks or scrolls). -->
<meta-data
android:name="io.sentry.traces.user-interaction.enable"
android:value="true" />
</application>
</manifest>

@ -37,6 +37,7 @@ import com.google.android.material.progressindicator.LinearProgressIndicator;
import eightbitlab.com.blurview.BlurView;
import eightbitlab.com.blurview.RenderScriptBlur;
import io.sentry.android.core.SentryAndroid;
public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRefreshListener,
SearchView.OnQueryTextListener, SearchView.OnCloseListener,

@ -27,6 +27,8 @@ import com.fox2code.mmm.utils.Http;
import com.fox2code.rosettax.LanguageSwitcher;
import com.topjohnwu.superuser.Shell;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@ -42,6 +44,9 @@ import io.noties.markwon.syntax.Prism4jThemeDefault;
import io.noties.markwon.syntax.SyntaxHighlightPlugin;
import io.noties.prism4j.Prism4j;
import io.noties.prism4j.annotations.PrismBundle;
import io.sentry.JsonObjectWriter;
import io.sentry.NoOpLogger;
import io.sentry.android.core.SentryAndroid;
@PrismBundle(
includeAll = true,
@ -49,6 +54,7 @@ import io.noties.prism4j.annotations.PrismBundle;
)
public class MainApplication extends FoxApplication
implements androidx.work.Configuration.Provider {
private static final String TAG = "MainApplication";
private static final String timeFormatString = "dd MMM yyyy"; // Example: 13 july 2001
private static Locale timeFormatLocale =
Resources.getSystem().getConfiguration().locale;
@ -168,6 +174,11 @@ public class MainApplication extends FoxApplication
getSharedPreferences().edit().putBoolean("has_root_access", bool).apply();
}
public static boolean isCrashReportingEnabled() {
return getSharedPreferences().getBoolean(
"crash_reporting", BuildConfig.DEFAULT_ENABLE_CRASH_REPORTING);
}
public static SharedPreferences getBootSharedPreferences() {
return bootSharedPreferences;
}
@ -341,6 +352,57 @@ public class MainApplication extends FoxApplication
Log.d("MainApplication", "Emoji compat loaded!");
}, "Emoji compat init.").start();
}
SentryAndroid.init(this, options -> {
// Note: Sentry library only take a screenshot of Fox Magisk Module Manager.
// The screen shot doesn't and cannot contain other applications (if in multi windows)
// status bar and notifications (even if notification shade is pulled down)
// In the possibility you find this library sending anything listed above,
// it's a serious bug and a security issue you should report to Google
// Google bug bounties on Android are huge, so you can also get rich by doing that.
options.setAttachScreenshot(true);
// Add a callback that will be used before the event is sent to Sentry.
// With this callback, you can modify the event or, when returning null, also discard the event.
options.setBeforeSend((event, hint) -> {
if (BuildConfig.DEBUG) { // Debug sentry events for debug.
StringBuilder stringBuilder = new StringBuilder("Sentry report debug: ");
try {
event.serialize(new JsonObjectWriter(new Writer() {
@Override
public void write(char[] cbuf) {
stringBuilder.append(cbuf);
}
@Override
public void write(char[] chars, int i, int i1) {
stringBuilder.append(chars, i, i1);
}
@Override
public void write(String str, int off, int len) {
stringBuilder.append(str, off, len);
}
@Override
public void flush() {}
@Override
public void close() {}
}, 4), NoOpLogger.getInstance());
} catch (IOException ignored) {}
Log.i(TAG, stringBuilder.toString());
}
// Check saved preferences to see if the user has opted out of crash reporting.
// If the user has opted out, return null.
if (isCrashReportingEnabled()) {
Log.i(TAG, "Relayed sentry report according to user preference");
return event;
} else {
Log.i(TAG, "Blocked sentry report according to user preference");
return null;
}
});
});
}
@Override

@ -21,24 +21,23 @@ import org.json.JSONObject;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import okhttp3.Cookie;
import okhttp3.HttpUrl;
@SuppressWarnings("KotlinInternalInJava")
public final class AndroidacyRepoData extends RepoData {
private static final String TAG = "AndroidacyRepoData";
private static final HttpUrl OK_HTTP_URL;
static {
HttpUrl.Builder OK_HTTP_URL_BUILDER =
new HttpUrl.Builder().scheme("https");
// Using HttpUrl.Builder.host(String) crash the app
OK_HTTP_URL_BUILDER.setHost$okhttp(".androidacy.com");
OK_HTTP_URL = OK_HTTP_URL_BUILDER.build();
OK_HTTP_URL_BUILDER.build();
}
// Avoid spamming requests to Androidacy
private long androidacyBlockade = 0;
private String token = null;
@ -60,30 +59,36 @@ public final class AndroidacyRepoData extends RepoData {
this.defaultSupport = "https://t.me/androidacy_discussions";
this.defaultDonate = "https://www.androidacy.com/membership-join/?utm_source=foxmmm&utm-medium=app&utm_campaign=fox-inapp";
this.defaultSubmitModule = "https://www.androidacy.com/module-repository-applications/";
this.host = testMode ? "staging-api.androidacy.com" : "api.androidacy.com";
this.host = testMode ? "staging-api.androidacy.com" : "production-api.androidacy.com";
this.testMode = testMode;
}
private static String getCookies() {
if (Http.hasWebView()) {
return CookieManager.getInstance().getCookie("https://.androidacy.com/");
} else {
Iterator<Cookie> cookies = Http.getCookieJar()
.loadForRequest(OK_HTTP_URL).iterator();
if (!cookies.hasNext()) return "";
StringBuilder stringBuilder = new StringBuilder();
while (true) {
stringBuilder.append(cookies.next().toString());
if (!cookies.hasNext()) return stringBuilder.toString();
stringBuilder.append(",");
}
}
}
public static AndroidacyRepoData getInstance() {
return RepoManager.getINSTANCE().getAndroidacyRepoData();
}
public <string> boolean isValidToken(string token) {
try {
Http.doHttpGet("https://" + this.host + "/auth/me?token=" + token, false);
} catch (Exception e) {
if ("Received error code: 419".equals(e.getMessage()) ||
"Received error code: 429".equals(e.getMessage())) {
Log.e(TAG, "We are being rate limited!", e);
long time = System.currentTimeMillis();
this.androidacyBlockade = time + 3_600_000L;
return false;
}
Log.w(TAG, "Invalid token, resetting...");
// Remove saved preference
SharedPreferences.Editor editor = this.cachedPreferences.edit();
editor.remove("androidacy_api_token");
editor.apply();
return false;
}
// If status code is 200, we are good
return true;
}
@Override
protected boolean prepare() {
// Implementation details discussed on telegram
@ -91,57 +96,33 @@ public final class AndroidacyRepoData extends RepoData {
long time = System.currentTimeMillis();
if (this.androidacyBlockade > time) return false;
this.androidacyBlockade = time + 30_000L;
String cookies = AndroidacyRepoData.getCookies();
int start = cookies == null ? -1 : cookies.indexOf("USER=") + 5;
String token = null;
if (start != -1) {
int end = cookies.indexOf(";", start);
if (end != -1)
token = cookies.substring(start, end);
}
// Get token from androidacy_api_token shared preference
String token = this.cachedPreferences.getString("androidacy_api_token", null);
if (token != null) {
try {
Http.doHttpGet("https://" + this.host + "/auth/me?token=" + token, true);
} catch (Exception e) {
if ("Received error code: 419".equals(e.getMessage()) ||
"Received error code: 429".equals(e.getMessage())) {
Log.e(TAG, "We are being rate limited!", e);
this.androidacyBlockade = time + 3_600_000L;
return false;
}
Log.w(TAG, "Invalid token, resetting...");
if (Http.hasWebView()) {
CookieManager.getInstance().setCookie("https://.androidacy.com/",
"USER=; expires=Thu, 01 Jan 1970 00:00:00 GMT;" +
" path=/; secure; domain=.androidacy.com");
} else {
Http.getCookieJar().saveFromResponse(
OK_HTTP_URL, Collections.emptyList());
}
this.token = token = null;
this.token = token;
if (!isValidToken(token)) {
token = null;
}
}
if (token == null) {
try {
Log.i(TAG, "Refreshing token...");
// POST request to https://production-api.androidacy.com/auth/register
token = new String(Http.doHttpPost(
"https://" + this.host + "/auth/register",
"",true), StandardCharsets.UTF_8);
if (Http.hasWebView()) {
CookieManager.getInstance().setCookie("https://.androidacy.com/",
"USER=" + token + "; expires=Fri, 31 Dec 9999 23:59:59 GMT;" +
" path=/; secure; domain=.androidacy.com");
} else {
Http.getCookieJar().saveFromResponse(OK_HTTP_URL,
Collections.singletonList(Cookie.parse(OK_HTTP_URL,
"USER=" + token + "; expires=Fri, 31 Dec 9999 23:59:59 GMT;" +
" path=/; secure; domain=.androidacy.com")));
}
"foxmmm=true", true), StandardCharsets.UTF_8);
// Parse token
JSONObject jsonObject = new JSONObject(token);
token = jsonObject.getString("token");
// Save token to shared preference
SharedPreferences.Editor editor = this.cachedPreferences.edit();
editor.putString("androidacy_api_token", token);
editor.apply();
} catch (Exception e) {
if ("Received error code: 419".equals(e.getMessage()) ||
"Received error code: 429".equals(e.getMessage()) ||
"Received error code: 503".equals(e.getMessage())
) {
) {
Log.e(TAG, "We are being rate limited!", e);
this.androidacyBlockade = time + 3_600_000L;
}
@ -194,7 +175,7 @@ public final class AndroidacyRepoData extends RepoData {
jsonObject.optString("zipUrl", ""));
repoModule.notesUrl = filterURL(
jsonObject.optString("notesUrl", ""));
if (repoModule.zipUrl == null) {
if (repoModule.zipUrl == null) {
repoModule.zipUrl = // Fallback url in case the API doesn't have zipUrl
"https://" + this.host + "/magisk/info/" + moduleId;
}
@ -264,7 +245,8 @@ public final class AndroidacyRepoData extends RepoData {
}
@Override
public void storeMetadata(RepoModule repoModule, byte[] data) {}
public void storeMetadata(RepoModule repoModule, byte[] data) {
}
@Override
public boolean tryLoadMetadata(RepoModule repoModule) {

@ -40,7 +40,7 @@ public final class RepoManager extends SyncManager {
"https://cdn.jsdelivr.net/gh/Magisk-Modules-Alt-Repo/json@main/modules.json";
public static final String ANDROIDACY_MAGISK_REPO_ENDPOINT =
"https://api.androidacy.com/magisk/repo";
"https://production-api.androidacy.com/magisk/repo";
public static final String ANDROIDACY_TEST_MAGISK_REPO_ENDPOINT =
"https://staging-api.androidacy.com/magisk/repo";
public static final String ANDROIDACY_MAGISK_REPO_HOMEPAGE =

@ -8,7 +8,10 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.Toast;
@ -17,10 +20,13 @@ import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreferenceCompat;
import androidx.preference.TwoStatePreference;
import com.fox2code.foxcompat.FoxActivity;
@ -32,6 +38,7 @@ import com.fox2code.mmm.Constants;
import com.fox2code.mmm.MainActivity;
import com.fox2code.mmm.MainApplication;
import com.fox2code.mmm.R;
import com.fox2code.mmm.androidacy.AndroidacyRepoData;
import com.fox2code.mmm.background.BackgroundUpdateChecker;
import com.fox2code.mmm.installer.InstallerInitializer;
import com.fox2code.mmm.module.ActionButtonType;
@ -45,6 +52,7 @@ import com.fox2code.rosettax.LanguageActivity;
import com.fox2code.rosettax.LanguageSwitcher;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.internal.TextWatcherAdapter;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
import com.mikepenz.aboutlibraries.LibsBuilder;
import com.topjohnwu.superuser.internal.UiThreadHandler;
@ -70,10 +78,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
setTitle(R.string.app_name);
setActionBarBackground(null);
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings, new SettingsFragment())
.commit();
getSupportFragmentManager().beginTransaction().replace(R.id.settings, new SettingsFragment()).commit();
}
}
@ -83,9 +88,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
Intent mStartActivity = new Intent(this, MainActivity.class);
mStartActivity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(this, mPendingIntentId,
mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
AlarmManager mgr = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
PendingIntent mPendingIntent = PendingIntent.getActivity(this, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
AlarmManager mgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0); // Exit app process
}
@ -96,8 +100,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
super.onPause();
}
public static class SettingsFragment extends PreferenceFragmentCompat
implements FoxActivity.OnBackPressedCallback {
public static class SettingsFragment extends PreferenceFragmentCompat implements FoxActivity.OnBackPressedCallback {
@Override
@SuppressWarnings("ConstantConditions")
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@ -119,11 +122,18 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
devModeStep = 0;
UiThreadHandler.handler.postDelayed(() -> {
MainApplication.getINSTANCE().updateTheme();
FoxActivity.getFoxActivity(this).setThemeRecreate(
MainApplication.getINSTANCE().getManagerThemeResId());
FoxActivity.getFoxActivity(this).setThemeRecreate(MainApplication.getINSTANCE().getManagerThemeResId());
}, 1);
return true;
});
// Crash reporting
TwoStatePreference crashReportingPreference = findPreference("pref_crash_reporting");
crashReportingPreference.setChecked(MainApplication.isCrashReportingEnabled());
crashReportingPreference.setOnPreferenceChangeListener((preference, newValue) -> {
devModeStep = 0;
getCrashReportingEditor(requireActivity()).putBoolean("crash_reporting", (boolean) newValue).apply();
return true;
});
Preference enableBlur = findPreference("pref_enable_blur");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
enableBlur.setSummary(R.string.require_android_6);
@ -138,8 +148,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
disableMonet.setOnPreferenceClickListener(preference -> {
UiThreadHandler.handler.postDelayed(() -> {
MainApplication.getINSTANCE().updateTheme();
((FoxActivity) this.requireActivity()).setThemeRecreate(
MainApplication.getINSTANCE().getManagerThemeResId());
((FoxActivity) this.requireActivity()).setThemeRecreate(MainApplication.getINSTANCE().getManagerThemeResId());
}, 1);
return true;
});
@ -182,8 +191,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
int level = this.currentLanguageLevel();
if (level != LANGUAGE_SUPPORT_LEVEL) {
Log.e(TAG, "Detected language level " + level +
", latest is " + LANGUAGE_SUPPORT_LEVEL);
Log.e(TAG, "Detected language level " + level + ", latest is " + LANGUAGE_SUPPORT_LEVEL);
languageSelector.setSummary(R.string.language_support_outdated);
} else {
if (!"Translated by Fox2Code".equals( // I don't "translate" english
@ -196,45 +204,45 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
if (!MainApplication.isDeveloper()) {
findPreference("pref_disable_low_quality_module_filter").setVisible(false);
// Hide the pref_crash option if not in debug mode - stop users from purposely crashing the app
Objects.requireNonNull((Preference) findPreference("pref_crash")).setVisible(false);
} else {
findPreference("pref_crash").setOnPreferenceClickListener(preference -> {
// Hard crash the app
throw new RuntimeException("This is a test crash");
});
}
if (InstallerInitializer.peekMagiskVersion() < Constants.MAGISK_VER_CODE_INSTALL_COMMAND
|| !MainApplication.isDeveloper()) {
if (InstallerInitializer.peekMagiskVersion() < Constants.MAGISK_VER_CODE_INSTALL_COMMAND || !MainApplication.isDeveloper()) {
findPreference("pref_use_magisk_install_command").setVisible(false);
}
Preference debugNotification = findPreference("pref_background_update_check_debug");
debugNotification.setEnabled(MainApplication.isBackgroundUpdateCheckEnabled());
debugNotification.setVisible(MainApplication.isDeveloper());
debugNotification.setOnPreferenceClickListener(preference -> {
BackgroundUpdateChecker.postNotification(
this.requireContext(), new Random().nextInt(4) + 2);
BackgroundUpdateChecker.postNotification(this.requireContext(), new Random().nextInt(4) + 2);
return true;
});
findPreference("pref_background_update_check").setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = Boolean.parseBoolean(String.valueOf(newValue));
debugNotification.setEnabled(enabled);
if (!enabled) {
BackgroundUpdateChecker.onMainActivityResume(
this.requireContext());
BackgroundUpdateChecker.onMainActivityResume(this.requireContext());
}
return true;
});
final LibsBuilder libsBuilder = new LibsBuilder().withShowLoadingProgress(false)
.withLicenseShown(true).withAboutMinimalDesign(false);
final LibsBuilder libsBuilder = new LibsBuilder().withShowLoadingProgress(false).withLicenseShown(true).withAboutMinimalDesign(false);
Preference update = findPreference("pref_update");
update.setVisible(BuildConfig.ENABLE_AUTO_UPDATER && (BuildConfig.DEBUG ||
AppUpdateManager.getAppUpdateManager().peekHasUpdate()));
update.setVisible(BuildConfig.ENABLE_AUTO_UPDATER && (BuildConfig.DEBUG || AppUpdateManager.getAppUpdateManager().peekHasUpdate()));
update.setOnPreferenceClickListener(p -> {
devModeStep = 0;
IntentHelper.openUrl(p.getContext(),
"https://github.com/Fox2Code/FoxMagiskModuleManager/releases");
IntentHelper.openUrl(p.getContext(), "https://github.com/Fox2Code/FoxMagiskModuleManager/releases");
return true;
});
if (BuildConfig.DEBUG || BuildConfig.ENABLE_AUTO_UPDATER) {
findPreference("pref_report_bug").setOnPreferenceClickListener(p -> {
devModeStep = 0;
IntentHelper.openUrl(p.getContext(),
"https://github.com/Fox2Code/FoxMagiskModuleManager/issues");
IntentHelper.openUrl(p.getContext(), "https://github.com/Fox2Code/FoxMagiskModuleManager/issues");
return true;
});
} else {
@ -244,20 +252,17 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
if (devModeStep == 2) {
devModeStep = 0;
if (MainApplication.isDeveloper() && !BuildConfig.DEBUG) {
MainApplication.getSharedPreferences().edit()
.putBoolean("developer", false).apply();
MainApplication.getSharedPreferences().edit().putBoolean("developer", false).apply();
Toast.makeText(getContext(), // Tell the user something changed
R.string.dev_mode_disabled, Toast.LENGTH_SHORT).show();
} else {
MainApplication.getSharedPreferences().edit()
.putBoolean("developer", true).apply();
MainApplication.getSharedPreferences().edit().putBoolean("developer", true).apply();
Toast.makeText(getContext(), // Tell the user something changed
R.string.dev_mode_enabled, Toast.LENGTH_SHORT).show();
}
return true;
}
IntentHelper.openUrl(p.getContext(),
"https://github.com/Fox2Code/FoxMagiskModuleManager");
IntentHelper.openUrl(p.getContext(), "https://github.com/Fox2Code/FoxMagiskModuleManager");
return true;
});
findPreference("pref_support").setOnPreferenceClickListener(p -> {
@ -271,43 +276,31 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
openFragment(libsBuilder.supportFragment(), R.string.licenses);
return true;
});
findPreference("pref_pkg_info").setSummary(
BuildConfig.APPLICATION_ID + " v" +
BuildConfig.VERSION_NAME + " (" +
BuildConfig.VERSION_CODE + ")");
findPreference("pref_pkg_info").setSummary(BuildConfig.APPLICATION_ID + " v" + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")");
}
private SharedPreferences.Editor getCrashReportingEditor(FragmentActivity requireActivity) {
return requireActivity.getSharedPreferences("crash_reporting", Context.MODE_PRIVATE).edit();
}
private void openFragment(Fragment fragment, @StringRes int title) {
FoxActivity compatActivity = getFoxActivity(this);
compatActivity.setOnBackPressedCallback(this);
compatActivity.setTitle(title);
compatActivity.getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings, fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
compatActivity.getSupportFragmentManager().beginTransaction().replace(R.id.settings, fragment).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).commit();
}
@Override
public boolean onBackPressed(FoxActivity compatActivity) {
compatActivity.setTitle(R.string.app_name);
compatActivity.getSupportFragmentManager()
.beginTransaction().replace(R.id.settings, this)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
compatActivity.getSupportFragmentManager().beginTransaction().replace(R.id.settings, this).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).commit();
return true;
}
private int currentLanguageLevel() {
int declaredLanguageLevel =
this.getResources().getInteger(R.integer.language_support_level);
if (declaredLanguageLevel != LANGUAGE_SUPPORT_LEVEL)
return declaredLanguageLevel;
if (!this.getResources().getConfiguration().locale.getLanguage().equals("en") &&
this.getResources().getString(R.string.notification_update_pref)
.equals("Background modules update check") &&
this.getResources().getString(R.string.notification_update_desc)
.equals("May increase battery usage")) {
int declaredLanguageLevel = this.getResources().getInteger(R.integer.language_support_level);
if (declaredLanguageLevel != LANGUAGE_SUPPORT_LEVEL) return declaredLanguageLevel;
if (!this.getResources().getConfiguration().locale.getLanguage().equals("en") && this.getResources().getString(R.string.notification_update_pref).equals("Background modules update check") && this.getResources().getString(R.string.notification_update_desc).equals("May increase battery usage")) {
return 0;
}
return LANGUAGE_SUPPORT_LEVEL;
@ -317,6 +310,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
public static class RepoFragment extends PreferenceFragmentCompat {
private static final int CUSTOM_REPO_ENTRIES = 5;
@SuppressLint("RestrictedApi")
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
getPreferenceManager().setSharedPreferencesName("mmm");
@ -326,28 +320,101 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
setRepoData(RepoManager.DG_MAGISK_REPO_GITHUB);
updateCustomRepoList(true);
if (!MainApplication.isDeveloper()) {
Objects.requireNonNull((Preference) findPreference(
"pref_androidacy_test_mode")).setVisible(false);
Objects.requireNonNull((Preference) findPreference("pref_androidacy_test_mode")).setVisible(false);
} else {
// Show a warning if user tries to enable test mode
Objects.requireNonNull((SwitchPreferenceCompat) findPreference("pref_androidacy_test_mode")).setOnPreferenceChangeListener((preference, newValue) -> {
if (Boolean.parseBoolean(String.valueOf(newValue))) {
new AlertDialog.Builder(this.requireContext())
.setTitle(R.string.warning)
.setMessage(R.string.androidacy_test_mode_warning)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
// Do nothing
})
.show();
}
return true;
});
}
String originalApiKey = MainApplication.getSharedPreferences().getString("pref_androidacy_api_token", "");
// Create the pref_androidacy_repo_api_key text input with validation
EditTextPreference prefAndroidacyRepoApiKey = findPreference("pref_androidacy_repo_api_key");
assert prefAndroidacyRepoApiKey != null;
prefAndroidacyRepoApiKey.setOnBindEditTextListener(editText -> {
editText.setSingleLine();
// Make the single line wrap
editText.setHorizontallyScrolling(false);
// Set the height to the height of 2 lines
editText.setHeight(editText.getLineHeight() * 3);
// Make ok button say "Save"
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
});
prefAndroidacyRepoApiKey.setPositiveButtonText(R.string.save_api_key);
prefAndroidacyRepoApiKey.setOnPreferenceChangeListener((preference, newValue) -> {
// Curious if this actually works - so crash the app on purpose
// throw new RuntimeException("This is a test crash");
// get original api key
String apiKey = String.valueOf(newValue);
// Show snack bar with indeterminate progress
Snackbar.make(requireView(), R.string.checking_api_key, Snackbar.LENGTH_INDEFINITE).setAction(R.string.cancel, v -> {
// Restore the original api key
prefAndroidacyRepoApiKey.setText(originalApiKey);
}).show();
// Check the API key on a background thread
new Thread(() -> {
// If key is empty, just remove it and change the text of the snack bar
if (apiKey.isEmpty()) {
MainApplication.getSharedPreferences().edit().remove("pref_androidacy_repo_api_key").apply();
new Handler(Looper.getMainLooper()).post(() -> Snackbar.make(requireView(), R.string.api_key_removed, Snackbar.LENGTH_SHORT).show());
} else {
// If key < 64 chars, it's not valid
if (apiKey.length() < 64) {
new Handler(Looper.getMainLooper()).post(() -> {
Snackbar.make(requireView(), R.string.api_key_invalid, Snackbar.LENGTH_SHORT).show();
// Save the original key
MainApplication.getSharedPreferences().edit().putString("pref_androidacy_api_token", originalApiKey).apply();
// Re-show the dialog with an error
prefAndroidacyRepoApiKey.performClick();
// Show error
prefAndroidacyRepoApiKey.setDialogMessage(getString(R.string.api_key_invalid));
});
} else {
boolean valid = AndroidacyRepoData.getInstance().isValidToken(apiKey);
// If the key is valid, save it
if (valid) {
MainApplication.getSharedPreferences().edit().putString("pref_androidacy_repo_api_key", apiKey).apply();
new Handler(Looper.getMainLooper()).post(() -> Snackbar.make(requireView(), R.string.api_key_valid, Snackbar.LENGTH_SHORT).show());
} else {
new Handler(Looper.getMainLooper()).post(() -> {
Snackbar.make(requireView(), R.string.api_key_invalid, Snackbar.LENGTH_SHORT).show();
// Save the original key
MainApplication.getSharedPreferences().edit().putString("pref_androidacy_api_token", originalApiKey).apply();
// Re-show the dialog with an error
prefAndroidacyRepoApiKey.performClick();
// Show error
prefAndroidacyRepoApiKey.setDialogMessage(getString(R.string.api_key_invalid));
});
}
}
}
}).start();
return true;
});
}
@SuppressLint("RestrictedApi")
public void updateCustomRepoList(boolean initial) {
final SharedPreferences sharedPreferences = Objects.requireNonNull(
this.getPreferenceManager().getSharedPreferences());
final CustomRepoManager customRepoManager =
RepoManager.getINSTANCE().getCustomRepoManager();
final SharedPreferences sharedPreferences = Objects.requireNonNull(this.getPreferenceManager().getSharedPreferences());
final CustomRepoManager customRepoManager = RepoManager.getINSTANCE().getCustomRepoManager();
for (int i = 0; i < CUSTOM_REPO_ENTRIES; i++) {
CustomRepoData repoData = customRepoManager.getRepo(i);
setRepoData(repoData, "pref_custom_repo_" + i);
if (initial) {
Preference preference =
findPreference("pref_custom_repo_" + i + "_delete");
Preference preference = findPreference("pref_custom_repo_" + i + "_delete");
if (preference == null) continue;
final int index = i;
preference.setOnPreferenceClickListener(preference1 -> {
sharedPreferences.edit().putBoolean(
"pref_custom_repo_" + index + "_enabled", false).apply();
sharedPreferences.edit().putBoolean("pref_custom_repo_" + index + "_enabled", false).apply();
customRepoManager.removeRepo(index);
updateCustomRepoList(false);
return true;
@ -356,16 +423,14 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
}
Preference preference = findPreference("pref_custom_add_repo");
if (preference == null) return;
preference.setVisible(customRepoManager.canAddRepo() &&
customRepoManager.getRepoCount() < CUSTOM_REPO_ENTRIES);
preference.setVisible(customRepoManager.canAddRepo() && customRepoManager.getRepoCount() < CUSTOM_REPO_ENTRIES);
if (initial) { // Custom repo add button part.
preference = findPreference("pref_custom_add_repo_button");
if (preference == null) return;
preference.setOnPreferenceClickListener(preference1 -> {
final Context context = this.requireContext();
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context);
final MaterialAutoCompleteTextView input =
new MaterialAutoCompleteTextView(context);
final MaterialAutoCompleteTextView input = new MaterialAutoCompleteTextView(context);
input.setHint(R.string.custom_url);
builder.setIcon(R.drawable.ic_baseline_add_box_24);
builder.setTitle(R.string.add_repo);
@ -373,28 +438,24 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
builder.setPositiveButton("OK", (dialog, which) -> {
String text = String.valueOf(input.getText());
if (customRepoManager.canAddRepo(text)) {
final CustomRepoData customRepoData =
customRepoManager.addRepo(text);
final CustomRepoData customRepoData = customRepoManager.addRepo(text);
customRepoData.setEnabled(true);
new Thread("Add Custom Repo Thread") {
@Override
public void run() {
try {
customRepoData.quickPrePopulate();
} catch (IOException|JSONException e) {
} catch (IOException | JSONException e) {
Log.e(TAG, "Failed to preload repo values", e);
}
UiThreadHandler.handler.post(() -> {
updateCustomRepoList(false);
});
UiThreadHandler.handler.post(() -> updateCustomRepoList(false));
}
}.start();
}
});
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
AlertDialog alertDialog = builder.show();
final Button positiveButton =
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
final Button positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
input.setValidator(new AutoCompleteTextView.Validator() {
@Override
public boolean isValid(CharSequence charSequence) {
@ -408,16 +469,12 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
});
input.addTextChangedListener(new TextWatcherAdapter() {
@Override
public void onTextChanged(
@NonNull CharSequence charSequence, int i, int i1, int i2) {
positiveButton.setEnabled(customRepoManager
.canAddRepo(charSequence.toString()) &&
customRepoManager.getRepoCount() < CUSTOM_REPO_ENTRIES);
public void onTextChanged(@NonNull CharSequence charSequence, int i, int i1, int i2) {
positiveButton.setEnabled(customRepoManager.canAddRepo(charSequence.toString()) && customRepoManager.getRepoCount() < CUSTOM_REPO_ENTRIES);
}
});
positiveButton.setEnabled(false);
int dp10 = FoxDisplay.dpToPixel(10),
dp20 = FoxDisplay.dpToPixel(20);
int dp10 = FoxDisplay.dpToPixel(10), dp20 = FoxDisplay.dpToPixel(20);
FoxViewCompat.setMargin(input, dp20, dp10, dp20, dp10);
return true;
});
@ -426,8 +483,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
private void setRepoData(String url) {
final RepoData repoData = RepoManager.getINSTANCE().get(url);
setRepoData(repoData, "pref_" + (repoData == null ?
RepoManager.internalIdOfUrl(url) : repoData.getPreferenceId()));
setRepoData(repoData, "pref_" + (repoData == null ? RepoManager.internalIdOfUrl(url) : repoData.getPreferenceId()));
}
private void setRepoData(final RepoData repoData, String preferenceName) {
@ -442,11 +498,9 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
preference = findPreference(preferenceName + "_enabled");
if (preference != null) {
((TwoStatePreference) preference).setChecked(repoData.isEnabled());
preference.setTitle(repoData.isEnabled() ?
R.string.repo_enabled : R.string.repo_disabled);
preference.setTitle(repoData.isEnabled() ? R.string.repo_enabled : R.string.repo_disabled);
preference.setOnPreferenceChangeListener((p, newValue) -> {
p.setTitle(((Boolean) newValue) ?
R.string.repo_enabled : R.string.repo_disabled);
p.setTitle(((Boolean) newValue) ? R.string.repo_enabled : R.string.repo_disabled);
return true;
});
}
@ -457,8 +511,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
preference.setVisible(true);
preference.setOnPreferenceClickListener(p -> {
if (homepage.startsWith("https://www.androidacy.com/")) {
IntentHelper.openUrlAndroidacy(
getFoxActivity(this), homepage, true);
IntentHelper.openUrlAndroidacy(getFoxActivity(this), homepage, true);
} else {
IntentHelper.openUrl(getFoxActivity(this), homepage);
}
@ -503,8 +556,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
preference.setVisible(true);
preference.setOnPreferenceClickListener(p -> {
if (submissionUrl.startsWith("https://www.androidacy.com/")) {
IntentHelper.openUrlAndroidacy(
getFoxActivity(this), submissionUrl, true);
IntentHelper.openUrlAndroidacy(getFoxActivity(this), submissionUrl, true);
} else {
IntentHelper.openUrl(getFoxActivity(this), submissionUrl);
}

@ -0,0 +1,10 @@
<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">
<path
android:fillColor="@android:color/white"
android:pathData="M12.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>

@ -92,4 +92,6 @@
<string name="enable_blur_pref">Povolit rozostření</string>
<string name="repo_enabled">Repozitář povolen</string>
<string name="repo_disabled">Repozitář zakázán</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -94,7 +94,6 @@
<string name="add_repo">Repo hinzufügen</string>
<string name="remove_repo">Repo entfernen</string>
<string name="custom_url">Eigene URL</string>
<string name="androidacy_repo_info">Das Androidacy-Repo enthält Anzeigen und Tracker.</string>
<string name="backup_module_list">Backup Modules</string>
<string name="restore_module_list">Module wiederherstellen</string>
<string name="require_internet">Dieser Vorgang erfordert eine Internetverbindung</string>
@ -103,4 +102,6 @@
<string name="description">Beschreibung</string>
<string name="uninstall">Deinstallieren</string>
<string name="config">Konfig</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -124,7 +124,6 @@
<string name="add_repo">Προσθήκη αποθετηρίου</string>
<string name="remove_repo">Αφαίρεση αποθετηρίου</string>
<string name="custom_url">Προσαρμοσμένη διεύθυνση url</string>
<string name="androidacy_repo_info">Το αποθετήριο Androidacy έχει διαφημίσεις και ιχνηλάτες.</string>
<string name="backup_module_list">Εφεδρικά modules</string>
<string name="restore_module_list">Επαναφορά module</string>
<string name="require_internet">Αυτή η λειτουργία απαιτεί σύνδεση στο Διαδίκτυο</string>
@ -144,4 +143,6 @@
<string name="language_support_outdated">Ορισμένες μεταφράσεις για την τρέχουσα γλώσσα δεν είναι ενημερωμένες, παρακαλούμε να συνεισφέρετε στις μεταφράσεις εφαρμογών στο GitHub</string>
<!-- Replace with your own username when translating -->
<string name="language_translated_by">Μεταφράστηκε απο Tha_14</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -124,8 +124,9 @@
<string name="add_repo">Añadir Repositorio</string>
<string name="remove_repo">Eliminar Repositorio</string>
<string name="custom_url">URL Personalizado</string>
<string name="androidacy_repo_info">El repositorio Androidacy tiene anuncios y trackers.</string>
<string name="backup_module_list">Hacer copia de seguridad de los módulos</string>
<string name="restore_module_list">Restaurar módulos</string>
<string name="require_internet">Esta operación requiere una conexión a Internet.</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -87,4 +87,6 @@
</string>
<string name="repo_enabled">Hoidla lubatud</string>
<string name="repo_disabled">Hoidla keelatud</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -124,8 +124,9 @@
<string name="add_repo">Ajouter dépôt</string>
<string name="remove_repo">Supprimer dépôt</string>
<string name="custom_url">URL personnalisée</string>
<string name="androidacy_repo_info">Le dépôt Androidacy utilise des publicités et des pisteurs.</string>
<string name="backup_module_list">Sauvegarder les modules</string>
<string name="restore_module_list">Restaurer les modules</string>
<string name="require_internet">Cette opération requière une connexion internet</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -93,4 +93,6 @@
<string name="enable_blur_pref">Aktifkan blur</string>
<string name="repo_enabled">Repo diaktifkan</string>
<string name="repo_disabled">Repo dinonaktifkan</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -127,7 +127,6 @@
<string name="add_repo">Aggiungi Repository</string>
<string name="remove_repo">Rimuovi Repository</string>
<string name="custom_url">Url personalizzato</string>
<string name="androidacy_repo_info">La repository di Androidacy contiene pubblicità e tracker.</string>
<string name="backup_module_list">Salva moduli</string>
<string name="restore_module_list">Ripristina moduli</string>
<string name="require_internet">Questa operazione richiede una connessione ad internet</string>
@ -149,4 +148,6 @@
<!-- Sostituisci con il tuo nome utente durante la traduzione -->
<string name="language_translated_by">Traduzione di tugaia56</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -40,4 +40,6 @@
<string name="source_code">ソースコード</string>
<string name="dev_mode_enabled">開発者モードが有効です</string>
<string name="force_english_pref">Force English language</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -94,5 +94,6 @@
<string name="enable_blur_pref">Tilsløring</string>
<string name="repo_enabled">Pakkebrønn på</string>
<string name="repo_disabled">Pakkebrønn av</string>
<string name="androidacy_repo_info">Androidacy-pakkebrønnen har reklame og sporere.</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -124,7 +124,6 @@
<string name="add_repo">Dodaj repozytorium</string>
<string name="remove_repo">Usuń repozytorium</string>
<string name="custom_url">Niestandardowy URL</string>
<string name="androidacy_repo_info">Repo Androidacy korzysta z reklam i trackerów.</string>
<string name="backup_module_list">Kopia zapasowa modułów</string>
<string name="restore_module_list">Przywracanie modułów</string>
<string name="require_internet">Ta operacja wymaga połączenia internetowego</string>
@ -147,4 +146,6 @@
prosimy o rozważenie uzupełnienia tłumaczeń aplikacji na GitHubie.</string>
<!-- Replace with your own username when translating -->
<string name="language_translated_by">Tłumaczenie: Daviteusz</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -127,7 +127,6 @@
<string name="add_repo">Adicionar Repositório</string>
<string name="remove_repo">Remover Repositórios</string>
<string name="custom_url">URL Customizado</string>
<string name="androidacy_repo_info">O Repositórios Androidacy possui anuncios e rastreadores.</string>
<string name="backup_module_list">Fazer backup dos modulos</string>
<string name="restore_module_list">Restaurar modulos</string>
<string name="require_internet">Essa operação requer uma conexão com a internet</string>
@ -149,4 +148,6 @@
<string name="language_support_outdated">Algumas traduções para sua lingua atual não esta em dia, por favor considere contribuir para as traduções do app no Github</string>
<!-- Replace with your own username when translating -->
<string name="language_translated_by">Traduzido por mi007d e DanGLES3</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -119,7 +119,6 @@
<string name="add_repo">Adăugare depozit</string>
<string name="remove_repo">Eliminare depozit</string>
<string name="custom_url">URL personalizat</string>
<string name="androidacy_repo_info">Depozitul Androidacy utilizează reclame și instrumente de urmărire.</string>
<string name="backup_module_list">Rezervare module</string>
<string name="restore_module_list">Restabilire module</string>
<string name="require_internet">Această operațiune necesită o conexiune la Internet</string>
@ -138,4 +137,6 @@
nu sunt actualizate, vă rugăm să luați în considerare contribuția la traducerea aplicației pe GitHub</string>
<!-- Replace with your own username when translating -->
<string name="language_translated_by">Tradus de Fox2Code</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -120,8 +120,9 @@
<string name="add_repo">Добавить репо</string>
<string name="remove_repo">Убрать репо</string>
<string name="custom_url">Свой URL</string>
<string name="androidacy_repo_info">Репо Androidacy содержит рекламу и трекеры.</string>
<string name="backup_module_list">Резервное копирование модулей</string>
<string name="restore_module_list">Восстановить модули</string>
<string name="require_internet">Для этого действия потребуется подключение к Интернету</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -92,4 +92,6 @@
<string name="enable_blur_pref">Povoliť rozostrenia</string>
<string name="repo_enabled">Repozitár povolený</string>
<string name="repo_disabled">Repozitár zakázaný</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -127,7 +127,6 @@
<string name="add_repo">Repo ekle</string>
<string name="remove_repo">Repo\'yu kaldır</string>
<string name="custom_url">Özel url</string>
<string name="androidacy_repo_info">Androidacy repo\'da reklamlar ve takipçiler vardır.</string>
<string name="backup_module_list">Modülleri yedekle</string>
<string name="restore_module_list">Modülleri geri yükle</string>
<string name="require_internet">Bu işlem bir internet bağlantısı gerektirir</string>
@ -147,4 +146,6 @@
<string name="language_support_outdated">Şimdiki dil için bazı çeviriler güncel değil, lütfen GitHub\'daki uygulama çevirilerine katkıda bulunmayı düşünün</string>
<!-- Replace with your own username when translating -->
<string name="language_translated_by">Alprnn357 tarafından çevrildi</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -119,8 +119,9 @@
<string name="add_repo">Thêm kho</string>
<string name="remove_repo">Gỡ kho</string>
<string name="custom_url">Url tuỳ chỉnh</string>
<string name="androidacy_repo_info">Kho Androidacy có các quảng cáo và trình theo dõi.</string>
<string name="backup_module_list">Sao lưu mô-đun</string>
<string name="restore_module_list">Khôi phục mô-đun</string>
<string name="require_internet">Quá trình này yêu cầu kết nối internet</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -129,7 +129,6 @@
<string name="add_repo">添加库</string>
<string name="remove_repo">移除库</string>
<string name="custom_url">自定义网址</string>
<string name="androidacy_repo_info">Androidacy repo具有广告和跟踪器.</string>
<string name="backup_module_list">备份模块</string>
<string name="restore_module_list">还原模块</string>
<string name="require_internet">此操作需要互联网连接</string>
@ -150,4 +149,6 @@
请考虑为 GitHub 上的应用程序翻译做出贡献</string>
<!-- Replace with your own username when translating -->
<string name="language_translated_by">由ender-zhao翻译</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -120,7 +120,6 @@
<string name="add_repo">新增倉庫</string>
<string name="remove_repo">移除倉庫</string>
<string name="custom_url">自定義網址</string>
<string name="androidacy_repo_info">Androidacy repo 內建廣告和跟蹤器.</string>
<string name="backup_module_list">備份模組</string>
<string name="restore_module_list">還原模組</string>
<string name="require_internet">需要網路連線</string>
@ -140,4 +139,6 @@
<string name="language_support_outdated">如果您使用的當前語言沒有及時更新,請考慮在 GitHub 上的為翻譯做出貢獻。</string>
<!-- Replace with your own username when translating -->
<string name="language_translated_by">由 OrStudio.tw(@crcky5322) 提供美妙的翻譯</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
</resources>

@ -24,4 +24,5 @@
<color name="light_colorBackgroundFloating">#FFFFFFFF</color>
<color name="light_backgroundColor">#FFFFFFFF</color>
<color name="light_chipBackgroundColor">#FFDADADA</color>
<color name="gray_900">#3A3A3A</color>
</resources>

@ -129,7 +129,7 @@
<string name="add_repo">Add Repo</string>
<string name="remove_repo">Remove Repo</string>
<string name="custom_url">Custom url</string>
<string name="androidacy_repo_info">The Androidacy repo has ads and trackers.</string>
<string name="androidacy_repo_info">This repository may display some non-intrusive advertising to cover server and development costs.</string>
<string name="backup_module_list">Backup modules</string>
<string name="restore_module_list">Restore modules</string>
<string name="require_internet">This operation require an internet connection</string>
@ -152,4 +152,20 @@
not up-to-date, please consider contributing to the app translations on GitHub</string>
<!-- Replace with your own username when translating -->
<string name="language_translated_by">Translated by Fox2Code</string>
<string name="crash_reporting">Automatically report bugs and performance to the developers</string>
<string name="crash_reporting_desc">If you disable this, the developer will not get automatic bug reports, and this may make troubleshooting harder</string>
<string name="api_key">Androidacy API Key</string>
<string name="api_key_summary">Use a custom API key for Androidacy. Useful for premium subscribers, to remove ads and more.</string>
<string name="api_key_not_set">Androidacy API key is empty</string>
<string name="api_key_set">Current Androidacy API key</string>
<string name="api_key_invalid">Could not validate API key. Please check it and try again.</string>
<string name="api_key_valid">API key is valid.</string>
<string name="checking_api_key">Validating API key...</string>
<string name="validating_api_key">Validating API key...</string>
<string name="please_wait">Please wait</string>
<string name="api_key_removed">Successfully reset API key</string>
<string name="save_api_key">Validate</string>
<string name="warning">Warning!</string>
<string name="androidacy_test_mode_warning">You are setting the app to use a non-production endpoint for Androidacy. This may result in app instability and failure to load the online repo. Do NOT report bugs if you have this switch on. Change will take effect on app restart.</string>
<string name="crash">Crash the app for testing</string>
</resources>

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
app:key="pref_magisk_alt_repo"
app:title="@string/loading">
@ -39,6 +40,27 @@
app:switchTextOn="@string/repo_enabled"
app:switchTextOff="@string/repo_disabled"
app:singleLineTitle="false" />
<!-- Allow user to set custom API key for Androidacy repo -->
<EditTextPreference
app:key="pref_androidacy_repo_api_key"
app:icon="@drawable/ic_baseline_vpn_key_24"
app:title="@string/api_key"
app:summary="@string/api_key_summary"
app:singleLineTitle="true"
app:dialogTitle="@string/api_key"
app:dialogIcon="@drawable/ic_baseline_vpn_key_24"
app:dependency="pref_androidacy_repo_enabled"
android:inputType="text"
android:selectAllOnFocus="true"
android:imeOptions="actionDone" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_androidacy_test_mode"
app:icon="@drawable/ic_baseline_bug_report_24"
app:title="@string/androidacy_test_mode_pref"
app:summary="@string/androidacy_test_mode_desc"
app:dependency="pref_androidacy_repo_enabled"
app:singleLineTitle="false" />
<Preference
app:key="pref_androidacy_repo_website"
app:icon="@drawable/ic_baseline_language_24"
@ -59,13 +81,6 @@
app:icon="@drawable/ic_baseline_upload_file_24"
app:title="@string/submit_modules"
app:singleLineTitle="false" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_androidacy_test_mode"
app:icon="@drawable/ic_baseline_bug_report_24"
app:title="@string/androidacy_test_mode_pref"
app:summary="@string/androidacy_test_mode_desc"
app:singleLineTitle="false" />
<Preference
app:key="pref_androidacy_ads_disclaimer"
app:icon="@drawable/ic_baseline_info_24"

@ -3,152 +3,165 @@
<!-- Custom repos has been announced, check https://github.com/Fox2Code/FoxMagiskModuleManager/issues/131 -->
<PreferenceCategory app:title="@string/pref_category_repos">
<Preference
app:key="pref_manage_repos"
app:icon="@drawable/ic_baseline_extension_24"
app:title="@string/manage_repos_pref"
app:singleLineTitle="false" />
app:key="pref_manage_repos"
app:singleLineTitle="false"
app:title="@string/manage_repos_pref" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_show_incompatible"
app:icon="@drawable/ic_baseline_hide_source_24"
app:title="@string/show_incompatible_pref"
app:key="pref_show_incompatible"
app:singleLineTitle="false"
app:summary="@string/show_incompatible_desc"
app:singleLineTitle="false" />
app:title="@string/show_incompatible_pref" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_disable_low_quality_module_filter"
app:icon="@drawable/ic_baseline_warning_24"
app:title="@string/disable_low_quality_module_filter_pref"
app:key="pref_disable_low_quality_module_filter"
app:singleLineTitle="false"
app:summary="@string/disable_low_quality_module_filter_desc"
app:singleLineTitle="false" />
app:title="@string/disable_low_quality_module_filter_pref" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_use_magisk_install_command"
app:icon="@drawable/ic_baseline_numbers_24"
app:title="@string/use_magisk_install_command_pref"
app:key="pref_use_magisk_install_command"
app:singleLineTitle="false"
app:summary="@string/use_magisk_install_command_desc"
app:singleLineTitle="false" />
app:title="@string/use_magisk_install_command_pref" />
<SwitchPreferenceCompat
app:defaultValue="true"
app:key="pref_background_update_check"
app:icon="@drawable/ic_baseline_notifications_24"
app:title="@string/notification_update_pref"
app:key="pref_background_update_check"
app:singleLineTitle="false"
app:summary="@string/notification_update_desc"
app:singleLineTitle="false" />
app:title="@string/notification_update_pref" />
<Preference
app:key="pref_background_update_check_debug"
app:title="@string/notification_update_debug_pref"
app:singleLineTitle="false" />
app:singleLineTitle="false"
app:title="@string/notification_update_debug_pref" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/pref_category_appearance">
<ListPreference
app:key="pref_theme"
app:icon="@drawable/ic_baseline_palette_24"
app:title="@string/theme_pref"
app:defaultValue="system"
app:entries="@array/theme_values_names"
app:entryValues="@array/theme_values"
app:singleLineTitle="false" />
app:icon="@drawable/ic_baseline_palette_24"
app:key="pref_theme"
app:singleLineTitle="false"
app:title="@string/theme_pref" />
<Preference
app:key="pref_language_selector"
app:icon="@drawable/ic_baseline_language_24"
app:title="@string/language" />
app:key="pref_language_selector"
app:title="@string/language" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_enable_blur"
app:icon="@drawable/ic_baseline_blur_on_24"
app:title="@string/enable_blur_pref"
app:singleLineTitle="false" />
app:key="pref_enable_blur"
app:singleLineTitle="false"
app:title="@string/enable_blur_pref" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_force_dark_terminal"
app:icon="@drawable/ic_baseline_list_24"
app:title="@string/force_dark_terminal_title"
app:singleLineTitle="false" />
app:key="pref_force_dark_terminal"
app:singleLineTitle="false"
app:title="@string/force_dark_terminal_title" />
<SwitchPreferenceCompat
app:defaultValue="@bool/monet_enabled_by_default"
app:key="pref_enable_monet"
app:icon="@drawable/ic_baseline_design_services_24"
app:title="@string/enable_monet"
app:singleLineTitle="false" />
app:key="pref_enable_monet"
app:singleLineTitle="false"
app:title="@string/enable_monet" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_wrap_text"
app:icon="@drawable/ic_baseline_keyboard_return_24"
app:title="@string/wrap_text_pref"
app:key="pref_wrap_text"
app:singleLineTitle="false"
app:summary="@string/wrap_text_desc"
app:singleLineTitle="false" />
app:title="@string/wrap_text_pref" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/pref_category_security">
<SwitchPreferenceCompat
app:defaultValue="true"
app:key="pref_dns_over_https"
app:icon="@drawable/ic_baseline_security_24"
app:title="@string/dns_over_https_pref"
app:key="pref_dns_over_https"
app:singleLineTitle="false"
app:summary="@string/dns_over_https_desc"
app:singleLineTitle="false" />
app:title="@string/dns_over_https_pref" />
<!-- Note: Lockdown mode used to be called showcase mode -->
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="pref_showcase_mode"
app:icon="@drawable/ic_baseline_lock_24"
app:title="@string/showcase_mode_pref"
app:key="pref_showcase_mode"
app:singleLineTitle="false"
app:summary="@string/showcase_mode_desc"
app:singleLineTitle="false" />
app:title="@string/showcase_mode_pref" />
<SwitchPreferenceCompat
app:defaultValue="true"
app:key="pref_prevent_reboot"
app:icon="@drawable/ic_reboot_24"
app:title="@string/prevent_reboot_pref"
app:key="pref_prevent_reboot"
app:singleLineTitle="false"
app:summary="@string/prevent_reboot_desc"
app:singleLineTitle="false" />
app:title="@string/prevent_reboot_pref" />
<!-- Crash reporting -->
<SwitchPreferenceCompat
app:defaultValue="true"
app:icon="@drawable/ic_baseline_bug_report_24"
app:key="pref_crash_reporting"
app:singleLineTitle="false"
app:summary="@string/crash_reporting_desc"
app:title="@string/crash_reporting" />
<!-- Purposely crash the app -->
<Preference
app:icon="@drawable/ic_baseline_bug_report_24"
app:key="pref_crash"
app:singleLineTitle="false"
app:title="@string/crash" />
</PreferenceCategory>
<PreferenceCategory
app:title="@string/pref_category_info">
<PreferenceCategory app:title="@string/pref_category_info">
<Preference
app:key="pref_update"
app:icon="@drawable/ic_baseline_system_update_24"
app:title="@string/app_update"
app:singleLineTitle="false" />
app:key="pref_update"
app:singleLineTitle="false"
app:title="@string/app_update" />
<Preference
app:key="pref_report_bug"
app:icon="@drawable/ic_baseline_bug_report_24"
app:title="@string/report_bugs"
app:singleLineTitle="false" />
app:key="pref_report_bug"
app:singleLineTitle="false"
app:title="@string/report_bugs" />
<Preference
app:key="pref_source_code"
app:icon="@drawable/ic_github"
app:title="@string/source_code"
app:singleLineTitle="false" />
app:key="pref_source_code"
app:singleLineTitle="false"
app:title="@string/source_code" />
<Preference
app:key="pref_support"
app:icon="@drawable/ic_baseline_telegram_24"
app:title="@string/support"
app:singleLineTitle="false" />
app:key="pref_support"
app:singleLineTitle="false"
app:title="@string/support" />
<Preference
app:key="pref_show_licenses"
app:icon="@drawable/ic_baseline_info_24"
app:title="@string/show_licenses"
app:singleLineTitle="false" />
app:key="pref_show_licenses"
app:singleLineTitle="false"
app:title="@string/show_licenses" />
<Preference
app:key="pref_pkg_info"
app:enabled="false"
app:summary="@string/loading"
app:iconSpaceReserved="false"
app:key="pref_pkg_info"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />
app:summary="@string/loading" />
</PreferenceCategory>
</PreferenceScreen>

@ -5,7 +5,7 @@ buildscript {
mavenCentral()
gradlePluginPortal()
}
project.ext.latestAboutLibsRelease = "10.3.1"
project.ext.latestAboutLibsRelease = "10.4.1-a01"
dependencies {
classpath 'com.android.tools.build:gradle:7.2.2'
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${latestAboutLibsRelease}"

Loading…
Cancel
Save