Compare commits

...
Author SHA1 Message Date
gdlbo 501e39429b Update WebCachePreloader.smali 2022-11-14 15:38:05 +03:00
gdlbo 604d19cc40 upgraded link parser 2022-11-14 14:56:21 +03:00
gdlbo a29e0dcf4b fixed articles 2022-11-14 14:26:42 +03:00
gdlbo ec551dcb33 BusinessNotif disabler 2022-11-13 20:33:46 +03:00
gdlbo cc4690965a Update preferences_feed.xml 2022-11-13 19:47:31 +03:00
gdlbo 65f32d3686 fixed articles 2022-11-13 18:15:33 +03:00
gdlbo bf15bb93ee support story download to video downloader btn 2022-11-10 15:27:15 +03:00
gdlbo cb3c537f1d updated ad filter 2022-11-10 14:58:44 +03:00
Vologhat bb0c845e74 Merge branch 'main' of https://github.com/vtosters/lite 2022-11-09 17:15:32 +03:00
Vologhat a4c88d0924 Fix video downloader 2022-11-09 17:14:00 +03:00
gdlbo 7f0b6c3c3d disabled undelete by default 2022-11-09 16:20:17 +03:00
gdlbo 31eedf4d6d updated feed settings 2022-11-09 11:48:31 +03:00
gdlbo bf23cc7305 deleted unused features 2022-11-09 11:09:57 +03:00
gdlbo 6bef2f1ea9 upd proxy information 2022-11-09 11:02:06 +03:00
gdlbo e561356690 deleted video analytics 2022-11-09 10:31:59 +03:00
gdlbo 64d6e4b529 deleted old abt lib 2022-11-09 10:20:40 +03:00
gdlbo 34d067d192 deleted some vk perf trackers 2022-11-08 18:53:02 +03:00
gdlbo c50511a12f deleted vk updates + google play core 2022-11-08 18:33:37 +03:00
gdlbo 0b748c16e4 deleted google ads lib 2022-11-08 18:21:46 +03:00
gdlbo f88dd17480 deleted measurement lib 2022-11-08 18:16:49 +03:00
gdlbo 892e9874cb deleted 60% of firebase lib 2022-11-08 18:11:34 +03:00
gdlbo 82a24e4abf Update GetFullUserProfile.smali 2022-11-08 16:18:57 +03:00
gdlbo 2631757a05 updated TGS Grabber
@egormetlitsky
2022-11-08 16:01:26 +03:00
gdlbo b2f7754ec9 updated old token req 2022-11-08 15:29:28 +03:00
aliveoutside 2175800f33 run auto code reformat 2022-11-02 16:10:56 +03:00
aliveoutside ab16fdcecb optimize imports 2022-11-02 16:01:38 +03:00
aliveoutside a34cad6837 move everything music related to "music" package 2022-11-02 15:57:23 +03:00
k1zn 34b2357a20 translate + move music settings above 2022-10-31 13:35:12 +05:00
gdlbo e47d6acbf1 fixed show cached pl 2022-10-30 00:54:59 +03:00
aliveoutside a5bd532570 use a singleton for okhttp so it will reduce OkHttpClients count 2022-10-29 19:16:21 +03:00
aliveoutside e4124f459f [music] move catalog json injector to separate package 2022-10-29 18:45:48 +03:00
aliveoutside 03328137df [music] fix not loading "main" page 2022-10-29 18:19:27 +03:00
Vologhat 906036854c maybe music fix 2022-10-29 17:57:39 +03:00
gdlbo 1dad82d61c Update MediaFragment.java 2022-10-28 03:51:39 +03:00
gdlbo 0d9f8360ce Update MediaFragment.java 2022-10-28 03:43:59 +03:00
gdlbo 5dc5f001f2 new feature old music catalog 2022-10-28 03:41:55 +03:00
gdlbo b6d26515ce added support of cache pl to empty pl catalog 2022-10-28 03:37:30 +03:00
gdlbo f02971e00d Update build.gradle 2022-10-28 03:00:01 +03:00
gdlbo 827bb9d9ce refactored catalog injector for caching 2022-10-28 02:57:28 +03:00
gdlbo 4a5a6b58e1 Update JsonInjectors.java 2022-10-26 10:36:25 +03:00
gdlbo fa2a1b083d AppVerHook 2022-10-26 10:11:24 +03:00
gdlbo d372b670c0 AppVerHook 2022-10-26 08:01:33 +03:00
gdlbo 86afcaeacb Update ModernSearchView.smali 2022-10-26 07:50:41 +03:00
gdlbo 027c7a7151 fix null crash 2022-10-26 00:09:32 +03:00
aliveoutside 7f304950a8 [music] support new catalogs 2022-10-22 20:32:16 +03:00
Vologhat fc44a9b263 fix apk install 2022-10-20 21:28:11 +03:00
Vologhat 235b287a36 fix telegram stickers notification crash 2022-10-18 16:14:47 +03:00
Vologhat 9317e86d66 Update build.gradle 2022-10-15 21:46:21 +03:00
aliveoutside 23f1b6c26b load ffmpeg-kit directly from libs folder via System.loadLibrary
add arm64 libs
2022-10-15 21:43:03 +03:00
aliveoutside a7d50bca26 remove ffmpeg libs from assets 2022-10-15 21:40:23 +03:00
aliveoutside 92fbd071de reduce ffmpeg-kit size 2022-10-15 21:12:56 +03:00
Vologhat b7860b857f Updated arm32-v7a libs 2022-10-15 20:20:36 +03:00
Vologhat cd0914041d arm64-v8a support 2022-10-15 15:05:41 +03:00
Vologhat 9f0230d935 Update R.java 2022-10-14 22:19:38 +03:00
Vologhat a05865c6a8 Added R.java generator and executing scripts 2022-10-14 22:14:56 +03:00
k1zn d678ff5e9b translate 2022-10-14 19:35:37 +05:00
gdlbo 4829acd869 fix slow stickers load + some imp 2022-10-14 00:43:17 +03:00
gdlbo 6df6fdf01c miniapps ban 2022-10-14 00:08:23 +03:00
k1zn 4a2e73d676 fix context crash 2022-10-13 21:44:37 +05:00
aliveoutside 4c5a1c5a17 download track synchronously 2022-10-13 03:17:17 +03:00
aliveoutside 1aedacf401 remove useless ffmpeg banner in logs 2022-10-13 03:17:05 +03:00
aliveoutside 9d4bffd8aa use an executor to download tracks 2022-10-13 02:52:23 +03:00
aliveoutside ede17b31a2 move vkexecutors receiving to separate package 2022-10-13 02:52:23 +03:00
aliveoutside e94f93facb update telegram stickers entry icons 2022-10-13 02:52:23 +03:00
gdlbo 2460b27af1 Update LastFMScrobbler.java 2022-10-12 23:59:50 +03:00
gdlbo 9cb9bf4167 max quality for external videos 2022-10-12 22:04:08 +03:00
gdlbo 6753dc9a8c superapp restart app 2022-10-12 21:34:05 +03:00
gdlbo c257e3a5ce refactored video alert adapter 2022-10-12 21:28:02 +03:00
k1zn a055656424 в 2022-10-12 18:30:06 +05:00
k1zn 4882315bf4 another translate 2022-10-12 18:27:31 +05:00
k1zn 1d8f998a5f translate 2022-10-12 18:08:13 +05:00
k1zn ff945b76b8 fix localization bug 2022-10-12 17:50:34 +05:00
gdlbo 2d14c78a90 fixed some long titles 2022-10-12 03:13:52 +03:00
gdlbo 10d1a40bd8 some code imp 2022-10-12 02:35:36 +03:00
gdlbo 78e3757cf4 deleted unused code 2022-10-12 01:58:02 +03:00
gdlbo 2aef797efe some dev fixes 2022-10-12 01:24:50 +03:00
gdlbo 20999810ab fixed load verifs from notif 2022-10-12 00:48:03 +03:00
gdlbo d8c45ffeff fix #695 2022-10-12 00:33:40 +03:00
gdlbo 05d339eeb0 fix #695 2022-10-12 00:29:01 +03:00
gdlbo e50366da8a added #701 2022-10-12 00:02:53 +03:00
gdlbo 915b31477b fix 700 2022-10-11 23:50:15 +03:00
aliveoutside 9d2878b9dc revert "fixed redundant thread creation" b9a55799
it breaks Telegram stickers downloading, we'll investigate later
2022-10-09 15:54:26 +03:00
gdlbo bcfefe777d fix executer 2022-10-09 01:38:47 +03:00
k1zn b69e55606a fix some mistake 2022-10-09 02:32:17 +05:00
k1zn 2f06d2a008 refactoring autocache code 2022-10-09 02:31:08 +05:00
aliveoutside d151d27063 fix #831 2022-10-09 00:23:35 +03:00
gdlbo ad128f1e7e Update OTADownloader.java 2022-10-08 23:52:22 +03:00
gdlbo efe8a2c883 fix toast dl dialogs 2022-10-08 23:11:19 +03:00
aliveoutside 5def26131b [foaf] fix regexes and run the dialog from ui thread 2022-10-08 23:06:53 +03:00
gdlbo a586e4e240 Update FoafBase.java 2022-10-08 22:46:31 +03:00
Vologhat 5e66a5b924 Merge branch 'main' of https://github.com/vtosters/lite 2022-10-08 20:54:54 +03:00
Vologhat 98a58c9e94 regenerated R.java and public.xml, replaced getIdentifier calls to id constants 2022-10-08 20:54:18 +03:00
aliveoutside baba2c0009 [music] download playlist synchronously 2022-10-08 17:45:36 +03:00
aliveoutside 2ae3f48d9a [music] move temp tses dir to app internal storage 2022-10-08 17:45:36 +03:00
k1zn 9e5eae49d1 remove shadow from attachments 2022-10-08 19:19:36 +05:00
Vologhat 9e50a116ef Merge pull request #824 from zelvalea/main
Чрезмерное создание потоков
2022-10-08 14:23:37 +03:00
Vologhat 19fb86ca58 refactored last.fm scrobbler 2022-10-08 10:37:47 +03:00
zelva e7db1e2359 cleanup and fixed unwanted races 2022-10-07 14:42:04 +03:00
aliveoutside bc25be1a27 Merge pull request #823 from vtosters/gettext-removing
remove clipdata$item gettext
2022-10-07 12:21:58 +03:00
k1zn a583c98f44 fix renaming app bug 2022-10-06 18:24:57 +05:00
gdlbo d40162caa1 disabled auto theme for non milk users 2022-10-05 20:57:15 +03:00
Sunmisc 5bc4451355 cleanup 2022-10-05 16:22:20 +03:00
Sunmisc b62de5b90e cleanup 2022-10-05 16:21:59 +03:00
Sunmisc e79322a18c cleaned up and got rid of deprecated class 2022-10-05 16:16:34 +03:00
Sunmisc b9a55799fe fixed redundant thread creation 2022-10-05 15:49:25 +03:00
gdlbo 9ba210e166 fixed crash 2022-10-05 15:33:34 +03:00
k1zn eab3549ff9 remove clipdata$item gettext 2022-10-05 16:58:25 +05:00
Vologhat 98bbdf872b returned alert dialog for disabling Doze and refactored code 2022-10-04 00:51:16 +03:00
Vologhat d17e4849eb remove comment 2022-10-04 00:28:34 +03:00
Vologhat 18709ac89f added permission in AndroidManifest.xml for ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS flag 2022-10-04 00:27:50 +03:00
gdlbo 9de8e3e409 newsfeed notif counter feature 2022-10-03 23:53:59 +03:00
gdlbo 3f3d1c7f28 Update DisableBattery.java 2022-10-03 22:59:55 +03:00
gdlbo 5250ba39d2 Update ContactsUtils.java 2022-10-03 22:59:48 +03:00
gdlbo ae08e57c80 magic fix 2022-10-03 21:29:04 +03:00
gdlbo 2f24eb6145 Update README.md 2022-10-03 20:28:43 +03:00
Denis 88fa60fcfb Update README.md 2022-10-03 20:19:28 +03:00
Denis df2d5ceb12 Update README.md 2022-10-03 20:19:28 +03:00
Denis f2bc275430 Update README.md 2022-10-03 20:19:28 +03:00
Denis fbf7a3520b Update README.md 2022-10-03 20:19:28 +03:00
Denis 510952913b Update features.md 2022-10-03 20:19:28 +03:00
Denis 39c05533d0 Create features.md 2022-10-03 20:19:28 +03:00
gdlbo 4f7d00b0a0 fixed saving pics...? 2022-10-03 19:53:33 +03:00
k1zn 12e9c14838 Update README.md 2022-10-03 20:17:31 +05:00
k1zn 072fd007ca Update README.md 2022-10-03 19:57:43 +05:00
k1zn 002bf7e155 Update README.md 2022-10-03 19:55:17 +05:00
1594 changed files with 44006 additions and 430902 deletions
+78
View File
@@ -0,0 +1,78 @@
### Все функции модификации
* Лента
* Блокировка рекламы в ленте
* Блокировка постов через фильтры
* Возможность добавлять в вайтлист фильтров группы, чтобы в них не удалялись посты
* Возможность отключить рекомендации от ВК
* Медиаконтент
* Округление дат
* 1 января в 4:20
* 1 января в 4:20:00
* 1 января 2000 в 4:20:00
* Округление чисел
* Сокращение постов **(Показать полностью)**
* Результаты опросов без участия
* Возможность указывать папку для загрузки фото/видео/музыки/всего
* Интеграция с <a href="https://www.last.fm/">LAST.FM</a> (а также возможность скробблинга)
* Возможность **кешировать музыку / автокешировать ее при прослушивании**
* Возможность выбирать раздел музыки, открываемый по умолчанию
* Возможность скачивать видео, очищать историю просмотра видео
* Возможность найти фотографию через поисковые системы
* Интеграция с <a href="https://vkx.app/">VK X</a>
* Возможность кешировать треки в приложении
* Сообщения
* Обои в сообщениях
* Возможность выключения кнопки записи голосовых сообщений
* Возможность скрыть блок рекомендаций в сообщениях
* Режим **VK Me**
* Возможность вернуть вкладку уведомлений для режима VK Me
* Встроенный переводчик текста для сообщений
* Возможность выбрать язык перевода
* Автоматический перевод ваших сообщений на выбранный язык
* Альтернативный дизайн эмодзи меню
* Возможность использовать системные эмодзи
* Возможнсть использовать Enter с аппаратной клавиатуры
* Панель ввода из приложения VK для iOS
* Telegram Стикеры
* Возможность загружать свои стикерпаки из Telegram во ВКонтакте
* Внешний вид
* Возможность отключать новый дизайн версий VK (Milkshake)
* Название заголовков в докбаре
* Возможность использовать акцент для иконок
* Возможность отключить счётчики в докбаре
* Смена иконки приложения (содержит много уникальных иконок для донатеров)
* Возможность покрасить панель навигации, веб-страницы
* Интерфейс
* Возможность отключить блок историй наверху ленты
* Возможность отключить боковую камеру в разделе «Новости»
* Возможность отключить блок «Что у вас нового?» в разделе «Новости»
* Возможность показывать лайки у постов справа
* Возможность менять стартовый раздел при запуске приложения
* Анимации фрагментов
* Возможность изменять размер закругления картинок (аватарок и прочего)
* Возможность отключить редизайн видеопостов
* Возможность отключить блок миниаппов/VK Pay/Superapp
* Возможность отключить сокращение названий разделов в меню
* Возможность скрыть блок рекомендаций друзей в разделе «Друзья»
* Возможность скрыть подписи в настройках
* Редактор докбара
* Редактор элементов Superapp
* Активность
* Возможность видеть удаленные сообщения
* Функционал, позволяющий оставаться в «оффлайне» (принудительный оффлайн/не отправлять статус онлайна и т.п.)
* Нечиталка/неписалка для ЛС/бесед/ботов/групп
* Возможность отключить информацию о том, что вы просмотрели историю/прослушали голосовое сообщение
* Возможность видеть онлайн пользователей, если у вас скрыт онлайн через VK Messenger
* Возможность сохранять настройки бесшумных сообщений/сообщений-бомбочек
* Отключить уведомление о том, что вы сделали скриншот в беседе
* Отключение редиректа через away.php
* Отключение отправки метрики
* Прокси
* Поддержка сторонних прокси, таких как: Zaborona, VikaMobile, рандомные прокси и прочие
* Возможность использовать **HTTP/HTTPS/SOCKS** прокси, менять домены **API/OAuth/Static**
* Другое
* Синхронизация контактов с VK
* Очистка кеша приложения (**всё/стикеры/изображения/видео/сообщения/WebView**)
* Автоочистка кеша при достижении указанного вами значения (**100/500 MB, 1/2/5 GB**)
* Функционал для **дебага приложения/бэкап возможности/верификации VTosters**
+22 -87
View File
@@ -41,96 +41,31 @@
### Быстрая навигация
* [Функционал](#функционал)
* [Отладка приложения](#отладка-приложения)
* [Разработка](#разработка)
* [Всё необходимое для сборки и компиляции](#всё-необходимое-для-сборки-и-компиляции)
* [Необходимые зависимости](#необходимые-зависимости)
* [Linux/macOS](#linuxmacos)
* [Windows](#windows)
- [Функциональность](#функциональность)
- [Отладка приложения](#отладка-приложения)
- [Разработка](#разработка)
- [Всё необходимое для сборки и компиляции](#всё-необходимое-для-сборки-и-компиляции)
- [Необходимые зависимости](#необходимые-зависимости)
- [Linux/macOS](#linuxmacos)
- [Windows](#windows)
## Функционал
## Функциональность
* Лента
* Блокировка рекламы в ленте
* Блокировка постов через фильтры
* Возможность добавлять в вайтлист фильтров группы, чтобы в них не удалялись посты
* Возможность отключить рекомендации от ВК
* Редактор докбара
* Редактор элементов Superapp
* Медиаконтент
* Округление дат
* 1 января в 4:20
* 1 января в 4:20:00
* 1 января 2000 в 4:20:00
* Округление чисел
* Сокращение постов **(Показать полностью)**
* Результаты опросов без участия
* Возможность указывать папку для загрузки фото/видео/музыки/всего
* Интеграция с <a href="https://www.last.fm/">LAST.FM</a> (а также возможность скробблинга)
* Возможность скачивать видео, очищать историю просмотра видео
* Возможность найти фотографию через поисковые системы
* Интеграция с <a href="https://vkx.app/">VK X</a>
* Возможность кешировать треки в приложении
* Сообщения
* Обои в сообщениях
* Возможность выключения кнопки записи голосовых сообщений
* Возможность скрыть блок рекомендаций в сообщениях
* Режим **VK Me**
* Возможность вернуть вкладку уведомлений для режима VK Me
* Встроенный переводчик текста для сообщений
* Возможность выбрать язык перевода
* Автоматический перевод ваших сообщений на выбранный язык
* Альтернативный дизайн эмодзи меню
* Возможность использовать системные эмодзи
* Возможнсть использовать Enter с аппаратной клавиатуры
* Панель ввода из приложения ВК для IOS
* Активность
* Возможность видеть удаленные сообщения
* Функционал, позволяющий оставаться в «оффлайне» (принудительный оффлайн/не отправлять статус онлайна и т.п.)
* Нечиталка/неписалка для ЛС/бесед/ботов/групп
* Возможность отключить информацию о том, что вы просмотрели историю/прослушали голосовое сообщение
* Возможность видеть онлайн пользователей, если у вас скрыт онлайн через VK Messenger
* Возможность сохранять настройки бесшумных сообщений/сообщений-бомбочек
* Отключить уведомление о том, что вы сделали скриншот в беседе
* Отключение редиректа через away.php
* Отключение отправки метрики
* Внешний вид
* **Milkshake** тема (дизайн новых версий ВК)
* Название заголовков в докбаре
* Возможность использовать акцент для иконок
* Возможность отключить счётчики в докбаре
* Смена иконки приложения (содержит много уникальных иконок для донатеров)
* Возможность покрасить панель навигации, веб-страницы
* Telegram Стикеры
* Возможность загружать свои стикерпаки из Telegram во ВКонтакте
* Интерфейс
* Возможность отключить блок историй наверху ленты
* Возможность отключить боковую камеру в разделе «Новости»
* Возможность отключить блок «Что у вас нового?» в разделе «Новости»
* Возможность показывать лайки у постов справа
* Возможность менять стартовый раздел при запуске приложения
* Анимации фрагментов
* Возможность изменять размер закругления картинок (аватарок и прочего)
* Возможность отключить редизайн видеопостов
* Возможность отключить блок миниаппов/VK Pay/Superapp
* Возможность отключить сокращение названий разделов в меню
* Возможность скрыть блок рекомендаций друзей в разделе «Друзья»
* Возможность скрыть подписи в настройках
* Прокси
* Поддержка сторонних прокси, таких как: Zaborona, VikaMobile, рандомные прокси и прочие
* Возможность использовать **HTTP/HTTPS/SOCKS** прокси, менять домены **API/OAuth/Static**
* Другое
* Очистка кеша приложения (**всё/стикеры/изображения/видео/сообщения/WebView**)
* Автоочистка кеша при достижении указанного вами значения (**100/500 MB, 1/2/5 GB**)
* Функционал для **дебага приложения/бэкап возможности/верификации VTosters**
* Возможность вернуть старый дизайн ВКонтакте
* Нет рекламы и ограничений музыки
* Интеграция с <a href="https://vkx.app/">VKX</a> и <a href="https://www.last.fm/">Last.FM</a>
* Самая большая кастомизация и фильтрация ленты новостей
* Кеширование и скачивание треков
* Редактор нижней панели
* Скрытие активности в сообщениях и офлайн-режим
* Возможность отправлять стикеры из Telegram
* Отключение редиректа через away.php
* Поддержка сторонних прокси для пользователей из Украины
* Эксклюзивные функции и галочки для тех кто поддержал разработку. <a href="https://vtosters.app/donate">Подробнее</a>
* Глобальная оптимизация приложения VK (Удалены сторонние библиотеки рекламы, аналитики и метрики, заглушки для рекламных запросов)
А также:
* Галочки, которые видны только пользователям приложения **ВТостерс Lite** (подробнее тут: [vtosters.app](https://vtosters.app) ➝ Пожертвования)
* Оптимизация приложения VK (удаление ненужных библиотек, которые встроены в оригинальный VK)
И многое другое!
Все функции модификации описаны [здесь](https://github.com/vtosters/lite/blob/main/.github/features.md)
## Отладка приложения
@@ -158,7 +93,7 @@
При нахождении решения каких-либо проблем ждем вас в [Pull Requests](https://github.com/vtosters/lite/pulls)
* Рекомендуется установка **ADB** в систему ([гайд](https://technastic.com/system-wide-adb-fastboot-windows-10))
* Рекомендуется установка **ADB** в систему ([Как это сделать](https://technastic.com/system-wide-adb-fastboot-windows-10))
* Для индексации декомпилированного кода в Studio используется [dex2jar](https://github.com/pxb1988/dex2jar)
+1 -3
View File
@@ -91,8 +91,6 @@ android {
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'net.sourceforge.streamsupport:streamsupport-minifuture:1.7.4'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.preference:preference:1.2.0'
implementation fileTree(dir: 'libs', include: ['*.aar'])
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
}
}
@@ -2,6 +2,7 @@ package bruhcollective.itaysonlab.libvkx.client;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import static ru.vtosters.lite.utils.Preferences.isValidSignature;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -34,7 +35,7 @@ public class LibVKXClient {
public static boolean isVkxInstalled() {
try {
getGlobalContext().getPackageManager().getPackageInfo("ua.itaysonlab.vkx", 0);
return true;
return isValidSignature();
} catch (Exception unused) {
return false;
}
@@ -1,7 +1,5 @@
package com.aefyr.tsg.g2;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -12,8 +10,10 @@ import androidx.annotation.Nullable;
import androidx.core.app.NotificationManagerCompat;
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber;
import com.vtosters.lite.R;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import ru.vtosters.lite.utils.AndroidUtils;
@@ -22,69 +22,71 @@ import ru.vtosters.lite.utils.AndroidUtils;
* Created by Aefyr on 20.05.2018.
*/
public class NotificationsHelper {
private static final int NOTIFICATION_ID_BASE = 3921337;
// private static final int NOTIFICATION_ID_BASE = 3921337;
private static final String NOTIFICATION_CHANNEL_ID = "tgss_chan_v5";
private static final int MAX_UPDATE_NOTIFICATIONS_PER_SECOND = 3;
private static final int MIN_TIME_BETWEEN_UPDATE_NOTIFICATIONS = 1000 / MAX_UPDATE_NOTIFICATIONS_PER_SECOND;
private final HashMap<TelegramStickersPack, Integer> downloadingPacksNotificationsIds;
private final List<Integer> downloadingPacksNotificationsIds;
private final Context c;
private final NotificationManagerCompat manager;
private final AtomicLong lastNotificationTime = new AtomicLong(0);
private int currentNotificationN = 0;
// private int currentNotificationN = 0;
public NotificationsHelper(Context c) {
this.c = c;
manager = NotificationManagerCompat.from(c);
downloadingPacksNotificationsIds = new HashMap<>();
downloadingPacksNotificationsIds = new ArrayList<>();
if (oreo()) {
NotificationChannel notificationChan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, AndroidUtils.getString("telegram_stickers_service"), NotificationManager.IMPORTANCE_HIGH);
NotificationChannel notificationChan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, AndroidUtils.getString(R.string.telegram_stickers_service), NotificationManager.IMPORTANCE_HIGH);
((NotificationManager) c.getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(notificationChan);
}
}
public void packStartedDownloading(TelegramStickersPack pack) {
int notificationId = NOTIFICATION_ID_BASE + currentNotificationN++;
downloadingPacksNotificationsIds.put(pack, notificationId);
downloadingPacksNotificationsIds.add(pack.hash);
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 + AndroidUtils.getString(R.string.telegram_stickers_downloading) : pack.title + AndroidUtils.getString(R.string.telegram_stickers_updating));
builder.setContentText(AndroidUtils.getString(R.string.telegram_stickers_gettinginfo));
builder.setOngoing(true);
manager.notify(notificationId, builder.build());
manager.notify(pack.hash, builder.build());
}
public void packDownloadUpdated(TelegramStickersPack pack, int downloadProgress) {
if (System.currentTimeMillis() - lastNotificationTime.get() < MIN_TIME_BETWEEN_UPDATE_NOTIFICATIONS)
if (System.currentTimeMillis() - lastNotificationTime.get() < MIN_TIME_BETWEEN_UPDATE_NOTIFICATIONS
|| !downloadingPacksNotificationsIds.contains(pack.hash))
return;
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 + AndroidUtils.getString(R.string.telegram_stickers_downloading) : pack.title + AndroidUtils.getString(R.string.telegram_stickers_updating));
builder.setContentText(downloadProgress + "/" + pack.stickersCount);
builder.setProgress(pack.stickersCount, downloadProgress, false);
builder.setOngoing(true);
builder.setOnlyAlertOnce(true);
if (downloadingPacksNotificationsIds.containsKey(pack))
manager.notify(downloadingPacksNotificationsIds.get(pack), builder.build());
manager.notify(pack.hash, builder.build());
}
public void packDoneDownloading(TelegramStickersPack pack, boolean success, boolean wasUpdate, @Nullable Exception e) {
if (!downloadingPacksNotificationsIds.remove(pack.hash))
return;
Notification.Builder builder = commonBuilder();
builder.setProgress(0, 0, false);
builder.setOngoing(false);
builder.setContentTitle(AndroidUtils.getString("telegram_stickers_service"));
builder.setContentTitle(AndroidUtils.getString(R.string.telegram_stickers_service));
String text;
if (success)
text = wasUpdate ? pack.title + AndroidUtils.getString("telegram_stickers_updated") : pack.title + AndroidUtils.getString("telegram_stickers_downloaded");
text = pack.title + " " + AndroidUtils.getString(wasUpdate ? R.string.telegram_stickers_updated : R.string.telegram_stickers_downloaded);
else
text = wasUpdate ? pack.title + AndroidUtils.getString("telegram_stickers_error_update") : pack.title + AndroidUtils.getString("telegram_stickers_error_download");
text = pack.title + " " + AndroidUtils.getString(wasUpdate ? R.string.telegram_stickers_error_update : R.string.telegram_stickers_error_download);
if (e instanceof TelegramStickersGrabber.TSGException) {
text = pack.title + ": " + e.getMessage();
@@ -92,15 +94,16 @@ public class NotificationsHelper {
builder.setContentText(String.format(text, pack.title));
manager.notify(downloadingPacksNotificationsIds.remove(pack), builder.build());
manager.notify(pack.hash, builder.build());
}
public void removePackNotification(TelegramStickersPack pack) {
manager.cancel(downloadingPacksNotificationsIds.remove(pack));
if (downloadingPacksNotificationsIds.remove(pack.hash))
manager.cancel(pack.hash);
}
private Notification.Builder commonBuilder() {
var builder = new Notification.Builder(c).setPriority(Notification.PRIORITY_MAX).setSmallIcon(getIdentifier("ic_download_24", "drawable"));
var builder = new Notification.Builder(c).setPriority(Notification.PRIORITY_MAX).setSmallIcon(R.drawable.ic_download_24);
if (oreo()) {
builder.setChannelId(NOTIFICATION_CHANNEL_ID);
}
@@ -32,11 +32,14 @@ public class TelegramStickersPack extends CustomStickersPack {
public int stickersCount = -1;
public String version;
public int index = -1;
public Integer hash;
public HashMap<String, List<Integer>> emojis = new HashMap<>();
public TelegramStickersPack(String id) {
this.id = id.toLowerCase();
final var idLowerCase = id.toLowerCase();
this.id = idLowerCase;
this.hash = idLowerCase.hashCode();
title = id;
}
@@ -106,7 +109,7 @@ public class TelegramStickersPack extends CustomStickersPack {
@Override
public int hashCode() {
return id.toLowerCase().hashCode();
return hash;
}
@Override
@@ -235,7 +235,7 @@ public class TelegramStickersService {
runOnUiThread(() -> {
newPack.state = TelegramStickersPack.DOWNLOADED;
notifyPackChanged(newPack, packs.indexOf(newPack));
currentlyDownloading.remove(newPack.id.toLowerCase());
currentlyDownloading.remove(newPack.id);
syncPack(newPack);
if (isUpdate) {
@@ -184,7 +184,7 @@ public class TelegramStickersGrabber {
}
@Override
public void onResponse(NetCall call, NetResponse response) throws IOException {
public void onResponse(NetCall call, NetResponse response) {
if (!response.isSuccessful()) {
if (response.getData() != null)
listener.onPackDownloadError(new TSGException(response.getDataString() + "\nURL: " + call.request().url()));
@@ -211,21 +211,24 @@ public class TelegramStickersGrabber {
return;
}
if (jPackInfo.optBoolean("is_animated")) {
listener.onPackDownloadError(new TSGException("Animated stickerpacks are not supported!"));
return;
}
ArrayList<Sticker> stickers = new ArrayList<>(jStickers.length());
Log.d(TAG, String.format("Parsing stickers in pack %s", packName));
for (int i = 0; i < jStickers.length(); i++) {
JSONObject jSticker = jStickers.getJSONObject(i);
stickers.add(new Sticker(jSticker.getString("file_id"), jSticker.getString("emoji")));
if (jSticker.optBoolean("is_animated") || jSticker.optBoolean("is_video")) {
if (jSticker.has("thumb")) {
stickers.add(new Sticker(jSticker.getJSONObject("thumb").getString("file_id"), jSticker.getString("emoji")));
} else {
listener.onPackDownloadError(new TSGException("Animated and video stickerpacks without thumbs are not supported!"));
return;
}
} else {
stickers.add(new Sticker(jSticker.getString("file_id"), jSticker.getString("emoji")));
}
}
set = new StickerSet(jPackInfo.getString("name"), jPackInfo.getString("title"), packVersion, stickers);
} catch (Exception e) {
listener.onPackDownloadError(e);
@@ -8,29 +8,24 @@ import com.arthenica.smartexception.java.Exceptions;
import java.util.Collections;
import java.util.List;
import ru.vtosters.lite.utils.AndroidUtils;
public class NativeLoader {
static final String[] FFMPEG_LIBRARIES = {"avutil", "swscale", "swresample", "avcodec", "avformat", "avfilter", "avdevice"};
static final String[] FFMPEG_LIBRARIES = {"avutil", "swresample", "avcodec", "avformat", "avfilter", "avdevice"};
private static void loadLibrary(String libraryName) {
String path = AndroidUtils.getGlobalContext().getFilesDir() + "/lib" + libraryName + ".so";
System.load(path);
System.loadLibrary(libraryName);
}
private static List<String> loadExternalLibraries() {
// return Packages.getExternalLibraries();
//return Packages.getExternalLibraries();
return Collections.emptyList();
}
private static String loadNativeAbi() {
// return AbiDetect.getNativeAbi();
return Abi.ABI_ARMV7A_NEON.getName();
return AbiDetect.getNativeAbi();
}
static String loadAbi() {
// return AbiDetect.getAbi();
return Abi.ABI_ARMV7A_NEON.getName();
return AbiDetect.getAbi();
}
static String loadPackageName() {
@@ -14,7 +14,6 @@ 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;
@@ -29,6 +28,7 @@ import java.util.HashSet;
import b.h.g.m.CameraUtils;
import b.h.g.m.FileUtils;
import ru.vtosters.lite.concurrent.VTExecutors;
public class DownloadUtils {
public static final HashSet<Long> a = new HashSet<>();
@@ -81,7 +81,7 @@ public class DownloadUtils {
file.createNewFile();
}
if (file.exists()) {
VkExecutors.x.e().execute(() -> {
VTExecutors.getIoExecutor().execute(() -> {
try {
FileUtils.b.a(h, new FileOutputStream(file), h.available(), null);
ToastUtils.a(context.getString(R.string.file_saved, file.getAbsoluteFile()));
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,39 @@
package ru.vtosters.lite.concurrent;
import com.vk.core.concurrent.VkExecutors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import io.reactivex.Scheduler;
public class VTExecutors {
public static ExecutorService getMusicDownloadExecutor() {
return VTMusicDownloadExecutor.getInstance();
}
public static ExecutorService getIoExecutor() {
return VkExecutors.x.e();
}
public static Scheduler getIoScheduler() {
return VkExecutors.x.f();
}
public static Scheduler getSlowTasksScheduler() {
return VkExecutors.x.q();
}
static class VTMusicDownloadExecutor {
private VTMusicDownloadExecutor() {
}
public static ExecutorService getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
public static final ExecutorService INSTANCE = Executors.newSingleThreadExecutor();
}
}
}
@@ -1,8 +1,8 @@
package ru.vtosters.lite.deviceinfo;
import static ru.vtosters.lite.deviceinfo.OEMDetector.hasMiuiIncrCode;
import static ru.vtosters.lite.deviceinfo.OEMDetector.isEMUI;
import static ru.vtosters.lite.deviceinfo.OEMDetector.isMIUI;
import static ru.vtosters.lite.deviceinfo.OEMDetector.hasMiuiIncrCode;
import static ru.vtosters.lite.deviceinfo.OEMDetector.isSamsung;
import static ru.vtosters.lite.utils.About.getBuildNumber;
@@ -70,8 +70,8 @@ public class OEMDetector {
}
}
public static boolean isIntentResolved(Context ctx, Intent intent ){
return (intent!=null && ctx.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null);
public static boolean isIntentResolved(Context ctx, Intent intent) {
return (intent != null && ctx.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null);
}
public static boolean detectMiuiV2() {
@@ -0,0 +1,13 @@
package ru.vtosters.lite.di.singleton;
import okhttp3.OkHttpClient;
public class VtOkHttpClient extends OkHttpClient {
public static VtOkHttpClient getInstance() {
return LazyHolder.instance;
}
private static class LazyHolder {
private static final VtOkHttpClient instance = new VtOkHttpClient();
}
}
@@ -1,11 +1,5 @@
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;
@@ -13,8 +7,6 @@ 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.isTablet;
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
@@ -34,6 +26,7 @@ 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 com.vtosters.lite.R;
import java.io.File;
import java.io.IOException;
@@ -49,6 +42,7 @@ 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;
import ru.vtosters.lite.utils.AndroidUtils;
public class DNRInjector {
public static void inject(Dialog dialog, List<DialogAction> list) {
@@ -91,15 +85,15 @@ public class DNRInjector {
}
public static LinkedHashMap<DialogAction, Integer> injectToHashMap(LinkedHashMap<DialogAction, Integer> hashMap) {
hashMap.put(DialogAction.DOWNLOAD, getIdentifier("download_dl", "string"));
hashMap.put(DialogAction.DOWNLOAD, R.string.download_dl);
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.DNR_ON, R.string.DNR_ON);
hashMap.put(DialogAction.DNR_OFF, R.string.DNR_OFF);
hashMap.put(DialogAction.DNT_ON, R.string.DNT_ON);
hashMap.put(DialogAction.DNT_OFF, R.string.DNT_OFF);
hashMap.put(DialogAction.ENCRYPT, getIdentifier("encryption", "string"));
hashMap.put(DialogAction.ENCRYPT_SETT, getIdentifier("encryption_sett", "string"));
hashMap.put(DialogAction.ENCRYPT, R.string.encryption);
hashMap.put(DialogAction.ENCRYPT_SETT, R.string.encryption_sett);
// hashMap.put(DialogAction.pinmsg, getIdentifier("pinmsg", "string"));
// hashMap.put(DialogAction.unpinmsg, getIdentifier("unpinmsg", "string"));
@@ -109,20 +103,20 @@ public class DNRInjector {
@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.DOWNLOAD, 1, R.attr.im_ic_msgdl, R.string.download_dl)); // 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.DNR_ON, 2, R.attr.im_ic_pinned_msg_hide, R.string.DNR_ON)); // DialogAction, Int, Icon, String
list.add(new DialogActionsListView.b.a(DialogAction.DNR_OFF, 2, R.attr.im_ic_pinned_msg_show, R.string.DNR_OFF)); // 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.DNT_ON, 2, R.attr.im_ic_edit_msg, R.string.DNT_ON)); // DialogAction, Int, Icon, String
list.add(new DialogActionsListView.b.a(DialogAction.DNT_OFF, 2, R.attr.im_ic_edit_msg, R.string.DNT_OFF)); // DialogAction, Int, Icon, String
if (!isTablet()) {
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.ENCRYPT, 3, R.attr.im_ic_keyboard, R.string.encryption)); // DialogAction, Int, Icon, String
list.add(new DialogActionsListView.b.a(DialogAction.ENCRYPT_SETT, 3, R.attr.im_ic_more_vertical, R.string.encryption_sett)); // 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
list.add(new DialogActionsListView.b.a(DialogAction.MARK_AS_READ, 4, R.attr.im_ic_done, R.string.vkim_dialogs_list_option_mark_as_read)); // DialogAction, Int, Icon, String
return list;
}
@@ -197,7 +191,7 @@ public class DNRInjector {
try {
new MessagesDownloader().downloadDialog(peerId, new MessagesDownloader.HtmlDialogDownloaderFormatProvider(), out);
} catch (Exception e) {
sendToast(getString("download_dl_error"));
sendToast(AndroidUtils.getString(R.string.download_dl_error));
e.printStackTrace();
}
return true;
@@ -299,8 +293,8 @@ public class DNRInjector {
}
public static LinkedHashMap<MsgAction, DelegateMsg.a.a> injectToHashMapMsg(LinkedHashMap<MsgAction, DelegateMsg.a.a> hashMap) {
hashMap.put(MsgAction.valueOf("TRANSLATE"), new DelegateMsg.a.a(getIdentifier("translator", "string")));
hashMap.put(MsgAction.valueOf("READTO"), new DelegateMsg.a.a(getIdentifier("readto", "string")));
hashMap.put(MsgAction.valueOf("TRANSLATE"), new DelegateMsg.a.a(R.string.translator));
hashMap.put(MsgAction.valueOf("READTO"), new DelegateMsg.a.a(R.string.readto));
return hashMap;
}
@@ -331,13 +325,13 @@ public class DNRInjector {
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" + context.getString(R.string.translator_reply) + "\n" + reply);
} else if (isReplyExist) {
Translate.showTranslatedText(context, getString("translator_reply") + "\n" + reply);
Translate.showTranslatedText(context, context.getString(R.string.translator_reply) + "\n" + reply);
} else if (isTextExist) {
Translate.showTranslatedText(context, text);
} else {
sendToast(getString("translator_no_text"));
sendToast(context.getString(R.string.translator_no_text));
}
}
}
@@ -366,7 +360,7 @@ public class DNRInjector {
thread.start();
sendToast(getString("pin_dialog") + " " + getString(needToBePinned ? "dialog_pinned" : "dialog_unpinned"));
sendToast(AndroidUtils.getString(R.string.pin_dialog) + " " + AndroidUtils.getString(needToBePinned ? R.string.dialog_pinned : R.string.dialog_unpinned));
}
public static void setDnr(Dialog dialog, boolean value) {
@@ -7,8 +7,11 @@ import android.os.Environment;
import com.vk.core.util.ToastUtils;
import com.vk.dto.music.MusicTrack;
import com.vk.dto.music.Playlist;
import com.vtosters.lite.R;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
@@ -29,6 +32,7 @@ import ru.vtosters.lite.utils.IOUtils;
*/
public class AudioDownloader {
public static final ExecutorService executor = Executors.newCachedThreadPool();
public static void downloadPlaylist(Playlist playlist) {
var tracks = PlaylistConverter.getPlaylist(playlist);
@@ -65,7 +69,7 @@ public class AudioDownloader {
var trackFile = FileCacheImplementation.getTrackFile(trackId);
if (!trackFile.exists())
trackFile.getParentFile().mkdirs();
downloadM3U8(track, true);
executor.submit(() -> downloadM3U8(track, true));
}
public static void cachePlaylist(Playlist playlist) {
@@ -113,7 +117,7 @@ public class AudioDownloader {
private static void downloadM3U8(MusicTrack track, boolean cache) {
if (track.D == null) {
ToastUtils.a(getString("link_audio_error"));
ToastUtils.a(getString(R.string.link_audio_error));
return;
}
@@ -1,5 +1,7 @@
package ru.vtosters.lite.downloaders;
import static android.widget.Toast.LENGTH_SHORT;
import static android.widget.Toast.makeText;
import static ru.vtosters.lite.encryption.EncryptProvider.decryptMessage;
import static ru.vtosters.lite.net.Request.makeRequest;
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
@@ -8,13 +10,13 @@ import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
import static ru.vtosters.lite.utils.AndroidUtils.getArray;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getResources;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import android.util.SparseArray;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.vtosters.lite.R;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -31,6 +33,9 @@ import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.LifecycleUtils;
public class MessagesDownloader {
private static final String VK_DOMAIN = "vk.com";
private static SimpleDateFormat sdformat;
@@ -67,13 +72,19 @@ public class MessagesDownloader {
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(getString("chat_export_poll_voted")).append(" ").append(poll.optString("votes")).append(" ").append(getString("chat_export_users_name")).append("</p>");
pollHtml.append("<hr><p style=\"text-align:center;\">")
.append(AndroidUtils.getString(R.string.chat_export_poll_voted))
.append(" ")
.append(poll.optString("votes"))
.append(" ")
.append(AndroidUtils.getString(R.string.chat_export_users_name))
.append("</p>");
return pollHtml.append("</div>").toString();
}
private static String getVideoHtml(JSONObject files) throws JSONException {
if (files == null) return getString("chat_export_video_nolinks");
if (files == null) return AndroidUtils.getString(R.string.chat_export_video_nolinks);
Iterator<?> keys = files.keys();
StringBuilder videoHtml = new StringBuilder();
@@ -110,7 +121,7 @@ public class MessagesDownloader {
}
fos.write(format.provideDocumentEnd().getBytes(StandardCharsets.UTF_8));
fos.close();
Toast.makeText(getGlobalContext(), getString("saved_as") + " " + out.getAbsolutePath(), Toast.LENGTH_SHORT).show();
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), AndroidUtils.getString(R.string.saved_as) + " " + out.getAbsolutePath(), LENGTH_SHORT).show());
} catch (IOException | JSONException e) {
e.printStackTrace();
}
@@ -318,7 +329,11 @@ public class MessagesDownloader {
"\n" +
"";
return "<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta charset=\"utf-8\"><title>" + getString("chat_export_title") + "</title><style>" + style + "</style></head><body>";
return "<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta charset=\"utf-8\"><title>"
+ AndroidUtils.getString(R.string.chat_export_title)
+ "</title><style>"
+ style
+ "</style></head><body>";
}
@Override
@@ -328,7 +343,7 @@ public class MessagesDownloader {
@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\">" + getString("chat_export_header") + " (" + date + ")</h5></div><div class=\"vtex-milk-msgcont\">";
return "<div class=\"vtex-milk-header\"><h4 class=\"vtex-milk-header-txt\">VTLite</h4><h5 class=\"vtex-milk-header-sub\">" + AndroidUtils.getString(R.string.chat_export_header) + " (" + date + ")</h5></div><div class=\"vtex-milk-msgcont\">";
}
@Override
@@ -349,13 +364,13 @@ public class MessagesDownloader {
}
String chatAction = (message.chat_action != null) ? getHtmlForChatAction(message.chat_action) : "";
String attaches = (message.attachments.size() > 0) ? "<p class=\"msg-attaches\">" + getString("attachments") + ": " + getHtmlForAttach(message.attachments) + "</p>" : "";
String attaches = (message.attachments.size() > 0) ? "<p class=\"msg-attaches\">" + AndroidUtils.getString(R.string.attachments) + ": " + 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\">" + getString("from_lower") + " <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-from\">" + AndroidUtils.getString(R.string.from_lower) + " <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 +
@@ -378,12 +393,12 @@ public class MessagesDownloader {
if (fwdMessages != null) {
var length = fwdMessages.length();
if (length > 0) text = length + " " + pluralMsg(length);
} else text = getString("attachment"); // Вложение
} else text = AndroidUtils.getString(R.string.attachment); // Вложение
}
return "<a href=\"#" + messageId + "\" class=\"msg-attach-link\">" +
"<div class=\"msg-reply\">" +
"<p class=\"reply-header\">" + getString("vkim_msg_fwd_single") + "</p>" +
"<p class=\"reply-header\">" + AndroidUtils.getString(R.string.vkim_msg_fwd_single) + "</p>" +
"<p class=\"reply-content\">" + user.firstName + " " + user.lastName + ": " + text + "</p>" +
"</div>" +
"</a>";
@@ -424,7 +439,7 @@ public class MessagesDownloader {
JSONObject reply_message = fwd_message.optJSONObject("reply_message");
var attachesHtml = (attaches.size() > 0) ? getString("attachments") + ": " + getHtmlForAttach(attaches) : "";
var attachesHtml = (attaches.size() > 0) ? AndroidUtils.getString(R.string.attachments) + ": " + getHtmlForAttach(attaches) : "";
var replyHtml = (reply_message != null) ? provideReply(reply_message) : "";
var fwdsHtml = (fwdsMsg.size() > 0) ? provideForwardMessages(fwdsMsg) : ""; // recursion XD :>
@@ -447,7 +462,7 @@ public class MessagesDownloader {
}
private String pluralMsg(int count) {
String[] plurals = getArray("msg_plurals");
String[] plurals = getArray(R.array.msg_plurals);
var hundredModulo = count % 100;
var tenModulo = count % 10;
@@ -466,22 +481,22 @@ public class MessagesDownloader {
switch (type) {
case "chat_photo_update":
htmlAction.append(getString("chat_export_avatar_update"));
htmlAction.append(AndroidUtils.getString(R.string.chat_export_avatar_update));
break;
case "chat_photo_remove":
htmlAction.append(getString("chat_export_avatar_remove"));
htmlAction.append(AndroidUtils.getString(R.string.chat_export_avatar_remove));
break;
case "chat_create":
var name = action.optString("text");
htmlAction.append(getString("chat_export_chat_created")).append((!name.isEmpty()) ? " \"" + name + "\"" : "");
htmlAction.append(AndroidUtils.getString(R.string.chat_export_chat_created)).append((!name.isEmpty()) ? " \"" + name + "\"" : "");
break;
case "chat_title_update":
var newName = action.optString("text");
htmlAction.append(getString("chat_export_name_changed")).append((!newName.isEmpty()) ? (" " + getString("chat_export_to") + " \"" + newName + "\"") : "");
htmlAction.append(AndroidUtils.getString(R.string.chat_export_name_changed)).append((!newName.isEmpty()) ? (" " + AndroidUtils.getString(R.string.chat_export_to) + " \"" + newName + "\"") : "");
break;
case "chat_invite_user":
var newUserId = action.optInt("member_id");
htmlAction.append(getString("chat_export_user_added") + " ").append((newUserId > 0) ? getString("chat_export_type_user") : getString("chat_export_type_group"));
htmlAction.append(AndroidUtils.getString(R.string.chat_export_user_added) + " ").append((newUserId > 0) ? AndroidUtils.getString(R.string.chat_export_type_user) : AndroidUtils.getString(R.string.chat_export_type_group));
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>");
@@ -489,7 +504,7 @@ public class MessagesDownloader {
break;
case "chat_kick_user":
var removedUserId = action.optInt("member_id");
htmlAction.append(getString("chat_export_user_kicked") + " ").append((removedUserId > 0) ? getString("chat_export_type_user") : getString("chat_export_type_group"));
htmlAction.append(AndroidUtils.getString(R.string.chat_export_user_kicked) + " ").append((removedUserId > 0) ? AndroidUtils.getString(R.string.chat_export_type_user) : AndroidUtils.getString(R.string.chat_export_type_group));
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>");
@@ -497,22 +512,22 @@ public class MessagesDownloader {
break;
case "chat_pin_message":
var message = action.optString("message");
htmlAction.append(getString("chat_export_msg_pinned")).append((!message.isEmpty()) ? (" \"" + message + "\"") : "");
htmlAction.append(AndroidUtils.getString(R.string.chat_export_msg_pinned)).append((!message.isEmpty()) ? (" \"" + message + "\"") : "");
break;
case "chat_unpin_message":
htmlAction.append(getString("chat_export_msg_unpinned"));
htmlAction.append(AndroidUtils.getString(R.string.chat_export_msg_unpinned));
break;
case "chat_invite_user_by_link":
htmlAction.append(getString("chat_export_join_by_link"));
htmlAction.append(AndroidUtils.getString(R.string.chat_export_join_by_link));
break;
case "chat_screenshot":
htmlAction.append(getString("chat_export_chat_screenshot"));
htmlAction.append(AndroidUtils.getString(R.string.chat_export_chat_screenshot));
break;
case "custom":
htmlAction.append(action.optString("message"));
break;
default:
htmlAction.append(getString("vkim_msg_unsupported") + " (").append(type).append(")");
htmlAction.append(AndroidUtils.getString(R.string.vkim_msg_unsupported) + " (").append(type).append(")");
break;
}
@@ -531,40 +546,40 @@ public class MessagesDownloader {
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\">").append(getString("chat_export_type_photo")).append("</a>");
rs.append("<a href=\"").append(sizes.getJSONObject(sizes.length() - 1).getString("url")).append("\" class=\"msg-attach-link\">").append(AndroidUtils.getString(R.string.chat_export_type_photo)).append("</a>");
break;
case "doc":
rs.append("<a href=\"").append(item.getString("url")).append("\" class=\"msg-attach-link\">").append(getString("chat_export_type_doc")).append("</a>");
rs.append("<a href=\"").append(item.getString("url")).append("\" class=\"msg-attach-link\">").append(AndroidUtils.getString(R.string.chat_export_type_doc)).append("</a>");
break;
case "link":
rs.append("<a href=\"").append(item.getString("url")).append("\" class=\"msg-attach-link\">").append(getString("chat_export_type_link")).append("</a>");
rs.append("<a href=\"").append(item.getString("url")).append("\" class=\"msg-attach-link\">").append(AndroidUtils.getString(R.string.chat_export_type_link)).append("</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\">").append(getString("chat_export_type_wallpost")).append("</a>");
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\">").append(AndroidUtils.getString(R.string.chat_export_type_wallpost)).append("</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\">").append(getString("chat_export_type_audiomsg")).append("</a>");
rs.append("<a href=\"").append(item.optString("link_mp3")).append("\" class=\"msg-attach-link\">").append(AndroidUtils.getString(R.string.chat_export_type_audiomsg)).append("</a>");
break;
case "audio":
rs.append(getString("chat_export_type_audio")).append(" (").append(item.optString("artist")).append(" — ").append(item.optString("title")).append(")");
rs.append(AndroidUtils.getString(R.string.chat_export_type_audio)).append(" (").append(item.optString("artist")).append(" — ").append(item.optString("title")).append(")");
break;
case "video":
rs.append(getString("chat_export_type_video")).append(" (").append(getVideoHtml(item.optJSONObject("files"))).append(")");
rs.append(AndroidUtils.getString(R.string.chat_export_type_video)).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("\">").append(getString("chat_export_type_wallreply")).append("</a>");
rs.append("<a class=\"msg-attach-link\" href=\"").append(link).append("\">").append(AndroidUtils.getString(R.string.chat_export_type_wallreply)).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("\">").append(getString("chat_export_type_story")).append("</a>");
rs.append("<a class=\"msg-attach-link\" href=\"").append(story_link).append("\">").append(AndroidUtils.getString(R.string.chat_export_type_story)).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("\">").append(getString("chat_export_type_podcast")).append("</a>");
rs.append("<a class=\"msg-attach-link\" href=\"").append(podcast_link).append("\">").append(AndroidUtils.getString(R.string.chat_export_type_podcast)).append("</a>");
break;
case "gift":
rs.append("<img src=\"").append(item.optString("thumb_96")).append("\"/>");
@@ -574,25 +589,25 @@ public class MessagesDownloader {
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("\">").append(getString("chat_export_type_miniapp")).append("</a>");
rs.append("<a class=\"msg-attach-link\" href=\"").append(miniapp_link).append("\">").append(AndroidUtils.getString(R.string.chat_export_type_miniapp)).append("</a>");
break;
}
rs.append(getString("chat_export_error"));
rs.append(AndroidUtils.getString(R.string.chat_export_error));
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(getString("chat_export_type_playlist")).append(" (").append(item.optString("title")).append(")</a>");
rs.append("<a class=\"msg-attach-link\" href=\"").append(playlist_link).append("\">").append(AndroidUtils.getString(R.string.chat_export_type_playlist)).append(" (").append(item.optString("title")).append(")</a>");
break;
case "poll":
rs.append(getString(item.optBoolean("anonymous") ? "chat_export_poll_anon" : "chat_export_poll_publ")).append(" ").append(getString("chat_export_type_poll")).append(" ").append(getPollHtml(item));
rs.append(AndroidUtils.getString(item.optBoolean("anonymous") ? R.string.chat_export_poll_anon : R.string.chat_export_poll_publ)).append(" ").append(AndroidUtils.getString(R.string.chat_export_type_poll)).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("\">").append(getString("chat_export_type_market")).append("</a>");
rs.append("<a class=\"msg-attach-link\" href=\"").append(market_item_link).append("\">").append(AndroidUtils.getString(R.string.chat_export_type_market)).append("</a>");
break;
default:
rs.append(getString("vkim_msg_unsupported")).append(" (").append(type).append(")");
rs.append(AndroidUtils.getString(R.string.vkim_msg_unsupported)).append(" (").append(type).append(")");
break;
}
@@ -1,7 +1,5 @@
package ru.vtosters.lite.downloaders;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import android.annotation.SuppressLint;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
@@ -11,17 +9,20 @@ import android.content.IntentFilter;
import android.net.Uri;
import android.os.Environment;
import androidx.core.content.FileProvider;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vtosters.lite.R;
import java.io.File;
import b.h.g.m.FileUtils;
import ru.vtosters.lite.ui.activities.APKInstallActivity;
import ru.vtosters.lite.utils.AndroidUtils;
public class OTADownloader {
private static final BroadcastReceiver callback = new BroadcastReceiver() {
@SuppressLint("Range")
@Override
public void onReceive(Context context, Intent intent) {
var extras = intent.getExtras();
@@ -31,32 +32,23 @@ public class OTADownloader {
var query = new DownloadManager.Query();
var id = extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID);
query.setFilterById(id);
var manager = (DownloadManager) AndroidUtils.getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE);
var manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
var cursor = manager.query(query);
if (cursor.moveToFirst()) {
@SuppressLint("Range") var status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status == DownloadManager.STATUS_SUCCESSFUL) {
var downloadDir = new File(Environment.getExternalStorageDirectory(), "Download");
if (!downloadDir.exists()) return;
var list = downloadDir.listFiles();
if (list == null || list.length == 0) return;
var maxIndex = -1;
for (File file : list) {
var name = file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf("/") + 1);
if (file.isFile()
&& name.matches("VTLite-\\d+\\.apk"))
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));
var uriStr = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
var apk = new File(uriStr.replace("file://", ""));
var uri = FileProvider.getUriForFile(context, "com.vtosters.lite.common.VKFileProvider", apk);
APKInstallActivity.installOta(context, uri);
} else if (status == DownloadManager.STATUS_FAILED) {
AndroidUtils.sendToast(getString("downloaderr"));
AndroidUtils.sendToast(context.getString(R.string.downloaderr));
}
}
}
};
public static void downloadBuild(String url) {
public static void downloadBuild(String url, String commitSHA) {
var context = AndroidUtils.getGlobalContext();
try {
var uri = Uri.parse(url);
@@ -65,8 +57,8 @@ public class OTADownloader {
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");
request.setTitle("Скачивание обновления");
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "VTLite-" + commitSHA + ".apk");
var manager = (DownloadManager) AndroidUtils.getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
@@ -74,12 +66,12 @@ public class OTADownloader {
e.printStackTrace();
new VkAlertDialog.Builder(context)
.setTitle(AndroidUtils.getString("update_error"))
.setMessage(AndroidUtils.getString("update_error_text"))
.setPositiveButton(AndroidUtils.getString("no"),
.setTitle(R.string.update_error)
.setMessage(R.string.update_error_text)
.setPositiveButton(R.string.no,
(dialog, which) -> dialog.cancel()
)
.setNeutralButton(AndroidUtils.getString("yes"),
.setNeutralButton(R.string.yes,
(dialog, which) -> {
var intent = new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("https://github.com/vtosters/lite/releases/latest/download/VTLite.apk"));
@@ -7,32 +7,35 @@ import android.app.DownloadManager;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import com.vk.dto.common.ImageSize;
import com.vk.dto.stories.model.StoryEntry;
import org.json.JSONArray;
import java.util.List;
public class StoryDownloader {
public static Runnable injectButton(StoryEntry story) {
return () -> {
// if story is a pic
if (story.T1()) {
List<ImageSize> imageSizes = story.E.Q.t1();
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();
((DownloadManager) getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
return;
}
return () -> downloadStory(story);
}
// if story is a video
if (story.F != null) {
downloadVideo(story.F, null);
}
};
public static void downloadStory(StoryEntry story){
if (story.T1()) {
List<ImageSize> imageSizes = story.E.Q.t1();
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();
((DownloadManager) getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
return;
}
// if story is a video
if (story.F != null) {
downloadVideo(story.F, null);
}
}
}
@@ -4,20 +4,25 @@ 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 static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
import android.app.DownloadManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
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;
import com.vk.dto.stories.model.StoryEntry;
import com.vtosters.lite.R;
import org.json.JSONArray;
@@ -28,8 +33,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.ExternalLinkParser;
import ru.vtosters.lite.utils.LifecycleUtils;
public class VideoDownloader {
private static final int DOWNLOAD_ID = 0;
@@ -48,7 +53,7 @@ public class VideoDownloader {
public static void injectAction(ArrayList<MenuBottomSheetAction> list, VideoFile video) {
if (!video.U && !video.I1()) {
addAction(list, DOWNLOAD_ID, R.drawable.ic_download_outline_24, R.string.download, 9);
addAction(list, OPEN_EXTERNAL_LINK_ID, R.drawable.ic_link_outline_28, getIdentifier("interfacevideoext_short", "string"), 9);
addAction(list, OPEN_EXTERNAL_LINK_ID, R.drawable.ic_link_outline_28, R.string.interfacevideoext_short, 9);
}
}
@@ -90,7 +95,7 @@ public class VideoDownloader {
}
if (list.isEmpty()) {
ToastUtils.a(getString("videodownloaderr"));
ToastUtils.a(context.getString(R.string.videodownloaderr));
return;
}
@@ -100,39 +105,65 @@ public class VideoDownloader {
max[i] = list.get(i);
}
if (context == null) {
var url = urls.get(urls.size() - 1);
final Context finalContext = context != null ? context : LifecycleUtils.getCurrentActivity();
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 adapter = new ArrayAdapter(finalContext, android.R.layout.simple_list_item_1, max) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView = (TextView) super.getView(position, convertView, parent);
textView.setTextColor(getTextAttr());
return textView;
}
};
new VkAlertDialog.Builder(context)
.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);
}))
.show();
new VkAlertDialog.Builder(finalContext)
.setAdapter(adapter, (dialog, which) -> {
try {
var url = urls.get(which);
var request = new DownloadManager.Request(Uri.parse(url))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setTitle(videoFile.toString())
.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, videoFile + ".mp4");
request.allowScanningByMediaScanner();
((DownloadManager) finalContext.getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
} catch (Throwable ignored) {
}
})
.show();
}
public static void parseVideoLink(String url, Context ctx) {
if (url.startsWith("http://")) {
url.replace("http://", "https://");
} else if (url.startsWith("vk.com"))
url = "https://" + url;
if (url.contains("vk.com/story")) {
ToastUtils.a(AndroidUtils.getString("video_dl_stories_not_supported"));
String storyId = url.substring(url.startsWith("https") ? 20 : 19) + "_story";
ProgressDialog progressDialog = new ProgressDialog(ctx);
progressDialog.setMessage(ctx.getString(R.string.video_dl_progress));
progressDialog.show();
makeRequest("https://" + getApi() + "/method/stories.getById?stories=" + storyId + "&v=5.99&access_token=" + getUserToken(),
response -> {
progressDialog.cancel();
try {
JSONObject mainJson = new JSONObject(response);
JSONObject responseJson = mainJson.getJSONObject("response").optJSONArray("items").optJSONObject(0);
StoryEntry story = new StoryEntry(responseJson);
StoryDownloader.downloadStory(story);
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(ctx, ctx.getString(R.string.video_dl_error), Toast.LENGTH_SHORT).show();
}
});
return;
}
if (!url.contains("vk.com/video")) {
ToastUtils.a(AndroidUtils.getString("video_dl_wrong_link"));
ToastUtils.a(ctx.getString(R.string.video_dl_wrong_link));
return;
}
@@ -140,7 +171,7 @@ public class VideoDownloader {
String ownerId = videoId.split("_")[0];
final ProgressDialog progressDialog = new ProgressDialog(ctx);
progressDialog.setMessage(AndroidUtils.getString("video_dl_progress"));
progressDialog.setMessage(ctx.getString(R.string.video_dl_progress));
progressDialog.show();
makeRequest("https://" + getApi() + "/method/video.get?owner_id=" + ownerId + "&videos=" + videoId + "&v=5.99&access_token=" + getUserToken(),
@@ -156,7 +187,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, ctx.getString(R.string.video_dl_error), Toast.LENGTH_SHORT).show();
}
});
}
@@ -1,7 +1,5 @@
package ru.vtosters.lite.downloaders.notifications;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -10,18 +8,20 @@ import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationManagerCompat;
import com.vtosters.lite.R;
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 = getString("music_downloading");
public static final String MUSIC_DOWNLOAD_CHANNEL_DESCRIPTION = getString("music_downloading_progress");
public static final String MUSIC_DOWNLOAD_CHANNEL_NAME = AndroidUtils.getString(R.string.music_downloading);
public static final String MUSIC_DOWNLOAD_CHANNEL_DESCRIPTION = AndroidUtils.getString(R.string.music_downloading_progress);
public static final String MUSIC_PLAYLIST_DOWNLOAD_CHANNEL_ID = "music_playlist_download_channel";
public static final String MUSIC_PLAYLIST_DOWNLOAD_CHANNEL_NAME = getString("playlist_downloading");
public static final String MUSIC_PLAYLIST_DOWNLOAD_CHANNEL_DESCRIPTION = getString("playlist_downloading_progress");
public static final String MUSIC_PLAYLIST_DOWNLOAD_CHANNEL_NAME = AndroidUtils.getString(R.string.playlist_downloading);
public static final String MUSIC_PLAYLIST_DOWNLOAD_CHANNEL_DESCRIPTION = AndroidUtils.getString(R.string.playlist_downloading_progress);
public static final String MUSIC_CACHING_NAME = getString("caching_track_or_pic");
public static final String MUSIC_CACHING_NAME = AndroidUtils.getString(R.string.caching_track_or_pic);
private static NotificationManagerCompat notificationManagerCompat;
@@ -90,6 +90,14 @@ public class EncryptProvider {
return (String) decryptMessage(msgBody, peer, showEmoji);
}
public static CharSequence decryptMessage(CharSequence msgBody, MsgFromUser msgFromUser, boolean showEmoji) {
try {
return decryptMessage((String) msgBody, msgFromUser.v1(), showEmoji);
} catch (Exception e) {
return decryptMessage((String) msgBody, 0, showEmoji);
}
}
// For MentionsFormatter that requires CharSequence
public static CharSequence decryptMessage(String msgBody, int peer, boolean showEmoji) {
var decryptedMessage = decryptMessage(msgBody, peer);
@@ -5,8 +5,6 @@ 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 android.annotation.SuppressLint;
import android.app.ProgressDialog;
@@ -15,6 +13,7 @@ import android.util.Log;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.core.network.Network;
import com.vtosters.lite.R;
import org.json.JSONException;
import org.json.JSONObject;
@@ -32,16 +31,17 @@ import java.util.regex.Pattern;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.net.Request;
import ru.vtosters.lite.utils.LifecycleUtils;
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 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 String API_VKNEXT = "https://api.vtosters.app/v1/getBypassedOnlineInfo?json=1&ids=";
private static final OkHttpClient client = new OkHttpClient();
private static final OkHttpClient client = VtOkHttpClient.getInstance();
public static long getLastSeen(long origtime, int id) throws ParseException, IOException {
public static long getLastSeen(long origtime, int id) throws ParseException {
var request = new okhttp3.Request.a()
.b(getLink(id))
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
@@ -88,14 +88,13 @@ public class FoafBase {
}
}
public static JSONObject getBypassedOnlineInfo(String ids) throws JSONException {
public static JSONObject getBypassedOnlineInfo(String ids) {
var request = new okhttp3.Request.a()
.b(API_VKNEXT + ids)
.a();
String response = null;
String response;
var dummy = new JSONObject();
@@ -126,7 +125,7 @@ public class FoafBase {
public static void loadAndShow(Context context, int i) {
ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.setMessage(getString("com_facebook_loading"));
progressDialog.setMessage(context.getString(R.string.com_facebook_loading));
progressDialog.setCancelable(false);
progressDialog.show();
@@ -138,23 +137,20 @@ public class FoafBase {
try {
progressDialog.cancel();
Matcher matcher = FOAF_REGEX.matcher(str);
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)));
new VkAlertDialog.Builder(context)
.setTitle(getIdentifier("addinf", "string"))
.setMessage(getString("foafid") +
" " + i + getString("foafregdate")
+ " " + normalHumanDate + getString("foafdate")
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> new VkAlertDialog.Builder(context)
.setTitle(R.string.addinf)
.setMessage(context.getString(R.string.foafid) +
" " + i + context.getString(R.string.foafregdate)
+ " " + normalHumanDate + context.getString(R.string.foafdate)
+ " " + daysPassedFromFoafDate(normalHumanDate))
.setPositiveButton(android.R.string.ok, null)
.show();
.show());
} catch (Exception e) {
e.printStackTrace();
makeText(getGlobalContext(), getString("foaferr"), LENGTH_SHORT).show();
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), context.getString(R.string.foaferr), LENGTH_SHORT).show());
}
}
@@ -9,6 +9,7 @@ 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.getBoolValue;
import static ru.vtosters.lite.utils.Preferences.postsrecomm;
import android.util.Log;
@@ -18,7 +19,6 @@ 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;
@@ -225,6 +225,12 @@ public class AdBlockHook {
continue;
}
if (hasMiniAppAds(list) && !isWhitelistedFilters(list)) {
if (dev())
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: MiniApp filters");
continue;
}
if (NewsFeedFiltersUtils.injectFiltersReposts(list) && !isWhitelistedFilters(list)) {
if (dev())
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: repost ad");
@@ -339,7 +345,10 @@ public class AdBlockHook {
return true;
}
var whitelist = AndroidUtils.getDefaultPrefs().getStringSet("whitelisted_filters_groups", Collections.synchronizedSet(new LinkedHashSet<>()));
var whitelist = AndroidUtils.getDefaultPrefs().getStringSet(
"whitelisted_filters_groups",
Collections.emptySet()
);
return whitelist.contains(id);
}
@@ -351,8 +360,24 @@ public class AdBlockHook {
id = String.valueOf(list.optInt("source_id"));
}
var whitelist = AndroidUtils.getDefaultPrefs().getStringSet("whitelisted_ad_groups", Collections.synchronizedSet(new LinkedHashSet<>()));
var whitelist = AndroidUtils.getDefaultPrefs().getStringSet(
"whitelisted_ad_groups",
Collections.emptySet()
);
return whitelist.contains(id);
}
public static Boolean hasMiniAppAds(JSONObject list) {
var attachments = list.optJSONArray("attachments");
if (attachments != null && getBoolValue("blockminiapps", false)) {
for (int j = 0; j < attachments.length(); j++) {
var type = attachments.optJSONObject(j).optString("type");
if (type.contains("mini_app")) return true;
}
}
return false;
}
}
@@ -0,0 +1,15 @@
package ru.vtosters.lite.hooks;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import b.h.g.g.BuildInfo;
public class AppVerHook {
public static int appBuild() {
return getBoolValue("useOldAppVer", false) ? 6561 : BuildInfo.i.e();
}
public static String appVer() {
return getBoolValue("useOldAppVer", false) ? "6.18.1" : BuildInfo.i.d();
}
}
@@ -0,0 +1,9 @@
package ru.vtosters.lite.hooks;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
public class BusinessNotifHook {
public static boolean hook(boolean i){
return !getBoolValue("businessDisabler", false) && i;
}
}
@@ -2,7 +2,6 @@ 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.getSTextAttr;
@@ -17,12 +16,14 @@ import android.widget.LinearLayout;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.im.engine.models.dialogs.Dialog;
import com.vtosters.lite.R;
import java.util.List;
import java.util.Objects;
import ru.vtosters.lite.encryption.EncryptProvider;
import ru.vtosters.lite.encryption.base.IMProcessor;
import ru.vtosters.lite.utils.AndroidUtils;
public class CryptImHook {
public static boolean isPrivateProcessor(int peerID) {
@@ -42,7 +43,7 @@ public class CryptImHook {
int enabledPosition = 0;
String[] titles = new String[processors.size() + 1];
titles[0] = getString("encryption_disable");
titles[0] = AndroidUtils.getString(R.string.encryption_disable);
for (int i = 0; i < processors.size(); i++) {
IMProcessor proc = processors.get(i);
@@ -59,12 +60,12 @@ public class CryptImHook {
Activity ctx = getCurrentActivity();
if (ctx == null) {
sendToast(getString("app_activities_error"));
sendToast(AndroidUtils.getString(R.string.app_activities_error));
return;
}
new VkAlertDialog.Builder(ctx)
.setTitle(getString("encryption_sett"))
.setTitle(AndroidUtils.getString(R.string.encryption_sett))
.setSingleChoiceItems(titles, enabledPosition, (dialog, which) -> {
if (which == 0) {
if (finalEnabled != null) finalEnabled.disableEncryptFor(peerId);
@@ -96,7 +97,7 @@ public class CryptImHook {
}
if (enabled != null && enabled.isPublic()) {
sendToast(getString("encryption_public_algorithm_error"));
sendToast(AndroidUtils.getString(R.string.encryption_public_algorithm_error));
return;
}
@@ -111,7 +112,7 @@ public class CryptImHook {
Context ctx = getCurrentActivity();
if (ctx == null) {
sendToast(getString("app_activities_error"));
sendToast(ctx.getString(R.string.app_activities_error));
return;
}
@@ -130,8 +131,8 @@ public class CryptImHook {
IMProcessor finalEnabled = enabled;
new VkAlertDialog.Builder(ctx)
.setTitle(getString("encryption_enter_key"))
.setMessage(String.format(getString("encryption_current_algorithm_title"), enabled.getUIName()))
.setTitle(R.string.encryption_enter_key)
.setMessage(String.format(ctx.getString(R.string.encryption_current_algorithm_title), enabled.getUIName()))
.setView(linearLayout)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
Editable edit = editText.getText();
@@ -1,16 +1,18 @@
package ru.vtosters.lite.hooks;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import static ru.vtosters.lite.utils.AndroidUtils.getStringDate;
import android.annotation.SuppressLint;
import com.vtosters.lite.R;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import ru.vtosters.lite.utils.AndroidUtils;
public class DateHook {
public static boolean fulltime() {
return getPrefsValue("dateformat").equals("noyear") || getPrefsValue("dateformat").equals("full") || getPrefsValue("dateformat").equals("noseconds");
@@ -19,11 +21,11 @@ public class DateHook {
public static String getDateFormat() {
switch (getPrefsValue("dateformat")) {
case "noyear":
return getString("fulltime2");
return AndroidUtils.getString(R.string.fulltime2);
case "full":
return getString("fulltime");
return AndroidUtils.getString(R.string.fulltime);
default:
return getString("fulltime3");
return AndroidUtils.getString(R.string.fulltime3);
}
}
@@ -38,7 +40,7 @@ public class DateHook {
if (!fulltime()) return null;
try {
return getStringDate(isFemale ? getIdentifier("last_seen_profile_f", "string") : getIdentifier("last_seen_profile_m", "string"), date.format(new Date(time)));
return getStringDate(isFemale ? R.string.last_seen_profile_f : R.string.last_seen_profile_m, date.format(new Date(time)));
} catch (Throwable th) {
th.printStackTrace();
return null;
@@ -83,7 +83,7 @@ public class DockBarInjector {
}
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException |
NoSuchMethodException | InvocationTargetException e) {
NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
@@ -209,10 +209,13 @@ public class DockBarInjector {
val = MenuCountersState.n();
break;
case tab_feedback:
case tab_news:
if (milkshake())
val = MenuCountersState.k();
break;
case tab_news:
if (milkshake() && getBoolValue("newsfeed_notif", true))
val = MenuCountersState.k();
break;
case menu_friends:
if (!milkshake())
val = MenuCountersState.k();
@@ -1,6 +1,6 @@
package ru.vtosters.lite.hooks;
import static ru.vtosters.lite.utils.Preferences.musicFixNew;
import static ru.vtosters.lite.utils.Preferences.isValidSignature;
import android.os.Build;
import android.util.Base64;
@@ -27,9 +27,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.HttpsURLConnection;
public class GcmHook {
private static final String agent = String.format("Android-GCM/1.5 (%s %s)", Build.MODEL, Build.MODEL);
private static KeyPair pair;
private static int rid = 0;
static {
@@ -37,14 +41,11 @@ public class GcmHook {
}
public static String requestTokenV2(String orig) {
if (musicFixNew()) return "null"; //not public
return orig;
return isValidSignature() ? "eyJhbGciOiAibm9uZSJ9eyJub25jZSI6ICJudWxsIn0=" : "e251bGx9";
}
public static String requestToken(String orig) {
if (musicFixNew()) return "{null}"; //not public
if (orig.equals("")) return requestToken();
return orig;
return requestToken();
}
public static String requestToken() {
@@ -60,6 +61,7 @@ public class GcmHook {
} catch (NoSuchAlgorithmException e) {
xappide = "";
}
AtomicBoolean wait = new AtomicBoolean(false);
StringBuilder sb = new StringBuilder();
List<String> params = new ArrayList<>();
@@ -71,17 +73,20 @@ public class GcmHook {
while (!wait.get()) {
Thread.sleep(100);
}
String token = sb.toString();
if (token.equals("REGISTRATION_ERROR")) {
return requestToken();
}
rid = 0;
String pub22 = genNewKey();
String sig2 = getSig(pub22);
params.clear();
fillParams(params, sig2, pub22, xappide, Long.parseLong(aid.split(" ")[1].split(":")[0]), true);
doRequest("https://android.clients.google.com/c2dm/register3", "POST", params, aid, GcmHook::lambda$requestToken$1);
return token;
return isValidSignature() ? token : null;
} catch (FileNotFoundException e2) {
return requestToken();
} catch (Exception e3) {
@@ -100,12 +105,14 @@ public class GcmHook {
private static void fillParams(List<String> params, String sig, String pub2, String xappid, long androidId, boolean del) {
rid++;
params.add("X-subtype=841415684880");
if (del) {
params.add("X-delete=1");
params.add("X-X-delete=1");
} else {
params.add("X-X-subscription=841415684880");
}
params.add("X-X-subtype=841415684880");
params.add("X-app_ver=" + "7.26");
params.add("X-kid=|ID|" + rid + "|");
@@ -115,19 +122,20 @@ public class GcmHook {
params.add("X-gmsv=11949480");
params.add("X-pub2=" + pub2);
params.add("X-X-kid=|ID|" + rid + "|");
StringBuilder sb = new StringBuilder();
sb.append("X-appid=");
sb.append(xappid);
params.add(sb.toString());
params.add("X-appid=" + xappid);
if (del) {
params.add("X-scope=GCM");
} else {
params.add("X-scope=*");
}
params.add("X-subscription=841415684880");
if (!del) {
params.add("X-gmp_app_id=1:841415684880:android:632f429381141121");
}
params.add("X-app_ver_name=" + "7.26");
params.add("app=com.vkontakte.android");
params.add("sender=841415684880");
@@ -139,9 +147,11 @@ public class GcmHook {
private static String join(String chr, Iterable<String> arr) {
String str = "";
for (String s : arr) {
str = str.isEmpty() ? s : str + chr + s;
}
return str;
}
@@ -168,8 +178,12 @@ public class GcmHook {
}
private static String getRandomAid() {
var arr1 = new String[]{"3974055026275073921", "4418584909973341826", "4585634953328772978"};
var arr2 = new String[]{"1932960345884890854", "6594645578425092292", "1792344590975444730"};
var arr1 = new String[]{
"3974055026275073921", "4418584909973341826", "4585634953328772978"
};
var arr2 = new String[]{
"1932960345884890854", "6594645578425092292", "1792344590975444730"
};
int r = new Random().nextInt(2);
return "AidLogin " + arr1[r] + ":" + arr2[r];
}
@@ -182,6 +196,7 @@ public class GcmHook {
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return Base64.encodeToString(pair.getPublic().getEncoded(), 0);
}
@@ -190,7 +205,9 @@ public class GcmHook {
PrivateKey key = pair.getPrivate();
Signature sign = Signature.getInstance(key instanceof RSAPrivateKey ? "SHA256withRSA" : "SHA256withECDSA");
sign.initSign(key);
sign.update(join("\n", new String[]{"com.vkontakte.android", pub2}).getBytes(StandardCharsets.UTF_8));
sign.update(join("\n", new String[]{
"com.vkontakte.android", pub2
}).getBytes(StandardCharsets.UTF_8));
return Base64.encodeToString(sign.sign(), 0);
} catch (Exception e) {
e.printStackTrace();
@@ -201,4 +218,4 @@ public class GcmHook {
public interface Callback {
void doCallback(String str);
}
}
}
@@ -1,19 +1,13 @@
package ru.vtosters.lite.hooks;
import static ru.vtosters.lite.foaf.FoafBase.getBypassedOnlineInfo;
import static ru.vtosters.lite.hooks.DateHook.getLocale;
import static ru.vtosters.lite.hooks.OnlineFormatterHook.onlineHookProfiles;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.*;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getCatalogHeader;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getCatalogSeparator;
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.Preferences.dev;
import static ru.vtosters.lite.utils.Preferences.friendsblock;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import static ru.vtosters.lite.utils.Preferences.hasVerification;
import static ru.vtosters.lite.utils.Preferences.podcastcatalog;
import static ru.vtosters.lite.utils.VTVerifications.isDeveloper;
import static ru.vtosters.lite.utils.VTVerifications.isPrometheus;
import static ru.vtosters.lite.utils.VTVerifications.isVerified;
@@ -21,9 +15,8 @@ import static ru.vtosters.lite.utils.VTVerifications.isVerified;
import android.text.TextUtils;
import android.util.Log;
import com.vk.core.network.Network;
import com.vk.core.util.DeviceIdProvider;
import com.vk.core.util.LangUtils;
import com.vtosters.lite.R;
import org.json.JSONArray;
import org.json.JSONException;
@@ -31,22 +24,17 @@ import org.json.JSONObject;
import java.io.IOException;
import java.text.ParseException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Random;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
public class JsonInjectors {
private static final OkHttpClient mClient = new OkHttpClient();
private static final OkHttpClient mClient = VtOkHttpClient.getInstance();
public static JSONObject profileButton(JSONObject orig) throws JSONException {
var id = orig.getInt("id");
@@ -71,7 +59,7 @@ public class JsonInjectors {
}
public static JSONObject donateRecomm() throws JSONException {
var title = AndroidUtils.getString("donate_to_vtl");
var title = AndroidUtils.getString(R.string.donate_to_vtl);
var link = "https://vk.com/vtosters_official";
var text_color = "2D81E0";
@@ -112,7 +100,7 @@ public class JsonInjectors {
}
public static JSONObject vktesters(int id) throws JSONException {
var title = AndroidUtils.getString("tester_profile");
var title = AndroidUtils.getString(R.string.tester_profile);
var text_color = "2D81E0";
var link = "https://" + getStatic() + "/bugs?lang=" + LangUtils.a() + "#/reporter" + id;
@@ -156,7 +144,7 @@ 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 = AndroidUtils.getString(R.string.no_data_error);
var link = "https://vtosters.app"; // can be null
var linktitle = "Test button"; // can be null
@@ -165,10 +153,11 @@ public class JsonInjectors {
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 (isVerified(peerid))
text = AndroidUtils.getString(R.string.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");
text = AndroidUtils.getString(R.string.i_bought) + " VTosters Premium Gold Prime Pro Plus";
if (isDeveloper(peerid)) text = AndroidUtils.getString(R.string.i_created_poop);
if (!isVerified(peerid) || text.equals("") || peerid == AccountManagerUtils.getUserId() || peerid == 0) {
if (getBoolValue("convBarRecomm", false)) {
@@ -242,19 +231,6 @@ public class JsonInjectors {
return json.putOpt("items", newItems);
}
public static JSONObject musiclink(JSONObject json) {
var links = json.optJSONArray("links");
if (links != null) {
if (links.optJSONObject(0).optString("url").contains("?section=recent")) {
json.remove("links");
if (dev()) Log.d("VKMusic", "Removed links buttons");
}
}
return json;
}
public static JSONObject setOnlineInfo(JSONObject json) throws JSONException {
var id = json.optInt("id");
@@ -336,193 +312,38 @@ public class JsonInjectors {
public static JSONArray newsfeedlist(JSONArray items) throws JSONException {
var selectedItems = getDefaultPrefs().getString("news_feed_selected_items", "");
var filtersSet = getDefaultPrefs().getStringSet("news_feed_items_set", null);
var mutableFiltersSet = Collections.synchronizedSet(new LinkedHashSet<String>());
var mutableFiltersSet = new LinkedHashSet<String>();
if (filtersSet != null)
mutableFiltersSet.addAll(filtersSet);
synchronized (mutableFiltersSet) {
for (int i = 0; i < items.length(); i++) {
var item = items.optJSONObject(i);
if (item == null) continue;
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");
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;
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);
mutableFiltersSet.add(id + "|" + title);
var hide = selectedItems.contains(id);
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");
}
getDefaultPrefs().edit().putStringSet("news_feed_items_set", mutableFiltersSet)
.apply();
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");
}
getDefaultPrefs().edit().putStringSet("news_feed_items_set", mutableFiltersSet)
.apply();
return items;
}
public static JSONObject music(JSONObject json) throws JSONException {
var catalog = json.optJSONObject("catalog");
JSONArray oldItems = null;
if (catalog != null) {
oldItems = catalog.optJSONArray("sections");
}
if (oldItems != null && oldItems.optJSONObject(0).optString("url").contains("general")) {
json.optJSONArray("playlists").put(getPlaylist());
if (podcastcatalog()) {
var podcasts = fetchCatalogPodcast();
if (podcasts != null) {
var catalogarr = podcasts.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
var title = catalogarr.optString("title");
var id = catalogarr.optString("id");
var url = catalogarr.optString("url");
if (dev()) Log.d("VKMusic", "Added " + title + " in music sections");
oldItems.put(new JSONObject().put("id", id).put("title", title).put("url", url));
}
}
var playlists = fetchCatalogId("https://vk.com/audio?section=my_playlists");
if (playlists != null) {
var catalogarr = playlists.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
var title = catalogarr.optString("title");
var id = catalogarr.optString("id");
var url = catalogarr.optString("url");
if (dev()) Log.d("VKMusic", "Added " + title + " in music sections");
oldItems.put(new JSONObject().put("id", id).put("title", title).put("url", url));
}
var albums = fetchCatalogId("https://vk.com/audio?section=albums");
if (albums != null) {
var catalogarr = albums.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
var title = catalogarr.optString("title");
var id = catalogarr.optString("id");
var url = catalogarr.optString("url");
if (dev()) Log.d("VKMusic", "Added " + title + " in music sections");
oldItems.put(new JSONObject().put("id", id).put("title", title).put("url", url));
}
var recent = fetchCatalogId("https://vk.com/audio?section=recent");
if (recent != null) {
var catalogarr = recent.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
var title = catalogarr.optString("title");
var id = catalogarr.optString("id");
var url = catalogarr.optString("url");
if (dev()) Log.d("VKMusic", "Added " + title + " in music sections");
oldItems.put(new JSONObject().put("id", id).put("title", title).put("url", url));
}
for (int i = 0; i < oldItems.length(); i++) {
var item = oldItems.optJSONObject(i);
var title = item.optString("title");
var id = item.optString("id");
var url = item.optString("url");
var value = AndroidUtils.getPrefsValue("musicdefcatalog");
Log.d("VKMusic", "title: " + title + " id: " + id + " url: " + url + " value: " + value);
if (url.contains(value) && !value.isEmpty()) {
catalog.put("default_section", id);
if (dev()) Log.d("VKMusic", "Added " + title + " as default music section");
}
}
if (CacheDatabaseDelegate.hasTracks() && !LibVKXClient.isIntegrationEnabled()){ // inj in playlist list
var blocks = oldItems.optJSONObject(0).optJSONArray("blocks");
var newBlocks = new JSONArray();
if (blocks != null){
newBlocks
.put(getCatalogHeader())
.put(getCatalogPlaylist())
.put(getCatalogSeparator());
Log.d("VKMusic", "added cache catalog playlist");
for (int i = 0; i < blocks.length(); i++) {
newBlocks.put(blocks.optJSONObject(i));
}
oldItems.optJSONObject(0).put("blocks", newBlocks);
}
}
}
return json;
}
public static JSONObject fetchCatalogId(String section) {
if (section.isEmpty()) return null;
var request = new Request.a()
.b("https://" + getApi() + "/method/catalog.getAudio"
+ "?v=5.119"
+ "&https=1"
+ "&need_blocks=1"
+ "&lang="
+ getLocale()
+ "&device_id="
+ DeviceIdProvider.d(AndroidUtils.getGlobalContext())
+ "&url="
+ section
+ "&access_token="
+ AccountManagerUtils.getUserToken())
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
try {
return new JSONObject(mClient.a(request).execute().a().g()).getJSONObject("response");
} catch (JSONException | IOException e) {
Log.d("VTLMusic", "Error: " + e.getMessage());
}
return null;
}
public static JSONObject fetchCatalogPodcast() {
var request = new Request.a()
.b("https://" + getApi() + "/method/catalog.getPodcasts"
+ "?v=5.119"
+ "&https=1"
+ "&need_blocks=1"
+ "&lang="
+ getLocale()
+ "&device_id="
+ DeviceIdProvider.d(AndroidUtils.getGlobalContext())
+ "&access_token="
+ AccountManagerUtils.getUserToken())
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
try {
return new JSONObject(mClient.a(request).execute().a().g()).getJSONObject("response");
} catch (JSONException | IOException e) {
Log.d("VTLMusic", "Error: " + e.getMessage());
}
return null;
}
public static JSONObject friends(JSONObject json) throws JSONException, ParseException, IOException {
JSONObject catalog = onlineHookProfiles(json);
boolean sectionexecute = true;
@@ -4,15 +4,12 @@ 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;
import android.app.Activity;
import android.os.Build;
import android.preference.PreferenceManager;
import com.vk.core.concurrent.VkExecutors;
import ru.vtosters.lite.concurrent.VTExecutors;
import ru.vtosters.lite.downloaders.notifications.NotificationChannels;
import ru.vtosters.lite.ui.dialogs.DisableBattery;
import ru.vtosters.lite.ui.dialogs.InstallGMS;
@@ -20,25 +17,17 @@ import ru.vtosters.lite.ui.dialogs.OTADialog;
import ru.vtosters.lite.ui.dialogs.Start;
import ru.vtosters.lite.utils.DeletedMessagesHandler;
/**
* @
*/
public class MainActivityInjector {
public static void inject(Activity activity) {
setNeededTheme(activity);
sendRequest();
if (checkupdates()) OTADialog.checkUpdates(activity);
VkExecutors.x.f().a(DeletedMessagesHandler::reloadMessagesList); // ioScheduler
VTExecutors.getIoScheduler().a(DeletedMessagesHandler::reloadMessagesList); // ioScheduler
Start.alert(activity);
InstallGMS.alert(activity);
DisableBattery.alert(activity);
PreferenceManager.getDefaultSharedPreferences(activity)
.edit()
.putBoolean("isdark", isDarkTheme())
.commit();
VkExecutors.x.q().a(() -> {
VTExecutors.getSlowTasksScheduler().a(() -> {
getInstance().autoCleaningCache();
}); // slowTasksScheduler
@@ -5,7 +5,6 @@ import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
import static ru.vtosters.lite.utils.Preferences.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.Preferences.getBoolValue;
@@ -70,19 +69,25 @@ public class NewsfeedHook {
}
public static boolean isWhitelistedFilter(ExtendedCommunityProfile eup) {
return getDefaultPrefs().getStringSet("whitelisted_filters_groups", Collections.synchronizedSet(new LinkedHashSet<>())).contains(String.valueOf(AccountManagerUtils.getUserID(eup)));
return getDefaultPrefs().getStringSet(
"whitelisted_filters_groups", Collections.emptySet()
).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)));
return getDefaultPrefs().getStringSet(
"whitelisted_ad_groups",
Collections.emptySet()
).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));
var mutableAdsSet = new LinkedHashSet<>(getDefaultPrefs().getStringSet(
"whitelisted_filters_groups",
Collections.emptySet())
);
if (needWhitelist) {
mutableAdsSet.add(id);
} else {
@@ -93,10 +98,11 @@ public class NewsfeedHook {
}
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));
var mutableAdsSet = new LinkedHashSet<>(getDefaultPrefs().getStringSet(
"whitelisted_ad_groups",
Collections.emptySet()));
if (needWhitelist) {
mutableAdsSet.add(id);
@@ -108,14 +114,16 @@ public class NewsfeedHook {
}
public static void adsParams(HashSet<String> hashSet) {
if (ads())
if (ads()) {
hashSet.add("ads_disabled");
} else {
hashSet.add("ads_app_slider");
hashSet.add("ads_site_slider");
}
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");
@@ -5,7 +5,6 @@ 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;
@@ -13,6 +12,8 @@ import static ru.vtosters.lite.utils.Preferences.getPrefsFromFile;
import android.util.Log;
import com.vtosters.lite.R;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -64,37 +65,37 @@ public class OnlineFormatterHook {
case 5027722:
return "VK Messenger (Desktop)";
case 6146827:
return AndroidUtils.getString("vk_messenger") + " (Android)"; // VK Мессенджер (Android)
return AndroidUtils.getString(R.string.vk_messenger) + " (Android)"; // VK Мессенджер (Android)
case 6482950:
return AndroidUtils.getString("vk_messenger") + " (iPhone)"; // VK Мессенджер (iPhone)
return AndroidUtils.getString(R.string.vk_messenger) + " (iPhone)"; // VK Мессенджер (iPhone)
case 6481715:
return AndroidUtils.getString("vk_messenger") + " Dev (iPhone)"; // VK Мессенджер Dev (iPhone)
return AndroidUtils.getString(R.string.vk_messenger) + " Dev (iPhone)"; // VK Мессенджер Dev (iPhone)
case 7799655:
return AndroidUtils.getString("vk_mail_online"); // VK Почта
return AndroidUtils.getString(R.string.vk_mail_online); // VK Почта
case 7598572:
return AndroidUtils.getString("sferum_online") + " (Android)"; // Сферум (Android)
return AndroidUtils.getString(R.string.sferum_online) + " (Android)"; // Сферум (Android)
case 7571751:
return AndroidUtils.getString("sferum_online") + " (iPhone)"; // Сферум (iPhone)
return AndroidUtils.getString(R.string.sferum_online) + " (iPhone)"; // Сферум (iPhone)
case 7556576:
return AndroidUtils.getString("sferum_online"); // Сферум
return AndroidUtils.getString(R.string.sferum_online); // Сферум
case 7497650:
return "VK ID";
case 8094476:
return AndroidUtils.getString("vk_calls_online") + " (Android)"; // VK Звонки (Android)
return AndroidUtils.getString(R.string.vk_calls_online) + " (Android)"; // VK Звонки (Android)
case 8093730:
return AndroidUtils.getString("vk_calls_online") + " (iPhone)"; // VK Звонки (iPhone)
return AndroidUtils.getString(R.string.vk_calls_online) + " (iPhone)"; // VK Звонки (iPhone)
case 7793118:
return AndroidUtils.getString("vk_calls_online") + " (Desktop)"; // VK Звонки (Desktop)
return AndroidUtils.getString(R.string.vk_calls_online) + " (Desktop)"; // VK Звонки (Desktop)
case 6767438:
return AndroidUtils.getString("vk_music_online") + " (Android)"; // VK Музыка (Android)
return AndroidUtils.getString(R.string.vk_music_online) + " (Android)"; // VK Музыка (Android)
case 8113297:
return AndroidUtils.getString("vk_clips_online") + " (Android)"; // VK Клипы (Android)
return AndroidUtils.getString(R.string.vk_clips_online) + " (Android)"; // VK Клипы (Android)
case 8106428:
return AndroidUtils.getString("vk_clips_online") + " (iPhone)"; // VK Клипы (iPhone)
return AndroidUtils.getString(R.string.vk_clips_online) + " (iPhone)"; // VK Клипы (iPhone)
case 5044491:
return "Candy";
case 8114066:
return AndroidUtils.getString("vk_video_online"); // VK Видео
return AndroidUtils.getString(R.string.vk_video_online); // VK Видео
case 4894723:
return "Phoenix Lite";
case 4994316:
@@ -173,7 +174,7 @@ public class OnlineFormatterHook {
if (appname == null) return null;
return getString("custom_online") + " " + appname;
return AndroidUtils.getString(R.string.custom_online) + " " + appname;
}
public static JSONObject onlineHook(JSONObject json) throws ParseException, IOException, JSONException {
@@ -1,8 +1,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;
@@ -39,14 +37,15 @@ import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.ThemesUtils;
public class PhotoViewer {
static OkHttpClient client = new OkHttpClient();
static OkHttpClient client = VtOkHttpClient.getInstance();
public static boolean interceptClick(AttachmentWithMedia attachment, MenuItem item, View view) {
if (item.getItemId() == AndroidUtils.getIdentifier("search_photo", "id")) {
if (item.getItemId() == R.id.search_photo) {
if (attachment instanceof PhotoAttachment) {
searchPhoto(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
} else if (attachment instanceof DocumentAttachment) {
@@ -55,13 +54,13 @@ public class PhotoViewer {
try {
searchPhoto(getUrlFromDocumentAttachment(documentAttachment));
} catch (Exception e) {
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
else
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
return true;
} else if (item.getItemId() == AndroidUtils.getIdentifier("copy_photo_url", "id")) {
} else if (item.getItemId() == R.id.copy_photo_url) {
if (attachment instanceof PhotoAttachment) {
copyPhotoUrl(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
} else if (attachment instanceof DocumentAttachment) {
@@ -70,13 +69,13 @@ public class PhotoViewer {
try {
copyPhotoUrl(getUrlFromDocumentAttachment(documentAttachment));
} catch (Exception e) {
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
else
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
return true;
} else if (item.getItemId() == AndroidUtils.getIdentifier("open_original_photo", "id")) {
} else if (item.getItemId() == R.id.open_original_photo) {
if (attachment instanceof PhotoAttachment) {
openUrl(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
} else if (attachment instanceof DocumentAttachment) {
@@ -85,19 +84,19 @@ public class PhotoViewer {
try {
openUrl(getUrlFromDocumentAttachment(documentAttachment));
} catch (Exception e) {
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
else
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
return true;
}
return false;
return true;
}
@SuppressLint("UseCompatLoadingForDrawables")
public static void addMenuItems(AttachmentWithMedia attachment, ActionsPopup.b actionPopup, int i, boolean z) {
actionPopup.a(getIdentifier("search_photo_content", "string"),
actionPopup.a(R.string.search_photo_content,
ThemesUtils.isDarkTheme()
? AndroidUtils.getGlobalContext().getDrawable(R.drawable.ic_menu_search_outline_28)
: new RecoloredDrawable(AndroidUtils.getGlobalContext().getDrawable(R.drawable.ic_menu_search_outline_28), ThemesUtils.getAccentColor()),
@@ -111,15 +110,15 @@ public class PhotoViewer {
try {
searchPhoto(getUrlFromDocumentAttachment(documentAttachment));
} catch (Exception e) {
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
else
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
return null;
}
);
actionPopup.a(getIdentifier("copy_photo_url_content", "string"),
actionPopup.a(R.string.copy_photo_url_content,
!ThemesUtils.isDarkTheme()
? new RecoloredDrawable(AndroidUtils.getGlobalContext().getDrawable(R.drawable.ic_copy_outline_28), ThemesUtils.getAccentColor())
: new RecoloredDrawable(AndroidUtils.getGlobalContext().getDrawable(R.drawable.ic_copy_outline_28), Color.WHITE),
@@ -133,15 +132,15 @@ public class PhotoViewer {
try {
copyPhotoUrl(getUrlFromDocumentAttachment(documentAttachment));
} catch (Exception e) {
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
else
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
return null;
}
);
actionPopup.a(getIdentifier("open_original_photo_content", "string"),
actionPopup.a(R.string.open_original_photo_content,
ThemesUtils.isDarkTheme()
? AndroidUtils.getGlobalContext().getDrawable(R.drawable.ic_link_outline_28)
: new RecoloredDrawable(AndroidUtils.getGlobalContext().getDrawable(R.drawable.ic_link_outline_28),
@@ -156,10 +155,10 @@ public class PhotoViewer {
try {
openUrl(getUrlFromDocumentAttachment(documentAttachment));
} catch (Exception e) {
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
else
ToastUtils.a(getString("photo_get_error"));
ToastUtils.a(R.string.photo_get_error);
}
return null;
}
@@ -248,7 +247,7 @@ public class PhotoViewer {
if (url == null || url.isEmpty()) return;
ClipboardManager manager = (ClipboardManager) AndroidUtils.getGlobalContext().getSystemService(Context.CLIPBOARD_SERVICE);
manager.setPrimaryClip(ClipData.newPlainText("vk_photo_url", url));
Toast.makeText(AndroidUtils.getGlobalContext(), AndroidUtils.getIdentifier("copied_to_clipboard", "string"), Toast.LENGTH_SHORT).show();
Toast.makeText(AndroidUtils.getGlobalContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
}
private static void openUrl(String url) {
@@ -0,0 +1,9 @@
package ru.vtosters.lite.hooks;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
public class PromoStickersHook {
public static String hook() {
return getBoolValue("promotedstickers", true) ? "purchased,active" : "purchased,active,promoted";
}
}
@@ -21,15 +21,14 @@ import androidx.appcompat.view.ContextThemeWrapper;
import com.vk.auth.ui.VkAuthTextView;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.navigation.Navigator;
import com.vtosters.lite.R;
import ru.vtosters.lite.ui.fragments.ProxySettingsFragment;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.ThemesUtils;
public class ProxyHook {
public static void hookAuth(View v) {
VkAuthTextView button = (VkAuthTextView) v;
button.setText(AndroidUtils.getString("proxy_setup"));
button.setText(R.string.proxy_setup);
button.setOnClickListener(v1 -> callProxyDialog(v1.getContext()));
}
@@ -54,16 +53,16 @@ public class ProxyHook {
rg.setPadding(dp2px(18f), dp2px(12f), dp2px(18f), 0);
rgDefault.setText(AndroidUtils.getString("proxy_disable"));
rgDefault.setText(ctx.getString(R.string.proxy_disable));
rgDefault.setTextColor(getTextAttr());
rgZaborona.setText(AndroidUtils.getString("proxy_enable") + " (Zaborona)");
rgZaborona.setText(ctx.getString(R.string.proxy_enable) + " (Zaborona)");
rgZaborona.setTextColor(getTextAttr());
rgRandomProxy.setText(AndroidUtils.getString("proxy_enable") + " (Random Socks Proxy)");
rgRandomProxy.setText(ctx.getString(R.string.proxy_enable) + " (Random Socks Proxy)");
rgRandomProxy.setTextColor(getTextAttr());
rgVika.setText(AndroidUtils.getString("proxy_enable") + " (Vika Mobile)");
rgVika.setText(ctx.getString(R.string.proxy_enable) + " (Vika Mobile)");
rgVika.setTextColor(getTextAttr());
rgZaborona.setChecked(isZaboronaEnabled());
@@ -71,11 +70,11 @@ public class ProxyHook {
rgRandomProxy.setChecked(isRandomProxyEnabled());
rgVika.setChecked(isVikaProxyEnabled());
new VkAlertDialog.Builder(ctx)
.setTitle(AndroidUtils.getString("vtlproxy"))
.setMessage(AndroidUtils.getString("proxy_warning"))
.setView(rg)
.setPositiveButton(AndroidUtils.getString("vtl_confirm"), ((dialog, which) -> { // Применить
new VkAlertDialog.Builder(ctx)
.setTitle(ctx.getString(R.string.vtlproxy))
.setMessage(ctx.getString(R.string.proxy_warning))
.setView(rg)
.setPositiveButton(ctx.getString(R.string.vtl_confirm), ((dialog, which) -> { // Применить
if (rgZaborona.isChecked()) {
edit().putString("proxy", "zaborona").commit();
restartApplication();
@@ -89,13 +88,13 @@ public class ProxyHook {
edit().putString("proxy", "noproxy").commit();
restartApplication();
}
}))
.setNeutralButton(AndroidUtils.getString("proxy_settings"), ((dialog, which) -> {
}))
.setNeutralButton(ctx.getString(R.string.proxy_settings), ((dialog, which) -> {
var intent = new Navigator(ProxySettingsFragment.class)
.b(ctx)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}))
.show();
}))
.show();
}
}
@@ -5,7 +5,6 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
import static ru.vtosters.lite.utils.ThemesUtils.getAttrId;
import static ru.vtosters.lite.utils.ThemesUtils.getBackgroundContent;
import static ru.vtosters.lite.utils.ThemesUtils.getBackgroundPage;
import static ru.vtosters.lite.utils.ThemesUtils.getColorFromAttr;
@@ -17,6 +16,7 @@ import static ru.vtosters.lite.utils.ThemesUtils.hex;
import android.webkit.WebView;
import com.vk.articles.preload.WebCachePreloader;
import com.vtosters.lite.R;
import com.vtosters.lite.data.ThemeTracker;
import java.io.BufferedReader;
@@ -61,10 +61,10 @@ public class VKUIHook {
.replace("%header_text%", hex(getHeaderText()))
.replace("%accent%", hex(getAccentColor()))
.replace("%background_page%", hex(getBackgroundPage()))
.replace("%content_tint_background%", hex(getColorFromAttr(getAttrId("content_tint_background"))))
.replace("%button_primary_background%", hex(getColorFromAttr(getAttrId("button_primary_background"))))
.replace("%button_outline_foreground%", hex(getColorFromAttr(getAttrId("button_outline_foreground"))))
.replace("%button_outline_border%", hex(getColorFromAttr(getAttrId("button_outline_border"))))
.replace("%content_tint_background%", hex(getColorFromAttr(R.attr.content_tint_background)))
.replace("%button_primary_background%", hex(getColorFromAttr(R.attr.button_primary_background)))
.replace("%button_outline_foreground%", hex(getColorFromAttr(R.attr.button_outline_foreground)))
.replace("%button_outline_border%", hex(getColorFromAttr(R.attr.button_outline_border)))
.replace("%text_primary%", hex(getTextAttr()));
@@ -2,12 +2,13 @@ package ru.vtosters.lite.hooks;
import static ru.vtosters.lite.utils.Preferences.wbios;
import ru.vtosters.lite.utils.AndroidUtils;
import com.vtosters.lite.R;
import ru.vtosters.lite.utils.ThemesUtils;
public class WritebarHook {
public static int getWriteBar() {
return AndroidUtils.getIdentifier((wbios() ? "write_bar_i" : "write_bar"), "layout");
return wbios() ? R.layout.write_bar_i : R.layout.write_bar;
}
public static int getIconsColors(int def) {
@@ -0,0 +1,221 @@
package ru.vtosters.lite.music;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import com.vk.dto.music.MusicTrack;
import com.vtosters.lite.R;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.downloaders.AudioDownloader;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.Preferences;
public class LastFMScrobbler {
private static final String KEY = "5965d63402414776c54c266db0211746";
private static final String KEY_SECRET = "d982180eed13275bb948e41cf225f88f";
private static final String URL = "https://ws.audioscrobbler.com/2.0/";
private static final OkHttpClient CLIENT = VtOkHttpClient.getInstance();
private static final List<String> SCROBBLED_UUIDS = new ArrayList<>();
public static void grabMusicTrack(MusicTrack musictrack) {
var uid = musictrack.y1();
var artist = musictrack.C;
var title = musictrack.f;
var duration = musictrack.h;
var track_id = musictrack.d;
var owner_id = musictrack.e;
var access_key = !TextUtils.isEmpty(musictrack.J) ? musictrack.J : "";
var album_id = musictrack.I;
var album = album_id != null ? album_id.getTitle() : null;
if (TextUtils.isEmpty(uid) || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0) {
Log.d("Scrobbler", "grabTrackInfo: " + "Empty track, info: " + artist + " - " + title + " - " + duration + " - " + uid);
return;
}
if (Preferences.autocache() && !CacheDatabaseDelegate.isCached(uid)) {
if (LibVKXClient.isIntegrationEnabled()) {
LibVKXClient.getInstance().runOnService(service -> {
try {
service.addTrackToCache(track_id, owner_id, access_key);
} catch (RemoteException e) {
e.printStackTrace();
}
});
} else {
AudioDownloader.cacheTrack(musictrack);
}
}
scrobbleTrack(duration, artist, title, uid, album);
}
public static void scrobbleTrack(
long duration,
String artist,
String title,
String uid,
@Nullable String album
) {
Log.d("Scrobbler", "scrobbleTrack: " + title + " - " + artist + " - " + duration + " - " + uid);
if (!needScrobbling(uid) || !isLoggedIn() || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0)
return;
SCROBBLED_UUIDS.add(uid);
var params = new TreeMap<String, String>();
params.put("api_key", KEY);
params.put("method", "track.scrobble");
params.put("sk", getSessionKey());
params.put("artist[0]", artist);
params.put("track[0]", title);
if (!TextUtils.isEmpty(album))
params.put("album[0]", album);
params.put("duration[0]", String.valueOf(duration));
params.put("timestamp[0]", String.valueOf(System.currentTimeMillis() / 1000));
fetch(params, new Callback() {
@Override
public void a(Call call, IOException e) {
Log.d("Scrobbler", e + "");
}
@Override
public void a(Call call, Response response) throws IOException {
Log.d("Scrobbler", "Scrobbled: " + artist + " - " + title);
Log.d("Scrobbler", "Response scrobble: " + response.a().g());
}
});
}
public static void authenticate(String username, String password) {
if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
AndroidUtils.sendToast(AndroidUtils.getString(R.string.lastfm_credentials_empty));
return;
}
var params = new TreeMap<String, String>();
params.put("api_key", KEY);
params.put("method", "auth.getMobileSession");
params.put("username", username);
params.put("password", password);
fetch(params, new Callback() {
@Override
public void a(Call call, IOException e) {
Log.d("Scrobbler", "Auth failed", e);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.auth_error_vtl));
}
@Override
public void a(Call call, Response response) throws IOException {
try {
var resBody = response.a().g();
var json = new JSONObject(resBody);
fetchSession(json);
Log.d("Scrobbler", "Auth response " + resBody);
} catch (JSONException e) {
Log.d("Scrobbler", "Auth failed", e);
}
}
});
}
private static String generateMD5(Map<String, String> params) {
var sb = new StringBuilder();
for (var entry : params.entrySet())
sb.append(entry.getKey()).append(entry.getValue());
return AndroidUtils.MD5(sb.append(KEY_SECRET).toString());
}
private static void fetch(TreeMap<String, String> params, Callback callback) {
// Each call must be signed with md5.
// For more information check https://www.last.fm/api
params.put("api_sig", generateMD5(params));
params.put("format", "json");
var reqBodyBuilder = new FormBody.a(StandardCharsets.UTF_8);
for (var entry : params.entrySet())
reqBodyBuilder.a(entry.getKey(), entry.getValue());
var req = new Request.a()
.b(URL)
.a(reqBodyBuilder.a())
.a();
CLIENT.a(req).a(callback);
}
public static void fetchSession(JSONObject json) throws JSONException {
if (!json.has("session")) {
Log.d("Scrobbler", "Auth failed - no session");
return;
}
var session = json.getJSONObject("session");
var name = session.getString("name");
var key = session.getString("key");
AndroidUtils.edit()
.putString("username", name)
.putString("sessionKey", key)
.putBoolean("lastfm_enabled", true)
.apply();
Log.d("Scrobbler", "Auth success as " + name + ", key " + key);
}
public static void logout() {
AndroidUtils.edit()
.remove("username")
.remove("sessionKey")
.putBoolean("lastfm_enabled", false)
.apply();
SCROBBLED_UUIDS.clear();
AndroidUtils.sendToast(AndroidUtils.getString(R.string.lastfm_logout_success));
}
public static boolean needScrobbling(String uid) {
return isLoggedIn() && isScrobblingEnabled() && (SCROBBLED_UUIDS.isEmpty() || !SCROBBLED_UUIDS.get(SCROBBLED_UUIDS.size() - 1).contains(uid));
}
public static boolean isLoggedIn() {
return !TextUtils.isEmpty(getSessionKey());
}
public static boolean isScrobblingEnabled() {
return AndroidUtils.getPreferences().getBoolean("lastfm_enabled", false);
}
public static String getUserName() {
return AndroidUtils.getDefaultPrefs().getString("username", null);
}
private static String getSessionKey() {
return AndroidUtils.getDefaultPrefs().getString("sessionKey", null);
}
}
@@ -15,54 +15,48 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.crypto.NoSuchPaddingException;
import java8.util.concurrent.CompletableFuture;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.music.converter.ts.FFMpeg;
import ru.vtosters.lite.music.converter.ts.TSMerger;
import ru.vtosters.lite.music.downloader.ThumbnailDownloader;
import ru.vtosters.lite.music.interfaces.ITrackDownloader;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.IOUtils;
public class M3UDownloader implements ITrackDownloader {
private static final OkHttpClient client = new OkHttpClient();
private static final OkHttpClient client = VtOkHttpClient.getInstance();
public static M3UDownloader getInstance() {
return Holder.INSTANCE;
}
public void downloadTrack(MusicTrack track, File outDir, Callback callback, boolean cache) {
var request = new Request.a()
.b(track.D)
.a();
client.a(request).a(new okhttp3.Callback() {
@Override
public void a(Call call, IOException e) {
callback.onFailure();
}
@Override
public void a(Call call, Response response) throws IOException {
parse(response.a().g(), outDir, callback, track, cache);
}
});
var request = new Request.a().b(track.D).a();
try {
var response = client.a(request).execute().a().g();
parse(response, outDir, callback, track, cache);
} catch (IOException e) {
e.printStackTrace();
callback.onFailure();
}
}
private void parse(String payload, File outDir, Callback callback, MusicTrack track, boolean cache) {
if (cache)
try {
ThumbnailDownloader.downloadThumbnails(track);
} catch (IOException e) {
e.printStackTrace();
}
if (cache) try {
ThumbnailDownloader.downloadThumbnails(track);
} catch (IOException e) {
e.printStackTrace();
}
VKM3UParser parser = new VKM3UParser(payload);
List<TransportStream> tses = parser.getTransportStreams();
AtomicInteger progress = new AtomicInteger(0);
List<CompletableFuture<Void>> futures = new ArrayList<>();
List<CompletableFuture<Void>> futures = new ArrayList<>(tses.size());
var tsesDir = new File(outDir, String.valueOf(track.d));
var filesDir = AndroidUtils.getGlobalContext().getFilesDir();
var tsesDir = new File(filesDir, String.valueOf(track.d));
tsesDir.mkdirs();
var resultTs = new File(tsesDir, "result.ts");
@@ -96,28 +90,23 @@ public class M3UDownloader implements ITrackDownloader {
IOUtils.writeToFile(tsDump, content);
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / tses.size()));
callback.onSizeReceived((long) content.length * tses.size(), parser.getHeapSize());
} catch (IOException | NoSuchPaddingException | NoSuchAlgorithmException |
InvalidAlgorithmParameterException | InvalidKeyException e) {
} catch (IOException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException e) {
callback.onFailure();
throw new RuntimeException(e);
}
}));
}
var future = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
future.join();
future.exceptionally(throwable -> {
callback.onFailure();
return null;
})
.thenApply(v -> TSMerger.merge(tsesDir, resultTs))
.thenApply(mergeResult -> mergeResult && FFMpeg.convert(resultTs, resultMp3.getAbsolutePath(), track))
.thenApply(convertResult -> {
if (convertResult)
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / tses.size()));
else callback.onFailure();
return convertResult;
})
.thenRun(() -> IOUtils.deleteRecursive(tsesDir))
.thenRun(callback::onSuccess);
callback.onFailure();
return null;
}).thenApply(v -> TSMerger.merge(tsesDir, resultTs)).thenApply(mergeResult -> mergeResult && FFMpeg.convert(resultTs, resultMp3.getAbsolutePath(), track)).thenApply(convertResult -> {
if (convertResult)
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / tses.size()));
else callback.onFailure();
return convertResult;
}).thenRun(() -> IOUtils.deleteRecursive(tsesDir)).thenRun(callback::onSuccess);
}
// Initialization-on-demand
@@ -1,213 +0,0 @@
package ru.vtosters.lite.music;
import static java.lang.String.valueOf;
import static bruhcollective.itaysonlab.libvkx.client.LibVKXClient.getInstance;
import static ru.vtosters.lite.music.cache.CacheDatabaseDelegate.*;
import static ru.vtosters.lite.utils.AndroidUtils.MD5;
import static ru.vtosters.lite.utils.AndroidUtils.edit;
import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs;
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
import static ru.vtosters.lite.utils.Preferences.autocache;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.Nullable;
import com.vk.dto.music.MusicTrack;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import ru.vtosters.lite.downloaders.AudioDownloader;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.net.NetCall;
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";
private static final String keysecret = "d982180eed13275bb948e41cf225f88f";
private static final String url = "https://ws.audioscrobbler.com/2.0/";
private static final NetClient client = new NetClient.Builder().build();
private static final ArrayList<String> scrobbled = new ArrayList<>();
public static void scrobbleTrack(long duration, String artist, String title, String uid, @Nullable String album) {
var string = getDefaultPrefs().getString("sessionKey", null);
var timestamp = System.currentTimeMillis() / 1000;
Log.d("Scrobbler", "scrobbleTrack: " + title + " - " + artist + " - " + duration + " - " + uid);
if (!needToBeScrobble(uid) ||
string == null ||
string.isEmpty() ||
artist == null ||
artist.isEmpty() ||
title == null ||
title.isEmpty() ||
duration == 0) return;
scrobbled.add(uid); // add to scrobbled list
TreeMap<String, String> treeMap = new TreeMap<>(); // create map for request
treeMap.put("method", "track.scrobble");
treeMap.put("sk", string);
treeMap.put("artist[0]", artist);
treeMap.put("track[0]", title);
if (album != null && !album.isEmpty())
treeMap.put("album[0]", album);
treeMap.put("timestamp[0]", valueOf(timestamp));
treeMap.put("api_key", key);
treeMap.put("duration[0]", valueOf(duration));
treeMap.put("api_sig", signMD5(treeMap));
treeMap.put("format", "json");
client.newCall(new NetRequest.Builder().url(url).post().params(treeMap).build()).enqueue(new NetCallback() {
@Override
public void onFailure(NetCall call, IOException e) {
Log.d("Scrobbler", "Error: " + e.getMessage());
}
@Override
public void onResponse(NetCall call, NetResponse response) {
Log.d("Scrobbler", "Scrobbled: " + artist + " - " + title);
Log.d("Scrobbler", "Response scrobble: " + response.getDataString());
}
});
}
public static void grabMusicTrack(MusicTrack musictrack) {
var uid = musictrack.y1();
var artist = musictrack.C;
var title = musictrack.f;
var duration = musictrack.h;
var track_id = musictrack.d;
var owner_id = musictrack.e;
var access_key = musictrack.J;
var albumid = musictrack.I;
String album;
if (albumid != null) {
album = albumid.getTitle();
} else {
album = null;
}
if (uid.isEmpty() || artist == null || artist.isEmpty() || title == null || title.isEmpty() || duration == 0) {
Log.d("Scrobbler", "grabTrackInfo: " + "Empty track, info: " + artist + " - " + title + " - " + duration + " - " + uid);
return;
}
if (autocache() && !isCached(uid)) {
if (LibVKXClient.isIntegrationEnabled()){
getInstance().runOnService(service -> {
try {
service.addTrackToCache(track_id, owner_id, (access_key != null) ? access_key : "");
} catch (RemoteException e) {
e.printStackTrace();
}
});
} else {
AudioDownloader.cacheTrack(musictrack);
}
}
scrobbleTrack(duration, artist, title, uid, album);
}
private static String signMD5(Map<String, String> map) {
var sb = new StringBuilder();
for (Map.Entry<String, String> entry : map.entrySet()) {
sb.append(entry.getKey());
sb.append(entry.getValue());
}
sb.append(keysecret);
return MD5(sb.toString());
}
public static void auth(String login, String pass) {
if (login == null || pass == null) {
sendToast(AndroidUtils.getString("lastfm_credentials_empty"));
return;
}
TreeMap<String, String> treeMap = new TreeMap<>(); // create map for request
treeMap.put("method", "auth.getMobileSession");
treeMap.put("api_key", key);
treeMap.put("username", login);
treeMap.put("password", pass);
treeMap.put("api_sig", signMD5(treeMap));
treeMap.put("format", "json");
client.newCall(new NetRequest.Builder().url(url).post().params(treeMap).build()).enqueue(new NetCallback() {
@Override
public void onFailure(NetCall call, IOException e) {
Log.d("Scrobbler", "Auth failed", e);
sendToast(AndroidUtils.getString("auth_error_vtl"));
}
@Override
public void onResponse(NetCall call, NetResponse response) {
try {
var jSONObject = new JSONObject(response.getDataString());
sessionFetcher(jSONObject);
Log.d("Scrobbler", "Auth response " + response.getDataString());
} catch (JSONException e) {
Log.d("Scrobbler", "Auth failed", e);
}
}
});
}
public static void sessionFetcher(JSONObject jsonObject) throws JSONException {
if (!jsonObject.has("session")) {
Log.d("Scrobbler", "Auth failed - no session");
return;
}
var session = jsonObject.getJSONObject("session");
var name = session.getString("name");
var key = session.getString("key");
getDefaultPrefs().edit().putString("username", name).
putString("sessionKey", key).apply();
Log.d("Scrobbler", "Auth success as " + name + ", key " + key);
}
public static void logout() {
edit().remove("username").apply();
edit().remove("sessionKey").apply();
scrobbled.clear();
sendToast(AndroidUtils.getString("lastfm_logout_success"));
}
public static boolean needToBeScrobble(String uid) {
return isLoggedIn() && isScrobblingEnabled() && !scrobbled.contains(uid);
}
public static boolean isLoggedIn() {
return getDefaultPrefs().getString("sessionKey", null) != null;
}
public static boolean isScrobblingEnabled() {
return getPreferences().getBoolean("lastfm_enabled", false);
}
public static String getUserName() {
return getDefaultPrefs().getString("username", null);
}
}
@@ -2,7 +2,6 @@ package ru.vtosters.lite.music.cache;
import static ru.vtosters.lite.music.cache.FileCacheImplementation.getCacheDir;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
import static ru.vtosters.lite.utils.IOUtils.deleteRecursive;
@@ -19,6 +18,7 @@ import androidx.annotation.Nullable;
import com.vk.core.util.ToastUtils;
import com.vk.dto.music.MusicTrack;
import com.vtosters.lite.R;
import org.json.JSONObject;
@@ -30,6 +30,7 @@ import java.util.List;
import bruhcollective.itaysonlab.libvkx.ILibVkxService;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClientImpl;
import ru.vtosters.lite.utils.AndroidUtils;
public class CacheDatabaseDelegate {
private static final int DB_VERSION = 0x1;
@@ -85,7 +86,7 @@ public class CacheDatabaseDelegate {
getHelper().getReadableDatabase().execSQL(formula);
} catch (Exception e) {
e.printStackTrace();
ToastUtils.a(getString("track_bd_insert_err") + " [" + e.getMessage() + "]", true);
ToastUtils.a(AndroidUtils.getString(R.string.track_bd_insert_err) + " [" + e.getMessage() + "]", true);
}
}
@@ -96,7 +97,7 @@ public class CacheDatabaseDelegate {
public static void clear() {
getHelper().getReadableDatabase().execSQL(String.format("DELETE FROM %s", TABLE_NAME));
deleteRecursive(getCacheDir());
sendToast(getString("cached_tracks_deleted"));
sendToast(AndroidUtils.getString(R.string.cached_tracks_deleted));
}
@NonNull
@@ -1,6 +1,5 @@
package ru.vtosters.lite.music.cache;
import android.content.Context;
import android.net.Uri;
import com.vk.dto.music.MusicTrack;
@@ -1,10 +1,9 @@
package ru.vtosters.lite.music.cache.helpers;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserPhoto;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import com.vk.dto.music.Playlist;
import com.vtosters.lite.R;
import org.json.JSONArray;
import org.json.JSONException;
@@ -15,7 +14,7 @@ import java.util.List;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.music.cache.FileCacheImplementation;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
public class PlaylistHelper {
@@ -55,7 +54,7 @@ public class PlaylistHelper {
.put("type", 1)
.put("album_type", "main_only")
.put("title", title)
.put("description", albumId + "/ " + getString("cached_album_warning"))
.put("description", albumId + "/ " + AndroidUtils.getString(R.string.cached_album_warning))
.put("main_artists", new JSONArray()
.put(new JSONObject().put("name", artist)
.put("id", "-1")
@@ -92,8 +91,8 @@ public class PlaylistHelper {
.put("owner_id", getUserId())
.put("type", 0)
.put("album_type", "playlist")
.put("title", getString("cached_tracks_title"))
.put("description", getString("cached_tracks_desc"))
.put("title", AndroidUtils.getString(R.string.cached_tracks_title))
.put("description", AndroidUtils.getString(R.string.cached_tracks_desc))
.put("access_key", "cache")
.put("genres", new JSONArray())
.put("is_following", false)
@@ -135,7 +134,7 @@ public class PlaylistHelper {
.put("data_type", "none")
.put("layout", new JSONObject()
.put("name", "header")
.put("title", getString("cached_tracks_title")));
.put("title", AndroidUtils.getString(R.string.cached_tracks_title)));
}
public static JSONObject getCatalogSeparator() throws JSONException {
@@ -13,6 +13,8 @@ import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import io.reactivex.Observable;
@@ -21,14 +23,13 @@ import ru.vtosters.lite.downloaders.AudioDownloader;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
import ru.vtosters.lite.utils.NetworkUtils;
public class PlaylistInjector {
public final static String CHANNEL_NAME = "VTCH";
private static final ExecutorService executor = Executors.newCachedThreadPool();
public static void injectDownloadPlaylist(Playlist playlist) {
AudioDownloader.cachePlaylist(playlist);
executor.submit(() -> AudioDownloader.cachePlaylist(playlist));
}
public static boolean eligibleForOfflineCaching() {
@@ -1,13 +1,18 @@
package ru.vtosters.lite.music.cache.injectors;
import static ru.vtosters.lite.music.cache.CacheDatabaseDelegate.hasTracks;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getCatalogHeader;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getCatalogPlaylist;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getCatalogSeparator;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getPlaylist;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
import android.util.Log;
import com.vk.catalog2.core.CatalogParser;
import com.vk.catalog2.core.api.dto.CatalogResponse;
import com.vk.dto.music.MusicTrack;
import com.vtosters.lite.R;
import org.json.JSONArray;
import org.json.JSONException;
@@ -20,9 +25,9 @@ import java.util.UUID;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.NetworkUtils;
public class TracklistInjector {
@@ -69,82 +74,73 @@ public class TracklistInjector {
}
private static JSONObject getEmptyCatalog() throws JSONException {
return new JSONObject("{\"catalog\":{\"default_section\":\"cache\",\"sections\":[{\"id\":\"cache\",\"title\":\"" + getString("cached_content_title") + "\",\"blocks\":[{\"data_type\":\"placeholder\",\"id\":\"0\",\"layout\":{\"name\":\"placeholder_big\"},\"placeholder_ids\":[\"_synth_trackEmpty\"]}]}]},\"audios\":[],\"playlists\":[],\"placeholders\":[{\"id\":\"_synth_trackEmpty\",\"title\":\"" + getString("cached_content_empty") + "\",\"text\":\"" + getString("cached_content_empty_desc") + "\",\"buttons\":[]}]}");
return new JSONObject("{\"catalog\":{\"default_section\":\"cache\",\"sections\":[{\"id\":\"cache\",\"title\":\"" + AndroidUtils.getString(R.string.cached_content_title) + "\",\"blocks\":[{\"data_type\":\"placeholder\",\"id\":\"0\",\"layout\":{\"name\":\"placeholder_big\"},\"placeholder_ids\":[\"_synth_trackEmpty\"]}]}]},\"audios\":[],\"playlists\":[],\"placeholders\":[{\"id\":\"_synth_trackEmpty\",\"title\":\"" + AndroidUtils.getString(R.string.cached_content_empty) + "\",\"text\":\"" + AndroidUtils.getString(R.string.cached_content_empty_desc) + "\",\"buttons\":[]}]}");
}
public static void injectIntoExistingCatalog(JSONObject catalogNode) {
Log.d("TracklistInjector", "injectIntoExistingCatalog");
if (!hasTracks()) return;
try {
var sectionsNode = catalogNode.getJSONObject("catalog")
.getJSONArray("sections");
var catalog = catalogNode.getJSONObject("catalog");
var sectionsNode = catalog.getJSONArray("sections");
var firstSection = sectionsNode.getJSONObject(0);
if (!firstSection.getString("url").equals("https://vk.com/audios" + AccountManagerUtils.getUserId() + "?section=all"))
return;
var foundPlaylistBlock = false;
var suitableIndex = 0;
if (!firstSection.getString("url").equals("https://vk.com/audios" + getUserId() + "?section=all"))
return;
var blocks = firstSection.getJSONArray("blocks");
for (int i = 0; i < blocks.length(); i++) {
var block = blocks.getJSONObject(i);
var dataType = block.getString("data_type");
if ("music_audios".equals(dataType)) {
suitableIndex = i - 1;
continue;
if (CacheDatabaseDelegate.hasTracks() && !LibVKXClient.isIntegrationEnabled()) { // inj in playlist list
var noPlaylists = blocks.optJSONObject(0).optJSONArray("buttons").optJSONObject(0).optJSONObject("action").optString("type").equals("create_playlist");
if (noPlaylists) {
catalogNode.put("playlists", new JSONArray().put(getPlaylist()));
Log.d("catalogInjector", "added new pl");
var newBlocks = new JSONArray();
newBlocks
.put(getCatalogHeader())
.put(getCatalogPlaylist())
.put(getCatalogSeparator());
Log.d("catalogInjector", "added cache catalog playlist");
for (int i = 0; i < blocks.length(); i++) {
newBlocks.put(blocks.optJSONObject(i));
}
firstSection.put("blocks", newBlocks);
} else {
try {
catalogNode.optJSONArray("playlists").put(getPlaylist());
Log.d("catalogInjector", "added to exist pl");
for (int i = 0; i < blocks.length(); i++) {
var j = blocks.optJSONObject(i);
var type = j.optString("data_type");
if (type.equals("music_playlists") && j.has("playlists_ids")) {
var newarr = new JSONArray();
var playlists_ids = j.optJSONArray("playlists_ids");
newarr.put(getUserId() + "_-1");
for (int n = 0; n < playlists_ids.length(); n++) {
newarr.put(playlists_ids.optString(n));
}
j.put("playlists_ids", newarr);
break;
}
}
} catch (Exception e) {
Log.d("catalogInjector", e.toString());
}
}
if (!"music_playlists".equals(dataType))
continue;
var playlistIds = block.getJSONArray("playlists_ids");
var newPlaylistIds = new JSONArray()
.put(AccountManagerUtils.getUserId() + "_-1");
for (int j = 0; j < playlistIds.length(); j++)
newPlaylistIds.put(playlistIds.get(j));
block.put("playlists_ids", newPlaylistIds);
// need test
blocks.remove(i);
blocks.put(i, block);
foundPlaylistBlock = true;
}
if (foundPlaylistBlock) {
var playlists = catalogNode.getJSONArray("playlists")
.put(0, PlaylistHelper.createCachedPlaylistMetadata().J());
catalogNode.put("playlists", playlists);
return;
}
var ids = new JSONArray()
.put(0, AccountManagerUtils.getUserId() + "_-1");
var playlistsBlock = new JSONObject()
.put("id", getRandomId())
.put("data_type", "music_playlists")
.put("url", "synth:cache:playlists")
.put("playlists_ids", ids);
var layout = new JSONObject()
.put("name", "large_slider")
.put("owner_id", AccountManagerUtils.getUserId());
playlistsBlock.put("layout", layout);
blocks.put(suitableIndex, playlistsBlock);
firstSection.put("blocks", blocks);
var playlists = new JSONArray()
.put(0, PlaylistHelper.createCachedPlaylistMetadata().J());
catalogNode.put("playlists", playlists);
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
Log.d("TracklistInjector", e.toString());
}
}
@@ -160,8 +156,8 @@ public class TracklistInjector {
var catalogBanner = new JSONObject()
.put("id", 1234)
.put("image_mode", "cover")
.put("title", getString("vkx_integration_title"))
.put("text", getString("vkx_integration_desc"))
.put("title", AndroidUtils.getString(R.string.vkx_integration_title))
.put("text", AndroidUtils.getString(R.string.vkx_integration_desc))
.put("click_action", new JSONObject().put("action", clickAction));
var catalogBanners = new JSONArray()
.put(catalogBanner);
@@ -174,7 +170,7 @@ public class TracklistInjector {
var layout = new JSONObject()
.put("name", "list")
.put("owner_id", AccountManagerUtils.getUserId());
.put("owner_id", getUserId());
audiosBlock.put("layout", layout);
@@ -200,7 +196,7 @@ public class TracklistInjector {
var section = new JSONObject()
.put("id", randomId)
.put("title", getString("saved_tracks_title"))
.put("title", AndroidUtils.getString(R.string.saved_tracks_title))
.put("url", "synth:cache")
.put("blocks", blocks);
@@ -1,14 +1,15 @@
package ru.vtosters.lite.music.callback;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.vtosters.lite.R;
import ru.vtosters.lite.downloaders.notifications.NotificationChannels;
import ru.vtosters.lite.music.Callback;
import ru.vtosters.lite.utils.AndroidUtils;
public class MusicCallbackBuilder {
private static final NotificationManagerCompat notificationManager = NotificationChannels.getNotificationManager();
@@ -35,7 +36,7 @@ public class MusicCallbackBuilder {
public void onSuccess() {
try {
notification
.setContentText(getString("player_download_finished"))
.setContentText(AndroidUtils.getString(R.string.player_download_finished))
.setProgress(0, 0, false)
.setSmallIcon(android.R.drawable.stat_sys_download_done);
notificationManager.notify(notificationId, notification.build());
@@ -48,7 +49,7 @@ public class MusicCallbackBuilder {
@Override
public void onFailure() {
notification.setContentText(getString("load_audio_error")).setProgress(0, 0, false);
notification.setContentText(AndroidUtils.getString(R.string.load_audio_error)).setProgress(0, 0, false);
notificationManager.notify(notificationId, notification.build());
}
@@ -66,7 +67,7 @@ public class MusicCallbackBuilder {
if (progress == playlistSize) {
onSuccess();
} else {
notification.setContentText(String.format(getString("playlist_download_notf"), progress, playlistSize));
notification.setContentText(String.format(AndroidUtils.getString(R.string.playlist_download_notf), progress, playlistSize));
notification.setProgress(playlistSize, progress, false);
}
notificationManager.notify(notificationId, notification.build());
@@ -74,13 +75,13 @@ public class MusicCallbackBuilder {
@Override
public void onSuccess() {
notification.setContentText(getString("player_download_finished"));
notification.setContentText(AndroidUtils.getString(R.string.player_download_finished));
notification.setProgress(0, 0, false);
}
@Override
public void onFailure() {
notification.setContentText(getString("load_audio_error")).setProgress(0, 0, false);
notification.setContentText(AndroidUtils.getString(R.string.load_audio_error)).setProgress(0, 0, false);
notificationManager.notify(notificationId, notification.build());
}
@@ -0,0 +1,293 @@
package ru.vtosters.lite.music.catalog.inject;
import static ru.vtosters.lite.hooks.DateHook.getLocale;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getCatalogHeader;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getCatalogPlaylist;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getCatalogSeparator;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.getPlaylist;
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
import static ru.vtosters.lite.utils.Preferences.dev;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import android.util.Log;
import com.vk.core.network.Network;
import com.vk.core.util.DeviceIdProvider;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
public class CatalogJsonInjector {
private static final OkHttpClient mClient = VtOkHttpClient.getInstance();
public static JSONObject music(JSONObject json) throws JSONException {
var catalog = json.optJSONObject("catalog");
JSONArray oldItems = null;
if (catalog != null) {
oldItems = catalog.optJSONArray("sections");
}
var useOldAppVer = getBoolValue("useOldAppVer", false);
var isUsersCatalog = oldItems.optJSONObject(0).optString("url").equals("https://vk.com/audios" + getUserId() + "?section=" + (useOldAppVer ? "all" : "general"));
if (oldItems != null && isUsersCatalog) {
var blocks = oldItems.optJSONObject(0).optJSONArray("blocks");
if (!useOldAppVer) {
if (blocks != null) {
for (int i = 0; i < blocks.length(); i++) {
var block = blocks.optJSONObject(i);
var layout = block.optJSONObject("layout");
if (layout != null) {
var name = layout.optString("name");
if (name.equals("header_extended")) {
if (layout.has("top_title")) blocks.remove(i);
try {
layout.put("name", "header");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
var playlists = fetchCatalogId("https://vk.com/audio?section=my_playlists");
if (playlists != null) {
var catalogarr = playlists.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
var title = catalogarr.optString("title");
var id = catalogarr.optString("id");
var url = catalogarr.optString("url");
if (dev()) Log.d("VKMusic", "Added " + title + " in music sections");
oldItems.put(new JSONObject().put("id", id).put("title", title).put("url", url));
}
var albums = fetchCatalogId("https://vk.com/audio?section=albums");
if (albums != null) {
var catalogarr = albums.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
var title = catalogarr.optString("title");
var id = catalogarr.optString("id");
var url = catalogarr.optString("url");
if (dev()) Log.d("VKMusic", "Added " + title + " in music sections");
oldItems.put(new JSONObject().put("id", id).put("title", title).put("url", url));
}
var recent = fetchCatalogId("https://vk.com/audio?section=recent");
if (recent != null) {
var catalogarr = recent.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
var title = catalogarr.optString("title");
var id = catalogarr.optString("id");
var url = catalogarr.optString("url");
if (dev()) Log.d("VKMusic", "Added " + title + " in music sections");
oldItems.put(new JSONObject().put("id", id).put("title", title).put("url", url));
}
for (int i = 0; i < oldItems.length(); i++) {
var item = oldItems.optJSONObject(i);
var title = item.optString("title");
var id = item.optString("id");
var url = item.optString("url");
var value = AndroidUtils.getPrefsValue("musicdefcatalog");
Log.d("VKMusic", "title: " + title + " id: " + id + " url: " + url + " value: " + value);
if (url.contains(value) && !value.isEmpty()) {
catalog.put("default_section", id);
if (dev()) Log.d("VKMusic", "Added " + title + " as default music section");
}
}
}
if (CacheDatabaseDelegate.hasTracks() && !LibVKXClient.isIntegrationEnabled()) { // inj in playlist list
var noPlaylists = !json.has("playlists");
if (noPlaylists) {
json.put("playlists", new JSONArray().put(getPlaylist()));
Log.d("catalogInjector", "added new pl");
} else {
try {
json.optJSONArray("playlists").put(getPlaylist());
Log.d("catalogInjector", "added to exist pl");
} catch (Exception e) {
Log.d("catalogInjector", e.toString());
}
}
if (blocks != null && (!useOldAppVer || noPlaylists)) {
var newBlocks = new JSONArray();
newBlocks
.put(getCatalogHeader())
.put(getCatalogPlaylist())
.put(getCatalogSeparator());
Log.d("VKMusic", "added cache catalog playlist");
for (int i = 0; i < blocks.length(); i++) {
newBlocks.put(blocks.optJSONObject(i));
}
oldItems.optJSONObject(0).put("blocks", newBlocks);
}
}
}
return json;
}
public static JSONObject catalogInjector(JSONObject json) {
try {
var section = json.optJSONObject("section");
var useOldAppVer = getBoolValue("useOldAppVer", false);
var isUsersCatalog = section.optString("url").equals("https://vk.com/audios" + getUserId() + "?section=" + (useOldAppVer ? "all" : "general"));
if (isUsersCatalog && CacheDatabaseDelegate.hasTracks() && !LibVKXClient.isIntegrationEnabled()) {
var blocks = section.getJSONArray("blocks");
var noPlaylists = !json.has("playlists");
// Log.d("catalogInjector", "type: " + blocks.optJSONObject(0).optJSONArray("buttons").optJSONObject(0).optJSONObject("action").optString("type"));
if (noPlaylists) {
json.put("playlists", new JSONArray().put(getPlaylist()));
Log.d("catalogInjector", "added new pl");
} else {
try {
json.optJSONArray("playlists").put(getPlaylist());
Log.d("catalogInjector", "added to exist pl");
} catch (Exception e) {
Log.d("catalogInjector", e.toString());
}
}
if (!useOldAppVer || noPlaylists) {
var newBlocks = new JSONArray();
newBlocks
.put(getCatalogHeader())
.put(getCatalogPlaylist())
.put(getCatalogSeparator());
Log.d("catalogInjector", "added cache catalog playlist");
for (int i = 0; i < blocks.length(); i++) {
newBlocks.put(blocks.optJSONObject(i));
}
section.put("blocks", newBlocks);
} else {
for (int i = 0; i < blocks.length(); i++) {
var j = blocks.optJSONObject(i);
var type = j.optString("data_type");
if (type.equals("music_playlists") && j.has("playlists_ids")) {
var newarr = new JSONArray();
var playlists_ids = j.optJSONArray("playlists_ids");
newarr.put(getUserId() + "_-1");
for (int n = 0; n < playlists_ids.length(); n++) {
newarr.put(playlists_ids.optString(n));
}
Log.d("catalogInjector", "added to pl ids");
j.put("playlists_ids", newarr);
break;
}
}
}
}
} catch (JSONException e) {
Log.d("catalogInjector", e.toString());
}
return json;
}
public static JSONObject musiclink(JSONObject json) {
var links = json.optJSONArray("links");
if (links != null && !getBoolValue("useOldAppVer", false)) {
if (links.optJSONObject(0).optString("url").contains("?section=recent")) {
json.remove("links");
if (dev()) Log.d("VKMusic", "Removed links buttons");
}
}
var section = json.optJSONObject("section");
if (section != null) {
var blocks = section.optJSONArray("blocks");
if (blocks != null) {
for (int i = 0; i < blocks.length(); i++) {
var block = blocks.optJSONObject(i);
var layout = block.optJSONObject("layout");
if (layout != null) {
var name = layout.optString("name");
if (name.equals("header_extended")) {
if (layout.has("top_title")) blocks.remove(i);
try {
layout.put("name", "header");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
}
return catalogInjector(json);
}
private static JSONObject fetchCatalogId(String section) {
if (section.isEmpty()) return null;
var request = new Request.a()
.b("https://" + getApi() + "/method/" + "catalog.getAudio"
+ "?v=5.119"
+ "&https=1"
+ "&need_blocks=1"
+ "&lang="
+ getLocale()
+ "&device_id="
+ DeviceIdProvider.d(AndroidUtils.getGlobalContext())
+ "&url="
+ section
+ "&access_token="
+ AccountManagerUtils.getUserToken())
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
try {
return new JSONObject(mClient.a(request).execute().a().g()).getJSONObject("response");
} catch (JSONException | IOException e) {
Log.d("VTLMusic", "Error: " + e.getMessage());
}
return null;
}
}
@@ -7,6 +7,7 @@ import com.arthenica.ffmpegkit.ReturnCode;
import com.vk.core.util.ToastUtils;
import com.vk.dto.music.Artist;
import com.vk.dto.music.MusicTrack;
import com.vtosters.lite.R;
import java.io.File;
import java.io.FileOutputStream;
@@ -27,15 +28,13 @@ public class FFMpeg {
* @return True if success, else false
*/
public static boolean convert(File in, String out, MusicTrack track) {
checkFFMpegLibs();
// convert .ts file to .mp3 file via ffmpeg
var sb = new StringBuilder();
sb.append("-y -i \"").append(in.getAbsolutePath()).append("\"");
sb.append(" -map 0 -dn ");
//sb.append(" -loglevel error");
sb.append(" -hide_banner");
//sb.append(" -hide_banner");
sb.append(" -write_id3v2 1");
String title = null;
@@ -99,7 +98,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(R.string.ffmpegkit_copy);
copyAssets();
}
}
@@ -7,6 +7,7 @@ import com.vk.dto.music.MusicTrack;
import java.io.File;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import ru.vtosters.lite.concurrent.VTExecutors;
import ru.vtosters.lite.music.Callback;
import ru.vtosters.lite.music.M3UDownloader;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
@@ -36,6 +37,9 @@ public class TrackDownloader {
Log.v("TrackDownloader", "Directory created");
else
Log.e("TrackDownloader", "Directory creation failed");
downloader.downloadTrack(track, outDir, callback, cache);
VTExecutors.getMusicDownloadExecutor().execute(
() -> downloader.downloadTrack(track, outDir, callback, cache)
);
}
}
@@ -1,4 +1,4 @@
package ru.vtosters.lite.feature.music;
package ru.vtosters.lite.music.hook;
import android.content.Context;
@@ -1,4 +1,4 @@
package ru.vtosters.lite.hooks.ui;
package ru.vtosters.lite.music.hook;
import static bruhcollective.itaysonlab.libvkx.client.LibVKXClient.asId;
import static bruhcollective.itaysonlab.libvkx.client.LibVKXClient.getInstance;
@@ -19,16 +19,11 @@ import com.vk.music.common.MusicPlaybackLaunchContext;
import com.vtosters.lite.R;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClientImpl;
import ru.vtosters.lite.downloaders.AudioDownloader;
import ru.vtosters.lite.utils.AndroidUtils;
public class MusicBottomSheetHook {
private static final ExecutorService executor = Executors.newCachedThreadPool();
public static ArrayList<MusicAction> hook(ArrayList<MusicAction> actions, MusicTrack musicTrack) {
if (musicTrack.F1()) return actions;
@@ -61,18 +56,18 @@ public class MusicBottomSheetHook {
if (isCached(trackid)) {
actions.add(new MusicAction(
AndroidUtils.getIdentifier("music_action_toggle_download", "id"),
R.id.music_action_toggle_download,
milkshake() ? R.drawable.ic_delete_outline_28 : R.drawable.ic_delete_24,
AndroidUtils.getIdentifier("remove_from_cache", "string"),
R.string.remove_from_cache,
musicTrack.F1() ? R.color.music_action_button_gray_50_alpha : R.color.caption_gray,
R.string.music_talkback_empty,
false
));
} else {
actions.add(new MusicAction(
AndroidUtils.getIdentifier("music_action_toggle_download", "id"),
R.id.music_action_toggle_download,
milkshake() ? R.drawable.ic_download_outline_28 : R.drawable.ic_download_24,
AndroidUtils.getIdentifier("add_to_cache", "string"),
R.string.add_to_cache,
musicTrack.F1() ? R.color.music_action_button_gray_50_alpha : R.color.caption_gray,
R.string.music_talkback_empty,
false
@@ -103,10 +98,10 @@ public class MusicBottomSheetHook {
}
public static boolean injectOnClick(int actionId, MusicTrack track, MusicPlaybackLaunchContext context, Playlist playlist) { // musictrack inj
if (actionId == AndroidUtils.getIdentifier("play_in_vkx", "id"))
if (actionId == R.id.play_in_vkx)
return tryPlayInVKX(track, context, playlist);
if (actionId == AndroidUtils.getIdentifier("remove_from_cache_vkx", "id")) {
if (actionId == R.id.remove_from_cache_vkx) {
getInstance().runOnService(service -> {
try {
service.deleteTrackFromCache(track.d, track.e);
@@ -115,7 +110,7 @@ public class MusicBottomSheetHook {
}
});
return true;
} else if (actionId == AndroidUtils.getIdentifier("add_to_cache_vkx", "id")) {
} else if (actionId == R.id.add_to_cache_vkx) {
getInstance().runOnService(service -> {
try {
service.addTrackToCache(track.d, track.e, (track.J != null) ? track.J : "");
@@ -126,7 +121,7 @@ public class MusicBottomSheetHook {
return true;
}
if (actionId == AndroidUtils.getIdentifier("download_mp3", "id")) {
if (actionId == R.id.download_mp3) {
if (isIntegrationEnabled()) {
getInstance().runOnService(service -> {
try {
@@ -146,15 +141,15 @@ public class MusicBottomSheetHook {
}
public static boolean injectOnClick(int actionId, Playlist playlist) { // playlist inj
if (actionId == AndroidUtils.getIdentifier("play_in_vkx", "id"))
if (actionId == R.id.play_in_vkx)
return tryPlayInVKX(null, null, playlist);
if (actionId == AndroidUtils.getIdentifier("add_to_cache", "id")) {
executor.submit(() -> AudioDownloader.cachePlaylist(playlist));
if (actionId == R.id.add_to_cache) {
AudioDownloader.cachePlaylist(playlist);
return true;
}
if (actionId == AndroidUtils.getIdentifier("remove_from_cache_vkx", "id")) {
if (actionId == R.id.remove_from_cache_vkx) {
getInstance().runOnService(service -> {
try {
service.deletePlaylistFromCache(playlist.a, playlist.b);
@@ -163,7 +158,7 @@ public class MusicBottomSheetHook {
}
});
return true;
} else if (actionId == AndroidUtils.getIdentifier("add_to_cache_vkx", "id")) {
} else if (actionId == R.id.add_to_cache_vkx) {
getInstance().runOnService(service -> {
try {
service.addPlaylistToCache(playlist.a, playlist.b, (playlist.Q != null) ? playlist.Q : "");
@@ -174,7 +169,7 @@ public class MusicBottomSheetHook {
return true;
}
if (actionId == AndroidUtils.getIdentifier("download_mp3", "id")) {
if (actionId == R.id.download_mp3) {
if (isIntegrationEnabled()) {
getInstance().runOnService(service -> {
try {
@@ -184,7 +179,7 @@ public class MusicBottomSheetHook {
}
});
} else {
executor.submit(() -> AudioDownloader.downloadPlaylist(playlist));
AudioDownloader.downloadPlaylist(playlist);
}
return true;
}
@@ -207,9 +202,9 @@ public class MusicBottomSheetHook {
private static MusicAction getPlayInVKXAction() {
return new MusicAction(
AndroidUtils.getIdentifier("play_in_vkx", "id"),
R.id.play_in_vkx,
milkshake() ? R.drawable.ic_music_outline_24 : R.drawable.ic_music_24,
AndroidUtils.getIdentifier("play_in_vkx", "string"),
R.string.play_in_vkx,
R.color.caption_gray,
R.string.music_talkback_empty,
false
@@ -218,9 +213,9 @@ public class MusicBottomSheetHook {
private static MusicAction getRemoveCacheTrackAction() {
return new MusicAction(
AndroidUtils.getIdentifier("remove_from_cache", "id"),
R.id.remove_from_cache,
milkshake() ? R.drawable.ic_delete_outline_28 : R.drawable.ic_delete_24,
AndroidUtils.getIdentifier("remove_from_cache", "string"),
R.string.remove_from_cache,
R.color.caption_gray,
R.string.music_talkback_empty,
false
@@ -229,9 +224,9 @@ public class MusicBottomSheetHook {
private static MusicAction addToCacheTrackAction() {
return new MusicAction(
AndroidUtils.getIdentifier("add_to_cache", "id"),
R.id.add_to_cache,
milkshake() ? R.drawable.ic_add_outline_28 : R.drawable.ic_add_24,
AndroidUtils.getIdentifier("add_to_cache", "string"),
R.string.add_to_cache,
R.color.caption_gray,
R.string.music_talkback_empty,
false
@@ -240,9 +235,9 @@ public class MusicBottomSheetHook {
private static MusicAction getRemoveCacheTrackVkxAction() {
return new MusicAction(
AndroidUtils.getIdentifier("remove_from_cache_vkx", "id"),
R.id.remove_from_cache_vkx,
milkshake() ? R.drawable.ic_delete_outline_28 : R.drawable.ic_delete_24,
AndroidUtils.getIdentifier("remove_from_cache_vkx", "string"),
R.string.remove_from_cache_vkx,
R.color.caption_gray,
R.string.music_talkback_empty,
false
@@ -251,9 +246,9 @@ public class MusicBottomSheetHook {
private static MusicAction addToCacheTrackVkxAction() {
return new MusicAction(
AndroidUtils.getIdentifier("add_to_cache_vkx", "id"),
R.id.add_to_cache_vkx,
milkshake() ? R.drawable.ic_add_outline_28 : R.drawable.ic_add_24,
AndroidUtils.getIdentifier("add_to_cache_vkx", "string"),
R.string.add_to_cache_vkx,
R.color.caption_gray,
R.string.music_talkback_empty,
false
@@ -262,9 +257,9 @@ public class MusicBottomSheetHook {
private static MusicAction downloadAsMp3Action() {
return new MusicAction(
AndroidUtils.getIdentifier("download_mp3", "id"),
R.id.download_mp3,
milkshake() ? R.drawable.ic_download_outline_28 : R.drawable.ic_download_24,
AndroidUtils.getIdentifier("download_mp3", "string"),
R.string.download_mp3,
R.color.caption_gray,
R.string.music_talkback_empty,
false
@@ -1,7 +1,5 @@
package ru.vtosters.lite.music.notification;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import android.app.Notification;
import android.os.Build;
@@ -9,6 +7,7 @@ import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.vk.dto.music.MusicTrack;
import com.vtosters.lite.R;
import ru.vtosters.lite.downloaders.notifications.NotificationChannels;
import ru.vtosters.lite.utils.AccountManagerUtils;
@@ -20,7 +19,7 @@ public class MusicNotificationBuilder {
public 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(getString("audio_downloading"))
.setContentTitle(AndroidUtils.getString(R.string.audio_downloading))
.setContentText(track.toString())
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
@@ -33,7 +32,7 @@ public class MusicNotificationBuilder {
public static NotificationCompat.Builder buildPlaylistDownloadNotification(String playlistName, int id) {
var notificationBuilder = new NotificationCompat.Builder(AndroidUtils.getGlobalContext(), NotificationChannels.MUSIC_PLAYLIST_DOWNLOAD_CHANNEL_ID)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentTitle(getString("playlist_downloading") + " «" + playlistName + "»")
.setContentTitle(AndroidUtils.getString(R.string.playlist_downloading) + " «" + playlistName + "»")
.setContentText(playlistName)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
@@ -46,8 +45,8 @@ public class MusicNotificationBuilder {
public static NotificationCompat.Builder buildAllAudiosDownloadNotification(int id) {
var notificationBuilder = new NotificationCompat.Builder(AndroidUtils.getGlobalContext(), NotificationChannels.MUSIC_PLAYLIST_DOWNLOAD_CHANNEL_ID)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentTitle(getString("notf_audio_dl_user") + " " + AccountManagerUtils.getUsername())
.setContentText(getString("all_audio"))
.setContentTitle(AndroidUtils.getString(R.string.notf_audio_dl_user) + " " + AccountManagerUtils.getUsername())
.setContentText(AndroidUtils.getString(R.string.all_audio))
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
.setAutoCancel(true)
@@ -66,7 +65,7 @@ public class MusicNotificationBuilder {
builder.setSmallIcon(com.vtosters.lite.R.drawable.ic_download_outline_28)
.setShowWhen(false)
.setContentTitle(getString("cached_track") + ": " + track.toString());
.setContentTitle(AndroidUtils.getString(R.string.cached_track) + ": " + track.toString());
notificationManager.notify(track.y1().hashCode(), builder.build());
}
@@ -8,24 +8,32 @@ import java.util.Arrays;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
public class GithubList {
private static final OkHttpClient mClient = new OkHttpClient();
private static final OkHttpClient mClient = VtOkHttpClient.getInstance();
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();
try {
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")));
} catch (Exception e) {
Log.d(proxyname, "Failed to fetch data, link: " + link);
if (!response.contains(":")) {
Log.d(proxyname, "No proxy found");
return null;
}
Log.d(proxyname, response);
return new ArrayList<>(Arrays.asList(response.split("\n")));
}
}
@@ -4,10 +4,11 @@ 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 com.vtosters.lite.R;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,7 +36,7 @@ public class Jetkai {
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
if (RandomProxy.showProxyResult) {
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
RandomProxy.showProxyResult = false;
RandomProxy.showProxyResult = false;
}
@@ -4,10 +4,11 @@ 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 com.vtosters.lite.R;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,7 +36,7 @@ public class TheSpeedX {
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
if (RandomProxy.showProxyResult) {
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
RandomProxy.showProxyResult = false;
}
@@ -4,10 +4,11 @@ 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 com.vtosters.lite.R;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,7 +36,7 @@ public class Jetkai {
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
if (RandomProxy.showProxyResult) {
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
RandomProxy.showProxyResult = false;
}
@@ -4,10 +4,11 @@ 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 com.vtosters.lite.R;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,7 +36,7 @@ public class Roosterkid {
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
if (RandomProxy.showProxyResult) {
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
RandomProxy.showProxyResult = false;
}
@@ -4,10 +4,11 @@ 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 com.vtosters.lite.R;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,7 +36,7 @@ public class Hookzof {
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
if (RandomProxy.showProxyResult) {
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
RandomProxy.showProxyResult = false;
}
@@ -4,10 +4,11 @@ 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 com.vtosters.lite.R;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,7 +36,7 @@ public class Jetkai {
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
if (RandomProxy.showProxyResult) {
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
RandomProxy.showProxyResult = false;
}
@@ -4,10 +4,11 @@ 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 com.vtosters.lite.R;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,7 +36,7 @@ public class Roosterkid {
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
if (RandomProxy.showProxyResult) {
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
RandomProxy.showProxyResult = false;
}
@@ -4,10 +4,11 @@ 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 com.vtosters.lite.R;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,7 +36,7 @@ public class TheSpeedX {
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
if (RandomProxy.showProxyResult) {
AndroidUtils.sendToast(getString("proxy_setup_success") + " " + proxy);
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
RandomProxy.showProxyResult = false;
}
@@ -14,6 +14,8 @@ import android.util.Log;
import androidx.annotation.Nullable;
import com.vtosters.lite.R;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -46,12 +48,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(), AndroidUtils.getString(R.string.logfile_error), 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(), AndroidUtils.getString(R.string.logfile_saved), LENGTH_SHORT).show();
stopSelf();
return START_NOT_STICKY;
@@ -1,7 +1,6 @@
package ru.vtosters.lite.tgs;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -12,6 +11,7 @@ import com.vk.dto.common.Attachment;
import com.vk.dto.stickers.StickerItem;
import com.vk.dto.stickers.StickerStockItem;
import com.vk.im.engine.models.attaches.Attach;
import com.vtosters.lite.R;
import com.vtosters.lite.attachments.PendingGraffitiAttachment;
import com.vtosters.lite.im.AppAttachToImAttachConverter;
import com.vtosters.lite.upload.Upload;
@@ -23,6 +23,8 @@ import org.json.JSONObject;
import java.util.List;
import java.util.Stack;
import ru.vtosters.lite.utils.AndroidUtils;
public class TGRoot {
public static final int N = 76820000;
public static final int X = 976820000;
@@ -32,11 +34,11 @@ public class TGRoot {
public static String getSummary() {
switch (TGPref.getTGConnectMethod()) {
case 0:
return getString("ctypedirect");
return AndroidUtils.getString(R.string.ctypedirect);
case 2:
return getString("ctypesocks");
return AndroidUtils.getString(R.string.ctypesocks);
default:
return getString("ctypedisabled");
return AndroidUtils.getString(R.string.ctypedisabled);
}
}
@@ -14,7 +14,12 @@ public abstract class BaseTranslator {
private static final int YANDEX = 0;
private static final int GOOGLE = 1;
private static final int DEEPL = 2;
private final LruCache<String, String> cache = new LruCache<>(200);
private final LruCache<String, String> cache = new LruCache<>(200) {
@Override
protected String create(@NonNull String text) {
return translate(text, getToLanguage());
}
};
public static String getToLanguage() {
var lang = preferences.getString("lang_target", "system");
@@ -43,11 +48,8 @@ public abstract class BaseTranslator {
@NonNull
public final String getTranslation(String text) {
var val = cache.get(text);
if (val != null)
return val;
var translation = translate(text, getToLanguage());
cache.put(text, translation);
return translation;
String v = cache.get(text);
assert v != null;
return v;
}
}
@@ -10,17 +10,17 @@ import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
public class DeepLTranslator extends BaseTranslator {
private static final OkHttpClient client = new OkHttpClient();
private static final OkHttpClient client = VtOkHttpClient.getInstance();
private static final Pattern pattern = Pattern.compile("[i]");
private static final String REQUEST_BODY_FORMAT = "{\n" +
" \"method\": \"LMT_handle_texts\",\n" +
@@ -49,14 +49,17 @@ public class DeepLTranslator extends BaseTranslator {
private static DeepLTranslator instance;
public static DeepLTranslator getInstance() {
if (instance == null)
instance = new DeepLTranslator();
return instance;
// Race safe when the new object does not contain the state of the previous one
DeepLTranslator translator = instance;
if (translator == null) {
return instance = new DeepLTranslator();
}
return translator;
}
private static Long getTimestamp(int iNumber) {
var now = System.currentTimeMillis();
return Long.valueOf((((long) iNumber) + now) - (now % ((long) iNumber)));
return (((long) iNumber) + now) - (now % ((long) iNumber));
}
@NonNull
@@ -73,16 +76,16 @@ public class DeepLTranslator extends BaseTranslator {
i++;
}
var id = new AtomicLong(ThreadLocalRandom.current().nextLong(Long.parseLong("10000000000")));
var id = ThreadLocalRandom.current().nextLong(1, 10000000000L);
var requestBody = String.format(REQUEST_BODY_FORMAT,
id.incrementAndGet(),
id,
text,
tl,
getTimestamp(i)
);
requestBody = (id.get() + 3) % 13 == 0 || (id.get() + 5) % 29 == 0
requestBody = (id + 3) % 13 == 0 || (id + 5) % 29 == 0
? requestBody.replace("hod\":\"", "hod\" : \"")
: requestBody.replace("hod\":\"", "hod\": \"");
@@ -10,10 +10,11 @@ import java.net.URLEncoder;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
public class GoogleTranslator extends BaseTranslator {
private static final OkHttpClient client = new OkHttpClient();
private static final OkHttpClient client = VtOkHttpClient.getInstance();
private static final String[] devices = new String[]{
"Linux; U; Android 10; Pixel 4",
"Linux; U; Android 10; Pixel 4 XL",
@@ -38,9 +39,11 @@ public class GoogleTranslator extends BaseTranslator {
private static GoogleTranslator instance;
public static GoogleTranslator getInstance() {
if (instance == null)
instance = new GoogleTranslator();
return instance;
// Race safe when the new object does not contain the state of the previous one
GoogleTranslator translator = instance;
if (translator == null)
return instance = new GoogleTranslator();
return translator;
}
@NonNull
@@ -13,18 +13,21 @@ import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
public class YandexTranslator extends BaseTranslator {
private static final OkHttpClient client = new OkHttpClient();
private static final OkHttpClient client = VtOkHttpClient.getInstance();
private static final String uuid = UUID.randomUUID().toString().replace("-", "");
private static YandexTranslator instance;
public static YandexTranslator getInstance() {
if (instance == null)
instance = new YandexTranslator();
return instance;
// Race safe when the new object does not contain the state of the previous one
YandexTranslator translator = instance;
if (translator == null)
return instance = new YandexTranslator();
return translator;
}
@NonNull
@@ -26,11 +26,16 @@ import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
import com.vtosters.lite.ui.MaterialSwitchPreference;
import java.util.Objects;
public class PreferencesUtil {
public static void addListPreference(MaterialPreferenceToolbarFragment fragment, String key, String def, CharSequence title, CharSequence[] entries, CharSequence[] entriesValue) {
public static void addListPreference(
MaterialPreferenceToolbarFragment fragment,
String key,
String def,
CharSequence title,
CharSequence[] entries,
CharSequence[] entriesValue
) {
ListPreference preference = new ListPreference(getGlobalContext());
preference.setEntries(entries);
preference.setEntryValues(entriesValue);
@@ -41,7 +46,17 @@ public class PreferencesUtil {
fragment.getPreferenceScreen().addPreference(preference); // fragment.getPreferenceScreen().addPreference(preference)
}
public static void addListPreferenceIcon(MaterialPreferenceToolbarFragment fragment, String key, String def, CharSequence title, String icon, CharSequence summary, CharSequence[] entries, CharSequence[] entriesValue, Preference.OnPreferenceChangeListener listener) {
public static void addListPreferenceIcon(
MaterialPreferenceToolbarFragment fragment,
String key,
String def,
CharSequence title,
int iconRes,
CharSequence summary,
CharSequence[] entries,
CharSequence[] entriesValue,
Preference.OnPreferenceChangeListener listener
) {
ListPreference preference = new ListPreference(getGlobalContext());
preference.setEntries(entries);
preference.setEntryValues(entriesValue);
@@ -53,12 +68,18 @@ public class PreferencesUtil {
preference.setValue(def);
preference.setOnPreferenceChangeListener(listener);
if (icon != null)
preference.setIcon(setTint(getGlobalContext(), getDrawable(getGlobalContext(), icon))); // preference.setIcon
if (iconRes != 0)
preference.setIcon(setTint(getGlobalContext(), getDrawable(getGlobalContext(), iconRes))); // preference.setIcon
fragment.getPreferenceScreen().addPreference(preference); // fragment.getPreferenceScreen().addPreference(preference)
}
public static void addMaterialSwitchPreference(MaterialPreferenceToolbarFragment materialPreferenceToolbarFragment, String key, CharSequence title, CharSequence summary, boolean defValue) {
public static void addMaterialSwitchPreference(
MaterialPreferenceToolbarFragment materialPreferenceToolbarFragment,
String key,
CharSequence title,
CharSequence summary,
boolean defValue
) {
MaterialSwitchPreference materialSwitchPreference = new MaterialSwitchPreference(getGlobalContext());
materialSwitchPreference.setTitle(title); // setTitle
materialSwitchPreference.setSummary(summary); // setSummary
@@ -68,21 +89,37 @@ public class PreferencesUtil {
materialPreferenceToolbarFragment.getPreferenceScreen().addPreference(materialSwitchPreference); // materialPreferenceToolbarFragment.getPreferenceScreen().addPreference(preference)
}
public static void addMaterialSwitchPreference(MaterialPreferenceToolbarFragment fragment, String key, CharSequence title, CharSequence summary, int icon, boolean defValue, Preference.OnPreferenceChangeListener listener) {
MaterialSwitchPreference materialSwitchPreference = new MaterialSwitchPreference(getGlobalContext());
materialSwitchPreference.setTitle(title); // setTitle
materialSwitchPreference.setSummary(summary); // setSummary
materialSwitchPreference.setKey(key); // setKey
materialSwitchPreference.setDefaultValue(defValue); // setDefaultValue
materialSwitchPreference.setOnPreferenceChangeListener(listener); // setOnPreferenceClickListener
// public static void addMaterialSwitchPreference(
// MaterialPreferenceToolbarFragment fragment,
// String key,
// CharSequence title,
// CharSequence summary,
// int iconRes,
// boolean defValue,
// Preference.OnPreferenceChangeListener listener
// ) {
// MaterialSwitchPreference materialSwitchPreference = new MaterialSwitchPreference(getGlobalContext());
// materialSwitchPreference.setTitle(title); // setTitle
// materialSwitchPreference.setSummary(summary); // setSummary
// materialSwitchPreference.setKey(key); // setKey
// materialSwitchPreference.setDefaultValue(defValue); // setDefaultValue
// materialSwitchPreference.setOnPreferenceChangeListener(listener); // setOnPreferenceClickListener
//
// if (iconRes != 0)
// materialSwitchPreference.setIcon(setTint(getGlobalContext(), Objects.requireNonNull(ContextCompat.getDrawable(getGlobalContext(), iconRes)))); // preference.setIcon
//
// fragment.getPreferenceScreen().addPreference(materialSwitchPreference); // fragment.getPreferenceScreen().addPreference(preference)
// }
if (icon != 1)
materialSwitchPreference.setIcon(setTint(getGlobalContext(), Objects.requireNonNull(ContextCompat.getDrawable(getGlobalContext(), icon)))); // preference.setIcon
fragment.getPreferenceScreen().addPreference(materialSwitchPreference); // fragment.getPreferenceScreen().addPreference(preference)
}
public static void addMaterialSwitchPreference(MaterialPreferenceToolbarFragment fragment, String key, CharSequence title, CharSequence summary, String icon, boolean defValue, Preference.OnPreferenceChangeListener listener) {
public static void addMaterialSwitchPreference(
MaterialPreferenceToolbarFragment fragment,
String key,
CharSequence title,
CharSequence summary,
int iconRes,
boolean defValue,
Preference.OnPreferenceChangeListener listener
) {
MaterialSwitchPreference materialSwitchPreference = new MaterialSwitchPreference(getGlobalContext());
materialSwitchPreference.setTitle(title); // setTitle
materialSwitchPreference.setSummary(summary); // setSummary
@@ -90,14 +127,19 @@ public class PreferencesUtil {
materialSwitchPreference.setDefaultValue(defValue); // setDefaultValue
fragment.getPreferenceScreen().addPreference(materialSwitchPreference); // materialPreferenceToolbarFragment.getPreferenceScreen().addPreference(preference)
if (icon != null)
materialSwitchPreference.setIcon(setTint(getGlobalContext(), getDrawable(getGlobalContext(), icon))); // preference.setIcon
if (iconRes != 0)
materialSwitchPreference.setIcon(setTint(getGlobalContext(), getDrawable(getGlobalContext(), iconRes))); // preference.setIcon
materialSwitchPreference.setOnPreferenceChangeListener(listener); // setOnPreferenceClickListener(listener)
fragment.getPreferenceScreen().addPreference(materialSwitchPreference); // fragment.getPreferenceScreen().addPreference(preference)
}
public static void addPreference(MaterialPreferenceToolbarFragment fragment, String key, CharSequence title, CharSequence summary) {
public static void addPreference(
MaterialPreferenceToolbarFragment fragment,
String key,
CharSequence title,
CharSequence summary
) {
Preference preference = new Preference(getGlobalContext());
preference.setSummary(summary); // setSummary
preference.setTitle(title); // setTitle
@@ -106,32 +148,51 @@ public class PreferencesUtil {
fragment.getPreferenceScreen().addPreference(preference); // fragment.getPreferenceScreen().addPreference(preference)
}
public static void addPreference(MaterialPreferenceToolbarFragment fragment, CharSequence title, CharSequence summary, @Nullable String icon, Preference.OnPreferenceClickListener listener) {
public static void addPreference(
MaterialPreferenceToolbarFragment fragment,
CharSequence title,
CharSequence summary,
int iconRes,
Preference.OnPreferenceClickListener listener
) {
Preference preference = new Preference(getGlobalContext());
preference.setSummary(summary); // setSummary
preference.setTitle(title); // setTitle
if (icon != null)
preference.setIcon(setTint(getGlobalContext(), getDrawable(getGlobalContext(), icon))); // preference.setIcon
if (iconRes != 0)
preference.setIcon(setTint(getGlobalContext(), getDrawable(getGlobalContext(), iconRes))); // preference.setIcon
preference.setOnPreferenceClickListener(listener); // preference.setOnPreferenceClickListener(listener)
fragment.getPreferenceScreen().addPreference(preference); // fragment.getPreferenceScreen().addPreference(preference)
}
public static void addPreference(MaterialPreferenceToolbarFragment fragment, String key, CharSequence title, CharSequence summary, @Nullable String icon, Preference.OnPreferenceClickListener listener) {
public static void addPreference(
MaterialPreferenceToolbarFragment fragment,
String key,
CharSequence title,
CharSequence summary,
int iconRes,
Preference.OnPreferenceClickListener listener) {
Preference preference = new Preference(getGlobalContext());
preference.setSummary(summary); // setSummary
preference.setTitle(title); // setTitle
preference.setKey(key); // setKey
if (icon != null)
preference.setIcon(setTint(getGlobalContext(), getDrawable(getGlobalContext(), icon))); // preference.setIcon
if (iconRes != 0)
preference.setIcon(setTint(getGlobalContext(), getDrawable(getGlobalContext(), iconRes))); // preference.setIcon
preference.setOnPreferenceClickListener(listener); // preference.setOnPreferenceClickListener(listener)
fragment.getPreferenceScreen().addPreference(preference); // fragment.getPreferenceScreen().addPreference(preference)
}
public static void addPreferenceDrawable(MaterialPreferenceToolbarFragment fragment, String key, CharSequence title, CharSequence summary, @Nullable Drawable icon, Preference.OnPreferenceClickListener listener) {
public static void addPreferenceDrawable(
MaterialPreferenceToolbarFragment fragment,
String key,
CharSequence title,
CharSequence summary,
@Nullable Drawable icon,
Preference.OnPreferenceClickListener listener
) {
Preference preference = new Preference(getGlobalContext());
preference.setSummary(summary); // setSummary
preference.setTitle(title); // setTitle
@@ -210,9 +271,8 @@ public class PreferencesUtil {
return typedValue.data;
}
private static Drawable getDrawable(Context ctx, String name) {
var id = ctx.getResources().getIdentifier(name, "drawable", ctx.getPackageName());
return ContextCompat.getDrawable(ctx, id);
private static Drawable getDrawable(Context ctx, int drawableRes) {
return ContextCompat.getDrawable(ctx, drawableRes);
}
public interface EditTextPrefChangeListener {
@@ -11,7 +11,7 @@ import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import ru.vtosters.lite.utils.AndroidUtils;
import com.vtosters.lite.R;
public class APKInstallActivity extends AppCompatActivity {
public static final int REQUEST_INSTALL_PERMISSION = 1;
@@ -67,7 +67,8 @@ public class APKInstallActivity extends AppCompatActivity {
startActivity(intent);
} catch (Exception e) {
Toast.makeText(this, AndroidUtils.getString("apk_install_error") + " " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
e.printStackTrace();
Toast.makeText(this, getString(R.string.apk_install_error) + " " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
finish();
@@ -2,7 +2,6 @@ package ru.vtosters.lite.ui.adapters;
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import android.content.res.ColorStateList;
import android.graphics.Typeface;
@@ -17,6 +16,8 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.vtosters.lite.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -261,7 +262,7 @@ public class CategorizedAdapter extends RecyclerView.Adapter<CategorizedAdapter.
}
public void bindCategory(boolean fist) {
mCategoryTitle.setText(getString(fist ? "selected_items" : "unselected_items"));
mCategoryTitle.setText(fist ? R.string.selected_items : R.string.unselected_items);
mCategoryTitleContainer.setVisibility(View.VISIBLE);
mMovingItemContainer.setVisibility(View.INVISIBLE);
}
@@ -18,6 +18,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.TextViewCompat;
import com.vtosters.lite.R;
import java.util.ArrayList;
import java.util.List;
@@ -92,11 +94,11 @@ public class ImagineArrayAdapter extends ArrayAdapter<ImagineArrayAdapter.Imagin
// if make radiobutton without layout inflation it can't be unclickable
var checkedTextView = (CheckedTextView) LayoutInflater.from(getContext())
.inflate(AndroidUtils.getIdentifier("select_dialog_singlechoice_material", "layout"), parent, false);
.inflate(R.layout.select_dialog_singlechoice_material, parent, false);
// for amoled
var tintList = new ColorStateList(
new int[][] { new int[] { android.R.attr.state_checked }, new int[] { -android.R.attr.state_checked }},
new int[] { ThemesUtils.getAccentColor(), ThemesUtils.getSTextAttr() });
new int[][]{new int[]{android.R.attr.state_checked}, new int[]{-android.R.attr.state_checked}},
new int[]{ThemesUtils.getAccentColor(), ThemesUtils.getSTextAttr()});
TextViewCompat.setCompoundDrawableTintList(checkedTextView, tintList);
checkedTextView.setChecked(position == mSelectedIndex);
container.addView(checkedTextView, LayoutUtils.createLinear(AndroidUtils.dp2px(50.0f), -2));
@@ -23,7 +23,7 @@ public class MessagesPreviewAdapter extends RecyclerView.Adapter<MessagesPreview
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 = AndroidUtils.getArray(R.array.wallpaper_change_dialog);
private static int getColorFromAttribute(Context context, int attrId) {
TypedValue typedValue = new TypedValue();
@@ -1,7 +1,6 @@
package ru.vtosters.lite.ui.adapters;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.AndroidUtils.getResources;
import static ru.vtosters.lite.utils.ThemesUtils.getSTextAttr;
import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
@@ -22,12 +21,12 @@ import androidx.recyclerview.widget.RecyclerView;
import com.aefyr.tsg.g2.TelegramStickersPack;
import com.aefyr.tsg.g2.TelegramStickersService;
import com.vtosters.lite.R;
import java.io.File;
import ru.vtosters.lite.tgs.TGPref;
import ru.vtosters.lite.ui.components.IItemMovingListener;
import ru.vtosters.lite.utils.AndroidUtils;
public class StickerPackAdapter extends RecyclerView.Adapter<StickerPackAdapter.StickerPackViewHolder> implements IItemMovingListener {
private static final TelegramStickersService sService = TelegramStickersService.getInstance(getGlobalContext());
@@ -36,13 +35,12 @@ public class StickerPackAdapter extends RecyclerView.Adapter<StickerPackAdapter.
@NonNull
@Override
public StickerPackViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
int resID = getIdentifier("tgs_entry", "layout");
var view = LayoutInflater.from(parent.getContext()).inflate(resID, parent, false);
var view = LayoutInflater.from(parent.getContext()).inflate(R.layout.tgs_entry, parent, false);
var holder = new StickerPackViewHolder(view);
holder.mStickerPreview.setImageResource(getIdentifier("icon_vk_104", "drawable"));
holder.mUpdateButton.setImageDrawable(recolorDrawable(getResources().getDrawable(getIdentifier("ic_camera_switch_48", "drawable"))));
holder.mDeleteButton.setImageDrawable(recolorDrawable(getResources().getDrawable(getIdentifier("vkim_ic_msg_delete", "drawable"))));
holder.mStickerPreview.setImageResource(R.drawable.icon_vk_104);
holder.mUpdateButton.setImageDrawable(recolorDrawable(getResources().getDrawable(R.drawable.ic_camera_switch_outline_24)));
holder.mDeleteButton.setImageDrawable(recolorDrawable(getResources().getDrawable(R.drawable.ic_delete_outline_28)));
return holder;
}
@@ -132,7 +130,7 @@ public class StickerPackAdapter extends RecyclerView.Adapter<StickerPackAdapter.
mName.setText(pack.title);
mSwitch.setChecked(pack.enabled);
mSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> sService.setPackEnabled(pack, isChecked, false));
mStickersCount.setText(pack.stickersCount + " " + AndroidUtils.getString("stickerscount"));
mStickersCount.setText(pack.stickersCount + " " + mStickersCount.getContext().getString(R.string.stickerscount));
// Color костыль
int color = getTextAttr();
@@ -11,6 +11,8 @@ import android.content.SharedPreferences;
import android.util.Log;
import android.widget.Toast;
import com.vtosters.lite.R;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@@ -43,7 +45,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(), AndroidUtils.getString(R.string.no_data_to_backup), LENGTH_SHORT).show();
return;
}
@@ -55,10 +57,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(), AndroidUtils.getString(R.string.backup_saved_in) + " " + file.getAbsolutePath(), LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getGlobalContext(), AndroidUtils.getString("backup_save_error"), LENGTH_SHORT).show();
Toast.makeText(getGlobalContext(), AndroidUtils.getString(R.string.backup_save_error), LENGTH_SHORT).show();
}
}
@@ -71,10 +73,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(), AndroidUtils.getString(R.string.backup_saved_in) + " " + file.getAbsolutePath(), LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getGlobalContext(), AndroidUtils.getString("backup_save_error"), LENGTH_SHORT).show();
Toast.makeText(getGlobalContext(), AndroidUtils.getString(R.string.backup_save_error), LENGTH_SHORT).show();
}
}
@@ -1,9 +1,6 @@
package ru.vtosters.lite.ui.components;
import static ru.vtosters.lite.utils.About.getBuildNumber;
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;
@@ -17,6 +14,8 @@ import android.net.Uri;
import android.os.Build;
import android.util.Log;
import com.vtosters.lite.R;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -65,13 +64,13 @@ public class CrashReporter {
var psaveLogIntent = PendingIntent.getService(getGlobalContext(), 0, saveLogIntent, PendingIntent.FLAG_CANCEL_CURRENT);
var builder = new Notification.Builder(getGlobalContext());
builder.setSmallIcon(getIdentifier("ic_bug_24", "drawable"));
builder.setContentTitle(getString("vtl_crashed"));
builder.setSmallIcon(R.drawable.ic_bug_24);
builder.setContentTitle(activity.getString(R.string.vtl_crashed));
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));
builder.addAction(new Notification.Action(0, activity.getString(R.string.vtl_crash_upload), PendingIntent.getActivity(getGlobalContext(), (int) (Math.random() * 100.0d), foxbinIntent, PendingIntent.FLAG_CANCEL_CURRENT)));
builder.addAction(new Notification.Action(0, activity.getString(R.string.vtl_crash_save), psaveLogIntent));
if (Build.VERSION.SDK_INT >= 26) {
builder.setChannelId("crashes");
@@ -1,24 +1,25 @@
package ru.vtosters.lite.ui.components;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
import android.content.res.Resources;
import androidx.fragment.app.FragmentTransaction;
import com.vtosters.lite.R;
public class FragAnimationKit {
// Q
private static final int actOpenEnter = getIdentifier("q_enter", "anim");
private static final int actOpenExit = getIdentifier("q_exit", "anim");
private static final int actCloseEnter = getIdentifier("q_pop_enter", "anim");
private static final int actCloseExit = getIdentifier("q_pop_exit", "anim");
private static final int actOpenEnter = R.anim.q_enter;
private static final int actOpenExit = R.anim.q_exit;
private static final int actCloseEnter = R.anim.q_pop_enter;
private static final int actCloseExit = R.anim.q_pop_exit;
// Slide
private static final int SactOpenEnter = getIdentifier("legacy_enter", "anim");
private static final int SactOpenExit = getIdentifier("legacy_exit", "anim");
private static final int SactCloseEnter = getIdentifier("legacy_pop_enter", "anim");
private static final int SactCloseExit = getIdentifier("legacy_pop_exit", "anim");
private static final int SactOpenEnter = R.anim.legacy_enter;
private static final int SactOpenExit = R.anim.legacy_exit;
private static final int SactCloseEnter = R.anim.legacy_pop_enter;
private static final int SactCloseExit = R.anim.legacy_pop_exit;
// System
private static final Resources resources = Resources.getSystem();
private static final int SSactOpenEnter = resources.getIdentifier("activity_open_enter", "anim", "android");
@@ -27,11 +27,11 @@ public class IconManager {
// available labels list
public static List<String> sLabels = Arrays.asList(
"standard", "vt"
"standard", "vt", "vkontakte"
);
public static List<String> sLabelsNames = Arrays.asList(
"VK", "VTLite"
"VK", "VTLite", "VKontakte"
);
// available icons list for verified users
@@ -43,15 +43,6 @@ public class IconManager {
"VK", "VTLite", "Navy", "Tiger", "Spring", "Sea", "Sakura", "Party", "Paint", "Flamingo", "Old Logo", "Navy alter", "Tiger alter", "Spring alter", "Sea alter", "Sakura alter", "Party alter", "Paint alter", "Flamingo alter"
);
// available labels list for verified users
public static List<String> sLabelsPlus = Arrays.asList(
"standard", "vt", "vkontakte"
);
public static List<String> sLabelsPlusNames = Arrays.asList(
"VK", "VTLite", "VKontakte"
);
public static List<String> icons() {
return hasVerification() && isValidSignature() ? sIconsPlusNames : sIconsNames; // delete later sdk check
}
@@ -73,16 +64,8 @@ public class IconManager {
Log.d("IconManager", "iconSwitcher: icon = " + icon + ", appname = " + appName);
List<String> iconsList;
List<String> labelsList;
if (hasVerification() && isValidSignature()) {
iconsList = sIconsPlus;
labelsList = sLabelsPlus;
} else {
iconsList = sIcons;
labelsList = sLabels;
}
List<String> iconsList = (hasVerification() && isValidSignature()) ? sIconsPlus : sIcons;
List<String> labelsList = sLabels;
if (oldIcon != null && oldAppName != null) {
oldIconIndex = iconsList.indexOf(oldIcon);
@@ -7,9 +7,10 @@ import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
import android.app.Activity;
import com.vtosters.lite.R;
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;
@@ -18,28 +19,26 @@ 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>();
var filtersSet = getDefaultPrefs().getStringSet("news_feed_items_set", Collections.emptySet());
var list = new ArrayList<VBListItem>(filtersSet.size());
if (filtersSet.size() == 0) {
sendToast(AndroidUtils.getString("newsfeed_list_update_feed"));
if (filtersSet.isEmpty()) {
sendToast(activity.getString(R.string.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);
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)));
}
list.add(new VBListItem(id, title, selectedItems.contains(id)));
}
VBottomSheetBuilder.show(activity, new VBottomSheetBuilder.VBSContent(
AndroidUtils.getString("newsfeed_list_choose_to_hide"),
activity.getString(R.string.newsfeed_list_choose_to_hide),
buildListOf(activity, list),
new VBottomSheetBuilder.VBSContent.VBSButton(
AndroidUtils.getString("save"),
activity.getString(R.string.save),
() -> {
var newSelectedItems = "";
for (VBListItem item : list)
@@ -48,15 +47,17 @@ public class NewsfeedListManager {
getDefaultPrefs().edit()
.putString("news_feed_selected_items", newSelectedItems)
.apply();
sendToast(AndroidUtils.getString("newsfeed_list_update_feed_to_work"));
sendToast(activity.getString(R.string.newsfeed_list_update_feed_to_work));
}
)
));
}
public static void resetHideItems() {
getDefaultPrefs().edit().remove("news_feed_selected_items").remove("news_feed_items_set")
getDefaultPrefs().edit()
.remove("news_feed_selected_items")
.remove("news_feed_items_set")
.apply();
sendToast(AndroidUtils.getString("newsfeed_list_hidden_reseted"));
sendToast(AndroidUtils.getString(R.string.newsfeed_list_hidden_reseted));
}
}
@@ -4,6 +4,8 @@ import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
import android.os.Build;
import com.vtosters.lite.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -87,33 +89,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", AndroidUtils.getString(R.string.superapp_menu));
case "miniapps":
return SuperAppItem.valuesOf("miniapps", AndroidUtils.getString("superapp_miniapps"));
return SuperAppItem.valuesOf("miniapps", AndroidUtils.getString(R.string.superapp_miniapps));
case "vkpay_slim":
return SuperAppItem.valuesOf("vkpay_slim", AndroidUtils.getString("superapp_vkpay"));
return SuperAppItem.valuesOf("vkpay_slim", AndroidUtils.getString(R.string.superapp_vkpay));
case "greeting":
return SuperAppItem.valuesOf("greeting", AndroidUtils.getString("superapp_greeting"));
return SuperAppItem.valuesOf("greeting", AndroidUtils.getString(R.string.superapp_greeting));
case "promo":
return SuperAppItem.valuesOf("promo", AndroidUtils.getString("superapp_miniapps_promo"));
return SuperAppItem.valuesOf("promo", AndroidUtils.getString(R.string.superapp_miniapps_promo));
case "holiday":
return SuperAppItem.valuesOf("holiday", AndroidUtils.getString("superapp_holiday"));
return SuperAppItem.valuesOf("holiday", AndroidUtils.getString(R.string.superapp_holiday));
case "weather":
return SuperAppItem.valuesOf("weather", AndroidUtils.getString("superapp_weather"));
return SuperAppItem.valuesOf("weather", AndroidUtils.getString(R.string.superapp_weather));
case "sport":
return SuperAppItem.valuesOf("sport", AndroidUtils.getString("superapp_sport"));
return SuperAppItem.valuesOf("sport", AndroidUtils.getString(R.string.superapp_sport));
case "games":
return SuperAppItem.valuesOf("games", AndroidUtils.getString("superapp_games"));
return SuperAppItem.valuesOf("games", AndroidUtils.getString(R.string.superapp_games));
case "informer":
return SuperAppItem.valuesOf("informer", AndroidUtils.getString("superapp_informer"));
return SuperAppItem.valuesOf("informer", AndroidUtils.getString(R.string.superapp_informer));
case "food":
return SuperAppItem.valuesOf("food", AndroidUtils.getString("superapp_food"));
return SuperAppItem.valuesOf("food", AndroidUtils.getString(R.string.superapp_food));
case "event":
return SuperAppItem.valuesOf("event", AndroidUtils.getString("superapp_event"));
return SuperAppItem.valuesOf("event", AndroidUtils.getString(R.string.superapp_event));
case "music":
return SuperAppItem.valuesOf("music", AndroidUtils.getString("superapp_music"));
return SuperAppItem.valuesOf("music", AndroidUtils.getString(R.string.superapp_music));
case "vk_run":
return SuperAppItem.valuesOf("vk_run", AndroidUtils.getString("superapp_vk_run"));
return SuperAppItem.valuesOf("vk_run", AndroidUtils.getString(R.string.superapp_vk_run));
default:
return null;
}
@@ -1,10 +1,5 @@
package ru.vtosters.lite.ui.dialogs;
import static ru.vtosters.lite.utils.AndroidUtils.edit;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -14,29 +9,32 @@ import android.os.PowerManager;
import android.provider.Settings;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vtosters.lite.R;
import ru.vtosters.lite.deviceinfo.OEMDetector;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.Preferences;
public class DisableBattery {
public static void alert(Activity activity) {
if (OEMDetector.isOEM() && Build.VERSION.SDK_INT >= 23 && getBoolValue("showDoze", true)) {
final Context context = getGlobalContext();
if (!((PowerManager) context.getSystemService(Context.POWER_SERVICE)).isIgnoringBatteryOptimizations(context.getPackageName())) {
new VkAlertDialog.Builder(activity)
.setTitle(getString("batteryissuetitle"))
.setMessage(getString("batteryissuesumm"))
.setCancelable(false)
.setPositiveButton(getString("batteryissuebtn1"), (dialogInterface, i) -> {
var intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
if (!(OEMDetector.isOEM() && Build.VERSION.SDK_INT >= 23 && Preferences.getBoolValue("showDoze", true)))
return;
final var packName = activity.getPackageName();
final var manager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
if (manager.isIgnoringBatteryOptimizations(packName)) return;
new VkAlertDialog.Builder(activity)
.setTitle(R.string.batteryissuetitle)
.setMessage(R.string.batteryissuesumm)
.setCancelable(false)
.setPositiveButton(R.string.batteryissuebtn1, (dialogInterface, i) -> {
var intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(Uri.parse("package:" + packName));
activity.startActivity(intent);
})
.setNeutralButton(getString("batteryissuebtn2"),
(dialogInterface, i) -> edit().putBoolean("showDoze", false).apply()
.setNeutralButton(R.string.batteryissuebtn2,
(dialogInterface, i) -> AndroidUtils.edit().putBoolean("showDoze", false).apply()
)
.show();
}
}
}
}
@@ -1,8 +1,6 @@
package ru.vtosters.lite.ui.dialogs;
import static ru.vtosters.lite.utils.AndroidUtils.edit;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import static ru.vtosters.lite.utils.GmsUtils.isGmsInstalled;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
@@ -11,6 +9,7 @@ import android.content.Intent;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.navigation.Navigator;
import com.vtosters.lite.R;
import ru.vtosters.lite.ui.fragments.InstallGMSFragment;
@@ -18,19 +17,18 @@ public class InstallGMS {
public static void alert(final Activity activity) {
if (!isGmsInstalled() && getBoolValue("showAlertGms", true)) {
new VkAlertDialog.Builder(activity)
.setTitle(getString("warning"))
.setMessage(getString("gmsissuesumm"))
.setTitle(activity.getString(R.string.warning))
.setMessage(activity.getString(R.string.gmsissuesumm))
.setCancelable(false)
.setPositiveButton(getString("gmsissuebtn1"), (
.setPositiveButton(activity.getString(R.string.gmsissuebtn1), (
dialogInterface, i) -> edit().putBoolean("showAlertGms", false).apply()
)
.setNeutralButton(getString("gmsissuebtn2"), (dialogInterface, i) -> {
.setNeutralButton(activity.getString(R.string.gmsissuebtn2), (dialogInterface, i) -> {
edit().putBoolean("showAlertGms", false).apply();
var context = getGlobalContext();
var intent = new Navigator(InstallGMSFragment.class)
.b(context)
.b(activity)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
activity.startActivity(intent);
})
.show();
}
@@ -16,7 +16,6 @@ import androidx.appcompat.widget.SwitchCompat;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vtosters.lite.R;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.LayoutUtils;
public class MessageSettings {
@@ -52,12 +51,12 @@ public class MessageSettings {
four.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
five.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
zero.setText(AndroidUtils.getString("proxy_disable")); // Отключить
one.setText(AndroidUtils.getString("message_self_destruct_15sec"));
two.setText(AndroidUtils.getString("message_self_destruct_1min"));
three.setText(AndroidUtils.getString("message_self_destruct_5min"));
four.setText(AndroidUtils.getString("message_self_destruct_1hour"));
five.setText(AndroidUtils.getString("message_self_destruct_24hours"));
zero.setText(context.getString(R.string.proxy_disable)); // Отключить
one.setText(context.getString(R.string.message_self_destruct_15sec));
two.setText(context.getString(R.string.message_self_destruct_1min));
three.setText(context.getString(R.string.message_self_destruct_5min));
four.setText(context.getString(R.string.message_self_destruct_1hour));
five.setText(context.getString(R.string.message_self_destruct_24hours));
zero.setTextColor(getTextAttr());
one.setTextColor(getTextAttr());
@@ -89,7 +88,7 @@ public class MessageSettings {
@SuppressLint("UseSwitchCompatOrMaterialCode")
var silentSwitch = new SwitchCompat(new ContextThemeWrapper(context, R.style.Widget_AppCompat_CompoundButton_Switch));
silentSwitch.setText(AndroidUtils.getString("silent_messages"));
silentSwitch.setText(context.getString(R.string.silent_messages));
silentSwitch.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
silentSwitch.setTextColor(getTextAttr());
silentSwitch.setChecked(isSilentEnabled);
@@ -106,12 +105,12 @@ public class MessageSettings {
mContainer.addView(silentSwitch, LayoutUtils.createLinear(-1, -2));
new VkAlertDialog.Builder(context)
.setTitle(AndroidUtils.getString("message_send_settings_title"))
.setMessage(AndroidUtils.getString("silent_messages_time_select"))
.setTitle(context.getString(R.string.message_send_settings_title))
.setMessage(context.getString(R.string.silent_messages_time_select))
.setCancelable(true)
.setView(mContainer)
.setNegativeButton(AndroidUtils.getString("cancel"), null)
.setPositiveButton(AndroidUtils.getString("vtl_confirm"), (dialog, which) -> { // Применить
.setNegativeButton(context.getString(R.string.cancel), null)
.setPositiveButton(context.getString(R.string.vtl_confirm), (dialog, which) -> { // Применить
var checked = rg.getCheckedRadioButtonId();
if (checked == zero.getId()) {
@@ -1,9 +1,9 @@
package ru.vtosters.lite.ui.dialogs;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import android.app.Activity;
import com.vtosters.lite.R;
import ru.vtosters.lite.downloaders.OTADownloader;
import ru.vtosters.lite.ui.vkui.ModalBottomSheetWrapper;
import ru.vtosters.lite.utils.OTAUtils;
@@ -29,10 +29,10 @@ public class OTADialog implements OTAUtils.OTAListener {
mActivity.runOnUiThread(() -> {
// Toast.makeText(mActivity, "Обновления найдены", Toast.LENGTH_SHORT).show();
new ModalBottomSheetWrapper(mActivity)
.setTitle(getString("newversion") + " " + mHelper.getNewVersionName())
.setTitle(mActivity.getString(R.string.newversion) + " " + mHelper.getNewVersionName())
.setUpdateInfoView(mHelper.getUpdateDescription())
.setPositiveButton(getString("updateanddownload"), () -> {
OTADownloader.downloadBuild(mHelper.getDownloadUrl());
.setPositiveButton(mActivity.getString(R.string.updateanddownload), () -> {
OTADownloader.downloadBuild(mHelper.getDownloadUrl(), mHelper.getCommitSHA());
})
.show();
});
@@ -10,8 +10,8 @@ import android.widget.LinearLayout;
import android.widget.SeekBar;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vtosters.lite.R;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.LayoutUtils;
public class RoundingSeekbarDialog {
@@ -26,12 +26,12 @@ public class RoundingSeekbarDialog {
mContainer.addView(seek, LayoutUtils.createLinear(-1, -2));
new VkAlertDialog.Builder(context)
.setTitle(AndroidUtils.getString("pic_rounding_title"))
.setMessage(AndroidUtils.getString("pic_rounding_info"))
.setTitle(context.getString(R.string.pic_rounding_title))
.setMessage(context.getString(R.string.pic_rounding_info))
.setCancelable(true)
.setNegativeButton(AndroidUtils.getString("cancel"), null)
.setNegativeButton(context.getString(R.string.cancel), null)
.setView(mContainer)
.setPositiveButton(AndroidUtils.getString("vtl_confirm"), (dialog, which) -> {
.setPositiveButton(context.getString(R.string.vtl_confirm), (dialog, which) -> {
edit().putInt("pic_rounding", seek.getProgress()).commit();
restartApplicationWithTimer();
})
@@ -22,10 +22,11 @@ import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.utils.LifecycleUtils;
public class ServerDialog {
private static final OkHttpClient client = new OkHttpClient();
private static final OkHttpClient client = VtOkHttpClient.getInstance();
public static Boolean showAlert;
private static String title;
private static String message;
@@ -1,7 +1,6 @@
package ru.vtosters.lite.ui.dialogs;
import static ru.vtosters.lite.utils.AndroidUtils.edit;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import android.app.Activity;
@@ -10,8 +9,10 @@ import android.net.Uri;
import android.os.Build;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vtosters.lite.R;
import ru.vtosters.lite.deviceinfo.OEMDetector;
import ru.vtosters.lite.utils.AndroidUtils;
public class Start {
public static void alert(final Activity activity) {
@@ -20,27 +21,27 @@ public class Start {
}
if (getBoolValue("showAlert", true))
new VkAlertDialog.Builder(activity)
.setTitle(getString("warning"))
.setTitle(R.string.warning)
.setMessage(getWelcome())
.setCancelable(false)
.setPositiveButton(getString("startbtn2"),
.setPositiveButton(R.string.startbtn2,
(dialogInterface, i) -> edit().putBoolean("showAlert", false).apply()
)
.setNeutralButton(getString("startbtn1"),
(dialogInterface, i) -> {
edit().putBoolean("showAlert", false).apply();
activity.startActivity(new Intent("android.intent.action.VIEW").setData(Uri.parse("https://t.me/vtosters")));
}
.setNeutralButton(R.string.startbtn1,
(dialogInterface, i) -> {
edit().putBoolean("showAlert", false).apply();
activity.startActivity(new Intent("android.intent.action.VIEW").setData(Uri.parse("https://t.me/vtosters")));
}
)
.show();
}
private static String getWelcome() {
String Default = getString("startsumm1");
String Default = AndroidUtils.getString(R.string.startsumm1);
if (OEMDetector.isOEM()) {
return Default + getString("startsumm2");
return Default + AndroidUtils.getString(R.string.startsumm2);
}
return Default;
@@ -1,13 +1,13 @@
package ru.vtosters.lite.ui.dialogs;
import static ru.vtosters.lite.utils.AndroidUtils.edit;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import static ru.vtosters.lite.utils.ThemesUtils.isDarkTheme;
import android.app.Activity;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.core.ui.themes.VKThemeHelper;
import com.vtosters.lite.R;
import ru.vtosters.lite.hooks.VKUIHook;
import ru.vtosters.lite.utils.Preferences;
@@ -16,15 +16,15 @@ public class ThemeChanging {
public static void changeTheme(Activity activity, float[] f) {
if (Preferences.systemtheme()) {
new VkAlertDialog.Builder(activity)
.setTitle(getString("warning"))
.setMessage(getString("system_theme_warning"))
.setTitle(R.string.warning)
.setMessage(R.string.system_theme_warning)
.setCancelable(false)
.setPositiveButton(getString("proxy_disable"), (dialogInterface, i) -> { // Отключить
.setPositiveButton(R.string.proxy_disable, (dialogInterface, i) -> { // Отключить
edit().putString("currsystemtheme", !isDarkTheme() ? "dark" : "light").commit();
VKThemeHelper.b(activity, f);
VKUIHook.clearWebCache();
})
.setNeutralButton(getString("cancel"), null)
.setNeutralButton(R.string.cancel, null)
.show();
} else {
VKThemeHelper.b(activity, f);
@@ -10,36 +10,54 @@ import android.os.Looper;
import android.util.Log;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vtosters.lite.R;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import ru.vtosters.lite.translators.BaseTranslator;
import ru.vtosters.lite.utils.AndroidUtils;
public class Translate {
private static final Executor ASYNC_EXECUTOR
= Executors.newSingleThreadExecutor();
private static final Executor MAIN_EXECUTOR
= new DelegateExecutor();
public static void showTranslatedText(Context context, String text) {
new Thread(() -> {
BaseTranslator translator = BaseTranslator.getInstance();
if (translator == null) return;
ASYNC_EXECUTOR.execute(() -> {
try {
var translation = BaseTranslator.getInstance().getTranslation(text);
new Handler(Looper.getMainLooper()).post(() -> {
showDialog(context, translation);
});
var translation = translator.getTranslation(text);
MAIN_EXECUTOR.execute(() -> showDialog(context, translation));
} catch (Exception e) {
Log.e("Translate", e + "");
}
}).start();
});
}
private static void showDialog(Context context, String text) {
new VkAlertDialog.Builder(context)
.setTitle(AndroidUtils.getString("translator_title"))
.setTitle(R.string.translator_title)
.setMessage(text)
.setPositiveButton(AndroidUtils.getString("close"),
.setPositiveButton(R.string.close,
(dialog, which) -> dialog.cancel())
.setNeutralButton(AndroidUtils.getString("copy"), (dialog, which) -> {
.setNeutralButton(R.string.copy, (dialog, which) -> {
var clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
var clip = ClipData.newPlainText("Copied Text", text);
clipboard.setPrimaryClip(clip);
sendToast(AndroidUtils.getString("copied_to_clipboard"));
sendToast(AndroidUtils.getString(R.string.copied_to_clipboard));
})
.show();
}
private static class DelegateExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable command) {
handler.post(command);
}
}
}
@@ -3,7 +3,6 @@ package ru.vtosters.lite.ui.dialogs;
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
import static ru.vtosters.lite.proxy.ProxyUtils.isAnyProxyEnabled;
import static ru.vtosters.lite.utils.AndroidUtils.edit;
import static ru.vtosters.lite.utils.AndroidUtils.getString;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import android.app.Activity;
@@ -11,6 +10,7 @@ import android.content.Intent;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.navigation.Navigator;
import com.vtosters.lite.R;
import ru.vtosters.lite.ui.fragments.VKUIwrapper;
@@ -18,12 +18,12 @@ public class VKIDProtection {
public static void alert(final Activity activity) {
if (!getBoolValue("showAlertVkId", true)) return;
new VkAlertDialog.Builder(activity)
.setTitle(getString("warning"))
.setMessage(getString("vkidsumm"))
.setTitle(R.string.warning)
.setMessage(R.string.vkidsumm)
.setCancelable(false)
.setPositiveButton(getString("startbtn2"),
.setPositiveButton(R.string.startbtn2,
(dialogInterface, i) -> edit().putBoolean("showAlertVkId", false).apply())
.setNeutralButton(getString("vkiddisable"), (dialogInterface, i) -> {
.setNeutralButton(R.string.vkiddisable, (dialogInterface, i) -> {
edit().putBoolean("showAlertVkId", false).apply();
VKUIwrapper.setLink(
isAnyProxyEnabled()
@@ -1,19 +1,19 @@
package ru.vtosters.lite.ui.fragments;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.Preferences.offline;
import android.os.Bundle;
import androidx.preference.Preference;
import com.vtosters.lite.R;
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
public class ActivityFragment extends MaterialPreferenceToolbarFragment {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(getIdentifier("preferences_activity", "xml"));
addPreferencesFromResource(R.xml.preferences_activity);
findPreference("setoffline").setEnabled(offline());
}
@@ -25,6 +25,6 @@ public class ActivityFragment extends MaterialPreferenceToolbarFragment {
@Override
public int T4() {
return getIdentifier("vtlactivity", "string");
return R.string.vtlactivity;
}
}
@@ -1,7 +1,6 @@
package ru.vtosters.lite.ui.fragments;
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.LifecycleUtils.restartApplication;
import android.os.Bundle;
@@ -25,14 +24,13 @@ import com.vtosters.lite.R;
import ru.vtosters.lite.ui.adapters.CategorizedAdapter;
import ru.vtosters.lite.ui.components.DockBarEditorManager;
import ru.vtosters.lite.ui.components.ItemMovingCallback;
import ru.vtosters.lite.utils.AndroidUtils;
public class DockBarEditorFragment extends BaseToolbarFragment {
@CallSuper
@Override
public View onCreateContent(@NonNull LayoutInflater inflater, @Nullable Bundle bundle) {
setTitle(getIdentifier("dockbar_editor", "string"));
setTitle(R.string.dockbar_editor);
FrameLayout content = new FrameLayout(getContext());
@@ -50,7 +48,7 @@ public class DockBarEditorFragment extends BaseToolbarFragment {
container.addView(buttonsContainer, new LinearLayout.LayoutParams(-1, -2));
TextView save = new TextView(new ContextThemeWrapper(getContext(), R.style.VKUIButton_Primary));
save.setText(AndroidUtils.getString("save"));
save.setText(requireContext().getString(R.string.save));
save.setOnClickListener(v -> {
DockBarEditorManager.getInstance().save();
restartApplication();
@@ -64,7 +62,7 @@ public class DockBarEditorFragment extends BaseToolbarFragment {
buttonsContainer.addView(divider, new LinearLayout.LayoutParams(dp2px(10), 0));
TextView reset = new TextView(new ContextThemeWrapper(getContext(), R.style.VKUIButton_Primary));
reset.setText(AndroidUtils.getString("reset"));
reset.setText(requireContext().getString(R.string.reset));
reset.setOnClickListener(v -> {
DockBarEditorManager.getInstance().reset();
restartApplication();
@@ -2,7 +2,6 @@ package ru.vtosters.lite.ui.fragments;
import static ru.vtosters.lite.utils.AndroidUtils.edit;
import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.AndroidUtils.getPrefsValue;
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.setupFilters;
@@ -18,16 +17,16 @@ import androidx.preference.Preference;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.navigation.Navigator;
import com.vk.newsfeed.NewsfeedSettingsFragment;
import com.vtosters.lite.R;
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
import ru.vtosters.lite.ui.components.NewsfeedListManager;
import ru.vtosters.lite.utils.AndroidUtils;
public class FeedFragment extends MaterialPreferenceToolbarFragment {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(getIdentifier("preferences_feed", "xml"));
addPreferencesFromResource(R.xml.preferences_feed);
prefs();
}
@@ -73,7 +72,7 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment {
});
var str = getDefaultPrefs().getString("news_feed_selected_items", "");
findPreference("newsfeedlistmanager").setSummary(
String.format(AndroidUtils.getString("feed_hidden"), (!TextUtils.isEmpty(str) ? str.split(",").length : 0))
String.format(requireContext().getString(R.string.feed_hidden), (!TextUtils.isEmpty(str) ? str.split(",").length : 0))
);
findPreference("newsfeedlistmanager_reset").setOnPreferenceClickListener(preference -> {
NewsfeedListManager.resetHideItems();
@@ -86,23 +85,23 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment {
var count = text.split(", ").length;
if (count < 1 || text.isEmpty()) {
return AndroidUtils.getString("feed_no_elements");
return requireContext().getString(R.string.feed_no_elements);
} else {
return String.format(AndroidUtils.getString("feed_elements_count"), count);
return String.format(requireContext().getString(R.string.feed_elements_count), count);
}
}
private void remdialog(String key, Context context) {
new VkAlertDialog.Builder(context)
.setTitle(AndroidUtils.getString("warning"))
.setMessage(AndroidUtils.getString("delete_elements_confirm"))
.setTitle(requireContext().getString(R.string.warning))
.setMessage(requireContext().getString(R.string.delete_elements_confirm))
.setCancelable(false)
.setPositiveButton(AndroidUtils.getString("yes"), (dialogInterface, i) -> {
.setPositiveButton(requireContext().getString(R.string.yes), (dialogInterface, i) -> {
edit().remove(key).apply();
sendToast(AndroidUtils.getString("elements_deleted_success"));
sendToast(requireContext().getString(R.string.elements_deleted_success));
setupFilters();
})
.setNegativeButton(AndroidUtils.getString("cancel"),
.setNegativeButton(requireContext().getString(R.string.cancel),
(dialogInterface, i) -> dialogInterface.dismiss())
.show();
}
@@ -119,9 +118,9 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment {
var count = str.toString().split(", ").length;
if (count < 1 || (str.length() == 0)) {
return AndroidUtils.getString("feed_no_elements");
return requireContext().getString(R.string.feed_no_elements);
} else {
return String.format(AndroidUtils.getString("feed_elements_count"), count);
return String.format(requireContext().getString(R.string.feed_elements_count), count);
}
}
@@ -133,6 +132,11 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment {
return super.onPreferenceTreeClick(preference);
}
@Override
public int T4() {
return R.string.vtlfeed;
}
public class openofficialsett implements Preference.OnPreferenceClickListener {
@Override // android.support.v7.preference.Preference.c
public boolean onPreferenceClick(Preference preference) {
@@ -143,9 +147,4 @@ public class FeedFragment extends MaterialPreferenceToolbarFragment {
return true;
}
}
@Override
public int T4() {
return getIdentifier("vtlfeed", "string");
}
}
@@ -31,10 +31,9 @@ import androidx.appcompat.view.ContextThemeWrapper;
import androidx.core.content.res.ResourcesCompat;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vtosters.lite.R;
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
import ru.vtosters.lite.utils.AndroidUtils;
public class IconsFragment extends MaterialPreferenceToolbarFragment {
@SuppressLint("SetTextI18n")
public static void callSelectDialog(Context ctx, String appicon) {
@@ -63,7 +62,7 @@ public class IconsFragment extends MaterialPreferenceToolbarFragment {
rgVK.setText("VK");
rgVK.setTextColor(getTextAttr());
rgVKontakte.setText(AndroidUtils.getString("app_name_alter"));
rgVKontakte.setText(ctx.getString(R.string.app_name_alter));
rgVKontakte.setTextColor(getTextAttr());
rgVKontakte.setChecked(defname.contains("vkontakte"));
@@ -71,9 +70,9 @@ public class IconsFragment extends MaterialPreferenceToolbarFragment {
rgDefault.setChecked(defname.contains("vt") || defname.isEmpty());
new VkAlertDialog.Builder(ctx)
.setTitle(AndroidUtils.getString("app_name_select_title"))
.setTitle(R.string.app_name_select_title)
.setView(rg)
.setPositiveButton(AndroidUtils.getString("vtl_confirm"), ((dialog, which) -> {
.setPositiveButton(R.string.vtl_confirm, ((dialog, which) -> {
if (rgDefault.isChecked()) {
edit().putString("appname", "vt").commit();
edit().putString("selectedicon", appicon).commit();
@@ -91,7 +90,7 @@ public class IconsFragment extends MaterialPreferenceToolbarFragment {
switchComponent(appicon, "vkontakte", deficon, defname);
}
}))
.setNegativeButton(AndroidUtils.getString("cancel"),
.setNegativeButton(R.string.cancel,
((dialog, which) -> dialog.dismiss()))
.show();
}
@@ -101,17 +100,16 @@ public class IconsFragment extends MaterialPreferenceToolbarFragment {
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
int vtosterXml = getIdentifier("empty", "xml");
this.addPreferencesFromResource(vtosterXml);
this.addPreferencesFromResource(R.xml.empty);
if (!hasVerification() && !getBoolValue("dialogrecomm", false)) {
addPreference(this, "", AndroidUtils.getString("icons_warning"), AndroidUtils.getString("icons_warning_info"), "ic_about_outline_28", preference -> {
addPreference(this, "", requireContext().getString(R.string.icons_warning), requireContext().getString(R.string.icons_warning_info), R.drawable.ic_about_outline_28, preference -> {
getContext().startActivity(new Intent("android.intent.action.VIEW").setData(Uri.parse("https://vtosters.app/donate/")));
return false;
});
}
addPreferenceCategory(this, AndroidUtils.getString("icons_title"));
addPreferenceCategory(this, requireContext().getString(R.string.icons_title));
for (var i = 0; i < icons().size(); i++) {
if (icons().get(i) == null || iconsValues().get(i) == null) return;
@@ -119,20 +117,20 @@ public class IconsFragment extends MaterialPreferenceToolbarFragment {
String iconname = icons().get(i);
String icon = iconsValues().get(i);
String icondrawable;
int iconRes;
if (icon.equals("vt")) {
icondrawable = "vt_launcher_round";
iconRes = R.mipmap.vt_launcher_round;
} else if (icon.contains("standard")) {
icondrawable = "ic_launcher_round";
iconRes = R.mipmap.ic_launcher_round;
} else {
icondrawable = "ic_launcher_" + icon;
iconRes = getIdentifier("ic_launcher_" + icon, "mipmap");
}
Drawable drawable = ResourcesCompat.getDrawable(getResources(), getIdentifier(icondrawable, "mipmap"), null);
Drawable drawable = ResourcesCompat.getDrawable(getResources(), iconRes, null);
if (drawable == null) {
drawable = ResourcesCompat.getDrawable(getResources(), getIdentifier("ic_bug_outline_28", "drawable"), null);
drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_bug_outline_28, null);
}
addPreferenceDrawable(this, icon, iconname, "", drawable, preference -> {
@@ -142,7 +140,7 @@ public class IconsFragment extends MaterialPreferenceToolbarFragment {
}
if (!hasVerification() && !getBoolValue("dialogrecomm", false)) {
addPreferenceCategory(this, AndroidUtils.getString("unavailable_icons"));
addPreferenceCategory(this, requireContext().getString(R.string.unavailable_icons));
for (var i = 2; i < sIconsPlusNames.size(); i++) {
if (sIconsPlusNames.get(i) == null || sIconsPlus.get(i) == null) return;
@@ -150,24 +148,24 @@ public class IconsFragment extends MaterialPreferenceToolbarFragment {
String iconname = sIconsPlusNames.get(i);
String icon = sIconsPlus.get(i);
String icondrawable;
int iconRes;
if (icon.equals("vt")) {
icondrawable = "vt_launcher_round";
iconRes = R.mipmap.vt_launcher_round;
} else if (icon.contains("standard")) {
icondrawable = "ic_launcher_round";
iconRes = R.mipmap.ic_launcher_round;
} else {
icondrawable = "ic_launcher_" + icon;
iconRes = getIdentifier("ic_launcher_" + icon, "mipmap");
}
Drawable drawable = ResourcesCompat.getDrawable(getResources(), getIdentifier(icondrawable, "mipmap"), null);
Drawable drawable = ResourcesCompat.getDrawable(getResources(), iconRes, null);
if (drawable == null) {
drawable = ResourcesCompat.getDrawable(getResources(), getIdentifier("ic_bug_outline_28", "drawable"), null);
drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_bug_outline_28, null);
}
addPreferenceDrawable(this, icon, iconname, "", drawable, preference -> {
sendToast(AndroidUtils.getString("unavailable_icon_warning"));
sendToast(requireContext().getString(R.string.unavailable_icon_warning));
return false;
});
}
@@ -1,20 +1,19 @@
package ru.vtosters.lite.ui.fragments;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import android.os.Bundle;
import com.vtosters.lite.R;
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
public class InstallGMSFragment extends MaterialPreferenceToolbarFragment {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(getIdentifier("preferences_gms", "xml"));
addPreferencesFromResource(R.xml.preferences_gms);
}
@Override
public int T4() {
return getIdentifier("installgms", "string");
return R.string.installgms;
}
}
@@ -1,6 +1,5 @@
package ru.vtosters.lite.ui.fragments;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
import static ru.vtosters.lite.utils.AndroidUtils.isTablet;
import static ru.vtosters.lite.utils.LifecycleUtils.restartApplicationWithTimer;
@@ -10,16 +9,16 @@ import android.os.Bundle;
import androidx.preference.Preference;
import com.vtosters.lite.R;
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
import ru.vtosters.lite.ui.dialogs.RoundingSeekbarDialog;
import ru.vtosters.lite.utils.AndroidUtils;
public class InterfaceFragment extends MaterialPreferenceToolbarFragment {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(getIdentifier("preferences_interface", "xml"));
addPreferencesFromResource(R.xml.preferences_interface);
prefs();
}
@@ -27,6 +26,7 @@ public class InterfaceFragment extends MaterialPreferenceToolbarFragment {
findPreference("stories").setOnPreferenceClickListener(new restart());
findPreference("swipe").setOnPreferenceClickListener(new restart());
findPreference("is_likes_on_right").setOnPreferenceClickListener(new restart());
findPreference("superapp").setOnPreferenceClickListener(new restart());
if (isTablet()) {
findPreference("menusett").setVisible(false);
@@ -43,9 +43,9 @@ public class InterfaceFragment extends MaterialPreferenceToolbarFragment {
}
if (getPreferences().getInt("pic_rounding", 0) == 0) {
findPreference("customrounding").setSummary(AndroidUtils.getString("disabled"));
findPreference("customrounding").setSummary(requireContext().getString(R.string.disabled));
} else {
findPreference("customrounding").setSummary(String.format(AndroidUtils.getString("rounding_size"), getPreferences().getInt("pic_rounding", 0)));
findPreference("customrounding").setSummary(String.format(requireContext().getString(R.string.rounding_size), getPreferences().getInt("pic_rounding", 0)));
}
}
@@ -54,15 +54,15 @@ public class InterfaceFragment extends MaterialPreferenceToolbarFragment {
return true;
}
@Override
public int T4() {
return R.string.vtlinterface;
}
public class restart implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
return InterfaceFragment.this.restart(preference);
}
}
@Override
public int T4() {
return getIdentifier("vtlinterface", "string");
}
}
@@ -1,15 +1,15 @@
package ru.vtosters.lite.ui.fragments;
import static bruhcollective.itaysonlab.libvkx.client.LibVKXClient.isVkxInstalled;
import static ru.vtosters.lite.music.Scrobbler.isLoggedIn;
import static ru.vtosters.lite.music.LastFMScrobbler.isLoggedIn;
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
import static ru.vtosters.lite.utils.AndroidUtils.edit;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
import static ru.vtosters.lite.utils.LifecycleUtils.restartApplicationWithTimer;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
import static ru.vtosters.lite.utils.ThemesUtils.getSTextAttr;
import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
@@ -29,6 +29,7 @@ import androidx.preference.Preference;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.core.network.Network;
import com.vtosters.lite.R;
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
import org.json.JSONObject;
@@ -44,7 +45,7 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import ru.vtosters.lite.downloaders.AudioDownloader;
import ru.vtosters.lite.downloaders.VideoDownloader;
import ru.vtosters.lite.music.Scrobbler;
import ru.vtosters.lite.music.LastFMScrobbler;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.ui.adapters.ImagineArrayAdapter;
import ru.vtosters.lite.utils.AndroidUtils;
@@ -66,8 +67,8 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
container.addView(input, lp);
new VkAlertDialog.Builder(ctx)
.setTitle(AndroidUtils.getString("video_dl_enter_link"))
.setPositiveButton(AndroidUtils.getString("download"),
.setTitle(R.string.video_dl_enter_link)
.setPositiveButton(R.string.download,
(dialog, which) -> VideoDownloader.parseVideoLink(input.getText().toString(), ctx))
.setView(container)
.show();
@@ -76,7 +77,7 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(getIdentifier("preferences_media", "xml"));
addPreferencesFromResource(R.xml.preferences_media);
prefs();
}
@@ -107,15 +108,15 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
});
if (isLoggedIn()) {
findPreference("lastfm_auth").setSummary(AndroidUtils.getString("lastfm_authorized_as") + " " + Scrobbler.getUserName());
findPreference("lastfm_auth").setSummary(requireContext().getString(R.string.lastfm_authorized_as) + " " + LastFMScrobbler.getUserName());
} else {
findPreference("lastfm_enabled").setEnabled(false);
}
findPreference("cached_tracks").setSummary(String.format(AndroidUtils.getString("cached_tracks_counter"), CacheDatabaseDelegate.getTrackCount()));
findPreference("cached_tracks").setSummary(String.format(requireContext().getString(R.string.cached_tracks_counter), CacheDatabaseDelegate.getTrackCount()));
findPreference("cached_tracks").setOnPreferenceClickListener(preference -> {
if (CacheDatabaseDelegate.getTrackCount() == 0) {
sendToast(AndroidUtils.getString("no_cache_error"));
sendToast(requireContext().getString(R.string.no_cache_error));
} else {
delcache(requireContext());
}
@@ -131,11 +132,17 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
findPreference("vkx_sett").setVisible(false);
}
findPreference("musicdefcatalog").setVisible(!getBoolValue("useOldAppVer", false));
findPreference("useOldAppVer").setOnPreferenceClickListener(preference -> {
restartApplicationWithTimer();
return true;
});
findPreference("select_photo_search_engine").setOnPreferenceClickListener(preference -> {
var items = Arrays.asList(
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("yandex", "drawable"), "Yandex"),
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("google", "drawable"), "Google"),
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("microsoft", "drawable"), "Bing")
new ImagineArrayAdapter.ImagineArrayAdapterItem(R.drawable.yandex, "Yandex"),
new ImagineArrayAdapter.ImagineArrayAdapterItem(R.drawable.google, "Google"),
new ImagineArrayAdapter.ImagineArrayAdapterItem(R.drawable.microsoft, "Bing")
);
var adapter = new ImagineArrayAdapter(getContext(), items);
@@ -156,7 +163,7 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
linearLayout.setOrientation(LinearLayout.VERTICAL);
final EditText fn = new EditText(ctx);
fn.setHint(AndroidUtils.getString("lastfm_login"));
fn.setHint(R.string.lastfm_login);
fn.setTextColor(getTextAttr());
fn.setHintTextColor(getSTextAttr());
fn.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
@@ -167,7 +174,7 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
fn.setLayoutParams(margin);
final EditText ln = new EditText(ctx);
ln.setHint(AndroidUtils.getString("lastfm_password"));
ln.setHint(R.string.lastfm_password);
ln.setTextColor(getTextAttr());
ln.setHintTextColor(getSTextAttr());
ln.setBackgroundTintList(ColorStateList.valueOf(getAccentColor()));
@@ -176,12 +183,12 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
ln.setLayoutParams(margin);
new VkAlertDialog.Builder(ctx)
.setTitle(AndroidUtils.getString("lastfm_enter_credentials"))
.setPositiveButton(AndroidUtils.getString("lastfm_enter"),
.setTitle(R.string.lastfm_enter_credentials)
.setPositiveButton(R.string.lastfm_enter,
(dialog, which) -> {
String login = fn.getText().toString();
String pass = ln.getText().toString();
Scrobbler.auth(login, pass);
LastFMScrobbler.authenticate(login, pass);
}
)
.setView(linearLayout)
@@ -190,39 +197,39 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
private void logout(Context ctx) {
new VkAlertDialog.Builder(ctx)
.setTitle(AndroidUtils.getString("lastfm_logout_title"))
.setMessage(AndroidUtils.getString("lastfm_logout_confirm"))
.setPositiveButton(AndroidUtils.getString("vkim_yes"),
(dialog, which) -> Scrobbler.logout())
.setNeutralButton(AndroidUtils.getString("vkim_no"),
.setTitle(R.string.lastfm_logout_title)
.setMessage(R.string.lastfm_logout_confirm)
.setPositiveButton(R.string.vkim_yes,
(dialog, which) -> LastFMScrobbler.logout())
.setNeutralButton(R.string.vkim_no,
(dialog, which) -> dialog.cancel())
.show();
}
private void delcache(Context ctx) {
new VkAlertDialog.Builder(ctx)
.setTitle(AndroidUtils.getString("warning"))
.setMessage(AndroidUtils.getString("cached_tracks_remove_confirm"))
.setPositiveButton(AndroidUtils.getString("yes"),
.setTitle(R.string.warning)
.setMessage(R.string.cached_tracks_remove_confirm)
.setPositiveButton(R.string.yes,
(dialog, which) -> executor.submit(CacheDatabaseDelegate::clear))
.setNeutralButton(AndroidUtils.getString("no"),
.setNeutralButton(R.string.no,
(dialog, which) -> dialog.cancel())
.show();
}
private void dlaudio(Context ctx) {
if (LibVKXClient.isIntegrationEnabled()) {
sendToast("Включена интеграция VKX. Глобальное кеширование доступно внутри VKX");
sendToast(AndroidUtils.getString("vkx_integration_enabled_info"));
return;
}
new VkAlertDialog.Builder(ctx)
.setTitle(AndroidUtils.getString("download_method"))
.setMessage(AndroidUtils.getString("download_method_desc"))
.setPositiveButton(AndroidUtils.getString("download_method_cache"), (dialog, which) -> {
.setTitle(R.string.download_method)
.setMessage(R.string.download_method_desc)
.setPositiveButton(R.string.download_method_cache, (dialog, which) -> {
executor.submit(AudioDownloader::cacheAllAudios);
})
.setNegativeButton(AndroidUtils.getString("download_method_mp3"), (dialog, which) -> {
.setNegativeButton(R.string.download_method_mp3, (dialog, which) -> {
executor.submit(AudioDownloader::downloadAllAudios);
})
.show();
@@ -240,9 +247,9 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
var response = new JSONObject(new OkHttpClient().a(request).execute().a().g());
if (response.optInt("response") == 1) {
requireActivity().runOnUiThread(() -> sendToast(AndroidUtils.getString("video_history_cleaned")));
requireActivity().runOnUiThread(() -> sendToast(requireContext().getString(R.string.video_history_cleaned)));
} else {
requireActivity().runOnUiThread(() -> sendToast(AndroidUtils.getString("delete_video_history_error")));
requireActivity().runOnUiThread(() -> sendToast(requireContext().getString(R.string.delete_video_history_error)));
}
Log.d("VideoHistory", response.toString());
@@ -259,16 +266,21 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
private void deleteVideoHistoryDialog(Context context) {
new VkAlertDialog.Builder(context)
.setTitle(AndroidUtils.getString("warning"))
.setMessage(AndroidUtils.getString("delete_video_history_confirm"))
.setTitle(R.string.warning)
.setMessage(R.string.delete_video_history_confirm)
.setCancelable(false)
.setPositiveButton(AndroidUtils.getString("yes"),
.setPositiveButton(R.string.yes,
(dialogInterface, i) -> deleteVideoHistory())
.setNegativeButton(AndroidUtils.getString("cancel"),
.setNegativeButton(R.string.cancel,
(dialogInterface, i) -> dialogInterface.dismiss())
.show();
}
@Override
public int T4() {
return R.string.vtlmedia;
}
private static class restart implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
@@ -285,9 +297,4 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
return true;
}
}
@Override
public int T4() {
return getIdentifier("vtlmedia", "string");
}
}
@@ -1,7 +1,6 @@
package ru.vtosters.lite.ui.fragments;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
import static ru.vtosters.lite.utils.AndroidUtils.isTablet;
import static ru.vtosters.lite.utils.LifecycleUtils.restartApplicationWithTimer;
@@ -12,12 +11,15 @@ import static ru.vtosters.lite.utils.ThemesUtils.recolorDrawable;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.preference.Preference;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.navigation.Navigator;
import com.vk.stickers.Stickers;
import com.vtosters.lite.R;
import com.vtosters.lite.general.fragments.MaterialPreferenceToolbarFragment;
import java.util.Arrays;
@@ -29,7 +31,7 @@ public class MessagesFragment extends MaterialPreferenceToolbarFragment {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(getIdentifier("preferences_messages", "xml"));
addPreferencesFromResource(R.xml.preferences_messages);
prefs();
}
@@ -44,8 +46,8 @@ public class MessagesFragment extends MaterialPreferenceToolbarFragment {
findPreference("lang_service").setOnPreferenceClickListener(preference -> {
var items = Arrays.asList(
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("ic_yandex_translate_icon", "drawable"), "Yandex Translate"),
new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("ic_google_translate_logo", "drawable"), "Google Translate")
new ImagineArrayAdapter.ImagineArrayAdapterItem(R.drawable.ic_yandex_translate_icon, "Yandex Translate"),
new ImagineArrayAdapter.ImagineArrayAdapterItem(R.drawable.ic_google_translate_logo, "Google Translate")
// new ImagineArrayAdapter.ImagineArrayAdapterItem(getIdentifier("ic_deepl_logo_icon", "drawable"), "DeepL")
);
@@ -63,8 +65,8 @@ public class MessagesFragment extends MaterialPreferenceToolbarFragment {
});
findPreference("vkme_notifs").setEnabled(vkme());
findPreference("wallpapers").setIcon(recolorDrawable(getGlobalContext().getDrawable(getIdentifier("ic_media_outline_28", "drawable"))));
findPreference("vkme").setIcon(getIdentifier("ic_vkme_28", "drawable"));
findPreference("wallpapers").setIcon(recolorDrawable(getGlobalContext().getDrawable(R.drawable.ic_media_outline_28)));
findPreference("vkme").setIcon(R.drawable.ic_vkme_28);
if (isTablet()) {
findPreference("alteremoji").setVisible(false);
@@ -84,6 +86,11 @@ public class MessagesFragment extends MaterialPreferenceToolbarFragment {
return true;
}
@Override
public int T4() {
return R.string.vtlmessages;
}
public class restart implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
@@ -108,9 +115,4 @@ public class MessagesFragment extends MaterialPreferenceToolbarFragment {
return true;
}
}
@Override
public int T4() {
return getIdentifier("vtlmessages", "string");
}
}

Some files were not shown because too many files have changed in this diff Show More