Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9eb29488d | ||
|
|
be3957db33 | ||
|
|
126f5259d1 | ||
|
|
2d1867197f | ||
|
|
3852425d2c | ||
|
|
c1d4216416 | ||
|
|
0f45a8d175 | ||
|
|
15ed01b4d3 | ||
|
|
41763a4b54 | ||
|
|
d98d81f105 | ||
|
|
899554a571 | ||
|
|
87b1a89bd8 |
@@ -2,7 +2,6 @@ package com.vk.libvideo;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
@@ -11,7 +10,6 @@ import com.vk.dto.common.VideoFile;
|
|||||||
import com.vk.media.player.PlayerTypes;
|
import com.vk.media.player.PlayerTypes;
|
||||||
import com.vk.navigation.NavigatorKeys;
|
import com.vk.navigation.NavigatorKeys;
|
||||||
import com.vk.statistic.Statistic;
|
import com.vk.statistic.Statistic;
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import ru.vtosters.hooks.other.Preferences;
|
import ru.vtosters.hooks.other.Preferences;
|
||||||
@@ -333,6 +331,6 @@ public class VideoTracker {
|
|||||||
jsonObject.put("position_sec", 0);
|
jsonObject.put("position_sec", 0);
|
||||||
jsonObject.put("cur_quality", "auto");
|
jsonObject.put("cur_quality", "auto");
|
||||||
|
|
||||||
Metrics.trackEvents(jsonObject);
|
Metrics.trackEvents(jsonObject, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,6 @@ import com.vk.music.stats.i.MusicPlaybackParams;
|
|||||||
import com.vk.navigation.NavigatorKeys;
|
import com.vk.navigation.NavigatorKeys;
|
||||||
import com.vtosters.lite.data.Analytics;
|
import com.vtosters.lite.data.Analytics;
|
||||||
import kotlin.jvm.b.Functions2;
|
import kotlin.jvm.b.Functions2;
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import ru.vtosters.hooks.other.Preferences;
|
import ru.vtosters.hooks.other.Preferences;
|
||||||
@@ -185,7 +184,7 @@ public final class VKMusicStatsTracker implements MusicStatsTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Metrics.trackEvents(event);
|
Metrics.trackEvents(event, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Analytics.l a(MusicPlaybackParams musicPlaybackParams, String str) {
|
private Analytics.l a(MusicPlaybackParams musicPlaybackParams, String str) {
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
package ru.vtosters.hooks;
|
package ru.vtosters.hooks;
|
||||||
|
|
||||||
|
import androidx.core.util.Pair;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import ru.vtosters.hooks.other.Preferences;
|
||||||
|
import ru.vtosters.lite.utils.RenameTool;
|
||||||
|
|
||||||
public class RenameHook {
|
public class RenameHook {
|
||||||
public static void injectIntoJson(JSONObject obj) throws JSONException {
|
public static void injectIntoJson(JSONObject obj) throws JSONException {
|
||||||
// int i = obj.getInt("id");
|
if (isEnabled()) {
|
||||||
// if (RenameTool.updateRequested) {
|
int i = obj.getInt("id");
|
||||||
// RenameTool.reloadDB();
|
if (RenameTool.updateRequested) {
|
||||||
// }
|
RenameTool.reloadDB();
|
||||||
//
|
}
|
||||||
// Pair<String, String> user = RenameTool.renamedUsers.get(i);
|
|
||||||
// if (user == null) return;
|
Pair<String, String> user = RenameTool.renamedUsers.get(i);
|
||||||
// obj.put(RenameTool.COLUMN_FIRSTNAME, user.first).put(RenameTool.COLUMN_LASTNAME, user.second);
|
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 {
|
public static void injectIntoJsonGroup(JSONObject obj) throws JSONException {
|
||||||
// int i = obj.getInt("id");
|
if (isEnabled()) {
|
||||||
//
|
int i = obj.getInt("id");
|
||||||
// if (RenameTool.updateRequested) {
|
|
||||||
// RenameTool.reloadDB();
|
if (RenameTool.updateRequested) {
|
||||||
// }
|
RenameTool.reloadDB();
|
||||||
//
|
}
|
||||||
// String user = RenameTool.renamedGroups.get(i);
|
|
||||||
// if (user == null) return;
|
String user = RenameTool.renamedGroups.get(i);
|
||||||
// obj.put("name", user);
|
if (user == null) return;
|
||||||
|
obj.put("name", user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,11 +42,13 @@ public class CatalogJsonInjector {
|
|||||||
|
|
||||||
removeUnsupportedLayouts(blocks);
|
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("playStatsCatalog", false)) {
|
||||||
fetchCatalogId("https://vk.com/audio?section=recent", oldItems);
|
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.MusicCacheImpl;
|
||||||
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
|
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
|
||||||
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
|
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
|
||||||
|
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -36,8 +37,10 @@ public class PlaylistInjector {
|
|||||||
|
|
||||||
public static Observable<AudioGetPlaylist.c> injectGetPlaylist(AudioGetPlaylist audioGetPlaylist) {
|
public static Observable<AudioGetPlaylist.c> injectGetPlaylist(AudioGetPlaylist audioGetPlaylist) {
|
||||||
try {
|
try {
|
||||||
if (MusicCacheImpl.isEmpty())
|
if (MusicCacheImpl.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var requestArgs = audioGetPlaylist.b();
|
var requestArgs = audioGetPlaylist.b();
|
||||||
|
|
||||||
var id = requestArgs.get("id");
|
var id = requestArgs.get("id");
|
||||||
@@ -45,9 +48,11 @@ public class PlaylistInjector {
|
|||||||
var accessKey = requestArgs.get("access_key");
|
var accessKey = requestArgs.get("access_key");
|
||||||
boolean isVirtualPlaylist = accessKey != null && (accessKey.equals("cache"));
|
boolean isVirtualPlaylist = accessKey != null && (accessKey.equals("cache"));
|
||||||
boolean isAlbumVirtualPlaylist = accessKey != null && (accessKey.equals("cacheAlbum"));
|
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 null;
|
||||||
|
}
|
||||||
|
|
||||||
return Observable.a((ObservableOnSubscribe<AudioGetPlaylist.c>) observableEmitter -> {
|
return Observable.a((ObservableOnSubscribe<AudioGetPlaylist.c>) observableEmitter -> {
|
||||||
AudioGetPlaylist.c response = new AudioGetPlaylist.c();
|
AudioGetPlaylist.c response = new AudioGetPlaylist.c();
|
||||||
@@ -81,13 +86,11 @@ public class PlaylistInjector {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.c = (ArrayList<MusicTrack>) MusicCacheImpl.getPlaylistSongs(ownerId, id);
|
if (isOwnCachePlaylist) {
|
||||||
|
response.c = (ArrayList<MusicTrack>) TracklistHelper.getMyCachedMusicTracks();
|
||||||
Log.d("Playlist", "Open playlist " + ownerId + "_" + id);
|
|
||||||
|
|
||||||
if (Objects.equals(id, "-1")) {
|
|
||||||
response.b = PlaylistHelper.createCachedPlaylistMetadata();
|
response.b = PlaylistHelper.createCachedPlaylistMetadata();
|
||||||
} else {
|
} else {
|
||||||
|
response.c = (ArrayList<MusicTrack>) MusicCacheImpl.getPlaylistSongs(ownerId, id);
|
||||||
response.b = MusicCacheImpl.getPlaylist(id, ownerId);
|
response.b = MusicCacheImpl.getPlaylist(id, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class TracklistInjector {
|
|||||||
Log.d("TracklistInjector", "Using vkx cache catalog");
|
Log.d("TracklistInjector", "Using vkx cache catalog");
|
||||||
observableEmitter.b(parser.c(new JSONObject(service.getCacheCatalog())));
|
observableEmitter.b(parser.c(new JSONObject(service.getCacheCatalog())));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.fillInStackTrace();
|
||||||
List<MusicTrack> tracks = new ArrayList<>();
|
List<MusicTrack> tracks = new ArrayList<>();
|
||||||
List<String> cache = service.getCache();
|
List<String> cache = service.getCache();
|
||||||
|
|
||||||
@@ -55,16 +55,14 @@ public class TracklistInjector {
|
|||||||
observableEmitter.b(parser.c(createVirtualCatalog(tracks)));
|
observableEmitter.b(parser.c(createVirtualCatalog(tracks)));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.fillInStackTrace();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (MusicCacheImpl.isEmpty()) {
|
if (MusicCacheImpl.isEmpty()) {
|
||||||
observableEmitter.b(parser.c(getEmptyCatalog()));
|
observableEmitter.b(parser.c(getEmptyCatalog()));
|
||||||
} else {
|
} else {
|
||||||
observableEmitter.b(parser.c(createVirtualCatalog(
|
observableEmitter.b(parser.c(createVirtualCatalog(TracklistHelper.getMyCachedMusicTracks())));
|
||||||
PlaylistCacheDbDelegate.getTracksInPlaylist(AndroidUtils.getGlobalContext(),
|
|
||||||
AccountManagerUtils.getUserId() + "_-1"))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ public class Preferences {
|
|||||||
return getBoolValue("vkme", false);
|
return getBoolValue("vkme", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean autocache() {
|
public static int autocache() {
|
||||||
return getBoolValue("autocache", false);
|
return Preferences.getPreferences().getInt("autocaching", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean adsstories() {
|
public static boolean adsstories() {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import ru.vtosters.hooks.other.Preferences;
|
|||||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||||
|
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||||
import ru.vtosters.lite.utils.AndroidUtils;
|
import ru.vtosters.lite.utils.AndroidUtils;
|
||||||
import ru.vtosters.lite.utils.music.MusicTrackUtils;
|
import ru.vtosters.lite.utils.music.MusicTrackUtils;
|
||||||
|
|
||||||
@@ -50,13 +51,14 @@ public class LastFMScrobbler {
|
|||||||
var access_key = !TextUtils.isEmpty(musictrack.J) ? musictrack.J : "";
|
var access_key = !TextUtils.isEmpty(musictrack.J) ? musictrack.J : "";
|
||||||
var album_id = musictrack.I;
|
var album_id = musictrack.I;
|
||||||
var album = album_id != null ? album_id.getTitle() : null;
|
var album = album_id != null ? album_id.getTitle() : null;
|
||||||
|
var isOwnTrack = musictrack.e == AccountManagerUtils.getUserId();
|
||||||
|
|
||||||
if (TextUtils.isEmpty(uid) || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0) {
|
if (TextUtils.isEmpty(uid) || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0) {
|
||||||
Log.d("Scrobbler", "grabTrackInfo: " + "Empty track, info: " + artist + " - " + title + " - " + duration + " - " + uid);
|
Log.d("Scrobbler", "grabTrackInfo: " + "Empty track, info: " + artist + " - " + title + " - " + duration + " - " + uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Preferences.autocache() && !MusicCacheImpl.isCachedTrack(uid)) {
|
if (needToCache(isOwnTrack) && !MusicCacheImpl.isCachedTrack(uid)) {
|
||||||
if (LibVKXClient.isIntegrationEnabled()) {
|
if (LibVKXClient.isIntegrationEnabled()) {
|
||||||
LibVKXClient.getInstance().runOnService(service -> {
|
LibVKXClient.getInstance().runOnService(service -> {
|
||||||
try {
|
try {
|
||||||
@@ -73,6 +75,12 @@ public class LastFMScrobbler {
|
|||||||
scrobbleTrack(duration, artist, title, uid, album);
|
scrobbleTrack(duration, artist, title, uid, album);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean needToCache(boolean isOwnTrack) {
|
||||||
|
int autocache = Preferences.autocache();
|
||||||
|
|
||||||
|
return autocache == 2 || (autocache == 1 && isOwnTrack);
|
||||||
|
}
|
||||||
|
|
||||||
public static void scrobbleTrack(
|
public static void scrobbleTrack(
|
||||||
long duration,
|
long duration,
|
||||||
String artist,
|
String artist,
|
||||||
|
|||||||
@@ -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;
|
||||||
import com.google.android.exoplayer2.source.hls.playlist.f.a;
|
import com.google.android.exoplayer2.source.hls.playlist.f.a;
|
||||||
import com.vk.dto.music.MusicTrack;
|
import com.vk.dto.music.MusicTrack;
|
||||||
|
import com.vk.dto.music.Playlist;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -20,7 +22,6 @@ import javax.crypto.Cipher;
|
|||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
import com.vk.dto.music.Playlist;
|
|
||||||
import ru.vtosters.hooks.other.Preferences;
|
import ru.vtosters.hooks.other.Preferences;
|
||||||
import ru.vtosters.lite.music.converter.ts.MpegDemuxer;
|
import ru.vtosters.lite.music.converter.ts.MpegDemuxer;
|
||||||
import ru.vtosters.lite.music.interfaces.Callback;
|
import ru.vtosters.lite.music.interfaces.Callback;
|
||||||
@@ -37,17 +38,29 @@ public final class Mp3Downloader implements ITrackDownloader {
|
|||||||
@Override
|
@Override
|
||||||
public void download(MusicTrack track, Callback callback, Playlist playlist) {
|
public void download(MusicTrack track, Callback callback, Playlist playlist) {
|
||||||
String uri = track.D;
|
String uri = track.D;
|
||||||
|
|
||||||
if (Objects.requireNonNull(uri).isEmpty()) {
|
if (Objects.requireNonNull(uri).isEmpty()) {
|
||||||
String msg = "link error: " + track.y1() + ", title: " + Mp3Downloader.getTitle(track);
|
String msg = "link error: " + track.y1() + ", title: " + Mp3Downloader.getTitle(track);
|
||||||
Log.d("Mp3Downloader", msg);
|
Log.d("Mp3Downloader", msg);
|
||||||
throw new RuntimeException(msg);
|
throw new RuntimeException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tsParser = new com.google.android.exoplayer2.source.hls.playlist.h(e.a(track.D));
|
if (Objects.requireNonNull(uri).contains("master.m3u8?siren=1")) {
|
||||||
var baseUri = track.D.substring(0, track.D.lastIndexOf("/") + 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 {
|
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);
|
byte[] buff = getMergedTs(baseUri, segments, callback);
|
||||||
MpegDemuxer.convert(buff, outputFile.getAbsolutePath());
|
MpegDemuxer.convert(buff, outputFile.getAbsolutePath());
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ package ru.vtosters.lite.ui.fragments;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||||
import com.vk.dto.music.Playlist;
|
import com.vk.dto.music.Playlist;
|
||||||
@@ -20,10 +23,14 @@ import ru.vtosters.lite.ui.PreferenceFragmentUtils;
|
|||||||
import ru.vtosters.lite.utils.AndroidUtils;
|
import ru.vtosters.lite.utils.AndroidUtils;
|
||||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
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 {
|
public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||||
private static final ExecutorService executor = Executors.newCachedThreadPool();
|
private static final ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
@@ -93,15 +100,38 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
}
|
}
|
||||||
).setEnabled(!MusicCacheImpl.isEmpty());
|
).setEnabled(!MusicCacheImpl.isEmpty());
|
||||||
|
|
||||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
PreferenceFragmentUtils.addPreference(
|
||||||
getPreferenceScreen(),
|
getPreferenceScreen(),
|
||||||
"autocache",
|
"autocache_params",
|
||||||
getString(com.vtosters.lite.R.string.autocache_title),
|
getString(com.vtosters.lite.R.string.autocache_title),
|
||||||
getString(com.vtosters.lite.R.string.autocache_summ),
|
getAutocacheSumm(),
|
||||||
null,
|
null,
|
||||||
false,
|
preference -> {
|
||||||
(preference, o) -> {
|
List<String> items = Arrays.asList("Не кешировать", "Только свои", "Все");
|
||||||
Preferences.getPreferences().edit().putBoolean("autocache", (boolean) o).apply();
|
|
||||||
|
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()) {
|
||||||
|
adapter.getItem(selectedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
new VkAlertDialog.Builder(getActivity())
|
||||||
|
.setAdapter(adapter, (dialog, which) -> {
|
||||||
|
adapter.getItem(which);
|
||||||
|
Preferences.getPreferences().edit().putInt("autocaching", which).apply();
|
||||||
|
findPreference("autocache_params").setSummary(getAutocacheSumm());
|
||||||
|
dialog.cancel();
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -166,6 +196,7 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Preferences.setMetadataSeparator(separator.getText().toString());
|
Preferences.setMetadataSeparator(separator.getText().toString());
|
||||||
|
findPreference("metadataSeparator").setSummary(separator.getText().toString());
|
||||||
})
|
})
|
||||||
.setNegativeButton("Отмена", (dialog, which) -> dialog.cancel())
|
.setNegativeButton("Отмена", (dialog, which) -> dialog.cancel())
|
||||||
.show();
|
.show();
|
||||||
@@ -188,6 +219,19 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||||
|
getPreferenceScreen(),
|
||||||
|
"playStatsCatalog",
|
||||||
|
"Список истории прослушиваний",
|
||||||
|
"Показывать вкладку истории прослушиваний в музыкальном разделе\n\nОтключение ускорит открытие музыкального раздела при медленном интернете",
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
(preference, o) -> {
|
||||||
|
Preferences.getPreferences().edit().putBoolean("playStatsCatalog", (boolean) o).apply();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
).setVisible(Preferences.sendMusicMetrics() && !getBoolValue("useOldAppVer", false));
|
||||||
|
|
||||||
if (!Preferences.serverFeaturesDisable()) {
|
if (!Preferences.serverFeaturesDisable()) {
|
||||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Интеграция Genius");
|
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Интеграция Genius");
|
||||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||||
@@ -295,6 +339,19 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
list.setVisible(!Preferences.getBoolValue("useOldAppVer", false));
|
list.setVisible(!Preferences.getBoolValue("useOldAppVer", false));
|
||||||
|
|
||||||
getPreferenceScreen().addPreference(list);
|
getPreferenceScreen().addPreference(list);
|
||||||
|
|
||||||
|
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||||
|
getPreferenceScreen(),
|
||||||
|
"playlistsCatalogs",
|
||||||
|
"Списки плейлистов",
|
||||||
|
"Показывать вкладку плейлистов и альбомов прослушиваний в музыкальном разделе\n\nОтключение ускорит открытие музыкального раздела при медленном интернете",
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
(preference, o) -> {
|
||||||
|
Preferences.getPreferences().edit().putBoolean("playStatsCatalog", (boolean) o).apply();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
).setVisible(!getBoolValue("useOldAppVer", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void lastfmAuth(Context ctx) {
|
private void lastfmAuth(Context ctx) {
|
||||||
@@ -334,6 +391,15 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getAutocacheSumm() {
|
||||||
|
int autocache = Preferences.autocache();
|
||||||
|
return switch (autocache) {
|
||||||
|
case 1 -> "Только для своих";
|
||||||
|
case 2 -> "Кешировать всё";
|
||||||
|
default -> "Отключено";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public void updateLastFmPref() {
|
public void updateLastFmPref() {
|
||||||
if (LastFMScrobbler.isLoggedIn()) {
|
if (LastFMScrobbler.isLoggedIn()) {
|
||||||
findPreference("lastfm_auth").setSummary(getString(com.vtosters.lite.R.string.lastfm_authorized_as) + " " + LastFMScrobbler.getUserName());
|
findPreference("lastfm_auth").setSummary(getString(com.vtosters.lite.R.string.lastfm_authorized_as) + " " + LastFMScrobbler.getUserName());
|
||||||
@@ -355,7 +421,8 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void cachedPlaylistsDialog(Context ctx) {
|
@SuppressLint("DefaultLocale")
|
||||||
|
private void cachedPlaylistsDialog(Context ctx) {
|
||||||
List<Playlist> playlists = PlaylistCacheDbDelegate.getAllPlaylists(ctx);
|
List<Playlist> playlists = PlaylistCacheDbDelegate.getAllPlaylists(ctx);
|
||||||
String[] playlistNames = new String[playlists.size()];
|
String[] playlistNames = new String[playlists.size()];
|
||||||
|
|
||||||
@@ -370,6 +437,7 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
String playlistId = selectedPlaylist.v1();
|
String playlistId = selectedPlaylist.v1();
|
||||||
PlaylistCacheDbDelegate.deletePlaylist(ctx, playlistId);
|
PlaylistCacheDbDelegate.deletePlaylist(ctx, playlistId);
|
||||||
AndroidUtils.sendToast("Плейлист удален");
|
AndroidUtils.sendToast("Плейлист удален");
|
||||||
|
findPreference("cached_playlists").setSummary(String.format("Скачано плейлистов: %d", MusicCacheImpl.getPlaylists().size()));
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.show();
|
builder.show();
|
||||||
@@ -379,10 +447,11 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
new VkAlertDialog.Builder(ctx)
|
new VkAlertDialog.Builder(ctx)
|
||||||
.setTitle(com.vtosters.lite.R.string.warning)
|
.setTitle(com.vtosters.lite.R.string.warning)
|
||||||
.setMessage(com.vtosters.lite.R.string.cached_tracks_remove_confirm)
|
.setMessage(com.vtosters.lite.R.string.cached_tracks_remove_confirm)
|
||||||
.setPositiveButton(com.vtosters.lite.R.string.yes,
|
.setPositiveButton(com.vtosters.lite.R.string.yes, (dialog, which) -> {
|
||||||
(dialog, which) -> executor.submit(MusicCacheImpl::clear))
|
executor.submit(MusicCacheImpl::clear);
|
||||||
.setNeutralButton(com.vtosters.lite.R.string.no,
|
findPreference("cached_tracks").setSummary(String.format(requireContext().getString(com.vtosters.lite.R.string.cached_tracks_counter), MusicCacheImpl.getTracksCount()));
|
||||||
(dialog, which) -> dialog.cancel())
|
})
|
||||||
|
.setNeutralButton(com.vtosters.lite.R.string.no, (dialog, which) -> dialog.cancel())
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,17 @@ public class OtherFragment extends TrackedMaterialPreferenceToolbarFragment {
|
|||||||
return true;
|
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 -> {
|
findPreference("copydebuginfo").setOnPreferenceClickListener(preference -> {
|
||||||
copyText(new DeviceInfoCollector().collect().forLogging());
|
copyText(new DeviceInfoCollector().collect().forLogging());
|
||||||
Toast.makeText(requireContext(), AndroidUtils.getString("device_info_copied"), Toast.LENGTH_SHORT).show();
|
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(
|
PreferenceFragmentUtils.addPreference(
|
||||||
getPreferenceScreen(),
|
getPreferenceScreen(),
|
||||||
"",
|
"",
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ import com.vtosters.lite.api.ExtendedCommunityProfile;
|
|||||||
import com.vtosters.lite.api.ExtendedUserProfile;
|
import com.vtosters.lite.api.ExtendedUserProfile;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import kotlin.jvm.b.Functions;
|
import kotlin.jvm.b.Functions;
|
||||||
|
import ru.vtosters.hooks.RenameHook;
|
||||||
import ru.vtosters.hooks.other.Preferences;
|
import ru.vtosters.hooks.other.Preferences;
|
||||||
import ru.vtosters.lite.foaf.FoafBase;
|
import ru.vtosters.lite.foaf.FoafBase;
|
||||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||||
import ru.vtosters.lite.utils.AndroidUtils;
|
import ru.vtosters.lite.utils.AndroidUtils;
|
||||||
|
import ru.vtosters.lite.utils.RenameTool;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@@ -66,10 +68,12 @@ public class MenuBuilder {
|
|||||||
return Unit.a;
|
return Unit.a;
|
||||||
});
|
});
|
||||||
|
|
||||||
// addItem(builder, AndroidUtils.getString(R.string.menu_change_name), () -> {
|
if (RenameHook.isEnabled()) {
|
||||||
// RenameTool.createDialog(eup, ctx);
|
addItem(builder, AndroidUtils.getString(R.string.menu_change_name), () -> {
|
||||||
// return Unit.a;
|
RenameTool.createDialog(eup, ctx);
|
||||||
// });
|
return Unit.a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
addItem(builder, AndroidUtils.getString(isPageWhitelistedFilter ? R.string.remove_from_filter_whitelist : R.string.add_to_filter_whitelist), () -> {
|
addItem(builder, AndroidUtils.getString(isPageWhitelistedFilter ? R.string.remove_from_filter_whitelist : R.string.add_to_filter_whitelist), () -> {
|
||||||
setWhitelistedFilter(eup, !isPageWhitelistedFilter);
|
setWhitelistedFilter(eup, !isPageWhitelistedFilter);
|
||||||
@@ -83,7 +87,7 @@ public class MenuBuilder {
|
|||||||
return Unit.a;
|
return Unit.a;
|
||||||
});
|
});
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
e.printStackTrace();
|
e.fillInStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,10 +104,12 @@ public class MenuBuilder {
|
|||||||
return Unit.a;
|
return Unit.a;
|
||||||
});
|
});
|
||||||
|
|
||||||
// addItem(builder, AndroidUtils.getString(R.string.menu_change_name), () -> {
|
if (RenameHook.isEnabled()) {
|
||||||
// RenameTool.createDialogGroup(ecp, ctx);
|
addItem(builder, AndroidUtils.getString(R.string.menu_change_name), () -> {
|
||||||
// return Unit.a;
|
RenameTool.createDialogGroup(ecp, ctx);
|
||||||
// });
|
return Unit.a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
addItem(builder, AndroidUtils.getString(isPageWhitelistedFilter ? R.string.remove_from_filter_whitelist : R.string.add_to_filter_whitelist), () -> {
|
addItem(builder, AndroidUtils.getString(isPageWhitelistedFilter ? R.string.remove_from_filter_whitelist : R.string.add_to_filter_whitelist), () -> {
|
||||||
setWhitelistedFilter(ecp, !isPageWhitelistedFilter);
|
setWhitelistedFilter(ecp, !isPageWhitelistedFilter);
|
||||||
@@ -123,7 +129,7 @@ public class MenuBuilder {
|
|||||||
return Unit.a;
|
return Unit.a;
|
||||||
});
|
});
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
e.printStackTrace();
|
e.fillInStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,25 @@ import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
|||||||
public class Metrics {
|
public class Metrics {
|
||||||
private static JSONArray events = new JSONArray();
|
private static JSONArray events = new JSONArray();
|
||||||
|
|
||||||
public static void trackEvents(JSONObject object) {
|
public static void trackEvents(JSONObject object, boolean isMusic) {
|
||||||
if (!NetworkUtils.isNetworkConnected()) {
|
if (NetworkUtils.isNetworkConnected()) {
|
||||||
events.put(object);
|
handleNetworkConnected(object, isMusic);
|
||||||
} else if (shouldSaveUserTraffic() || events.length() > 0) {
|
|
||||||
trackEventList(object);
|
|
||||||
} else {
|
} else {
|
||||||
|
handleNetworkDisconnected(object, isMusic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void handleNetworkConnected(JSONObject object, boolean isMusic) {
|
||||||
|
if (isMusic || shouldSaveUserTraffic() || events.length() > 0) {
|
||||||
trackEventsImmediately(object);
|
trackEventsImmediately(object);
|
||||||
|
} else {
|
||||||
|
trackEventList(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void handleNetworkDisconnected(JSONObject object, boolean isMusic) {
|
||||||
|
if (!isMusic) {
|
||||||
|
events.put(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.vtosters.lite.utils;
|
package ru.vtosters.lite.utils;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@@ -12,15 +13,15 @@ import android.widget.LinearLayout;
|
|||||||
import androidx.core.util.Pair;
|
import androidx.core.util.Pair;
|
||||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||||
import com.vk.dto.user.UserProfile;
|
import com.vk.dto.user.UserProfile;
|
||||||
import com.vk.im.engine.models.users.User;
|
|
||||||
import com.vtosters.lite.R;
|
import com.vtosters.lite.R;
|
||||||
import com.vtosters.lite.api.ExtendedCommunityProfile;
|
import com.vtosters.lite.api.ExtendedCommunityProfile;
|
||||||
import com.vtosters.lite.api.ExtendedUserProfile;
|
import com.vtosters.lite.api.ExtendedUserProfile;
|
||||||
import ru.vtosters.hooks.other.ThemesUtils;
|
import ru.vtosters.hooks.other.ThemesUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import static ru.vtosters.hooks.other.ThemesUtils.getSTextAttr;
|
import static ru.vtosters.hooks.other.ThemesUtils.getSTextAttr;
|
||||||
import static ru.vtosters.hooks.other.ThemesUtils.getTextAttr;
|
import static ru.vtosters.hooks.other.ThemesUtils.getTextAttr;
|
||||||
@@ -47,69 +48,40 @@ public class RenameTool {
|
|||||||
return helperInstance;
|
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() {
|
public static void reloadDB() {
|
||||||
renamedGroups.clear();
|
renamedGroups.clear();
|
||||||
renamedUsers.clear();
|
renamedUsers.clear();
|
||||||
updateRequested = false;
|
updateRequested = false;
|
||||||
|
|
||||||
try (Cursor cursor = getHelper().getReadableDatabase().rawQuery(String.format("SELECT * FROM %s", TABLE_NAME), new String[0])) {
|
loadData(TABLE_NAME, (cursor, vkID) -> {
|
||||||
while (cursor.moveToNext()) {
|
String firstName = decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_FIRSTNAME)));
|
||||||
String firstName = URLDecoder.decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_FIRSTNAME)), "UTF-8");
|
String lastName = decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_LASTNAME)));
|
||||||
String lastName = URLDecoder.decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_LASTNAME)), "UTF-8");
|
renamedUsers.put(vkID, new Pair<>(firstName, lastName));
|
||||||
int vkID = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_VKID));
|
});
|
||||||
renamedUsers.put(vkID, new Pair<>(firstName, lastName));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
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()) {
|
while (cursor.moveToNext()) {
|
||||||
String name = URLDecoder.decode(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME)), "UTF-8");
|
|
||||||
int vkID = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_VKID));
|
int vkID = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_VKID));
|
||||||
renamedGroups.put(vkID, name);
|
consumer.accept(cursor, vkID);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
throw new RuntimeException("Failed to load data from " + tableName, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void injectIntoChat(User u) {
|
private static String decode(String value) {
|
||||||
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) {
|
|
||||||
try {
|
try {
|
||||||
Field f = User.class.getDeclaredField(name);
|
return URLDecoder.decode(value, "UTF-8");
|
||||||
f.setAccessible(true);
|
} catch (UnsupportedEncodingException e) {
|
||||||
f.set(instance, obj);
|
throw new RuntimeException("UTF-8 encoding not supported", e);
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +89,7 @@ public class RenameTool {
|
|||||||
LinearLayout linearLayout = new LinearLayout(ctx);
|
LinearLayout linearLayout = new LinearLayout(ctx);
|
||||||
linearLayout.setOrientation(LinearLayout.VERTICAL);
|
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.setHint(R.string.vk_auth_sign_up_first_name);
|
||||||
fn.setTextColor(getTextAttr());
|
fn.setTextColor(getTextAttr());
|
||||||
fn.setHintTextColor(getSTextAttr());
|
fn.setHintTextColor(getSTextAttr());
|
||||||
@@ -128,7 +100,7 @@ public class RenameTool {
|
|||||||
margin.setMargins(dp2px(20f), 0, dp2px(20f), 0);
|
margin.setMargins(dp2px(20f), 0, dp2px(20f), 0);
|
||||||
fn.setLayoutParams(margin);
|
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.setHint(R.string.vk_auth_sign_up_last_name);
|
||||||
ln.setTextColor(getTextAttr());
|
ln.setTextColor(getTextAttr());
|
||||||
ln.setHintTextColor(getSTextAttr());
|
ln.setHintTextColor(getSTextAttr());
|
||||||
@@ -137,69 +109,93 @@ public class RenameTool {
|
|||||||
ln.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
ln.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
ln.setLayoutParams(margin);
|
ln.setLayoutParams(margin);
|
||||||
|
|
||||||
final UserProfile profile = AccountManagerUtils.fromEup(eup);
|
UserProfile profile = AccountManagerUtils.fromEup(eup);
|
||||||
fn.setText(AccountManagerUtils.getUserFirstName(profile));
|
fn.setText(AccountManagerUtils.getUserFirstName(profile));
|
||||||
ln.setText(AccountManagerUtils.getUserLastName(profile));
|
ln.setText(AccountManagerUtils.getUserLastName(profile));
|
||||||
|
|
||||||
int id = AccountManagerUtils.getUserID(profile);
|
int id = AccountManagerUtils.getUserID(profile);
|
||||||
|
|
||||||
var builder = new VkAlertDialog.Builder(ctx)
|
VkAlertDialog.Builder builder = new VkAlertDialog.Builder(ctx)
|
||||||
.setTitle(R.string.rename_title)
|
.setTitle(R.string.rename_title)
|
||||||
.setMessage(R.string.rename_message)
|
.setMessage(R.string.rename_message)
|
||||||
.setView(linearLayout)
|
.setView(linearLayout)
|
||||||
.setPositiveButton("OK", (dialog, which) -> {
|
.setPositiveButton("OK", (dialog, which) -> updateName(ctx, fn.getText().toString(), ln.getText().toString(), id));
|
||||||
String firstName = fn.getText().toString();
|
|
||||||
String lastName = ln.getText().toString();
|
if (isChangedName(id)) {
|
||||||
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
|
builder.setNeutralButton(R.string.rename_reset, (dialog, which) -> deleteUser(ctx, id));
|
||||||
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));
|
|
||||||
|
|
||||||
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();
|
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) {
|
public static void createDialogGroup(ExtendedCommunityProfile eup, final Context ctx) {
|
||||||
LinearLayout linearLayout = new LinearLayout(ctx);
|
LinearLayout linearLayout = new LinearLayout(ctx);
|
||||||
linearLayout.setOrientation(LinearLayout.VERTICAL);
|
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.setHint(R.string.vk_auth_sign_up_first_name);
|
||||||
fn.setHintTextColor(getSTextAttr());
|
fn.setHintTextColor(getSTextAttr());
|
||||||
fn.setTextColor(getTextAttr());
|
fn.setTextColor(getTextAttr());
|
||||||
@@ -210,52 +206,61 @@ public class RenameTool {
|
|||||||
margin.setMargins(dp2px(20f), 0, dp2px(20f), 0);
|
margin.setMargins(dp2px(20f), 0, dp2px(20f), 0);
|
||||||
fn.setLayoutParams(margin);
|
fn.setLayoutParams(margin);
|
||||||
|
|
||||||
final UserProfile profile = AccountManagerUtils.fromEup(eup);
|
UserProfile profile = AccountManagerUtils.fromEup(eup);
|
||||||
fn.setText(AccountManagerUtils.getGroupName(profile));
|
fn.setText(AccountManagerUtils.getGroupName(profile));
|
||||||
|
|
||||||
int fid = AccountManagerUtils.getUserID(profile);
|
int fid = AccountManagerUtils.getUserID(profile);
|
||||||
|
|
||||||
if (fid < 0) fid = -fid;
|
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)
|
.setTitle(R.string.rename_title)
|
||||||
.setMessage(R.string.rename_message)
|
.setMessage(R.string.rename_message)
|
||||||
.setView(linearLayout)
|
.setView(linearLayout)
|
||||||
.setPositiveButton("OK", (dialog, which) -> {
|
.setPositiveButton("OK", (dialog, which) -> updateGroupName(ctx, fn.getText().toString(), id));
|
||||||
String firstName = fn.getText().toString();
|
|
||||||
SQLiteDatabase writableDatabase = getHelper().getWritableDatabase();
|
if (isChangedNameGroup(id)) {
|
||||||
try {
|
builder.setNeutralButton(R.string.rename_reset, (dialog, which) -> deleteGroupName(ctx, id));
|
||||||
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));
|
|
||||||
});
|
|
||||||
builder.show();
|
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) {
|
public static boolean isChangedName(int uid) {
|
||||||
return renamedUsers.get(uid) != null;
|
return renamedUsers.get(uid) != null;
|
||||||
}
|
}
|
||||||
@@ -264,10 +269,6 @@ public class RenameTool {
|
|||||||
return renamedGroups.get(uid) != null;
|
return renamedGroups.get(uid) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isIdInList(UserProfile profile) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DbHelper extends SQLiteOpenHelper {
|
private static class DbHelper extends SQLiteOpenHelper {
|
||||||
public DbHelper(Context context) {
|
public DbHelper(Context context) {
|
||||||
super(context, DB_NAME, null, DB_VERSION);
|
super(context, DB_NAME, null, DB_VERSION);
|
||||||
|
|||||||
@@ -61,6 +61,18 @@ public class FiltersPreferences {
|
|||||||
editor.apply();
|
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) {
|
public static boolean getSavedKeyValue(int id) {
|
||||||
return getFilter(id) != null;
|
return getFilter(id) != null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.vtosters.sponsorpost.utils;
|
package ru.vtosters.sponsorpost.utils;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import ru.vtosters.lite.utils.NetworkUtils;
|
import ru.vtosters.lite.utils.NetworkUtils;
|
||||||
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
|
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
|
||||||
import ru.vtosters.sponsorpost.data.Filter;
|
import ru.vtosters.sponsorpost.data.Filter;
|
||||||
@@ -31,14 +32,17 @@ public class Updates {
|
|||||||
for (Filter filter : filters) {
|
for (Filter filter : filters) {
|
||||||
Filter localFilter = findLocalFilterById(localFilters, filter.getId());
|
Filter localFilter = findLocalFilterById(localFilters, filter.getId());
|
||||||
if (localFilter == null) {
|
if (localFilter == null) {
|
||||||
|
Log.d("Updates", "local filter is not exist, adding new: " + filter.getId());
|
||||||
FiltersPreferences.saveFilter(filter);
|
FiltersPreferences.saveFilter(filter);
|
||||||
} else {
|
} else {
|
||||||
String remoteVersion = filter.getVersion();
|
String remoteVersion = filter.getVersion();
|
||||||
String localVersion = localFilter.getVersion();
|
String localVersion = localFilter.getVersion();
|
||||||
if (Objects.equals(remoteVersion, localVersion)) {
|
if (Objects.equals(remoteVersion, localVersion)) {
|
||||||
FiltersPreferences.saveFilter(filter);
|
Log.d("Updates", "saved local filter: " + localFilter.getId());
|
||||||
} else {
|
|
||||||
FiltersPreferences.saveFilter(localFilter);
|
FiltersPreferences.saveFilter(localFilter);
|
||||||
|
} else {
|
||||||
|
Log.d("Updates", "saved remote filter: " + filter.getId());
|
||||||
|
FiltersPreferences.saveFilter(filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6437,7 +6437,7 @@
|
|||||||
<string name="update_latest">У вас установлена последняя версия приложения</string>
|
<string name="update_latest">У вас установлена последняя версия приложения</string>
|
||||||
<string name="update_err">Ошибка проверки обновления</string>
|
<string name="update_err">Ошибка проверки обновления</string>
|
||||||
<string name="serverFeaturesDisable">Отключить все внешние подключения</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_missing">Токен отсутствует</string>
|
||||||
<string name="tgs_token_reset_dialog">Сбросить токен бота?</string>
|
<string name="tgs_token_reset_dialog">Сбросить токен бота?</string>
|
||||||
|
|||||||
@@ -8,11 +8,21 @@
|
|||||||
<Preference
|
<Preference
|
||||||
android:key="microgsettings"
|
android:key="microgsettings"
|
||||||
android:title="@string/microgsett"/>
|
android:title="@string/microgsett"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory android:title="Экспериментальные функции">
|
||||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="batchmessages"
|
android:key="batchmessages"
|
||||||
android:summary="Поможет исправить скорость загрузки сообщений, но работает нестабильно"
|
android:summary="Поможет исправить скорость загрузки сообщений, но работает нестабильно"
|
||||||
android:title="Альтернативная загрузка сообщений"/>
|
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>
|
||||||
<PreferenceCategory android:title="@string/vtverify">
|
<PreferenceCategory android:title="@string/vtverify">
|
||||||
<Preference
|
<Preference
|
||||||
|
|||||||
Reference in New Issue
Block a user