diff --git a/app/src/main/java/com/fox2code/mmm/background/BackgroundUpdateChecker.java b/app/src/main/java/com/fox2code/mmm/background/BackgroundUpdateChecker.java index bfe7b9c..df1cb10 100644 --- a/app/src/main/java/com/fox2code/mmm/background/BackgroundUpdateChecker.java +++ b/app/src/main/java/com/fox2code/mmm/background/BackgroundUpdateChecker.java @@ -37,8 +37,10 @@ import com.fox2code.mmm.repo.RepoModule; import com.fox2code.mmm.utils.io.PropUtils; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.TimeUnit; import timber.log.Timber; @@ -136,12 +138,52 @@ public class BackgroundUpdateChecker extends Worker { if ("twrp-keep".equals(localModuleInfo.id)) continue; // exclude all modules with id's stored in the pref pref_background_update_check_excludes try { - if (Objects.requireNonNull(MainApplication.getSharedPreferences("mmm").getStringSet("pref_background_update_check_excludes", null)).contains(localModuleInfo.id)) + if (Objects.requireNonNull(MainApplication.getSharedPreferences("mmm").getStringSet("pref_background_update_check_excludes", new HashSet<>())).contains(localModuleInfo.id)) continue; } catch (Exception ignored) { } + // now, we just had to make it more fucking complicated, didn't we? + // we now have pref_background_update_check_excludes_version, which is a id:version stringset of versions the user may want to "skip" + // oh, and because i hate myself, i made ^ at the beginning match that version and newer, and $ at the end match that version and older + Set stringSet = MainApplication.getSharedPreferences("mmm").getStringSet("pref_background_update_check_excludes_version", new HashSet<>()); + String version = ""; + if (stringSet.contains(localModuleInfo.id)) { + // get the one matching + version = stringSet.stream().filter(s -> s.startsWith(localModuleInfo.id)).findFirst().orElse(""); + } RepoModule repoModule = repoModules.get(localModuleInfo.id); localModuleInfo.checkModuleUpdate(); + String remoteVersion = localModuleInfo.updateVersion; + String remoteVersionCode = String.valueOf(localModuleInfo.updateVersionCode); + if (repoModule != null) { + remoteVersion = repoModule.moduleInfo.version; + remoteVersionCode = String.valueOf(repoModule.moduleInfo.versionCode); + } + // now, coerce everything into an int + int localVersionCode = Integer.parseInt(String.valueOf(localModuleInfo.versionCode)); + int remoteVersionCodeInt = Integer.parseInt(remoteVersionCode); + // we also have to match the version name + int localVersion = Integer.parseInt(localModuleInfo.version); + int remoteVersionInt = Integer.parseInt(remoteVersion); + int wantsVersion = Integer.parseInt(version.split(":")[1]); + // now find out if user wants up to and including this version, or this version and newer + // if it starts with ^, it's this version and newer, if it ends with $, it's this version and older + if (version.startsWith("^")) { + // this version and newer + if (wantsVersion > localVersion || wantsVersion > remoteVersionInt || wantsVersion > remoteVersionCodeInt || wantsVersion < localVersionCode) { + // if it is, we skip it + continue; + } + } else if (version.endsWith("$")) { + // this version and older + if (wantsVersion < localVersion || wantsVersion < remoteVersionInt || wantsVersion < remoteVersionCodeInt || wantsVersion > localVersionCode) { + // if it is, we skip it + continue; + } + } else if (wantsVersion == localVersion || wantsVersion == remoteVersionInt || wantsVersion == remoteVersionCodeInt || wantsVersion == localVersionCode) { + // if it is, we skip it + continue; + } if (localModuleInfo.updateVersionCode > localModuleInfo.versionCode && !PropUtils.isNullString(localModuleInfo.updateVersion)) { moduleUpdateCount++; updateableModules.put(localModuleInfo.name, localModuleInfo.version); diff --git a/app/src/main/java/com/fox2code/mmm/module/ModuleViewAdapter.java b/app/src/main/java/com/fox2code/mmm/module/ModuleViewAdapter.java index 321d14b..afd388d 100644 --- a/app/src/main/java/com/fox2code/mmm/module/ModuleViewAdapter.java +++ b/app/src/main/java/com/fox2code/mmm/module/ModuleViewAdapter.java @@ -12,6 +12,7 @@ import android.view.ViewGroup; import android.widget.HorizontalScrollView; import android.widget.ImageButton; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; @@ -212,6 +213,21 @@ public final class ModuleViewAdapter extends RecyclerView.Adapter { + // if both local and remote moduleInfo are available, show the versionCode of both + if (localModuleInfo != null) { + // if moduleInfo and localModuleInfo have the same versionCode, only show one, otherwise show both + if (localModuleInfo.versionCode == moduleInfo.versionCode) { + Toast.makeText(this.itemView.getContext(), this.getString(R.string.module_version) + " " + localModuleInfo.version + " (" + localModuleInfo.versionCode + ")", Toast.LENGTH_LONG).show(); + } else { + // format is Version: version (versionCode) | Remote Version: version (versionCode) + Toast.makeText(this.itemView.getContext(), this.getString(R.string.module_version) + " " + localModuleInfo.version + " (" + localModuleInfo.versionCode + ") | " + this.getString(R.string.module_remote_version) + " " + moduleInfo.version + " (" + moduleInfo.versionCode + ")", Toast.LENGTH_LONG).show(); + } + } else { + Toast.makeText(this.itemView.getContext(), this.getString(R.string.module_remote_version) + " " + moduleInfo.version + " (" + moduleInfo.versionCode + ")", Toast.LENGTH_LONG).show(); + } + }); if (moduleInfo.description == null || moduleInfo.description.isEmpty()) { this.descriptionText.setText(R.string.no_desc_found); } else { diff --git a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java index a1bcd3d..a367423 100644 --- a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java +++ b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java @@ -22,9 +22,12 @@ import android.provider.Settings; import android.text.Editable; import android.text.TextWatcher; import android.view.View; +import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ScrollView; import android.widget.Toast; import androidx.annotation.StringRes; @@ -76,6 +79,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.navigation.NavigationBarView; import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.textview.MaterialTextView; import com.mikepenz.aboutlibraries.LibsBuilder; import com.topjohnwu.superuser.internal.UiThreadHandler; @@ -579,18 +583,18 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { String[] moduleNames = new String[localModuleInfos.size()]; checkedItems = new boolean[localModuleInfos.size()]; int i = 0; + // get the stringset pref_background_update_check_excludes + Set stringSetTemp = sharedPreferences.getStringSet("pref_background_update_check_excludes", new HashSet<>()); + // copy to a new set so we can modify it + Set stringSet = new HashSet<>(stringSetTemp); for (LocalModuleInfo localModuleInfo : localModuleInfos) { moduleNames[i] = localModuleInfo.name; - // get the stringset pref_background_update_check_excludes - Set stringSet = sharedPreferences.getStringSet("pref_background_update_check_excludes", new HashSet<>()); // Stringset uses id, we show name checkedItems[i] = stringSet.contains(localModuleInfo.id); Timber.d("name: %s, checked: %s", moduleNames[i], checkedItems[i]); i++; } new MaterialAlertDialogBuilder(this.requireContext()).setTitle(R.string.background_update_check_excludes).setMultiChoiceItems(moduleNames, checkedItems, (dialog, which, isChecked) -> { - // get the stringset pref_background_update_check_excludes - Set stringSet = new HashSet<>(sharedPreferences.getStringSet("pref_background_update_check_excludes", new HashSet<>())); // get id from name String id; if (localModuleInfos.stream().anyMatch(localModuleInfo -> localModuleInfo.name.equals(moduleNames[which]))) { @@ -614,6 +618,72 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { } return true; }); + // now handle pref_background_update_check_excludes_version + updateCheckVersionExcludes.setVisible(MainApplication.isBackgroundUpdateCheckEnabled() && !MainApplication.isWrapped()); + updateCheckVersionExcludes.setOnPreferenceClickListener(preference -> { + // get the stringset pref_background_update_check_excludes_version + Set stringSet = sharedPreferences.getStringSet("pref_background_update_check_excludes_version", new HashSet<>()); + Timber.d("stringSet: %s", stringSet); + // for every module, add it's name and a text field to the dialog. the text field should accept a comma separated list of versions + Collection localModuleInfos = ModuleManager.getINSTANCE().getModules().values(); + // make sure we have modules + if (localModuleInfos.isEmpty()) { + new MaterialAlertDialogBuilder(this.requireContext()).setTitle(R.string.background_update_check_excludes).setMessage(R.string.background_update_check_excludes_no_modules).setPositiveButton(R.string.ok, (dialog, which) -> { + }).show(); + } else { + LinearLayout layout = new LinearLayout(this.requireContext()); + layout.setOrientation(LinearLayout.VERTICAL); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + params.setMargins(48, 0, 48, 0); + // add a summary + MaterialTextView textView = new MaterialTextView(this.requireContext()); + textView.setLayoutParams(params); + textView.setText(R.string.background_update_check_excludes_version_summary); + for (LocalModuleInfo localModuleInfo : localModuleInfos) { + // two views: materialtextview for name, edittext for version + MaterialTextView materialTextView = new MaterialTextView(this.requireContext()); + materialTextView.setLayoutParams(params); + materialTextView.setPadding(12, 8, 12, 8); + materialTextView.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1); + materialTextView.setText(localModuleInfo.name); + layout.addView(materialTextView); + EditText editText = new EditText(this.requireContext()); + editText.setLayoutParams(params); + editText.setHint(R.string.background_update_check_excludes_version_hint); + // stringset uses id:version, we show version for name + // so we need to get id from name, then get version from stringset + String id = localModuleInfos.stream().filter(localModuleInfo1 -> localModuleInfo1.name.equals(localModuleInfo.name)).findFirst().orElse(null).id; + String version = stringSet.stream().filter(s -> s.startsWith(id)).findFirst().orElse(""); + if (!version.isEmpty()) { + editText.setText(version.split(":")[1]); + } + layout.addView(editText); + } + ScrollView scrollView = new ScrollView(this.requireContext()); + scrollView.addView(layout); + new MaterialAlertDialogBuilder(this.requireContext()).setTitle(R.string.background_update_check_excludes_version).setView(scrollView).setPositiveButton(R.string.ok, (dialog, which) -> { + Timber.d("ok clicked"); + // for every module, get the text field and save it to the stringset + Set stringSetTemp = new HashSet<>(); + for (int i = 0; i < layout.getChildCount(); i++) { + EditText editText = (EditText) layout.getChildAt(i); + String text = editText.getText().toString(); + if (!text.isEmpty()) { + // text cannot contain a colon because we use that to split id and version + text = text.replace(":", ""); + // we have to use module id even though we show name + stringSetTemp.add(localModuleInfos.stream().filter(localModuleInfo -> localModuleInfo.name.equals(editText.getHint().toString())).findFirst().orElse(null).id + ":" + text); + Timber.d("text is %s for %s", text, editText.getHint().toString()); + } else { + Timber.d("text is empty for %s", editText.getHint().toString()); + } + } + sharedPreferences.edit().putStringSet("pref_background_update_check_excludes_version", stringSetTemp).apply(); + }).setNegativeButton(R.string.cancel, (dialog, which) -> { + }).show(); + } + return true; + }); final LibsBuilder libsBuilder = new LibsBuilder().withShowLoadingProgress(false).withLicenseShown(true).withAboutMinimalDesign(false); ClipboardManager clipboard = (ClipboardManager) requireContext().getSystemService(Context.CLIPBOARD_SERVICE); LongClickablePreference linkClickable = findPreference("pref_update"); diff --git a/app/src/main/res/layout/activity_crash_handler.xml b/app/src/main/res/layout/activity_crash_handler.xml index 3eae9ca..cfb764e 100644 --- a/app/src/main/res/layout/activity_crash_handler.xml +++ b/app/src/main/res/layout/activity_crash_handler.xml @@ -68,8 +68,8 @@ To enable the finish button, scroll to the bottom and acknowledge you have read and agree to the EULA and license(s). Ignore specific versions when checking for module updates. Disabling update checks per-module above overrides this setting! Exclude version(s) from update checks + Exclude version(s) of modules from checks + Specify versions of modules you\'d like to ignore. Version code or version name will work, but version code may be more accurate. Use ^ at the beginning to match that version and newer. Use $ at the end to match up until that version. + "Version: " + Remote version + Version(s) to ignore