0
0
Fork 0
mirror of https://github.com/YTVanced/VancedManager synced 2024-11-18 01:05:10 +00:00

Compare commits

...

610 commits
v2.3.0 ... dev

Author SHA1 Message Date
KevinX8
8b3f2c5e2e
New Crowdin updates (#700)
* New translations strings.xml (Indonesian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Persian)

* New translations strings.xml (Persian)

* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* New translations strings.xml (Russian)

* New translations strings.xml (Russian)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Russian)

* New translations strings.xml (Russian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Bengali)

* New translations strings.xml (German)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Filipino)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (German)

* New translations strings.xml (Russian)

* New translations strings.xml (Belarusian)

* New translations strings.xml (Belarusian)

* New translations strings.xml (Belarusian)

* New translations strings.xml (Odia)

* New translations strings.xml (Odia)

* New translations strings.xml (German)

* New translations strings.xml (Finnish)
2022-03-14 01:11:33 +00:00
Xinto
7421ed9462
Merge pull request #797 from BioGeek/dev
Fix typo
2022-02-27 00:48:22 +04:00
Jeroen Van Goey
2ded1e87dd
Fix typo
user-freindly -> user-friendly
2022-02-17 15:13:12 +01:00
Xinto
dcc3ad9a55
Merge pull request #783 from zamansoum/dev
Added Google Advanced Protection Program instructions
2022-02-04 14:09:15 +04:00
AmineMansoum
42bb94bd84
Fix Typos 2022-02-02 13:08:58 -05:00
AmineMansoum
0db7ddd83a
Added Google Advanced Protection Program notice 2022-02-02 13:07:32 -05:00
Xinto
fc9da62528
Merge pull request #782 from AlphaVS-76/patch-3
Update README.md
2022-02-01 10:19:05 +04:00
Vaibhav Sharma
dd9ffeca18
Update README.md 2022-02-01 09:43:36 +05:30
Xinto
a2720c00fd
Merge pull request #781 from zamansoum/dev
Vanced FAQ not available on the playstore anymore
2022-01-31 12:58:07 +04:00
AmineMansoum
a2d6c1b9de
Vanced FAQ not available on the playstore anymore 2022-01-30 18:33:18 -05:00
Xinto
a170835b1d
Merge pull request #721 from NotWoods/autoupdate
Add background updates on Android 12
2021-10-27 00:29:50 -07:00
Tiger Oakes
9ca0fb789b Updated installSplitApks 2021-10-26 20:11:38 -07:00
Xinto
eb28c6163c
Merge pull request #724 from NotWoods/viewmodel-no-leak
Remove HomeViewModel memory leak
2021-10-25 02:17:33 -07:00
Tiger Oakes
368808de0c Remove viewmodel memory leak 2021-10-24 23:36:47 -07:00
Tiger Oakes
4af47e8de0 Remove lifecycleOwner parameter from DataModel 2021-10-24 13:13:03 -07:00
Tiger Oakes
9a14d0f10c Add background updates on Android 12 2021-10-23 19:21:29 -07:00
X1nto
25f8f800ea update templates 2021-10-11 17:34:57 +04:00
X1nto
851727a1c1 bumped up version 2021-10-11 15:01:38 +04:00
X1nto
7c1dbb654a small optimization 2021-10-11 15:01:15 +04:00
X1nto
7c1392de94 preheat the shell in splash screen 2021-10-11 15:01:07 +04:00
X1nto
9a31f2b7e3 disable busybox 2021-10-11 15:00:51 +04:00
X1nto
f887ba5d6c root installer improvements 2021-10-11 15:00:25 +04:00
X1nto
ec17869600 Merge branch 'dev' of https://github.com/YTVanced/VancedManager into dev 2021-10-08 22:58:34 +04:00
X1nto
17f3af190f removed guide button 2021-10-08 22:58:23 +04:00
KevinX8
4eae61e7a6 update deps 2021-10-08 21:57:08 +03:00
X1nto
36fc660811 cleanup 2021-10-08 19:22:44 +04:00
X1nto
f882e05965 updated buildscript 2021-10-08 19:10:32 +04:00
X1nto
e7c6d2dc3d updated bottom sheet fragments 2021-10-08 19:10:24 +04:00
X1nto
bbe993edf7 Merge branch 'dev' of https://github.com/YTVanced/VancedManager into dev 2021-10-08 17:55:28 +04:00
X1nto
9358447838 import cleanup 2021-10-08 17:55:18 +04:00
KevinX8
f110dc6a14
New Crowdin updates (#694)
* New translations strings.xml (Filipino)

* New translations strings.xml (Filipino)

* New translations strings.xml (Romanian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Tamil)

* New translations strings.xml (Bengali)

* New translations strings.xml (Marathi)

* New translations strings.xml (Thai)

* New translations strings.xml (Estonian)

* New translations strings.xml (Russian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Hindi)

* New translations strings.xml (Filipino)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Sinhala)

* New translations strings.xml (Bengali, India)

* New translations strings.xml (Kurmanji (Kurdish))

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Pashto)

* New translations strings.xml (Somali)

* New translations strings.xml (Swedish)

* New translations strings.xml (Portuguese)

* New translations strings.xml (French)

* New translations strings.xml (Danish)

* New translations strings.xml (Slovak)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Punjabi)

* New translations strings.xml (Spanish)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Arabic)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Catalan)

* New translations strings.xml (German)

* New translations strings.xml (Polish)

* New translations strings.xml (Greek)

* New translations strings.xml (Finnish)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Italian)

* New translations strings.xml (Japanese)

* New translations strings.xml (Georgian)

* New translations strings.xml (Korean)

* New translations strings.xml (Lithuanian)

* New translations strings.xml (Dutch)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Punjabi, Pakistan)

* New translations strings.xml (Spanish)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Dutch)

* New translations strings.xml (Slovak)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Filipino)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Japanese)

* New translations strings.xml (Filipino)

* New translations strings.xml (Arabic)

* New translations strings.xml (Italian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Polish)

* New translations strings.xml (German)

* New translations strings.xml (German)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Odia)

* New translations strings.xml (Turkish)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Finnish)

* New translations strings.xml (Russian)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Finnish)

* New translations strings.xml (Tamil)

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Thai)

* New translations strings.xml (Thai)

* New translations strings.xml (Thai)

* New translations strings.xml (German)

* New translations strings.xml (Danish)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Thai)

* New translations strings.xml (Croatian)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Hindi)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Slovak)

* New translations strings.xml (Spanish)

* New translations strings.xml (Thai)
2021-10-08 06:52:35 -07:00
Xinto
ad97dab04a
Merge pull request #632 from RDKRACZ/oxi
Optimize assets.
2021-10-08 06:37:50 -07:00
X1nto
6ed72d3b65 bundle busybox 2021-10-08 17:31:47 +04:00
X1nto
ccd82f3bce fix unresolved references 2021-10-08 17:31:29 +04:00
X1nto
e787217bf2 fix save button going offscreen when list is too large 2021-10-08 17:11:55 +04:00
X1nto
0a87f0d81c add config file 2021-10-08 17:01:07 +04:00
X1nto
0db9faad94 switch to github issue forms 2021-10-08 16:58:15 +04:00
X1nto
a70d731ec4 update workflow 2021-10-08 16:19:46 +04:00
X1nto
ce18bb0963 updated flexbox 2021-10-08 16:18:58 +04:00
X1nto
a101e3a79f updated buildscript for subprojects 2021-10-08 16:17:08 +04:00
X1nto
b1a51f837f replace jcenter with maven central 2021-10-08 16:04:50 +04:00
X1nto
02f7fe62ba declare array as nullable 2021-10-08 15:58:07 +04:00
X1nto
4a50b27812 bump up version 2021-10-08 15:45:34 +04:00
X1nto
465d9f4fdb buildscript cleanup 2021-10-08 15:45:11 +04:00
X1nto
5ef967f097 fuck crowdin 2021-10-08 15:19:15 +04:00
X1nto
7fca85be14 finish the uninstall dialog 2021-10-08 15:13:07 +04:00
X1nto
1cd0294801 android 12 crash fixes 2021-10-08 15:05:46 +04:00
X1nto
715eb9cf7a android 12 2021-10-08 14:48:32 +04:00
X1nto
46cb058cab dependency updates 2021-10-08 14:21:44 +04:00
K0RR
697fbf5ea7 Optimize assets.
Lossless compression.
2021-08-02 15:00:27 +02:00
KevinX8
bd04fddeb0 fix build error 2021-06-03 12:40:53 +01:00
Tornike Khintibidze
1e0c187b43
Merge pull request #570 from seahindeniz/dev
Fix some strings
2021-06-03 14:59:59 +04:00
Sahin Deniz
d23f9a7bcf Add new line 🙂 2021-06-03 13:48:36 +03:00
Sahin Deniz
be35498e65 Ignore .vscode folder 2021-06-03 13:46:54 +03:00
Sahin Deniz
6445564c85 Capitalize "just" 2021-06-03 13:45:55 +03:00
Sahin Deniz
bb100aeefd Capitalize "apk" 2021-06-03 13:45:04 +03:00
Sahin Deniz
1759c01e98 Decapitalize "project" 2021-06-03 13:43:18 +03:00
KevinX8
956d8800e9
New Crowdin updates (#568)
* New translations strings.xml (Romanian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Tamil)

* New translations strings.xml (Bengali)

* New translations strings.xml (Marathi)

* New translations strings.xml (Thai)

* New translations strings.xml (Estonian)

* New translations strings.xml (Russian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Hindi)

* New translations strings.xml (Filipino)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Sinhala)

* New translations strings.xml (Bengali, India)

* New translations strings.xml (Kurmanji (Kurdish))

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Pashto)

* New translations strings.xml (Somali)

* New translations strings.xml (Swedish)

* New translations strings.xml (Portuguese)

* New translations strings.xml (French)

* New translations strings.xml (Danish)

* New translations strings.xml (Slovak)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Punjabi)

* New translations strings.xml (Spanish)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Arabic)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Catalan)

* New translations strings.xml (Czech)

* New translations strings.xml (German)

* New translations strings.xml (Polish)

* New translations strings.xml (Greek)

* New translations strings.xml (Finnish)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Italian)

* New translations strings.xml (Japanese)

* New translations strings.xml (Georgian)

* New translations strings.xml (Korean)

* New translations strings.xml (Lithuanian)

* New translations strings.xml (Dutch)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Punjabi, Pakistan)
2021-06-01 20:39:46 +01:00
Tornike Khintibidze
a7ee51a90b
Merge pull request #562 from cl-ement05/dev
Minor UI/UX improvements (show changelog after update + show pathy of saved log file)
2021-05-29 17:39:47 +04:00
cl-ement05
f98c21ddbe revert back to first version 2021-05-29 15:34:05 +02:00
cl-ement05
d7dfb27ca5 set default value to VERSION_CODE and removed useless blocks 2021-05-29 14:35:39 +02:00
cl-ement05
b9820468c6 very small UI improvement (show log save location) 2021-05-28 23:02:13 +02:00
cl-ement05
1ea32c75ff show changelog after app update 2021-05-28 15:11:34 +02:00
X1nto
e6f04a95c8 Merge branch 'dev' of https://github.com/YTVanced/VancedManager into dev 2021-05-24 21:57:37 +04:00
X1nto
9346324ec5 updated issue templates 2021-05-24 21:57:27 +04:00
Tornike Khintibidze
4167aa422e
Merge pull request #551 from atahabaki/splash-screen-bg-fix-469
Splash screen background color (fix for #469)
2021-05-13 13:07:10 +04:00
A. Taha Baki
58a0b06b92 night theme splash color => #000... 2021-05-12 23:33:38 +03:00
A. Taha Baki
b53d9f35cc light theme splash color => #cfcfcf... 2021-05-12 23:33:05 +03:00
Tornike Khintibidze
1150f5800b
Merge pull request #544 from sudo-nautilus/dev
Ignore Markdown Files While Pushing Or Pull Requesting
2021-05-08 12:01:39 +04:00
Nautilus
cd7c05d25a
Merge pull request #1 from sudo-nautilus/workflow-patch
Ignore Markdown Files While Pushing Or Pull Request
2021-05-08 08:38:26 +05:30
Nautilus
04d3500bb0
Ignore .md files while pushing or pull request 2021-05-08 08:34:58 +05:30
Tornike Khintibidze
0e93d2091a
Merge pull request #540 from sudo-nautilus/dev
Beautify Readme
2021-05-06 16:08:02 +04:00
Nautilus
df56ee8f04
Hotfix V2 2021-05-06 17:37:52 +05:30
Nautilus
bfd8a0e1ef
OwO Hotfix Badge Alignment 2021-05-06 17:34:20 +05:30
Nautilus
ecca7dfcba
OwO-Ify V2
UwU Buttons And Playstore Button
2021-05-06 17:31:50 +05:30
Nautilus
c4ae3887fb
Revet To Orginal Readme 2021-05-06 17:16:43 +05:30
Nautilus
f15dcdfaef
OwO-Ify 2021-05-06 10:51:06 +05:30
X1nto
81f8c7a036 updated bug template 2021-05-01 19:16:31 +04:00
X1nto
c69bccfc99 updated bug template 2021-05-01 19:11:58 +04:00
Tornike Khintibidze
c5a92d51b2
Merge pull request #523 from cl-ement05/dev
added an AppUninstallDialog
2021-04-29 12:19:17 +04:00
cl-ement05
69e0221e82 added an AppUninstallDialog 2021-04-28 16:30:42 +02:00
KevinX8
96a69144fe Updated deps 2021-04-27 13:20:06 +01:00
KevinX8
d8fc45dd39
New Crowdin updates (#515)
* New translations strings.xml (Arabic)

* New translations strings.xml (Greek)

* New translations strings.xml (Dutch)

* New translations strings.xml (Turkish)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Indonesian)
2021-04-27 12:23:57 +01:00
Tornike Khintibidze
ffdc76a2ca
Merge pull request #512 from YTVanced/l10n_dev
New Crowdin updates
2021-04-27 10:23:22 +04:00
KevinX8
88c3a3b12b New translations strings.xml (Polish) 2021-04-26 23:12:38 +01:00
KevinX8
28346f7ae3 New translations strings.xml (Korean) 2021-04-26 23:12:34 +01:00
KevinX8
f92061f54d New translations strings.xml (Slovak) 2021-04-26 23:12:31 +01:00
KevinX8
822d7bdb78 New translations strings.xml (Arabic) 2021-04-26 23:12:24 +01:00
KevinX8
a420ab2d79 New translations strings.xml (Portuguese, Brazilian) 2021-04-26 23:12:08 +01:00
KevinX8
822b900396 New translations strings.xml (Lithuanian) 2021-04-26 21:36:32 +01:00
KevinX8
5a2be52767 New translations strings.xml (Russian) 2021-04-26 21:36:31 +01:00
KevinX8
f6231f809c New translations strings.xml (Portuguese) 2021-04-26 21:36:30 +01:00
KevinX8
24cac1920f New translations strings.xml (Polish) 2021-04-26 21:36:28 +01:00
KevinX8
835f84078b New translations strings.xml (Punjabi) 2021-04-26 21:36:27 +01:00
KevinX8
00896b77c3 New translations strings.xml (Norwegian) 2021-04-26 21:36:26 +01:00
KevinX8
c40c83d91c New translations strings.xml (Dutch) 2021-04-26 21:36:25 +01:00
KevinX8
48632c3d2a New translations strings.xml (Kurdish) 2021-04-26 21:36:24 +01:00
KevinX8
ab6beff186 New translations strings.xml (Korean) 2021-04-26 21:36:23 +01:00
KevinX8
ac8f5f6540 New translations strings.xml (Georgian) 2021-04-26 21:36:21 +01:00
KevinX8
de8c0a7ac7 New translations strings.xml (Japanese) 2021-04-26 21:36:20 +01:00
KevinX8
0a7f579063 New translations strings.xml (Italian) 2021-04-26 21:36:19 +01:00
KevinX8
487dc15c2a New translations strings.xml (Slovak) 2021-04-26 21:36:18 +01:00
KevinX8
afe6ec2f07 New translations strings.xml (Hungarian) 2021-04-26 21:36:17 +01:00
KevinX8
521495eaa8 New translations strings.xml (Finnish) 2021-04-26 21:36:16 +01:00
KevinX8
10c683a66c New translations strings.xml (Greek) 2021-04-26 21:36:15 +01:00
KevinX8
287b169bc9 New translations strings.xml (German) 2021-04-26 21:36:14 +01:00
KevinX8
b3db04e96e New translations strings.xml (Danish) 2021-04-26 21:36:12 +01:00
KevinX8
48dbb7527b New translations strings.xml (Czech) 2021-04-26 21:36:11 +01:00
KevinX8
b6e53bafa4 New translations strings.xml (Catalan) 2021-04-26 21:36:10 +01:00
KevinX8
a7107e4427 New translations strings.xml (Bulgarian) 2021-04-26 21:36:09 +01:00
KevinX8
91f40ad846 New translations strings.xml (Arabic) 2021-04-26 21:36:07 +01:00
KevinX8
2c3cdd0697 New translations strings.xml (Afrikaans) 2021-04-26 21:36:06 +01:00
KevinX8
606664cf39 New translations strings.xml (Spanish) 2021-04-26 21:36:05 +01:00
KevinX8
4e776e78ca New translations strings.xml (Hebrew) 2021-04-26 21:36:04 +01:00
KevinX8
bfb094f6b3 New translations strings.xml (French) 2021-04-26 21:36:03 +01:00
KevinX8
f9c40b12b2 New translations strings.xml (Serbian (Cyrillic)) 2021-04-26 21:36:01 +01:00
KevinX8
4adfb9db3c New translations strings.xml (Turkish) 2021-04-26 21:36:00 +01:00
KevinX8
f248bdba62 New translations strings.xml (Punjabi, Pakistan) 2021-04-26 21:35:59 +01:00
KevinX8
cd3a419326 New translations strings.xml (Somali) 2021-04-26 21:35:58 +01:00
KevinX8
ac09ae3c58 New translations strings.xml (Pashto) 2021-04-26 21:35:56 +01:00
KevinX8
e43bef60e5 New translations strings.xml (Sorani (Kurdish)) 2021-04-26 21:35:55 +01:00
KevinX8
0a354f4e3d New translations strings.xml (Kurmanji (Kurdish)) 2021-04-26 21:35:54 +01:00
KevinX8
2a1fc505ea New translations strings.xml (Bengali, India) 2021-04-26 21:35:53 +01:00
KevinX8
0e0ed12401 New translations strings.xml (Sinhala) 2021-04-26 21:35:51 +01:00
KevinX8
431139eb6b New translations strings.xml (Malayalam) 2021-04-26 21:35:50 +01:00
KevinX8
56a3850b5e New translations strings.xml (Filipino) 2021-04-26 21:35:49 +01:00
KevinX8
c1cb75afe6 New translations strings.xml (Hindi) 2021-04-26 21:35:48 +01:00
KevinX8
3620438efb New translations strings.xml (Azerbaijani) 2021-04-26 21:35:46 +01:00
KevinX8
33bfedfdf2 New translations strings.xml (Swedish) 2021-04-26 21:35:45 +01:00
KevinX8
01fadc6854 New translations strings.xml (Estonian) 2021-04-26 21:35:44 +01:00
KevinX8
b0d9611056 New translations strings.xml (Thai) 2021-04-26 21:35:43 +01:00
KevinX8
b264c13623 New translations strings.xml (Marathi) 2021-04-26 21:35:42 +01:00
KevinX8
5b78a5b4b7 New translations strings.xml (Bengali) 2021-04-26 21:35:41 +01:00
KevinX8
1aff587b09 New translations strings.xml (Tamil) 2021-04-26 21:35:39 +01:00
KevinX8
b89e6d01c8 New translations strings.xml (Indonesian) 2021-04-26 21:35:38 +01:00
KevinX8
de94258b11 New translations strings.xml (Portuguese, Brazilian) 2021-04-26 21:35:37 +01:00
KevinX8
5f87878d94 New translations strings.xml (Vietnamese) 2021-04-26 21:35:36 +01:00
KevinX8
0969b8d744 New translations strings.xml (Chinese Traditional) 2021-04-26 21:35:35 +01:00
KevinX8
fac5ec0f1b New translations strings.xml (Chinese Simplified) 2021-04-26 21:35:34 +01:00
KevinX8
5914932728 New translations strings.xml (Ukrainian) 2021-04-26 21:35:32 +01:00
KevinX8
b119be8bbf New translations strings.xml (Croatian) 2021-04-26 21:35:31 +01:00
KevinX8
24424c1d52 New translations strings.xml (Romanian) 2021-04-26 21:35:30 +01:00
X1nto
9db254d2f2 fixed version code comparison 2021-04-27 00:27:11 +04:00
X1nto
9368af2187 removed microg bug dialog 2021-04-26 23:40:53 +04:00
X1nto
f1b6519825 removed path prefix for api urls 2021-04-26 23:11:53 +04:00
X1nto
96d01de045 updated icons in expandable app item 2021-04-26 23:08:39 +04:00
X1nto
5b2c8ce671 improved layout flexibility 2021-04-26 23:00:42 +04:00
X1nto
f0f98b40b6 fixed lint for core-ui 2021-04-20 18:38:05 +04:00
X1nto
135454645a removed unecessary path from file_provider 2021-04-20 18:36:26 +04:00
X1nto
8bdeff3c83 fixed dark overlay not disappearing after bottom dialog has been dismissed 2021-04-20 18:08:55 +04:00
X1nto
33d059d002 removed unused event file 2021-04-19 19:57:51 +04:00
X1nto
82ba0b2615 cleanup 2021-04-19 19:57:14 +04:00
X1nto
108ca5ae5d use storage perms only on android 5 2021-04-19 19:52:12 +04:00
X1nto
4086b1150b updated base url 2021-04-19 19:50:56 +04:00
X1nto
b84a2bd930 updated readme 2021-04-18 22:01:52 +04:00
X1nto
a14eeda825 prevent stacktrace ovfuscation 2021-04-18 15:45:28 +04:00
X1nto
5d63aaf510 reverted all storage-related commits 2021-04-18 15:42:23 +04:00
X1nto
a570aae1a1 Revert "Added an option to switch between internal and external storage"
This reverts commit 98c4b88961.
2021-04-18 15:31:54 +04:00
X1nto
f82dc4eecf Revert "added back a fix for split installer"
This reverts commit aeaa0d445e.
2021-04-18 15:30:24 +04:00
X1nto
29158e7c9a Revert "prevent stacktrace from obfuscating"
This reverts commit 2d30eb60af.
2021-04-18 15:28:32 +04:00
X1nto
ebf9e8031b added -r option for root music installer 2021-04-18 14:58:04 +04:00
X1nto
aeaa0d445e added back a fix for split installer 2021-04-18 14:56:51 +04:00
X1nto
4b645ef1c0 removed warning for music vanced 2021-04-18 14:35:44 +04:00
X1nto
98c4b88961 Added an option to switch between internal and external storage 2021-04-18 14:22:54 +04:00
X1nto
2d30eb60af prevent stacktrace from obfuscating 2021-04-18 12:48:03 +04:00
X1nto
e08f6513cf Updated build instructions 2021-04-17 20:19:25 +04:00
X1nto
65f6a1c8d3 Added build section to readme 2021-04-17 20:16:22 +04:00
X1nto
7550c37fb6 fixed readme 2021-04-17 20:06:53 +04:00
X1nto
39b9b981ca updated readme 2021-04-17 20:04:45 +04:00
X1nto
4fee34b661 fixed buttontag getter 2021-04-17 13:28:36 +04:00
X1nto
c1770e2217 moved splash screen activity to parent dir 2021-04-17 13:24:35 +04:00
X1nto
af3937e23f preview adjustments to navigation xml 2021-04-17 13:23:30 +04:00
X1nto
7e3edb9cb6 Added button info on long press 2021-04-17 13:16:46 +04:00
X1nto
b5b577cf8b Merge branch 'dev' of https://github.com/YTVanced/VancedManager into dev 2021-04-16 17:57:48 +04:00
KevinX8
3d8886359c
New Crowdin updates (#489)
* New translations strings.xml (Romanian)

* New translations strings.xml (Bengali)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Swedish)

* New translations strings.xml (Turkish)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Tamil)

* New translations strings.xml (Marathi)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Thai)

* New translations strings.xml (Croatian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Hindi)

* New translations strings.xml (Filipino)

* New translations strings.xml (Sinhala)

* New translations strings.xml (Bengali, India)

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Pashto)

* New translations strings.xml (Somali)

* New translations strings.xml (Russian)

* New translations strings.xml (Polish)

* New translations strings.xml (Arabic)

* New translations strings.xml (Spanish)

* New translations strings.xml (Slovak)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Japanese)

* New translations strings.xml (Estonian)

* New translations strings.xml (French)

* New translations strings.xml (Kurdish)

* New translations strings.xml (Kurmanji (Kurdish))

* New translations strings.xml (Hungarian)

* New translations strings.xml (Finnish)

* New translations strings.xml (Korean)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Punjabi)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Catalan)

* New translations strings.xml (Czech)

* New translations strings.xml (Danish)

* New translations strings.xml (German)

* New translations strings.xml (Greek)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Italian)

* New translations strings.xml (Georgian)

* New translations strings.xml (Dutch)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Punjabi, Pakistan)
2021-04-13 13:39:22 +01:00
X1nto
c0d2dd6aa9 fixed crash on manager update 2021-04-13 16:03:10 +04:00
X1nto
1a4504de1c updated version 2021-04-13 14:47:06 +04:00
X1nto
e2a6f056c9 bumped up dependencies 2021-04-13 14:45:38 +04:00
X1nto
982fff9989 improved layouts to look more close to each other 2021-04-13 14:28:00 +04:00
X1nto
0673920103 sorted strings xml 2021-04-13 14:22:16 +04:00
X1nto
e73b56ed4d require external storage 2021-04-13 14:18:53 +04:00
X1nto
1c3ab835a6 only run 1 animation at once 2021-03-20 10:36:44 +04:00
X1nto
16e7d1586d always notify about miui error 2021-03-13 14:15:02 +04:00
X1nto
140a3ebf4b updated strings 2021-03-13 14:14:08 +04:00
X1nto
f7d90b7c59 added a check for session id in root installer 2021-03-07 21:59:52 +04:00
X1nto
85e2d0c5c2 fixed viewpager navigation on RTL layout 2021-03-07 15:20:19 +04:00
X1nto
6c506c989c Merge branch 'dev' of https://github.com/YTVanced/VancedManager into dev 2021-03-01 22:55:45 +04:00
X1nto
38860ace07 fixed #435 2021-03-01 22:51:15 +04:00
X1nto
e11d918a82 fixed #437 2021-03-01 22:50:24 +04:00
X1nto
22d67b51c3 bumped up kotlin to 1.4.31 2021-02-28 17:29:10 +04:00
X1nto
5583674974 fixed changelog not appearing when pressing card in about menu 2021-02-28 17:10:18 +04:00
X1nto
ad17c6dfec added progress indicators to download dialogs 2021-02-28 15:49:06 +04:00
X1nto
ad299ed96d small accent update 2021-02-28 15:05:42 +04:00
X1nto
3525ef88c1 property access syntax goes brrrrr 2021-02-28 15:02:01 +04:00
X1nto
1f600430ea optimised lifecycleOwner getter 2021-02-28 14:58:34 +04:00
X1nto
18cad94748 removed useless check inside 'when' statement 2021-02-28 14:23:55 +04:00
X1nto
ae37a1e406 updated old stuff 2021-02-28 14:17:46 +04:00
X1nto
2e3416ef43 reference accent color variable instead of getting preference value every time 2021-02-28 14:13:21 +04:00
X1nto
4fcfe72a0f kotlin extensions are stonks 2021-02-28 13:52:02 +04:00
X1nto
b7a5741f70 removed useless attribute 2021-02-27 23:46:01 +04:00
X1nto
ff8177e147 removed unnoticable animation to improve performance 2021-02-27 23:43:57 +04:00
X1nto
c84e795d75 fixed grammar 2021-02-26 20:54:23 +04:00
X1nto
365fb4aede bug fixes 2021-02-26 20:02:05 +04:00
X1nto
5c7b953fb4 fixed conflicts 2021-02-26 19:36:37 +04:00
X1nto
fd9defcb5e updated app card UI 2021-02-26 19:34:22 +04:00
KevinX8
7c6e3e6d6f
Merge pull request #419 from YTVanced/l10n_dev
New Crowdin updates
2021-02-24 12:22:35 +00:00
KevinX8
72b46024c0 New translations strings.xml (Vietnamese) 2021-02-24 12:00:07 +00:00
KevinX8
ab0e73745c New translations strings.xml (Russian) 2021-02-24 00:03:57 +00:00
X1nto
7c72632f73 updated deps 2021-02-23 20:00:07 +04:00
X1nto
ab3014d5af replaced any() with contains() 2021-02-23 19:34:48 +04:00
X1nto
b32ebe51a0 bumped up version and updated language getter 2021-02-23 19:33:23 +04:00
X1nto
e9ff1bfd9d prevent screen from sleeping when installation dialog is visible 2021-02-23 19:27:06 +04:00
KevinX8
42d1c1ec3a New translations strings.xml (Chinese Traditional) 2021-02-23 12:02:10 +00:00
KevinX8
4107464c48 New translations strings.xml (Romanian) 2021-02-23 12:02:09 +00:00
KevinX8
5ee365cffb New translations strings.xml (Indonesian) 2021-02-23 12:02:07 +00:00
KevinX8
208def0baa New translations strings.xml (Punjabi, Pakistan) 2021-02-22 23:37:12 +00:00
KevinX8
46378af4c9 New translations strings.xml (Somali) 2021-02-22 23:37:10 +00:00
KevinX8
1bb2c0de93 New translations strings.xml (Bulgarian) 2021-02-22 23:37:09 +00:00
KevinX8
99674b38c5 New translations strings.xml (Danish) 2021-02-22 23:37:08 +00:00
KevinX8
2c8e69bbf0 New translations strings.xml (Czech) 2021-02-22 23:37:07 +00:00
KevinX8
6c1dd9ecab New translations strings.xml (Catalan) 2021-02-22 23:37:06 +00:00
KevinX8
e99bd102e4 New translations strings.xml (Arabic) 2021-02-22 23:37:04 +00:00
KevinX8
60d01d4c49 New translations strings.xml (Afrikaans) 2021-02-22 23:37:03 +00:00
KevinX8
a712853d8c New translations strings.xml (French) 2021-02-22 23:37:02 +00:00
KevinX8
430cafbaf6 New translations strings.xml (Chinese Simplified) 2021-02-22 23:37:00 +00:00
KevinX8
af8922bb82 New translations strings.xml (Romanian) 2021-02-22 23:36:59 +00:00
KevinX8
22d6d1e84a New translations strings.xml (Hindi) 2021-02-22 23:36:58 +00:00
KevinX8
922fbbc96e New translations strings.xml (Sorani (Kurdish)) 2021-02-22 23:36:56 +00:00
KevinX8
3e588fa75e New translations strings.xml (Filipino) 2021-02-22 23:36:55 +00:00
KevinX8
a11faf346b New translations strings.xml (Azerbaijani) 2021-02-22 23:36:53 +00:00
KevinX8
08be8526eb New translations strings.xml (Croatian) 2021-02-22 23:36:52 +00:00
KevinX8
943e5256f4 New translations strings.xml (Ukrainian) 2021-02-22 23:36:51 +00:00
KevinX8
e2ef42a8fb New translations strings.xml (Korean) 2021-02-22 23:36:50 +00:00
KevinX8
1fb3a79d06 New translations strings.xml (Hungarian) 2021-02-22 23:36:49 +00:00
KevinX8
5f4afe9dd1 New translations strings.xml (Greek) 2021-02-22 23:36:47 +00:00
KevinX8
630e27d170 New translations strings.xml (Indonesian) 2021-02-22 23:36:45 +00:00
KevinX8
f9b6fb9831 New translations strings.xml (Spanish) 2021-02-22 23:36:44 +00:00
KevinX8
880d6f4f3f New translations strings.xml (Malayalam) 2021-02-22 23:36:42 +00:00
KevinX8
2d58e20e85 New translations strings.xml (Thai) 2021-02-22 23:36:41 +00:00
KevinX8
6604be1698 New translations strings.xml (German) 2021-02-22 23:36:40 +00:00
KevinX8
89093222dc New translations strings.xml (Finnish) 2021-02-22 23:36:39 +00:00
KevinX8
81d1b30b9e New translations strings.xml (Hebrew) 2021-02-22 23:36:37 +00:00
KevinX8
e664ae6a57 New translations strings.xml (Italian) 2021-02-22 23:36:36 +00:00
KevinX8
c4d886bde3 New translations strings.xml (Pashto) 2021-02-22 23:36:35 +00:00
KevinX8
b5ce1f14ff New translations strings.xml (Kurmanji (Kurdish)) 2021-02-22 23:36:34 +00:00
KevinX8
b6df68a5ff New translations strings.xml (Bengali, India) 2021-02-22 23:36:33 +00:00
KevinX8
4c181d743f New translations strings.xml (Sinhala) 2021-02-22 23:36:32 +00:00
KevinX8
167f3ce1aa New translations strings.xml (Estonian) 2021-02-22 23:36:30 +00:00
KevinX8
6d530b48a7 New translations strings.xml (Marathi) 2021-02-22 23:36:29 +00:00
KevinX8
f97325fd6a New translations strings.xml (Bengali) 2021-02-22 23:36:27 +00:00
KevinX8
257a14104e New translations strings.xml (Tamil) 2021-02-22 23:36:26 +00:00
KevinX8
d00699bde9 New translations strings.xml (Portuguese, Brazilian) 2021-02-22 23:36:25 +00:00
KevinX8
1b25daed4b New translations strings.xml (Vietnamese) 2021-02-22 23:36:23 +00:00
KevinX8
7616582094 New translations strings.xml (Japanese) 2021-02-22 23:36:22 +00:00
KevinX8
dde4d24e9b New translations strings.xml (Chinese Traditional) 2021-02-22 23:36:21 +00:00
KevinX8
30fbb53395 New translations strings.xml (Serbian (Cyrillic)) 2021-02-22 23:36:20 +00:00
KevinX8
6543ac47e3 New translations strings.xml (Russian) 2021-02-22 23:36:19 +00:00
KevinX8
0ec97c10a8 New translations strings.xml (Portuguese) 2021-02-22 23:36:17 +00:00
KevinX8
fdabeb75c4 New translations strings.xml (Polish) 2021-02-22 23:36:16 +00:00
KevinX8
416738a8a8 New translations strings.xml (Punjabi) 2021-02-22 23:36:14 +00:00
KevinX8
5f08cf0759 New translations strings.xml (Norwegian) 2021-02-22 23:36:13 +00:00
KevinX8
15e11254fd New translations strings.xml (Dutch) 2021-02-22 23:36:12 +00:00
KevinX8
388880395e New translations strings.xml (Kurdish) 2021-02-22 23:36:10 +00:00
KevinX8
4ba33c8482 New translations strings.xml (Georgian) 2021-02-22 23:36:09 +00:00
KevinX8
3ea4059d00 New translations strings.xml (Swedish) 2021-02-22 23:36:08 +00:00
KevinX8
5dce2f5073 New translations strings.xml (Turkish) 2021-02-22 23:36:06 +00:00
X1nto
64fd410d43 minor adjustments to root split installer 2021-02-22 20:41:34 +04:00
X1nto
18b79aace8 removed gradient from sponsor buttons 2021-02-22 20:27:48 +04:00
X1nto
98f07cdf50 removed -S parameter from root installer 2021-02-22 20:22:51 +04:00
X1nto
dced053569 more logging 2021-02-22 20:00:11 +04:00
X1nto
ac076f5035 updated strings 2021-02-22 15:52:43 +04:00
X1nto
c783de1d74 removed su -c from install-write 2021-02-22 15:34:55 +04:00
X1nto
979e1da8f7 updated mount script 2021-02-22 15:34:14 +04:00
KevinX8
dcaaa04796 New translations strings.xml (Vietnamese) 2021-02-21 07:41:43 +00:00
KevinX8
5ddfcec174 New translations strings.xml (Japanese) 2021-02-21 07:41:40 +00:00
KevinX8
598d75dc88 New translations strings.xml (Russian) 2021-02-20 19:44:12 +00:00
KevinX8
01cd25d8b2 New translations strings.xml (French) 2021-02-20 19:44:10 +00:00
KevinX8
a53e4a1c83 New translations strings.xml (Turkish) 2021-02-20 19:44:09 +00:00
X1nto
494ea8b6a2 darkened surface color a little bit 2021-02-20 17:37:07 +04:00
X1nto
a283097491 logging adjustments 2021-02-20 14:45:48 +04:00
X1nto
95bb60981b rewrite root split installer 2021-02-20 14:25:41 +04:00
KevinX8
935c656520 New translations strings.xml (Chinese Simplified) 2021-02-19 19:18:53 +00:00
X1nto
7acb40234b added jetpack compose testing samples; migrating after AS Arctic Fox releases 2021-02-19 17:51:34 +04:00
KevinX8
eb17a0d6f6 New translations strings.xml (Chinese Traditional) 2021-02-19 07:20:31 +00:00
KevinX8
b7d72bd2e3 New translations strings.xml (Finnish) 2021-02-19 07:20:29 +00:00
KevinX8
28539c7466 New translations strings.xml (Indonesian) 2021-02-19 07:20:28 +00:00
KevinX8
9297023201 New translations strings.xml (Spanish) 2021-02-19 07:20:27 +00:00
KevinX8
557cf8a934 New translations strings.xml (Thai) 2021-02-19 07:20:25 +00:00
KevinX8
4ab533bf7e New translations strings.xml (Hindi) 2021-02-18 19:13:41 +00:00
KevinX8
bbee245d96 New translations strings.xml (Croatian) 2021-02-18 19:13:39 +00:00
KevinX8
91167f1a28 New translations strings.xml (Ukrainian) 2021-02-18 19:13:38 +00:00
KevinX8
93b5e1b3a4 New translations strings.xml (Indonesian) 2021-02-18 07:01:05 +00:00
X1nto
ae1d5691ac implemented a better way to animate welcome activity 2021-02-17 23:00:35 +04:00
KevinX8
87eeeaf65f New translations strings.xml (Swedish) 2021-02-17 18:52:55 +00:00
KevinX8
ccd3d6b71c New translations strings.xml (German) 2021-02-17 18:52:53 +00:00
X1nto
8c4b8332e8 improved AppListAdapter 2021-02-17 21:00:39 +04:00
KevinX8
a4e5c008ec New translations strings.xml (Bulgarian) 2021-02-17 06:49:24 +00:00
KevinX8
ad907a6565 New translations strings.xml (Afrikaans) 2021-02-17 06:49:23 +00:00
KevinX8
c5991a8456 New translations strings.xml (French) 2021-02-17 06:49:22 +00:00
KevinX8
31b36dec76 New translations strings.xml (Chinese Simplified) 2021-02-17 06:49:20 +00:00
KevinX8
42f2908dc1 New translations strings.xml (Romanian) 2021-02-17 06:49:19 +00:00
KevinX8
479d3025e5 New translations strings.xml (Hindi) 2021-02-17 06:49:18 +00:00
KevinX8
0d7ca349c6 New translations strings.xml (Sorani (Kurdish)) 2021-02-17 06:49:16 +00:00
KevinX8
44ee4a6112 New translations strings.xml (Filipino) 2021-02-17 06:49:15 +00:00
KevinX8
e6c7a23cfd New translations strings.xml (Arabic) 2021-02-17 06:49:14 +00:00
KevinX8
71daba634e New translations strings.xml (Azerbaijani) 2021-02-17 06:49:13 +00:00
KevinX8
581cb0c551 New translations strings.xml (Ukrainian) 2021-02-17 06:49:11 +00:00
KevinX8
629e2e5200 New translations strings.xml (Korean) 2021-02-17 06:49:10 +00:00
KevinX8
043c890bf3 New translations strings.xml (Hungarian) 2021-02-17 06:49:09 +00:00
KevinX8
38ad763613 New translations strings.xml (Greek) 2021-02-17 06:49:08 +00:00
KevinX8
2b46f8c3b8 New translations strings.xml (Indonesian) 2021-02-17 06:49:06 +00:00
KevinX8
231916f0a7 New translations strings.xml (Spanish) 2021-02-17 06:49:05 +00:00
KevinX8
37cedd74a9 New translations strings.xml (Malayalam) 2021-02-17 06:49:04 +00:00
KevinX8
438ddffc85 New translations strings.xml (Croatian) 2021-02-17 06:49:03 +00:00
KevinX8
bd97270626 New translations strings.xml (Thai) 2021-02-17 06:49:02 +00:00
KevinX8
00d4c42a57 New translations strings.xml (Catalan) 2021-02-17 06:49:00 +00:00
KevinX8
fb57354a3a New translations strings.xml (Danish) 2021-02-17 06:48:59 +00:00
KevinX8
9c9c93c0ee New translations strings.xml (Punjabi, Pakistan) 2021-02-17 06:48:58 +00:00
KevinX8
835e6c4611 New translations strings.xml (Somali) 2021-02-17 06:48:57 +00:00
KevinX8
073caa4469 New translations strings.xml (Pashto) 2021-02-17 06:48:56 +00:00
KevinX8
b4b950e5e4 New translations strings.xml (Kurmanji (Kurdish)) 2021-02-17 06:48:54 +00:00
KevinX8
bda401bd93 New translations strings.xml (Bengali, India) 2021-02-17 06:48:53 +00:00
KevinX8
2136d21af9 New translations strings.xml (Sinhala) 2021-02-17 06:48:52 +00:00
KevinX8
5f87eb936a New translations strings.xml (Estonian) 2021-02-17 06:48:51 +00:00
KevinX8
8f97203cb4 New translations strings.xml (Czech) 2021-02-17 06:48:49 +00:00
KevinX8
fcae09c41a New translations strings.xml (Marathi) 2021-02-17 06:48:48 +00:00
KevinX8
dba3824cbc New translations strings.xml (Tamil) 2021-02-17 06:48:47 +00:00
KevinX8
b0d194724c New translations strings.xml (Polish) 2021-02-17 06:48:46 +00:00
KevinX8
fd9a4990e1 New translations strings.xml (Georgian) 2021-02-17 06:48:45 +00:00
KevinX8
7656af8d45 New translations strings.xml (Italian) 2021-02-17 06:48:44 +00:00
KevinX8
3a5db1f7ef New translations strings.xml (Hebrew) 2021-02-17 06:48:43 +00:00
KevinX8
ee8d17a40b New translations strings.xml (Finnish) 2021-02-17 06:48:39 +00:00
KevinX8
6e7c64d7d4 New translations strings.xml (German) 2021-02-17 06:48:38 +00:00
KevinX8
73d7d9e679 New translations strings.xml (Bengali) 2021-02-17 06:48:37 +00:00
KevinX8
4cc4744a3c New translations strings.xml (Japanese) 2021-02-17 06:48:35 +00:00
KevinX8
54b90237fd New translations strings.xml (Chinese Traditional) 2021-02-16 18:49:02 +00:00
KevinX8
8d2b55aad9 New translations strings.xml (Swedish) 2021-02-16 18:49:01 +00:00
KevinX8
54103c28d1 New translations strings.xml (Serbian (Cyrillic)) 2021-02-16 18:48:59 +00:00
KevinX8
84005a7f85 New translations strings.xml (Russian) 2021-02-16 18:48:58 +00:00
KevinX8
52a8581f50 New translations strings.xml (Portuguese) 2021-02-16 18:48:57 +00:00
KevinX8
c19ffdac1b New translations strings.xml (Polish) 2021-02-16 18:48:56 +00:00
KevinX8
9a0313d450 New translations strings.xml (Punjabi) 2021-02-16 18:48:54 +00:00
KevinX8
b4690d97b2 New translations strings.xml (Norwegian) 2021-02-16 18:48:53 +00:00
KevinX8
9dfa8b774a New translations strings.xml (Dutch) 2021-02-16 18:48:52 +00:00
KevinX8
abfabe10f2 New translations strings.xml (Kurdish) 2021-02-16 18:48:50 +00:00
KevinX8
d0c9329a6a New translations strings.xml (Vietnamese) 2021-02-16 18:48:49 +00:00
KevinX8
f99cb1136a New translations strings.xml (Turkish) 2021-02-16 18:48:48 +00:00
X1nto
537e76499a added another way to check if miui optimizations are enabled 2021-02-16 19:30:24 +04:00
X1nto
597d7a7a4e Merge branch 'dev' of https://github.com/YTVanced/VancedManager into dev 2021-02-16 18:41:17 +04:00
X1nto
cb97aa2fe1 reverted MIUI warning system 2021-02-16 18:41:06 +04:00
KevinX8
66184450ea
Merge branch 'master' into dev 2021-02-16 13:31:07 +00:00
KevinX8
f1a43970b6
Merge pull request #408 from YTVanced/l10n_dev
New Crowdin updates
2021-02-16 13:20:36 +00:00
KevinX8
af9524fb2e bumped deps 2021-02-16 12:50:33 +00:00
X1nto
26bf0a90d7 improved MIUI warning 2021-02-16 15:00:36 +04:00
X1nto
d0e765fa39 moved progressmodel out of class 2021-02-16 12:26:40 +04:00
KevinX8
fbc5c6eec0 New translations strings.xml (Bulgarian) 2021-02-16 06:51:23 +00:00
KevinX8
6f4516f439 New translations strings.xml (Portuguese, Brazilian) 2021-02-16 06:51:21 +00:00
KevinX8
ba61a9409a New translations strings.xml (Chinese Traditional) 2021-02-16 06:51:20 +00:00
KevinX8
4dd5e9f66d New translations strings.xml (Italian) 2021-02-16 06:51:18 +00:00
KevinX8
15eabf37fb New translations strings.xml (French) 2021-02-16 06:51:17 +00:00
KevinX8
b5803994c6 New translations strings.xml (Croatian) 2021-02-16 06:51:15 +00:00
KevinX8
ca19201899 New translations strings.xml (Korean) 2021-02-16 06:51:14 +00:00
KevinX8
d61937a41b New translations strings.xml (Greek) 2021-02-16 06:51:13 +00:00
KevinX8
150eb5bbf3 New translations strings.xml (Indonesian) 2021-02-16 06:51:11 +00:00
KevinX8
2bfef3bdf7 New translations strings.xml (Turkish) 2021-02-16 06:51:10 +00:00
KevinX8
3b11865f3b New translations strings.xml (Bulgarian) 2021-02-15 18:50:04 +00:00
KevinX8
c1fd1d945e New translations strings.xml (German) 2021-02-15 18:50:02 +00:00
KevinX8
c5de17d34c New translations strings.xml (Danish) 2021-02-15 18:50:01 +00:00
KevinX8
6ddd3cee9e New translations strings.xml (Czech) 2021-02-15 18:49:59 +00:00
KevinX8
03a69cfd9c New translations strings.xml (Catalan) 2021-02-15 18:49:58 +00:00
KevinX8
564e9b13b9 New translations strings.xml (Arabic) 2021-02-15 18:49:57 +00:00
KevinX8
eac1cfeecd New translations strings.xml (Afrikaans) 2021-02-15 18:49:56 +00:00
KevinX8
e95abb8383 New translations strings.xml (French) 2021-02-15 18:49:55 +00:00
KevinX8
814dd399e9 New translations strings.xml (Chinese Simplified) 2021-02-15 18:49:54 +00:00
KevinX8
1b86674735 New translations strings.xml (Romanian) 2021-02-15 18:49:52 +00:00
KevinX8
805ff46048 New translations strings.xml (Hindi) 2021-02-15 18:49:51 +00:00
KevinX8
c0af27ec93 New translations strings.xml (Finnish) 2021-02-15 18:49:50 +00:00
KevinX8
ce2687b772 New translations strings.xml (Sorani (Kurdish)) 2021-02-15 18:49:49 +00:00
KevinX8
69accb784d New translations strings.xml (Azerbaijani) 2021-02-15 18:49:47 +00:00
KevinX8
05c0b01eb7 New translations strings.xml (Croatian) 2021-02-15 18:49:46 +00:00
KevinX8
c1c5458aaa New translations strings.xml (Ukrainian) 2021-02-15 18:49:45 +00:00
KevinX8
79f0a44bee New translations strings.xml (Korean) 2021-02-15 18:49:44 +00:00
KevinX8
e23e72f845 New translations strings.xml (Hungarian) 2021-02-15 18:49:43 +00:00
KevinX8
5f325789cd New translations strings.xml (Greek) 2021-02-15 18:49:42 +00:00
KevinX8
5bf881cd2a New translations strings.xml (Indonesian) 2021-02-15 18:49:40 +00:00
KevinX8
95db340034 New translations strings.xml (Spanish) 2021-02-15 18:49:39 +00:00
KevinX8
8ffe5a7389 New translations strings.xml (Malayalam) 2021-02-15 18:49:38 +00:00
KevinX8
09825992b5 New translations strings.xml (Thai) 2021-02-15 18:49:37 +00:00
KevinX8
9fe527de6b New translations strings.xml (Filipino) 2021-02-15 18:49:35 +00:00
KevinX8
bb6812c4df New translations strings.xml (Japanese) 2021-02-15 18:49:34 +00:00
KevinX8
4b9287a11c New translations strings.xml (Hebrew) 2021-02-15 18:49:33 +00:00
KevinX8
2cb4578316 New translations strings.xml (Georgian) 2021-02-15 18:49:32 +00:00
KevinX8
70c2ecfb31 New translations strings.xml (Punjabi, Pakistan) 2021-02-15 18:49:31 +00:00
KevinX8
3c7ecd155d New translations strings.xml (Somali) 2021-02-15 18:49:29 +00:00
KevinX8
bdce53e44b New translations strings.xml (Pashto) 2021-02-15 18:49:28 +00:00
KevinX8
6d4adc8ef4 New translations strings.xml (Kurmanji (Kurdish)) 2021-02-15 18:49:27 +00:00
KevinX8
067aa25606 New translations strings.xml (Bengali, India) 2021-02-15 18:49:26 +00:00
KevinX8
eab6a83edc New translations strings.xml (Sinhala) 2021-02-15 18:49:24 +00:00
KevinX8
45291c0f37 New translations strings.xml (Estonian) 2021-02-15 18:49:23 +00:00
KevinX8
35c52e9cdb New translations strings.xml (Marathi) 2021-02-15 18:49:22 +00:00
KevinX8
b69b4df687 New translations strings.xml (Bengali) 2021-02-15 18:49:21 +00:00
KevinX8
8e553ab669 New translations strings.xml (Tamil) 2021-02-15 18:49:20 +00:00
KevinX8
a3c7a1dce7 New translations strings.xml (Italian) 2021-02-15 18:49:18 +00:00
KevinX8
260c032fe0 New translations strings.xml (Portuguese, Brazilian) 2021-02-15 18:49:17 +00:00
KevinX8
7e58bcd30d New translations strings.xml (Chinese Traditional) 2021-02-15 18:49:16 +00:00
KevinX8
d33d9c8077 New translations strings.xml (Swedish) 2021-02-15 18:49:14 +00:00
KevinX8
b309f36c29 New translations strings.xml (Serbian (Cyrillic)) 2021-02-15 18:49:13 +00:00
KevinX8
65c807a878 New translations strings.xml (Russian) 2021-02-15 18:49:12 +00:00
KevinX8
b8560b210e New translations strings.xml (Portuguese) 2021-02-15 18:49:10 +00:00
KevinX8
37417fe6b4 New translations strings.xml (Polish) 2021-02-15 18:49:09 +00:00
KevinX8
0d3c06b558 New translations strings.xml (Punjabi) 2021-02-15 18:49:08 +00:00
KevinX8
199e6e9517 New translations strings.xml (Norwegian) 2021-02-15 18:49:07 +00:00
KevinX8
f63dacbd1e New translations strings.xml (Dutch) 2021-02-15 18:49:05 +00:00
KevinX8
bb6ec588ef New translations strings.xml (Kurdish) 2021-02-15 18:49:04 +00:00
KevinX8
a650d75a73 New translations strings.xml (Vietnamese) 2021-02-15 18:49:03 +00:00
KevinX8
a3eb10f5a4 New translations strings.xml (Turkish) 2021-02-15 18:49:01 +00:00
X1nto
ab5f5182b1 updated about fragment padding in order to match other fragments 2021-02-15 22:30:44 +04:00
X1nto
ae72720d42 updated about menu 2021-02-15 22:28:34 +04:00
X1nto
1769d86a88 removed empty git file 2021-02-15 21:42:42 +04:00
X1nto
15b259d853 fixed NPE 2021-02-15 20:02:13 +04:00
X1nto
cb38dedb11 removed downloadProgress from livedata 2021-02-15 19:49:01 +04:00
X1nto
62b540b95c removed logging 2021-02-15 19:34:52 +04:00
X1nto
b6c01333b0 theming fixes 2021-02-15 19:29:36 +04:00
X1nto
0c2b9805e4 added a separate brave image for light theme 2021-02-15 19:21:26 +04:00
X1nto
0cff9f51b5 updated issue template 2021-02-15 19:12:42 +04:00
X1nto
7d75990f30 bumped up version 2021-02-15 17:19:51 +04:00
KevinX8
ee608c72ae New translations strings.xml (Sorani (Kurdish)) 2021-02-15 06:39:28 +00:00
KevinX8
6ddd67a8d7 New translations strings.xml (Indonesian) 2021-02-15 06:39:27 +00:00
KevinX8
66a1b10e00 New translations strings.xml (Swedish) 2021-02-14 18:23:31 +00:00
X1nto
c9245122f5 added an outline to sponsor buttons 2021-02-14 16:54:44 +04:00
X1nto
dfbb623102 replaced deprecated method 2021-02-14 13:58:10 +04:00
X1nto
dc0a66c700 prevent activity recreation on screen rotate 2021-02-14 13:57:48 +04:00
KevinX8
55e1d41f25 New translations strings.xml (Vietnamese) 2021-02-14 06:12:21 +00:00
KevinX8
da9ecb08a6 New translations strings.xml (German) 2021-02-14 06:12:20 +00:00
KevinX8
6a4b68e491 New translations strings.xml (Chinese Simplified) 2021-02-14 06:12:18 +00:00
KevinX8
07b2acf237 New translations strings.xml (Romanian) 2021-02-14 06:12:17 +00:00
KevinX8
089e54426c New translations strings.xml (Indonesian) 2021-02-14 06:12:16 +00:00
KevinX8
ac611373aa New translations strings.xml (Bulgarian) 2021-02-13 18:13:09 +00:00
KevinX8
e37561ad39 New translations strings.xml (German) 2021-02-13 18:13:08 +00:00
KevinX8
34df7b156e New translations strings.xml (Danish) 2021-02-13 18:13:07 +00:00
KevinX8
ed61fd1c1a New translations strings.xml (Czech) 2021-02-13 18:13:06 +00:00
KevinX8
3aad0c2f90 New translations strings.xml (Catalan) 2021-02-13 18:13:05 +00:00
KevinX8
0d0cca6eaf New translations strings.xml (Arabic) 2021-02-13 18:13:04 +00:00
KevinX8
419cbd7319 New translations strings.xml (Afrikaans) 2021-02-13 18:13:03 +00:00
KevinX8
3e5bb35342 New translations strings.xml (French) 2021-02-13 18:13:02 +00:00
KevinX8
28aa185a73 New translations strings.xml (Chinese Simplified) 2021-02-13 18:13:00 +00:00
KevinX8
0f5b5c6d53 New translations strings.xml (Romanian) 2021-02-13 18:12:59 +00:00
KevinX8
b1a0b1db87 New translations strings.xml (Hindi) 2021-02-13 18:12:58 +00:00
KevinX8
4d9bc88ada New translations strings.xml (Finnish) 2021-02-13 18:12:57 +00:00
KevinX8
672113248a New translations strings.xml (Sorani (Kurdish)) 2021-02-13 18:12:56 +00:00
KevinX8
2441fd4834 New translations strings.xml (Azerbaijani) 2021-02-13 18:12:55 +00:00
KevinX8
8569bb3af4 New translations strings.xml (Croatian) 2021-02-13 18:12:54 +00:00
KevinX8
ee1bd06249 New translations strings.xml (Ukrainian) 2021-02-13 18:12:53 +00:00
KevinX8
7fe8445162 New translations strings.xml (Korean) 2021-02-13 18:12:52 +00:00
KevinX8
18cb0cd504 New translations strings.xml (Hungarian) 2021-02-13 18:12:51 +00:00
KevinX8
414a7fa819 New translations strings.xml (Greek) 2021-02-13 18:12:49 +00:00
KevinX8
8baccc0909 New translations strings.xml (Indonesian) 2021-02-13 18:12:48 +00:00
KevinX8
34c8ed2f6b New translations strings.xml (Spanish) 2021-02-13 18:12:47 +00:00
KevinX8
0ea2c6881d New translations strings.xml (Malayalam) 2021-02-13 18:12:46 +00:00
KevinX8
ca2ef94978 New translations strings.xml (Thai) 2021-02-13 18:12:45 +00:00
KevinX8
30c39210cf New translations strings.xml (Filipino) 2021-02-13 18:12:44 +00:00
KevinX8
811fd789c7 New translations strings.xml (Japanese) 2021-02-13 18:12:43 +00:00
KevinX8
80c33a2d26 New translations strings.xml (Hebrew) 2021-02-13 18:12:41 +00:00
KevinX8
eeed6624de New translations strings.xml (Georgian) 2021-02-13 18:12:40 +00:00
KevinX8
0575f2ecbd New translations strings.xml (Punjabi, Pakistan) 2021-02-13 18:12:39 +00:00
KevinX8
01bc70c1c7 New translations strings.xml (Somali) 2021-02-13 18:12:38 +00:00
KevinX8
bffcd4000d New translations strings.xml (Pashto) 2021-02-13 18:12:37 +00:00
KevinX8
79864e3d53 New translations strings.xml (Kurmanji (Kurdish)) 2021-02-13 18:12:36 +00:00
KevinX8
bd231022c6 New translations strings.xml (Bengali, India) 2021-02-13 18:12:35 +00:00
KevinX8
6587359cfb New translations strings.xml (Sinhala) 2021-02-13 18:12:34 +00:00
KevinX8
5cb1564362 New translations strings.xml (Estonian) 2021-02-13 18:12:32 +00:00
KevinX8
703a669261 New translations strings.xml (Marathi) 2021-02-13 18:12:31 +00:00
KevinX8
16246aa51f New translations strings.xml (Bengali) 2021-02-13 18:12:30 +00:00
KevinX8
9df77a8ef7 New translations strings.xml (Tamil) 2021-02-13 18:12:29 +00:00
KevinX8
813d9682e0 New translations strings.xml (Italian) 2021-02-13 18:12:28 +00:00
KevinX8
69f50e5d58 New translations strings.xml (Portuguese, Brazilian) 2021-02-13 18:12:27 +00:00
KevinX8
e218441710 New translations strings.xml (Chinese Traditional) 2021-02-13 18:12:26 +00:00
KevinX8
446fa9092c New translations strings.xml (Swedish) 2021-02-13 18:12:25 +00:00
KevinX8
425622bf5e New translations strings.xml (Serbian (Cyrillic)) 2021-02-13 18:12:24 +00:00
KevinX8
ef234f2529 New translations strings.xml (Russian) 2021-02-13 18:12:22 +00:00
KevinX8
df594df1fe New translations strings.xml (Portuguese) 2021-02-13 18:12:21 +00:00
KevinX8
c0ab5f0279 New translations strings.xml (Polish) 2021-02-13 18:12:20 +00:00
KevinX8
fa664dd056 New translations strings.xml (Punjabi) 2021-02-13 18:12:19 +00:00
KevinX8
4e08e39c4c New translations strings.xml (Norwegian) 2021-02-13 18:12:18 +00:00
KevinX8
0a00a81d70 New translations strings.xml (Kurdish) 2021-02-13 18:12:16 +00:00
KevinX8
7829916289 New translations strings.xml (Vietnamese) 2021-02-13 18:12:15 +00:00
X1nto
f6790ff22c cleanup 2021-02-13 17:36:50 +04:00
X1nto
4aae6e0c81 string adjustments 2021-02-13 17:34:28 +04:00
X1nto
238943af62 clickable boundary adjustments 2021-02-13 17:31:09 +04:00
X1nto
4efaaed304 rewrite nonroot split installer and clean up PackageHelper 2021-02-13 17:10:57 +04:00
X1nto
3896e7daad bumped up dependencies 2021-02-13 15:03:47 +04:00
KevinX8
c08636c505 New translations strings.xml (Malayalam) 2021-02-13 06:12:32 +00:00
KevinX8
ca2a89aa1d New translations strings.xml (Japanese) 2021-02-13 06:12:30 +00:00
KevinX8
e406d75200 New translations strings.xml (Romanian) 2021-02-12 18:17:10 +00:00
KevinX8
68ef2d4e61 New translations strings.xml (Indonesian) 2021-02-11 18:11:46 +00:00
KevinX8
3bfa8a6c01 New translations strings.xml (German) 2021-02-10 18:11:13 +00:00
KevinX8
33e7e8cf4f New translations strings.xml (Bulgarian) 2021-02-09 18:09:29 +00:00
KevinX8
587c1a1a4a New translations strings.xml (Croatian) 2021-02-09 18:09:28 +00:00
KevinX8
0f938c33c6 New translations strings.xml (Finnish) 2021-02-09 05:56:24 +00:00
KevinX8
56ea23df97 New translations strings.xml (German) 2021-02-09 05:56:23 +00:00
KevinX8
c07ac96fca New translations strings.xml (Thai) 2021-02-09 05:56:21 +00:00
KevinX8
6fed5fadd0 New translations strings.xml (Chinese Traditional) 2021-02-08 17:52:53 +00:00
KevinX8
0e85fa8e85 New translations strings.xml (Chinese Simplified) 2021-02-08 05:54:51 +00:00
KevinX8
195fe4d17c New translations strings.xml (Japanese) 2021-02-08 05:54:50 +00:00
KevinX8
c894a92aab New translations strings.xml (Bulgarian) 2021-02-07 17:51:06 +00:00
KevinX8
b3328bd34a New translations strings.xml (Portuguese, Brazilian) 2021-02-07 17:51:04 +00:00
KevinX8
bcfd1de35b New translations strings.xml (Czech) 2021-02-07 17:51:02 +00:00
KevinX8
581df0873d New translations strings.xml (Filipino) 2021-02-07 17:51:00 +00:00
KevinX8
d028ca9953 New translations strings.xml (Croatian) 2021-02-07 17:50:59 +00:00
X1nto
e0f672acec improved logging 2021-02-07 14:12:54 +04:00
X1nto
284a6c07a8 made logs readable on light theme 2021-02-07 14:08:55 +04:00
KevinX8
baeb657ebf New translations strings.xml (Polish) 2021-02-07 05:52:53 +00:00
KevinX8
74dcd98d7b New translations strings.xml (Vietnamese) 2021-02-06 17:42:49 +00:00
KevinX8
2830aebc83 New translations strings.xml (Spanish) 2021-02-06 17:42:46 +00:00
KevinX8
2fec062f42 New translations strings.xml (Bulgarian) 2021-02-06 05:44:35 +00:00
KevinX8
1ef4afc2ba New translations strings.xml (Vietnamese) 2021-02-06 05:44:34 +00:00
KevinX8
b8d1553bb6 New translations strings.xml (Italian) 2021-02-06 05:44:32 +00:00
KevinX8
b5f0c46711 New translations strings.xml (Hungarian) 2021-02-06 05:44:29 +00:00
KevinX8
a8878aed9f New translations strings.xml (Greek) 2021-02-06 05:44:28 +00:00
KevinX8
65ad9d12db New translations strings.xml (Spanish) 2021-02-06 05:44:26 +00:00
KevinX8
c9c08baffa New translations strings.xml (Bulgarian) 2021-02-05 17:49:10 +00:00
KevinX8
9f6bf97fe6 New translations strings.xml (German) 2021-02-05 17:49:08 +00:00
KevinX8
e776ad35e7 New translations strings.xml (Danish) 2021-02-05 17:49:07 +00:00
KevinX8
d4fe9c4c5a New translations strings.xml (Czech) 2021-02-05 17:49:05 +00:00
KevinX8
eb690d4229 New translations strings.xml (Catalan) 2021-02-05 17:49:03 +00:00
KevinX8
d5741b609d New translations strings.xml (Arabic) 2021-02-05 17:49:02 +00:00
KevinX8
4044771843 New translations strings.xml (Afrikaans) 2021-02-05 17:49:00 +00:00
KevinX8
6dcfc4c706 New translations strings.xml (French) 2021-02-05 17:48:58 +00:00
KevinX8
5b88baedab New translations strings.xml (Chinese Simplified) 2021-02-05 17:48:56 +00:00
KevinX8
89e2b498f7 New translations strings.xml (Romanian) 2021-02-05 17:48:54 +00:00
KevinX8
6c9e4a175d New translations strings.xml (Hindi) 2021-02-05 17:48:52 +00:00
KevinX8
9a8a329df2 New translations strings.xml (Finnish) 2021-02-05 17:48:50 +00:00
KevinX8
782e200020 New translations strings.xml (Sorani (Kurdish)) 2021-02-05 17:48:49 +00:00
KevinX8
554c53fcba New translations strings.xml (Azerbaijani) 2021-02-05 17:48:47 +00:00
KevinX8
75c4b48daf New translations strings.xml (Croatian) 2021-02-05 17:48:45 +00:00
KevinX8
60cc27570d New translations strings.xml (Ukrainian) 2021-02-05 17:48:43 +00:00
KevinX8
738da25881 New translations strings.xml (Korean) 2021-02-05 17:48:42 +00:00
KevinX8
8e99791721 New translations strings.xml (Hungarian) 2021-02-05 17:48:40 +00:00
KevinX8
5272c98289 New translations strings.xml (Greek) 2021-02-05 17:48:38 +00:00
KevinX8
4df1f39dad New translations strings.xml (Indonesian) 2021-02-05 17:48:36 +00:00
KevinX8
b022621108 New translations strings.xml (Spanish) 2021-02-05 17:48:34 +00:00
KevinX8
7d8915cb28 New translations strings.xml (Malayalam) 2021-02-05 17:48:32 +00:00
KevinX8
2aefce3aed New translations strings.xml (Thai) 2021-02-05 17:48:30 +00:00
KevinX8
3110e917a5 New translations strings.xml (Filipino) 2021-02-05 17:48:29 +00:00
KevinX8
a8768c5fc3 New translations strings.xml (Japanese) 2021-02-05 17:48:27 +00:00
KevinX8
2f5e5e2b21 New translations strings.xml (Hebrew) 2021-02-05 17:48:26 +00:00
KevinX8
fbf251f72e New translations strings.xml (Georgian) 2021-02-05 17:48:24 +00:00
KevinX8
fe2862d79a New translations strings.xml (Punjabi, Pakistan) 2021-02-05 17:48:22 +00:00
KevinX8
2849b2c4a6 New translations strings.xml (Somali) 2021-02-05 17:48:20 +00:00
KevinX8
4b5ff4a093 New translations strings.xml (Pashto) 2021-02-05 17:48:19 +00:00
KevinX8
5464b8f1cf New translations strings.xml (Kurmanji (Kurdish)) 2021-02-05 17:48:17 +00:00
KevinX8
c37f493cc8 New translations strings.xml (Bengali, India) 2021-02-05 17:48:15 +00:00
KevinX8
7517cbe14f New translations strings.xml (Sinhala) 2021-02-05 17:48:11 +00:00
KevinX8
a34af2edbd New translations strings.xml (Estonian) 2021-02-05 17:48:09 +00:00
KevinX8
d10a9b2fca New translations strings.xml (Marathi) 2021-02-05 17:48:08 +00:00
KevinX8
26cacd813d New translations strings.xml (Bengali) 2021-02-05 17:48:06 +00:00
KevinX8
cbfd0e54c4 New translations strings.xml (Tamil) 2021-02-05 17:48:05 +00:00
KevinX8
8318a4a819 New translations strings.xml (Italian) 2021-02-05 17:48:03 +00:00
KevinX8
1cd0e8e48d New translations strings.xml (Portuguese, Brazilian) 2021-02-05 17:48:02 +00:00
KevinX8
eb21e1dde5 New translations strings.xml (Chinese Traditional) 2021-02-05 17:48:00 +00:00
KevinX8
d170f44a88 New translations strings.xml (Swedish) 2021-02-05 17:47:57 +00:00
KevinX8
3d9cec54c2 New translations strings.xml (Serbian (Cyrillic)) 2021-02-05 17:47:55 +00:00
KevinX8
ad46571905 New translations strings.xml (Russian) 2021-02-05 17:47:53 +00:00
KevinX8
cddd9951f2 New translations strings.xml (Portuguese) 2021-02-05 17:47:52 +00:00
KevinX8
9e41333d22 New translations strings.xml (Polish) 2021-02-05 17:47:50 +00:00
KevinX8
aa2fcd1ff3 New translations strings.xml (Punjabi) 2021-02-05 17:47:48 +00:00
KevinX8
6e16620a8d New translations strings.xml (Norwegian) 2021-02-05 17:47:47 +00:00
KevinX8
d0c3dbca70 New translations strings.xml (Dutch) 2021-02-05 17:47:45 +00:00
KevinX8
508e7e3d70 New translations strings.xml (Kurdish) 2021-02-05 17:47:43 +00:00
KevinX8
edfdaeea3a New translations strings.xml (Vietnamese) 2021-02-05 17:47:41 +00:00
KevinX8
6780e34da0 New translations strings.xml (Turkish) 2021-02-05 17:47:40 +00:00
KevinX8
7f6d0b30fb
Merge pull request #406 from YTVanced/dev
Manager v2.4.0 release
2021-02-05 10:37:53 +00:00
X1nto
e5a0050cb5 rollback 2021-02-05 14:19:44 +04:00
X1nto
2c7f040b21 refactored faq to guide 2021-02-05 14:17:15 +04:00
KevinX8
53c164e532
New Crowdin updates (#405)
* New translations strings.xml (Malayalam)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Tamil)
2021-02-05 10:06:12 +00:00
KevinX8
ece088b9b3 Merge remote-tracking branch 'origin/dev' into dev 2021-02-05 10:00:37 +00:00
KevinX8
bab9ab0a93 bump okhttp3 & coroutines to latest stable 2021-02-05 10:00:06 +00:00
X1nto
0abf89acbb removed useless variable 2021-02-05 13:57:48 +04:00
X1nto
f99c20c1de cleanup 2021-02-05 13:34:43 +04:00
X1nto
63aeab827a rounded corners for accent color dialog 2021-02-05 13:32:43 +04:00
X1nto
930f37fa17 updated strings 2021-02-05 13:27:46 +04:00
X1nto
61eed341ff Merge branch 'dev' of https://github.com/YTVanced/VancedManager into dev 2021-02-05 13:07:29 +04:00
X1nto
f087893557 fixed some background crashes 2021-02-05 13:07:05 +04:00
KevinX8
808327b697
New Crowdin updates (#394)
* New translations strings.xml (Thai)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Spanish)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Greek)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Korean)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Finnish)

* New translations strings.xml (Hindi)

* New translations strings.xml (Romanian)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Arabic)

* New translations strings.xml (Catalan)

* New translations strings.xml (Czech)

* New translations strings.xml (Danish)

* New translations strings.xml (German)

* New translations strings.xml (Punjabi, Pakistan)

* New translations strings.xml (Turkish)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Kurdish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Punjabi)

* New translations strings.xml (Polish)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Russian)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Swedish)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Italian)

* New translations strings.xml (Tamil)

* New translations strings.xml (Bengali)

* New translations strings.xml (Marathi)

* New translations strings.xml (Estonian)

* New translations strings.xml (Sinhala)

* New translations strings.xml (Bengali, India)

* New translations strings.xml (Kurmanji (Kurdish))

* New translations strings.xml (Pashto)

* New translations strings.xml (Somali)

* New translations strings.xml (Punjabi, Pakistan)

* New translations strings.xml (Georgian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Japanese)

* New translations strings.xml (Filipino)

* New translations strings.xml (Thai)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Spanish)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Greek)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Korean)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Finnish)

* New translations strings.xml (Hindi)

* New translations strings.xml (Romanian)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Arabic)

* New translations strings.xml (Catalan)

* New translations strings.xml (Czech)

* New translations strings.xml (Danish)

* New translations strings.xml (German)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Kurdish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Punjabi)

* New translations strings.xml (Polish)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Russian)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Swedish)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Italian)

* New translations strings.xml (Tamil)

* New translations strings.xml (Bengali)

* New translations strings.xml (Marathi)

* New translations strings.xml (Estonian)

* New translations strings.xml (Sinhala)

* New translations strings.xml (Bengali, India)

* New translations strings.xml (Kurmanji (Kurdish))

* New translations strings.xml (Pashto)

* New translations strings.xml (Somali)

* New translations strings.xml (Punjabi, Pakistan)

* New translations strings.xml (Georgian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Japanese)

* New translations strings.xml (Filipino)

* New translations strings.xml (Thai)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Spanish)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Greek)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Korean)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Finnish)

* New translations strings.xml (Hindi)

* New translations strings.xml (Romanian)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Arabic)

* New translations strings.xml (Catalan)

* New translations strings.xml (Czech)

* New translations strings.xml (Danish)

* New translations strings.xml (German)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Greek)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Korean)

* New translations strings.xml (Arabic)

* New translations strings.xml (German)

* New translations strings.xml (Italian)

* New translations strings.xml (Polish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Danish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Korean)

* New translations strings.xml (Croatian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Russian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Greek)

* New translations strings.xml (Croatian)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Turkish)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Kurdish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Punjabi)

* New translations strings.xml (Polish)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Russian)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Swedish)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Italian)

* New translations strings.xml (Tamil)

* New translations strings.xml (Bengali)

* New translations strings.xml (Marathi)

* New translations strings.xml (Estonian)

* New translations strings.xml (Sinhala)

* New translations strings.xml (Bengali, India)

* New translations strings.xml (Kurmanji (Kurdish))

* New translations strings.xml (Pashto)

* New translations strings.xml (Somali)

* New translations strings.xml (Punjabi, Pakistan)

* New translations strings.xml (Georgian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Japanese)

* New translations strings.xml (Filipino)

* New translations strings.xml (Thai)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Spanish)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Greek)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Korean)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Finnish)

* New translations strings.xml (Hindi)

* New translations strings.xml (Romanian)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Arabic)

* New translations strings.xml (Catalan)

* New translations strings.xml (Czech)

* New translations strings.xml (Danish)

* New translations strings.xml (German)

* New translations strings.xml (Bulgarian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Kurdish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Punjabi)

* New translations strings.xml (Polish)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Russian)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Swedish)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Italian)

* New translations strings.xml (Tamil)

* New translations strings.xml (Bengali)

* New translations strings.xml (Marathi)

* New translations strings.xml (Estonian)

* New translations strings.xml (Sinhala)

* New translations strings.xml (Bengali, India)

* New translations strings.xml (Kurmanji (Kurdish))

* New translations strings.xml (Pashto)

* New translations strings.xml (Somali)

* New translations strings.xml (Punjabi, Pakistan)

* New translations strings.xml (Georgian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Japanese)

* New translations strings.xml (Filipino)

* New translations strings.xml (Thai)

* New translations strings.xml (Malayalam)

* New translations strings.xml (Spanish)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Greek)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Korean)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Croatian)

* New translations strings.xml (Azerbaijani)

* New translations strings.xml (Sorani (Kurdish))

* New translations strings.xml (Finnish)

* New translations strings.xml (Hindi)

* New translations strings.xml (Romanian)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Arabic)

* New translations strings.xml (Catalan)

* New translations strings.xml (Czech)

* New translations strings.xml (Danish)

* New translations strings.xml (German)

* New translations strings.xml (Bulgarian)
2021-02-04 23:11:29 +00:00
Tornike Khintibidze
0519cd4abd
Removed shitty joke from readmeme 2021-02-04 20:50:49 +04:00
Tornike Khintibidze
b30e79069c
Update README.md 2021-02-04 20:47:50 +04:00
X1nto
a71f834e36 updated gradle files 2021-02-04 20:10:35 +04:00
X1nto
2973d1db92 version bumpup 2021-02-04 19:58:02 +04:00
X1nto
928aec22e9 adjusted save button margins again 2021-02-04 19:36:12 +04:00
X1nto
15a28473e0 adjusted save button margins 2021-02-04 19:35:17 +04:00
X1nto
d4c868c1e4 enabled instant support for FAQ 2021-02-04 19:30:52 +04:00
X1nto
6a76edd101 small adjustment 2021-02-04 12:36:09 +04:00
X1nto
a494951831 improved faq button 2021-02-04 12:35:07 +04:00
X1nto
a18f9c05a9 string adjustments 2021-02-04 11:56:11 +04:00
X1nto
351f849da8 added FAQ button 2021-02-04 11:55:12 +04:00
X1nto
efa9ec7bc6 fixed incorrect error code by unifying error reporters 2021-02-04 11:47:13 +04:00
X1nto
44351912b4 fixed accent dialog 2021-02-04 11:29:58 +04:00
X1nto
a3fd2111d4 fixed notification adapter 2021-02-04 11:27:55 +04:00
X1nto
ed39a2ebf6 removed unused attribute 2021-02-03 23:45:03 +04:00
X1nto
8643ced9f4 fixed accent color for slider 2021-02-03 23:43:41 +04:00
X1nto
9c2b530d4d added log fragment 2021-02-03 22:24:28 +04:00
X1nto
d58a2c3f71 fixed warnings for music and vanced 2021-02-03 20:12:32 +04:00
X1nto
3a4fa0abe0 Merge branch 'dev' of https://github.com/YTVanced/VancedManager into dev 2021-02-01 19:54:08 +04:00
X1nto
89611742ed fixed some strings not being translated 2021-02-01 19:54:03 +04:00
KevinX8
9e41d32592
Update strings.xml 2021-01-31 21:01:33 +00:00
KevinX8
83d184ca44
fix 2021-01-31 20:42:11 +00:00
X1nto
7e63ef1a6a fixed grammar lol 2021-01-31 21:09:56 +04:00
X1nto
bff17853d7 fixed notifications not turning off when unselecting app 2021-01-30 13:53:13 +04:00
X1nto
6a0bd14680 added warning for music 2021-01-28 15:23:36 +04:00
X1nto
a7fa67e726 updated notification logo 2021-01-28 13:26:30 +04:00
241 changed files with 6362 additions and 4326 deletions

View file

@ -1,29 +0,0 @@
---
name: Bug issue template
about: Vanced Manager Bug template
title: ''
labels: ''
assignees: ''
---
**Please only report your issue here, if all points below are true**
- I installed the App from [vancedapp.com](https://vancedapp.com), this github repository or the Vanced Discord server
- I am using the latest version
- This is an issue in the Vanced Manager app (NOT Youtube Vanced)
- This issue keeps re-occurring every time I try
- For MIUI users: I disabled MIUI optimisation
**Phone Specifications:**
- Brand:
- Operating System:
- Android Version:
- Vanced Manager Version:
**Please describe the problem you are having in as much detail as possible:**
**Steps to reproduce:**
**Further details:**

View file

@ -0,0 +1,41 @@
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug"]
assignees:
- X1nto
body:
- type: textarea
id: device-info
attributes:
label: Device
description: What device are you using?
value: |
Device:
Operating System:
Android Version:
validations:
required: true
- type: textarea
id: manager-version
attributes:
label: Version
description: What version of Vanced Manager are you using?
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: Bug Description
description: Describe the bug and how to reproduce it in as much detail as possible.
validations:
required: true
- type: checkboxes
id: is-manager-bug
attributes:
label: Additional checks
options:
- label: I have checked other bug reports and this is not a duplicate.
required: true
- label: This is a bug in Vanced Manager and NOT YouTube Vanced/YouTube Vanced Music/Vanced microG.
required: true

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1 @@
blank_issues_enabled: false

View file

@ -0,0 +1,29 @@
name: Feature Request
description: Request a feature
title: "[Feature]: "
labels: ["enhancement"]
assignees:
- X1nto
body:
- type: textarea
id: suggestion
attributes:
label: Suggestion
validations:
required: true
- type: textarea
id: suggestion-relevancy
attributes:
label: Additional Information
description: Why is this suggestion relevant?
validations:
required: true
- type: checkboxes
id: is-manager-suggestion
attributes:
label: Additional checks
options:
- label: I have checked other feature requests and this is not a duplicate.
required: true
- label: This is a suggestion for Vanced Manager and NOT YouTube Vanced/YouTube Vanced Music/Vanced microG.
required: true

View file

@ -4,27 +4,28 @@ on:
push:
branches:
- dev
paths-ignore:
- '**.md'
pull_request:
branches:
- dev
paths-ignore:
- '**.md'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
- name: set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 1.8
java-version: 11
- name: Grant rights
run: chmod +x ./gradlew
- name: Build project with Gradle
run: ./gradlew build
- name: Build Debug APK with Gradle
- name: Build debug APK with Gradle
run: ./gradlew assembleDebug
- name: Upload Debug

2
.gitignore vendored
View file

@ -6,5 +6,5 @@ app/src/main/java/com/vanced/manager/core/base/DummyJava.java
app/build/
app/release
local.properties
/.github/
*.iml
.vscode/

View file

@ -1,35 +1,64 @@
Pull requests should be made to the Dev branch as that is the working branch, master is for release code.
======
For anyone who wants to provide translations please submit them to https://crowdin.com/project/vanced-manager as we also use it for YouTube Vanced. Any issues with translations should be posted there too.
======
Vanced FAQ (from the faq branch) now available on the playstore! https://play.google.com/store/apps/details?id=com.vanced.faq
## The FAQ app has just been suspended due to "Impersonating Vanced", an appeal has been filed, reporting other apps which impersonate Vanced on the play store is appreciated.
[![Github All Releases](https://img.shields.io/github/downloads/YTVanced/VancedManager/total.svg)](https://github.com/YTVanced/VancedManager/releases/latest) [![Github All Releases](https://img.shields.io/github/release/YTVanced/VancedManager.svg)](https://github.com/YTVanced/VancedManager/releases/latest)
# Vanced Manager
Hi, when we released Vanced 15.05.54, people were upset because it used the .apks format, which was way harder to install than a traditional .apk file. Even though we wrote clear instructions on how to install the new Vanced build, people still couldn't figure it out.
Then we thought, "why don't we make a manager for vanced, which will download, update and uninstall Vanced and MicroG, have an easy and understandable UI and be less than 10mb?" and that's how Vanced Manager was born.
<div>
[![Github All Releases](https://img.shields.io/github/downloads/YTVanced/VancedManager/total.svg?style=for-the-badge)](https://github.com/YTVanced/VancedManager/releases/latest) [![Github All Releases](https://img.shields.io/github/release/YTVanced/VancedManager.svg?style=for-the-badge)](https://github.com/YTVanced/VancedManager/releases/latest)
</div>
## Introduction
Hi, when we released Vanced 15.05.54, people were upset because it used the .apks format, which was burdensome to install than a traditional .apk file. Even though we wrote clear instructions on how to install the new Vanced build, people still couldn't figure it out.
Then we thought, "why don't we make a manager for vanced, which will download, update and uninstall Vanced and MicroG, have an easy and user-friendly UI and be less than 10mb?" and that's how Vanced Manager was born.
After 3 months of development, we are finally ready to introduce Vanced Manager to the masses. Vanced manager can easily install and uninstall vanced and microg, has various settings for customisation and better experience. The Manager comes with an easy-to-use interface
After 3 months of development, we are finally ready to Introduce [Vanced Manager](https://github.com/YTVanced/VancedManager) to the masses!!
##### Background download/installation feature is no longer supported due to problems with some ROMs, please do NOT report issues regarding background activity.
## Features
## Vanced Developers
- xfileFIN
- KevinX8
- Zanezam
- Laura Almeida
- Vanced manager can easily install and uninstall Vanced and MicroG.
- It has various settings for customization and better experience.
- The Manager comes with an easy-to-use Interface.
## Vanced Manager Developers
- Xinto (X1nto)
- Koopah (ostajic)
</br>
## Contributors
- AioiLight
- HaliksaR
<div class="note">
<p><strong>NOTE: </strong>Background download/installation feature is no longer supported due to problems with some ROMs, please <b>DO NOT</b> report issues regarding background activity.</p>
</div>
<!-- ##### Background download/installation feature is no longer supported due to problems with some ROMs, please do NOT report issues regarding background activity. -->
## Contributions
Pull Requests should be made to the [Dev](https://github.com/YTVanced/VancedManager) Branch as that is the working branch, master is for Release code only.
For anyone who wants to provide translations please submit them to this [link](https://crowdin.com/project/vanced-manager) as we also use it for YouTube Vanced. Any issues with translations should be posted there too.
## TODO
- [ ] Clean up the ViewModel and DataModel code
- [ ] Migrate to Jetpack Compose when it's officially released
## Building
<div>
[![Build](https://github.com/YTVanced/VancedManager/actions/workflows/debug.yml/badge.svg?branch=dev)](https://github.com/YTVanced/VancedManager/actions/workflows/debug.yml)
</div>
## Using Android Studio
Clone the Repository, open it in Android Studio and build the application.
## Google Advanced Protection Program
If you are using this feature on your Google account, you must either disable it or log out from your Google account before installing Youtube Vanced via Vanced Manager.
The Google Advanced Protection Program does not allow the installation of apps from unknown sources. These security measures are tied to the protected account and not the device. After the installation, you will be able to log back in or enroll again into the program.
## Using Command Line
#### On Windows:
```powershell
.\gradlew.bat assembleDebug
```
#### On Linux/macOS:
```bash
chmod +x gradlew
./gradlew assembleDebug
```
## Credits
- topjohnwu for his wonderful [LibSU](https://github.com/topjohnwu/libsu)
- aefyr for [SAI](https://github.com/aefyr/SAI), which was an inspiration for our Manager
- kittinunf for [Fuel](https://github.com/kittinunf/Fuel) HTTP client
- cbeust for [klaxon](https://github.com/cbeust/klaxon) JSON parser

View file

@ -48,6 +48,3 @@ Vanced Manager sucks 100% of your CPU to mine Bitcoins, this is a new technique
![Zanezam](https://i.imgur.com/QVcXA6q.png)
- Laura Almeida
![Laura Almeida](https://i.imgur.com/ovVD939.png)
###### If someone is reading this pls help me, KevinX8 is bullying me and forces me to develop manager. please send bobs and veganas and call 911

View file

@ -6,28 +6,27 @@ plugins {
id("com.google.firebase.crashlytics")
id("com.google.firebase.firebase-perf")
id("androidx.navigation.safeargs.kotlin")
id("kotlin-android")
}
android {
compileSdkVersion(30)
compileSdk = 31
defaultConfig {
applicationId = "com.vanced.manager"
minSdkVersion(21)
targetSdkVersion(30)
versionCode = 230
versionName = "2.3.0 (MicroShitMoment)"
minSdk = 21
targetSdk = 31
versionCode = 262
versionName = "2.6.2 (Crimson)"
vectorDrawables.useSupportLibrary = true
vectorDrawables {
useSupportLibrary = true
}
buildConfigField("String[]", "MANAGER_LANGUAGES", "{" + getLanguages() + "}")
buildConfigField("Boolean", "ENABLE_CROWDIN_AUTH", "false")
buildConfigField("String", "CROWDIN_HASH", "\"${System.getenv("CROWDIN_HASH")}\"")
buildConfigField("String", "CROWDIN_CLIENT_ID", "\"${System.getenv("CROWDIN_CLIENT_ID")}\"")
buildConfigField("String", "CROWDIN_CLIENT_SECRET", "\"${System.getenv("CROWDIN_CLIENT_SECRET")}\"")
buildConfigField("String[]", "MANAGER_LANGUAGES", "{$languages}")
}
lintOptions {
lint {
disable("MissingTranslation", "ExtraTranslation")
}
@ -43,13 +42,14 @@ android {
}
buildFeatures {
dataBinding = true // ObservableField migrate to flow or liveData
viewBinding = true
}
packagingOptions {
exclude("META-INF/DEPENDENCIES")
exclude("META-INF/*.kotlin_module")
resources {
excludes += "META-INF/DEPENDENCIES"
excludes += "META-INF/*.kotlin_module"
}
}
// To inline the bytecode built with JVM target 1.8 into
@ -68,75 +68,72 @@ android {
}
fun getLanguages(): String {
val languages: String get() {
val langs = arrayListOf("en", "bn_BD", "bn_IN", "pa_IN", "pa_PK", "pt_BR", "pt_PT", "zh_CN", "zh_TW")
val exceptions = arrayOf("bn", "pa", "pt", "zh")
File("$projectDir/src/main/res").listFiles()?.forEach { dir ->
if (dir.name.startsWith("values-") && !dir.name.contains("v23")) {
val dirname = dir.name.substringAfter("-").substringBefore("-")
if (!exceptions.any { dirname == it }) {
langs.add(dirname)
}
File("$projectDir/src/main/res").listFiles()?.filter {
val name = it.name
name.startsWith("values-") && !name.contains("v23")
}?.forEach { dir ->
val dirname = dir.name.substringAfter("-").substringBefore("-")
if (!exceptions.contains(dirname)) {
langs.add(dirname)
}
}
return langs.joinToString(", ") { "\"$it\"" }
}
dependencies {
implementation(project(":core-presentation"))
implementation(project(":core-ui"))
implementation(project(":library-network"))
// Kotlin
// Kotlin
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
// AndroidX
implementation("androidx.appcompat:appcompat:1.2.0")
// AndroidX
implementation("androidx.appcompat:appcompat:1.3.1")
implementation("androidx.browser:browser:1.3.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
implementation("androidx.core:core-ktx:1.3.2")
implementation("androidx.fragment:fragment-ktx:1.2.5")
implementation("androidx.lifecycle:lifecycle-livedata-core-ktx:2.2.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.1")
implementation("androidx.core:core-ktx:1.6.0")
implementation("androidx.fragment:fragment-ktx:1.3.6")
implementation("androidx.lifecycle:lifecycle-livedata-core-ktx:2.3.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1")
implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.0.0")
implementation("androidx.navigation:navigation-fragment-ktx:2.3.2")
implementation("androidx.navigation:navigation-ui-ktx:2.3.2")
implementation("androidx.navigation:navigation-fragment-ktx:2.3.5")
implementation("androidx.navigation:navigation-ui-ktx:2.3.5")
implementation("androidx.preference:preference-ktx:1.1.1")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.work:work-runtime-ktx:2.7.0-rc01")
//Appearance
implementation("com.github.madrapps:pikolo:2.0.1")
implementation("com.google.android.material:material:1.3.0-rc01")
implementation("com.github.madrapps:pikolo:2.0.2")
implementation("com.google.android.material:material:1.5.0-alpha04")
// JSON parser
implementation("com.beust:klaxon:5.4")
// Crowdin
implementation("com.crowdin.platform:mobile-sdk:1.2.0")
// Tips
implementation("com.github.florent37:viewtooltip:1.2.2")
implementation("com.beust:klaxon:5.5")
// HTTP networking
implementation("com.github.kittinunf.fuel:fuel:2.3.0")
implementation("com.github.kittinunf.fuel:fuel-coroutines:2.2.3")
implementation("com.github.kittinunf.fuel:fuel-json:2.2.3")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")
implementation("com.github.kittinunf.fuel:fuel:2.3.1")
implementation("com.github.kittinunf.fuel:fuel-coroutines:2.3.1")
implementation("com.github.kittinunf.fuel:fuel-json:2.3.1")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.2")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// Root permissions
implementation("com.github.topjohnwu.libsu:core:3.0.2")
implementation("com.github.topjohnwu.libsu:io:3.0.2")
val libsuVersion = "3.1.2"
implementation("com.github.topjohnwu.libsu:core:$libsuVersion")
implementation("com.github.topjohnwu.libsu:io:$libsuVersion")
//implementation("com.github.topjohnwu.libsu:busybox:$libsuVersion")
// Layout
implementation("com.google.android:flexbox:2.0.1")
implementation("com.google.android.flexbox:flexbox:3.0.0")
// Firebase
implementation("com.google.firebase:firebase-analytics-ktx:18.0.1")
implementation("com.google.firebase:firebase-crashlytics:17.3.0")
implementation("com.google.firebase:firebase-messaging:21.0.1")
implementation("com.google.firebase:firebase-perf:19.1.0")
implementation("com.google.firebase:firebase-analytics-ktx:19.0.2")
implementation("com.google.firebase:firebase-crashlytics:18.2.3")
implementation("com.google.firebase:firebase-messaging:22.0.0")
implementation("com.google.firebase:firebase-perf:20.0.3")
}

View file

@ -17,7 +17,7 @@
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
-keepattributes SourceFile, LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.

View file

@ -6,9 +6,9 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- is required for some Android 5.x devices -->
<uses-permission
@ -21,6 +21,7 @@
<package android:name="com.vanced.android.apps.youtube.music" />
<package android:name="com.google.android.apps.youtube.music" />
<package android:name="com.mgoogle.android.gms" />
<package android:name="com.vanced.faq" />
<package android:name="com.android.vending" />
</queries>
@ -31,13 +32,13 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
tools:ignore="UnusedAttribute">
android:supportsRtl="true">
<activity
android:name=".ui.core.SplashScreenActivity"
android:name=".ui.SplashScreenActivity"
android:label="@string/app_name"
android:theme="@style/SplashTheme">
android:theme="@style/SplashTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -55,10 +56,10 @@
<activity
android:name=".ui.MainActivity"
android:configChanges="layoutDirection|locale"
android:exported="true"
android:configChanges="layoutDirection|locale|keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:theme="@style/DarkTheme">
android:theme="@style/DarkTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -66,8 +67,7 @@
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="vancedapp.com"
android:pathPrefix="/downloads"/>
android:host="api.vancedapp.com"/>
</intent-filter>
@ -76,8 +76,8 @@
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -1,123 +0,0 @@
package com.vanced.manager.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleOwner
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import androidx.recyclerview.widget.RecyclerView
import com.github.florent37.viewtooltip.ViewTooltip
import com.vanced.manager.R
import com.vanced.manager.databinding.ViewAppBinding
import com.vanced.manager.model.DataModel
import com.vanced.manager.model.RootDataModel
import com.vanced.manager.ui.dialogs.AppInfoDialog
import com.vanced.manager.ui.viewmodels.HomeViewModel
import com.vanced.manager.utils.enableMusic
import com.vanced.manager.utils.enableVanced
import com.vanced.manager.utils.managerVariant
class AppListAdapter(
private val context: FragmentActivity,
private val viewModel: HomeViewModel,
private val lifecycleOwner: LifecycleOwner,
private val tooltip: ViewTooltip
) : RecyclerView.Adapter<AppListAdapter.ListViewHolder>() {
val apps = mutableListOf<String>()
private val dataModels = mutableListOf<DataModel?>()
private val rootDataModels = mutableListOf<RootDataModel?>()
private val prefs = getDefaultSharedPreferences(context)
private var itemCount = 0
private val isRoot = prefs.managerVariant == "root"
inner class ListViewHolder(private val binding: ViewAppBinding) : RecyclerView.ViewHolder(binding.root) {
val appCard = binding.appCard
fun bind(position: Int) {
val dataModel = if (isRoot) rootDataModels[position] else dataModels[position]
with(binding) {
appName.text = dataModel?.appName
dataModel?.buttonTxt?.observe(lifecycleOwner) {
appInstallButton.text = it
}
appInstallButton.setOnClickListener {
viewModel.openInstallDialog(it, apps[position])
}
appUninstall.setOnClickListener {
dataModel?.appPkg?.let { it1 -> viewModel.uninstallPackage(it1) }
}
appLaunch.setOnClickListener {
viewModel.launchApp(apps[position], isRoot)
}
with(dataModel?.isAppInstalled?.value) {
appUninstall.isVisible = this == true
appLaunch.isVisible = this == true
}
dataModel?.isAppInstalled?.observe(lifecycleOwner) {
appUninstall.isVisible = it
appLaunch.isVisible = it
}
dataModel?.versionName?.observe(lifecycleOwner) {
appRemoteVersion.text = it
}
dataModel?.installedVersionName?.observe(lifecycleOwner) {
appInstalledVersion.text = it
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
val view = ViewAppBinding.inflate(LayoutInflater.from(context), parent, false)
return ListViewHolder(view)
}
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
holder.bind(position)
val dataModel = if (isRoot) rootDataModels[position] else dataModels[position]
holder.appCard.setOnClickListener {
tooltip.close()
AppInfoDialog.newInstance(
appName = apps[position],
appIcon = dataModel?.appIcon,
changelog = dataModel?.changelog?.value
).show(context.supportFragmentManager, "info")
}
}
override fun getItemCount(): Int = itemCount
init {
if (prefs.enableVanced) {
if (isRoot) {
rootDataModels.add(viewModel.vancedRootModel.value)
} else {
dataModels.add(viewModel.vancedModel.value)
}
apps.add(context.getString(R.string.vanced))
itemCount++
}
if (prefs.enableMusic) {
if (isRoot) {
rootDataModels.add(viewModel.musicRootModel.value)
} else {
dataModels.add(viewModel.musicModel.value)
}
apps.add(context.getString(R.string.music))
itemCount++
}
if (!isRoot) {
dataModels.add(viewModel.microgModel.value)
apps.add(context.getString(R.string.microg))
itemCount++
}
}
}

View file

@ -0,0 +1,199 @@
package com.vanced.manager.adapter
import android.animation.ValueAnimator
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.animation.addListener
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.FragmentActivity
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.card.MaterialCardView
import com.vanced.manager.R
import com.vanced.manager.databinding.ViewAppExpandableBinding
import com.vanced.manager.model.ButtonTag
import com.vanced.manager.model.DataModel
import com.vanced.manager.ui.dialogs.AppInfoDialog
import com.vanced.manager.ui.dialogs.AppUninstallDialog
import com.vanced.manager.ui.viewmodels.HomeViewModel
import com.vanced.manager.utils.*
class ExpandableAppListAdapter(
private val activity: FragmentActivity,
private val viewModel: HomeViewModel
) : RecyclerView.Adapter<ExpandableAppListAdapter.ListViewHolder>() {
private val apps = mutableListOf<String>()
private val dataModels = mutableListOf<DataModel?>()
private val prefs = getDefaultSharedPreferences(activity)
private val isRoot = prefs.managerVariant == "root"
private var isAnimationRunning = false
inner class ListViewHolder(private val binding: ViewAppExpandableBinding) :
RecyclerView.ViewHolder(binding.root) {
private var isExpanded = false
fun bind(position: Int) {
val dataModel = dataModels[position]
with(binding) {
appTitle.text = dataModel?.appName
appDescription.text = dataModel?.appDescription
dataModel?.appIcon?.let { appIcon.setImageResource(it) }
appClickableLayout.setOnClickListener {
if (isAnimationRunning) return@setOnClickListener
val rootHeight = root.measuredHeight
val expandedViewHeight = appExpandedView.height
val expandedTranslation = appClickableLayout.height.toFloat()
when (isExpanded.also { isExpanded = !isExpanded }) {
true -> {
appExpandedView.toggle(0f, 0.8f, -expandedTranslation)
root.toggleCard(rootHeight - expandedViewHeight)
appExpandArrow.rotateArrow(90f)
}
false -> {
root.toggleCard(rootHeight + expandedViewHeight)
appExpandedView.toggle(1f, 1f, expandedTranslation)
appExpandArrow.rotateArrow(-90f)
}
}
}
appUninstall.setOnClickListener {
AppUninstallDialog.newInstance(
dataModel?.appName,
dataModel?.appPkg
).show(activity.supportFragmentManager, null)
}
appLaunch.setOnClickListener {
viewModel.launchApp(apps[position], isRoot)
}
appInfo.setOnClickListener {
AppInfoDialog.newInstance(
appName = apps[position],
appIcon = dataModel?.appIcon,
changelog = dataModel?.changelog?.value
).show(activity.supportFragmentManager, "info")
}
dataModel?.buttonTag?.observe(activity) { buttonTag ->
appDownload.apply {
setOnClickListener {
viewModel.openInstallDialog(
activity.supportFragmentManager,
buttonTag,
apps[position]
)
}
appDownload.setIconResource(buttonTag.image)
contentDescription = activity.getString(
when (buttonTag) {
ButtonTag.UPDATE -> R.string.accessibility_update
ButtonTag.REINSTALL -> R.string.accessibility_reinstall
else -> R.string.accessibility_download
}
)
}
}
dataModel?.isAppInstalled?.observe(activity) {
appUninstall.isVisible = it
appLaunch.isVisible = it
}
dataModel?.versionName?.observe(activity) {
appVersionLatest.text = it
appDownload.isGone = it == activity.getString(R.string.unavailable)
}
dataModel?.installedVersionName?.observe(activity) {
appVersionInstalled.text = it
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
val view = ViewAppExpandableBinding.inflate(LayoutInflater.from(activity), parent, false)
return ListViewHolder(view)
}
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
holder.bind(position)
}
override fun getItemCount(): Int = apps.size
private fun ImageView.rotateArrow(degrees: Float) {
animate().apply {
duration = animationDuration
rotation(degrees)
}
}
private fun View.toggle(
alpha: Float,
scale: Float,
translation: Float
) {
animate().apply {
duration = animationDuration
scaleX(scale)
scaleY(scale)
alpha(alpha)
translationYBy(translation)
}
}
private fun MaterialCardView.toggleCard(resultHeight: Int) {
ValueAnimator.ofInt(measuredHeight, resultHeight).apply {
duration = animationDuration
addUpdateListener { value ->
updateLayoutParams {
height = value.animatedValue as Int
}
}
addListener(
onStart = {
isAnimationRunning = true
},
onEnd = {
isAnimationRunning = false
}
)
}.start()
}
init {
if (prefs.enableVanced) {
if (isRoot) {
dataModels.add(viewModel.vancedRootModel.value)
} else {
dataModels.add(viewModel.vancedModel.value)
}
apps.add(activity.getString(R.string.vanced))
}
if (prefs.enableMusic) {
if (isRoot) {
dataModels.add(viewModel.musicRootModel.value)
} else {
dataModels.add(viewModel.musicModel.value)
}
apps.add(activity.getString(R.string.music))
}
if (!isRoot) {
dataModels.add(viewModel.microgModel.value)
apps.add(activity.getString(R.string.microg))
}
}
companion object {
const val animationDuration = 250L
}
}

View file

@ -8,10 +8,13 @@ import com.google.firebase.messaging.FirebaseMessaging
import com.vanced.manager.R
import com.vanced.manager.databinding.ViewNotificationSettingBinding
import com.vanced.manager.model.NotifModel
import com.vanced.manager.utils.defPrefs
class GetNotifAdapter(private val context: Context) :
RecyclerView.Adapter<GetNotifAdapter.GetNotifViewHolder>() {
private val prefs = context.defPrefs
private val vanced = NotifModel(
"Vanced-Update",
context.getString(R.string.push_notifications, context.getString(R.string.vanced)),
@ -33,15 +36,24 @@ class GetNotifAdapter(private val context: Context) :
private val apps = arrayOf(vanced, music, microg)
inner class GetNotifViewHolder(val binding: ViewNotificationSettingBinding) : RecyclerView.ViewHolder(binding.root) {
inner class GetNotifViewHolder(val binding: ViewNotificationSettingBinding) :
RecyclerView.ViewHolder(binding.root) {
val switch = binding.notifSwitch
fun bind(position: Int) {
val app = apps[position]
with(binding.notifSwitch) {
setKey(apps[position].key)
setSummary(apps[position].switchSummary)
setTitle(apps[position].switchTitle)
setKey(app.key)
setSummary(app.switchSummary)
setTitle(app.switchTitle)
setDefaultValue(true)
with(prefs) {
setChecked(
getBoolean(
"enable_" + app.key.substringBefore("_"),
true
) && getBoolean(app.key, true)
)
}
}
}
}

View file

@ -57,13 +57,14 @@ class LinkAdapter(
val links = arrayOf(instagram, youtube, github, website, telegram, twitter, discord, reddit)
inner class LinkViewHolder(private val binding: ViewSocialLinkBinding) : RecyclerView.ViewHolder(binding.root) {
inner class LinkViewHolder(private val binding: ViewSocialLinkBinding) :
RecyclerView.ViewHolder(binding.root) {
val logo = binding.linkImage
fun bind(position: Int) {
binding.linkBg.setOnClickListener {
viewModel.openUrl(links[position].linkUrl)
viewModel.openUrl(context, links[position].linkUrl)
}
}
}

View file

@ -18,21 +18,22 @@ class SelectAppsAdapter(private val context: Context) :
private val vanced = SelectAppModel(
context.getString(R.string.vanced),
context.getString(R.string.select_apps_vanced),
context.getString(R.string.description_vanced),
"vanced",
prefs.enableVanced
)
private val music = SelectAppModel(
context.getString(R.string.music),
context.getString(R.string.select_apps_music),
context.getString(R.string.description_vanced_music),
"music",
prefs.enableMusic
)
val apps = arrayOf(vanced, music)
inner class SelectAppsViewHolder(binding: ViewAppCheckboxBinding) : RecyclerView.ViewHolder(binding.root) {
inner class SelectAppsViewHolder(binding: ViewAppCheckboxBinding) :
RecyclerView.ViewHolder(binding.root) {
val appName = binding.appCheckboxText
val appDescription = binding.appCheckboxDescription
val appCard = binding.appCheckboxBg

View file

@ -9,15 +9,19 @@ import com.vanced.manager.R
import com.vanced.manager.databinding.ViewSponsorBinding
import com.vanced.manager.model.SponsorModel
import com.vanced.manager.ui.viewmodels.HomeViewModel
import com.vanced.manager.utils.LIGHT
import com.vanced.manager.utils.currentTheme
class SponsorAdapter(
private val context: Context,
private val viewModel: HomeViewModel,
//private val json: ObservableField<JsonObject?>
private val viewModel: HomeViewModel
) : RecyclerView.Adapter<SponsorAdapter.LinkViewHolder>() {
private val brave = SponsorModel(
AppCompatResources.getDrawable(context, R.drawable.ic_brave),
if (currentTheme == LIGHT) AppCompatResources.getDrawable(
context,
R.drawable.ic_brave_light
) else AppCompatResources.getDrawable(context, R.drawable.ic_brave),
"Brave",
BRAVE
)
@ -38,7 +42,7 @@ class SponsorAdapter(
with(binding) {
sponsorName.text = sponsors[position].name
cardSponsor.setOnClickListener {
viewModel.openUrl(sponsors[position].url)
viewModel.openUrl(context, sponsors[position].url)
}
}
}

View file

@ -0,0 +1,23 @@
package com.vanced.manager.adapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.vanced.manager.ui.fragments.GrantRootFragment
import com.vanced.manager.ui.fragments.SelectAppsFragment
import com.vanced.manager.ui.fragments.WelcomeFragment
class WelcomePageAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
override fun getItemCount(): Int = 3
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> WelcomeFragment()
1 -> SelectAppsFragment()
2 -> GrantRootFragment()
else -> throw IllegalArgumentException("Unknown fragment")
}
}
}

View file

@ -1,21 +1,18 @@
package com.vanced.manager.core
import android.app.Application
import android.content.res.Configuration
import android.util.Log
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.crowdin.platform.Crowdin
import com.crowdin.platform.CrowdinConfig
import com.crowdin.platform.data.model.AuthConfig
import com.crowdin.platform.data.remote.NetworkType
import com.vanced.manager.BuildConfig.*
import com.topjohnwu.superuser.Shell
import com.vanced.manager.BuildConfig
import com.vanced.manager.utils.loadJson
import com.vanced.manager.utils.managerAccent
import com.vanced.manager.utils.mutableAccentColor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
open class App: Application() {
class App : Application() {
private val prefs by lazy { getDefaultSharedPreferences(this) }
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
@ -23,30 +20,15 @@ open class App: Application() {
override fun onCreate() {
scope.launch { loadJson(this@App) }
super.onCreate()
Crowdin.init(this,
CrowdinConfig.Builder().apply {
withDistributionHash(CROWDIN_HASH)
withNetworkType(NetworkType.WIFI)
if (ENABLE_CROWDIN_AUTH) {
if (prefs.getBoolean("crowdin_real_time", false))
withRealTimeUpdates()
withSourceLanguage("en")
withAuthConfig(AuthConfig(CROWDIN_CLIENT_ID, CROWDIN_CLIENT_SECRET, null))
withScreenshotEnabled()
Log.d("test", "crowdin credentials")
}
}.build()
mutableAccentColor.value = prefs.managerAccent
Shell.enableVerboseLogging = BuildConfig.DEBUG
Shell.setDefaultBuilder(
Shell.Builder
.create()
.setFlags(Shell.FLAG_REDIRECT_STDERR)
//.setInitializers(BusyBoxInstaller::class.java) //TODO fix busybox
.setTimeout(10)
)
if (prefs.getBoolean("crowdin_upload_screenshot", false))
Crowdin.registerScreenShotContentObserver(this)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
Crowdin.onConfigurationChanged()
}
}

View file

@ -0,0 +1,37 @@
package com.vanced.manager.core
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
/**
* CombinedLiveData is a helper class to combine results from two LiveData sources.
* @param combine Function reference that will be used to combine all LiveData data.
* @param R The type of data returned after combining all LiveData data.
* Usage:
* CombinedLiveData(
* getLiveData1(),
* getLiveData2()
* ) { data1, data2 ->
* // Use datas[0], datas[1], ..., datas[N] to return a value
* }
*/
class CombinedLiveData<R, A, B>(
liveDataA: LiveData<A>,
liveDataB: LiveData<B>,
private val combine: (a: A?, b: B?) -> R
) : MediatorLiveData<R>() {
private var a: A? = null
private var b: B? = null
init {
addSource(liveDataA) {
a = it
value = combine(a, b)
}
addSource(liveDataB) {
b = it
value = combine(a, b)
}
}
}

View file

@ -2,11 +2,9 @@ package com.vanced.manager.core.downloader
import android.content.Context
import com.vanced.manager.R
import com.vanced.manager.utils.*
import com.vanced.manager.utils.DownloadHelper.download
import com.vanced.manager.utils.DownloadHelper.downloadProgress
import com.vanced.manager.utils.PackageHelper.install
import com.vanced.manager.utils.baseInstallUrl
import com.vanced.manager.utils.microg
object MicrogDownloader {
@ -18,14 +16,14 @@ object MicrogDownloader {
download(url, "$baseInstallUrl/", folderName, fileName, context, onDownloadComplete = {
startMicrogInstall(context)
}, onError = {
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, fileName))
downloadingFile.postValue(context.getString(R.string.error_downloading, fileName))
})
}
fun startMicrogInstall(context: Context) {
downloadProgress.value?.installing?.postValue(true)
downloadProgress.value?.postReset()
installing.postValue(true)
postReset()
install("${context.getExternalFilesDir(folderName)}/$fileName", context)
}
}

View file

@ -6,7 +6,6 @@ import com.vanced.manager.utils.*
import com.vanced.manager.utils.AppUtils.musicRootPkg
import com.vanced.manager.utils.AppUtils.validateTheme
import com.vanced.manager.utils.DownloadHelper.download
import com.vanced.manager.utils.DownloadHelper.downloadProgress
import com.vanced.manager.utils.PackageHelper.downloadStockCheck
import com.vanced.manager.utils.PackageHelper.install
import com.vanced.manager.utils.PackageHelper.installMusicRoot
@ -14,19 +13,21 @@ import com.vanced.manager.utils.PackageHelper.installMusicRoot
object MusicDownloader {
private var variant: String? = null
private var version: String? = null
private var musicVersion: String? = null
private var versionCode: Int? = null
private var baseurl = ""
private var folderName: String? = null
private var downloadPath: String? = null
private var hashUrl: String? = null
fun downloadMusic(context: Context) {
fun downloadMusic(context: Context, version: String? = null) {
val prefs = context.defPrefs
version = prefs.musicVersion?.getLatestAppVersion(musicVersions.value?.value ?: listOf(""))
musicVersion = version ?: prefs.musicVersion?.getLatestAppVersion(
musicVersions.value?.value ?: listOf("")
)
versionCode = music.value?.int("versionCode")
variant = prefs.managerVariant
baseurl = "$baseInstallUrl/music/v$version"
baseurl = "$baseInstallUrl/music/v$musicVersion"
folderName = "music/$variant"
downloadPath = context.getExternalFilesDir(folderName)?.path
hashUrl = "$baseurl/hash.json"
@ -36,36 +37,48 @@ object MusicDownloader {
private fun downloadApk(context: Context, apk: String = "music") {
val url = if (apk == "stock") "$baseurl/stock/${getArch()}.apk" else "$baseurl/$variant.apk"
download(url, "$baseurl/", folderName!!, getFileNameFromUrl(url), context, onDownloadComplete = {
if (variant == "root" && apk != "stock") {
downloadApk(context, "stock")
return@download
}
when (apk) {
"music" -> {
if (variant == "root") {
if (validateTheme(downloadPath!!, "root", hashUrl!!, context)) {
if (downloadStockCheck(musicRootPkg, versionCode!!, context))
downloadApk(context, "stock")
else
startMusicInstall(context)
} else {
downloadApk(context, apk)
}
} else
startMusicInstall(context)
download(
url,
"$baseurl/",
folderName!!,
getFileNameFromUrl(url),
context,
onDownloadComplete = {
if (variant == "root" && apk != "stock") {
downloadApk(context, "stock")
return@download
}
"stock" -> startMusicInstall(context)
}
}, onError = {
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, getFileNameFromUrl(url)))
})
when (apk) {
"music" -> {
if (variant == "root") {
if (validateTheme(downloadPath!!, "root", hashUrl!!, context)) {
if (downloadStockCheck(musicRootPkg, versionCode!!, context))
downloadApk(context, "stock")
else
startMusicInstall(context)
} else {
downloadApk(context, apk)
}
} else
startMusicInstall(context)
}
"stock" -> startMusicInstall(context)
}
},
onError = {
downloadingFile.postValue(
context.getString(
R.string.error_downloading,
getFileNameFromUrl(url)
)
)
})
}
fun startMusicInstall(context: Context) {
downloadProgress.value?.installing?.postValue(true)
downloadProgress.value?.postReset()
installing.postValue(true)
postReset()
if (variant == "root")
installMusicRoot(context)
else

View file

@ -2,22 +2,21 @@ package com.vanced.manager.core.downloader
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.logEvent
import com.vanced.manager.R
import com.vanced.manager.utils.*
import com.vanced.manager.utils.AppUtils.log
import com.vanced.manager.utils.AppUtils.validateTheme
import com.vanced.manager.utils.AppUtils.vancedRootPkg
import com.vanced.manager.utils.DownloadHelper.download
import com.vanced.manager.utils.DownloadHelper.downloadProgress
import com.vanced.manager.utils.PackageHelper.downloadStockCheck
import com.vanced.manager.utils.PackageHelper.installVanced
import com.vanced.manager.utils.PackageHelper.installSplitApkFiles
import com.vanced.manager.utils.PackageHelper.installVancedRoot
import java.io.File
object VancedDownloader {
private lateinit var prefs: SharedPreferences
private lateinit var defPrefs: SharedPreferences
private lateinit var arch: String
@ -48,7 +47,9 @@ object VancedDownloader {
lang = it.split(", ").toMutableList()
}
theme = prefs.theme
vancedVersion = version ?: defPrefs.vancedVersion?.getLatestAppVersion(vancedVersions.value?.value ?: listOf(""))
vancedVersion = version ?: defPrefs.vancedVersion?.getLatestAppVersion(
vancedVersions.value?.value ?: listOf("")
)
themePath = "$baseInstallUrl/apks/v$vancedVersion/$variant/Theme"
hashUrl = "apks/v$vancedVersion/$variant/Theme/hash.json"
arch = getArch()
@ -58,8 +59,8 @@ object VancedDownloader {
try {
downloadSplits(context)
} catch (e: Exception) {
Log.d("VMDownloader", e.stackTraceToString())
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, "Vanced"))
log("VMDownloader", e.stackTraceToString())
downloadingFile.postValue(context.getString(R.string.error_downloading, "Vanced"))
}
}
@ -69,58 +70,73 @@ object VancedDownloader {
"theme" -> "$themePath/$theme.apk"
"arch" -> "$baseInstallUrl/apks/v$vancedVersion/$variant/Arch/split_config.$arch.apk"
"stock" -> "$themePath/stock.apk"
"dpi" -> "$themePath/dpi.apk"
"dpi" -> "$themePath/dpi.apk"
"lang" -> "$baseInstallUrl/apks/v$vancedVersion/$variant/Language/split_config.${lang[count]}.apk"
else -> throw NotImplementedError("This type of APK is NOT valid. What the hell did you even do?")
}
download(url, "$baseInstallUrl/", folderName!!, getFileNameFromUrl(url), context, onDownloadComplete = {
when (type) {
"theme" ->
if (variant == "root") {
if (validateTheme(downloadPath!!, theme!!, hashUrl, context)) {
if (downloadStockCheck(vancedRootPkg, vancedVersionCode, context))
downloadSplits(context, "arch")
else
startVancedInstall(context)
download(
url,
"$baseInstallUrl/",
folderName!!,
getFileNameFromUrl(url),
context,
onDownloadComplete = {
when (type) {
"theme" ->
if (variant == "root") {
if (validateTheme(downloadPath!!, theme!!, hashUrl, context)) {
if (downloadStockCheck(vancedRootPkg, vancedVersionCode, context))
downloadSplits(context, "arch")
else
startVancedInstall(context)
} else
downloadSplits(context, "theme")
} else
downloadSplits(context, "theme")
} else
downloadSplits(context, "arch")
"arch" -> if (variant == "root") downloadSplits(context, "stock") else downloadSplits(context, "lang")
"stock" -> downloadSplits(context, "dpi")
"dpi" -> downloadSplits(context, "lang")
"lang" -> {
count++
succesfulLangCount++
if (count < lang.size)
downloadSplits(context, "lang")
else
startVancedInstall(context)
}
}
}, onError = {
if (type == "lang") {
count++
when {
count < lang.size -> downloadSplits(context, "lang")
succesfulLangCount == 0 -> {
lang.add("en")
downloadSplits(context, "lang")
downloadSplits(context, "arch")
"arch" -> if (variant == "root") downloadSplits(
context,
"stock"
) else downloadSplits(context, "lang")
"stock" -> downloadSplits(context, "dpi")
"dpi" -> downloadSplits(context, "lang")
"lang" -> {
count++
succesfulLangCount++
if (count < lang.size)
downloadSplits(context, "lang")
else
startVancedInstall(context)
}
else -> startVancedInstall(context)
}
} else {
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, getFileNameFromUrl(url)))
}
})
}
},
onError = {
if (type == "lang") {
count++
when {
count < lang.size -> downloadSplits(context, "lang")
succesfulLangCount == 0 -> {
lang.add("en")
downloadSplits(context, "lang")
}
else -> startVancedInstall(context)
}
} else {
downloadingFile.postValue(
context.getString(
R.string.error_downloading,
getFileNameFromUrl(url)
)
)
}
})
}
fun startVancedInstall(context: Context, variant: String? = this.variant) {
downloadProgress.value?.installing?.postValue(true)
downloadProgress.value?.postReset()
installing.postValue(true)
postReset()
FirebaseAnalytics.getInstance(context).logEvent(FirebaseAnalytics.Event.SELECT_ITEM) {
variant?.let { param("vanced_variant", it) }
theme?.let { param("vanced_theme", it) }
@ -128,6 +144,6 @@ object VancedDownloader {
if (variant == "root")
installVancedRoot(context)
else
installVanced(context)
installSplitApkFiles(context, "vanced")
}
}

View file

@ -1,13 +1,12 @@
package com.vanced.manager.core.firebase
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService
import com.vanced.manager.utils.AppUtils.log
class CloudMessaging : FirebaseMessagingService() {
override fun onNewToken(p0: String) {
super.onNewToken(p0)
Log.d("VMC", "Generated new token: $p0")
log("VMC", "Generated new token: $p0")
}
}

View file

@ -4,33 +4,35 @@ import android.app.Service
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.IBinder
import android.util.Log
import com.vanced.manager.utils.AppUtils.log
import com.vanced.manager.utils.AppUtils.sendCloseDialog
import com.vanced.manager.utils.AppUtils.sendFailure
import com.vanced.manager.utils.AppUtils.sendRefresh
class AppInstallerService: Service() {
class AppInstallerService : Service() {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Log.d(TAG, "Requesting user confirmation for installation")
log(TAG, "Requesting user confirmation for installation")
val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
startActivity(confirmationIntent)
} catch (e: Exception) {
Log.d("VMInstall", "Unable to start installation")
log("VMInstall", "Unable to start installation")
}
}
PackageInstaller.STATUS_SUCCESS -> {
Log.d(TAG, "Installation succeed")
log(TAG, "Installation succeed")
sendCloseDialog(this)
sendRefresh(this)
}
else -> {
sendCloseDialog(this)
sendFailure(intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999), intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE),this)
intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)?.let {
sendFailure(it, this)
}
}
}
stopSelf()

View file

@ -4,16 +4,16 @@ import android.app.Service
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.IBinder
import android.util.Log
import com.vanced.manager.utils.AppUtils.log
import com.vanced.manager.utils.AppUtils.sendRefresh
class AppUninstallerService: Service() {
class AppUninstallerService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val pkgName = intent?.getStringExtra("pkg")
when (intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Log.d(AppInstallerService.TAG, "Requesting user confirmation for uninstallation")
log(AppInstallerService.TAG, "Requesting user confirmation for uninstallation")
val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
@ -24,11 +24,11 @@ class AppUninstallerService: Service() {
//Delay broadcast until activity (and fragment) show up on the screen
PackageInstaller.STATUS_SUCCESS -> {
sendRefresh(this)
Log.d("VMpm", "Successfully uninstalled $pkgName")
log("VMpm", "Successfully uninstalled $pkgName")
}
PackageInstaller.STATUS_FAILURE -> {
sendRefresh(this)
Log.d("VMpm", "Failed to uninstall $pkgName")
log("VMpm", "Failed to uninstall $pkgName")
}
}
stopSelf()

View file

@ -0,0 +1,10 @@
package com.vanced.manager.model
import androidx.annotation.DrawableRes
import com.vanced.manager.R
enum class ButtonTag(@DrawableRes val image: Int) {
INSTALL(R.drawable.ic_app_download),
UPDATE(R.drawable.ic_app_update),
REINSTALL(R.drawable.ic_app_reinstall)
}

View file

@ -3,88 +3,79 @@ package com.vanced.manager.model
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Build
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.lifecycle.*
import com.beust.klaxon.JsonObject
import com.vanced.manager.R
import com.vanced.manager.core.CombinedLiveData
import com.vanced.manager.utils.PackageHelper.isPackageInstalled
open class DataModel(
private val jsonObject: LiveData<JsonObject?>,
private val context: Context,
lifecycleOwner: LifecycleOwner,
jsonObject: LiveData<JsonObject?>,
context: Context,
val appPkg: String,
val appName: String,
val appIcon: Drawable?,
val appDescription: String,
@DrawableRes val appIcon: Int
) {
private val versionCode = MutableLiveData<Int>()
private val installedVersionCode = MutableLiveData<Int>()
val isAppInstalled = Transformations.map(jsonObject) { isAppInstalled(appPkg) }
val isAppInstalled = MutableLiveData<Boolean>()
val versionName = MutableLiveData<String>()
val installedVersionName = MutableLiveData<String>()
val buttonTxt = MutableLiveData<String>()
val changelog = MutableLiveData<String>()
private val versionCode = Transformations.map(jsonObject) { jobj ->
jobj?.int("versionCode") ?: 0
}
private val installedVersionCode = Transformations.map(isAppInstalled) {
getPkgVersionCode(appPkg, it)
}
private val unavailable = context.getString(R.string.unavailable)
private val pm = context.packageManager
private fun fetch() {
val jobj = jsonObject.value
isAppInstalled.value = isAppInstalled(appPkg)
versionCode.value = jobj?.int("versionCode") ?: 0
versionName.value = jobj?.string("version")?.removeSuffix("-vanced") ?: context.getString(R.string.unavailable)
changelog.value = jobj?.string("changelog") ?: context.getString(R.string.unavailable)
val versionName = Transformations.map(jsonObject) { jobj ->
jobj?.string("version") ?: unavailable
}
val changelog = Transformations.map(jsonObject) { jobj ->
jobj?.string("changelog") ?: unavailable
}
val installedVersionName = Transformations.map(isAppInstalled) {
getPkgVersionName(appPkg, it)
}
val buttonTag = CombinedLiveData(versionCode, installedVersionCode) { versionCode, installedVersionCode ->
compareInt(installedVersionCode, versionCode)
}
init {
fetch()
with(lifecycleOwner) {
jsonObject.observe(this) {
fetch()
}
isAppInstalled.observe(this) {
installedVersionCode.value = getPkgVersionCode(appPkg)
installedVersionName.value = getPkgVersionName(appPkg)
}
versionCode.observe(this) { versionCode ->
installedVersionCode.observe(this) { installedVersionCode ->
buttonTxt.value = compareInt(installedVersionCode, versionCode)
}
}
}
}
open fun isAppInstalled(pkg: String): Boolean = isPackageInstalled(pkg, pm)
open fun isAppInstalled(pkg: String): Boolean = isPackageInstalled(pkg, context.packageManager)
private fun getPkgVersionName(pkg: String): String {
val pm = context.packageManager
return if (isAppInstalled.value == true) {
pm?.getPackageInfo(pkg, 0)?.versionName?.removeSuffix("-vanced") ?: context.getString(R.string.unavailable)
private fun getPkgVersionName(pkg: String, isAppInstalled: Boolean): String {
return if (isAppInstalled) {
pm?.getPackageInfo(pkg, 0)?.versionName?.removeSuffix("-vanced") ?: unavailable
} else {
context.getString(R.string.unavailable)
unavailable
}
}
@Suppress("DEPRECATION")
private fun getPkgVersionCode(pkg: String): Int {
val pm = context.packageManager
return if (isAppInstalled.value == true) {
private fun getPkgVersionCode(pkg: String, isAppInstalled: Boolean): Int {
return if (isAppInstalled) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
pm?.getPackageInfo(pkg, 0)?.longVersionCode?.and(0xFFFFFFFF)?.toInt() ?: 0
else
pm?.getPackageInfo(pkg, 0)?.versionCode ?: 0
} else 0
} else {
0
}
}
private fun compareInt(int1: Int?, int2: Int?): String {
private fun compareInt(int1: Int?, int2: Int?): ButtonTag {
if (int2 != null && int1 != null) {
return when {
int1 == 0 -> context.getString(R.string.install)
int2 > int1 -> context.getString(R.string.update)
int2 == int1 || int1 > int2 -> context.getString(R.string.button_reinstall)
else -> context.getString(R.string.install)
int1 == 0 -> ButtonTag.INSTALL
int2 > int1 -> ButtonTag.UPDATE
int1 >= int2 -> ButtonTag.REINSTALL
else -> ButtonTag.INSTALL
}
}
return context.getString(R.string.install)
return ButtonTag.INSTALL
}
}

View file

@ -4,5 +4,5 @@ import android.graphics.drawable.Drawable
data class LinkModel(
val linkIcon: Drawable?,
val linkUrl: String,
val linkUrl: String
)

View file

@ -1,8 +1,8 @@
package com.vanced.manager.model
data class NotifModel(
val topic: String,
val switchTitle: String,
val switchSummary: String,
val key: String
val topic: String,
val switchTitle: String,
val switchSummary: String,
val key: String
)

View file

@ -1,30 +0,0 @@
package com.vanced.manager.model
import androidx.lifecycle.MutableLiveData
import okhttp3.ResponseBody
import retrofit2.Call
open class ProgressModel {
val downloadProgress = MutableLiveData<Int>()
val downloadingFile = MutableLiveData<String>()
val installing = MutableLiveData<Boolean>()
var currentDownload: Call<ResponseBody>? = null
fun reset() {
downloadProgress.value = 0
downloadingFile.value = ""
}
fun postReset() {
downloadProgress.postValue(0)
downloadingFile.postValue("")
}
init {
installing.postValue(false)
reset()
}
}

View file

@ -1,7 +1,7 @@
package com.vanced.manager.model
import android.content.Context
import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import com.beust.klaxon.JsonObject
@ -10,18 +10,18 @@ import com.vanced.manager.utils.PackageHelper
class RootDataModel(
jsonObject: LiveData<JsonObject?>,
context: Context,
lifecycleOwner: LifecycleOwner,
appPkg: String,
appName: String,
appIcon: Drawable?,
appDescription: String,
@DrawableRes appIcon: Int,
//BUG THIS!
//kotlin thinks that this value is null if we use
//private val scriptName: String
//Although it's impossible for it to be null.
//Ironic, isn't it?
private val scriptName: String?
): DataModel(
jsonObject, context, lifecycleOwner, appPkg, appName, appIcon
) : DataModel(
jsonObject, context, appPkg, appName, appDescription, appIcon
) {
override fun isAppInstalled(pkg: String): Boolean {

View file

@ -3,7 +3,7 @@ package com.vanced.manager.model
import android.graphics.drawable.Drawable
data class SponsorModel(
val logo: Drawable?,
val name: String,
val url: String
val logo: Drawable?,
val name: String,
val url: String
)

View file

@ -1,10 +1,12 @@
package com.vanced.manager.ui
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
@ -13,10 +15,7 @@ import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.crowdin.platform.Crowdin
import com.crowdin.platform.LoadingStateListener
import com.google.firebase.messaging.FirebaseMessaging
import com.vanced.manager.BuildConfig.ENABLE_CROWDIN_AUTH
import com.vanced.manager.BuildConfig.VERSION_CODE
import com.vanced.manager.R
import com.vanced.manager.databinding.ActivityMainBinding
@ -26,30 +25,21 @@ import com.vanced.manager.ui.dialogs.URLChangeDialog
import com.vanced.manager.ui.fragments.HomeFragmentDirections
import com.vanced.manager.ui.fragments.SettingsFragmentDirections
import com.vanced.manager.utils.*
import com.vanced.manager.utils.AppUtils.currentLocale
import com.vanced.manager.utils.AppUtils.faqpkg
import com.vanced.manager.utils.AppUtils.log
import com.vanced.manager.utils.AppUtils.playStorePkg
import com.vanced.manager.utils.AppUtils.vancedRootPkg
import com.vanced.manager.utils.PackageHelper.isPackageInstalled
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
private val navHost by lazy { findNavController(R.id.nav_host) }
private val loadingObserver = object : LoadingStateListener {
val tag = "VMLocalisation"
override fun onDataChanged() {
Log.d(tag, "Loaded data")
}
override fun onFailure(throwable: Throwable) {
Log.d(tag, "Failed to load data: $throwable")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
setFinalTheme()
super.onCreate(savedInstanceState)
if (ENABLE_CROWDIN_AUTH)
authCrowdin()
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
@ -68,7 +58,7 @@ class MainActivity : AppCompatActivity() {
initDialogs(intent.getBooleanExtra("firstLaunch", false))
manager.observe(this) {
if (manager.value?.int("versionCode") ?: 0 > VERSION_CODE) {
ManagerUpdateDialog.newInstance(false).show(this)
ManagerUpdateDialog.newInstance(true).show(this)
}
}
}
@ -79,36 +69,35 @@ class MainActivity : AppCompatActivity() {
}
private fun setDisplayHomeAsUpEnabled(isNeeded: Boolean) {
binding.toolbar.navigationIcon = if (isNeeded) ContextCompat.getDrawable(this, R.drawable.ic_keyboard_backspace_black_24dp) else null
}
override fun onPause() {
super.onPause()
Crowdin.unregisterDataLoadingObserver(loadingObserver)
binding.toolbar.navigationIcon = if (isNeeded) ContextCompat.getDrawable(
this,
R.drawable.ic_keyboard_backspace_black_24dp
) else null
}
override fun onResume() {
setFinalTheme()
super.onResume()
Crowdin.registerDataLoadingObserver(loadingObserver)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
onBackPressedDispatcher.onBackPressed()
return true
}
return when (item.itemId) {
R.id.toolbar_about -> {
navHost.navigate(HomeFragmentDirections.toAboutFragment())
return true
true
}
R.id.toolbar_settings -> {
navHost.navigate(HomeFragmentDirections.toSettingsFragment())
return true
true
}
R.id.toolbar_log -> {
navHost.navigate(HomeFragmentDirections.toLogFragment())
true
}
R.id.toolbar_update_manager -> {
ManagerUpdateDialog.newInstance(false).show(supportFragmentManager, "manager_update")
ManagerUpdateDialog.newInstance(false)
.show(supportFragmentManager, "manager_update")
true
}
R.id.dev_settings -> {
navHost.navigate(SettingsFragmentDirections.toDevSettingsFragment())
@ -116,22 +105,34 @@ class MainActivity : AppCompatActivity() {
}
else -> super.onOptionsItemSelected(item)
}
return false
}
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(Crowdin.wrapContext(LanguageContextWrapper.wrap(newBase)))
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
onActivityResult(requestCode)
super.attachBaseContext(LanguageContextWrapper.wrap(newBase))
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
recreate() //restarting activity to recreate viewmodels, otherwise some text won't update
//update manager language when system language is changed
@Suppress("DEPRECATION")
if (newConfig.locale != currentLocale) {
recreate() //restarting activity in order to recreate viewmodels, otherwise some text won't update
return
}
when (newConfig.orientation) {
Configuration.ORIENTATION_PORTRAIT -> log(
"VMUI",
"screen orientation changed to portrait"
)
Configuration.ORIENTATION_LANDSCAPE -> log(
"VMUI",
"screen orientation changed to landscape"
)
else -> log("VMUI", "screen orientation changed to [REDACTED]")
}
}
override fun recreate() {
@ -153,26 +154,30 @@ class MainActivity : AppCompatActivity() {
urldialog.show(this)
}
when {
firstLaunch -> {
DialogContainer.showSecurityDialog(this)
with(FirebaseMessaging.getInstance()) {
subscribeToTopic("Vanced-Update")
subscribeToTopic("Music-Update")
subscribeToTopic("MicroG-Update")
}
if (firstLaunch) {
DialogContainer.showSecurityDialog(this)
with(FirebaseMessaging.getInstance()) {
subscribeToTopic("Vanced-Update")
subscribeToTopic("Music-Update")
subscribeToTopic("MicroG-Update")
}
!prefs.getBoolean("statement", true) -> DialogContainer.statementFalse(this)
variant == "root" -> {
if (PackageHelper.getPackageVersionName(
"com.google.android.youtube",
packageManager
) == "14.21.54")
DialogContainer.basicDialog(
getString(R.string.hold_on),
getString(R.string.magisk_vanced),
this
)
} else {
if (isMiuiOptimizationsEnabled) {
DialogContainer.miuiDialog(this)
}
}
if (!prefs.getBoolean("statement", true)) {
DialogContainer.statementFalse(this)
}
if (variant == "root") {
if (PackageHelper.getPackageVersionName(vancedRootPkg, packageManager) == "14.21.54") {
DialogContainer.basicDialog(
getString(R.string.hold_on),
getString(R.string.magisk_vanced),
this
)
}
}
}

View file

@ -0,0 +1,26 @@
package com.vanced.manager.ui
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.topjohnwu.superuser.Shell
class SplashScreenActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//Preheat the shell
Shell.getShell {
if (getDefaultSharedPreferences(this).getBoolean("firstLaunch", true)) {
startActivity(Intent(this, WelcomeActivity::class.java))
finish()
} else {
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}
}
}

View file

@ -1,21 +1,86 @@
package com.vanced.manager.ui
import android.animation.ValueAnimator
import android.os.Bundle
import android.util.LayoutDirection
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import com.vanced.manager.R
import androidx.core.animation.addListener
import androidx.viewpager2.widget.ViewPager2
import com.vanced.manager.adapter.WelcomePageAdapter
import com.vanced.manager.databinding.ActivityWelcomeBinding
import kotlin.math.abs
class WelcomeActivity : AppCompatActivity() {
private val navHost by lazy { findNavController(R.id.welcome_navhost) }
private lateinit var binding: ActivityWelcomeBinding
private var isRtl = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_welcome)
binding = ActivityWelcomeBinding.inflate(layoutInflater)
setContentView(binding.root)
isRtl = resources.configuration.layoutDirection == LayoutDirection.RTL
binding.welcomeViewpager.apply {
adapter = WelcomePageAdapter(this@WelcomeActivity)
isUserInputEnabled = false
setPageTransformer { page, position ->
page.apply {
val pageWidth = width.toFloat()
//Thank you, fragula dev!
when {
position > 0 && position < 1 -> {
alpha = 1f
translationX = 0f
}
position > -1 && position <= 0 -> {
alpha = 1.0f - abs(position * 0.7f)
translationX = pageWidth.rtlCompat * position / 1.3F
}
}
}
}
}
}
override fun onBackPressed() {
if (!navHost.popBackStack())
finish()
with(binding) {
if (welcomeViewpager.currentItem == 0) {
super.onBackPressed()
} else {
navigateTo(welcomeViewpager.currentItem - 1)
}
}
}
fun navigateTo(position: Int) {
binding.welcomeViewpager.currentPosition = position
}
private val Float.rtlCompat get() = if (isRtl) this else -this
//Shit way to implement animation duration, but at least it works
private var ViewPager2.currentPosition: Int
get() = currentItem
set(value) {
val pixelsToDrag: Int = width * (value - currentItem)
val animator = ValueAnimator.ofInt(0, pixelsToDrag)
var previousValue = 0
animator.apply {
addUpdateListener { valueAnimator ->
val currentValue = valueAnimator.animatedValue as Int
val currentPxToDrag = (currentValue - previousValue).toFloat()
fakeDragBy(currentPxToDrag.rtlCompat)
previousValue = currentValue
}
addListener(
onStart = { beginFakeDrag() },
onEnd = { endFakeDrag() }
)
duration = 500
start()
}
}
}

View file

@ -0,0 +1,2 @@
package com.vanced.manager.ui.compose

View file

@ -0,0 +1,107 @@
package com.vanced.manager.ui.compose
//import androidx.compose.foundation.clickable
//import androidx.compose.foundation.layout.Column
//import androidx.compose.foundation.layout.ColumnScope
//import androidx.compose.foundation.layout.padding
//import androidx.compose.material.Switch
//import androidx.compose.material.Text
//import androidx.compose.runtime.*
//import androidx.compose.ui.Modifier
//import androidx.compose.ui.graphics.Color
//import androidx.compose.ui.platform.LocalContext
//import androidx.compose.ui.tooling.preview.Preview
//import androidx.compose.ui.unit.dp
//import androidx.compose.ui.unit.em
//import androidx.compose.ui.unit.sp
//import androidx.constraintlayout.compose.ConstraintLayout
//import androidx.core.content.edit
//import androidx.preference.PreferenceManager
//
//@Composable
//@Preview
//inline fun PreferenceCategory(
// categoryTitle: String,
// content: @Composable ColumnScope.() -> Unit
//) {
// Column {
// Text(
// categoryTitle,
// letterSpacing = 0.15.em,
// color = Color(LocalContext.current.accentColor)
// )
// content()
// }
//}
//
//
//@Composable
//@Preview
//inline fun SwitchPreference(
// preferenceTitle: String,
// preferenceDescription: String? = null,
// preferenceKey: String,
// defValue: Boolean = true,
// crossinline onCheckedChange: (Boolean) -> Unit = {}
//) {
// val prefs = PreferenceManager.getDefaultSharedPreferences(LocalContext.current)
// val isChecked = remember { mutableStateOf(prefs.getBoolean(preferenceKey, defValue)) }
// ConstraintLayout(modifier = Modifier.padding(12.dp, 4.dp).clickable {
// isChecked.value = !isChecked.value
// }) {
// val (title, description, switch) = createRefs()
// Text(preferenceTitle, fontSize = 16.sp, modifier = Modifier.constrainAs(title) {
// top.linkTo(parent.top)
// start.linkTo(parent.start)
// end.linkTo(switch.start, 4.dp)
// if (preferenceDescription != null) {
// bottom.linkTo(description.top)
// } else {
// bottom.linkTo(parent.bottom)
// }
// })
// if (preferenceDescription != null) {
// Text(preferenceDescription, fontSize = 13.sp, modifier = Modifier.constrainAs(description) {
// top.linkTo(title.bottom)
// start.linkTo(parent.start)
// end.linkTo(switch.start, 8.dp)
// })
// }
// Switch(
// isChecked.value,
// onCheckedChange = {
// prefs.edit { putBoolean(preferenceKey, it) }
// onCheckedChange(it)
// },
// modifier = Modifier.clickable(false) {}
// )
// }
//}
//
//@Composable
//@Preview
//fun Preference(
// preferenceTitle: String,
// preferenceDescription: String? = null,
// onClick: () -> Unit
//) {
// ConstraintLayout(modifier = Modifier.padding(12.dp, 4.dp).clickable(onClick = onClick)) {
// val (title, description, switch) = createRefs()
// Text(preferenceTitle, fontSize = 16.sp, modifier = Modifier.constrainAs(title) {
// top.linkTo(parent.top)
// start.linkTo(parent.start)
// end.linkTo(switch.start, 4.dp)
// if (preferenceDescription != null) {
// bottom.linkTo(description.top)
// } else {
// bottom.linkTo(parent.bottom)
// }
// })
// if (preferenceDescription != null) {
// Text(preferenceDescription, fontSize = 13.sp, modifier = Modifier.constrainAs(description) {
// top.linkTo(title.bottom)
// })
// }
// }
//
//}

View file

@ -0,0 +1,52 @@
package com.vanced.manager.ui.compose
//import android.content.Context
//import androidx.compose.foundation.isSystemInDarkTheme
//import androidx.compose.material.MaterialTheme
//import androidx.compose.material.darkColors
//import androidx.compose.material.lightColors
//import androidx.compose.runtime.Composable
//import androidx.compose.runtime.MutableState
//import androidx.compose.runtime.mutableStateOf
//import androidx.compose.runtime.remember
//import androidx.compose.ui.graphics.Color
//import androidx.compose.ui.platform.LocalContext
//import androidx.preference.PreferenceManager.getDefaultSharedPreferences
//import com.vanced.manager.utils.mutableAccentColor
//
//const val Dark = "Dark"
//const val SystemDefault = "System Default"
//
//const val defAccentColor: Int = -13732865
//
//val Context.accentColor get() = mutableAccentColor.value ?: getDefaultSharedPreferences(this).getInt("manager_accent_color", defAccentColor)
//
//enum class Theme {
// DARK, LIGHT
//}
//
//val lightColors = lightColors(
// primary = Color(defAccentColor)
//)
//
//val darkColors = darkColors(
// primary = Color(defAccentColor)
//)
//
//fun Context.retrieveTheme(): Theme = when (getDefaultSharedPreferences(this).getString("manager_theme", SystemDefault)) {
// SystemDefault -> if (isSystemInDarkTheme()) Theme.DARK else Theme.LIGHT
// Dark -> Theme.DARK
// else -> Theme.LIGHT
//}
//
//val Context.isDarkTheme: Boolean
// get() = retrieveTheme() == Theme.DARK
//
//fun Context.ManagerTheme(
// content: @Composable () -> Unit
//) {
// MaterialTheme(
// colors = if (isDarkTheme) darkColors else lightColors,
// content = content
// )
//}

View file

@ -31,7 +31,7 @@ class EmptyPreference @JvmOverloads constructor(
}
fun setSummary(newSummary: String) {
with (binding) {
with(binding) {
preferenceSummary.text = newSummary
preferenceSummary.isVisible = true
preferenceTitle.setPadding(0, 0, 0, 0)
@ -40,10 +40,11 @@ class EmptyPreference @JvmOverloads constructor(
private fun initAttrs(context: Context, attrs: AttributeSet?) {
attrs?.let { mAttrs ->
val typedArray = context.obtainStyledAttributes(mAttrs, R.styleable.EmptyPreference, 0, 0)
val typedArray =
context.obtainStyledAttributes(mAttrs, R.styleable.EmptyPreference, 0, 0)
val title = typedArray.getText(R.styleable.EmptyPreference_preference_title)
val summary = typedArray.getText(R.styleable.EmptyPreference_preference_summary)
with (binding) {
with(binding) {
if (summary != null) {
preferenceSummary.text = summary
} else {

View file

@ -10,7 +10,7 @@ import com.vanced.manager.databinding.ViewPreferenceCategoryBinding
class PreferenceCategory @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0,
defStyle: Int = 0
) : LinearLayout(context, attrs, defStyle) {
private var _binding: ViewPreferenceCategoryBinding? = null
@ -27,7 +27,8 @@ class PreferenceCategory @JvmOverloads constructor(
private fun initAttrs(context: Context, attrs: AttributeSet?) {
attrs.let { mAttrs ->
val typedArray = context.obtainStyledAttributes(mAttrs, R.styleable.PreferenceCategory, 0, 0)
val typedArray =
context.obtainStyledAttributes(mAttrs, R.styleable.PreferenceCategory, 0, 0)
val title = typedArray.getText(R.styleable.PreferenceCategory_category_title)
binding.categoryTitle.text = title

View file

@ -1,6 +1,7 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.content.SharedPreferences
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.CompoundButton
@ -31,6 +32,13 @@ class PreferenceSwitch @JvmOverloads constructor(
private var mListener: OnCheckedListener? = null
private val prefListener =
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
if (key == prefKey) {
binding.preferenceSwitch.isChecked = sharedPreferences.getBoolean(key, defValue)
}
}
private var _binding: ViewPreferenceSwitchBinding? = null
val binding: ViewPreferenceSwitchBinding
@ -38,6 +46,7 @@ class PreferenceSwitch @JvmOverloads constructor(
init {
_binding = ViewPreferenceSwitchBinding.inflate(LayoutInflater.from(context), this, true)
prefs.registerOnSharedPreferenceChangeListener(prefListener)
attrs?.let { mAttrs ->
with(context.obtainStyledAttributes(mAttrs, R.styleable.PreferenceSwitch, 0, 0)) {
val title = getText(R.styleable.PreferenceSwitch_switch_title)
@ -85,4 +94,8 @@ class PreferenceSwitch @JvmOverloads constructor(
defValue = newVal
binding.preferenceSwitch.isChecked = prefs.getBoolean(prefKey, newVal)
}
fun setChecked(checked: Boolean) {
binding.preferenceSwitch.isChecked = checked
}
}

View file

@ -1,32 +0,0 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.util.AttributeSet
import androidx.constraintlayout.widget.ConstraintLayout
open class SlidingConstraintLayout : ConstraintLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(
context,
attrs
)
var xFraction: Float
get() {
val width = width
return if (width != 0)
x / getWidth()
else
x
}
set(xFraction) {
val width = width
val newWidth =
if (width > 0)
xFraction * width
else
(1).toFloat()
x = newWidth
}
}

View file

@ -1,51 +0,0 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
open class SlidingLinearLayout: LinearLayout {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(
context,
attrs
)
var yFraction: Float
get() {
val height = height
return if (height != 0)
y / height
else
y
}
set(yFraction) {
val height = height
val newHeight =
if (height > 0)
yFraction * height
else
(1).toFloat()
y = newHeight
}
var xFraction: Float
get() {
val width = width
return if (width != 0)
x / getWidth()
else
x
}
set(xFraction) {
val width = width
val newWidth =
if (width > 0)
xFraction * width
else
(1).toFloat()
x = newWidth
}
}

View file

@ -1,32 +0,0 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.util.AttributeSet
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
open class SlidingSwipeRefreshLayout : SwipeRefreshLayout {
constructor(context: Context?) : super(context!!)
constructor(context: Context?, attrs: AttributeSet?) : super(
context!!,
attrs
)
var xFraction: Float
get() {
val width = width
return if (width != 0)
x / getWidth()
else
x
}
set(xFraction) {
val width = width
val newWidth =
if (width > 0)
xFraction * width
else
(1).toFloat()
x = newWidth
}
}

View file

@ -1,24 +0,0 @@
package com.vanced.manager.ui.core
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.vanced.manager.ui.MainActivity
import com.vanced.manager.ui.WelcomeActivity
class SplashScreenActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (getDefaultSharedPreferences(this).getBoolean("firstLaunch", true)) {
startActivity(Intent(this, WelcomeActivity::class.java))
finish()
} else {
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}
}

View file

@ -0,0 +1,19 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import com.google.android.material.card.MaterialCardView
import com.vanced.manager.utils.accentColor
class ThemedAppCard @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
defStyleAttr: Int = 0
) : MaterialCardView(context, attributeSet, defStyleAttr) {
init {
setCardBackgroundColor(ColorStateList.valueOf(accentColor.value!!).withAlpha(35))
}
}

View file

@ -0,0 +1,24 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import android.widget.Toast
import com.google.android.material.button.MaterialButton
import com.vanced.manager.utils.accentColor
class ThemedIconButton @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
defStyleAttr: Int = 0
) : MaterialButton(context, attributeSet, defStyleAttr) {
init {
iconTint = ColorStateList.valueOf(accentColor.value!!)
setOnLongClickListener {
Toast.makeText(context, contentDescription, Toast.LENGTH_SHORT).show()
true
}
}
}

View file

@ -7,9 +7,7 @@ import androidx.core.graphics.ColorUtils
import com.google.android.material.button.MaterialButton
import com.vanced.manager.R
import com.vanced.manager.utils.accentColor
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.lifecycleOwner
import com.vanced.manager.utils.managerAccent
class ThemedMaterialButton @JvmOverloads constructor(
context: Context,
@ -18,8 +16,7 @@ class ThemedMaterialButton @JvmOverloads constructor(
) : MaterialButton(context, attributeSet, defStyleAttr) {
init {
setBgColor(context.defPrefs.managerAccent)
context.lifecycleOwner()?.let { owner ->
context.lifecycleOwner?.let { owner ->
accentColor.observe(owner) { color ->
setBgColor(color.toInt())
}

View file

@ -5,14 +5,13 @@ import android.content.res.ColorStateList
import android.util.AttributeSet
import com.google.android.material.checkbox.MaterialCheckBox
import com.vanced.manager.R
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.managerAccent
import com.vanced.manager.utils.accentColor
class ThemedMaterialCheckbox @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
) : MaterialCheckBox(context, attributeSet, R.attr.checkboxStyle) {
init {
buttonTintList = ColorStateList.valueOf(context.defPrefs.managerAccent)
buttonTintList = ColorStateList.valueOf(accentColor.value!!)
}
}

View file

@ -5,14 +5,13 @@ import android.content.res.ColorStateList
import android.util.AttributeSet
import com.google.android.material.radiobutton.MaterialRadioButton
import com.vanced.manager.R
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.managerAccent
import com.vanced.manager.utils.accentColor
class ThemedMaterialRadioButton @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
) : MaterialRadioButton(context, attributeSet, R.attr.radioButtonStyle) {
init {
buttonTintList = ColorStateList.valueOf(context.defPrefs.managerAccent)
buttonTintList = ColorStateList.valueOf(accentColor.value!!)
}
}

View file

@ -4,17 +4,20 @@ import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import com.google.android.material.slider.Slider
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.managerAccent
import com.vanced.manager.utils.accentColor
class ThemedMaterialSlider@JvmOverloads constructor(
class ThemedMaterialSlider @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
defStyleAttr: Int = 0
) : Slider(context, attributeSet, defStyleAttr) {
init {
thumbStrokeColor = ColorStateList.valueOf(context.defPrefs.managerAccent)
val accentValue = ColorStateList.valueOf(accentColor.value!!)
thumbTintList = accentValue
trackActiveTintList = accentValue
trackInactiveTintList = accentValue.withAlpha(70)
haloTintList = accentValue.withAlpha(60)
}
}

View file

@ -6,10 +6,7 @@ import android.util.AttributeSet
import androidx.core.graphics.ColorUtils
import com.google.android.material.button.MaterialButton
import com.vanced.manager.utils.accentColor
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.lifecycleOwner
import com.vanced.manager.utils.managerAccent
class ThemedOutlinedMaterialButton @JvmOverloads constructor(
context: Context,
@ -17,8 +14,7 @@ class ThemedOutlinedMaterialButton @JvmOverloads constructor(
defStyleAttr: Int = 0
) : MaterialButton(context, attributeSet, defStyleAttr) {
init {
applyAccent(context.defPrefs.managerAccent)
context.lifecycleOwner()?.let { owner ->
context.lifecycleOwner?.let { owner ->
accentColor.observe(owner) { color ->
applyAccent(color.toInt())
}
@ -27,6 +23,9 @@ class ThemedOutlinedMaterialButton @JvmOverloads constructor(
private fun applyAccent(color: Int) {
setTextColor(color)
rippleColor = ColorStateList(arrayOf(intArrayOf()), intArrayOf(ColorUtils.setAlphaComponent(color, 50)))
rippleColor = ColorStateList(
arrayOf(intArrayOf()),
intArrayOf(ColorUtils.setAlphaComponent(color, 50))
)
}
}

View file

@ -4,21 +4,27 @@ import android.content.Context
import android.util.AttributeSet
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.vanced.manager.R
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.managerAccent
import com.vanced.manager.utils.accentColor
class ThemedSwipeRefreshlayout @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null
) : SwipeRefreshLayout(context, attributeSet) {
init {
setColorSchemeColors(context.defPrefs.managerAccent)
setColorSchemeColors(accentColor.value!!)
initAttrs(context, attributeSet)
}
private fun initAttrs(context: Context, attributeSet: AttributeSet?) {
attributeSet.let {
val typedAttrs = context.obtainStyledAttributes(it, R.styleable.ThemedSwipeRefreshlayout, 0, 0)
setProgressBackgroundColorSchemeColor(typedAttrs.getColor(R.styleable.ThemedSwipeRefreshlayout_progressBackgroundColor, 0))
val typedAttrs =
context.obtainStyledAttributes(it, R.styleable.ThemedSwipeRefreshlayout, 0, 0)
setProgressBackgroundColorSchemeColor(
typedAttrs.getColor(
R.styleable.ThemedSwipeRefreshlayout_progressBackgroundColor,
0
)
)
typedAttrs.recycle()
}
}

View file

@ -9,20 +9,18 @@ import androidx.core.graphics.ColorUtils
import androidx.core.graphics.drawable.DrawableCompat
import com.vanced.manager.R
import com.vanced.manager.utils.accentColor
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.lifecycleOwner
import com.vanced.manager.utils.managerAccent
class ThemedSwitchCompat @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
) : SwitchCompat(context, attributeSet, R.attr.switchStyle) {
private val states = arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked))
private val states =
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked))
init {
setSwitchColors(context.defPrefs.managerAccent)
context.lifecycleOwner()?.let { owner ->
context.lifecycleOwner?.let { owner ->
accentColor.observe(owner) { color ->
setSwitchColors(color.toInt())
}
@ -32,7 +30,13 @@ class ThemedSwitchCompat @JvmOverloads constructor(
private fun setSwitchColors(color: Int) {
val thumbColors = intArrayOf(Color.LTGRAY, color)
val trackColors = intArrayOf(Color.GRAY, ColorUtils.setAlphaComponent(color, 70))
DrawableCompat.setTintList(DrawableCompat.wrap(thumbDrawable), ColorStateList(states, thumbColors))
DrawableCompat.setTintList(DrawableCompat.wrap(trackDrawable), ColorStateList(states, trackColors))
DrawableCompat.setTintList(
DrawableCompat.wrap(thumbDrawable),
ColorStateList(states, thumbColors)
)
DrawableCompat.setTintList(
DrawableCompat.wrap(trackDrawable),
ColorStateList(states, trackColors)
)
}
}

View file

@ -4,9 +4,7 @@ import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import com.vanced.manager.utils.accentColor
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.lifecycleOwner
import com.vanced.manager.utils.managerAccent
class ThemedTextView @JvmOverloads constructor(
context: Context,
@ -14,8 +12,7 @@ class ThemedTextView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : AppCompatTextView(context, attributeSet, defStyleAttr) {
init {
setTextColor(context.defPrefs.managerAccent)
context.lifecycleOwner()?.let { owner ->
context.lifecycleOwner?.let { owner ->
accentColor.observe(owner) { color ->
setTextColor(color.toInt())
}

View file

@ -1,5 +1,6 @@
package com.vanced.manager.ui.dialogs
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@ -17,8 +18,7 @@ import com.vanced.manager.core.downloader.MusicDownloader.downloadMusic
import com.vanced.manager.core.downloader.VancedDownloader.downloadVanced
import com.vanced.manager.core.ui.base.BindingDialogFragment
import com.vanced.manager.databinding.DialogAppDownloadBinding
import com.vanced.manager.utils.DownloadHelper.downloadProgress
import com.vanced.manager.utils.applyAccent
import com.vanced.manager.utils.*
class AppDownloadDialog : BindingDialogFragment<DialogAppDownloadBinding>() {
@ -73,39 +73,43 @@ class AppDownloadDialog : BindingDialogFragment<DialogAppDownloadBinding>() {
appDownloadHeader.text = app
if (arguments?.getBoolean(TAG_INSTALLING) == false) {
when (app) {
getString(R.string.vanced) -> downloadVanced(requireContext(), arguments?.getString(TAG_VERSION))
getString(R.string.music) -> downloadMusic(requireContext())
getString(R.string.vanced) -> downloadVanced(
requireContext(),
arguments?.getString(TAG_VERSION)
)
getString(R.string.music) -> downloadMusic(
requireContext(),
arguments?.getString(TAG_VERSION)
)
getString(R.string.microg) -> downloadMicrog(requireContext())
}
}
}
}
@SuppressLint("SetTextI18n")
private fun DialogAppDownloadBinding.bindDownloadProgress() {
with(downloadProgress) {
observe(viewLifecycleOwner) { progressModel ->
progressModel.downloadProgress.observe(viewLifecycleOwner) {
appDownloadProgressbar.progress = it
}
progressModel.installing.observe(viewLifecycleOwner) { installing ->
appDownloadProgressbar.isVisible = !installing
appInstallProgressbar.isVisible = installing
appDownloadFile.isVisible = !installing
appDownloadCancel.isEnabled = !installing
appDownloadCancel.setOnClickListener {
if (installing) {
return@setOnClickListener
}
progressModel.currentDownload?.cancel()
progressModel.downloadProgress.value = 0
dismiss()
}
}
progressModel.downloadingFile.observe(viewLifecycleOwner) {
appDownloadFile.text = it
downloadProgress.observe(viewLifecycleOwner) {
appDownloadProgressbar.progress = it
appDownloadProgress.text = "$it%"
}
installing.observe(viewLifecycleOwner) { installing ->
appDownloadProgressbarContainer.isVisible = !installing
appInstallProgressbar.isVisible = installing
appDownloadFile.isVisible = !installing
appDownloadCancel.isEnabled = !installing
appDownloadCancel.setOnClickListener {
if (installing) {
return@setOnClickListener
}
currentDownload?.cancel()
downloadProgress.value = 0
dismiss()
}
}
downloadingFile.observe(viewLifecycleOwner) {
appDownloadFile.text = it
}
}
override fun onResume() {

View file

@ -2,11 +2,10 @@ package com.vanced.manager.ui.dialogs
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.graphics.drawable.toBitmap
import androidx.annotation.DrawableRes
import com.vanced.manager.R
import com.vanced.manager.core.ui.base.BindingDialogFragment
import com.vanced.manager.databinding.DialogAppInfoBinding
@ -21,13 +20,15 @@ class AppInfoDialog : BindingDialogFragment<DialogAppInfoBinding>() {
fun newInstance(
appName: String?,
appIcon: Drawable?,
@DrawableRes appIcon: Int?,
changelog: String?
): AppInfoDialog = AppInfoDialog().apply {
arguments = Bundle().apply {
putString(TAG_APP_NAME, appName)
putString(TAG_CHANGELOG, changelog)
putParcelable(TAG_APP_ICON, appIcon?.toBitmap())
if (appIcon != null) {
putInt(TAG_APP_ICON, appIcon)
}
}
}
}
@ -47,7 +48,7 @@ class AppInfoDialog : BindingDialogFragment<DialogAppInfoBinding>() {
with(binding) {
aboutAppName.text = getString(R.string.about_app, arguments?.getString(TAG_APP_NAME))
aboutAppChangelog.text = arguments?.getString(TAG_CHANGELOG)
aboutAppImage.setImageBitmap(arguments?.getParcelable(TAG_APP_ICON))
arguments?.getInt(TAG_APP_ICON)?.let { aboutAppImage.setImageResource(it) }
}
}
}

View file

@ -0,0 +1,62 @@
package com.vanced.manager.ui.dialogs
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import com.vanced.manager.R
import com.vanced.manager.core.ui.base.BindingDialogFragment
import com.vanced.manager.databinding.DialogAppUninstallBinding
import com.vanced.manager.utils.PackageHelper
class AppUninstallDialog : BindingDialogFragment<DialogAppUninstallBinding>() {
companion object {
private const val TAG_APP_NAME = "APP_NAME"
private const val TAG_APP_PACKAGE = "APP_PACKAGE"
fun newInstance(
appName: String?,
appPackage: String?,
) = AppUninstallDialog().apply {
arguments = Bundle().apply {
putString(TAG_APP_NAME, appName)
putString(TAG_APP_PACKAGE, appPackage)
}
}
}
override fun binding(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) = DialogAppUninstallBinding.inflate(inflater, container, false)
override fun otherSetups() {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
bindData()
}
private fun bindData() {
val appName = arguments?.getString(TAG_APP_NAME)
val appPackage = arguments?.getString(TAG_APP_PACKAGE)
with(binding) {
appUninstallConfirm.setOnClickListener {
if (appPackage != null) {
PackageHelper.uninstallApk(
pkg = appPackage,
context = requireActivity()
)
}
dismiss()
}
appUninstallCancel.setOnClickListener {
dismiss()
}
appUninstallMessage.text = getString(R.string.uninstall_app_text, appName)
}
}
}

View file

@ -11,10 +11,12 @@ import com.vanced.manager.core.ui.base.BindingBottomSheetDialogFragment
import com.vanced.manager.core.ui.ext.showDialog
import com.vanced.manager.databinding.DialogBottomRadioButtonBinding
import com.vanced.manager.ui.core.ThemedMaterialRadioButton
import com.vanced.manager.utils.checkedButtonTag
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.getCheckedButtonTag
import com.vanced.manager.utils.formatVersion
class AppVersionSelectorDialog : BindingBottomSheetDialogFragment<DialogBottomRadioButtonBinding>() {
class AppVersionSelectorDialog :
BindingBottomSheetDialogFragment<DialogBottomRadioButtonBinding>() {
private val prefs by lazy { requireActivity().defPrefs }
@ -63,7 +65,7 @@ class AppVersionSelectorDialog : BindingBottomSheetDialogFragment<DialogBottomRa
}
dialogTitle.text = getString(R.string.version)
dialogSave.setOnClickListener {
val checkedTag = dialogRadiogroup.getCheckedButtonTag()
val checkedTag = dialogRadiogroup.checkedButtonTag
if (checkedTag != null) {
prefs.edit { putString("${arguments?.getString(TAG_APP)}_version", checkedTag) }
}
@ -75,7 +77,7 @@ class AppVersionSelectorDialog : BindingBottomSheetDialogFragment<DialogBottomRa
private fun loadBoxes() =
arguments?.getStringArrayList(TAG_VERSIONS)?.map { version ->
ThemedMaterialRadioButton(requireActivity()).apply {
text = version
text = version.formatVersion(requireActivity())
tag = version
textSize = 18f
}

View file

@ -5,9 +5,9 @@ import androidx.core.content.edit
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.vanced.manager.R
import com.vanced.manager.utils.applyAccent
import com.vanced.manager.utils.isMiui
import com.vanced.manager.utils.isMiuiOptimizationsEnabled
import com.vanced.manager.utils.openUrl
import com.vanced.manager.utils.showWithAccent
object DialogContainer {
@ -16,26 +16,21 @@ object DialogContainer {
setTitle(context.resources.getString(R.string.welcome))
setMessage(context.resources.getString(R.string.security_context))
setPositiveButton(context.resources.getString(R.string.close)) { dialog, _ ->
dialog.dismiss()
}
setOnDismissListener {
if (isMiui()) {
applyAccentMiuiDialog(context)
}
dialog.cancel()
}
setOnCancelListener {
if (isMiui()) {
applyAccentMiuiDialog(context)
if (context.isMiuiOptimizationsEnabled) {
miuiDialog(context)
}
}
create()
applyAccent()
showWithAccent()
}
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.edit { putBoolean("firstLaunch", false) }
}
private fun applyAccentMiuiDialog(context: Context) {
fun miuiDialog(context: Context) {
MaterialAlertDialogBuilder(context).apply {
setTitle(context.getString(R.string.miui_one_title))
setMessage(context.getString(R.string.miui_one))
@ -49,7 +44,7 @@ object DialogContainer {
}
setCancelable(false)
create()
applyAccent()
showWithAccent()
}
}
@ -59,7 +54,7 @@ object DialogContainer {
setMessage("So this statement is false huh? I'll go with True!")
setPositiveButton("wut?") { dialog, _ -> dialog.dismiss() }
create()
applyAccent()
showWithAccent()
}
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
@ -73,28 +68,54 @@ object DialogContainer {
when (msg) {
context.getString(R.string.installation_signature) -> {
setPositiveButton(context.getString(R.string.guide)) { _, _ ->
openUrl("https://lmgtfy.com/?q=andnixsh+apk+verification+disable", R.color.Twitter, context)
openUrl(
"https://lmgtfy.com/?q=andnixsh+apk+verification+disable",
R.color.Twitter,
context
)
}
setNeutralButton(context.getString(R.string.close)) { dialog, _ -> dialog.dismiss() }
if (fullMsg != null)
setNegativeButton(context.getString(R.string.advanced)) { _, _ -> basicDialog(context.getString(R.string.advanced), fullMsg, context) }
setNegativeButton(context.getString(R.string.advanced)) { _, _ ->
basicDialog(
context.getString(R.string.advanced),
fullMsg,
context
)
}
}
context.getString(R.string.installation_miui) -> {
setPositiveButton(context.getString(R.string.guide)) { _, _ ->
openUrl("https://telegra.ph/How-to-install-v15-on-MIUI-02-11", R.color.Telegram, context)
openUrl(
"https://telegra.ph/How-to-install-v15-on-MIUI-02-11",
R.color.Telegram,
context
)
}
setNeutralButton(context.getString(R.string.close)) { dialog, _ -> dialog.dismiss() }
if (fullMsg != null)
setNegativeButton(context.getString(R.string.advanced)) { _, _ -> basicDialog(context.getString(R.string.advanced), fullMsg, context) }
setNegativeButton(context.getString(R.string.advanced)) { _, _ ->
basicDialog(
context.getString(R.string.advanced),
fullMsg,
context
)
}
}
else -> {
setPositiveButton(context.getString(R.string.close)) { dialog, _ -> dialog.dismiss() }
if (fullMsg != null)
setNegativeButton(context.getString(R.string.advanced)) { _, _ -> basicDialog(context.getString(R.string.advanced), fullMsg, context) }
setNegativeButton(context.getString(R.string.advanced)) { _, _ ->
basicDialog(
context.getString(R.string.advanced),
fullMsg,
context
)
}
}
}
create()
applyAccent()
showWithAccent()
}
}
@ -104,7 +125,7 @@ object DialogContainer {
setMessage(msg)
setPositiveButton(context.getString(R.string.close)) { dialog, _ -> dialog.dismiss() }
create()
applyAccent()
showWithAccent()
}
}

View file

@ -13,7 +13,8 @@ import com.vanced.manager.databinding.DialogInstallationFilesDetectedBinding
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.managerVariant
class InstallationFilesDetectedDialog : BindingBottomSheetDialogFragment<DialogInstallationFilesDetectedBinding>() {
class InstallationFilesDetectedDialog :
BindingBottomSheetDialogFragment<DialogInstallationFilesDetectedBinding>() {
companion object {
@ -40,15 +41,17 @@ class InstallationFilesDetectedDialog : BindingBottomSheetDialogFragment<DialogI
private fun bindData() {
with(binding) {
val app = arguments?.getString(TAG_APP) ?: throw IllegalArgumentException("app name is null")
val app =
arguments?.getString(TAG_APP) ?: throw IllegalArgumentException("app name is null")
installationDetectedTitle.text = getString(R.string.app_install_files_detected, app)
installationDetectedSummary.text = getString(R.string.app_install_files_detected_summary, app)
installationDetectedSummary.text =
getString(R.string.app_install_files_detected_summary, app)
installationDetectedRedownload.setOnClickListener {
dismiss()
if (app == getString(R.string.vanced))
showDialog(VancedPreferencesDialog())
else {
showDialog(AppDownloadDialog.newInstance(app))
when (app) {
getString(R.string.vanced) -> showDialog(VancedPreferencesDialog())
getString(R.string.music) -> showDialog(MusicPreferencesDialog())
else -> showDialog(AppDownloadDialog.newInstance(app))
}
}
installationDetectedInstall.setOnClickListener {

View file

@ -2,10 +2,10 @@ package com.vanced.manager.ui.dialogs
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
@ -16,6 +16,7 @@ import com.vanced.manager.R
import com.vanced.manager.core.ui.base.BindingDialogFragment
import com.vanced.manager.databinding.DialogManagerAccentColorBinding
import com.vanced.manager.utils.*
import com.vanced.manager.utils.AppUtils.log
class ManagerAccentColorDialog : BindingDialogFragment<DialogManagerAccentColorBinding>() {
@ -34,6 +35,7 @@ class ManagerAccentColorDialog : BindingDialogFragment<DialogManagerAccentColorB
) = DialogManagerAccentColorBinding.inflate(inflater, container, false)
override fun otherSetups() {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
bindData()
}
@ -48,9 +50,20 @@ class ManagerAccentColorDialog : BindingDialogFragment<DialogManagerAccentColorB
hexEdittext.apply {
setText(accent.toHex(), TextView.BufferType.EDITABLE)
addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
override fun onTextChanged(
s: CharSequence?,
start: Int,
before: Int,
count: Int
) {
if (length() == 0) {
setText("#")
setSelection(1)
@ -61,7 +74,8 @@ class ManagerAccentColorDialog : BindingDialogFragment<DialogManagerAccentColorB
val colorFromEditText = Color.parseColor(text.toString())
accentPicker.setColor(colorFromEditText)
mutableAccentColor.value = colorFromEditText
} catch (e: IllegalArgumentException) {}
} catch (e: IllegalArgumentException) {
}
}
}
@ -93,8 +107,12 @@ class ManagerAccentColorDialog : BindingDialogFragment<DialogManagerAccentColorB
mutableAccentColor.value = colorFromEditText
prefs.managerAccent = colorFromEditText
} catch (e: IllegalArgumentException) {
Log.d("VMTheme", getString(R.string.failed_accent))
Toast.makeText(requireActivity(), getString(R.string.failed_accent), Toast.LENGTH_SHORT).show()
log("VMTheme", getString(R.string.failed_accent))
Toast.makeText(
requireActivity(),
getString(R.string.failed_accent),
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}

View file

@ -10,7 +10,7 @@ import com.vanced.manager.BuildConfig.MANAGER_LANGUAGES
import com.vanced.manager.core.ui.base.BindingBottomSheetDialogFragment
import com.vanced.manager.databinding.DialogManagerLanguageBinding
import com.vanced.manager.ui.core.ThemedMaterialRadioButton
import com.vanced.manager.utils.getCheckedButtonTag
import com.vanced.manager.utils.checkedButtonTag
import com.vanced.manager.utils.getLanguageFormat
import com.vanced.manager.utils.managerLang
@ -43,7 +43,7 @@ class ManagerLanguageDialog : BindingBottomSheetDialogFragment<DialogManagerLang
val language = prefs.managerLang
root.findViewWithTag<ThemedMaterialRadioButton>(language)?.isChecked = true
languageSave.setOnClickListener {
val newPref = binding.languageRadiogroup.getCheckedButtonTag()
val newPref = binding.languageRadiogroup.checkedButtonTag
if (language != newPref) {
prefs.managerLang = newPref
dismiss()

View file

@ -7,7 +7,7 @@ import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.google.android.material.radiobutton.MaterialRadioButton
import com.vanced.manager.core.ui.base.BindingBottomSheetDialogFragment
import com.vanced.manager.databinding.DialogManagerThemeBinding
import com.vanced.manager.utils.getCheckedButtonTag
import com.vanced.manager.utils.checkedButtonTag
import com.vanced.manager.utils.managerTheme
class ManagerThemeDialog : BindingBottomSheetDialogFragment<DialogManagerThemeBinding>() {
@ -36,7 +36,7 @@ class ManagerThemeDialog : BindingBottomSheetDialogFragment<DialogManagerThemeBi
val theme = prefs.managerTheme
root.findViewWithTag<MaterialRadioButton>(theme).isChecked = true
themeSave.setOnClickListener {
val newPref = themeRadiogroup.getCheckedButtonTag()
val newPref = themeRadiogroup.checkedButtonTag
if (theme != newPref) {
prefs.managerTheme = newPref
dismiss()

View file

@ -1,5 +1,6 @@
package com.vanced.manager.ui.dialogs
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@ -16,8 +17,9 @@ import com.vanced.manager.R
import com.vanced.manager.core.ui.base.BindingDialogFragment
import com.vanced.manager.databinding.DialogManagerUpdateBinding
import com.vanced.manager.utils.DownloadHelper.downloadManager
import com.vanced.manager.utils.DownloadHelper.downloadProgress
import com.vanced.manager.utils.applyAccent
import com.vanced.manager.utils.currentDownload
import com.vanced.manager.utils.downloadProgress
import com.vanced.manager.utils.manager
class ManagerUpdateDialog : BindingDialogFragment<DialogManagerUpdateBinding>() {
@ -56,7 +58,8 @@ class ManagerUpdateDialog : BindingDialogFragment<DialogManagerUpdateBinding>()
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
bindData()
if (arguments?.getBoolean(TAG_FORCE_UPDATE) == true) {
binding.managerUpdatePatient.text = requireActivity().getString(R.string.please_be_patient)
binding.managerUpdatePatient.text =
requireActivity().getString(R.string.please_be_patient)
downloadManager(requireActivity())
} else {
checkUpdates()
@ -68,24 +71,20 @@ class ManagerUpdateDialog : BindingDialogFragment<DialogManagerUpdateBinding>()
isCancelable = false
managerUpdateProgressbar.applyAccent()
managerUpdateCancel.setOnClickListener {
with(downloadProgress.value) {
this?.downloadProgress?.value = 0
this?.currentDownload?.cancel()
}
downloadProgress.value = 0
currentDownload?.cancel()
dismiss()
}
bindDownloadProgress()
}
}
@SuppressLint("SetTextI18n")
private fun DialogManagerUpdateBinding.bindDownloadProgress() {
with(downloadProgress) {
observe(viewLifecycleOwner) { progressModel ->
progressModel.downloadProgress.observe(viewLifecycleOwner) {
managerUpdateProgressbar.progress = it
managerUpdateProgressbar.isVisible = it != 0
}
}
downloadProgress.observe(viewLifecycleOwner) {
managerUpdateProgressbar.progress = it
managerUpdateProgressbarContainer.isVisible = it != 0
managerUpdateProgress.text = "$it%"
}
}
@ -94,12 +93,19 @@ class ManagerUpdateDialog : BindingDialogFragment<DialogManagerUpdateBinding>()
registerReceiver()
}
override fun onPause() {
super.onPause()
localBroadcastManager.unregisterReceiver(broadcastReceiver)
}
private fun checkUpdates() {
if (manager.value?.int("versionCode") ?: 0 > VERSION_CODE) {
binding.managerUpdatePatient.text = requireActivity().getString(R.string.please_be_patient)
binding.managerUpdatePatient.text =
requireActivity().getString(R.string.please_be_patient)
downloadManager(requireActivity())
} else {
binding.managerUpdatePatient.text = requireActivity().getString(R.string.update_not_found)
binding.managerUpdatePatient.text =
requireActivity().getString(R.string.update_not_found)
}
}

View file

@ -8,7 +8,7 @@ import com.google.android.material.radiobutton.MaterialRadioButton
import com.topjohnwu.superuser.Shell
import com.vanced.manager.core.ui.base.BindingBottomSheetDialogFragment
import com.vanced.manager.databinding.DialogManagerVariantBinding
import com.vanced.manager.utils.getCheckedButtonTag
import com.vanced.manager.utils.checkedButtonTag
import com.vanced.manager.utils.managerVariant
class ManagerVariantDialog : BindingBottomSheetDialogFragment<DialogManagerVariantBinding>() {
@ -37,11 +37,11 @@ class ManagerVariantDialog : BindingBottomSheetDialogFragment<DialogManagerVaria
val variant = prefs.managerVariant
root.findViewWithTag<MaterialRadioButton>(variant).isChecked = true
variantSave.setOnClickListener {
val newPref = variantRadiogroup.getCheckedButtonTag()
val newPref = variantRadiogroup.checkedButtonTag
if (variant != newPref) {
prefs.managerVariant =
if (newPref == "root" && Shell.rootAccess()) {
"root"
"root"
} else {
"nonroot"
}

View file

@ -7,9 +7,7 @@ import com.vanced.manager.R
import com.vanced.manager.core.ui.base.BindingBottomSheetDialogFragment
import com.vanced.manager.core.ui.ext.showDialog
import com.vanced.manager.databinding.DialogMusicPreferencesBinding
import com.vanced.manager.utils.convertToAppVersions
import com.vanced.manager.utils.defPrefs
import com.vanced.manager.utils.musicVersions
import com.vanced.manager.utils.*
class MusicPreferencesDialog : BindingBottomSheetDialogFragment<DialogMusicPreferencesBinding>() {
@ -35,9 +33,13 @@ class MusicPreferencesDialog : BindingBottomSheetDialogFragment<DialogMusicPrefe
private fun bindData() {
with(binding) {
val musicVersionsConv = musicVersions.value?.value?.convertToAppVersions()
musicInstallTitle.text = getString(R.string.app_installation_preferences, getString(R.string.music))
musicVersion.text = getString(R.string.chosen_version, prefs.getString("music_version", "latest"))
openVersionSelector.setOnClickListener {
musicInstallTitle.text =
getString(R.string.app_installation_preferences, getString(R.string.music))
musicVersion.text = getString(
R.string.chosen_version,
prefs.musicVersion?.formatVersion(requireActivity())
)
openVersionSelectorLayout.setOnClickListener {
dismiss()
showDialog(
AppVersionSelectorDialog.newInstance(

View file

@ -43,12 +43,17 @@ class SelectAppsDialog : BindingBottomSheetDialogFragment<DialogSelectAppsBindin
}
selectAppsSave.setOnClickListener {
if (ad.apps.all { app -> !app.isChecked }) {
Toast.makeText(requireActivity(), R.string.select_at_least_one_app, Toast.LENGTH_SHORT).show()
Toast.makeText(
requireActivity(),
R.string.select_at_least_one_app,
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
prefs.edit {
ad.apps.forEach { app ->
putBoolean("enable_${app.tag}", app.isChecked)
putBoolean("${app.tag}_notifs", app.isChecked)
}
}
dismiss()

View file

@ -32,7 +32,7 @@ class ServiceDTimerDialog : BindingDialogFragment<DialogServicedTimerBinding>()
}
private fun bindData() {
with (binding) {
with(binding) {
servicedSlider.value = prefs.getInt("serviced_sleep_timer", 1).toFloat()
servicedCancel.setOnClickListener {
dismiss()
@ -41,12 +41,26 @@ class ServiceDTimerDialog : BindingDialogFragment<DialogServicedTimerBinding>()
try {
arrayOf("vanced", "music").forEach { app ->
if (scriptExists(app)) {
val apkFPath = "${PackageHelper.apkInstallPath}/${app.capitalize(Locale.ROOT)}/base.apk"
getPackageDir(requireActivity(), getPkgNameRoot(app))?.let { it1 -> requireActivity().writeServiceDScript(apkFPath, it1, app) }
val apkFPath =
"${PackageHelper.apkInstallPath}/${app.capitalize(Locale.ROOT)}/base.apk"
getPackageDir(
requireActivity(),
getPkgNameRoot(app)
)?.let { it1 ->
requireActivity().writeServiceDScript(
apkFPath,
it1,
app
)
}
}
}
} catch (e: IOException) {
Toast.makeText(requireActivity(), R.string.script_save_failed, Toast.LENGTH_SHORT).show()
Toast.makeText(
requireActivity(),
R.string.script_save_failed,
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}

View file

@ -45,11 +45,12 @@ class URLChangeDialog : BindingDialogFragment<DialogCustomUrlBinding>() {
TextView.BufferType.EDITABLE
)
urlSave.setOnClickListener {
val finalUrl = if (urlInput.text?.startsWith("https://") == true || urlInput.text?.startsWith("http://") == true) {
urlInput.text?.removeSuffix("/").toString()
} else {
"https://${urlInput.text}".removeSuffix("/")
}
val finalUrl =
if (urlInput.text?.startsWith("https://") == true || urlInput.text?.startsWith("http://") == true) {
urlInput.text?.removeSuffix("/").toString()
} else {
"https://${urlInput.text}".removeSuffix("/")
}
saveUrl(finalUrl)
}
urlReset.setOnClickListener { saveUrl(baseUrl) }

View file

@ -19,7 +19,8 @@ import com.vanced.manager.utils.lang
import com.vanced.manager.utils.vanced
import java.util.*
class VancedLanguageSelectionDialog : BindingBottomSheetDialogFragment<DialogVancedLanguageSelectionBinding>() {
class VancedLanguageSelectionDialog :
BindingBottomSheetDialogFragment<DialogVancedLanguageSelectionBinding>() {
companion object {
@ -52,7 +53,11 @@ class VancedLanguageSelectionDialog : BindingBottomSheetDialogFragment<DialogVan
}
}
if (chosenLangs.isEmpty()) {
Toast.makeText(requireActivity(), R.string.select_at_least_one_lang, Toast.LENGTH_SHORT).show()
Toast.makeText(
requireActivity(),
R.string.select_at_least_one_lang,
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
prefs.lang = chosenLangs.joinToString()

View file

@ -3,14 +3,11 @@ package com.vanced.manager.ui.dialogs
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.vanced.manager.R
import com.vanced.manager.core.ui.base.BindingBottomSheetDialogFragment
import com.vanced.manager.core.ui.ext.showDialog
import com.vanced.manager.databinding.DialogVancedPreferencesBinding
import com.vanced.manager.utils.*
import com.vanced.manager.utils.AppUtils.vancedPkg
import com.vanced.manager.utils.PackageHelper.isPackageInstalled
import java.util.*
class VancedPreferencesDialog : BindingBottomSheetDialogFragment<DialogVancedPreferencesBinding>() {
@ -38,20 +35,27 @@ class VancedPreferencesDialog : BindingBottomSheetDialogFragment<DialogVancedPre
private fun bindData() {
with(binding) {
val showLang = mutableListOf<String>()
installPrefs.lang?.split(", ")?.toTypedArray()?.forEach { lang ->
installPrefs.lang?.split(", ")?.forEach { lang ->
val loc = Locale(lang)
showLang.add(loc.getDisplayLanguage(loc).capitalize(Locale.ROOT))
}
val vancedVersionsConv = vancedVersions.value?.value?.convertToAppVersions()
vancedInstallTitle.text = getString(R.string.app_installation_preferences, getString(R.string.vanced))
vancedTheme.text = getString(R.string.chosen_theme, installPrefs.getString("theme", "dark")?.convertToAppTheme(requireActivity()))
vancedVersion.text = getString(R.string.chosen_version, defPrefs.getString("vanced_version", "latest"))
vancedInstallTitle.text =
getString(R.string.app_installation_preferences, getString(R.string.vanced))
vancedTheme.text = getString(
R.string.chosen_theme,
installPrefs.theme?.convertToAppTheme(requireActivity())
)
vancedVersion.text = getString(
R.string.chosen_version,
defPrefs.vancedVersion?.formatVersion(requireActivity())
)
vancedLang.text = getString(R.string.chosen_lang, showLang)
openThemeSelector.setOnClickListener {
openThemeSelectorLayout.setOnClickListener {
dismiss()
showDialog(VancedThemeSelectorDialog())
}
openVersionSelector.setOnClickListener {
openVersionSelectorLayout.setOnClickListener {
dismiss()
showDialog(
AppVersionSelectorDialog.newInstance(
@ -60,7 +64,7 @@ class VancedPreferencesDialog : BindingBottomSheetDialogFragment<DialogVancedPre
)
)
}
openLanguageSelector.setOnClickListener {
openLanguageSelectorLayout.setOnClickListener {
dismiss()
showDialog(VancedLanguageSelectionDialog())
}
@ -68,33 +72,12 @@ class VancedPreferencesDialog : BindingBottomSheetDialogFragment<DialogVancedPre
if (showLang.isEmpty()) {
installPrefs.lang = "en"
}
fun downloadVanced(version: String? = null) {
dismiss()
showDialog(
AppDownloadDialog.newInstance(
app = getString(R.string.vanced),
version = version
)
dismiss()
showDialog(
AppDownloadDialog.newInstance(
app = getString(R.string.vanced)
)
}
if (defPrefs.managerVariant == "nonroot" && isMicrogBroken && installPrefs.vancedVersion?.getLatestAppVersion(vancedVersions.value?.value ?: listOf(""))?.take(2)?.toIntOrNull() == 16 && !isPackageInstalled(vancedPkg, requireActivity().packageManager)) {
MaterialAlertDialogBuilder(requireActivity()).apply {
setTitle(R.string.microg_bug)
setMessage(R.string.microg_bug_summary)
setPositiveButton(R.string.auth_dialog_ok) { _, _ ->
downloadVanced("15.43.32")
}
setNeutralButton(R.string.cancel) { _, _ ->
dismiss()
}
create()
}.applyAccent()
return@setOnClickListener
}
downloadVanced()
)
}
}
}

View file

@ -10,12 +10,13 @@ import com.vanced.manager.core.ui.base.BindingBottomSheetDialogFragment
import com.vanced.manager.core.ui.ext.showDialog
import com.vanced.manager.databinding.DialogBottomRadioButtonBinding
import com.vanced.manager.ui.core.ThemedMaterialRadioButton
import com.vanced.manager.utils.checkedButtonTag
import com.vanced.manager.utils.convertToAppTheme
import com.vanced.manager.utils.getCheckedButtonTag
import com.vanced.manager.utils.theme
import com.vanced.manager.utils.vanced
class VancedThemeSelectorDialog : BindingBottomSheetDialogFragment<DialogBottomRadioButtonBinding>() {
class VancedThemeSelectorDialog :
BindingBottomSheetDialogFragment<DialogBottomRadioButtonBinding>() {
companion object {
@ -24,7 +25,12 @@ class VancedThemeSelectorDialog : BindingBottomSheetDialogFragment<DialogBottomR
}
}
private val prefs by lazy { requireActivity().getSharedPreferences("installPrefs", Context.MODE_PRIVATE) }
private val prefs by lazy {
requireActivity().getSharedPreferences(
"installPrefs",
Context.MODE_PRIVATE
)
}
override fun binding(
inflater: LayoutInflater,
@ -51,7 +57,7 @@ class VancedThemeSelectorDialog : BindingBottomSheetDialogFragment<DialogBottomR
tag.isChecked = true
}
dialogSave.setOnClickListener {
val checkedTag = binding.dialogRadiogroup.getCheckedButtonTag()
val checkedTag = binding.dialogRadiogroup.checkedButtonTag
if (checkedTag != null) {
prefs.theme = checkedTag
}
@ -60,7 +66,7 @@ class VancedThemeSelectorDialog : BindingBottomSheetDialogFragment<DialogBottomR
}
}
private fun loadButtons() = vanced.value?.array<String>("themes")?.value?.map {theme ->
private fun loadButtons() = vanced.value?.array<String>("themes")?.value?.map { theme ->
ThemedMaterialRadioButton(requireActivity()).apply {
text = theme.convertToAppTheme(requireActivity())
tag = theme

View file

@ -1,23 +0,0 @@
package com.vanced.manager.ui.events
open class Event<out T>(private val content: T) {
private var hasBeenHandled = false
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}

View file

@ -6,7 +6,6 @@ import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.edit
import androidx.fragment.app.viewModels
import androidx.preference.PreferenceManager
@ -37,11 +36,11 @@ class AboutFragment : BindingFragment<FragmentAboutBinding>() {
@SuppressLint("ClickableViewAccessibility")
private fun dataBind() {
requireActivity().title = getString(R.string.title_about)
binding.aboutHeader.root.setOnClickListener {
binding.aboutVersionCard.setOnClickListener {
showDialog(
AppInfoDialog.newInstance(
appName = getString(R.string.app_name),
appIcon = AppCompatResources.getDrawable(requireActivity(), R.mipmap.ic_launcher),
appIcon = R.mipmap.ic_launcher,
changelog = manager.value?.string("changelog")
)
)
@ -61,17 +60,25 @@ class AboutFragment : BindingFragment<FragmentAboutBinding>() {
val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
val devSettings = prefs.getBoolean("devSettings", false)
if (!devSettings) {
Toast.makeText(requireContext(), "Dev options unlocked!", Toast.LENGTH_SHORT).show()
Toast.makeText(
requireContext(),
"Dev options unlocked!",
Toast.LENGTH_SHORT
).show()
prefs.edit { putBoolean("devSettings", true) }
} else
Toast.makeText(requireContext(), "Dev options already unlocked", Toast.LENGTH_SHORT).show()
Toast.makeText(
requireContext(),
"Dev options already unlocked",
Toast.LENGTH_SHORT
).show()
}
return@setOnTouchListener true
}
false
}
binding.aboutSources.aboutGithubButton.setOnClickListener { viewModel.openUrl("https://github.com/YTVanced/VancedInstaller") }
binding.aboutSources.aboutLicenseButton.setOnClickListener { viewModel.openUrl("https://raw.githubusercontent.com/YTVanced/VancedInstaller/dev/LICENSE") }
binding.aboutGithubButton.setOnClickListener { viewModel.openUrl("https://github.com/YTVanced/VancedInstaller") }
binding.aboutLicenseButton.setOnClickListener { viewModel.openUrl("https://raw.githubusercontent.com/YTVanced/VancedInstaller/dev/LICENSE") }
}
}

View file

@ -3,22 +3,15 @@ package com.vanced.manager.ui.fragments
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.core.content.edit
import androidx.core.net.toUri
import androidx.core.view.isVisible
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.crowdin.platform.Crowdin
import com.vanced.manager.BuildConfig
import com.vanced.manager.core.ui.base.BindingFragment
import com.vanced.manager.databinding.FragmentDevSettingsBinding
import com.vanced.manager.ui.WelcomeActivity
import com.vanced.manager.ui.dialogs.ManagerUpdateDialog
import com.vanced.manager.ui.dialogs.URLChangeDialog
import com.vanced.manager.utils.authCrowdin
class DevSettingsFragment : BindingFragment<FragmentDevSettingsBinding>() {
@ -40,7 +33,6 @@ class DevSettingsFragment : BindingFragment<FragmentDevSettingsBinding>() {
bindWelcomeLauncher()
bindForceUpdate()
bindChannelURL()
bindCrowdin()
bindKernelArch()
bindAndroidVersion()
}
@ -72,31 +64,6 @@ class DevSettingsFragment : BindingFragment<FragmentDevSettingsBinding>() {
}
}
private fun FragmentDevSettingsBinding.bindCrowdin() {
if (BuildConfig.ENABLE_CROWDIN_AUTH) {
val isAuthorized = Crowdin.isAuthorized()
crowdinCategory.isVisible = true
crowdinAuth.isVisible = !isAuthorized
screenshotUploading.isVisible = isAuthorized
realTimeUpdates.isVisible = isAuthorized
crowdinAuth.setOnClickListener {
requireActivity().authCrowdin()
@RequiresApi(Build.VERSION_CODES.M)
if (!Settings.canDrawOverlays(requireActivity())) {
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
("package:" + requireActivity().packageName).toUri()
)
startActivityForResult(intent, 69)
}
Crowdin.authorize(requireActivity())
}
}
}
private fun FragmentDevSettingsBinding.bindKernelArch() {
val supportedAbis: Array<String> = Build.SUPPORTED_ABIS

View file

@ -41,7 +41,12 @@ class GrantRootFragment : BindingFragment<FragmentGrantRootBinding>() {
private fun grantRoot() {
if (Shell.rootAccess()) {
getDefaultSharedPreferences(requireActivity()).edit { putString("vanced_variant", "root") }
getDefaultSharedPreferences(requireActivity()).edit {
putString(
"vanced_variant",
"root"
)
}
navigateToFirstLaunch()
} else {
Toast.makeText(requireActivity(), R.string.root_not_granted, Toast.LENGTH_SHORT).show()

View file

@ -9,41 +9,36 @@ import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.ViewGroup
import androidx.core.content.edit
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.viewModels
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.crowdin.platform.util.inflateWithCrowdin
import com.github.florent37.viewtooltip.ViewTooltip
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.flexbox.JustifyContent
import com.vanced.manager.BuildConfig.VERSION_CODE
import com.vanced.manager.R
import com.vanced.manager.adapter.AppListAdapter
import com.vanced.manager.adapter.ExpandableAppListAdapter
import com.vanced.manager.adapter.LinkAdapter
import com.vanced.manager.adapter.SponsorAdapter
import com.vanced.manager.core.ui.base.BindingFragment
import com.vanced.manager.core.ui.ext.showDialog
import com.vanced.manager.databinding.FragmentHomeBinding
import com.vanced.manager.ui.dialogs.AppInfoDialog
import com.vanced.manager.ui.dialogs.DialogContainer.installAlertBuilder
import com.vanced.manager.ui.viewmodels.HomeViewModel
import com.vanced.manager.ui.viewmodels.HomeViewModelFactory
import com.vanced.manager.utils.isFetching
import com.vanced.manager.utils.manager
open class HomeFragment : BindingFragment<FragmentHomeBinding>() {
class HomeFragment : BindingFragment<FragmentHomeBinding>() {
companion object {
const val INSTALL_FAILED = "INSTALL_FAILED"
const val REFRESH_HOME = "REFRESH_HOME"
}
private val viewModel: HomeViewModel by viewModels {
HomeViewModelFactory(requireActivity())
}
private val viewModel: HomeViewModel by viewModels()
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(requireActivity()) }
private val prefs by lazy { PreferenceManager.getDefaultSharedPreferences(requireActivity()) }
private lateinit var tooltip: ViewTooltip
override fun binding(
inflater: LayoutInflater,
@ -58,28 +53,27 @@ open class HomeFragment : BindingFragment<FragmentHomeBinding>() {
private fun bindData() {
requireActivity().title = getString(R.string.title_home)
setHasOptionsMenu(true)
with (binding) {
with(binding) {
homeRefresh.setOnRefreshListener { viewModel.fetchData() }
isFetching.observe(viewLifecycleOwner) { homeRefresh.isRefreshing = it }
tooltip = ViewTooltip
.on(recyclerAppList)
.position(ViewTooltip.Position.TOP)
.autoHide(false, 0)
.color(ResourcesCompat.getColor(requireActivity().resources, R.color.Twitter, null))
.withShadow(false)
.corner(25)
.onHide {
prefs.edit { putBoolean("show_changelog_tooltip", false) }
}
.text(requireActivity().getString(R.string.app_changelog_tooltip))
if (prefs.getBoolean("show_changelog_tooltip", true)) {
tooltip.show()
}
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
if (prefs.contains("LastVersionCode")) {
if (prefs.getInt("LastVersionCode", -1) < VERSION_CODE) {
showDialog(
AppInfoDialog.newInstance(
appName = getString(R.string.app_name),
appIcon = R.mipmap.ic_launcher,
changelog = manager.value?.string("changelog")
)
)
prefs.edit().putInt("LastVersionCode", VERSION_CODE).apply()
}
} else prefs.edit().putInt("LastVersionCode", VERSION_CODE).apply()
recyclerAppList.apply {
layoutManager = LinearLayoutManager(requireActivity())
adapter = AppListAdapter(requireActivity(), viewModel, viewLifecycleOwner, tooltip)
adapter = ExpandableAppListAdapter(requireActivity(), viewModel /*, tooltip*/)
setHasFixedSize(true)
}
@ -102,14 +96,12 @@ open class HomeFragment : BindingFragment<FragmentHomeBinding>() {
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflateWithCrowdin(R.menu.toolbar_menu, menu, resources)
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.toolbar_menu, menu)
}
override fun onPause() {
super.onPause()
localBroadcastManager.unregisterReceiver(broadcastReceiver)
tooltip.close()
}
override fun onResume() {
@ -120,7 +112,11 @@ open class HomeFragment : BindingFragment<FragmentHomeBinding>() {
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
INSTALL_FAILED -> installAlertBuilder(intent.getStringExtra("errorMsg").toString(), intent.getStringExtra("fullErrorMsg"), requireActivity())
INSTALL_FAILED -> installAlertBuilder(
intent.getStringExtra("errorMsg").toString(),
intent.getStringExtra("fullErrorMsg"),
requireActivity()
)
REFRESH_HOME -> viewModel.fetchData()
}
}

View file

@ -0,0 +1,57 @@
package com.vanced.manager.ui.fragments
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import com.vanced.manager.R
import com.vanced.manager.core.ui.base.BindingFragment
import com.vanced.manager.databinding.FragmentLogBinding
import com.vanced.manager.utils.AppUtils.logs
import java.io.File
import java.io.FileWriter
import java.io.IOException
import java.util.*
class LogFragment : BindingFragment<FragmentLogBinding>() {
override fun binding(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) = FragmentLogBinding.inflate(inflater, container, false)
override fun otherSetups() {
binding.bindData()
}
private fun FragmentLogBinding.bindData() {
val logs = TextUtils.concat(*logs.toTypedArray())
logText.text = logs
logSave.setOnClickListener {
try {
val calendar = Calendar.getInstance()
val year = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH)
val day = calendar.get(Calendar.DAY_OF_MONTH)
val hour = calendar.get(Calendar.HOUR_OF_DAY)
val minute = calendar.get(Calendar.MINUTE)
val second = calendar.get(Calendar.SECOND)
val savePath = requireActivity().getExternalFilesDir("logs")?.path + "/$year$month${day}_$hour$minute$second.log"
val log =
File(savePath)
FileWriter(log).apply {
append(logs)
flush()
close()
}
Toast.makeText(requireActivity(), getString(R.string.logs_saved, savePath), Toast.LENGTH_SHORT).show()
} catch (e: IOException) {
Toast.makeText(requireActivity(), R.string.logs_not_saved, Toast.LENGTH_SHORT)
.show()
}
}
}
}

View file

@ -5,13 +5,13 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.edit
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import androidx.recyclerview.widget.LinearLayoutManager
import com.vanced.manager.R
import com.vanced.manager.adapter.SelectAppsAdapter
import com.vanced.manager.core.ui.base.BindingFragment
import com.vanced.manager.databinding.FragmentSelectAppsBinding
import com.vanced.manager.ui.WelcomeActivity
class SelectAppsFragment : BindingFragment<FragmentSelectAppsBinding>() {
@ -45,13 +45,14 @@ class SelectAppsFragment : BindingFragment<FragmentSelectAppsBinding>() {
private fun actionOnClickAppsFab() {
if (selectAdapter.apps.all { app -> !app.isChecked }) {
Toast.makeText(requireActivity(), R.string.select_at_least_one_app, Toast.LENGTH_SHORT).show()
Toast.makeText(requireActivity(), R.string.select_at_least_one_app, Toast.LENGTH_SHORT)
.show()
return
}
val prefs = getDefaultSharedPreferences(requireActivity())
selectAdapter.apps.forEach { app ->
prefs.edit { putBoolean("enable_${app.tag}", app.isChecked) }
}
findNavController().navigate(SelectAppsFragmentDirections.selectAppsToGrantRoot())
(requireActivity() as WelcomeActivity).navigateTo(2)
}
}

View file

@ -7,6 +7,7 @@ import android.view.MenuInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.firebase.analytics.FirebaseAnalytics
@ -34,6 +35,7 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
private val prefs by lazy { getDefaultSharedPreferences(requireActivity()) }
private lateinit var variant: String
private lateinit var parentActivity: FragmentActivity
override fun binding(
inflater: LayoutInflater,
@ -43,6 +45,7 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
override fun otherSetups() {
setHasOptionsMenu(true)
parentActivity = requireActivity()
bindData()
}
@ -63,8 +66,8 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
private fun FragmentSettingsBinding.bindRecycler() {
notificationsRecycler.apply {
layoutManager = LinearLayoutManager(requireActivity())
adapter = GetNotifAdapter(requireActivity())
layoutManager = LinearLayoutManager(parentActivity)
adapter = GetNotifAdapter(parentActivity)
}
}
@ -72,7 +75,7 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
firebase.setOnCheckedListener { _, isChecked ->
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(isChecked)
FirebasePerformance.getInstance().isPerformanceCollectionEnabled = isChecked
FirebaseAnalytics.getInstance(requireActivity()).setAnalyticsCollectionEnabled(isChecked)
FirebaseAnalytics.getInstance(parentActivity).setAnalyticsCollectionEnabled(isChecked)
}
}
@ -93,7 +96,13 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
private fun FragmentSettingsBinding.bindClearFiles() {
clearFiles.setOnClickListener {
with(requireActivity()) {
listOf("vanced/nonroot", "vanced/root", "music/nonroot", "music/root", "microg").forEach { dir ->
listOf(
"vanced/nonroot",
"vanced/root",
"music/nonroot",
"music/root",
"microg"
).forEach { dir ->
File(getExternalFilesDir(dir)?.path.toString()).deleteRecursively()
}
Toast.makeText(this, getString(R.string.cleared_files), Toast.LENGTH_SHORT).show()
@ -116,7 +125,7 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
}
private fun FragmentSettingsBinding.bindManagerAccentColor() {
managerAccentColor.apply{
managerAccentColor.apply {
setSummary(prefs.getInt("manager_accent_color", defAccentColor).toHex())
setOnClickListener { showDialog(ManagerAccentColorDialog()) }
accentColor.observe(viewLifecycleOwner) {
@ -128,14 +137,15 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
private fun FragmentSettingsBinding.bindManagerLanguage() {
val langPref = prefs.getString("manager_lang", "System Default")
managerLanguage.apply {
setSummary(getLanguageFormat(requireActivity(), requireNotNull(langPref)))
setSummary(getLanguageFormat(parentActivity, requireNotNull(langPref)))
setOnClickListener { showDialog(ManagerLanguageDialog()) }
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
val devSettings = getDefaultSharedPreferences(requireActivity()).getBoolean("devSettings", false)
val devSettings =
getDefaultSharedPreferences(requireActivity()).getBoolean("devSettings", false)
if (devSettings) {
inflater.inflate(R.menu.dev_settings_menu, menu)
}

View file

@ -0,0 +1,56 @@
package com.vanced.manager.ui.fragments
//import android.os.Bundle
//import android.view.LayoutInflater
//import android.view.View
//import android.view.ViewGroup
//import androidx.compose.foundation.lazy.LazyColumn
//import androidx.compose.ui.platform.ComposeView
//import androidx.fragment.app.Fragment
//import com.vanced.manager.R
//import com.vanced.manager.ui.compose.Preference
//import com.vanced.manager.ui.compose.PreferenceCategory
//import com.vanced.manager.ui.compose.SwitchPreference
//
//class SettingsFragmentCompose : Fragment() {
//
// override fun onCreateView(
// inflater: LayoutInflater,
// container: ViewGroup?,
// savedInstanceState: Bundle?
// ): View {
// return ComposeView(requireActivity()).apply {
// setContent {
// LazyColumn {
// // use `item` for separate elements like headers
// // and `items` for lists of identical elements
// item {
// PreferenceCategory(
// categoryTitle = getString(R.string.category_behaviour)
// ) {
// SwitchPreference(
// preferenceTitle = getString(R.string.use_custom_tabs),
// preferenceDescription = getString(R.string.link_custom_tabs),
// preferenceKey = "use_custom_tabs"
// )
// }
// }
// item {
// PreferenceCategory(
// categoryTitle = getString(R.string.category_appearance)
// ) {
// Preference(
// preferenceTitle = "test",
// preferenceDescription = "test",
// ) {}
// Preference(
// preferenceTitle = "test"
// ) {}
// }
// }
// }
// }
// }
// }
//
//}

View file

@ -3,9 +3,9 @@ package com.vanced.manager.ui.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.vanced.manager.core.ui.base.BindingFragment
import com.vanced.manager.databinding.FragmentWelcomeBinding
import com.vanced.manager.ui.WelcomeActivity
class WelcomeFragment : BindingFragment<FragmentWelcomeBinding>() {
@ -20,10 +20,8 @@ class WelcomeFragment : BindingFragment<FragmentWelcomeBinding>() {
}
private fun bindData() {
binding.welcomeGetStarted.setOnClickListener { navigateToWelcome() }
}
private fun navigateToWelcome() {
findNavController().navigate(WelcomeFragmentDirections.welcomeToSelectApps())
binding.welcomeGetStarted.setOnClickListener {
(requireActivity() as WelcomeActivity).navigateTo(1)
}
}
}

View file

@ -5,7 +5,7 @@ import androidx.lifecycle.AndroidViewModel
import com.vanced.manager.R
import com.vanced.manager.utils.openUrl
class AboutViewModel(application: Application): AndroidViewModel(application) {
class AboutViewModel(application: Application) : AndroidViewModel(application) {
fun openUrl(url: String) {
openUrl(url, R.color.GitHub, getApplication())

View file

@ -1,25 +1,23 @@
package com.vanced.manager.ui.viewmodels
import android.app.Application
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.crowdin.platform.Crowdin
import com.google.android.material.button.MaterialButton
import com.vanced.manager.R
import com.vanced.manager.adapter.LinkAdapter.Companion.DISCORD
import com.vanced.manager.adapter.LinkAdapter.Companion.REDDIT
import com.vanced.manager.adapter.LinkAdapter.Companion.TELEGRAM
import com.vanced.manager.adapter.LinkAdapter.Companion.TWITTER
import com.vanced.manager.adapter.SponsorAdapter.Companion.BRAVE
import com.vanced.manager.model.ButtonTag
import com.vanced.manager.model.DataModel
import com.vanced.manager.model.RootDataModel
import com.vanced.manager.ui.dialogs.AppDownloadDialog
@ -27,6 +25,7 @@ import com.vanced.manager.ui.dialogs.InstallationFilesDetectedDialog
import com.vanced.manager.ui.dialogs.MusicPreferencesDialog
import com.vanced.manager.ui.dialogs.VancedPreferencesDialog
import com.vanced.manager.utils.*
import com.vanced.manager.utils.AppUtils.log
import com.vanced.manager.utils.AppUtils.managerPkg
import com.vanced.manager.utils.AppUtils.microgPkg
import com.vanced.manager.utils.AppUtils.musicPkg
@ -40,10 +39,11 @@ import com.vanced.manager.utils.PackageHelper.uninstallRootApk
import com.vanced.manager.utils.PackageHelper.vancedInstallFilesExist
import kotlinx.coroutines.launch
open class HomeViewModel(private val activity: FragmentActivity): ViewModel() {
class HomeViewModel(application: Application) : AndroidViewModel(application) {
private val prefs = getDefaultSharedPreferences(activity)
private val prefs = getDefaultSharedPreferences(context)
private val variant get() = prefs.getString("vanced_variant", "nonroot")
private val context: Context get() = getApplication()
val vancedModel = MutableLiveData<DataModel>()
val vancedRootModel = MutableLiveData<RootDataModel>()
@ -54,14 +54,13 @@ open class HomeViewModel(private val activity: FragmentActivity): ViewModel() {
fun fetchData() {
viewModelScope.launch {
loadJson(activity)
Crowdin.forceUpdate(activity)
loadJson(context)
}
}
private val microgToast = Toast.makeText(activity, R.string.no_microg, Toast.LENGTH_LONG)
fun openUrl(url: String) {
private val microgToast = Toast.makeText(context, R.string.no_microg, Toast.LENGTH_LONG)
fun openUrl(context: Context, url: String) {
val color: Int =
when (url) {
DISCORD -> R.color.Discord
@ -71,75 +70,83 @@ open class HomeViewModel(private val activity: FragmentActivity): ViewModel() {
BRAVE -> R.color.Brave
else -> R.color.Vanced
}
openUrl(url, color, activity)
openUrl(url, color, context)
}
fun launchApp(app: String, isRoot: Boolean) {
val componentName = when (app) {
activity.getString(R.string.vanced) -> if (isRoot) ComponentName(vancedRootPkg, "$vancedRootPkg.HomeActivity") else ComponentName(vancedPkg, "$vancedRootPkg.HomeActivity")
activity.getString(R.string.music) -> if (isRoot) ComponentName(musicRootPkg, "$musicRootPkg.activities.MusicActivity") else ComponentName(musicPkg, "$musicRootPkg.activities.MusicActivity")
activity.getString(R.string.microg) -> ComponentName(microgPkg, "org.microg.gms.ui.SettingsActivity")
context.getString(R.string.vanced) -> if (isRoot) ComponentName(
vancedRootPkg,
"$vancedRootPkg.HomeActivity"
) else ComponentName(vancedPkg, "$vancedRootPkg.HomeActivity")
context.getString(R.string.music) -> if (isRoot) ComponentName(
musicRootPkg,
"$musicRootPkg.activities.MusicActivity"
) else ComponentName(musicPkg, "$musicRootPkg.activities.MusicActivity")
context.getString(R.string.microg) -> ComponentName(
microgPkg,
"org.microg.gms.ui.SettingsActivity"
)
else -> throw IllegalArgumentException("Can't open this app")
}
try {
activity.startActivity(Intent().setComponent(componentName))
context.startActivity(Intent().setComponent(componentName))
} catch (e: ActivityNotFoundException) {
Log.d("VMHMV", e.toString())
log("VMHMV", e.toString())
}
}
fun openInstallDialog(view: View, app: String) {
if (variant == "nonroot" && app != activity.getString(R.string.microg) && !microgModel.value?.isAppInstalled?.value!!) {
fun openInstallDialog(fragmentManager: FragmentManager, buttonTag: ButtonTag?, app: String) {
if (variant == "nonroot" && app != context.getString(R.string.microg) && !microgModel.value?.isAppInstalled?.value!!) {
microgToast.show()
return
}
if ((view as MaterialButton).text == activity.getString(R.string.update)) {
if (buttonTag == ButtonTag.UPDATE) {
when (app) {
activity.getString(R.string.vanced) -> VancedPreferencesDialog().show(activity)
activity.getString(R.string.music) -> MusicPreferencesDialog().show(activity)
else -> AppDownloadDialog.newInstance(app).show(activity)
context.getString(R.string.vanced) -> VancedPreferencesDialog().show(fragmentManager)
context.getString(R.string.music) -> MusicPreferencesDialog().show(fragmentManager)
else -> AppDownloadDialog.newInstance(app).show(fragmentManager)
}
return
}
when (app) {
activity.getString(R.string.vanced) -> {
context.getString(R.string.vanced) -> {
when (variant) {
"nonroot" -> {
if (vancedInstallFilesExist(activity)) {
InstallationFilesDetectedDialog.newInstance(app).show(activity)
if (vancedInstallFilesExist(context)) {
InstallationFilesDetectedDialog.newInstance(app).show(fragmentManager)
} else {
VancedPreferencesDialog().show(activity)
VancedPreferencesDialog().show(fragmentManager)
}
}
"root" -> {
VancedPreferencesDialog().show(activity)
VancedPreferencesDialog().show(fragmentManager)
}
}
}
activity.getString(R.string.music) -> {
context.getString(R.string.music) -> {
when (variant) {
"nonroot" -> {
if (musicApkExists(activity)) {
InstallationFilesDetectedDialog.newInstance(app).show(activity)
if (musicApkExists(context)) {
InstallationFilesDetectedDialog.newInstance(app).show(fragmentManager)
} else {
MusicPreferencesDialog().show(activity)
MusicPreferencesDialog().show(fragmentManager)
}
}
"root" -> {
MusicPreferencesDialog().show(activity)
MusicPreferencesDialog().show(fragmentManager)
}
}
}
activity.getString(R.string.microg) -> {
if (apkExist(activity, "microg.apk")) {
InstallationFilesDetectedDialog.newInstance(app).show(activity)
context.getString(R.string.microg) -> {
if (apkExist(context, "microg.apk")) {
InstallationFilesDetectedDialog.newInstance(app).show(fragmentManager)
} else {
AppDownloadDialog.newInstance(app).show(activity)
AppDownloadDialog.newInstance(app).show(fragmentManager)
}
}
}
@ -148,23 +155,67 @@ open class HomeViewModel(private val activity: FragmentActivity): ViewModel() {
fun uninstallPackage(pkg: String) {
if (variant == "root" && uninstallRootApk(pkg)) {
viewModelScope.launch { loadJson(activity) }
viewModelScope.launch { loadJson(context) }
} else {
uninstallApk(pkg, activity)
uninstallApk(pkg, context)
}
}
init {
with (activity) {
with(context) {
if (variant == "root") {
vancedRootModel.value = RootDataModel(vanced, this, this, vancedRootPkg, this.getString(R.string.vanced), AppCompatResources.getDrawable(this, R.drawable.ic_vanced), "vanced")
musicRootModel.value = RootDataModel(music, this, this, musicRootPkg, this.getString(R.string.music), AppCompatResources.getDrawable(this, R.drawable.ic_music), "music")
vancedRootModel.value = RootDataModel(
vanced,
this,
vancedRootPkg,
this.getString(R.string.vanced),
this.getString(R.string.description_vanced),
R.drawable.ic_vanced,
"vanced"
)
musicRootModel.value = RootDataModel(
music,
this,
musicRootPkg,
this.getString(R.string.music),
this.getString(R.string.description_vanced_music),
R.drawable.ic_music,
"music"
)
} else {
vancedModel.value = DataModel(vanced, this, this, vancedPkg, this.getString(R.string.vanced), AppCompatResources.getDrawable(this, R.drawable.ic_vanced))
musicModel.value = DataModel(music, this, this, musicPkg, this.getString(R.string.music), AppCompatResources.getDrawable(this, R.drawable.ic_music))
microgModel.value = DataModel(microg, this, this, microgPkg, this.getString(R.string.microg), AppCompatResources.getDrawable(this, R.drawable.ic_microg))
vancedModel.value = DataModel(
vanced,
this,
vancedPkg,
this.getString(R.string.vanced),
this.getString(R.string.description_vanced),
R.drawable.ic_vanced
)
musicModel.value = DataModel(
music,
this,
musicPkg,
this.getString(R.string.music),
this.getString(R.string.description_vanced_music),
R.drawable.ic_music
)
microgModel.value = DataModel(
microg,
this,
microgPkg,
this.getString(R.string.microg),
this.getString(R.string.description_microg),
R.drawable.ic_microg
)
}
managerModel.value = DataModel(manager, this, this, managerPkg, this.getString(R.string.app_name), AppCompatResources.getDrawable(this, R.mipmap.ic_launcher))
managerModel.value = DataModel(
manager,
this,
managerPkg,
this.getString(R.string.app_name),
"Just manager meh",
R.mipmap.ic_launcher
)
}
}
}

View file

@ -1,14 +0,0 @@
package com.vanced.manager.ui.viewmodels
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
class HomeViewModelFactory(private val activity: FragmentActivity) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return HomeViewModel(activity) as T
}
}

View file

@ -2,65 +2,81 @@ package com.vanced.manager.utils
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.graphics.Color
import android.graphics.Typeface
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan
import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.BuildConfig
import com.vanced.manager.BuildConfig.APPLICATION_ID
import com.vanced.manager.R
import com.vanced.manager.ui.dialogs.AppDownloadDialog
import com.vanced.manager.ui.fragments.HomeFragment
import com.vanced.manager.utils.DownloadHelper.downloadProgress
import kotlinx.coroutines.*
import java.io.File
import java.io.IOException
import java.security.MessageDigest
import java.util.*
object AppUtils: CoroutineScope by CoroutineScope(Dispatchers.IO) {
object AppUtils : CoroutineScope by CoroutineScope(Dispatchers.IO) {
const val vancedPkg = "com.vanced.android.youtube"
const val vancedRootPkg = "com.google.android.youtube"
const val musicPkg = "com.vanced.android.apps.youtube.music"
const val musicRootPkg = "com.google.android.apps.youtube.music"
const val microgPkg = "com.mgoogle.android.gms"
const val faqpkg = "com.vanced.faq"
const val managerPkg = APPLICATION_ID
const val playStorePkg = "com.android.vending"
val logs = mutableListOf<Spannable>()
var currentLocale: Locale? = null
fun log(tag: String, message: String) {
logs.add(
SpannableString("$tag: $message\n").apply {
setSpan(ForegroundColorSpan(Color.parseColor("#2e73ff")), 0, tag.length + 1, 0)
setSpan(StyleSpan(Typeface.BOLD), 0, tag.length + 1, 0)
setSpan(
ForegroundColorSpan(Color.MAGENTA),
tag.length + 2,
tag.length + message.length + 2,
0
)
}
)
if (BuildConfig.DEBUG) {
Log.d(tag, message)
}
}
fun sendRefresh(context: Context): Job {
return launch {
delay(700)
LocalBroadcastManager.getInstance(context).sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
LocalBroadcastManager.getInstance(context)
.sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
}
}
fun sendCloseDialog(context: Context): Job {
return launch {
delay(700)
downloadProgress.value?.installing?.postValue(false)
LocalBroadcastManager.getInstance(context).sendBroadcast(Intent(AppDownloadDialog.CLOSE_DIALOG))
installing.postValue(false)
LocalBroadcastManager.getInstance(context)
.sendBroadcast(Intent(AppDownloadDialog.CLOSE_DIALOG))
}
}
fun sendFailure(status: Int, fullError: String?, context: Context): Job {
//Delay error broadcast until activity (and fragment) get back to the screen
return launch {
delay(700)
val intent = Intent(HomeFragment.INSTALL_FAILED)
intent.putExtra("errorMsg", getErrorMessage(status, context))
intent.putExtra("fullErrorMsg", fullError)
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
}
}
fun sendFailure(error: MutableList<String>, context: Context): Job {
return launch {
delay(700)
val intent = Intent(HomeFragment.INSTALL_FAILED)
intent.putExtra("errorMsg", getErrorMessage(error.joinToString(), context))
intent.putExtra("fullErrorMsg", error.joinToString(" "))
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
}
fun sendFailure(error: List<String>, context: Context) {
sendFailure(error.joinToString(" "), context)
}
fun sendFailure(error: String, context: Context): Job {
//Delay error broadcast until activity (and fragment) get back to the screen
return launch {
delay(700)
val intent = Intent(HomeFragment.INSTALL_FAILED)
@ -86,7 +102,7 @@ object AppUtils: CoroutineScope by CoroutineScope(Dispatchers.IO) {
private fun printableHexString(data: ByteArray): String {
// Create Hex String
val hexString: StringBuilder = StringBuilder()
for (aMessageDigest:Byte in data) {
for (aMessageDigest: Byte in data) {
var h: String = Integer.toHexString(0xFF and aMessageDigest.toInt())
while (h.length < 2)
h = "0$h"
@ -106,6 +122,7 @@ object AppUtils: CoroutineScope by CoroutineScope(Dispatchers.IO) {
}
private fun getErrorMessage(status: String, context: Context): String {
log("VMInstall", status)
return when {
status.contains("INSTALL_FAILED_ABORTED") -> context.getString(R.string.installation_aborted)
status.contains("INSTALL_FAILED_ALREADY_EXISTS") -> context.getString(R.string.installation_conflict)
@ -120,27 +137,10 @@ object AppUtils: CoroutineScope by CoroutineScope(Dispatchers.IO) {
status.contains("ModApk_Missing") -> context.getString(R.string.modapk_missing)
status.contains("Files_Missing_VA") -> context.getString(R.string.files_missing_va)
status.contains("Path_Missing") -> context.getString(R.string.path_missing)
else ->
if (isMiui())
context.getString(R.string.installation_miui)
else
context.getString(R.string.installation_failed)
}
}
private fun getErrorMessage(status: Int, context: Context): String {
return when (status) {
PackageInstaller.STATUS_FAILURE_ABORTED -> context.getString(R.string.installation_aborted)
PackageInstaller.STATUS_FAILURE_BLOCKED -> context.getString(R.string.installation_blocked)
PackageInstaller.STATUS_FAILURE_CONFLICT -> context.getString(R.string.installation_conflict)
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> context.getString(R.string.installation_incompatible)
PackageInstaller.STATUS_FAILURE_INVALID -> context.getString(R.string.installation_invalid)
PackageInstaller.STATUS_FAILURE_STORAGE -> context.getString(R.string.installation_storage)
else ->
if (isMiui())
context.getString(R.string.installation_miui)
else
context.getString(R.string.installation_failed)
status.contains("INSTALL_FAILED_INTERNAL_ERROR: Permission Denied") -> context.getString(
R.string.installation_miui
)
else -> context.getString(R.string.installation_failed)
}
}
}

View file

@ -1,9 +1,16 @@
package com.vanced.manager.utils
import android.app.PendingIntent
import android.os.Build
fun getArch(): String = when {
Build.SUPPORTED_ABIS.contains("x86") -> "x86"
Build.SUPPORTED_ABIS.contains("arm64-v8a") -> "arm64_v8a"
else -> "armeabi_v7a"
}
}
val intentFlags =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
PendingIntent.FLAG_MUTABLE
else
0

View file

@ -1,15 +1,14 @@
package com.vanced.manager.utils
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.core.content.FileProvider
import androidx.lifecycle.MutableLiveData
import com.vanced.manager.R
import com.vanced.manager.library.network.providers.createService
import com.vanced.manager.model.ProgressModel
import com.vanced.manager.utils.AppUtils.log
import com.vanced.manager.utils.AppUtils.sendCloseDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -39,40 +38,49 @@ object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
fileFolder: String,
fileName: String,
context: Context,
onDownloadComplete: () -> Unit,
onError: (error: String) -> Unit
onDownloadComplete: () -> Unit = {},
onError: (error: String) -> Unit = {}
) {
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.downloading_file, fileName))
downloadingFile.postValue(context.getString(R.string.downloading_file, fileName))
val downloadInterface = createService(DownloadHelper::class, baseUrl)
val download = downloadInterface.download(url)
downloadProgress.value?.currentDownload = download
currentDownload = download
download.enqueue(object : Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.isSuccessful) {
CoroutineScope(Dispatchers.IO).launch {
if (response.body()?.let { writeFile(it, context.getExternalFilesDir(fileFolder)?.path + "/" + fileName) } == true) {
launch {
if (response.body()?.let {
writeFile(
it,
context.getExternalFilesDir(fileFolder)?.path + "/" + fileName
)
} == true) {
onDownloadComplete()
} else {
onError("Could not save file")
downloadProgress.value?.downloadProgress?.postValue(0)
Log.d("VMDownloader", "Failed to save file: $url")
downloadProgress.postValue(0)
log(
"VMDownloader",
"Failed to save file: $url\n${response.errorBody()}"
)
}
}
} else {
onError(response.errorBody().toString())
downloadProgress.value?.downloadProgress?.postValue(0)
Log.d("VMDownloader", "Failed to download file: $url")
val errorBody = response.errorBody().toString()
onError(errorBody)
downloadProgress.postValue(0)
log("VMDownloader", "Failed to download file: $url\n$errorBody")
}
}
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
if (call.isCanceled) {
Log.d("VMDownloader", "Download canceled")
downloadProgress.value?.downloadProgress?.postValue(0)
log("VMDownloader", "Download canceled")
downloadProgress.postValue(0)
} else {
onError(t.stackTraceToString())
downloadProgress.value?.downloadProgress?.postValue(0)
Log.d("VMDownloader", "Failed to download file: $url")
downloadProgress.postValue(0)
log("VMDownloader", "Failed to download file: $url")
}
}
@ -94,7 +102,7 @@ object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
while (inputStream.read(fileReader).also { read = it } != -1) {
outputStream.write(fileReader, 0, read)
downloadedBytes += read.toLong()
downloadProgress.value?.downloadProgress?.postValue((downloadedBytes * 100 / totalBytes).toInt())
downloadProgress.postValue((downloadedBytes * 100 / totalBytes).toInt())
}
outputStream.flush()
true
@ -109,36 +117,42 @@ object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
}
}
val downloadProgress = MutableLiveData<ProgressModel>()
init {
downloadProgress.value = ProgressModel()
}
fun downloadManager(context: Context) {
val url = "https://github.com/YTVanced/VancedManager/releases/latest/download/manager.apk"
download(url,"https://github.com/YTVanced/VancedManager/", "manager", "manager.apk", context, onDownloadComplete = {
val apk = File("${context.getExternalFilesDir("manager")?.path}/manager.apk")
val uri =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
FileProvider.getUriForFile(context, "${context.packageName}.provider", apk)
else
Uri.fromFile(apk)
download(
url,
"https://github.com/YTVanced/VancedManager/",
"manager",
"manager.apk",
context,
onDownloadComplete = {
val apk = File("${context.getExternalFilesDir("manager")?.path}/manager.apk")
val uri =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
FileProvider.getUriForFile(context, "${context.packageName}.provider", apk)
else
Uri.fromFile(apk)
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, "application/vnd.android.package-archive")
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(intent)
sendCloseDialog(context)
}, onError = {
downloadProgress.value?.downloadingFile?.postValue(
context.getString(
R.string.error_downloading,
"manager.apk"
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, "application/vnd.android.package-archive")
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
log("VMDownloader", e.stackTraceToString())
} finally {
sendCloseDialog(context)
}
},
onError = {
downloadingFile.postValue(
context.getString(
R.string.error_downloading,
"manager.apk"
)
)
)
})
})
}
}

View file

@ -3,11 +3,11 @@ package com.vanced.manager.utils
import android.content.Context
import android.content.ContextWrapper
import android.content.DialogInterface
import android.util.Log
import android.widget.RadioGroup
import androidx.core.graphics.ColorUtils
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.LinearProgressIndicator
@ -15,55 +15,61 @@ import com.google.android.material.radiobutton.MaterialRadioButton
import com.topjohnwu.superuser.io.SuFile
import com.topjohnwu.superuser.io.SuFileOutputStream
import com.vanced.manager.R
import com.vanced.manager.utils.AppUtils.log
import java.util.*
fun RadioGroup.getCheckedButtonTag(): String? {
return findViewById<MaterialRadioButton>(checkedRadioButtonId)?.tag?.toString()
val RadioGroup.checkedButtonTag: String?
get() = findViewById<MaterialRadioButton>(
checkedRadioButtonId
)?.tag?.toString()
fun DialogFragment.show(fragmentManager: FragmentManager) {
try {
show(fragmentManager, "")
} catch (e: Exception) {
log("VMUI", e.stackTraceToString())
}
}
fun DialogFragment.show(activity: FragmentActivity) {
try {
show(activity.supportFragmentManager, "")
} catch (e: Exception) {
Log.d("VMUI", e.stackTraceToString())
}
show(activity.supportFragmentManager)
}
fun List<String>.convertToAppVersions(): List<String> = listOf("latest") + reversed()
fun String.convertToAppTheme(context: Context): String {
return context.getString(R.string.light_plus_other, this.capitalize(Locale.ROOT))
fun String.formatVersion(context: Context): String =
if (this == "latest") context.getString(R.string.install_latest) else this
fun String.convertToAppTheme(context: Context): String = with(context) {
getString(
R.string.light_plus_other,
if (this@convertToAppTheme == "dark") getString(R.string.vanced_dark) else getString(R.string.vanced_black)
)
}
fun String.getLatestAppVersion(versions: List<String>): String = if (this == "latest") versions.reversed()[0] else this
fun String.getLatestAppVersion(versions: List<String>): String =
if (this == "latest") versions.reversed()[0] else this
fun Context.lifecycleOwner(): LifecycleOwner? {
var curContext = this
var maxDepth = 20
while (maxDepth-- > 0 && curContext !is LifecycleOwner) {
curContext = (curContext as ContextWrapper).baseContext
val Context.lifecycleOwner: LifecycleOwner?
get() = when (this) {
is LifecycleOwner -> this
!is LifecycleOwner -> (this as ContextWrapper).baseContext as LifecycleOwner
else -> null
}
return if (curContext is LifecycleOwner) {
curContext
} else {
null
}
}
fun Int.toHex(): String = java.lang.String.format("#%06X", 0xFFFFFF and this)
//Material team decided to keep their LinearProgressIndicator final
//At least extension methods exist
fun LinearProgressIndicator.applyAccent() {
with(accentColor.value ?: context.defPrefs.managerAccent) {
with(accentColor.value!!) {
setIndicatorColor(this)
trackColor = ColorUtils.setAlphaComponent(this, 70)
}
}
fun MaterialAlertDialogBuilder.applyAccent() {
with(accentColor.value ?: context.defPrefs.managerAccent) {
fun MaterialAlertDialogBuilder.showWithAccent() {
with(accentColor.value!!) {
show().apply {
getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(this@with)
getButton(DialogInterface.BUTTON_NEGATIVE).setTextColor(this@with)
@ -75,6 +81,12 @@ fun MaterialAlertDialogBuilder.applyAccent() {
fun Context.writeServiceDScript(apkFPath: String, path: String, app: String) {
val shellFileZ = SuFile.open("/data/adb/service.d/$app.sh")
shellFileZ.createNewFile()
val code = """#!/system/bin/sh${"\n"}while [ "`getprop sys.boot_completed | tr -d '\r' `" != "1" ]; do sleep ${defPrefs.serviceDSleepTimer}; done${"\n"}chcon u:object_r:apk_data_file:s0 $apkFPath${"\n"}mount -o bind $apkFPath $path"""
SuFileOutputStream(shellFileZ).use { out -> out.write(code.toByteArray())}
val script = """
#!/system/bin/sh
while [ "$(getprop sys.boot_completed | tr -d '\r')" != "1" ]; do sleep 1; done
sleep ${defPrefs.serviceDSleepTimer}
chcon u:object_r:apk_data_file:s0 $apkFPath
mount -o bind $apkFPath $path
""".trimIndent()
SuFileOutputStream.open(shellFileZ).use { out -> out.write(script.toByteArray()) }
}

View file

@ -1,14 +0,0 @@
package com.vanced.manager.utils
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
open class FileInfo(val name: String, val fileSize: Long, val file: File? = null) {
open fun getInputStream(): InputStream =
if (file!= null)
FileInputStream(file)
else
throw NotImplementedError("need some way to create InputStream")
}

View file

@ -4,7 +4,11 @@ import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
val Context.installPrefs: SharedPreferences get() = getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
val Context.installPrefs: SharedPreferences
get() = getSharedPreferences(
"installPrefs",
Context.MODE_PRIVATE
)
var SharedPreferences.lang
get() = getString("lang", getDefaultVancedLanguages())

View file

@ -15,6 +15,7 @@ import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject
import com.vanced.manager.R
import com.vanced.manager.utils.AppUtils.generateChecksum
import com.vanced.manager.utils.AppUtils.log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
@ -31,8 +32,8 @@ val music = MutableLiveData<JsonObject?>()
val microg = MutableLiveData<JsonObject?>()
val manager = MutableLiveData<JsonObject?>()
val vancedVersions = MutableLiveData<JsonArray<String>>()
val musicVersions = MutableLiveData<JsonArray<String>>()
val vancedVersions = MutableLiveData<JsonArray<String>?>()
val musicVersions = MutableLiveData<JsonArray<String>?>()
val isFetching = MutableLiveData<Boolean>()
@ -42,19 +43,28 @@ var baseInstallUrl = ""
fun openUrl(url: String, color: Int, context: Context) {
try {
val customTabPrefs = getDefaultSharedPreferences(context).getBoolean("use_custom_tabs", true)
val customTabPrefs =
getDefaultSharedPreferences(context).getBoolean("use_custom_tabs", true)
if (customTabPrefs) {
val builder = CustomTabsIntent.Builder()
val params = CustomTabColorSchemeParams.Builder().setToolbarColor(ContextCompat.getColor(context, color))
val params = CustomTabColorSchemeParams.Builder()
.setToolbarColor(ContextCompat.getColor(context, color))
builder.setDefaultColorSchemeParams(params.build())
val customTabsIntent = builder.build()
customTabsIntent.intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
customTabsIntent.launchUrl(context, url.toUri())
} else
context.startActivity(Intent(Intent.ACTION_VIEW, url.toUri()).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
context.startActivity(
Intent(
Intent.ACTION_VIEW,
url.toUri()
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
} catch (e: ActivityNotFoundException) {
Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show()
} catch (e: SecurityException) {
Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show()
}
}
@ -78,17 +88,17 @@ suspend fun loadJson(context: Context) = withContext(Dispatchers.IO) {
connect()
}
if (connection.responseCode != 200) {
Log.d(TAG, latestbaseUrl + ": " + connection.responseCode.toString())
log(TAG, latestbaseUrl + ": " + connection.responseCode.toString())
baseInstallUrl = "https://mirror.codebucket.de/vanced/api/v1"
}
} catch (e: IOException) {
baseInstallUrl = "https://mirror.codebucket.de/vanced/api/v1"
} catch (e: SocketTimeoutException) {
Log.d(TAG, "connection timed out")
log(TAG, "connection timed out")
baseInstallUrl = "https://mirror.codebucket.de/vanced/api/v1"
}
Log.d(TAG, "Fetching using URL: $baseInstallUrl")
log(TAG, "Fetching using URL: $baseInstallUrl")
val calendar = Calendar.getInstance()
val hour = calendar.get(Calendar.HOUR_OF_DAY)
@ -100,7 +110,7 @@ suspend fun loadJson(context: Context) = withContext(Dispatchers.IO) {
val versions = getJson("$baseInstallUrl/versions.json?$fetchTime")
isMicrogBroken = latest?.boolean("is_microg_broken") ?: false
vanced.postValue(latest?.obj("vanced"))
vancedVersions.postValue(versions?.array("vanced") )
vancedVersions.postValue(versions?.array("vanced"))
music.postValue(latest?.obj("music"))
musicVersions.postValue(versions?.array("music"))
microg.postValue(latest?.obj("microg"))
@ -134,4 +144,4 @@ fun checkSHA256(sha256: String, updateFile: File): Boolean {
}
}
const val baseUrl = "https://vancedapp.com/api/v1"
const val baseUrl = "https://api.vancedapp.com/api/v1"

View file

@ -4,8 +4,7 @@ import android.content.Context
import android.content.ContextWrapper
import android.content.res.Configuration
import android.content.res.Resources
import androidx.preference.PreferenceManager
import com.crowdin.platform.Crowdin
import com.vanced.manager.utils.AppUtils.currentLocale
import java.util.*
class LanguageContextWrapper(base: Context?) : ContextWrapper(base) {
@ -15,20 +14,22 @@ class LanguageContextWrapper(base: Context?) : ContextWrapper(base) {
fun wrap(context: Context): ContextWrapper {
val config: Configuration = context.resources.configuration
context.createConfigurationContext(setLocale(config, context))
Crowdin.wrapContext(context)
return LanguageContextWrapper(context)
}
@Suppress("DEPRECATION")
private fun setLocale(config: Configuration, context: Context): Configuration {
val pref = PreferenceManager.getDefaultSharedPreferences(context).getString("manager_lang", "System Default")
val pref = context.defPrefs.managerLang
val sysLocale = Resources.getSystem().configuration.locale
val locale =
when {
pref == "System Default" -> Locale(sysLocale.language, sysLocale.country)
pref?.length!! > 2 -> Locale(pref.substring(0, pref.length - 3), pref.substring(pref.length - 2))
else -> Locale(pref)
}
val locale = when {
pref == "System Default" -> Locale(sysLocale.language, sysLocale.country)
pref?.length!! > 2 -> Locale(
pref.substring(0, pref.length - 3),
pref.substring(pref.length - 2)
)
else -> Locale(pref)
}
currentLocale = locale
Locale.setDefault(locale)
config.setLocale(locale)
return config

View file

@ -1,15 +1,10 @@
package com.vanced.manager.utils
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.net.Uri
import android.os.Build
import android.os.LocaleList
import android.provider.Settings
import androidx.annotation.RequiresApi
import com.crowdin.platform.Crowdin
import com.vanced.manager.R
import java.util.*
@ -34,7 +29,10 @@ fun getLanguageFormat(context: Context, language: String): String {
@Suppress("DEPRECATION")
fun getDefaultVancedLanguages(): String {
val serverLangs = vanced.value?.array("langs") ?: mutableListOf("")
val sysLocales = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) Resources.getSystem().configuration.locales.toLangTags() else arrayOf(Resources.getSystem().configuration.locale.language)
val sysLocales =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) Resources.getSystem().configuration.locales.toLangTags() else arrayOf(
Resources.getSystem().configuration.locale.language
)
val finalLangs = mutableListOf<String>()
sysLocales.forEach { sysLocale ->
when {
@ -53,26 +51,4 @@ fun LocaleList.toLangTags(): Array<String> {
langTags[i] = langTags[i].substring(0, 2)
}
return langTags
}
fun Activity.authCrowdin() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:$packageName")
)
startActivityForResult(intent, 69)
return
}
Crowdin.authorize(this)
}
}
fun Activity.onActivityResult(requestCode: Int) {
if (requestCode == 69 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.canDrawOverlays(this)) {
Crowdin.authorize(this)
}
}
}

View file

@ -1,22 +1,12 @@
package com.vanced.manager.utils
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import android.content.Context
import android.provider.Settings
private const val MIUI_PROP_NAME = "ro.miui.ui.version.name"
private const val MIUI_OPTIMIZATION = "miui_optimization"
fun isMiui(): Boolean = !getSystemProps(MIUI_PROP_NAME).isNullOrEmpty()
private fun getSystemProps(propname: String): String? {
var input: BufferedReader? = null
return try {
val process = Runtime.getRuntime().exec("getprop $propname")
input = BufferedReader(InputStreamReader(process.inputStream), 1024)
input.readLine()
} catch (e: IOException) {
null
} finally {
input?.close()
}
}
val Context.isMiuiOptimizationsEnabled: Boolean
get() = Settings.Secure.getString(
contentResolver,
MIUI_OPTIMIZATION
) == "1"

View file

@ -7,12 +7,11 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile
import com.vanced.manager.BuildConfig
import com.vanced.manager.core.installer.AppInstallerService
import com.vanced.manager.core.installer.AppUninstallerService
import com.vanced.manager.utils.AppUtils.log
import com.vanced.manager.utils.AppUtils.musicRootPkg
import com.vanced.manager.utils.AppUtils.playStorePkg
import com.vanced.manager.utils.AppUtils.sendCloseDialog
@ -22,27 +21,18 @@ import com.vanced.manager.utils.AppUtils.vancedRootPkg
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.*
import java.text.SimpleDateFormat
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.util.*
import java.util.regex.Pattern
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
object PackageHelper {
const val apkInstallPath = "/data/adb"
private const val INSTALLER_TAG = "VMInstall"
private val vancedThemes = vanced.value?.array<String>("themes")?.value ?: listOf("black", "dark", "pink", "blue")
init {
Shell.enableVerboseLogging = BuildConfig.DEBUG
Shell.setDefaultBuilder(
Shell.Builder.create()
.setFlags(Shell.FLAG_REDIRECT_STDERR)
.setTimeout(10)
)
}
private val vancedThemes =
vanced.value?.array<String>("themes")?.value ?: listOf("black", "dark", "pink", "blue")
private fun getAppNameRoot(pkg: String): String {
return when (pkg) {
@ -61,7 +51,6 @@ object PackageHelper {
return false
}
fun getPkgNameRoot(app: String): String {
return when (app) {
"vanced" -> vancedRootPkg
@ -69,6 +58,7 @@ object PackageHelper {
else -> ""
}
}
fun isPackageInstalled(packageName: String, packageManager: PackageManager): Boolean {
return try {
packageManager.getPackageInfo(packageName, 0)
@ -86,7 +76,7 @@ object PackageHelper {
}
@Suppress("DEPRECATION")
fun getPkgVerCode(pkg: String, pm:PackageManager): Int? {
fun getPkgVerCode(pkg: String, pm: PackageManager): Int? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
pm.getPackageInfo(pkg, 0)?.longVersionCode?.and(0xFFFFFFFF)?.toInt()
else
@ -127,9 +117,15 @@ object PackageHelper {
if (files?.isNotEmpty() == true) {
for (file in files) {
when {
vancedThemes.any { file.name == "$it.apk" } && !splitFiles.contains("base") -> splitFiles.add("base")
file.name.matches(Regex("split_config\\.(..)\\.apk")) && !splitFiles.contains("lang") -> splitFiles.add("lang")
(file.name.startsWith("split_config.arm") || file.name.startsWith("split_config.x86")) && !splitFiles.contains("arch") -> splitFiles.add("arch")
vancedThemes.any { file.name == "$it.apk" } && !splitFiles.contains("base") -> splitFiles.add(
"base"
)
file.name.matches(Regex("split_config\\.(..)\\.apk")) && !splitFiles.contains(
"lang"
) -> splitFiles.add("lang")
(file.name.startsWith("split_config.arm") || file.name.startsWith("split_config.x86")) && !splitFiles.contains(
"arch"
) -> splitFiles.add("arch")
}
if (splitFiles.size == 3) {
@ -153,7 +149,7 @@ object PackageHelper {
fun uninstallApk(pkg: String, context: Context) {
val callbackIntent = Intent(context, AppUninstallerService::class.java)
callbackIntent.putExtra("pkg", pkg)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, 0)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, intentFlags)
try {
context.packageManager.packageInstaller.uninstall(pkg, pendingIntent.intentSender)
} catch (e: Exception) {
@ -162,73 +158,94 @@ object PackageHelper {
}
fun install(path: String, context: Context) {
val callbackIntent = Intent(context, AppInstallerService::class.java)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, intentFlags)
val packageInstaller = context.packageManager.packageInstaller
val params =
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
params.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED)
}
val sessionId: Int
var session: PackageInstaller.Session? = null
try {
val callbackIntent = Intent(context, AppInstallerService::class.java)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, 0)
val packageInstaller = context.packageManager.packageInstaller
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)
sessionId = packageInstaller.createSession(params)
session = packageInstaller.openSession(sessionId)
val inputStream: InputStream = FileInputStream(path)
val outputStream = session.openWrite("install", 0, -1)
val buffer = ByteArray(65536)
var c: Int
while (inputStream.read(buffer).also { c = it } != -1) {
outputStream.write(buffer, 0, c)
var length: Int
while (inputStream.read(buffer).also { length = it } > 0) {
outputStream.write(buffer, 0, length)
}
session.fsync(outputStream)
inputStream.close()
outputStream.close()
session.commit(pendingIntent.intentSender)
} catch (e: IOException) {
Log.d(INSTALLER_TAG, e.stackTraceToString())
} catch (e: Exception) {
log(INSTALLER_TAG, e.stackTraceToString())
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
} finally {
session?.close()
}
}
private fun installRootMusic(files: ArrayList<FileInfo>, context: Context): Boolean {
private fun installRootMusic(files: List<File>, context: Context): Boolean {
files.forEach { apk ->
if (apk.name != "root.apk") {
val newPath = "/data/local/tmp/${apk.file?.name}"
val newPath = "/data/local/tmp/${apk.name}"
//moving apk to tmp folder in order to avoid permission denials
Shell.su("mv ${apk.file?.path} $newPath").exec()
val command = Shell.su("pm install $newPath").exec()
//Copy apk to tmp folder in order to avoid permission denials
Shell.su("cp ${apk.path} $newPath").exec()
val command = Shell.su("pm install -r $newPath").exec()
Shell.su("rm $newPath").exec()
if (command.isSuccess) {
return true
} else {
if (!command.isSuccess) {
sendFailure(command.out, context)
sendCloseDialog(context)
return false
}
}
}
return false
return true
}
private fun installRootApp(context: Context, app: String, appVerCode: Int, pkg: String, modApkBool: (fileName: String) -> Boolean) = CoroutineScope(Dispatchers.IO).launch {
Shell.getShell {
val apkFilesPath = context.getExternalFilesDir("$app/root")?.path
val fileInfoList = apkFilesPath?.let { it1 -> getFileInfoList(it1) }
if (fileInfoList != null) {
val modApk: FileInfo? = fileInfoList.lastOrNull { modApkBool(it.name) }
if (modApk != null) {
if (overwriteBase(modApk, fileInfoList, appVerCode, pkg, app, context)) {
private fun installRootApp(
context: Context,
app: String,
appVerCode: Int?,
pkg: String,
modApkBool: (fileName: String) -> Boolean
) = CoroutineScope(Dispatchers.IO).launch {
if (!isMagiskInstalled()) {
sendFailure("NO_MAGISK", context)
sendCloseDialog(context)
return@launch
}
val apkFilesPath = context.getExternalFilesDir("$app/root")?.path
val files = File(apkFilesPath.toString()).listFiles()?.toList()
if (files != null) {
val modApk: File? = files.lastOrNull { modApkBool(it.name) }
if (modApk != null) {
if (appVerCode != null) {
if (overwriteBase(modApk, files, appVerCode, pkg, app, context)) {
setInstallerPackage(context, pkg, playStorePkg)
Log.d(INSTALLER_TAG, "Finished installation")
log(INSTALLER_TAG, "Finished installation")
sendRefresh(context)
sendCloseDialog(context)
}
} else {
sendFailure(listOf("ModApk_Missing").toMutableList(), context)
sendFailure("appVerCode is null", context)
sendCloseDialog(context)
}
} else {
sendFailure(listOf("Files_Missing_VA").toMutableList(), context)
sendFailure("ModApk_Missing", context)
sendCloseDialog(context)
}
} else {
sendFailure("Files_Missing_VA", context)
sendCloseDialog(context)
}
}
@ -237,7 +254,7 @@ object PackageHelper {
installRootApp(
context,
"music",
music.value?.int("versionCode")!!,
music.value?.int("versionCode"),
musicRootPkg
) {
it == "root.apk"
@ -248,202 +265,95 @@ object PackageHelper {
installRootApp(
context,
"vanced",
vanced.value?.int("versionCode")!!,
vanced.value?.int("versionCode"),
vancedRootPkg
) { fileName ->
vancedThemes.any { fileName == "$it.apk" }
}
}
fun installVanced(context: Context): Int {
val apkFolderPath = context.getExternalFilesDir("vanced/nonroot")?.path.toString() + "/"
val nameSizeMap = HashMap<String, Long>()
var totalSize: Long = 0
var sessionId = 0
val folder = File(apkFolderPath)
val listOfFiles = folder.listFiles()
fun installSplitApkFiles(
context: Context,
appName: String
) {
val packageInstaller = context.packageManager.packageInstaller
val folder = File(context.getExternalFilesDir("$appName/nonroot")?.path.toString())
var session: PackageInstaller.Session? = null
val sessionId: Int
val sessionParams =
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
sessionParams.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED)
}
val callbackIntent = Intent(context, AppInstallerService::class.java)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, intentFlags)
try {
for (listOfFile in listOfFiles!!) {
if (listOfFile.isFile) {
Log.d(INSTALLER_TAG, "installApk: " + listOfFile.name)
nameSizeMap[listOfFile.name] = listOfFile.length()
totalSize += listOfFile.length()
sessionId = packageInstaller.createSession(sessionParams)
session = packageInstaller.openSession(sessionId)
folder.listFiles()?.forEach { apk ->
val inputStream = FileInputStream(apk)
val outputStream = session.openWrite(apk.name, 0, apk.length())
val buffer = ByteArray(65536)
var length: Int
while (inputStream.read(buffer).also { length = it } > 0) {
outputStream.write(buffer, 0, length)
}
session.fsync(outputStream)
inputStream.close()
outputStream.close()
}
} catch (e: Exception) {
e.printStackTrace()
return -1
}
val installParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
installParams.setSize(totalSize)
try {
sessionId = context.packageManager.packageInstaller.createSession(installParams)
Log.d(INSTALLER_TAG,"Success: created install session [$sessionId]")
for ((key, value) in nameSizeMap) {
doWriteSession(sessionId, apkFolderPath + key, value, key, context)
}
doCommitSession(sessionId, context)
Log.d(INSTALLER_TAG,"Success")
} catch (e: Exception) {
e.printStackTrace()
}
return sessionId
}
private fun doWriteSession(sessionId: Int, inPath: String?, sizeBytes: Long, splitName: String, context: Context): Int {
var inPathToUse = inPath
var sizeBytesToUse = sizeBytes
if ("-" == inPathToUse) {
inPathToUse = null
} else if (inPathToUse != null) {
val file = File(inPathToUse)
if (file.isFile)
sizeBytesToUse = file.length()
}
var session: PackageInstaller.Session? = null
var inputStream: InputStream? = null
var out: OutputStream? = null
try {
session = context.packageManager.packageInstaller.openSession(sessionId)
if (inPathToUse != null) {
inputStream = FileInputStream(inPathToUse)
}
out = session.openWrite(splitName, 0, sizeBytesToUse)
var total = 0
val buffer = ByteArray(65536)
var c: Int
while (true) {
c = inputStream!!.read(buffer)
if (c == -1)
break
total += c
out.write(buffer, 0, c)
}
session.fsync(out)
Log.d(INSTALLER_TAG, "Success: streamed $total bytes")
return PackageInstaller.STATUS_SUCCESS
} catch (e: IOException) {
Log.e(INSTALLER_TAG, "Error: failed to write; " + e.message)
return PackageInstaller.STATUS_FAILURE
} finally {
try {
out?.close()
inputStream?.close()
session?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
private fun doCommitSession(sessionId: Int, context: Context) {
var session: PackageInstaller.Session? = null
try {
session = context.packageManager.packageInstaller.openSession(sessionId)
val callbackIntent = Intent(context, AppInstallerService::class.java)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, 0)
session.commit(pendingIntent.intentSender)
session.close()
Log.d(INSTALLER_TAG, "install request sent")
Log.d(INSTALLER_TAG, "doCommitSession: " + context.packageManager.packageInstaller.mySessions)
Log.d(INSTALLER_TAG, "doCommitSession: after session commit ")
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
log(INSTALLER_TAG, e.stackTraceToString())
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
} finally {
session?.close()
}
}
private fun installSplitApkFiles(apkFiles: ArrayList<FileInfo>, context: Context) : Boolean {
var sessionId: Int?
private fun installSplitApkFilesRoot(apkFiles: List<File>?, context: Context): Boolean {
val filenames = arrayOf("black.apk", "dark.apk", "blue.apk", "pink.apk", "hash.json")
Log.d(INSTALLER_TAG, "installing split apk files: $apkFiles")
run {
val sessionIdResult = Shell.su("pm install-create -r -t").exec().out
val sessionIdPattern = Pattern.compile("(\\d+)")
val sessionIdMatcher = sessionIdPattern.matcher(sessionIdResult[0])
sessionIdMatcher.find()
sessionId = Integer.parseInt(sessionIdMatcher.group(1)!!)
}
apkFiles.forEach { apkFile ->
if (!filenames.any { apkFile.name == it }) {
Log.d(INSTALLER_TAG, "installing APK: ${apkFile.name} ${apkFile.fileSize}")
val command = arrayOf("su", "-c", "pm", "install-write", "-S", "${apkFile.fileSize}", "$sessionId", apkFile.name)
val process: Process = Runtime.getRuntime().exec(command)
val inputPipe = apkFile.getInputStream()
try {
process.outputStream.use { outputStream -> inputPipe.copyTo(outputStream) }
} catch (e: Exception) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
process.destroyForcibly()
else
process.destroy()
log(INSTALLER_TAG, "installing split apk files: ${apkFiles?.map { it.name }}")
val sessionId =
Shell.su("pm install-create -r").exec().out.joinToString(" ").filter { it.isDigit() }
.toIntOrNull()
sendFailure(e.stackTrace.map { it.toString() }.toMutableList(), context)
sendCloseDialog(context)
}
process.waitFor()
if (sessionId == null) {
sendFailure("Session ID is null", context)
sendCloseDialog(context)
return false
}
apkFiles?.filter { !filenames.contains(it.name) }?.forEach { apkFile ->
val apkName = apkFile.name
log(INSTALLER_TAG, "installing APK: $apkName")
val newPath = "/data/local/tmp/$apkName"
//Copy apk to tmp folder in order to avoid permission denials
Shell.su("cp ${apkFile.path} $newPath").exec()
val command = Shell.su("pm install-write $sessionId $apkName $newPath").exec()
Shell.su("rm $newPath").exec()
if (!command.isSuccess) {
sendFailure(command.out, context)
sendCloseDialog(context)
return false
}
}
Log.d(INSTALLER_TAG, "committing...")
log(INSTALLER_TAG, "committing...")
val installResult = Shell.su("pm install-commit $sessionId").exec()
if (installResult.isSuccess) {
return true
if (!installResult.isSuccess) {
sendFailure(installResult.out, context)
sendCloseDialog(context)
return false
}
sendFailure(installResult.out, context)
sendCloseDialog(context)
return false
return true
}
private fun SimpleDateFormat.tryParse(str: String) = try {
parse(str) != null
} catch (e: Exception) {
false
}
private fun getFileInfoList(splitApkPath: String): ArrayList<FileInfo> {
val parentFile = File(splitApkPath)
val result = ArrayList<FileInfo>()
if (parentFile.exists() && parentFile.canRead()) {
val listFiles = parentFile.listFiles() ?: return ArrayList()
listFiles.mapTo(result) {
FileInfo(it.name, it.length(), it)
}
return result
}
val longLines = Shell.su("ls -l $splitApkPath").exec().out
val pattern = Pattern.compile(" +")
val formatter = SimpleDateFormat("HH:mm", Locale.getDefault())
longLinesLoop@ for (line in longLines) {
val matcher = pattern.matcher(line)
for (i in 0 until 4)
if (!matcher.find())
continue@longLinesLoop
val startSizeStr = matcher.end()
matcher.find()
val endSizeStr = matcher.start()
val fileSizeStr = line.substring(startSizeStr, endSizeStr)
while (true) {
val testTimeStr: String =
line.substring(matcher.end(), line.indexOf(' ', matcher.end()))
if (formatter.tryParse(testTimeStr)) {
//found time, so apk is next
val fileName = line.substring(line.indexOf(' ', matcher.end()) + 1)
if (fileName.endsWith("apk"))
result.add(FileInfo(fileName, fileSizeStr.toLong(), File(splitApkPath, fileName)))
break
}
matcher.find()
}
}
return result
}
//overwrite stock Vanced/Music
private fun overwriteBase(
apkFile: FileInfo,
baseApkFiles: ArrayList<FileInfo>,
apkFile: File,
baseApkFiles: List<File>,
versionCode: Int,
pkg: String,
app: String,
@ -451,17 +361,15 @@ object PackageHelper {
): Boolean {
if (checkVersion(versionCode, baseApkFiles, pkg, context)) {
val path = getPackageDir(context, pkg)
apkFile.file?.let {
val apath = it.absolutePath
val apath = apkFile.absolutePath
setupFolder("$apkInstallPath/${app.capitalize(Locale.ROOT)}")
if (path != null) {
val apkFPath = "$apkInstallPath/${app.capitalize(Locale.ROOT)}/base.apk"
if (moveAPK(apath, apkFPath, pkg, context)) {
if (chConV(apkFPath, context)) {
if (setupScript(apkFPath, path, app, pkg, context)) {
return linkApp(apkFPath, pkg, path)
}
setupFolder("$apkInstallPath/${app.capitalize(Locale.ROOT)}")
if (path != null) {
val apkFPath = "$apkInstallPath/${app.capitalize(Locale.ROOT)}/base.apk"
if (moveAPK(apath, apkFPath, pkg, context)) {
if (chConV(apkFPath, context)) {
if (setupScript(apkFPath, path, app, pkg, context)) {
return linkApp(apkFPath, pkg, path)
}
}
}
@ -470,23 +378,32 @@ object PackageHelper {
return false
}
private fun setupScript(apkFPath: String, path: String, app: String, pkg: String, context: Context): Boolean
{
private fun setupScript(
apkFPath: String,
path: String,
app: String,
pkg: String,
context: Context
): Boolean {
try {
Log.d(INSTALLER_TAG, "Setting up script")
log(INSTALLER_TAG, "Setting up script")
context.writeServiceDScript(apkFPath, path, app)
Shell.su("""echo "#!/system/bin/sh\nwhile read line; do echo \${"$"}{line} | grep $pkg | awk '{print \${'$'}2}' | xargs umount -l; done< /proc/mounts" > /data/adb/post-fs-data.d/$app.sh""").exec()
Shell.su("""echo "#!/system/bin/sh\nwhile read line; do echo \${"$"}{line} | grep $pkg | awk '{print \${'$'}2}' | xargs umount -l; done< /proc/mounts" > /data/adb/post-fs-data.d/$app.sh""")
.exec()
return Shell.su("chmod 744 /data/adb/service.d/$app.sh").exec().isSuccess
} catch (e: IOException) {
e.printStackTrace()
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
log(INSTALLER_TAG, e.stackTraceToString())
}
return false
}
private fun linkApp(apkFPath: String, pkg: String, path: String): Boolean {
Log.d(INSTALLER_TAG, "Linking app")
log(INSTALLER_TAG, "Linking app")
Shell.su("am force-stop $pkg").exec()
Shell.su("""for i in ${'$'}(ls /data/app/ | grep $pkg | tr " "); do umount -l "/data/app/${"$"}i/base.apk"; done """).exec()
Shell.su("""for i in ${'$'}(ls /data/app/ | grep $pkg | tr " "); do umount -l "/data/app/${"$"}i/base.apk"; done """)
.exec()
val response = Shell.su("""su -mm -c "mount -o bind $apkFPath $path"""").exec()
Thread.sleep(500)
Shell.su("am force-stop $pkg").exec()
@ -498,12 +415,17 @@ object PackageHelper {
}
//check version and perform action based on result
private fun checkVersion(versionCode: Int, baseApkFiles: ArrayList<FileInfo>, pkg: String, context: Context): Boolean {
Log.d(INSTALLER_TAG, "Checking stock version")
private fun checkVersion(
versionCode: Int,
baseApkFiles: List<File>,
pkg: String,
context: Context
): Boolean {
log(INSTALLER_TAG, "Checking stock version")
val path = getPackageDir(context, pkg)
if (path != null) {
if (path.contains("/data/app/")) {
when (getVersionNumber(pkg, context)?.let { compareVersion(it,versionCode) } ) {
when (getVersionNumber(pkg, context)?.let { compareVersion(it, versionCode) }) {
1 -> return fixHigherVer(baseApkFiles, pkg, context)
-1 -> return installStock(baseApkFiles, pkg, context)
}
@ -517,8 +439,8 @@ object PackageHelper {
private fun getPkgInfo(pkg: String, context: Context): PackageInfo? {
return try {
context.packageManager.getPackageInfo(pkg, 0)
} catch (e:Exception) {
Log.d(INSTALLER_TAG, "Unable to get package info")
} catch (e: Exception) {
log(INSTALLER_TAG, "Unable to get package info")
null
}
}
@ -532,10 +454,13 @@ object PackageHelper {
}
//uninstall current update and install base that works with patch
private fun fixHigherVer(apkFiles: ArrayList<FileInfo>, pkg: String, context: Context) : Boolean {
Log.d(INSTALLER_TAG, "Downgrading stock")
private fun fixHigherVer(apkFiles: List<File>, pkg: String, context: Context): Boolean {
log(INSTALLER_TAG, "Downgrading stock")
if (uninstallRootApk(pkg)) {
return if (pkg == vancedRootPkg) installSplitApkFiles(apkFiles, context) else installRootMusic(apkFiles, context)
return if (pkg == vancedRootPkg) installSplitApkFilesRoot(
apkFiles,
context
) else installRootMusic(apkFiles, context)
}
sendFailure(listOf("Failed_Uninstall").toMutableList(), context)
sendCloseDialog(context)
@ -543,78 +468,70 @@ object PackageHelper {
}
//install stock youtube matching vanced version
private fun installStock(baseApkFiles: ArrayList<FileInfo>, pkg: String, context: Context): Boolean {
Log.d(INSTALLER_TAG, "Installing stock")
return if (pkg == vancedRootPkg) installSplitApkFiles(baseApkFiles, context) else installRootMusic(baseApkFiles, context)
private fun installStock(baseApkFiles: List<File>, pkg: String, context: Context): Boolean {
log(INSTALLER_TAG, "Installing stock")
return if (pkg == vancedRootPkg) installSplitApkFilesRoot(
baseApkFiles,
context
) else installRootMusic(baseApkFiles, context)
}
private fun isMagiskInstalled() = Shell.su("magisk -c").exec().isSuccess
//set chcon to apk_data_file
private fun chConV(apkFPath: String, context: Context): Boolean {
Log.d(INSTALLER_TAG, "Running chcon")
log(INSTALLER_TAG, "Running chcon")
val response = Shell.su("chcon u:object_r:apk_data_file:s0 $apkFPath").exec()
//val response = Shell.su("chcon -R u:object_r:system_file:s0 $path").exec()
return if (response.isSuccess) {
true
} else {
if (!response.isSuccess) {
sendFailure(response.out, context)
sendCloseDialog(context)
false
return false
}
return true
}
//move patch to data/app
private fun moveAPK(apkFile: String, path: String, pkg: String, context: Context) : Boolean {
Log.d(INSTALLER_TAG, "Moving app")
val apkinF = SuFile.open(apkFile)
val apkoutF = SuFile.open(path)
private fun moveAPK(apkFile: String, path: String, pkg: String, context: Context): Boolean {
log(INSTALLER_TAG, "Moving app")
Shell.su("am force-stop $pkg").exec()
if(apkinF.exists()) {
try {
Shell.su("am force-stop $pkg").exec()
//Shell.su("rm -r SuFile.open(path).parent")
copy(apkinF,apkoutF)
Shell.su("chmod 644 $path").exec().isSuccess
return if(Shell.su("chown system:system $path").exec().isSuccess) {
true
} else {
sendFailure(listOf("Chown_Fail").toMutableList(), context)
sendCloseDialog(context)
false
}
}
catch (e: IOException)
{
sendFailure(listOf("${e.message}").toMutableList(), context)
sendCloseDialog(context)
return false
}
val mv = Shell.su("cp $apkFile $path").exec()
if (!mv.isSuccess) {
sendFailure(mv.out.apply { add(0, "MV_Fail") }, context)
sendCloseDialog(context)
return false
}
sendFailure(listOf("IFile_Missing").toMutableList(), context)
sendCloseDialog(context)
return false
}
val chmod = Shell.su("chmod 644 $path").exec()
if (!chmod.isSuccess) {
sendFailure(chmod.out.apply { add(0, "Chmod_Fail") }, context)
sendCloseDialog(context)
return false
}
@Throws(IOException::class)
fun copy(src: File, dst: File) {
val cmd = Shell.su("mv ${src.absolutePath} ${dst.absolutePath}").exec().isSuccess
Log.d("ZLog", cmd.toString())
val chown = Shell.su("chown system:system $path").exec()
if (!chown.isSuccess) {
sendFailure(chown.out.apply { add(0, "Chown_Fail") }, context)
sendCloseDialog(context)
return false
}
return true
}
@Suppress("DEPRECATION")
private fun getVersionNumber(pkg: String, context: Context): Int? {
try {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
context.packageManager.getPackageInfo(vancedRootPkg, 0).longVersionCode.and(0xFFFFFFFF).toInt()
context.packageManager.getPackageInfo(vancedRootPkg, 0).longVersionCode.and(
0xFFFFFFFF
).toInt()
else
context.packageManager.getPackageInfo(vancedRootPkg, 0).versionCode
}
catch (e : Exception) {
} catch (e: Exception) {
val execRes = Shell.su("dumpsys package $pkg | grep versionCode").exec()
if(execRes.isSuccess) {
if (execRes.isSuccess) {
val result = execRes.out
var version = 0
result
@ -630,22 +547,16 @@ object PackageHelper {
}
//get path of the installed youtube
fun getPackageDir(context: Context, pkg: String): String?
{
fun getPackageDir(context: Context, pkg: String): String? {
val p = getPkgInfo(pkg, context)
return if(p != null)
{
return if (p != null) {
p.applicationInfo.sourceDir
}
else
{
} else {
val execRes = Shell.su("dumpsys package $pkg | grep codePath").exec()
if(execRes.isSuccess)
{
if (execRes.isSuccess) {
val result = execRes.out
for (line in result)
{
if(line.contains("data/app")) "${line.substringAfter("=")}/base.apk"
for (line in result) {
if (line.contains("data/app")) "${line.substringAfter("=")}/base.apk"
}
}
null
@ -655,16 +566,17 @@ object PackageHelper {
private fun setInstallerPackage(context: Context, target: String, installer: String) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return
try {
Log.d(INSTALLER_TAG, "Setting installer package to $installer for $target")
log(INSTALLER_TAG, "Setting installer package to $installer for $target")
val installerUid = context.packageManager.getPackageUid(installer, 0)
val res = Shell.su("""su $installerUid -c 'pm set-installer $target $installer'""").exec()
val res =
Shell.su("""su $installerUid -c 'pm set-installer $target $installer'""").exec()
if (res.out.any { line -> line.contains("Success") }) {
Log.d(INSTALLER_TAG, "Installer package successfully set")
log(INSTALLER_TAG, "Installer package successfully set")
return
}
Log.d(INSTALLER_TAG, "Failed setting installer package")
log(INSTALLER_TAG, "Failed setting installer package")
} catch (e: PackageManager.NameNotFoundException) {
Log.d(INSTALLER_TAG, "Installer package $installer not found. Skipping setting installer")
log(INSTALLER_TAG, "Installer package $installer not found. Skipping setting installer")
}
}
}

View file

@ -7,15 +7,15 @@ import androidx.preference.PreferenceManager.getDefaultSharedPreferences
val Context.defPrefs: SharedPreferences get() = getDefaultSharedPreferences(this)
var SharedPreferences.managerTheme
var SharedPreferences.managerTheme
get() = getString("manager_theme", "System Default")
set(value) = edit { putString("manager_theme", value) }
var SharedPreferences.managerAccent
var SharedPreferences.managerAccent
get() = getInt("manager_accent_color", defAccentColor)
set(value) = edit { putInt("manager_accent_color", value) }
var SharedPreferences.managerVariant
var SharedPreferences.managerVariant
get() = getString("vanced_variant", "nonroot")
set(value) = edit { putString("vanced_variant", value) }
@ -23,11 +23,11 @@ var SharedPreferences.managerLang
get() = getString("manager_lang", "System Default")
set(value) = edit { putString("manager_lang", value) }
var SharedPreferences.installUrl
var SharedPreferences.installUrl
get() = getString("install_url", baseUrl)
set(value) = edit { putString("install_url", value) }
var SharedPreferences.vancedVersion
var SharedPreferences.vancedVersion
get() = getString("vanced_version", "latest")
set(value) = edit { putString("vanced_version", value) }

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