Compare commits

...
403 Commits
Author SHA1 Message Date
gdlbo efb909ce64 fix artists catalog 2023-02-12 14:24:17 +03:00
Saoqqandsaoq 62c11b90dc Forward calls from msg to off VK apps (#1094)
Co-authored-by: saoq <wfmfe@ya.ru>
2023-02-12 02:18:27 +03:00
gdlbo a15cd9bd0b fixed compressing jpegs 2023-02-08 18:32:58 +03:00
gdlbo 6d9f4a23c8 added newsfeed update dialog 2023-02-08 18:00:36 +03:00
gdlbo 0677f77fde Update BackupManager.java 2023-02-08 17:55:26 +03:00
gdlbo 1b274fdb91 Update DockBarEditorManager.java 2023-02-08 17:08:22 +03:00
gdlbo c4bf9f8f88 some switch fixes 2023-02-08 16:41:56 +03:00
gdlbo e9a98afae9 Update ThemesCore.java 2023-02-07 01:35:36 +03:00
gdlbo 856bd63b43 updated VTSettings.java 2023-02-07 00:48:35 +03:00
gdlbo 606c908b90 some color fixes 2023-02-07 00:09:52 +03:00
gdlbo 0adc9ca3fd updated switch cases 2023-02-06 21:47:33 +03:00
gdlbo 3345382383 jdk upped to 14 2023-02-06 21:35:48 +03:00
gdlbo 7e7f8d0efa Update InterfaceFragment.java 2023-02-06 20:00:17 +03:00
gdlbo 84e0601b76 refactoring 2023-02-06 02:51:32 +03:00
gdlbo bc43b788d8 Update ThemesCore.java 2023-02-06 02:19:36 +03:00
gdlbo 22bd830353 fix #1062 2023-02-06 01:03:31 +03:00
gdlbo c2ff38044c fixed проксi moment 2023-02-05 23:53:28 +03:00
Pavel af312540df Escape character in values-be (#1088) 2023-02-04 21:44:00 +03:00
mysh228 1cee582dbf Apostrophes fixes in arrays 2023-02-04 00:52:05 +03:00
mysh228 664ea02dd0 Apostrophes fix 2023-02-04 00:52:05 +03:00
mysh228 4fe85d264d Belarusian translation 2023-02-04 00:52:05 +03:00
gdlbo e8a1d814c1 fixed false injection 2023-02-03 16:07:42 +03:00
gdlbo 76d0dd2ad6 disabled vigo 2023-02-03 15:56:17 +03:00
gdlbo 4658338fbb Update strings.xml 2023-02-03 15:25:07 +03:00
awers24 745ccd6e1d ukrainian translate (#1083)
* ukrainian translation
2023-02-02 20:52:24 +03:00
k1zn da76da8e35 Update strings.xml 2023-02-01 20:25:08 +05:00
gdlbo 249d1de1a1 Update R.java 2023-01-31 14:50:54 +03:00
gdlbo 1a82b40a7f Update RandomProxy.java 2023-01-31 14:43:01 +03:00
k1zn 83093be566 another translate 2023-01-31 15:58:24 +05:00
gdlbo 5994172095 fixed undelete msg
fixed all bugs omg
2023-01-30 21:36:13 +03:00
gdlbo a645e2fe32 Update CallsHook.java 2023-01-30 18:07:55 +03:00
gdlbo 87f59b2ea8 Update R.java 2023-01-29 15:44:26 +03:00
gdlbo 131bd0bdcc fixed def music catalog 2023-01-29 15:24:19 +03:00
gdlbo 7618c37d4c fix samsung awful icon system 2023-01-27 19:35:37 +03:00
gdlbo 41f978cc26 added monochrome for old icon 2023-01-27 18:44:58 +03:00
gdlbo 489246347f code cleanup 2023-01-27 17:37:49 +03:00
gdlbo a68e580436 fix null link crash for music tracks 2023-01-27 16:12:27 +03:00
gdlbo 0ef33f5c52 Update AndroidUtils.java 2023-01-27 15:41:02 +03:00
gdlbo daac037285 code cleanup 2023-01-24 18:12:01 +03:00
k1zn 09f9adafb0 translate 2023-01-24 15:26:08 +05:00
gdlbo f746753b15 updated translator 2023-01-21 17:28:00 +03:00
gdlbo 2b3da25099 Update AndroidUtils.java 2023-01-21 16:56:00 +03:00
gdlbo 94e8c49784 added links verif dialog 2023-01-21 16:50:23 +03:00
gdlbo afef886293 fixed calls moment 2023-01-21 15:58:37 +03:00
gdlbo acf3a77fe7 Implementation of domain verification 2023-01-16 17:42:03 +03:00
gdlbo 7de0d9a269 updated device info collector for simplify gh issues 2023-01-16 17:26:04 +03:00
dalvesrever 75732deb61 simplify OnPreferenceClickListener implementations
add NavigatorUtils
2023-01-15 19:45:12 +03:00
dalvesrever 923586cc33 close #1014; Make message text selectable 2023-01-15 18:30:15 +03:00
abslike eac9b2f83a Fix highlight on Amoled+Monet theme (#1041)
* Fix monet

* Try to fix part 2

* Fixed outgoing message

* Update styles.xml

* FIX MONET PART IV

* fix monet part of endless

* fix monet on white theme

* Fix highlight

* Fix highlight and other

* Fix text + highlight

* Fix highlight and text

* highlight

* Monet fixes

* Fix monet

* build fix

* build fixes

* Update styles.xml

* fix highlightes Amoled theme

* fix highlight Amoled theme
2023-01-14 12:53:48 +03:00
xsafter bfc718bc98 Рефактор Utils (#1000)
* Refactor:обновил Deprecated в новых Андроидах вызовы в некоторых утилитах

* Refactor:обновил Deprecated в новых Андроидах вызовы в некоторых утилитах

* Пофиксил
2023-01-11 13:41:46 +03:00
gdlbo effab03fd2 Merge pull request #1027 from Saoqq/vk-im-calls-forward
Quick calls integration with VK messenger app
2023-01-11 12:55:34 +03:00
saoq 6b1501b0fa Fix fun name 2023-01-10 23:52:58 +03:00
saoq 4f2d97fd7b Support VK off client 2023-01-10 23:39:48 +03:00
saoq 26b1db0900 Quick calls integration with VK messenger app 2023-01-10 19:21:24 +03:00
k1zn 6936079803 fix #1026 2023-01-10 20:51:25 +05:00
gdlbo eba6c43d4c dockbar and superapp editor moved 2023-01-06 18:48:49 +03:00
gdlbo 6667dc0be8 added manual verif data update 2023-01-06 16:32:14 +03:00
gdlbo 26e59629aa some settings refactoring 2023-01-06 16:25:58 +03:00
gdlbo 14f9f6dcf8 fixed msg preview 2023-01-06 16:10:41 +03:00
gdlbo 0a8ecd8b0a Update FeedFragment.java 2023-01-06 14:47:23 +03:00
gdlbo a4113ba6d5 auto refactor xmls 2023-01-06 14:47:16 +03:00
gdlbo 4f5193f170 Update Preferences.java 2023-01-06 14:28:52 +03:00
gdlbo 81a62d5400 some code updates 2023-01-03 13:59:39 +03:00
gdlbo 1a7031ead1 fixed init filters 2023-01-01 18:43:05 +03:00
Vologhat 40a1ab64cb add generateRjava task to gradle script 2023-01-01 18:30:48 +03:00
gdlbo 78f0eae9c3 fix #1001 2023-01-01 18:23:32 +03:00
Vologhat b5de88a370 update R.java 2023-01-01 18:19:32 +03:00
Vologhat 1e9a6c6840 fix shell script 2023-01-01 18:12:46 +03:00
gdlbo eb8939021d Update styles.xml 2023-01-01 18:04:34 +03:00
Vologhat a53f90367e fix item swipe disappearance 2023-01-01 17:45:01 +03:00
gdlbo f19aae542e fixed dialog stats from dialogs list 2023-01-01 16:15:38 +03:00
gdlbo f34b895485 added some photo quality magic 2023-01-01 16:13:48 +03:00
gdlbo 5c194891ba disabled more stats 2023-01-01 15:45:25 +03:00
Vologhat e7c08406a5 replace tags with ids 2023-01-01 15:29:42 +03:00
Vologhat c3a08ea7a8 change item width to match_parent 2023-01-01 15:23:25 +03:00
Vologhat 69ea193771 refactor CategorizedAdapter, DockBarEditor, SuperAppEditor 2023-01-01 15:08:32 +03:00
gdlbo 562bfc0ed0 added webview wrapper 2023-01-01 15:08:22 +03:00
Vologhat 919d7cb19d refactor CategorizedAdapter, DockBarEditor, SuperAppEditor 2023-01-01 15:06:55 +03:00
gdlbo 0a766038da updated icon for dialog stats 2022-12-31 23:04:26 +03:00
gdlbo dabc79cdb2 chat stats 2022-12-31 21:42:42 +03:00
gdlbo 4cb73d669a Update StickerPackAdapter.java 2022-12-30 17:50:03 +03:00
gdlbo dfddb13d2d Update CatalogJsonInjector.java 2022-12-30 17:45:39 +03:00
Vologhat f17c57bac2 add tgs stickers preview in settings 2022-12-30 17:32:14 +03:00
Vologhat a6c4c376c3 fix tgs stickers updating on keyboard stickers panel 2022-12-30 17:12:16 +03:00
gdlbo 3e4f14678e fixed nonmilk profile hide 2022-12-30 16:35:20 +03:00
gdlbo f860eb2cc0 Merge pull request #995 from psamur/main
New icons in profile buttons
2022-12-30 16:01:46 +03:00
gdlbo 2a6b9da4ef ImBanner cleanup code 2022-12-30 15:58:10 +03:00
Pavel 6224a4afdf new icons in profile buttons 2022-12-30 15:54:12 +03:00
gdlbo 8650124860 refactored ssfs utils 2022-12-30 15:35:55 +03:00
gdlbo 5e35a61473 refactored profile buttons injector 2022-12-30 14:52:29 +03:00
Vologhat 578f1a2221 add launch task 2022-12-30 14:28:30 +03:00
gdlbo 0fb3ff6c53 deleted useless logs 2022-12-30 02:38:28 +03:00
abslike 7fbfbd1e1e Fix Monet on nonmilkshake (#991) 2022-12-30 02:35:08 +03:00
gdlbo 71de558e5c ssfs update
added support for im banners
2022-12-30 02:31:09 +03:00
gdlbo 606b89a4ec ssfs update
added profile hide
2022-12-30 01:34:15 +03:00
Vologhat b4bdb3070a fix tgs preference summary 2022-12-29 20:53:01 +03:00
Vologhat 9f4b5990b7 refactor PreferencesUtil.java to PreferenceFragmentUtils.java 2022-12-29 19:08:15 +03:00
Vologhat 93b28b0a8f add non-null annotation 2022-12-29 19:04:11 +03:00
gdlbo ed0587b9b6 Merge pull request #988 from psamur/main
"View all..." normal translation
2022-12-29 10:43:16 +03:00
Pavel 6ce72dfc8b - bad translate + normal translate requested in VKTCH 2022-12-29 01:21:10 +03:00
gdlbo 65f44d32ca Update ThemesUtils.java 2022-12-28 23:41:45 +03:00
k1zn 8e57d5ab44 fix crash notf name and translate
crash
2022-12-29 00:52:17 +05:00
gdlbo c2b6bffb17 added articles colors inj 2022-12-28 22:17:43 +03:00
gdlbo 550fbf8f6c Merge pull request #982 from abslike/patch-2
Fix monet in messages(nomilkshake)
2022-12-28 22:01:49 +03:00
gdlbo 79d3287143 fixed #969 again for muted accent 2022-12-28 21:56:34 +03:00
gdlbo 2242e37315 fixed outgoing msg highlighted status 2022-12-28 21:50:21 +03:00
gdlbo 7099da0387 fixed searchDialog 2022-12-28 21:39:56 +03:00
k1zn 9b29288351 fix #986 2022-12-28 22:07:03 +05:00
abslike e000bd7971 Fix monet in messages(nomilkshake) 2022-12-28 00:40:24 +05:00
gdlbo 8eb725148f added search engine selection 2022-12-27 18:05:54 +03:00
gdlbo af1d175415 fix #969 2022-12-27 16:28:19 +03:00
Vologhat 92edbd4686 add keyaboard popup 2022-12-27 16:20:31 +03:00
gdlbo 8d9812ebe0 fix #978 2022-12-27 15:54:55 +03:00
gdlbo 33477e809c fixed #974 2022-12-27 15:22:10 +03:00
Vologhat 04f4f7d2ad fix #972 2022-12-27 11:54:08 +03:00
gdlbo 80b8399cb8 added link to bot in tg stickers info 2022-12-27 01:05:51 +03:00
gdlbo 483c9eda4d added more anime pic search engine 2022-12-27 00:38:38 +03:00
gdlbo c76a7a5332 fixed crash SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 2022-12-26 23:20:07 +03:00
gdlbo c470062d70 fixed crash getColor 2022-12-26 23:11:42 +03:00
gdlbo 52f69c792d fixed google pic search for Ukraine users 2022-12-26 21:51:45 +03:00
Vologhat 33f150eb43 uncomment and refactor ota code 2022-12-26 21:49:48 +03:00
gdlbo e165f388f5 fixed google pic search 2022-12-26 21:39:24 +03:00
Vologhat 761ff263be fix qualities list sorting 2022-12-26 20:46:47 +03:00
gdlbo 8918f203fc disabled accent for nonmilk 2022-12-26 19:29:46 +03:00
gdlbo 6039d0cf43 fixed msgs 2022-12-26 13:32:30 +03:00
gdlbo af902f945e Update styles.xml 2022-12-26 13:12:44 +03:00
gdlbo a90d96b00f disabled accents in nonmilk + enabled monet for nonmilk 2022-12-26 12:14:25 +03:00
gdlbo 550d3dadd8 some themesutils code fixes 2022-12-26 11:58:53 +03:00
gdlbo 82720adb61 fixed statusbar in audioplayer 2022-12-26 11:29:41 +03:00
gdlbo 2a3e12b39a fixed borders in monet 2022-12-26 11:06:43 +03:00
gdlbo 87407b0007 fixed accent hardcode in search 2022-12-26 10:50:44 +03:00
gdlbo ff2e33d9a2 fixed header text in monet nonmilk 2022-12-25 19:02:05 +03:00
Vologhat 61b6b0a1ec replace qualified name with import 2022-12-25 18:43:36 +03:00
gdlbo 9db18f526a Update ThemesCore.java 2022-12-25 18:31:10 +03:00
gdlbo 043253ffff disabled outgoing msg accenting in dark theme 2022-12-25 18:02:56 +03:00
gdlbo 756ab2b7c0 fixed muted colors on nonmilk 2022-12-25 17:56:59 +03:00
gdlbo 2ba5aef993 fixed accents exceptions 2022-12-25 17:54:08 +03:00
gdlbo ab3bd09ab7 fixed colors exceptions 2022-12-25 17:35:58 +03:00
gdlbo 7990d269aa refactored icon manager 2022-12-25 16:58:13 +03:00
gdlbo fffda61a83 fixup! disabled monet for nonmilk 2022-12-25 16:04:25 +03:00
gdlbo d817ccd292 disabled monet for nonmilk 2022-12-25 16:03:31 +03:00
gdlbo 02de3699cc fixed fix separator
dead fix xd
2022-12-24 13:53:53 +03:00
aliveoutside 81b214bcff fix vkui BottomConfirmButton 2022-12-24 13:24:17 +03:00
gdlbo 5dcf50fdc2 some sharing dialog fixes 2022-12-24 12:46:38 +03:00
gdlbo 81d4f9ec99 fixed search bar tint 2022-12-23 17:19:30 +03:00
gdlbo 29596b5dd1 fixed menu items coloring with monet theme 2022-12-23 17:10:30 +03:00
gdlbo b789840498 fixed control_foreground + control_background 2022-12-23 16:18:40 +03:00
gdlbo fce6c2b14f fixed vkim unread dot text 2022-12-23 16:05:54 +03:00
aliveoutside f2ac2c6a37 [monet] impl disabled buttons color 2022-12-23 15:45:40 +03:00
aliveoutside 61881f4e9d [monet] improve vkui buttons 2022-12-23 15:31:54 +03:00
aliveoutside 92f74aa5fb [monet] fix friends recom card background 2022-12-23 15:13:48 +03:00
aliveoutside 0c968de977 [monet] fix buttons tint in friends list 2022-12-23 14:51:50 +03:00
gdlbo 51efc8f4c6 disabled alpha picker 2022-12-21 19:41:33 +03:00
aliveoutside 4dbf1756e1 [monet] fix icon placeholder color on amoled theme 2022-12-21 19:16:24 +03:00
aliveoutside 8d4d88e099 [monet] fix icon placeholder color on dark theme 2022-12-21 19:10:28 +03:00
aliveoutside dd953d39e7 [monet] fix icon placeholder color 2022-12-21 18:52:26 +03:00
aliveoutside 4902938016 [monet] add a small accent to background_content 2022-12-21 18:36:16 +03:00
gdlbo 54de4fd060 Update styles.xml 2022-12-21 18:33:08 +03:00
gdlbo 6d9f3029d3 Update styles.xml 2022-12-19 14:23:52 +03:00
gdlbo 332fe678b9 Update styles.xml 2022-12-19 13:49:55 +03:00
gdlbo 04eee5cc26 Update JsonInjectors.java 2022-12-19 13:33:35 +03:00
Vologhat bc94f1ac77 reduce redundant reflection usage 2022-12-17 14:51:39 +03:00
gdlbo fc423d5ccd fixed cards colors 2022-12-16 20:31:28 +03:00
gdlbo f0993bee15 Update HomeFragment.smali 2022-12-16 19:58:28 +03:00
k1zn 22ef4bd646 Update strings.xml 2022-12-16 19:24:16 +05:00
k1zn c4cc678c82 add summary to themes 2022-12-16 19:22:47 +05:00
k1zn 350c25faff translate 2022-12-16 19:08:41 +05:00
aliveoutside 89ea35dd82 [monet] make newsfeed less ugly 2022-12-16 17:04:46 +03:00
aliveoutside cd858266a8 fix highlight monet color by @absl1ke 2022-12-16 16:42:11 +03:00
gdlbo 0549b07c49 Update stickers_keyboard_navigation.xml 2022-12-14 17:22:46 +03:00
gdlbo a7fd5536f6 fixed writebar issues 2022-12-14 17:11:29 +03:00
gdlbo 1397653b55 disabled NOTIFICATION_ANIM toggle 2022-12-14 15:57:59 +03:00
gdlbo ec1a0fc2d5 separator fixes 2022-12-14 15:57:47 +03:00
gdlbo b75dca5515 disabled shadow in milk news 2022-12-14 15:57:36 +03:00
gdlbo f31fade75a disabled clipdata ddos 2022-12-14 15:57:24 +03:00
gdlbo 347e0fb9c4 some monet fixes 2022-12-14 15:01:07 +03:00
gdlbo bf1a73f606 Update build.gradle 2022-12-13 22:10:23 +03:00
gdlbo 82e268ffa7 Update styles.xml 2022-12-13 22:10:11 +03:00
gdlbo f3acbf74a8 Update ThemesUtils.java 2022-12-13 20:37:22 +03:00
gdlbo 7126af6240 Update styles.xml 2022-12-13 20:20:29 +03:00
gdlbo ef2946a700 Update PhotoViewer.java 2022-12-13 20:08:09 +03:00
gdlbo 8821574412 fix 2022-12-13 19:59:20 +03:00
gdlbo 8257a374da monet separator fixes 2022-12-13 19:46:47 +03:00
gdlbo 3985593842 Update build.gradle 2022-12-13 18:54:23 +03:00
gdlbo 92d8c9a90d Update styles.xml 2022-12-12 22:41:56 +03:00
gdlbo 6f9c325b0d Update styles.xml 2022-12-12 22:37:02 +03:00
gdlbo 1010821cf4 Revert "add CompoundButton hook"
This reverts commit 04488314b5.
2022-12-12 22:16:08 +03:00
gdlbo 012dfa7063 fixed cards in monet style 2022-12-12 21:56:49 +03:00
gdlbo 01adf656e2 added support for monet light style 2022-12-12 17:04:37 +03:00
gdlbo bb64ed8d2a monet prefs imp 2022-12-12 16:47:08 +03:00
gdlbo 1ec78a8fbd some theme upgrades
monet theme disabled
amoled theme switch
some fixes with vkui inj
2022-12-12 16:34:52 +03:00
k1zn f1436ebbde fix music downloading with proxy 2022-12-11 23:32:13 +05:00
k1zn c4efb751c9 miui checks fix 2022-12-11 18:23:40 +05:00
Vologhat 6e902d4bca add miui checks 2022-12-11 15:54:03 +03:00
Vologhat 07b49a4a74 Merge branch 'main' of https://github.com/vtosters/lite 2022-12-11 15:51:22 +03:00
gdlbo c6fdf65137 fixed btns color 2022-12-11 15:50:59 +03:00
gdlbo 18e2554d5e fixed btns color 2022-12-11 14:17:03 +03:00
Vologhat 04488314b5 add CompoundButton hook 2022-12-11 14:12:29 +03:00
gdlbo 3eec52db3b fixed null crash csl in BottomNavigationItemView 2022-12-11 14:00:25 +03:00
gdlbo 132df6080e added useful feature 2022-12-11 13:33:55 +03:00
gdlbo d8f91bc730 fixed vologhat's best code reviewing 2022-12-11 13:32:44 +03:00
Vologhat 270c2af5c1 small messages downloader refactoring 2022-12-10 22:41:31 +03:00
Vologhat 99c500ed69 load placeholder image firstly 2022-12-10 22:21:40 +03:00
gdlbo 8174be1768 updated monet theme 2022-12-10 12:51:14 +03:00
Vologhat a88f59bac1 load user avatar image asynchronously 2022-12-09 21:03:50 +03:00
aliveoutside 1eaa3748c4 Merge remote-tracking branch 'origin/main' 2022-12-09 18:39:18 +03:00
aliveoutside 27836f72f5 Merge branch 'accents' 2022-12-09 18:35:03 +03:00
Saoqqandsaoq 70e048a1ad Add zipalign to CI and build.sh (#928)
* Add zipalign to CI and build.sh

* Revert accidentally removed cleanup

Co-authored-by: saoq <wfmfe@ya.ru>
2022-12-09 18:33:44 +03:00
aliveoutside e915b26918 fix incorrect downloaded tracks length
closes #868
2022-12-09 18:07:40 +03:00
gdlbo 8a6a92f77b upgraded color refs 2022-12-08 14:36:33 +03:00
gdlbo cb492b5949 handle color + highlight color fix 2022-12-08 13:43:57 +03:00
gdlbo f15e4c004d color handles 2022-12-08 13:28:50 +03:00
gdlbo f7f2cf3e58 color cursor 2022-12-08 13:01:22 +03:00
gdlbo 578fa86f19 Update ThemesUtils.java 2022-12-07 18:46:23 +03:00
gdlbo a9bcb19ebf Update StandartFilter.txt 2022-12-07 18:40:07 +03:00
gdlbo cf6b993172 Update EditTextExt.smali 2022-12-07 18:32:34 +03:00
gdlbo 145a6a668b Update date_picker_selector.xml 2022-12-07 18:08:37 +03:00
gdlbo 6b2752db67 Update ColorReferences.java 2022-12-07 18:03:51 +03:00
gdlbo 58fb6224f4 color imp 2022-12-07 17:51:53 +03:00
gdlbo b6406bcebf fixed some coloring 2022-12-07 17:33:21 +03:00
gdlbo 6c7733f1a0 updated code 2022-12-07 17:17:04 +03:00
gdlbo 5373002666 some mbsh updates 2022-12-07 16:49:58 +03:00
gdlbo 4005ac2ef1 Update ColorReferences.java 2022-12-07 10:26:47 +03:00
gdlbo 30de30cf64 fixed many colors 2022-12-07 01:41:22 +03:00
gdlbo 0feeacb533 Update ColorReferences.java 2022-12-06 22:03:17 +03:00
gdlbo de511d15a6 some code upgrades 2022-12-06 18:45:33 +03:00
aliveoutside dc1be1434a Merge pull request #931 from rekayno/patch-1
Update build.yml
2022-12-06 18:32:45 +03:00
gdlbo 6b88996962 fixed ssfs 2022-12-06 16:59:22 +03:00
gdlbo bb35b2b252 Update styles.xml 2022-12-05 17:14:51 +03:00
gdlbo b2f1cfea5e Update ThemesUtils.java 2022-12-05 16:38:44 +03:00
gdlbo 2748ec6902 added muted coloring 2022-12-05 16:19:05 +03:00
gdlbo 17b9c7075e muted accent 2022-12-05 15:20:28 +03:00
gdlbo fd070323b0 Update TextViewHook.java 2022-12-05 14:49:26 +03:00
gdlbo 03a43326b7 tablayout color fix 2022-12-05 14:34:02 +03:00
gdlbo a0b28b6c12 fixed crash 2022-12-05 13:34:48 +03:00
gdlbo 5d46edb91a Update TogglesHook.java 2022-12-05 13:32:41 +03:00
gdlbo 0e751533b5 fixed crashes 2022-12-05 12:53:58 +03:00
gdlbo 32d5ba792a Update PhotoListFragment.smali 2022-12-05 12:47:45 +03:00
gdlbo eb96137c3a ultra upgraded theming csl 2022-12-05 01:20:02 +03:00
gdlbo 09f7a07226 Update SuperAppEditorFragment.java 2022-12-05 00:52:56 +03:00
gdlbo 251f9935aa fixed toolbar 2022-12-05 00:43:20 +03:00
gdlbo a75070f8d3 Update ToolbarHook.java 2022-12-05 00:04:04 +03:00
gdlbo 972921a05c OverlayTextView hooked 2022-12-04 23:31:38 +03:00
gdlbo 3b2586ade5 some hooks update 2022-12-04 23:11:07 +03:00
gdlbo 58ea05cc9d updated toolbar icons hook 2022-12-04 22:33:13 +03:00
gdlbo 441baac671 Update ViewInjector.java 2022-12-04 22:23:34 +03:00
Vologhat a1efd38048 add toolbar icons hook 2022-12-04 22:21:40 +03:00
gdlbo d8be2fe7b7 some hooks updates 2022-12-04 22:14:29 +03:00
k1zn 27fdbf2407 [accents] translate colorpickers 2022-12-04 17:27:31 +05:00
k1zn fd954f5bab [accents] translate 2022-12-04 01:21:48 +05:00
gdlbo 3295e40231 Update vkim_bg_dialog_bar_button_primary.xml 2022-12-03 16:15:54 +03:00
gdlbo f88596025f fixed sending icon im msgs 2022-12-03 15:22:34 +03:00
gdlbo 9c5f584d1b disabled calls button 2022-12-03 15:19:20 +03:00
gdlbo 537a3759d0 fixed accent resetting 2022-12-03 14:57:12 +03:00
gdlbo f2fcc5f4d1 some hardcode color fixes 2022-12-02 19:58:09 +03:00
gdlbo db651c462a Update ThemesFragment.java 2022-12-02 19:27:13 +03:00
gdlbo 4f06fda96d Update styles.xml 2022-12-02 19:19:22 +03:00
gdlbo 1344e88b95 added alpha dark/amoled theme monet on sdk 31
todo light theme
2022-12-02 18:53:20 +03:00
Vologhat 23dd5a71e0 add new accent choices 2022-12-02 18:48:47 +03:00
Vologhat 810e5c72c1 add palettes 2022-12-02 18:48:22 +03:00
Vologhat 045daeea47 update ModalBottomSheetWrapper 2022-12-02 18:45:40 +03:00
Vologhat f45de44c75 add color picker by Martin Stone
Add own modification of HSV-Alpha Color Picker for Android https://github.com/martin-stone/hsv-alpha-color-picker-android
2022-12-02 18:37:12 +03:00
gdlbo d2911e5b6b updated msg colors 2022-12-02 14:52:54 +03:00
gdlbo 576890189c fixed accent fragment and color resetting 2022-12-02 13:44:08 +03:00
gdlbo 5ce6ab3aa8 removed global context from adding prefs 2022-12-02 13:43:50 +03:00
Vologhat 1451e2d3ac downgrade buildToolsVersion 2022-12-02 11:53:39 +03:00
Vologhat 95958a85e9 Update IOUtils.java 2022-12-02 11:52:49 +03:00
Vologhat 9f2b3edbe8 Update IOUtils.java 2022-12-01 23:23:55 +03:00
gdlbo ee4249c688 Revert "Update IOUtils.java"
This reverts commit 2f46c193dd.
2022-12-01 23:17:40 +03:00
Vologhat 2f46c193dd Update IOUtils.java 2022-12-01 23:08:29 +03:00
Vologhat 09807a2954 coloring outgoing messages in accent 2022-12-01 22:52:21 +03:00
gdlbo 163cd44dcc getAccenedColorStateList 2022-12-01 21:45:40 +03:00
gdlbo 2bdff722d4 Updated default accent color 2022-12-01 20:46:49 +03:00
gdlbo e206e85324 updated color hooks 2022-12-01 20:34:48 +03:00
rekayno 40159a2a9f Update build.yml
update actions
2022-11-30 17:00:49 +03:00
Denis 54d59e1f2f Update README.md 2022-11-30 15:01:33 +05:00
Vologhat 1b797325f0 Update MessagesPreviewAdapter.java 2022-11-30 11:49:02 +03:00
Vologhat 63c3c0ee32 refactoring 2022-11-30 00:26:58 +03:00
Vologhat 4b6a7aeb84 invalidate color state of dockbar tab titles 2022-11-29 23:16:36 +03:00
Vologhat 38f65997a6 add input format for color string, and reset button 2022-11-29 22:13:30 +03:00
Vologhat d718851d0c fix accent color resetting 2022-11-29 16:00:31 +03:00
gdlbo b30ad26f54 fixed vk cringe bg color in volume control 2022-11-28 12:23:26 +03:00
gdlbo 5f5fb650f2 fixed volume control color 2022-11-28 12:06:05 +03:00
gdlbo 76260981c5 disabled useless hide button 2022-11-28 12:01:29 +03:00
gdlbo ceb84ed6f6 reply bar fix 2022-11-28 11:51:47 +03:00
gdlbo e8a2c3af56 ssfs update 2022-11-27 15:20:27 +03:00
gdlbo 80e78fa2c1 some music coloring 2022-11-27 02:34:22 +03:00
gdlbo 7b35501461 coloring playlists icons 2022-11-27 02:13:40 +03:00
gdlbo c9cfc5e749 updated msg recoloring 2022-11-27 00:36:39 +03:00
gdlbo f0a915be05 Merge pull request #920 from Saoqq/r/sh-build-script
Refactor buildscripts
2022-11-26 18:19:26 +03:00
saoq f2b8624cc4 Update README.md 2022-11-26 01:38:33 +03:00
saoq ccaa10d224 Extract dex move to gradle task, apply to CI .yml 2022-11-26 01:38:22 +03:00
saoqq 6325d8fe68 Remove complication for Win script call, fix sh script invocation 2022-11-25 23:04:37 +03:00
saoqq e243522f95 Ensure Win buildscript works 2022-11-25 21:52:22 +03:00
saoq d87a59bcb0 Refactor build scripts 2022-11-25 08:56:52 +03:00
saoq 724fafc3fd Make build.sh dir independent 2022-11-25 06:13:31 +03:00
gdlbo 8c03ab60fc updated attrs and some swipe coloring 2022-11-24 15:00:02 +03:00
gdlbo 985ced6e3c deleted useless hook 2022-11-24 11:57:49 +03:00
aliveoutside 88339feb12 [accents] create a separate fragment for accents 2022-11-23 23:29:01 +03:00
aliveoutside 2bcf5d1c2d [accents] highlight edittext field 2022-11-23 23:08:01 +03:00
aliveoutside 77f9c60be7 [accents] replace AlertDialog with VkAlertDialog 2022-11-23 23:06:31 +03:00
aliveoutside 76468d8863 [WIP] Accent picker in settings 2022-11-23 22:24:25 +03:00
gdlbo c17e604db6 fixed cringe code + coloring bug 2022-11-22 22:31:32 +03:00
gdlbo 1a96f77aa1 some crash fixes 2022-11-22 21:34:48 +03:00
gdlbo 3fd0757fd4 Update DialogActionsListView.smali 2022-11-22 21:06:26 +03:00
gdlbo 989075a3d2 Update DrawableExt.smali 2022-11-22 20:21:29 +03:00
aliveoutside 802d88cad7 fix AppCompatResources 2022-11-22 20:09:12 +03:00
gdlbo 95a0451c6b fixed dw coloring 2022-11-22 20:06:56 +03:00
aliveoutside 3b83f05bf0 init ThemesCore 2022-11-22 19:08:47 +03:00
aliveoutside c7d350f5b1 remove logger from TextViewHook 2022-11-22 19:08:39 +03:00
gdlbo d3eeaf5f23 removed some hardcode 2022-11-22 19:06:06 +03:00
aliveoutside 4dcea46be7 recolor CSL where it is possible 2022-11-22 18:06:32 +03:00
aliveoutside 96de61fd15 move some stuff from ThemesUtils 2022-11-22 18:00:12 +03:00
aliveoutside 47f4c5c911 Init 2022-11-22 16:58:09 +03:00
aliveoutside fcbf9238cf wait for the pfp loaded in settings
fixes #912
2022-11-21 10:51:05 +03:00
gdlbo 4a8a2adb4e Update MediaFragment.java 2022-11-14 21:06:03 +03:00
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
1899 changed files with 27581 additions and 405822 deletions
+1 -4
View File
@@ -19,9 +19,6 @@ assignees: ''
**Скриншот ошибки**
**Информация об устройстве:**
- Устройство: Samsung Galaxy J1 Mini
- OS: Android 9 | OneUi 3.0
- Коммит: fa12e8f (В О Приложении написана версия коммита)
**Скопируйте сюда информацию об устройстве нажав на кнопку "Скопировать информацию об устройстве" в Настройках -> Другое и удалите этот текст**
**Дополнительная информация о баге или мыслях почему оно может происходить (если есть)**
Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+11 -7
View File
@@ -21,33 +21,37 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up JDK 11
uses: actions/setup-java@v2
- name: Set up JDK 14
uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '14'
distribution: 'adopt'
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Download tools
run: |
sudo apt update
sudo apt install default-jre
sudo apt install python3
sudo apt install zipalign
chmod +x scripts/apktool.jar
chmod +x scripts/apksigner.jar
- name: Build VTLite
run: |
bash scripts/buildworkflow.sh
gradle prepareDexForMerge
java -jar scripts/apktool.jar b smali -o smali/VTLite.apk --use-aapt2 -p scripts/framework/
zipalign -p -f 4 smali/VTLite.apk smali/VTLite.apk_aligned
mv smali/VTLite.apk_aligned smali/VTLite.apk
- name: Sign and verify the apk
run: |
java -jar scripts/apksigner.jar sign --ks scripts/debug.keystore --ks-key-alias androiddebugkey --ks-pass pass:android smali/VTLite.apk
java -jar scripts/apksigner.jar verify smali/VTLite.apk
- name: Upload apk to artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: VTLite.apk
path: smali/VTLite.apk
+1
View File
@@ -30,3 +30,4 @@ smali/build/resources.zip
smali/assets/version.properties
*.keystore
gradle.properties
scripts/build.sh
+6 -9
View File
@@ -46,8 +46,7 @@
- [Разработка](#разработка)
- [Всё необходимое для сборки и компиляции](#всё-необходимое-для-сборки-и-компиляции)
- [Необходимые зависимости](#необходимые-зависимости)
- [Linux/macOS](#linuxmacos)
- [Windows](#windows)
- [Linux/MacOS/Windows](#LinuxmacOSWindows)
## Функциональность
@@ -122,12 +121,10 @@
<a href="https://developer.android.com/studio"><img src="https://i.imgur.com/cPvvFDP.png" align="center" width="20" height="23"/> **Android Studio**</a>
### Linux/macOS
Для сборки используется файл `./build.sh`
### Linux/macOS/Windows
<img src="https://i.imgur.com/8BMX8lG.png" width="550" height="368"/>
Для сборки необходимо вызвать одну из следующих gradle tasks:
### Windows
Для сборки используется файл `build.bat`
<img src="https://i.imgur.com/iZSUKJ6.png" width="550" height="368"/>
+ `./gradlew buildVTL` - соберет и подпишет APK
+ `./gradlew buildAndInstallVTL` - соберет, подпишет и попытается установить через ADB
+ [FOR DEVS] `./gradlew prepareDexForMerge` - соберет все необходимое для сборки в `smali/`
+80 -8
View File
@@ -1,3 +1,5 @@
import org.apache.tools.ant.taskdefs.condition.Os
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipInputStream
@@ -7,9 +9,15 @@ plugins {
id 'net.nemerosa.versioning' version '2.15.1'
}
def smaliFolder = projectDir.toPath().resolve("../smali").normalize()
def scriptsFolder = projectDir.toPath().resolve("../scripts").normalize()
versionFile {
File moduleDir = projectDir
file = new File(moduleDir.getAbsolutePath() + "/src/main/assets/version.properties")
file = projectDir.toPath().resolve("src/main/assets/version.properties").toFile()
}
task cleanVersionFile {
projectDir.toPath().resolve("src/main/assets/version.properties").toFile().delete()
}
task exportDex {
@@ -69,7 +77,13 @@ task exportDex {
android {
compileSdkVersion 32
buildToolsVersion '33.0.0'
buildToolsVersion '32.0.0'
sourceSets {
main {
java.srcDirs += 'build/generated/aidl_source_output_dir/release/out'
}
}
defaultConfig {
applicationId "ru.vtosters.lite.utils.lite"
@@ -82,8 +96,8 @@ android {
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
sourceCompatibility JavaVersion.VERSION_14
targetCompatibility JavaVersion.VERSION_14
}
namespace 'ru.vtosters.lite'
}
@@ -91,8 +105,66 @@ 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'])
}
}
task prepareDexForMerge(type: Copy) {
dependsOn('exportDex')
into smaliFolder.toString()
from(projectDir) {
include 'classes6.dex'
include 'classes7.dex'
}
from(projectDir) {
include 'version.properties'
into("assets")
}
doLast {
new File(projectDir, "classes6.dex").delete()
new File(projectDir, "classes7.dex").delete()
new File(projectDir, "version.properties").delete()
}
}
task buildVTL(type: Exec) {
dependsOn('prepareDexForMerge')
workingDir(projectDir.parentFile)
if (Os.isFamily("unix") || Os.isFamily("mac")) {
commandLine 'bash', '-c', './scripts/build.sh'
} else {
commandLine 'cmd', '/C', '.\\scripts\\build.bat'
}
}
task buildAndInstallVTL(type: Exec) {
dependsOn('buildVTL')
workingDir(scriptsFolder.toString())
ignoreExitValue true
if (Os.isFamily("unix") || Os.isFamily("mac")) {
commandLine 'bash', '-c', 'adb install VTLite.apk'
} else {
commandLine 'adb', 'install', 'VTLite.apk'
}
}
task buildAndLaunchVTL(type: Exec) {
dependsOn('buildAndInstallVTL')
if (Os.isFamily("unix") || Os.isFamily("mac"))
commandLine 'bash', '-c', 'adb shell monkey -p com.vtosters.lite -c android.intent.category.LAUNCHER 1'
else
commandLine 'adb', 'shell', 'monkey', '-p', 'com.vtosters.lite', '-c', 'android.intent.category.LAUNCHER', '1'
}
task generateRjava(type: Exec) {
workingDir(projectDir.parentFile)
if (Os.isFamily("unix") || Os.isFamily("mac"))
commandLine "bash", "-c", "./scripts/rclass_regenerator.sh"
else
commandLine "cmd", "/C", ".\\scripts\\rclass_regenerator.sh"
}
exportDex.dependsOn('assembleRelease')
clean.dependsOn('cleanVersionFile')
versionFile.dependsOn('cleanVersionFile')
preBuild.dependsOn('versionFile')
@@ -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;
}
@@ -12,7 +12,8 @@ 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;
@@ -21,22 +22,22 @@ 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(R.string.telegram_stickers_service), NotificationManager.IMPORTANCE_HIGH);
@@ -45,19 +46,19 @@ public class NotificationsHelper {
}
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(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());
@@ -69,11 +70,13 @@ public class NotificationsHelper {
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);
@@ -81,9 +84,9 @@ public class NotificationsHelper {
String text;
if (success)
text = wasUpdate ? pack.title + AndroidUtils.getString(R.string.telegram_stickers_updated) : pack.title + AndroidUtils.getString(R.string.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(R.string.telegram_stickers_error_update) : pack.title + AndroidUtils.getString(R.string.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();
@@ -91,11 +94,12 @@ 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() {
@@ -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
@@ -1,16 +1,14 @@
package com.aefyr.tsg.g2;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.aefyr.tsg.g2.sql.TelegramStickersDbHelper;
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber;
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersPackInfo;
import ru.vtosters.lite.ui.fragments.tgstickers.StickersFragment;
import java.io.File;
import java.util.ArrayList;
@@ -19,7 +17,7 @@ import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import ru.vtosters.lite.ui.fragments.tgstickers.StickersFragment;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
/**
* Created by Aefyr on 19.05.2018.
@@ -227,6 +225,7 @@ public class TelegramStickersService {
currentlyDownloading.add(id.toLowerCase());
notificationsHelper.packStartedDownloading(newPack);
grabber.enableProxy();
grabber.grabPack(id, packFolder, pack.version, new TelegramStickersGrabber.PackDownloadListener() {
@Override
@@ -235,7 +234,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) {
@@ -383,7 +382,7 @@ public class TelegramStickersService {
getPacksListReference().set(li1, p2);
}
interface StickersEventsListener {
public interface StickersEventsListener {
void onPackAdded(TelegramStickersPack pack, int atIndex);
void onPackRemoved(TelegramStickersPack pack, int atIndex);
@@ -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() {
@@ -0,0 +1,132 @@
package com.vk.core.drawable;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import ru.vtosters.lite.themes.utils.RecolorUtils;
public class RecoloredDrawable extends Drawable implements Drawable.Callback {
private Drawable drawable;
private ColorStateList colorStateList;
private int c;
private int d;
public RecoloredDrawable(Drawable drawable, ColorStateList colorStateList) {
this.c = 255;
this.d = 255;
try {
this.drawable = drawable.mutate();
} catch (Exception e) {
e.printStackTrace();
}
this.drawable.setCallback(this);
this.colorStateList = RecolorUtils.themeCSL(colorStateList);
onStateChange(new int[0]);
}
public void a(int i) {
a(new ColorStateList(new int[][]{new int[0]}, new int[]{i}));
}
@Override
public void draw(@NonNull Canvas canvas) {
this.drawable.draw(canvas);
}
@Override
public int getIntrinsicHeight() {
return this.drawable.getIntrinsicHeight();
}
@Override
public int getIntrinsicWidth() {
return this.drawable.getIntrinsicWidth();
}
@Override
public int getOpacity() {
return this.drawable.getOpacity();
}
@Override
public void invalidateDrawable(@NonNull Drawable drawable) {
invalidateSelf();
}
@Override
public boolean isStateful() {
return this.colorStateList.isStateful();
}
@Override
protected boolean onStateChange(int[] iArr) {
super.onStateChange(iArr);
ColorStateList colorStateList = this.colorStateList;
this.drawable.setColorFilter(colorStateList.getColorForState(iArr, colorStateList.getDefaultColor()), PorterDuff.Mode.SRC_IN);
int length = iArr.length;
boolean z = false;
int i = 0;
while (true) {
if (i >= length) {
break;
} else if (iArr[i] == 0x010100a1) {
z = true;
break;
} else {
i++;
}
}
this.drawable.setState(iArr);
this.drawable.setAlpha(z ? this.c : this.d);
return true;
}
@Override
public void scheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable, long j) {
scheduleSelf(runnable, j);
}
@Override
public void setAlpha(int i) {
this.c = i;
this.d = i;
this.drawable.setAlpha(i);
}
@Override
public void setBounds(int i, int i2, int i3, int i4) {
super.setBounds(i, i2, i3, i4);
this.drawable.setBounds(i, i2, i3, i4);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public void unscheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable) {
unscheduleSelf(runnable);
}
public void a(ColorStateList colorStateList) {
this.colorStateList = colorStateList;
onStateChange(getState());
invalidateSelf();
}
public Drawable a() {
return this.drawable;
}
public RecoloredDrawable(Drawable drawable, int i) {
this(drawable, new ColorStateList(new int[][]{new int[0]}, new int[]{i}));
}
public RecoloredDrawable() {
this.c = 255;
this.d = 255;
}
}
@@ -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()));
@@ -191,7 +191,7 @@ public class DownloadUtils {
if (!file.exists()) {
return false;
}
Intent intent = new Intent("android.intent.action.VIEW");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
var mimeType = FileUtils.f(file);
var uri = FileUtils.uriFromFile(file);
@@ -222,7 +222,7 @@ public class DownloadUtils {
var mimeType = FileUtils.f(file);
var uri = FileUtils.uriFromFile(file);
Intent intent = new Intent("android.intent.action.VIEW");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, mimeType);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Log.d("DownloadUtils", "openFile: " + file.getAbsolutePath() + "| mimetype " + mimeType + "| uri " + uri);
@@ -36,5 +36,6 @@ public enum DialogAction {
unpinmsg,
ENCRYPT_SETT,
ENCRYPT,
DOWNLOAD
DOWNLOAD,
STAT
}
@@ -0,0 +1,72 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.vk.im.ui.components.viewcontrollers.msg_list.adapter;
import android.util.SparseIntArray;
import androidx.annotation.ColorInt;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import com.vk.im.engine.j.StickersAnimationLoader;
import com.vk.im.engine.models.ImExperimentsProvider;
import com.vk.im.engine.models.Member;
import com.vk.im.engine.models.ProfilesSimpleInfo;
import com.vk.im.engine.models.attaches.Attach;
import com.vk.im.engine.models.messages.Msg;
import com.vk.im.engine.models.messages.NestedMsg;
import com.vk.im.ui.media.audio.AudioTrack;
import com.vk.im.ui.q.h.VideoAutoPlayer;
import com.vk.im.ui.views.span.OnSpanClickListener;
import com.vk.im.ui.views.span.OnSpanLongPressListener;
import com.vk.im.ui.views.sticker.StickerAnimationState;
import java.util.List;
@MainThread
public class MsgPartHolderBindArgs {
public SparseIntArray A;
public AudioTrack B;
public AudioMsgInfo C;
public StickerAnimationState D;
public StickersAnimationLoader E;
@Nullable
public OnSpanClickListener F;
@Nullable
public OnSpanLongPressListener G;
@Nullable
public MsgListAdapterCallback H;
@Nullable
public VideoAutoPlayer I;
public Msg a;
public NestedMsg b;
public CharSequence c;
public Attach d;
public List<Attach> e;
public boolean f;
public int g;
public int h;
public int i;
public int j;
public int k;
@ColorInt
public int l;
public Member m;
public ProfilesSimpleInfo n;
public ImExperimentsProvider o;
public int p;
public int q;
public int r;
public boolean s;
public boolean t;
public boolean u;
public boolean v;
public boolean w;
public boolean x;
public boolean y;
public boolean isSelected;
public SparseIntArray z;
public MsgPartHolderBindArgs() {
}
}
@@ -0,0 +1,547 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.vk.im.ui.components.viewcontrollers.msg_list.adapter;
import android.util.SparseIntArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.vk.core.network.TimeProvider;
import com.vk.im.engine.j.StickersAnimationLoader;
import com.vk.im.engine.models.ImBgSyncState;
import com.vk.im.engine.models.ImExperimentsProvider;
import com.vk.im.engine.models.Member;
import com.vk.im.engine.models.ProfilesSimpleInfo;
import com.vk.im.engine.models.attaches.AttachAudioMsg;
import com.vk.im.engine.models.dialogs.Dialog;
import com.vk.im.engine.models.dialogs.DialogTheme;
import com.vk.im.engine.models.messages.Msg;
import com.vk.im.engine.models.messages.MsgFromUser;
import com.vk.im.engine.models.messages.MsgIdType;
import com.vk.im.engine.models.messages.MsgSyncState;
import com.vk.im.engine.models.messages.WithUserContent;
import com.vk.im.engine.utils.collection.IntSet;
import com.vk.im.ui.components.viewcontrollers.msg_list.entry.AdapterEntry;
import com.vk.im.ui.media.audio.AudioTrack;
import com.vk.im.ui.q.h.VideoAutoPlayer;
import com.vk.im.ui.views.span.OnSpanClickListener;
import com.vk.im.ui.views.span.OnSpanLongPressListener;
import com.vk.im.ui.views.sticker.StickerAnimationState;
public class VhBindArgs {
public MsgListAdapterCallback A;
@Nullable
public VideoAutoPlayer B = null;
@Nullable
public MsgIdType C = null;
public int D = -1;
public AdapterEntry a;
public AdapterEntry b;
public AdapterEntry c;
public int d;
@Nullable
public Dialog e;
@NonNull
public DialogTheme f;
public Member g;
public ProfilesSimpleInfo h;
public int i;
public boolean j;
public boolean k;
public boolean l;
public long m;
public ImExperimentsProvider n;
public ImBgSyncState o;
public int p;
public boolean q;
public IntSet r;
public SparseIntArray s;
public SparseIntArray t;
public AudioTrack u;
public AudioMsgInfo v;
public StickerAnimationState w;
public StickersAnimationLoader x;
@Nullable
public OnSpanClickListener y;
@Nullable
public OnSpanLongPressListener z;
public VhBindArgs() {
}
private long K() {
Msg var1 = this.b.c;
return var1 == null ? Long.MAX_VALUE : TimeProvider.f.b() - var1.getTime();
}
private boolean L() {
boolean var1;
if (this.K() <= this.m && !TimeProvider.f.c()) {
var1 = false;
} else {
var1 = true;
}
return var1;
}
public boolean A() {
AdapterEntry var1 = this.a;
boolean var2 = false;
boolean var3 = var2;
if (var1 != null) {
if (var1.d()) {
var3 = var2;
} else {
Msg var4 = this.a.c;
Msg var5 = this.b.c;
var3 = var2;
if (var4.W() == var5.W()) {
var3 = var2;
if (var4.e0() == var5.e0()) {
var3 = true;
}
}
}
}
return var3;
}
public boolean B() {
AdapterEntry var1 = this.a;
boolean var2;
if (var1 != null && var1.c()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean C() {
AdapterEntry var1 = this.a;
boolean var2;
if (var1 != null && var1.c() && this.a.c.getLocalId() == this.b.c.getLocalId()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean D() {
AdapterEntry var1 = this.a;
boolean var2;
if (var1 != null && var1.a == 83) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean E() {
Msg var1 = this.b.c;
boolean var2;
if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).i2()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean F() {
Msg var1 = this.b.c;
boolean var2;
if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).F0()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean G() {
AdapterEntry var1 = this.b;
boolean var2;
if (var1 != null && var1.a == 51) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public int H() {
return this.b.i;
}
public boolean I() {
long var1 = this.K();
long var3 = this.m;
boolean var5;
if (var1 > var3 && var1 < var3 * 2L) {
var5 = true;
} else {
var5 = false;
}
return var5;
}
public boolean J() {
Msg var1 = this.b.c;
boolean var2 = false;
if (var1 == null) {
return false;
} else if (!(var1 instanceof MsgFromUser)) {
return false;
} else {
MsgFromUser var7 = (MsgFromUser)var1;
Msg var3 = this.a.c;
boolean var4;
if (var3 != null && var3.d() == MsgSyncState.DONE) {
var4 = true;
} else {
var4 = false;
}
boolean var5;
if (this.o == ImBgSyncState.CONNECTED) {
var5 = true;
} else {
var5 = false;
}
boolean var6 = var2;
if (!var7.H0()) {
var6 = var2;
if (var5) {
var6 = var2;
if (!this.L()) {
var6 = var2;
if (var4) {
var6 = true;
}
}
}
}
return var6;
}
}
public int a() {
boolean var1 = this.h();
byte var2 = 0;
int var3 = var2;
if (var1) {
AttachAudioMsg var4 = (AttachAudioMsg)((MsgFromUser)this.b.c).c(AttachAudioMsg.class, false);
var3 = var2;
if (var4 != null) {
var3 = var4.f();
}
}
return var3;
}
public int b() {
Msg var1 = this.b.c;
int var2;
if (var1 != null) {
var2 = var1.B1();
} else {
var2 = 0;
}
return var2;
}
public boolean c() {
Msg var1 = this.b.c;
boolean var2;
if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).I0()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean d() {
Msg var1 = this.b.c;
boolean var2;
if (var1 instanceof WithUserContent && ((WithUserContent)var1).D0() != null) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean e() {
boolean var1;
if (this.b.i > 0) {
var1 = true;
} else {
var1 = false;
}
return var1;
}
public boolean f() {
AdapterEntry var1 = this.b;
boolean var2;
if (var1 != null) {
Msg var3 = var1.c;
if (var3 != null && var3.P1()) {
var2 = true;
return var2;
}
}
var2 = false;
return var2;
}
public boolean g() {
Msg var1 = this.b.c;
boolean var2;
if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).G0()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean h() {
Msg var1 = this.b.c;
boolean var2;
if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).Z1()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean i() {
boolean var1;
if (this.j && !this.u() && !this.l()) {
var1 = true;
} else {
var1 = false;
}
return var1;
}
public boolean j() {
boolean var1;
if (!this.j || this.u() || this.B() && this.A() && !this.a.c.H1()) {
var1 = false;
} else {
var1 = true;
}
return var1;
}
public boolean k() {
Dialog var1 = this.e;
boolean var2;
if (var1 != null && var1.U1()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean l() {
Dialog var1 = this.e;
boolean var2;
if (var1 != null && var1.V1()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean m() {
Dialog var1 = this.e;
boolean var2;
if (var1 != null && var1.W1()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean n() {
int var1 = this.b.a;
return var1 == 52 || var1 == 53 || var1 == 56 || var1 == 57 || var1 == 70 || var1 == 77 || var1 == 85 || var1 == 94 || var1 == 95;
}
public boolean o() {
AdapterEntry var1 = this.b;
boolean var2;
if (var1 != null && var1.a == 101) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean p() {
Msg var1 = this.b.c;
boolean var2;
if (var1 != null && var1.G1()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean q() {
AdapterEntry var1 = this.b;
boolean var3;
if (var1 != null) {
int var2 = var1.a;
if (var2 == 59 || var2 == 58 || var2 == 61 || var2 == 60) {
var3 = true;
return var3;
}
}
var3 = false;
return var3;
}
public boolean r() {
Msg var1 = this.b.c;
boolean var2;
if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).e2()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean s() {
if(this.C != null)
return switch (this.C) {
case LOCAL_ID -> this.D == this.b.c.getLocalId();
case VK_ID -> this.D == this.b.c.C1();
};
return false;
}
public boolean t() {
AdapterEntry var1 = this.b;
boolean var2;
if (var1 != null) {
Msg var3 = var1.c;
if (var3 != null && !var3.b(this.g)) {
var2 = true;
return var2;
}
}
var2 = false;
return var2;
}
public boolean u() {
Msg var1 = this.b.c;
if (var1 != null) {
return var1.b(this.g);
} else {
throw new RuntimeException();
}
}
public boolean v() {
IntSet var1 = this.r;
boolean var2;
if (var1 != null && var1.a(this.b.c.getLocalId())) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean w() {
return this.z() ^ true;
}
public boolean x() {
AdapterEntry var1 = this.c;
boolean var2;
if (var1 != null && var1.a == 100) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean y() {
AdapterEntry var1 = this.c;
boolean var2;
if (var1 != null && var1.a == 96) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean z() {
AdapterEntry var1 = this.c;
boolean var2;
if (var1 != null && var1.c() && this.c.c.getLocalId() == this.b.c.getLocalId()) {
var2 = true;
} else {
var2 = false;
}
return var2;
}
public boolean isSelected() {
return this.b != null && this.b.c != null && this.r.a(this.b.c.getLocalId());
}
}
@@ -0,0 +1,176 @@
package com.vk.im.ui.components.viewcontrollers.msg_list.adapter.msgparts;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.vk.core.util.DurationFormatter;
import com.vk.im.engine.models.CallState;
import com.vk.im.engine.models.Member;
import com.vk.im.engine.models.attaches.Attach;
import com.vk.im.engine.models.attaches.AttachCall;
import com.vk.im.engine.models.dialogs.BubbleColors;
import com.vk.im.engine.models.messages.Msg;
import com.vk.im.ui.components.viewcontrollers.msg_list.adapter.MsgPartHolderBase;
import com.vk.im.ui.components.viewcontrollers.msg_list.adapter.MsgPartHolderBindArgs;
import com.vk.im.ui.components.viewcontrollers.msg_list.adapter.utils.MsgTimeFormatter;
import com.vk.im.ui.j;
import com.vk.im.ui.m;
import com.vk.im.ui.n;
import com.vk.im.ui.views.msg.MsgPartIconTwoRowView;
import com.vtosters.lite.R;
import kotlin.TypeCastException;
import kotlin.jvm.internal.Intrinsics;
import ru.vtosters.lite.hooks.CallsHook;
public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
public static final a I = new a();
private final Context C;
private final DurationFormatter D;
private final StringBuilder E;
private final MsgTimeFormatter F;
private final StringBuilder G;
private final MsgPartIconTwoRowView H;
private boolean incoming;
public MsgPartCallHolder(MsgPartIconTwoRowView var1) {
this.H = var1;
this.C = this.H.getContext();
Context var2 = this.H.getContext();
Intrinsics.a(var2, "view.context");
this.D = new DurationFormatter(var2);
this.E = new StringBuilder();
this.F = MsgTimeFormatter.f;
this.G = new StringBuilder();
}
private final void a(Msg var1) {
this.G.setLength(0);
MsgTimeFormatter var2 = this.F;
Context var3 = this.C;
Intrinsics.a(var3, "context");
var2.a(var1, var3, this.G);
this.H.setTimeText(this.G);
}
private final void a(boolean var1) {
MsgPartIconTwoRowView var2 = this.H;
int var3;
if (var1) {
var3 = R.drawable.vkim_ic_attach_video_call;
} else {
var3 = R.drawable.vkim_ic_attach_call;
}
var2.setIcon(var3);
}
private final void a(boolean var1, AttachCall var2) {
boolean var3 = !var1;
if (var2.h() == CallState.ERROR) {
this.H.setSubtitleText(m.vkim_msg_list_call_error);
this.H.setSubtitleTextAppearance(n.VkIm_MsgPart_Call_Failure);
} else if (var2.h() == CallState.DONE) {
this.E.setLength(0);
this.D.a(var2.a(), this.E);
this.H.setSubtitleText(this.E);
this.H.setSubtitleTextAppearance(n.VkIm_MsgPart_Call_Duration);
} else if (var1) {
this.H.setSubtitleText(m.vkim_msg_list_call_missed);
this.H.setSubtitleTextAppearance(n.VkIm_MsgPart_Call_Failure);
} else if (var2.h() == CallState.CANCELLED) {
this.H.setSubtitleText(m.vkim_msg_list_call_cancelled);
this.H.setSubtitleTextAppearance(n.VkIm_MsgPart_Call_Failure);
} else if (var2.h() == CallState.DECLINED) {
this.H.setSubtitleText(m.vkim_msg_list_call_declined);
this.H.setSubtitleTextAppearance(n.VkIm_MsgPart_Call_Failure);
}
}
private void b(boolean var1) {
incoming = var1;
if (incoming) {
this.H.setTitleText(m.vkim_msg_list_call_incoming);
} else {
this.H.setTitleText(m.vkim_msg_list_call_outgoing);
}
}
private void c() {
this.H.setTimeText(null);
}
private void c(MsgPartHolderBindArgs var1) {
super.f = var1.H;
super.g = var1.a;
super.h = var1.b;
Attach var2 = var1.d;
if (var2 != null) {
super.B = (AttachCall) var2;
} else {
throw new TypeCastException("null cannot be cast to non-null type com.vk.im.engine.models.attaches.AttachCall");
}
}
protected View b(LayoutInflater var1, ViewGroup var2) {
this.H.setOnClickListener(var11 -> {
if (incoming) {
CallsHook.forwardToVkOffApps(C, super.B.f().getId());
} else {
CallsHook.forwardToVkOffApps(C, super.B.g().getId());
}
});
return this.H;
}
protected void b(BubbleColors var1) {
this.a(this.H, var1);
}
protected void b(MsgPartHolderBindArgs var1) {
Msg var2 = var1.a;
if (var2 != null) {
Attach var3 = var1.d;
if (var3 != null) {
AttachCall var4 = (AttachCall) var3;
Member var5 = var4.f();
Member var8 = var1.m;
Intrinsics.a(var8, "bindArgs.currentMember");
boolean var6 = var5.e(var8);
boolean var7 = var4.i();
this.c(var1);
this.b(var6);
this.a(var6, var4);
this.a(var7);
if (var1.f) {
this.a(var2);
} else {
this.c();
}
} else {
throw new TypeCastException("null cannot be cast to non-null type com.vk.im.engine.models.attaches.AttachCall");
}
} else {
Intrinsics.a();
throw null;
}
}
public static final class a {
private a() {
}
public MsgPartCallHolder a(LayoutInflater var1, ViewGroup var2) {
View var3 = var1.inflate(j.vkim_msg_part_call, var2, false);
if (var3 != null) {
return new MsgPartCallHolder((MsgPartIconTwoRowView) var3);
} else {
throw new TypeCastException("null cannot be cast to non-null type com.vk.im.ui.views.msg.MsgPartIconTwoRowView");
}
}
}
}
@@ -0,0 +1,48 @@
package com.vk.im.ui.components.viewcontrollers.msg_list.adapter.msgparts;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.vk.im.engine.models.attaches.Attach;
import com.vk.im.engine.models.dialogs.BubbleColors;
import com.vk.im.ui.components.viewcontrollers.msg_list.adapter.MsgPartHolderBase;
import com.vk.im.ui.components.viewcontrollers.msg_list.adapter.MsgPartHolderBindArgs;
import com.vk.im.ui.views.msg.MsgPartTextView;
import com.vk.im.ui.views.msg.WithTime;
import com.vtosters.lite.R;
public class MsgPartTextHolder extends MsgPartHolderBase<Attach> {
private FrameLayout mContainer;
private MsgPartTextView mTextPart;
@Override
protected View b(LayoutInflater inflater, ViewGroup parent) {
mTextPart = (MsgPartTextView) inflater.inflate(R.layout.vkim_msg_part_text, parent, false);
mTextPart.setOnClickListener(view -> {
MsgPartTextHolder.this.f.a(MsgPartTextHolder.this.g.getLocalId());
});
mTextPart.setOnLongClickListener(view -> {
if(!mTextPart.isTextSelectable()) MsgPartTextHolder.this.f.b(MsgPartTextHolder.this.g.getLocalId());
return false;
});
return mTextPart;
}
@Override
protected void b(BubbleColors colors) {
mTextPart.setTimeTextColor(colors.h);
mTextPart.setLinkTextColor(colors.d);
mTextPart.setTextColor(colors.f);
}
@Override
protected void b(MsgPartHolderBindArgs bindArgs) {
mTextPart.setOnSpanClickListener(bindArgs.F);
mTextPart.setOnSpanLongPressListener(bindArgs.G);
mTextPart.setText(bindArgs.c);
mTextPart.setTextIsSelectable(bindArgs.isSelected);
a(bindArgs, (WithTime) mTextPart);
}
}
@@ -0,0 +1,171 @@
package com.vk.stickers.details;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.vk.core.ui.themes.VKThemeHelper;
import com.vk.core.util.Screen;
import com.vk.dto.stickers.StickerItem;
import com.vk.dto.stickers.StickerStockItem;
import com.vk.extensions.ViewExtKt;
import com.vk.imageloader.view.VKImageView;
import com.vk.stickers.views.VKStickerImageView;
import com.vtosters.lite.R;
import java.util.List;
public final class StickerDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<StickerItem> mItems;
private final StickerStockItem mItem;
private boolean mIsTelegramPack = false;
public StickerDetailsAdapter(StickerStockItem stickerStockItem) {
this.mItem = stickerStockItem;
this.mItems = this.mItem.T1();
}
public void setTelegramPack(boolean state) {
mIsTelegramPack = state;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return switch (i) {
case 0 -> new c(viewGroup);
case 1 -> new d(viewGroup);
case 2 -> new b(viewGroup);
default -> throw new IllegalArgumentException("Unknown viewType: " + i);
};
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
switch (getItemViewType(i)) {
case 0 -> ((c) viewHolder).a(this.mItem);
case 1 -> ((d) viewHolder).a(this.mItems.get(H(i)));
}
}
@Override
public int getItemCount() {
return mIsTelegramPack ? mItems.size() : this.mItems.size() + 2;
}
@Override
public int getItemViewType(int i) {
if (mIsTelegramPack) return 1;
if (i == 0) {
return 0;
}
return i == k() ? 2 : 1;
}
public int H(int i) {
return mIsTelegramPack ? i : i - j();
}
public boolean I(int i) {
return getItemViewType(i) == 1;
}
public int j() {
return 1;
}
public int k() {
return l() + 1;
}
public int l() {
return (this.mItems.size() + j()) - 1;
}
public int m() {
return 0;
}
public List<StickerItem> n() {
return this.mItems;
}
public boolean v() {
return false;
}
private static final class b extends RecyclerView.ViewHolder {
public b(ViewGroup viewGroup) {
super(ViewExtKt.a(viewGroup, R.layout.sticker_details_hold_to_view_item, false));
}
}
private final class c extends RecyclerView.ViewHolder {
private final VKImageView mImageBg;
private final VKImageView mPackImage;
private final ImageView mAnimPack;
private final TextView mPackTitle;
private final TextView mPackAuthor;
private final TextView mPackSubtitle;
private final TextView mDescription;
public c(ViewGroup viewGroup) {
super(LayoutInflater.from(VKThemeHelper.u()).inflate(R.layout.sticker_details_info_item, viewGroup, false));
this.mImageBg = this.itemView.findViewById(R.id.pack_image_bg);
this.mPackImage = this.itemView.findViewById(R.id.pack_image);
this.mAnimPack = this.itemView.findViewById(R.id.anim_pack);
this.mPackTitle = this.itemView.findViewById(R.id.pack_title);
this.mPackAuthor = this.itemView.findViewById(R.id.pack_author);
this.mPackSubtitle = this.itemView.findViewById(R.id.pack_subtitle);
this.mDescription = this.itemView.findViewById(R.id.description);
}
public void a(StickerStockItem stickerStockItem) {
this.mImageBg.a(stickerStockItem.R1());
this.mImageBg.getHierarchy().a().setVisible(true, true);
this.mImageBg.getHierarchy().a(0);
this.mImageBg.getHierarchy().e(new ColorDrawable(VKThemeHelper.d(R.attr.placeholder_icon_background)));
this.mPackImage.a(stickerStockItem.h(Screen.a(68)));
this.mPackImage.getHierarchy().a().setVisible(true, true);
this.mPackImage.getHierarchy().a(0);
if (stickerStockItem.E1()) {
ViewExtKt.r(this.mAnimPack);
} else {
ViewExtKt.p(this.mAnimPack);
}
this.mPackTitle.setText(stickerStockItem.getTitle());
this.mPackAuthor.setText(stickerStockItem.v1());
ViewExtKt.p(this.mPackSubtitle);
this.mDescription.setText(stickerStockItem.C1());
}
}
private static final class d extends RecyclerView.ViewHolder {
private final VKStickerImageView mImage;
public d(ViewGroup viewGroup) {
super(new VKStickerImageView(viewGroup.getContext()));
this.mImage = (VKStickerImageView) itemView;
this.mImage.setAspectRatio(1.0f);
this.mImage.setClickable(true);
this.mImage.getHierarchy().a().setVisible(true, true);
this.mImage.getHierarchy().a(0);
this.mImage.setContentDescription(this.mImage.getContext().getString(R.string.stickers_accessibility_sticker));
}
public void a(StickerItem stickerItem) {
this.mImage.a(stickerItem.h(Screen.a(80)));
this.mImage.setTag(R.id.id, stickerItem.getId());
}
}
}
+76 -1
View File
@@ -1,6 +1,7 @@
package com.vtosters.lite;
public class R {
public final class R {
public static final class anim {
public static final int abc_fade_in = 0x7f010000; // 2130771968
public static final int abc_fade_out = 0x7f010001; // 2130771969
@@ -220,6 +221,9 @@ public class R {
public static final int targetlang_value = 0x7f030074; // 2130903156
public static final int undel_value = 0x7f030075; // 2130903157
public static final int wallpaper_change_dialog = 0x7f030076; // 2130903158
public static final int accent_select_type = 0x7f030077; // 2130903159
public static final int theme_type_name = 0x7f030078; // 2130903160
public static final int theme_type_name_checkbox = 0x7f030079; // 2130903161
}
public static final class attr {
@@ -2133,6 +2137,7 @@ public class R {
public static final int zOrderOnTop = 0x7f040773; // 2130970483
public static final int im_ic_msgdl = 0x7f040774; // 2130970484
public static final int im_ic_msgreload = 0x7f040775; // 2130970485
public static final int im_ic_stats = 0x7f040776; // 2130970486
}
public static final class bool {
@@ -2152,6 +2157,7 @@ public class R {
public static final int spb_default_progressiveStart_activated = 0x7f05000d; // 2131034125
public static final int spb_default_reversed = 0x7f05000e; // 2131034126
public static final int vk_is_tablet = 0x7f05000f; // 2131034127
public static final int com_samsung_android_icon_container_has_icon_container = 0x7f050010; // 2131034128
}
public static final class color {
@@ -2961,6 +2967,7 @@ public class R {
public static final int yellow_sunflower = 0x7f060324; // 2131100452
public static final int iclauncher = 0x7f060325; // 2131100453
public static final int abc_color_highlight_material = 0x7f060004; // 2131099652
public static final int alpha05 = 0x7f060326; // 2131100454
}
public static final class dimen {
@@ -4971,6 +4978,7 @@ public class R {
public static final int roundmsg = 0x7f080bd3; // 2131233747
public static final int tgs_entry_background = 0x7f080bd4; // 2131233748
public static final int yandex = 0x7f080bd7; // 2131233751
public static final int checker_background = 0x7f080bd8; // 2131233752
public static final int abc_control_background_material = 0x7f080032; // 2131230770
public static final int ic_action_close = 0x7f080322; // 2131231522
public static final int ic_camera_outline_28_new = 0x7f0803a0; // 2131231648
@@ -11025,6 +11033,10 @@ public class R {
public static final int savedmsg = 0x7f0a101e; // 2131365918
public static final int search_photo = 0x7f0a101f; // 2131365919
public static final int text_hex_wrapper = 0x7f0a1020; // 2131365920
public static final int color_preview = 0x7f0a1021; // 2131365921
public static final int color_name = 0x7f0a1022; // 2131365922
public static final int color_value = 0x7f0a1023; // 2131365923
public static final int color_preview_border = 0x7f0a1024; // 2131365924
}
public static final class integer {
@@ -12845,6 +12857,7 @@ public class R {
public static final int tgs_entry = 0x7f0d06de; // 2131560158
public static final int wppreview = 0x7f0d06df; // 2131560159
public static final int write_bar_i = 0x7f0d06e0; // 2131560160
public static final int color_picker_item = 0x7f0d06e1; // 2131560161
}
public static final class menu {
@@ -19514,6 +19527,50 @@ public class R {
public static final int whitelisted_filters_groups_title = 0x7f121838; // 2131892280
public static final int why_news_not_updated_summ = 0x7f121839; // 2131892281
public static final int why_news_not_updated_title = 0x7f12183a; // 2131892282
public static final int accent_color_summ = 0x7f12183b; // 2131892283
public static final int accent_color_title = 0x7f12183c; // 2131892284
public static final int accents = 0x7f12183d; // 2131892285
public static final int amoledtheme_summ = 0x7f12183e; // 2131892286
public static final int amoledtheme_title = 0x7f12183f; // 2131892287
public static final int app_open_by_default_settings = 0x7f121840; // 2131892288
public static final int audio_deleted_from_cache = 0x7f121841; // 2131892289
public static final int blockminiapps_summ = 0x7f121842; // 2131892290
public static final int blockminiapps_title = 0x7f121843; // 2131892291
public static final int businessDisabler_title = 0x7f121844; // 2131892292
public static final int by_choice = 0x7f121845; // 2131892293
public static final int calls_not_available = 0x7f121846; // 2131892294
public static final int cannot_write = 0x7f121847; // 2131892295
public static final int change_accent_color = 0x7f121848; // 2131892296
public static final int copydebuginfo_summ = 0x7f121849; // 2131892297
public static final int copydebuginfo_title = 0x7f12184a; // 2131892298
public static final int copyownlink_summ = 0x7f12184b; // 2131892299
public static final int copyownlink_title = 0x7f12184c; // 2131892300
public static final int crash_service_name = 0x7f12184d; // 2131892301
public static final int current_theme = 0x7f12184e; // 2131892302
public static final int custom_links_warning = 0x7f12184f; // 2131892303
public static final int data_updated = 0x7f121850; // 2131892304
public static final int device_info = 0x7f121851; // 2131892305
public static final int device_info_copied = 0x7f121852; // 2131892306
public static final int dialogstats = 0x7f121853; // 2131892307
public static final int downloading_update = 0x7f121854; // 2131892308
public static final int invalid_pack_link = 0x7f121855; // 2131892309
public static final int maxquality_summ = 0x7f121856; // 2131892310
public static final int maxquality_title = 0x7f121857; // 2131892311
public static final int monettheme_summ = 0x7f121858; // 2131892312
public static final int monettheme_title = 0x7f121859; // 2131892313
public static final int newsfeed_notif_summ = 0x7f12185a; // 2131892314
public static final int newsfeed_notif_title = 0x7f12185b; // 2131892315
public static final int open_bot = 0x7f12185c; // 2131892316
public static final int promotedstickers_title = 0x7f12185d; // 2131892317
public static final int select_color = 0x7f12185e; // 2131892318
public static final int select_palette = 0x7f12185f; // 2131892319
public static final int sources = 0x7f121860; // 2131892320
public static final int updateverifdata_summ = 0x7f121861; // 2131892321
public static final int updateverifdata_title = 0x7f121862; // 2131892322
public static final int useOldAppVer_summ = 0x7f121863; // 2131892323
public static final int useOldAppVer_title = 0x7f121864; // 2131892324
public static final int vkx_integration_enabled_info = 0x7f121865; // 2131892325
public static final int writebar_ios_title = 0x7f121866; // 2131892326
}
public static final class style {
@@ -20658,6 +20715,24 @@ public class R {
public static final int Base_V26_Widget_AppCompat_Toolbar = 0x7f1300a1; // 2131951777
public static final int Base_V28_Theme_AppCompat = 0x7f1300a2; // 2131951778
public static final int Base_V28_Theme_AppCompat_Light = 0x7f1300a3; // 2131951779
public static final int Vk_Theme_VkApp_amoled_monet_generated = 0x7f130475; // 2131952757
public static final int Vk_Theme_VkApp_amoled_monet_old_generated = 0x7f130476; // 2131952758
public static final int Vk_Theme_VkApp_bright_light_monet_generated = 0x7f130477; // 2131952759
public static final int Vk_Theme_VkApp_client_dark_monet_generated = 0x7f130478; // 2131952760
public static final int Vk_Theme_VkApp_client_light_monet_generated = 0x7f130479; // 2131952761
public static final int Vk_Theme_VkApp_space_gray_monet_generated = 0x7f13047a; // 2131952762
public static final int VkAmoledMonetStyle = 0x7f13047b; // 2131952763
public static final int VkAmoledMonetTheme = 0x7f13047c; // 2131952764
public static final int VkDarkMonetStyle = 0x7f13047d; // 2131952765
public static final int VkDarkMonetTheme = 0x7f13047e; // 2131952766
public static final int VkLightMonetStyle = 0x7f13047f; // 2131952767
public static final int VkLightMonetTheme = 0x7f130480; // 2131952768
public static final int VkMilkAmoledMonetStyle = 0x7f130481; // 2131952769
public static final int VkMilkAmoledMonetTheme = 0x7f130482; // 2131952770
public static final int VkMilkDarkMonetStyle = 0x7f130483; // 2131952771
public static final int VkMilkDarkMonetTheme = 0x7f130484; // 2131952772
public static final int VkMilkLightMonetStyle = 0x7f130485; // 2131952773
public static final int VkMilkLightMonetTheme = 0x7f130486; // 2131952774
}
public static final class xml {
@@ -71,12 +71,11 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
this.mIcon.getLayoutParams().width = V.a(28.0F);
this.mIcon.getLayoutParams().height = V.a(28.0F);
var colorStateList = getCSTDock();
this.mSmallLabel = this.findViewById(R.id.smallLabel);
mSmallLabel.setTextColor(colorStateList);
mSmallLabel.setTextColor(getCSTDock());
this.mLargeLabel = this.findViewById(R.id.largeLabel);
mLargeLabel.setTextColor(colorStateList);
mLargeLabel.setTextColor(getCSTDock());
LayoutInflater.from(this.getContext()).inflate(R.layout.navigation_bottom_counter, this, true);
this.mCounterContainer = this.findViewById(R.id.counter_container);
@@ -280,12 +279,13 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
@SuppressLint("RestrictedApi")
public void setIcon(Drawable drawable) {
if (drawable != null) {
var csl = this.mColorStateList;
if (drawable != null && csl != null) {
if (drawable.getConstantState() != null)
drawable = drawable.getConstantState().newDrawable();
drawable = DrawableCompat.wrap(drawable).mutate();
DrawableCompat.setTintList(drawable, this.mColorStateList);
DrawableCompat.setTintList(drawable, csl);
}
this.mIcon.setImageDrawable(drawable);
@@ -326,6 +326,8 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
}
public void setTextColor(ColorStateList colorStateList) {
this.mSmallLabel.setTextColor(colorStateList);
this.mLargeLabel.setTextColor(colorStateList);
}
@SuppressLint("RestrictedApi")
@@ -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,5 +1,7 @@
package ru.vtosters.lite.deviceinfo;
import ru.vtosters.lite.utils.AndroidUtils;
import static ru.vtosters.lite.deviceinfo.OEMDetector.hasMiuiIncrCode;
import static ru.vtosters.lite.deviceinfo.OEMDetector.isEMUI;
import static ru.vtosters.lite.deviceinfo.OEMDetector.isMIUI;
@@ -101,4 +103,20 @@ public class Device {
+ (isEMUI() ? "', EmuiVersion='" + this.EmuiVersion : "")
+ "', modelName='" + this.modelName + "'";
}
public String forLogging() {
return "**" + AndroidUtils.getString("device_info") + ":** " + "\n\n"
+ "- Commit: " + getBuildNumber() + "\n"
+ "- Android SDK: " + this.sdkVersion + "\n"
+ "- Product: " + this.productName + "\n"
+ "- Device: " + this.deviceName + "\n"
+ "- Board: " + this.boardName + "\n"
+ "- Manufacturer: " + this.manufacturerName + "\n"
+ "- Brand: " + this.brandName + "\n"
+ "- Model: " + this.modelName
+ (isMIUI() ? "- Miui Version Code: " + this.MiuiUiVersionCode + "\n" + "- Miui Version Name: " + this.MiuiUiVersionName + "\n" : "")
+ (isSamsung() ? "- OneUi Major Version: " + this.OneUiMajorVersion + "\n" + "- OneUi Minor Version: " + this.OneUiMinorVersion + "\n" : "")
+ (hasMiuiIncrCode() ? "- Miui Version Incremental Code: " + this.MiuiIncrementalCode + "\n" : "")
+ (isEMUI() ? "- Emui Version: " + this.EmuiVersion : "");
}
}
@@ -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,20 +1,9 @@
package ru.vtosters.lite.dnr;
import static ru.vtosters.lite.dnr.DNRModule.hookDNR;
import static ru.vtosters.lite.dnr.DNRModule.hookDNT;
import static ru.vtosters.lite.dnr.DNRModule.isDnrEnabledFor;
import static ru.vtosters.lite.dnr.DNRModule.isDntEnabledFor;
import static ru.vtosters.lite.encryption.EncryptProvider.decryptMessage;
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
import static ru.vtosters.lite.utils.AndroidUtils.isTablet;
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
import com.vk.core.network.Network;
import com.vk.im.engine.ImEngine1;
import com.vk.im.engine.events.OnDialogUpdateEvent;
@@ -27,6 +16,16 @@ 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 okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import ru.vtosters.lite.downloaders.messages.HtmlDialogDownloaderFormatProvider;
import ru.vtosters.lite.downloaders.messages.MessagesDownloader;
import ru.vtosters.lite.encryption.EncryptProvider;
import ru.vtosters.lite.encryption.base.IMProcessor;
import ru.vtosters.lite.hooks.CryptImHook;
import ru.vtosters.lite.ui.dialogs.Translate;
import ru.vtosters.lite.utils.AndroidUtils;
import java.io.File;
import java.io.IOException;
@@ -34,20 +33,16 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import ru.vtosters.lite.downloaders.MessagesDownloader;
import ru.vtosters.lite.encryption.EncryptProvider;
import ru.vtosters.lite.encryption.base.IMProcessor;
import ru.vtosters.lite.hooks.CryptImHook;
import ru.vtosters.lite.ui.dialogs.Translate;
import ru.vtosters.lite.utils.AndroidUtils;
import static ru.vtosters.lite.dnr.DNRModule.*;
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.isTablet;
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
public class DNRInjector {
public static void inject(Dialog dialog, List<DialogAction> list) {
int peerId = 0;
if (dialog != null) {
try {
peerId = dialog.getId();
@@ -60,6 +55,7 @@ public class DNRInjector {
return;
}
list.add(DialogAction.STAT);
list.add(DialogAction.DOWNLOAD);
list.add(DialogAction.pinmsg);
@@ -85,6 +81,7 @@ public class DNRInjector {
}
public static LinkedHashMap<DialogAction, Integer> injectToHashMap(LinkedHashMap<DialogAction, Integer> hashMap) {
hashMap.put(DialogAction.STAT, AndroidUtils.getIdentifier("dialogstats", "string"));
hashMap.put(DialogAction.DOWNLOAD, R.string.download_dl);
hashMap.put(DialogAction.DNR_ON, R.string.DNR_ON);
@@ -103,6 +100,8 @@ 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.STAT, 1, R.attr.im_ic_stats, R.string.dialogstats)); // 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, R.attr.im_ic_pinned_msg_hide, R.string.DNR_ON)); // DialogAction, Int, Icon, String
@@ -142,6 +141,8 @@ public class DNRInjector {
return actions;
}
actions.add(DialogAction.STAT);
actions.add(DialogAction.DOWNLOAD);
if (isDnrEnabledFor(peerId)) {
@@ -186,10 +187,15 @@ public class DNRInjector {
forceInvalidateDialogActions(dialog);
}
if (action == DialogAction.STAT) {
DNRModule.hookDialogInfo(dialog);
return true;
}
if (action == DialogAction.DOWNLOAD) {
File out = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "dialog-" + peerId + ".html");
try {
new MessagesDownloader().downloadDialog(peerId, new MessagesDownloader.HtmlDialogDownloaderFormatProvider(), out);
new MessagesDownloader().downloadDialog(peerId, new HtmlDialogDownloaderFormatProvider(), out);
} catch (Exception e) {
sendToast(AndroidUtils.getString(R.string.download_dl_error));
e.printStackTrace();
@@ -247,10 +253,14 @@ public class DNRInjector {
DNRModule.hookRead(dialog);
}
if (action == DialogAction.STAT) {
DNRModule.hookDialogInfo(dialog);
return true;
}
if (action == DialogAction.DOWNLOAD) {
File out = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), peerId + "-dialog.html");
try {
new MessagesDownloader().downloadDialog(peerId, new MessagesDownloader.HtmlDialogDownloaderFormatProvider(), out);
new MessagesDownloader().downloadDialog(peerId, new HtmlDialogDownloaderFormatProvider(), out);
} catch (Exception e) {
e.printStackTrace();
}
@@ -308,27 +318,14 @@ public class DNRInjector {
if (msg instanceof MsgFromUser) {
var text = ((MsgFromUser) msg).f();
var fullMsg = ((MsgFromUser) msg).j2(); // text + reply
var reply = fullMsg.substring(text.length() + 1);
var isTextExist = !text.isEmpty() && !text.equals(" ");
var isReplyExist = !reply.isEmpty() && !reply.equals(" ");
if (isReplyExist) {
reply = decryptMessage(reply, peerId);
}
if (isTextExist) {
text = decryptMessage(text, peerId);
}
if (action == MsgAction.valueOf("TRANSLATE")) {
if (isTextExist && isReplyExist) {
Translate.showTranslatedText(context, text + "\n\n" + context.getString(R.string.translator_reply) + "\n" + reply);
} else if (isReplyExist) {
Translate.showTranslatedText(context, context.getString(R.string.translator_reply) + "\n" + reply);
} else if (isTextExist) {
if (isTextExist) {
Translate.showTranslatedText(context, text);
} else {
sendToast(context.getString(R.string.translator_no_text));
@@ -4,16 +4,31 @@ 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 android.content.Intent;
import android.net.Uri;
import android.os.MessageQueue;
import android.util.Log;
import com.vk.core.util.LangUtils;
import com.vk.im.engine.commands.messages.SetUserActivityCmd;
import com.vk.im.engine.models.dialogs.Dialog;
import com.vk.im.engine.models.messages.Msg;
import java.util.List;
import com.vk.im.ui.fragments.ChatFragment;
import com.vk.navigation.Navigator;
import com.vk.webapp.VkUiFragment;
import com.vtosters.lite.general.fragments.WebViewFragment;
import ru.vtosters.lite.dnr.helpers.DoNotReadDBHelper;
import ru.vtosters.lite.dnr.helpers.DoNotTypeDBHelper;
import ru.vtosters.lite.ssfs.Utils;
import ru.vtosters.lite.ui.fragments.VKUIwrapper;
import ru.vtosters.lite.ui.fragments.VTSettings;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.LifecycleUtils;
import ru.vtosters.lite.utils.ThemesUtils;
public class DNRModule {
public static DoNotReadDBHelper mDoNotReadDBHelper = new DoNotReadDBHelper();
@@ -63,6 +78,17 @@ public class DNRModule {
});
}
public static void hookDialogInfo(Dialog dialog) {
AndroidUtils.openWebView("https://vkscripts.ru/run/i/" +
AccountManagerUtils.getUserToken() +
"?peer_id=" +
dialog.getId() +
"&lang=" +
LangUtils.a() +
"&color=" +
ThemesUtils.hexx(ThemesUtils.getAccentColor()), LifecycleUtils.getCurrentActivity());
}
public static void hookDNR(int peerId) {
mDoNotReadDBHelper.setEnabledForPeerId(peerId, !mDoNotReadDBHelper.isEnabledForPeerId(peerId));
}
@@ -10,6 +10,8 @@ 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;
@@ -21,6 +23,7 @@ import ru.vtosters.lite.music.downloader.PlaylistDownloader;
import ru.vtosters.lite.music.downloader.TrackDownloader;
import ru.vtosters.lite.music.notification.MusicNotificationBuilder;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.IOUtils;
/**
@@ -30,6 +33,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);
@@ -60,13 +64,14 @@ public class AudioDownloader {
if (CacheDatabaseDelegate.isCached(trackId)) {
CacheDatabaseDelegate.removeTrackFromCache(LibVKXClient.asId(track));
AndroidUtils.sendToast(AndroidUtils.getString("audio_deleted_from_cache"));
return;
}
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) {
@@ -1,621 +0,0 @@
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;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
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 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;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
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;
private static SparseArray<MiniUser> usersArray;
public static String formatTime(long now) {
return sdformat.format(new Date(now));
}
public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
StringBuilder builder = new StringBuilder();
for (CharSequence cs : elements) {
builder.append(cs).append(delimiter);
}
return builder.toString();
}
private static String getPollHtml(JSONObject poll) throws JSONException {
StringBuilder pollHtml = new StringBuilder(
"<div class=\"vtex-milk-msg poll\">" +
"<p style=\"text-align:center;\">" + poll.optString("question") + "</p>"
);
var answers = poll.optJSONArray("answers");
for (int i = 0; i < answers.length(); i++) {
var jsonObject = answers.optJSONObject(i);
if (jsonObject != null)
pollHtml.append("<hr><p>").append(jsonObject.optString("text")).append(" · ").append(jsonObject.optString("votes")).append(" (").append(jsonObject.optString("rate")).append("%)</p>");
}
pollHtml.append("<hr><p style=\"text-align:center;\">")
.append(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 AndroidUtils.getString(R.string.chat_export_video_nolinks);
Iterator<?> keys = files.keys();
StringBuilder videoHtml = new StringBuilder();
int qualityIndex = 0;
String[] quality = {"144", "240", "360", "480", "720", "1080", "1440", "2160"};
while (keys.hasNext()) {
String key = (String) keys.next();
if (key.equals("mp4_" + quality[qualityIndex])) {
videoHtml.append("<a class=\"msg-attach-link\" href=\"").append(files.get(key)).append("\">").append(quality[qualityIndex]).append("p</a>").append(" ");
if (qualityIndex == quality.length - 1) break;
++qualityIndex;
}
}
return videoHtml.toString();
}
public void downloadDialog(int peer_id, DialogDownloaderFormatProvider format, File out) throws Exception {
sdformat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss", getResources().getConfiguration().locale);
FileOutputStream fos = new FileOutputStream(out);
// fix TODO with conversation name (API method messages.getConversationsById)
fos.write(format.provideDocumentStart("TODO", formatTime(System.currentTimeMillis())).getBytes(StandardCharsets.UTF_8));
fetchDialogInfo(peer_id, 0, ((users, messages) -> {
try {
fos.write(format.provideHeader("TODO", formatTime(System.currentTimeMillis())).getBytes(StandardCharsets.UTF_8));
for (MiniMsg msg : messages) {
fos.write(format.provideMessage(msg, users.get(msg.fromId)).getBytes(StandardCharsets.UTF_8));
}
fos.write(format.provideDocumentEnd().getBytes(StandardCharsets.UTF_8));
fos.close();
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), AndroidUtils.getString(R.string.saved_as) + " " + out.getAbsolutePath(), LENGTH_SHORT).show());
} catch (IOException | JSONException e) {
e.printStackTrace();
}
}));
}
public void fetchDialogInfo(int peer_id, int offset, FetchListener fl) {
makeRequest("https://" + getApi() + "/method/messages.getHistory?extended=1&v=5.140&offset=" + offset + "&count=200&peer_id=" + peer_id + "&access_token=" + getUserToken(),
response -> {
try {
JSONObject mainJson = new JSONObject(response);
JSONObject obj = mainJson.getJSONObject("response");
SparseArray<MiniUser> users = new SparseArray<>();
parseUsers(users, obj.optJSONArray("profiles"), false);
parseUsers(users, obj.optJSONArray("groups"), true);
List<MiniMsg> msgs = parseMessages(obj.getJSONArray("items"));
usersArray = users;
fl.onReceive(users, msgs);
} catch (JSONException e) {
e.printStackTrace();
}
});
}
private List<MiniMsg> parseMessages(JSONArray jsonArray) throws JSONException {
ArrayList<MiniMsg> thing = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
MiniMsg msg = new MiniMsg(jsonArray.getJSONObject(i));
thing.add(msg);
}
return thing;
}
private void parseUsers(SparseArray<MiniUser> array, @Nullable JSONArray jsonArray, boolean groups) throws JSONException {
if (jsonArray == null) return;
for (int i = 0; i < jsonArray.length(); i++) {
MiniUser user = new MiniUser(jsonArray.getJSONObject(i), groups);
array.put(groups ? -user.id : user.id, user);
}
}
interface FetchListener {
void onReceive(SparseArray<MiniUser> users, List<MiniMsg> messages);
}
static class MiniUser {
public String firstName;
public String lastName;
public boolean isGroup;
int id;
String photo100;
public MiniUser(JSONObject obj, boolean is_group) throws JSONException {
id = obj.getInt("id");
firstName = obj.optString("first_name", obj.optString("name"));
lastName = obj.optString("last_name", "");
photo100 = obj.getString("photo_100");
isGroup = is_group;
}
}
static class MiniMsg {
long date;
int fromId;
int id; // message id
String text;
List<JSONObject> attachments;
List<JSONObject> fwd_messages;
JSONObject reply_message; // one reply
JSONObject chat_action;
JSONObject geo;
public MiniMsg(JSONObject obj) throws JSONException {
date = obj.getLong("date") * 1000;
fromId = obj.getInt("from_id");
id = obj.getInt("id");
text = decryptMessage(obj.getString("text"), obj.getInt("peer_id"));
reply_message = obj.optJSONObject("reply_message");
chat_action = obj.optJSONObject("action");
geo = obj.optJSONObject("geo");
attachments = new ArrayList<>();
fwd_messages = new ArrayList<>();
JSONArray arr = obj.optJSONArray("attachments");
if (arr != null)
for (int i = 0; i < arr.length(); i++) attachments.add(arr.getJSONObject(i));
JSONArray fwdArr = obj.optJSONArray("fwd_messages");
if (fwdArr != null)
for (int i = 0; i < fwdArr.length(); i++) fwd_messages.add(fwdArr.getJSONObject(i));
}
}
// This class defines everything which is needed to create an output file
abstract static class DialogDownloaderFormatProvider {
// Internal, for JSON/HTML
abstract String provideDocumentStart(String dialogName, String date);
abstract String provideDocumentEnd();
abstract String provideHeader(String dialogName, String date);
abstract String provideMessage(MiniMsg message, MiniUser user) throws JSONException;
}
public static class HtmlDialogDownloaderFormatProvider extends DialogDownloaderFormatProvider {
@Override
String provideDocumentStart(String dialogName, String date) {
String style = ".vtex-milk-msg {\n" +
" border-radius: 8px;\n" +
" padding: 24px;\n" +
" background: white;\n" +
" margin: 16px;\n" +
" box-shadow: 0 4px 8px 0 rgba(0,0,0,0.07);\n" +
" word-wrap: break-word;\n" +
"}\n" +
"\n" +
".vtex-milk-msgcont br {\n" +
" display: none;\n" +
"}\n" +
"\n" +
".vtex-milk-msg p {\n" +
" margin: 0;\n" +
"}\n" +
"\n" +
".vtex-milk-msg.vtex-milk-msg-out {\n" +
" background: #ADD3FF;\n" +
"}\n" +
"\n" +
"p.msg-attaches {\n" +
" margin-top: 8px;\n" +
" font-style: italic;\n" +
"}\n" +
"p.chat-action {\n" +
" font-style: italic;\n" +
"}\n" +
"\n" +
".vtex-milk-header {\n" +
" border-radius: 8px;\n" +
" padding: 24px;\n" +
" background: white;\n" +
" margin: 16px;\n" +
" box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);\n" +
"}\n" +
"\n" +
"h4.vtex-milk-header-txt {\n" +
" margin: 0;\n" +
"}\n" +
"\n" +
"h5.vtex-milk-header-sub {\n" +
" margin: 0;\n" +
" padding-top: 8px;\n" +
"}\n" +
"\n" +
"a.msg-attach-link {\n" +
" color: #5181B8;\n" +
" text-decoration: none;\n" +
"}\n" +
"\n" +
".msg-from a {\n" +
" color: #5181B8;\n" +
" text-decoration: none;\n" +
"}\n" +
"\n" +
".msg-from-date {\n" +
" color: rgba(0, 0, 0, 0.75);\n" +
"}\n" +
"\n" +
"body {\n" +
" font-family: Roboto, system-ui, sans-serif;\n" +
"}\n" +
"\n" +
".msg-body {\n" +
" padding-top: 4px;\n" +
"}\n" +
".msg-reply {\n" +
" border-left: 3px solid #7aa7f6;\n" +
" margin-top: 5px;\n" +
" padding-left: 3px;\n" +
"}\n\n" +
".msg-reply p {\n" +
" padding-left: 5px;\n" +
"}\n\n" +
".msg-reply p.reply-header {\n" +
" color: #5181B8;\n" +
"}\n\n" +
".msg-reply p.reply-content {\n" +
" color: #000000;\n" +
"}\n" +
".vtex-milk-msg.poll {\n" +
" width: 45%;\n" +
" background: linear-gradient(to bottom right, #707c8c, #4d5565);\n" +
" font-style: normal;" +
"}\n" +
".vtex-milk-msg.poll p { color: white; }\n" +
".vtex-milk-msg.poll hr { border-top: 1px; background: #ffffff; }\n" +
"\n" +
"";
return "<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta charset=\"utf-8\"><title>"
+ AndroidUtils.getString(R.string.chat_export_title)
+ "</title><style>"
+ style
+ "</style></head><body>";
}
@Override
String provideDocumentEnd() {
return "</div></body></html>";
}
@Override
String provideHeader(String dialogName, String date) {
return "<div class=\"vtex-milk-header\"><h4 class=\"vtex-milk-header-txt\">VTLite</h4><h5 class=\"vtex-milk-header-sub\">" + AndroidUtils.getString(R.string.chat_export_header) + " (" + date + ")</h5></div><div class=\"vtex-milk-msgcont\">";
}
@Override
String provideMessage(MiniMsg message, MiniUser user) throws JSONException {
String isOut = (user.id == getUserId()) ? " vtex-milk-msg-out" : "";
String geoPosition = "";
if (message.geo != null) {
var coordinates = message.geo.optJSONObject("coordinates");
if (coordinates != null) {
var latitude = coordinates.optDouble("latitude");
var longitude = coordinates.optDouble("longitude");
var ll = longitude + "," + latitude;
geoPosition = "<a href=\"https://yandex.ru/maps/?ll=" + ll + "&mode=search&sll=" + ll + "&text=" + latitude + "," + longitude + "&z=12\">" +
"<img src=\"https://static-maps.yandex.ru/1.x/?ll=" + longitude + "," + latitude + "&z=12&l=map&size=300,200&pt=" + ll + ",vkgrm\"/>" +
"</a>";
}
}
String chatAction = (message.chat_action != null) ? getHtmlForChatAction(message.chat_action) : "";
String attaches = (message.attachments.size() > 0) ? "<p class=\"msg-attaches\">" + 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\">" + 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 +
attaches +
reply +
fwdMessages +
"</div>";
}
private String provideReply(JSONObject replyMessage) {
var messageId = replyMessage.optInt("id");
var userId = replyMessage.optInt("from_id");
var peerId = replyMessage.optInt("peer_id");
var text = mentionsReplace(decryptMessage(replyMessage.optString("text"), peerId));
var fwdMessages = replyMessage.optJSONArray("fwd_messages");
var user = usersArray.get(userId);
if (text.isEmpty()) {
if (fwdMessages != null) {
var length = fwdMessages.length();
if (length > 0) text = length + " " + pluralMsg(length);
} else text = AndroidUtils.getString(R.string.attachment); // Вложение
}
return "<a href=\"#" + messageId + "\" class=\"msg-attach-link\">" +
"<div class=\"msg-reply\">" +
"<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>";
}
private String provideForwardMessages(List<JSONObject> fwd_messages) throws JSONException {
StringBuilder fwdmsgs = new StringBuilder("<div class=\"msg-reply\">");
for (JSONObject fwd_message : fwd_messages) {
if (fwd_message == null) continue;
List<JSONObject> attaches = new ArrayList<>();
JSONArray arr = fwd_message.optJSONArray("attachments");
if (arr != null) {
for (int i = 0; i < arr.length(); i++) {
try {
attaches.add(arr.getJSONObject(i));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
List<JSONObject> fwdsMsg = new ArrayList<>();
JSONArray fwd_msgs = fwd_message.optJSONArray("fwd_messages");
if (fwd_msgs != null) {
for (int i = 0; i < fwd_msgs.length(); i++) {
try {
fwdsMsg.add(fwd_msgs.getJSONObject(i));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
JSONObject reply_message = fwd_message.optJSONObject("reply_message");
var attachesHtml = (attaches.size() > 0) ? AndroidUtils.getString(R.string.attachments) + ": " + getHtmlForAttach(attaches) : "";
var replyHtml = (reply_message != null) ? provideReply(reply_message) : "";
var fwdsHtml = (fwdsMsg.size() > 0) ? provideForwardMessages(fwdsMsg) : ""; // recursion XD :>
var userId = fwd_message.optInt("from_id");
var peerId = fwd_message.optInt("peer_id");
var text = mentionsReplace(decryptMessage(fwd_message.optString("text"), peerId));
var userLink = ((userId < 0) ? "club" : "id") + Math.abs(userId);
fwdmsgs.append("<p class=\"reply-content\"><a class=\"msg-attach-link\" href=\"https://" + VK_DOMAIN + "/").append(userLink).append("\">@").append(userLink).append("</a>: ").append(text).append(attachesHtml).append(replyHtml).append(fwdsHtml);
}
return fwdmsgs.append("</div>").toString();
}
private String mentionsReplace(String text) {
var matcher = Pattern.compile("\\[((?:club|id|public)\\d+)\\|([^]]+)\\]").matcher(text);
return matcher.replaceAll("<a class=\"msg-attach-link\" href=\"https://" + VK_DOMAIN + "/$1\">$2</a>");
}
private String pluralMsg(int count) {
String[] plurals = getArray(R.array.msg_plurals);
var hundredModulo = count % 100;
var tenModulo = count % 10;
if (hundredModulo > 10 && hundredModulo < 20) return plurals[2];
else if (tenModulo > 1 && tenModulo < 5) return plurals[1];
else if (tenModulo == 1) return plurals[0];
return plurals[2];
}
private String getHtmlForChatAction(JSONObject action) {
var type = action.optString("type");
StringBuilder htmlAction = new StringBuilder("<p class=\"chat-action\">");
switch (type) {
case "chat_photo_update":
htmlAction.append(AndroidUtils.getString(R.string.chat_export_avatar_update));
break;
case "chat_photo_remove":
htmlAction.append(AndroidUtils.getString(R.string.chat_export_avatar_remove));
break;
case "chat_create":
var name = action.optString("text");
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(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(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>");
}
break;
case "chat_kick_user":
var removedUserId = action.optInt("member_id");
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>");
}
break;
case "chat_pin_message":
var message = action.optString("message");
htmlAction.append(AndroidUtils.getString(R.string.chat_export_msg_pinned)).append((!message.isEmpty()) ? (" \"" + message + "\"") : "");
break;
case "chat_unpin_message":
htmlAction.append(AndroidUtils.getString(R.string.chat_export_msg_unpinned));
break;
case "chat_invite_user_by_link":
htmlAction.append(AndroidUtils.getString(R.string.chat_export_join_by_link));
break;
case "chat_screenshot":
htmlAction.append(AndroidUtils.getString(R.string.chat_export_chat_screenshot));
break;
case "custom":
htmlAction.append(action.optString("message"));
break;
default:
htmlAction.append(AndroidUtils.getString(R.string.vkim_msg_unsupported) + " (").append(type).append(")");
break;
}
return htmlAction.append("</p>").toString();
}
private String getHtmlForAttach(List<JSONObject> attaches) throws JSONException {
StringBuilder rs = new StringBuilder();
for (JSONObject attach : attaches) {
String type = attach.getString("type");
JSONObject item = attach.optJSONObject(type);
if (item == null) continue;
switch (type) { // market_album is not supported
case "photo":
var sizes = item.getJSONArray("sizes");
rs.append("<a href=\"").append(sizes.getJSONObject(sizes.length() - 1).getString("url")).append("\" class=\"msg-attach-link\">").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(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(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(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(AndroidUtils.getString(R.string.chat_export_type_audiomsg)).append("</a>");
break;
case "audio":
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(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(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(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(AndroidUtils.getString(R.string.chat_export_type_podcast)).append("</a>");
break;
case "gift":
rs.append("<img src=\"").append(item.optString("thumb_96")).append("\"/>");
break;
case "mini_app":
var app = item.optJSONObject("app");
if (app != null) {
var miniapp_link = "https://" + VK_DOMAIN + "/app" + app.optString("id");
rs.append("<a class=\"msg-attach-link\" href=\"").append(miniapp_link).append("\">").append(AndroidUtils.getString(R.string.chat_export_type_miniapp)).append("</a>");
break;
}
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(AndroidUtils.getString(R.string.chat_export_type_playlist)).append(" (").append(item.optString("title")).append(")</a>");
break;
case "poll":
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(AndroidUtils.getString(R.string.chat_export_type_market)).append("</a>");
break;
default:
rs.append(AndroidUtils.getString(R.string.vkim_msg_unsupported)).append(" (").append(type).append(")");
break;
}
rs.append(" ");
}
return rs.toString();
}
}
}
@@ -9,18 +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();
@@ -30,24 +32,15 @@ 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(context.getString(R.string.downloaderr));
}
@@ -55,7 +48,7 @@ public class OTADownloader {
}
};
public static void downloadBuild(String url) {
public static void downloadBuild(String url, String commitSHA) {
var context = AndroidUtils.getGlobalContext();
try {
var uri = Uri.parse(url);
@@ -64,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(AndroidUtils.getString("downloading_update"));
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "VTLite-" + commitSHA + ".apk");
var manager = (DownloadManager) AndroidUtils.getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
@@ -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);
}
}
}
@@ -1,32 +1,35 @@
package ru.vtosters.lite.downloaders;
import static ru.vtosters.lite.net.Request.makeRequest;
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import android.app.DownloadManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
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;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.utils.ExternalLinkParser;
import ru.vtosters.lite.utils.LifecycleUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import ru.vtosters.lite.utils.ExternalLinkParser;
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.ThemesUtils.getTextAttr;
public class VideoDownloader {
private static final int DOWNLOAD_ID = 0;
@@ -54,77 +57,105 @@ public class VideoDownloader {
}
public static void downloadVideo(VideoFile videoFile, Context context) {
final List<String> list = new ArrayList<>();
final List<String> qualities = new ArrayList<>();
final List<String> urls = new ArrayList<>();
if (!Objects.equals(videoFile.e, "")) {
list.add("240p");
urls.add(videoFile.e);
}
if (!Objects.equals(videoFile.f, "")) {
list.add("360p");
urls.add(videoFile.f);
}
if (!Objects.equals(videoFile.g, "")) {
list.add("480p");
urls.add(videoFile.g);
}
if (!Objects.equals(videoFile.h, "")) {
list.add("720p");
urls.add(videoFile.h);
}
if (!Objects.equals(videoFile.B, "")) {
list.add("1080p");
urls.add(videoFile.B);
}
if (!Objects.equals(videoFile.C, "")) {
list.add("1440p");
urls.add(videoFile.C);
}
if (!Objects.equals(videoFile.D, "")) {
list.add("2160p");
if (!TextUtils.isEmpty(videoFile.D)) {
qualities.add("2160p");
urls.add(videoFile.D);
}
if (list.isEmpty()) {
ToastUtils.a(context.getString(R.string.videodownloaderr));
if (!TextUtils.isEmpty(videoFile.C)) {
qualities.add("1440p");
urls.add(videoFile.C);
}
if (!TextUtils.isEmpty(videoFile.B)) {
qualities.add("1080p");
urls.add(videoFile.B);
}
if (!TextUtils.isEmpty(videoFile.h)) {
qualities.add("720p");
urls.add(videoFile.h);
}
if (!TextUtils.isEmpty(videoFile.g)) {
qualities.add("480p");
urls.add(videoFile.g);
}
if (!TextUtils.isEmpty(videoFile.f)) {
qualities.add("360p");
urls.add(videoFile.f);
}
if (!TextUtils.isEmpty(videoFile.e)) {
qualities.add("240p");
urls.add(videoFile.e);
}
Context finalContext = context != null ? context : LifecycleUtils.getCurrentActivity();
if (qualities.isEmpty()) {
ToastUtils.a(finalContext.getString(R.string.videodownloaderr));
return;
}
var max = new String[list.size()];
var adapter = new ArrayAdapter(
finalContext,
android.R.layout.simple_list_item_1,
qualities.toArray(new String[0])) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView = (TextView) super.getView(position, convertView, parent);
textView.setTextColor(getTextAttr());
return textView;
}
};
for (int i = 0; i < list.size(); i++) {
max[i] = list.get(i);
}
if (context == null) {
var url = urls.get(urls.size() - 1);
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;
}
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(ctx.getString(R.string.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;
}
@@ -0,0 +1,96 @@
package ru.vtosters.lite.downloaders.messages;
public class Constants {
public static final String VK_DOMAIN = "vk.com";
public static final String HTML_DOC_STYLE = ".vtex-milk-msg {\n" +
" border-radius: 8px;\n" +
" padding: 24px;\n" +
" background: white;\n" +
" margin: 16px;\n" +
" box-shadow: 0 4px 8px 0 rgba(0,0,0,0.07);\n" +
" word-wrap: break-word;\n" +
"}\n" +
"\n" +
".vtex-milk-msgcont br {\n" +
" display: none;\n" +
"}\n" +
"\n" +
".vtex-milk-msg p {\n" +
" margin: 0;\n" +
"}\n" +
"\n" +
".vtex-milk-msg.vtex-milk-msg-out {\n" +
" background: #ADD3FF;\n" +
"}\n" +
"\n" +
"p.msg-attaches {\n" +
" margin-top: 8px;\n" +
" font-style: italic;\n" +
"}\n" +
"p.chat-action {\n" +
" font-style: italic;\n" +
"}\n" +
"\n" +
".vtex-milk-header {\n" +
" border-radius: 8px;\n" +
" padding: 24px;\n" +
" background: white;\n" +
" margin: 16px;\n" +
" box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);\n" +
"}\n" +
"\n" +
"h4.vtex-milk-header-txt {\n" +
" margin: 0;\n" +
"}\n" +
"\n" +
"h5.vtex-milk-header-sub {\n" +
" margin: 0;\n" +
" padding-top: 8px;\n" +
"}\n" +
"\n" +
"a.msg-attach-link {\n" +
" color: #5181B8;\n" +
" text-decoration: none;\n" +
"}\n" +
"\n" +
".msg-from a {\n" +
" color: #5181B8;\n" +
" text-decoration: none;\n" +
"}\n" +
"\n" +
".msg-from-date {\n" +
" color: rgba(0, 0, 0, 0.75);\n" +
"}\n" +
"\n" +
"body {\n" +
" font-family: Roboto, system-ui, sans-serif;\n" +
"}\n" +
"\n" +
".msg-body {\n" +
" padding-top: 4px;\n" +
"}\n" +
".msg-reply {\n" +
" border-left: 3px solid #7aa7f6;\n" +
" margin-top: 5px;\n" +
" padding-left: 3px;\n" +
"}\n\n" +
".msg-reply p {\n" +
" padding-left: 5px;\n" +
"}\n\n" +
".msg-reply p.reply-header {\n" +
" color: #5181B8;\n" +
"}\n\n" +
".msg-reply p.reply-content {\n" +
" color: #000000;\n" +
"}\n" +
".vtex-milk-msg.poll {\n" +
" width: 45%;\n" +
" background: linear-gradient(to bottom right, #707c8c, #4d5565);\n" +
" font-style: normal;" +
"}\n" +
".vtex-milk-msg.poll p { color: white; }\n" +
".vtex-milk-msg.poll hr { border-top: 1px; background: #ffffff; }\n" +
"\n" +
"";
}
@@ -0,0 +1,17 @@
package ru.vtosters.lite.downloaders.messages;
import org.json.JSONException;
import ru.vtosters.lite.downloaders.messages.items.MiniMsg;
import ru.vtosters.lite.downloaders.messages.items.MiniUser;
// This class defines everything which is needed to create an output file
public abstract class DialogDownloaderFormatProvider {
// Internal, for JSON/HTML
public abstract String provideDocumentStart(String dialogName, String date);
public abstract String provideDocumentEnd();
public abstract String provideHeader(String dialogName, String date);
public abstract String provideMessage(MiniMsg message, MiniUser user) throws JSONException;
}
@@ -0,0 +1,402 @@
package ru.vtosters.lite.downloaders.messages;
import com.vtosters.lite.R;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.downloaders.messages.items.MiniMsg;
import ru.vtosters.lite.downloaders.messages.items.MiniUser;
import ru.vtosters.lite.utils.AndroidUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import static ru.vtosters.lite.encryption.EncryptProvider.decryptMessage;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
import static ru.vtosters.lite.utils.AndroidUtils.getArray;
public class HtmlDialogDownloaderFormatProvider extends DialogDownloaderFormatProvider {
@Override
public String provideDocumentStart(String dialogName, String date) {
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>"
+ Constants.HTML_DOC_STYLE
+ "</style></head><body>";
}
@Override
public String provideDocumentEnd() {
return "</div></body></html>";
}
@Override
public 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\">"
+ AndroidUtils.getString(R.string.chat_export_header)
+ " (" + date + ")</h5></div><div class=\"vtex-milk-msgcont\">";
}
@Override
public String provideMessage(MiniMsg message, MiniUser user) throws JSONException {
String isOut = (user.id == getUserId()) ? " vtex-milk-msg-out" : "";
String geoPosition = "";
if (message.geo != null) {
var coordinates = message.geo.optJSONObject("coordinates");
if (coordinates != null) {
var latitude = coordinates.optDouble("latitude");
var longitude = coordinates.optDouble("longitude");
var ll = longitude + "," + latitude;
geoPosition = "<a href=\"https://yandex.ru/maps/?ll=" + ll + "&mode=search&sll=" + ll + "&text=" + latitude + "," + longitude + "&z=12\">" +
"<img src=\"https://static-maps.yandex.ru/1.x/?ll=" + longitude + "," + latitude + "&z=12&l=map&size=300,200&pt=" + ll + ",vkgrm\"/>" +
"</a>";
}
}
String chatAction = (message.chat_action != null) ? getHtmlForChatAction(message.chat_action) : "";
String attaches = (message.attachments.size() > 0) ? "<p class=\"msg-attaches\">" + 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\">" + AndroidUtils.getString(R.string.from_lower)
+ " <a href=\"https://" + Constants.VK_DOMAIN + "/" + userLink + "\">" + user.firstName + " " + user.lastName
+ "</a> <span class=\"msg-from-date\">" + MessagesDownloader.formatTime(message.date) + "</span></p>" + // TODO photo100
"<p class=\"msg-body\">" + mentionsReplace(message.text) + "</p>" +
geoPosition +
chatAction +
attaches +
reply +
fwdMessages +
"</div>";
}
private String provideReply(JSONObject replyMessage) {
var text = mentionsReplace(decryptMessage(replyMessage.optString("text"), replyMessage.optInt("peer_id")));
var fwdMessages = replyMessage.optJSONArray("fwd_messages");
var user = MessagesDownloader.usersArray.get(replyMessage.optInt("from_id"));
if (text.isEmpty()) {
if (fwdMessages != null) {
var length = fwdMessages.length();
if (length > 0) text = length + " " + pluralMsg(length);
} else text = AndroidUtils.getString(R.string.attachment); // Вложение
}
return "<a href=\"#" + replyMessage.optInt("id") + "\" class=\"msg-attach-link\">" +
"<div class=\"msg-reply\">" +
"<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>";
}
private String provideForwardMessages(List<JSONObject> fwd_messages) throws JSONException {
StringBuilder fwdmsgs = new StringBuilder("<div class=\"msg-reply\">");
for (JSONObject fwd_message : fwd_messages) {
if (fwd_message == null) continue;
List<JSONObject> attaches = new ArrayList<>();
JSONArray arr = fwd_message.optJSONArray("attachments");
if (arr != null) {
for (int i = 0; i < arr.length(); i++) {
try {
attaches.add(arr.getJSONObject(i));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
List<JSONObject> fwdsMsg = new ArrayList<>();
JSONArray fwd_msgs = fwd_message.optJSONArray("fwd_messages");
if (fwd_msgs != null) {
for (int i = 0; i < fwd_msgs.length(); i++) {
try {
fwdsMsg.add(fwd_msgs.getJSONObject(i));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
JSONObject reply_message = fwd_message.optJSONObject("reply_message");
var attachesHtml = (attaches.size() > 0) ? AndroidUtils.getString(R.string.attachments) + ": " + getHtmlForAttach(attaches) : "";
var replyHtml = (reply_message != null) ? provideReply(reply_message) : "";
var fwdsHtml = (fwdsMsg.size() > 0) ? provideForwardMessages(fwdsMsg) : ""; // recursion XD :>
var userId = fwd_message.optInt("from_id");
var peerId = fwd_message.optInt("peer_id");
var text = mentionsReplace(decryptMessage(fwd_message.optString("text"), peerId));
var userLink = ((userId < 0) ? "club" : "id") + Math.abs(userId);
fwdmsgs.append("<p class=\"reply-content\"><a class=\"msg-attach-link\" href=\"https://" + Constants.VK_DOMAIN + "/")
.append(userLink)
.append("\">@")
.append(userLink)
.append("</a>: ")
.append(text)
.append(attachesHtml)
.append(replyHtml)
.append(fwdsHtml);
}
return fwdmsgs.append("</div>").toString();
}
private String mentionsReplace(String text) {
var matcher = Pattern.compile("\\[((?:club|id|public)\\d+)\\|([^]]+)\\]").matcher(text);
return matcher.replaceAll("<a class=\"msg-attach-link\" href=\"https://" + Constants.VK_DOMAIN + "/$1\">$2</a>");
}
private String pluralMsg(int count) {
String[] plurals = getArray(R.array.msg_plurals);
var hundredModulo = count % 100;
var tenModulo = count % 10;
if (hundredModulo > 10 && hundredModulo < 20) return plurals[2];
else if (tenModulo > 1 && tenModulo < 5) return plurals[1];
else if (tenModulo == 1) return plurals[0];
return plurals[2];
}
private String getHtmlForChatAction(JSONObject action) {
var type = action.optString("type");
StringBuilder htmlAction = new StringBuilder("<p class=\"chat-action\">");
switch (type) {
case "chat_photo_update" -> htmlAction.append(AndroidUtils.getString(R.string.chat_export_avatar_update));
case "chat_photo_remove" -> htmlAction.append(AndroidUtils.getString(R.string.chat_export_avatar_remove));
case "chat_create" -> {
htmlAction.append(AndroidUtils.getString(R.string.chat_export_chat_created));
var name = action.optString("text");
if (!name.isEmpty())
htmlAction.append(" \"").append(name).append("\"");
}
case "chat_title_update" -> {
var newName = action.optString("text");
htmlAction.append(AndroidUtils.getString(R.string.chat_export_name_changed));
if (!newName.isEmpty())
htmlAction.append(" ")
.append(AndroidUtils.getString(R.string.chat_export_to))
.append(" \"")
.append(newName)
.append("\"");
}
case "chat_invite_user" -> {
var newMemberId = action.optInt("member_id");
htmlAction.append(AndroidUtils.getString(R.string.chat_export_user_added))
.append(" ");
if (newMemberId != 0) {
int id;
String endpoint;
if (newMemberId >= 0) {
id = R.string.chat_export_type_user;
endpoint = "id" + newMemberId;
} else {
id = R.string.chat_export_type_group;
endpoint = "club" + -newMemberId;
}
htmlAction.append(AndroidUtils.getString(id))
.append(" <a href=\"https://" + Constants.VK_DOMAIN + "/")
.append(endpoint)
.append("\" class=\"msg-attach-link\">@")
.append(endpoint)
.append("</a>");
}
}
case "chat_kick_user" -> {
var removedMemberId = action.optInt("member_id");
htmlAction.append(AndroidUtils.getString(R.string.chat_export_user_kicked))
.append(" ");
if (removedMemberId != 0) {
int id;
String endpoint;
if (removedMemberId >= 0) {
id = R.string.chat_export_type_user;
endpoint = "id" + removedMemberId;
} else {
id = R.string.chat_export_type_group;
endpoint = "club" + -removedMemberId;
}
htmlAction.append(AndroidUtils.getString(id))
.append(" <a href=\"https://" + Constants.VK_DOMAIN + "/")
.append(endpoint)
.append("\" class=\"msg-attach-link\">@")
.append(endpoint)
.append("</a>");
}
}
case "chat_pin_message" -> {
var message = action.optString("message");
htmlAction.append(AndroidUtils.getString(R.string.chat_export_msg_pinned));
if (!message.isEmpty()) htmlAction.append(" \"").append(message).append("\"");
}
case "chat_unpin_message" -> htmlAction.append(AndroidUtils.getString(R.string.chat_export_msg_unpinned));
case "chat_invite_user_by_link" ->
htmlAction.append(AndroidUtils.getString(R.string.chat_export_join_by_link));
case "chat_screenshot" -> htmlAction.append(AndroidUtils.getString(R.string.chat_export_chat_screenshot));
case "custom" -> htmlAction.append(action.optString("message"));
default ->
htmlAction.append(AndroidUtils.getString(R.string.vkim_msg_unsupported)).append(" (").append(type).append(")");
}
return htmlAction.append("</p>").toString();
}
private String getHtmlForAttach(List<JSONObject> attaches) throws JSONException {
StringBuilder rs = new StringBuilder();
for (JSONObject attach : attaches) {
String type = attach.getString("type");
JSONObject item = attach.optJSONObject(type);
if (item == null) continue;
switch (type) { // market_album is not supported
case "photo" -> {
var sizes = item.getJSONArray("sizes");
rs.append("<a href=\"")
.append(sizes.getJSONObject(sizes.length() - 1).getString("url"))
.append("\" class=\"msg-attach-link\">")
.append(AndroidUtils.getString(R.string.chat_export_type_photo))
.append("</a>");
}
case "doc" -> rs.append("<a href=\"")
.append(item.getString("url"))
.append("\" class=\"msg-attach-link\">")
.append(AndroidUtils.getString(R.string.chat_export_type_doc))
.append("</a>");
case "link" -> rs.append("<a href=\"")
.append(item.getString("url"))
.append("\" class=\"msg-attach-link\">")
.append(AndroidUtils.getString(R.string.chat_export_type_link))
.append("</a>");
case "wall" -> rs.append("<a href=\"https://" + Constants.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>");
case "sticker" -> rs.append("<img style=\"width:128px;height:128px;\" src=\"")
.append(item.getJSONArray("images")
.getJSONObject(1)
.getString("url"))
.append("\"/>");
case "audio_message" -> 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>");
case "audio" -> rs.append(AndroidUtils.getString(R.string.chat_export_type_audio))
.append(" (")
.append(item.optString("artist"))
.append(" — ")
.append(item.optString("title"))
.append(")");
case "video" -> rs.append(AndroidUtils.getString(R.string.chat_export_type_video))
.append(" (")
.append(MessagesDownloader.getVideoHtml(item.optJSONObject("files")))
.append(")");
case "wall_reply" -> {
var link = String.format("https://" + Constants.VK_DOMAIN + "/wall%s_%s?reply=%s",
item.optString("owner_id"),
item.optString("post_id"),
item.optString("id"));
rs.append("<a class=\"msg-attach-link\" href=\"")
.append(link).append("\">")
.append(AndroidUtils.getString(R.string.chat_export_type_wallreply))
.append("</a>");
}
case "story" -> {
var story_link = String.format("https://" + Constants.VK_DOMAIN + "/story%s_%s",
item.optString("owner_id"),
item.optString("id"));
rs.append("<a class=\"msg-attach-link\" href=\"")
.append(story_link)
.append("\">")
.append(AndroidUtils.getString(R.string.chat_export_type_story))
.append("</a>");
}
case "podcast" -> {
var podcast_link = String.format("https://" + Constants.VK_DOMAIN + "/podcast%s_%s",
item.optString("owner_id"),
item.optString("id"));
rs.append("<a class=\"msg-attach-link\" href=\"")
.append(podcast_link)
.append("\">")
.append(AndroidUtils.getString(R.string.chat_export_type_podcast))
.append("</a>");
}
case "gift" -> rs.append("<img src=\"")
.append(item.optString("thumb_96"))
.append("\"/>");
case "mini_app" -> {
var app = item.optJSONObject("app");
if (app != null) {
var miniapp_link = String.format("https://" + Constants.VK_DOMAIN + "/app%s", app.optString("id"));
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(AndroidUtils.getString(R.string.chat_export_error));
}
case "audio_playlist" -> {
var playlist_link = String.format("https://" + Constants.VK_DOMAIN + "/music/album/%s_%s_%s",
item.optString("owner_id"),
item.optString("id"),
item.optString("access_key"));
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>");
}
case "poll" ->
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(MessagesDownloader.getPollHtml(item));
case "market" -> {
var market_item_link = String.format("https://" + Constants.VK_DOMAIN + "/market%s_%s",
item.optString("owner_id"),
item.optString("id"));
rs.append("<a class=\"msg-attach-link\" href=\"")
.append(market_item_link)
.append("\">")
.append(AndroidUtils.getString(R.string.chat_export_type_market))
.append("</a>");
}
default -> rs.append(AndroidUtils.getString(R.string.vkim_msg_unsupported))
.append(" (")
.append(type)
.append(")");
}
rs.append(" ");
}
return rs.toString();
}
}
@@ -0,0 +1,162 @@
package ru.vtosters.lite.downloaders.messages;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.Nullable;
import com.vk.core.util.ToastUtils;
import com.vtosters.lite.R;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.downloaders.messages.items.MiniMsg;
import ru.vtosters.lite.downloaders.messages.items.MiniUser;
import ru.vtosters.lite.proxy.ProxyUtils;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
public class MessagesDownloader {
private static final int[] VIDEO_QUALITIES = { 144, 240, 360, 480, 720, 1080, 1440, 2160 };
private static final SimpleDateFormat SDFORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss", AndroidUtils.getResources().getConfiguration().locale);
public static SparseArray<MiniUser> usersArray;
public static String formatTime(long now) {
return SDFORMAT.format(new Date(now));
}
public static String getPollHtml(JSONObject poll) {
StringBuilder pollHtml = new StringBuilder(
"<div class=\"vtex-milk-msg poll\">" +
"<p style=\"text-align:center;\">" + poll.optString("question") + "</p>"
);
var answers = poll.optJSONArray("answers");
for (int i = 0; i < answers.length(); i++) {
var jsonObject = answers.optJSONObject(i);
if (jsonObject != null)
pollHtml.append("<hr><p>")
.append(jsonObject.optString("text"))
.append(" · ")
.append(jsonObject.optString("votes"))
.append(" (")
.append(jsonObject.optString("rate"))
.append("%)</p>");
}
pollHtml.append("<hr><p style=\"text-align:center;\">")
.append(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>")
.append("</div>");
return pollHtml.toString();
}
public static String getVideoHtml(JSONObject files) throws JSONException {
if (files == null) return AndroidUtils.getString(R.string.chat_export_video_nolinks);
Iterator<? extends String> keys = files.keys();
StringBuilder videoHtml = new StringBuilder();
int i = 0;
while (keys.hasNext() && i < VIDEO_QUALITIES.length) {
var key = keys.next();
if (key.equals("mp4_" + VIDEO_QUALITIES[i])) {
videoHtml.append("<a class=\"msg-attach-link\" href=\"")
.append(files.get(key))
.append("\">")
.append(VIDEO_QUALITIES[i])
.append("p</a>")
.append(" ");
}
++i;
}
return videoHtml.toString();
}
public void downloadDialog(int peer_id, DialogDownloaderFormatProvider format, File out) throws Exception {
FileOutputStream fos = new FileOutputStream(out);
// fix TODO with conversation name (API method messages.getConversationsById)
fos.write(format.provideDocumentStart("TODO", formatTime(System.currentTimeMillis())).getBytes(StandardCharsets.UTF_8));
var url = String.format("https://" + ProxyUtils.getApi() + "/method/messages.getHistory?extended=1&v=5.140&offset=%d&count=200&peer_id=%d&access_token=%s",
0,
peer_id,
AccountManagerUtils.getUserToken());
var req = new Request.a()
.b(url)
.a();
VtOkHttpClient.getInstance().a(req).a(new Callback() {
@Override
public void a(Call call, IOException e) {
Log.d("MessagesDownloader", e+"");
}
@Override
public void a(Call call, Response response)
throws IOException {
try {
JSONObject obj = new JSONObject(response.a().g()).getJSONObject("response");
SparseArray<MiniUser> users = new SparseArray<>();
parseUsers(users, obj.optJSONArray("profiles"), false);
parseUsers(users, obj.optJSONArray("groups"), true);
List<MiniMsg> msgs = parseMessages(obj.getJSONArray("items"));
usersArray = users;
fos.write(format.provideHeader("TODO", formatTime(System.currentTimeMillis())).getBytes(StandardCharsets.UTF_8));
for (MiniMsg msg : msgs) {
fos.write(format.provideMessage(msg, users.get(msg.fromId)).getBytes(StandardCharsets.UTF_8));
}
fos.write(format.provideDocumentEnd().getBytes(StandardCharsets.UTF_8));
fos.close();
ToastUtils.a(AndroidUtils.getString(R.string.saved_as) + " " + out.getAbsolutePath());
} catch (IOException | JSONException e) {
e.printStackTrace();
}
}
});
}
private List<MiniMsg> parseMessages(JSONArray jsonArray) throws JSONException {
List<MiniMsg> thing = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++)
thing.add(new MiniMsg(jsonArray.getJSONObject(i)));
return thing;
}
private void parseUsers(SparseArray<MiniUser> array, @Nullable JSONArray jsonArray, boolean groups) throws JSONException {
if (jsonArray == null) return;
for (int i = 0; i < jsonArray.length(); i++) {
MiniUser user = new MiniUser(jsonArray.getJSONObject(i), groups);
array.put(groups ? -user.id : user.id, user);
}
}
}
@@ -0,0 +1,42 @@
package ru.vtosters.lite.downloaders.messages.items;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import static ru.vtosters.lite.encryption.EncryptProvider.decryptMessage;
public class MiniMsg {
public long date;
public int fromId;
public int id; // message id
public String text;
public List<JSONObject> attachments;
public List<JSONObject> fwd_messages;
public JSONObject reply_message; // one reply
public JSONObject chat_action;
public JSONObject geo;
public MiniMsg(JSONObject obj) throws JSONException {
date = obj.getLong("date") * 1000;
fromId = obj.getInt("from_id");
id = obj.getInt("id");
text = decryptMessage(obj.getString("text"), obj.getInt("peer_id"));
reply_message = obj.optJSONObject("reply_message");
chat_action = obj.optJSONObject("action");
geo = obj.optJSONObject("geo");
attachments = new ArrayList<>();
fwd_messages = new ArrayList<>();
JSONArray arr = obj.optJSONArray("attachments");
if (arr != null)
for (int i = 0; i < arr.length(); i++) attachments.add(arr.getJSONObject(i));
JSONArray fwdArr = obj.optJSONArray("fwd_messages");
if (fwdArr != null)
for (int i = 0; i < fwdArr.length(); i++) fwd_messages.add(fwdArr.getJSONObject(i));
}
}
@@ -0,0 +1,20 @@
package ru.vtosters.lite.downloaders.messages.items;
import org.json.JSONException;
import org.json.JSONObject;
public class MiniUser {
public String firstName;
public String lastName;
public boolean isGroup;
public int id;
public String photo100;
public MiniUser(JSONObject obj, boolean is_group) throws JSONException {
id = obj.getInt("id");
firstName = obj.optString("first_name", obj.optString("name"));
lastName = obj.optString("last_name", "");
photo100 = obj.getString("photo_100");
isGroup = is_group;
}
}
@@ -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);
@@ -31,6 +31,7 @@ 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;
@@ -38,7 +39,7 @@ 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 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 {
var request = new okhttp3.Request.a()
@@ -148,8 +149,8 @@ public class FoafBase {
.setPositiveButton(android.R.string.ok, null)
.show());
} catch (Exception e) {
e.printStackTrace();
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), context.getString(R.string.foaferr), LENGTH_SHORT).show());
e.printStackTrace();
}
}
@@ -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;
@@ -224,12 +225,22 @@ public class AdBlockHook {
continue;
}
if (NewsFeedFiltersUtils.injectFiltersReposts(list) && !isWhitelistedFilters(list)) {
if (hasMiniAppAds(list) && !isWhitelistedFilters(list)) {
if (dev())
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: repost ad");
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: MiniApp filters");
continue;
}
try {
if (NewsFeedFiltersUtils.injectFiltersReposts(list) && !isWhitelistedFilters(list)) {
if (dev())
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: repost ad");
continue;
}
} catch (Exception ex) {
Log.d("RepostInj", ex.getMessage());
}
newItems.put(list);
}
@@ -266,41 +277,9 @@ public class AdBlockHook {
}
}
if (!json.has("items")) return json;
var items = json.optJSONArray("items");
if (items != null) {
for (int i = 0; i < items.length(); i++) {
var item = items.optJSONObject(i);
if (item != null) {
parseStoriesItem(item);
}
}
}
return json;
}
private static void parseStoriesItem(JSONObject item) throws JSONException {
var stories = item.optJSONArray("stories");
var newStories = new JSONArray();
if (stories == null) return;
for (int j = 0; j < stories.length(); j++) {
var story = stories.optJSONObject(j);
if (!story.optBoolean("is_ads") && !story.optBoolean("is_promo")) {
newStories.put(story);
} else {
if (dev())
Log.d("StoriesAds", "Fetched ad, owner id " + story.optString("owner_id") + ", caption " + story.optString("caption"));
}
}
item.put("stories", newStories);
}
public static Boolean isAds(JSONObject list, String type) throws JSONException {
if (list == null || type == null || !ads()) return false;
@@ -360,4 +339,17 @@ public class AdBlockHook {
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;
}
}
@@ -0,0 +1,67 @@
package ru.vtosters.lite.hooks;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.view.View;
import android.widget.Toast;
import com.vk.im.engine.models.dialogs.Dialog;
import com.vtosters.lite.api.ExtendedUserProfile;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.LifecycleUtils;
import static android.widget.Toast.LENGTH_SHORT;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
public class CallsHook {
public static void forwardToVkOffApps(View view, ExtendedUserProfile p) {
call(view.getContext(), AccountManagerUtils.getUserID(p));
}
public static void forwardToVkOffApps(View view, Dialog dl) {
call(view.getContext(), dl.getId());
}
public static void forwardToVkOffApps(Context ctx, int userId) {
call(ctx, userId);
}
public static void call(Context ctx, int id) {
// FIXME: add com.vk.calls, right now it doesn't support intent
var vkim = checkPackage("com.vk.im");
var vk = checkPackage("com.vkontakte.android");
var callsAvailable = vkim || vk;
if (!callsAvailable) {
Toast.makeText(LifecycleUtils.getCurrentActivity(), AndroidUtils.getString("calls_not_available"), LENGTH_SHORT).show();
try {
var action = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.vkontakte.android"));
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(action);
} catch (android.content.ActivityNotFoundException e) {
var action = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=com.vkontakte.android"));
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(action);
}
return;
}
var link = "https://vk.com/call?id=" + id;
var startCall = new Intent(Intent.ACTION_VIEW, Uri.parse(link)).setPackage(vk ? "com.vkontakte.android" : "com.vk.im");
startCall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(startCall);
}
private static Boolean checkPackage(String packageName) {
try {
var pm = getGlobalContext().getPackageManager();
return pm.getApplicationInfo(packageName, 0).enabled;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}
@@ -59,11 +59,6 @@ public class CryptImHook {
IMProcessor finalEnabled = enabled;
Activity ctx = getCurrentActivity();
if (ctx == null) {
sendToast(AndroidUtils.getString(R.string.app_activities_error));
return;
}
new VkAlertDialog.Builder(ctx)
.setTitle(AndroidUtils.getString(R.string.encryption_sett))
.setSingleChoiceItems(titles, enabledPosition, (dialog, which) -> {
@@ -111,11 +106,6 @@ public class CryptImHook {
Context ctx = getCurrentActivity();
if (ctx == null) {
sendToast(ctx.getString(R.string.app_activities_error));
return;
}
LinearLayout linearLayout = new LinearLayout(ctx);
final EditText editText = new EditText(ctx);
@@ -19,14 +19,11 @@ public class DateHook {
}
public static String getDateFormat() {
switch (getPrefsValue("dateformat")) {
case "noyear":
return AndroidUtils.getString(R.string.fulltime2);
case "full":
return AndroidUtils.getString(R.string.fulltime);
default:
return AndroidUtils.getString(R.string.fulltime3);
}
return switch (getPrefsValue("dateformat")) {
case "noyear" -> AndroidUtils.getString(R.string.fulltime2);
case "full" -> AndroidUtils.getString(R.string.fulltime);
default -> AndroidUtils.getString(R.string.fulltime3);
};
}
@SuppressLint("SimpleDateFormat")
@@ -83,7 +83,7 @@ public class DockBarInjector {
}
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException |
NoSuchMethodException | InvocationTargetException e) {
NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
@@ -102,6 +102,7 @@ public class DockBarInjector {
item.setStaticMode(true);
item.setIconsMode(false);
item.setShiftingMode(false);
item.setTextColor(getCSTDock());
}
}
}
@@ -190,36 +191,24 @@ public class DockBarInjector {
int val = 0;
switch (tabId) {
case tab_messages:
val = MenuCountersState.j();
break;
case menu_groups:
val = MenuCountersState.h();
break;
case menu_fave:
val = MenuCountersState.c();
break;
case menu_games:
val = MenuCountersState.a();
break;
case menu_photos:
val = MenuCountersState.l();
break;
case menu_videos:
val = MenuCountersState.n();
break;
case tab_feedback:
case tab_messages -> val = MenuCountersState.j();
case menu_groups -> val = MenuCountersState.h();
case menu_fave -> val = MenuCountersState.c();
case menu_games -> val = MenuCountersState.a();
case menu_photos -> val = MenuCountersState.l();
case menu_videos -> val = MenuCountersState.n();
case tab_feedback -> {
if (milkshake())
val = MenuCountersState.k();
break;
case tab_news:
}
case tab_news -> {
if (milkshake() && getBoolValue("newsfeed_notif", true))
val = MenuCountersState.k();
break;
case menu_friends:
}
case menu_friends -> {
if (!milkshake())
val = MenuCountersState.k();
break;
}
}
//
// val = MenuCountersState.g(); // friends ?????? menu_friends
@@ -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() ? "eyJhbGciOiAibm9uZSJ9.eyJub25jZSI6ICJ0ZXN0PT0ifQ." : "e251bGx9";
}
public static String requestToken(String orig) {
if (musicFixNew()) return "{null}"; //not public
if (orig.equals("")) return requestToken();
return orig;
return "yssp9o9p9pamz5t-nvmq8spgwtin3e0==";
}
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,20 +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.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.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;
@@ -22,8 +15,6 @@ 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;
@@ -37,170 +28,12 @@ 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.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();
public static JSONObject profileButton(JSONObject orig) throws JSONException {
var id = orig.getInt("id");
var newItem = new JSONArray();
if (orig.has("buttons")) {
newItem = orig.getJSONArray("buttons");
}
if (!haveDonateButton() && id == AccountManagerUtils.getUserId()) {
newItem.put(donateRecomm());
}
if (!orig.has("type") && AccountManagerUtils.isVKTester()) {
newItem.put(vktesters(id));
}
orig.put("buttons", newItem);
return orig;
}
public static JSONObject donateRecomm() throws JSONException {
var title = AndroidUtils.getString(R.string.donate_to_vtl);
var link = "https://vk.com/vtosters_official";
var text_color = "2D81E0";
var json = new JSONObject();
var icons = new JSONArray();
var action = new JSONObject();
action.put("target", "internal");
action.put("type", "open_url"); // may be open_url, open_internal_vkui, open_game, help_hint, show_full_post, open_vkapp, show_recommendations_for_post and groups_advertisement
action.put("url", link);
json.put("action", action);
json.put("title", title);
var icon1 = new JSONObject();
icon1.put("url", "https://sun2-10.userapi.com/NLd_rNpGuSaBnPV6O-j5mqCGZk8BK8drAMd2LQ/5R-DEF37PFs.png");
icon1.put("width", "20");
icon1.put("height", "20");
icons.put(icon1);
var icon2 = new JSONObject();
icon2.put("url", "https://sun2-12.userapi.com/N8y9pU1meJq_eug-wB1u-HUuGyMqDfdq7A025w/A4Aio-xuLY8.png");
icon2.put("width", "40");
icon2.put("height", "40");
icons.put(icon2);
var icon3 = new JSONObject();
icon3.put("url", "https://sun2-9.userapi.com/3Hx4hff63_2Lt6wjjthJMF_3QLUswNNlQKoAXQ/oyzEu1NL9T8.png");
icon3.put("width", "80");
icon3.put("height", "80");
icons.put(icon3);
json.put("icons", icons);
json.put("text_color", text_color);
return json;
}
public static JSONObject vktesters(int id) throws JSONException {
var title = AndroidUtils.getString(R.string.tester_profile);
var text_color = "2D81E0";
var link = "https://" + getStatic() + "/bugs?lang=" + LangUtils.a() + "#/reporter" + id;
var json = new JSONObject();
var icons = new JSONArray();
var action = new JSONObject();
action.put("target", "internal");
action.put("type", "open_internal_vkui");
action.put("url", link);
json.put("action", action);
json.put("title", title);
var icon1 = new JSONObject();
icon1.put("url", "https://sun2-10.userapi.com/NLd_rNpGuSaBnPV6O-j5mqCGZk8BK8drAMd2LQ/5R-DEF37PFs.png");
icon1.put("width", "20");
icon1.put("height", "20");
icons.put(icon1);
var icon2 = new JSONObject();
icon2.put("url", "https://sun2-12.userapi.com/N8y9pU1meJq_eug-wB1u-HUuGyMqDfdq7A025w/A4Aio-xuLY8.png");
icon2.put("width", "40");
icon2.put("height", "40");
icons.put(icon2);
var icon3 = new JSONObject();
icon3.put("url", "https://sun2-9.userapi.com/3Hx4hff63_2Lt6wjjthJMF_3QLUswNNlQKoAXQ/oyzEu1NL9T8.png");
icon3.put("width", "80");
icon3.put("height", "80");
icons.put(icon3);
json.put("icons", icons);
json.put("text_color", text_color);
return json;
}
public static JSONObject convBar(JSONObject orig) throws JSONException {
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(R.string.no_data_error);
var link = "https://vtosters.app"; // can be null
var linktitle = "Test button"; // can be null
var hasIcon = !pic.isEmpty();
var hasButton = !link.isEmpty();
var isPicture = pic.endsWith(".png") || pic.endsWith(".jpg") || pic.endsWith(".jpeg") || pic.endsWith(".webp");
if (isVerified(peerid)) text = AndroidUtils.getString(R.string.i_bought) + " VTosters Premium";
if (isPrometheus(peerid))
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)) {
return null;
} else {
return orig.optJSONObject("conversation_bar");
}
}
if (!dev()) return orig.optJSONObject("conversation_bar"); // for devs only
var json = new JSONObject();
var buttonsJson = new JSONObject();
buttonsJson.put("layout", "tertiary");
buttonsJson.put("text", linktitle);
buttonsJson.put("type", "link");
buttonsJson.put("link", link);
var buttonsjson = new JSONArray(); // max 3 buttons in array
if (hasButton) buttonsjson.put(buttonsJson);
json.put("name", "group_admin_welcome");
json.put("text", text);
json.put("buttons", buttonsjson);
if (hasIcon && isPicture) {
json.put("icon", pic);
}
return json;
}
public static JSONObject menu(JSONObject orig) throws JSONException {
var Special = orig.optJSONArray("special");
var Main = orig.getJSONArray("main");
@@ -242,19 +75,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");
@@ -368,159 +188,6 @@ public class JsonInjectors {
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;
@@ -586,8 +253,4 @@ public class JsonInjectors {
return json;
}
public static boolean haveDonateButton() {
return hasVerification() || new Random().nextInt(6) != 1;
}
}
@@ -4,16 +4,14 @@ 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.ssfs.UsersList;
import ru.vtosters.lite.ui.dialogs.DisableBattery;
import ru.vtosters.lite.ui.dialogs.InstallGMS;
import ru.vtosters.lite.ui.dialogs.OTADialog;
@@ -24,18 +22,14 @@ public class MainActivityInjector {
public static void inject(Activity activity) {
setNeededTheme(activity);
sendRequest();
UsersList.getUsersList();
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
@@ -99,19 +99,13 @@ public class MessagesHook {
}
private static int expireTime() {
switch (bombCount) {
case "15s":
return 15;
case "1m":
return 60;
case "5m":
return 300;
case "1h":
return 3600;
case "24h":
return 86400;
default:
return 0;
}
return switch (bombCount) {
case "15s" -> 15;
case "1m" -> 60;
case "5m" -> 300;
case "1h" -> 3600;
case "24h" -> 86400;
default -> 0;
};
}
}
@@ -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;
@@ -30,14 +29,12 @@ public class NewsfeedHook {
if (vkme()) {
return MAX_VALUE;
}
switch (getPrefsValue("newsupdate")) {
case "no_update":
return MAX_VALUE;
case "imd_update":
return 10000L;
default:
return Preference.b().getLong(refresh_timeout ? "refresh_timeout_top" : "refresh_timeout_recent", 600000L);
}
return switch (getPrefsValue("newsupdate")) {
case "no_update" -> MAX_VALUE;
case "imd_update" -> 10000L;
default ->
Preference.b().getLong(refresh_timeout ? "refresh_timeout_top" : "refresh_timeout_recent", 600000L);
};
}
public static List hideElement(ArrayList list) {
@@ -115,14 +112,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");
@@ -29,117 +29,61 @@ public class OnlineFormatterHook {
public static String getAppName(int appid) { // thanks to egormetlitsky (vk mp3 mod) for helping with online ids
if (appid <= 3 || !getBoolValue("onlineformatter", true)) return null;
switch (appid) {
case 2274003:
return "Android";
case 6328039:
case 6328868:
case 6820516:
return "VK mp3 mod";
case 5910839:
return "DarkVK";
case 3140623:
return "iPhone";
case 3087106:
return "iPhone (Dev)";
case 3682744:
return "iPad";
case 4083558:
case 5316500:
return "VFeed (iPhone)";
case 4385266:
return "VFeed Pro (iPhone)";
case 3502557:
case 3502561:
return "Windows Phone";
case 3697615:
return "Windows";
case 2685278:
return "Kate Mobile";
case 3469984:
return "Lynt";
case 6121396:
return "VK Admin (Android)";
case 5776857:
return "VK Admin (iPhone)";
case 5027722:
return "VK Messenger (Desktop)";
case 6146827:
return AndroidUtils.getString(R.string.vk_messenger) + " (Android)"; // VK Мессенджер (Android)
case 6482950:
return AndroidUtils.getString(R.string.vk_messenger) + " (iPhone)"; // VK Мессенджер (iPhone)
case 6481715:
return AndroidUtils.getString(R.string.vk_messenger) + " Dev (iPhone)"; // VK Мессенджер Dev (iPhone)
case 7799655:
return AndroidUtils.getString(R.string.vk_mail_online); // VK Почта
case 7598572:
return AndroidUtils.getString(R.string.sferum_online) + " (Android)"; // Сферум (Android)
case 7571751:
return AndroidUtils.getString(R.string.sferum_online) + " (iPhone)"; // Сферум (iPhone)
case 7556576:
return AndroidUtils.getString(R.string.sferum_online); // Сферум
case 7497650:
return "VK ID";
case 8094476:
return AndroidUtils.getString(R.string.vk_calls_online) + " (Android)"; // VK Звонки (Android)
case 8093730:
return AndroidUtils.getString(R.string.vk_calls_online) + " (iPhone)"; // VK Звонки (iPhone)
case 7793118:
return AndroidUtils.getString(R.string.vk_calls_online) + " (Desktop)"; // VK Звонки (Desktop)
case 6767438:
return AndroidUtils.getString(R.string.vk_music_online) + " (Android)"; // VK Музыка (Android)
case 8113297:
return AndroidUtils.getString(R.string.vk_clips_online) + " (Android)"; // VK Клипы (Android)
case 8106428:
return AndroidUtils.getString(R.string.vk_clips_online) + " (iPhone)"; // VK Клипы (iPhone)
case 5044491:
return "Candy";
case 8114066:
return AndroidUtils.getString(R.string.vk_video_online); // VK Видео
case 4894723:
return "Phoenix Lite";
case 4994316:
return "Phoenix for VK";
case 3032107:
return "Vika";
case 3698024:
return "Instagram";
case 4580399:
return "Snapster (Android)";
case 4986954:
return "Snapster (iPhone)";
case 3900098:
case 5353544:
return "Домофон";
case 5462895:
return "Fast Messenger";
case 6964679:
return "Fast";
case 6030003:
return "Juno Messenger";
case 5955265:
return "VK Mobile";
case 6614620:
return "Laney";
case 5632485:
return "SpaceVK";
case 6287487:
return "vk.com";
case 4542624:
return "Black VK";
case 3917910:
return "Miranda NG (bridge)";
case 8043814:
return "Quise";
case 7221936:
return "Вечный Online";
case 6892935:
return "VK Helper";
case 6248661:
return "MemeVoices for VK";
default:
return getAppNameFromOnline(appid);
}
return switch (appid) {
case 2274003 -> "Android";
case 6328039, 6328868, 6820516 -> "VK mp3 mod";
case 5910839 -> "DarkVK";
case 3140623 -> "iPhone";
case 3087106 -> "iPhone (Dev)";
case 3682744 -> "iPad";
case 4083558, 5316500 -> "VFeed (iPhone)";
case 4385266 -> "VFeed Pro (iPhone)";
case 3502557, 3502561 -> "Windows Phone";
case 3697615 -> "Windows";
case 2685278 -> "Kate Mobile";
case 3469984 -> "Lynt";
case 6121396 -> "VK Admin (Android)";
case 5776857 -> "VK Admin (iPhone)";
case 5027722 -> "VK Messenger (Desktop)";
case 6146827 -> AndroidUtils.getString(R.string.vk_messenger) + " (Android)"; // VK Мессенджер (Android)
case 6482950 -> AndroidUtils.getString(R.string.vk_messenger) + " (iPhone)"; // VK Мессенджер (iPhone)
case 6481715 ->
AndroidUtils.getString(R.string.vk_messenger) + " Dev (iPhone)"; // VK Мессенджер Dev (iPhone)
case 7799655 -> AndroidUtils.getString(R.string.vk_mail_online); // VK Почта
case 7598572 -> AndroidUtils.getString(R.string.sferum_online) + " (Android)"; // Сферум (Android)
case 7571751 -> AndroidUtils.getString(R.string.sferum_online) + " (iPhone)"; // Сферум (iPhone)
case 7556576 -> AndroidUtils.getString(R.string.sferum_online); // Сферум
case 7497650 -> "VK ID";
case 8094476 -> AndroidUtils.getString(R.string.vk_calls_online) + " (Android)"; // VK Звонки (Android)
case 8093730 -> AndroidUtils.getString(R.string.vk_calls_online) + " (iPhone)"; // VK Звонки (iPhone)
case 7793118 -> AndroidUtils.getString(R.string.vk_calls_online) + " (Desktop)"; // VK Звонки (Desktop)
case 6767438 -> AndroidUtils.getString(R.string.vk_music_online) + " (Android)"; // VK Музыка (Android)
case 8113297 -> AndroidUtils.getString(R.string.vk_clips_online) + " (Android)"; // VK Клипы (Android)
case 8106428 -> AndroidUtils.getString(R.string.vk_clips_online) + " (iPhone)"; // VK Клипы (iPhone)
case 5044491 -> "Candy";
case 8114066 -> AndroidUtils.getString(R.string.vk_video_online); // VK Видео
case 4894723 -> "Phoenix Lite";
case 4994316 -> "Phoenix for VK";
case 3032107 -> "Vika";
case 3698024 -> "Instagram";
case 4580399 -> "Snapster (Android)";
case 4986954 -> "Snapster (iPhone)";
case 3900098, 5353544 -> "Домофон";
case 5462895 -> "Fast Messenger";
case 6964679 -> "Fast";
case 6030003 -> "Juno Messenger";
case 5955265 -> "VK Mobile";
case 6614620 -> "Laney";
case 5632485 -> "SpaceVK";
case 6287487 -> "vk.com";
case 4542624 -> "Black VK";
case 3917910 -> "Miranda NG (bridge)";
case 8043814 -> "Quise";
case 7221936 -> "Вечный Online";
case 6892935 -> "VK Helper";
case 6248661 -> "MemeVoices for VK";
default -> getAppNameFromOnline(appid);
};
}
@@ -7,7 +7,6 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.util.Log;
import android.view.MenuItem;
@@ -17,7 +16,9 @@ import android.widget.Toast;
import androidx.annotation.Nullable;
import com.vk.core.dialogs.actionspopup.ActionsPopup;
import com.vk.core.drawable.RecoloredDrawable;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.core.ui.themes.VKThemeHelper;
import com.vk.core.util.ContextExtKt;
import com.vk.core.util.ToastUtils;
import com.vk.dto.common.AttachmentWithMedia;
import com.vk.dto.common.ImageSize;
@@ -37,21 +38,22 @@ 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;
import ru.vtosters.lite.utils.LifecycleUtils;
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() == R.id.search_photo) {
if (attachment instanceof PhotoAttachment) {
searchPhoto(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
searchDialog(LifecycleUtils.getCurrentActivity(), getUrlFromPhotoAttachment((PhotoAttachment) attachment));
} else if (attachment instanceof DocumentAttachment) {
var documentAttachment = (DocumentAttachment) attachment;
if (documentAttachment.J != null)
try {
searchPhoto(getUrlFromDocumentAttachment(documentAttachment));
searchDialog(LifecycleUtils.getCurrentActivity(), getUrlFromDocumentAttachment(documentAttachment));
} catch (Exception e) {
ToastUtils.a(R.string.photo_get_error);
}
@@ -96,18 +98,16 @@ public class PhotoViewer {
@SuppressLint("UseCompatLoadingForDrawables")
public static void addMenuItems(AttachmentWithMedia attachment, ActionsPopup.b actionPopup, int i, boolean z) {
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()),
ContextExtKt.b(AndroidUtils.getGlobalContext(), R.drawable.ic_menu_search_outline_28, VKThemeHelper.g(R.attr.header_tint)),
false,
() -> {
if (attachment instanceof PhotoAttachment) {
searchPhoto(getUrlFromPhotoAttachment((PhotoAttachment) attachment));
searchDialog(LifecycleUtils.getCurrentActivity(), getUrlFromPhotoAttachment((PhotoAttachment) attachment));
} else if (attachment instanceof DocumentAttachment) {
var documentAttachment = (DocumentAttachment) attachment;
if (documentAttachment.J != null)
try {
searchPhoto(getUrlFromDocumentAttachment(documentAttachment));
searchDialog(LifecycleUtils.getCurrentActivity(), getUrlFromDocumentAttachment(documentAttachment));
} catch (Exception e) {
ToastUtils.a(R.string.photo_get_error);
}
@@ -118,9 +118,7 @@ public class PhotoViewer {
}
);
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),
ContextExtKt.b(AndroidUtils.getGlobalContext(), R.drawable.ic_copy_outline_28, VKThemeHelper.g(R.attr.header_tint)),
false,
() -> {
if (attachment instanceof PhotoAttachment) {
@@ -140,10 +138,7 @@ public class PhotoViewer {
}
);
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),
ThemesUtils.getAccentColor()),
ContextExtKt.b(AndroidUtils.getGlobalContext(), R.drawable.ic_link_outline_28, VKThemeHelper.g(R.attr.header_tint)),
false,
() -> {
if (attachment instanceof PhotoAttachment) {
@@ -191,21 +186,46 @@ public class PhotoViewer {
return max.url;
}
private static void searchPhoto(String url) {
if (url == null || url.isEmpty()) return;
switch (getPreferences().getInt("search_engine", 0)) {
case 0:
searchWithYandex(url);
break;
case 1:
searchWithGoogle(url);
break;
case 2:
searchWithBing(url);
break;
private static void searchDialog(Context context, String url) {
if (selectedEngine() == 0) {
var items = new String[]{
"Yandex", "Google", "Bing", "TraceMoe", "Ascii2d", "Saucenao"
};
new VkAlertDialog.Builder(context)
.setItems(items, (dl, i) -> {
searchPhoto(i + 1, url);
})
.show();
} else {
searchPhoto(selectedEngine(), url);
}
}
private static int selectedEngine() {
return getPreferences().getInt("search_engine", 0);
}
private static void searchPhoto(int i, String url) {
if (url == null || url.isEmpty()) {
Log.d("PhotoViewer", "url is null or empty");
return;
}
switch (i) {
case 1 -> searchWithYandex(url);
case 2 -> searchWithGoogle(url);
case 3 -> searchWithBing(url);
case 4 -> searchWithTraceMoe(url);
case 5 -> searchWithAscii2d(url);
case 6 -> searchWithSaucenao(url);
}
}
private static void searchPhoto(String url) {
searchPhoto(selectedEngine(), url);
}
private static void searchWithYandex(String url) {
var request = new Request.a()
.b(String.format("https://yandex.ru/images-apphost/image-download?url=%s&images_avatars_size=preview&images_avatars_namespace=images-cbir",
@@ -233,8 +253,19 @@ public class PhotoViewer {
}
private static void searchWithGoogle(String url) {
openUrl("https://www.google.ru/searchbyimage?image_url=" +
URLEncoder.encode(url));
openUrl("https://www.google.com/searchbyimage?image_url=" + URLEncoder.encode(url) + "&client=app");
}
private static void searchWithTraceMoe(String url) {
openUrl("https://trace.moe/?url=" + URLEncoder.encode(url));
}
private static void searchWithAscii2d(String url) {
openUrl("https://ascii2d.net/search/url/" + URLEncoder.encode(url));
}
private static void searchWithSaucenao(String url) {
openUrl("https://saucenao.com/search.php?url=" + URLEncoder.encode(url));
}
private static void searchWithBing(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";
}
}
@@ -24,6 +24,7 @@ import com.vk.navigation.Navigator;
import com.vtosters.lite.R;
import ru.vtosters.lite.ui.fragments.ProxySettingsFragment;
import ru.vtosters.lite.utils.NavigatorUtils;
public class ProxyHook {
public static void hookAuth(View v) {
@@ -70,11 +71,11 @@ public class ProxyHook {
rgRandomProxy.setChecked(isRandomProxyEnabled());
rgVika.setChecked(isVikaProxyEnabled());
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) -> { // Применить
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();
@@ -88,13 +89,10 @@ public class ProxyHook {
edit().putString("proxy", "noproxy").commit();
restartApplication();
}
}))
.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();
}))
.setNeutralButton(ctx.getString(R.string.proxy_settings), (dialog, which) -> {
NavigatorUtils.switchFragment(ctx, ProxySettingsFragment.class);
})
.show();
}
}
@@ -35,47 +35,28 @@ public class StartFragmentHook {
if (vkme()) {
return DialogsFragment.class;
}
switch (getPrefsValue("start_values")) {
case "newsfeed":
return milkshake() ? HomeFragment.class : NewsfeedFragment.class;
case "messenger":
return DialogsFragment.class;
case "groups":
return milkshake() ? CommunitiesCatalogFragment.class : GroupsFragment1.class;
case "music":
return MusicCatalogFragment1.class;
case "friends":
return FriendsFragment.class;
case "photos":
return PhotosFragment.class;
case "videos":
return VideoCatalogFragment.class;
case "settings":
return useNewSettings();
case "apps":
return AppsFragment.class;
case "discover":
return DiscoverFragment.class;
case "notifications":
return NotificationsContainerFragment.class;
case "money":
return MoneyTransfersFragment.class;
case "games":
return GamesFragment.class;
case "liked":
return FaveTabFragment.class;
case "menu":
return milkshake() ? (superapp() ? SuperAppFragment.class : SearchMenuFragment.class) : MenuFragment.class;
case "profile":
return ProfileFragment.class;
case "lives":
return LivesTabsFragment.class;
case "docs":
return DocumentsViewFragment.class;
case "brtd":
return BirthdaysFragment.class;
default:
return getInstance().getSelectedTabs().get(0).fragmentClass;
}
return switch (getPrefsValue("start_values")) {
case "newsfeed" -> milkshake() ? HomeFragment.class : NewsfeedFragment.class;
case "messenger" -> DialogsFragment.class;
case "groups" -> milkshake() ? CommunitiesCatalogFragment.class : GroupsFragment1.class;
case "music" -> MusicCatalogFragment1.class;
case "friends" -> FriendsFragment.class;
case "photos" -> PhotosFragment.class;
case "videos" -> VideoCatalogFragment.class;
case "settings" -> useNewSettings();
case "apps" -> AppsFragment.class;
case "discover" -> DiscoverFragment.class;
case "notifications" -> NotificationsContainerFragment.class;
case "money" -> MoneyTransfersFragment.class;
case "games" -> GamesFragment.class;
case "liked" -> FaveTabFragment.class;
case "menu" ->
milkshake() ? (superapp() ? SuperAppFragment.class : SearchMenuFragment.class) : MenuFragment.class;
case "profile" -> ProfileFragment.class;
case "lives" -> LivesTabsFragment.class;
case "docs" -> DocumentsViewFragment.class;
case "brtd" -> BirthdaysFragment.class;
default -> getInstance().getSelectedTabs().get(0).fragmentClass;
};
}
}
@@ -12,137 +12,25 @@ import com.vk.toggle.Features;
public class TogglesHook {
public static boolean shouldPatch(Features.Type feature) {
switch (feature) {
case AB_IM_LONGPOLL_MSG_BATCHING:
case AB_IM_VIEW_POOL:
case AB_MULTI_GIFTS:
case AB_NEWS_VIDEO_LAYOUT_TEXT:
case AB_STICKERS_DISCOVER:
case AB_GIFTS_FROM_KEYBOARD:
case FEATURE_FEED_DEFAULT_LIST_ALWAYS:
case EXPERIMENT_NEWS_VIDEO_LAYOUT_TEXT:
case FEATURE_MILKSHAKE_DISCOVER_IN_MENU:
case FEATURE_DISCOVER_CATEGORIES:
case FEATURE_FAVE_PERF_IMPROVE:
case FEATURE_GROUP_ADMIN_MESSAGES:
case FEATURE_GROUP_MSG_PUSH_PARAM:
case FEATURE_IMAGE_QUALITY_UPGRADE:
case FEATURE_IM_AUDIO_MSG_TRANSCRIPT:
case FEATURE_IM_CASPER_MSGS:
case FEATURE_IM_DISABLE_FORCE_OPEN_VK_ME:
case FEATURE_IM_GIF_AUTOPLAY:
case FEATURE_IM_MR_IN_VKAPP:
case FEATURE_MEMORIES_ENABLED:
case FEATURE_MENU_GAMES_CAROUSEL:
case FEATURE_MILKSHAKE:
case FEATURE_MILKSHAKE_CHANGE_FEED_BY_TIMEOUT:
case FEATURE_MILKSHAKE_NEWS_SCROLL_ON_BACK:
case FEATURE_MILKSHAKE_SWITCH_THEME_ON_TAP:
case FEATURE_ML_BRANDS:
case FEATURE_ML_FEATURES:
case FEATURE_ML_MODELS_LOADING:
case FEATURE_MONEY_TRANSFERS_VKPAY:
case FEATURE_MUSIC_ARTIST_CATALOG:
case FEATURE_MUSIC_NEW_CATALOG:
case FEATURE_NARRATIVE_SNIPPET_TYPE:
case FEATURE_NEWS_GAMES_IN_DISCOVER:
case FEATURE_NEWS_HEADER_SCROLL:
case FEATURE_NEW_FORMAT_SHOW_WPB:
case FEATURE_NOTIFICATION_ANIM:
case FEATURE_PODCASTS_PAGE:
case FEATURE_QR_CREATE_QR:
case FEATURE_QR_DYNAMIC_FRAME:
case FEATURE_QR_SCAN_FROM_PHOTO:
case FEATURE_QR_VISION_DECODER:
case FEATURE_QUEUE_COUNTERS:
case FEATURE_REEF:
case FEATURE_ROAMING_AUTOPLAY:
case FEATURE_SHARE_MSGS_ON_INVITE:
case FEATURE_STICKERS_BOT_LINK:
case FEATURE_STICKERS_NEW_CATALOG:
case FEATURE_STORIES_AVATAR:
case FEATURE_STORIES_FEED_TYPE:
case FEATURE_STORIES_SHOW_ALWAYS:
case FEATURE_STORY_ANSWER_PUBLIC:
case FEATURE_STORY_APP_STICKER:
case FEATURE_STORY_ARCHIVE:
case FEATURE_STORY_ARCHIVE_POST:
case FEATURE_STORY_BAKGROUND_ALL:
case FEATURE_STORY_BOX:
case FEATURE_STORY_CADRE:
case FEATURE_STORY_CAMERA_TOOLTIP:
case FEATURE_STORY_EDITOR_GALLERY:
case FEATURE_STORY_EDITOR_TYPE:
case FEATURE_STORY_ENDLESS_VIDEO:
case FEATURE_STORY_FAST_REACTIONS:
case FEATURE_STORY_GIF:
case FEATURE_STORY_GROUPED:
case FEATURE_STORY_HIGH_QUALITY:
case FEATURE_STORY_MASKS_FRONTAL:
case FEATURE_STORY_MENTION_ICON:
case FEATURE_STORY_MODERN_PUBLISH:
case FEATURE_STORY_MUSIC_EDITOR:
case FEATURE_STORY_MUSIC_REPLIES:
case FEATURE_STORY_MUSIC_REPLIES_2:
case FEATURE_STORY_NEW_FRAME:
case FEATURE_STORY_ONE_TIME:
case FEATURE_STORY_PHOTO_SHARING:
case FEATURE_STORY_PHOTO_STICKER:
case FEATURE_STORY_POLLS:
case FEATURE_STORY_POST_REPOST:
case FEATURE_STORY_PRELOADING:
case FEATURE_STORY_QUESTION:
case FEATURE_STORY_QUESTION_STYLE:
case FEATURE_STORY_RLOTTIE:
case FEATURE_STORY_RLOTTIE_CACHE:
case FEATURE_STORY_SAVE_DEFAULT_ON:
case FEATURE_STORY_SEND_DIALOG_LIST:
case FEATURE_STORY_STICKER_PACK:
case FEATURE_STORY_TIME:
case FEATURE_STORY_VIEWER_CAMERA:
case FEATURE_STORY_VOICE_ANSWER:
case FEATURE_STORY_WITH_CONTEXT:
case FEATURE_SUPERAPP_MENU:
case FEATURE_TRAFFIC_SAVER:
case FEATURE_VKPAY_WIDGET:
case FEATURE_VKUI_INTERNAL_TO_MINI_APPS:
case FEATURE_VKUI_TOKEN_CACHE:
case FEATURE_VK_APPS_SEARCH:
case FEATURE_VOTES_BALANCE:
case FEATURE_WEBVIEW_TOKEN_ACTIVE:
case FEATURE_WISHLIST_ENTRY_POINT:
case FEATURE_WISHLIST_MY_PROFILE:
case FEATURE_MILKSHAKE_FORCE_DISABLED:
case FEATURE_MILKSHAKE_ACTIVATION_DISABLED:
case EXPERIMENT_NEWS_DISABLE_CACHE:
return true;
default:
return false;
}
return switch (feature) {
case AB_IM_LONGPOLL_MSG_BATCHING, FEATURE_MOZJPEG, AB_IM_VIEW_POOL, AB_MULTI_GIFTS, AB_NEWS_VIDEO_LAYOUT_TEXT, AB_STICKERS_DISCOVER, AB_GIFTS_FROM_KEYBOARD, FEATURE_FEED_DEFAULT_LIST_ALWAYS, EXPERIMENT_NEWS_VIDEO_LAYOUT_TEXT, FEATURE_MILKSHAKE_DISCOVER_IN_MENU, FEATURE_DISCOVER_CATEGORIES, FEATURE_FAVE_PERF_IMPROVE, FEATURE_GROUP_ADMIN_MESSAGES, FEATURE_GROUP_MSG_PUSH_PARAM, FEATURE_IMAGE_QUALITY_UPGRADE, FEATURE_IM_AUDIO_MSG_TRANSCRIPT, FEATURE_IM_CASPER_MSGS, FEATURE_IM_DISABLE_FORCE_OPEN_VK_ME, FEATURE_IM_GIF_AUTOPLAY, FEATURE_IM_MR_IN_VKAPP, FEATURE_MEMORIES_ENABLED, FEATURE_MENU_GAMES_CAROUSEL, FEATURE_MILKSHAKE, FEATURE_MILKSHAKE_CHANGE_FEED_BY_TIMEOUT, FEATURE_MILKSHAKE_NEWS_SCROLL_ON_BACK, FEATURE_MILKSHAKE_SWITCH_THEME_ON_TAP, FEATURE_ML_BRANDS, FEATURE_ML_FEATURES, FEATURE_ML_MODELS_LOADING, FEATURE_MONEY_TRANSFERS_VKPAY, FEATURE_MUSIC_ARTIST_CATALOG, FEATURE_MUSIC_NEW_CATALOG, FEATURE_NARRATIVE_SNIPPET_TYPE, FEATURE_NEWS_GAMES_IN_DISCOVER, FEATURE_NEWS_HEADER_SCROLL, FEATURE_NEW_FORMAT_SHOW_WPB, FEATURE_PODCASTS_PAGE, FEATURE_QR_CREATE_QR, FEATURE_QR_DYNAMIC_FRAME, FEATURE_QR_SCAN_FROM_PHOTO, FEATURE_QR_VISION_DECODER, FEATURE_QUEUE_COUNTERS, FEATURE_REEF, FEATURE_ROAMING_AUTOPLAY, FEATURE_SHARE_MSGS_ON_INVITE, FEATURE_STICKERS_BOT_LINK, FEATURE_STICKERS_NEW_CATALOG, FEATURE_STORIES_AVATAR, FEATURE_STORIES_FEED_TYPE, FEATURE_STORIES_SHOW_ALWAYS, FEATURE_STORY_ANSWER_PUBLIC, FEATURE_STORY_APP_STICKER, FEATURE_STORY_ARCHIVE, FEATURE_STORY_ARCHIVE_POST, FEATURE_STORY_BAKGROUND_ALL, FEATURE_STORY_BOX, FEATURE_STORY_CADRE, FEATURE_STORY_CAMERA_TOOLTIP, FEATURE_STORY_EDITOR_GALLERY, FEATURE_STORY_EDITOR_TYPE, FEATURE_STORY_ENDLESS_VIDEO, FEATURE_STORY_FAST_REACTIONS, FEATURE_STORY_GIF, FEATURE_STORY_GROUPED, FEATURE_STORY_HIGH_QUALITY, FEATURE_STORY_MASKS_FRONTAL, FEATURE_STORY_MENTION_ICON, FEATURE_STORY_MODERN_PUBLISH, FEATURE_STORY_MUSIC_EDITOR, FEATURE_STORY_MUSIC_REPLIES, FEATURE_STORY_MUSIC_REPLIES_2, FEATURE_STORY_NEW_FRAME, FEATURE_STORY_ONE_TIME, FEATURE_STORY_PHOTO_SHARING, FEATURE_STORY_PHOTO_STICKER, FEATURE_STORY_POLLS, FEATURE_STORY_POST_REPOST, FEATURE_STORY_PRELOADING, FEATURE_STORY_QUESTION, FEATURE_STORY_QUESTION_STYLE, FEATURE_STORY_RLOTTIE, FEATURE_STORY_RLOTTIE_CACHE, FEATURE_STORY_SAVE_DEFAULT_ON, FEATURE_STORY_SEND_DIALOG_LIST, FEATURE_STORY_STICKER_PACK, FEATURE_STORY_TIME, FEATURE_STORY_VIEWER_CAMERA, FEATURE_STORY_VOICE_ANSWER, FEATURE_STORY_WITH_CONTEXT, FEATURE_SUPERAPP_MENU, FEATURE_TRAFFIC_SAVER, FEATURE_VKPAY_WIDGET, FEATURE_VKUI_INTERNAL_TO_MINI_APPS, FEATURE_VKUI_TOKEN_CACHE, FEATURE_VK_APPS_SEARCH, FEATURE_VOTES_BALANCE, FEATURE_WEBVIEW_TOKEN_ACTIVE, FEATURE_MILKSHAKE_FORCE_DISABLED, FEATURE_MILKSHAKE_ACTIVATION_DISABLED, EXPERIMENT_NEWS_DISABLE_CACHE ->
true;
default -> false;
};
}
public static boolean redirect(Features.Type feature) {
switch (feature) {
case EXPERIMENT_NEWS_DISABLE_CACHE:
return !feedcache();
case FEATURE_SUPERAPP_MENU:
return superapp();
case FEATURE_MILKSHAKE:
return milkshake();
case FEATURE_MILKSHAKE_FORCE_DISABLED:
case FEATURE_MILKSHAKE_ACTIVATION_DISABLED:
return !milkshake();
case AB_NEWS_VIDEO_LAYOUT_TEXT:
case FEATURE_COMPACT_REPOST:
case EXPERIMENT_NEWS_VIDEO_LAYOUT_TEXT:
return postsredesign();
case FEATURE_IMAGE_QUALITY_UPGRADE:
return !getBoolValue("compressPhotos", true);
case FEATURE_MENU_GAMES_CAROUSEL:
return miniapps();
default:
return true;
}
return switch (feature) {
case EXPERIMENT_NEWS_DISABLE_CACHE -> !feedcache();
case FEATURE_SUPERAPP_MENU -> superapp();
case FEATURE_MILKSHAKE -> milkshake();
case FEATURE_MILKSHAKE_FORCE_DISABLED, FEATURE_MILKSHAKE_ACTIVATION_DISABLED -> !milkshake();
case AB_NEWS_VIDEO_LAYOUT_TEXT, FEATURE_COMPACT_REPOST, EXPERIMENT_NEWS_VIDEO_LAYOUT_TEXT ->
postsredesign();
case FEATURE_IMAGE_QUALITY_UPGRADE -> !getBoolValue("compressPhotos", true);
case FEATURE_MENU_GAMES_CAROUSEL -> miniapps();
default -> true;
};
}
public static FeatureManager.b redirectStrings(Features.Type feature) {
@@ -18,6 +18,8 @@ import android.webkit.WebView;
import com.vk.articles.preload.WebCachePreloader;
import com.vtosters.lite.R;
import com.vtosters.lite.data.ThemeTracker;
import ru.vtosters.lite.themes.ThemesCore;
import ru.vtosters.lite.utils.ThemesUtils;
import java.io.BufferedReader;
import java.io.IOException;
@@ -77,22 +79,19 @@ public class VKUIHook {
}
public static void inject(WebView webView) {
String string = getPrefsValue("darktheme");
if (getBoolValue("VKUI_INJ", true)) {
if (!isLoaded) {
load();
}
StringBuilder sb = new StringBuilder();
if (true/*Themes.isAccentedCache()*/) {
if (ThemesCore.isCachedAccents()) {
sb.append("\n\n");
sb.append(loadedCSS);
}
if (string.equals("amoled")) {
if (ThemesUtils.isAmoledTheme()) {
sb.append("\n\n");
sb.append(loadedCSSAmoled);
}
@@ -8,7 +8,7 @@ import ru.vtosters.lite.utils.ThemesUtils;
public class WritebarHook {
public static int getWriteBar() {
return wbios() ? R.layout.write_bar_i : R.layout.write_bar;
return wbios() ? R.layout.write_bar_i : R.layout.write_bar;
}
public static int getIconsColors(int def) {
@@ -26,6 +26,7 @@ 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;
@@ -35,7 +36,7 @@ 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 = new OkHttpClient();
private static final OkHttpClient CLIENT = VtOkHttpClient.getInstance();
private static final List<String> SCROBBLED_UUIDS = new ArrayList<>();
public static void grabMusicTrack(MusicTrack musictrack) {
@@ -55,7 +56,7 @@ public class LastFMScrobbler {
}
if (Preferences.autocache() && !CacheDatabaseDelegate.isCached(uid)) {
if (LibVKXClient.isIntegrationEnabled()){
if (LibVKXClient.isIntegrationEnabled()) {
LibVKXClient.getInstance().runOnService(service -> {
try {
service.addTrackToCache(track_id, owner_id, access_key);
@@ -100,7 +101,7 @@ public class LastFMScrobbler {
fetch(params, new Callback() {
@Override
public void a(Call call, IOException e) {
Log.d("Scrobbler", e+"");
Log.d("Scrobbler", e + "");
}
@Override
@@ -199,7 +200,7 @@ public class LastFMScrobbler {
}
public static boolean needScrobbling(String uid) {
return isLoggedIn() && isScrobblingEnabled() && !SCROBBLED_UUIDS.contains(uid);
return isLoggedIn() && isScrobblingEnabled() && (SCROBBLED_UUIDS.isEmpty() || !SCROBBLED_UUIDS.get(SCROBBLED_UUIDS.size() - 1).contains(uid));
}
public static boolean isLoggedIn() {
@@ -1,5 +1,6 @@
package ru.vtosters.lite.music;
import android.util.Log;
import com.vk.dto.music.MusicTrack;
import java.io.File;
@@ -10,8 +11,6 @@ import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import javax.crypto.NoSuchPaddingException;
@@ -19,6 +18,7 @@ import javax.crypto.NoSuchPaddingException;
import java8.util.concurrent.CompletableFuture;
import okhttp3.OkHttpClient;
import okhttp3.Request;
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;
@@ -27,14 +27,19 @@ 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 ExecutorService executorService = Executors.newSingleThreadExecutor();
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) {
if (track.D.isEmpty()) {
Log.d("TrackDownloader", "link error: " + track.y1() + ", title: " + M3UDownloader.getTitle(track));
callback.onFailure();
return;
}
var request = new Request.a().b(track.D).a();
try {
var response = client.a(request).execute().a().g();
@@ -62,16 +67,7 @@ public class M3UDownloader implements ITrackDownloader {
tsesDir.mkdirs();
var resultTs = new File(tsesDir, "result.ts");
String title = null;
if (track.f != null) {
title = track.f;
if (!track.g.isEmpty()) {
title += " (" + track.g + ")";
}
}
var fileName = IOUtils.getValidFileName((cache ? "track" : track.C + " - " + title) + ".mp3");
var fileName = IOUtils.getValidFileName((cache ? "track" : track.C + " - " + getTitle(track)) + ".mp3");
var resultMp3 = new File(outDir, fileName);
callback.onProgress(5);
@@ -99,6 +95,7 @@ public class M3UDownloader implements ITrackDownloader {
}));
}
var future = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
future.join();
future.exceptionally(throwable -> {
callback.onFailure();
return null;
@@ -110,6 +107,19 @@ public class M3UDownloader implements ITrackDownloader {
}).thenRun(() -> IOUtils.deleteRecursive(tsesDir)).thenRun(callback::onSuccess);
}
public static String getTitle(MusicTrack track) {
String title = null;
if (track.f != null) {
title = track.f;
if (!track.g.isEmpty()) {
title += " (" + track.g + ")";
}
}
return title;
}
// Initialization-on-demand
private static class Holder {
private static final M3UDownloader INSTANCE = new M3UDownloader();
@@ -45,7 +45,7 @@ public class VKM3UParser {
if (mTransportStreams.size() == i)
mTransportStreams.add(new TransportStream());
} else if (isM3U8(line)) {
mTransportStreams.get(i).setName(line);
mTransportStreams.get(i).setName(line.substring(line.lastIndexOf("/") + 1));
++i;
}
}
@@ -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;
@@ -23,11 +25,11 @@ import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
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,6 +1,11 @@
package ru.vtosters.lite.music.cache.injectors;
import static ru.vtosters.lite.music.cache.CacheDatabaseDelegate.hasTracks;
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;
@@ -20,9 +25,8 @@ 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;
@@ -76,76 +80,67 @@ public class TracklistInjector {
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());
}
}
@@ -175,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);
@@ -0,0 +1,296 @@
package ru.vtosters.lite.music.catalog.inject;
import android.util.Log;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import com.vk.core.network.Network;
import com.vk.core.util.DeviceIdProvider;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import java.io.IOException;
import static ru.vtosters.lite.hooks.DateHook.getLocale;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.*;
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;
public class CatalogJsonInjector {
private static final OkHttpClient mClient = VtOkHttpClient.getInstance();
private static boolean isLoaded;
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 (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));
}
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());
isLoaded = false;
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) && !isLoaded) {
var newBlocks = new JSONArray();
newBlocks
.put(getCatalogHeader())
.put(getCatalogPlaylist())
.put(getCatalogSeparator());
isLoaded = true;
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");
}
}
try {
fixHeaders(json.getJSONObject("section"));
} catch (Exception e) {
e.printStackTrace();
}
return catalogInjector(json);
}
public static JSONObject fixArtists(JSONObject json) {
try {
fixHeaders(json.getJSONObject("catalog").getJSONArray("sections").getJSONObject(0));
} catch (Exception e) {
e.printStackTrace();
}
return json;
}
public static void fixHeaders(JSONObject json) {
var blocks = json.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();
}
}
}
}
}
}
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;
}
}
@@ -28,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;
@@ -60,6 +58,7 @@ public class FFMpeg {
if (track.I != null) {
sb.append(" -metadata album=\"").append(track.I.getTitle()).append("\"");
}
sb.append(" -write_xing 0");
sb.append(" -c copy \"").append(out).append("\"");
@@ -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;
@@ -15,6 +16,12 @@ import ru.vtosters.lite.music.interfaces.ITrackDownloader;
public class TrackDownloader {
public static void downloadTrack(MusicTrack track, String path, Callback callback) {
if (track.D.isEmpty()) {
Log.d("TrackDownloader", "link error: " + track.y1() + ", title: " + M3UDownloader.getTitle(track));
callback.onFailure();
return;
}
download(track, path, callback, M3UDownloader.getInstance(), false);
}
@@ -22,6 +29,10 @@ public class TrackDownloader {
if (CacheDatabaseDelegate.isCached(track.y1())) {
callback.onSuccess();
return;
} else if (track.D.isEmpty()) {
Log.d("TrackDownloader", "link error: " + track.y1() + ", title: " + M3UDownloader.getTitle(track));
callback.onFailure();
return;
}
var path = FileCacheImplementation.getTrackFolder(LibVKXClient.asId(track)).getAbsolutePath();
@@ -36,6 +47,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,15 +19,13 @@ 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.music.cache.CacheDatabaseDelegate;
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;
@@ -40,9 +38,15 @@ public class MusicBottomSheetHook {
if (isIntegrationEnabled()) {
if (isVkxCached(trackid)) {
actions.add(getRemoveCacheTrackVkxAction());
} else {
} else if (isNetworkConnected()){
actions.add(addToCacheTrackVkxAction());
}
} else {
if (isCached(trackid)) {
actions.add(getRemoveCacheTrackAction());
} else if (isNetworkConnected()){
actions.add(addToCacheTrackAction());
}
}
if (isNetworkConnected()) {
@@ -89,10 +93,10 @@ public class MusicBottomSheetHook {
if (isIntegrationEnabled()) {
if (isVkxCached(playlist.a, playlist.b)) {
actions.add(getRemoveCacheTrackVkxAction());
} else {
} else if (isNetworkConnected()){
actions.add(addToCacheTrackVkxAction());
}
} else {
} else if (isNetworkConnected()){
actions.add(addToCacheTrackAction());
}
@@ -125,6 +129,15 @@ public class MusicBottomSheetHook {
return true;
}
if (actionId == R.id.remove_from_cache) {
CacheDatabaseDelegate.removeTrackFromCache(asId(track));
AndroidUtils.sendToast(AndroidUtils.getString("audio_deleted_from_cache"));
return true;
} else if (actionId == R.id.add_to_cache) {
AudioDownloader.cacheTrack(track);
return true;
}
if (actionId == R.id.download_mp3) {
if (isIntegrationEnabled()) {
getInstance().runOnService(service -> {
@@ -149,7 +162,7 @@ public class MusicBottomSheetHook {
return tryPlayInVKX(null, null, playlist);
if (actionId == R.id.add_to_cache) {
executor.submit(() -> AudioDownloader.cachePlaylist(playlist));
AudioDownloader.cachePlaylist(playlist);
return true;
}
@@ -183,7 +196,7 @@ public class MusicBottomSheetHook {
}
});
} else {
executor.submit(() -> AudioDownloader.downloadPlaylist(playlist));
AudioDownloader.downloadPlaylist(playlist);
}
return true;
}
@@ -1,6 +1,7 @@
package ru.vtosters.lite.net;
import android.util.Base64;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -14,30 +15,24 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Executor;
public final class NetCall {
private final NetRequest req;
private final NetClient cl;
private final Executor executor;
protected NetCall(NetClient cl, NetRequest req, Executor executor) {
protected NetCall(NetClient cl, NetRequest req) {
this.req = req;
this.cl = cl;
this.executor = executor;
}
private static String constructArgs(Map<String, String> args) throws UnsupportedEncodingException {
args = new TreeMap<>(args);
StringBuilder str = new StringBuilder();
String str = "";
for (Map.Entry<String, String> en : args.entrySet()) {
if (str.length() > 0)
str.append("&");
str.append(URLEncoder.encode(en.getKey(), "UTF-8"))
.append("=")
.append(URLEncoder.encode(en.getValue(), "UTF-8"));
if (!str.isEmpty()) str += "&";
str += URLEncoder.encode(en.getKey(), "UTF-8") + "=" + URLEncoder.encode(en.getValue(), "UTF-8");
}
return str.toString();
return str;
}
public NetRequest request() {
@@ -82,13 +77,22 @@ public final class NetCall {
}
public void enqueue(NetCallback cb) {
executor.execute(() -> {
try {
NetResponse resp = execute();
cb.onResponse(NetCall.this, resp);
} catch (IOException e) {
cb.onFailure(NetCall.this, e);
new Thread() {
@Override
public void run() {
try {
NetResponse resp = execute();
cb.onResponse(NetCall.this, resp);
} catch (IOException e) {
cb.onFailure(NetCall.this, e);
}
try {
interrupt();
join();
} catch (Exception e) {
Log.e("NetCall", "Failed to interrupt and join thread", e);
}
}
});
}.start();
}
}
@@ -2,16 +2,12 @@ package ru.vtosters.lite.net;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class NetClient {
private final long timeout;
private final Proxy proxy;
private final PasswordAuthentication authenticator;
private final Executor executor
= Executors.newSingleThreadExecutor();
protected NetClient(Builder b) {
timeout = b.timeout;
@@ -28,7 +24,7 @@ public class NetClient {
}
public NetCall newCall(NetRequest req) {
return new NetCall(this, req, executor);
return new NetCall(this, req);
}
public PasswordAuthentication getAuthenticator() {
@@ -49,27 +45,14 @@ public class NetClient {
private PasswordAuthentication auth;
public Builder connectTimeout(long l, TimeUnit unit) {
int m;
switch (unit) {
case SECONDS:
m = 1000;
break;
case MILLISECONDS:
m = 1;
break;
case HOURS:
m = 1000 * 60 * 60;
break;
case DAYS:
m = 1000 * 60 * 60 * 24;
break;
case MINUTES:
m = 1000 * 60;
break;
default:
m = 1;
break;
}
int m = switch (unit) {
case SECONDS -> 1000;
case MILLISECONDS -> 1;
case HOURS -> 1000 * 60 * 60;
case DAYS -> 1000 * 60 * 60 * 24;
case MINUTES -> 1000 * 60;
default -> 1;
};
timeout = l * m;
return this;
}
@@ -2,77 +2,75 @@ package ru.vtosters.lite.net;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
import android.os.AsyncTask;
import com.vk.core.network.Network;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Request {
private static final Executor EXECUTOR =
Executors.newSingleThreadExecutor();
public static void makeRequest(byte[] bArr, RequestCallback callback) {
EXECUTOR.execute(new MakeRequestTask(bArr, callback));
public static void makeRequest(byte[] bArr, RequestCallback RequestCallback) {
new MakeRequestTask(bArr, RequestCallback).execute();
}
public static void makeRequest(String str, RequestCallback callback) {
makeRequest(str.getBytes(), callback);
public static void makeRequest(String str, RequestCallback RequestCallback) {
new MakeRequestTask(str.getBytes(), RequestCallback).execute();
}
public interface RequestCallback {
void onResponse(String str);
}
private static class MakeRequestTask implements Runnable {
private static class MakeRequestTask extends AsyncTask<Void, Void, String> {
private final RequestCallback callback;
private final byte[] url;
private final boolean mIsPut;
private final boolean mIsVTostersRequest;
public MakeRequestTask(byte[] bArr, RequestCallback callback) {
this.mIsVTostersRequest = false;
this.mIsPut = false;
this.callback = callback;
this.url = bArr;
public MakeRequestTask(byte[] bArr, RequestCallback RequestCallback) {
mIsVTostersRequest = false;
mIsPut = false;
callback = RequestCallback;
url = bArr;
}
@Override
public void run() {
public String doInBackground(Void... voidArr) {
try {
HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(new String(url)).openConnection();
httpURLConnection.setRequestMethod(mIsPut ? "PUT" : "GET");
if (mIsVTostersRequest) {
httpURLConnection.setRequestProperty("Token", getUserToken());
} else {
}
if (!mIsVTostersRequest) {
httpURLConnection.setRequestProperty("User-Agent", Network.l.c().a());
}
httpURLConnection.setRequestProperty("Content-Type", mIsVTostersRequest
? "Content-Type"
: "application/x-www-form-urlencoded");
httpURLConnection.setRequestProperty("Content-Type", mIsVTostersRequest ? "Content-Type" : "application/x-www-form-urlencoded");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
StringBuilder builder = new StringBuilder();
StringBuffer stringBuffer = new StringBuffer();
while (true) {
String readLine = bufferedReader.readLine();
if (readLine != null) {
builder.append(readLine);
stringBuffer.append(readLine);
} else {
bufferedReader.close();
callback.onResponse(builder.toString());
break;
return stringBuffer.toString();
}
}
} catch (Exception e) {
callback.onResponse(e.getLocalizedMessage());
return e.getLocalizedMessage();
}
}
public void onPostExecute(String str) {
super.onPostExecute(str);
callback.onResponse(str);
}
}
}
@@ -8,9 +8,10 @@ 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()
@@ -28,7 +29,7 @@ public class GithubList {
Log.d(proxyname, response);
return new ArrayList<>(Arrays.asList(response.split("\n")));
} catch (Exception e){
} catch (Exception e) {
Log.d(proxyname, "Failed to fetch data, link: " + link);
return null;
@@ -134,24 +134,12 @@ public class ProxyUtils {
public static void setProxy() throws IOException {
switch (getPrefsValue("proxy")) {
case "zaborona":
Zaborona.loadProxy();
break;
case "randomproxy":
RandomProxy.loadProxy();
break;
case "socks":
CustomSocks.loadProxy();
break;
case "http":
CustomHttp.loadProxy();
break;
case "https":
CustomHttps.loadProxy();
break;
default:
resetProxy();
break;
case "zaborona" -> Zaborona.loadProxy();
case "randomproxy" -> RandomProxy.loadProxy();
case "socks" -> CustomSocks.loadProxy();
case "http" -> CustomHttp.loadProxy();
case "https" -> CustomHttps.loadProxy();
default -> resetProxy();
}
}
@@ -19,24 +19,23 @@ public class RandomProxy {
public static void loadProxy() throws IOException {
if (host.isEmpty()) {
getProxy();
loadProxy();
if (getProxy()) loadProxy();
return;
}
switch (type) {
case "socks":
case "socks" -> {
System.setProperty("socksProxyHost", host.split(":")[0]);
System.setProperty("socksProxyPort", host.split(":")[1]);
break;
case "http":
}
case "http" -> {
System.setProperty("http.proxyHost", host.split(":")[0]);
System.setProperty("http.proxyPort", host.split(":")[1]);
break;
case "https":
}
case "https" -> {
System.setProperty("https.proxyHost", host.split(":")[0]);
System.setProperty("https.proxyPort", host.split(":")[1]);
break;
}
}
}
@@ -51,34 +50,20 @@ public class RandomProxy {
edit().putString("proxy", "randomproxy").commit();
}
public static void getProxy() throws IOException {
public static boolean getProxy() throws IOException {
var random = new java.util.Random();
var randomInt = random.nextInt(7);
var randomInt = random.nextInt(8);
switch (randomInt) {
case 0:
Hookzof.loadProxy();
break;
case 1:
TheSpeedX.loadProxy();
break;
case 2:
Jetkai.loadProxy();
break;
case 3:
Roosterkid.loadProxy();
break;
case 4:
ru.vtosters.lite.proxy.http.Jetkai.loadProxy();
break;
case 5:
ru.vtosters.lite.proxy.http.TheSpeedX.loadProxy();
break;
case 6:
ru.vtosters.lite.proxy.https.Jetkai.loadProxy();
break;
case 7:
ru.vtosters.lite.proxy.https.Roosterkid.loadProxy();
break;
case 0 -> Hookzof.loadProxy();
case 1 -> TheSpeedX.loadProxy();
case 2 -> Jetkai.loadProxy();
case 3 -> Roosterkid.loadProxy();
case 4 -> ru.vtosters.lite.proxy.http.Jetkai.loadProxy();
case 5 -> ru.vtosters.lite.proxy.http.TheSpeedX.loadProxy();
case 6 -> ru.vtosters.lite.proxy.https.Jetkai.loadProxy();
case 7 -> ru.vtosters.lite.proxy.https.Roosterkid.loadProxy();
}
return true;
}
}
@@ -0,0 +1,39 @@
package ru.vtosters.lite.ssfs;
import android.util.Log;
import okhttp3.Request;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import java.io.IOException;
public class Handler {
private static final String TAG = "SSFSHandler";
public static JSONObject getBanner(int id) {
Request request = new Request.a()
.b(Utils.getDomain() + "/api/getChatBanner" + "?user_id=" + id)
.a();
try {
return new JSONObject(VtOkHttpClient.getInstance().a(request).execute().a().g()).getJSONObject("response");
} catch (JSONException | IOException e) {
Log.d(TAG, e.getMessage());
return null;
}
}
public static String getDescription(int id) {
Request request = new Request.a()
.b(Utils.getDomain() + "/api/getServiceDescription" + "?user_id=" + id)
.a();
try {
return new JSONObject(VtOkHttpClient.getInstance().a(request).execute().a().g()).getString("response");
} catch (JSONException | IOException e) {
Log.d(TAG, e.getMessage());
return null;
}
}
}
@@ -0,0 +1,88 @@
package ru.vtosters.lite.ssfs;
import android.util.Log;
import com.vk.core.dialogs.alert.VkAlertDialog;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.vtosters.lite.R;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.LifecycleUtils;
import ru.vtosters.lite.utils.Preferences;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
public class ImBanner {
private static final String TAG = "ImBanner";
public static JSONObject convBar(JSONObject orig) throws JSONException {
var user_id = orig.getJSONObject("peer").getInt("id");
if (!UsersList.hasBanner(user_id) || user_id == 0) {
if (getBoolValue("convBarRecomm", false)) {
return null;
} else {
return orig.optJSONObject("conversation_bar");
}
}
try {
var jsonBanner = Handler.getBanner(user_id);
var pic = jsonBanner.optString("picture");
var text = jsonBanner.getString("text");
var link = jsonBanner.optString("link");
var link_text = jsonBanner.optString("link_text");
var hasIcon = !pic.isEmpty();
var hasButton = !link.isEmpty();
var isPicture = pic.endsWith(".png") || pic.endsWith(".jpg") || pic.endsWith(".jpeg") || pic.endsWith(".webp");
var json = new JSONObject();
var buttonsJson = new JSONObject();
buttonsJson.put("layout", "tertiary");
buttonsJson.put("text", link_text);
buttonsJson.put("type", "link");
buttonsJson.put("link", link);
var buttons = new JSONArray(); // max 3 buttons in array
if (hasButton) buttons.put(buttonsJson);
json.put("name", "group_admin_welcome");
json.put("text", text);
json.put("buttons", buttons);
if (hasIcon && isPicture) {
json.put("icon", pic);
}
return json;
} catch (JSONException e) {
Log.d(TAG, e.getMessage());
return null;
}
}
public static boolean showAlert() {
var context = LifecycleUtils.getCurrentActivity();
var bool = Preferences.getBoolValue("linkalert", false);
if (!bool) {
new VkAlertDialog.Builder(context)
.setTitle(R.string.warning)
.setMessage(AndroidUtils.getString("custom_links_warning"))
.setCancelable(false)
.setPositiveButton(R.string.continue_, (dialogInterface, i) -> {
Preferences.preferences.edit().putBoolean("linkalert", true).commit();
})
.setNeutralButton(R.string.cancel, (dialogInterface, i) -> {
dialogInterface.cancel();
})
.show();
}
return bool;
}
}
@@ -0,0 +1,98 @@
package ru.vtosters.lite.ssfs;
import android.util.Log;
import com.vk.core.util.LangUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.VTVerifications;
import java.util.HashMap;
import static ru.vtosters.lite.proxy.ProxyUtils.getStatic;
public class ProfileButtons {
private static final String TAG = "ProfileButtons";
public static JSONObject profileButton(JSONObject orig) {
try {
int id = orig.getInt("id");
var newItem = new JSONArray();
if (orig.has("buttons")) {
newItem = orig.getJSONArray("buttons");
}
if (!VTVerifications.haveDonateButton() && id == AccountManagerUtils.getUserId()) {
var map = new HashMap<>();
map.put("20", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/20.png");
map.put("40", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/40.png");
map.put("80", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/80.png");
newItem.put(generateJsonObject(
AndroidUtils.getString(com.vtosters.lite.R.string.donate_to_vtl),
"https://vk.com/vtosters_official",
"2D81E0",
"open_url",
map
));
}
if (!orig.has("type") && AccountManagerUtils.isVKTester()) {
var map = new HashMap<>();
map.put("20", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/bug_icon/20.png");
map.put("40", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/bug_icon/40.png");
map.put("80", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/bug_icon/80.png");
newItem.put(generateJsonObject(
AndroidUtils.getString(com.vtosters.lite.R.string.tester_profile),
"https://" + getStatic() + "/bugs?lang=" + LangUtils.a() + "#/reporter" + id,
"2D81E0",
"open_internal_vkui",
map
));
}
orig.put("buttons", newItem);
} catch (JSONException e) {
Log.d(TAG, e.getMessage());
}
return orig;
}
public static JSONObject generateJsonObject(String title, String link, String text_color, String url_type, HashMap<Object, Object> iconsList) {
try {
var json = new JSONObject();
var icons = new JSONArray();
var action = new JSONObject().put("target", "internal");
action.put("type", url_type); // may be open_url, open_internal_vkui, open_game, help_hint, show_full_post, open_vkapp, show_recommendations_for_post and groups_advertisement
action.put("url", link);
json.put("action", action);
json.put("title", title);
for (var entry : iconsList.entrySet()) {
var icon = new JSONObject();
icon.put("url", entry.getValue());
icon.put("width", entry.getKey());
icon.put("height", entry.getKey());
icons.put(icon);
}
json.put("icons", icons);
json.put("text_color", text_color);
return json;
} catch (JSONException e) {
Log.d(TAG, e.getMessage());
}
return null;
}
}
@@ -0,0 +1,42 @@
package ru.vtosters.lite.ssfs;
import android.text.TextUtils;
import android.util.Log;
import com.vk.profile.presenter.UserPresenter;
import com.vtosters.lite.api.ExtendedUserProfile;
import org.json.JSONObject;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserID;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
public class ProfileHider {
private static final String TAG = "ProfileHider";
public static boolean isService(Integer id) {
return UsersList.hasDescription(id) || id == 100 || id == 101 || id == 333;
}
public static void fetchInfo(ExtendedUserProfile extendedUserProfile, JSONObject jsonObject) {
int userID = getUserID(extendedUserProfile);
if (UsersList.hasDescription(userID)) {
try {
extendedUserProfile.z2 = Handler.getDescription(userID);
} catch (NullPointerException e) {
Log.e(TAG, "null \"profiles\" node\n" + e);
}
}
}
public static String getInfo(ExtendedUserProfile extendedUserProfile) {
int userID = getUserID(extendedUserProfile);
if (UsersList.hasDescription(userID)) {
if (!TextUtils.isEmpty(extendedUserProfile.z2)) {
return extendedUserProfile.z2;
} else {
return Handler.getDescription(userID);
}
}
return getGlobalContext().getString(UserPresenter.q0.a(userID));
}
}
@@ -0,0 +1,81 @@
package ru.vtosters.lite.ssfs;
import android.util.Log;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.NetworkUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static ru.vtosters.lite.utils.Preferences.dev;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
public class UsersList {
private static final String TAG = "UsersList";
private static final List<Integer> descriptionsList = new ArrayList<>();
private static final List<Integer> bannersList = new ArrayList<>();
public static void getUsersList() {
var prefs = AndroidUtils.getGlobalContext().getSharedPreferences("vt_another_data", 0);
if ((!NetworkUtils.isNetworkConnected() || getBoolValue("isRoamingState", false)) && prefs.contains("ids")) {
return;
}
Request request = new Request.a()
.b(Utils.getDomain() + "/api/getUsersWithServiceDescriptionsAndBanners")
.a();
VtOkHttpClient.getInstance().a(request).a(new Callback() {
@Override
public void a(Call call, IOException e) {
Log.d(TAG, e.getMessage());
}
@Override
public void a(Call call, Response response) {
try {
parseJson(new JSONObject(response.a().g()).getJSONObject("response"));
} catch (JSONException | IOException e) {
Log.d(TAG, e.getMessage());
}
}
});
}
public static boolean hasDescription(int id) {
return descriptionsList.contains(id) && id != AccountManagerUtils.getUserId();
}
public static boolean hasBanner(int id) {
return bannersList.contains(id) && id != AccountManagerUtils.getUserId();
}
static void parseJson(JSONObject json) throws JSONException {
var idsDescription = json.getJSONArray("with_service_descriptions");
var idsBanner = json.getJSONArray("with_chat_banners");
if (dev()) {
Log.d(TAG, idsDescription.toString());
Log.d(TAG, idsBanner.toString());
}
processIds(idsBanner, bannersList);
processIds(idsDescription, descriptionsList);
}
static void processIds(JSONArray jsonIds, List<Integer> member) {
for (int i = 0; i < jsonIds.length(); i++)
member.add(jsonIds.optInt(i));
}
}
@@ -0,0 +1,29 @@
package ru.vtosters.lite.ssfs;
import com.vk.core.network.Network;
import ru.vtosters.lite.hooks.DateHook;
import ru.vtosters.lite.proxy.ProxyUtils;
import ru.vtosters.lite.utils.*;
public class Utils {
public static String getVKUILink() {
return getDomain() +
"?token=" + AccountManagerUtils.getUserToken() +
"&vt_dark=" + (ThemesUtils.isDarkTheme() ? "1" : "0") +
"&vt_amoled=" + (ThemesUtils.isAmoledTheme() && ThemesUtils.isDarkTheme() ? "1" : "0") +
"&secret=" + AccountManagerUtils.getUserSecret() +
"&proxy=" + (ProxyUtils.isAnyProxyEnabled() ? "1" : "0") +
"&lang=" + DateHook.getLocale() +
"&vt=1" +
"&useragent=" + Base64Utils.encodeValue(Base64Utils.encode(Network.l.c().a())) +
"&vt_debug=" + (Preferences.dev() ? "1" : "0");
}
public static String getDomain() {
String string = AndroidUtils.getPrefsValue("ssfscustom");
if (!string.isEmpty()) return string;
return "https://ssfs.vtosters.app";
}
}
@@ -1,10 +1,7 @@
package ru.vtosters.lite.tgs;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.aefyr.tsg.g2.TelegramStickersPack;
import com.aefyr.tsg.g2.TelegramStickersService;
import com.vk.dto.common.Attachment;
@@ -15,15 +12,15 @@ import com.vtosters.lite.R;
import com.vtosters.lite.attachments.PendingGraffitiAttachment;
import com.vtosters.lite.im.AppAttachToImAttachConverter;
import com.vtosters.lite.upload.Upload;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.utils.AndroidUtils;
import java.util.List;
import java.util.Stack;
import ru.vtosters.lite.utils.AndroidUtils;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
public class TGRoot {
public static final int N = 76820000;
@@ -32,14 +29,11 @@ public class TGRoot {
private static final String TAG = "TGRoot";
public static String getSummary() {
switch (TGPref.getTGConnectMethod()) {
case 0:
return AndroidUtils.getString(R.string.ctypedirect);
case 2:
return AndroidUtils.getString(R.string.ctypesocks);
default:
return AndroidUtils.getString(R.string.ctypedisabled);
}
return switch (TGPref.getTGConnectMethod()) {
case 0 -> AndroidUtils.getString(R.string.ctypedirect);
case 2 -> AndroidUtils.getString(R.string.ctypesocks);
default -> AndroidUtils.getString(R.string.ctypedisabled);
};
}
public static Attachment processSticker(StickerItem item) {
@@ -101,7 +95,7 @@ public class TGRoot {
}
}
private static StickerStockItem toStickerPack(TelegramStickersPack p) throws JSONException {
public static StickerStockItem toStickerPack(TelegramStickersPack p) throws JSONException {
JSONArray arr = new JSONArray();
for (int j = 0; j < p.stickersCount; j++)
@@ -0,0 +1,157 @@
package ru.vtosters.lite.themes;
import android.content.res.ColorStateList;
import android.graphics.Color;
import java.util.Arrays;
import java.util.List;
import static com.vtosters.lite.R.color.*;
public class ColorReferences {
public static List<Integer> accentColors = Arrays.asList(
Color.parseColor("#3f8ae0"), // azure_300 (light accent)
Color.parseColor("#4986cc"), // azure_a400
Color.parseColor("#528bcc"), // another light accent
Color.parseColor("#71aaeb"), // vk_sky_300 (dark accent)
Color.parseColor("#5181b8"), // header_blue
Color.parseColor("#5a9eff"),
Color.parseColor("#5692d7"),
Color.parseColor("#5c9ce6"),
Color.parseColor("#518bcc"),
Color.parseColor("#74a2d6")
);
public static List<Integer> mutedAccentColors = Arrays.asList(
Color.parseColor("#663f8ae0"),
Color.parseColor("#19528bcc"),
Color.parseColor("#66528bcc"),
Color.parseColor("#1971aaeb"),
Color.parseColor("#665181b8"),
Color.parseColor("#1a003973"),
Color.parseColor("#a800244d"),
Color.parseColor("#14001c3d"),
Color.parseColor("#3d001c3d"),
Color.parseColor("#67a5eb"),
Color.parseColor("#45678f"),
Color.parseColor("#6645678f"),
Color.parseColor("#0099cc"),
Color.parseColor("#664986cc")
);
public static List<Integer> accents = Arrays.asList(
viewer_retry_button_text_color,
azure_300,
picker_camera_button,
music_check_button_bg_pressed,
notification_color,
music_text_counter,
music_follow_button_bg_pressed,
music_blue_button_normal,
music_check_button_bg_normal,
vk_terms_link,
vk_blue_200,
accent_blue,
azure_A400,
vk_azure_A400,
blue,
blue_200,
vk_blue_300,
vk_blue_400,
blue_300,
blue_400,
cool_blue,
cornflower_blue,
cornflower_blue_two,
dot_unread,
fave_promo_btn_pressed,
header_blue,
colorAccent,
live_emoji_butt_hide,
music_action_button_blue,
name,
picker_blue,
picker_blue_pressed,
picker_tab_bg_selected,
picker_tab_text_selected,
sharing_blue_btn_normal,
sharing_blue_btn_pressed,
vk_sky_300,
vk_blue_A400,
blue_A400,
sky_300,
text_blue,
tip_background,
tw__blue_default,
tw__blue_pressed,
vkim_msg_sending_ic,
vkim_playing_drawable_rect,
vk_white_blue32,
date_picker_selector,
post_suggest_blue,
list_dialog_blue,
music_tab_bg_normal,
toolbar_blue_background,
toolbar_blue_statusBarColorBack
);
public static List<Integer> mutedAccents = Arrays.asList(
blue_200_muted,
vk_blue_200_muted,
white_blue32,
vk_white_blue32,
header_blue_opacity16,
black_blue45_alpha10,
music_check_button_bg_checked,
vk_black_blue45_alpha10,
black_blue30_alpha66,
vk_black_blue30_alpha66,
attachpicker_item_background,
black_blue24_alpha8,
music_placeholder_artist_bg,
black_blue24_alpha24,
vk_black_blue24_alpha24,
azure_100_muted,
vk_azure_100_muted,
muted_blue,
blue_600,
light_blue,
vk_blue_600,
muted_blue_opacity40,
muted_blue_old,
darker_blue,
header_blue_opacity40
);
public static boolean isAccentedColor(ColorStateList target) {
return target != null && isAccentedColor(target.getDefaultColor());
}
public static boolean isAccentedColor(int target) {
return accentColors.contains(target);
}
public static boolean isMutedAccentedColor(ColorStateList target) {
return target != null && isMutedAccentedColor(target.getDefaultColor());
}
public static boolean isMutedAccentedColor(int target) {
return mutedAccentColors.contains(target);
}
public static boolean isColorRefAccented(int target) {
return accents.contains(target);
}
public static boolean isColorRefMutedAccented(int target) {
return mutedAccents.contains(target);
}
public static boolean isCslNeedToBeThemed(ColorStateList csl) {
int unsel = csl.getColorForState(new int[]{-android.R.attr.state_selected}, Color.BLACK);
int sel = csl.getColorForState(new int[]{android.R.attr.state_selected}, Color.BLACK);
boolean isUnselAccent = isAccentedColor(unsel);
boolean isSelAccent = isAccentedColor(sel);
return ThemesCore.isCachedAccents() && (isUnselAccent || isSelAccent);
}
}
@@ -0,0 +1,196 @@
package ru.vtosters.lite.themes;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import androidx.annotation.IdRes;
import com.vtosters.lite.R;
import ru.vtosters.lite.utils.ThemesUtils;
public class ThemesCore {
private static final String TAG = "ThemesCore";
public static SparseIntArray themedColors = new SparseIntArray();
public static SparseBooleanArray ACCENT_THEME_ONLY_LIGHT = new SparseBooleanArray();
public static SparseBooleanArray ACCENT_THEME_ONLY_DARK = new SparseBooleanArray();
public static SparseBooleanArray ACCENT_THEME_ONLY_NOMILK_LIGHT = new SparseBooleanArray();
public static SparseBooleanArray ACCENT_THEME_ONLY_NOMILK_DARK = new SparseBooleanArray();
public static SparseBooleanArray ACCENT_THEME_ONLY_MILK_LIGHT = new SparseBooleanArray();
public static SparseBooleanArray ACCENT_THEME_ONLY_MILK_DARK = new SparseBooleanArray();
private static boolean cachedAccents = false;
private static int outgoinging_msg;
private static int outgoinging_msg_highlight;
private static int darken_color;
static {
setExceptions();
setThemedColors(ThemesUtils.getAccentColor());
}
public static void setExceptions() {
ACCENT_THEME_ONLY_LIGHT.clear();
ACCENT_THEME_ONLY_DARK.clear();
ACCENT_THEME_ONLY_NOMILK_LIGHT.clear();
ACCENT_THEME_ONLY_NOMILK_DARK.clear();
ACCENT_THEME_ONLY_MILK_LIGHT.clear();
ACCENT_THEME_ONLY_MILK_DARK.clear();
ACCENT_THEME_ONLY_LIGHT.put(R.attr.attach_picker_tab_active_background, false);
ACCENT_THEME_ONLY_LIGHT.put(R.attr.attach_picker_tab_active_text, false);
ACCENT_THEME_ONLY_LIGHT.put(R.attr.newsfeed_action_color, false);
ACCENT_THEME_ONLY_MILK_LIGHT.put(R.attr.newsfeed_post_title_color, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.newsfeed_post_title_color, false);
ACCENT_THEME_ONLY_MILK_LIGHT.put(R.attr.header_background, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.header_background, false);
ACCENT_THEME_ONLY_MILK_LIGHT.put(R.attr.header_alternate_background, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.header_alternate_background, false);
ACCENT_THEME_ONLY_MILK_LIGHT.put(R.attr.header_background_before_blur, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.header_background_before_blur, false);
ACCENT_THEME_ONLY_MILK_LIGHT.put(R.attr.header_background_before_blur_alternate, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.header_background_before_blur_alternate, false);
ACCENT_THEME_ONLY_NOMILK_LIGHT.put(R.attr.header_tint, false);
ACCENT_THEME_ONLY_NOMILK_LIGHT.put(R.attr.header_tint_alternate, false);
ACCENT_THEME_ONLY_NOMILK_LIGHT.put(R.attr.toolbarIconsColor, false);
ACCENT_THEME_ONLY_NOMILK_LIGHT.put(R.attr.header_tab_active_indicator, false);
ACCENT_THEME_ONLY_NOMILK_LIGHT.put(R.attr.header_alternate_tab_active_indicator, false);
ACCENT_THEME_ONLY_MILK_LIGHT.put(R.attr.im_dropdown_arrow_tint, false);
ACCENT_THEME_ONLY_NOMILK_DARK.put(R.attr.im_dropdown_icon_color, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.icon_name, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.text_name, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.button_primary_background, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.button_secondary_foreground, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.button_tertiary_foreground, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.button_muted_foreground, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.button_outline_border, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.counter_primary_background, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.action_sheet_action_foreground, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.im_bubble_wallpaper_outgoing, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.im_bubble_outgoing, false);
ACCENT_THEME_ONLY_DARK.put(R.attr.im_bubble_outgoing_highlighted, false);
}
public static void setThemedColors(int accentColor) {
int mutedAccentColor = ThemesUtils.getMutedColor(accentColor);
cachedAccents = true;
themedColors.clear();
themedColors.put(R.attr.accent, accentColor);
themedColors.put(R.attr.newsfeed_dropdown_color, accentColor);
themedColors.put(R.attr.icon_name, accentColor);
themedColors.put(R.attr.vk_accent, accentColor);
themedColors.put(R.attr.accentColor, accentColor);
themedColors.put(R.attr.text_name, accentColor);
themedColors.put(R.attr.tabbar_active_icon, accentColor);
// themedColors.put(com.vtosters.lite.R.attr.header_background, accentColor);
// themedColors.put(com.vtosters.lite.R.attr.header_alternate_background, accentColor);
// themedColors.put(com.vtosters.lite.R.attr.header_background_before_blur, accentColor);
// themedColors.put(com.vtosters.lite.R.attr.header_background_before_blur_alternate, accentColor);
themedColors.put(R.attr.header_tint, accentColor);
themedColors.put(R.attr.header_tint_alternate, accentColor);
themedColors.put(R.attr.activity_indicator_tint, accentColor);
themedColors.put(R.attr.toolbarIconsColor, accentColor);
themedColors.put(R.attr.button_primary_background, accentColor);
themedColors.put(R.attr.button_secondary_foreground, accentColor);
themedColors.put(R.attr.button_tertiary_foreground, accentColor);
themedColors.put(R.attr.button_outline_border, accentColor);
themedColors.put(R.attr.button_muted_foreground, accentColor);
themedColors.put(R.attr.header_tab_active_indicator, accentColor);
themedColors.put(R.attr.header_alternate_tab_active_indicator, accentColor);
themedColors.put(R.attr.button_primary_background_disabled, mutedAccentColor);
themedColors.put(R.attr.button_secondary_foreground_disabled, mutedAccentColor);
themedColors.put(R.attr.button_tertiary_foreground_disabled, mutedAccentColor);
themedColors.put(R.attr.button_outline_border_disabled, mutedAccentColor);
themedColors.put(R.attr.button_muted_foreground_disabled, mutedAccentColor);
themedColors.put(R.attr.im_dropdown_icon_color, accentColor);
themedColors.put(R.attr.im_dropdown_arrow_tint, accentColor);
themedColors.put(R.attr.im_attach_tint, accentColor);
themedColors.put(R.attr.im_forward_line_tint, accentColor);
themedColors.put(R.attr.link_alternate, accentColor);
darken_color = ThemesUtils.darken(accentColor, 0.15f);
themedColors.put(R.attr.newsfeed_post_title_color, darken_color);
themedColors.put(R.attr.text_link, accentColor);
themedColors.put(R.attr.attach_picker_tab_active_background, accentColor);
themedColors.put(R.attr.attach_picker_tab_active_text, accentColor);
themedColors.put(R.attr.newsfeed_action_color, accentColor);
themedColors.put(R.attr.counter_primary_background, accentColor);
themedColors.put(R.attr.dynamic_blue, accentColor);
themedColors.put(R.attr.action_sheet_action_foreground, accentColor);
// messages
themedColors.put(R.attr.im_reply_separator, accentColor);
themedColors.put(R.attr.im_text_name, accentColor);
outgoinging_msg = ThemesUtils.lighten(accentColor, 0.76f);
outgoinging_msg_highlight = ThemesUtils.lighten(accentColor, 0.5f);
themedColors.put(R.attr.im_ic_send_msg, accentColor);
themedColors.put(R.attr.im_bubble_wallpaper_outgoing, accentColor);
themedColors.put(R.attr.im_bubble_outgoing, accentColor);
themedColors.put(R.attr.im_bubble_outgoing_highlighted, accentColor);
}
@SuppressLint("NonConstantResourceId")
public static int getThemedAttr(Context context, @IdRes int attr) {
return switch (attr) {
case R.attr.im_bubble_wallpaper_outgoing, R.attr.im_bubble_outgoing -> outgoinging_msg;
case R.attr.im_bubble_outgoing_highlighted -> outgoinging_msg_highlight;
case R.attr.newsfeed_post_title_color -> darken_color;
default -> themedColors.get(attr);
};
}
public static boolean hasThemedAttr(Context context, int attrID) {
// try {
// Log.d(TAG, "Requesting color by attr " + context.getResources().getResourceName(attrID));
// } catch (Exception e) {
// }
if (isCachedAccents()) {
if (ThemesUtils.isDarkTheme()) {
return (themedColors.get(attrID) != 0 && ACCENT_THEME_ONLY_DARK.get(attrID, true) && (
ThemesUtils.isMilkshake() ?
ACCENT_THEME_ONLY_MILK_DARK.get(attrID, true) :
ACCENT_THEME_ONLY_NOMILK_DARK.get(attrID, true)));
} else {
return (themedColors.get(attrID) != 0 && ACCENT_THEME_ONLY_LIGHT.get(attrID, true) && (
ThemesUtils.isMilkshake() ?
ACCENT_THEME_ONLY_MILK_LIGHT.get(attrID, true) :
ACCENT_THEME_ONLY_NOMILK_LIGHT.get(attrID, true)));
}
} else {
return themedColors.get(attrID) != 0;
}
}
public static void clear() {
cachedAccents = false;
themedColors.clear();
}
public static boolean isCachedAccents() {
return cachedAccents;
}
}
@@ -0,0 +1,54 @@
package ru.vtosters.lite.themes;
import android.content.Context;
import android.graphics.drawable.*;
import android.os.Build;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
import com.vtosters.lite.R;
import ru.vtosters.lite.themes.utils.RecolorUtils;
import ru.vtosters.lite.utils.ThemesUtils;
public class ThemesHacks {
// Фиксит селектор (все/свои/архив) в профиле
public static void fixProfileSelector(View view) {
if (!ThemesUtils.isMilkshake()) return;
var id = view.getId();
if (id == R.id.profile_wall_owner_posts || id == R.id.profile_wall_all_posts || id == R.id.profile_wall_archived_posts) {
StateListDrawable states = (StateListDrawable) ((LayerDrawable) view.getBackground()).getDrawable(0);
LayerDrawable selected = (LayerDrawable) ((DrawableContainer.DrawableContainerState) states.getConstantState()).getChildren()[0];
((ColorDrawable) selected.getDrawable(0)).setColor(ThemesUtils.getAccentColor());
}
}
public static void fixThemedFeed(TextView textView, int i) {
if (i != R.layout.themed_feed_tab_2) {
return;
}
textView.setTextColor(RecolorUtils.recolorCSL(textView.getTextColors()));
((InsetDrawable) ((DrawableContainer.DrawableContainerState) textView.getBackground().getConstantState()).getChildren()[0]).getDrawable().setTint(ThemesUtils.lighten(ThemesUtils.getAccentColor(), 0.15f));
}
public static void fixDropdown(Drawable drawable) {
if (!ThemesUtils.isDarkTheme() && ThemesUtils.isMilkshake() && ThemesCore.isCachedAccents()) {
StateListDrawable stateListDrawable = (StateListDrawable) drawable;
((DrawableContainer.DrawableContainerState) stateListDrawable.getConstantState()).getChildren()[0].setTint(ThemesUtils.getAccentColor());
((DrawableContainer.DrawableContainerState) stateListDrawable.getConstantState()).getChildren()[1].setTint(ThemesUtils.halfAlpha(ThemesUtils.getAccentColor()));
}
}
public static int getHackedColor(@NonNull Context context, @ColorRes int color) {
if (ThemesCore.isCachedAccents() && ColorReferences.isAccentedColor(context.getResources().getColor(color))) {
return ThemesUtils.getAccentColor();
}
if (ThemesCore.isCachedAccents() && ColorReferences.isMutedAccentedColor(context.getResources().getColor(color))) {
return ThemesUtils.getMutedAccentColor();
}
return Build.VERSION.SDK_INT > 23 ? context.getColor(color) : context.getResources().getColor(color);
}
}
@@ -0,0 +1,92 @@
package ru.vtosters.lite.themes;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import androidx.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import ru.vtosters.lite.utils.ThemesUtils;
public class VTLResources extends Resources {
private static final String TAG = "VTLResources";
private final Context context;
private static Field typedArrayField;
private static final List<Integer> attributesToTheme = new ArrayList<>();
static {
try {
typedArrayField = TypedArray.class.getDeclaredField("mData");
typedArrayField.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
attributesToTheme.add(16843041);
attributesToTheme.add(android.R.attr.backgroundTint);
attributesToTheme.add(16843173);
}
public VTLResources(Context context, Resources parent) {
super(parent.getAssets(), parent.getDisplayMetrics(), parent.getConfiguration());
this.context = context;
// Log.d(TAG, "VTLResources: init");
}
@Override
public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
var typedArray = super.obtainAttributes(set, attrs);
var data = getArrayData(typedArray);
for (int i = 0; i < attrs.length; i++) {
try {
int attrID = attrs[i];
if (attributesToTheme.contains(attrID)) {
int type = data[i*6];
int cnt = data[(i*6)+1];
if (type == TypedValue.TYPE_ATTRIBUTE && isAttrThemeable(cnt)) {
data[i*6] = TypedValue.TYPE_INT_COLOR_RGB8;
data[(i*6)+1] = ThemesUtils.getAccentColor();
data[(i*6)+2] = 0; // clear reference content
}
}
} catch (Exception e) {
Log.e(TAG, "TAVzlom failed! (obtainAttributes)");
e.printStackTrace();
}
}
return typedArray;
}
@Override
public Drawable getDrawable(int id, @Nullable Theme theme) throws NotFoundException {
var drawable = super.getDrawable(id, theme);
if (id == com.vtosters.lite.R.drawable.newsfeed_tab_dropdown_16) {
ThemesHacks.fixDropdown(drawable);
}
return drawable;
}
private static boolean isAttrThemeable(int attrID) {
return !ThemesUtils.isDarkTheme() && attrID == com.vtosters.lite.R.attr.button_primary_background;
}
private static int[] getArrayData(TypedArray arr) {
try {
return (int[]) typedArrayField.get(arr);
} catch (IllegalAccessException e) {
Log.e(TAG, "getArrayData: ", e);
e.printStackTrace();
return new int[0];
}
}
}
@@ -0,0 +1,43 @@
package ru.vtosters.lite.themes;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import ru.vtosters.lite.themes.hooks.BaseHook;
import ru.vtosters.lite.themes.hooks.ButtonHook;
import ru.vtosters.lite.themes.hooks.ImageViewHook;
import ru.vtosters.lite.themes.hooks.ProgressWheelHook;
import ru.vtosters.lite.themes.hooks.TabLayoutHook;
import ru.vtosters.lite.themes.hooks.TextViewHook;
import ru.vtosters.lite.themes.hooks.ToolbarHook;
import ru.vtosters.lite.themes.hooks.VKImageViewHook;
public class ViewInjector {
public static ArrayList<BaseHook> hooks = new ArrayList<>();
static {
hooks.add(new ButtonHook());
hooks.add(new ImageViewHook());
hooks.add(new TabLayoutHook());
hooks.add(new TextViewHook());
hooks.add(new ToolbarHook());
hooks.add(new VKImageViewHook());
hooks.add(new ProgressWheelHook());
}
public static View inject(View view, int i, boolean z) {
for (BaseHook hook : hooks) {
hook.inject(view, i, z);
}
if (view instanceof ViewGroup) {
var viewGroup = (ViewGroup) view;
for (int i2 = 0; i2 < viewGroup.getChildCount(); i2++) {
inject(viewGroup.getChildAt(i2), i, false);
}
}
return view;
}
}
@@ -0,0 +1,7 @@
package ru.vtosters.lite.themes.hooks;
import android.view.View;
public interface BaseHook {
void inject(View view, int i, boolean z);
}
@@ -0,0 +1,29 @@
package ru.vtosters.lite.themes.hooks;
import android.content.res.ColorStateList;
import android.view.View;
import android.widget.Button;
import ru.vtosters.lite.themes.ColorReferences;
import ru.vtosters.lite.utils.ThemesUtils;
public class ButtonHook implements BaseHook {
@Override
public void inject(View view, int i, boolean z) {
if (view instanceof Button) {
var button = (Button) view;
if (button.getBackgroundTintList() != null && ColorReferences.isMutedAccentedColor(button.getBackgroundTintList())) {
button.setBackgroundTintList(ColorStateList.valueOf(ThemesUtils.getMutedAccentColor()));
}
if (button.getBackgroundTintList() != null && ColorReferences.isAccentedColor(button.getBackgroundTintList())) {
button.setBackgroundTintList(ColorStateList.valueOf(ThemesUtils.getAccentColor()));
}
if (TextViewHook.isPositiveButton(button) || TextViewHook.isVkUiButton(view)) {
button.setBackgroundTintList(ColorStateList.valueOf(ThemesUtils.getAccentColor()));
}
}
}
}
@@ -0,0 +1,24 @@
package ru.vtosters.lite.themes.hooks;
import android.content.res.ColorStateList;
import android.view.View;
import android.widget.ImageView;
import ru.vtosters.lite.themes.ColorReferences;
import ru.vtosters.lite.themes.ThemesCore;
import ru.vtosters.lite.utils.ThemesUtils;
public class ImageViewHook implements BaseHook {
@Override
public void inject(View view, int i, boolean z) {
if (view instanceof ImageView) {
if (ThemesCore.isCachedAccents()) {
var imageView = (ImageView) view;
if (imageView.getImageTintList() == null) return;
if (ColorReferences.isCslNeedToBeThemed(imageView.getImageTintList())) {
imageView.setImageTintList(ColorStateList.valueOf(ThemesUtils.getAccentColor()));
}
}
}
}
}
@@ -0,0 +1,21 @@
package ru.vtosters.lite.themes.hooks;
import android.view.View;
import com.pnikosis.materialishprogress.ProgressWheel;
import ru.vtosters.lite.themes.ThemesCore;
import ru.vtosters.lite.utils.ThemesUtils;
public class ProgressWheelHook implements BaseHook {
@Override
public void inject(View view, int i, boolean z) {
if (view instanceof ProgressWheel) {
if (ThemesCore.isCachedAccents()) {
var progressWheel = (ProgressWheel) view;
progressWheel.setBarColor(ThemesUtils.getAccentColor());
}
}
}
}
@@ -0,0 +1,21 @@
package ru.vtosters.lite.themes.hooks;
import android.content.res.ColorStateList;
import android.view.View;
import com.vk.core.view.VKTabLayout;
import ru.vtosters.lite.utils.ThemesUtils;
public class TabLayoutHook implements BaseHook {
@Override
public void inject(View view, int i, boolean z) {
if (view instanceof VKTabLayout) {
var tabLayout = (VKTabLayout) view;
tabLayout.setSelectedTabIndicatorColor(ThemesUtils.getAccentColor());
tabLayout.setTabRippleColor(ColorStateList.valueOf(ThemesUtils.getAccentColor()));
}
}
}

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