Compare commits

..
Author SHA1 Message Date
gdlbo adc5bb2b8c some more global renames 2024-03-29 15:16:33 +03:00
gdlbo 34f49a9b42 fixed rename in wall 2024-03-29 15:12:56 +03:00
gdlbo 84ad75e948 fixed disabler for playlist catalog 2024-03-29 13:45:28 +03:00
gdlbo e049b5f989 Update OEMDetector.java 2024-03-29 13:41:55 +03:00
Artur Skubei 5de52ed6b5 Rename Profiles/Groups v2 (#1596) 2024-03-29 13:38:30 +03:00
gdlbo 46c4f1c6dc hyperos support + gms refactored 2024-03-29 13:37:25 +03:00
gdlbo 126f5259d1 fixes 2024-03-29 10:47:18 +03:00
gdlbo 2d1867197f fixes of sponsorpost sdk
also added force update of filters
2024-03-28 22:20:07 +03:00
gdlbo c1d4216416 music stats catalog disabler 2024-03-28 20:16:39 +03:00
gdlbo 0f45a8d175 Update strings.xml 2024-03-28 20:10:08 +03:00
gdlbo 15ed01b4d3 fixed cache playlist shuffle 2024-03-28 20:05:10 +03:00
aliveoutside 41763a4b54 master.m3u8 fix 2024-03-26 22:59:32 +03:00
gdlbo d98d81f105 fixed autocache text dialog with dark theme 2024-03-26 17:47:10 +03:00
Artur Skubei 899554a571 Music autocaching v2 (#1591) 2024-03-26 17:36:34 +03:00
21 changed files with 403 additions and 232 deletions
@@ -11,37 +11,37 @@ import com.vtosters.lite.R;
import ru.vtosters.lite.utils.AndroidUtils;
public class GmsHook {
private static final boolean needToSpoof = !isGmsInstalled() && (isFakeGmsInstalled() || isFakeGms2Installed());
private static final String[] spoofPackages = {"com.mgoogle", "app.revanced"};
private static final String currentGms;
static {
currentGms = getSpoofPackagePrefix();
}
private static boolean isPackageInstalled(String packageName) {
try {
AndroidUtils.getGlobalContext().getPackageManager().getPackageInfo(packageName, 0);
return true;
} catch (Exception unused) {
return false;
}
}
public static boolean isGmsInstalled() {
try {
AndroidUtils.getGlobalContext().getPackageManager().getPackageInfo("com.google.android.gms", 0);
return true;
} catch (Exception unused) {
return false;
}
} // Google Market Services check
return isPackageInstalled("com.google.android.gms");
}
public static boolean isFakeGmsInstalled() {
try {
AndroidUtils.getGlobalContext().getPackageManager().getPackageInfo("com.mgoogle.android.gms", 0);
return true;
} catch (Exception unused) {
return false;
}
} // Microg Google Market Services check
public static boolean isFakeGms2Installed() {
try {
AndroidUtils.getGlobalContext().getPackageManager().getPackageInfo("app.revanced.android.gms", 0);
return true;
} catch (Exception unused) {
return false;
}
} // Microg Google Market Services check
public static boolean isSpoofPackageInstalled(String packageName) {
return isPackageInstalled(packageName + ".android.gms");
}
public static boolean isAnyServicesInstalled() {
return isGmsInstalled() || isFakeGmsInstalled() || isFakeGms2Installed();
for (String packageName : spoofPackages) {
if (isSpoofPackageInstalled(packageName)) {
return true;
}
}
return false;
}
public static void fixGapps() {
@@ -52,10 +52,10 @@ public class GmsHook {
notificationManager.createNotificationChannel(new NotificationChannel("audio_playback_channel", AndroidUtils.getResources().getString(R.string.audio_message_play_error), NotificationManager.IMPORTANCE_LOW));
}
}
} // Music channels fix
}
public static String replaceGMSPackage(String str) {
return needToSpoof ? str.replaceAll("com.google", (isFakeGms2Installed() ? "app.revanced" : "com.mgoogle")) : str;
return shouldSpoof() ? str.replaceAll("com.google", currentGms) : str;
}
public static String getFirebaseInstanceIdReceiver() {
@@ -63,6 +63,37 @@ public class GmsHook {
}
public static Class getFirebaseInstanceIdReceiverClass() {
return needToSpoof ? (isFakeGms2Installed() ? FirebaseInstanceIdReceiver3.class : FirebaseInstanceIdReceiver2.class) : FirebaseInstanceIdReceiver.class;
return getSpoofFirebaseInstanceIdReceiverClass();
}
}
public static String getCurrentGms() {
return currentGms;
}
private static boolean shouldSpoof() {
return !isGmsInstalled() && (isSpoofPackageInstalled("com.mgoogle") || isSpoofPackageInstalled("app.revanced"));
}
private static String getSpoofPackagePrefix() {
for (String packageName : spoofPackages) {
if (isSpoofPackageInstalled(packageName)) {
return packageName;
}
}
return "com.google";
}
private static Class getSpoofFirebaseInstanceIdReceiverClass() {
switch (currentGms) {
case "com.mgoogle" -> {
return FirebaseInstanceIdReceiver2.class;
}
case "app.revanced" -> {
return FirebaseInstanceIdReceiver3.class;
}
default -> {
return FirebaseInstanceIdReceiver.class;
}
}
}
}
@@ -1,29 +1,40 @@
package ru.vtosters.hooks;
import androidx.core.util.Pair;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.utils.RenameTool;
public class RenameHook {
public static void injectIntoJson(JSONObject obj) throws JSONException {
// int i = obj.getInt("id");
// if (RenameTool.updateRequested) {
// RenameTool.reloadDB();
// }
//
// Pair<String, String> user = RenameTool.renamedUsers.get(i);
// if (user == null) return;
// obj.put(RenameTool.COLUMN_FIRSTNAME, user.first).put(RenameTool.COLUMN_LASTNAME, user.second);
if (isEnabled()) {
int i = obj.getInt("id");
if (RenameTool.updateRequested) {
RenameTool.reloadDB();
}
Pair<String, String> user = RenameTool.renamedUsers.get(i);
if (user == null) return;
obj.put(RenameTool.COLUMN_FIRSTNAME, user.first).put(RenameTool.COLUMN_LASTNAME, user.second);
}
}
public static boolean isEnabled() {
return Preferences.getBoolValue("unstableNameChanger", true);
}
public static void injectIntoJsonGroup(JSONObject obj) throws JSONException {
// int i = obj.getInt("id");
//
// if (RenameTool.updateRequested) {
// RenameTool.reloadDB();
// }
//
// String user = RenameTool.renamedGroups.get(i);
// if (user == null) return;
// obj.put("name", user);
if (isEnabled()) {
int i = obj.getInt("id");
if (RenameTool.updateRequested) {
RenameTool.reloadDB();
}
String user = RenameTool.renamedGroups.get(i);
if (user == null) return;
obj.put("name", user);
}
}
}
@@ -42,11 +42,13 @@ public class CatalogJsonInjector {
removeUnsupportedLayouts(blocks);
fetchCatalogId("https://vk.com/audio?section=my_playlists", oldItems);
if (Preferences.getBoolValue("playlistsCatalogs", true)) {
fetchCatalogId("https://vk.com/audio?section=my_playlists", oldItems);
fetchCatalogId("https://vk.com/audio?section=albums", oldItems);
fetchCatalogId("https://vk.com/audio?section=albums", oldItems);
}
if (Preferences.sendMusicMetrics()) {
if (Preferences.sendMusicMetrics() && Preferences.getBoolValue("playStatCatalog", false)) {
fetchCatalogId("https://vk.com/audio?section=recent", oldItems);
}
@@ -15,6 +15,7 @@ import ru.vtosters.lite.downloaders.AudioDownloader;
import ru.vtosters.lite.music.cache.MusicCacheImpl;
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
import ru.vtosters.lite.utils.AccountManagerUtils;
import java.util.ArrayList;
import java.util.List;
@@ -36,8 +37,10 @@ public class PlaylistInjector {
public static Observable<AudioGetPlaylist.c> injectGetPlaylist(AudioGetPlaylist audioGetPlaylist) {
try {
if (MusicCacheImpl.isEmpty())
if (MusicCacheImpl.isEmpty()) {
return null;
}
var requestArgs = audioGetPlaylist.b();
var id = requestArgs.get("id");
@@ -45,9 +48,11 @@ public class PlaylistInjector {
var accessKey = requestArgs.get("access_key");
boolean isVirtualPlaylist = accessKey != null && (accessKey.equals("cache"));
boolean isAlbumVirtualPlaylist = accessKey != null && (accessKey.equals("cacheAlbum"));
boolean isOwnCachePlaylist = Objects.equals(ownerId, String.valueOf(AccountManagerUtils.getUserId())) && Objects.equals(id, "-1");
if (TextUtils.isEmpty(id) || (!isVirtualPlaylist && !isAlbumVirtualPlaylist))
if (TextUtils.isEmpty(id) || (!isVirtualPlaylist && !isAlbumVirtualPlaylist)) {
return null;
}
return Observable.a((ObservableOnSubscribe<AudioGetPlaylist.c>) observableEmitter -> {
AudioGetPlaylist.c response = new AudioGetPlaylist.c();
@@ -81,13 +86,11 @@ public class PlaylistInjector {
return;
}
response.c = (ArrayList<MusicTrack>) MusicCacheImpl.getPlaylistSongs(ownerId, id);
Log.d("Playlist", "Open playlist " + ownerId + "_" + id);
if (Objects.equals(id, "-1")) {
if (isOwnCachePlaylist) {
response.c = (ArrayList<MusicTrack>) TracklistHelper.getMyCachedMusicTracks();
response.b = PlaylistHelper.createCachedPlaylistMetadata();
} else {
response.c = (ArrayList<MusicTrack>) MusicCacheImpl.getPlaylistSongs(ownerId, id);
response.b = MusicCacheImpl.getPlaylist(id, ownerId);
}
@@ -42,7 +42,7 @@ public class TracklistInjector {
Log.d("TracklistInjector", "Using vkx cache catalog");
observableEmitter.b(parser.c(new JSONObject(service.getCacheCatalog())));
} catch (Exception e) {
e.printStackTrace();
e.fillInStackTrace();
List<MusicTrack> tracks = new ArrayList<>();
List<String> cache = service.getCache();
@@ -55,16 +55,14 @@ public class TracklistInjector {
observableEmitter.b(parser.c(createVirtualCatalog(tracks)));
}
} catch (Exception e) {
e.printStackTrace();
e.fillInStackTrace();
}
});
} else {
if (MusicCacheImpl.isEmpty()) {
observableEmitter.b(parser.c(getEmptyCatalog()));
} else {
observableEmitter.b(parser.c(createVirtualCatalog(
PlaylistCacheDbDelegate.getTracksInPlaylist(AndroidUtils.getGlobalContext(),
AccountManagerUtils.getUserId() + "_-1"))));
observableEmitter.b(parser.c(createVirtualCatalog(TracklistHelper.getMyCachedMusicTracks())));
}
}
});
@@ -115,7 +115,7 @@ public class Device {
+ "- Manufacturer: " + this.manufacturerName + "\n"
+ "- Brand: " + this.brandName + "\n"
+ "- Model: " + this.modelName + "\n"
+ (isMIUI() ? "- Miui Version Code: " + this.MiuiUiVersionCode + "\n" + "- Miui Version Name: " + this.MiuiUiVersionName + "\n" : "")
+ (isMIUI() || isHyperOs() ? "- Miui/HyperOS Version Code: " + this.MiuiUiVersionCode + "\n" + "- Miui/HyperOS Version Name: " + this.MiuiUiVersionName + "\n" : "")
+ (isSamsung() ? "- OneUi Major Version: " + this.OneUiMajorVersion + "\n" + "- OneUi Minor Version: " + this.OneUiMinorVersion + "\n" : "")
+ (hasMiuiIncrCode() ? "- Miui Version Incremental Code: " + this.MiuiIncrementalCode + "\n" : "")
+ (isEMUI() ? "- Emui Version: " + this.EmuiVersion : "");
@@ -56,7 +56,7 @@ public class OEMDetector {
}
public static boolean isOEM() {
return isMIUI() || isEMUI() || isFlyme() || isZenUI() || isSamsung() || isVivo() || isOneUi();
return isMIUI() || isEMUI() || isFlyme() || isZenUI() || isSamsung() || isVivo() || isOneUi() || isHyperOs();
}
public static boolean isMIUI() {
@@ -68,6 +68,15 @@ public class OEMDetector {
}
}
public static boolean isHyperOs() {
try {
int miuiVer = Integer.parseInt(getMiuiUiVersionCode()); // cuz hyperos gives 816 and etc
return miuiVer > 14 && isMIUI();
} catch (Exception unused) {
return false;
}
}
public static boolean isIntentResolved(Context ctx, Intent intent) {
return (intent != null && ctx.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null);
}
@@ -124,7 +133,6 @@ public class OEMDetector {
try {
return (String) getPropMtd.invoke(null, prop);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
@@ -8,9 +8,11 @@ import com.google.android.exoplayer2.source.hls.playlist.e;
import com.google.android.exoplayer2.source.hls.playlist.f;
import com.google.android.exoplayer2.source.hls.playlist.f.a;
import com.vk.dto.music.MusicTrack;
import com.vk.dto.music.Playlist;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;
@@ -20,7 +22,6 @@ import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.vk.dto.music.Playlist;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.music.converter.ts.MpegDemuxer;
import ru.vtosters.lite.music.interfaces.Callback;
@@ -37,17 +38,29 @@ public final class Mp3Downloader implements ITrackDownloader {
@Override
public void download(MusicTrack track, Callback callback, Playlist playlist) {
String uri = track.D;
if (Objects.requireNonNull(uri).isEmpty()) {
String msg = "link error: " + track.y1() + ", title: " + Mp3Downloader.getTitle(track);
Log.d("Mp3Downloader", msg);
throw new RuntimeException(msg);
}
var tsParser = new com.google.android.exoplayer2.source.hls.playlist.h(e.a(track.D));
var baseUri = track.D.substring(0, track.D.lastIndexOf("/") + 1);
if (Objects.requireNonNull(uri).contains("master.m3u8?siren=1")) {
try {
String content = IOUtils.readAllLines(new URL(uri).openStream());
String replacement = content.split("\n")[2].trim();
uri = uri.replace("master.m3u8?siren=1", replacement);
} catch (IOException e) {
callback.onFailure(e);
return;
}
}
var tsParser = new com.google.android.exoplayer2.source.hls.playlist.h(e.a(uri));
var baseUri = uri.substring(0, uri.lastIndexOf("/") + 1);
try {
var segments = ((f) tsParser.a(Uri.parse(baseUri), IOUtils.openStream(track.D))).o;
var segments = ((f) tsParser.a(Uri.parse(baseUri), IOUtils.openStream(uri))).o;
byte[] buff = getMergedTs(baseUri, segments, callback);
MpegDemuxer.convert(buff, outputFile.getAbsolutePath());
@@ -10,7 +10,7 @@ import ru.vtosters.lite.utils.NavigatorUtils;
public class InstallGMS {
public static void alert(final Activity activity) {
if (!GmsHook.isAnyServicesInstalled() && Preferences.getBoolValue("showAlertGms", true)) {
if (!GmsHook.isAnyServicesInstalled() && !GmsHook.isGmsInstalled() && Preferences.getBoolValue("showAlertGms", true)) {
new VkAlertDialog.Builder(activity)
.setTitle(activity.getString(R.string.warning))
.setMessage(activity.getString(R.string.gmsissuesumm))
@@ -3,10 +3,12 @@ package ru.vtosters.lite.ui.fragments;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.dto.music.Playlist;
@@ -26,6 +28,9 @@ import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
import static ru.vtosters.hooks.other.ThemesUtils.getTextAttr;
public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
private static final ExecutorService executor = Executors.newCachedThreadPool();
@@ -104,7 +109,14 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
preference -> {
List<String> items = Arrays.asList("Не кешировать", "Только свои", "Все");
ArrayAdapter<String> adapter = new ArrayAdapter<>(requireContext(), android.R.layout.simple_list_item_1, items);
ArrayAdapter<String> adapter = new ArrayAdapter<>(requireContext(), android.R.layout.simple_list_item_1, items) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView = (TextView) super.getView(position, convertView, parent);
textView.setTextColor(getTextAttr());
return textView;
}
};
int selectedItem = Preferences.getPreferences().getInt("autocaching", 0);
if (selectedItem >= 0 && selectedItem < items.size()) {
@@ -207,6 +219,19 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
}
);
PreferenceFragmentUtils.addMaterialSwitchPreference(
getPreferenceScreen(),
"playStatCatalog",
"Список истории прослушиваний",
"Показывать вкладку истории прослушиваний в музыкальном разделе\n\nОтключение ускорит открытие музыкального раздела при медленном интернете",
null,
false,
(preference, o) -> {
Preferences.getPreferences().edit().putBoolean("playStatCatalog", (boolean) o).apply();
return true;
}
).setVisible(Preferences.sendMusicMetrics() && !getBoolValue("useOldAppVer", false));
if (!Preferences.serverFeaturesDisable()) {
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Интеграция Genius");
PreferenceFragmentUtils.addMaterialSwitchPreference(
@@ -314,6 +339,19 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
list.setVisible(!Preferences.getBoolValue("useOldAppVer", false));
getPreferenceScreen().addPreference(list);
PreferenceFragmentUtils.addMaterialSwitchPreference(
getPreferenceScreen(),
"playlistsCatalogs",
"Списки плейлистов",
"Показывать вкладку плейлистов и альбомов прослушиваний в музыкальном разделе\n\nОтключение ускорит открытие музыкального раздела при медленном интернете",
null,
true,
(preference, o) -> {
Preferences.getPreferences().edit().putBoolean("playlistsCatalogs", (boolean) o).apply();
return true;
}
).setVisible(!getBoolValue("useOldAppVer", false));
}
private void lastfmAuth(Context ctx) {
@@ -60,12 +60,12 @@ public class OtherFragment extends TrackedMaterialPreferenceToolbarFragment {
return true;
});
findPreference("microgsettings").setVisible(GmsHook.isFakeGmsInstalled() && !GmsHook.isGmsInstalled());
findPreference("microgsettings").setVisible(GmsHook.isAnyServicesInstalled() && !GmsHook.isGmsInstalled());
findPreference("microgsettings").setOnPreferenceClickListener(preference -> {
try {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName((GmsHook.isFakeGms2Installed() ? "app.revanced.android.gms" : "com.mgoogle.android.gms"), "org.microg.gms.ui.SettingsActivity"));
intent.setComponent(new ComponentName(GmsHook.getCurrentGms() + ".android.gms", "org.microg.gms.ui.SettingsActivity"));
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
@@ -81,6 +81,17 @@ public class OtherFragment extends TrackedMaterialPreferenceToolbarFragment {
return true;
});
findPreference("unstableNameChangerDrop").setOnPreferenceClickListener(preference -> {
RenameTool.clearDatabase();
LifecycleUtils.restartApplicationWithTimer();
return true;
});
findPreference("unstableNameChanger").setOnPreferenceChangeListener((preference, o) -> {
LifecycleUtils.restartApplicationWithTimer();
return true;
});
findPreference("copydebuginfo").setOnPreferenceClickListener(preference -> {
copyText(new DeviceInfoCollector().collect().forLogging());
Toast.makeText(requireContext(), AndroidUtils.getString("device_info_copied"), Toast.LENGTH_SHORT).show();
@@ -227,6 +227,23 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
}
);
if (NetworkUtils.isNetworkConnected()) {
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
"Обновить списки фильтров",
null,
null,
preference -> {
this.requireActivity().runOnUiThread(() -> {
FiltersPreferences.forceUpdateFilters();
AndroidUtils.sendToast("Обновлено");
});
return false;
}
);
}
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
@@ -13,6 +13,8 @@ import ru.vtosters.lite.ui.PreferenceFragmentUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.VersionReader;
import static ru.vtosters.hooks.GmsHook.isSpoofPackageInstalled;
public class SystemInfo extends TrackedMaterialPreferenceToolbarFragment {
@Override
@@ -46,11 +48,11 @@ public class SystemInfo extends TrackedMaterialPreferenceToolbarFragment {
boolean isZenUI = OEMDetector.isZenUI();
boolean isEMUI = OEMDetector.isEMUI();
boolean hasMiuiIncrCode = OEMDetector.hasMiuiIncrCode();
boolean isHyperOS = OEMDetector.isHyperOs();
boolean hasGMS = GmsHook.isGmsInstalled();
boolean hasVancedMicroG = GmsHook.isFakeGmsInstalled();
boolean hasReVancedMicroG = GmsHook.isFakeGms2Installed();
String GMSPackageName = hasGMS ? "com.google.android.gms" : hasVancedMicroG ? "com.mgoogle.android.gms" : hasReVancedMicroG ? "app.revanced.android.gms" : "no gms or microg";
boolean hasVancedMicroG = GmsHook.isAnyServicesInstalled();
String GMSPackageName = hasGMS ? "com.google.android.gms" : hasVancedMicroG ? GmsHook.getCurrentGms() + ".android.gms" : "no gms or microg";
boolean isValidSignature = Preferences.isValidSignature();
boolean isTablet = AndroidUtils.isTablet();
@@ -104,9 +106,7 @@ public class SystemInfo extends TrackedMaterialPreferenceToolbarFragment {
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "isInstalledGoogleGMS", "Value: " + hasGMS, 0, null);
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "isInstalledVancedMicroG", "Value: " + hasVancedMicroG, 0, null);
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "isInstalledReVancedMicroG", "Value: " + hasReVancedMicroG, 0, null);
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "isInstalledMicroG", "Value: " + hasVancedMicroG, 0, null);
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "Product Name", productName, 0, preference -> {
((ClipboardManager) requireActivity().getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("MBH-ST", productName));
@@ -194,6 +194,8 @@ public class SystemInfo extends TrackedMaterialPreferenceToolbarFragment {
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "isMiui", "Value: " + isMiui, 0, null);
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "isHyperOS", "Value: " + isHyperOS, 0, null);
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "isEMUI", "Value: " + isEMUI, 0, null);
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", "isFlyme", "Value: " + isFlyme, 0, null);
@@ -108,7 +108,7 @@ public class VTSettings extends TrackedMaterialPreferenceToolbarFragment {
boolean isLinksUnverified = AndroidUtils.isLinksUnverified(requireActivity());
boolean isDozingAvailable = Build.VERSION.SDK_INT >= 23 && !manager.isIgnoringBatteryOptimizations(AndroidUtils.getPackageName());
boolean areNotificationsDisabled = !AndroidUtils.areNotificationsEnabled() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
boolean isGMSNotInstalled = !GmsHook.isAnyServicesInstalled();
boolean isGMSNotInstalled = !GmsHook.isAnyServicesInstalled() && !GmsHook.isGmsInstalled();
if (AccountManagerUtils.isLogin()) {
Preference accountSwitcher = PreferenceFragmentUtils.addPreference(
@@ -584,7 +584,7 @@ public class VTSettings extends TrackedMaterialPreferenceToolbarFragment {
}
);
if (Build.VERSION.SDK_INT >= 33 && !OEMDetector.isMIUI()) {
if (Build.VERSION.SDK_INT >= 33 && (!OEMDetector.isMIUI() || OEMDetector.isHyperOs())) {
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
@@ -14,10 +14,12 @@ import com.vtosters.lite.api.ExtendedCommunityProfile;
import com.vtosters.lite.api.ExtendedUserProfile;
import kotlin.Unit;
import kotlin.jvm.b.Functions;
import ru.vtosters.hooks.RenameHook;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.foaf.FoafBase;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.RenameTool;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -66,10 +68,12 @@ public class MenuBuilder {
return Unit.a;
});
// addItem(builder, AndroidUtils.getString(R.string.menu_change_name), () -> {
// RenameTool.createDialog(eup, ctx);
// return Unit.a;
// });
if (RenameHook.isEnabled()) {
addItem(builder, AndroidUtils.getString(R.string.menu_change_name), () -> {
RenameTool.createDialog(eup, ctx);
return Unit.a;
});
}
addItem(builder, AndroidUtils.getString(isPageWhitelistedFilter ? R.string.remove_from_filter_whitelist : R.string.add_to_filter_whitelist), () -> {
setWhitelistedFilter(eup, !isPageWhitelistedFilter);
@@ -83,7 +87,7 @@ public class MenuBuilder {
return Unit.a;
});
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
e.fillInStackTrace();
}
}
@@ -100,10 +104,12 @@ public class MenuBuilder {
return Unit.a;
});
// addItem(builder, AndroidUtils.getString(R.string.menu_change_name), () -> {
// RenameTool.createDialogGroup(ecp, ctx);
// return Unit.a;
// });
if (RenameHook.isEnabled()) {
addItem(builder, AndroidUtils.getString(R.string.menu_change_name), () -> {
RenameTool.createDialogGroup(ecp, ctx);
return Unit.a;
});
}
addItem(builder, AndroidUtils.getString(isPageWhitelistedFilter ? R.string.remove_from_filter_whitelist : R.string.add_to_filter_whitelist), () -> {
setWhitelistedFilter(ecp, !isPageWhitelistedFilter);
@@ -123,7 +129,7 @@ public class MenuBuilder {
return Unit.a;
});
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
e.fillInStackTrace();
}
}
@@ -1,5 +1,6 @@
package ru.vtosters.lite.utils;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
@@ -12,15 +13,15 @@ import android.widget.LinearLayout;
import androidx.core.util.Pair;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.dto.user.UserProfile;
import com.vk.im.engine.models.users.User;
import com.vtosters.lite.R;
import com.vtosters.lite.api.ExtendedCommunityProfile;
import com.vtosters.lite.api.ExtendedUserProfile;
import ru.vtosters.hooks.other.ThemesUtils;
import java.lang.reflect.Field;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.function.BiConsumer;
import static ru.vtosters.hooks.other.ThemesUtils.getSTextAttr;
import static ru.vtosters.hooks.other.ThemesUtils.getTextAttr;
@@ -47,69 +48,40 @@ public class RenameTool {
return helperInstance;
}
public static String getCurrentModifiedUser() {
Cursor rawQuery = getHelper().getReadableDatabase().rawQuery(String.format("SELECT * FROM %s WHERE %s=%s", TABLE_NAME, COLUMN_VKID, AccountManagerUtils.getUserId()), new String[0]);
if (rawQuery.moveToFirst()) {
try {
String decode = URLDecoder.decode(rawQuery.getString(rawQuery.getColumnIndexOrThrow(COLUMN_FIRSTNAME)), "UTF-8");
return decode + " " + URLDecoder.decode(rawQuery.getString(rawQuery.getColumnIndexOrThrow(COLUMN_LASTNAME)), "UTF-8");
} catch (java.io.UnsupportedEncodingException | java.lang.IllegalArgumentException e) {
e.printStackTrace();
} finally {
rawQuery.close();
}
} else rawQuery.close();
return null;
}
// Reload all values from DB
public static void reloadDB() {
renamedGroups.clear();
renamedUsers.clear();
updateRequested = false;
try (Cursor cursor = getHelper().getReadableDatabase().rawQuery(String.format("SELECT * FROM %s", TABLE_NAME), new String[0])) {
while (cursor.moveToNext()) {
String firstName = URLDecoder.decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_FIRSTNAME)), "UTF-8");
String lastName = URLDecoder.decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_LASTNAME)), "UTF-8");
int vkID = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_VKID));
renamedUsers.put(vkID, new Pair<>(firstName, lastName));
}
} catch (Exception e) {
e.printStackTrace();
}
loadData(TABLE_NAME, (cursor, vkID) -> {
String firstName = decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_FIRSTNAME)));
String lastName = decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_LASTNAME)));
renamedUsers.put(vkID, new Pair<>(firstName, lastName));
});
try (Cursor cursor = getHelper().getReadableDatabase().rawQuery(String.format("SELECT * FROM %s", TABLE_NAME_GROUP), new String[0])) {
loadData(TABLE_NAME_GROUP, (cursor, vkID) -> {
String name = decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME)));
renamedGroups.put(vkID, name);
});
}
// Generic method to load data from the database
private static void loadData(String tableName, BiConsumer<Cursor, Integer> consumer) {
try (Cursor cursor = getHelper().getReadableDatabase().rawQuery("SELECT * FROM " + tableName, null)) {
while (cursor.moveToNext()) {
String name = URLDecoder.decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME)), "UTF-8");
int vkID = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_VKID));
renamedGroups.put(vkID, name);
consumer.accept(cursor, vkID);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to load data from " + tableName, e);
}
}
public static void injectIntoChat(User u) {
int id = u.getId();
if (updateRequested) {
reloadDB();
}
Pair<String, String> user = renamedUsers.get(id);
if (user == null) return;
setObject(u, "I", user.first);
setObject(u, "J", user.second);
}
public static void setObject(User instance, String name, Object obj) {
private static String decode(String value) {
try {
Field f = User.class.getDeclaredField(name);
f.setAccessible(true);
f.set(instance, obj);
} catch (Exception e) {
e.printStackTrace();
return URLDecoder.decode(value, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 encoding not supported", e);
}
}
@@ -117,7 +89,7 @@ public class RenameTool {
LinearLayout linearLayout = new LinearLayout(ctx);
linearLayout.setOrientation(LinearLayout.VERTICAL);
final EditText fn = new EditText(ctx);
EditText fn = new EditText(ctx);
fn.setHint(R.string.vk_auth_sign_up_first_name);
fn.setTextColor(getTextAttr());
fn.setHintTextColor(getSTextAttr());
@@ -128,7 +100,7 @@ public class RenameTool {
margin.setMargins(dp2px(20f), 0, dp2px(20f), 0);
fn.setLayoutParams(margin);
final EditText ln = new EditText(ctx);
EditText ln = new EditText(ctx);
ln.setHint(R.string.vk_auth_sign_up_last_name);
ln.setTextColor(getTextAttr());
ln.setHintTextColor(getSTextAttr());
@@ -137,69 +109,93 @@ public class RenameTool {
ln.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
ln.setLayoutParams(margin);
final UserProfile profile = AccountManagerUtils.fromEup(eup);
UserProfile profile = AccountManagerUtils.fromEup(eup);
fn.setText(AccountManagerUtils.getUserFirstName(profile));
ln.setText(AccountManagerUtils.getUserLastName(profile));
int id = AccountManagerUtils.getUserID(profile);
var builder = new VkAlertDialog.Builder(ctx)
VkAlertDialog.Builder builder = new VkAlertDialog.Builder(ctx)
.setTitle(R.string.rename_title)
.setMessage(R.string.rename_message)
.setView(linearLayout)
.setPositiveButton("OK", (dialog, which) -> {
String firstName = fn.getText().toString();
String lastName = ln.getText().toString();
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
try {
if (isChangedName(id)) {
writableDatabase.execSQL(
String.format("UPDATE %s SET %s='%s', %s='%s' WHERE %s='%s'",
TABLE_NAME,
COLUMN_FIRSTNAME, URLEncoder.encode(firstName, "UTF-8"),
COLUMN_LASTNAME, URLEncoder.encode(lastName, "UTF-8"),
COLUMN_VKID, id));
} else {
writableDatabase.execSQL(
String.format("INSERT INTO %s (%s, %s, %s) VALUES (%s, '%s', '%s')",
TABLE_NAME,
COLUMN_VKID, COLUMN_FIRSTNAME, COLUMN_LASTNAME,
id, URLEncoder.encode(firstName, "UTF-8"), URLEncoder.encode(lastName, "UTF-8")));
}
updateRequested = true;
if (id == AccountManagerUtils.getUserId()) {
ctx.sendBroadcast(new Intent("com.vkontakte.android.USER_NAME_CHANGED"));
}
ctx.sendBroadcast(new Intent("com.vkontakte.android.ACTION_PROFILE_UPDATED").putExtra("uid", id));
.setPositiveButton("OK", (dialog, which) -> updateName(ctx, fn.getText().toString(), ln.getText().toString(), id));
if (isChangedName(id)) {
builder.setNeutralButton(R.string.rename_reset, (dialog, which) -> deleteUser(ctx, id));
}
sendToast(ctx.getString(R.string.rename_success));
} catch (Exception e) {
e.printStackTrace();
sendToast(ctx.getString(R.string.rename_error));
}
});
if (isChangedName(id))
builder.setNeutralButton(R.string.rename_reset, (dialog, which) -> {
getHelper().getWritableDatabase().execSQL(
String.format(
"DELETE FROM %s WHERE %s='%s'",
TABLE_NAME,
COLUMN_VKID, id));
if (id == AccountManagerUtils.getUserId()) {
ctx.sendBroadcast(new Intent("com.vkontakte.android.USER_NAME_CHANGED"));
}
updateRequested = true;
ctx.sendBroadcast(new Intent("com.vkontakte.android.ACTION_PROFILE_UPDATED").putExtra("uid", id));
sendToast(ctx.getString(R.string.rename_remove_from_bd_success));
});
builder.show();
}
public static void deleteUser(Context ctx, int id) {
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
writableDatabase.delete(TABLE_NAME, COLUMN_VKID + "=?", new String[]{String.valueOf(id)});
updateRequested = true;
notifyUser(ctx, id);
sendToast(ctx.getString(R.string.rename_remove_from_bd_success));
}
public static void clearDatabase() {
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
writableDatabase.delete(TABLE_NAME, null, null);
writableDatabase.delete(TABLE_NAME_GROUP, null, null);
renamedGroups.clear();
renamedUsers.clear();
updateRequested = true;
}
public static void updateName(Context ctx, String firstName, String lastName, int id) {
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
try {
ContentValues values = new ContentValues();
values.put(COLUMN_FIRSTNAME, encode(firstName));
values.put(COLUMN_LASTNAME, encode(lastName));
if (isChangedName(id)) {
// Update existing record
writableDatabase.update(TABLE_NAME, values, COLUMN_VKID + "=?", new String[]{String.valueOf(id)});
} else {
// Insert new record
values.put(COLUMN_VKID, id);
writableDatabase.insert(TABLE_NAME, null, values);
}
updateRequested = true;
notifyUser(ctx, id);
sendToast(ctx.getString(R.string.rename_success));
} catch (Exception e) {
throw new RuntimeException("Database operation failed", e);
}
}
private static String encode(String value) {
try {
return URLEncoder.encode(value, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 encoding not supported", e);
}
}
private static void notifyUser(Context ctx, int id) {
if (id == AccountManagerUtils.getUserId()) {
ctx.sendBroadcast(new Intent("com.vkontakte.android.USER_NAME_CHANGED"));
}
ctx.sendBroadcast(new Intent("com.vkontakte.android.ACTION_PROFILE_UPDATED").putExtra("uid", id));
}
public static void createDialogGroup(ExtendedCommunityProfile eup, final Context ctx) {
LinearLayout linearLayout = new LinearLayout(ctx);
linearLayout.setOrientation(LinearLayout.VERTICAL);
final EditText fn = new EditText(ctx);
EditText fn = new EditText(ctx);
fn.setHint(R.string.vk_auth_sign_up_first_name);
fn.setHintTextColor(getSTextAttr());
fn.setTextColor(getTextAttr());
@@ -210,52 +206,61 @@ public class RenameTool {
margin.setMargins(dp2px(20f), 0, dp2px(20f), 0);
fn.setLayoutParams(margin);
final UserProfile profile = AccountManagerUtils.fromEup(eup);
UserProfile profile = AccountManagerUtils.fromEup(eup);
fn.setText(AccountManagerUtils.getGroupName(profile));
int fid = AccountManagerUtils.getUserID(profile);
if (fid < 0) fid = -fid;
final int id = fid;
int id = fid;
var builder = new VkAlertDialog.Builder(ctx)
VkAlertDialog.Builder builder = new VkAlertDialog.Builder(ctx)
.setTitle(R.string.rename_title)
.setMessage(R.string.rename_message)
.setView(linearLayout)
.setPositiveButton("OK", (dialog, which) -> {
String firstName = fn.getText().toString();
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
try {
if (isChangedNameGroup(id)) {
writableDatabase.execSQL(
String.format(
"UPDATE %s SET %s='%s' WHERE %s='%s'",
TABLE_NAME_GROUP,
COLUMN_NAME, URLEncoder.encode(firstName, "UTF-8"),
COLUMN_VKID, id));
} else {
writableDatabase.execSQL(
String.format(
"INSERT INTO %s (%s, %s) VALUES (%s, '%s')",
TABLE_NAME_GROUP,
COLUMN_VKID, COLUMN_NAME,
id, URLEncoder.encode(firstName, "UTF-8")));
}
updateRequested = true;
sendToast(AndroidUtils.getString(R.string.rename_group_success));
} catch (Exception e) {
e.printStackTrace();
}
});
if (isChangedNameGroup(id))
builder.setNeutralButton(R.string.rename_reset, (dialog, which) -> {
getHelper().getWritableDatabase().execSQL(String.format("DELETE FROM %s WHERE %s='%s'", TABLE_NAME_GROUP, COLUMN_VKID, id));
updateRequested = true;
sendToast(ctx.getString(R.string.rename_remove_group_from_bd_success));
});
.setPositiveButton("OK", (dialog, which) -> updateGroupName(ctx, fn.getText().toString(), id));
if (isChangedNameGroup(id)) {
builder.setNeutralButton(R.string.rename_reset, (dialog, which) -> deleteGroupName(ctx, id));
}
builder.show();
}
public static void deleteGroupName(Context ctx, int id) {
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
writableDatabase.delete(TABLE_NAME_GROUP, COLUMN_VKID + "=?", new String[]{String.valueOf(id)});
updateRequested = true;
sendToast(ctx.getString(R.string.rename_remove_group_from_bd_success));
}
public static void updateGroupName(Context ctx, String groupName, int id) {
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
try {
ContentValues values = new ContentValues();
values.put(COLUMN_NAME, encode(groupName));
if (isChangedNameGroup(id)) {
// Update existing record
writableDatabase.update(TABLE_NAME_GROUP, values, COLUMN_VKID + "=?", new String[]{String.valueOf(id)});
} else {
// Insert new record
values.put(COLUMN_VKID, id);
writableDatabase.insert(TABLE_NAME_GROUP, null, values);
}
updateRequested = true;
sendToast(AndroidUtils.getString(R.string.rename_group_success));
} catch (Exception e) {
throw new RuntimeException("Database operation failed", e);
}
}
public static boolean isChangedName(int uid) {
return renamedUsers.get(uid) != null;
}
@@ -264,10 +269,6 @@ public class RenameTool {
return renamedGroups.get(uid) != null;
}
public static boolean isIdInList(UserProfile profile) {
return true;
}
private static class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
@@ -61,6 +61,18 @@ public class FiltersPreferences {
editor.apply();
}
public static void forceUpdateFilters() {
SharedPreferences.Editor editor = preferences.edit();
preferences.getAll().keySet().stream()
.filter(key -> key.endsWith(":" + PREF_KEY_VERSION))
.forEach(key -> editor.putString(key, "0"));
editor.apply();
Updates.updateFilters();
}
public static boolean getSavedKeyValue(int id) {
return getFilter(id) != null;
}
@@ -1,5 +1,6 @@
package ru.vtosters.sponsorpost.utils;
import android.util.Log;
import ru.vtosters.lite.utils.NetworkUtils;
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
import ru.vtosters.sponsorpost.data.Filter;
@@ -31,14 +32,17 @@ public class Updates {
for (Filter filter : filters) {
Filter localFilter = findLocalFilterById(localFilters, filter.getId());
if (localFilter == null) {
Log.d("Updates", "local filter is not exist, adding new: " + filter.getId());
FiltersPreferences.saveFilter(filter);
} else {
String remoteVersion = filter.getVersion();
String localVersion = localFilter.getVersion();
if (Objects.equals(remoteVersion, localVersion)) {
FiltersPreferences.saveFilter(filter);
} else {
Log.d("Updates", "saved local filter: " + localFilter.getId());
FiltersPreferences.saveFilter(localFilter);
} else {
Log.d("Updates", "saved remote filter: " + filter.getId());
FiltersPreferences.saveFilter(filter);
}
}
}
+1 -1
View File
@@ -6437,7 +6437,7 @@
<string name="update_latest">У вас установлена последняя версия приложения</string>
<string name="update_err">Ошибка проверки обновления</string>
<string name="serverFeaturesDisable">Отключить все внешние подключения</string>
<string name="serverFeaturesDisable_summ">Отключает галочки и все дополнительные функции связанные с получением данных с сервера ВТостерс.\n\nАктульно для тех у кого безлимитный интернет на ВКонтакте</string>
<string name="serverFeaturesDisable_summ">Отключает галочки и все дополнительные функции связанные с получением данных с сервера ВТостерс.\n\nАктуально для тех у кого безлимитный интернет на ВКонтакте</string>
<string name="tgs_token_missing">Токен отсутствует</string>
<string name="tgs_token_reset_dialog">Сбросить токен бота?</string>
+10
View File
@@ -8,11 +8,21 @@
<Preference
android:key="microgsettings"
android:title="@string/microgsett"/>
</PreferenceCategory>
<PreferenceCategory android:title="Экспериментальные функции">
<com.vtosters.lite.ui.MaterialSwitchPreference
android:defaultValue="false"
android:key="batchmessages"
android:summary="Поможет исправить скорость загрузки сообщений, но работает нестабильно"
android:title="Альтернативная загрузка сообщений"/>
<com.vtosters.lite.ui.MaterialSwitchPreference
android:defaultValue="true"
android:key="unstableNameChanger"
android:title="Редактор имен"
android:summary="Редактор имен групп и профилей людей\n\nПри проблемах с работой сообщений лучше отключить данную функцию"/>
<Preference
android:key="unstableNameChangerDrop"
android:title="Сбросить информацию о переименованиях"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/vtverify">
<Preference
@@ -390,6 +390,8 @@
.method public static final b(Lorg/json/JSONObject;)Lcom/vk/dto/newsfeed/Owner;
.locals 1
invoke-static {p0}, Lru/vtosters/hooks/RenameHook;->injectIntoJsonGroup(Lorg/json/JSONObject;)V
sget-object v0, Lcom/vk/dto/newsfeed/Owner;->h:Lcom/vk/dto/newsfeed/Owner$b;
invoke-virtual {v0, p0}, Lcom/vk/dto/newsfeed/Owner$b;->b(Lorg/json/JSONObject;)Lcom/vk/dto/newsfeed/Owner;
@@ -402,6 +404,8 @@
.method public static final c(Lorg/json/JSONObject;)Lcom/vk/dto/newsfeed/Owner;
.locals 1
invoke-static {p0}, Lru/vtosters/hooks/RenameHook;->injectIntoJson(Lorg/json/JSONObject;)V
sget-object v0, Lcom/vk/dto/newsfeed/Owner;->h:Lcom/vk/dto/newsfeed/Owner$b;
invoke-virtual {v0, p0}, Lcom/vk/dto/newsfeed/Owner$b;->c(Lorg/json/JSONObject;)Lcom/vk/dto/newsfeed/Owner;