Compare commits

...

571 Commits
v2.4.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
234 changed files with 5793 additions and 4445 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,34 +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
[![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

@ -10,25 +10,23 @@ plugins {
}
android {
compileSdkVersion(30)
compileSdk = 31
defaultConfig {
applicationId = "com.vanced.manager"
minSdkVersion(21)
targetSdkVersion(30)
versionCode = 240
versionName = "2.4.0 (java.lang.TrashManagerException)"
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")
}
@ -48,8 +46,10 @@ android {
}
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.3")
implementation("androidx.navigation:navigation-ui-ktx:2.3.3")
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.1")
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.2")
implementation("com.google.firebase:firebase-crashlytics:17.3.1")
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
@ -32,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" />
@ -56,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" />
@ -67,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>
@ -77,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,117 +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.*
class AppListAdapter(
private val context: FragmentActivity,
private val viewModel: HomeViewModel,
private val lifecycleOwner: LifecycleOwner,
private val tooltip: ViewTooltip
) : RecyclerView.Adapter<AppListAdapter.ListViewHolder>() {
private val apps = mutableListOf<String>()
private val dataModels = mutableListOf<DataModel?>()
private val rootDataModels = mutableListOf<RootDataModel?>()
private val prefs = getDefaultSharedPreferences(context)
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 {
if (vanced.value != null) {
viewModel.openInstallDialog(it, apps[position])
} else {
return@setOnClickListener
}
}
appUninstall.setOnClickListener {
dataModel?.appPkg?.let { it1 -> viewModel.uninstallPackage(it1) }
}
appLaunch.setOnClickListener {
viewModel.launchApp(apps[position], isRoot)
}
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 = apps.size
init {
if (prefs.enableVanced) {
if (isRoot) {
rootDataModels.add(viewModel.vancedRootModel.value)
} else {
dataModels.add(viewModel.vancedModel.value)
}
apps.add(context.getString(R.string.vanced))
}
if (prefs.enableMusic) {
if (isRoot) {
rootDataModels.add(viewModel.musicRootModel.value)
} else {
dataModels.add(viewModel.musicModel.value)
}
apps.add(context.getString(R.string.music))
}
if (!isRoot) {
dataModels.add(viewModel.microgModel.value)
apps.add(context.getString(R.string.microg))
}
}
}

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

@ -10,7 +10,8 @@ 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>() {
class GetNotifAdapter(private val context: Context) :
RecyclerView.Adapter<GetNotifAdapter.GetNotifViewHolder>() {
private val prefs = context.defPrefs
@ -35,7 +36,8 @@ class GetNotifAdapter(private val context: Context) : RecyclerView.Adapter<GetNo
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]
@ -44,15 +46,21 @@ class GetNotifAdapter(private val context: Context) : RecyclerView.Adapter<GetNo
setSummary(app.switchSummary)
setTitle(app.switchTitle)
setDefaultValue(true)
with (prefs) {
setChecked(getBoolean( "enable_" + app.key.substringBefore("_"), true) && getBoolean(app.key, true))
with(prefs) {
setChecked(
getBoolean(
"enable_" + app.key.substringBefore("_"),
true
) && getBoolean(app.key, true)
)
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GetNotifViewHolder {
val view = ViewNotificationSettingBinding.inflate(LayoutInflater.from(context), parent, false)
val view =
ViewNotificationSettingBinding.inflate(LayoutInflater.from(context), parent, false)
return GetNotifViewHolder(view)
}

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 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.vanced.manager.utils.AppUtils.log
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("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
@ -23,7 +22,9 @@ object MusicDownloader {
fun downloadMusic(context: Context, version: String? = null) {
val prefs = context.defPrefs
musicVersion = 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$musicVersion"
@ -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

@ -10,14 +10,13 @@ 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()
@ -59,7 +60,7 @@ object VancedDownloader {
downloadSplits(context)
} catch (e: Exception) {
log("VMDownloader", e.stackTraceToString())
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, "Vanced"))
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

@ -9,7 +9,7 @@ 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)) {
@ -31,7 +31,7 @@ class AppInstallerService: Service() {
else -> {
sendCloseDialog(this)
intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)?.let {
sendFailure(it,this)
sendFailure(it, this)
}
}
}

View File

@ -7,7 +7,7 @@ import android.os.IBinder
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")

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

@ -1,93 +1,81 @@
package com.vanced.manager.model
import android.content.Context
import android.content.pm.PackageManager
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 try {
pm?.getPackageInfo(pkg, 0)?.versionName?.removeSuffix("-vanced") ?: context.getString(R.string.unavailable)
} catch (e: PackageManager.NameNotFoundException) {
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 {
unavailable
}
}
@Suppress("DEPRECATION")
private fun getPkgVersionCode(pkg: String): Int {
val pm = context.packageManager
return try {
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
} catch (e: PackageManager.NameNotFoundException) {
} 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,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)
postReset()
}
}

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

@ -15,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
@ -28,9 +25,11 @@ 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() {
@ -38,23 +37,9 @@ 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(tag, "Loaded data")
}
override fun onFailure(throwable: Throwable) {
log(tag, "Failed to load data: ${throwable.stackTraceToString()}")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
setFinalTheme()
super.onCreate(savedInstanceState)
if (ENABLE_CROWDIN_AUTH)
authCrowdin()
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
@ -73,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)
}
}
}
@ -84,26 +69,19 @@ 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 {
return when (item.itemId) {
android.R.id.home -> {
onBackPressedDispatcher.onBackPressed()
true
}
R.id.toolbar_about -> {
navHost.navigate(HomeFragmentDirections.toAboutFragment())
true
@ -116,30 +94,9 @@ class MainActivity : AppCompatActivity() {
navHost.navigate(HomeFragmentDirections.toLogFragment())
true
}
R.id.toolbar_guide -> {
try {
val intent = if (isPackageInstalled(faqpkg, packageManager)) {
Intent().apply {
component = ComponentName(faqpkg, "$faqpkg.ui.MainActivity")
}
} else {
Intent(Intent.ACTION_VIEW).apply {
val uriBuilder = Uri.parse("https://play.google.com/store/apps/details")
.buildUpon()
.appendQueryParameter("id", faqpkg)
.appendQueryParameter("launch", "true")
data = uriBuilder.build()
setPackage(playStorePkg)
}
}
startActivity(intent)
true
} catch (e: ActivityNotFoundException) {
false
}
}
R.id.toolbar_update_manager -> {
ManagerUpdateDialog.newInstance(false).show(supportFragmentManager, "manager_update")
ManagerUpdateDialog.newInstance(false)
.show(supportFragmentManager, "manager_update")
true
}
R.id.dev_settings -> {
@ -151,17 +108,31 @@ class MainActivity : AppCompatActivity() {
}
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() {
@ -183,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,11 +46,7 @@ class PreferenceSwitch @JvmOverloads constructor(
init {
_binding = ViewPreferenceSwitchBinding.inflate(LayoutInflater.from(context), this, true)
prefs.registerOnSharedPreferenceChangeListener { sharedPreferences, key ->
if (key == prefKey) {
binding.preferenceSwitch.isChecked = sharedPreferences.getBoolean(key, defValue)
}
}
prefs.registerOnSharedPreferenceChangeListener(prefListener)
attrs?.let { mAttrs ->
with(context.obtainStyledAttributes(mAttrs, R.styleable.PreferenceSwitch, 0, 0)) {
val title = getText(R.styleable.PreferenceSwitch_switch_title)

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,8 +4,7 @@ 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(
context: Context,
@ -14,7 +13,7 @@ class ThemedMaterialSlider @JvmOverloads constructor(
) : Slider(context, attributeSet, defStyleAttr) {
init {
val accentValue = ColorStateList.valueOf(context.defPrefs.managerAccent)
val accentValue = ColorStateList.valueOf(accentColor.value!!)
thumbTintList = accentValue
trackActiveTintList = accentValue
trackInactiveTintList = accentValue.withAlpha(70)

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(), arguments?.getString(TAG_VERSION))
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,11 +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.formatVersion
import com.vanced.manager.utils.getCheckedButtonTag
class AppVersionSelectorDialog : BindingBottomSheetDialogFragment<DialogBottomRadioButtonBinding>() {
class AppVersionSelectorDialog :
BindingBottomSheetDialogFragment<DialogBottomRadioButtonBinding>() {
private val prefs by lazy { requireActivity().defPrefs }
@ -64,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) }
}

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,9 +41,11 @@ 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()
when (app) {

View File

@ -50,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)
@ -63,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) {
}
}
}
@ -96,7 +108,11 @@ class ManagerAccentColorDialog : BindingDialogFragment<DialogManagerAccentColorB
prefs.managerAccent = colorFromEditText
} catch (e: IllegalArgumentException) {
log("VMTheme", getString(R.string.failed_accent))
Toast.makeText(requireActivity(), getString(R.string.failed_accent), Toast.LENGTH_SHORT).show()
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%"
}
}
@ -101,10 +100,12 @@ class ManagerUpdateDialog : BindingDialogFragment<DialogManagerUpdateBinding>()
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

@ -3,7 +3,6 @@ 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
@ -34,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.musicVersion?.formatVersion(requireActivity()))
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(
@ -46,36 +49,12 @@ class MusicPreferencesDialog : BindingBottomSheetDialogFragment<DialogMusicPrefe
)
}
musicInstall.setOnClickListener {
fun downloadMusic(version: String? = null) {
dismiss()
showDialog(
AppDownloadDialog.newInstance(
app = getString(R.string.music),
version = version
)
dismiss()
showDialog(
AppDownloadDialog.newInstance(
app = getString(R.string.music)
)
}
if (prefs.managerVariant == "nonroot" && isMicrogBroken && prefs.musicVersion?.getLatestAppVersion(musicVersions.value?.value ?: listOf(""))?.replace(".", "")?.take(3)?.toIntOrNull() ?: 0 >= 411 &&
!PackageHelper.isPackageInstalled(
AppUtils.musicPkg,
requireActivity().packageManager
)
) {
MaterialAlertDialogBuilder(requireActivity()).apply {
setTitle(R.string.microg_bug)
setMessage(R.string.microg_bug_summary_music)
setPositiveButton(R.string.auth_dialog_ok) { _, _ ->
downloadMusic("4.07.51")
}
setNeutralButton(R.string.cancel) { _, _ ->
dismiss()
}
create()
}.applyAccent()
return@setOnClickListener
}
downloadMusic()
)
}
}
}

View File

@ -43,7 +43,11 @@ 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 {

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>() {
@ -43,15 +40,22 @@ class VancedPreferencesDialog : BindingBottomSheetDialogFragment<DialogVancedPre
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.theme?.convertToAppTheme(requireActivity()))
vancedVersion.text = getString(R.string.chosen_version, defPrefs.vancedVersion?.formatVersion(requireActivity()))
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 && defPrefs.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

@ -38,15 +38,18 @@ class LogFragment : BindingFragment<FragmentLogBinding>() {
val hour = calendar.get(Calendar.HOUR_OF_DAY)
val minute = calendar.get(Calendar.MINUTE)
val second = calendar.get(Calendar.SECOND)
val log = File(requireActivity().getExternalFilesDir("logs")?.path + "/$year$month${day}_$hour$minute$second.log")
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(), R.string.logs_saved, Toast.LENGTH_SHORT).show()
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()
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,24 +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.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
@ -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("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

@ -3,22 +3,25 @@ package com.vanced.manager.utils
import android.content.Context
import android.content.Intent
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"
@ -31,33 +34,45 @@ object AppUtils: CoroutineScope by CoroutineScope(Dispatchers.IO) {
val logs = mutableListOf<Spannable>()
var currentLocale: Locale? = null
fun log(tag: String, message: String) {
logs.add(
SpannableString("$tag: $message\n").apply {
setSpan(ForegroundColorSpan(Color.CYAN), 0, tag.length + 1, 0)
setSpan(ForegroundColorSpan(Color.GREEN), tag.length + 2, tag.length + message.length + 2, 0)
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
)
}
)
Log.d(tag, message)
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(error: MutableList<String>, context: Context) {
sendFailure(error.joinToString(), context)
fun sendFailure(error: List<String>, context: Context) {
sendFailure(error.joinToString(" "), context)
}
fun sendFailure(error: String, context: Context): Job {
@ -87,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"
@ -122,11 +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)
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

@ -6,10 +6,8 @@ import android.content.Intent
import android.net.Uri
import android.os.Build
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
@ -40,39 +38,48 @@ 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("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("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("VMDownloader", "Download canceled")
downloadProgress.value?.downloadProgress?.postValue(0)
downloadProgress.postValue(0)
} else {
onError(t.stackTraceToString())
downloadProgress.value?.downloadProgress?.postValue(0)
downloadProgress.postValue(0)
log("VMDownloader", "Failed to download file: $url")
}
}
@ -95,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
@ -110,41 +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)
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
log("VMDownloader", e.stackTraceToString())
} finally {
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

@ -7,6 +7,7 @@ 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
@ -17,57 +18,58 @@ 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(activity: FragmentActivity) {
fun DialogFragment.show(fragmentManager: FragmentManager) {
try {
show(activity.supportFragmentManager, "")
show(fragmentManager, "")
} catch (e: Exception) {
log("VMUI", e.stackTraceToString())
}
}
fun DialogFragment.show(activity: FragmentActivity) {
show(activity.supportFragmentManager)
}
fun List<String>.convertToAppVersions(): List<String> = listOf("latest") + reversed()
fun String.formatVersion(context: Context): String = if (this == "latest") context.getString(R.string.install_latest) else this
fun String.formatVersion(context: Context): String =
if (this == "latest") context.getString(R.string.install_latest) else this
fun String.convertToAppTheme(context: Context): String {
return 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.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)
@ -79,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

@ -32,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>()
@ -43,16 +43,23 @@ 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()
@ -103,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"))
@ -137,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

@ -9,7 +9,6 @@ import android.content.pm.PackageManager
import android.os.Build
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
@ -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,79 +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(INSTALLER_TAG, e.stackTraceToString())
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
} catch (e: SecurityException) {
} 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(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)
}
}
@ -243,7 +254,7 @@ object PackageHelper {
installRootApp(
context,
"music",
music.value?.int("versionCode")!!,
music.value?.int("versionCode"),
musicRootPkg
) {
it == "root.apk"
@ -254,113 +265,46 @@ 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(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) {
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
e.printStackTrace()
return -1
}
val installParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
installParams.setSize(totalSize)
try {
sessionId = context.packageManager.packageInstaller.createSession(installParams)
log(INSTALLER_TAG,"Success: created install session [$sessionId]")
for ((key, value) in nameSizeMap) {
doWriteSession(sessionId, apkFolderPath + key, value, key, context)
}
doCommitSession(sessionId, context)
log(INSTALLER_TAG,"Success")
} catch (e: Exception) {
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
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(INSTALLER_TAG, "Success: streamed $total bytes")
return PackageInstaller.STATUS_SUCCESS
} catch (e: IOException) {
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
log(INSTALLER_TAG, "Error: failed to write; " + e.message)
return PackageInstaller.STATUS_FAILURE
} finally {
try {
out?.close()
inputStream?.close()
session?.close()
} catch (e: IOException) {
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
}
}
}
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(INSTALLER_TAG, "install request sent")
log(INSTALLER_TAG, "doCommitSession: " + context.packageManager.packageInstaller.mySessions)
log(INSTALLER_TAG, "doCommitSession: after session commit ")
} catch (e: IOException) {
} catch (e: Exception) {
log(INSTALLER_TAG, e.stackTraceToString())
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
} finally {
@ -368,96 +312,48 @@ object PackageHelper {
}
}
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(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(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(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,
@ -465,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)
}
}
}
@ -484,17 +378,23 @@ 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(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) {
sendFailure(e.stackTraceToString(), context)
sendCloseDialog(context)
e.printStackTrace()
log(INSTALLER_TAG, e.stackTraceToString())
}
return false
}
@ -502,7 +402,8 @@ object PackageHelper {
private fun linkApp(apkFPath: String, pkg: String, path: String): Boolean {
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()
@ -514,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 {
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)
}
@ -533,7 +439,7 @@ object PackageHelper {
private fun getPkgInfo(pkg: String, context: Context): PackageInfo? {
return try {
context.packageManager.getPackageInfo(pkg, 0)
} catch (e:Exception) {
} catch (e: Exception) {
log(INSTALLER_TAG, "Unable to get package info")
null
}
@ -548,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 {
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)
@ -559,78 +468,70 @@ object PackageHelper {
}
//install stock youtube matching vanced version
private fun installStock(baseApkFiles: ArrayList<FileInfo>, pkg: String, context: Context): Boolean {
private fun installStock(baseApkFiles: List<File>, pkg: String, context: Context): Boolean {
log(INSTALLER_TAG, "Installing stock")
return if (pkg == vancedRootPkg) installSplitApkFiles(baseApkFiles, context) else installRootMusic(baseApkFiles, context)
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(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 {
private fun moveAPK(apkFile: String, path: String, pkg: String, context: Context): Boolean {
log(INSTALLER_TAG, "Moving app")
val apkinF = SuFile.open(apkFile)
val apkoutF = SuFile.open(path)
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("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
@ -646,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
@ -673,7 +568,8 @@ object PackageHelper {
try {
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(INSTALLER_TAG, "Installer package successfully set")
return

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) }

View File

@ -0,0 +1,22 @@
package com.vanced.manager.utils
import androidx.lifecycle.MutableLiveData
import okhttp3.ResponseBody
import retrofit2.Call
val downloadProgress = MutableLiveData(0)
val downloadingFile = MutableLiveData("")
val installing = MutableLiveData(false)
var currentDownload: Call<ResponseBody>? = null
fun reset() {
downloadProgress.value = 0
downloadingFile.value = ""
}
fun postReset() {
downloadProgress.postValue(0)
downloadingFile.postValue("")
}

View File

@ -7,20 +7,30 @@ import androidx.lifecycle.MutableLiveData
import com.vanced.manager.R
const val defAccentColor: Int = -13732865
const val LIGHT = "Light"
const val DARK = "Dark"
const val SYSTEM_DEFAULT = "System Default"
val mutableAccentColor = MutableLiveData<Int>()
val mutableAccentColor = MutableLiveData(defAccentColor)
val accentColor: LiveData<Int> = mutableAccentColor
var currentTheme = ""
fun Activity.setFinalTheme() {
when (defPrefs.managerTheme) {
"Light" -> setTheme(R.style.LightTheme)
"Dark" -> setTheme(R.style.DarkTheme)
"System Default" -> {
LIGHT -> setTheme(R.style.LightTheme, LIGHT)
DARK -> setTheme(R.style.DarkTheme, DARK)
SYSTEM_DEFAULT -> {
when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
Configuration.UI_MODE_NIGHT_YES -> setTheme(R.style.DarkTheme)
Configuration.UI_MODE_NIGHT_NO -> setTheme(R.style.LightTheme)
Configuration.UI_MODE_NIGHT_YES -> setTheme(R.style.DarkTheme, DARK)
Configuration.UI_MODE_NIGHT_NO -> setTheme(R.style.LightTheme, LIGHT)
}
}
else -> setTheme(R.style.LightTheme)
else -> setTheme(R.style.LightTheme, LIGHT)
}
}
fun Activity.setTheme(resId: Int, themeValue: String) {
setTheme(resId)
currentTheme = themeValue
}

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:valueType="floatType"
android:valueFrom="1.0"
android:valueTo="0"
android:propertyName="xFraction" />
</set>

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