Compare commits
58
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff404b21b5 | ||
|
|
aeed9efaeb | ||
|
|
29b9251763 | ||
|
|
91e6c3185f | ||
|
|
7169e3ab8b | ||
|
|
97a0ae4b95 | ||
|
|
5d5ad70e7e | ||
|
|
752c59e2a2 | ||
|
|
e3b33a88c7 | ||
|
|
b35d5c428f | ||
|
|
c796006b94 | ||
|
|
70d3b8f8c0 | ||
|
|
15f678e20d | ||
|
|
011698a722 | ||
|
|
d127fbbd22 | ||
|
|
eb167be1c0 | ||
|
|
19fa48a1f6 | ||
|
|
e96ba600cb | ||
|
|
70c75edacc | ||
|
|
5a048eff92 | ||
|
|
9abed48ec0 | ||
|
|
6758c8735c | ||
|
|
b20fdee8da | ||
|
|
dffa4ff7c4 | ||
|
|
6dd715af0b | ||
|
|
10de24f119 | ||
|
|
2cd856e574 | ||
|
|
9e9617fd16 | ||
|
|
3ae2637da0 | ||
|
|
94438662cb | ||
|
|
aa3d4df40a | ||
|
|
1e5fdde641 | ||
|
|
b37b41ddd3 | ||
|
|
25d6231ae3 | ||
|
|
db83fbff52 | ||
|
|
48e6b4f54d | ||
|
|
937c7efb03 | ||
|
|
86c513ed58 | ||
|
|
e701d03233 | ||
|
|
097faf6b38 | ||
|
|
4f4b167d99 | ||
|
|
d886e43f3d | ||
|
|
fcf1ee608d | ||
|
|
cd15541583 | ||
|
|
7bdaa736ef | ||
|
|
74f10e6ab2 | ||
|
|
678a398612 | ||
|
|
7e1c3d62cf | ||
|
|
c0ce22565e | ||
|
|
217a376f5b | ||
|
|
35f486dc86 | ||
|
|
252d761b9e | ||
|
|
237be0cc88 | ||
|
|
2717fd5736 | ||
|
|
81cf7ad694 | ||
|
|
34007658d5 | ||
|
|
3d1ca8d36a | ||
|
|
99f8e4f896 |
@@ -1,27 +0,0 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Заготовка для репорта багов
|
||||
title: Ошибка обновлении ленты новостей
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Опишите сам баг**
|
||||
При обновлении новостей вылезает ошибка
|
||||
|
||||
**Опишите действия для воспроизведения ошибки**
|
||||
1. Обновил ленту интересных новостей
|
||||
2. Пролистал до конца страницы
|
||||
|
||||
**Опишите ожидаемый результат**
|
||||
Интересная лента должна прогружать результаты
|
||||
|
||||
**Скриншот ошибки**
|
||||
|
||||
**Информация об устройстве:**
|
||||
- Устройство: Samsung Galaxy J1 Mini
|
||||
- OS: Android 9 | OneUi 3.0
|
||||
- Коммит: fa12e8f (В О Приложении написана версия коммита)
|
||||
|
||||
**Дополнительная информация о баге или мыслях почему оно может происходить (если есть)**
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Предложение функции
|
||||
title: Улучшение голосовых сообщений
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Опишите вашу идею максимально подробно и понятно**
|
||||
Необходима функция улучшения голосовых сообщений. Она значительно улучшит запись голосовых сообщений и собеседнику будет лучше слышно меня
|
||||
|
||||
**Опишите возможное решение/реализацию функции (если понимаете как это можно реализовать на Java/C++)**
|
||||
|
||||
**Остальные мысли о предложенной функции**
|
||||
@@ -29,4 +29,3 @@ smali2/build/resources.zip
|
||||
smali/build/resources.zip
|
||||
smali/assets/version.properties
|
||||
*.keystore
|
||||
gradle.properties
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
* Лента
|
||||
* Блокировка рекламы в ленте
|
||||
* Блокировка постов через фильтры
|
||||
* Возможность добавлять в вайтлист фильтров группы, чтобы в них не удалялись посты
|
||||
* Возможность отключить рекомендации от ВК
|
||||
* Редактор докбара
|
||||
* Редактор элементов Superapp
|
||||
@@ -67,34 +66,30 @@
|
||||
* Округление чисел
|
||||
* Сокращение постов **(Показать полностью)**
|
||||
* Результаты опросов без участия
|
||||
* Возможность указывать папку для загрузки фото/видео/музыки/всего
|
||||
* Интеграция с <a href="https://www.last.fm/">LAST.FM</a> (а также возможность скробблинга)
|
||||
* Новый раздел музыки
|
||||
* Возможность скачивать видео, очищать историю просмотра видео
|
||||
* Возможность скачивать видео
|
||||
* Возможность найти фотографию через поисковые системы
|
||||
* Интеграция с <a href="https://vkx.app/">VK X</a>
|
||||
* Сообщения
|
||||
* ~Обои в сообщениях~ (временно недоступно из-за проблем с производительностью)
|
||||
* Обои в сообщениях
|
||||
* Возможность выключения кнопки записи голосовых сообщений
|
||||
* Возможность скрыть блок рекомендаций в сообщениях
|
||||
* Режим **VK Me**
|
||||
* Возможность вернуть вкладку уведомлений для режима VK Me
|
||||
* Возможность вернуть вкладку уведомлений
|
||||
* Встроенный переводчик текста для сообщений
|
||||
* Возможность выбрать язык перевода
|
||||
* Автоматический перевод ваших сообщений на выбранный язык
|
||||
* Автоматический перевод ваших сообщений на выбранный язык
|
||||
* Альтернативный дизайн эмодзи меню
|
||||
* Возможность использовать системные эмодзи
|
||||
* Возможнсть использовать Enter с аппаратной клавиатуры
|
||||
* Активность
|
||||
* Возможность видеть удаленные сообщения
|
||||
* Функционал, позволяющий оставаться в «оффлайне» (принудительный оффлайн/не отправлять статус онлайна и т.п.)
|
||||
* Нечиталка/неписалка для ЛС/бесед/ботов/групп
|
||||
* Возможность отключить информацию о том, что вы просмотрели историю/прослушали голосовое сообщение
|
||||
* Возможность видеть онлайн пользователей, если у вас скрыт онлайн через VK Messenger
|
||||
* Возможность сохранять настройки бесшумных сообщений/сообщений-бомбочек
|
||||
* Отключить уведомление о том, что вы сделали скриншот в беседе
|
||||
* Отключение редиректа через away.php
|
||||
* Отключение отправки метрики
|
||||
* Внешний вид
|
||||
* **Milkshake** тема (дизайн новых версий ВК)
|
||||
* Название заголовков в докбаре
|
||||
@@ -108,17 +103,14 @@
|
||||
* Возможность отключить блок историй наверху ленты
|
||||
* Возможность отключить боковую камеру в разделе «Новости»
|
||||
* Возможность отключить блок «Что у вас нового?» в разделе «Новости»
|
||||
* Возможность показывать лайки у постов справа
|
||||
* Возможность менять стартовый раздел при запуске приложения
|
||||
* Возможность менять раздел, который запускается при запуске
|
||||
* Анимации фрагментов
|
||||
* Возможность изменять размер закругления картинок (аватарок и прочего)
|
||||
* Возможность отключить редизайн видеопостов
|
||||
* Возможность отключить блок миниаппов/VK Pay/Superapp
|
||||
* Возможность отключить сокращение названий разделов в меню
|
||||
* Возможность скрыть блок рекомендаций друзей в разделе «Друзья»
|
||||
* Возможность скрыть подписи в настройках
|
||||
* Прокси
|
||||
* Поддержка сторонних прокси, таких как: Zaborona, VikaMobile, рандомные прокси и прочие
|
||||
* Возможность использовать **HTTP/HTTPS/SOCKS** прокси, менять домены **API/OAuth/Static**
|
||||
* Другое
|
||||
* Очистка кеша приложения (**всё/стикеры/изображения/видео/сообщения/WebView**)
|
||||
|
||||
+5
-3
@@ -69,15 +69,16 @@ task exportDex {
|
||||
|
||||
android {
|
||||
compileSdkVersion 32
|
||||
buildToolsVersion '33.0.0'
|
||||
buildToolsVersion '32.0.0'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "ru.vtosters.lite.utils.lite"
|
||||
minSdk 22
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 32
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
multiDexEnabled false
|
||||
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
@@ -88,6 +89,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.multidex:multidex:2.0.1"
|
||||
implementation 'com.google.android.material:material:1.6.1'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -16,7 +16,6 @@ import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
/**
|
||||
* Created by Aefyr on 20.05.2018.
|
||||
@@ -40,7 +39,7 @@ public class NotificationsHelper {
|
||||
downloadingPacksNotificationsIds = new HashMap<>();
|
||||
|
||||
if (oreo()) {
|
||||
NotificationChannel notificationChan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, AndroidUtils.getString("telegram_stickers_service"), NotificationManager.IMPORTANCE_HIGH);
|
||||
NotificationChannel notificationChan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "Сервис стикеров Telegram в VTosters", NotificationManager.IMPORTANCE_HIGH);
|
||||
((NotificationManager) c.getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(notificationChan);
|
||||
}
|
||||
}
|
||||
@@ -50,8 +49,8 @@ public class NotificationsHelper {
|
||||
downloadingPacksNotificationsIds.put(pack, notificationId);
|
||||
|
||||
Notification.Builder builder = commonBuilder();
|
||||
builder.setContentTitle(pack.state == TelegramStickersPack.DOWNLOADING ? pack.title + AndroidUtils.getString("telegram_stickers_downloading") : pack.title + AndroidUtils.getString("telegram_stickers_updating"));
|
||||
builder.setContentText(AndroidUtils.getString("telegram_stickers_gettinginfo"));
|
||||
builder.setContentTitle(pack.state == TelegramStickersPack.DOWNLOADING ? pack.title + ": загрузка" : pack.title + ": обновление");
|
||||
builder.setContentText("Получение информации");
|
||||
builder.setOngoing(true);
|
||||
|
||||
manager.notify(notificationId, builder.build());
|
||||
@@ -64,7 +63,7 @@ public class NotificationsHelper {
|
||||
lastNotificationTime.set(System.currentTimeMillis());
|
||||
|
||||
Notification.Builder builder = commonBuilder();
|
||||
builder.setContentTitle(pack.state == TelegramStickersPack.DOWNLOADING ? pack.title + AndroidUtils.getString("telegram_stickers_downloading") : pack.title + AndroidUtils.getString("telegram_stickers_updating"));
|
||||
builder.setContentTitle(pack.state == TelegramStickersPack.DOWNLOADING ? pack.title + ": загрузка" : pack.title + ": обновление");
|
||||
builder.setContentText(downloadProgress + "/" + pack.stickersCount);
|
||||
builder.setProgress(pack.stickersCount, downloadProgress, false);
|
||||
builder.setOngoing(true);
|
||||
@@ -78,13 +77,13 @@ public class NotificationsHelper {
|
||||
Notification.Builder builder = commonBuilder();
|
||||
builder.setProgress(0, 0, false);
|
||||
builder.setOngoing(false);
|
||||
builder.setContentTitle(AndroidUtils.getString("telegram_stickers_service"));
|
||||
builder.setContentTitle("Сервис стикеров Telegram в VTosters");
|
||||
|
||||
String text;
|
||||
if (success)
|
||||
text = wasUpdate ? pack.title + AndroidUtils.getString("telegram_stickers_updated") : pack.title + AndroidUtils.getString("telegram_stickers_downloaded");
|
||||
text = wasUpdate ? pack.title + " успешно обновлен" : pack.title + " успешно загружен";
|
||||
else
|
||||
text = wasUpdate ? pack.title + AndroidUtils.getString("telegram_stickers_error_update") : pack.title + AndroidUtils.getString("telegram_stickers_error_download");
|
||||
text = wasUpdate ? pack.title + ": ошибка при обновлении" : pack.title + ": ошибка при загрузке";
|
||||
|
||||
if (e instanceof TelegramStickersGrabber.TSGException) {
|
||||
text = pack.title + ": " + e.getMessage();
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.vk.core.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
public class VKLayoutInflater extends LayoutInflater {
|
||||
|
||||
private final static String[] DEFAULT_PACKAGES = {
|
||||
"android.widget.", "android.webkit.", "android.app."
|
||||
};
|
||||
|
||||
public VKLayoutInflater(LayoutInflater original, Context context) {
|
||||
super(original, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutInflater cloneInContext(Context newContext) {
|
||||
return new VKLayoutInflater(this, newContext);
|
||||
}
|
||||
|
||||
public final View createView(View parent, String name, Context context, AttributeSet attrs) {
|
||||
if (!name.startsWith("android.")) {
|
||||
try {
|
||||
return onCreateView(parent, name, attrs);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
try {
|
||||
return createView(name, null, attrs);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
|
||||
for (var defPackage : DEFAULT_PACKAGES) {
|
||||
try {
|
||||
View view = createView(name, defPackage, attrs);
|
||||
if (view != null) return view;
|
||||
} catch (ClassCastException | ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return super.onCreateView(name, attrs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.vk.core.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.InflateException;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.core.util.OsUtil;
|
||||
import com.vk.core.view.NavigationSpinner;
|
||||
import com.vk.core.view.TextViewColorStateListAndAlphaSupportPreV23;
|
||||
import com.vk.core.view.VKAppBarLayout;
|
||||
|
||||
public class VKUILayoutFactory implements LayoutInflater.Factory2 {
|
||||
|
||||
private final static int[] FONT_ATTR = { android.R.attr.font };
|
||||
private AppCompatDelegate mDelegate;
|
||||
private VKLayoutInflater mInflater;
|
||||
|
||||
public VKUILayoutFactory(AppCompatDelegate delegate, VKLayoutInflater inflater) {
|
||||
mDelegate = delegate;
|
||||
mInflater = inflater;
|
||||
}
|
||||
|
||||
private void setTypeface(TextView textView, Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, FONT_ATTR, android.R.attr.textViewStyle, 0);
|
||||
if (ta == null) return;
|
||||
Font font = Font.Companion.a(ta.getString(0));
|
||||
if (font != null && Build.VERSION.SDK_INT < font.a())
|
||||
textView.setTypeface(font.c());
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
|
||||
View view = null;
|
||||
try {
|
||||
if (!(parent instanceof NavigationSpinner) && !OsUtil.b())
|
||||
view = new TextViewColorStateListAndAlphaSupportPreV23(context, attrs, 0);
|
||||
else if (mDelegate != null)
|
||||
view = mDelegate.createView(parent, name, context, attrs);
|
||||
else if (mInflater != null)
|
||||
view = mInflater.createView(parent, name, context, attrs);
|
||||
} catch (Throwable unused) {
|
||||
throw new InflateException(
|
||||
"parent=" + parent.getClass().getName()
|
||||
+ ":" + getResourceIdName(view)
|
||||
+ ", view=" + name
|
||||
+ ":" + getResourceIdName(context, attrs));
|
||||
}
|
||||
if (view == null &&
|
||||
("com.google.android.material.appbar.AppBarLayout".equals(name)
|
||||
|| "android.support.design.widget.AppBarLayout".equals(name)))
|
||||
view = new VKAppBarLayout(context, attrs);
|
||||
|
||||
if (view != null) {
|
||||
if (!(view.getTag() instanceof String)) {
|
||||
if (view instanceof TextView) {
|
||||
setTypeface((TextView) view, context, attrs);
|
||||
if (view instanceof CheckBox)
|
||||
VKThemeHelper.k.a((CheckBox) view);
|
||||
else if (view instanceof RadioButton)
|
||||
VKThemeHelper.k.a((RadioButton) view);
|
||||
else if (view instanceof SwitchCompat)
|
||||
VKThemeHelper.k.a((SwitchCompat) view);
|
||||
else if (view instanceof Switch)
|
||||
VKThemeHelper.k.a((Switch) view);
|
||||
} else if (view instanceof WebView) {
|
||||
VKThemeHelper.a((WebView) view);
|
||||
}
|
||||
VKThemeHelper.k.a(view, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private String getResourceIdName(View view) {
|
||||
try {
|
||||
if (view != null) {
|
||||
if (view.getId() != -1)
|
||||
return view.getResources().getResourceName(view.getId());
|
||||
return "NO_ID";
|
||||
}
|
||||
return "null";
|
||||
} catch (Throwable unused) {
|
||||
return "FAILED_TO_GET_ID";
|
||||
}
|
||||
}
|
||||
|
||||
private String getResourceIdName(Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.id });
|
||||
int resId = ta.getResourceId(0, -1);
|
||||
ta.recycle();
|
||||
return resId != -1
|
||||
? context.getResources().getResourceName(resId)
|
||||
: "NO_ID";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
|
||||
return onCreateView(null, name, context, attrs);
|
||||
}
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
package com.vk.core.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.common.i.MediaUtils;
|
||||
import com.facebook.x.g.EncodedImage;
|
||||
import com.vk.core.concurrent.VkExecutors;
|
||||
import com.vk.imageloader.VKImageLoader;
|
||||
import com.vk.log.L;
|
||||
import com.vk.metrics.eventtracking.VkTracker;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
|
||||
import b.h.g.m.CameraUtils;
|
||||
import b.h.g.m.FileUtils;
|
||||
|
||||
public class DownloadUtils {
|
||||
public static final HashSet<Long> a = new HashSet<>();
|
||||
|
||||
public static void a(Context context, String str, String str2) {
|
||||
a(context, str, str2, false);
|
||||
}
|
||||
|
||||
public static void b(Context context, String str, String str2) {
|
||||
a(context, str, str2, true);
|
||||
}
|
||||
|
||||
private static void a(Context context, String str, String str2, boolean z) {
|
||||
try {
|
||||
b(context, str, str2, z);
|
||||
} catch (Exception e2) {
|
||||
L.d(e2);
|
||||
ToastUtils.a(context.getString(R.string.error) + " [" + e2.getMessage() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private static void b(final Context context, String str, String uri, boolean z) {
|
||||
if (TextUtils.isEmpty(uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fileName = a(str, uri);
|
||||
File file;
|
||||
|
||||
Log.v("DownloadUtils", "download: filename = " + fileName + " | str = " + str + "| str2 = " + uri);
|
||||
|
||||
if (fileName.endsWith(".jpg") || fileName.endsWith(".png") || fileName.endsWith(".jpeg")) {
|
||||
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath(), fileName);
|
||||
} else if (fileName.endsWith(".mp3") || fileName.endsWith(".wav") || fileName.endsWith(".ogg") || fileName.endsWith(".aac") || fileName.endsWith(".flac") || fileName.endsWith(".m4a")) {
|
||||
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath(), fileName);
|
||||
} else if (fileName.endsWith(".mp4") || fileName.endsWith(".mkv") || fileName.endsWith(".avi") || fileName.endsWith(".flv") || fileName.endsWith(".wmv") || fileName.endsWith(".mov") || fileName.endsWith(".3gp")) {
|
||||
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath(), fileName);
|
||||
} else {
|
||||
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(), fileName);
|
||||
}
|
||||
|
||||
boolean isImage = MediaUtils.c(FileUtils.f(file));
|
||||
|
||||
if (isImage) {
|
||||
EncodedImage encodedImage = VKImageLoader.c(Uri.parse(uri));
|
||||
final InputStream h = encodedImage == null ? null : encodedImage.h();
|
||||
if (h != null) {
|
||||
try {
|
||||
if (file.getParentFile() != null) {
|
||||
file.createNewFile();
|
||||
}
|
||||
if (file.exists()) {
|
||||
VkExecutors.x.e().execute(() -> {
|
||||
try {
|
||||
FileUtils.b.a(h, new FileOutputStream(file), h.available(), null);
|
||||
ToastUtils.a(context.getString(R.string.file_saved, file.getAbsoluteFile()));
|
||||
} catch (IOException e) {
|
||||
ToastUtils.a(context.getString(R.string.error) + " [" + e.getMessage() + "]");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} catch (Exception e2) {
|
||||
L.a(e2);
|
||||
}
|
||||
|
||||
CameraUtils.a(context, file, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(uri));
|
||||
var mimeType = FileUtils.f(file);
|
||||
request.setDestinationUri(Uri.fromFile(file));
|
||||
request.setMimeType(mimeType);
|
||||
request.setNotificationVisibility(1);
|
||||
request.allowScanningByMediaScanner();
|
||||
request.setTitle(str);
|
||||
DownloadManager a2 = a(context);
|
||||
if (a2 == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
long enqueue = a2.enqueue(request);
|
||||
if (!z) {
|
||||
return;
|
||||
}
|
||||
a.add(enqueue);
|
||||
} catch (IllegalArgumentException e3) {
|
||||
L.a(e3);
|
||||
b(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static String a(String str, String str2) {
|
||||
String lastPathSegment = Uri.parse(str2).getLastPathSegment();
|
||||
if (!TextUtils.isEmpty(str)) {
|
||||
String replace = str.replace('/', '_');
|
||||
return !replace.contains(".") ? lastPathSegment : replace;
|
||||
}
|
||||
return lastPathSegment;
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("Range")
|
||||
public static boolean a(Context context, Uri uri) {
|
||||
try {
|
||||
Cursor query = a(context).query(new DownloadManager.Query().setFilterByStatus(11));
|
||||
if (query != null && query.moveToFirst()) {
|
||||
while (!uri.toString().equals(query.getString(query.getColumnIndex("uri")))) {
|
||||
if (!query.moveToNext()) {
|
||||
query.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@SuppressLint("Range")
|
||||
int i = query.getInt(query.getColumnIndex("status"));
|
||||
@SuppressLint("Range")
|
||||
String string = query.getString(query.getColumnIndex("local_uri"));
|
||||
query.close();
|
||||
if (i == 1 || i == 2) {
|
||||
ToastUtils.a(R.string.download_is_in_progress);
|
||||
query.close();
|
||||
return true;
|
||||
} else if (i != 8) {
|
||||
query.close();
|
||||
return false;
|
||||
} else {
|
||||
boolean a2 = a(context, string);
|
||||
query.close();
|
||||
return a2;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (SQLiteException e2) {
|
||||
VkTracker.k.b(e2);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void b(Context context) {
|
||||
if (context != null) {
|
||||
try {
|
||||
context.startActivity(new Intent("android.settings.APPLICATION_DETAILS_SETTINGS").setData(Uri.parse("package:com.android.providers.downloads")));
|
||||
} catch (ActivityNotFoundException e2) {
|
||||
L.a(e2);
|
||||
context.startActivity(new Intent("android.settings.MANAGE_APPLICATIONS_SETTINGS"));
|
||||
}
|
||||
ToastUtils.a("Please enable download manager", true);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean a(Context context, String str) {
|
||||
File file;
|
||||
try {
|
||||
try {
|
||||
file = new File(new URI(str));
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
Intent intent = new Intent("android.intent.action.VIEW");
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
var mimeType = FileUtils.f(file);
|
||||
var uri = FileUtils.uriFromFile(file);
|
||||
Log.d("DownloadUtils", "openFile: " + file.getAbsolutePath() + "| mimetype " + mimeType + "| uri " + uri);
|
||||
if (!TextUtils.isEmpty(mimeType)) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setDataAndType(uri, mimeType);
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
throw new ActivityNotFoundException();
|
||||
} catch (ActivityNotFoundException unused) {
|
||||
return a(context, file);
|
||||
}
|
||||
} catch (ActivityNotFoundException unused2) {
|
||||
unused2.printStackTrace();
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
VkTracker.k.b(th);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean a(Context context, File file) {
|
||||
if (file != null && file.exists()) {
|
||||
var mimeType = FileUtils.f(file);
|
||||
var uri = FileUtils.uriFromFile(file);
|
||||
|
||||
Intent intent = new Intent("android.intent.action.VIEW");
|
||||
intent.setDataAndType(uri, mimeType);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
Log.d("DownloadUtils", "openFile: " + file.getAbsolutePath() + "| mimetype " + mimeType + "| uri " + uri);
|
||||
try {
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
} catch (ActivityNotFoundException e2) {
|
||||
L.a(e2);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static DownloadManager a(Context context) {
|
||||
return (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,4 @@ public enum DialogAction {
|
||||
DNT_OFF,
|
||||
pinmsg,
|
||||
unpinmsg,
|
||||
ENCRYPT_SETT,
|
||||
ENCRYPT,
|
||||
DOWNLOAD
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ public final class DialogActionsHelper {
|
||||
CollectionExt.a(arrayList, DialogAction.NOTIFICATIONS_OFF, dialog.b(b2));
|
||||
return arrayList;
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
package com.vk.im.ui.views;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class Corners{
|
||||
private int topLeft;
|
||||
private int topRight;
|
||||
private int bottomLeft;
|
||||
private int bottomRight;
|
||||
|
||||
public Corners(int i, int i2, int i3, int i4){
|
||||
this.topLeft = i;
|
||||
this.topRight = i2;
|
||||
this.bottomLeft = i3;
|
||||
this.bottomRight = i4;
|
||||
}
|
||||
|
||||
public Corners(int i, int i2, int i3, int i4, int i5) {
|
||||
this((i5 & 1) != 0 ? 0 : i, (i5 & 2) != 0 ? 0 : i2, (i5 & 4) != 0 ? 0 : i3, (i5 & 8) != 0 ? 0 : i4);
|
||||
}
|
||||
|
||||
public Corners() {
|
||||
this(0, 0, 0, 0, 15);
|
||||
}
|
||||
|
||||
public static Corners a(Corners corners, int i, int i2, int i3, int i4, int i5, Object obj){
|
||||
if ((i5 & 1) != 0) {
|
||||
i = corners.topLeft;
|
||||
}
|
||||
if ((i5 & 2) != 0) {
|
||||
i2 = corners.topRight;
|
||||
}
|
||||
if ((i5 & 4) != 0) {
|
||||
i3 = corners.bottomLeft;
|
||||
}
|
||||
if ((i5 & 8) != 0) {
|
||||
i4 = corners.bottomRight;
|
||||
}
|
||||
corners.a(i, i2, i3, i4);
|
||||
return corners;
|
||||
}
|
||||
|
||||
public int a(){
|
||||
return this.bottomLeft;
|
||||
}
|
||||
|
||||
public int b(){
|
||||
return this.bottomRight;
|
||||
}
|
||||
|
||||
public int c(){
|
||||
return this.topLeft;
|
||||
}
|
||||
|
||||
public int d(){
|
||||
return this.topRight;
|
||||
}
|
||||
|
||||
public boolean e(){
|
||||
int i;
|
||||
int i2 = this.topLeft;
|
||||
int i3 = this.topRight;
|
||||
return i2 == i3 && i3 == (i = this.bottomRight) && this.bottomLeft == i;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj){
|
||||
if (this != obj) {
|
||||
if (!(obj instanceof Corners)) {
|
||||
return false;
|
||||
}
|
||||
Corners corners = (Corners) obj;
|
||||
return this.topLeft == corners.topLeft && this.topRight == corners.topRight && this.bottomLeft == corners.bottomLeft && this.bottomRight == corners.bottomRight;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean f(){
|
||||
return this.topLeft == 0 && e();
|
||||
}
|
||||
|
||||
public void g(){
|
||||
a(0, 0);
|
||||
}
|
||||
|
||||
public int hashCode(){
|
||||
return (((((this.topLeft * 31) + this.topRight) * 31) + this.bottomLeft) * 31) + this.bottomRight;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String toString(){
|
||||
return "Corners(topLeft=" + this.topLeft + ", topRight=" + this.topRight + ", bottomLeft=" + this.bottomLeft + ", bottomRight=" + this.bottomRight + ")";
|
||||
}
|
||||
|
||||
public Corners a(int i, int i2){
|
||||
if ((i2 & 1) > 0) {
|
||||
this.topLeft = i;
|
||||
}
|
||||
if ((i2 & 2) > 0) {
|
||||
this.topRight = i;
|
||||
}
|
||||
if ((i2 & 4) > 0) {
|
||||
this.bottomLeft = i;
|
||||
}
|
||||
if ((i2 & 8) > 0) {
|
||||
this.bottomRight = i;
|
||||
}
|
||||
if (i2 == 0) {
|
||||
this.topLeft = 0;
|
||||
this.topRight = 0;
|
||||
this.bottomLeft = 0;
|
||||
this.bottomRight = 0;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Corners a(int i, int i2, int i3, int i4){
|
||||
this.topLeft = i;
|
||||
this.topRight = i2;
|
||||
this.bottomLeft = i3;
|
||||
this.bottomRight = i4;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Corners a(Corners corners){
|
||||
this.topLeft = corners.topLeft;
|
||||
this.topRight = corners.topRight;
|
||||
this.bottomLeft = corners.bottomLeft;
|
||||
this.bottomRight = corners.bottomRight;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package com.vk.im.ui.views.avatars;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.vk.im.ui.o;
|
||||
|
||||
public class StoryBorderView extends View {
|
||||
private boolean B;
|
||||
private final Paint a;
|
||||
private LinearGradient f15747b;
|
||||
private int f15748c;
|
||||
private int f15749d;
|
||||
private int f15750e;
|
||||
private int f15751f;
|
||||
private final int g;
|
||||
private final int h;
|
||||
|
||||
public StoryBorderView(Context context) {
|
||||
this(context, null, 0, 6);
|
||||
}
|
||||
|
||||
public StoryBorderView(Context context, AttributeSet attributeSet) {
|
||||
this(context, attributeSet, 0, 4);
|
||||
}
|
||||
|
||||
public StoryBorderView(Context context, AttributeSet attributeSet, int i, int i2) {
|
||||
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
|
||||
}
|
||||
|
||||
public int getBorderColor() {
|
||||
return this.f15749d;
|
||||
}
|
||||
|
||||
public int getBorderGradientEndColor() {
|
||||
return this.h;
|
||||
}
|
||||
|
||||
public int getBorderGradientStartColor() {
|
||||
return this.g;
|
||||
}
|
||||
|
||||
public int getBorderWidth() {
|
||||
return this.f15750e;
|
||||
}
|
||||
|
||||
public int getPadding() {
|
||||
return this.f15751f;
|
||||
}
|
||||
|
||||
public int getViewSize() {
|
||||
return this.f15748c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
canvas.drawOval(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom(), this.a);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int i, int i2) {
|
||||
int i3 = this.f15748c;
|
||||
setMeasuredDimension(i3, i3);
|
||||
}
|
||||
|
||||
public void setBorderColor(int i) {
|
||||
if (this.f15749d != i) {
|
||||
this.f15749d = i;
|
||||
this.a.setColor(i);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setBorderWidth(int i) {
|
||||
if (this.f15750e != i) {
|
||||
this.f15750e = i;
|
||||
this.a.setStrokeWidth(i);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutParams(ViewGroup.LayoutParams layoutParams) {
|
||||
super.setLayoutParams(layoutParams);
|
||||
boolean z = false;
|
||||
this.f15748c = Math.min(layoutParams != null ? layoutParams.width : 0, layoutParams != null ? layoutParams.height : 0);
|
||||
this.f15747b = new LinearGradient(0.0f, 0.0f, 0.0f, this.f15748c, this.g, this.h, Shader.TileMode.MIRROR);
|
||||
if (this.f15748c > 0) {
|
||||
z = true;
|
||||
}
|
||||
if (z) {
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("Only exact size supported, specify avatar sizes in layout params");
|
||||
}
|
||||
|
||||
public void setLive(boolean z) {
|
||||
if (this.B != z) {
|
||||
this.a.setShader(z ? this.f15747b : null);
|
||||
this.a.setColor(z ? -1 : this.f15749d);
|
||||
this.B = z;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPadding(int i) {
|
||||
if (this.f15751f != i) {
|
||||
this.f15751f = i;
|
||||
setPadding(i, i, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewSize(int i) {
|
||||
this.f15748c = i;
|
||||
}
|
||||
|
||||
public StoryBorderView(Context context, AttributeSet attributeSet, int i) {
|
||||
super(context, attributeSet, i);
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
this.a = paint;
|
||||
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, o.StoryBorderView);
|
||||
setBorderColor(obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderColor, 0));
|
||||
this.g = obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderGradientStartColor, 0);
|
||||
this.h = obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderGradientEndColor, 0);
|
||||
setBorderWidth(obtainStyledAttributes.getDimensionPixelSize(o.StoryBorderView_vkim_borderWidth, 0));
|
||||
obtainStyledAttributes.recycle();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,106 +0,0 @@
|
||||
package com.vk.profile.ui.community;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.vk.core.ui.themes.Themable;
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.core.util.ContextExtKt;
|
||||
import com.vk.dto.stories.model.StoriesContainer;
|
||||
import com.vk.stories.view.BorderedCircleImageView;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
public final class CommunityBorderedImageView extends BorderedCircleImageView implements Themable{
|
||||
private boolean f0;
|
||||
private int g0;
|
||||
private int h0;
|
||||
private PorterDuffColorFilter i0;
|
||||
private PorterDuffColorFilter j0;
|
||||
private int unread;
|
||||
private int read;
|
||||
|
||||
public CommunityBorderedImageView(Context context){
|
||||
this(context, null, 0, 6);
|
||||
}
|
||||
|
||||
public CommunityBorderedImageView(Context context, AttributeSet attributeSet){
|
||||
this(context, attributeSet, 0, 4);
|
||||
}
|
||||
|
||||
public CommunityBorderedImageView(Context context, AttributeSet attributeSet, int i, int i2){
|
||||
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
|
||||
}
|
||||
|
||||
public CommunityBorderedImageView(Context context, AttributeSet attributeSet, int i){
|
||||
super(context, attributeSet, i);
|
||||
this.g0 = VKThemeHelper.d((int) R.attr.accent);
|
||||
this.h0 = ContextExtKt.a(context, (int) R.color.gray_200);
|
||||
this.i0 = new PorterDuffColorFilter(this.g0, PorterDuff.Mode.SRC_IN);
|
||||
this.j0 = new PorterDuffColorFilter(this.h0, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
public final void c(int unread, int read){ // get unread and read resid
|
||||
this.unread = unread;
|
||||
this.read = read;
|
||||
this.T = BitmapFactory.decodeResource(getResources(), this.unread);
|
||||
}
|
||||
|
||||
public final int getPrimaryColor(){
|
||||
return this.g0;
|
||||
}
|
||||
|
||||
public final void setPrimaryColor(int i){
|
||||
this.g0 = i;
|
||||
this.i0 = new PorterDuffColorFilter(i, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
public final int getWasViewedColor(){
|
||||
return this.h0;
|
||||
}
|
||||
|
||||
public final void setWasViewedColor(int i){
|
||||
this.h0 = i;
|
||||
this.j0 = new PorterDuffColorFilter(i, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
public final void o(){
|
||||
this.f0 = false;
|
||||
l();
|
||||
}
|
||||
|
||||
@Override // com.vk.stories.view.ClippedImageView, android.widget.ImageView, android.view.View
|
||||
public void onDraw(Canvas canvas){
|
||||
super.onDraw(canvas);
|
||||
if (this.f0) {
|
||||
a(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
public final void setStoryContainer(StoriesContainer storiesContainer){
|
||||
if (storiesContainer.L1()) {
|
||||
this.f0 = true;
|
||||
m();
|
||||
if (storiesContainer.K1()) {
|
||||
this.T = BitmapFactory.decodeResource(getResources(), this.unread);
|
||||
setBorderColorFilter(this.i0);
|
||||
b(getWidth(), getHeight());
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
this.T = BitmapFactory.decodeResource(getResources(), this.read);
|
||||
setBorderColorFilter(this.j0);
|
||||
b(getWidth(), getHeight());
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
o();
|
||||
}
|
||||
|
||||
@Override // com.vk.core.ui.themes.Themable
|
||||
public void v(){
|
||||
}
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
package com.vk.sharing.view;
|
||||
|
||||
import static b.h.z.f.roboto_medium;
|
||||
import static ru.vtosters.lite.utils.Preferences.preferences;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.view.DraweeHolder;
|
||||
import com.vk.core.util.ContextExtKt;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.im.ui.views.avatars.AbbreviationAvatarDrawable;
|
||||
import com.vk.imageloader.view.VKMultiImageView;
|
||||
import com.vk.navigation.NavigatorKeys;
|
||||
import com.vtosters.lite.R;
|
||||
import com.vtosters.lite.a0;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@UiThread
|
||||
public class TargetImageView extends VKMultiImageView {
|
||||
private static final int I = Screen.a(2);
|
||||
private final int B;
|
||||
private final int C;
|
||||
private Drawable D;
|
||||
private String[] F;
|
||||
private int G;
|
||||
private final RectF f21629d;
|
||||
private final Paint f21630e;
|
||||
private Canvas f21631f;
|
||||
private final RectF g;
|
||||
private final Paint h;
|
||||
|
||||
public TargetImageView(Context context, Drawable d) {
|
||||
this(context, null, 0, 6);
|
||||
}
|
||||
|
||||
public TargetImageView(Context context, AttributeSet attributeSet) {
|
||||
this(context, attributeSet, 0, 4);
|
||||
}
|
||||
|
||||
public TargetImageView(Context context, AttributeSet attributeSet, int i, int i2) {
|
||||
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
|
||||
}
|
||||
|
||||
private void e() {
|
||||
int i = this.G;
|
||||
for (int i2 = 0; i2 < i; i2++) {
|
||||
a(i2, this.F[i2]);
|
||||
}
|
||||
}
|
||||
|
||||
private void f() {
|
||||
int paddingLeft = getPaddingLeft();
|
||||
int paddingTop = getPaddingTop();
|
||||
int width = (getWidth() - paddingLeft) - getPaddingRight();
|
||||
int height = (getHeight() - paddingTop) - getPaddingBottom();
|
||||
int i = width / 2;
|
||||
int i2 = height / 2;
|
||||
int i3 = this.G;
|
||||
if (i3 == 1) {
|
||||
DraweeHolder<GenericDraweeHierarchy> a2 = this.a.a(0);
|
||||
Drawable d2 = a2.d();
|
||||
if (d2 != null) {
|
||||
d2.setBounds(paddingLeft, paddingTop, width + paddingLeft, height + paddingTop);
|
||||
}
|
||||
} else if (i3 == 2) {
|
||||
DraweeHolder<GenericDraweeHierarchy> a3 = this.a.a(0);
|
||||
Drawable d3 = a3.d();
|
||||
if (d3 != null) {
|
||||
int i4 = i + paddingLeft;
|
||||
int i5 = height + paddingTop;
|
||||
d3.setBounds(paddingLeft, paddingTop, i4, i5);
|
||||
DraweeHolder<GenericDraweeHierarchy> a4 = this.a.a(1);
|
||||
Drawable d4 = a4.d();
|
||||
if (d4 != null) {
|
||||
d4.setBounds(i4, paddingTop, paddingLeft + width, i5);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (i3 == 3) {
|
||||
DraweeHolder<GenericDraweeHierarchy> a5 = this.a.a(0);
|
||||
Drawable d5 = a5.d();
|
||||
if (d5 != null) {
|
||||
int i6 = i + paddingLeft;
|
||||
int i7 = height + paddingTop;
|
||||
d5.setBounds(paddingLeft, paddingTop, i6, i7);
|
||||
DraweeHolder<GenericDraweeHierarchy> a6 = this.a.a(1);
|
||||
Drawable d6 = a6.d();
|
||||
if (d6 != null) {
|
||||
int i9 = paddingLeft + width;
|
||||
int i10 = i2 + paddingTop;
|
||||
d6.setBounds(i6, paddingTop, i9, i10);
|
||||
DraweeHolder<GenericDraweeHierarchy> a7 = this.a.a(2);
|
||||
Drawable d7 = a7.d();
|
||||
if (d7 != null) {
|
||||
d7.setBounds(i6, i10, i9, i7);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
DraweeHolder<GenericDraweeHierarchy> a8 = this.a.a(0);
|
||||
Drawable d8 = a8.d();
|
||||
if (d8 != null) {
|
||||
int i11 = i + paddingLeft;
|
||||
int i13 = i2 + paddingTop;
|
||||
d8.setBounds(paddingLeft, paddingTop, i11, i13);
|
||||
DraweeHolder<GenericDraweeHierarchy> a9 = this.a.a(1);
|
||||
Drawable d9 = a9.d();
|
||||
if (d9 != null) {
|
||||
int i16 = height + paddingTop;
|
||||
d9.setBounds(paddingLeft, i13, i11, i16);
|
||||
DraweeHolder<GenericDraweeHierarchy> a10 = this.a.a(2);
|
||||
Drawable d10 = a10.d();
|
||||
if (d10 != null) {
|
||||
int i18 = paddingLeft + width;
|
||||
d10.setBounds(i11, paddingTop, i18, i13);
|
||||
DraweeHolder<GenericDraweeHierarchy> a11 = this.a.a(3);
|
||||
Drawable d11 = a11.d();
|
||||
if (d11 != null) {
|
||||
d11.setBounds(i11, i13, i18, i16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void g() {
|
||||
if (getWidth() == 0 || getHeight() == 0) {
|
||||
return;
|
||||
}
|
||||
f();
|
||||
}
|
||||
|
||||
private AbbreviationAvatarDrawable getAbbreviationDrawable() {
|
||||
return a(getContext(), null, 2);
|
||||
}
|
||||
|
||||
private AbbreviationAvatarDrawable a(Context context, Typeface typeface, int i) {
|
||||
return new AbbreviationAvatarDrawable(context, (i & 2) != 0 ? ContextExtKt.e(context, roboto_medium) : typeface);
|
||||
}
|
||||
|
||||
public void a(String str) {
|
||||
Arrays.fill(this.F, null);
|
||||
if (str == null) {
|
||||
b();
|
||||
this.G = 1;
|
||||
g();
|
||||
e();
|
||||
return;
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(str);
|
||||
if (uri.getScheme().equals("vkchatphoto")) {
|
||||
this.G = 0;
|
||||
while (true) {
|
||||
String queryParameter = uri.getQueryParameter("photo" + this.G);
|
||||
if (queryParameter != null) {
|
||||
int i = this.G;
|
||||
this.G = i + 1;
|
||||
this.F[i] = queryParameter;
|
||||
} else {
|
||||
g();
|
||||
e();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (uri.getScheme().equals("vkchatplaceholder")) {
|
||||
this.G = 1;
|
||||
g();
|
||||
AbbreviationAvatarDrawable abbreviationDrawable = getAbbreviationDrawable();
|
||||
String queryParameter2 = uri.getQueryParameter(NavigatorKeys.Q);
|
||||
int parseInt = queryParameter2 != null ? Integer.parseInt(queryParameter2) : 0;
|
||||
String queryParameter3 = uri.getQueryParameter(NavigatorKeys.d);
|
||||
if (queryParameter3 == null) {
|
||||
queryParameter3 = "";
|
||||
}
|
||||
abbreviationDrawable.a(parseInt, queryParameter3);
|
||||
a(0, getAbbreviationDrawable());
|
||||
} else {
|
||||
this.F[0] = str;
|
||||
this.G = 1;
|
||||
g();
|
||||
e();
|
||||
}
|
||||
}
|
||||
|
||||
@Override // android.view.View
|
||||
protected void onDraw(Canvas canvas) {
|
||||
Canvas canvas2 = this.f21631f;
|
||||
int pref = preferences.getInt("pic_rounding", 0);
|
||||
|
||||
if (canvas2 != null) {
|
||||
canvas2.drawColor(0, PorterDuff.Mode.CLEAR);
|
||||
}
|
||||
int i = this.G;
|
||||
for (int i2 = 0; i2 < i; i2++) {
|
||||
DraweeHolder<GenericDraweeHierarchy> a2 = this.a.a(i2);
|
||||
Drawable d2 = a2.d();
|
||||
if (d2 != null) {
|
||||
Canvas canvas3 = this.f21631f;
|
||||
d2.draw(canvas3);
|
||||
}
|
||||
}
|
||||
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(this.f21629d, pref, pref, this.f21630e);
|
||||
} else {
|
||||
canvas.drawOval(this.f21629d, this.f21630e);
|
||||
}
|
||||
|
||||
if (isSelected()) {
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(this.g.left, this.g.top, this.g.right, this.g.bottom, pref, pref, this.h);
|
||||
} else {
|
||||
canvas.drawCircle(this.g.centerX(), this.g.centerY(), this.g.width() / 2, this.h);
|
||||
}
|
||||
|
||||
this.D.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // android.view.View
|
||||
protected void onSizeChanged(int i, int i2, int i3, int i4) {
|
||||
super.onSizeChanged(i, i2, i3, i4);
|
||||
int paddingLeft = getPaddingLeft();
|
||||
int paddingRight = getPaddingRight();
|
||||
int paddingTop = getPaddingTop();
|
||||
int i5 = i - paddingRight;
|
||||
int paddingBottom = i2 - getPaddingBottom();
|
||||
this.f21629d.set(paddingLeft, paddingTop, i5, paddingBottom);
|
||||
Bitmap createBitmap = Bitmap.createBitmap(i5, paddingBottom, Bitmap.Config.ARGB_8888);
|
||||
this.f21631f = new Canvas(createBitmap);
|
||||
Shader.TileMode tileMode = Shader.TileMode.CLAMP;
|
||||
this.f21630e.setShader(new BitmapShader(createBitmap, tileMode, tileMode));
|
||||
float f2 = I / 2;
|
||||
this.g.set(f2, f2, i - f2, (float) i2 - f2);
|
||||
float f4 = i / 2;
|
||||
this.h.setShader(new LinearGradient(f4, 0.0f, f4, (float) i2, this.B, this.C, Shader.TileMode.CLAMP));
|
||||
Drawable drawable = this.D;
|
||||
drawable.setBounds(i - drawable.getIntrinsicWidth(), i2 - this.D.getIntrinsicHeight(), i, i2);
|
||||
f();
|
||||
}
|
||||
|
||||
public TargetImageView(Context context, AttributeSet attributeSet, int i) {
|
||||
super(context, attributeSet, i);
|
||||
this.f21629d = new RectF();
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setDither(true);
|
||||
paint.setFilterBitmap(true);
|
||||
this.f21630e = paint;
|
||||
this.g = new RectF();
|
||||
Paint paint2 = new Paint();
|
||||
paint2.setAntiAlias(true);
|
||||
paint2.setStrokeWidth(I);
|
||||
paint2.setStyle(Paint.Style.STROKE);
|
||||
this.h = paint2;
|
||||
this.B = getAccentColor();
|
||||
this.C = this.B;
|
||||
Drawable c2 = ContextExtKt.c(context, R.drawable.ic_check_circle_composite_24_full);
|
||||
if (c2 != null) {
|
||||
this.D = c2;
|
||||
this.F = new String[4];
|
||||
int i2 = I * 2;
|
||||
setPadding(i2, i2, i2, i2);
|
||||
if (attributeSet != null) {
|
||||
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, a0.TargetImageView);
|
||||
setSelected(obtainStyledAttributes.getBoolean(0, false));
|
||||
obtainStyledAttributes.recycle();
|
||||
}
|
||||
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.user_placeholder);
|
||||
for (int i3 = 0; i3 <= 3; i3++) {
|
||||
a();
|
||||
DraweeHolder<GenericDraweeHierarchy> a3 = this.a.a(i3);
|
||||
a3.b().e(drawable);
|
||||
}
|
||||
setScaleType(ScalingUtils.b.o);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,442 +0,0 @@
|
||||
package com.vk.stories.view;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.airbnb.lottie.LottieComposition;
|
||||
import com.airbnb.lottie.LottieCompositionFactory;
|
||||
import com.airbnb.lottie.LottieDrawable;
|
||||
import com.airbnb.lottie.LottieListener;
|
||||
import com.facebook.common.internal.Supplier;
|
||||
import com.facebook.common.references.CloseableReference;
|
||||
import com.facebook.datasource.DataSource;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import com.facebook.u.b.a.PipelineDraweeControllerBuilder;
|
||||
import com.facebook.x.g.CloseableImage;
|
||||
import com.vk.core.ui.themes.Themable;
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.core.util.DrawableUtils;
|
||||
import com.vk.core.util.ResUtils;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.dto.stories.d.StoriesContainerExt;
|
||||
import com.vk.dto.stories.model.CommunityGroupedStoriesContainer;
|
||||
import com.vk.dto.stories.model.StoriesContainer;
|
||||
import com.vk.dto.stories.model.StoryEntry;
|
||||
import com.vk.im.engine.models.Image;
|
||||
import com.vk.im.ui.views.avatars.AvatarDataSource;
|
||||
import com.vk.imageloader.FrescoWrapper;
|
||||
import com.vk.stories.StoriesController;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class StoryCircleImageView extends BorderedCircleImageView implements Themable{
|
||||
private static final HashSet<Integer> B0 = new HashSet<>();
|
||||
private final PipelineDraweeControllerBuilder f0;
|
||||
private int A0;
|
||||
private Drawable g0;
|
||||
private Drawable h0;
|
||||
private Drawable i0;
|
||||
private int j0;
|
||||
private int k0;
|
||||
private int l0;
|
||||
private int m0;
|
||||
private int n0;
|
||||
private int o0;
|
||||
private Bitmap p0;
|
||||
private Bitmap q0;
|
||||
private Bitmap r0;
|
||||
private Bitmap s0;
|
||||
private boolean t0;
|
||||
private boolean u0;
|
||||
private boolean v0;
|
||||
private boolean w0;
|
||||
private boolean x0;
|
||||
private String y0;
|
||||
private LottieDrawable z0;
|
||||
|
||||
public StoryCircleImageView(Context context){
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public StoryCircleImageView(Context context, AttributeSet attributeSet){
|
||||
this(context, attributeSet, 0);
|
||||
}
|
||||
|
||||
public StoryCircleImageView(Context context, AttributeSet attributeSet, int i){
|
||||
super(context, attributeSet, i);
|
||||
this.f0 = FrescoWrapper.c.d();
|
||||
a(context, attributeSet, i);
|
||||
}
|
||||
|
||||
private void b(Canvas canvas){
|
||||
this.z0.draw(canvas);
|
||||
}
|
||||
|
||||
private boolean o(){
|
||||
return !this.u0 && !this.t0 && this.z0 == null && !this.w0 && !this.v0;
|
||||
}
|
||||
|
||||
private void p(){
|
||||
this.z0.stop();
|
||||
this.z0 = null;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void q(){
|
||||
int i = this.j0;
|
||||
if (i != 0 && VKThemeHelper.k.a(i)) {
|
||||
this.k0 = VKThemeHelper.d(this.j0);
|
||||
}
|
||||
this.g0 = DrawableUtils.a(this.g0, ColorStateList.valueOf(this.k0));
|
||||
Drawable drawable = this.g0;
|
||||
int i2 = this.A0;
|
||||
this.p0 = DrawableUtils.a(drawable, i2, i2);
|
||||
int i3 = this.l0;
|
||||
if (i3 != 0 && VKThemeHelper.k.a(i3)) {
|
||||
this.m0 = VKThemeHelper.d(this.l0);
|
||||
}
|
||||
int i4 = this.m0;
|
||||
if (i4 != 0) {
|
||||
this.i0 = DrawableUtils.a(this.i0, ColorStateList.valueOf(i4));
|
||||
}
|
||||
int i5 = this.n0;
|
||||
if (i5 != 0 && VKThemeHelper.k.a(i5)) {
|
||||
this.o0 = VKThemeHelper.d(this.n0);
|
||||
}
|
||||
Drawable a2 = DrawableUtils.a(this.g0, ColorStateList.valueOf(0));
|
||||
int i6 = this.A0;
|
||||
DrawableUtils.a(a2, i6, i6);
|
||||
Drawable a3 = DrawableUtils.a(this.h0, ColorStateList.valueOf(this.o0));
|
||||
int i7 = this.A0;
|
||||
this.r0 = DrawableUtils.a(a3, i7, i7);
|
||||
Drawable a4 = DrawableUtils.a(this.g0, ColorStateList.valueOf(ContextCompat.getColor(getContext(), R.color.orange)));
|
||||
int i8 = this.A0;
|
||||
this.s0 = DrawableUtils.a(a4, i8, i8);
|
||||
}
|
||||
|
||||
private void r(){
|
||||
this.c0 = Screen.a(o() ? 0 : 2);
|
||||
m();
|
||||
q();
|
||||
}
|
||||
|
||||
private void setUploadFailed(boolean z){
|
||||
this.u0 = z;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override // com.vk.stories.view.ClippedImageView, android.widget.ImageView, android.view.View
|
||||
public void onDraw(Canvas canvas){
|
||||
super.onDraw(canvas);
|
||||
setBorderAlpha(255);
|
||||
if (this.u0) {
|
||||
this.i0.draw(canvas);
|
||||
} else if (this.t0) {
|
||||
if (this.z0 != null) {
|
||||
b(canvas);
|
||||
return;
|
||||
}
|
||||
this.T = this.x0 ? this.s0 : this.p0;
|
||||
b(getWidth(), getHeight());
|
||||
a(canvas);
|
||||
} else if (this.z0 != null) {
|
||||
p();
|
||||
} else if (!this.w0) {
|
||||
|
||||
} else {
|
||||
this.T = this.r0;
|
||||
setBorderAlpha(163);
|
||||
b(getWidth(), getHeight());
|
||||
a(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // com.vk.stories.view.BorderedCircleImageView, android.view.View
|
||||
public void onSizeChanged(int i, int i2, int i3, int i4){
|
||||
super.onSizeChanged(i, i2, i3, i4);
|
||||
this.i0.setBounds(0, 0, i, i2);
|
||||
b(i);
|
||||
}
|
||||
|
||||
public void setStoryContainer(@Nullable StoriesContainer storiesContainer){
|
||||
boolean z = true;
|
||||
boolean z2 = storiesContainer != null && storiesContainer.Q1();
|
||||
this.v0 = storiesContainer != null && storiesContainer.S1() && !storiesContainer.L1();
|
||||
boolean z3 = storiesContainer instanceof CommunityGroupedStoriesContainer;
|
||||
this.x0 = z3;
|
||||
if (storiesContainer != null) {
|
||||
if (!StoriesContainerExt.c(storiesContainer) && !StoriesContainerExt.d(storiesContainer)) {
|
||||
this.T = this.p0;
|
||||
} else {
|
||||
this.T = this.q0;
|
||||
}
|
||||
b(getWidth(), getHeight());
|
||||
if (StoriesContainerExt.e(storiesContainer)) {
|
||||
a(storiesContainer);
|
||||
} else if (this.z0 != null) {
|
||||
p();
|
||||
}
|
||||
this.w0 = !storiesContainer.K1() && storiesContainer.L1();
|
||||
if (z2) {
|
||||
String h = storiesContainer.h(ResUtils.c(R.dimen.story_preview_image_size));
|
||||
if (h != null) {
|
||||
a(h);
|
||||
} else {
|
||||
g();
|
||||
}
|
||||
if (StoriesController.a(storiesContainer)) {
|
||||
setUploadFailed(true);
|
||||
a(false, false);
|
||||
} else {
|
||||
setUploadFailed(false);
|
||||
if (!storiesContainer.K1() && !StoriesContainerExt.c(storiesContainer)) {
|
||||
a(false, false);
|
||||
} else {
|
||||
StoryEntry A1 = storiesContainer.A1();
|
||||
if (A1 != null) {
|
||||
a(true, !B0.contains(A1.b));
|
||||
B0.add(A1.b);
|
||||
} else {
|
||||
a(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setUploadFailed(false);
|
||||
if (!storiesContainer.K1() && !StoriesContainerExt.c(storiesContainer)) {
|
||||
z = false;
|
||||
}
|
||||
a(z, false);
|
||||
if (z3) {
|
||||
b(((CommunityGroupedStoriesContainer) storiesContainer).j(ResUtils.c(R.dimen.story_preview_image_size)));
|
||||
} else {
|
||||
String h2 = storiesContainer.h(ResUtils.c(R.dimen.story_preview_image_size));
|
||||
if (h2 != null) {
|
||||
a(h2);
|
||||
} else {
|
||||
g();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g();
|
||||
a(false, false);
|
||||
setUploadFailed(false);
|
||||
this.w0 = false;
|
||||
}
|
||||
r();
|
||||
}
|
||||
|
||||
@Override // com.vk.core.ui.themes.Themable
|
||||
public void v(){
|
||||
r();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void b(int i){
|
||||
LottieDrawable lottieDrawable = this.z0;
|
||||
if (lottieDrawable == null || lottieDrawable.e() == null) {
|
||||
return;
|
||||
}
|
||||
this.z0.d(i / this.z0.e().a().width());
|
||||
}
|
||||
|
||||
protected void a(Context context, AttributeSet attributeSet, int i){
|
||||
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, com.vtosters.lite.a0.StoryCircleImageView, i, 0);
|
||||
a(context, attributeSet, obtainStyledAttributes);
|
||||
obtainStyledAttributes.recycle();
|
||||
r();
|
||||
this.T = this.p0;
|
||||
}
|
||||
|
||||
public void b(@Nullable List<String> list){
|
||||
PipelineDraweeControllerBuilder pipelineDraweeControllerBuilder = this.f0;
|
||||
pipelineDraweeControllerBuilder.j();
|
||||
pipelineDraweeControllerBuilder.a(getController());
|
||||
setControllerListener(pipelineDraweeControllerBuilder);
|
||||
a(pipelineDraweeControllerBuilder, list);
|
||||
setController(pipelineDraweeControllerBuilder.k0());
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType")
|
||||
private void a(Context context, AttributeSet attributeSet, TypedArray typedArray){ // bullshit vk code is not working with custom bordered circle image
|
||||
Drawable drawable;
|
||||
this.A0 = typedArray.getDimensionPixelSize(0, Screen.a(64.0f));
|
||||
if (typedArray.hasValue(2)) {
|
||||
this.g0 = typedArray.getDrawable(2);
|
||||
} else {
|
||||
this.g0 = ContextCompat.getDrawable(context, R.drawable.bg_stores_unread_border_80);
|
||||
}
|
||||
if (typedArray.hasValue(3)) {
|
||||
this.h0 = typedArray.getDrawable(3);
|
||||
} else {
|
||||
this.h0 = ContextCompat.getDrawable(context, R.drawable.bg_stores_read_border_80);
|
||||
}
|
||||
|
||||
int b2 = VKThemeHelper.b(attributeSet, "vk_borderTint");
|
||||
if (b2 != 0 && VKThemeHelper.k.a(b2)) {
|
||||
this.j0 = b2;
|
||||
} else if (typedArray.hasValue(5)) {
|
||||
this.k0 = typedArray.getColor(5, 0);
|
||||
} else {
|
||||
this.j0 = R.attr.accent;
|
||||
}
|
||||
|
||||
int b3 = VKThemeHelper.b(attributeSet, "vk_failBorderTint");
|
||||
if (b3 != 0 && VKThemeHelper.k.a(b3)) {
|
||||
this.l0 = b3;
|
||||
} else if (typedArray.hasValue(7)) {
|
||||
this.m0 = typedArray.getColor(7, 0);
|
||||
}
|
||||
|
||||
int b4 = VKThemeHelper.b(attributeSet, "vk_borderSeenTint");
|
||||
if (b4 != 0 && VKThemeHelper.k.a(b4)) {
|
||||
this.n0 = b4;
|
||||
} else if (typedArray.hasValue(4)) {
|
||||
this.o0 = typedArray.getColor(4, 0);
|
||||
} else {
|
||||
this.o0 = 0;
|
||||
}
|
||||
if (typedArray.hasValue(6)) {
|
||||
this.i0 = typedArray.getDrawable(6);
|
||||
} else {
|
||||
this.i0 = ContextCompat.getDrawable(context, R.drawable.ic_story_error_size64);
|
||||
}
|
||||
if (typedArray.hasValue(8)) {
|
||||
drawable = typedArray.getDrawable(8);
|
||||
} else {
|
||||
drawable = ContextCompat.getDrawable(context, R.drawable.bg_live_unread_border);
|
||||
}
|
||||
if (typedArray.hasValue(9)) {
|
||||
this.y0 = typedArray.getString(9);
|
||||
} else {
|
||||
this.y0 = "stories_animation_64.json";
|
||||
}
|
||||
|
||||
int i = this.A0;
|
||||
this.q0 = DrawableUtils.a(Objects.requireNonNull(drawable), i, i);
|
||||
Drawable drawable2 = this.g0;
|
||||
int i2 = this.A0;
|
||||
DrawableUtils.a(drawable2, i2, i2);
|
||||
Drawable drawable3 = this.h0;
|
||||
int i3 = this.A0;
|
||||
this.r0 = DrawableUtils.a(drawable3, i3, i3);
|
||||
Drawable drawable4 = this.g0;
|
||||
int i4 = this.A0;
|
||||
this.s0 = DrawableUtils.a(drawable4, i4, i4);
|
||||
}
|
||||
|
||||
public void a(StoriesContainer storiesContainer){
|
||||
if (this.z0 == null) {
|
||||
LottieCompositionFactory.a(getContext(), this.y0).b(new a(storiesContainer));
|
||||
}
|
||||
}
|
||||
|
||||
public void a(StoriesContainer storiesContainer, LottieComposition lottieComposition){
|
||||
this.z0 = new LottieDrawable();
|
||||
this.z0.a(lottieComposition);
|
||||
this.z0.d(-1);
|
||||
b(getWidth());
|
||||
if (!StoriesContainerExt.f(storiesContainer)) {
|
||||
this.z0.a(new b());
|
||||
this.z0.start();
|
||||
return;
|
||||
}
|
||||
this.z0.stop();
|
||||
}
|
||||
|
||||
private void a(boolean z, boolean z2){
|
||||
k();
|
||||
this.t0 = z;
|
||||
if (!z2) {
|
||||
setSelectionAmount(1.0f);
|
||||
} else {
|
||||
n();
|
||||
}
|
||||
}
|
||||
|
||||
private void a(@NonNull PipelineDraweeControllerBuilder pipelineDraweeControllerBuilder, @Nullable final List<String> list){
|
||||
pipelineDraweeControllerBuilder.b(null);
|
||||
pipelineDraweeControllerBuilder.a((Supplier<DataSource<CloseableReference<com.facebook.x.g.CloseableImage>>>) null);
|
||||
if (list != null && !list.isEmpty()) {
|
||||
if (list.size() == 1) {
|
||||
ImageRequestBuilder b2 = ImageRequestBuilder.b(Uri.parse(list.get(0)));
|
||||
b2.a(ImageRequest.CacheChoice.SMALL);
|
||||
pipelineDraweeControllerBuilder.b(b2.a());
|
||||
return;
|
||||
}
|
||||
|
||||
pipelineDraweeControllerBuilder.a((Supplier<DataSource<CloseableReference<CloseableImage>>>) () -> StoryCircleImageView.this.a(list));
|
||||
return;
|
||||
}
|
||||
pipelineDraweeControllerBuilder.b(null);
|
||||
}
|
||||
|
||||
public DataSource<CloseableReference<CloseableImage>> a(@Nullable List<String> list){
|
||||
ArrayList<Image> arrayList = new ArrayList<>();
|
||||
for (String o : Objects.requireNonNull(list)) {
|
||||
arrayList.add(new Image(-1, -1, o));
|
||||
}
|
||||
return AvatarDataSource.a(arrayList, this.A0, 0);
|
||||
}
|
||||
|
||||
public class a implements LottieListener<LottieComposition>{
|
||||
final StoriesContainer a;
|
||||
|
||||
a(StoriesContainer storiesContainer){
|
||||
this.a = storiesContainer;
|
||||
}
|
||||
|
||||
@Override // com.airbnb.lottie.LottieListener
|
||||
public void a(LottieComposition lottieComposition){
|
||||
if (StoryCircleImageView.this.getWidth() > 0) {
|
||||
StoryCircleImageView.this.a(this.a, lottieComposition);
|
||||
} else {
|
||||
StoryCircleImageView.this.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver$OnGlobalLayoutListenerC0393a(lottieComposition));
|
||||
}
|
||||
}
|
||||
|
||||
public class ViewTreeObserver$OnGlobalLayoutListenerC0393a implements ViewTreeObserver.OnGlobalLayoutListener{
|
||||
final LottieComposition a;
|
||||
|
||||
ViewTreeObserver$OnGlobalLayoutListenerC0393a(LottieComposition lottieComposition){
|
||||
this.a = lottieComposition;
|
||||
}
|
||||
|
||||
@Override // android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||
public void onGlobalLayout(){
|
||||
StoryCircleImageView.this.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
a aVar = a.this;
|
||||
StoryCircleImageView.this.a(aVar.a, this.a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class b implements ValueAnimator.AnimatorUpdateListener{
|
||||
b(){
|
||||
}
|
||||
|
||||
@Override // android.animation.ValueAnimator.AnimatorUpdateListener
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator){
|
||||
StoryCircleImageView.this.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3560,26 +3560,26 @@ public class R {
|
||||
public static final int stickers_notifications_size = 0x7f070285;
|
||||
public static final int stickers_tabs_padding = 0x7f070286;
|
||||
public static final int stickers_tabs_size = 0x7f070287;
|
||||
public static final int stickers_catalog_button_padding_bottom = 0x7f070288;
|
||||
public static final int stickers_catalog_button_padding_left = 0x7f070289;
|
||||
public static final int stickers_catalog_button_padding_right = 0x7f07028a;
|
||||
public static final int stickers_catalog_button_padding_top = 0x7f07028b;
|
||||
public static final int stickers_catalog_double_stacked_slider_image_bg_size = 0x7f07028c;
|
||||
public static final int stickers_catalog_double_stacked_slider_image_corner_radius = 0x7f07028d;
|
||||
public static final int stickers_catalog_double_stacked_slider_image_size = 0x7f07028e;
|
||||
public static final int stickers_catalog_large_slider_image_bg_height = 0x7f07028f;
|
||||
public static final int stickers_catalog_large_slider_image_bg_width = 0x7f070290;
|
||||
public static final int stickers_catalog_large_slider_image_corner_radius = 0x7f070291;
|
||||
public static final int stickers_catalog_large_slider_image_size = 0x7f070292;
|
||||
public static final int stickers_catalog_small_slider_image_bg_size = 0x7f070293;
|
||||
public static final int stickers_catalog_small_slider_image_corner_radius = 0x7f070294;
|
||||
public static final int stickers_catalog_small_slider_image_size = 0x7f070295;
|
||||
public static final int stickers_catalog_triple_stacked_slider_image_bg_size = 0x7f070296;
|
||||
public static final int stickers_catalog_triple_stacked_slider_image_corner_radius = 0x7f070297;
|
||||
public static final int stickers_catalog_triple_stacked_slider_image_size = 0x7f070298;
|
||||
public static final int stickers_catalog_vertical_list_image_bg_size = 0x7f070299;
|
||||
public static final int stickers_catalog_vertical_list_image_corner_radius = 0x7f07029a;
|
||||
public static final int stickers_catalog_vertical_list_image_size = 0x7f07029b;
|
||||
public static final int stiсkers_catalog_button_padding_bottom = 0x7f070288;
|
||||
public static final int stiсkers_catalog_button_padding_left = 0x7f070289;
|
||||
public static final int stiсkers_catalog_button_padding_right = 0x7f07028a;
|
||||
public static final int stiсkers_catalog_button_padding_top = 0x7f07028b;
|
||||
public static final int stiсkers_catalog_double_stacked_slider_image_bg_size = 0x7f07028c;
|
||||
public static final int stiсkers_catalog_double_stacked_slider_image_corner_radius = 0x7f07028d;
|
||||
public static final int stiсkers_catalog_double_stacked_slider_image_size = 0x7f07028e;
|
||||
public static final int stiсkers_catalog_large_slider_image_bg_height = 0x7f07028f;
|
||||
public static final int stiсkers_catalog_large_slider_image_bg_width = 0x7f070290;
|
||||
public static final int stiсkers_catalog_large_slider_image_corner_radius = 0x7f070291;
|
||||
public static final int stiсkers_catalog_large_slider_image_size = 0x7f070292;
|
||||
public static final int stiсkers_catalog_small_slider_image_bg_size = 0x7f070293;
|
||||
public static final int stiсkers_catalog_small_slider_image_corner_radius = 0x7f070294;
|
||||
public static final int stiсkers_catalog_small_slider_image_size = 0x7f070295;
|
||||
public static final int stiсkers_catalog_triple_stacked_slider_image_bg_size = 0x7f070296;
|
||||
public static final int stiсkers_catalog_triple_stacked_slider_image_corner_radius = 0x7f070297;
|
||||
public static final int stiсkers_catalog_triple_stacked_slider_image_size = 0x7f070298;
|
||||
public static final int stiсkers_catalog_vertical_list_image_bg_size = 0x7f070299;
|
||||
public static final int stiсkers_catalog_vertical_list_image_corner_radius = 0x7f07029a;
|
||||
public static final int stiсkers_catalog_vertical_list_image_size = 0x7f07029b;
|
||||
public static final int story_author_title_top_space = 0x7f07029c;
|
||||
public static final int story_cadre_bottom_btn_top_padding = 0x7f07029d;
|
||||
public static final int story_camera_tabs_height = 0x7f07029e;
|
||||
|
||||
+4
-11
@@ -1,6 +1,5 @@
|
||||
package com.vtosters.lite.ui.bottomnavigation;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getCSTDock;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
@@ -220,19 +219,13 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
|
||||
// ViewCompat.setScaleY(mLargeLabel, !mStaticModeEnabled && !checked ? mLargeScale : 1.0f);
|
||||
ViewCompat.setScaleX(mSmallLabel, !mStaticModeEnabled && checked ? mSmallScale : 1.0f);
|
||||
ViewCompat.setScaleY(mSmallLabel, !mStaticModeEnabled && checked ? mSmallScale : 1.0f);
|
||||
// make mLargeLabel and mSmallLabel are bold
|
||||
mLargeLabel.setTypeface(null, Typeface.BOLD);
|
||||
mSmallLabel.setTypeface(null, Typeface.BOLD);
|
||||
|
||||
int textsize;
|
||||
|
||||
if (vkme()){
|
||||
textsize = 11;
|
||||
} else {
|
||||
textsize = 10;
|
||||
}
|
||||
|
||||
mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, textsize);
|
||||
mSmallLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, textsize);
|
||||
// make mLargeLabel and mSmallLabel text size is 10sp
|
||||
mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
|
||||
mSmallLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
|
||||
|
||||
mLargeLabel.setVisibility(/*checked ? VISIBLE :*/ INVISIBLE);
|
||||
mSmallLabel.setVisibility(VISIBLE);//checked ? INVISIBLE : VISIBLE);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package ru.vtosters.lite.deviceinfo;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class Device {
|
||||
private String androidId;
|
||||
private String bluetoothMac;
|
||||
@@ -88,7 +86,6 @@ public class Device {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return "Device{serialId='" + this.serialId + "', androidId='" + this.androidId + "', wifiMac='" + this.wifiMac + "', bluetoothMac='" + this.bluetoothMac + "'}";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package ru.vtosters.lite.deviceinfo;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.Context;
|
||||
import android.net.wifi.WifiInfo;
|
||||
@@ -29,7 +28,6 @@ public class DeviceInfoCollector {
|
||||
private String serialId() {
|
||||
String str;
|
||||
try {
|
||||
@SuppressLint("PrivateApi")
|
||||
Class<?> cls = Class.forName("android.os.SystemProperties");
|
||||
Method method = cls.getMethod("get", String.class);
|
||||
str = (String) method.invoke(cls, "gsm.sn1");
|
||||
@@ -55,7 +53,6 @@ public class DeviceInfoCollector {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
private String androidId(Context context) {
|
||||
return Settings.Secure.getString(context.getContentResolver(), "android_id").toLowerCase();
|
||||
}
|
||||
@@ -102,7 +99,7 @@ public class DeviceInfoCollector {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int length = hardwareAddress.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(String.format("%02X:", hardwareAddress[i]));
|
||||
sb.append(String.format("%02X:", Byte.valueOf(hardwareAddress[i])));
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
|
||||
@@ -1,294 +1,93 @@
|
||||
package ru.vtosters.lite.dnr;
|
||||
|
||||
import static com.vk.im.engine.h.im_ic_done;
|
||||
import static com.vk.im.engine.h.im_ic_edit_msg;
|
||||
import static com.vk.im.engine.h.im_ic_more_vertical;
|
||||
import static com.vk.im.engine.h.im_ic_pinned_msg_hide;
|
||||
import static com.vk.im.engine.h.im_ic_pinned_msg_show;
|
||||
import static com.vk.im.ui.c.im_ic_keyboard;
|
||||
import static ru.vtosters.lite.dnr.DNRModule.hookDNR;
|
||||
import static ru.vtosters.lite.dnr.DNRModule.hookDNT;
|
||||
import static ru.vtosters.lite.dnr.DNRModule.isDnrEnabledFor;
|
||||
import static ru.vtosters.lite.dnr.DNRModule.isDntEnabledFor;
|
||||
import static ru.vtosters.lite.encryption.EncryptProvider.decryptMessage;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.im.engine.ImEngine1;
|
||||
import com.vk.im.engine.events.OnDialogUpdateEvent;
|
||||
import com.vk.im.engine.models.EntityIntMap;
|
||||
import com.vk.im.engine.models.dialogs.Dialog;
|
||||
import com.vk.im.engine.models.messages.Msg;
|
||||
import com.vk.im.engine.models.messages.MsgFromUser;
|
||||
import com.vk.im.ui.components.common.DialogAction;
|
||||
import com.vk.im.ui.components.common.MsgAction;
|
||||
import com.vk.im.ui.components.viewcontrollers.popup.DelegateMsg;
|
||||
import com.vk.im.ui.views.dialog_actions.DialogActionsListView;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import ru.vtosters.lite.downloaders.MessagesDownloader;
|
||||
import ru.vtosters.lite.encryption.EncryptProvider;
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
import ru.vtosters.lite.hooks.CryptImHook;
|
||||
import ru.vtosters.lite.ui.dialogs.Translate;
|
||||
|
||||
public class DNRInjector {
|
||||
public static void inject(Dialog dialog, List<DialogAction> list) {
|
||||
int peerId = 0;
|
||||
int peerId = dialog.getId();
|
||||
|
||||
if (dialog != null) {
|
||||
try {
|
||||
peerId = dialog.getId();
|
||||
} catch (Exception e){
|
||||
Log.d("DialoggetId", "null");
|
||||
}
|
||||
}
|
||||
|
||||
if (peerId == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
list.add(DialogAction.DOWNLOAD);
|
||||
|
||||
list.add(DialogAction.pinmsg);
|
||||
list.add(DialogAction.unpinmsg);
|
||||
list.add(DialogAction.valueOf("pinmsg"));
|
||||
list.add(DialogAction.valueOf("unpinmsg"));
|
||||
|
||||
if (isDnrEnabledFor(peerId)) {
|
||||
list.add(DialogAction.DNR_OFF);
|
||||
list.add(DialogAction.valueOf("DNR_OFF"));
|
||||
} else {
|
||||
list.add(DialogAction.DNR_ON);
|
||||
list.add(DialogAction.valueOf("DNR_ON"));
|
||||
}
|
||||
|
||||
if (isDntEnabledFor(peerId)) {
|
||||
list.add(DialogAction.DNT_OFF);
|
||||
list.add(DialogAction.valueOf("DNT_OFF"));
|
||||
} else {
|
||||
list.add(DialogAction.DNT_ON);
|
||||
}
|
||||
|
||||
list.add(DialogAction.ENCRYPT);
|
||||
IMProcessor prov = EncryptProvider.getProcessorFor(peerId);
|
||||
if (prov != null && !prov.isPublic()) {
|
||||
list.add(DialogAction.ENCRYPT_SETT);
|
||||
list.add(DialogAction.valueOf("DNT_ON"));
|
||||
}
|
||||
}
|
||||
|
||||
public static LinkedHashMap<DialogAction, Integer> injectToHashMap(LinkedHashMap<DialogAction, Integer> hashMap) {
|
||||
hashMap.put(DialogAction.DOWNLOAD, getIdentifier("download_dl", "string"));
|
||||
hashMap.put(DialogAction.valueOf("DNR_ON"), getIdentifier("DNR_ON", "string"));
|
||||
hashMap.put(DialogAction.valueOf("DNR_OFF"), getIdentifier("DNR_OFF", "string"));
|
||||
hashMap.put(DialogAction.valueOf("DNT_ON"), getIdentifier("DNT_ON", "string"));
|
||||
hashMap.put(DialogAction.valueOf("DNT_OFF"), getIdentifier("DNT_OFF", "string"));
|
||||
|
||||
hashMap.put(DialogAction.DNR_ON, getIdentifier("DNR_ON", "string"));
|
||||
hashMap.put(DialogAction.DNR_OFF, getIdentifier("DNR_OFF", "string"));
|
||||
hashMap.put(DialogAction.DNT_ON, getIdentifier("DNT_ON", "string"));
|
||||
hashMap.put(DialogAction.DNT_OFF, getIdentifier("DNT_OFF", "string"));
|
||||
|
||||
hashMap.put(DialogAction.ENCRYPT, getIdentifier("encryption", "string"));
|
||||
hashMap.put(DialogAction.ENCRYPT_SETT, getIdentifier("encryption_sett", "string"));
|
||||
|
||||
// hashMap.put(DialogAction.pinmsg, getIdentifier("pinmsg", "string"));
|
||||
// hashMap.put(DialogAction.unpinmsg, getIdentifier("unpinmsg", "string"));
|
||||
hashMap.put(DialogAction.valueOf("pinmsg"), getIdentifier("pinmsg", "string"));
|
||||
hashMap.put(DialogAction.valueOf("unpinmsg"), getIdentifier("unpinmsg", "string"));
|
||||
return hashMap;
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType")
|
||||
public static List<Object> injectToList(List<Object> actions) {
|
||||
var list = new ArrayList<>(actions);
|
||||
list.add(new DialogActionsListView.b.a(DialogAction.DOWNLOAD, 1, getIdentifier("im_ic_msgdl", "attr"), getIdentifier("download_dl", "string"))); // DialogAction, Int, Icon, String
|
||||
|
||||
list.add(new DialogActionsListView.b.a(DialogAction.DNR_ON, 2, im_ic_pinned_msg_hide, getIdentifier("DNR_ON", "string"))); // DialogAction, Int, Icon, String
|
||||
list.add(new DialogActionsListView.b.a(DialogAction.DNR_OFF, 2, im_ic_pinned_msg_show, getIdentifier("DNR_OFF", "string"))); // DialogAction, Int, Icon, String
|
||||
|
||||
list.add(new DialogActionsListView.b.a(DialogAction.DNT_ON, 2, im_ic_edit_msg, getIdentifier("DNT_ON", "string"))); // DialogAction, Int, Icon, String
|
||||
list.add(new DialogActionsListView.b.a(DialogAction.DNT_OFF, 2, im_ic_edit_msg, getIdentifier("DNT_OFF", "string"))); // DialogAction, Int, Icon, String
|
||||
|
||||
list.add(new DialogActionsListView.b.a(DialogAction.ENCRYPT, 3, im_ic_keyboard, getIdentifier("encryption", "string"))); // DialogAction, Int, Icon, String
|
||||
list.add(new DialogActionsListView.b.a(DialogAction.ENCRYPT_SETT, 3, im_ic_more_vertical, getIdentifier("encryption_sett", "string"))); // DialogAction, Int, Icon, String
|
||||
|
||||
list.add(new DialogActionsListView.b.a(DialogAction.MARK_AS_READ, 4, im_ic_done, getIdentifier("vkim_dialogs_list_option_mark_as_read", "string"))); // DialogAction, Int, Icon, String
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void forceInvalidateDialogActions(Dialog d) {
|
||||
EntityIntMap<Dialog> map = new EntityIntMap<>();
|
||||
map.a(d.getId(), d);
|
||||
ImEngine1.a().a(new OnDialogUpdateEvent(null, map));
|
||||
}
|
||||
|
||||
public static List<DialogAction> injectToListAccess(List<DialogAction> actions, Dialog dialog) {
|
||||
int peerId = 0;
|
||||
|
||||
if (dialog != null) {
|
||||
try {
|
||||
peerId = dialog.getId();
|
||||
} catch (Exception e){
|
||||
Log.d("DialoggetId", "null");
|
||||
}
|
||||
}
|
||||
|
||||
if (peerId == 0) {
|
||||
return actions;
|
||||
}
|
||||
|
||||
actions.add(DialogAction.DOWNLOAD);
|
||||
|
||||
if (isDnrEnabledFor(peerId)) {
|
||||
actions.add(DialogAction.DNR_OFF);
|
||||
} else {
|
||||
actions.add(DialogAction.DNR_ON);
|
||||
}
|
||||
|
||||
if (isDntEnabledFor(peerId)) {
|
||||
actions.add(DialogAction.DNT_OFF);
|
||||
} else {
|
||||
actions.add(DialogAction.DNT_ON);
|
||||
}
|
||||
|
||||
actions.add(DialogAction.ENCRYPT);
|
||||
IMProcessor prov = EncryptProvider.getProcessorFor(peerId);
|
||||
if (prov != null && !prov.isPublic()) {
|
||||
actions.add(DialogAction.ENCRYPT_SETT);
|
||||
}
|
||||
|
||||
actions.add(DialogAction.MARK_AS_READ);
|
||||
return actions;
|
||||
}
|
||||
|
||||
public static boolean onClickHeader(DialogAction action, Dialog dialog) {
|
||||
int peerId = 0;
|
||||
|
||||
if (dialog != null) {
|
||||
try {
|
||||
peerId = dialog.getId();
|
||||
} catch (Exception e){
|
||||
Log.d("DialoggetId", "null");
|
||||
}
|
||||
}
|
||||
|
||||
if (peerId == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.MARK_AS_READ) {
|
||||
DNRModule.hookRead(dialog);
|
||||
forceInvalidateDialogActions(dialog);
|
||||
}
|
||||
|
||||
if (action == DialogAction.DOWNLOAD) {
|
||||
File out = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "dialog-" + peerId + ".html");
|
||||
try {
|
||||
new MessagesDownloader().downloadDialog(peerId, new MessagesDownloader.HtmlDialogDownloaderFormatProvider(), out);
|
||||
} catch (Exception e) {
|
||||
sendToast(getString("download_dl_error"));
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.DNR_ON) {
|
||||
setDnr(dialog, true);
|
||||
forceInvalidateDialogActions(dialog);
|
||||
return true;
|
||||
} else if (action == DialogAction.DNR_OFF) {
|
||||
setDnr(dialog, false);
|
||||
forceInvalidateDialogActions(dialog);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.DNT_ON) {
|
||||
setDnt(dialog, true);
|
||||
forceInvalidateDialogActions(dialog);
|
||||
return true;
|
||||
} else if (action == DialogAction.DNT_OFF) {
|
||||
setDnt(dialog, false);
|
||||
forceInvalidateDialogActions(dialog);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.ENCRYPT_SETT) {
|
||||
CryptImHook.hookPref(peerId);
|
||||
return true;
|
||||
} else if (action == DialogAction.ENCRYPT) {
|
||||
CryptImHook.hook(peerId, dialog);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean onClick(Dialog dialog, DialogAction action) {
|
||||
int peerId = 0;
|
||||
var id = dialog.getId();
|
||||
|
||||
if (dialog != null) {
|
||||
try {
|
||||
peerId = dialog.getId();
|
||||
} catch (Exception e){
|
||||
Log.d("DialoggetId", "null");
|
||||
}
|
||||
}
|
||||
|
||||
if (peerId == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.MARK_AS_READ) {
|
||||
if (action == DialogAction.valueOf("MARK_AS_READ")) {
|
||||
DNRModule.hookRead(dialog);
|
||||
}
|
||||
|
||||
if (action == DialogAction.DOWNLOAD) {
|
||||
File out = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), peerId + "-dialog.html");
|
||||
try {
|
||||
new MessagesDownloader().downloadDialog(peerId, new MessagesDownloader.HtmlDialogDownloaderFormatProvider(), out);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.DNR_ON) {
|
||||
if (action == DialogAction.valueOf("DNR_ON")) {
|
||||
setDnr(dialog, true);
|
||||
return true;
|
||||
} else if (action == DialogAction.DNR_OFF) {
|
||||
} else if (action == DialogAction.valueOf("DNR_OFF")) {
|
||||
setDnr(dialog, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.DNT_ON) {
|
||||
if (action == DialogAction.valueOf("DNT_ON")) {
|
||||
setDnt(dialog, true);
|
||||
return true;
|
||||
} else if (action == DialogAction.DNT_OFF) {
|
||||
} else if (action == DialogAction.valueOf("DNT_OFF")) {
|
||||
setDnt(dialog, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.pinmsg) {
|
||||
pinnedMsg(peerId, true);
|
||||
if (action == DialogAction.valueOf("pinmsg")) {
|
||||
pinnedMsg(id, true);
|
||||
return true;
|
||||
} else if (action == DialogAction.unpinmsg) {
|
||||
pinnedMsg(peerId, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action == DialogAction.ENCRYPT_SETT) {
|
||||
CryptImHook.hookPref(peerId);
|
||||
return true;
|
||||
} else if (action == DialogAction.ENCRYPT) {
|
||||
CryptImHook.hook(peerId, dialog);
|
||||
} else if (action == DialogAction.valueOf("unpinmsg")) {
|
||||
pinnedMsg(id, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -303,7 +102,6 @@ public class DNRInjector {
|
||||
|
||||
public static boolean onClickMsg(Context context, MsgAction action, Msg msg) {
|
||||
var text = ((MsgFromUser) msg).f();
|
||||
var peerId = msg.v1();
|
||||
var fullMsg = ((MsgFromUser) msg).j2(); // text + reply
|
||||
var reply = fullMsg.substring(text.length() + 1);
|
||||
|
||||
@@ -315,24 +113,15 @@ public class DNRInjector {
|
||||
var isTextExist = !text.isEmpty() && !text.equals(" ");
|
||||
var isReplyExist = !reply.isEmpty() && !reply.equals(" ");
|
||||
|
||||
|
||||
if (isReplyExist) {
|
||||
reply = decryptMessage(reply, peerId);
|
||||
}
|
||||
|
||||
if (isTextExist) {
|
||||
text = decryptMessage(text, peerId);
|
||||
}
|
||||
|
||||
if (action == MsgAction.valueOf("TRANSLATE")) {
|
||||
if (isTextExist && isReplyExist) {
|
||||
Translate.showTranslatedText(context, text + "\n\n" + getString("translator_reply") + "\n" + reply);
|
||||
Translate.showTranslatedText(context, text + "\n\nРеплай:\n" + reply);
|
||||
} else if (isReplyExist) {
|
||||
Translate.showTranslatedText(context, getString("translator_reply") + "\n" + reply);
|
||||
Translate.showTranslatedText(context, "Реплай:\n" + reply);
|
||||
} else if (isTextExist) {
|
||||
Translate.showTranslatedText(context, text);
|
||||
} else {
|
||||
sendToast(getString("translator_no_text"));
|
||||
sendToast("Нет текста для перевода");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +132,7 @@ public class DNRInjector {
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
var request = new Request.a()
|
||||
.b("https://" + getApi() + "/method/" + (needToBePinned ? "messages.pinConversation" : "messages.unpinConversation") + "?peer_id=" + dialogid + "&access_token=" + getUserToken() + "&v=5.119")
|
||||
.b("https://api.vk.com/method/" + (needToBePinned ? "messages.pinConversation" : "messages.unpinConversation") + "?peer_id=" + dialogid + "&access_token=" + getUserToken() + "&v=5.119")
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8"))
|
||||
.a();
|
||||
|
||||
@@ -360,27 +149,15 @@ public class DNRInjector {
|
||||
|
||||
thread.start();
|
||||
|
||||
sendToast(getString("pin_dialog") + " " + getString(needToBePinned ? "dialog_pinned" : "dialog_unpinned"));
|
||||
sendToast("Диалог успешно " + (needToBePinned ? "закреплен" : "откреплен"));
|
||||
}
|
||||
|
||||
public static void setDnr(Dialog dialog, boolean value) {
|
||||
int peerId = 0;
|
||||
|
||||
if (dialog != null) {
|
||||
peerId = dialog.getId();
|
||||
}
|
||||
|
||||
hookDNR(peerId);
|
||||
hookDNR(dialog.getId());
|
||||
}
|
||||
|
||||
public static void setDnt(Dialog dialog, boolean value) {
|
||||
int peerId = 0;
|
||||
|
||||
if (dialog != null) {
|
||||
peerId = dialog.getId();
|
||||
}
|
||||
|
||||
hookDNT(peerId);
|
||||
hookDNT(dialog.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package ru.vtosters.lite.dnr;
|
||||
|
||||
import static ru.vtosters.lite.net.Request.makeRequest;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
import static ru.vtosters.lite.utils.ProxyUtils.getApi;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
@@ -31,21 +31,11 @@ public class AudioDownloader {
|
||||
|
||||
public static void downloadM3U8(MusicTrack track) {
|
||||
if (track.D == null) {
|
||||
ToastUtils.a(AndroidUtils.getString("link_audio_error"));
|
||||
ToastUtils.a("Не удалось найти ссылку на аудиозапись");
|
||||
return;
|
||||
}
|
||||
|
||||
var musicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath();
|
||||
var musicDir = new File(musicPath);
|
||||
if (!musicDir.exists()) {
|
||||
if (musicDir.mkdirs()) {
|
||||
Log.d("AudioDownloader", "Created music dir");
|
||||
} else {
|
||||
Log.e("AudioDownloader", "Failed to create music dir");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var tempId = track.d;
|
||||
var downloadPath = musicPath + File.separator + tempId;
|
||||
|
||||
@@ -64,7 +54,7 @@ public class AudioDownloader {
|
||||
var success = FFMpeg.convert(downloadPath, musicPath + File.separator + fileName + ".mp3");
|
||||
if (success) {
|
||||
notification
|
||||
.setContentText(AndroidUtils.getString("player_download_finished"))
|
||||
.setContentText("Загрузка завершена")
|
||||
.setProgress(0, 0, false)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download_done);
|
||||
notificationManager.notify(tempId, notification.build());
|
||||
@@ -72,7 +62,7 @@ public class AudioDownloader {
|
||||
onFailure();
|
||||
}
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
Log.e("AudioDownloader", "native libs");
|
||||
Log.e("AudioDownloader", "Опять эти нативные либы");
|
||||
Log.e("AudioDownloader", e.getMessage());
|
||||
onFailure();
|
||||
}
|
||||
@@ -80,7 +70,7 @@ public class AudioDownloader {
|
||||
|
||||
@Override
|
||||
public void onFailure() {
|
||||
notification.setContentText(AndroidUtils.getString("load_audio_error")).setProgress(0, 0, false);
|
||||
notification.setContentText("Не удалось загрузить аудиозапись").setProgress(0, 0, false);
|
||||
notificationManager.notify(tempId, notification.build());
|
||||
}
|
||||
|
||||
@@ -109,7 +99,7 @@ public class AudioDownloader {
|
||||
private static NotificationCompat.Builder buildDownloadNotification(MusicTrack track, int id) {
|
||||
var notificationBuilder = new NotificationCompat.Builder(AndroidUtils.getGlobalContext(), NotificationChannels.MUSIC_DOWNLOAD_CHANNEL_ID)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
.setContentTitle(AndroidUtils.getString("audio_downloading"))
|
||||
.setContentTitle("Загрузка аудиозаписи")
|
||||
.setContentText(track.toString())
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
|
||||
|
||||
@@ -1,604 +0,0 @@
|
||||
package ru.vtosters.lite.downloaders;
|
||||
import static ru.vtosters.lite.encryption.EncryptProvider.decryptMessage;
|
||||
import static ru.vtosters.lite.net.Request.makeRequest;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getResources;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MessagesDownloader{
|
||||
private static SimpleDateFormat sdformat;
|
||||
|
||||
private static SparseArray<MiniUser> usersArray;
|
||||
|
||||
private static final String VK_DOMAIN = "vk.com";
|
||||
|
||||
public static String formatTime(long now){
|
||||
return sdformat.format(new Date(now));
|
||||
}
|
||||
|
||||
public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements){
|
||||
Objects.requireNonNull(delimiter);
|
||||
Objects.requireNonNull(elements);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (CharSequence cs : elements) {
|
||||
builder.append(cs).append(delimiter);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public void downloadDialog(int peer_id, DialogDownloaderFormatProvider format, File out) throws Exception{
|
||||
sdformat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss", getResources().getConfiguration().locale);
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(out);
|
||||
|
||||
// fix TODO with conversation name (API method messages.getConversationsById)
|
||||
fos.write(format.provideDocumentStart("TODO", formatTime(System.currentTimeMillis())).getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
fetchDialogInfo(peer_id, 0, ((users, messages) -> {
|
||||
try {
|
||||
fos.write(format.provideHeader("TODO", formatTime(System.currentTimeMillis())).getBytes(StandardCharsets.UTF_8));
|
||||
for (MiniMsg msg : messages) {
|
||||
fos.write(format.provideMessage(msg, users.get(msg.fromId)).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
fos.write(format.provideDocumentEnd().getBytes(StandardCharsets.UTF_8));
|
||||
fos.close();
|
||||
Toast.makeText(getGlobalContext(), "Сохранено как " + out.getAbsolutePath(), Toast.LENGTH_SHORT).show();
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public void fetchDialogInfo(int peer_id, int offset, FetchListener fl){
|
||||
makeRequest("https://" + getApi() + "/method/messages.getHistory?extended=1&v=5.140&offset=" + offset + "&count=200&peer_id=" + peer_id + "&access_token=" + getUserToken(),
|
||||
response -> {
|
||||
try {
|
||||
JSONObject mainJson = new JSONObject(response);
|
||||
JSONObject obj = mainJson.getJSONObject("response");
|
||||
|
||||
SparseArray<MiniUser> users = new SparseArray<>();
|
||||
parseUsers(users, obj.optJSONArray("profiles"), false);
|
||||
parseUsers(users, obj.optJSONArray("groups"), true);
|
||||
|
||||
List<MiniMsg> msgs = parseMessages(obj.getJSONArray("items"));
|
||||
|
||||
usersArray = users;
|
||||
|
||||
fl.onReceive(users, msgs);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<MiniMsg> parseMessages(JSONArray jsonArray) throws JSONException{
|
||||
ArrayList<MiniMsg> thing = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
MiniMsg msg = new MiniMsg(jsonArray.getJSONObject(i));
|
||||
thing.add(msg);
|
||||
}
|
||||
|
||||
return thing;
|
||||
}
|
||||
|
||||
private void parseUsers(SparseArray<MiniUser> array, @Nullable JSONArray jsonArray, boolean groups) throws JSONException{
|
||||
if (jsonArray == null) return;
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
MiniUser user = new MiniUser(jsonArray.getJSONObject(i), groups);
|
||||
array.put(groups ? -user.id : user.id, user);
|
||||
}
|
||||
}
|
||||
|
||||
interface FetchListener{
|
||||
void onReceive(SparseArray<MiniUser> users, List<MiniMsg> messages);
|
||||
}
|
||||
|
||||
static class MiniUser{
|
||||
public String firstName;
|
||||
public String lastName;
|
||||
public boolean isGroup;
|
||||
int id;
|
||||
String photo100;
|
||||
|
||||
public MiniUser(JSONObject obj, boolean is_group) throws JSONException {
|
||||
id = obj.getInt("id");
|
||||
firstName = obj.optString("first_name", obj.optString("name"));
|
||||
lastName = obj.optString("last_name", "");
|
||||
photo100 = obj.getString("photo_100");
|
||||
isGroup = is_group;
|
||||
}
|
||||
}
|
||||
|
||||
static class MiniMsg{
|
||||
long date;
|
||||
int fromId;
|
||||
int id; // message id
|
||||
String text;
|
||||
List<JSONObject> attachments;
|
||||
List<JSONObject> fwd_messages;
|
||||
JSONObject reply_message; // one reply
|
||||
JSONObject chat_action;
|
||||
JSONObject geo;
|
||||
|
||||
public MiniMsg(JSONObject obj) throws JSONException{
|
||||
date = obj.getLong("date") * 1000;
|
||||
fromId = obj.getInt("from_id");
|
||||
id = obj.getInt("id");
|
||||
text = decryptMessage(obj.getString("text"), obj.getInt("peer_id"));
|
||||
reply_message = obj.optJSONObject("reply_message");
|
||||
chat_action = obj.optJSONObject("action");
|
||||
geo = obj.optJSONObject("geo");
|
||||
|
||||
attachments = new ArrayList<>();
|
||||
fwd_messages = new ArrayList<>();
|
||||
|
||||
JSONArray arr = obj.optJSONArray("attachments");
|
||||
if (arr != null)
|
||||
for (int i = 0; i < arr.length(); i++) attachments.add(arr.getJSONObject(i));
|
||||
|
||||
JSONArray fwdArr = obj.optJSONArray("fwd_messages");
|
||||
if (fwdArr != null)
|
||||
for (int i = 0; i < fwdArr.length(); i++) fwd_messages.add(fwdArr.getJSONObject(i));
|
||||
}
|
||||
}
|
||||
|
||||
// This class defines everything which is needed to create an output file
|
||||
abstract static class DialogDownloaderFormatProvider{
|
||||
// Internal, for JSON/HTML
|
||||
abstract String provideDocumentStart(String dialogName, String date);
|
||||
|
||||
abstract String provideDocumentEnd();
|
||||
|
||||
abstract String provideHeader(String dialogName, String date);
|
||||
|
||||
abstract String provideMessage(MiniMsg message, MiniUser user) throws JSONException;
|
||||
}
|
||||
|
||||
public static class HtmlDialogDownloaderFormatProvider extends DialogDownloaderFormatProvider{
|
||||
@Override
|
||||
String provideDocumentStart(String dialogName, String date){
|
||||
String style = ".vtex-milk-msg {\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 24px;\n" +
|
||||
" background: white;\n" +
|
||||
" margin: 16px;\n" +
|
||||
" box-shadow: 0 4px 8px 0 rgba(0,0,0,0.07);\n" +
|
||||
" word-wrap: break-word;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".vtex-milk-msgcont br {\n" +
|
||||
" display: none;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".vtex-milk-msg p {\n" +
|
||||
" margin: 0;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".vtex-milk-msg.vtex-milk-msg-out {\n" +
|
||||
" background: #ADD3FF;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"p.msg-attaches {\n" +
|
||||
" margin-top: 8px;\n" +
|
||||
" font-style: italic;\n" +
|
||||
"}\n" +
|
||||
"p.chat-action {\n" +
|
||||
" font-style: italic;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".vtex-milk-header {\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 24px;\n" +
|
||||
" background: white;\n" +
|
||||
" margin: 16px;\n" +
|
||||
" box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"h4.vtex-milk-header-txt {\n" +
|
||||
" margin: 0;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"h5.vtex-milk-header-sub {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding-top: 8px;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"a.msg-attach-link {\n" +
|
||||
" color: #5181B8;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".msg-from a {\n" +
|
||||
" color: #5181B8;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".msg-from-date {\n" +
|
||||
" color: rgba(0, 0, 0, 0.75);\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"body {\n" +
|
||||
" font-family: Roboto, system-ui, sans-serif;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
".msg-body {\n" +
|
||||
" padding-top: 4px;\n" +
|
||||
"}\n" +
|
||||
".msg-reply {\n" +
|
||||
" border-left: 3px solid #7aa7f6;\n" +
|
||||
" margin-top: 5px;\n" +
|
||||
" padding-left: 3px;\n" +
|
||||
"}\n\n" +
|
||||
".msg-reply p {\n" +
|
||||
" padding-left: 5px;\n" +
|
||||
"}\n\n" +
|
||||
".msg-reply p.reply-header {\n" +
|
||||
" color: #5181B8;\n" +
|
||||
"}\n\n" +
|
||||
".msg-reply p.reply-content {\n" +
|
||||
" color: #000000;\n" +
|
||||
"}\n" +
|
||||
".vtex-milk-msg.poll {\n" +
|
||||
" width: 45%;\n" +
|
||||
" background: linear-gradient(to bottom right, #707c8c, #4d5565);\n" +
|
||||
" font-style: normal;" +
|
||||
"}\n" +
|
||||
".vtex-milk-msg.poll p { color: white; }\n" +
|
||||
".vtex-milk-msg.poll hr { border-top: 1px; background: #ffffff; }\n" +
|
||||
"\n" +
|
||||
"";
|
||||
|
||||
return "<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta charset=\"utf-8\"><title>Экспорт из VTLite</title><style>" + style + "</style></head><body>";
|
||||
}
|
||||
|
||||
@Override
|
||||
String provideDocumentEnd(){
|
||||
return "</div></body></html>";
|
||||
}
|
||||
|
||||
@Override
|
||||
String provideHeader(String dialogName, String date){
|
||||
return "<div class=\"vtex-milk-header\"><h4 class=\"vtex-milk-header-txt\">VTLite</h4><h5 class=\"vtex-milk-header-sub\">Экспорт истории чата (" + date + ")</h5></div><div class=\"vtex-milk-msgcont\">";
|
||||
}
|
||||
|
||||
@Override
|
||||
String provideMessage(MiniMsg message, MiniUser user) throws JSONException{
|
||||
String isOut = (user.id == getUserId()) ? " vtex-milk-msg-out" : "";
|
||||
|
||||
String geoPosition = "";
|
||||
if (message.geo != null) {
|
||||
var coordinates = message.geo.optJSONObject("coordinates");
|
||||
if (coordinates != null) {
|
||||
var latitude = coordinates.optDouble("latitude");
|
||||
var longitude = coordinates.optDouble("longitude");
|
||||
var ll = longitude + "," + latitude;
|
||||
geoPosition = "<a href=\"https://yandex.ru/maps/?ll=" + ll + "&mode=search&sll=" + ll + "&text=" + latitude + "," + longitude + "&z=12\">" +
|
||||
"<img src=\"https://static-maps.yandex.ru/1.x/?ll=" + longitude + "," + latitude + "&z=12&l=map&size=300,200&pt=" + ll + ",vkgrm\"/>" +
|
||||
"</a>";
|
||||
}
|
||||
}
|
||||
|
||||
String chatAction = (message.chat_action != null) ? getHtmlForChatAction(message.chat_action) : "";
|
||||
String attaches = (message.attachments.size() > 0) ? "<p class=\"msg-attaches\">Вложения: " + getHtmlForAttach(message.attachments) + "</p>" : "";
|
||||
String reply = (message.reply_message != null) ? provideReply(message.reply_message) : "";
|
||||
String fwdMessages = (message.fwd_messages.size() > 0) ? provideForwardMessages(message.fwd_messages) : "";
|
||||
String userLink = (user.isGroup ? "club" : "id") + user.id;
|
||||
|
||||
return "<div class=\"vtex-milk-msg" + isOut + "\" id=\"" + message.id + "\">" +
|
||||
"<p class=\"msg-from\">от <a href=\"https://" + VK_DOMAIN + "/" + userLink + "\">" + user.firstName + " " + user.lastName + "</a> <span class=\"msg-from-date\">" + formatTime(message.date) + "</span></p>" + // TODO photo100
|
||||
"<p class=\"msg-body\">" + mentionsReplace(message.text) + "</p>" +
|
||||
geoPosition +
|
||||
chatAction +
|
||||
attaches +
|
||||
reply +
|
||||
fwdMessages +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
private String provideReply(JSONObject replyMessage) {
|
||||
var messageId = replyMessage.optInt("id");
|
||||
var userId = replyMessage.optInt("from_id");
|
||||
var peerId = replyMessage.optInt("peer_id");
|
||||
var text = mentionsReplace(decryptMessage(replyMessage.optString("text"), peerId));
|
||||
var fwdMessages = replyMessage.optJSONArray("fwd_messages");
|
||||
|
||||
var user = usersArray.get(userId);
|
||||
|
||||
if (text.isEmpty()) {
|
||||
if (fwdMessages != null) {
|
||||
var length = fwdMessages.length();
|
||||
if (length > 0) text = length + " " + pluralMsg(length);
|
||||
} else text = "Вложение";
|
||||
}
|
||||
|
||||
return "<a href=\"#" + messageId + "\" class=\"msg-attach-link\">" +
|
||||
"<div class=\"msg-reply\">" +
|
||||
"<p class=\"reply-header\">Пересланное сообщение</p>" +
|
||||
"<p class=\"reply-content\">" + user.firstName + " " + user.lastName + ": " + text + "</p>" +
|
||||
"</div>" +
|
||||
"</a>";
|
||||
}
|
||||
|
||||
private String provideForwardMessages(List<JSONObject> fwd_messages) throws JSONException {
|
||||
StringBuilder fwdmsgs = new StringBuilder("<div class=\"msg-reply\">");
|
||||
|
||||
for (JSONObject fwd_message : fwd_messages) {
|
||||
|
||||
if (fwd_message == null) continue;
|
||||
|
||||
List<JSONObject> attaches = new ArrayList<>();
|
||||
|
||||
JSONArray arr = fwd_message.optJSONArray("attachments");
|
||||
if (arr != null) {
|
||||
for (int i = 0; i < arr.length(); i++) {
|
||||
try {
|
||||
attaches.add(arr.getJSONObject(i));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JSONObject> fwdsMsg = new ArrayList<>();
|
||||
|
||||
JSONArray fwd_msgs = fwd_message.optJSONArray("fwd_messages");
|
||||
if (fwd_msgs != null) {
|
||||
for (int i = 0; i < fwd_msgs.length(); i++) {
|
||||
try {
|
||||
fwdsMsg.add(fwd_msgs.getJSONObject(i));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSONObject reply_message = fwd_message.optJSONObject("reply_message");
|
||||
|
||||
var attachesHtml = (attaches.size() > 0) ? "Вложения: " + getHtmlForAttach(attaches) : "";
|
||||
var replyHtml = (reply_message != null) ? provideReply(reply_message) : "";
|
||||
var fwdsHtml = (fwdsMsg.size() > 0) ? provideForwardMessages(fwdsMsg) : ""; // recursion XD :>
|
||||
|
||||
var userId = fwd_message.optInt("from_id");
|
||||
var peerId = fwd_message.optInt("peer_id");
|
||||
var text = mentionsReplace(decryptMessage(fwd_message.optString("text"), peerId));
|
||||
|
||||
var userLink = ((userId < 0) ? "club" : "id") + Math.abs(userId);
|
||||
|
||||
fwdmsgs.append("<p class=\"reply-content\"><a class=\"msg-attach-link\" href=\"https://" + VK_DOMAIN + "/").append(userLink).append("\">@").append(userLink).append("</a>: ").append(text).append(attachesHtml).append(replyHtml).append(fwdsHtml);
|
||||
}
|
||||
|
||||
return fwdmsgs.append("</div>").toString();
|
||||
}
|
||||
|
||||
private String mentionsReplace(String text) {
|
||||
var matcher = Pattern.compile("\\[((?:club|id|public)\\d+)\\|([^]]+)\\]").matcher(text);
|
||||
|
||||
return matcher.replaceAll("<a class=\"msg-attach-link\" href=\"https://" + VK_DOMAIN + "/$1\">$2</a>");
|
||||
}
|
||||
|
||||
private String pluralMsg(int count) {
|
||||
String[] plurals = {"сообщение", "сообщения", "сообщений"};
|
||||
|
||||
var hundredModulo = count % 100;
|
||||
var tenModulo = count % 10;
|
||||
|
||||
if (hundredModulo > 10 && hundredModulo < 20) return plurals[2];
|
||||
else if (tenModulo > 1 && tenModulo < 5) return plurals[1];
|
||||
else if (tenModulo == 1) return plurals[0];
|
||||
|
||||
return plurals[2];
|
||||
}
|
||||
|
||||
private String getHtmlForChatAction(JSONObject action) {
|
||||
var type = action.optString("type");
|
||||
|
||||
StringBuilder htmlAction = new StringBuilder("<p class=\"chat-action\">");
|
||||
|
||||
switch(type) {
|
||||
case "chat_photo_update":
|
||||
htmlAction.append("Обновил фотографию беседы");
|
||||
break;
|
||||
case "chat_photo_remove":
|
||||
htmlAction.append("Удалил фотографию беседы");
|
||||
break;
|
||||
case "chat_create":
|
||||
var name = action.optString("text");
|
||||
htmlAction.append("Создал беседу").append((!name.isEmpty()) ? " с названием \"" + name + "\"" : "");
|
||||
break;
|
||||
case "chat_title_update":
|
||||
var newName = action.optString("text");
|
||||
htmlAction.append("Сменил название беседы").append((!newName.isEmpty()) ? " на \"" + newName : "\"");
|
||||
break;
|
||||
case "chat_invite_user":
|
||||
var newUserId = action.optInt("member_id");
|
||||
htmlAction.append("Добавил ").append((newUserId > 0) ? "пользователя" : "группу");
|
||||
if (newUserId != 0) {
|
||||
var userLink = ((newUserId < 0) ? "club" : "id") + Math.abs(newUserId);
|
||||
htmlAction.append(" <a href=\"https://" + VK_DOMAIN + "/").append(userLink).append("\" class=\"msg-attach-link\">@").append(userLink).append("</a>");
|
||||
}
|
||||
break;
|
||||
case "chat_kick_user":
|
||||
var removedUserId = action.optInt("member_id");
|
||||
htmlAction.append("Исключил ").append((removedUserId > 0) ? "пользователя" : "группу");
|
||||
if (removedUserId != 0) {
|
||||
var userLink = ((removedUserId < 0) ? "club" : "id") + Math.abs(removedUserId);
|
||||
htmlAction.append(" <a href=\"https://" + VK_DOMAIN + "/").append(userLink).append("\" class=\"msg-attach-link\">@").append(userLink).append("</a>");
|
||||
}
|
||||
break;
|
||||
case "chat_pin_message":
|
||||
var message = action.optString("message");
|
||||
htmlAction.append("Закрепил сообщение").append((!message.isEmpty()) ? (" с текстом: \"" + message + "\"") : "");
|
||||
break;
|
||||
case "chat_unpin_message":
|
||||
htmlAction.append("Открепил сообщение");
|
||||
break;
|
||||
case "chat_invite_user_by_link":
|
||||
htmlAction.append("Вступил в беседу по ссылке");
|
||||
break;
|
||||
case "chat_screenshot":
|
||||
htmlAction.append("Сделал скриншот беседы");
|
||||
break;
|
||||
case "custom":
|
||||
htmlAction.append(action.optString("message"));
|
||||
break;
|
||||
default:
|
||||
htmlAction.append("Действие не поддерживается (").append(type).append(")");
|
||||
break;
|
||||
}
|
||||
|
||||
return htmlAction.append("</p>").toString();
|
||||
}
|
||||
|
||||
private String getHtmlForAttach(List<JSONObject> attaches) throws JSONException{
|
||||
StringBuilder rs = new StringBuilder();
|
||||
|
||||
for (JSONObject attach : attaches) {
|
||||
String type = attach.getString("type");
|
||||
JSONObject item = attach.optJSONObject(type);
|
||||
|
||||
if (item == null) continue;
|
||||
|
||||
switch(type) { // market_album is not supported
|
||||
case "photo":
|
||||
var sizes = item.getJSONArray("sizes");
|
||||
rs.append("<a href=\"").append(sizes.getJSONObject(sizes.length() - 1).getString("url")).append("\" class=\"msg-attach-link\">фотография</a>");
|
||||
break;
|
||||
case "doc":
|
||||
rs.append("<a href=\"").append(item.getString("url")).append("\" class=\"msg-attach-link\">документ</a>");
|
||||
break;
|
||||
case "link":
|
||||
rs.append("<a href=\"").append(item.getString("url")).append("\" class=\"msg-attach-link\">ссылка</a>");
|
||||
break;
|
||||
case "wall":
|
||||
rs.append("<a href=\"https://" + VK_DOMAIN + "/wall").append(item.optString("to_id", item.optString("owner_id"))).append("_").append(item.getString("id")).append("\" class=\"msg-attach-link\">запись на стене</a>");
|
||||
break;
|
||||
case "sticker":
|
||||
rs.append("<img style=\"width:128px;height:128px;\" src=\"").append(item.getJSONArray("images").getJSONObject(1).getString("url")).append("\"/>");
|
||||
break;
|
||||
case "audio_message":
|
||||
rs.append("<a href=\"").append(item.optString("link_mp3")).append("\" class=\"msg-attach-link\">голосовое сообщение</a>");
|
||||
break;
|
||||
case "audio":
|
||||
rs.append("аудиозапись (").append(item.optString("artist")).append(" — ").append(item.optString("title")).append(")");
|
||||
break;
|
||||
case "video":
|
||||
rs.append("видеозапись ( ").append(getVideoHtml(item.optJSONObject("files"))).append(")");
|
||||
break;
|
||||
case "wall_reply":
|
||||
var link = "https://" + VK_DOMAIN + "/wall" + item.optString("owner_id") + "_" + item.optString("post_id") + "?reply=" + item.optString("id");
|
||||
rs.append("<a class=\"msg-attach-link\" href=\"").append(link).append("\">комментарий на стене</a>");
|
||||
break;
|
||||
case "story":
|
||||
var story_link = "https://" + VK_DOMAIN + "/story" + item.optString("owner_id") + "_" + item.optString("id");
|
||||
rs.append("<a class=\"msg-attach-link\" href=\"").append(story_link).append("\">история</a>");
|
||||
break;
|
||||
case "podcast":
|
||||
var podcast_link = "https://" + VK_DOMAIN + "/podcast" + item.optString("owner_id") + "_" + item.optString("id");
|
||||
rs.append("<a class=\"msg-attach-link\" href=\"").append(podcast_link).append("\">подкаст</a>");
|
||||
break;
|
||||
case "gift":
|
||||
rs.append("<img src=\"").append(item.optString("thumb_96")).append("\"/>");
|
||||
break;
|
||||
case "mini_app":
|
||||
var app = item.optJSONObject("app");
|
||||
|
||||
if (app != null) {
|
||||
var miniapp_link = "https://" + VK_DOMAIN + "/app" + app.optString("id");
|
||||
rs.append("<a class=\"msg-attach-link\" href=\"").append(miniapp_link).append("\">мини-приложение</a>");
|
||||
break;
|
||||
}
|
||||
|
||||
rs.append("ошибка");
|
||||
break;
|
||||
case "audio_playlist":
|
||||
var playlist_link = "https://" + VK_DOMAIN + "/music/album/" + item.optString("owner_id") + "_" + item.optString("id") + "_" + item.optString("access_key");
|
||||
rs.append("<a class=\"msg-attach-link\" href=\"").append(playlist_link).append("\">плейлист (").append(item.optString("title")).append(")</a>");
|
||||
break;
|
||||
case "poll":
|
||||
rs.append((item.optBoolean("anonymous") ? "анонимный" : "публичный")).append(" опрос ").append(getPollHtml(item));
|
||||
break;
|
||||
case "market":
|
||||
var market_item_link = "https://" + VK_DOMAIN + "/market" + item.optString("owner_id") + "_" + item.optString("id");
|
||||
rs.append("<a class=\"msg-attach-link\" href=\"").append(market_item_link).append("\">товар</a>");
|
||||
break;
|
||||
default:
|
||||
rs.append("не поддерживается (").append(type).append(")");
|
||||
break;
|
||||
}
|
||||
|
||||
rs.append(" ");
|
||||
}
|
||||
|
||||
return rs.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getPollHtml(JSONObject poll) throws JSONException {
|
||||
StringBuilder pollHtml = new StringBuilder(
|
||||
"<div class=\"vtex-milk-msg poll\">" +
|
||||
"<p style=\"text-align:center;\">" + poll.optString("question") + "</p>"
|
||||
);
|
||||
|
||||
var answers = poll.optJSONArray("answers");
|
||||
|
||||
for (int i = 0; i < answers.length(); i++) {
|
||||
var jsonObject = answers.optJSONObject(i);
|
||||
if (jsonObject != null)
|
||||
pollHtml.append("<hr><p>").append(jsonObject.optString("text")).append(" · ").append(jsonObject.optString("votes")).append(" (").append(jsonObject.optString("rate")).append("%)</p>");
|
||||
}
|
||||
|
||||
pollHtml.append("<hr><p style=\"text-align:center;\">Проголосовало ").append(poll.optString("votes")).append(" чел.</p>");
|
||||
|
||||
return pollHtml.append("</div>").toString();
|
||||
}
|
||||
|
||||
private static String getVideoHtml(JSONObject files) throws JSONException {
|
||||
if (files == null) return "ссылки отсутствуют";
|
||||
|
||||
Iterator< ? > keys = files.keys();
|
||||
StringBuilder videoHtml = new StringBuilder();
|
||||
|
||||
int qualityIndex = 0;
|
||||
String[] quality = {"144", "240", "360", "480", "720", "1080", "1440", "2160"};
|
||||
|
||||
while (keys.hasNext()) {
|
||||
String key = (String) keys.next();
|
||||
if (key.equals("mp4_" + quality[qualityIndex])) {
|
||||
videoHtml.append("<a class=\"msg-attach-link\" href=\"").append(files.get(key)).append("\">").append(quality[qualityIndex]).append("p</a>").append(" ");
|
||||
|
||||
if (qualityIndex == quality.length - 1) break;
|
||||
++qualityIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return videoHtml.toString();
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,6 @@ import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import b.h.g.m.FileUtils;
|
||||
@@ -48,7 +46,7 @@ public class OTADownloader {
|
||||
maxIndex = Math.max(maxIndex, Integer.parseInt(name.replaceFirst(".+-(\\d+).+", "$1")));
|
||||
}
|
||||
File apk = maxIndex == -1 ? new File(downloadDir, "VTLite.apk") : new File(downloadDir, "VTLite-" + maxIndex + ".apk");
|
||||
APKInstallActivity.installOta(context, FileUtils.uriFromFile(apk));
|
||||
APKInstallActivity.installOta(context, FileUtils.n(apk));
|
||||
} else if (status == DownloadManager.STATUS_FAILED) {
|
||||
AndroidUtils.sendToast(getString("downloaderr"));
|
||||
}
|
||||
@@ -58,31 +56,16 @@ public class OTADownloader {
|
||||
|
||||
public static void downloadBuild(String url) {
|
||||
var context = AndroidUtils.getGlobalContext();
|
||||
try {
|
||||
var uri = Uri.parse(url);
|
||||
var uri = Uri.parse(url);
|
||||
|
||||
context.registerReceiver(callback, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
context.registerReceiver(callback, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
|
||||
var request = new DownloadManager.Request(uri);
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle("VTLite.apk");
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "VTLite.apk");
|
||||
var request = new DownloadManager.Request(uri);
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle("VTLite.apk");
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "VTLite.apk");
|
||||
|
||||
var manager = (DownloadManager) AndroidUtils.getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
manager.enqueue(request);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
VkAlertDialog.Builder alertDialog = new VkAlertDialog.Builder(context);
|
||||
alertDialog.setTitle(AndroidUtils.getString("update_error"));
|
||||
alertDialog.setMessage(AndroidUtils.getString("update_error_text"));
|
||||
alertDialog.setPositiveButton(AndroidUtils.getString("no"), (dialog, which) -> {
|
||||
dialog.cancel();
|
||||
});
|
||||
alertDialog.setNeutralButton(AndroidUtils.getString("yes"), (dialog, which) -> {
|
||||
context.startActivity(new Intent("android.intent.action.VIEW").setData(Uri.parse("https://github.com/vtosters/lite/releases/latest/download/VTLite.apk")));
|
||||
});
|
||||
var alert = alertDialog.create();
|
||||
alert.show();
|
||||
}
|
||||
var manager = (DownloadManager) AndroidUtils.getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
manager.enqueue(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,8 @@ public class StoryDownloader {
|
||||
String url = imageSizes.get(imageSizes.size() - 1).url;
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle("photo" + story.E.a + ".jpg");
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, "photo" + story.E.a + ".jpg");
|
||||
request.allowScanningByMediaScanner();
|
||||
request.setTitle("photo" + story.E.a);
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DCIM, "/Stories/photo" + story.E.a + ".jpg");
|
||||
((DownloadManager) getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package ru.vtosters.lite.downloaders;
|
||||
|
||||
import static ru.vtosters.lite.net.Request.makeRequest;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DownloadManager;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
@@ -14,7 +14,6 @@ import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.dialogs.bottomsheet.MenuBottomSheetAction;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vk.dto.common.VideoFile;
|
||||
@@ -28,7 +27,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.ExternalLinkParser;
|
||||
|
||||
public class VideoDownloader {
|
||||
@@ -106,19 +104,17 @@ public class VideoDownloader {
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle(videoFile.toString());
|
||||
request.allowScanningByMediaScanner();
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, videoFile + ".mp4");
|
||||
((DownloadManager) getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
return;
|
||||
}
|
||||
|
||||
var builder = new VkAlertDialog.Builder(context);
|
||||
var builder = new AlertDialog.Builder(context);
|
||||
builder.setItems(max, ((dialog, which) -> {
|
||||
var url = urls.get(which);
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle(videoFile.toString());
|
||||
request.allowScanningByMediaScanner();
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, videoFile + ".mp4");
|
||||
((DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
}));
|
||||
@@ -126,13 +122,13 @@ public class VideoDownloader {
|
||||
}
|
||||
|
||||
public static void parseVideoLink(String url, Context ctx) {
|
||||
if (url.contains("vk.com/story") || url.contains("vk.com/story")) {
|
||||
ToastUtils.a(AndroidUtils.getString("video_dl_stories_not_supported"));
|
||||
if (url.contains("vk.com/story")) {
|
||||
ToastUtils.a("Не поддерживается загрузка историй");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!url.contains("vk.com/video") || !url.contains("vk.com/video")) {
|
||||
ToastUtils.a(AndroidUtils.getString("video_dl_wrong_link"));
|
||||
if (!url.contains("vk.com/video")) {
|
||||
ToastUtils.a("Неверная ссылка");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -140,10 +136,10 @@ public class VideoDownloader {
|
||||
String ownerId = videoId.split("_")[0];
|
||||
|
||||
final ProgressDialog progressDialog = new ProgressDialog(ctx);
|
||||
progressDialog.setMessage(AndroidUtils.getString("video_dl_progress"));
|
||||
progressDialog.setMessage("Обработка видео");
|
||||
progressDialog.show();
|
||||
|
||||
makeRequest("https://" + getApi() + "/method/video.get?owner_id=" + ownerId + "&videos=" + videoId + "&v=5.99&access_token=" + getUserToken(),
|
||||
makeRequest("https://" + "api.vk.com" + "/method/video.get?owner_id=" + ownerId + "&videos=" + videoId + "&v=5.99&access_token=" + getUserToken(),
|
||||
response -> {
|
||||
progressDialog.cancel();
|
||||
|
||||
@@ -156,7 +152,7 @@ public class VideoDownloader {
|
||||
downloadVideo(videoFile, ctx);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(ctx, AndroidUtils.getString("video_dl_error"), Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(ctx, "Видео нельзя скачать", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+2
-2
@@ -12,8 +12,8 @@ import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class NotificationChannels {
|
||||
public static final String MUSIC_DOWNLOAD_CHANNEL_ID = "music_download_channel";
|
||||
public static final String MUSIC_DOWNLOAD_CHANNEL_NAME = AndroidUtils.getString("music_dl_title");
|
||||
public static final String MUSIC_DOWNLOAD_CHANNEL_DESCRIPTION = AndroidUtils.getString("music_dl_progress");
|
||||
public static final String MUSIC_DOWNLOAD_CHANNEL_NAME = "Загрузка музыки";
|
||||
public static final String MUSIC_DOWNLOAD_CHANNEL_DESCRIPTION = "Прогресс загрузки музыки";
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void createChannels() {
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package ru.vtosters.lite.encryption;
|
||||
|
||||
import static ru.vtosters.lite.hooks.MessagesHook.injectOwnText;
|
||||
import static ru.vtosters.lite.hooks.MessagesHook.injectOwnTextAll;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.vk.im.engine.models.messages.Msg;
|
||||
import com.vk.im.engine.models.messages.MsgFromUser;
|
||||
import com.vk.im.ui.components.msg_list.MsgListComponent;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -52,48 +48,6 @@ public class EncryptProvider {
|
||||
public static int getPeerId(Msg msg) {
|
||||
return msg.v1();
|
||||
}
|
||||
|
||||
// For message editing
|
||||
public static String decryptMessage(MsgFromUser msg, boolean showEmoji) {
|
||||
var decryptedMessage = decryptMessage(getBody(msg), getPeerId(msg));
|
||||
if (!showEmoji && !decryptedMessage.equals(injectOwnTextAll(getBody(msg)))) decryptedMessage = decryptedMessage.replaceAll("^\uD83D\uDD12 ", "");
|
||||
return decryptedMessage;
|
||||
}
|
||||
|
||||
public static String decryptMessage(String msg, MsgListComponent list) {
|
||||
var peerid = list.G().getId();
|
||||
var decryptedMessage = decryptMessage(msg, peerid);
|
||||
if (!decryptedMessage.equals(injectOwnTextAll(msg))) decryptedMessage = decryptedMessage.replaceAll("^\uD83D\uDD12 ", "");
|
||||
return decryptedMessage;
|
||||
}
|
||||
|
||||
public static CharSequence decryptMessage(CharSequence msg, int peerid) {
|
||||
return decryptMessage(msg.toString(), peerid);
|
||||
}
|
||||
|
||||
public static CharSequence decryptMessage(Msg msg, CharSequence orig) {
|
||||
if (msg instanceof MsgFromUser) {
|
||||
var decrypted = decryptMessage(((MsgFromUser) msg).f(), msg.v1());
|
||||
|
||||
if (decrypted.contains("\uD83D\uDD12")) {
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
public static String decryptMessages(String msgBody, int peer, boolean showEmoji) {
|
||||
return (String) decryptMessage(msgBody, peer, showEmoji);
|
||||
}
|
||||
|
||||
// For MentionsFormatter that requires CharSequence
|
||||
public static CharSequence decryptMessage(String msgBody, int peer, boolean showEmoji) {
|
||||
var decryptedMessage = decryptMessage(msgBody, peer);
|
||||
if (!showEmoji && !decryptedMessage.equals(injectOwnTextAll(msgBody))) decryptedMessage = decryptedMessage.replaceAll("^\uD83D\uDD12 ", "");
|
||||
return decryptedMessage;
|
||||
}
|
||||
|
||||
// This will run through EVERY single processor available.
|
||||
public static String decryptMessage(MsgFromUser msg) {
|
||||
@@ -104,13 +58,12 @@ public class EncryptProvider {
|
||||
try {
|
||||
for (IMProcessor processor : processors) {
|
||||
if ((processor.isUsed() || !processor.isPublic()) && processor.isEncrypted(msgBody) && (processor.isPublic() || getKeyForProcessor(processor, peer) != null))
|
||||
return "\uD83D\uDD12 " + injectOwnTextAll(processor.decode(msgBody, getKeyForProcessor(processor, peer)));
|
||||
return "\uD83D\uDD12 " + processor.decode(msgBody, getKeyForProcessor(processor, peer));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return injectOwnTextAll(msgBody);
|
||||
return msgBody;
|
||||
}
|
||||
|
||||
private static byte[] getKeyForProcessor(IMProcessor processor, int peer) {
|
||||
@@ -131,8 +84,9 @@ public class EncryptProvider {
|
||||
return keyString.getBytes();
|
||||
}
|
||||
|
||||
// This will use only the processor which was chosen in chat menu
|
||||
// This will use only the processor which was chosen in chat menu [that's why ID is needed, bruh]
|
||||
public static String encryptMessage(MsgFromUser msg) {
|
||||
|
||||
String msgBody = getBody(msg);
|
||||
|
||||
Log.d("EncryptProvider", "encryptMessage: msg = " + msg);
|
||||
@@ -142,11 +96,11 @@ public class EncryptProvider {
|
||||
for (IMProcessor processor : processors) {
|
||||
int peer = getPeerId(msg);
|
||||
if (processor.isUsedToEncrypt(peer)) {
|
||||
return injectOwnText(processor.encode(msgBody, getKeyForProcessor(processor, peer)));
|
||||
return processor.encode(msgBody, getKeyForProcessor(processor, peer));
|
||||
}
|
||||
}
|
||||
|
||||
return injectOwnText(msgBody);
|
||||
return msgBody;
|
||||
}
|
||||
|
||||
// For rendering UI
|
||||
|
||||
@@ -2,13 +2,12 @@ package ru.vtosters.lite.foaf;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static android.widget.Toast.makeText;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.isAnyProxyEnabled;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
import static ru.vtosters.lite.utils.ProxyUtils.apiproxy;
|
||||
import static ru.vtosters.lite.utils.ProxyUtils.getApi;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
@@ -18,15 +17,11 @@ import androidx.exifinterface.media.ExifInterface;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.network.Network;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -40,7 +35,6 @@ public class FoafBase {
|
||||
private static final Pattern FOAF_REGEX = Pattern.compile("<ya:created dc:date=\"(.+?)\"\\/>");
|
||||
private static final Pattern FOAF_REGEX_LAST_SEEN = Pattern.compile("<ya:lastLoggedIn dc:date=\"(.*)(((\\+|-)\\d\\d):(\\d\\d))\"\\/>");
|
||||
private static final Pattern FOAF_REGEX_LOGIN = Pattern.compile("<ya:created dc:date=\"(.+?)\"\\/>");
|
||||
private static final String API_VKNEXT = "https://api.vtosters.app/v1/getBypassedOnlineInfo?json=1&ids=";
|
||||
private static final OkHttpClient client = new OkHttpClient();
|
||||
|
||||
public static long getLastSeen(long origtime, int id) throws ParseException, IOException {
|
||||
@@ -64,57 +58,15 @@ public class FoafBase {
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
|
||||
Date date = sdf.parse(Objects.requireNonNull(matcher.group(1)));
|
||||
Date date = sdf.parse(matcher.group(1));
|
||||
sdf.setTimeZone(TimeZone.getDefault());
|
||||
return sdf.parse(sdf.format(date)).getTime() / 1000;
|
||||
}
|
||||
|
||||
|
||||
public static JSONObject getBypassedOnlineInfo(int id) throws JSONException {
|
||||
var request = new okhttp3.Request.a()
|
||||
.b(API_VKNEXT + Integer.toString(id))
|
||||
.a();
|
||||
|
||||
String response = null;
|
||||
|
||||
var dummy = new JSONObject();
|
||||
dummy.put("last_seen", 0);
|
||||
|
||||
try {
|
||||
response = client.a(request).execute().a().g();
|
||||
var online_info = new JSONObject(response).optJSONObject("response").optJSONObject(Integer.toString(id));
|
||||
return online_info == null ? dummy : online_info;
|
||||
} catch (Exception e) {
|
||||
Log.e("GetBypassedOnlineInfo", e.getMessage());
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONObject getBypassedOnlineInfo(String ids) throws JSONException {
|
||||
|
||||
|
||||
var request = new okhttp3.Request.a()
|
||||
.b(API_VKNEXT + ids)
|
||||
.a();
|
||||
|
||||
String response = null;
|
||||
|
||||
var dummy = new JSONObject();
|
||||
|
||||
try {
|
||||
response = client.a(request).execute().a().g();
|
||||
var online_info = new JSONObject(response).optJSONObject("response");
|
||||
return online_info == null ? dummy : online_info;
|
||||
} catch (Exception e) {
|
||||
Log.e("GetBypassedOnlineInfo1", e.getMessage());
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getLink(int i) {
|
||||
String str;
|
||||
StringBuilder sb;
|
||||
if (isAnyProxyEnabled()) {
|
||||
if (apiproxy()) {
|
||||
sb = new StringBuilder();
|
||||
str = "https://" + getApi() + "/_/vk.com/foaf.php?id=";
|
||||
} else {
|
||||
@@ -143,8 +95,8 @@ public class FoafBase {
|
||||
Matcher matcher2 = FOAF_REGEX_LOGIN.matcher(str);
|
||||
matcher.find();
|
||||
matcher2.find();
|
||||
String normalHumanDate = getNormalHumanDate(Objects.requireNonNull(matcher.group(1)));
|
||||
getNormalHumanDate(Objects.requireNonNull(matcher2.group(1)));
|
||||
String normalHumanDate = getNormalHumanDate(matcher.group(1));
|
||||
getNormalHumanDate(matcher2.group(1));
|
||||
VkAlertDialog.Builder a2 = new VkAlertDialog.Builder(context).setTitle(getIdentifier("addinf", "string"));
|
||||
a2.setMessage(getString("foafid") + " " + i + getString("foafregdate") + " " + normalHumanDate + getString("foafdate") + " " + daysPassedFromFoafDate(normalHumanDate)).setPositiveButton(17039370, null).create().show();
|
||||
} catch (Exception e) {
|
||||
@@ -153,9 +105,8 @@ public class FoafBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static long daysPassedFromFoafDate(String str) {
|
||||
private static long daysPassedFromFoafDate(String str) {
|
||||
try {
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
Date parse = new SimpleDateFormat("yyyy-MM-dd").parse(str.split(" ")[1]);
|
||||
return TimeUnit.DAYS.convert(new Date().getTime() - parse.getTime(), TimeUnit.MILLISECONDS);
|
||||
} catch (ParseException e) {
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.checkCaption;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.checkCopyright;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isBadNews;
|
||||
import static ru.vtosters.lite.utils.Preferences.ads;
|
||||
import static ru.vtosters.lite.utils.Preferences.adsgroup;
|
||||
import static ru.vtosters.lite.utils.Preferences.adsstories;
|
||||
import static ru.vtosters.lite.utils.Preferences.authorsrecomm;
|
||||
import static ru.vtosters.lite.utils.Preferences.dev;
|
||||
import static ru.vtosters.lite.utils.Preferences.friendsrecomm;
|
||||
import static ru.vtosters.lite.utils.Preferences.postsrecomm;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.NewsFeedFiltersUtils;
|
||||
|
||||
public class AdBlockHook {
|
||||
public static Boolean discoverAdBlock(JSONObject jsonObject) {
|
||||
if (jsonObject == null) return true;
|
||||
|
||||
try {
|
||||
var type = jsonObject.optString("type");
|
||||
var post = jsonObject.optJSONObject("post");
|
||||
|
||||
if (jsonObject.optString("template").contains("ads") || jsonObject.has("ads")) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + (post != null ? post.optInt("post_id") : 0) + " from discover, Reason: ads");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isAds(post, type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (authorsrecomm() && (type.equals("authors_rec")
|
||||
|| type.startsWith("recommended_") && (type.endsWith("audios")
|
||||
|| type.endsWith("artists")
|
||||
|| type.endsWith("playlists")
|
||||
|| type.endsWith("groups")))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + (post != null ? post.optInt("post_id") : 0) + " from discover, Reason: authorsrecomm");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (postsrecomm() && (type.equals("inline_user_rec") || type.equals("live_recommended"))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + (post != null ? post.optInt("post_id") : 0) + " from discover, Reason: postsrecomm");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (friendsrecomm() && (type.equals("user_rec") || type.equals("friends_recomm"))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + (post != null ? post.optInt("post_id") : 0) + " from discover, Reason: friendsrecomm");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (adsgroup() && (post != null ? post.optInt("marked_as_ads") : 0) == 1 && !isWhitelistedAd(post)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + post.optInt("post_id") + " from discover, Reason: marked_as_ads is true");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (post != null) {
|
||||
if (isBadNews(post.optString("text")) && !isWhitelistedFilters(post)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + post.optInt("post_id") + " from discover, Reason: text filters");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkCopyright(post) && !isWhitelistedFilters(post)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + post.optInt("post_id") + " from discover, Reason: copyright filters");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkCaption(post) && !isWhitelistedFilters(post)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + post.optInt("post_id") + " from discover, Reason: caption filters");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NewsFeedFiltersUtils.injectFiltersReposts(post) && !isWhitelistedFilters(post)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + post.optInt("post_id") + " from discover, Reason: repost ad");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("NewsfeedAdBlockV2", "discover: " + e.getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static JSONObject discoverInject(JSONObject json) throws JSONException {
|
||||
var items = json.optJSONArray("items");
|
||||
var newObj = new JSONArray();
|
||||
|
||||
// newObj.put(discoverObj()); // template injection
|
||||
|
||||
for (int i = 0; i < (items != null ? items.length() : 0); i++) {
|
||||
try {
|
||||
var curr = items.getJSONObject(i);
|
||||
if (!curr.optString("template").contains("info") && discoverAdBlock(curr)) {
|
||||
newObj.put(items.optJSONObject(i));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("NewsfeedAdBlockV2", "discover: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
json.put("items", newObj);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONObject discoverObj() throws JSONException {
|
||||
var mainjson = new JSONObject();
|
||||
|
||||
var info = new JSONObject();
|
||||
info.put("title", "Test Injection");
|
||||
info.put("text_color", "#ffffff");
|
||||
info.put("description", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat");
|
||||
|
||||
var image = new JSONArray();
|
||||
var imageQuality1 = new JSONObject();
|
||||
imageQuality1.put("url", "https://w7.pngwing.com/pngs/505/1021/png-transparent-konata-izumi-lucky-star-desktop-anime-anime-blue-mammal-face.png");
|
||||
imageQuality1.put("width", 72); // 72, 108, 144, 216, 288
|
||||
imageQuality1.put("height", 72); // 72, 108, 144, 216, 288
|
||||
image.put(imageQuality1);
|
||||
|
||||
var background = new JSONArray();
|
||||
var backgroundQuality1 = new JSONObject();
|
||||
backgroundQuality1.put("url", "https://2ch.life/vg/arch/2022-08-22/src/38524739/16440606579870.jpg");
|
||||
backgroundQuality1.put("width", 344); // 344, 516, 680, 1032, 1376
|
||||
backgroundQuality1.put("height", 215); // 215, 323, 426, 645, 860
|
||||
background.put(backgroundQuality1);
|
||||
|
||||
info.put("image", image);
|
||||
info.put("background", background);
|
||||
|
||||
mainjson.put("info", info);
|
||||
mainjson.put("track_code", "info_banner_donut_catalog");
|
||||
mainjson.put("template", "info");
|
||||
|
||||
var action = new JSONObject();
|
||||
action.put("type", "open_url");
|
||||
action.put("url", "vk.com/vtosters_official");
|
||||
action.put("target", "internal");
|
||||
|
||||
mainjson.put("action", action);
|
||||
|
||||
return mainjson;
|
||||
}
|
||||
|
||||
public static JSONArray feedInject(JSONArray items) {
|
||||
if (items.length() == 0) return items;
|
||||
|
||||
try {
|
||||
var newItems = new JSONArray();
|
||||
|
||||
for (int j = 0; j < items.length(); j++) {
|
||||
var list = items.optJSONObject(j);
|
||||
|
||||
if (list == null) continue;
|
||||
|
||||
var type = list.optString("type");
|
||||
|
||||
if (isAds(list, type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (authorsrecomm() && (type.equals("authors_rec")
|
||||
|| type.startsWith("recommended_") && (type.endsWith("audios")
|
||||
|| type.endsWith("artists")
|
||||
|| type.endsWith("playlists")
|
||||
|| type.endsWith("groups")))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: authorsrecomm");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (postsrecomm() && (type.equals("inline_user_rec") || type.equals("live_recommended"))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: postsrecomm");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (friendsrecomm() && (type.equals("user_rec") || type.equals("friends_recomm"))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: friendsrecomm");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (adsgroup() && list.optInt("marked_as_ads") == 1 && !isWhitelistedAd(list)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: marked_as_ads is true");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isBadNews(list.optString("text")) && !isWhitelistedFilters(list)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: text filters");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkCopyright(list) && !isWhitelistedFilters(list)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: copyright filters");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkCaption(list) && !isWhitelistedFilters(list)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: caption filters");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NewsFeedFiltersUtils.injectFiltersReposts(list) && !isWhitelistedFilters(list)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: repost ad");
|
||||
continue;
|
||||
}
|
||||
|
||||
newItems.put(list);
|
||||
}
|
||||
|
||||
return newItems;
|
||||
} catch (Exception e) {
|
||||
Log.d("NewsfeedAdBlockV2", e.getMessage());
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
public static JSONObject storiesads(JSONObject json, boolean isDeleteFix) throws JSONException {
|
||||
if (!adsstories()) {
|
||||
return json;
|
||||
}
|
||||
|
||||
if (json.has("ads")) {
|
||||
var ad = json.optJSONObject("ads");
|
||||
if (isDeleteFix) {
|
||||
if (ad != null) {
|
||||
ad.optJSONObject("settings")
|
||||
.put("stories_interval", 0)
|
||||
.put("authors_interval", 0)
|
||||
.put("time_interval", 0)
|
||||
.put("stories_init", 0)
|
||||
.put("authors_init", 0)
|
||||
.put("time_init", 0);
|
||||
}
|
||||
if (dev()) Log.d("StoriesAds", "Set ads settings at zero values");
|
||||
} else {
|
||||
json.remove("ads");
|
||||
if (dev()) Log.d("StoriesAds", "Removed ads block");
|
||||
}
|
||||
}
|
||||
|
||||
if (!json.has("items")) return json;
|
||||
|
||||
var items = json.optJSONArray("items");
|
||||
if (items != null) {
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
var item = items.optJSONObject(i);
|
||||
if (item != null) {
|
||||
parseStoriesItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
private static void parseStoriesItem(JSONObject item) throws JSONException {
|
||||
var stories = item.optJSONArray("stories");
|
||||
var newStories = new JSONArray();
|
||||
|
||||
if (stories == null) return;
|
||||
|
||||
for (int j = 0; j < stories.length(); j++) {
|
||||
var story = stories.optJSONObject(j);
|
||||
|
||||
if (!story.optBoolean("is_ads") && !story.optBoolean("is_promo")) {
|
||||
newStories.put(story);
|
||||
} else {
|
||||
if (dev())
|
||||
Log.d("StoriesAds", "Fetched ad, owner id " + story.optString("owner_id") + ", caption " + story.optString("caption"));
|
||||
}
|
||||
}
|
||||
|
||||
item.put("stories", newStories);
|
||||
}
|
||||
|
||||
public static Boolean isAds(JSONObject list, String type) throws JSONException {
|
||||
if (list == null || type == null || !ads()) return false;
|
||||
|
||||
if (list.has("ads")
|
||||
|| type.equals("ads")
|
||||
|| type.equals("carousel")
|
||||
|| type.equals("html5_ad")
|
||||
|| type.equals("ads_easy_promote")) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: ads");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.equals("promo_button")
|
||||
|| type.equals("app_widget")
|
||||
|| type.equals("app_video")
|
||||
|| type.equals("app_slider")
|
||||
|| type.equals("tags_suggestions")) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: promo");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Boolean isWhitelistedFilters(JSONObject list) {
|
||||
var id = String.valueOf(list.optInt("owner_id"));
|
||||
|
||||
if (id.equals("0")) {
|
||||
id = String.valueOf(list.optInt("source_id"));
|
||||
}
|
||||
|
||||
if (id.equals("-189659924")){
|
||||
return true;
|
||||
}
|
||||
|
||||
var whitelist = AndroidUtils.getDefaultPrefs().getStringSet("whitelisted_filters_groups", Collections.synchronizedSet(new LinkedHashSet<>()));
|
||||
|
||||
return whitelist.contains(id);
|
||||
}
|
||||
|
||||
public static Boolean isWhitelistedAd(JSONObject list) {
|
||||
var id = String.valueOf(list.optInt("owner_id"));
|
||||
|
||||
if (id.equals("0")) {
|
||||
id = String.valueOf(list.optInt("source_id"));
|
||||
}
|
||||
|
||||
var whitelist = AndroidUtils.getDefaultPrefs().getStringSet("whitelisted_ad_groups", Collections.synchronizedSet(new LinkedHashSet<>()));
|
||||
|
||||
return whitelist.contains(id);
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
import static ru.vtosters.lite.dnr.DNRInjector.forceInvalidateDialogActions;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
import static ru.vtosters.lite.utils.LifecycleUtils.getCurrentActivity;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAlertStyle;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getSTextAttr;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.text.Editable;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.im.engine.models.dialogs.Dialog;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import ru.vtosters.lite.encryption.EncryptProvider;
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
|
||||
public class CryptImHook{
|
||||
public static boolean isPrivateProcessor(int peerID){
|
||||
for (IMProcessor processor : EncryptProvider.processors) {
|
||||
if (processor.isUsedToEncrypt(peerID)) {
|
||||
return !processor.isPublic();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void hook(int peerId, Dialog d){
|
||||
List<IMProcessor> processors = EncryptProvider.processors;
|
||||
|
||||
IMProcessor enabled = null;
|
||||
int enabledPosition = 0;
|
||||
|
||||
String[] titles = new String[processors.size() + 1];
|
||||
titles[0] = getString("encryption_disable");
|
||||
|
||||
for (int i = 0; i < processors.size(); i++) {
|
||||
IMProcessor proc = processors.get(i);
|
||||
|
||||
titles[i + 1] = proc.getUIName();
|
||||
|
||||
if (proc.isUsedToEncrypt(peerId)) {
|
||||
enabled = proc;
|
||||
enabledPosition = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
IMProcessor finalEnabled = enabled;
|
||||
new VkAlertDialog.Builder(getCurrentActivity())
|
||||
.setTitle(getString("encryption_sett"))
|
||||
.setSingleChoiceItems(titles, enabledPosition, (dialog, which) -> {
|
||||
if (which == 0) {
|
||||
if (finalEnabled != null) finalEnabled.disableEncryptFor(peerId);
|
||||
} else {
|
||||
IMProcessor proc = processors.get(which - 1);
|
||||
|
||||
if (proc.isUsedToEncrypt(peerId)) {
|
||||
proc.disableEncryptFor(peerId);
|
||||
} else {
|
||||
proc.enableEncryptFor(peerId);
|
||||
if (finalEnabled != null) finalEnabled.disableEncryptFor(peerId);
|
||||
}
|
||||
}
|
||||
|
||||
dialog.dismiss();
|
||||
forceInvalidateDialogActions(d);
|
||||
}).create().show();
|
||||
}
|
||||
|
||||
public static void hookPref(int peerId){
|
||||
IMProcessor enabled = null;
|
||||
String key = null;
|
||||
|
||||
for (IMProcessor processor : EncryptProvider.processors) {
|
||||
if (processor.isUsedToEncrypt(peerId)) {
|
||||
enabled = processor;
|
||||
}
|
||||
}
|
||||
|
||||
if (enabled != null && enabled.isPublic()) {
|
||||
sendToast(getString("encryption_public_algorithm_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Objects.requireNonNull(enabled).getEncryptionKeyFor(peerId) != null) {
|
||||
key = enabled.getEncryptionKeyFor(peerId);
|
||||
}
|
||||
|
||||
if (key.equals("VTAesDefault")) {
|
||||
key = null;
|
||||
}
|
||||
|
||||
Context ctx = getCurrentActivity();
|
||||
|
||||
LinearLayout linearLayout = new LinearLayout(ctx);
|
||||
|
||||
final EditText editText = new EditText(ctx);
|
||||
editText.setHintTextColor(getSTextAttr());
|
||||
editText.setBackgroundTintList(ColorStateList.valueOf(getSTextAttr()));
|
||||
|
||||
linearLayout.addView(editText);
|
||||
editText.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
ViewGroup.MarginLayoutParams margin = ((ViewGroup.MarginLayoutParams) editText.getLayoutParams());
|
||||
margin.setMargins(dp2px(24f), 0, dp2px(24f), 0);
|
||||
editText.setLayoutParams(margin);
|
||||
editText.setText(key == null ? "" : key);
|
||||
|
||||
IMProcessor finalEnabled = enabled;
|
||||
new AlertDialog.Builder(ctx, getAlertStyle())
|
||||
.setTitle(getString("encryption_enter_key"))
|
||||
.setMessage(String.format(getString("encryption_current_algorithm_title"), enabled.getUIName()))
|
||||
.setView(linearLayout)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
Editable edit = editText.getText();
|
||||
finalEnabled.setEncryptionKeyFor(peerId, edit == null ? null : edit.toString());
|
||||
}).setNegativeButton(android.R.string.cancel, null).create().show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
|
||||
import com.vk.extensions.ViewExtKt;
|
||||
import com.vk.navigation.right.RightMenuPresenter;
|
||||
|
||||
import ru.vtosters.lite.ui.views.VTLCheckableButton;
|
||||
|
||||
public class DayNightButtonHook {
|
||||
|
||||
public static void injectOnClick(VTLCheckableButton button, RightMenuPresenter presenter) {
|
||||
button.postOnAnimationDelayed(() -> {
|
||||
var rect = ViewExtKt.e(button);
|
||||
presenter.a(new float[] { rect.centerX(), rect.centerY() });
|
||||
}, 550); // minimal delay for fix toggle animation
|
||||
button.toggle();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,10 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.MD5;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class DeviceInfoHook{
|
||||
public static String getDeviceInfo(String input) {
|
||||
Log.d("DeviceInfoHook", "getDeviceInfo: " + input);
|
||||
@@ -16,30 +13,27 @@ public class DeviceInfoHook{
|
||||
}
|
||||
|
||||
public static String getDeviceId(String input) {
|
||||
return findDeviceId() + ":" + getDeviceId();
|
||||
Log.d("DeviceInfoHook", "getDeviceId: " + input);
|
||||
Log.d("DeviceInfoHook", "getDeviceId shuffled: " + shuffle(input));
|
||||
if (getBoolValue("hideDeviceInfo", true)) return shuffle(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
public static String getDeviceId() {
|
||||
String sb2 = Build.PRODUCT +
|
||||
Build.BOARD +
|
||||
Build.BOOTLOADER +
|
||||
Build.BRAND +
|
||||
Build.DEVICE +
|
||||
Build.DISPLAY +
|
||||
Build.FINGERPRINT +
|
||||
Build.HARDWARE +
|
||||
Build.HOST +
|
||||
Build.ID +
|
||||
Build.MANUFACTURER +
|
||||
Build.MODEL +
|
||||
Build.PRODUCT +
|
||||
Build.TAGS;
|
||||
public static String shuffle(String string) {
|
||||
StringBuilder sb = new StringBuilder(string.length());
|
||||
double rnd;
|
||||
for (char c: string.toCharArray()) {
|
||||
rnd = Math.random();
|
||||
if (rnd < 0.34)
|
||||
sb.append(c);
|
||||
else if (rnd < 0.67)
|
||||
sb.insert(sb.length() / 2, c);
|
||||
else
|
||||
sb.insert(0, c);
|
||||
|
||||
return MD5(sb2);
|
||||
}
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
private static String findDeviceId() {
|
||||
return Settings.Secure.getString(getGlobalContext().getContentResolver(), "android_id");
|
||||
sb.append(new Random().nextInt(10));
|
||||
sb.deleteCharAt(0);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import java.util.Map;
|
||||
|
||||
import ru.vtosters.lite.ui.components.DockBarEditorManager;
|
||||
import ru.vtosters.lite.ui.items.DockBarTab;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class DockBarInjector {
|
||||
private static final DockBarEditorManager sManager = DockBarEditorManager.getInstance();
|
||||
@@ -67,6 +68,7 @@ public class DockBarInjector {
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
public static void inject(BottomNavigationView navigationView) {
|
||||
navigationView.setBackgroundColor(ThemesUtils.getBackgroundContent());
|
||||
Menu menu = navigationView.getMenu();
|
||||
menu.clear();
|
||||
try {
|
||||
@@ -86,14 +88,11 @@ public class DockBarInjector {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (DockBarTab tab : sManager.getSelectedTabs()) {
|
||||
MenuItem add = menu.add(0, tab.id, 0, tab.titleID);
|
||||
Drawable drawable = getResources().getDrawable(tab.iconID);
|
||||
for (DockBarTab tab : sManager.getSelectedTabs())
|
||||
menu.add(0, tab.id, 0, tab.titleID)
|
||||
.setIcon(tab.iconID)
|
||||
.setCheckable(true);
|
||||
|
||||
add.setIcon(new RecoloredDrawable(drawable, getCSTDock()));
|
||||
add.setTitle(getGlobalContext().getString(tab.titleID));
|
||||
add.setCheckable(true);
|
||||
}
|
||||
if (getBoolValue("dockbar_tab_titles", true)) {
|
||||
var menuView = (BottomNavigationMenuView) navigationView.getChildAt(0);
|
||||
for (int i = 0; i < menuView.getChildCount(); i++) {
|
||||
@@ -286,7 +285,7 @@ public class DockBarInjector {
|
||||
}
|
||||
|
||||
public static Class<?> interceptClick(int id, RightMenu rightMenu) {
|
||||
if (id == tab_menu && rightMenu != null) {
|
||||
if (id == tab_menu) {
|
||||
rightMenu.a();
|
||||
}
|
||||
|
||||
@@ -294,7 +293,6 @@ public class DockBarInjector {
|
||||
if (id == tab.id)
|
||||
return tab.fragmentClass;
|
||||
}
|
||||
|
||||
for (DockBarTab tab : sManager.getDisabledTabs()) {
|
||||
if (id == tab.id)
|
||||
return tab.fragmentClass;
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
|
||||
import static ru.vtosters.lite.foaf.FoafBase.getBypassedOnlineInfo;
|
||||
import static ru.vtosters.lite.foaf.FoafBase.getLastSeen;
|
||||
import static ru.vtosters.lite.hooks.DateHook.getLocale;
|
||||
import static ru.vtosters.lite.hooks.OnlineFormatterHook.onlineHookProfiles;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getStatic;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs;
|
||||
import static ru.vtosters.lite.utils.Base64Utils.decode;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.checkCaption;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.checkCopyright;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isBadNews;
|
||||
import static ru.vtosters.lite.utils.Preferences.ads;
|
||||
import static ru.vtosters.lite.utils.Preferences.adsgroup;
|
||||
import static ru.vtosters.lite.utils.Preferences.adsstories;
|
||||
import static ru.vtosters.lite.utils.Preferences.authorsrecomm;
|
||||
import static ru.vtosters.lite.utils.Preferences.dev;
|
||||
import static ru.vtosters.lite.utils.Preferences.friendsblock;
|
||||
import static ru.vtosters.lite.utils.Preferences.friendsrecomm;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.hasVerification;
|
||||
import static ru.vtosters.lite.utils.Preferences.podcastcatalog;
|
||||
import static ru.vtosters.lite.utils.Preferences.postsrecomm;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.accentColors;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.hex2;
|
||||
import static ru.vtosters.lite.utils.VTVerifications.isDeveloper;
|
||||
import static ru.vtosters.lite.utils.VTVerifications.isPrometheus;
|
||||
import static ru.vtosters.lite.utils.VTVerifications.isVerified;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.graphics.Color;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vk.core.network.Network;
|
||||
@@ -28,8 +37,7 @@ import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -38,6 +46,7 @@ import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.NewsFeedFiltersUtils;
|
||||
|
||||
public class JsonInjectors {
|
||||
private static final OkHttpClient mClient = new OkHttpClient();
|
||||
@@ -59,13 +68,24 @@ public class JsonInjectors {
|
||||
newItem.put(vktesters(id));
|
||||
}
|
||||
|
||||
// get text color from all items
|
||||
for (int i = 0; i < newItem.length(); i++) {
|
||||
var item = newItem.getJSONObject(i);
|
||||
if (item.has("text_color")) {
|
||||
var textColor = item.getString("text_color");
|
||||
if (accentColors.contains(Color.parseColor(textColor.startsWith("#") ? textColor : "#" + textColor))) {
|
||||
item.put("text_color", hex2(getAccentColor()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orig.put("buttons", newItem);
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
public static JSONObject donateRecomm() throws JSONException {
|
||||
var title = AndroidUtils.getString("donate_to_vtl");
|
||||
var title = "Помоги проекту донатом и получи бонус!";
|
||||
var link = "https://vk.com/vtosters_official";
|
||||
var text_color = "2D81E0";
|
||||
|
||||
@@ -106,9 +126,9 @@ public class JsonInjectors {
|
||||
}
|
||||
|
||||
public static JSONObject vktesters(int id) throws JSONException {
|
||||
var title = AndroidUtils.getString("tester_profile");
|
||||
var title = "Карточка Тестера";
|
||||
var text_color = "2D81E0";
|
||||
var link = "https://" + getStatic() + "/bugs?lang=" + LangUtils.a() + "#/reporter" + id;
|
||||
var link = "https://static.vk.com/bugs?lang=" + LangUtils.a() + "#/reporter" + id;
|
||||
|
||||
var json = new JSONObject();
|
||||
var icons = new JSONArray();
|
||||
@@ -150,20 +170,27 @@ public class JsonInjectors {
|
||||
var peerid = Objects.requireNonNull(orig.optJSONObject("peer")).optInt("id");
|
||||
|
||||
var pic = "https://image.pngaaa.com/641/326641-middle.png"; // can be null
|
||||
var text = AndroidUtils.getString("no_data_error");
|
||||
var text = "Я не загрузил данные (9(9((";
|
||||
var link = "https://vtosters.app"; // can be null
|
||||
var linktitle = "Test button"; // can be null
|
||||
|
||||
var hasIcon = !pic.isEmpty();
|
||||
var hasButton = !link.isEmpty();
|
||||
// "{\"layout\":\"tertiary\",\"text\":\"" + linktitle + "\",\"type\":\"link\",\"link\":\"" + link + "\"}";
|
||||
var buttons = decode("eyJsYXlvdXQiOiJ0ZXJ0aWFyeSIsInRleHQiOiI=") + linktitle + decode("IiwidHlwZSI6ImxpbmsiLCJsaW5rIjoi") + link + decode("In0=");
|
||||
// ,"icon":" + pic + "
|
||||
var icon = decode("LCJpY29uIjoi") + pic + decode("Ig==");
|
||||
|
||||
var hasIcon = !pic.isEmpty();
|
||||
var hasButton = !buttons.isEmpty();
|
||||
var isPicture = pic.endsWith(".png") || pic.endsWith(".jpg") || pic.endsWith(".jpeg") || pic.endsWith(".webp");
|
||||
|
||||
if (isVerified(peerid)) text = AndroidUtils.getString("i_bought") + " VTosters Premium";
|
||||
if (isPrometheus(peerid)) text = AndroidUtils.getString("i_bought") + " VTosters Premium Gold Prime Pro Plus";
|
||||
if (isDeveloper(peerid)) text = AndroidUtils.getString("i_created_poop");
|
||||
if (!isPicture) hasIcon = false;
|
||||
if (!hasIcon) icon = "";
|
||||
if (!hasButton) buttons = "";
|
||||
|
||||
if (!isVerified(peerid) || text.equals("") || peerid == AccountManagerUtils.getUserId() || peerid == 0) {
|
||||
if (isVerified(peerid)) text = "Я купил VTosters Premium";
|
||||
if (isPrometheus(peerid)) text = "Я купил VTosters Premium Gold Prime Pro Plus";
|
||||
if (isDeveloper(peerid)) text = "Я создал говно";
|
||||
if (!isVerified(peerid) || text.equals("")) {
|
||||
if (getBoolValue("convBarRecomm", false)) {
|
||||
return null;
|
||||
} else {
|
||||
@@ -171,27 +198,14 @@ public class JsonInjectors {
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev()) return orig.optJSONObject("conversation_bar"); // for devs only
|
||||
if (!dev()) return orig.optJSONObject("conversation_bar");
|
||||
|
||||
var json = new JSONObject();
|
||||
|
||||
var buttonsJson = new JSONObject();
|
||||
buttonsJson.put("layout", "tertiary");
|
||||
buttonsJson.put("text", linktitle);
|
||||
buttonsJson.put("type", "link");
|
||||
buttonsJson.put("link", link);
|
||||
|
||||
var buttonsjson = new JSONArray(); // max 3 buttons in array
|
||||
if (hasButton) buttonsjson.put(buttonsJson);
|
||||
|
||||
json.put("name", "group_admin_welcome");
|
||||
json.put("text", text);
|
||||
json.put("buttons", buttonsjson);
|
||||
if (hasIcon && isPicture) {
|
||||
json.put("icon", pic);
|
||||
}
|
||||
|
||||
return json;
|
||||
// JSONObject("{\"name\":\"group_admin_welcome\",\"text\":\"" + textverif + "\",\"buttons\":[],\"icon\":\"" + pic + "\"}");
|
||||
return new JSONObject(decode("eyJuYW1lIjoiZ3JvdXBfYWRtaW5fd2VsY29tZSIsInRleHQiOiI=")
|
||||
+ text + decode("IiwiYnV0dG9ucyI6Ww==")
|
||||
+ buttons + decode("XQ==")
|
||||
+ icon
|
||||
+ decode("fQ=="));
|
||||
}
|
||||
|
||||
public static JSONObject menu(JSONObject orig) throws JSONException {
|
||||
@@ -267,120 +281,195 @@ public class JsonInjectors {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONObject setOnlineInfo(JSONObject json) throws JSONException {
|
||||
public static JSONObject setOnlineInfo(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
var id = json.optInt("id");
|
||||
if (id == AccountManagerUtils.getUserId()) {
|
||||
var onlineinfo = json.optJSONObject("online_info");
|
||||
var time = getLastSeen(0L, id);
|
||||
|
||||
if (time != 0L && onlineinfo != null && !onlineinfo.optBoolean("is_online") && id != AccountManagerUtils.getUserId()) {
|
||||
json.remove("online_info");
|
||||
|
||||
var online_info = new JSONObject()
|
||||
.put("visible", true)
|
||||
.put("last_seen", time)
|
||||
.put("is_online", false)
|
||||
.put("app_id", 0)
|
||||
.put("is_mobile", false);
|
||||
|
||||
var last_seen = new JSONObject()
|
||||
.put("platform", 4)
|
||||
.put("time", time);
|
||||
|
||||
json.put("last_seen", last_seen).put("online_info", online_info);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONObject storiesads(JSONObject json, boolean isDeleteFix) throws JSONException {
|
||||
if (!adsstories()) {
|
||||
return json;
|
||||
}
|
||||
var onlineinfo = json.optJSONObject("online_info");
|
||||
if (onlineinfo != null && !onlineinfo.optBoolean("visible")) {
|
||||
var bypassed = getBypassedOnlineInfo(id);
|
||||
if (bypassed.optInt("last_seen", 0) != 0) {
|
||||
json.remove("online_info");
|
||||
|
||||
var online_info = new JSONObject()
|
||||
.put("visible", true)
|
||||
.put("last_seen", bypassed.optInt("last_seen"))
|
||||
.put("is_online", bypassed.optBoolean("is_online"))
|
||||
.put("app_id", bypassed.optInt("app_id"))
|
||||
.put("is_mobile", bypassed.optBoolean("is_mobile"));
|
||||
if (json.has("ads")) {
|
||||
if (isDeleteFix) {
|
||||
json.optJSONObject("ads").optJSONObject("settings")
|
||||
.put("stories_interval", 0)
|
||||
.put("authors_interval", 0)
|
||||
.put("time_interval", 0)
|
||||
.put("stories_init", 0)
|
||||
.put("authors_init", 0)
|
||||
.put("time_init", 0);
|
||||
if (dev()) Log.d("StoriesAds", "Set ads settings at zero values");
|
||||
} else {
|
||||
json.remove("ads");
|
||||
if (dev()) Log.d("StoriesAds", "Removed ads block");
|
||||
}
|
||||
}
|
||||
|
||||
var last_seen = new JSONObject()
|
||||
.put("platform", bypassed.optInt("platform"))
|
||||
.put("time", bypassed.optInt("last_seen"));
|
||||
if (!json.has("items")) return json;
|
||||
|
||||
json.put("last_seen", last_seen).put("online_info", online_info);
|
||||
var items = json.optJSONArray("items");
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
var item = items.optJSONObject(i);
|
||||
if (item != null) {
|
||||
parseStoriesItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONArray setOnlineInfoUsers(JSONArray profiles) throws JSONException {
|
||||
if (profiles == null || profiles.length() == 0) return profiles;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var curVkId = AccountManagerUtils.getUserId();
|
||||
for (int i=0; i < profiles.length(); i++) {
|
||||
JSONObject profile = profiles.getJSONObject(i);
|
||||
int id = profile.optInt("id", -1);
|
||||
JSONObject onlinfo = profile.optJSONObject("online_info");
|
||||
if (id == curVkId || id < 0 || onlinfo == null || onlinfo.optBoolean("visible")) {
|
||||
continue;
|
||||
private static void parseStoriesItem(JSONObject item) throws JSONException {
|
||||
var stories = item.optJSONArray("stories");
|
||||
var newStories = new JSONArray();
|
||||
|
||||
if (stories == null) return;
|
||||
|
||||
for (int j = 0; j < stories.length(); j++) {
|
||||
var story = stories.optJSONObject(j);
|
||||
|
||||
if (!story.optBoolean("is_ads") && !story.optBoolean("is_promo")) {
|
||||
newStories.put(story);
|
||||
} else {
|
||||
if (dev())
|
||||
Log.d("StoriesAds", "Fetched ad, owner id " + story.optString("owner_id") + ", caption " + story.optString("caption"));
|
||||
}
|
||||
sb.append(id);
|
||||
sb.append(",");
|
||||
}
|
||||
var ids = sb.toString();
|
||||
if (ids.length() > 0) {
|
||||
ids = ids.substring(0, ids.length() - 1);
|
||||
} else {
|
||||
return profiles;
|
||||
}
|
||||
|
||||
JSONObject bypassedObj = getBypassedOnlineInfo(ids);
|
||||
for (int i=0; i < profiles.length(); i++) {
|
||||
JSONObject profile = profiles.getJSONObject(i);
|
||||
int id = profile.optInt("id");
|
||||
JSONObject bypassed = bypassedObj.optJSONObject(Integer.toString(id));
|
||||
if (bypassed == null) {
|
||||
continue;
|
||||
}
|
||||
profile.remove("online_info");
|
||||
item.put("stories", newStories);
|
||||
}
|
||||
|
||||
var online_info = new JSONObject()
|
||||
.put("visible", true)
|
||||
.put("last_seen", bypassed.optInt("last_seen"))
|
||||
.put("is_online", bypassed.optBoolean("is_online"))
|
||||
.put("app_id", bypassed.optInt("app_id"))
|
||||
.put("is_mobile", bypassed.optBoolean("is_mobile"));
|
||||
public static Boolean isAds(JSONObject list, String type) throws JSONException {
|
||||
if (list == null || type == null || !ads()) return false;
|
||||
|
||||
var last_seen = new JSONObject()
|
||||
.put("platform", bypassed.optInt("platform"))
|
||||
.put("time", bypassed.optInt("last_seen"));
|
||||
|
||||
profile.put("last_seen", last_seen).put("online_info", online_info);
|
||||
if (list.has("ads")
|
||||
|| type.equals("ads")
|
||||
|| type.equals("carousel")
|
||||
|| type.equals("html5_ad")
|
||||
|| type.equals("ads_easy_promote")) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: ads");
|
||||
return true;
|
||||
}
|
||||
|
||||
return profiles;
|
||||
if (type.equals("promo_button")
|
||||
|| type.equals("app_widget")
|
||||
|| type.equals("app_video")
|
||||
|| type.equals("app_slider")
|
||||
|| type.equals("tags_suggestions")) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: promo");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static JSONArray newsfeedlist(JSONArray items) throws JSONException {
|
||||
var selectedItems = getDefaultPrefs().getString("news_feed_selected_items", "");
|
||||
var filtersSet = getDefaultPrefs().getStringSet("news_feed_items_set", null);
|
||||
var mutableFiltersSet = Collections.synchronizedSet(new LinkedHashSet<String>());
|
||||
if (filtersSet != null)
|
||||
mutableFiltersSet.addAll(filtersSet);
|
||||
for (int j = 0; j < items.length(); j++) {
|
||||
var list = items.optJSONObject(j);
|
||||
var name = list.optString("id");
|
||||
|
||||
synchronized (mutableFiltersSet) {
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
var item = items.optJSONObject(i);
|
||||
if (item == null) continue;
|
||||
|
||||
var id = item.optString("id");
|
||||
var title = item.optString("title");
|
||||
|
||||
if (TextUtils.isEmpty(id) || TextUtils.isEmpty(title)
|
||||
// this items not working
|
||||
|| id.equals("kpop") || id.equals("foryou")
|
||||
|| id.equals("qazaqstan") || id.equals("podcasts"))
|
||||
continue;
|
||||
|
||||
mutableFiltersSet.add(id + "|" + title);
|
||||
|
||||
var hide = selectedItems.contains(id);
|
||||
|
||||
Log.d("NewsfeedList", "Added list " + id + " to feed");
|
||||
item.put("is_hidden", hide)
|
||||
.put("is_unavailable", hide);
|
||||
if (dev()) Log.d("NewsfeedListInj", "Unlocked " + id + " in newsfeed list");
|
||||
if (!name.equals("kpop") && !name.equals("foryou") && !name.equals("qazaqstan")) {
|
||||
list.put("is_hidden", false).put("is_unavailable", false);
|
||||
if (dev()) Log.d("NewsfeedListInj", "Unlocked " + name + " in newsfeed list");
|
||||
}
|
||||
getDefaultPrefs().edit().putStringSet("news_feed_items_set", mutableFiltersSet)
|
||||
.apply();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public static JSONArray newsfeedadtest(JSONArray items) throws JSONException {
|
||||
if (!getBoolValue("newadblock", true)) return items;
|
||||
var newItems = new JSONArray();
|
||||
|
||||
for (int j = 0; j < items.length(); j++) {
|
||||
var list = items.optJSONObject(j);
|
||||
var type = list.optString("type");
|
||||
|
||||
if (isAds(list, type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (authorsrecomm() && (type.equals("authors_rec")
|
||||
|| type.startsWith("recommended_") && (type.endsWith("audios")
|
||||
|| type.endsWith("artists")
|
||||
|| type.endsWith("playlists")
|
||||
|| type.endsWith("groups")))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: authorsrecomm");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (postsrecomm() && (type.equals("inline_user_rec") || type.equals("live_recommended"))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: postsrecomm");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (friendsrecomm() && (type.equals("user_rec") || type.equals("friends_recomm"))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: friendsrecomm");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (adsgroup() && list.optInt("marked_as_ads") == 1) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: marked_as_ads is true");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isBadNews(list.optString("text"))) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: text filters");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkCopyright(list)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: copyright filters");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkCaption(list)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: caption filters");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NewsFeedFiltersUtils.injectFiltersReposts(list)) {
|
||||
if (dev())
|
||||
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: repost ad");
|
||||
continue;
|
||||
}
|
||||
|
||||
newItems.put(list);
|
||||
}
|
||||
|
||||
return newItems;
|
||||
}
|
||||
|
||||
public static JSONObject music(JSONObject json) throws JSONException {
|
||||
var catalog = json.optJSONObject("catalog");
|
||||
|
||||
@@ -454,7 +543,7 @@ public class JsonInjectors {
|
||||
|
||||
Log.d("VKMusic", "title: " + title + " id: " + id + " url: " + url + " value: " + value);
|
||||
|
||||
if (url.contains(value) && !value.isEmpty()) {
|
||||
if (url.contains(value)) {
|
||||
catalog.put("default_section", id);
|
||||
if (dev()) Log.d("VKMusic", "Added " + title + " as default music section");
|
||||
}
|
||||
@@ -468,7 +557,7 @@ public class JsonInjectors {
|
||||
if (section == null) return null;
|
||||
|
||||
var request = new Request.a()
|
||||
.b("https://" + getApi() + "/method/catalog.getAudio"
|
||||
.b("https://api.vk.com/method/catalog.getAudio"
|
||||
+ "?v=5.119"
|
||||
+ "&https=1"
|
||||
+ "&need_blocks=1"
|
||||
@@ -492,7 +581,7 @@ public class JsonInjectors {
|
||||
|
||||
public static JSONObject fetchCatalogPodcast() {
|
||||
var request = new Request.a()
|
||||
.b("https://" + getApi() + "/method/catalog.getPodcasts"
|
||||
.b("https://api.vk.com/method/catalog.getPodcasts"
|
||||
+ "?v=5.119"
|
||||
+ "&https=1"
|
||||
+ "&need_blocks=1"
|
||||
@@ -512,8 +601,8 @@ public class JsonInjectors {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static JSONObject friends(JSONObject json) throws JSONException, ParseException, IOException {
|
||||
JSONObject catalog = onlineHookProfiles(json);
|
||||
public static JSONObject friends(JSONObject json) throws JSONException {
|
||||
JSONObject catalog = json;
|
||||
boolean sectionexecute = true;
|
||||
boolean hasBirthday = false;
|
||||
|
||||
@@ -578,6 +667,7 @@ public class JsonInjectors {
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
public static boolean haveDonateButton() {
|
||||
int randomshower = new Random().nextInt(6);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package ru.vtosters.lite.hooks;
|
||||
|
||||
import static ru.vtosters.lite.ui.dialogs.ServerDialog.sendRequest;
|
||||
import static ru.vtosters.lite.utils.CacheUtils.getInstance;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.setupFilters;
|
||||
import static ru.vtosters.lite.utils.Preferences.checkupdates;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.isDarkTheme;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.setNeededTheme;
|
||||
@@ -11,24 +10,19 @@ import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.vk.core.concurrent.VkExecutors;
|
||||
|
||||
import ru.vtosters.lite.downloaders.notifications.NotificationChannels;
|
||||
import ru.vtosters.lite.ui.dialogs.DisableBattery;
|
||||
import ru.vtosters.lite.ui.dialogs.InstallGMS;
|
||||
import ru.vtosters.lite.ui.dialogs.OTADialog;
|
||||
import ru.vtosters.lite.ui.dialogs.ServerDialog;
|
||||
import ru.vtosters.lite.ui.dialogs.Start;
|
||||
import ru.vtosters.lite.utils.DeletedMessagesHandler;
|
||||
|
||||
public class MainActivityInjector{
|
||||
|
||||
public static void inject(Activity activity){
|
||||
public class MainActivityInjector {
|
||||
public static void inject(Activity activity) {
|
||||
setNeededTheme(activity);
|
||||
ServerDialog.activity = activity;
|
||||
sendRequest();
|
||||
if (checkupdates()) OTADialog.checkUpdates(activity);
|
||||
VkExecutors.x.f().a(DeletedMessagesHandler::reloadMessagesList); // ioScheduler
|
||||
Start.alert(activity);
|
||||
InstallGMS.alert(activity);
|
||||
DisableBattery.alert(activity);
|
||||
@@ -36,17 +30,10 @@ public class MainActivityInjector{
|
||||
.edit()
|
||||
.putBoolean("isdark", isDarkTheme())
|
||||
.commit();
|
||||
|
||||
VkExecutors.x.q().a(() -> {
|
||||
getInstance().autoCleaningCache();
|
||||
}); // slowTasksScheduler
|
||||
|
||||
setupFilters();
|
||||
|
||||
getInstance().autoCleaningCache();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannels.createChannels();
|
||||
}
|
||||
|
||||
// VKIDProtection.alert(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,12 @@ import android.view.View;
|
||||
|
||||
import com.vk.api.internal.MethodCall;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ru.vtosters.lite.translators.BaseTranslator;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MessagesHook {
|
||||
public static String injectOwnText(String oldText) {
|
||||
if (!autotranslate() || TextUtils.isEmpty(oldText))
|
||||
|
||||
@@ -1,27 +1,58 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
|
||||
import static java.lang.Long.MAX_VALUE;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.ads;
|
||||
import static ru.vtosters.lite.utils.Preferences.adsslider;
|
||||
import static ru.vtosters.lite.utils.Preferences.authorsrecomm;
|
||||
import static ru.vtosters.lite.utils.Preferences.friendsrecomm;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.checkCaption;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.checkCopyright;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.injectFiltersReposts;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isAds;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isAuthorRecommendations;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isBadNews;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isFriendsRecommendations;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isGroupAds;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isMusicBlock;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isNewsBlock;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isPostRecommendations;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.isRecomsGroup;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme;
|
||||
|
||||
import com.vk.core.preference.Preference;
|
||||
import com.vtosters.lite.api.ExtendedCommunityProfile;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
|
||||
public class NewsfeedHook {
|
||||
public static boolean injectFilters(JSONObject obj) throws JSONException {
|
||||
if (getBoolValue("newadblock", true)) return true;
|
||||
|
||||
var optString = obj.optString("type", "");
|
||||
if (isAds(optString) || isAuthorRecommendations(optString) || isPostRecommendations(optString) || isFriendsRecommendations(optString) || isRecomsGroup(optString) || isMusicBlock(optString) || isNewsBlock(optString)) {
|
||||
return false;
|
||||
}
|
||||
optString = obj.optString("post_type", "");
|
||||
if (isAds(optString) || isAuthorRecommendations(optString) || isPostRecommendations(optString) || isFriendsRecommendations(optString) || isMusicBlock(optString) || isNewsBlock(optString)) {
|
||||
return false;
|
||||
}
|
||||
optString = obj.optString("filters", "");
|
||||
if (isAds(optString) || isAuthorRecommendations(optString) || isPostRecommendations(optString) || isFriendsRecommendations(optString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkCopyright(obj)) return false;
|
||||
|
||||
if (isBadNews(obj.optString("text", ""))) return false;
|
||||
|
||||
if (checkCaption(obj)) return false;
|
||||
|
||||
if (isGroupAds(obj)) return false;
|
||||
|
||||
return !injectFiltersReposts(obj);
|
||||
} // inject our filters to newsfeed, getpost and discover
|
||||
|
||||
public static long getUpdateNewsfeed(boolean refresh_timeout) {
|
||||
if (vkme()) {
|
||||
return MAX_VALUE;
|
||||
@@ -42,84 +73,4 @@ public class NewsfeedHook {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static String[] feedParams(){
|
||||
HashSet<String> params = new HashSet<>();
|
||||
params.add("post");
|
||||
params.add("photo");
|
||||
params.add("photo_tag");
|
||||
|
||||
if (!friendsrecomm() && !getBoolValue("donotgetads", false)) {
|
||||
params.add("friends_recomm");
|
||||
}
|
||||
|
||||
if (!ads()) {
|
||||
params.add("app_widget");
|
||||
params.add("promo_button");
|
||||
}
|
||||
|
||||
if (!authorsrecomm() && !getBoolValue("donotgetads", false)) {
|
||||
params.add("authors_rec");
|
||||
}
|
||||
|
||||
return params.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public static boolean isWhitelistedFilter(ExtendedCommunityProfile eup) {
|
||||
return getDefaultPrefs().getStringSet("whitelisted_filters_groups", Collections.synchronizedSet(new LinkedHashSet<>())).contains(String.valueOf(AccountManagerUtils.getUserID(eup)));
|
||||
}
|
||||
|
||||
public static boolean isWhitelistedAd(ExtendedCommunityProfile eup) {
|
||||
return getDefaultPrefs().getStringSet("whitelisted_ad_groups", Collections.synchronizedSet(new LinkedHashSet<>())).contains(String.valueOf(AccountManagerUtils.getUserID(eup)));
|
||||
}
|
||||
|
||||
public static void setWhitelistedFilter(ExtendedCommunityProfile eup, boolean needWhitelist) {
|
||||
var mutableAdsSet = Collections.synchronizedSet(new LinkedHashSet<String>());
|
||||
var id = String.valueOf(AccountManagerUtils.getUserID(eup));
|
||||
|
||||
mutableAdsSet.addAll(getDefaultPrefs().getStringSet("whitelisted_filters_groups", mutableAdsSet));
|
||||
|
||||
if (needWhitelist) {
|
||||
mutableAdsSet.add(id);
|
||||
} else {
|
||||
mutableAdsSet.remove(id);
|
||||
}
|
||||
|
||||
getDefaultPrefs().edit().putStringSet("whitelisted_filters_groups", mutableAdsSet).apply();
|
||||
}
|
||||
|
||||
public static void setWhitelistedAd(ExtendedCommunityProfile eup, boolean needWhitelist) {
|
||||
var mutableAdsSet = Collections.synchronizedSet(new LinkedHashSet<String>());
|
||||
var id = String.valueOf(AccountManagerUtils.getUserID(eup));
|
||||
|
||||
mutableAdsSet.addAll(getDefaultPrefs().getStringSet("whitelisted_ad_groups", mutableAdsSet));
|
||||
|
||||
if (needWhitelist) {
|
||||
mutableAdsSet.add(id);
|
||||
} else {
|
||||
mutableAdsSet.remove(id);
|
||||
}
|
||||
|
||||
getDefaultPrefs().edit().putStringSet("whitelisted_ad_groups", mutableAdsSet).apply();
|
||||
}
|
||||
|
||||
public static void adsParams(HashSet<String> hashSet) {
|
||||
if (ads()) {
|
||||
hashSet.add("ads_disabled");
|
||||
if (getBoolValue("donotgetads", false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hashSet.add("ads_app");
|
||||
hashSet.add("ads_site");
|
||||
hashSet.add("ads_post");
|
||||
if (!adsslider()) {
|
||||
hashSet.add("ads_app_slider");
|
||||
}
|
||||
hashSet.add("ads_site_slider");
|
||||
hashSet.add("ads_app_video");
|
||||
hashSet.add("ads_post_pretty_cards");
|
||||
hashSet.add("ads_post_snippet_video");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
|
||||
import static ru.vtosters.lite.hooks.JsonInjectors.setOnlineInfo;
|
||||
import static ru.vtosters.lite.hooks.JsonInjectors.setOnlineInfoUsers;
|
||||
import static ru.vtosters.lite.net.Request.makeRequest;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
import static ru.vtosters.lite.utils.Preferences.dev;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.getPrefsFromFile;
|
||||
|
||||
import android.util.Log;
|
||||
import static ru.vtosters.lite.utils.ProxyUtils.getApi;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@@ -20,8 +17,6 @@ import org.json.JSONObject;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class OnlineFormatterHook {
|
||||
private static String AppName;
|
||||
|
||||
@@ -64,37 +59,37 @@ public class OnlineFormatterHook {
|
||||
case 5027722:
|
||||
return "VK Messenger (Desktop)";
|
||||
case 6146827:
|
||||
return AndroidUtils.getString("vk_messenger") + " (Android)"; // VK Мессенджер (Android)
|
||||
return "VK Мессенджер (Android)";
|
||||
case 6482950:
|
||||
return AndroidUtils.getString("vk_messenger") + " (iPhone)"; // VK Мессенджер (iPhone)
|
||||
return "VK Мессенджер (iPhone)";
|
||||
case 6481715:
|
||||
return AndroidUtils.getString("vk_messenger") + " Dev (iPhone)"; // VK Мессенджер Dev (iPhone)
|
||||
return "VK Мессенджер Dev (iPhone)";
|
||||
case 7799655:
|
||||
return AndroidUtils.getString("vk_mail_online"); // VK Почта
|
||||
return "VK Почта";
|
||||
case 7598572:
|
||||
return AndroidUtils.getString("sferum_online") + " (Android)"; // Сферум (Android)
|
||||
return "Сферум (Android)";
|
||||
case 7571751:
|
||||
return AndroidUtils.getString("sferum_online") + " (iPhone)"; // Сферум (iPhone)
|
||||
return "Сферум (iPhone)";
|
||||
case 7556576:
|
||||
return AndroidUtils.getString("sferum_online"); // Сферум
|
||||
return "Сферум";
|
||||
case 7497650:
|
||||
return "VK ID";
|
||||
case 8094476:
|
||||
return AndroidUtils.getString("vk_calls_online") + " (Android)"; // VK Звонки (Android)
|
||||
return "VK Звонки (Android)";
|
||||
case 8093730:
|
||||
return AndroidUtils.getString("vk_calls_online") + " (iPhone)"; // VK Звонки (iPhone)
|
||||
return "VK Звонки (iPhone)";
|
||||
case 7793118:
|
||||
return AndroidUtils.getString("vk_calls_online") + " (Desktop)"; // VK Звонки (Desktop)
|
||||
return "VK Звонки (Desktop)";
|
||||
case 6767438:
|
||||
return AndroidUtils.getString("vk_music_online") + " (Android)"; // VK Музыка (Android)
|
||||
return "VK Музыка (Android)";
|
||||
case 8113297:
|
||||
return AndroidUtils.getString("vk_clips_online") + " (Android)"; // VK Клипы (Android)
|
||||
return "VK Клипы (Android)";
|
||||
case 8106428:
|
||||
return AndroidUtils.getString("vk_clips_online") + " (iPhone)"; // VK Клипы (iPhone)
|
||||
return "VK Клипы (iPhone)";
|
||||
case 5044491:
|
||||
return "Candy";
|
||||
case 8114066:
|
||||
return AndroidUtils.getString("vk_video_online"); // VK Видео
|
||||
return "VK Видео";
|
||||
case 4894723:
|
||||
return "Phoenix Lite";
|
||||
case 4994316:
|
||||
@@ -130,12 +125,6 @@ public class OnlineFormatterHook {
|
||||
return "Miranda NG (bridge)";
|
||||
case 8043814:
|
||||
return "Quise";
|
||||
case 7221936:
|
||||
return "Вечный Online";
|
||||
case 6892935:
|
||||
return "VK Helper";
|
||||
case 6248661:
|
||||
return "MemeVoices for VK";
|
||||
default:
|
||||
return getAppNameFromOnline(appid);
|
||||
}
|
||||
@@ -176,66 +165,14 @@ public class OnlineFormatterHook {
|
||||
return getString("custom_online") + " " + appname;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHook(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
if (getBoolValue("onlinefix", false)) setOnlineInfo(json);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONArray onlineHookList(JSONArray jsonArr) throws ParseException, IOException, JSONException {
|
||||
if (!getBoolValue("onlinefix", false)) return jsonArr;
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(jsonArr);
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookProfiles", e.getMessage());
|
||||
}
|
||||
|
||||
return jsonArr;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookProfiles(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
public static JSONObject onlineHook(JSONObject json, boolean isGlobalHook) throws ParseException, IOException, JSONException {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONArray("profiles"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookProfiles", e.getMessage());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookItems(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONArray("items"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookItems", e.getMessage());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookRequestsAndRecommendations(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONObject("read_requests").optJSONArray("items"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookItems", e.getMessage());
|
||||
if (isGlobalHook && !getBoolValue("globalUsersOnline", false)) {
|
||||
return json;
|
||||
}
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONObject("recommendations").optJSONArray("items"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookItems", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONArray("profiles"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookItems", e.getMessage());
|
||||
}
|
||||
setOnlineInfo(json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package ru.vtosters.lite.hooks;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ClipData;
|
||||
@@ -16,15 +15,10 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.vk.core.dialogs.actionspopup.ActionsPopup;
|
||||
import com.vk.core.drawable.RecoloredDrawable;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vk.dto.common.AttachmentWithMedia;
|
||||
import com.vk.dto.common.ImageSize;
|
||||
import com.vtosters.lite.R;
|
||||
import com.vtosters.lite.attachments.DocumentAttachment;
|
||||
import com.vtosters.lite.attachments.PhotoAttachment;
|
||||
|
||||
import org.json.JSONException;
|
||||
@@ -32,7 +26,6 @@ import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
@@ -43,17 +36,18 @@ import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class PhotoViewer {
|
||||
|
||||
static OkHttpClient client = new OkHttpClient();
|
||||
|
||||
public static boolean interceptClick(AttachmentWithMedia attachment, MenuItem item, View view) {
|
||||
if (item.getItemId() == AndroidUtils.getIdentifier("search_photo", "id")) {
|
||||
searchPhoto(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
|
||||
searchPhoto(getUrlFromAttachment((PhotoAttachment) attachment));
|
||||
return true;
|
||||
} else if (item.getItemId() == AndroidUtils.getIdentifier("copy_photo_url", "id")) {
|
||||
copyPhotoUrl(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
|
||||
copyPhotoUrl(getUrlFromAttachment((PhotoAttachment) attachment));
|
||||
return true;
|
||||
} else if (item.getItemId() == AndroidUtils.getIdentifier("open_original_photo", "id")) {
|
||||
openUrl(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
|
||||
openUrl(getUrlFromAttachment((PhotoAttachment) attachment));
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
@@ -67,19 +61,7 @@ public class PhotoViewer {
|
||||
: new RecoloredDrawable(AndroidUtils.getGlobalContext().getDrawable(R.drawable.ic_menu_search_outline_28), ThemesUtils.getAccentColor()),
|
||||
false,
|
||||
() -> {
|
||||
if (attachment instanceof PhotoAttachment) {
|
||||
searchPhoto(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
|
||||
} else if (attachment instanceof DocumentAttachment) {
|
||||
var documentAttachment = (DocumentAttachment) attachment;
|
||||
if (documentAttachment.J != null)
|
||||
try {
|
||||
searchPhoto(getUrlFromDocumentAttachment(documentAttachment));
|
||||
} catch (Exception e) {
|
||||
ToastUtils.a(getString("photo_get_error"));
|
||||
}
|
||||
else
|
||||
ToastUtils.a(getString("photo_get_error"));
|
||||
}
|
||||
searchPhoto(getUrlFromAttachment((PhotoAttachment) attachment));
|
||||
return null;
|
||||
}
|
||||
);
|
||||
@@ -89,19 +71,7 @@ public class PhotoViewer {
|
||||
: new RecoloredDrawable(AndroidUtils.getGlobalContext().getDrawable(R.drawable.ic_copy_outline_28), Color.WHITE),
|
||||
false,
|
||||
() -> {
|
||||
if (attachment instanceof PhotoAttachment) {
|
||||
copyPhotoUrl(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
|
||||
} else if (attachment instanceof DocumentAttachment) {
|
||||
var documentAttachment = (DocumentAttachment) attachment;
|
||||
if (documentAttachment.J != null)
|
||||
try {
|
||||
copyPhotoUrl(getUrlFromDocumentAttachment(documentAttachment));
|
||||
} catch (Exception e) {
|
||||
ToastUtils.a(getString("photo_get_error"));
|
||||
}
|
||||
else
|
||||
ToastUtils.a(getString("photo_get_error"));
|
||||
}
|
||||
copyPhotoUrl(getUrlFromAttachment((PhotoAttachment) attachment));
|
||||
return null;
|
||||
}
|
||||
);
|
||||
@@ -112,39 +82,14 @@ public class PhotoViewer {
|
||||
ThemesUtils.getAccentColor()),
|
||||
false,
|
||||
() -> {
|
||||
if (attachment instanceof PhotoAttachment) {
|
||||
openUrl(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
|
||||
} else if (attachment instanceof DocumentAttachment) {
|
||||
var documentAttachment = (DocumentAttachment) attachment;
|
||||
if (documentAttachment.J != null)
|
||||
try {
|
||||
openUrl(getUrlFromDocumentAttachment(documentAttachment));
|
||||
} catch (Exception e) {
|
||||
ToastUtils.a(getString("photo_get_error"));
|
||||
}
|
||||
else
|
||||
ToastUtils.a(getString("photo_get_error"));
|
||||
}
|
||||
openUrl(getUrlFromAttachment((PhotoAttachment) attachment));
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static String getUrlFromDocumentAttachment(DocumentAttachment attachment) {
|
||||
List<ImageSize> imageSizes = null;
|
||||
if (attachment.J != null) {
|
||||
imageSizes = attachment.J.t1();
|
||||
}
|
||||
return getUrlFromImageSizeList(imageSizes != null ? imageSizes : null);
|
||||
}
|
||||
|
||||
private static String getUrlFromPhotoAttachment(PhotoAttachment attachment) {
|
||||
private static String getUrlFromAttachment(PhotoAttachment attachment) {
|
||||
var imageSizes = attachment.D.Q.t1();
|
||||
return getUrlFromImageSizeList(imageSizes);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getUrlFromImageSizeList(List<ImageSize> imageSizes) {
|
||||
if (imageSizes.isEmpty())
|
||||
return null;
|
||||
var max = imageSizes.get(0);
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
import static ru.vtosters.lite.utils.Preferences.preferences;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class PicRoundingHook{
|
||||
private static final int pref = preferences.getInt("pic_rounding", 0);
|
||||
|
||||
public static RoundingParams inject() {
|
||||
if (pref > 0) {
|
||||
return customParams();
|
||||
} else {
|
||||
return new RoundingParams().a(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static RoundingParams inject(float orig) {
|
||||
if (pref > 0) {
|
||||
return customParams();
|
||||
} else {
|
||||
return new RoundingParams().b(orig);
|
||||
}
|
||||
}
|
||||
|
||||
public static RoundingParams inject(float orig, float orig2, float orig3, float orig4) {
|
||||
if (pref > 0) {
|
||||
return new RoundingParams().a(AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref));
|
||||
} else {
|
||||
return new RoundingParams().a(orig, orig2, orig3, orig4);
|
||||
}
|
||||
}
|
||||
|
||||
public static void inject(float orig, Canvas canvas, Paint paint){
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), paint);
|
||||
} else {
|
||||
canvas.drawCircle(orig, orig, orig, paint);
|
||||
}
|
||||
}
|
||||
|
||||
public static void inject(Canvas canvas, Paint paint, float orig){
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), paint);
|
||||
} else {
|
||||
canvas.drawCircle(canvas.getClipBounds().exactCenterX(), canvas.getClipBounds().exactCenterY(), orig, paint);
|
||||
}
|
||||
}
|
||||
|
||||
public static void inject(Canvas canvas, float orig, float orig2, float orig3, Paint paint){
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), paint);
|
||||
} else {
|
||||
canvas.drawCircle(orig, orig2, orig3, paint);
|
||||
}
|
||||
}
|
||||
|
||||
public static void inject(Bitmap bitmap, Bitmap bitmap2, Paint b2) {
|
||||
Shader.TileMode tileMode = Shader.TileMode.CLAMP;
|
||||
b2.setShader(new BitmapShader(bitmap2, tileMode, tileMode));
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
float width = bitmap2.getWidth() / 2;
|
||||
|
||||
if (pref > 0) {
|
||||
canvas.drawRoundRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), b2);
|
||||
} else {
|
||||
canvas.drawCircle(width, width, width, b2);
|
||||
}
|
||||
}
|
||||
|
||||
private static RoundingParams customParams(){
|
||||
return RoundingParams.b(AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref), AndroidUtils.dp2px(pref));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.isRandomProxyEnabled;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.isVikaProxyEnabled;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.isZaboronaEnabled;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
import static ru.vtosters.lite.utils.LifecycleUtils.restartApplication;
|
||||
import static ru.vtosters.lite.utils.ProxyUtils.apiproxy;
|
||||
import static ru.vtosters.lite.utils.ProxyUtils.isZaboronaEnabled;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAlertStyle;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
|
||||
@@ -14,6 +14,7 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.RadioButton;
|
||||
@@ -26,12 +27,11 @@ import com.vk.auth.ui.VkAuthTextView;
|
||||
import com.vk.navigation.Navigator;
|
||||
|
||||
import ru.vtosters.lite.ui.fragments.ProxySettingsFragment;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class ProxyHook {
|
||||
public static void hookAuth(View v) {
|
||||
VkAuthTextView button = (VkAuthTextView) v;
|
||||
button.setText(AndroidUtils.getString("proxy_setup"));
|
||||
button.setText("Настроить прокси");
|
||||
button.setOnClickListener(v1 -> callProxyDialog(v1.getContext()));
|
||||
}
|
||||
|
||||
@@ -40,60 +40,44 @@ public class ProxyHook {
|
||||
RadioGroup rg = new RadioGroup(ctx);
|
||||
|
||||
RadioButton rgDefault = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgZaborona = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgRandomProxy = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgVika = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgProxy = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
|
||||
rg.addView(rgDefault);
|
||||
rg.addView(rgVika);
|
||||
rg.addView(rgZaborona);
|
||||
rg.addView(rgRandomProxy);
|
||||
rg.addView(rgProxy);
|
||||
|
||||
rgDefault.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgZaborona.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgRandomProxy.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgVika.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgProxy.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
|
||||
rg.setPadding(dp2px(18f), dp2px(12f), dp2px(18f), 0);
|
||||
|
||||
rgDefault.setText(AndroidUtils.getString("proxy_disable"));
|
||||
rgDefault.setText("Отключить");
|
||||
rgDefault.setTextColor(getTextAttr());
|
||||
|
||||
rgZaborona.setText(AndroidUtils.getString("proxy_enable") + " (Zaborona)");
|
||||
rgZaborona.setTextColor(getTextAttr());
|
||||
rgProxy.setText("Включить (Zaborona)");
|
||||
rgProxy.setTextColor(getTextAttr());
|
||||
|
||||
rgRandomProxy.setText(AndroidUtils.getString("proxy_enable") + " (Random Socks Proxy)");
|
||||
rgRandomProxy.setTextColor(getTextAttr());
|
||||
|
||||
rgVika.setText(AndroidUtils.getString("proxy_enable") + " (Vika Mobile)");
|
||||
rgVika.setTextColor(getTextAttr());
|
||||
|
||||
rgZaborona.setChecked(isZaboronaEnabled());
|
||||
rgDefault.setChecked(!isZaboronaEnabled() && !isRandomProxyEnabled() && !isVikaProxyEnabled());
|
||||
rgRandomProxy.setChecked(isRandomProxyEnabled());
|
||||
rgVika.setChecked(isVikaProxyEnabled());
|
||||
rgProxy.setChecked(isZaboronaEnabled());
|
||||
rgDefault.setChecked(!isZaboronaEnabled());
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx, getAlertStyle());
|
||||
builder.setTitle(AndroidUtils.getString("vtlproxy"));
|
||||
builder.setMessage(AndroidUtils.getString("proxy_warning"));
|
||||
builder.setTitle("Прокси");
|
||||
builder.setMessage("Zaborona никак не связана с ВТостерс и мы не можем гарантировать её работу и безопасность");
|
||||
builder.setView(rg);
|
||||
builder.setPositiveButton(AndroidUtils.getString("vtl_confirm"), ((dialog, which) -> { // Применить
|
||||
if (rgZaborona.isChecked()) {
|
||||
builder.setPositiveButton("Применить", ((dialog, which) -> {
|
||||
if (rgProxy.isChecked()) {
|
||||
edit().putString("proxy", "zaborona").commit();
|
||||
restartApplication();
|
||||
} else if (rgRandomProxy.isChecked()) {
|
||||
edit().putString("proxy", "randomproxy").commit();
|
||||
restartApplication();
|
||||
} else if (rgVika.isChecked()) {
|
||||
edit().putString("proxy", "vika").commit();
|
||||
restartApplication();
|
||||
} else {
|
||||
if (isZaboronaEnabled()) {
|
||||
edit().putString("proxy", "noproxy").commit();
|
||||
restartApplication();
|
||||
}
|
||||
|
||||
edit().putString("proxy", "noproxy").commit();
|
||||
restartApplication();
|
||||
}
|
||||
}));
|
||||
|
||||
builder.setNeutralButton(AndroidUtils.getString("proxy_settings"), ((dialog, which) -> {
|
||||
builder.setNeutralButton("Настройки прокси", ((dialog, which) -> {
|
||||
Intent a2 = new Navigator(ProxySettingsFragment.class).b(ctx);
|
||||
a2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ctx.startActivity(a2);
|
||||
@@ -106,4 +90,47 @@ public class ProxyHook {
|
||||
alert.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(getAccentColor());
|
||||
alert.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor(getAccentColor());
|
||||
}
|
||||
|
||||
public static String linkReplacer(String link) {
|
||||
var vkapi = "api.vk.com";
|
||||
var oauth = "oauth.vk.com";
|
||||
var vkstatic = "static.vk.com";
|
||||
|
||||
var proxyapi = getPrefsValue("proxyapi");
|
||||
var proxyoauth = getPrefsValue("proxyoauth");
|
||||
var proxystatic = getPrefsValue("proxystatic");
|
||||
|
||||
if (!apiproxy() || link.isEmpty()) {
|
||||
return link;
|
||||
}
|
||||
|
||||
if (proxyapi.isEmpty() || proxyoauth.isEmpty() || proxystatic.isEmpty()) {
|
||||
Log.d("VTLite", "Proxy is not set" + " " + proxyapi + " " + proxyoauth + " " + proxystatic);
|
||||
return link;
|
||||
}
|
||||
|
||||
if (link.contains(vkapi)) {
|
||||
return link.replace(proxyapi, vkapi);
|
||||
}
|
||||
|
||||
if (link.contains(oauth)) {
|
||||
return link.replace(proxyoauth, oauth);
|
||||
}
|
||||
|
||||
if (link.contains(vkstatic)) {
|
||||
return link.replace(proxystatic, vkstatic);
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
public static String getAwayPhpCom() {
|
||||
var proxyapi = getPrefsValue("proxyapi");
|
||||
|
||||
if (apiproxy() & !proxyapi.isEmpty()) {
|
||||
return proxyapi;
|
||||
}
|
||||
|
||||
return "m.vk.com";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
|
||||
import static ru.vtosters.lite.encryption.EncryptProvider.decryptMessage;
|
||||
|
||||
import com.vk.im.engine.models.ProfilesSimpleInfo;
|
||||
import com.vk.im.engine.models.messages.MsgFromUser;
|
||||
import com.vk.im.engine.models.messages.NestedMsg;
|
||||
import com.vk.im.ui.views.ReplyView;
|
||||
|
||||
public class ReplyMsgHook {
|
||||
public static void injectWithDecrypt(ReplyView replyView, MsgFromUser msgFromUser, ProfilesSimpleInfo profilesSimpleInfo, boolean someBool) {
|
||||
msgFromUser.d(decryptMessage(msgFromUser)); // set new value of text in MsgFromUser class
|
||||
replyView.a(msgFromUser, profilesSimpleInfo, someBool);
|
||||
}
|
||||
|
||||
public static void injectWithDecrypt(ReplyView replyView, NestedMsg nestedMsg, ProfilesSimpleInfo profilesSimpleInfo, boolean someBool) {
|
||||
nestedMsg.d(decryptMessage(nestedMsg.f(), nestedMsg.t1())); // set new value of text in NestedMsg class
|
||||
replyView.a(nestedMsg, profilesSimpleInfo, someBool);
|
||||
}
|
||||
|
||||
public static void injectWithDecrypt(ReplyView replyView, NestedMsg nestedMsg, ProfilesSimpleInfo profilesSimpleInfo, boolean someBool, int i) {
|
||||
if ((i & 4) != 0) someBool = false;
|
||||
injectWithDecrypt(replyView, nestedMsg, profilesSimpleInfo, someBool);
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ import com.vk.api.internal.MethodCall;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class RequestDumper{
|
||||
public static void addParams(MethodCall.a paramslist, String method, LinkedHashMap<String, String> params, String apiver) {
|
||||
if (method.contains("execute.getGiftByStickerId") ) {
|
||||
apiver = "5.186";
|
||||
public static void addParams(MethodCall.a paramslist, String method, LinkedHashMap params, String apiver) {
|
||||
if (method.contains("execute.getGiftByStickerId")) {
|
||||
apiver = "5.187";
|
||||
}
|
||||
|
||||
if (dev()) {
|
||||
|
||||
@@ -5,12 +5,11 @@ import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.milkshake;
|
||||
import static ru.vtosters.lite.utils.Preferences.superapp;
|
||||
import static ru.vtosters.lite.utils.Preferences.useNewSettings;
|
||||
import static ru.vtosters.lite.utils.Preferences.videonewcatalog;
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme;
|
||||
|
||||
import com.vk.apps.AppsFragment;
|
||||
import com.vk.discover.DiscoverFragment;
|
||||
import com.vk.discover.ThemedFeedFragment;
|
||||
import com.vk.fave.fragments.FaveTabFragment;
|
||||
import com.vk.menu.MenuFragment;
|
||||
import com.vk.menu.SearchMenuFragment;
|
||||
@@ -34,6 +33,8 @@ import com.vtosters.lite.fragments.y2.VideosFragment;
|
||||
import com.vtosters.lite.general.fragments.GamesFragment;
|
||||
import com.vtosters.lite.general.fragments.PhotosFragment;
|
||||
|
||||
import ru.vtosters.lite.ui.fragments.VTSettings;
|
||||
|
||||
public class StartFragmentHook {
|
||||
public static Class getStartFragment() {
|
||||
if (vkme()) {
|
||||
@@ -55,11 +56,11 @@ public class StartFragmentHook {
|
||||
case "videos":
|
||||
return videonewcatalog() ? VideoCatalogFragment.class : VideosFragment.class;
|
||||
case "settings":
|
||||
return useNewSettings();
|
||||
return VTSettings.class;
|
||||
case "apps":
|
||||
return AppsFragment.class;
|
||||
case "discover":
|
||||
return DiscoverFragment.class;
|
||||
return ThemedFeedFragment.class;
|
||||
case "notifications":
|
||||
return NotificationsContainerFragment.class;
|
||||
case "money":
|
||||
|
||||
@@ -41,7 +41,7 @@ public class FFMpeg {
|
||||
private static void checkFFMpegLibs() {
|
||||
var lib = new File(AndroidUtils.getGlobalContext().getFilesDir(), "libffmpegkit_abidetect.so");
|
||||
if (!lib.exists()) {
|
||||
ToastUtils.a(AndroidUtils.getString("ffmpegkit_copy"));
|
||||
ToastUtils.a("Копирование библиотеки ffmpegkit");
|
||||
copyAssets();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
package ru.vtosters.lite.music;
|
||||
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
|
||||
import org.json.JSONException;
|
||||
@@ -28,13 +23,13 @@ import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class MP3Downloader {
|
||||
|
||||
private static final String URL_FORMAT = "https://" + getApi() + "/method/audio.getById?v=5.131&access_token=%s&audios=%s©right=https://vtosters.app/";
|
||||
private static final String URL_FORMAT = "https://api.vk.com/method/audio.getById?v=5.131&access_token=%s&audios=%s©right=https://vtosters.app/";
|
||||
private static final OkHttpClient client = new OkHttpClient();
|
||||
|
||||
public static void execute(MusicTrack track) {
|
||||
var token = AndroidUtils.getPreferences().getString("vk_admin_token", "");
|
||||
if (token.isEmpty()) {
|
||||
Toast.makeText(AndroidUtils.getGlobalContext(), AndroidUtils.getString("update_vk_admin_token"), Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(AndroidUtils.getGlobalContext(), "Обновите токен VK Admin в настройках", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
var request = new Request.a()
|
||||
@@ -58,10 +53,12 @@ public class MP3Downloader {
|
||||
if (responseNode.has("url")) {
|
||||
var url = responseNode.optString("url");
|
||||
Log.d("MP3Downloader", url);
|
||||
if (url.endsWith(".mp3")) {
|
||||
downloadMP3(track.toString(), url);
|
||||
} else if (VKM3UParser.isM3U8(url)) {
|
||||
AudioDownloader.downloadM3U8(track);
|
||||
if (url != null) {
|
||||
if (url.endsWith(".mp3")) {
|
||||
downloadMP3(track.toString(), url);
|
||||
} else if (VKM3UParser.isM3U8(url)) {
|
||||
AudioDownloader.downloadM3U8(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,14 +69,13 @@ public class MP3Downloader {
|
||||
});
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private static void downloadMP3(String title, String url) {
|
||||
var downloadManager = AndroidUtils.getGlobalContext().getSystemService(DownloadManager.class);
|
||||
var request = new DownloadManager.Request(Uri.parse(url))
|
||||
.setAllowedOverRoaming(true)
|
||||
.setTitle("Downloading " + title)
|
||||
.setDestinationInExternalFilesDir(AndroidUtils.getGlobalContext(),
|
||||
Environment.DIRECTORY_MUSIC,
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(),
|
||||
title + ".mp3")
|
||||
.setVisibleInDownloadsUi(true);
|
||||
downloadManager.enqueue(request);
|
||||
|
||||
@@ -24,7 +24,6 @@ import ru.vtosters.lite.net.NetCallback;
|
||||
import ru.vtosters.lite.net.NetClient;
|
||||
import ru.vtosters.lite.net.NetRequest;
|
||||
import ru.vtosters.lite.net.NetResponse;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class Scrobbler {
|
||||
private static final String key = "5965d63402414776c54c266db0211746";
|
||||
@@ -104,7 +103,7 @@ public class Scrobbler {
|
||||
|
||||
public static void auth(String login, String pass) {
|
||||
if (login == null || pass == null) {
|
||||
sendToast(AndroidUtils.getString("lastfm_credentials_empty"));
|
||||
sendToast("Логин или пароль не заданы");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -120,7 +119,7 @@ public class Scrobbler {
|
||||
@Override
|
||||
public void onFailure(NetCall call, IOException e) {
|
||||
Log.d("Scrobbler", "Auth failed", e);
|
||||
sendToast(AndroidUtils.getString("lastfm_auth_error"));
|
||||
sendToast("Ошибка входа");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,7 +155,7 @@ public class Scrobbler {
|
||||
edit().remove("username").apply();
|
||||
edit().remove("sessionKey").apply();
|
||||
scrobbled.clear();
|
||||
sendToast(AndroidUtils.getString("lastfm_logout_success"));
|
||||
sendToast("Вы успешно вышли из учетной записи");
|
||||
}
|
||||
|
||||
public static boolean needToBeScrobble(String uid) {
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package ru.vtosters.lite.proxy;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
|
||||
public class GithubList{
|
||||
private static final OkHttpClient mClient = new OkHttpClient();
|
||||
|
||||
public static ArrayList<String> getProxy(String url, String proxyname) throws IOException{
|
||||
Request link = new Request.a()
|
||||
.b(url)
|
||||
.a();
|
||||
|
||||
var response = mClient.a(link).execute().a().g();
|
||||
|
||||
if (!response.contains(":")) {
|
||||
Log.d(proxyname, "No proxy found");
|
||||
return null;
|
||||
}
|
||||
|
||||
Log.d(proxyname, response);
|
||||
|
||||
return new ArrayList<>(Arrays.asList(response.split("\n")));
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
package ru.vtosters.lite.proxy;
|
||||
|
||||
import static java.lang.System.clearProperty;
|
||||
import static ru.vtosters.lite.proxy.api.VikaMobile.getApiHost;
|
||||
import static ru.vtosters.lite.proxy.api.VikaMobile.getOauthHost;
|
||||
import static ru.vtosters.lite.proxy.api.VikaMobile.getStaticHost;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import ru.vtosters.lite.proxy.http.CustomHttp;
|
||||
import ru.vtosters.lite.proxy.https.CustomHttps;
|
||||
import ru.vtosters.lite.proxy.socks.CustomSocks;
|
||||
import ru.vtosters.lite.proxy.socks.Zaborona;
|
||||
|
||||
public class ProxyUtils{
|
||||
public static String getApi(){
|
||||
var proxyapi = getPrefsValue("proxyapi");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
proxyapi = getApiHost();
|
||||
}
|
||||
|
||||
if (isAnyProxyEnabled() & !proxyapi.isEmpty()) {
|
||||
return proxyapi;
|
||||
}
|
||||
|
||||
return "api.vk.com";
|
||||
}
|
||||
|
||||
public static String getOauth(){
|
||||
var oauth = getPrefsValue("proxyoauth");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
oauth = getOauthHost();
|
||||
}
|
||||
|
||||
if (isAnyProxyEnabled() & !oauth.isEmpty()) {
|
||||
return oauth;
|
||||
}
|
||||
|
||||
return "oauth.vk.com";
|
||||
}
|
||||
|
||||
public static String getStatic(){
|
||||
var staticapi = getPrefsValue("proxystatic");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
staticapi = getStaticHost();
|
||||
}
|
||||
|
||||
if (isAnyProxyEnabled() & !staticapi.isEmpty()) {
|
||||
return staticapi;
|
||||
}
|
||||
|
||||
return "static.vk.com";
|
||||
}
|
||||
|
||||
public static Boolean isAnyProxyEnabled(){
|
||||
return isApiProxyEnabled() || isVikaProxyEnabled();
|
||||
}
|
||||
|
||||
public static Boolean isZaboronaEnabled(){
|
||||
return getPrefsValue("proxy").equals("zaborona");
|
||||
}
|
||||
|
||||
public static Boolean isRandomProxyEnabled(){
|
||||
return getPrefsValue("proxy").equals("randomproxy");
|
||||
}
|
||||
|
||||
public static Boolean isApiProxyEnabled(){
|
||||
return getPrefsValue("proxy").equals("apiproxy");
|
||||
}
|
||||
|
||||
public static Boolean isVikaProxyEnabled(){
|
||||
return getPrefsValue("proxy").equals("vika");
|
||||
}
|
||||
|
||||
public static void forceProxyApplying(){
|
||||
Log.d("Proxy", "Setting proxy...");
|
||||
try {
|
||||
var context = getGlobalContext().getApplicationContext();
|
||||
Class<?> applicationClass = Class.forName("android.app.Application");
|
||||
@SuppressLint("DiscouragedPrivateApi") @SuppressWarnings("JavaReflectionMemberAccess")
|
||||
Field mLoadedApkField = applicationClass.getDeclaredField("mLoadedApk");
|
||||
mLoadedApkField.setAccessible(true);
|
||||
Object mLoadedApkObject = mLoadedApkField.get(context);
|
||||
|
||||
@SuppressLint("PrivateApi")
|
||||
Class<?> loadedApkClass = Class.forName("android.app.LoadedApk");
|
||||
@SuppressLint("DiscouragedPrivateApi") Field mReceiversField = loadedApkClass.getDeclaredField("mReceivers");
|
||||
mReceiversField.setAccessible(true);
|
||||
ArrayMap<?, ?> receivers = (ArrayMap<?, ?>) mReceiversField.get(mLoadedApkObject);
|
||||
if (receivers != null) {
|
||||
for (Object receiverMap : receivers.values()) {
|
||||
for (Object receiver : ((ArrayMap<?, ?>) receiverMap).keySet()) {
|
||||
Class<?> receiverClass = receiver.getClass();
|
||||
|
||||
if (receiverClass.getName().contains("ProxyChangeListener")) {
|
||||
Method onReceiveMethod = receiverClass.getDeclaredMethod("onReceive", Context.class, Intent.class);
|
||||
Intent intent = new Intent(android.net.Proxy.PROXY_CHANGE_ACTION);
|
||||
onReceiveMethod.invoke(receiver, context, intent);
|
||||
} else {
|
||||
for (Field field : receiverClass.getDeclaredFields()) {
|
||||
if (field.getType().getName().contains("ProxyChangeListener")) {
|
||||
Method onReceiveMethod = receiverClass.getDeclaredMethod("onReceive", Context.class, Intent.class);
|
||||
Intent intent = new Intent(android.net.Proxy.PROXY_CHANGE_ACTION);
|
||||
onReceiveMethod.invoke(receiver, context, intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.d("Proxy", "Setting proxy successful!");
|
||||
} catch (Exception e) {
|
||||
Log.d("Proxy", "Setting proxy failed!");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasProxy(String list){
|
||||
return list.contains(":"); // proxy format: ip:port
|
||||
}
|
||||
|
||||
public static void setProxy() throws IOException{
|
||||
switch(getPrefsValue("proxy")) {
|
||||
case "zaborona":
|
||||
Zaborona.loadProxy();
|
||||
break;
|
||||
case "randomproxy":
|
||||
RandomProxy.loadProxy();
|
||||
break;
|
||||
case "socks":
|
||||
CustomSocks.loadProxy();
|
||||
break;
|
||||
case "http":
|
||||
CustomHttp.loadProxy();
|
||||
break;
|
||||
case "https":
|
||||
CustomHttps.loadProxy();
|
||||
break;
|
||||
default:
|
||||
resetProxy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetProxy(){
|
||||
clearProperty("https.proxyHost");
|
||||
clearProperty("https.proxyPort");
|
||||
clearProperty("https.proxyUser");
|
||||
clearProperty("https.proxyPassword");
|
||||
clearProperty("http.proxyHost");
|
||||
clearProperty("http.proxyPort");
|
||||
clearProperty("http.proxyUser");
|
||||
clearProperty("http.proxyPassword");
|
||||
clearProperty("socksProxyHost");
|
||||
clearProperty("socksPortHost");
|
||||
} // Reset all proxies
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package ru.vtosters.lite.proxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.resetProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.Preferences.preferences;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ru.vtosters.lite.proxy.socks.Hookzof;
|
||||
import ru.vtosters.lite.proxy.socks.Jetkai;
|
||||
import ru.vtosters.lite.proxy.socks.Roosterkid;
|
||||
import ru.vtosters.lite.proxy.socks.TheSpeedX;
|
||||
|
||||
public class RandomProxy{
|
||||
public static String type = preferences.getString("random_type", "none");
|
||||
public static String host = preferences.getString("random_host", "");
|
||||
public static boolean showProxyResult = false;
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
if (host.isEmpty()) {
|
||||
getProxy();
|
||||
loadProxy();
|
||||
return;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case "socks":
|
||||
System.setProperty("socksProxyHost", host.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", host.split(":")[1]);
|
||||
break;
|
||||
case "http":
|
||||
System.setProperty("http.proxyHost", host.split(":")[0]);
|
||||
System.setProperty("http.proxyPort", host.split(":")[1]);
|
||||
break;
|
||||
case "https":
|
||||
System.setProperty("https.proxyHost", host.split(":")[0]);
|
||||
System.setProperty("https.proxyPort", host.split(":")[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setupNewProxy() throws IOException{
|
||||
edit().putString("random_type", "none").putString("random_host", "").commit();
|
||||
|
||||
resetProxy();
|
||||
forceProxyApplying();
|
||||
|
||||
showProxyResult = true;
|
||||
getProxy();
|
||||
edit().putString("proxy", "randomproxy").commit();
|
||||
}
|
||||
|
||||
public static void getProxy() throws IOException{
|
||||
var random = new java.util.Random();
|
||||
var randomInt = random.nextInt(7);
|
||||
switch(randomInt) {
|
||||
case 0:
|
||||
Hookzof.loadProxy();
|
||||
break;
|
||||
case 1:
|
||||
TheSpeedX.loadProxy();
|
||||
break;
|
||||
case 2:
|
||||
Jetkai.loadProxy();
|
||||
break;
|
||||
case 3:
|
||||
Roosterkid.loadProxy();
|
||||
break;
|
||||
case 4:
|
||||
ru.vtosters.lite.proxy.http.Jetkai.loadProxy();
|
||||
break;
|
||||
case 5:
|
||||
ru.vtosters.lite.proxy.http.TheSpeedX.loadProxy();
|
||||
break;
|
||||
case 6:
|
||||
ru.vtosters.lite.proxy.https.Jetkai.loadProxy();
|
||||
break;
|
||||
case 7:
|
||||
ru.vtosters.lite.proxy.https.Roosterkid.loadProxy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.api;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.isAnyProxyEnabled;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.isVikaProxyEnabled;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class ApiProxy{
|
||||
public static String linkReplacer(String link){
|
||||
var vkapi = "api.vk.com";
|
||||
var oauth = "oauth.vk.com";
|
||||
var vkstatic = "static.vk.com";
|
||||
|
||||
var proxyapi = getPrefsValue("proxyapi");
|
||||
var proxyoauth = getPrefsValue("proxyoauth");
|
||||
var proxystatic = getPrefsValue("proxystatic");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
proxyapi = VikaMobile.getApiHost();
|
||||
proxyoauth = VikaMobile.getOauthHost();
|
||||
proxystatic = VikaMobile.getStaticHost();
|
||||
}
|
||||
|
||||
if (!isAnyProxyEnabled() || link.isEmpty()) {
|
||||
return link;
|
||||
}
|
||||
|
||||
if (proxyapi.isEmpty() || proxyoauth.isEmpty() || proxystatic.isEmpty()) {
|
||||
Log.d("VTLite", "Proxy is not set" + " " + proxyapi + " " + proxyoauth + " " + proxystatic);
|
||||
return link;
|
||||
}
|
||||
|
||||
if (link.contains(vkapi)) {
|
||||
return link.replaceAll(vkapi, proxyapi);
|
||||
}
|
||||
|
||||
if (link.contains(oauth)) {
|
||||
return link.replaceAll(oauth, proxyoauth);
|
||||
}
|
||||
|
||||
if (link.contains(vkstatic)) {
|
||||
return link.replaceAll(vkstatic, proxystatic);
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
public static String staticFix(String str) {
|
||||
var string = getPrefsValue("proxystatic");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
string = VikaMobile.getStaticHost();
|
||||
}
|
||||
|
||||
if (isAnyProxyEnabled() && !string.isEmpty()) {
|
||||
return str.replaceAll(string, "static.vk.com");
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String getAwayPhpCom(){
|
||||
var proxyapi = getPrefsValue("proxyapi");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
proxyapi = VikaMobile.getApiHost();
|
||||
}
|
||||
|
||||
if (isAnyProxyEnabled() && !proxyapi.isEmpty()) {
|
||||
return proxyapi;
|
||||
}
|
||||
|
||||
return "m.vk.com";
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.api;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
|
||||
public class VikaMobile{
|
||||
public static String getApiHost(){
|
||||
return isAlternativeHost() ? "vk-api-proxy.vikamobile.ru" : "vk-api-proxy.symbian.live";
|
||||
}
|
||||
|
||||
public static String getOauthHost(){
|
||||
return isAlternativeHost() ? "vk-oauth-proxy.vikamobile.ru" : "vk-oauth-proxy.symbian.live";
|
||||
}
|
||||
|
||||
public static String getStaticHost(){
|
||||
return isAlternativeHost() ? "vk-static-proxy.vikamobile.ru" : "vk-static-proxy.symbian.live";
|
||||
}
|
||||
|
||||
public static Boolean isAlternativeHost(){
|
||||
return getBoolValue("altervika", false);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.http;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
|
||||
public class CustomHttp{
|
||||
public static void loadProxy(){
|
||||
System.setProperty("http.proxyHost", proxyHostHTTP());
|
||||
System.setProperty("http.proxyPort", proxyPortHTTP());
|
||||
System.setProperty("http.proxyUser", proxyUserHTTP());
|
||||
System.setProperty("http.proxyPassword", proxyPassHTTP());
|
||||
forceProxyApplying();
|
||||
}
|
||||
|
||||
private static String proxyHostHTTP(){
|
||||
var string = getPrefsValue("proxyHostHTTP");
|
||||
return string.isEmpty() ? "192.168.0.1" : string;
|
||||
}
|
||||
|
||||
private static String proxyPortHTTP(){
|
||||
var string = getPrefsValue("proxyPortHTTP");
|
||||
return string.isEmpty() ? "8888" : string;
|
||||
}
|
||||
|
||||
private static String proxyUserHTTP(){
|
||||
var string = getPrefsValue("proxyUserHTTP");
|
||||
return string.isEmpty() ? "" : string;
|
||||
}
|
||||
|
||||
private static String proxyPassHTTP(){
|
||||
var string = getPrefsValue("proxyPassHTTP");
|
||||
return string.isEmpty() ? "" : string;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.http;
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class Jetkai{
|
||||
private static final String TAG = "Jetkai_Http";
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-http.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
edit().putString("random_type", "http").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("http.proxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("http.proxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.http;
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class TheSpeedX{
|
||||
private static final String TAG = "TheSpeedX_Http";
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
edit().putString("random_type", "http").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("http.proxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("http.proxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.https;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
|
||||
public class CustomHttps{
|
||||
public static void loadProxy(){
|
||||
System.setProperty("https.proxyHost", proxyHostHTTPS());
|
||||
System.setProperty("https.proxyPort", proxyPortHTTPS());
|
||||
System.setProperty("https.proxyUser", proxyUserHTTPS());
|
||||
System.setProperty("https.proxyPassword", proxyPassHTTPS());
|
||||
forceProxyApplying();
|
||||
}
|
||||
|
||||
private static String proxyHostHTTPS(){
|
||||
var string = getPrefsValue("proxyHostHTTPS");
|
||||
return string.isEmpty() ? "192.168.0.1" : string;
|
||||
}
|
||||
|
||||
private static String proxyPortHTTPS(){
|
||||
var string = getPrefsValue("proxyPortHTTPS");
|
||||
return string.isEmpty() ? "8888" : string;
|
||||
}
|
||||
|
||||
private static String proxyUserHTTPS(){
|
||||
var string = getPrefsValue("proxyUserHTTPS");
|
||||
return string.isEmpty() ? "" : string;
|
||||
}
|
||||
|
||||
private static String proxyPassHTTPS(){
|
||||
String string = getPrefsValue("proxyPassHTTPS");
|
||||
return string.isEmpty() ? "" : string;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.https;
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class Jetkai{
|
||||
private static final String TAG = "Jetkai_Https";
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-https.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
edit().putString("random_type", "https").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("https.proxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("https.proxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.https;
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class Roosterkid{
|
||||
private static final String TAG = "Roosterkid_Https";
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/roosterkid/openproxylist/main/HTTPS_RAW.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
edit().putString("random_type", "https").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("https.proxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("https.proxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
|
||||
|
||||
public class CustomSocks{
|
||||
public static void loadProxy(){
|
||||
System.setProperty("socksProxyHost", proxyHostSocks());
|
||||
System.setProperty("socksProxyPort", proxyPortSocks());
|
||||
forceProxyApplying();
|
||||
}
|
||||
|
||||
private static String proxyHostSocks(){
|
||||
var string = getPrefsValue("proxyHostSocks");
|
||||
return string.isEmpty() ? "192.168.0.1" : string;
|
||||
}
|
||||
|
||||
private static String proxyPortSocks(){
|
||||
var string = getPrefsValue("proxyPortSocks");
|
||||
return string.isEmpty() ? "8888" : string;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class Hookzof{
|
||||
private static final String TAG = "Hookzof_Socks";
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/hookzof/socks5_list/master/proxy.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
edit().putString("random_type", "socks").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("socksProxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class Jetkai{
|
||||
private static final String TAG = "Jetkai_Socks";
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-socks5.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
edit().putString("random_type", "socks").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("socksProxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class Roosterkid{
|
||||
private static final String TAG = "Roosterkid_Socks";
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/roosterkid/openproxylist/main/SOCKS5_RAW.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
edit().putString("random_type", "socks").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("socksProxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class TheSpeedX{
|
||||
private static final String TAG = "TheSpeedX_Socks";
|
||||
|
||||
public static void loadProxy() throws IOException{
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/socks5.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
edit().putString("random_type", "socks").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("socksProxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
|
||||
public class Zaborona{
|
||||
public static void loadProxy(){
|
||||
System.setProperty("socksProxyHost", "socks.zaboronahelp.pp.ua");
|
||||
System.setProperty("socksProxyPort", "1488");
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,6 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class LogWriterService extends Service {
|
||||
public LogWriterService() {
|
||||
}
|
||||
@@ -46,12 +44,12 @@ public class LogWriterService extends Service {
|
||||
writeLog(intent, file);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
makeText(getGlobalContext(), AndroidUtils.getString("logfile_error"), LENGTH_SHORT).show();
|
||||
makeText(getGlobalContext(), "Не удалось сохранить лог-файл", LENGTH_SHORT).show();
|
||||
}
|
||||
var notificationId = intent.getIntExtra("notificationId", 1);
|
||||
var manager = (NotificationManager) getGlobalContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
manager.cancel(notificationId);
|
||||
makeText(getGlobalContext(), AndroidUtils.getString("logfile_saved"), LENGTH_SHORT).show();
|
||||
makeText(getGlobalContext(), "Лог-файл был сохранен", LENGTH_SHORT).show();
|
||||
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package ru.vtosters.lite.themes;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.vk.core.view.TintTextView;
|
||||
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class Recolor {
|
||||
|
||||
private static int getColor(int original) {
|
||||
var color = VTLColors.getColor(original);
|
||||
if (color != -1) return color;
|
||||
return original;
|
||||
}
|
||||
|
||||
public static void recolorToolbar(Toolbar toolbar) {
|
||||
if (ThemesUtils.isCustomThemeApplied())
|
||||
toolbar.setBackgroundColor(ThemesUtils.getHeaderBackground());
|
||||
}
|
||||
|
||||
public static void recolorIconToAccent(ImageView iv) {
|
||||
if (ThemesUtils.isCustomThemeApplied())
|
||||
iv.setImageTintList(ColorStateList.valueOf(VTLColors.getAccentColor()));
|
||||
}
|
||||
|
||||
public static void recolorTextToAccent(TextView iv) {
|
||||
iv.setTextColor(VTLColors.getAccentColor());
|
||||
}
|
||||
|
||||
public static void recolorTintTextViewToAccent(TintTextView ttv) {
|
||||
ttv.setDrawableTint(VTLColors.getAccentColor());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package ru.vtosters.lite.themes;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.core.util.ContextExtKt;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.themes.models.ThemeModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class VTLColors {
|
||||
private static final ThemesManager themesManager = ThemesManager.getInstance();
|
||||
private static final ThemeModel currentTheme = themesManager.getCurrentTheme();
|
||||
|
||||
public static int getAccentColor() {
|
||||
return getColor(R.attr.accent, R.attr.accentColor, R.attr.colorAccent, R.attr.vk_accent);
|
||||
}
|
||||
|
||||
public static int getTextPrimaryColor() {
|
||||
return getColor(R.attr.text_primary);
|
||||
}
|
||||
|
||||
public static int getTextSecondaryColor() {
|
||||
return getColor(R.attr.text_secondary);
|
||||
}
|
||||
|
||||
public static int getTabbarBackground() {
|
||||
return getColor(R.attr.tabbar_background);
|
||||
}
|
||||
|
||||
public static int getTabbarActiveColor() {
|
||||
if (ThemesUtils.isCustomThemeApplied())
|
||||
return getColor(R.attr.tabbar_active_icon);
|
||||
return Preferences.dockbar_accent()
|
||||
? getAccentColor()
|
||||
: AndroidUtils.getResources().getColor(ThemesUtils.isDarkTheme() ? R.color.white : R.color.gray_700);
|
||||
}
|
||||
|
||||
public static int getTabbarInactiveColor() {
|
||||
if (ThemesUtils.isCustomThemeApplied())
|
||||
return getColor(R.attr.tabbar_inactive_icon);
|
||||
return AndroidUtils.getResources().getColor(ThemesUtils.isDarkTheme() ? R.color.gray_500 : R.color.vk_steel_gray_300);
|
||||
}
|
||||
|
||||
public static int getBackgroundContent() {
|
||||
return getColor(R.attr.background_content);
|
||||
}
|
||||
|
||||
public static int getBackgroundPage() {
|
||||
return getColor(R.attr.background_page);
|
||||
}
|
||||
|
||||
public static int getHeaderBackground() {
|
||||
return getColor(R.attr.header_background);
|
||||
}
|
||||
|
||||
public static int getHeaderText() {
|
||||
return getColor(R.attr.header_text);
|
||||
}
|
||||
|
||||
//region Hooks
|
||||
|
||||
public static int getColor(int... attrs) {
|
||||
return getColor(attrs[0]);
|
||||
}
|
||||
|
||||
public static int getColor(int attr) {
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
int color = currentTheme.getColor(attr);
|
||||
if (color != -1)
|
||||
return color;
|
||||
}
|
||||
return VKThemeHelper.d(attr);
|
||||
}
|
||||
|
||||
public static int getColor(Context context, int colorId) {
|
||||
try {
|
||||
Log.d("VTLColors", "getColor(Landroid/content/Context;I): " + AndroidUtils.getResources().getResourceEntryName(colorId));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
int color = currentTheme.getColor(colorId);
|
||||
if (color != -1)
|
||||
return color;
|
||||
}
|
||||
return ContextExtKt.h(context, colorId);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package ru.vtosters.lite.themes;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.utils.ReflectionUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class VTLResources {
|
||||
private static final int STYLE_NUM_ENTRIES = Build.VERSION.SDK_INT >= 29 ? 7 : 6;
|
||||
public static final SparseIntArray forcedAttrs = new SparseIntArray();
|
||||
public static final SparseIntArray otherAttrs = new SparseIntArray();
|
||||
|
||||
private static Field dataField;
|
||||
|
||||
static {
|
||||
try {
|
||||
dataField = ReflectionUtils.getDeclaredField(TypedArray.class, "mData");
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
otherAttrs.put(R.attr.vklib_alv_optionIconTint, R.attr.im_dropdown_icon_color);
|
||||
otherAttrs.put(R.attr.vkim_colorPrimary, R.attr.accent);
|
||||
otherAttrs.put(R.attr.statusBarColorBack, R.attr.statusBarColorBack);
|
||||
otherAttrs.put(R.attr.statusBarColorFront, R.attr.statusBarColorFront);
|
||||
// android attributes
|
||||
otherAttrs.put(android.R.attr.backgroundTint, R.attr.accent);
|
||||
otherAttrs.put(android.R.attr.tint, R.attr.accent);
|
||||
otherAttrs.put(android.R.attr.color, R.attr.accent);
|
||||
|
||||
forcedAttrs.put(-0x8e5515, R.attr.accent);
|
||||
forcedAttrs.put(-0xe6e6e6, R.attr.background_content);
|
||||
}
|
||||
|
||||
public static void prepareTypedArray(TypedArray target, int[] attrs) {
|
||||
if (!ThemesUtils.isCustomThemeApplied() || attrs == null) return;
|
||||
var theme = ThemesManager.getInstance().getCurrentTheme();
|
||||
var data = getData(target);
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
//var attr = attrs[i];
|
||||
var off = STYLE_NUM_ENTRIES * i;
|
||||
var type = data[off];
|
||||
var replacement = -1;
|
||||
if (type == TypedValue.TYPE_ATTRIBUTE) {
|
||||
replacement = theme.getColor(data[off + 0x1]);
|
||||
} else if (type == TypedValue.TYPE_INT_COLOR_ARGB8 || type == TypedValue.TYPE_INT_COLOR_RGB8) {
|
||||
replacement = forcedAttrs.get(data[off + 0x1], -1);
|
||||
if (replacement == -1
|
||||
&& ThemesUtils.accentColors.contains(data[off + 0x1]))
|
||||
replacement = ThemesUtils.getAccentColor();
|
||||
}
|
||||
if (replacement == -1) continue;
|
||||
try {
|
||||
data[off] = TypedValue.TYPE_INT_COLOR_RGB8; // type
|
||||
data[off + 0x1] = replacement; // data
|
||||
data[off + 0x2] = 0x0; // asset cookie
|
||||
data[off + 0x3] = 0x0; // resource id
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] getData(TypedArray target) {
|
||||
try {
|
||||
return (int[]) dataField.get(target);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
//region Hooks
|
||||
|
||||
public static TypedArray obtainStyledAttributes(Context context, int[] attrs) {
|
||||
var target = context.obtainStyledAttributes(attrs);
|
||||
prepareTypedArray(target, attrs);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static TypedArray obtainStyledAttributes(Context context, int resId, int[] attrs) {
|
||||
var target = context.obtainStyledAttributes(resId, attrs);
|
||||
prepareTypedArray(target, attrs);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static TypedArray obtainStyledAttributes(Context context, AttributeSet set, int[] attrs) {
|
||||
var target = context.obtainStyledAttributes(set, attrs);
|
||||
prepareTypedArray(target, attrs);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static TypedArray obtainStyledAttributes(Context context, AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
|
||||
var target = context.obtainStyledAttributes(set, attrs, defStyleAttr, defStyleRes);
|
||||
prepareTypedArray(target, attrs);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static int getColor(Resources res, int colorId) {
|
||||
return VTLColors.getColor(colorId);//res.getColor(colorId);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static int getColor(Resources res, int colorId, Resources.Theme theme) {
|
||||
return VTLColors.getColor(colorId);
|
||||
}
|
||||
|
||||
@SuppressLint("UseCompatLoadingForColorStateLists")
|
||||
public static ColorStateList getColorStateList(Resources res, int colorId) {
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
int color = VTLColors.getColor(colorId);
|
||||
if (color != -1)
|
||||
return ColorStateList.valueOf(color);
|
||||
}
|
||||
return res.getColorStateList(colorId);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static ColorStateList getColorStateList(Resources res, int colorId, Resources.Theme theme) {
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
int color = VTLColors.getColor(colorId);
|
||||
if (color != -1)
|
||||
return ColorStateList.valueOf(color);
|
||||
}
|
||||
return res.getColorStateList(colorId, theme);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package ru.vtosters.lite.themes.managers;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.themes.models.PaletteModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
|
||||
public class PalettesManager {
|
||||
|
||||
private static PalettesManager instance;
|
||||
|
||||
private static File palettesDir = new File(Environment.getExternalStorageDirectory(), "VTL/themes/palettes");
|
||||
|
||||
private List<PaletteModel> palettes = new ArrayList<>();
|
||||
|
||||
public static PalettesManager getInstance() {
|
||||
if (instance == null)
|
||||
instance = new PalettesManager();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public PalettesManager() {
|
||||
load();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
palettes.clear();
|
||||
if (!palettesDir.exists())
|
||||
palettesDir.mkdirs();
|
||||
final var palettes = palettesDir.listFiles((dir, name) -> name.endsWith(".json"));
|
||||
var check = true;
|
||||
if (palettes == null || palettes.length == 0)
|
||||
check = copyPaletteFromAssets();
|
||||
if (check)
|
||||
parsePalettes();
|
||||
}
|
||||
|
||||
private boolean copyPaletteFromAssets() {
|
||||
try {
|
||||
final var manager = AndroidUtils.getGlobalContext().getAssets();
|
||||
final var assets = manager.list("vtl_themes/palettes/");
|
||||
if (assets == null || assets.length == 0) return false;
|
||||
var i = 0;
|
||||
for (var asset : assets) {
|
||||
try {
|
||||
IOUtils.copyFile(manager.open("vtl_themes/palettes/" + asset), new File(palettesDir, asset));
|
||||
i++;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return i > 0;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void parsePalettes() {
|
||||
var arr = palettesDir.listFiles((dir, name) -> name.endsWith(".json"));
|
||||
if (arr == null || arr.length == 0)
|
||||
throw new RuntimeException("Can't load palettes");
|
||||
for (var file : arr) {
|
||||
try {
|
||||
var json = new JSONObject(IOUtils.readAllLines(file));
|
||||
palettes.add(PaletteModel.fromJson(json));
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PaletteModel getPalette(String id) {
|
||||
for (PaletteModel palette : palettes) {
|
||||
if (id.equals(palette.id))
|
||||
return palette;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PaletteModel getPalette(int i) {
|
||||
return palettes.get(i);
|
||||
}
|
||||
|
||||
public int getPalettesCount() {
|
||||
return palettes.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
package ru.vtosters.lite.themes.managers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.os.StrictMode;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vtosters.lite.auth.VKAccountManager;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import ru.vtosters.lite.ui.dialogs.ThemesEditorBottomSheetDialog;
|
||||
import ru.vtosters.lite.themes.models.ThemeModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class ThemesManager {
|
||||
|
||||
private static File themesDir;
|
||||
private static ThemesManager instance;
|
||||
private static ThemeModel currentTheme = null;
|
||||
private List<ThemeModel> themes = new ArrayList<>();
|
||||
|
||||
public static ThemesManager getInstance() {
|
||||
if (instance == null)
|
||||
instance = new ThemesManager();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public ThemesManager() {
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
themes = new ArrayList<>();
|
||||
currentTheme = new ThemeModel().setName("Тема по умолчанию")
|
||||
.setAuthor("Разработчики ВК")
|
||||
.setDarkMode(ThemesUtils.isDarkTheme())
|
||||
.setId("default");
|
||||
themes.add(currentTheme);
|
||||
themesDir = new File(Environment.getExternalStorageDirectory(), "VTL/themes");
|
||||
if (!themesDir.exists()) {
|
||||
themesDir.mkdirs();
|
||||
return;
|
||||
}
|
||||
// Support themes from Sova V RE (.svt)
|
||||
var files = themesDir.listFiles((dir, name) -> name.endsWith(".vtlt") || name.endsWith(".svt") || name.endsWith(".json"));
|
||||
if (files == null || files.length == 0)
|
||||
return;
|
||||
var currentThemeId = AndroidUtils.getPreferences().getString("vtl_theme_id", "default");
|
||||
for (File file : files) {
|
||||
try {
|
||||
ThemeModel theme;
|
||||
var abs = file.getAbsolutePath();
|
||||
if (abs.endsWith(".svt") || abs.endsWith(".json"))
|
||||
theme = svt2vtlt(file);
|
||||
else
|
||||
theme = read(file);
|
||||
if (theme != null) {
|
||||
Log.d("ThemesManager", theme.toString());
|
||||
if (currentThemeId.equals(theme.id))
|
||||
currentTheme = theme;
|
||||
themes.add(theme);
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ("default".equals(currentTheme.id))
|
||||
setTheme(currentTheme);
|
||||
}
|
||||
|
||||
private ThemeModel svt2vtlt(File file) {
|
||||
try {
|
||||
var theme = read(file);
|
||||
save(theme);
|
||||
return theme;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
init();
|
||||
}
|
||||
|
||||
public File getThemeFile(ThemeModel theme) throws IOException {
|
||||
if (!themesDir.exists()) {
|
||||
themesDir.mkdirs();
|
||||
throw new FileNotFoundException("theme file not found");
|
||||
}
|
||||
|
||||
var themeFile = new File(themesDir, theme.id + ".svt");
|
||||
if (!themeFile.exists()) {
|
||||
themeFile = new File(themesDir, theme.id + ".vtlt");
|
||||
if (!themeFile.exists())
|
||||
themeFile.createNewFile();
|
||||
}
|
||||
|
||||
return themeFile;
|
||||
}
|
||||
|
||||
public void setTheme(ThemeModel theme) {
|
||||
AndroidUtils.getPreferences()
|
||||
.edit()
|
||||
.putString("vtl_theme_id", theme.id)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public ThemeModel getTheme(int i) {
|
||||
return themes.get(i);
|
||||
}
|
||||
|
||||
public ThemeModel getCurrentTheme() {
|
||||
return currentTheme;
|
||||
}
|
||||
|
||||
public int getThemesCount() {
|
||||
return themes.size();
|
||||
}
|
||||
|
||||
public boolean isCurrentTheme(ThemeModel theme) {
|
||||
return currentTheme.id.equals(theme.id);
|
||||
}
|
||||
|
||||
public boolean hasTheme(ThemeModel theme) {
|
||||
return hasTheme(theme.id);
|
||||
}
|
||||
|
||||
public boolean hasTheme(String id) {
|
||||
for (ThemeModel theme : themes) {
|
||||
if (id.equals(theme.id))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Theme file storing method from Sova V RE is storing json clearly or compressed with gzip.
|
||||
* If first byte byte is 0x1 or 0x2 json has been compressed with gzip,
|
||||
* but if first byte is 0x2 next int is length of json string. */
|
||||
|
||||
private ThemeModel read(InputStream fis) throws IOException, JSONException {
|
||||
InputStream is = fis;
|
||||
var first = is.read();
|
||||
if (first > 0x0 && first < 0x3) {
|
||||
var gzis = new GZIPInputStream(is);
|
||||
var dis = new DataInputStream(gzis);
|
||||
if (first == 0x2)
|
||||
dis.readInt();
|
||||
is = dis;
|
||||
}
|
||||
return ThemeModel.fromJson(IOUtils.readAllLines(is));
|
||||
}
|
||||
|
||||
private ThemeModel read(File file) throws IOException, JSONException {
|
||||
return read(new FileInputStream(file));
|
||||
}
|
||||
|
||||
public void save(ThemeModel theme) throws IOException, JSONException {
|
||||
var buffer = theme.toJson().toString().getBytes(StandardCharsets.UTF_8);
|
||||
var fos = new FileOutputStream(getThemeFile(theme));
|
||||
// writing with data length
|
||||
fos.write(0x2);
|
||||
var gzos = new GZIPOutputStream(fos);
|
||||
var dos = new DataOutputStream(gzos);
|
||||
dos.writeInt(buffer.length);
|
||||
dos.write(buffer);
|
||||
dos.close();
|
||||
}
|
||||
|
||||
public void delete(ThemeModel theme) {
|
||||
try {
|
||||
getThemeFile(theme).delete();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
themes.remove(theme);
|
||||
if (isCurrentTheme(theme)) {
|
||||
setTheme(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void create(Activity activity, String name) throws JSONException, IOException {
|
||||
var id = name.toLowerCase().replace(" ", "-");
|
||||
if (hasTheme(id)) {
|
||||
var i = 1;
|
||||
while (hasTheme(id + "-" + i)) {
|
||||
i++;
|
||||
}
|
||||
id += "-" + i;
|
||||
}
|
||||
var userProfile = VKAccountManager.d().e1();
|
||||
ThemeModel theme = new ThemeModel()
|
||||
.setName(name)
|
||||
.setAuthor(userProfile.c + " " + userProfile.e)
|
||||
.setDarkMode(true)
|
||||
// .setColors(DEFAULT_COLORS)
|
||||
.setId(id);
|
||||
themes.add(theme);
|
||||
ThemesEditorBottomSheetDialog.create(activity, theme, false);
|
||||
save(theme);
|
||||
}
|
||||
|
||||
public void copy(ContentResolver contentResolver, Uri uri) throws IOException, JSONException {
|
||||
var theme = read(contentResolver.openInputStream(uri));
|
||||
if (isCurrentTheme(theme)) {
|
||||
int i = 1;
|
||||
while (hasTheme(theme.id + "-" + i)) {
|
||||
i++;
|
||||
}
|
||||
theme.id += "-" + i;
|
||||
}
|
||||
themes.add(theme);
|
||||
save(theme);
|
||||
}
|
||||
|
||||
public void share(Context context, ThemeModel theme) throws Exception {
|
||||
var vmPolicy = StrictMode.getVmPolicy();
|
||||
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build());
|
||||
var intent = new Intent(Intent.ACTION_SEND)
|
||||
.setType("file/*")
|
||||
.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(getThemeFile(theme)));
|
||||
context.startActivity(Intent.createChooser(intent, ""));
|
||||
StrictMode.setVmPolicy(vmPolicy);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package ru.vtosters.lite.themes.models;
|
||||
|
||||
public class ColorModel {
|
||||
|
||||
public String resName;
|
||||
public int id;
|
||||
public int color;
|
||||
|
||||
public ColorModel(int id, int color) {
|
||||
this.id = id;
|
||||
this.color = color;
|
||||
}
|
||||
public ColorModel(String resName, int id, int color) {
|
||||
this.resName = resName;
|
||||
this.id = id;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public static ColorModel create(int id, int color) {
|
||||
return new ColorModel(id, color);
|
||||
}
|
||||
|
||||
public static ColorModel create(String resName, int id, int color) {
|
||||
return new ColorModel(resName, id, color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package ru.vtosters.lite.themes.models;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PaletteModel {
|
||||
public String id;
|
||||
public String name;
|
||||
public String author;
|
||||
public List<ColorModel> colors = new ArrayList<>();
|
||||
|
||||
public PaletteModel() {
|
||||
|
||||
}
|
||||
|
||||
public PaletteModel(String id, String name, String author, List<ColorModel> colors) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.author = author;
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public PaletteModel setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaletteModel setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaletteModel setAuthor(String author) {
|
||||
this.author = author;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaletteModel setColors(List<ColorModel> colors) {
|
||||
this.colors = colors;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PaletteModel setColor(String name, int color) {
|
||||
this.colors.add(new ColorModel(name, 0, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getColor(String name) {
|
||||
for (var item : colors)
|
||||
if (name.equals(item.resName))
|
||||
return item.color;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static PaletteModel fromJson(JSONObject json) throws JSONException {
|
||||
var palette = new PaletteModel()
|
||||
.setId(json.optString("palette_id"))
|
||||
.setName(json.optString("name"))
|
||||
.setAuthor(json.optString("author"));
|
||||
var paletteNode = json.getJSONArray("palette");
|
||||
for (int i = 0; i < paletteNode.length(); i++) {
|
||||
var colorNode = paletteNode.getJSONObject(i);
|
||||
var name = colorNode.getString("name");
|
||||
if (colorNode.has("colors")) {
|
||||
var colorsNode = colorNode.getJSONArray("colors");
|
||||
for (int j = 0; j < colorsNode.length(); j++) {
|
||||
var subColorNode = colorsNode.getJSONObject(j);
|
||||
var index = subColorNode.getString("index");
|
||||
var subColor = subColorNode.getString("color");
|
||||
if (!subColor.startsWith("#")) subColor = "#" + subColor;
|
||||
palette.setColor(name + " " + index, Color.parseColor(subColor));
|
||||
}
|
||||
} else {
|
||||
var color = colorNode.getString("color");
|
||||
if (!color.startsWith("#")) color = "#" + color;
|
||||
palette.setColor(name, Color.parseColor(color));
|
||||
}
|
||||
}
|
||||
return palette;
|
||||
}
|
||||
|
||||
public static PaletteModel valuesOf(String id, String name, String author, List<ColorModel> colors) {
|
||||
return new PaletteModel()
|
||||
.setId(id)
|
||||
.setName(name)
|
||||
.setAuthor(author)
|
||||
.setColors(colors);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package ru.vtosters.lite.themes.models;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.PalettesManager;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class ThemeModel {
|
||||
|
||||
public String author;
|
||||
public String name;
|
||||
public boolean isDarkMode;
|
||||
public String id;
|
||||
public List<ColorModel> colors = new ArrayList<>();
|
||||
|
||||
public ThemeModel() {
|
||||
}
|
||||
|
||||
public ThemeModel(String author, String name, boolean darkMode, String id, List<ColorModel> colors) {
|
||||
this.author = author;
|
||||
this.name = name;
|
||||
this.isDarkMode = darkMode;
|
||||
this.id = id;
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public ThemeModel setAuthor(String author) {
|
||||
this.author = author;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setDarkMode(boolean b) {
|
||||
this.isDarkMode = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setColors(List<ColorModel> colors) {
|
||||
this.colors = colors;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeModel setColor(int attrId, int color) {
|
||||
this.colors.add(new ColorModel(attrId, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getColor(int attrId) {
|
||||
for (var item : colors)
|
||||
if (attrId == item.id)
|
||||
return item.color;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static ThemeModel valuesOf(String author, String name, boolean darkMode, String id, List<ColorModel> colors) {
|
||||
var theme = new ThemeModel()
|
||||
.setAuthor(author)
|
||||
.setName(name)
|
||||
.setDarkMode(darkMode)
|
||||
.setId(id)
|
||||
.setColors(colors);
|
||||
return theme;
|
||||
}
|
||||
|
||||
public static ThemeModel fromJson(String json) throws JSONException {
|
||||
return fromJson(new JSONObject(json));
|
||||
}
|
||||
|
||||
public static ThemeModel fromJson(JSONObject json) {
|
||||
List<String> palettes;
|
||||
if (json.has("palettes")) {
|
||||
palettes = new ArrayList<>();
|
||||
var arr = json.optString("palettes")
|
||||
.split("\\||,|&|;");
|
||||
Collections.addAll(palettes, arr);
|
||||
}
|
||||
List<ColorModel> colors = new ArrayList<>();
|
||||
var colorsJson = json.optJSONObject("colors");
|
||||
var names = colorsJson.names();
|
||||
for (int i = 0; i < colorsJson.length(); i++) {
|
||||
var name = names.optString(i);
|
||||
var value = colorsJson.optString(name);
|
||||
int attrId;
|
||||
try {
|
||||
attrId = AndroidUtils.getIdentifier(name, "attr");
|
||||
} catch (Resources.NotFoundException e) {
|
||||
attrId = AndroidUtils.getIdentifier(name, "color");
|
||||
}
|
||||
final int color;
|
||||
if (value.contains(".")) {
|
||||
var paletteId = value.substring(0, value.indexOf("."));
|
||||
var palette = PalettesManager.getInstance().getPalette(paletteId);
|
||||
var paletteColor = value.substring(value.indexOf(".") + 1);
|
||||
color = palette.getColor(paletteColor);
|
||||
} else {
|
||||
color = Color.parseColor(value.startsWith("#") ? value : "#" + value);
|
||||
}
|
||||
colors.add(new ColorModel(name, attrId, color));
|
||||
}
|
||||
return valuesOf(
|
||||
json.optString("author"),
|
||||
json.optString("name"),
|
||||
json.optBoolean("dark"),
|
||||
json.optString("id"),
|
||||
colors
|
||||
);
|
||||
}
|
||||
|
||||
public JSONObject toJson() throws JSONException {
|
||||
var colorsJson = new JSONObject();
|
||||
for (var item : colors)
|
||||
colorsJson.put(item.resName, Integer.toHexString(item.color).toUpperCase());
|
||||
return new JSONObject()
|
||||
.put("author", this.author)
|
||||
.put("name", this.name)
|
||||
.put("dark", this.isDarkMode)
|
||||
.put("id", this.id)
|
||||
.put("colors", colorsJson);
|
||||
}
|
||||
|
||||
public ThemeModel clone() {
|
||||
return new ThemeModel(
|
||||
author,
|
||||
name,
|
||||
isDarkMode,
|
||||
id,
|
||||
colors.stream()
|
||||
.map(colorModel -> new ColorModel(colorModel.resName, colorModel.id, colorModel.color))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package ru.vtosters.lite.themes.models;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ViewModel {
|
||||
|
||||
@IdRes public int id;
|
||||
public List<Pair<Integer, Integer>> attrs = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package ru.vtosters.lite.themes.proxy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.XmlRes;
|
||||
|
||||
import ru.vtosters.lite.themes.VTLResources;
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class ProxyResources extends Resources {
|
||||
|
||||
private final Resources mOriginalResource;
|
||||
|
||||
public ProxyResources(Context context, Resources original) {
|
||||
this(original);
|
||||
}
|
||||
|
||||
public ProxyResources(Resources original) {
|
||||
super(original.getAssets(), original.getDisplayMetrics(), original.getConfiguration());
|
||||
mOriginalResource = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor(int id, @Nullable Resources.Theme theme) throws Resources.NotFoundException {
|
||||
if (ThemesUtils.isCustomThemeApplied()) {
|
||||
var color = ThemesManager.getInstance().getCurrentTheme().getColor(id);
|
||||
if (color != -1)
|
||||
return color;
|
||||
}
|
||||
return mOriginalResource.getColor(id, theme);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@NonNull
|
||||
@Override
|
||||
public ColorStateList getColorStateList(@XmlRes int id, @Nullable Resources.Theme theme)
|
||||
throws Resources.NotFoundException {
|
||||
var target = mOriginalResource.getColorStateList(id, theme);
|
||||
if (ThemesUtils.isCustomThemeApplied() && ThemesUtils.isAccentedColor(target)) {
|
||||
return ColorStateList.valueOf(ThemesUtils.getAccentColor());
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Drawable getDrawableForDensity(int id, int density, @Nullable Resources.Theme theme) {
|
||||
return mOriginalResource.getDrawableForDensity(id, density, theme);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
|
||||
var ta = super.obtainAttributes(set, attrs);
|
||||
VTLResources.prepareTypedArray(ta, attrs);
|
||||
return ta;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,6 @@ import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class APKInstallActivity extends AppCompatActivity {
|
||||
public static final int REQUEST_INSTALL_PERMISSION = 1;
|
||||
|
||||
@@ -67,7 +65,7 @@ public class APKInstallActivity extends AppCompatActivity {
|
||||
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(this, AndroidUtils.getString("apk_install_error") + " " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, "Ошибка установки обновления " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
finish();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package ru.vtosters.lite.ui.activities;
|
||||
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getOauth;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
@@ -22,7 +20,7 @@ import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
public class VKAdminTokenActivity extends AppCompatActivity {
|
||||
|
||||
private static final String URL = "https://" + getOauth() +"/authorize?client_id=6121396&scope=1073737727&redirect_uri=https://oauth.vk.com/blank.html&display=page&response_type=token&revoke=1";
|
||||
private static final String URL = "https://oauth.vk.com/authorize?client_id=6121396&scope=1073737727&redirect_uri=https://oauth.vk.com/blank.html&display=page&response_type=token&revoke=1";
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle bundle) {
|
||||
@@ -39,7 +37,7 @@ public class VKAdminTokenActivity extends AppCompatActivity {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
var url = request.getUrl().toString();
|
||||
if (url.startsWith("https://" + getOauth() + "/auth_redirect?")) {
|
||||
if (url.startsWith("https://oauth.vk.com/auth_redirect?")) {
|
||||
var redirectUri = Uri.parse(URLDecoder.decode(url));
|
||||
var authorizeUrl = redirectUri.getQueryParameter("authorize_url");
|
||||
var accessToken = authorizeUrl.substring(authorizeUrl.indexOf("=") + 1, authorizeUrl.indexOf("&"));
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package ru.vtosters.lite.ui.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuInflater;
|
||||
|
||||
import com.vk.core.ui.themes.ThemableActivity;
|
||||
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
public class VTLThemableActivity extends ThemableActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
LifecycleUtils.addActivity(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
LifecycleUtils.removeActivity(this);
|
||||
}
|
||||
}
|
||||
@@ -34,10 +34,10 @@ public class CategorizedAdapter extends RecyclerView.Adapter<CategorizedAdapter.
|
||||
public static final int SELECTED_STATE = -0x1;
|
||||
public static final int DISABLED_STATE = -0x2;
|
||||
|
||||
private final List mSelectedItems;
|
||||
private final List mDisabledItems;
|
||||
private final List mUnmovedItems;
|
||||
private final IViewHolderBinder mBinder;
|
||||
private List mSelectedItems;
|
||||
private List mDisabledItems;
|
||||
private List mUnmovedItems;
|
||||
private IViewHolderBinder mBinder;
|
||||
|
||||
private int mMinSelectedItems = -1;
|
||||
private int mMaxSelectedItems = -1;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package ru.vtosters.lite.ui.adapters;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.vk.core.drawable.BorderDrawable;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.stories.view.StoryCircleImageView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.themes.models.ColorModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class ColorPickerAdapter extends RecyclerView.Adapter<ColorPickerAdapter.ColorPickerViewHolder> {
|
||||
|
||||
private List<ColorModel> mColors;
|
||||
private OnColorSelectListener mSelectListener;
|
||||
|
||||
public ColorPickerAdapter(List<ColorModel> colors, OnColorSelectListener selectListener) {
|
||||
this.mColors = colors;
|
||||
this.mSelectListener = selectListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ColorPickerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
var container = LayoutInflater.from(parent.getContext())
|
||||
.inflate(AndroidUtils.getIdentifier("color_picker_item", "layout"), parent, false);
|
||||
return new ColorPickerViewHolder(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ColorPickerViewHolder holder, int pos) {
|
||||
holder.bind(mColors.get(pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mColors.size();
|
||||
}
|
||||
|
||||
public class ColorPickerViewHolder extends RecyclerView.ViewHolder {
|
||||
private View mContainer;
|
||||
private FrameLayout mColorPreviewBorder;
|
||||
private StoryCircleImageView mColorPreview;
|
||||
private TextView mColorName;
|
||||
private TextView mColorValue;
|
||||
|
||||
public ColorPickerViewHolder(@NonNull View view) {
|
||||
super(view);
|
||||
|
||||
mContainer = view;
|
||||
mColorPreviewBorder = view.findViewById(AndroidUtils.getIdentifier("color_preview_border", "id"));
|
||||
mColorPreview = view.findViewById(AndroidUtils.getIdentifier("color_preview", "id"));
|
||||
mColorName = view.findViewById(AndroidUtils.getIdentifier("color_name", "id"));
|
||||
mColorValue = view.findViewById(AndroidUtils.getIdentifier("color_value", "id"));
|
||||
}
|
||||
|
||||
public void bind(ColorModel item) {
|
||||
mContainer.setOnClickListener(v -> mSelectListener.onColorSelected(ColorPickerAdapter.this, item));
|
||||
mColorPreviewBorder.setBackground(new BorderDrawable(ThemesUtils.isDarkTheme() ? Color.WHITE : Color.BLACK, Screen.c(24.0f), Screen.c(1.0f)));
|
||||
mColorPreview.setPlaceholderColor(item.color);
|
||||
mColorName.setText(item.resName);
|
||||
mColorValue.setText("#" + Integer.toHexString(item.color).toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnColorSelectListener {
|
||||
|
||||
void onColorSelected(ColorPickerAdapter adapter, ColorModel colorModel);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import ru.vtosters.lite.utils.LayoutUtils;
|
||||
public class ImagineArrayAdapter extends ArrayAdapter<ImagineArrayAdapter.ImagineArrayAdapterItem> {
|
||||
|
||||
private List<ImagineArrayAdapterItem> mItems = new ArrayList<>();
|
||||
private final OnClickListener mListener;
|
||||
private OnClickListener mListener;
|
||||
private int mSelectedIndex = -1;
|
||||
|
||||
public ImagineArrayAdapter(@NonNull Context context, OnClickListener listener) {
|
||||
@@ -134,8 +134,8 @@ public class ImagineArrayAdapter extends ArrayAdapter<ImagineArrayAdapter.Imagin
|
||||
}
|
||||
|
||||
public static class ImagineArrayAdapterItem {
|
||||
private final Drawable mIcon;
|
||||
private final String mText;
|
||||
private Drawable mIcon;
|
||||
private String mText;
|
||||
|
||||
public ImagineArrayAdapterItem(Drawable icon, String text) {
|
||||
this.mIcon = icon;
|
||||
@@ -167,6 +167,6 @@ public class ImagineArrayAdapter extends ArrayAdapter<ImagineArrayAdapter.Imagin
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
void onClick(int i);
|
||||
public void onClick(int i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,13 @@ import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class MessagesPreviewAdapter extends RecyclerView.Adapter<MessagesPreviewAdapter.MessagePreviewViewHolder> {
|
||||
|
||||
private static final int ME = 0x0;
|
||||
private static final int ANONYMOUS = -0x1;
|
||||
|
||||
private final String[] mMessages = AndroidUtils.getArray("wallpaper_change_dialog");
|
||||
private final String[] mMessages = {
|
||||
"Доброе время", "Доброе утро, день, вечер. ночь", "Как живёшь?", "Не мёртвый, и то хорошо"
|
||||
};
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int i) {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package ru.vtosters.lite.ui.adapters;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.PalettesManager;
|
||||
import ru.vtosters.lite.ui.dialogs.PalettesBottomSheetDialog;
|
||||
import ru.vtosters.lite.themes.models.PaletteModel;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class PalettesAdapter extends RecyclerView.Adapter<PalettesAdapter.PaletteViewHolder> {
|
||||
|
||||
private PalettesManager manager = PalettesManager.getInstance();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public PaletteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
var container = LayoutInflater.from(parent.getContext()).inflate(
|
||||
AndroidUtils.getIdentifier("palette_manager_item", "layout"), parent, false
|
||||
);
|
||||
return new PaletteViewHolder(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull PaletteViewHolder holder, int pos) {
|
||||
holder.bind(manager.getPalette(pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return manager.getPalettesCount();
|
||||
}
|
||||
|
||||
public static class PaletteViewHolder extends RecyclerView.ViewHolder {
|
||||
private View mContainer;
|
||||
private TextView mName;
|
||||
private TextView mAuthor;
|
||||
|
||||
public PaletteViewHolder(@NonNull View view) {
|
||||
super(view);
|
||||
|
||||
mContainer = view;
|
||||
mName = view.findViewById(R.id.name);
|
||||
mAuthor = view.findViewById(AndroidUtils.getIdentifier("author", "id"));
|
||||
}
|
||||
|
||||
public void bind(PaletteModel palette) {
|
||||
mContainer.setOnClickListener(v -> {
|
||||
PalettesBottomSheetDialog.create((Activity) v.getContext(), palette);
|
||||
});
|
||||
mName.setText(palette.name);
|
||||
mAuthor.setText(palette.author);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import static ru.vtosters.lite.utils.ThemesUtils.getSTextAttr;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.recolorDrawable;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.net.Uri;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -29,9 +28,8 @@ import ru.vtosters.lite.tgs.TGPref;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class StickerPackAdapter extends RecyclerView.Adapter<StickerPackAdapter.StickerPackViewHolder> {
|
||||
private static final TelegramStickersService sService = TelegramStickersService.getInstance(getGlobalContext());
|
||||
private static TelegramStickersService sService = TelegramStickersService.getInstance(getGlobalContext());
|
||||
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
@NonNull
|
||||
@Override
|
||||
public StickerPackViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
@@ -63,13 +61,13 @@ public class StickerPackAdapter extends RecyclerView.Adapter<StickerPackAdapter.
|
||||
}
|
||||
|
||||
public class StickerPackViewHolder extends RecyclerView.ViewHolder {
|
||||
private final LinearLayout mContainer;
|
||||
private final ImageView mStickerPreview;
|
||||
private final ImageView mUpdateButton;
|
||||
private final ImageView mDeleteButton;
|
||||
private final TextView mName;
|
||||
private final TextView mStickersCount;
|
||||
private final SwitchCompat mSwitch;
|
||||
private LinearLayout mContainer;
|
||||
private ImageView mStickerPreview;
|
||||
private ImageView mUpdateButton;
|
||||
private ImageView mDeleteButton;
|
||||
private TextView mName;
|
||||
private TextView mStickersCount;
|
||||
private SwitchCompat mSwitch;
|
||||
|
||||
|
||||
public StickerPackViewHolder(@NonNull View view) {
|
||||
@@ -84,7 +82,6 @@ public class StickerPackAdapter extends RecyclerView.Adapter<StickerPackAdapter.
|
||||
mStickersCount = view.findViewWithTag("vkim_cancel_label_text");
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
public void bind(int position) {
|
||||
final TelegramStickersPack pack = sService.getPacksListReference().get(position);
|
||||
if (pack.state != TelegramStickersPack.DOWNLOADED) return;
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
package ru.vtosters.lite.ui.adapters;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.vk.core.drawable.BorderDrawable;
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ru.vtosters.lite.themes.managers.ThemesManager;
|
||||
import ru.vtosters.lite.ui.dialogs.EditTextDialog;
|
||||
import ru.vtosters.lite.ui.dialogs.ThemesEditorBottomSheetDialog;
|
||||
import ru.vtosters.lite.themes.models.ThemeModel;
|
||||
import ru.vtosters.lite.ui.views.NoTouchRadioButton;
|
||||
import ru.vtosters.lite.ui.vkui.VKUIActionPopup;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
public class ThemesAdapter extends RecyclerView.Adapter<ThemesAdapter.ThemeViewHolder> {
|
||||
|
||||
public ThemesManager mManager = ThemesManager.getInstance();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ThemeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
var container = LayoutInflater.from(parent.getContext()).inflate(
|
||||
AndroidUtils.getIdentifier("theme_manager_item", "layout"), parent, false
|
||||
);
|
||||
return new ThemeViewHolder(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ThemeViewHolder holder, int pos) {
|
||||
holder.bind(mManager.getTheme(pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mManager.getThemesCount();
|
||||
}
|
||||
|
||||
public class ThemeViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private ConstraintLayout mContainer;
|
||||
private FrameLayout mThemeModePreviewBorder;
|
||||
private ImageView mThemeModePreview;
|
||||
private TextView mName;
|
||||
private TextView mAuthor;
|
||||
private NoTouchRadioButton mRadioButton;
|
||||
|
||||
public ThemeViewHolder(@NonNull View view) {
|
||||
super(view);
|
||||
|
||||
mContainer = (ConstraintLayout) view;
|
||||
mThemeModePreviewBorder = view.findViewById(AndroidUtils.getIdentifier("theme_mode_preview_border", "id"));
|
||||
mThemeModePreview = view.findViewById(AndroidUtils.getIdentifier("theme_mode_preview", "id"));
|
||||
mName = view.findViewById(R.id.name);
|
||||
mAuthor = view.findViewById(AndroidUtils.getIdentifier("author", "id"));
|
||||
mRadioButton = view.findViewById(AndroidUtils.getIdentifier("selection", "id"));
|
||||
}
|
||||
|
||||
public void bind(ThemeModel theme) {
|
||||
var accent = getAccentColorFromCustomTheme(theme);
|
||||
mThemeModePreviewBorder.setBackground(new BorderDrawable(accent, Screen.c(24.0f), Screen.c(1.0f)));
|
||||
mThemeModePreview.setImageResource(AndroidUtils.getIdentifier(
|
||||
"vk_icon_" + (theme.isDarkMode ? "moon" : "sun") + "_outline_28",
|
||||
"drawable"));
|
||||
mThemeModePreview.setImageTintList(ColorStateList.valueOf(accent));
|
||||
var isCurrentTheme = mManager.isCurrentTheme(theme);
|
||||
if (!isCurrentTheme)
|
||||
mContainer.setOnClickListener(v -> {
|
||||
mManager.setTheme(theme);
|
||||
LifecycleUtils.restartApplication();
|
||||
});
|
||||
if (!"default".equals(theme.id))
|
||||
mContainer.setOnLongClickListener(v -> {
|
||||
showActionPopup(v.getContext(), v, isCurrentTheme, theme);
|
||||
return true;
|
||||
});
|
||||
else
|
||||
mContainer.setOnLongClickListener(null);
|
||||
mRadioButton.setChecked(isCurrentTheme);
|
||||
mName.setText(theme.name);
|
||||
mAuthor.setText(theme.author);
|
||||
}
|
||||
|
||||
private void showActionPopup(Context context, View anchorView, boolean isCurrentTheme, ThemeModel theme) {
|
||||
var builder = new VKUIActionPopup(context, anchorView, true, R.color.colorAccent)
|
||||
.setItem("Редактировать название",
|
||||
() -> showEditThemeNameDialog(context, theme))
|
||||
.setItem("Изменить цвета",
|
||||
() -> ThemesEditorBottomSheetDialog.create((Activity) context, theme, isCurrentTheme))
|
||||
.setItem("Поделиться темой", () -> {
|
||||
try {
|
||||
mManager.share(context, theme);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
ToastUtils.a("Не удалось поделиться темой");
|
||||
}})
|
||||
.setItem("Удалить тему", () -> {
|
||||
mManager.delete(theme);
|
||||
if (isCurrentTheme)
|
||||
LifecycleUtils.restartApplication();
|
||||
else
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
builder.create().d();
|
||||
}
|
||||
|
||||
private void showEditThemeNameDialog(Context context, ThemeModel theme) {
|
||||
EditTextDialog.create(context, "Редактирование названия темы", "Название темы", theme.name, (dialog, which, editText) -> {
|
||||
var newName = editText.getText().toString();
|
||||
if (TextUtils.isEmpty(newName)) {
|
||||
ToastUtils.a("Название не может быть пустым");
|
||||
return;
|
||||
}
|
||||
if (newName.equals(theme.name)) {
|
||||
ToastUtils.a("Вы не изменили название");
|
||||
return;
|
||||
}
|
||||
theme.setName(newName);
|
||||
try {
|
||||
mManager.save(theme);
|
||||
notifyDataSetChanged();
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
ToastUtils.a("Не удалось изменить название темы");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private int getAccentColorFromCustomTheme(ThemeModel theme) {
|
||||
if (!"default".equals(theme.id)) {
|
||||
int color = theme.getColor(R.attr.accent);
|
||||
if (color != -1)
|
||||
return color;
|
||||
color = theme.getColor(R.attr.colorAccent);
|
||||
if (color != -1)
|
||||
return color;
|
||||
color = theme.getColor(R.attr.vk_accent);
|
||||
if (color != -1)
|
||||
return color;
|
||||
}
|
||||
return VKThemeHelper.d((R.attr.accent));
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
|
||||
@@ -43,7 +42,7 @@ public class BackupManager {
|
||||
|
||||
public static void backupOnlines() throws IOException {
|
||||
if (getPrefContent("onlines.xml") == null) {
|
||||
Toast.makeText(getGlobalContext(), AndroidUtils.getString("no_data_to_backup"), LENGTH_SHORT).show();
|
||||
Toast.makeText(getGlobalContext(), "Нет данных для резервного копирования", LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -55,10 +54,10 @@ public class BackupManager {
|
||||
FileWriter out = new FileWriter(file);
|
||||
out.write(getPrefContent("onlines.xml"));
|
||||
out.close();
|
||||
Toast.makeText(getGlobalContext(), AndroidUtils.getString("backup_saved_in") + " " + file.getAbsolutePath(), LENGTH_LONG).show();
|
||||
Toast.makeText(getGlobalContext(), "Сохранено в файл " + file.getAbsolutePath(), LENGTH_LONG).show();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(getGlobalContext(), AndroidUtils.getString("backup_save_error"), LENGTH_SHORT).show();
|
||||
Toast.makeText(getGlobalContext(), "Не удалось сохранить файл", LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +70,10 @@ public class BackupManager {
|
||||
FileWriter out = new FileWriter(file);
|
||||
out.write(getPrefContent("com.vtosters.lite_preferences.xml"));
|
||||
out.close();
|
||||
Toast.makeText(getGlobalContext(), AndroidUtils.getString("backup_saved_in") + " " + file.getAbsolutePath(), LENGTH_LONG).show();
|
||||
Toast.makeText(getGlobalContext(), "Сохранено в файл " + file.getAbsolutePath(), LENGTH_LONG).show();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(getGlobalContext(), AndroidUtils.getString("backup_save_error"), LENGTH_SHORT).show();
|
||||
Toast.makeText(getGlobalContext(), "Не удалось сохранить файл", LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
@@ -58,7 +57,6 @@ public class CrashReporter {
|
||||
var saveLogIntent = new Intent(getGlobalContext(), LogWriterService.class);
|
||||
saveLogIntent.putExtra("log", logString);
|
||||
saveLogIntent.putExtra("notificationId", 1);
|
||||
@SuppressLint("UnspecifiedImmutableFlag")
|
||||
var psaveLogIntent = PendingIntent.getService(getGlobalContext(), 0, saveLogIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
var builder = new Notification.Builder(getGlobalContext());
|
||||
@@ -67,8 +65,12 @@ public class CrashReporter {
|
||||
builder.setContentText(logString);
|
||||
builder.setStyle(new Notification.BigTextStyle().bigText(logString));
|
||||
builder.setAutoCancel(true);
|
||||
builder.addAction(new Notification.Action(0, getString("vtl_crash_upload"), PendingIntent.getActivity(getGlobalContext(), (int) (Math.random() * 100.0d), foxbinIntent, PendingIntent.FLAG_CANCEL_CURRENT)));
|
||||
builder.addAction(new Notification.Action(0, getString("vtl_crash_save"), psaveLogIntent));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
|
||||
builder.addAction(new Notification.Action(0, getString("vtl_crash_upload"), PendingIntent.getActivity(getGlobalContext(), (int) (Math.random() * 100.0d), foxbinIntent, PendingIntent.FLAG_CANCEL_CURRENT)));
|
||||
builder.addAction(new Notification.Action(0, getString("vtl_crash_save"), psaveLogIntent));
|
||||
} else {
|
||||
builder.setContentIntent(PendingIntent.getActivity(activity, 0, foxbinIntent, PendingIntent.FLAG_ONE_SHOT));
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
builder.setChannelId("crashes");
|
||||
|
||||
@@ -5,15 +5,12 @@ import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.milkshake;
|
||||
import static ru.vtosters.lite.utils.Preferences.superapp;
|
||||
import static ru.vtosters.lite.utils.Preferences.useNewSettings;
|
||||
import static ru.vtosters.lite.utils.Preferences.videonewcatalog;
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme;
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme_notifs;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.vk.apps.AppsFragment;
|
||||
import com.vk.discover.DiscoverFragment;
|
||||
import com.vk.discover.ThemedFeedFragment;
|
||||
import com.vk.fave.fragments.FaveTabFragment;
|
||||
import com.vk.feedlikes.d.FeedLikesFragment;
|
||||
import com.vk.friends.catalog.FriendsCatalogFragment;
|
||||
@@ -45,10 +42,12 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ru.vtosters.lite.ui.fragments.VTSettings;
|
||||
import ru.vtosters.lite.ui.items.DockBarTab;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class DockBarEditorManager {
|
||||
|
||||
public static final int MIN_SELECTED_TABS = 3;
|
||||
public static final int MAX_SELECTED_TABS = 9;
|
||||
|
||||
@@ -97,31 +96,19 @@ public class DockBarEditorManager {
|
||||
private void parseSelectedTabs(String[] selectedTabsTags) {
|
||||
List<String> allTags = new ArrayList<>(Arrays.asList("tab_news", "tab_superapps", "tab_messages", "tab_feedback", "tab_profile",
|
||||
"tab_friends", "tab_groups", "tab_photos", "tab_audios", "tab_videos", "tab_lives", "tab_games", "tab_liked",
|
||||
"tab_fave", "tab_documents", "tab_payments", "tab_vk_apps", "tab_settings"));
|
||||
|
||||
"tab_fave", "tab_documents", "tab_payments", "tab_vk_apps", "tab_settings", "tab_menu"));
|
||||
for (String tag : selectedTabsTags) {
|
||||
mSelectedTabs.add(getTabByTag(tag));
|
||||
allTags.remove(tag);
|
||||
}
|
||||
|
||||
for (String tag : allTags) {
|
||||
mDisabledTabs.add(getTabByTag(tag));
|
||||
}
|
||||
allTags.forEach(tag -> mDisabledTabs.add(getTabByTag(tag)));
|
||||
}
|
||||
|
||||
public void save() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
getPreferences().edit().putString("dockbar_tabs", mSelectedTabs.stream()
|
||||
.map(tab -> tab.tag)
|
||||
.collect(Collectors.joining(",")))
|
||||
.commit();
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DockBarTab tab : mSelectedTabs) {
|
||||
sb.append(tab.tag).append(",");
|
||||
}
|
||||
getPreferences().edit().putString("dockbar_tabs", sb.toString()).commit();
|
||||
}
|
||||
AndroidUtils.getPreferences().edit().putString("dockbar_tabs", mSelectedTabs.stream()
|
||||
.map(tab -> tab.tag)
|
||||
.collect(Collectors.joining(",")))
|
||||
.commit();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
@@ -154,7 +141,7 @@ public class DockBarEditorManager {
|
||||
milkshake() ? R.drawable.ic_services_outline_28 : R.drawable.ic_menu_search_outline_28,
|
||||
milkshake() ? R.string.super_app_title : R.string.search,
|
||||
R.id.tab_discover,
|
||||
milkshake() ? (superapp() ? SuperAppFragment.class : SearchMenuFragment.class) : DiscoverFragment.class);
|
||||
milkshake() ? (superapp() ? SuperAppFragment.class : SearchMenuFragment.class) : ThemedFeedFragment.class);
|
||||
case "tab_messages":
|
||||
return DockBarTab.valuesOf(
|
||||
"tab_messages",
|
||||
@@ -260,6 +247,13 @@ public class DockBarEditorManager {
|
||||
R.string.menu_apps,
|
||||
R.id.menu_vk_apps,
|
||||
AppsFragment.class);
|
||||
case "tab_menu":
|
||||
return DockBarTab.valuesOf(
|
||||
"tab_menu",
|
||||
milkshake() ? R.drawable.ic_user_circle_outline_28 : R.drawable.ic_menu_more_outline_28,
|
||||
milkshake() ? R.string.profile : R.string.menu,
|
||||
R.id.tab_menu,
|
||||
milkshake() ? ProfileFragment.class : MenuFragment.class);
|
||||
case "tab_settings":
|
||||
default:
|
||||
return DockBarTab.valuesOf(
|
||||
@@ -267,7 +261,7 @@ public class DockBarEditorManager {
|
||||
R.drawable.ic_settings_outline_28,
|
||||
R.string.menu_settings,
|
||||
R.id.menu_settings,
|
||||
useNewSettings());
|
||||
VTSettings.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ru.vtosters.lite.ui.components;
|
||||
|
||||
public interface IItemMovingListener {
|
||||
|
||||
void onItemDismiss(int index);
|
||||
|
||||
boolean onItemMove(int fromPosition, int toPosition);
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package ru.vtosters.lite.ui.components;
|
||||
|
||||
import static ru.vtosters.lite.ui.vkui.VBListBuilder.VBListItem;
|
||||
import static ru.vtosters.lite.ui.vkui.VBListBuilder.buildListOf;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import ru.vtosters.lite.ui.vkui.VBottomSheetBuilder;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class NewsfeedListManager {
|
||||
|
||||
public static void callEditorPopup(Activity activity) {
|
||||
var selectedItems = getDefaultPrefs().getString("news_feed_selected_items", "");
|
||||
var filtersSet = getDefaultPrefs().getStringSet("news_feed_items_set", Collections.synchronizedSet(new LinkedHashSet<>()));
|
||||
var list = new ArrayList<VBListItem>();
|
||||
|
||||
if (filtersSet.size() == 0) {
|
||||
sendToast(AndroidUtils.getString("newsfeed_list_update_feed"));
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (filtersSet) {
|
||||
for (String item : filtersSet) {
|
||||
var id = item.substring(0, item.indexOf("|"));
|
||||
var title = item.substring(item.indexOf("|") + 1);
|
||||
|
||||
list.add(new VBListItem(id, title, selectedItems.contains(id)));
|
||||
}
|
||||
}
|
||||
|
||||
VBottomSheetBuilder.show(activity, new VBottomSheetBuilder.VBSContent(
|
||||
AndroidUtils.getString("newsfeed_list_choose_to_hide"),
|
||||
buildListOf(activity, list),
|
||||
new VBottomSheetBuilder.VBSContent.VBSButton(
|
||||
AndroidUtils.getString("save"),
|
||||
() -> {
|
||||
var newSelectedItems = "";
|
||||
for (VBListItem item : list)
|
||||
if (item.checked)
|
||||
newSelectedItems += item.id + ",";
|
||||
getDefaultPrefs().edit()
|
||||
.putString("news_feed_selected_items", newSelectedItems)
|
||||
.apply();
|
||||
sendToast(AndroidUtils.getString("newsfeed_list_update_feed_to_work"));
|
||||
}
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
public static void resetHideItems() {
|
||||
getDefaultPrefs().edit().remove("news_feed_selected_items").remove("news_feed_items_set")
|
||||
.apply();
|
||||
sendToast(AndroidUtils.getString("newsfeed_list_hidden_reseted"));
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package ru.vtosters.lite.ui.components;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -42,30 +40,15 @@ public class SuperAppEditorManager {
|
||||
mSelectedItems.add(getItemByTag(tag));
|
||||
allTags.remove(tag);
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
allTags.forEach(tag -> mDisabledItems.add(getItemByTag(tag)));
|
||||
} else {
|
||||
for (String tag : allTags) {
|
||||
mDisabledItems.add(getItemByTag(tag));
|
||||
}
|
||||
}
|
||||
allTags.forEach(tag -> mDisabledItems.add(getItemByTag(tag)));
|
||||
}
|
||||
|
||||
public void save() {
|
||||
if (mSelectedItems.size() > 0)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
getPreferences().edit().putString("superapp_items", mSelectedItems.stream()
|
||||
.map(item -> item.type)
|
||||
.collect(Collectors.joining(",")))
|
||||
.commit();
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (SuperAppItem item : mSelectedItems) {
|
||||
sb.append(item.type);
|
||||
sb.append(",");
|
||||
}
|
||||
getPreferences().edit().putString("superapp_items", sb.toString()).commit();
|
||||
}
|
||||
getPreferences().edit().putString("superapp_items", mSelectedItems.stream()
|
||||
.map(item -> item.type)
|
||||
.collect(Collectors.joining(",")))
|
||||
.commit();
|
||||
else
|
||||
reset();
|
||||
}
|
||||
@@ -88,33 +71,33 @@ public class SuperAppEditorManager {
|
||||
private SuperAppItem getItemByTag(String tag) {
|
||||
switch (tag) {
|
||||
case "menu":
|
||||
return SuperAppItem.valuesOf("menu", AndroidUtils.getString("superapp_menu"));
|
||||
return SuperAppItem.valuesOf("menu", "Меню приложения");
|
||||
case "miniapps":
|
||||
return SuperAppItem.valuesOf("miniapps", AndroidUtils.getString("superapp_miniapps"));
|
||||
return SuperAppItem.valuesOf("miniapps", "Mini Apps: виджет");
|
||||
case "vkpay_slim":
|
||||
return SuperAppItem.valuesOf("vkpay_slim", AndroidUtils.getString("superapp_vkpay"));
|
||||
return SuperAppItem.valuesOf("vkpay_slim", "VK Pay");
|
||||
case "greeting":
|
||||
return SuperAppItem.valuesOf("greeting", AndroidUtils.getString("superapp_greeting"));
|
||||
return SuperAppItem.valuesOf("greeting", "Приветствие");
|
||||
case "promo":
|
||||
return SuperAppItem.valuesOf("promo", AndroidUtils.getString("superapp_miniapps_promo"));
|
||||
return SuperAppItem.valuesOf("promo", "Mini Apps: промо");
|
||||
case "holiday":
|
||||
return SuperAppItem.valuesOf("holiday", AndroidUtils.getString("superapp_holiday"));
|
||||
return SuperAppItem.valuesOf("holiday", "Дни рождения у друзей");
|
||||
case "weather":
|
||||
return SuperAppItem.valuesOf("weather", AndroidUtils.getString("superapp_weather"));
|
||||
return SuperAppItem.valuesOf("weather", "Погода");
|
||||
case "sport":
|
||||
return SuperAppItem.valuesOf("sport", AndroidUtils.getString("superapp_sport"));
|
||||
return SuperAppItem.valuesOf("sport", "Спортивные события");
|
||||
case "games":
|
||||
return SuperAppItem.valuesOf("games", AndroidUtils.getString("superapp_games"));
|
||||
return SuperAppItem.valuesOf("games", "Игры");
|
||||
case "informer":
|
||||
return SuperAppItem.valuesOf("informer", AndroidUtils.getString("superapp_informer"));
|
||||
return SuperAppItem.valuesOf("informer", "Информер");
|
||||
case "food":
|
||||
return SuperAppItem.valuesOf("food", AndroidUtils.getString("superapp_food"));
|
||||
return SuperAppItem.valuesOf("food", "Еда");
|
||||
case "event":
|
||||
return SuperAppItem.valuesOf("event", AndroidUtils.getString("superapp_event"));
|
||||
return SuperAppItem.valuesOf("event", "Мероприятия");
|
||||
case "music":
|
||||
return SuperAppItem.valuesOf("music", AndroidUtils.getString("superapp_music"));
|
||||
return SuperAppItem.valuesOf("music", "Музыка");
|
||||
case "vk_run":
|
||||
return SuperAppItem.valuesOf("vk_run", AndroidUtils.getString("superapp_vk_run"));
|
||||
return SuperAppItem.valuesOf("vk_run", "VK Run");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
|
||||
import static ru.vtosters.lite.themes.VTLColors.getTextSecondaryColor;
|
||||
import static ru.vtosters.lite.themes.VTLColors.getTextPrimaryColor;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
|
||||
import ru.vtosters.lite.ui.vkui.VKUIEditText;
|
||||
import ru.vtosters.lite.ui.vkui.VKUITextView;
|
||||
import ru.vtosters.lite.utils.LayoutUtils;
|
||||
|
||||
public class EditTextDialog {
|
||||
public static void create(Context context, String title, String hint, String text, OnClickListener clickListener) {
|
||||
var container = new LinearLayout(context);
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
container.setPadding(
|
||||
dp2px(8), dp2px(12), dp2px(8), dp2px(12)
|
||||
);
|
||||
|
||||
if (!TextUtils.isEmpty(hint)) {
|
||||
var hitText = new VKUITextView(context, VKUITextView.STYLE_SUBHEAD_1);
|
||||
hitText.setText(hint);
|
||||
hitText.setPadding(dp2px(8), 0, 0, dp2px(8));
|
||||
container.addView(hitText, LayoutUtils.createLinear(-2, -2));
|
||||
}
|
||||
|
||||
var editText = new VKUIEditText(context);
|
||||
if (!TextUtils.isEmpty(text))
|
||||
editText.setText(text);
|
||||
editText.setTextColor(getTextPrimaryColor());
|
||||
editText.setHintTextColor(getTextSecondaryColor());
|
||||
editText.setPadding(dp2px(8), 0, dp2px(8), 0);
|
||||
|
||||
var editTextParams = LayoutUtils.createLinear(-1, dp2px(44));
|
||||
container.addView(editText, editTextParams);
|
||||
|
||||
VkAlertDialog.Builder builder = new VkAlertDialog.Builder(context);
|
||||
if (!TextUtils.isEmpty(title))
|
||||
builder.setTitle(title);
|
||||
builder.setPositiveButton("OK", (dialog, which) -> clickListener.onClick(dialog, which, editText));
|
||||
builder.setNegativeButton("Отмена", (dialog, which) -> dialog.cancel());
|
||||
|
||||
var alert = builder.create();
|
||||
alert.setView(container);
|
||||
alert.show();
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
void onClick(DialogInterface dialog, int which, EditText editText);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user