diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 93e1b8878..d2e517b51 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,6 +37,8 @@ jobs: sudo apt install zipalign chmod +x scripts/apktool.jar chmod +x scripts/apksigner.jar + rustup target add armv7-linux-androideabi + rustup target add aarch64-linux-android - name: Build VTLite run: | diff --git a/.gitignore b/.gitignore index 9dec8284e..31e717eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ smali/assets/version.properties *.keystore gradle.properties scripts/build.sh +smali/lib/arm64-v8a/libnative_effects.so +smali/lib/armeabi-v7a/libnative_effects.so diff --git a/README.md b/README.md index 413e1f080..101a180a0 100644 --- a/README.md +++ b/README.md @@ -117,9 +117,13 @@ * Все необходимые скрипты/.jar файлы для компиляции APK, его подписывании и не только находятся в `/scripts` ### Необходимые зависимости - **JDK** >11 версии + [**JDK**](https://adoptium.net/temurin/releases/) >14 версии + + [**Rust**](https://www.rust-lang.org/learn/get-started) с Android ARM тулчейнами: `rustup target add aarch64-linux-android armv7-linux-androideabi` + + Android SDK и NDK (устанавливаются через +[sdkmanager](https://developer.android.com/studio/command-line/sdkmanager) или [Android Studio](https://developer.android.com/studio)) - **Android Studio** ### Linux/macOS/Windows diff --git a/app/build.gradle b/app/build.gradle index f7e6ee2cb..5f8f766c6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,6 +7,16 @@ import java.util.zip.ZipInputStream plugins { id 'com.android.application' id 'net.nemerosa.versioning' version '2.15.1' + id 'org.mozilla.rust-android-gradle.rust-android' +} + +cargo { + profile = 'release' + module = '../native-effects' + libname = 'native-effects' + targets = ["arm", "arm64"] + prebuiltToolchains = true + pythonCommand = "python3" } def smaliFolder = projectDir.toPath().resolve("../smali").normalize() @@ -100,6 +110,7 @@ android { targetCompatibility JavaVersion.VERSION_14 } namespace 'ru.vtosters.lite' + ndkVersion '25.2.9519653' } dependencies { @@ -112,6 +123,8 @@ dependencies { task prepareDexForMerge(type: Copy) { dependsOn('exportDex') + // Remove comment for native lib build + dependsOn('cargoBuild') into smaliFolder.toString() from(projectDir) { include 'classes6.dex' @@ -119,7 +132,16 @@ task prepareDexForMerge(type: Copy) { } from(projectDir) { include 'version.properties' - into("assets") + into 'assets' + } + // Remove comment for native lib build + from('../native-effects/target/aarch64-linux-android/release'){ + include 'libnative_effects.so' + into 'lib/arm64-v8a' + } + from('../native-effects/target/armv7-linux-androideabi/release'){ + include 'libnative_effects.so' + into 'lib/armeabi-v7a' } doLast { new File(projectDir, "classes6.dex").delete() diff --git a/app/src/main/java/com/vk/sharing/view/TargetImageView.java b/app/src/main/java/com/vk/sharing/view/TargetImageView.java index 9daf7139f..7358ce917 100644 --- a/app/src/main/java/com/vk/sharing/view/TargetImageView.java +++ b/app/src/main/java/com/vk/sharing/view/TargetImageView.java @@ -1,7 +1,6 @@ package com.vk.sharing.view; import static b.h.z.f.roboto_medium; -import static ru.vtosters.lite.utils.Preferences.preferences; import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor; import android.content.Context; @@ -32,6 +31,7 @@ import com.vk.imageloader.view.VKMultiImageView; import com.vk.navigation.NavigatorKeys; import com.vtosters.lite.R; import com.vtosters.lite.a0; +import ru.vtosters.lite.utils.Preferences; import java.util.Arrays; @@ -208,7 +208,7 @@ public class TargetImageView extends VKMultiImageView { @Override // android.view.View protected void onDraw(Canvas canvas) { Canvas canvas2 = this.f21631f; - int pref = preferences.getInt("pic_rounding", 0); + int pref = Preferences.getPreferences().getInt("pic_rounding", 0); if (canvas2 != null) { canvas2.drawColor(0, PorterDuff.Mode.CLEAR); diff --git a/app/src/main/java/ru/vtosters/lite/encryption/base/IMProcessor.java b/app/src/main/java/ru/vtosters/lite/encryption/base/IMProcessor.java index 2d96779c4..55f68d0b9 100644 --- a/app/src/main/java/ru/vtosters/lite/encryption/base/IMProcessor.java +++ b/app/src/main/java/ru/vtosters/lite/encryption/base/IMProcessor.java @@ -6,6 +6,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public abstract class IMProcessor { // By default it checks start and end tag. @@ -67,20 +68,20 @@ public abstract class IMProcessor { } public void enableEncryptFor(int id) { - AndroidUtils.getDefaultPrefs().edit().putBoolean("VT_IMEncode_" + getPrefKey() + "_" + id, true).apply(); + Preferences.getPreferences().edit().putBoolean("VT_IMEncode_" + getPrefKey() + "_" + id, true).apply(); } public void disableEncryptFor(int id) { - AndroidUtils.getDefaultPrefs().edit().putBoolean("VT_IMEncode_" + getPrefKey() + "_" + id, false).apply(); + Preferences.getPreferences().edit().putBoolean("VT_IMEncode_" + getPrefKey() + "_" + id, false).apply(); } public void setEncryptionKeyFor(int id, @Nullable String key) { if (key == null || key.isEmpty()) key = "VTAesDefault"; - AndroidUtils.getDefaultPrefs().edit().putString("VT_IMEncodeKey_" + getPrefKey() + "_" + id, key).apply(); + Preferences.getPreferences().edit().putString("VT_IMEncodeKey_" + getPrefKey() + "_" + id, key).apply(); } @Nullable public String getEncryptionKeyFor(int id) { - return AndroidUtils.getDefaultPrefs().getString("VT_IMEncodeKey_" + getPrefKey() + "_" + id, null); + return Preferences.getPreferences().getString("VT_IMEncodeKey_" + getPrefKey() + "_" + id, null); } } diff --git a/app/src/main/java/ru/vtosters/lite/encryption/processors/VTostersAESProcessor.java b/app/src/main/java/ru/vtosters/lite/encryption/processors/VTostersAESProcessor.java index 7f72be876..2d47494c1 100644 --- a/app/src/main/java/ru/vtosters/lite/encryption/processors/VTostersAESProcessor.java +++ b/app/src/main/java/ru/vtosters/lite/encryption/processors/VTostersAESProcessor.java @@ -18,6 +18,7 @@ import javax.crypto.spec.SecretKeySpec; import ru.vtosters.lite.encryption.base.IMProcessor; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class VTostersAESProcessor extends IMProcessor { private final static String CIPHER_INSTANCE = "AES/CBC/PKCS7Padding"; @@ -114,7 +115,7 @@ public class VTostersAESProcessor extends IMProcessor { @Nullable @Override public String getEncryptionKeyFor(int id) { - return AndroidUtils.getDefaultPrefs().getString("VT_IMEncodeKey_" + getPrefKey() + "_" + id, "VTAesDefault"); + return Preferences.getPreferences().getString("VT_IMEncodeKey_" + getPrefKey() + "_" + id, "VTAesDefault"); } public static class Triple { diff --git a/app/src/main/java/ru/vtosters/lite/hooks/AdBlockHook.java b/app/src/main/java/ru/vtosters/lite/hooks/AdBlockHook.java index 00096abd7..f7f343c91 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/AdBlockHook.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/AdBlockHook.java @@ -22,6 +22,7 @@ import java.util.Collections; import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.NewsFeedFiltersUtils; +import ru.vtosters.lite.utils.Preferences; public class AdBlockHook { public static Boolean discoverAdBlock(JSONObject jsonObject) { @@ -351,7 +352,7 @@ public class AdBlockHook { return true; } - var whitelist = AndroidUtils.getDefaultPrefs().getStringSet( + var whitelist = Preferences.getPreferences().getStringSet( "whitelisted_filters_groups", Collections.emptySet() ); @@ -366,7 +367,7 @@ public class AdBlockHook { id = String.valueOf(list.optInt("source_id")); } - var whitelist = AndroidUtils.getDefaultPrefs().getStringSet( + var whitelist = Preferences.getPreferences().getStringSet( "whitelisted_ad_groups", Collections.emptySet() ); @@ -377,7 +378,7 @@ public class AdBlockHook { public static Boolean isWhitelistedAdStories(JSONObject list) { var id = String.valueOf(list.optInt("owner_id")); - var whitelist = AndroidUtils.getDefaultPrefs().getStringSet( + var whitelist = Preferences.getPreferences().getStringSet( "whitelisted_stories_ad", Collections.emptySet() ); diff --git a/app/src/main/java/ru/vtosters/lite/hooks/DateHook.java b/app/src/main/java/ru/vtosters/lite/hooks/DateHook.java index edf3c405d..beff9cf6b 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/DateHook.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/DateHook.java @@ -1,6 +1,6 @@ package ru.vtosters.lite.hooks; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; import static ru.vtosters.lite.utils.AndroidUtils.getStringDate; import android.annotation.SuppressLint; @@ -15,11 +15,11 @@ import ru.vtosters.lite.utils.AndroidUtils; public class DateHook { public static boolean fulltime() { - return getPrefsValue("dateformat").equals("noyear") || getPrefsValue("dateformat").equals("full") || getPrefsValue("dateformat").equals("noseconds"); + return getString("dateformat").equals("noyear") || getString("dateformat").equals("full") || getString("dateformat").equals("noseconds"); } public static String getDateFormat() { - return switch (getPrefsValue("dateformat")) { + return switch (getString("dateformat")) { case "noyear" -> AndroidUtils.getString(R.string.fulltime2); case "full" -> AndroidUtils.getString(R.string.fulltime); default -> AndroidUtils.getString(R.string.fulltime3); @@ -45,7 +45,7 @@ public class DateHook { } public static String getLocale() { - String string = getPrefsValue("lang_value"); + String string = getString("lang_value"); if (string.equals("system")) { return Locale.getDefault().getLanguage(); diff --git a/app/src/main/java/ru/vtosters/lite/hooks/DockBarInjector.java b/app/src/main/java/ru/vtosters/lite/hooks/DockBarInjector.java index ee4344c06..243211d76 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/DockBarInjector.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/DockBarInjector.java @@ -108,10 +108,8 @@ public class DockBarInjector { private static void removeAllChildren(ViewGroup view) { for (int i = 0; i < view.getChildCount(); i++) { - if (view instanceof ViewGroup) { - removeAllChildren((ViewGroup) view.getChildAt(i)); - view.removeAllViews(); - } + removeAllChildren((ViewGroup) view.getChildAt(i)); + view.removeAllViews(); } } @@ -247,8 +245,8 @@ public class DockBarInjector { } try { JSONArray jSONArray = new JSONArray(); - for (int i = 0; i < arrayList.size(); i++) { - jSONArray.put(new JSONObject().put("name", arrayList.get(i))); + for (String s : arrayList) { + jSONArray.put(new JSONObject().put("name", s)); } for (int i2 = 0; i2 < arr.length(); i2++) { jSONArray.put(arr.getJSONObject(i2)); diff --git a/app/src/main/java/ru/vtosters/lite/hooks/FragAnimationHook.java b/app/src/main/java/ru/vtosters/lite/hooks/FragAnimationHook.java index 67e6dd8f4..c9b2f5f64 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/FragAnimationHook.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/FragAnimationHook.java @@ -1,7 +1,7 @@ package ru.vtosters.lite.hooks; import static ru.vtosters.lite.ui.components.FragAnimationKit.setAnimations; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; import androidx.fragment.app.FragmentTransaction; @@ -9,7 +9,7 @@ public class FragAnimationHook { public static boolean animateOpen(FragmentTransaction transaction) { setAnimations(transaction); - return getPrefsValue("anim_rtrn_type").equals("noanim") || getPrefsValue("anim_rtrn_type").isEmpty(); + return getString("anim_rtrn_type").equals("noanim") || getString("anim_rtrn_type").isEmpty(); } public static void animateClose(FragmentTransaction transaction) { diff --git a/app/src/main/java/ru/vtosters/lite/hooks/JsonInjectors.java b/app/src/main/java/ru/vtosters/lite/hooks/JsonInjectors.java index 22a2b28f6..292a7f227 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/JsonInjectors.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/JsonInjectors.java @@ -1,37 +1,22 @@ package ru.vtosters.lite.hooks; -import static ru.vtosters.lite.foaf.FoafBase.getBypassedOnlineInfo; -import static ru.vtosters.lite.hooks.OnlineFormatterHook.onlineHookProfiles; -import static ru.vtosters.lite.proxy.ProxyUtils.getStatic; -import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs; -import static ru.vtosters.lite.utils.Preferences.dev; -import static ru.vtosters.lite.utils.Preferences.friendsblock; -import static ru.vtosters.lite.utils.Preferences.getBoolValue; -import static ru.vtosters.lite.utils.Preferences.hasVerification; -import static ru.vtosters.lite.utils.VTVerifications.isDeveloper; -import static ru.vtosters.lite.utils.VTVerifications.isPrometheus; -import static ru.vtosters.lite.utils.VTVerifications.isVerified; - import android.text.TextUtils; import android.util.Log; - -import com.vk.core.util.LangUtils; -import com.vtosters.lite.R; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import ru.vtosters.lite.utils.AccountManagerUtils; +import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; import java.io.IOException; import java.text.ParseException; import java.util.LinkedHashSet; -import java.util.Objects; -import java.util.Random; -import okhttp3.OkHttpClient; -import ru.vtosters.lite.di.singleton.VtOkHttpClient; -import ru.vtosters.lite.utils.AccountManagerUtils; -import ru.vtosters.lite.utils.AndroidUtils; +import static ru.vtosters.lite.foaf.FoafBase.getBypassedOnlineInfo; +import static ru.vtosters.lite.hooks.OnlineFormatterHook.onlineHookProfiles; +import static ru.vtosters.lite.utils.Preferences.dev; +import static ru.vtosters.lite.utils.Preferences.friendsblock; public class JsonInjectors { public static JSONObject menu(JSONObject orig) throws JSONException { @@ -47,7 +32,7 @@ public class JsonInjectors { } public static JSONObject superapp(JSONObject json) throws JSONException { - var superApps = AndroidUtils.getPreferences().getString("superapp_items", + var superApps = Preferences.getPreferences().getString("superapp_items", "menu,miniapps,vkpay_slim,greeting,promo,holiday,weather,sport,games,informer,food,event,music,vk_run").split(","); if (superApps.length == 0) return json; @@ -154,8 +139,8 @@ public class JsonInjectors { } public static JSONArray newsfeedlist(JSONArray items) throws JSONException { - var selectedItems = getDefaultPrefs().getString("news_feed_selected_items", ""); - var filtersSet = getDefaultPrefs().getStringSet("news_feed_items_set", null); + var selectedItems = Preferences.getPreferences().getString("news_feed_selected_items", ""); + var filtersSet = Preferences.getPreferences().getStringSet("news_feed_items_set", null); var mutableFiltersSet = new LinkedHashSet(); if (filtersSet != null) mutableFiltersSet.addAll(filtersSet); @@ -182,7 +167,7 @@ public class JsonInjectors { .put("is_unavailable", hide); if (dev()) Log.d("NewsfeedListInj", "Unlocked " + id + " in newsfeed list"); } - getDefaultPrefs().edit().putStringSet("news_feed_items_set", mutableFiltersSet) + Preferences.getPreferences().edit().putStringSet("news_feed_items_set", mutableFiltersSet) .apply(); return items; diff --git a/app/src/main/java/ru/vtosters/lite/hooks/MainActivityInjector.java b/app/src/main/java/ru/vtosters/lite/hooks/MainActivityInjector.java index a1b3ac91a..e902cfe5e 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/MainActivityInjector.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/MainActivityInjector.java @@ -9,29 +9,28 @@ import static ru.vtosters.lite.utils.ThemesUtils.setNeededTheme; import android.app.Activity; import android.content.Intent; import android.os.Build; - import com.guardanis.applock.AppLock; import com.guardanis.applock.activities.UnlockActivity; - +import b.h.g.k.VKProgressDialog; +import com.vk.core.dialogs.alert.VkAlertDialog; +import com.vtosters.lite.R; import ru.vtosters.lite.concurrent.VTExecutors; import ru.vtosters.lite.downloaders.notifications.NotificationChannels; import ru.vtosters.lite.ssfs.UsersList; +import ru.vtosters.lite.themes.ThemesManager; import ru.vtosters.lite.ui.dialogs.DisableBattery; import ru.vtosters.lite.ui.dialogs.InstallGMS; import ru.vtosters.lite.ui.dialogs.OTADialog; import ru.vtosters.lite.ui.dialogs.Start; -import ru.vtosters.lite.utils.DeletedMessagesHandler; +import ru.vtosters.lite.utils.*; public class MainActivityInjector { public static void inject(Activity activity) { setNeededTheme(activity); sendRequest(); UsersList.getUsersList(); + if (checkupdates()) OTADialog.checkUpdates(activity); - VTExecutors.getIoScheduler().a(DeletedMessagesHandler::reloadMessagesList); // ioScheduler - Start.alert(activity); - InstallGMS.alert(activity); - DisableBattery.alert(activity); VTExecutors.getSlowTasksScheduler().a(() -> { getInstance().autoCleaningCache(); @@ -47,6 +46,45 @@ public class MainActivityInjector { activity.startActivity(intent); } + if(Preferences.isNewBuild() && !ThemesUtils.isMonetTheme() && ThemesManager.canApplyCustomAccent()) { + Preferences.updateBuildNumber(); + updateBinsAndTmpArchive(activity); + } + + VTExecutors.getIoScheduler().a(DeletedMessagesHandler::reloadMessagesList); // ioScheduler + + if(activity.getIntent().getAction() != null && Intent.ACTION_APPLICATION_PREFERENCES.equals(activity.getIntent().getAction())) { + NavigatorUtils.switchToSettings(activity); + return; + } + + Start.alert(activity); + InstallGMS.alert(activity); + DisableBattery.alert(activity); // VKIDProtection.alert(activity); } + + private static void updateBinsAndTmpArchive(Activity activity) { + final VKProgressDialog dialog = new VKProgressDialog(activity); + + dialog.setMessage("Применение акцента"); + dialog.show(); + + VTExecutors.getIoExecutor().execute(() -> { + try { + ThemesManager.generateModApk(ThemesUtils.getReservedAccent()); + activity.runOnUiThread(LifecycleUtils::restartApplication); + } catch(Throwable e) { + e.printStackTrace(); + activity.runOnUiThread(() -> { + dialog.cancel(); + new VkAlertDialog.Builder(activity) + .setTitle("Ошикба") + .setMessage("Ошибка при применении акцента:\n" + e) + .setPositiveButton(R.string.ok, null) + .show(); + }); + } + }); + } } diff --git a/app/src/main/java/ru/vtosters/lite/hooks/NewsfeedHook.java b/app/src/main/java/ru/vtosters/lite/hooks/NewsfeedHook.java index d0fac6988..3dbbaefbc 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/NewsfeedHook.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/NewsfeedHook.java @@ -1,9 +1,8 @@ package ru.vtosters.lite.hooks; import static java.lang.Long.MAX_VALUE; -import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs; import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; import static ru.vtosters.lite.utils.Preferences.ads; import static ru.vtosters.lite.utils.Preferences.authorsrecomm; import static ru.vtosters.lite.utils.Preferences.friendsrecomm; @@ -23,13 +22,14 @@ import java.util.LinkedHashSet; import java.util.List; import ru.vtosters.lite.utils.AccountManagerUtils; +import ru.vtosters.lite.utils.Preferences; public class NewsfeedHook { public static long getUpdateNewsfeed(boolean refresh_timeout) { if (vkme()) { return MAX_VALUE; } - return switch (getPrefsValue("newsupdate")) { + return switch (getString("newsupdate")) { case "no_update" -> MAX_VALUE; case "imd_update" -> 10000L; default -> @@ -67,20 +67,20 @@ public class NewsfeedHook { } public static boolean isWhitelistedFilter(ExtendedCommunityProfile eup) { - return getDefaultPrefs().getStringSet( + return Preferences.getPreferences().getStringSet( "whitelisted_filters_groups", Collections.emptySet() ).contains(String.valueOf(AccountManagerUtils.getUserID(eup))); } public static boolean isWhitelistedAd(ExtendedCommunityProfile eup) { - return getDefaultPrefs().getStringSet( + return Preferences.getPreferences().getStringSet( "whitelisted_ad_groups", Collections.emptySet() ).contains(String.valueOf(AccountManagerUtils.getUserID(eup))); } public static boolean isWhitelistedAdStories(ExtendedCommunityProfile eup) { - return getDefaultPrefs().getStringSet( + return Preferences.getPreferences().getStringSet( "whitelisted_stories_ad", Collections.emptySet() ).contains(String.valueOf(AccountManagerUtils.getUserID(eup))); @@ -89,7 +89,7 @@ public class NewsfeedHook { public static void setWhitelistedFilter(ExtendedCommunityProfile eup, boolean needWhitelist) { var id = String.valueOf(AccountManagerUtils.getUserID(eup)); - var mutableAdsSet = new LinkedHashSet<>(getDefaultPrefs().getStringSet( + var mutableAdsSet = new LinkedHashSet<>(Preferences.getPreferences().getStringSet( "whitelisted_filters_groups", Collections.emptySet()) ); @@ -99,13 +99,13 @@ public class NewsfeedHook { mutableAdsSet.remove(id); } - getDefaultPrefs().edit().putStringSet("whitelisted_filters_groups", mutableAdsSet).apply(); + Preferences.getPreferences().edit().putStringSet("whitelisted_filters_groups", mutableAdsSet).apply(); } public static void setWhitelistedAd(ExtendedCommunityProfile eup, boolean needWhitelist) { var id = String.valueOf(AccountManagerUtils.getUserID(eup)); - var mutableAdsSet = new LinkedHashSet<>(getDefaultPrefs().getStringSet( + var mutableAdsSet = new LinkedHashSet<>(Preferences.getPreferences().getStringSet( "whitelisted_ad_groups", Collections.emptySet())); @@ -115,13 +115,13 @@ public class NewsfeedHook { mutableAdsSet.remove(id); } - getDefaultPrefs().edit().putStringSet("whitelisted_ad_groups", mutableAdsSet).apply(); + Preferences.getPreferences().edit().putStringSet("whitelisted_ad_groups", mutableAdsSet).apply(); } public static void setWhitelistedAdStories(ExtendedCommunityProfile eup, boolean needWhitelist) { var id = String.valueOf(AccountManagerUtils.getUserID(eup)); - var mutableAdsSet = new LinkedHashSet<>(getDefaultPrefs().getStringSet( + var mutableAdsSet = new LinkedHashSet<>(Preferences.getPreferences().getStringSet( "whitelisted_stories_ad", Collections.emptySet())); @@ -131,7 +131,7 @@ public class NewsfeedHook { mutableAdsSet.remove(id); } - getDefaultPrefs().edit().putStringSet("whitelisted_stories_ad", mutableAdsSet).apply(); + Preferences.getPreferences().edit().putStringSet("whitelisted_stories_ad", mutableAdsSet).apply(); } public static void adsParams(HashSet hashSet) { diff --git a/app/src/main/java/ru/vtosters/lite/hooks/PhotoViewer.java b/app/src/main/java/ru/vtosters/lite/hooks/PhotoViewer.java index 653f9b112..fd1614fa8 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/PhotoViewer.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/PhotoViewer.java @@ -1,6 +1,5 @@ package ru.vtosters.lite.hooks; -import static ru.vtosters.lite.utils.AndroidUtils.getPreferences; import android.annotation.SuppressLint; import android.content.ClipData; @@ -12,9 +11,7 @@ import android.util.Log; import android.view.MenuItem; import android.view.View; import android.widget.Toast; - import androidx.annotation.Nullable; - import com.vk.core.dialogs.actionspopup.ActionsPopup; import com.vk.core.dialogs.alert.VkAlertDialog; import com.vk.core.ui.themes.VKThemeHelper; @@ -25,23 +22,18 @@ import com.vk.dto.common.ImageSize; import com.vtosters.lite.R; import com.vtosters.lite.attachments.DocumentAttachment; import com.vtosters.lite.attachments.PhotoAttachment; - +import okhttp3.*; import org.json.JSONException; import org.json.JSONObject; +import ru.vtosters.lite.di.singleton.VtOkHttpClient; +import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.LifecycleUtils; +import ru.vtosters.lite.utils.Preferences; import java.io.IOException; import java.net.URLEncoder; import java.util.List; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import ru.vtosters.lite.di.singleton.VtOkHttpClient; -import ru.vtosters.lite.utils.AndroidUtils; -import ru.vtosters.lite.utils.LifecycleUtils; - public class PhotoViewer { static OkHttpClient client = VtOkHttpClient.getInstance(); @@ -203,7 +195,7 @@ public class PhotoViewer { } private static int selectedEngine() { - return getPreferences().getInt("search_engine", 0); + return Preferences.getPreferences().getInt("search_engine", 0); } private static void searchPhoto(int i, String url) { diff --git a/app/src/main/java/ru/vtosters/lite/hooks/PicRoundingHook.java b/app/src/main/java/ru/vtosters/lite/hooks/PicRoundingHook.java index f4b3874ed..e1a36c8b0 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/PicRoundingHook.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/PicRoundingHook.java @@ -1,20 +1,12 @@ package ru.vtosters.lite.hooks; -import static ru.vtosters.lite.utils.Preferences.preferences; - -import android.graphics.Bitmap; -import android.graphics.BitmapShader; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.RectF; -import android.graphics.Shader; - +import android.graphics.*; import com.facebook.drawee.generic.RoundingParams; - import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class PicRoundingHook { - private static final int pref = preferences.getInt("pic_rounding", 0); + private static final int pref = Preferences.getPreferences().getInt("pic_rounding", 0); public static RoundingParams inject() { if (pref > 0) { diff --git a/app/src/main/java/ru/vtosters/lite/hooks/ProxyHook.java b/app/src/main/java/ru/vtosters/lite/hooks/ProxyHook.java index 40aff781a..7584c10a6 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/ProxyHook.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/ProxyHook.java @@ -1,30 +1,23 @@ package ru.vtosters.lite.hooks; -import static ru.vtosters.lite.proxy.ProxyUtils.isRandomProxyEnabled; -import static ru.vtosters.lite.proxy.ProxyUtils.isVikaProxyEnabled; -import static ru.vtosters.lite.proxy.ProxyUtils.isZaboronaEnabled; -import static ru.vtosters.lite.utils.AndroidUtils.dp2px; -import static ru.vtosters.lite.utils.AndroidUtils.edit; -import static ru.vtosters.lite.utils.LifecycleUtils.restartApplication; -import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr; - import android.annotation.SuppressLint; import android.content.Context; -import android.content.Intent; import android.util.TypedValue; import android.view.View; import android.widget.RadioButton; import android.widget.RadioGroup; - import androidx.appcompat.view.ContextThemeWrapper; - import com.vk.auth.ui.VkAuthTextView; import com.vk.core.dialogs.alert.VkAlertDialog; -import com.vk.navigation.Navigator; import com.vtosters.lite.R; - import ru.vtosters.lite.ui.fragments.ProxySettingsFragment; import ru.vtosters.lite.utils.NavigatorUtils; +import ru.vtosters.lite.utils.Preferences; + +import static ru.vtosters.lite.proxy.ProxyUtils.*; +import static ru.vtosters.lite.utils.AndroidUtils.dp2px; +import static ru.vtosters.lite.utils.LifecycleUtils.restartApplication; +import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr; public class ProxyHook { public static void hookAuth(View v) { @@ -77,16 +70,16 @@ public class ProxyHook { .setView(rg) .setPositiveButton(ctx.getString(R.string.vtl_confirm), ((dialog, which) -> { // Применить if (rgZaborona.isChecked()) { - edit().putString("proxy", "zaborona").commit(); + Preferences.getPreferences().edit().putString("proxy", "zaborona").commit(); restartApplication(); } else if (rgRandomProxy.isChecked()) { - edit().putString("proxy", "randomproxy").commit(); + Preferences.getPreferences().edit().putString("proxy", "randomproxy").commit(); restartApplication(); } else if (rgVika.isChecked()) { - edit().putString("proxy", "vika").commit(); + Preferences.getPreferences().edit().putString("proxy", "vika").commit(); restartApplication(); } else { - edit().putString("proxy", "noproxy").commit(); + Preferences.getPreferences().edit().putString("proxy", "noproxy").commit(); restartApplication(); } })) diff --git a/app/src/main/java/ru/vtosters/lite/hooks/StartFragmentHook.java b/app/src/main/java/ru/vtosters/lite/hooks/StartFragmentHook.java index 19aed89c9..d6b8cf7db 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/StartFragmentHook.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/StartFragmentHook.java @@ -1,7 +1,7 @@ package ru.vtosters.lite.hooks; import static ru.vtosters.lite.ui.components.DockBarEditorManager.getInstance; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; import static ru.vtosters.lite.utils.Preferences.milkshake; import static ru.vtosters.lite.utils.Preferences.superapp; import static ru.vtosters.lite.utils.Preferences.useNewSettings; @@ -35,7 +35,7 @@ public class StartFragmentHook { if (vkme()) { return DialogsFragment.class; } - return switch (getPrefsValue("start_values")) { + return switch (getString("start_values")) { case "newsfeed" -> milkshake() ? HomeFragment.class : NewsfeedFragment.class; case "messenger" -> DialogsFragment.class; case "groups" -> milkshake() ? CommunitiesCatalogFragment.class : GroupsFragment1.class; diff --git a/app/src/main/java/ru/vtosters/lite/hooks/VKUIHook.java b/app/src/main/java/ru/vtosters/lite/hooks/VKUIHook.java index 7c1c3b6b4..348fad1b3 100644 --- a/app/src/main/java/ru/vtosters/lite/hooks/VKUIHook.java +++ b/app/src/main/java/ru/vtosters/lite/hooks/VKUIHook.java @@ -1,20 +1,6 @@ package ru.vtosters.lite.hooks; -import static android.util.Base64.encodeToString; -import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; -import static ru.vtosters.lite.utils.Preferences.getBoolValue; -import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor; -import static ru.vtosters.lite.utils.ThemesUtils.getBackgroundContent; -import static ru.vtosters.lite.utils.ThemesUtils.getBackgroundPage; -import static ru.vtosters.lite.utils.ThemesUtils.getColorFromAttr; -import static ru.vtosters.lite.utils.ThemesUtils.getHeaderBackground; -import static ru.vtosters.lite.utils.ThemesUtils.getHeaderText; -import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr; -import static ru.vtosters.lite.utils.ThemesUtils.hex; - import android.webkit.WebView; - import com.vk.articles.preload.WebCachePreloader; import com.vtosters.lite.R; import com.vtosters.lite.data.ThemeTracker; @@ -27,6 +13,11 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import static android.util.Base64.encodeToString; +import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; +import static ru.vtosters.lite.utils.Preferences.getBoolValue; +import static ru.vtosters.lite.utils.ThemesUtils.*; + public class VKUIHook { public static boolean isLoaded = false; private static String loadedCSS = ""; diff --git a/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java b/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java index 70fe7e201..bf5313fe2 100644 --- a/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java +++ b/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java @@ -180,7 +180,7 @@ public class LastFMScrobbler { var name = session.getString("name"); var key = session.getString("key"); - AndroidUtils.edit() + Preferences.getPreferences().edit() .putString("username", name) .putString("sessionKey", key) .putBoolean("lastfm_enabled", true) @@ -190,7 +190,7 @@ public class LastFMScrobbler { } public static void logout() { - AndroidUtils.edit() + Preferences.getPreferences().edit() .remove("username") .remove("sessionKey") .putBoolean("lastfm_enabled", false) @@ -208,14 +208,14 @@ public class LastFMScrobbler { } public static boolean isScrobblingEnabled() { - return AndroidUtils.getPreferences().getBoolean("lastfm_enabled", false); + return Preferences.getPreferences().getBoolean("lastfm_enabled", false); } public static String getUserName() { - return AndroidUtils.getDefaultPrefs().getString("username", null); + return Preferences.getPreferences().getString("username", null); } private static String getSessionKey() { - return AndroidUtils.getDefaultPrefs().getString("sessionKey", null); + return Preferences.getPreferences().getString("sessionKey", null); } } diff --git a/app/src/main/java/ru/vtosters/lite/music/catalog/inject/CatalogJsonInjector.java b/app/src/main/java/ru/vtosters/lite/music/catalog/inject/CatalogJsonInjector.java index d769cc972..7b8365bff 100644 --- a/app/src/main/java/ru/vtosters/lite/music/catalog/inject/CatalogJsonInjector.java +++ b/app/src/main/java/ru/vtosters/lite/music/catalog/inject/CatalogJsonInjector.java @@ -14,6 +14,7 @@ import ru.vtosters.lite.di.singleton.VtOkHttpClient; import ru.vtosters.lite.music.cache.CacheDatabaseDelegate; import ru.vtosters.lite.utils.AccountManagerUtils; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; import java.io.IOException; @@ -93,7 +94,7 @@ public class CatalogJsonInjector { var title = item.optString("title"); var id = item.optString("id"); var url = item.optString("url"); - var value = AndroidUtils.getPrefsValue("musicdefcatalog"); + var value = Preferences.getString("musicdefcatalog"); Log.d("VKMusic", "title: " + title + " id: " + id + " url: " + url + " value: " + value); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/ProxyUtils.java b/app/src/main/java/ru/vtosters/lite/proxy/ProxyUtils.java index 9e178d784..e0333d31f 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/ProxyUtils.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/ProxyUtils.java @@ -5,7 +5,7 @@ import static ru.vtosters.lite.proxy.api.VikaMobile.getApiHost; import static ru.vtosters.lite.proxy.api.VikaMobile.getOauthHost; import static ru.vtosters.lite.proxy.api.VikaMobile.getStaticHost; import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; + import android.annotation.SuppressLint; import android.content.Context; @@ -21,10 +21,11 @@ import ru.vtosters.lite.proxy.http.CustomHttp; import ru.vtosters.lite.proxy.https.CustomHttps; import ru.vtosters.lite.proxy.socks.CustomSocks; import ru.vtosters.lite.proxy.socks.Zaborona; +import ru.vtosters.lite.utils.Preferences; public class ProxyUtils { public static String getApi() { - var proxyapi = getPrefsValue("proxyapi"); + var proxyapi = Preferences.getString("proxyapi"); if (isVikaProxyEnabled()) { proxyapi = getApiHost(); @@ -38,7 +39,7 @@ public class ProxyUtils { } public static String getOauth() { - var oauth = getPrefsValue("proxyoauth"); + var oauth = Preferences.getString("proxyoauth"); if (isVikaProxyEnabled()) { oauth = getOauthHost(); @@ -52,7 +53,7 @@ public class ProxyUtils { } public static String getStatic() { - var staticapi = getPrefsValue("proxystatic"); + var staticapi = Preferences.getString("proxystatic"); if (isVikaProxyEnabled()) { staticapi = getStaticHost(); @@ -70,19 +71,19 @@ public class ProxyUtils { } public static Boolean isZaboronaEnabled() { - return getPrefsValue("proxy").equals("zaborona"); + return Preferences.getString("proxy").equals("zaborona"); } public static Boolean isRandomProxyEnabled() { - return getPrefsValue("proxy").equals("randomproxy"); + return Preferences.getString("proxy").equals("randomproxy"); } public static Boolean isApiProxyEnabled() { - return getPrefsValue("proxy").equals("apiproxy"); + return Preferences.getString("proxy").equals("apiproxy"); } public static Boolean isVikaProxyEnabled() { - return getPrefsValue("proxy").equals("vika"); + return Preferences.getString("proxy").equals("vika"); } public static void forceProxyApplying() { @@ -134,7 +135,7 @@ public class ProxyUtils { public static void setProxy() throws IOException { if (!isAnyProxyEnabled()) return; - switch (getPrefsValue("proxy")) { + switch (Preferences.getString("proxy")) { case "zaborona" -> Zaborona.loadProxy(); case "randomproxy" -> RandomProxy.loadProxy(); case "socks" -> CustomSocks.loadProxy(); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/RandomProxy.java b/app/src/main/java/ru/vtosters/lite/proxy/RandomProxy.java index 1ae0c613f..6e85036bf 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/RandomProxy.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/RandomProxy.java @@ -1,20 +1,18 @@ package ru.vtosters.lite.proxy; -import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; -import static ru.vtosters.lite.proxy.ProxyUtils.resetProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; -import static ru.vtosters.lite.utils.Preferences.preferences; - -import java.io.IOException; - import ru.vtosters.lite.proxy.socks.Hookzof; import ru.vtosters.lite.proxy.socks.Jetkai; import ru.vtosters.lite.proxy.socks.Roosterkid; import ru.vtosters.lite.proxy.socks.TheSpeedX; +import ru.vtosters.lite.utils.Preferences; + +import java.io.IOException; + +import static ru.vtosters.lite.proxy.ProxyUtils.resetProxy; public class RandomProxy { - public static String type = preferences.getString("random_type", "none"); - public static String host = preferences.getString("random_host", ""); + public static String type = Preferences.getPreferences().getString("random_type", "none"); + public static String host = Preferences.getPreferences().getString("random_host", ""); public static boolean showProxyResult = false; public static void loadProxy() throws IOException { @@ -40,13 +38,13 @@ public class RandomProxy { } public static void setupNewProxy() throws IOException { - edit().putString("random_type", "none").putString("random_host", "").commit(); + Preferences.getPreferences().edit().putString("random_type", "none").putString("random_host", "").commit(); resetProxy(); showProxyResult = true; getProxy(); - edit().putString("proxy", "randomproxy").commit(); + Preferences.getPreferences().edit().putString("proxy", "randomproxy").commit(); } public static boolean getProxy() throws IOException { diff --git a/app/src/main/java/ru/vtosters/lite/proxy/api/ApiProxy.java b/app/src/main/java/ru/vtosters/lite/proxy/api/ApiProxy.java index 60b8da1e9..425acd715 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/api/ApiProxy.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/api/ApiProxy.java @@ -2,7 +2,7 @@ package ru.vtosters.lite.proxy.api; import static ru.vtosters.lite.proxy.ProxyUtils.isAnyProxyEnabled; import static ru.vtosters.lite.proxy.ProxyUtils.isVikaProxyEnabled; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; import android.util.Log; @@ -12,9 +12,9 @@ public class ApiProxy { var oauth = "oauth.vk.com"; var vkstatic = "static.vk.com"; - var proxyapi = getPrefsValue("proxyapi"); - var proxyoauth = getPrefsValue("proxyoauth"); - var proxystatic = getPrefsValue("proxystatic"); + var proxyapi = getString("proxyapi"); + var proxyoauth = getString("proxyoauth"); + var proxystatic = getString("proxystatic"); if (isVikaProxyEnabled()) { proxyapi = VikaMobile.getApiHost(); @@ -47,7 +47,7 @@ public class ApiProxy { } public static String staticFix(String str) { - var string = getPrefsValue("proxystatic"); + var string = getString("proxystatic"); if (isVikaProxyEnabled()) { string = VikaMobile.getStaticHost(); @@ -61,7 +61,7 @@ public class ApiProxy { } public static String getAwayPhpCom() { - var proxyapi = getPrefsValue("proxyapi"); + var proxyapi = getString("proxyapi"); if (isVikaProxyEnabled()) { proxyapi = VikaMobile.getApiHost(); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/http/CustomHttp.java b/app/src/main/java/ru/vtosters/lite/proxy/http/CustomHttp.java index bc4dc265f..33dfe6b29 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/http/CustomHttp.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/http/CustomHttp.java @@ -1,7 +1,7 @@ package ru.vtosters.lite.proxy.http; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; public class CustomHttp { public static void loadProxy() { @@ -13,22 +13,22 @@ public class CustomHttp { } private static String proxyHostHTTP() { - var string = getPrefsValue("proxyHostHTTP"); + var string = getString("proxyHostHTTP"); return string.isEmpty() ? "192.168.0.1" : string; } private static String proxyPortHTTP() { - var string = getPrefsValue("proxyPortHTTP"); + var string = getString("proxyPortHTTP"); return string.isEmpty() ? "8888" : string; } private static String proxyUserHTTP() { - var string = getPrefsValue("proxyUserHTTP"); + var string = getString("proxyUserHTTP"); return string.isEmpty() ? "" : string; } private static String proxyPassHTTP() { - var string = getPrefsValue("proxyPassHTTP"); + var string = getString("proxyPassHTTP"); return string.isEmpty() ? "" : string; } } diff --git a/app/src/main/java/ru/vtosters/lite/proxy/http/Jetkai.java b/app/src/main/java/ru/vtosters/lite/proxy/http/Jetkai.java index 6ff0a39b3..73b088758 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/http/Jetkai.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/http/Jetkai.java @@ -3,7 +3,6 @@ package ru.vtosters.lite.proxy.http; import static ru.vtosters.lite.proxy.GithubList.getProxy; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import android.util.Log; @@ -14,6 +13,7 @@ import java.util.ArrayList; import ru.vtosters.lite.proxy.RandomProxy; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class Jetkai { private static final String TAG = "Jetkai_Http"; @@ -41,7 +41,7 @@ public class Jetkai { RandomProxy.showProxyResult = false; } - edit().putString("random_type", "http").putString("random_host", proxy).commit(); + Preferences.getPreferences().edit().putString("random_type", "http").putString("random_host", proxy).commit(); System.setProperty("http.proxyHost", proxy.split(":")[0]); System.setProperty("http.proxyPort", proxy.split(":")[1]); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/http/TheSpeedX.java b/app/src/main/java/ru/vtosters/lite/proxy/http/TheSpeedX.java index 29f2e6657..4c662602f 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/http/TheSpeedX.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/http/TheSpeedX.java @@ -3,7 +3,6 @@ package ru.vtosters.lite.proxy.http; import static ru.vtosters.lite.proxy.GithubList.getProxy; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import android.util.Log; @@ -14,6 +13,7 @@ import java.util.ArrayList; import ru.vtosters.lite.proxy.RandomProxy; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class TheSpeedX { private static final String TAG = "TheSpeedX_Http"; @@ -40,7 +40,7 @@ public class TheSpeedX { RandomProxy.showProxyResult = false; } - edit().putString("random_type", "http").putString("random_host", proxy).commit(); + Preferences.getPreferences().edit().putString("random_type", "http").putString("random_host", proxy).commit(); System.setProperty("http.proxyHost", proxy.split(":")[0]); System.setProperty("http.proxyPort", proxy.split(":")[1]); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/https/CustomHttps.java b/app/src/main/java/ru/vtosters/lite/proxy/https/CustomHttps.java index bcb1cb96d..5a6af8c21 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/https/CustomHttps.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/https/CustomHttps.java @@ -1,7 +1,7 @@ package ru.vtosters.lite.proxy.https; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; public class CustomHttps { public static void loadProxy() { @@ -13,22 +13,22 @@ public class CustomHttps { } private static String proxyHostHTTPS() { - var string = getPrefsValue("proxyHostHTTPS"); + var string = getString("proxyHostHTTPS"); return string.isEmpty() ? "192.168.0.1" : string; } private static String proxyPortHTTPS() { - var string = getPrefsValue("proxyPortHTTPS"); + var string = getString("proxyPortHTTPS"); return string.isEmpty() ? "8888" : string; } private static String proxyUserHTTPS() { - var string = getPrefsValue("proxyUserHTTPS"); + var string = getString("proxyUserHTTPS"); return string.isEmpty() ? "" : string; } private static String proxyPassHTTPS() { - String string = getPrefsValue("proxyPassHTTPS"); + String string = getString("proxyPassHTTPS"); return string.isEmpty() ? "" : string; } } diff --git a/app/src/main/java/ru/vtosters/lite/proxy/https/Jetkai.java b/app/src/main/java/ru/vtosters/lite/proxy/https/Jetkai.java index 79e2c737a..a9260d8f4 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/https/Jetkai.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/https/Jetkai.java @@ -3,7 +3,6 @@ package ru.vtosters.lite.proxy.https; import static ru.vtosters.lite.proxy.GithubList.getProxy; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import android.util.Log; @@ -14,6 +13,7 @@ import java.util.ArrayList; import ru.vtosters.lite.proxy.RandomProxy; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class Jetkai { private static final String TAG = "Jetkai_Https"; @@ -40,7 +40,7 @@ public class Jetkai { RandomProxy.showProxyResult = false; } - edit().putString("random_type", "https").putString("random_host", proxy).commit(); + Preferences.getPreferences().edit().putString("random_type", "https").putString("random_host", proxy).commit(); System.setProperty("https.proxyHost", proxy.split(":")[0]); System.setProperty("https.proxyPort", proxy.split(":")[1]); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/https/Roosterkid.java b/app/src/main/java/ru/vtosters/lite/proxy/https/Roosterkid.java index 442a02cbe..d1a4be5ae 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/https/Roosterkid.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/https/Roosterkid.java @@ -3,7 +3,6 @@ package ru.vtosters.lite.proxy.https; import static ru.vtosters.lite.proxy.GithubList.getProxy; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import android.util.Log; @@ -14,6 +13,7 @@ import java.util.ArrayList; import ru.vtosters.lite.proxy.RandomProxy; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class Roosterkid { private static final String TAG = "Roosterkid_Https"; @@ -40,7 +40,7 @@ public class Roosterkid { RandomProxy.showProxyResult = false; } - edit().putString("random_type", "https").putString("random_host", proxy).commit(); + Preferences.getPreferences().edit().putString("random_type", "https").putString("random_host", proxy).commit(); System.setProperty("https.proxyHost", proxy.split(":")[0]); System.setProperty("https.proxyPort", proxy.split(":")[1]); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/socks/CustomSocks.java b/app/src/main/java/ru/vtosters/lite/proxy/socks/CustomSocks.java index 87429899d..711b68328 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/socks/CustomSocks.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/socks/CustomSocks.java @@ -1,7 +1,7 @@ package ru.vtosters.lite.proxy.socks; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; public class CustomSocks { public static void loadProxy() { @@ -11,12 +11,12 @@ public class CustomSocks { } private static String proxyHostSocks() { - var string = getPrefsValue("proxyHostSocks"); + var string = getString("proxyHostSocks"); return string.isEmpty() ? "192.168.0.1" : string; } private static String proxyPortSocks() { - var string = getPrefsValue("proxyPortSocks"); + var string = getString("proxyPortSocks"); return string.isEmpty() ? "8888" : string; } } diff --git a/app/src/main/java/ru/vtosters/lite/proxy/socks/Hookzof.java b/app/src/main/java/ru/vtosters/lite/proxy/socks/Hookzof.java index ffe8d681e..22a44c01f 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/socks/Hookzof.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/socks/Hookzof.java @@ -3,7 +3,6 @@ package ru.vtosters.lite.proxy.socks; import static ru.vtosters.lite.proxy.GithubList.getProxy; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import android.util.Log; @@ -14,6 +13,7 @@ import java.util.ArrayList; import ru.vtosters.lite.proxy.RandomProxy; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class Hookzof { private static final String TAG = "Hookzof_Socks"; @@ -40,7 +40,7 @@ public class Hookzof { RandomProxy.showProxyResult = false; } - edit().putString("random_type", "socks").putString("random_host", proxy).commit(); + Preferences.getPreferences().edit().putString("random_type", "socks").putString("random_host", proxy).commit(); System.setProperty("socksProxyHost", proxy.split(":")[0]); System.setProperty("socksProxyPort", proxy.split(":")[1]); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/socks/Jetkai.java b/app/src/main/java/ru/vtosters/lite/proxy/socks/Jetkai.java index 0ab9ae73e..c42595f9b 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/socks/Jetkai.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/socks/Jetkai.java @@ -3,7 +3,6 @@ package ru.vtosters.lite.proxy.socks; import static ru.vtosters.lite.proxy.GithubList.getProxy; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import android.util.Log; @@ -14,6 +13,7 @@ import java.util.ArrayList; import ru.vtosters.lite.proxy.RandomProxy; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class Jetkai { private static final String TAG = "Jetkai_Socks"; @@ -40,7 +40,7 @@ public class Jetkai { RandomProxy.showProxyResult = false; } - edit().putString("random_type", "socks").putString("random_host", proxy).commit(); + Preferences.getPreferences().edit().putString("random_type", "socks").putString("random_host", proxy).commit(); System.setProperty("socksProxyHost", proxy.split(":")[0]); System.setProperty("socksProxyPort", proxy.split(":")[1]); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/socks/Roosterkid.java b/app/src/main/java/ru/vtosters/lite/proxy/socks/Roosterkid.java index 1ad4ae45f..03b4a15f8 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/socks/Roosterkid.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/socks/Roosterkid.java @@ -3,7 +3,6 @@ package ru.vtosters.lite.proxy.socks; import static ru.vtosters.lite.proxy.GithubList.getProxy; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import android.util.Log; @@ -14,6 +13,7 @@ import java.util.ArrayList; import ru.vtosters.lite.proxy.RandomProxy; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class Roosterkid { private static final String TAG = "Roosterkid_Socks"; @@ -40,7 +40,7 @@ public class Roosterkid { RandomProxy.showProxyResult = false; } - edit().putString("random_type", "socks").putString("random_host", proxy).commit(); + Preferences.getPreferences().edit().putString("random_type", "socks").putString("random_host", proxy).commit(); System.setProperty("socksProxyHost", proxy.split(":")[0]); System.setProperty("socksProxyPort", proxy.split(":")[1]); diff --git a/app/src/main/java/ru/vtosters/lite/proxy/socks/TheSpeedX.java b/app/src/main/java/ru/vtosters/lite/proxy/socks/TheSpeedX.java index 64ab42813..29c3d63be 100644 --- a/app/src/main/java/ru/vtosters/lite/proxy/socks/TheSpeedX.java +++ b/app/src/main/java/ru/vtosters/lite/proxy/socks/TheSpeedX.java @@ -3,7 +3,6 @@ package ru.vtosters.lite.proxy.socks; import static ru.vtosters.lite.proxy.GithubList.getProxy; import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying; import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import android.util.Log; @@ -14,6 +13,7 @@ import java.util.ArrayList; import ru.vtosters.lite.proxy.RandomProxy; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class TheSpeedX { private static final String TAG = "TheSpeedX_Socks"; @@ -40,7 +40,7 @@ public class TheSpeedX { RandomProxy.showProxyResult = false; } - edit().putString("random_type", "socks").putString("random_host", proxy).commit(); + Preferences.getPreferences().edit().putString("random_type", "socks").putString("random_host", proxy).commit(); System.setProperty("socksProxyHost", proxy.split(":")[0]); System.setProperty("socksProxyPort", proxy.split(":")[1]); diff --git a/app/src/main/java/ru/vtosters/lite/ssfs/ImBanner.java b/app/src/main/java/ru/vtosters/lite/ssfs/ImBanner.java index e15c7333f..11029fd8e 100644 --- a/app/src/main/java/ru/vtosters/lite/ssfs/ImBanner.java +++ b/app/src/main/java/ru/vtosters/lite/ssfs/ImBanner.java @@ -75,7 +75,7 @@ public class ImBanner { .setMessage(AndroidUtils.getString("custom_links_warning")) .setCancelable(false) .setPositiveButton(R.string.continue_, (dialogInterface, i) -> { - Preferences.preferences.edit().putBoolean("linkalert", true).commit(); + Preferences.getPreferences().edit().putBoolean("linkalert", true).commit(); }) .setNeutralButton(R.string.cancel, (dialogInterface, i) -> { dialogInterface.cancel(); diff --git a/app/src/main/java/ru/vtosters/lite/ssfs/Utils.java b/app/src/main/java/ru/vtosters/lite/ssfs/Utils.java index 854a1a2a1..6a9ccc8d2 100644 --- a/app/src/main/java/ru/vtosters/lite/ssfs/Utils.java +++ b/app/src/main/java/ru/vtosters/lite/ssfs/Utils.java @@ -3,7 +3,10 @@ package ru.vtosters.lite.ssfs; import com.vk.core.network.Network; import ru.vtosters.lite.hooks.DateHook; import ru.vtosters.lite.proxy.ProxyUtils; -import ru.vtosters.lite.utils.*; +import ru.vtosters.lite.utils.AccountManagerUtils; +import ru.vtosters.lite.utils.Base64Utils; +import ru.vtosters.lite.utils.Preferences; +import ru.vtosters.lite.utils.ThemesUtils; public class Utils { public static String getVKUILink() { @@ -20,7 +23,7 @@ public class Utils { } public static String getDomain() { - String string = AndroidUtils.getPrefsValue("ssfscustom"); + String string = Preferences.getString("ssfscustom"); if (!string.isEmpty()) return string; diff --git a/app/src/main/java/ru/vtosters/lite/themes/ThemesCore.java b/app/src/main/java/ru/vtosters/lite/themes/ThemesCore.java index 0a3f4bb27..a5eafa49e 100644 --- a/app/src/main/java/ru/vtosters/lite/themes/ThemesCore.java +++ b/app/src/main/java/ru/vtosters/lite/themes/ThemesCore.java @@ -2,10 +2,12 @@ package ru.vtosters.lite.themes; import android.annotation.SuppressLint; import android.content.Context; +import android.util.Log; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import androidx.annotation.IdRes; import com.vtosters.lite.R; +import ru.vtosters.lite.utils.Preferences; import ru.vtosters.lite.utils.ThemesUtils; @@ -161,12 +163,13 @@ public class ThemesCore { } public static boolean hasThemedAttr(Context context, int attrID) { -// try { -// Log.d(TAG, "Requesting color by attr " + context.getResources().getResourceName(attrID)); -// } catch (Exception e) { -// } - if (ThemesUtils.isCustomAccentEnabled()) { + if (Preferences.dev()) { + try { + Log.d(TAG, "Requesting color by attr " + context.getResources().getResourceName(attrID)); + } catch (Exception ignored) {} + } + if (isCachedAccents()) { if (ThemesUtils.isDarkTheme()) { return (themedColors.get(attrID) != 0 && ACCENT_THEME_ONLY_DARK.get(attrID, true) && ( diff --git a/app/src/main/java/ru/vtosters/lite/themes/ThemesManager.java b/app/src/main/java/ru/vtosters/lite/themes/ThemesManager.java index 1a5f24fbf..07b979a79 100644 --- a/app/src/main/java/ru/vtosters/lite/themes/ThemesManager.java +++ b/app/src/main/java/ru/vtosters/lite/themes/ThemesManager.java @@ -2,18 +2,18 @@ package ru.vtosters.lite.themes; import android.app.Application; import android.content.Context; +import android.graphics.Color; import android.util.Log; import com.google.devrel.gmscore.tools.apk.arsc.BinaryResourceFile; import com.vtosters.lite.R; import ru.vtosters.lite.themes.loaders.ResourcesLoader; import ru.vtosters.lite.themes.utils.ArscEditor; import ru.vtosters.lite.utils.IOUtils; +import ru.vtosters.lite.utils.Preferences; import ru.vtosters.lite.utils.ThemesUtils; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; +import java.io.*; +import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; @@ -95,144 +95,126 @@ public class ThemesManager { R.color.darker_blue, R.color.header_blue_opacity40 }; - private final static String[] NAMES = { - "resources.arsc", - "res", - "assets" + // modify it if "doNotCompress" in apktool.yml has been edited + private final static String[] DO_NOT_COMPRESS = { + ".png", + ".jpg", + ".mp3", + "res/raw/keep_cronet_api.xml" }; + private static String baseApkPath; + + private static boolean validated = false; + // Directories private static File mainDir; - private static File binDir; - private static File palettesDir; + private static File colorSchemesDir; - // Files - - // Temp archive with resources.arsc and res.zip content for loading resources - private static File resTmpZipFile = null; - - // Archive with assets folder content for loading resources - private static File assetsZipFile = null; - - // Archive with res folder content - private static File resZipFile = null; - - // Resources table file - private static File resourcesArscFile = null; + // Modified archive with resources.arsc, other resources and assets + private static File modApk; public static void init(Application app) { try { - Log.d("ThemesManager", "init paths"); initPaths(app); + validateModApk(); - if (hasTmpArchive() && !ThemesUtils.isMonetTheme()) { + if (!Preferences.isNewBuild() && !ThemesUtils.isMonetTheme() && canApplyCustomAccent()) { ResourcesLoader.init(app); - ResourcesLoader.load(app, resTmpZipFile.getAbsolutePath(), assetsZipFile.getAbsolutePath(), false); + ResourcesLoader.load(app, modApk.getAbsolutePath(), false); } } catch (Exception e) { - Log.e("ThemesManager", String.valueOf(e)); + Log.e("ThemesManager", e+""); } } + // validate modded apk before loading + private static void validateModApk() + throws IOException { + final var apk = new ZipFile(modApk); + apk.close(); + + validated = true; + } + private static void initPaths(Context context) { + baseApkPath = context.getApplicationInfo().publicSourceDir; + mainDir = new File(context.getFilesDir(), "VTLThemes"); if (!mainDir.exists()) mainDir.mkdir(); - binDir = new File(mainDir, "bin"); - if (!binDir.exists()) mainDir.mkdir(); + colorSchemesDir = new File(mainDir, "color_schemes"); + if (!colorSchemesDir.exists()) colorSchemesDir.mkdir(); - palettesDir = new File(mainDir, "palettes"); - if (!palettesDir.exists()) palettesDir.mkdir(); - - assetsZipFile = new File(binDir, "assets.zip"); - resZipFile = new File(binDir, "res.zip"); - resourcesArscFile = new File(binDir, "resources.arsc"); - resTmpZipFile = new File(binDir, "res.tmp.zip"); + modApk = new File(mainDir, "mod.apk"); } - public static void generateBins(Context context) - throws IOException { - try (final var apk = new ZipFile(context.getApplicationInfo().sourceDir)) { - for (var filename : NAMES) { - final var bin = new File(binDir, filename); - if (!bin.exists()) - if (filename.contains(".")) extractFile(apk, filename, bin); - else extractAndCompressDirectory(apk, filename, new File(binDir, filename + ".zip")); - } - } + public static boolean canApplyCustomAccent() { + return validated && modApk.exists() && ThemesUtils.getReservedAccent() != Color.TRANSPARENT; } - private static void extractFile(ZipFile apk, String name, File out) - throws IOException { - final var is = apk.getInputStream(apk.getEntry(name)); - if (!out.exists()) out.getParentFile().mkdirs(); - IOUtils.copy(is, out); - } + public static void generateModApk(int accentColor) + throws Throwable { + try( + final var apk = new ZipFile(baseApkPath) + ) { + final var arscEntry = apk.getEntry("resources.arsc"); + final var arscBis = new BufferedInputStream(apk.getInputStream(arscEntry)); + final var arsc = BinaryResourceFile.fromInputStream(arscBis); + if(!ArscEditor.changeColors(arsc, ACCENT_COLORS, accentColor)) + throw new IllegalStateException("Not all colors have been changed"); - private static void extractAndCompressDirectory(ZipFile apk, String dirName, File out) - throws IOException { - final var zos = new ZipOutputStream(new FileOutputStream(out)); - try (zos) { - final var entries = apk.entries(); - while (entries.hasMoreElements()) { - final var entry = entries.nextElement(); - if (!entry.getName().startsWith(dirName + "/")) continue; + try( + final var zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(modApk))) + ) { + final var arscBuff = arsc.toByteArray(); + final var newArscEntry = new ZipEntry("resources.arsc"); - zos.putNextEntry(new ZipEntry(entry.getName())); + final var crc = new CRC32(); + crc.update(arscBuff); - final var zis = apk.getInputStream(entry); - IOUtils.copy(zis, zos); + newArscEntry.setSize(arscBuff.length); + newArscEntry.setMethod(ZipEntry.STORED); + newArscEntry.setCrc(crc.getValue()); - zis.close(); + zos.putNextEntry(newArscEntry); + zos.write(arscBuff); zos.closeEntry(); + + final var entries = apk.entries(); + while(entries.hasMoreElements()) { + final var entry = entries.nextElement(); + final var name = entry.getName(); + + if(!name.startsWith("res/") && !name.startsWith("assets/") || name.equals("resources.arsc")) continue; + + var doNotCompress = false; + for(var suffix : DO_NOT_COMPRESS) { + if(name.endsWith(suffix)) { + doNotCompress = true; + break; + } + } + + final var entryBis = new BufferedInputStream(apk.getInputStream(entry)); + final var newEntry = new ZipEntry(name); + + if(doNotCompress) { + newEntry.setMethod(ZipEntry.STORED); + newEntry.setSize(entry.getSize()); + newEntry.setCrc(entry.getCrc()); + } else newEntry.setMethod(ZipEntry.DEFLATED); + + zos.putNextEntry(newEntry); + IOUtils.copy(entryBis, zos); + entryBis.close(); + zos.closeEntry(); + } } } } - public static boolean hasBins() { - return assetsZipFile.exists() && resZipFile.exists() && resourcesArscFile.exists(); - } - - public static boolean hasTmpArchive() { - return resTmpZipFile.exists(); - } - - public static void generateTempResArchive(int accentColor) - throws IOException { - final var resZip = new ZipFile(resZipFile); - final var zos = new ZipOutputStream(new FileOutputStream(resTmpZipFile)); - try (zos) { - final var entries = resZip.entries(); - while (entries.hasMoreElements()) { - final var entry = entries.nextElement(); - final var is = resZip.getInputStream(entry); - - zos.putNextEntry(new ZipEntry(entry.getName())); - IOUtils.copy(is, zos); - - is.close(); - zos.closeEntry(); - } - - final var arsc = new BinaryResourceFile(IOUtils.readFully(resourcesArscFile)); - if (!ArscEditor.changeColors(arsc, ACCENT_COLORS, accentColor)) { - resZip.close(); - resTmpZipFile.delete(); - throw new IOException("Error while generating res.tmp.res"); - } - - zos.putNextEntry(new ZipEntry("resources.arsc")); - IOUtils.copy(new ByteArrayInputStream(arsc.toByteArray()), zos); - } - } - - public static void deleteBins() { - assetsZipFile.delete(); - resZipFile.delete(); - resourcesArscFile.delete(); - } - - public static void deleteTmpArchive() { - resTmpZipFile.delete(); + public static void deleteModification() { + modApk.delete(); } } diff --git a/app/src/main/java/ru/vtosters/lite/themes/loaders/ResourcesLoader.java b/app/src/main/java/ru/vtosters/lite/themes/loaders/ResourcesLoader.java index e4c4ec8b6..84df42503 100644 --- a/app/src/main/java/ru/vtosters/lite/themes/loaders/ResourcesLoader.java +++ b/app/src/main/java/ru/vtosters/lite/themes/loaders/ResourcesLoader.java @@ -108,7 +108,7 @@ public class ResourcesLoader { } } - public static void load(Context context, String resPath, String assetsPath, boolean reinject) + public static void load(Context context, String resPath, boolean reinject) throws Exception { final ApplicationInfo appInfo = context.getApplicationInfo(); @@ -136,8 +136,7 @@ public class ResourcesLoader { sAssetManager = AssetManager.class.newInstance(); // Create a new AssetManager instance and point it to the resources installed under - if (AssetManagerHelper.addAssetPath(sAssetManager, resPath) == 0 - || AssetManagerHelper.addAssetPath(sAssetManager, assetsPath) == 0) + if (AssetManagerHelper.addAssetPath(sAssetManager, resPath) == 0) throw new IllegalStateException("Could not create new AssetManager"); // Add SharedLibraries to AssetManager for resolve system resources not found issue @@ -192,10 +191,10 @@ public class ResourcesLoader { } } - installResourceInsuranceHacks(context, resPath, assetsPath); + installResourceInsuranceHacks(context, resPath); } - private static void installResourceInsuranceHacks(Context context, String patchedResApkPath, String patchedAssetsApkPath) { + private static void installResourceInsuranceHacks(Context context, String patchedResApkPath) { try { final Object activityThread = ReflectionUtils.getActivityThread(context, null); final Field mHField = ReflectionUtils.findField(activityThread, "mH"); @@ -204,7 +203,7 @@ public class ResourcesLoader { final Handler.Callback originCallback = (Handler.Callback) mCallbackField.get(mH); if (!(originCallback instanceof ResourceInsuranceHandlerCallback)) { final ResourceInsuranceHandlerCallback hackCallback = new ResourceInsuranceHandlerCallback( - context, patchedResApkPath, patchedAssetsApkPath, originCallback, mH.getClass()); + context, patchedResApkPath, originCallback, mH.getClass()); mCallbackField.set(mH, hackCallback); } else { Log.w("ResourcesLoader", "installResourceInsuranceHacks: already installed, skip rest logic."); @@ -274,7 +273,6 @@ public class ResourcesLoader { private final Context mContext; private final String mPatchResApkPath; - private final String mPatchedAssetsApkPath; private final Handler.Callback mOriginalCallback; private final int LAUNCH_ACTIVITY; @@ -284,11 +282,10 @@ public class ResourcesLoader { private Method mGetCallbacksMethod = null; private boolean mSkipInterceptExecuteTransaction = false; - ResourceInsuranceHandlerCallback(Context context, String patchResApkPath, String patchedAssetsApkPath, Handler.Callback original, Class hClazz) { + ResourceInsuranceHandlerCallback(Context context, String patchResApkPath, Handler.Callback original, Class hClazz) { Context appContext = context.getApplicationContext(); mContext = (appContext != null ? appContext : context); mPatchResApkPath = patchResApkPath; - mPatchedAssetsApkPath = patchedAssetsApkPath; mOriginalCallback = original; LAUNCH_ACTIVITY = fetchMessageId(hClazz, "LAUNCH_ACTIVITY", 100); RELAUNCH_ACTIVITY = fetchMessageId(hClazz, "RELAUNCH_ACTIVITY", 126); @@ -365,7 +362,7 @@ public class ResourcesLoader { } if (shouldReInjectPatchedResources) { try { - load(mContext, mPatchResApkPath, mPatchedAssetsApkPath, true); + load(mContext, mPatchResApkPath, true); } catch (Throwable thr) { thr.printStackTrace(); } diff --git a/app/src/main/java/ru/vtosters/lite/themes/utils/ArscEditor.java b/app/src/main/java/ru/vtosters/lite/themes/utils/ArscEditor.java index c37f8b926..d25e6b705 100644 --- a/app/src/main/java/ru/vtosters/lite/themes/utils/ArscEditor.java +++ b/app/src/main/java/ru/vtosters/lite/themes/utils/ArscEditor.java @@ -19,8 +19,8 @@ public class ArscEditor { final var id = BinaryResourceIdentifier.create(packageChunk.getId(), typeSpecChunk.getId(), entry.getKey()); - for (int i = 0; i < colorIds.length; ++i) { - if (colorIds[i] != id.resId()) continue; + for (int colorId : colorIds) { + if (colorId != id.resId()) continue; final var value = entry.getValue(); value.updateValue(new BinaryResourceValue(8, value.value().type(), color /*colors[i]*/)); diff --git a/app/src/main/java/ru/vtosters/lite/translators/BaseTranslator.java b/app/src/main/java/ru/vtosters/lite/translators/BaseTranslator.java index b220c526b..07a994b18 100644 --- a/app/src/main/java/ru/vtosters/lite/translators/BaseTranslator.java +++ b/app/src/main/java/ru/vtosters/lite/translators/BaseTranslator.java @@ -1,6 +1,6 @@ package ru.vtosters.lite.translators; -import static ru.vtosters.lite.utils.Preferences.preferences; +import static ru.vtosters.lite.utils.Preferences.getPreferences; import androidx.annotation.NonNull; import androidx.collection.LruCache; @@ -8,6 +8,7 @@ import androidx.collection.LruCache; import java.util.Locale; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public abstract class BaseTranslator { @@ -22,7 +23,7 @@ public abstract class BaseTranslator { }; public static String getToLanguage() { - var lang = preferences.getString("lang_target", "system"); + var lang = getPreferences().getString("lang_target", "system"); var systemLang = Locale.getDefault().getLanguage(); if (lang.isEmpty() || lang.equals(systemLang) || lang.equals("system")) @@ -32,7 +33,7 @@ public abstract class BaseTranslator { } public static BaseTranslator getInstance() { - return switch (AndroidUtils.getPreferences().getInt("translator", 0)) { + return switch (Preferences.getPreferences().getInt("translator", 0)) { case YANDEX -> YandexTranslator.getInstance(); case GOOGLE -> GoogleTranslator.getInstance(); case DEEPL -> DeepLTranslator.getInstance(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/components/DockBarEditorManager.java b/app/src/main/java/ru/vtosters/lite/ui/components/DockBarEditorManager.java index 83e788a9f..9ccb9cff1 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/components/DockBarEditorManager.java +++ b/app/src/main/java/ru/vtosters/lite/ui/components/DockBarEditorManager.java @@ -26,6 +26,7 @@ import com.vtosters.lite.general.fragments.GamesFragment; import com.vtosters.lite.general.fragments.PhotosFragment; import ru.vtosters.lite.ui.items.DockBarTab; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; import java.io.File; import java.util.ArrayList; @@ -33,7 +34,6 @@ import java.util.Arrays; import java.util.List; import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.getPreferences; import static ru.vtosters.lite.utils.Preferences.*; public class DockBarEditorManager { @@ -110,7 +110,7 @@ public class DockBarEditorManager { } public void reset() { - AndroidUtils.getPreferences() + Preferences.getPreferences() .edit() .putString("dockbar_tabs", "tab_news,tab_superapps,tab_messages,tab_friends,tab_profile") .commit(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/components/FragAnimationKit.java b/app/src/main/java/ru/vtosters/lite/ui/components/FragAnimationKit.java index 101b8ce0c..0cfab19aa 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/components/FragAnimationKit.java +++ b/app/src/main/java/ru/vtosters/lite/ui/components/FragAnimationKit.java @@ -1,13 +1,11 @@ package ru.vtosters.lite.ui.components; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; - import android.content.res.Resources; - import androidx.fragment.app.FragmentTransaction; - import com.vtosters.lite.R; +import static ru.vtosters.lite.utils.Preferences.getString; + public class FragAnimationKit { // Q @@ -33,8 +31,8 @@ public class FragAnimationKit { private static final int SSTactCloseExit = resources.getIdentifier("task_close_exit", "anim", "android"); public static void setAnimations(FragmentTransaction transaction) { - if (transaction != null && !getPrefsValue("anim_rtrn_type").equals("noanim")) { - switch (getPrefsValue("anim_rtrn_type")) { + if (transaction != null && !getString("anim_rtrn_type").equals("noanim")) { + switch (getString("anim_rtrn_type")) { case "q" -> transaction.setCustomAnimations( actOpenEnter, actOpenExit, diff --git a/app/src/main/java/ru/vtosters/lite/ui/components/NewsfeedListManager.java b/app/src/main/java/ru/vtosters/lite/ui/components/NewsfeedListManager.java index 5901db7c7..f12d297d3 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/components/NewsfeedListManager.java +++ b/app/src/main/java/ru/vtosters/lite/ui/components/NewsfeedListManager.java @@ -2,11 +2,11 @@ package ru.vtosters.lite.ui.components; import static ru.vtosters.lite.ui.vkui.VBListBuilder.VBListItem; import static ru.vtosters.lite.ui.vkui.VBListBuilder.buildListOf; -import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs; import static ru.vtosters.lite.utils.AndroidUtils.sendToast; import android.app.Activity; +import com.vk.core.preference.Preference; import com.vtosters.lite.R; import java.util.ArrayList; @@ -14,12 +14,13 @@ import java.util.Collections; import ru.vtosters.lite.ui.vkui.VBottomSheetBuilder; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; public class NewsfeedListManager { public static void callEditorPopup(Activity activity) { - var selectedItems = getDefaultPrefs().getString("news_feed_selected_items", ""); - var filtersSet = getDefaultPrefs().getStringSet("news_feed_items_set", Collections.emptySet()); + var selectedItems = Preferences.getString("news_feed_selected_items"); + var filtersSet = Preferences.getPreferences().getStringSet("news_feed_items_set", Collections.emptySet()); var list = new ArrayList(filtersSet.size()); if (filtersSet.isEmpty()) { @@ -44,7 +45,8 @@ public class NewsfeedListManager { for (VBListItem item : list) if (item.checked) newSelectedItems += item.id + ","; - getDefaultPrefs().edit() + Preferences.getPreferences() + .edit() .putString("news_feed_selected_items", newSelectedItems) .apply(); sendToast(activity.getString(R.string.newsfeed_list_update_feed_to_work)); @@ -54,7 +56,8 @@ public class NewsfeedListManager { } public static void resetHideItems() { - getDefaultPrefs().edit() + Preferences.getPreferences() + .edit() .remove("news_feed_selected_items") .remove("news_feed_items_set") .apply(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/components/SuperAppEditorManager.java b/app/src/main/java/ru/vtosters/lite/ui/components/SuperAppEditorManager.java index a20e57427..58dde7cce 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/components/SuperAppEditorManager.java +++ b/app/src/main/java/ru/vtosters/lite/ui/components/SuperAppEditorManager.java @@ -4,14 +4,13 @@ import android.os.Build; import com.vtosters.lite.R; import ru.vtosters.lite.ui.items.SuperAppItem; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import static ru.vtosters.lite.utils.AndroidUtils.getPreferences; - public class SuperAppEditorManager { private static SuperAppEditorManager sInstance; @@ -29,7 +28,7 @@ public class SuperAppEditorManager { } private void init() { - var tmp = getPreferences().getString("superapp_items", "menu,miniapps,vkpay_slim,greeting,promo,holiday,weather,sport,games,informer,food,event,music,vk_run"); + var tmp = Preferences.getPreferences().getString("superapp_items", "menu,miniapps,vkpay_slim,greeting,promo,holiday,weather,sport,games,informer,food,event,music,vk_run"); var selectedTags = !tmp.isEmpty() ? tmp.split(",") : new String[0]; parseSelectedItems(selectedTags); } @@ -49,7 +48,7 @@ public class SuperAppEditorManager { public void save() { if (mSelectedItems.size() > 0) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - getPreferences().edit().putString("superapp_items", mSelectedItems.stream() + Preferences.getPreferences().edit().putString("superapp_items", mSelectedItems.stream() .map(item -> item.type) .collect(Collectors.joining(","))) .commit(); @@ -59,14 +58,14 @@ public class SuperAppEditorManager { sb.append(item.type); sb.append(","); } - getPreferences().edit().putString("superapp_items", sb.toString()).commit(); + Preferences.getPreferences().edit().putString("superapp_items", sb.toString()).commit(); } else reset(); } public void reset() { - AndroidUtils.getPreferences() + Preferences.getPreferences() .edit() .putString("superapp_items", "menu,miniapps,vkpay_slim,greeting,promo,holiday,informer,event,weather,sport,games,food,music,vk_run") .commit(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/DisableBattery.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/DisableBattery.java index 24ba7f18b..8d93afaa8 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/DisableBattery.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/DisableBattery.java @@ -1,5 +1,6 @@ package ru.vtosters.lite.ui.dialogs; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -7,12 +8,9 @@ import android.net.Uri; import android.os.Build; import android.os.PowerManager; import android.provider.Settings; - import com.vk.core.dialogs.alert.VkAlertDialog; import com.vtosters.lite.R; - import ru.vtosters.lite.deviceinfo.OEMDetector; -import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.Preferences; public class DisableBattery { @@ -27,13 +25,14 @@ public class DisableBattery { .setMessage(R.string.batteryissuesumm) .setCancelable(false) .setPositiveButton(R.string.batteryissuebtn1, (dialogInterface, i) -> { + @SuppressLint("BatteryLife") var intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .setData(Uri.parse("package:" + packName)); activity.startActivity(intent); }) .setNeutralButton(R.string.batteryissuebtn2, - (dialogInterface, i) -> AndroidUtils.edit().putBoolean("showDoze", false).apply() + (dialogInterface, i) -> Preferences.getPreferences().edit().putBoolean("showDoze", false).apply() ) .show(); } diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/InstallGMS.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/InstallGMS.java index 7e31cb3f2..18320d919 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/InstallGMS.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/InstallGMS.java @@ -1,18 +1,14 @@ package ru.vtosters.lite.ui.dialogs; -import static ru.vtosters.lite.utils.AndroidUtils.edit; -import static ru.vtosters.lite.utils.GmsUtils.isGmsInstalled; -import static ru.vtosters.lite.utils.Preferences.getBoolValue; - import android.app.Activity; -import android.content.Intent; - import com.vk.core.dialogs.alert.VkAlertDialog; -import com.vk.navigation.Navigator; import com.vtosters.lite.R; - import ru.vtosters.lite.ui.fragments.InstallGMSFragment; import ru.vtosters.lite.utils.NavigatorUtils; +import ru.vtosters.lite.utils.Preferences; + +import static ru.vtosters.lite.utils.GmsUtils.isGmsInstalled; +import static ru.vtosters.lite.utils.Preferences.getBoolValue; public class InstallGMS { public static void alert(final Activity activity) { @@ -22,10 +18,10 @@ public class InstallGMS { .setMessage(activity.getString(R.string.gmsissuesumm)) .setCancelable(false) .setPositiveButton(activity.getString(R.string.gmsissuebtn1), ( - dialogInterface, i) -> edit().putBoolean("showAlertGms", false).apply() + dialogInterface, i) -> Preferences.getPreferences().edit().putBoolean("showAlertGms", false).apply() ) .setNeutralButton(activity.getString(R.string.gmsissuebtn2), (dialogInterface, i) -> { - edit().putBoolean("showAlertGms", false).apply(); + Preferences.getPreferences().edit().putBoolean("showAlertGms", false).apply(); NavigatorUtils.switchFragment(activity, InstallGMSFragment.class); }) .show(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/RoundingSeekbarDialog.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/RoundingSeekbarDialog.java index 35858712a..45fe13a0a 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/RoundingSeekbarDialog.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/RoundingSeekbarDialog.java @@ -1,18 +1,15 @@ package ru.vtosters.lite.ui.dialogs; -import static ru.vtosters.lite.utils.AndroidUtils.dp2px; -import static ru.vtosters.lite.utils.AndroidUtils.edit; -import static ru.vtosters.lite.utils.AndroidUtils.getPreferences; -import static ru.vtosters.lite.utils.LifecycleUtils.restartApplicationWithTimer; - import android.content.Context; import android.widget.LinearLayout; import android.widget.SeekBar; - import com.vk.core.dialogs.alert.VkAlertDialog; import com.vtosters.lite.R; - import ru.vtosters.lite.utils.LayoutUtils; +import ru.vtosters.lite.utils.Preferences; + +import static ru.vtosters.lite.utils.AndroidUtils.*; +import static ru.vtosters.lite.utils.LifecycleUtils.restartApplicationWithTimer; public class RoundingSeekbarDialog { public static void dialog(Context context) { @@ -20,7 +17,7 @@ public class RoundingSeekbarDialog { SeekBar seek = new SeekBar(context); seek.setMax(10); seek.setKeyProgressIncrement(0); - seek.setProgress(getPreferences().getInt("pic_rounding", 0)); + seek.setProgress(Preferences.getPreferences().getInt("pic_rounding", 0)); seek.setPadding(dp2px(16f), dp2px(16f), dp2px(16f), dp2px(16f)); mContainer.addView(seek, LayoutUtils.createLinear(-1, -2)); @@ -32,7 +29,7 @@ public class RoundingSeekbarDialog { .setNegativeButton(context.getString(R.string.cancel), null) .setView(mContainer) .setPositiveButton(context.getString(R.string.vtl_confirm), (dialog, which) -> { - edit().putInt("pic_rounding", seek.getProgress()).commit(); + Preferences.getPreferences().edit().putInt("pic_rounding", seek.getProgress()).commit(); restartApplicationWithTimer(); }) .show(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/ServerDialog.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/ServerDialog.java index 2fcff6121..4839a24a5 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/ServerDialog.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/ServerDialog.java @@ -1,7 +1,6 @@ package ru.vtosters.lite.ui.dialogs; import static android.content.ContentValues.TAG; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import static ru.vtosters.lite.utils.NetworkUtils.isNetworkIsSlow; import static ru.vtosters.lite.utils.Preferences.getBoolValue; import static ru.vtosters.lite.utils.Preferences.hasVerification; @@ -24,6 +23,7 @@ import okhttp3.Request; import okhttp3.Response; import ru.vtosters.lite.di.singleton.VtOkHttpClient; import ru.vtosters.lite.utils.LifecycleUtils; +import ru.vtosters.lite.utils.Preferences; public class ServerDialog { private static final OkHttpClient client = VtOkHttpClient.getInstance(); @@ -101,9 +101,9 @@ public class ServerDialog { .setMessage(message) .setCancelable(cancelable) .setPositiveButton(positiveButton, - (dialogInterface, i) -> edit().putBoolean(key, false).apply()) + (dialogInterface, i) -> Preferences.getPreferences().edit().putBoolean(key, false).apply()) .setNeutralButton(neutralButton, (dialogInterface, i) -> { - edit().putBoolean(key, false).apply(); + Preferences.getPreferences().edit().putBoolean(key, false).apply(); var intent = new Intent(Intent.ACTION_VIEW) .setData(Uri.parse(link)); activity.startActivity(intent); diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/Start.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/Start.java index 940d2c2af..b60848dc0 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/Start.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/Start.java @@ -8,8 +8,8 @@ import com.vk.core.dialogs.alert.VkAlertDialog; import com.vtosters.lite.R; import ru.vtosters.lite.deviceinfo.OEMDetector; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import static ru.vtosters.lite.utils.Preferences.getBoolValue; public class Start { @@ -23,11 +23,11 @@ public class Start { .setMessage(getWelcome()) .setCancelable(false) .setPositiveButton(R.string.startbtn2, - (dialogInterface, i) -> edit().putBoolean("showAlert", false).apply() + (dialogInterface, i) -> Preferences.getPreferences().edit().putBoolean("showAlert", false).apply() ) .setNeutralButton(R.string.startbtn1, (dialogInterface, i) -> { - edit().putBoolean("showAlert", false).apply(); + Preferences.getPreferences().edit().putBoolean("showAlert", false).apply(); activity.startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://t.me/vtosters"))); } ) diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/ThemeChanging.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/ThemeChanging.java index 36f33fc3d..882fed54b 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/ThemeChanging.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/ThemeChanging.java @@ -1,17 +1,14 @@ package ru.vtosters.lite.ui.dialogs; -import static ru.vtosters.lite.utils.AndroidUtils.edit; -import static ru.vtosters.lite.utils.ThemesUtils.isDarkTheme; - import android.app.Activity; - import com.vk.core.dialogs.alert.VkAlertDialog; import com.vk.core.ui.themes.VKThemeHelper; import com.vtosters.lite.R; - import ru.vtosters.lite.hooks.VKUIHook; import ru.vtosters.lite.utils.Preferences; +import static ru.vtosters.lite.utils.ThemesUtils.isDarkTheme; + public class ThemeChanging { public static void changeTheme(Activity activity, float[] f) { if (Preferences.systemtheme()) { @@ -20,7 +17,7 @@ public class ThemeChanging { .setMessage(R.string.system_theme_warning) .setCancelable(false) .setPositiveButton(R.string.proxy_disable, (dialogInterface, i) -> { // Отключить - edit().putString("currsystemtheme", !isDarkTheme() ? "dark" : "light").commit(); + Preferences.getPreferences().edit().putString("currsystemtheme", !isDarkTheme() ? "dark" : "light").commit(); VKThemeHelper.b(activity, f); VKUIHook.clearWebCache(); }) @@ -28,7 +25,7 @@ public class ThemeChanging { .show(); } else { VKThemeHelper.b(activity, f); - edit().putString("currsystemtheme", isDarkTheme() ? "dark" : "light").commit(); + Preferences.getPreferences().edit().putString("currsystemtheme", isDarkTheme() ? "dark" : "light").commit(); VKUIHook.clearWebCache(); } } diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/Translate.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/Translate.java index c26ed3474..09a8f543b 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/Translate.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/Translate.java @@ -32,7 +32,7 @@ public class Translate { var translation = translator.getTranslation(text); MAIN_EXECUTOR.execute(() -> showDialog(context, translation)); } catch (Exception e) { - Log.e("Translate", e + ""); + Log.e("Translate", String.valueOf(e)); } }); } diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/VKIDProtection.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/VKIDProtection.java index 208f9b7b4..2a85465e4 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/VKIDProtection.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/VKIDProtection.java @@ -1,20 +1,16 @@ package ru.vtosters.lite.ui.dialogs; +import android.app.Activity; +import com.vk.core.dialogs.alert.VkAlertDialog; +import com.vtosters.lite.R; +import ru.vtosters.lite.ui.fragments.VKUIwrapper; +import ru.vtosters.lite.utils.NavigatorUtils; +import ru.vtosters.lite.utils.Preferences; + import static ru.vtosters.lite.proxy.ProxyUtils.getApi; import static ru.vtosters.lite.proxy.ProxyUtils.isAnyProxyEnabled; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import static ru.vtosters.lite.utils.Preferences.getBoolValue; -import android.app.Activity; -import android.content.Intent; - -import com.vk.core.dialogs.alert.VkAlertDialog; -import com.vk.navigation.Navigator; -import com.vtosters.lite.R; - -import ru.vtosters.lite.ui.fragments.VKUIwrapper; -import ru.vtosters.lite.utils.NavigatorUtils; - public class VKIDProtection { public static void alert(final Activity activity) { if (!getBoolValue("showAlertVkId", true)) return; @@ -23,9 +19,9 @@ public class VKIDProtection { .setMessage(R.string.vkidsumm) .setCancelable(false) .setPositiveButton(R.string.startbtn2, - (dialogInterface, i) -> edit().putBoolean("showAlertVkId", false).apply()) + (dialogInterface, i) -> Preferences.getPreferences().edit().putBoolean("showAlertVkId", false).apply()) .setNeutralButton(R.string.vkiddisable, (dialogInterface, i) -> { - edit().putBoolean("showAlertVkId", false).apply(); + Preferences.getPreferences().edit().putBoolean("showAlertVkId", false).apply(); VKUIwrapper.setLink( isAnyProxyEnabled() ? "https://id.vk.com/account" diff --git a/app/src/main/java/ru/vtosters/lite/ui/dialogs/VTColorPickerBottomSheetDialog.java b/app/src/main/java/ru/vtosters/lite/ui/dialogs/VTColorPickerBottomSheetDialog.java index 8444ca3d1..924042f12 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/dialogs/VTColorPickerBottomSheetDialog.java +++ b/app/src/main/java/ru/vtosters/lite/ui/dialogs/VTColorPickerBottomSheetDialog.java @@ -12,8 +12,8 @@ import ru.vtosters.lite.utils.LayoutUtils; public class VTColorPickerBottomSheetDialog extends ModalBottomSheetWrapper { - private Activity mActivity; - private LinearLayout mContainer; + private final Activity mActivity; + private final LinearLayout mContainer; public VTColorPickerBottomSheetDialog(Activity activity) { super(activity); diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/BaseToolbarFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/BaseToolbarFragment.java index 1a1e5f905..42beb9f76 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/BaseToolbarFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/BaseToolbarFragment.java @@ -43,6 +43,9 @@ public abstract class BaseToolbarFragment extends FragmentImpl { public void setNavigationIconEnabled(boolean enabled) { if (enabled) { ViewUtils.a(mToolbar, R.drawable.ic_back_outline_28); + mToolbar.setNavigationOnClickListener(v -> { + ToolbarHelper.b(this); + }); } else { ToolbarHelper.a(this, mToolbar); } diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/FeedFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/FeedFragment.java index 97d7dd6d4..ade068b0f 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/FeedFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/FeedFragment.java @@ -43,9 +43,9 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment { return true; }); - findPreference("spamfilters").setSummary(count(getPrefsValue("spamfilters"))); - findPreference("sourcenamefilter").setSummary(count(getPrefsValue("sourcenamefilter"))); - findPreference("linkfilter").setSummary(count(getPrefsValue("linkfilter"))); + findPreference("spamfilters").setSummary(count(Preferences.getString("spamfilters"))); + findPreference("sourcenamefilter").setSummary(count(Preferences.getString("sourcenamefilter"))); + findPreference("linkfilter").setSummary(count(Preferences.getString("linkfilter"))); findPreference("spamfilters").setOnPreferenceClickListener(preference -> { NewsFeedFiltersUtils.setupFilters(); @@ -86,7 +86,7 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment { return true; }); - var str = getDefaultPrefs().getString("news_feed_selected_items", ""); + var str = Preferences.getPreferences().getString("news_feed_selected_items", ""); findPreference("newsfeedlistmanager").setSummary( String.format(requireContext().getString(R.string.feed_hidden), (!TextUtils.isEmpty(str) ? str.split(",").length : 0)) ); @@ -96,7 +96,7 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment { return true; }); - findPreference("feedcache").setVisible(!getPrefsValue("newsupdate").equals("no_update")); + findPreference("feedcache").setVisible(!Preferences.getString("newsupdate").equals("no_update")); } private String count(String text) { @@ -116,7 +116,7 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment { .setMessage(requireContext().getString(R.string.delete_elements_confirm)) .setCancelable(false) .setPositiveButton(requireContext().getString(R.string.yes), (dialogInterface, i) -> { - edit().remove(key).apply(); + Preferences.getPreferences().edit().remove(key).apply(); sendToast(requireContext().getString(R.string.elements_deleted_success)); NewsFeedFiltersUtils.setupFilters(); }) @@ -126,7 +126,7 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment { } private String countSet(String key) { - var set = getDefaultPrefs().getStringSet(key, null); + var set = Preferences.getPreferences().getStringSet(key, null); StringBuilder str = new StringBuilder(); if (set != null) { for (var s : set) { diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/IconsFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/IconsFragment.java index c08b78921..d655ef43c 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/IconsFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/IconsFragment.java @@ -23,8 +23,8 @@ import ru.vtosters.lite.utils.ThemesUtils; public class IconsFragment extends MaterialPreferenceToolbarFragment { @SuppressLint("SetTextI18n") public static void callSelectDialog(Context ctx, String appicon) { - var defname = Preferences.preferences.getString("appname", "vt"); - var deficon = Preferences.preferences.getString("selectedicon", "vt"); + var defname = Preferences.getPreferences().getString("appname", "vt"); + var deficon = Preferences.getPreferences().getString("selectedicon", "vt"); RadioGroup rg = new RadioGroup(ctx); @@ -60,18 +60,18 @@ public class IconsFragment extends MaterialPreferenceToolbarFragment { .setView(rg) .setPositiveButton(R.string.vtl_confirm, ((dialog, which) -> { if (rgDefault.isChecked()) { - AndroidUtils.edit().putString("appname", "vt").commit(); - AndroidUtils.edit().putString("selectedicon", appicon).commit(); + Preferences.getPreferences().edit().putString("appname", "vt").commit(); + Preferences.getPreferences().edit().putString("selectedicon", appicon).commit(); IconManager.switchComponent(appicon, "vt"); } else if (rgVK.isChecked()) { - AndroidUtils.edit().putString("appname", "standard").commit(); - AndroidUtils.edit().putString("selectedicon", appicon).commit(); + Preferences.getPreferences().edit().putString("appname", "standard").commit(); + Preferences.getPreferences().edit().putString("selectedicon", appicon).commit(); IconManager.switchComponent(appicon, "standard"); } else if (rgVKontakte.isChecked()) { - AndroidUtils.edit().putString("appname", "vkontakte").commit(); - AndroidUtils.edit().putString("selectedicon", appicon).commit(); + Preferences.getPreferences().edit().putString("appname", "vkontakte").commit(); + Preferences.getPreferences().edit().putString("selectedicon", appicon).commit(); IconManager.switchComponent(appicon, "vkontakte"); } diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/InterfaceFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/InterfaceFragment.java index f32be4dbb..a5623c565 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/InterfaceFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/InterfaceFragment.java @@ -11,7 +11,7 @@ import ru.vtosters.lite.utils.NavigatorUtils; import ru.vtosters.lite.utils.Preferences; import ru.vtosters.lite.utils.ThemesUtils; -import static ru.vtosters.lite.utils.AndroidUtils.*; +import static ru.vtosters.lite.utils.AndroidUtils.isTablet; import static ru.vtosters.lite.utils.LifecycleUtils.restartApplicationWithTimer; public class InterfaceFragment extends MaterialPreferenceToolbarFragment { @@ -45,7 +45,7 @@ public class InterfaceFragment extends MaterialPreferenceToolbarFragment { }); findPreference("dateformat").setOnPreferenceChangeListener((preference, o) -> { - edit().putString("dateformat", o.toString()).commit(); + Preferences.getPreferences().edit().putString("dateformat", o.toString()).commit(); restartApplicationWithTimer(); return true; }); @@ -78,10 +78,10 @@ public class InterfaceFragment extends MaterialPreferenceToolbarFragment { findPreference("anim_rtrn_type").setVisible(false); } - if (getPreferences().getInt("pic_rounding", 0) == 0) { + if (Preferences.getPreferences().getInt("pic_rounding", 0) == 0) { findPreference("customrounding").setSummary(requireContext().getString(R.string.disabled)); } else { - findPreference("customrounding").setSummary(String.format(requireContext().getString(R.string.rounding_size), getPreferences().getInt("pic_rounding", 0))); + findPreference("customrounding").setSummary(String.format(requireContext().getString(R.string.rounding_size), Preferences.getPreferences().getInt("pic_rounding", 0))); } } diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/MediaFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/MediaFragment.java index 0665eb56c..1c2842786 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/MediaFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/MediaFragment.java @@ -25,6 +25,7 @@ import ru.vtosters.lite.music.LastFMScrobbler; import ru.vtosters.lite.music.cache.CacheDatabaseDelegate; import ru.vtosters.lite.ui.adapters.ImagineArrayAdapter; import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; import ru.vtosters.lite.utils.ThemesUtils; import java.io.IOException; @@ -152,11 +153,11 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment { ); var adapter = new ImagineArrayAdapter(requireContext(), items); - adapter.setSelected(getPreferences().getInt("search_engine", 0)); + adapter.setSelected(Preferences.getPreferences().getInt("search_engine", 0)); new VkAlertDialog.Builder(getActivity()) .setAdapter(adapter, (dialog, which) -> { - getPreferences().edit().putInt("search_engine", which).apply(); + Preferences.getPreferences().edit().putInt("search_engine", which).apply(); dialog.cancel(); }) .show(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/MessagesFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/MessagesFragment.java index 28e27dd35..8b690aec2 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/MessagesFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/MessagesFragment.java @@ -7,10 +7,10 @@ import com.vk.core.dialogs.alert.VkAlertDialog; import com.vtosters.lite.R; import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment; import ru.vtosters.lite.ui.adapters.ImagineArrayAdapter; +import ru.vtosters.lite.utils.Preferences; import java.util.Arrays; -import static ru.vtosters.lite.utils.AndroidUtils.getPreferences; import static ru.vtosters.lite.utils.AndroidUtils.isTablet; import static ru.vtosters.lite.utils.LifecycleUtils.restartApplicationWithTimer; import static ru.vtosters.lite.utils.Preferences.autoalltranslate; @@ -47,11 +47,11 @@ public class MessagesFragment extends MaterialPreferenceToolbarFragment { ); var adapter = new ImagineArrayAdapter(requireContext(), items); - adapter.setSelected(getPreferences().getInt("translator", 0)); + adapter.setSelected(Preferences.getPreferences().getInt("translator", 0)); new VkAlertDialog.Builder(getActivity()) .setAdapter(adapter, (dialog, which) -> { - getPreferences().edit().putInt("translator", which).apply(); + Preferences.getPreferences().edit().putInt("translator", which).apply(); dialog.cancel(); }) .show(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/OtherFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/OtherFragment.java index f792c5276..f6dd269ef 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/OtherFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/OtherFragment.java @@ -81,7 +81,7 @@ public class OtherFragment extends MaterialPreferenceToolbarFragment { if (requestCode == VK_ADMIN_TOKEN_REQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { String token = data.getStringExtra("token"); - AndroidUtils.getPreferences().edit().putString("vk_admin_token", token).apply(); + Preferences.getPreferences().edit().putString("vk_admin_token", token).apply(); Toast.makeText(getContext(), requireContext().getString(R.string.token_saved), LENGTH_SHORT).show(); } } @@ -161,7 +161,7 @@ public class OtherFragment extends MaterialPreferenceToolbarFragment { return true; }); - var pref = getDefaultPrefs().getString("autoclearcache", "Default"); + var pref = Preferences.getPreferences().getString("autoclearcache", "Default"); switch (pref) { case "Default" -> findPreference("autoclearcache").setSummary(requireContext().getString(R.string.cache_disabled)); @@ -222,7 +222,7 @@ public class OtherFragment extends MaterialPreferenceToolbarFragment { }); var vkAdminTokenPref = findPreference("vk_admin_token"); - vkAdminTokenPref.setVisible(AndroidUtils.getDefaultPrefs().getBoolean("new_music_downloading_way", false)); + vkAdminTokenPref.setVisible(Preferences.getPreferences().getBoolean("new_music_downloading_way", false)); if (vkAdminTokenPref.isVisible()) { vkAdminTokenPref.setOnPreferenceClickListener(preference -> { startActivityForResult(new Intent(getContext(), VKAdminTokenActivity.class), VK_ADMIN_TOKEN_REQUEST_CODE); @@ -236,7 +236,7 @@ public class OtherFragment extends MaterialPreferenceToolbarFragment { private void cacheAutoCleanDialog() { String[] cacheText = {null, "100 MB", "500 MB", "1 GB", "2 GB", "5 GB"}; - var val = getDefaultPrefs().getInt("autoclearcache_size", 0); + var val = Preferences.getPreferences().getInt("autoclearcache_size", 0); RadioGroup rg = new RadioGroup(getContext()); rg.setPadding(dp2px(18f), dp2px(12f), dp2px(18f), 0); @@ -263,7 +263,7 @@ public class OtherFragment extends MaterialPreferenceToolbarFragment { .setPositiveButton(requireContext().getString(R.string.save), (dialog, which) -> { var sizes = new String[]{"Default", "100mb", "500mb", "1gb", "2gb", "5gb"}; var id = rg.getCheckedRadioButtonId(); - getDefaultPrefs().edit() + Preferences.getPreferences().edit() .putInt("autoclearcache_size", id) .putString("autoclearcache", sizes[id]) .apply(); diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/ThemesFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/ThemesFragment.java index 0ad088de2..4099fd57f 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/ThemesFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/ThemesFragment.java @@ -1,6 +1,7 @@ package ru.vtosters.lite.ui.fragments; import android.content.DialogInterface; +import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.util.Log; @@ -19,22 +20,15 @@ import ru.vtosters.lite.ui.views.rarepebble.ColorPickerView; import ru.vtosters.lite.ui.wallpapers.WallpaperMenuFragment; import ru.vtosters.lite.utils.*; -import java.io.IOException; - import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; import static ru.vtosters.lite.utils.ThemesUtils.recolorDrawable; public class ThemesFragment extends MaterialPreferenceToolbarFragment { - private VKProgressDialog mProgressDialog; - @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); - mProgressDialog = new VKProgressDialog(requireContext()); - mProgressDialog.setCancelable(false); - addPreferencesFromResource(R.xml.preferences_themes); initPreferences(); } @@ -57,20 +51,12 @@ public class ThemesFragment extends MaterialPreferenceToolbarFragment { }); var invalidateThemeCache = findPreference("invalidate_theme_cache"); - invalidateThemeCache.setOnPreferenceClickListener(preference -> { - mProgressDialog.setMessage("Инвалидация кэша..."); - mProgressDialog.show(); - VTExecutors.getIoExecutor().execute(() -> { - ThemesManager.deleteBins(); - try { - ThemesManager.generateBins(requireContext()); - requireActivity().runOnUiThread(this::restart); - } catch(IOException e) { - requireActivity().runOnUiThread(() -> showErrorDialog("Ошибка при инвалидации кэша")); - } + if(ThemesUtils.getReservedAccent() != Color.TRANSPARENT) + invalidateThemeCache.setOnPreferenceClickListener(preference -> { + setAccentColor(ThemesUtils.getReservedAccent()); + return true; }); - return true; - }); + else invalidateThemeCache.setVisible(false); var navBarPreference = findPreference("navbar"); navBarPreference.setOnPreferenceClickListener(preference -> { @@ -172,8 +158,9 @@ public class ThemesFragment extends MaterialPreferenceToolbarFragment { } }) .setNegativeButton(R.string.reset, (dialog, which) -> { - ThemesManager.deleteTmpArchive(); - LifecycleUtils.restartApplicationWithTimer(); + ThemesManager.deleteModification(); + ThemesUtils.reserveAccentColor(Color.TRANSPARENT, false); + restart(); }) .setPositiveButton(R.string.cancel, null) .show(); @@ -218,47 +205,29 @@ public class ThemesFragment extends MaterialPreferenceToolbarFragment { } void setAccentColor(int color) { - String message; - Runnable task; - if(!ThemesManager.hasBins()) { - message = "Генерация файлов..."; - task = () -> { - try { - ThemesManager.generateBins(requireContext()); - requireActivity().runOnUiThread(() -> setAccentColor(color)); - } catch(IOException e) { - Log.e("ThemesFragment", e+""); - ThemesManager.deleteBins(); - requireActivity().runOnUiThread(() -> showErrorDialog("Ошибка при генерации файлов")); - } - }; - } else { - message = "Применение акцента..."; - task = () -> { - try { - ThemesManager.generateTempResArchive(color); - requireActivity().runOnUiThread(this::restart); - } catch(IOException e) { - Log.e("ThemesFragment", e+""); - ThemesManager.deleteTmpArchive(); - requireActivity().runOnUiThread(() -> showErrorDialog("Ошибка при применении акцента")); - } - }; - } + final VKProgressDialog dialog = new VKProgressDialog(requireContext()); + dialog.setCancelable(false); + dialog.setMessage("Применение акцента..."); + dialog.show(); - mProgressDialog.setMessage(message); - mProgressDialog.show(); - - VTExecutors.getIoExecutor().execute(task); - } - - void showErrorDialog(String msg) { - mProgressDialog.dismiss(); - new VkAlertDialog.Builder(requireContext()) - .setTitle("Ошибка") - .setMessage(msg) - .setPositiveButton("OK", null) - .show(); + VTExecutors.getIoExecutor().execute(() -> { + try { + ThemesUtils.reserveAccentColor(color, true); + ThemesManager.generateModApk(color); + requireActivity().runOnUiThread(this::restart); + } catch(Throwable e) { + Log.e("ThemesFragment", e+""); + ThemesManager.deleteModification(); + requireActivity().runOnUiThread(() -> { + dialog.dismiss(); + new VkAlertDialog.Builder(requireContext()) + .setTitle("Ошибка") + .setMessage("Ошибка при применении акцента:\n" + e) + .setPositiveButton("OK", null) + .show(); + }); + } + }); } void restart() { diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/VTSettings.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/VTSettings.java index b107a043d..9b195d91c 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/VTSettings.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/VTSettings.java @@ -30,6 +30,9 @@ import ru.vtosters.lite.ui.dialogs.OTADialog; import ru.vtosters.lite.ui.fragments.tgstickers.StickersFragment; import ru.vtosters.lite.utils.*; +import static ru.vtosters.lite.utils.Preferences.VERSIONNAME; +import static ru.vtosters.lite.utils.Preferences.isValidSignature; + public class VTSettings extends MaterialPreferenceToolbarFragment implements TelegramStickersService.StickersEventsListener { public static String getValAsString(@StringRes int strRes, Boolean value) { @@ -52,7 +55,7 @@ public class VTSettings extends MaterialPreferenceToolbarFragment implements Tel } public static String getProxysumm() { - var type = AndroidUtils.getPrefsValue("proxy"); + var type = Preferences.getString("proxy"); if(type.equals("noproxy") || type.isEmpty()) type = AndroidUtils.getString(R.string.vtlsettdisabled); @@ -63,7 +66,7 @@ public class VTSettings extends MaterialPreferenceToolbarFragment implements Tel public static String getThemesumm() { String[] themeTypeName = AndroidUtils.getArray("theme_type_name"); - return AndroidUtils.getString("current_theme") + ": " + switch (AndroidUtils.getPrefsValue("currsystemtheme")) { + return AndroidUtils.getString("current_theme") + ": " + switch (Preferences.getString("currsystemtheme")) { case "system" -> themeTypeName[0]; case "dark" -> themeTypeName[1]; case "light" -> themeTypeName[2]; @@ -115,47 +118,49 @@ public class VTSettings extends MaterialPreferenceToolbarFragment implements Tel AndroidUtils.checkLinksVerified(this.requireActivity()); - var accountSwitcher = PreferenceFragmentUtils.addPreference( - getPreferenceScreen(), - "account_switcher", - AccountManagerUtils.getUsername(), - requireContext().getString(R.string.vtllogout), - requireContext().getDrawable(R.drawable.ic_user_circle_outline_28), - preference -> { - try { - VKAuth.a("logout", false); - } catch(Exception ignored) { - } + if (AccountManagerUtils.isLogin()) { + var accountSwitcher = PreferenceFragmentUtils.addPreference( + getPreferenceScreen(), + "account_switcher", + AccountManagerUtils.getUsername(), + requireContext().getString(R.string.vtllogout), + requireContext().getDrawable(R.drawable.ic_user_circle_outline_28), + preference -> { + try { + VKAuth.a("logout", false); + } catch(Exception ignored) { + } - var intent = new Intent(requireContext(), MainActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - requireContext().startActivity(intent); + var intent = new Intent(requireContext(), MainActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + requireContext().startActivity(intent); - return false; + return false; + }); + + VTExecutors.getIoScheduler().a(() -> { + var icon = ImageUtils.getDrawableFromUrl(AccountManagerUtils.getUserPhoto(), 0, true, true); + if(icon == null) return; + requireActivity().runOnUiThread(() -> { + accountSwitcher.setIcon(icon); }); - - VTExecutors.getIoScheduler().a(() -> { - var icon = ImageUtils.getDrawableFromUrl(AccountManagerUtils.getUserPhoto(), 0, true, true); - if(icon == null) return; - requireActivity().runOnUiThread(() -> { - accountSwitcher.setIcon(icon); }); - }); - PreferenceFragmentUtils.addPreference( - getPreferenceScreen(), - "", - requireContext().getString(R.string.vtssfs), - getSSFSsumm(), - R.drawable.ic_link_circle_outline_28, - preference -> { - VKUIwrapper.setLink(Utils.getVKUILink()); - NavigatorUtils.switchFragment(requireContext(), VKUIwrapper.class); - return false; - } - ); + PreferenceFragmentUtils.addPreference( + getPreferenceScreen(), + "", + requireContext().getString(R.string.vtssfs), + getSSFSsumm(), + R.drawable.ic_link_circle_outline_28, + preference -> { + VKUIwrapper.setLink(Utils.getVKUILink()); + NavigatorUtils.switchFragment(requireContext(), VKUIwrapper.class); + return false; + } + ); + } PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), R.string.appearance_theme_use_system); @@ -175,7 +180,7 @@ public class VTSettings extends MaterialPreferenceToolbarFragment implements Tel var theme = value.equals("dark") ? ThemesUtils.getDarkTheme() : ThemesUtils.getLightTheme(); ThemesUtils.applyTheme(theme); } - AndroidUtils.edit().putString("currsystemtheme", value).commit(); + Preferences.getPreferences().edit().putString("currsystemtheme", value).commit(); SystemThemeChangerHook.onThemeChanged(getResources().getConfiguration()); return true; }); @@ -235,7 +240,7 @@ public class VTSettings extends MaterialPreferenceToolbarFragment implements Tel R.drawable.ic_globe_outline_28, true, (preference, o) -> { - AndroidUtils.edit().putBoolean("ssl", (boolean) o).commit(); + Preferences.getPreferences().edit().putBoolean("ssl", (boolean) o).commit(); return true; } ); @@ -250,65 +255,67 @@ public class VTSettings extends MaterialPreferenceToolbarFragment implements Tel true, (preference, o) -> { boolean value = (boolean) o; - AndroidUtils.edit().putBoolean("autoupdates", value).commit(); + Preferences.getPreferences().edit().putBoolean("autoupdates", value).commit(); return true; } ); } } - PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), R.string.vtsettaccount); + if (AccountManagerUtils.isLogin()) { + PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), R.string.vtsettaccount); - PreferenceFragmentUtils.addPreference( - getPreferenceScreen(), - "", - requireContext().getString(R.string.vkconnect), - "", - R.drawable.ic_user_circle_outline_28, - preference -> { - VKUIwrapper.officalLinks("account"); - NavigatorUtils.switchFragment(requireContext(), VKUIwrapper.class); - return false; - } - ); - - PreferenceFragmentUtils.addPreference( - getPreferenceScreen(), - "", - requireContext().getString(R.string.privacy_settings), - "", - R.drawable.ic_privacy_outline_28, - preference -> { - NavigatorUtils.switchFragment(requireContext(), PrivacyFragment.class); - return false; - } - ); - - PreferenceFragmentUtils.addPreference( - getPreferenceScreen(), - "", - requireContext().getString(R.string.sett_account), - "", - R.drawable.ic_user_outline_28, - preference -> { - NavigatorUtils.switchFragment(requireContext(), SettingsAccountFragment.class); - return false; - } - ); - - if(AccountManagerUtils.isVKTester()) { PreferenceFragmentUtils.addPreference( getPreferenceScreen(), "", - requireContext().getString(R.string.bugs), + requireContext().getString(R.string.vkconnect), "", - R.drawable.ic_bug_outline_28, + R.drawable.ic_user_circle_outline_28, preference -> { - VKUIwrapper.officalLinks("bugs"); + VKUIwrapper.officalLinks("account"); NavigatorUtils.switchFragment(requireContext(), VKUIwrapper.class); return false; } ); + + PreferenceFragmentUtils.addPreference( + getPreferenceScreen(), + "", + requireContext().getString(R.string.privacy_settings), + "", + R.drawable.ic_privacy_outline_28, + preference -> { + NavigatorUtils.switchFragment(requireContext(), PrivacyFragment.class); + return false; + } + ); + + PreferenceFragmentUtils.addPreference( + getPreferenceScreen(), + "", + requireContext().getString(R.string.sett_account), + "", + R.drawable.ic_user_outline_28, + preference -> { + NavigatorUtils.switchFragment(requireContext(), SettingsAccountFragment.class); + return false; + } + ); + + if(AccountManagerUtils.isVKTester()) { + PreferenceFragmentUtils.addPreference( + getPreferenceScreen(), + "", + requireContext().getString(R.string.bugs), + "", + R.drawable.ic_bug_outline_28, + preference -> { + VKUIwrapper.officalLinks("bugs"); + NavigatorUtils.switchFragment(requireContext(), VKUIwrapper.class); + return false; + } + ); + } } PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), requireContext().getString(R.string.vtlvksettings)); @@ -504,7 +511,7 @@ public class VTSettings extends MaterialPreferenceToolbarFragment implements Tel getPreferenceScreen(), "", requireContext().getString(R.string.menu_about), - "Commit: " + About.getBuildNumber(), + (isValidSignature() ? VERSIONNAME : "Dev") + " | " + About.getBuildNumber(), R.drawable.ic_about_outline_28, preference -> { NavigatorUtils.switchFragment(requireContext(), AboutAppFragment.class); diff --git a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ConvolutionMatrix.java b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ConvolutionMatrix.java index 1e195f190..9fd3d434d 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ConvolutionMatrix.java +++ b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ConvolutionMatrix.java @@ -3,6 +3,8 @@ package ru.vtosters.lite.ui.wallpapers; import android.graphics.Bitmap; import android.graphics.Color; +import java.util.Arrays; + public class ConvolutionMatrix { public static final int SIZE = 3; @@ -83,17 +85,13 @@ public class ConvolutionMatrix { public void setAll(double value) { for (int x = 0; x < SIZE; ++x) { - for (int y = 0; y < SIZE; ++y) { - Matrix[x][y] = value; - } + Arrays.fill(Matrix[x], value); } } public void applyConfig(double[][] config) { for (int x = 0; x < SIZE; ++x) { - for (int y = 0; y < SIZE; ++y) { - Matrix[x][y] = config[x][y]; - } + System.arraycopy(config[x], 0, Matrix[x], 0, SIZE); } } } \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ImageEffect.java b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ImageEffect.java new file mode 100644 index 000000000..0ff8f2576 --- /dev/null +++ b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ImageEffect.java @@ -0,0 +1,245 @@ +package ru.vtosters.lite.ui.wallpapers; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.vtosters.lite.R; +import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; + +import java.nio.ByteBuffer; + +import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; + +enum ImageEffects { + Blur(true, + AndroidUtils.getArray(R.array.filter_types), + new String[]{"disabled", "low", "med", "high"}, + getGlobalContext().getString(R.string.filter_blur) + ) { + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + int radius; + switch (Preferences.getPreferences().getString(ImageEffects.Blur.toString(), "disabled")) { + case "low": + radius = 8; + break; + case "med": + radius = 14; + break; + case "high": + radius = 20; + break; + default: + return; + } + NativeEffects.gaussian(bitmap, height, width, radius); + } + + @Override + public String getSummary() { + switch (Preferences.getPreferences().getString(ImageEffects.Blur.toString(), "disabled")) { + case "low": + return AndroidUtils.getString(R.string.wallpapers_low); + case "med": + return AndroidUtils.getString(R.string.wallpapers_med); + case "high": + return AndroidUtils.getString(R.string.wallpapers_high); + default: + return AndroidUtils.getString(R.string.wallpapers_disabled); + } + } + }, + Dim(true, + AndroidUtils.getArray(R.array.filter_dim_types), + new String[]{"disabled", "dim_black", "dim_white"}, + getGlobalContext().getString(R.string.filter_dim)) { + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + var delta = 0; + switch (Preferences.getPreferences().getString(ImageEffects.Dim.toString(), "disabled")) { + case "dim_black": + delta = -50; break; + case "dim_white": + delta = 50; break; + default: + return; + } + NativeEffects.dim(bitmap, height, width, delta); + } + + @Override + public String getSummary() { + switch (Preferences.getPreferences().getString(ImageEffects.Dim.toString(), "disabled")) { + case "dim_black": + return AndroidUtils.getString(R.string.wallpapers_dim_black); + case "dim_white": + return AndroidUtils.getString(R.string.wallpapers_dim_white); + default: + return AndroidUtils.getString(R.string.wallpapers_disabled); + } + } + }, + Mosaic(true, + AndroidUtils.getArray(R.array.filter_types), + new String[]{"disabled", "low", "med", "high"}, + getGlobalContext().getString(R.string.filter_mosaic)) { + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + var scale = 0; + switch (Preferences.getPreferences().getString(ImageEffects.Mosaic.toString(), "disabled")) { + case "high": + scale = 50; break; + case "med": + scale = 25; break; + case "low": + scale = 10; break; + default: + return; + } + NativeEffects.mosaic(bitmap, height, width, scale); + } + + @Override + public String getSummary() { + switch (Preferences.getPreferences().getString(ImageEffects.Mosaic.toString(), "disabled")) { + case "low": + return AndroidUtils.getString(R.string.wallpapers_low); + case "med": + return AndroidUtils.getString(R.string.wallpapers_med); + case "high": + return AndroidUtils.getString(R.string.wallpapers_high); + default: + return AndroidUtils.getString(R.string.wallpapers_disabled); + } + } + }, + Monochrome(false, null, null, + getGlobalContext().getString(R.string.filter_monochrome)) { + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + if (isApplied()) { + NativeEffects.monochrome(bitmap); + } + } + }, + Invert(false, null, null, + getGlobalContext().getString(R.string.filter_invert_colors)) { + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + if (isApplied()) { + NativeEffects.invert(bitmap); + } + } + }, + Sepia(false, null, null, + getGlobalContext().getString(R.string.filter_sepia)) { + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + if (isApplied()) { + NativeEffects.sepia(bitmap); + } + } + }, + Emboss(false, null, null, + getGlobalContext().getString(R.string.filter_emboss)) { + @Override + public String getSummary() { + return getGlobalContext().getString(R.string.filter_maybe_lag); + } + + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + if (isApplied()) { + NativeEffects.emboss(bitmap, height, width); + } + } + }, + Engrave(false, null, null, + getGlobalContext().getString(R.string.filter_engrave)) { + @Override + public String getSummary() { + return getGlobalContext().getString(R.string.filter_maybe_lag); + } + + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + if (isApplied()) { + NativeEffects.engrave(bitmap, height, width); + } + } + }, + Flea(false, null, null, + getGlobalContext().getString(R.string.filter_flea)) { + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + if (isApplied()) { + NativeEffects.flea(bitmap); + } + } + }, + Snow(false, null, null, + getGlobalContext().getString(R.string.filter_snow)) { + @Override + public void applyEffect(ByteBuffer bitmap, int height, int width) { + if (isApplied()){ + NativeEffects.snow(bitmap); + } + } + }; + + private final boolean free; + private final String title; + @Nullable + private final String[] entryValues; + @Nullable + private final String[] entries; + + ImageEffects(boolean free, @Nullable String[] entries, @Nullable String[] entryValues, String title) { + this.free = free; + this.entries = entries; + this.entryValues = entryValues; + this.title = title; + } + + public String getTitle() { + return title; + } + + public Boolean isSwitch() { + return entryValues == null || entryValues.length == 0; + } + + public Boolean isList() { + return entryValues != null && entryValues.length > 0; + } + + public boolean isFree() { + return free; + } + + @Nullable + public String[] getEntries() { + return entries; + } + + @Nullable + public String[] getEntryValues() { + return entryValues; + } + + public String getSummary() { + return ""; + } + + public abstract void applyEffect(ByteBuffer bitmap, int height, int width); + + protected boolean isApplied() { + return Preferences.getPreferences().getBoolean(this.toString(), false); + } + + @NonNull + @Override + public String toString() { + return "msg_" + super.toString(); + } +} diff --git a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ImageFilters.java b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ImageFilters.java index a41079e7c..165560054 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ImageFilters.java +++ b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/ImageFilters.java @@ -1,351 +1,37 @@ package ru.vtosters.lite.ui.wallpapers; -import static ru.vtosters.lite.utils.AndroidUtils.getPreferences; import static ru.vtosters.lite.utils.AndroidUtils.getResources; -import static ru.vtosters.lite.utils.Preferences.hasVerification; import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.LightingColorFilter; -import android.graphics.Matrix; -import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.util.Log; -import com.vk.medianative.MediaNative; - -import java.util.Random; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; public class ImageFilters { - public static final int COLOR_MAX = 0xFF; public static Drawable getFilteredDrawable(Drawable orig) { if (orig == null) return null; if (!(orig instanceof BitmapDrawable)) return orig; - if (!getPreferences().getString("msg_blur_radius", "disabled").equals("disabled")) { - orig = getBlurredWallpaper(orig, getRadius()); + Bitmap bitmap = ((BitmapDrawable) orig).getBitmap(); + if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) { + bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); } - if (!getPreferences().getString("msg_dim", "off").equals("off")) { - orig = getDimmed(orig); + var directBuff = ByteBuffer.allocateDirect(bitmap.getByteCount()); + directBuff.order(ByteOrder.nativeOrder()); + bitmap.copyPixelsToBuffer(directBuff); + + // FIXME: preserve order of filters + // e.g. user turned invert first then mosaic then monochrome + // invocation here happens regardless of that order + for (var type : ImageEffects.values()) { + type.applyEffect(directBuff, bitmap.getHeight(), bitmap.getWidth()); } - - if (!getPreferences().getString("msg_mosaic", "disabled").equals("disabled")) { - orig = getMosaic(orig); - } - - if (!hasVerification()) { - return orig; - } - - if (getPreferences().getBoolean("msg_monochrome", false)) { - orig = getMonochrome(orig); - } - - Bitmap bm; - - if (orig != null) { - bm = ((BitmapDrawable) orig).getBitmap(); - } else { - return null; - } - - Bitmap instance = bm.copy(Bitmap.Config.ARGB_8888, true); - - if (getPreferences().getBoolean("msg_invert", false)) { - instance = applyInvertEffect(instance); - } - - if (getPreferences().getBoolean("msg_sepia", false)) { - instance = applySepiaEffect(instance); - } - - if (getPreferences().getBoolean("msg_emboss", false)) { - instance = applyEmbossEffect(instance); - } - - if (getPreferences().getBoolean("msg_engrave", false)) { - instance = applyEngraveEffect(instance); - } - - if (getPreferences().getBoolean("msg_flea", false)) { - instance = applyFleaEffect(instance); - } - - if (getPreferences().getBoolean("msg_snow", false)) { - instance = applySnowEffect(instance); - } - - return new BitmapDrawable(getResources(), instance); - } - - private static int getRadius() { - String radius = getPreferences().getString("msg_blur_radius", "disabled"); - return switch (radius) { - case "low" -> 8; - case "med" -> 14; - default -> 20; - }; - } - - public static Drawable getBlurredWallpaper(Drawable orig, int radius) { - try { - if (orig == null) return null; - if (!(orig instanceof BitmapDrawable)) return orig; // we need only BitmapDrawable - Bitmap bm = ((BitmapDrawable) orig).getBitmap(); - - Bitmap instance = bm.copy(Bitmap.Config.ARGB_8888, true); - - MediaNative.blurBitmap(instance, radius); - return new BitmapDrawable(getResources(), instance); - } catch (Exception e) { - e.printStackTrace(); - return orig; - } - } - - public static Drawable getMosaic(Drawable orig) { - int scale = 100; - - if (orig == null) return null; - if (!(orig instanceof BitmapDrawable)) return orig; - Bitmap bm = ((BitmapDrawable) orig).getBitmap(); - - - Bitmap instance = bm.copy(Bitmap.Config.ARGB_8888, true); - - - String radius = getPreferences().getString("msg_mosaic", "disabled"); - - switch (radius) { - case "high" -> scale = 25; - case "med" -> scale = 50; - case "low" -> scale = 75; - } - - Bitmap temp = Bitmap.createScaledBitmap(instance, scale, scale, false); - Bitmap mosaicBitmap = Bitmap.createScaledBitmap(temp, instance.getWidth(), instance.getHeight(), false); - - return new BitmapDrawable(getResources(), mosaicBitmap); - } - - public static Drawable getDimmed(Drawable orig) { - if (orig == null) return null; - if (!(orig instanceof BitmapDrawable)) return orig; - Bitmap bm = ((BitmapDrawable) orig).getBitmap(); - - Bitmap instance = bm.copy(Bitmap.Config.ARGB_8888, true); - - String radius = getPreferences().getString("msg_dim", "disabled"); - switch (radius) { - case "dim_black": - darken(instance); - case "dim_white": - lighten(instance); - } - return new BitmapDrawable(getResources(), instance); - } - - public static Drawable getMonochrome(Drawable orig) { - if (orig == null) return null; - if (!(orig instanceof BitmapDrawable)) return orig; - Bitmap bm = ((BitmapDrawable) orig).getBitmap(); - - Bitmap instance = bm.copy(Bitmap.Config.ARGB_8888, true); - - Bitmap bwBitmap = Bitmap.createBitmap(instance.getWidth(), instance.getHeight(), Bitmap.Config.RGB_565); - float[] hsv = new float[3]; - for (int col = 0; col < instance.getWidth(); col++) { - for (int row = 0; row < instance.getHeight(); row++) { - Color.colorToHSV(instance.getPixel(col, row), hsv); - if (hsv[2] > 0.5f) { - bwBitmap.setPixel(col, row, 0xffffffff); - } else { - bwBitmap.setPixel(col, row, 0xff000000); - } - } - } - - return new BitmapDrawable(getResources(), bwBitmap); - } - - private static void darken(Bitmap bm) { - try { - Canvas canvas = new Canvas(bm); - Paint p = new Paint(Color.RED); - ColorFilter filter = new LightingColorFilter(0xFF7F7F7F, 0x00000000); // darken - p.setColorFilter(filter); - canvas.drawBitmap(bm, new Matrix(), p); - } catch (Exception e) { - Log.d("WallpaperD", e.getMessage()); - } - } - - private static void lighten(Bitmap bm) { - try { - Canvas canvas = new Canvas(bm); - Paint p = new Paint(Color.RED); - ColorFilter filter = new LightingColorFilter(0xFFFFFFFF, 0x00222222); // lighten - p.setColorFilter(filter); - canvas.drawBitmap(bm, new Matrix(), p); - } catch (Exception e) { - Log.d("WallpaperL", e.getMessage()); - } - } - - public static Bitmap applyInvertEffect(Bitmap src) { - // create new bitmap with the same settings as source bitmap - Bitmap bmOut = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig()); - // color info - int A, R, G, B; - int pixelColor; - // image size - int height = src.getHeight(); - int width = src.getWidth(); - - // scan through every pixel - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - // get one pixel - pixelColor = src.getPixel(x, y); - // saving alpha channel - A = Color.alpha(pixelColor); - // inverting byte for each R/G/B channel - R = 255 - Color.red(pixelColor); - G = 255 - Color.green(pixelColor); - B = 255 - Color.blue(pixelColor); - // set newly-inverted pixel to output image - bmOut.setPixel(x, y, Color.argb(A, R, G, B)); - } - } - - // return final bitmap - return bmOut; - } - - public static Bitmap applySepiaEffect(Bitmap src) { - // image size - int width = src.getWidth(); - int height = src.getHeight(); - // create output bitmap - Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig()); - // constant grayscale - final double GS_RED = 0.3; - final double GS_GREEN = 0.59; - final double GS_BLUE = 0.11; - // color information - int A, R, G, B; - int pixel; - - // scan through all pixels - for (int x = 0; x < width; ++x) { - for (int y = 0; y < height; ++y) { - // get pixel color - pixel = src.getPixel(x, y); - // get color on each channel - A = Color.alpha(pixel); - R = Color.red(pixel); - G = Color.green(pixel); - B = Color.blue(pixel); - // apply grayscale sample - B = (int) (GS_RED * R + GS_GREEN * G + GS_BLUE * B); - // apply intensity level for sepia tone - R = G = B = (int) (B * 0.9); - // set new pixel color to output bitmap - bmOut.setPixel(x, y, Color.argb(A, R, G, B)); - } - } - - // return final image - return bmOut; - } - - public static Bitmap applyEmbossEffect(Bitmap src) { - double[][] EmbossConfig = new double[][]{ - {-1, 0, -1}, - {0, 4, 0}, - {-1, 0, -1} - }; - ConvolutionMatrix convMatrix = new ConvolutionMatrix(3); - convMatrix.applyConfig(EmbossConfig); - convMatrix.Factor = 1; - convMatrix.Offset = 127; - return ConvolutionMatrix.computeConvolution3x3(src, convMatrix); - } - - public static Bitmap applyEngraveEffect(Bitmap src) { - ConvolutionMatrix convMatrix = new ConvolutionMatrix(3); - convMatrix.setAll(0); - convMatrix.Matrix[0][0] = -2; - convMatrix.Matrix[1][1] = 2; - convMatrix.Factor = 1; - convMatrix.Offset = 95; - return ConvolutionMatrix.computeConvolution3x3(src, convMatrix); - } - - public static Bitmap applyFleaEffect(Bitmap source) { - // get image size - int width = source.getWidth(); - int height = source.getHeight(); - int[] pixels = new int[width * height]; - // get pixel array from source - source.getPixels(pixels, 0, width, 0, 0, width, height); - // a random object - Random random = new Random(); - - int index; - // iteration through pixels - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - // get current index in 2D-matrix - index = y * width + x; - // get random color - int randColor = Color.rgb(random.nextInt(COLOR_MAX), - random.nextInt(COLOR_MAX), random.nextInt(COLOR_MAX)); - // OR - pixels[index] |= randColor; - } - } - // output bitmap - Bitmap bmOut = Bitmap.createBitmap(width, height, source.getConfig()); - bmOut.setPixels(pixels, 0, width, 0, 0, width, height); - return bmOut; - } - - public static Bitmap applySnowEffect(Bitmap source) { - // get image size - int width = source.getWidth(); - int height = source.getHeight(); - int[] pixels = new int[width * height]; - // get pixel array from source - source.getPixels(pixels, 0, width, 0, 0, width, height); - // random object - Random random = new Random(); - - int R, G, B, index, thresHold; - // iteration through pixels - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - // get current index in 2D-matrix - index = y * width + x; - // get color - R = Color.red(pixels[index]); - G = Color.green(pixels[index]); - B = Color.blue(pixels[index]); - // generate threshold - thresHold = random.nextInt(COLOR_MAX); - if (R > thresHold && G > thresHold && B > thresHold) { - pixels[index] = Color.rgb(COLOR_MAX, COLOR_MAX, COLOR_MAX); - } - } - } - // output bitmap - Bitmap bmOut = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); - bmOut.setPixels(pixels, 0, width, 0, 0, width, height); - return bmOut; + directBuff.flip(); + bitmap.copyPixelsFromBuffer(directBuff); + return new BitmapDrawable(getResources(), bitmap); } } diff --git a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/NativeEffects.java b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/NativeEffects.java new file mode 100644 index 000000000..1ae99fdcd --- /dev/null +++ b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/NativeEffects.java @@ -0,0 +1,22 @@ +package ru.vtosters.lite.ui.wallpapers; + +import java.nio.ByteBuffer; + +public class NativeEffects { + + static { + System.loadLibrary("native_effects"); + } + + public static native String monochrome(ByteBuffer input); + public static native String invert(ByteBuffer input); + public static native String sepia(ByteBuffer input); + public static native String emboss(ByteBuffer input, int height, int width); + public static native String engrave(ByteBuffer input, int height, int width); + public static native String flea(ByteBuffer input); + public static native String snow(ByteBuffer input); + // FIXME: slow when comparing with MediaNative.blurBitmap + public static native String gaussian(ByteBuffer input, int height, int width, float radius); + public static native String dim(ByteBuffer input, int height, int width, int delta); + public static native String mosaic(ByteBuffer input, int height, int width, int scale); +} diff --git a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpaperMenuFragment.java b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpaperMenuFragment.java index eac75f554..19119165b 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpaperMenuFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpaperMenuFragment.java @@ -7,20 +7,19 @@ import android.net.Uri; import android.os.Bundle; import android.widget.Toast; import androidx.annotation.Nullable; -import androidx.preference.ListPreference; import com.vtosters.lite.R; import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment; import com.vtosters.lite.im.ImEngineProvider; import ru.vtosters.lite.ui.PreferenceFragmentUtils; -import ru.vtosters.lite.utils.AndroidUtils; +import ru.vtosters.lite.utils.Preferences; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Arrays; import static ru.vtosters.lite.ui.wallpapers.WallpapersHooks.*; -import static ru.vtosters.lite.utils.AndroidUtils.edit; import static ru.vtosters.lite.utils.Preferences.getBoolValue; import static ru.vtosters.lite.utils.Preferences.hasVerification; @@ -29,7 +28,6 @@ public class WallpaperMenuFragment extends MaterialPreferenceToolbarFragment { private WallpaperPreferences mWPPreviewPref; public static void copyStream(InputStream copyFrom, OutputStream copyTo) throws IOException { - byte[] buffer = new byte[1024]; int length; while ((length = copyFrom.read(buffer)) > 0) { @@ -47,146 +45,117 @@ public class WallpaperMenuFragment extends MaterialPreferenceToolbarFragment { addPreferencesFromResource(R.xml.empty); - PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), requireContext().getString(R.string.vkim_settings_appearance_chat_preview_title)); + PreferenceFragmentUtils.addPreferenceCategory( + getPreferenceScreen(), + requireContext().getString(R.string.vkim_settings_appearance_chat_preview_title) + ); mWPPreviewPref = new WallpaperPreferences(getContext()); mWPPreviewPref.setIcon(null); mWPPreviewPref.setIconSpaceReserved(false); getPreferenceScreen().addPreference(mWPPreviewPref); - PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "wp_set", requireContext().getString(R.string.wallpaper_select), requireContext().getString(R.string.wallpaper_from_gallery), R.drawable.ic_picture_outline_28, preference -> { - startActivityForResult(new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI), 1488); - removeStickCache(); - return true; - }); + PreferenceFragmentUtils.addPreference( + getPreferenceScreen(), + "wp_set", + requireContext().getString(R.string.wallpaper_select), + requireContext().getString(R.string.wallpaper_from_gallery), + R.drawable.ic_picture_outline_28, + preference -> { + startActivityForResult( + new Intent( + Intent.ACTION_PICK, + android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI + ), + 1488 + ); + removeStickCache(); + return true; + }); - PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "wp_clear", requireContext().getString(R.string.wallpaper_remove), "", R.drawable.ic_delete_outline_28, preference -> { - removeWallpaper(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - removeStickCache(); - return true; - }); + PreferenceFragmentUtils.addPreference( + getPreferenceScreen(), + "wp_clear", + requireContext().getString(R.string.wallpaper_remove), + "", + R.drawable.ic_delete_outline_28, + preference -> { + removeWallpaper(); + requestUpdateWallpaper(); + mWPPreviewPref.redraw(); + removeStickCache(); + return true; + }); PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), requireContext().getString(R.string.vtlfilters)); if (!hasVerification() && !getBoolValue("dialogrecomm", false)) { - PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", requireContext().getString(R.string.filters_warning), requireContext().getString(R.string.icons_warning_info), 0, preference -> { - requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://vtosters.app/donate/"))); - return false; - }); + PreferenceFragmentUtils.addPreference( + getPreferenceScreen(), + "", + requireContext().getString(R.string.filters_warning), + requireContext().getString(R.string.icons_warning_info), + 0, + preference -> { + requireContext().startActivity( + new Intent(Intent.ACTION_VIEW) + .setData(Uri.parse("https://vtosters.app/donate/")) + ); + return false; + }); } - PreferenceFragmentUtils.addListPreference(getPreferenceScreen(), "msg_blur_radius", "disabled", requireContext().getString(R.string.filter_blur), AndroidUtils.getArray(R.array.filter_types), new String[]{ - "disabled", "low", "med", "high" - }); + Arrays.stream(ImageEffects.values()) + .filter(imageEffects -> imageEffects.isFree() || hasVerification()) + .forEach(it -> { + if (it.isList()) { + var pref = PreferenceFragmentUtils.addListPreference( + getPreferenceScreen(), + it.toString(), + "disabled", + it.getTitle(), + it.getEntries(), + it.getEntryValues() + ); + pref.setSummary(it.getSummary()); + pref.setOnPreferenceChangeListener((preference, o) -> { + Preferences.getPreferences().edit().putString(it.toString(), (String) o).apply(); + preference.setSummary(it.getSummary()); + requestUpdateWallpaper(); + mWPPreviewPref.redraw(); + return true; + }); + } else if (it.isSwitch()) { + PreferenceFragmentUtils.addMaterialSwitchPreference( + getPreferenceScreen(), + it.toString(), + it.getTitle(), + it.getSummary(), + 0, + false, + (preference, o) -> { + Preferences.getPreferences().edit().putBoolean(it.toString(), (Boolean) o).apply(); + requestUpdateWallpaper(); + mWPPreviewPref.redraw(); + return true; + }); + } + }); - PreferenceFragmentUtils.addListPreference(getPreferenceScreen(), "msg_dim", "off", requireContext().getString(R.string.filter_dim), AndroidUtils.getArray(R.array.filter_dim_types), new String[]{ - "off", "dim_black", "dim_white" - }); - - - PreferenceFragmentUtils.addListPreference(getPreferenceScreen(), "msg_mosaic", "disabled", requireContext().getString(R.string.filter_mosaic), AndroidUtils.getArray(R.array.filter_types), new String[]{ - "disabled", "low", "med", "high" - }); - - if (hasVerification()) { - PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "msg_monochrome", requireContext().getString(R.string.filter_monochrome), "", 0, false, (preference, o) -> { - boolean value = (boolean) o; - edit().putBoolean("msg_monochrome", value).commit(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "msg_invert", requireContext().getString(R.string.filter_invert_colors), "", 0, false, (preference, o) -> { - boolean value = (boolean) o; - edit().putBoolean("msg_invert", value).commit(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "msg_sepia", requireContext().getString(R.string.filter_sepia), "", 0, false, (preference, o) -> { - boolean value = (boolean) o; - edit().putBoolean("msg_sepia", value).commit(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "msg_emboss", requireContext().getString(R.string.filter_emboss), requireContext().getString(R.string.filter_maybe_lag), 0, false, (preference, o) -> { - boolean value = (boolean) o; - edit().putBoolean("msg_emboss", value).commit(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "msg_engrave", requireContext().getString(R.string.filter_engrave), requireContext().getString(R.string.filter_maybe_lag), 0, false, (preference, o) -> { - boolean value = (boolean) o; - edit().putBoolean("msg_engrave", value).commit(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "msg_flea", requireContext().getString(R.string.filter_flea), "", 0, false, (preference, o) -> { - boolean value = (boolean) o; - edit().putBoolean("msg_flea", value).commit(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "msg_snow", requireContext().getString(R.string.filter_flea), "", 0, false, (preference, o) -> { - boolean value = (boolean) o; - edit().putBoolean("msg_snow", value).commit(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - } - - PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "compresswp", requireContext().getString(R.string.compress_wallpaper_title), requireContext().getString(R.string.compress_wallpaper_summ), 0, true, (preference, o) -> { - boolean value = (boolean) o; - edit().putBoolean("compresswp", value).commit(); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - ListPreference blur = (ListPreference) findPreference("msg_blur_radius"); - ListPreference dim = (ListPreference) findPreference("msg_dim"); - ListPreference mosaic = (ListPreference) findPreference("msg_mosaic"); - - blur.setSummary(getRadiusSummary()); - dim.setSummary(getDimmingSummary()); - mosaic.setSummary(getMosaicSummary()); - - blur.setOnPreferenceChangeListener((preference, o) -> { - edit().putString("msg_blur_radius", (String) o).apply(); - preference.setSummary(getRadiusSummary()); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - dim.setOnPreferenceChangeListener((preference, o) -> { - edit().putString("msg_dim", (String) o).apply(); - preference.setSummary(getDimmingSummary()); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); - - mosaic.setOnPreferenceChangeListener((preference, o) -> { - edit().putString("msg_mosaic", (String) o).apply(); - preference.setSummary(getMosaicSummary()); - requestUpdateWallpaper(); - mWPPreviewPref.redraw(); - return true; - }); + PreferenceFragmentUtils.addMaterialSwitchPreference( + getPreferenceScreen(), + "compresswp", + requireContext().getString(R.string.compress_wallpaper_title), + requireContext().getString(R.string.compress_wallpaper_summ), + 0, + true, + (preference, o) -> { + boolean value = (boolean) o; + Preferences.getPreferences().edit().putBoolean("compresswp", value).commit(); + requestUpdateWallpaper(); + mWPPreviewPref.redraw(); + return true; + }); } @Override diff --git a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpaperPreferences.java b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpaperPreferences.java index e2970e6c7..f098503e9 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpaperPreferences.java +++ b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpaperPreferences.java @@ -1,7 +1,6 @@ package ru.vtosters.lite.ui.wallpapers; -import static ru.vtosters.lite.ui.wallpapers.WallpapersHooks.getFilteredFile; -import static ru.vtosters.lite.ui.wallpapers.WallpapersHooks.getWallpaperFile; +import static ru.vtosters.lite.ui.wallpapers.WallpapersHooks.*; import static ru.vtosters.lite.utils.AndroidUtils.dp2px; import android.annotation.SuppressLint; @@ -59,12 +58,8 @@ public class WallpaperPreferences extends Preference { } private void requestBg() { - final Drawable drawable = getFilteredFile(); - - if (drawable != null && getWallpaperFile() != null) - mChatBackground.setImageDrawable(drawable); - else - mChatBackground.setImageDrawable(null); + final Drawable drawable = getWallpaper(); + mChatBackground.setImageDrawable(drawable); } @SuppressLint("NotifyDataSetChanged") diff --git a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpapersHooks.java b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpapersHooks.java index 80bbba440..423f47604 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpapersHooks.java +++ b/app/src/main/java/ru/vtosters/lite/ui/wallpapers/WallpapersHooks.java @@ -1,78 +1,97 @@ package ru.vtosters.lite.ui.wallpapers; -import static com.vk.im.engine.h.im_bg_chat; -import static ru.vtosters.lite.ui.wallpapers.ImageFilters.getFilteredDrawable; -import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.getPreferences; -import static ru.vtosters.lite.utils.AndroidUtils.sendToast; -import static ru.vtosters.lite.utils.Preferences.getBoolValue; - import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.view.View; import android.widget.ImageView; - import com.vtosters.lite.R; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; - import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.ThemesUtils; import vigo.sdk.Log; +import java.io.File; +import java.io.FileOutputStream; +import java.util.function.Supplier; + +import static com.vk.im.engine.h.im_bg_chat; +import static ru.vtosters.lite.ui.wallpapers.ImageFilters.getFilteredDrawable; +import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; +import static ru.vtosters.lite.utils.AndroidUtils.sendToast; +import static ru.vtosters.lite.utils.Preferences.getBoolValue; + public class WallpapersHooks { - private static final boolean compress = getBoolValue("compresswp", true); - private static File mWallpaperFile; + // TODO: force compress by default not asking user about that? + private static final Supplier compress = () -> getBoolValue("compresswp", true); + private static final File originalWp = new File(getGlobalContext().getFilesDir(), "wallpaper.jpeg"); + private static final File compressedWp = new File(getGlobalContext().getFilesDir(), "compressedwp.jpeg"); + // TODO: cache to file? private static Drawable mWallpaper; private static boolean mUpdateWallpaperRequested = true; - private static boolean mUpdateWallpaperFileRequested = true; - public static File getWallpaperFile() { - if (mWallpaperFile == null) { - mWallpaperFile = new File(getGlobalContext().getFilesDir(), "wallpaper.webp"); + // TODO: respect blur, when there is blur/mosaic effect applied these two can be even less, just HD (1280x720) for e.g. + private static final int MAX_WP_WIDTH = 1080; + private static final int MAX_WP_HEIGHT = 1920; + + + public static void setBg(View view) { + if (hasWallpapers()) { + ((ImageView) view).setImageDrawable(getWallpaper()); // set picture to background + } else { + view.setBackgroundColor(ThemesUtils.getColorFromAttr(im_bg_chat)); // set default bg color } - - return mWallpaperFile; } - public static Drawable getFilteredFile() { - File file = null; - File wp = mWallpaperFile; - String temp = getGlobalContext().getFilesDir() + File.separator + "filteredwp.webp"; - - if (wp != null && mUpdateWallpaperFileRequested) { - try { - file = new File(temp); - file.createNewFile(); - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ((BitmapDrawable) getFilteredDrawable(Drawable.createFromPath(wp.getAbsolutePath()))).getBitmap().compress(Bitmap.CompressFormat.WEBP, (compress ? 80 : 95), bos); - byte[] bitmapdata = bos.toByteArray(); - - FileOutputStream fos = new FileOutputStream(file); - fos.write(bitmapdata); - fos.flush(); - fos.close(); - - } catch (Exception e) { - Log.d("Wallpapers", e.getMessage()); - } - - mUpdateWallpaperFileRequested = false; - } - - try { - return Drawable.createFromPath(temp); - } catch (Exception e) { - if (file != null) { - return Drawable.createFromPath(file.getAbsolutePath()); - } else { + public static Drawable getWallpaper() { + if (mWallpaper == null || mUpdateWallpaperRequested) { + if (!originalWp.exists()) { return null; } + Drawable drawable; + if (compress.get()) { + if (!compressedWp.exists() && !prepareCompressed()) { + return null; + } + drawable = Drawable.createFromPath(compressedWp.getAbsolutePath()); + } else { + drawable = Drawable.createFromPath(originalWp.getAbsolutePath()); + } + + if (drawable == null) { + return null; + } + mWallpaper = getFilteredDrawable(drawable); + mUpdateWallpaperRequested = false; } + + return mWallpaper; + } + + private static boolean prepareCompressed() { + // TODO remove this check? with "compress" enabled it should be fine + if (!eligibleWallpaperFile(originalWp)) { + return false; + } + try (var f = new FileOutputStream(compressedWp)) { + var bitmap = BitmapFactory.decodeFile(originalWp.getAbsolutePath()); + + if (bitmap.getHeight() > MAX_WP_HEIGHT || bitmap.getWidth() > MAX_WP_WIDTH) { + bitmap = resize(bitmap, MAX_WP_WIDTH, MAX_WP_HEIGHT); + } + var drawable = new BitmapDrawable(null, bitmap); + // TODO: remove duplication without changes when provided image already fits required params + drawable.getBitmap().compress(Bitmap.CompressFormat.WEBP, 90, f); + } catch (Exception e) { + Log.d("Wallpapers", e.getMessage()); + return false; + } + return true; + } + + + public static File getWallpaperFile() { + return originalWp; } private static Boolean eligibleWallpaperFile(File file) { @@ -85,94 +104,40 @@ public class WallpapersHooks { } } - public static void setBg(View view) { - if (hasWallpapers()) { - ((ImageView) view).setImageDrawable(getFilteredFile()); // set picture to background - } else { - view.setBackgroundColor(ThemesUtils.getColorFromAttr(im_bg_chat)); // set default bg color - } - } - - public static String getWallpaperUrl() { - var file = getWallpaperFile(); - - if (file.exists() && eligibleWallpaperFile(file)) { - return file.getAbsolutePath(); - } - - return "default"; - } - public static boolean hasWallpapers() { return getWallpaper() != null; } - public static Drawable getWallpaper() { - if (mWallpaper == null || mUpdateWallpaperRequested) { - String url = getWallpaperUrl(); - - if (url.equals("default") || url.isEmpty()) { - return null; - } - - Drawable drawable = Drawable.createFromPath(getWallpaperUrl()); - - if (drawable == null) { - return null; - } - - mWallpaper = drawable; - - mWallpaper = getFilteredDrawable(mWallpaper); - - mUpdateWallpaperRequested = false; - } - - return mWallpaper; - } - public static void requestUpdateWallpaper() { mUpdateWallpaperRequested = true; - mUpdateWallpaperFileRequested = true; } - public static String getRadiusSummary() { - String radius = getPreferences().getString("msg_blur_radius", "disabled"); - return switch (radius) { - case "low" -> AndroidUtils.getString(R.string.wallpapers_low); - case "med" -> AndroidUtils.getString(R.string.wallpapers_med); - case "high" -> AndroidUtils.getString(R.string.wallpapers_high); - default -> AndroidUtils.getString(R.string.wallpapers_disabled); - }; - } - - public static String getDimmingSummary() { - String radius = getPreferences().getString("msg_dim", "disabled"); - return switch (radius) { - case "dim_black" -> AndroidUtils.getString(R.string.wallpapers_dim_black); - case "dim_white" -> AndroidUtils.getString(R.string.wallpapers_dim_white); - default -> AndroidUtils.getString(R.string.wallpapers_disabled); - }; - } - - public static String getMosaicSummary() { - String radius = getPreferences().getString("msg_mosaic", "disabled"); - return switch (radius) { - case "low" -> AndroidUtils.getString(R.string.wallpapers_low); - case "med" -> AndroidUtils.getString(R.string.wallpapers_med); - case "high" -> AndroidUtils.getString(R.string.wallpapers_high); - default -> AndroidUtils.getString(R.string.wallpapers_disabled); - }; - } - - public static void removeWallpaper() { try { - new File(getGlobalContext().getFilesDir(), "wallpaper.webp").delete(); - new File(getGlobalContext().getFilesDir(), "filteredwp.webp").delete(); - mWallpaperFile = null; + mWallpaper = null; + originalWp.delete(); + compressedWp.delete(); } catch (Exception e) { Log.d("Wallpapers", e.getMessage()); } } + + private static Bitmap resize(Bitmap image, int maxWidth, int maxHeight) { + if (maxHeight > 0 && maxWidth > 0) { + int width = image.getWidth(); + int height = image.getHeight(); + float ratioBitmap = (float) width / (float) height; + float ratioMax = (float) maxWidth / (float) maxHeight; + + int finalWidth = maxWidth; + int finalHeight = maxHeight; + if (ratioMax > ratioBitmap) { + finalWidth = (int) ((float) maxHeight * ratioBitmap); + } else { + finalHeight = (int) ((float) maxWidth / ratioBitmap); + } + image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true); + } + return image; + } } diff --git a/app/src/main/java/ru/vtosters/lite/utils/About.java b/app/src/main/java/ru/vtosters/lite/utils/About.java index 87b816a0b..1e45e2c93 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/About.java +++ b/app/src/main/java/ru/vtosters/lite/utils/About.java @@ -1,21 +1,17 @@ package ru.vtosters.lite.utils; -import static ru.vtosters.lite.utils.AndroidUtils.edit; -import static ru.vtosters.lite.utils.AndroidUtils.getApplicationName; -import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.sendToast; -import static ru.vtosters.lite.utils.Preferences.VERSIONNAME; -import static ru.vtosters.lite.utils.Preferences.devmenu; -import static ru.vtosters.lite.utils.Preferences.isValidSignature; - import android.content.Context; +import android.content.res.AssetManager; +import android.text.TextUtils; import android.view.View; - import com.vtosters.lite.R; import java.io.IOException; import java.util.Scanner; +import static ru.vtosters.lite.utils.AndroidUtils.*; +import static ru.vtosters.lite.utils.Preferences.*; + public class About { public static String getBuildNumber() { return getBuild(getGlobalContext(), "version.properties"); @@ -26,7 +22,7 @@ public class About { if (devmenu()) { sendToast(AndroidUtils.getString(R.string.debug_menu_already_activated)); } else { - edit().putBoolean("devmenu", true).apply(); + Preferences.getPreferences().edit().putBoolean("devmenu", true).apply(); sendToast(AndroidUtils.getString(R.string.debug_menu_activated)); } return true; @@ -38,16 +34,14 @@ public class About { } public static String getBuild(Context context, String name) { - try ( - Scanner scanner = new Scanner(context.getAssets().open(name)) - ) { - while (scanner.hasNextLine()) { - String line = scanner.findInLine("VERSION_BUILD=.+"); - if (line != null) - return line.replace("VERSION_BUILD=", ""); - return "0000000"; + try { + final var scanner = new Scanner(context.getAssets().open(name, AssetManager.ACCESS_BUFFER)); + while(scanner.hasNextLine()) { + final var line = scanner.findInLine("VERSION_BUILD=.+"); + if(!TextUtils.isEmpty(line)) + return line.substring(14); } - } catch (IOException e) { + } catch(IOException e) { e.printStackTrace(); } return "0000000"; diff --git a/app/src/main/java/ru/vtosters/lite/utils/AccountManagerUtils.java b/app/src/main/java/ru/vtosters/lite/utils/AccountManagerUtils.java index 9ef64ec56..e42efda6b 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/AccountManagerUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/AccountManagerUtils.java @@ -53,6 +53,10 @@ public class AccountManagerUtils { return userProfile.b; } // UserId Profile via userProfile + public static boolean isLogin() { + return VKAccountManager.d().b1(); + } + public static int getUserID(ExtendedUserProfile extendedUserProfile) { return getUserID(fromEup(extendedUserProfile)); } // UserId Profile via extendedUserProfile diff --git a/app/src/main/java/ru/vtosters/lite/utils/AndroidUtils.java b/app/src/main/java/ru/vtosters/lite/utils/AndroidUtils.java index 2bf8985d6..b7de9826a 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/AndroidUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/AndroidUtils.java @@ -32,28 +32,10 @@ import static ru.vtosters.lite.utils.Preferences.getBoolValue; public class AndroidUtils { - public static SharedPreferences getDefaultPrefs() { - if (Preferences.preferences == null) - Preferences.preferences = PreferenceManager.getDefaultSharedPreferences(getGlobalContext()); - return Preferences.preferences; - } - - public static SharedPreferences getPreferences() { - return PreferenceManager.getDefaultSharedPreferences(getGlobalContext()); - } - public static boolean isTablet() { return Screen.l(getGlobalContext()); } - public static String getPrefsValue(String pref) { - return getPreferences().getString(pref, ""); - } // Get pref value as string - - public static SharedPreferences.Editor edit() { - return PreferenceManager.getDefaultSharedPreferences(getGlobalContext()).edit(); - } // Edit SharedPreferences - @NonNull public static Context getGlobalContext() { try { @@ -176,7 +158,7 @@ public class AndroidUtils { .setMessage(AndroidUtils.getString("app_open_by_default_settings")) .setCancelable(false) .setPositiveButton(com.vtosters.lite.R.string.social_graph_skip, - (dialogInterface, i) -> edit().putBoolean("showUnverifDialog", false).apply() + (dialogInterface, i) -> Preferences.getPreferences().edit().putBoolean("showUnverifDialog", false).apply() ) .setNeutralButton(com.vtosters.lite.R.string.open_settings, (dialogInterface, i) -> { diff --git a/app/src/main/java/ru/vtosters/lite/utils/DeletedMessagesHandler.java b/app/src/main/java/ru/vtosters/lite/utils/DeletedMessagesHandler.java index 97bb041b4..0639b2349 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/DeletedMessagesHandler.java +++ b/app/src/main/java/ru/vtosters/lite/utils/DeletedMessagesHandler.java @@ -1,7 +1,7 @@ package ru.vtosters.lite.utils; import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; import static ru.vtosters.lite.utils.Preferences.getBoolValue; import android.annotation.SuppressLint; @@ -73,7 +73,7 @@ public class DeletedMessagesHandler { } private static String getPrefixUndelete() { - var prefs = getPrefsValue("undeletemsg_prefix_value"); + var prefs = getString("undeletemsg_prefix_value"); if (prefs.isEmpty()) { return "\uD83D\uDDD1 "; diff --git a/app/src/main/java/ru/vtosters/lite/utils/IOUtils.java b/app/src/main/java/ru/vtosters/lite/utils/IOUtils.java index afb0aad51..d5e09582a 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/IOUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/IOUtils.java @@ -17,7 +17,7 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class IOUtils { - public static final int BUFFER_SIZE = 0x800; + public static final int BUFFER_SIZE = 8192; public static byte[] decodeStream(InputStream encIs, String keyURL) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException { @@ -112,7 +112,7 @@ public class IOUtils { public static void deleteRecursive(File f, boolean selfDeletion) { if (f.isDirectory()) { var fs = f.listFiles(); - if (fs != null && fs.length > 0) + if (fs != null) for (var child : fs) deleteRecursive(child, true); } diff --git a/app/src/main/java/ru/vtosters/lite/utils/ImageUtils.java b/app/src/main/java/ru/vtosters/lite/utils/ImageUtils.java index 065e9ac8b..66b29c15a 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/ImageUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/ImageUtils.java @@ -58,7 +58,7 @@ public class ImageUtils { final int width = bitmap.getWidth(); final int height = bitmap.getHeight(); final Bitmap outputBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - int pref = Preferences.preferences.getInt("pic_rounding", 0); + int pref = Preferences.getPreferences().getInt("pic_rounding", 0); final Canvas canvas = new Canvas(outputBitmap); final Path path = new Path(); diff --git a/app/src/main/java/ru/vtosters/lite/utils/NavigatorUtils.java b/app/src/main/java/ru/vtosters/lite/utils/NavigatorUtils.java index 7e7206b06..00c2d6434 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/NavigatorUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/NavigatorUtils.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import com.vk.core.fragments.FragmentImpl; import com.vk.navigation.Navigator; +import ru.vtosters.lite.ui.fragments.VTSettings; public class NavigatorUtils { @@ -13,4 +14,14 @@ public class NavigatorUtils { .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } + + /** + * switch to settings for {@link Intent.ACTION_APPLICATION_PREFERENCES}*/ + public static void switchToSettings(Context context) { + var intent = new Navigator(VTSettings.class) + .b(context) + .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivity(intent); + } + } diff --git a/app/src/main/java/ru/vtosters/lite/utils/NewsFeedFiltersUtils.java b/app/src/main/java/ru/vtosters/lite/utils/NewsFeedFiltersUtils.java index b9c235f71..555f13b49 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/NewsFeedFiltersUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/NewsFeedFiltersUtils.java @@ -1,7 +1,7 @@ package ru.vtosters.lite.utils; import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; +import static ru.vtosters.lite.utils.Preferences.getString; import static ru.vtosters.lite.utils.Preferences.ads; import static ru.vtosters.lite.utils.Preferences.adsgroup; import static ru.vtosters.lite.utils.Preferences.authorsrecomm; @@ -41,17 +41,17 @@ public class NewsFeedFiltersUtils { getFilter("shitposting", "IDontWantToReadIt.txt", mFilters); getFilter("cringecopyright", "CopyrightAds.txt", mFiltersLinks); - var customFilters = getPrefsValue("spamfilters"); + var customFilters = getString("spamfilters"); if (!customFilters.isEmpty()) { mFilters.addAll(Arrays.asList(customFilters.toLowerCase().split(", "))); } - var sourceNameFilter = getPrefsValue("sourcenamefilter"); + var sourceNameFilter = getString("sourcenamefilter"); if (!sourceNameFilter.isEmpty()) { mFiltersNames.addAll(Arrays.asList(sourceNameFilter.toLowerCase().split(", "))); } - var linkFilter = getPrefsValue("linkfilter"); + var linkFilter = getString("linkfilter"); if (!linkFilter.isEmpty()) { mFiltersLinks.addAll(Arrays.asList(linkFilter.toLowerCase().split(", "))); } @@ -156,7 +156,7 @@ public class NewsFeedFiltersUtils { } public static String getAllFilters() { - return getPrefsValue("spamfilters"); + return getString("spamfilters"); } public static boolean isBadNews(String text) { diff --git a/app/src/main/java/ru/vtosters/lite/utils/Preferences.java b/app/src/main/java/ru/vtosters/lite/utils/Preferences.java index 6369d6098..543372128 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/Preferences.java +++ b/app/src/main/java/ru/vtosters/lite/utils/Preferences.java @@ -1,33 +1,26 @@ package ru.vtosters.lite.utils; -import static java.lang.Long.MAX_VALUE; -import static ru.vtosters.lite.proxy.ProxyUtils.setProxy; -import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; -import static ru.vtosters.lite.utils.AndroidUtils.getPreferences; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; -import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.setupFilters; -import static ru.vtosters.lite.utils.SignatureChecker.validateAppSignature; -import static ru.vtosters.lite.utils.VTVerifications.isPrometheus; -import static ru.vtosters.lite.utils.VTVerifications.isVerified; - import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; import android.os.StrictMode; -import android.preference.PreferenceManager; - -import android.util.Log; import com.vtosters.lite.data.Users; import com.vtosters.lite.fragments.SettingsListFragment; +import ru.vtosters.lite.ui.fragments.VTSettings; import java.security.NoSuchAlgorithmException; -import ru.vtosters.lite.ui.fragments.VTSettings; +import static java.lang.Long.MAX_VALUE; +import static ru.vtosters.lite.proxy.ProxyUtils.setProxy; +import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext; +import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.setupFilters; +import static ru.vtosters.lite.utils.SignatureChecker.validateAppSignature; +import static ru.vtosters.lite.utils.VTVerifications.isPrometheus; +import static ru.vtosters.lite.utils.VTVerifications.isVerified; public class Preferences { - public static SharedPreferences preferences = getGlobalContext().getSharedPreferences("com.vtosters.lite_preferences", Context.MODE_PRIVATE); public static String VERSIONNAME = "Beta"; public static void init(Application application) throws Exception { @@ -41,6 +34,14 @@ public class Preferences { LifecycleUtils.registerActivities(application); } // VK Init + public static SharedPreferences getPreferences() { + return getGlobalContext().getSharedPreferences("com.vtosters.lite_preferences", Context.MODE_PRIVATE); + } + + public static String getString(String name) { + return getPreferences().getString(name, ""); + } + public static void forceOffline() { setupFilters(); @@ -50,10 +51,7 @@ public class Preferences { } public static boolean getBoolValue(String key, Boolean value) { - if (preferences == null) { - preferences = PreferenceManager.getDefaultSharedPreferences(getGlobalContext()); - } - return preferences.getBoolean(key, value); + return getPreferences().getBoolean(key, value); } // Set bool by default and get value public static SharedPreferences getPrefsFromFile(String filename) { @@ -291,6 +289,15 @@ public class Preferences { return !getBoolValue("isRoamingState", false) && isValidSignature() && (!dev() || getBoolValue("autoupdates", true)); } + public static boolean isNewBuild() { + return !getPreferences().getString("build_number", "") + .equals(About.getBuildNumber()); + } + + public static void updateBuildNumber() { + getPreferences().edit().putString("build_number", About.getBuildNumber()).commit(); + } + public static boolean isValidSignature() { try { return validateAppSignature(); @@ -313,7 +320,7 @@ public class Preferences { } public static long getSizeForDelete() { - return switch (getPrefsValue("clearcache")) { + return switch (Preferences.getPreferences().getString("clearcache", "")) { case "100mb" -> 104857600L; case "500mb" -> 524288000L; case "1gb" -> 1073741824L; diff --git a/app/src/main/java/ru/vtosters/lite/utils/ReflectionUtils.java b/app/src/main/java/ru/vtosters/lite/utils/ReflectionUtils.java index dee5776b2..34d7305b1 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/ReflectionUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/ReflectionUtils.java @@ -78,8 +78,7 @@ public class ReflectionUtils { return findMethod(instance.getClass(), methodName, params); } - public static Object getActivityThread(Context context, Class clz) - throws InvocationTargetException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException { + public static Object getActivityThread(Context context, Class clz) { try { if(clz == null) clz = findClass("android.app.ActivityThread"); final Method currentActivityThreadMtd = findMethod(clz, "currentActivityThread"); diff --git a/app/src/main/java/ru/vtosters/lite/utils/ThemesUtils.java b/app/src/main/java/ru/vtosters/lite/utils/ThemesUtils.java index 9070bf3fe..7952b308e 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/ThemesUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/ThemesUtils.java @@ -48,7 +48,7 @@ public class ThemesUtils { } // Apply VKTheme and ImTheme (hard applying without dynamic theme changing) public static boolean isCustomAccentEnabled() { - return ThemesUtils.isMonetTheme() || ThemesManager.hasTmpArchive(); + return ThemesUtils.isMonetTheme() || ThemesManager.canApplyCustomAccent(); } public static ColorStateList getAccenedColorStateList() { @@ -101,6 +101,21 @@ public class ThemesUtils { return getColorFromAttr(R.attr.accent); } // Color accent + //region Used for migrating accent color to new version + + public static int getReservedAccent() { + return Preferences.getPreferences().getInt("reserved_accent_color", Color.TRANSPARENT); + } + + public static void reserveAccentColor(int accent, boolean async) { + final var editor = Preferences.getPreferences().edit(); + editor.putInt("reserved_accent_color", accent); + if(async) editor.apply(); + else editor.commit(); + } + + //endregion + public static int getMutedAccentColor() { return getMutedColor(getAccentColor()); } @@ -197,7 +212,7 @@ public class ThemesUtils { } public static void setCustomAccentColor(int newColor, boolean async) { - var editor = AndroidUtils.edit().putInt("accent_color", newColor); + var editor = Preferences.getPreferences().edit().putInt("accent_color", newColor); if (async) editor.apply(); else editor.commit(); } diff --git a/app/src/main/java/ru/vtosters/lite/utils/VKMeHandler.java b/app/src/main/java/ru/vtosters/lite/utils/VKMeHandler.java index d176d89e7..91187ebb8 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/VKMeHandler.java +++ b/app/src/main/java/ru/vtosters/lite/utils/VKMeHandler.java @@ -1,19 +1,15 @@ package ru.vtosters.lite.utils; +import android.util.Log; +import com.vtosters.lite.R; +import org.json.JSONException; +import org.json.JSONObject; + import static ru.vtosters.lite.net.Request.makeRequest; import static ru.vtosters.lite.proxy.ProxyUtils.getApi; import static ru.vtosters.lite.proxy.ProxyUtils.getOauth; -import static ru.vtosters.lite.utils.AndroidUtils.edit; -import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue; import static ru.vtosters.lite.utils.AndroidUtils.sendToast; -import android.util.Log; - -import com.vtosters.lite.R; - -import org.json.JSONException; -import org.json.JSONObject; - public class VKMeHandler { public static void getVkMeToken(String username, String password) { makeRequest("https://" + @@ -45,15 +41,15 @@ public class VKMeHandler { } public static void removeToken() { - edit().remove("vkmetoken").commit(); + Preferences.getPreferences().edit().remove("vkmetoken").commit(); } public static String getToken() { - return getPrefsValue("vkmetoken"); + return Preferences.getString("vkmetoken"); } public static void setToken(String token) { - edit().putString("vkmetoken", token).commit(); + Preferences.getPreferences().edit().putString("vkmetoken", token).commit(); } public static void setPrivacyStatus(String status) { diff --git a/build.gradle b/build.gradle index 868de8026..61a22649a 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,13 @@ buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { classpath 'com.android.tools.build:gradle:7.3.1' + classpath 'org.mozilla.rust-android-gradle:plugin:0.9.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/native-effects/.gitignore b/native-effects/.gitignore new file mode 100644 index 000000000..96ef6c0b9 --- /dev/null +++ b/native-effects/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/native-effects/Cargo.toml b/native-effects/Cargo.toml new file mode 100644 index 000000000..b4f69397c --- /dev/null +++ b/native-effects/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "native-effects" +version = "0.1.0" +edition = "2021" + +[profile.release] +opt-level = 3 +strip = true +lto = true +codegen-units = 1 + +[lib] +crate-type = ["cdylib"] + +[dependencies] +jni = "0.20.0" +rand = "0.8.5" +image = "0.24.5" diff --git a/native-effects/src/lib.rs b/native-effects/src/lib.rs new file mode 100644 index 000000000..340a66ec7 --- /dev/null +++ b/native-effects/src/lib.rs @@ -0,0 +1,365 @@ +use jni::objects::JByteBuffer; +use jni::objects::JClass; +use jni::sys::jfloat; +use jni::sys::jint; +use jni::sys::jstring; +use jni::JNIEnv; +use rand::Rng; +use std::cmp::max; + +// We assume that input ByteBuffer is always in ARGB_8888 format +#[repr(C)] +#[derive(Debug, Clone, Copy)] +struct Pixel { + r: u8, + g: u8, + b: u8, + a: u8, +} + +impl Pixel { + fn set_color(&mut self, r: u8, g: u8, b: u8) { + self.r = r; + self.g = g; + self.b = b; + } + + fn invert(&mut self) { + self.r = 255 - self.r; + self.g = 255 - self.g; + self.b = 255 - self.b; + } +} + +fn resolve_pixel_slice<'a>(env: &JNIEnv<'a>, bitmap_buffer: &JByteBuffer<'a>) -> &'a mut [Pixel] { + let start = env + .get_direct_buffer_address(*bitmap_buffer) + .expect("Unable to resolve DirectBuffer address"); + let capacity = env + .get_direct_buffer_capacity(*bitmap_buffer) + .expect("Unable to resolve DirectBuffer size"); + let s = start as *mut Pixel; + unsafe { std::slice::from_raw_parts_mut(s, capacity / 4) } +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_monochrome( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, +) -> jstring { + let pixels = resolve_pixel_slice(&env, &bitmap_buffer); + pixels.iter_mut().for_each(|p| { + // value (V) from HSV + let value = max(p.r, max(p.g, p.b)); + if value > 127 { + p.set_color(255, 255, 255); + } else { + p.set_color(0, 0, 0); + } + }); + + let output = env + .new_string("Applied Monochrome effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_invert( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, +) -> jstring { + let pixels = resolve_pixel_slice(&env, &bitmap_buffer); + + pixels.iter_mut().for_each(|p| p.invert()); + + let output = env + .new_string("Applied Invert effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_sepia( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, +) -> jstring { + let pixels = resolve_pixel_slice(&env, &bitmap_buffer); + + pixels.iter_mut().for_each(|p| { + let r = p.r as f32; + let g = p.g as f32; + let b = p.b as f32; + + let new_red = 0.393 * r + 0.769 * g + 0.189 * b; + let new_green = 0.349 * r + 0.686 * g + 0.168 * b; + let new_blue = 0.272 * r + 0.534 * g + 0.131 * b; + + p.set_color(new_red as u8, new_green as u8, new_blue as u8); + }); + + let output = env + .new_string("Applied Sepia effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_emboss( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, + height: jint, + width: jint, +) -> jstring { + let pixels = resolve_pixel_slice(&env, &bitmap_buffer); + let kernel = [-1.0, 0.0, -1.0, 0.0, 4.0, 0.0, -1.0, 0.0, -1.0]; + let out: &mut Vec = &mut Vec::new(); + for (y, row) in pixels.chunks(width as usize).enumerate() { + for (x, pixel) in row.iter().enumerate() { + if y == 0 || x == 0 || y == (height - 1) as usize || x == (width - 1) as usize { + out.push(*pixel); + continue; + } + let start = y * width as usize + x - 1; + let end = start + 3; + let matrix = [ + &pixels[start - width as usize..end - width as usize], + &pixels[start..end], + &pixels[start + width as usize..end + width as usize], + ] + .concat(); + let mut acc = [64.0, 64.0, 64.0]; + for (p, k) in matrix.iter().zip(kernel.iter()) { + acc[0] += p.r as f32 * k; + acc[1] += p.g as f32 * k; + acc[2] += p.b as f32 * k; + } + + out.push(Pixel { + r: acc[0] as u8, + g: acc[1] as u8, + b: acc[2] as u8, + a: pixel.a, + }); + } + } + + pixels.copy_from_slice(&out); + + let output = env + .new_string("Applied Emboss effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_engrave( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, + height: jint, + width: jint, +) -> jstring { + let pixels = resolve_pixel_slice(&env, &bitmap_buffer); + let kernel = [-2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0]; + let out: &mut Vec = &mut Vec::new(); + for (y, row) in pixels.chunks(width as usize).enumerate() { + for (x, pixel) in row.iter().enumerate() { + if y == 0 || x == 0 || y == (height - 1) as usize || x == (width - 1) as usize { + out.push(*pixel); + continue; + } + let start = y * width as usize + x - 1; + let end = start + 3; + let matrix = [ + &pixels[start - width as usize..end - width as usize], + &pixels[start..end], + &pixels[start + width as usize..end + width as usize], + ] + .concat(); + let mut acc = [95.0, 95.0, 95.0]; + for (p, k) in matrix.iter().zip(kernel.iter()) { + acc[0] += p.r as f32 * k; + acc[1] += p.g as f32 * k; + acc[2] += p.b as f32 * k; + } + + out.push(Pixel { + r: acc[0] as u8, + g: acc[1] as u8, + b: acc[2] as u8, + a: pixel.a, + }); + } + } + + pixels.copy_from_slice(&out); + + let output = env + .new_string("Applied Engrave effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_flea( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, +) -> jstring { + let mut rng = rand::thread_rng(); + let pixels = resolve_pixel_slice(&env, &bitmap_buffer); + for p in pixels { + p.set_color( + p.r | rng.gen::(), + p.g | rng.gen::(), + p.b | rng.gen::(), + ) + } + + let output = env + .new_string("Applied Flea effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_snow( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, +) -> jstring { + let mut rng = rand::thread_rng(); + let pixels = resolve_pixel_slice(&env, &bitmap_buffer); + for p in pixels { + let threshold: u8 = rng.gen(); + if p.r > threshold && p.g > threshold && p.b > threshold { + p.set_color(255, 255, 255); + } + } + + let output = env + .new_string("Applied Snow effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_gaussian( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, + height: jint, + width: jint, + radius: jfloat, +) -> jstring { + let start = env + .get_direct_buffer_address(bitmap_buffer) + .expect("Unable to resolve DirectBuffer address"); + let capacity = env + .get_direct_buffer_capacity(bitmap_buffer) + .expect("Unable to resolve DirectBuffer size"); + let s = start as *mut u8; + let s = unsafe { std::slice::from_raw_parts_mut(s, capacity) }; + + let mut img = image::ImageBuffer::, Vec>::from_raw( + width as u32, + height as u32, + s.to_vec(), + ) + .unwrap(); + + let img = image::imageops::blur(&mut img, radius); + + s.copy_from_slice(img.as_raw()); + + let output = env + .new_string("Applied Gaussian effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_dim( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, + height: jint, + width: jint, + delta: jint, +) -> jstring { + let start = env + .get_direct_buffer_address(bitmap_buffer) + .expect("Unable to resolve DirectBuffer address"); + let capacity = env + .get_direct_buffer_capacity(bitmap_buffer) + .expect("Unable to resolve DirectBuffer size"); + let s = start as *mut u8; + let s = unsafe { std::slice::from_raw_parts_mut(s, capacity) }; + + let img = image::ImageBuffer::, Vec>::from_raw( + width as u32, + height as u32, + s.to_vec(), + ) + .unwrap(); + + let img = image::imageops::brighten(&img, delta); + + s.copy_from_slice(img.as_raw()); + + let output = env + .new_string("Applied Dim effect!") + .expect("Couldn't create java string!"); + return **output; +} + +#[no_mangle] +pub extern "C" fn Java_ru_vtosters_lite_ui_wallpapers_NativeEffects_mosaic( + env: JNIEnv, + _: JClass, + bitmap_buffer: JByteBuffer, + height: jint, + width: jint, + scale: jint, +) -> jstring { + let start = env + .get_direct_buffer_address(bitmap_buffer) + .expect("Unable to resolve DirectBuffer address"); + let capacity = env + .get_direct_buffer_capacity(bitmap_buffer) + .expect("Unable to resolve DirectBuffer size"); + let s = start as *mut u8; + let s = unsafe { std::slice::from_raw_parts_mut(s, capacity) }; + + let mut img = image::ImageBuffer::, Vec>::from_raw( + width as u32, + height as u32, + s.to_vec(), + ) + .unwrap(); + + img = image::imageops::resize( + &img, + (width / scale) as u32, + (height / scale) as u32, + image::imageops::FilterType::Nearest, + ); + img = image::imageops::resize( + &img, + width as u32, + height as u32, + image::imageops::FilterType::Nearest, + ); + + s.copy_from_slice(img.as_raw()); + + let output = env + .new_string("Applied Mosaic effect!") + .expect("Couldn't create java string!"); + return **output; +} diff --git a/smali/AndroidManifest.xml b/smali/AndroidManifest.xml index 8b4b838fc..25661a1d1 100644 --- a/smali/AndroidManifest.xml +++ b/smali/AndroidManifest.xml @@ -142,7 +142,7 @@ + getWallpaperUrl()Ljava/lang/String; +# invoke-static {}, Lru/vtosters/lite/ui/wallpapers/WallpapersHooks;->getWallpaperUrl()Ljava/lang/String; - move-result-object v0 +# move-result-object v0 - return-object v0 +# return-object v0 - .line 1 - invoke-direct {p0}, Lcom/vk/im/ui/ImUiPrefs;->k()Landroid/content/SharedPreferences; +# .line 1 +# invoke-direct {p0}, Lcom/vk/im/ui/ImUiPrefs;->k()Landroid/content/SharedPreferences; - move-result-object v0 +# move-result-object v0 - const-string v1, "pref_dialog_background_uri" +# const-string v1, "pref_dialog_background_uri" - const-string v2, "default" +# const-string v2, "default" - invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +# invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; - move-result-object v0 +# move-result-object v0 - if-eqz v0, :cond_0 +# if-eqz v0, :cond_0 - goto :goto_0 +# goto :goto_0 - :cond_0 - const-string v0, "" +# :cond_0 +# const-string v0, "" - :goto_0 - return-object v0 -.end method +# :goto_0 +# return-object v0 +# .end method .method public final d()J .locals 4 diff --git a/smali/smali_classes3/com/vk/im/ui/fragments/ChatFragment.smali b/smali/smali_classes3/com/vk/im/ui/fragments/ChatFragment.smali index 101c61a3c..83279a023 100644 --- a/smali/smali_classes3/com/vk/im/ui/fragments/ChatFragment.smali +++ b/smali/smali_classes3/com/vk/im/ui/fragments/ChatFragment.smali @@ -772,180 +772,180 @@ return-void - .line 1 - sget-object v0, Lcom/vk/im/ui/ImUiPrefs;->g:Lcom/vk/im/ui/ImUiPrefs; + # .line 1 + # sget-object v0, Lcom/vk/im/ui/ImUiPrefs;->g:Lcom/vk/im/ui/ImUiPrefs; - invoke-virtual {v0}, Lcom/vk/im/ui/ImUiPrefs;->c()Ljava/lang/String; + # invoke-virtual {v0}, Lcom/vk/im/ui/ImUiPrefs;->c()Ljava/lang/String; - move-result-object v0 + # move-result-object v0 - .line 2 - invoke-interface {v0}, Ljava/lang/CharSequence;->length()I + # .line 2 + # invoke-interface {v0}, Ljava/lang/CharSequence;->length()I - move-result v1 + # move-result v1 - const/4 v2, 0x1 + # const/4 v2, 0x1 - const/4 v3, 0x0 + # const/4 v3, 0x0 - if-nez v1, :cond_0 + # if-nez v1, :cond_0 - const/4 v1, 0x1 + # const/4 v1, 0x1 - goto :goto_0 + # goto :goto_0 - :cond_0 - const/4 v1, 0x0 + # :cond_0 + # const/4 v1, 0x0 - :goto_0 - const-string v4, "msgListComponent" + # :goto_0 + # const-string v4, "msgListComponent" - const-string v5, "dialogBackgroundView" + # const-string v5, "dialogBackgroundView" - const/4 v6, 0x0 + # const/4 v6, 0x0 - if-nez v1, :cond_6 + # if-nez v1, :cond_6 - const-string v1, "default" + # const-string v1, "default" - invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->a(Ljava/lang/Object;Ljava/lang/Object;)Z + # invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->a(Ljava/lang/Object;Ljava/lang/Object;)Z - move-result v1 + # move-result v1 - if-nez v1, :cond_6 + # if-nez v1, :cond_6 - iget-object v1, p0, Lcom/vk/im/ui/fragments/ChatFragment;->E:Lcom/vk/im/engine/models/dialogs/DialogExt; + # iget-object v1, p0, Lcom/vk/im/ui/fragments/ChatFragment;->E:Lcom/vk/im/engine/models/dialogs/DialogExt; - if-eqz v1, :cond_5 + # if-eqz v1, :cond_5 - invoke-virtual {v1}, Lcom/vk/im/engine/models/dialogs/DialogExt;->t1()Lcom/vk/im/engine/models/dialogs/Dialog; + # invoke-virtual {v1}, Lcom/vk/im/engine/models/dialogs/DialogExt;->t1()Lcom/vk/im/engine/models/dialogs/Dialog; - move-result-object v1 + # move-result-object v1 - invoke-virtual {v1}, Lcom/vk/im/engine/models/dialogs/Dialog;->U1()Z + # invoke-virtual {v1}, Lcom/vk/im/engine/models/dialogs/Dialog;->U1()Z - move-result v1 + # move-result v1 - if-eqz v1, :cond_1 + # if-eqz v1, :cond_1 - goto :goto_1 + # goto :goto_1 - .line 3 - :cond_1 - iget-object v1, p0, Lcom/vk/im/ui/fragments/ChatFragment;->k0:Lcom/vk/im/ui/views/FrescoImageView; + # .line 3 + # :cond_1 + # iget-object v1, p0, Lcom/vk/im/ui/fragments/ChatFragment;->k0:Lcom/vk/im/ui/views/FrescoImageView; - if-eqz v1, :cond_4 + # if-eqz v1, :cond_4 - new-instance v3, Lcom/vk/im/engine/models/Image; + # new-instance v3, Lcom/vk/im/engine/models/Image; - invoke-direct {v3, v0}, Lcom/vk/im/engine/models/Image;->(Ljava/lang/String;)V + # invoke-direct {v3, v0}, Lcom/vk/im/engine/models/Image;->(Ljava/lang/String;)V - invoke-virtual {v1, v3}, Lcom/vk/im/ui/views/FrescoImageView;->setLocalImage(Lcom/vk/im/engine/models/Image;)V + # invoke-virtual {v1, v3}, Lcom/vk/im/ui/views/FrescoImageView;->setLocalImage(Lcom/vk/im/engine/models/Image;)V - .line 4 - iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->k0:Lcom/vk/im/ui/views/FrescoImageView; + # .line 4 + # iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->k0:Lcom/vk/im/ui/views/FrescoImageView; - if-eqz v0, :cond_3 + # if-eqz v0, :cond_3 - invoke-virtual {v0, v6}, Lcom/vk/im/ui/views/FrescoImageView;->setBackgroundImage(Landroid/graphics/drawable/Drawable;)V + # invoke-virtual {v0, v6}, Lcom/vk/im/ui/views/FrescoImageView;->setBackgroundImage(Landroid/graphics/drawable/Drawable;)V - .line 5 - iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->d0:Lcom/vk/im/ui/components/msg_list/MsgListComponent; + # .line 5 + # iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->d0:Lcom/vk/im/ui/components/msg_list/MsgListComponent; - if-eqz v0, :cond_2 + # if-eqz v0, :cond_2 - invoke-virtual {v0, v2}, Lcom/vk/im/ui/components/msg_list/MsgListComponent;->b(Z)V + # invoke-virtual {v0, v2}, Lcom/vk/im/ui/components/msg_list/MsgListComponent;->b(Z)V - goto :goto_2 + # goto :goto_2 - :cond_2 - invoke-static {v4}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V + # :cond_2 + # invoke-static {v4}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V - throw v6 + # throw v6 - .line 6 - :cond_3 - invoke-static {v5}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V + # .line 6 + # :cond_3 + # invoke-static {v5}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V - throw v6 + # throw v6 - .line 7 - :cond_4 - invoke-static {v5}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V + # .line 7 + # :cond_4 + # invoke-static {v5}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V - throw v6 + # throw v6 - :cond_5 - const-string v0, "dialogExt" + # :cond_5 + # const-string v0, "dialogExt" - .line 8 - invoke-static {v0}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V + # .line 8 + # invoke-static {v0}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V - throw v6 + # throw v6 - .line 9 - :cond_6 - :goto_1 - iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->k0:Lcom/vk/im/ui/views/FrescoImageView; + # .line 9 + # :cond_6 + # :goto_1 + # iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->k0:Lcom/vk/im/ui/views/FrescoImageView; - if-eqz v0, :cond_a + # if-eqz v0, :cond_a - invoke-virtual {v0, v6}, Lcom/vk/im/ui/views/FrescoImageView;->setLocalImage(Lcom/vk/im/engine/models/Image;)V + # invoke-virtual {v0, v6}, Lcom/vk/im/ui/views/FrescoImageView;->setLocalImage(Lcom/vk/im/engine/models/Image;)V - .line 10 - iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->k0:Lcom/vk/im/ui/views/FrescoImageView; + # .line 10 + # iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->k0:Lcom/vk/im/ui/views/FrescoImageView; - if-eqz v0, :cond_9 + # if-eqz v0, :cond_9 - new-instance v1, Landroid/graphics/drawable/ColorDrawable; + # new-instance v1, Landroid/graphics/drawable/ColorDrawable; - iget-object v2, p0, Lcom/vk/im/ui/fragments/ChatFragment;->L:Landroid/content/Context; + # iget-object v2, p0, Lcom/vk/im/ui/fragments/ChatFragment;->L:Landroid/content/Context; - if-eqz v2, :cond_8 + # if-eqz v2, :cond_8 - sget v5, Lcom/vk/im/ui/c;->im_bg_chat:I + # sget v5, Lcom/vk/im/ui/c;->im_bg_chat:I - invoke-static {v2, v5}, Lcom/vk/core/util/ContextExtKt;->h(Landroid/content/Context;I)I + # invoke-static {v2, v5}, Lcom/vk/core/util/ContextExtKt;->h(Landroid/content/Context;I)I - move-result v2 + # move-result v2 - invoke-direct {v1, v2}, Landroid/graphics/drawable/ColorDrawable;->(I)V + # invoke-direct {v1, v2}, Landroid/graphics/drawable/ColorDrawable;->(I)V - invoke-virtual {v0, v1}, Lcom/vk/im/ui/views/FrescoImageView;->setBackgroundImage(Landroid/graphics/drawable/Drawable;)V + # invoke-virtual {v0, v1}, Lcom/vk/im/ui/views/FrescoImageView;->setBackgroundImage(Landroid/graphics/drawable/Drawable;)V - .line 11 - iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->d0:Lcom/vk/im/ui/components/msg_list/MsgListComponent; + # .line 11 + # iget-object v0, p0, Lcom/vk/im/ui/fragments/ChatFragment;->d0:Lcom/vk/im/ui/components/msg_list/MsgListComponent; - if-eqz v0, :cond_7 + # if-eqz v0, :cond_7 - invoke-virtual {v0, v3}, Lcom/vk/im/ui/components/msg_list/MsgListComponent;->b(Z)V + # invoke-virtual {v0, v3}, Lcom/vk/im/ui/components/msg_list/MsgListComponent;->b(Z)V - :goto_2 - return-void + # :goto_2 + # return-void - :cond_7 - invoke-static {v4}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V + # :cond_7 + # invoke-static {v4}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V - throw v6 + # throw v6 - :cond_8 - const-string v0, "themedContext" + # :cond_8 + # const-string v0, "themedContext" - .line 12 - invoke-static {v0}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V + # .line 12 + # invoke-static {v0}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V - throw v6 + # throw v6 - :cond_9 - invoke-static {v5}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V + # :cond_9 + # invoke-static {v5}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V - throw v6 + # throw v6 - .line 13 - :cond_a - invoke-static {v5}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V + # .line 13 + # :cond_a + # invoke-static {v5}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/String;)V - throw v6 + # throw v6 .end method .method private final Y4()V