Compare commits

...

615 Commits

Author SHA1 Message Date
Ushie
419fe3bac1 feat: Sort bundles by patch count 2025-05-05 01:29:06 +03:00
Ushie
6e57a6e977 fix: Ignore long click when already in delete mode
closes #2503
2025-04-30 13:34:33 +03:00
Ax333l
10001b492b feat: add network checks for features that require it 2025-04-28 18:10:01 +02:00
Ax333l
d37ed050bc feat: move plugin api to another repository 2025-04-28 17:19:07 +02:00
kitadai31
ee07621e37 fix: Do not poll battery optimization status (#2491) 2025-04-23 19:26:04 +02:00
Ushie
fc05f95837 feat: Improve update screen design (#2487) 2025-04-23 20:09:05 +03:00
Ushie
d5c63ead26 fix: Use compatible rather than support when referring to patch compatibility (#2422) 2025-02-13 00:40:47 +07:00
Ushie
1956982060 feat: Improve APK file name formatting on save (#2421) 2025-02-13 00:40:36 +07:00
dependabot[bot]
e10e5e4e3f build(deps): bump the gradle-compose group with 16 updates (#2407) 2025-02-01 10:45:14 +07:00
Ushie
ede1ab5ed4 feat: Reorder Import & Export settings (#2403) 2025-02-01 04:05:28 +03:00
Ushie
1092188ab0 feat: TopAppBar scroll behavior (#2397) 2025-01-31 15:03:50 +03:00
Pun Butrach
f348eba115 ci: Generate release artifact provenance (#2324)
Signed-off-by: validcube <pun.butrach@gmail.com>
2025-01-29 20:43:16 +01:00
Robert
3d234820a3 fix: improve keystore import error handling and show toast 2025-01-29 19:58:38 +01:00
validcube
cd06d36f68 build: Enable pseudo locale for debug variant 2025-01-29 23:22:24 +07:00
validcube
242c4570ce chore: Update project's dependencies to latest 2025-01-29 23:17:34 +07:00
Robert
71b73a3b42 fix: show install button when installation has been cancelled 2025-01-29 15:17:41 +01:00
Ushie
067020f38f feat: Screen slide transition (#2396) 2025-01-27 19:28:55 +07:00
Ushie
2aef67872d fix: Offset badge 2025-01-27 03:56:15 +03:00
validcube
818dc09aa4 build: Bump AGP to 8.8.0
build: Bump AGP to 8.8.0
2025-01-19 17:47:56 +07:00
Pun Butrach
a762969966 docs: Merge documentation from Flutter to Compose 2025-01-19 17:08:07 +07:00
Tornike Khintibidze
74338931b8 feat: Redesign the patches screen (#2381) 2025-01-18 17:03:38 +01:00
Ax333l
0ab424bfdb fix: available updates dialog list item color 2025-01-05 00:12:00 +01:00
Ax333l
fff1a41fee refactor: use EventEffect for legacy import 2025-01-05 00:08:29 +01:00
Ax333l
7644a74648 feat: add required options screen (#2378) 2025-01-03 22:26:40 +01:00
aAbed
9db3bd5b3f feat: Add confirm dialogs when toggling dangerous settings (#2072)
Co-authored-by: Ax333l <main@axelen.xyz>
2024-12-23 16:35:27 +01:00
Ax333l
b81bd17fbc chore: add .kotlin to gitignore 2024-12-23 14:40:28 +01:00
Ax333l
cf3866f892 fix: remove battery optimization notification if user grants the permission 2024-12-23 14:39:57 +01:00
Ax333l
5d3a81f4b9 feat: switch to androidx.navigation (#2362) 2024-12-23 14:31:31 +01:00
Ax333l
f9831d4da5 refactor: remove unnecessary function 2024-12-23 13:13:08 +01:00
Ax333l
8a20d8cf9b fix: contributors screen repository name 2024-12-22 22:32:15 +01:00
Ax333l
49f75f9edd fix: process death resilience and account for android 11 bug (#2355) 2024-12-22 22:28:54 +01:00
kitadai31
9916e4da4d fix: Screen turns off while patching due to wrong WakeLock (#2147) 2024-12-21 10:25:59 +01:00
Ax333l
2ec1c0238d feat: Add downloader plugin system (#2041) 2024-12-19 21:41:04 +01:00
Ax333l
9dc716b1c8 feat: switch to revanced api v4 2024-12-12 17:52:21 +01:00
Pun Butrach
31fb8b1404 chore: Nitpick on misspelling of comment 2024-12-01 01:13:03 +07:00
somni
0685479d53 feat: Make patch bundles list scrollable (#2322) 2024-11-22 16:57:23 +03:00
Ax333l
20c13ee71c chore: update dependencies
🦀 integrations are gone! 🦀
2024-11-13 22:11:36 +01:00
Ax333l
cf322147d5 fix: only perform haptics on events 2024-11-12 21:17:02 +01:00
Benjamin
b4c37e6ddc feat: Add haptic feedback (#1457)
Co-authored-by: Ushie <ushiekane@gmail.com>
2024-11-06 23:48:40 +03:00
kitadai31
697386c36c fix: Match "Installation incompatible" dialog message with Flutter Manager (#2231) 2024-09-30 18:51:22 +02:00
alieRN
f6f72387b9 feat(patcher): Improve installation (#2185) 2024-09-19 21:17:38 +02:00
oSumAtrIX
d201bdc422 feat: Add installer status dialog (#1473)
Co-authored-by: Benjamin Halko <benjaminhalko@hotmail.com>
Co-authored-by: Benjamin <73490201+BenjaminHalko@users.noreply.github.com>
Co-authored-by: Ushie <ushiekane@gmail.com>
Co-authored-by: Ax333l <main@axelen.xyz>
2024-08-29 18:28:13 +02:00
Ushie
2055400565 feat: View bundle patches (#2065) 2024-08-25 01:23:13 +03:00
kitadai31
10e7e4b39f feat: Open the app-specific manage all files permission dialog (#2148) 2024-08-18 17:54:07 +07:00
Ushie
edb4e421e2 feat: Improve patch bundle screen (#2070) 2024-08-17 01:58:43 +03:00
Pun Butrach
747017a5f9 feat: Improve Settings order (#2060)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: Ax333l <main@axelen.xyz>
2024-08-15 14:59:06 +02:00
Ax333l
e992a99783 fix: remove the unique constraint for patch bundle names 2024-08-12 22:42:55 +02:00
kitadai31
e869db0555 fix: Move temporary files outside of the cache directory (#2122) 2024-08-12 18:23:31 +02:00
Ushie
936a9efd0b refactor: Add parameters for custom rotation values in ArrowButton 2024-08-08 02:49:07 +03:00
validcube
edc11b6e1d ci: Actually enable caching of Gradle 2024-08-07 22:51:04 +07:00
aAbed
32f2710763 fix: Turn off filters by default (#2079) 2024-08-06 03:46:50 +03:00
aAbed
4257c32bf5 fix: ExtendedFloatingActionButton not accessible by screen readers (#2080) 2024-08-06 03:46:41 +03:00
Ushie
c18901c35b feat: Improve unsupported patch warnings (#2066)
Closes #2052
2024-07-29 18:21:10 +03:00
Robert
f126fe9fa8 fix: show available and selected patches in patch selector screen 2024-07-29 15:00:24 +02:00
Ushie
4cbd480e84 feat: Add reset button to custom API (#2076)
Closes #2051
2024-07-29 13:14:13 +03:00
Ushie
afc72ffd85 feat: Show manager update dialog (#2069)
Closes #1963, closes #1958
2024-07-29 00:09:56 +03:00
oSumAtrIX
cdc69ea8ff fix: Support patching on ARMv7 by updating AAPT2 (#2084) 2024-07-28 22:43:10 +02:00
Ushie
52a89b1638 feat: Improve update setting tile titles
Closes #1968
2024-07-24 04:48:53 +03:00
Pun Butrach
641d518b6e build: Enable Gradle Configuration Cache (#2059) 2024-07-22 15:41:50 +07:00
Ax333l
2eca45d397 fix: always use default patch selection if customization is disabled 2024-07-20 16:17:41 +02:00
Robert
de6fddf405 fix: android icon not loading in app selector 2024-07-20 12:24:21 +02:00
Pun Butrach
45f32040f8 feat: Improve custom API URL dialog (#2033)
Signed-off-by: validcube <pun.butrach@gmail.com>
2024-07-18 04:22:37 +03:00
Ushie
42ef2ca99d fix: Broken header padding in AlertDialogExtended when using an Icon 2024-07-18 00:56:18 +03:00
Ushie
563f2f37f7 fix: Remove unnecessary screen padding
Closes #2062
2024-07-18 00:55:15 +03:00
Ushie
881b13740a feat: Improve overall UI and fix inconsistencies (#2028) 2024-07-11 01:09:45 +03:00
Ushie
d39804f7ed Merge branch 'compose-dev' into fix/minor-issues 2024-07-11 01:08:34 +03:00
Ushie
b8a85c4891 refactor: Use lastIndex
Co-authored-by: Ax333l <main@axelen.xyz>
2024-07-11 01:07:57 +03:00
validcube
37e9630b9c fix: Inconsistent padding for battery optimisation warning
The problem came after moving the card to DashboardScreen, this is because the card specified padding modifier but others does not. This commit remove the modifier completely.
2024-07-07 17:58:51 +07:00
validcube
40492b67d1 refactor: Use TextButton instead of FilledButton for consistency 2024-07-07 17:54:04 +07:00
Pun Butrach
f655a6e03a ci: Bump dependencies to latest (#2039) 2024-07-07 15:42:56 +07:00
Ax333l
36f864efbb chore: update dependencies 2024-07-06 22:47:27 +02:00
Ax333l
a995f43b7b fix: move battery warning to dashboard 2024-07-06 18:12:44 +02:00
Ax333l
1ee1330e47 feat: improve the safeguards (#2038) 2024-07-06 15:43:37 +00:00
Ax333l
3f4a234915 fix: run props flow on correct dispatcher (#2035) 2024-07-05 18:41:29 +00:00
Pun Butrach
032ca39cf6 feat: Automatic language detection (#2032) 2024-07-05 18:34:13 +00:00
Ax333l
6f9a984541 fix: improve bundle page strings 2024-07-05 20:31:49 +02:00
Ax333l
e6e043f168 fix: cleanup advanced settings screen 2024-07-05 19:41:27 +02:00
Ax333l
7c7fb7b343 feat: dont ask for root on launch 2024-07-05 19:06:10 +02:00
Ushie
b26fe30861 Merge branch 'compose-dev' of https://github.com/ReVanced/revanced-manager into fix/minor-issues 2024-07-04 23:34:22 +03:00
Ax333l
f99cdfe926 feat: improve UX for failed or missing bundles 2024-07-04 19:36:31 +02:00
Ax333l
ec0a077539 feat: implement more patch option types (#2015) 2024-07-04 17:34:55 +00:00
Ax333l
a22158d070 fix: crash when removing used bundles 2024-07-04 13:58:55 +02:00
Ax333l
48fe3a707e fix: import export screen UX 2024-07-03 14:46:00 +02:00
Ax333l
8d3d500b7b feat: add ability to share debug logs 2024-07-03 13:54:37 +02:00
Ax333l
d8248cc915 fix: import bundles on another thread 2024-07-03 12:27:39 +02:00
Ushie
397a1f8f9c Merge branch 'compose-dev' of https://github.com/ReVanced/revanced-manager into fix/minor-issues 2024-07-03 03:55:12 +03:00
Ushie
a0f187354f feat: Remove tag from changelog 2024-07-03 03:48:19 +03:00
Ushie
1bf004ddee feat: Progressive AlertDialog for adding bundles
Closes #1992
2024-07-03 03:48:04 +03:00
Ushie
495100dea9 fix: Use the correct icon in API URL dialog
Closes #1972
2024-07-03 02:49:16 +03:00
Ushie
e3bd8a8b22 feat: Add sensitivity to isScrollingUp 2024-07-03 02:46:01 +03:00
Ushie
d987ac6c7a feat: Add isScrollingUp support for ScrollState 2024-07-03 02:45:45 +03:00
Ushie
9883dcd0a7 fix: Use FAB instead of ListItem to patch in App Overview
Closes #1995
2024-07-03 02:44:10 +03:00
Ushie
d63133189d feat: Improve device information in debugging section
Closes #1977
2024-07-03 01:34:01 +03:00
Ushie
39fbb87010 fix: Change the title in the Update screen from "Updates" to "Update"
Closes #1960
2024-07-03 01:28:33 +03:00
Ushie
f197760efd feat: Change "Update" to "Show" in Update Available notification
Closes #1959
2024-07-03 01:27:13 +03:00
Ushie
fa13d4a538 feat: Highlight links in Markdown
Closes #1962
2024-07-03 01:26:05 +03:00
Ushie
71b5f539c1 feat: Improve initial update popup wording
Closes #1956
2024-07-03 01:25:25 +03:00
Ushie
603a827e45 chore: Remove unused ARMv7 AAPT binary
Closes #1954
2024-07-03 01:24:55 +03:00
Ushie
47bdc69a43 refactor: Improve naming consistency in libs.version.toml
Closes #1953
2024-07-03 01:24:10 +03:00
Ax333l
1ce56af3b1 feat: get bundle information from jar manifest (#2027) 2024-07-02 19:50:28 +00:00
Ax333l
a12c5c583b fix: add bounds checks in patch selector 2024-07-02 15:43:06 +02:00
Robert
5455cf20ab feat: rename main bundle to Default 2024-06-25 23:54:59 +02:00
Robert
75fcdb139c fix: use proper update icon 2024-06-25 23:49:28 +02:00
Robert
269fa79136 feat: improve patcher screen labels 2024-06-23 21:01:20 +02:00
Robert
16fea59605 fix: scrolling in patch selector 2024-06-23 20:17:42 +02:00
Robert
c7d183ee8d feat: rename debug build to ReVanced Manager (dev) 2024-06-23 17:27:40 +02:00
Robert
413083c58d fix(downloader): versions not loading correctly 2024-05-29 23:25:15 +02:00
Robert
1f671aba33 fix: automatically focus search views 2024-05-27 22:49:08 +02:00
Robert
6bfd9098d6 feat: move update to notification card (#1917) 2024-05-27 21:50:02 +02:00
Robert
4e7d96e91d feat: revert to blue theme colors 2024-05-22 20:05:27 +02:00
Ax333l
ac0a036035 refactor: fix more warnings 2024-04-05 20:04:27 +02:00
Ax333l
2a1445d61f build(deps): update ksp 2024-04-05 19:22:54 +02:00
Ax333l
0df39a1136 refactor: replace deprecated functions 2024-04-05 19:09:39 +02:00
Ax333l
634d793839 fix: crash caused by compose inlining bug
This is a bug in jetpack compose. Inlining this function wasn't very
important anyways so it's best to just stop inlining it to avoid the
crash.
2024-04-04 17:50:31 +02:00
dependabot[bot]
afd6c5d6b7 build(deps): bump aboutLibrariesGradlePlugin from 11.1.0 to 11.1.1 (#1813)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 15:28:19 +00:00
dependabot[bot]
ab0682cc5c build(deps): bump androidx.compose.ui:ui-tooling from 1.6.3 to 1.6.4 (#1814)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 15:27:59 +00:00
dependabot[bot]
60ca901ac7 build(deps): bump androidx.compose:compose-bom from 2024.02.02 to 2024.03.00 (#1812)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 15:27:45 +00:00
dependabot[bot]
91ca5be57a build(deps): bump libsu from 5.2.1 to 5.2.2 (#1810)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 15:27:24 +00:00
dependabot[bot]
ac47a7eaa4 build(deps): bump plugin.serialization from 1.9.22 to 1.9.23 (#1811)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 15:26:17 +00:00
Ax333l
ce134224a8 fix: correctly patch apk files 2024-04-03 17:07:29 +02:00
Ax333l
ca49d3a465 feat: add external process runtime (#1799) 2024-03-29 15:00:52 +00:00
Ax333l
5d7f9d1387 feat: check if the version being used is the recommended version (#1675) 2024-03-15 17:57:53 +00:00
Benjamin
8d5d86fea8 feat: add social links (#1294)
Co-authored-by: Pun Butrach <pun.butrach@gmail.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: Ax333l <main@axelen.xyz>
2024-03-12 17:09:39 -07:00
Benjamin
6709505e9e chore: Upgrade dependencies (#1761)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-10 11:05:47 -07:00
Benjamin
088de60c91 chore: upgrade dependencies (#1670) 2024-03-05 06:35:13 -08:00
Ax333l
ef041869e5 fix(VersionSelector): use correct LazyColumn item key 2024-03-05 14:34:45 +01:00
Benjamin
16cdc7aca4 refactor: Disable update for dev build (#1673)
Co-authored-by: Pun Butrach <pun.butrach@gmail.com>
2024-02-17 18:17:27 +00:00
Ushie
39536c0e18 feat: Collapse ExtendedFAB on scroll (#1630) 2024-02-03 19:12:12 +00:00
Ax333l
607d8b67c9 feat: add toast feedback to the bundle update button 2024-01-21 14:34:18 +01:00
Ax333l
0b9889ea44 fix: patch options reset button being broken 2024-01-21 14:24:39 +01:00
Ax333l
4acef776b2 refactor: use consistent wording for the version compat check 2024-01-20 17:48:08 +01:00
Pun Butrach
e186dfdaa9 docs(security): init (#1612)
Co-authored-by: Ax333l <main@axelen.xyz>
2024-01-20 16:35:32 +00:00
Ax333l
c0f3d02e6f refactor: fix terminology and wording related to patches (#1623) 2024-01-18 19:50:24 +00:00
Ushie
36c8f59d6f feat: Scrollbars (#1479) 2024-01-08 01:28:16 +03:00
Robert
f38b31a591 fix: progress bar not updating 2024-01-07 13:29:09 +01:00
Robert
3232bb10e6 feat: improve patcher UI (#1494) 2024-01-06 16:51:11 +01:00
Ax333l
b7cb6b94f5 feat: updater UI and code improvements (#1597) 2024-01-05 22:05:02 +00:00
Ushie
aa6e612fba feat: Select bundle type before adding bundle (#1490) 2024-01-04 21:54:44 +00:00
Benjamin
d9d7b98409 feat: Purple default theme (#1601) 2023-12-27 16:35:23 -08:00
Benjamin
4fdd6bbe5f chore: upgrade AGP to 8.2.0 + migrate deprecated functions (#1574) 2023-12-26 20:37:42 +00:00
Ax333l
439f6250f3 chore(deps): update jetpack compose 2023-12-25 23:28:42 +01:00
aAbed
d55abf5dda feat(app-selector): show patchable installed apps first (#1496) 2023-12-14 11:50:14 +01:00
validcube
a8b9d9316f docs: update revanced url 2023-12-02 17:18:21 +07:00
validcube
55c7800f39 build: bump Gradle to v8.5
build: update Gradle wrapper
2023-12-02 17:17:03 +07:00
validcube
d9eb1c42bc refactor: slight formatting of build.gradle.kts 2023-12-02 17:00:52 +07:00
validcube
8cd617e32d chore(template): update label name for feature 2023-12-02 16:58:47 +07:00
validcube
a17a05995a ci: caching with gradle-build-action
Allow for automatic capture of buildscan in job summary, and smarter
caching than the one provided by `setup-java`.
2023-12-02 16:55:04 +07:00
Ax333l
de4e616dcc chore(deps): bump revanced patcher and library 2023-12-01 13:21:20 +01:00
Benjamin
12b00e5c8d fix: specify multithreadingDexFileWriter in PatcherOptions (#1402)
Co-authored-by: Ax333l <main@axelen.xyz>
2023-11-29 21:33:00 +00:00
Ax333l
9cab91959e fix: load patch bundles earlier 2023-11-29 22:11:57 +01:00
Ushie
bd9778a3d1 feat(Update Screen): changelogs & handle states (#1464)
Co-authored-by: Ax333l <main@axelen.xyz>
2023-11-19 23:28:28 +03:00
Ushie
62a5fce66c feat(Contributors Screen): implement design from Figma (#1465)
Co-authored-by: Robert <72943079+CnC-Robert@users.noreply.github.com>
Co-authored-by: Ax333l <main@axelen.xyz>
2023-11-19 23:27:13 +03:00
Ax333l
2bd84636d6 fix: parcel error for nullable types 2023-11-15 21:32:54 +01:00
oSumAtrIX
ac561e7aca feat: Use correct casing in module description 2023-11-07 23:59:33 +01:00
Ax333l
59daceef99 chore: bump patcher 2023-11-06 19:33:06 +01:00
Robert
1dc41badd9 feat: check for updates on startup (#1462) 2023-11-05 13:19:55 +01:00
Ushie
1a83315424 feat(Changelogs): overall improvement (#1429) 2023-11-03 18:03:14 +00:00
Ushie
3c5776214f feat(Installer): use BottomAppBar (#1428) 2023-11-03 09:15:17 +00:00
Benjamin
5fff0a2923 fix: option state crash (#1456)
Co-authored-by: Ax333l <main@axelen.xyz>
2023-11-02 15:46:53 +00:00
Ax333l
8df7f2992d refactor(ui-components): deduplicate colors and move to settings folder 2023-11-01 21:57:00 +01:00
Ushie
7741394c9c feat(NotificationCard): rewrite & consistent usage (#1426) 2023-11-01 20:54:06 +03:00
Ushie
25bd91debc feat(Settings): use SettingsListItem consistently and overall improvements (#1427) 2023-11-01 20:11:43 +03:00
Ax333l
7fe4724e10 feat: remember patch options (#1449) 2023-10-31 20:16:02 +00:00
Benjamin
123ae37524 chore: add issue template (#1432) 2023-10-28 12:54:33 +07:00
Ax333l
172604fcdb feat(installer): sign apk in patcher worker 2023-10-27 23:30:45 +02:00
Ax333l
7d887c73e8 fix: use correct checksum 2023-10-27 17:33:11 +02:00
Benjamin
6abaac25d9 chore: upgrade dependencies (#1401) 2023-10-26 07:25:12 -07:00
Ax333l
cc897840e2 fix: perform selected app operations in the correct order 2023-10-26 09:06:42 +02:00
Ax333l
757840b76f feat(bundles tab): add BackHandler 2023-10-26 09:03:26 +02:00
Ax333l
50e8d1f8f4 docs: clarify license 2023-10-21 16:10:10 +02:00
Ax333l
65f8d38c59 feat: show toast when no patches are selected 2023-10-20 23:16:00 +02:00
Ax333l
e70c10adbd feat: add checkboxes to the downloaded apps page 2023-10-20 23:02:35 +02:00
Ax333l
64ec73d821 fix: more android 34 fixes 2023-10-20 22:59:16 +02:00
Ax333l
32e8a37f33 fix: handle exceptions when checking for bundle updates 2023-10-20 19:43:26 +02:00
Ax333l
5290713504 feat(patch-selector): remove TODO about an unplanned feature 2023-10-20 19:24:17 +02:00
Ax333l
18cfb56b45 fix: bundles not loading on Android 14 2023-10-20 18:49:44 +02:00
Ax333l
4b12ae1531 fix: jvm signature clash error 2023-10-20 17:21:59 +02:00
Ax333l
9df98edca5 fix: use upsert when modifying installed apps 2023-10-19 22:01:32 +02:00
Ax333l
c3af6acb2c feat: selected app info page (#1395) 2023-10-19 19:44:50 +00:00
Ax333l
7ba00cafd9 refactor: move mount code to when block 2023-10-17 09:21:06 +02:00
Benjamin
5aefb3bc59 fix: hide patch button (#1284) 2023-10-16 12:48:51 -07:00
Benjamin
212e55ffd8 feat: add user agent (#1382) 2023-10-16 17:39:17 +00:00
Ax333l
bf54d38c91 chore: bump patcher 2023-10-15 14:03:53 +02:00
Ax333l
cee2240cdc chore: bump compose 2023-10-15 13:17:07 +02:00
Ax333l
4c1ad868a9 fix: broken logo in about page on release builds 2023-10-15 00:22:12 +02:00
Ax333l
f5b3b29d6d feat: hide unfinished pages in release mode 2023-10-14 18:48:07 +02:00
Ax333l
8f5449527d feat: armv7 warning 2023-10-14 18:24:40 +02:00
Ax333l
8f6d720454 refactor(downloaders): improve file system code (#1379) 2023-10-14 15:42:10 +00:00
Benjamin
56a4a7043d feat: settings migration (compose) (#1309) 2023-10-13 10:39:10 -07:00
Ax333l
5762859906 feat: add patches selector bottom sheet (#1360) 2023-10-13 16:11:40 +00:00
Ax333l
608bac6854 feat: use revanced api for changelogs 2023-10-07 17:07:19 +02:00
Ax333l
723f9cd98c fix: delete temporary files (#1341) 2023-10-07 14:09:02 +00:00
Ax333l
abf4d91703 fix: use correct classes to determine option type
I can't believe this happened
2023-10-06 16:41:00 +02:00
Ax333l
d8392ad3eb feat(settings): move experimental patches option to advanced 2023-10-05 22:16:58 +02:00
Ax333l
39caad18a5 feat(installer): adjust arrow icon size 2023-10-05 22:06:20 +02:00
Ax333l
6437f7bb65 feat(installer): adjust step icon size and alignment 2023-10-05 21:51:48 +02:00
Ax333l
e232044157 chore: switch to revanced library and bump patcher (#1314) 2023-10-05 15:36:33 +00:00
Ax333l
f78b56ef0a feat(patch-selector): default patches selection (#1272) 2023-10-01 18:56:16 +00:00
Ax333l
ca3c9af3b8 feat: remove dead help icons
These never did anything and were removed from the figma a while ago.
2023-10-01 19:02:11 +02:00
Ax333l
b8b2e74151 chore: fully remove idea project files 2023-10-01 18:12:08 +02:00
Benjamin Halko
1f8341ac42 fix: remove misc.xml and kotlinc.xml 2023-09-27 10:20:18 -07:00
Benjamin
0964f15475 docs: init (#1224) 2023-09-26 16:54:02 -07:00
Benjamin
63fd7957c6 ci: Add release workflow (#1235) 2023-09-25 19:02:18 +02:00
Benjamin
65377ffd9e fix: Updates popup shows incorrect names (#1283) 2023-09-23 19:42:27 -07:00
Benjamin
f79320c013 fix: use ReVanced ring logo in about section (#1302) 2023-09-22 14:19:48 -07:00
Benjamin
cf71ea26ec feat: implement Submit Issue button (#1276) 2023-09-21 19:18:42 +00:00
Benjamin
ee96c37c20 refactor: update progress onBackClick function (#1277) 2023-09-21 19:16:39 +00:00
Benjamin
a86923aee1 fix: disable WebView history (#1278) 2023-09-21 19:13:57 +00:00
Benjamin
e0f8d06152 fix(ui): make entire patches view button selectable (#1271) 2023-09-21 19:13:25 +00:00
Benjamin Halko
4cb4ce298a feat: change appID and name of debug builds 2023-09-20 20:15:55 -07:00
Benjamin Halko
36de61a57f ci: build pull requests (#1228) 2023-09-20 20:14:26 -07:00
Benjamin
6f2ca5bb89 fix: typo in string name import_keystore_description (#1273) 2023-09-18 16:59:03 +07:00
Benjamin
940885768d fix: contributors screen fix (#1256) 2023-09-15 16:33:14 +00:00
Patryk Miś
fc577b4c3e chore: update dependencies (#1247) 2023-09-15 16:30:46 +00:00
Robert
bf10af2ae2 feat: root installation (#1243) 2023-09-09 13:18:00 +00:00
Benjamin
b4dfcf1bb4 fix: minify crash on building release (#1245) 2023-09-06 17:49:11 +00:00
Benjamin
0b0ba21852 fix: providers.gradleProperty (#1223) 2023-09-06 17:48:48 +00:00
Tyff
42e0346e25 feat: make bundles selectable (#1237) 2023-09-04 07:05:55 +02:00
Pun Butrach
212db84d0b ci(config): appreciation for first-time contributors
Show appreciation message for new contributors
2023-09-03 21:47:05 +07:00
Benjamin
e6eb8accf2 docs: update readme badges (#1227) 2023-09-03 09:40:54 +07:00
Pun Butrach
8bd73c3afa ci(release): don't build when not necessary
Add paths-ignore to all markdown files, and .idea folder
2023-09-02 21:59:23 +07:00
Pun Butrach
5369a25fa2 docs: update badge's repository
The repository was moved from `revanced-manager-compose` to the main one, which is `revanced-manager`.

The organisation's name has also switched to `ReVanced` (used to be `revanced`).
2023-09-02 21:51:48 +07:00
Ax333l
eeae46a415 chore: bump kotlinx.serialization plugin and patcher 2023-09-01 10:50:13 +02:00
Patryk Miś
c0badbe96b build: updates (#85) 2023-08-26 14:03:44 +00:00
Ax333l
2bb51c136a fix(deps): use correct work-runtime version string 2023-08-26 15:52:40 +02:00
Tyff
3cfa4ea6d6 feat: more info for the select from application screen (#81) 2023-08-23 20:05:21 +02:00
Pun Butrach
f01adf5eb0 ci(release): migrate from node12 to node16
This bump `actions/upload-artifact`@v2 to `actions/upload-artifact`@v3
2023-08-19 16:00:01 +07:00
Robert
a0b92554e9 feat: store patched apps (#79)
* feat: store patched apps

* fix: missing string

* feat: save patch selection

* feat: things

* fix: fix broken query

* fix: remove redundant `withContext`

* fix: fix
2023-08-17 17:42:10 +02:00
Palm
ac4c7e06e7 ci(release): use correct vars context object
why am i so stupid
2023-08-17 19:30:31 +07:00
Palm
0f9a6f4340 ci(release): no longer store keystore alias in secrets
fixes an issue where GitHub Actions logs would be censored
2023-08-17 19:13:18 +07:00
Ax333l
9586a9c0dd fix: patches not being reloaded 2023-08-14 18:29:56 +02:00
Ax333l
f6563b265b fix: permission error when using installed app 2023-08-12 14:52:34 +02:00
Ax333l
7aea9473de feat: patch options UI (#80) 2023-08-12 08:41:22 +00:00
Ax333l
3f059d7748 feat: switch to the new api (#75) 2023-08-07 09:03:50 +00:00
Ax333l
7e3c31c4b2 chore: bump patcher 2023-08-04 12:55:14 +02:00
Ax333l
1707a9690a feat: improve bundle dialog UI 2023-08-04 12:46:07 +02:00
Ax333l
379ce917a9 feat: finish implementing the sources system (#70) 2023-08-03 11:15:42 +00:00
Ax333l
299aaa2b68 fix: library info not being embedded 2023-08-01 21:14:15 +02:00
Pun Butrach
5cf5e87fa8 ci(release): task naming consistency 2023-08-01 15:30:56 +07:00
CnC-Robert
55f22562eb fix: don't store app list in parcel 2023-07-31 13:24:49 +02:00
Ax333l
272d911464 fix(installer): progress tracking 2023-07-31 12:16:13 +02:00
Robert
6beb34baa8 ci: init 2023-07-30 20:23:51 +00:00
CnC-Robert
61de0b67fa feat: show installed app in version selector 2023-07-30 19:45:40 +02:00
Robert
aec8cec9b8 feat: download apps in patcher screen (#73) 2023-07-30 10:29:22 +00:00
Pun
83b9573b52 docs(readme): minor fix to displaying url
When you hover on Commit & Activity badges, `revanced` will appear in url display, but on License badge, `ReVanced` will display

This commit fix that by changing the organisation to what we're supposed to be using which is {org_name}/{repo_name} (ReVanced/...)
2023-07-24 16:24:21 +07:00
Tyff
21d99a1f24 feat: add patch bundle info screen (#55) 2023-07-23 15:27:07 +00:00
Ax333l
1331479072 fix: serialization not working 2023-07-17 16:48:29 +02:00
Patryk Miś
b472a36a9a fix: buildfile syntax (#66)
Signed-off-by: Patryk Miś <foss@patrykmis.com>
2023-07-17 14:41:17 +00:00
Patryk Miś
3238fcdae7 build: updates (#63)
* Update Java base to 17
* update Kotlin to 1.8.22
* update Bouncycastle
* update all dependencies
* follow the manifest on jni libs packaging
* enhance app optimization by specifying resource configurations, excluding dependencies info and unnessesary files
* Remove obsolete SDK check as we are already using minSdk 26

Signed-off-by: Patryk Miś <foss@patrykmis.com>
2023-07-17 12:27:19 +00:00
Patryk Miś
cd2587b1fd feat: improve accessibility (#64)
* Label Back button
* Mark group section headings as headings

Signed-off-by: Patryk Miś <foss@patrykmis.com>
2023-07-17 12:20:54 +00:00
Ax333l
879884a9fa feat: switch to Preferences DataStore (#60) 2023-07-15 09:52:12 +00:00
CnC-Robert
5d3b963682 feat: disable filter chips when there are no patches 2023-07-14 21:37:50 +02:00
CnC-Robert
955e7a4f1c feat: ReVanced theme colors 2023-07-14 21:35:17 +02:00
Ax333l
d2dcd4209d fix: release builds not working properly 2023-07-14 13:11:34 +02:00
Rom Reviewer
6299ff5b48 chore: migrate dependencies to version catalogs (#58) 2023-07-14 10:33:42 +00:00
Robert
94a4dbaba1 feat: app downloader (#43) 2023-07-14 08:54:42 +00:00
Pun Butrach
c36deea045 build: update gradle to v8.2.1 2023-07-12 20:36:23 +07:00
Pun
7030d43aa5 docs(readme): minor changes to how badges works
* Better description for the repository license badge

* Clicking on badges open you the relevant url
2023-07-08 20:43:10 +07:00
Ax333l
aa02e9f8cf feat: improve keystore UI and UX (#52) 2023-07-07 18:48:36 +00:00
Pun Butrach
37e177b56e revert: downgrade Kotlin to 1.8.21
"A what? 1.8.22 isn't compatible, but the version bump indicate that it's supposed to be bug fixes????"
2023-07-07 23:16:07 +07:00
Ax333l
453f4da8ec feat: advanced settings page with device info (#51) 2023-07-07 15:35:36 +00:00
Pun Butrach
400163b820 build: update dependencies
There are 9 dependencies update, changelog of this commit are available
below here.

Android Gradle Plugin: 8.0.1 -> 8.0.2
Kotlin: 1.8.21 -> 1.8.22
Android Compose BOM: 2023.05.01 -> 2023.06.01
Room: 2.5.1 -> 2.5.2
ReVanced Patcher: 11.0.1 -> 11.0.4
APKsig: 8.2.0-alpha05 -> 8.2.0-alpha10
Koin (Android, workmanager): 3.4.0 -> 3.4.2
Koin (Androidx Compose): 3.4.4 -> 3.4.5
Ktor: 2.3.0 -> 2.3.1
2023-07-07 20:27:53 +07:00
Ax333l
4ae9904c8a fix(installer): sign and install on threads
This is needed to avoid ANRs because it takes a while if the Apk is 100+
MB.
2023-07-07 12:31:31 +02:00
Ax333l
fe5e191cb5 feat: updater changelogs (#48)
---------

Co-authored-by: Aunali321 <aunvakil.aa@gmail.com>
2023-07-07 08:56:04 +00:00
Ax333l
d9d83df9de feat: allow user to save logs 2023-07-06 20:01:44 +02:00
Ax333l
8dd8f88d2b feat: save patch options and selected patches in bundle (#50) 2023-07-04 09:09:16 +00:00
Ax333l
01fd4c8ffa feat: patch options (#45) 2023-07-03 09:12:34 +00:00
Ax333l
7ac3bb74e0 refactor: use getDir instead of filesDir directly 2023-07-03 10:09:01 +02:00
Ax333l
3b65cd0edc fix: use correct directory 2023-07-01 16:02:34 +02:00
Ax333l
a9606728bf build: bump patcher 2023-07-01 15:09:21 +02:00
Pun Butrach
4d4f1a242c build: update gradle to v8.2 2023-07-01 12:40:01 +07:00
Ax333l
6b7143dd8f feat: licenses screen (#47) 2023-06-29 20:05:43 +00:00
Ax333l
7e4ee00cb2 chore: update links in about page 2023-06-29 18:10:40 +02:00
Ax333l
4868c45b43 feat: animate the arrow button 2023-06-29 17:26:49 +02:00
Ax333l
81f485da6b refactor: use correct coroutine scopes 2023-06-29 10:35:23 +02:00
Ax333l
18cbe51e6b fix(installer): save step incorrectly being marked as completed 2023-06-29 10:11:44 +02:00
Ax333l
149c8cc8b2 fix: sources screen being misaligned during transitions 2023-06-29 10:03:15 +02:00
Tyff
0dccb8c27b feat: contributors screen (#42)
* Contributors page
- https://github.com/revanced/revanced-manager-compose/issues/34

* feat: adding ContributorScreen as clickable icons like the website

* feat: adding ContributorScreen
- Made changes that were asked for in prev PR
- Currently just waiting on a git merge to get ArrowButton in

* feat: adding ContributorScreen
- Made changes that were asked for in prev PR
- ArrowButton is also in use

* feat: adding ContributorScreen
- Made changes that were asked for in prev PR
- ArrowButton is also in use
- Fixed other PR comment changes

* Apply suggestions from code review

* Remove unused string resources

---------

Co-authored-by: Ax333l <main@axelen.xyz>
2023-06-28 19:51:12 +00:00
Ax333l
4302ea8832 fix: pass worker inputs without serialization (#44)
Because androidx.work.Data sucks and causes our app to crash.
2023-06-27 14:39:30 +00:00
Ax333l
1eac42dab8 fix(installer): make the correct column scrollable 2023-06-27 15:12:55 +02:00
Ax333l
9dd74f1f22 feat: experimental patches setting 2023-06-27 15:05:31 +02:00
Ax333l
923ce74735 feat: save patch selection using room db (#38) 2023-06-22 10:20:30 +00:00
Ax333l
2d9f9adfee refactor: better PatchBundle docs and naming 2023-06-17 13:59:37 +02:00
Ax333l
9a55e51a3a build: bump patcher 2023-06-17 13:47:55 +02:00
Ax333l
5681c917c5 feat: show stacktrace in installer ui (#36) 2023-06-17 11:45:52 +00:00
CnC-Robert
6309e8bdf5 feat: filter options for patches 2023-06-15 22:20:17 +02:00
Ax333l
535efa3d73 fix: run blocking IO operations in the correct context 2023-06-11 17:52:43 +02:00
Ax333l
b8a51d32f5 fix(patcher): add notification and wakelock to worker; chore: add app icon 2023-06-11 17:49:42 +02:00
Ax333l
919b6b7014 feat: keystore import/export (#30) 2023-06-11 14:38:56 +00:00
Ax333l
971277ed39 fix(installer): properly track worker state (#32) 2023-06-09 15:34:10 +00:00
Ax333l
7ce4de7a8b feat(koin): use the android logger 2023-06-06 12:27:42 +02:00
CnC-Robert
9591f4e14f feat: ProGuard 2023-06-04 19:37:23 +02:00
CnC-Robert
27426b1390 feat: rename package to app.revanced.manager 2023-06-04 18:27:40 +02:00
CnC-Robert
fcb75dd780 feat: improved compose stability 2023-06-04 17:50:40 +02:00
CnC-Robert
1be9c9c1bd fix: use correct getViewModel 2023-06-04 17:42:21 +02:00
CnC-Robert
e088d053ab feat: rename ViewModels for consistency 2023-06-03 23:27:01 +02:00
CnC-Robert
ffa8d9c063 feat: hide tabs when 1 bundle is used 2023-06-03 20:12:03 +02:00
Robert
7a5596a281 refactor: PackageManager (#31)
* refactor: refactor `PM`

* feat: use plurals for patch count

* fix: support apk's from storage

* feat: use ViewModel for loading apps and bundles

* fix: fix file selector that has no reason to be broken

* refactor: rename parameter

* refactor: `MainViewModel`

* feat: make all apps use `path`

* build: target java 11
2023-06-03 18:03:14 +00:00
Ax333l
9f46f74357 refactor(logs): use consistent tag 2023-05-26 15:39:56 +02:00
Ax333l
36c4e2dfe0 refactor(di): use constructor DSL for VMs
Instead of doing it manually with viewModel { }
2023-05-26 15:25:08 +02:00
Ax333l
5cb31dbe9d chore(deps): bump revanced-patcher to 9.0.0 2023-05-26 15:17:57 +02:00
Ax333l
399fc98dec feat: better installer ui (#29)
based cossale

Co-authored-by: Aunali321 <aunvakil.aa@gmail.com>
2023-05-26 13:14:21 +00:00
Ax333l
c22371e0c5 feat: patch bundle sources system (#24) 2023-05-26 12:58:14 +00:00
Aunali321
a4842c078b feat: in-app updater (#25) 2023-05-23 11:02:22 +02:00
Aunali321
c332760786 feat(settings screen): add battery optimization notification 2023-05-22 05:17:26 +05:30
Aunali321
ea4247c688 feat(update screen): complete main update screen 2023-05-22 04:14:43 +05:30
Aunali321
fec8c0cc14 feat(about screen): complete about screen 2023-05-22 03:23:14 +05:30
Aunali321
9b585c73fb feat(settings screen): match typography from figma 2023-05-22 02:34:07 +05:30
Aunali321
c695fa525f refactor(settings screen): clean code up a bit 2023-05-22 02:29:19 +05:30
Ax333l
93f3e27d48 fix: dont crash when the bundle cannot be downloaded 2023-05-20 17:14:05 +02:00
Ax333l
52ab7937bd feat(installer): apk signing and installation 2023-05-20 12:30:24 +02:00
Ax333l
762bfa8514 fix(patches selector): copy the selected patches list 2023-05-20 09:47:42 +02:00
Ax333l
ca20996b62 refactor(ui): move PatchItem to the only file where it is used 2023-05-19 21:21:37 +02:00
Ax333l
ad14818de8 refactor(net apis): remove unnecessary interfaces
Having interfaces like that is only really useful if you have unit
tests, which we don't.

Other similar compose projects don't make interfaces either.
Not having them is more readable.
2023-05-19 21:01:33 +02:00
Ax333l
32839656f8 style: run formatter 2023-05-19 20:58:44 +02:00
Patryk Miś
a48faad17a build: updates (#23) 2023-05-19 18:54:21 +00:00
Ax333l
40487923f9 feat: integrate revanced patcher (#22) 2023-05-19 18:49:32 +00:00
CnC-Robert
f1656c6d1e feat: improved dashboard screen 2023-05-18 13:46:59 +02:00
CnC-Robert
4c3dbbd8d5 feat: patches selector screen 2023-05-18 13:44:19 +02:00
CnC-Robert
4088ed747e feat: settings screen 2023-05-18 13:38:02 +02:00
Patryk Miś
bca8df8efd build: updates (#21)
* perf: obsolete sdk check

Signed-off-by: Patryk Mis <foss@patrykmis.com>

* chore: bump dependencies

Signed-off-by: Patryk Mis <foss@patrykmis.com>

---------

Signed-off-by: Patryk Mis <foss@patrykmis.com>
2023-05-13 12:00:06 +00:00
CnC-Robert
54f0a69596 feat: app selector screen 2023-05-06 12:42:30 +02:00
Aunali321
9065c0d260 feat: Dashboard Screen (#18)
* feat: add Dashboard Screen and Sources Screen

* fix: fix tab onClick not working

* refactor: remove AppBar

---------

Co-authored-by: CnC-Robert <CnC.Rob3rt@gmail.com>
2023-04-30 19:27:14 +00:00
Ax333l
cb0150a0f9 fix: gradlew permissions on unix 2023-04-23 14:45:07 +02:00
Patryk Miś
ec0f7e3f7a build: dependency and syntax updates (#17)
* build: Update Gradle to v8.1.1

* build: Bump dependencies

* build: move repo configurations to settings

---------

Co-authored-by: Patryk Mis <24607131+PatrickMis@users.noreply.github.com>
2023-04-23 12:36:52 +00:00
CnC-Robert
e5d898f025 feat: backend 2023-03-18 11:53:25 +01:00
Alexandre Teles
52bdb1cd6a Create README.md 2023-01-31 19:14:18 -03:00
Canny
49f9dfcf95 feat: splash screen 2023-01-28 02:30:39 +03:00
Canny
9536cdcae1 feat: implement navigation 2023-01-28 02:28:39 +03:00
Canny
57e2632f38 feat: implement DI 2023-01-28 02:19:44 +03:00
Canny
b372f7ee84 feat: initialize project 2023-01-28 02:00:52 +03:00
oSumAtrIX
70e8253b63 Migrate to compose branch
This commit was made to allow cherry-picking the first commit of the followup commits according to https://github.com/ReVanced/revanced-manager-compose/issues/65#issue-1806335545
2023-08-26 18:07:57 +02:00
Pun Butrach
d9953b1473 fix(installer): use correct elevation level 2023-08-24 19:00:50 +07:00
aAbed
c6ac898390 fix: universal patches not selectable 2023-08-17 18:25:23 +05:45
Pun Butrach
43f98cec43 build: make variant more identifiable
Release variant will use the "ReVanced Manager" app name, Debug will use "ReVanced Manager Debug"
2023-08-15 21:31:34 +07:00
Pun Butrach
63175cdec6 ci(build): create debug variant instead of release 2023-08-15 20:55:11 +07:00
Pun Butrach
6436a1ec61 build: debug apk come with application suffix
Instead of using the same one as Release, app.revanced.manager.flutter - We add .debug to it, yay, co-installation of two variants!
2023-08-15 20:37:43 +07:00
aAbed
c400619338 feat: disable changing patches selection by default (#1132)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-08-15 16:05:27 +07:00
Ushie
dcd5ba41cf build: add mavenlocal to repositories 2023-08-14 03:40:05 +03:00
Pun Butrach
7525e52fab fix(installer): use correct bg colour for dialog 2023-08-12 15:07:04 +07:00
Pun Butrach
72fd24e624 fix: use i18n translation for installer page 2023-08-12 15:06:17 +07:00
Pun Butrach
11d8f9fd30 refactor: apply changes according to Dart
trailing commas
2023-08-12 14:53:54 +07:00
Pun Butrach
4b0c8cecc8 ci(build): update event trigger
This add ".github/workflows/pr-build.yml" to build on every change to the CI Build to check if there's no error when it got modified.

And also remove "fastlane/**" because that's not related to the ReVanced Manager's code
2023-08-12 13:56:18 +07:00
Dhruvan Bhalara
372ce174c9 fix: overlapping issue in application selection page (#1128) 2023-08-11 19:19:44 +03:00
kitadai31
381daff980 fix: exclude x86 aapt2 binary from release builds (#1126) 2023-08-11 19:19:33 +03:00
Subhamoy Biswas
94acebbebd docs(fixed): replaced some emoji icons, not rendering on chromium based browsers on windows (#1123) 2023-08-11 10:17:46 +07:00
aAbed
f90f6e81ee feat: patch apps without internet (#1114) 2023-08-11 08:11:19 +07:00
Dhruvan Bhalara
97e37f304b refactor: migrate MediaQuery properties to InheritedModel (#1115)
Co-authored-by: Ushie <ushiekane@gmail.com>
2023-08-10 15:25:07 +03:00
Pun Butrach
f5e45ead26 ci(build): don't build on every pull request unrelated to application 2023-08-10 19:14:13 +07:00
Pun Butrach
14f765f4b4 ci(build): don't cache Gradle
Gradle take up so much space in cache that it wouldn't make sense for us to cache it since we are rapidly hitting the cache limit every time.
2023-08-10 19:12:15 +07:00
Pun Butrach
b77d46b2c2 feat(installer): redesign utility options (#1062)
Co-authored-by: Ushie <ushiekane@gmail.com>
2023-08-10 19:02:30 +07:00
Ushie
1442916b20 build: bump version to 1.8.0 2023-08-10 03:01:03 +03:00
Ushie
c6a5f42d23 chore: merge dev to main (#1120) 2023-08-10 03:00:27 +03:00
Ushie
580d50eb8d fix: use right label for auto patch 2023-08-10 00:05:47 +03:00
Ushie
9a66b6e50d fix(root-install): create service and postfs directories if they dont exist (#1116)
Fixes #860
2023-08-09 23:57:09 +03:00
aAbed
acec064cb7 feat(patcher-view): show notice for removed patches that were used previously (#1107) 2023-08-09 22:32:13 +03:00
aAbed
ea05d13a1f fix(patches-selector): New tag showing for old patches (#1113) 2023-08-09 22:31:37 +03:00
Ushie
fd741f2ccf build: bump version to v1.7.0 2023-08-08 03:52:03 +03:00
Ushie
055c52178f chore: merge dev branch to main branch (#1096) 2023-08-08 03:51:05 +03:00
aAbed
722a5859a5 fix: pair integrations and patches updates (#1102) 2023-08-08 03:30:48 +03:00
aAbed
1714c3fa86 feat(patches-selector): show New tag for new patches (#1099) 2023-08-07 22:28:09 +07:00
Pun Butrach
131df28110 docs(managing): update to reflect current changes
The chip was removed because it was not implemented for too long.
2023-08-07 20:13:23 +07:00
aAbed
1be284f8d8 feat: switch to the new ReVanced API (#1101) 2023-08-07 17:14:16 +07:00
Pun Butrach
218e53ae75 refactor(analysis): migrate deprecated rule
deprecated since Dart 2.0, yike
2023-08-06 14:41:15 +07:00
Pun Butrach
264d8d90c4 refactor: apply changes according to analysis
trailing commas, and sort import alphabetically
2023-08-06 14:39:46 +07:00
aAbed
0b529c2629 fix(patches-selector): separate all universal patches to the bottom (#1092) 2023-08-06 12:12:01 +07:00
aAbed
5abcc7191f fix: experimental/universal patches being used even when turned off (#1090)
Co-authored-by: Pun Butrach <pun.butrach@gmail.com>
2023-08-06 12:10:57 +07:00
aAbed
5346f6e1bf fix(patch-item): hide universal patches if not enabled (#1087) 2023-08-05 20:19:36 +07:00
oSumAtrIX
2f471b3de4 fix: use user friendly strings (#1088) 2023-08-05 20:19:03 +07:00
Ushie
3cf06efddf build: bump version to v1.6.1 2023-08-04 03:33:19 +03:00
Ushie
1f4f0a3bb7 build: revert patcher to v11.0.4 2023-08-04 03:32:50 +03:00
Ushie
c07f8eae9b build: bump version to v1.6.0 2023-08-04 00:54:13 +03:00
aAbed
374eb3d06d feat: abort patching process at any time (#1072) 2023-08-04 00:40:08 +03:00
BrentBoyMeBob
fe75b75ddc feat: dpi responsive layout (#361) 2023-08-04 00:38:38 +03:00
Pun Butrach
d3790bf64b refactor: remove unimplemented features (#1061)
Co-authored-by: Ushie <ushiekane@gmail.com>
2023-08-03 23:58:50 +03:00
aAbed
f905a52988 feat: allow control over patches update (#1063)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-08-03 23:23:56 +03:00
aAbed
e55f427b05 build: bump patcher version to v12.1.1 2023-08-04 01:53:19 +05:45
aAbed
0f000fc4d1 build: bump version to v1.5.2 2023-08-04 01:52:24 +05:45
Ushie
a0339e3c19 chore: merge dev to main (#1077) 2023-08-03 05:24:25 +03:00
Ushie
9cfa274d81 build: bump version to v1.5.1 2023-08-03 05:23:47 +03:00
Ushie
8c79f5e371 build: bump patcher to v12.1.0 2023-08-03 05:23:16 +03:00
aAbed
0d716513d7 fix: keystore password dialog showing up before importing (#1068) 2023-08-03 08:36:39 +07:00
Ushie
08f6724060 chore: merge dev branch to main branch (#1060) 2023-08-03 02:20:24 +03:00
Ushie
29daf51e64 build: bump version to 2023-08-03 02:19:14 +03:00
Pun Butrach
b3b2b01c0f ci(build): use pr event trigger for now
I just heard of cache eviction policy :)
2023-08-01 20:20:27 +07:00
Pun Butrach
c3212d0308 ci(build): update event trigger
Run on every PR

Run on every Push, ignore main branch, and ignore tag
2023-08-01 19:32:52 +07:00
Pun Butrach
aaa114ba13 ci(pr-build): reinstate functionality
PR Build was never use because it have to be manually trigger
2023-08-01 19:26:26 +07:00
Pun Butrach
8ca6418630 refactor(settings): improve clarity of the warning dialogs (#1058) 2023-07-31 21:53:23 +07:00
Pun Butrach
95632b7f55 chore(deps): update revanced-patcher to v12.0.0 2023-07-30 11:49:01 +07:00
aAbed
64744b2abf fix: original.apk not found despite existing (#1052) 2023-07-30 10:35:34 +07:00
aAbed
096b315701 fix(patch-item): remove redundant patch version completely (#1059)
https://github.com/ReVanced/revanced-patches/pull/2709
2023-07-29 16:21:30 +07:00
Pun Butrach
c27ca08d3a docs: leftovers from 6495687841 2023-07-29 16:08:54 +07:00
Aunali321
0011222371 chore:fix incorrect version 2023-07-23 14:25:11 +05:30
Aunali321
29db947e25 fix: using non const value in a const variable 2023-07-23 14:04:35 +05:30
Aunali321
fd43ac7581 chore: merge dev branch to main branch (#1032) 2023-07-23 13:53:25 +05:30
Aunali321
e49c19b3cd feat: support older version of android for reddit client patches 2023-07-23 13:51:36 +05:30
Pun
06f0e59967 chore(deps): update libsu to v5.2.0 2023-07-22 13:21:13 +07:00
Pun
c5fc5ee93b build: speed up compilation time
faster build faster build faster build faster build faster build
2023-07-19 18:30:50 +07:00
Dhruvan Bhalara
159c85bd1f fix: close previous dialog when user reset the API URL (#1025) 2023-07-16 21:04:35 +07:00
Pun
2460acf0f4 ci(analyze): don't run when PR is in draft 2023-07-16 17:10:29 +07:00
Pun
6495687841 docs: correct misspelling (EN_US)
This correct spelling to English American, because by default, we use English US.
2023-07-16 16:31:08 +07:00
Pun
d229ccb36c ci(analyze): clarify job name that the job do static analysis & format checking 2023-07-16 16:21:16 +07:00
Pun
4d6a57ddcf ci(analyze): restore run when commit push to dev branch 2023-07-16 16:17:15 +07:00
Aabed Khan
d161d55aaf fix: patched applications not showing at launch (#1031) 2023-07-16 12:46:01 +07:00
Pun
768ad0c9bc chore: merge dev branch to main branch (#1011)
ReVanced Manager v1.4.1
2023-07-15 20:33:30 +07:00
Pun Butrach
29323d4e20 build: update app version to v1.4.1 2023-07-15 12:55:59 +07:00
Pun Butrach
630b22e193 refactor: applies changes from formatter & linter 2023-07-15 12:41:03 +07:00
Aabed Khan
79116f9e67 fix(patched-applications): non-patched app showing on Installed section (#1022) 2023-07-15 08:11:51 +07:00
Aabed Khan
eb58475259 fix: showing Installed when it's actually not (#1021) 2023-07-15 08:10:36 +07:00
ponces
a879ac30fb fix: prevent unsupported operation exception (#1018) 2023-07-14 17:55:04 +07:00
Aabed Khan
c5b0621323 fix(navigation-view): back button closing the app from any page (#1019) 2023-07-13 19:25:48 +05:45
Aabed Khan
0462815014 fix(app-selector): fix text overflow on small screen (#1017) 2023-07-13 00:16:53 +05:45
Aabed Khan
e64318c947 fix(app-selector): fix text overflow on small screen 2023-07-13 00:14:47 +05:45
Pun Butrach
b784482788 chore: update libsu to 5.1.0
This should fixes some issues with root
2023-07-11 19:28:59 +07:00
Aabed Khan
2834e8b348 fix: patchable apps not showing if none of them is installed (#1009) 2023-07-11 17:11:45 +07:00
Aunali321
b23dfd4289 chore: merge dev branch to main branch (#1010) 2023-07-11 01:24:54 +05:30
Aunali321
217d525cb2 build: update app version to v1.4.0 2023-07-11 01:22:57 +05:30
Aunali321
85b166cbda fix: update hardcoded patch name 2023-07-11 01:21:45 +05:30
Pun Butrach
9a57f8b858 ci(build): use correct JDK version
There's no reasons to go higher than JDK 11 since we compile the application using JDK 11
2023-07-10 21:42:24 +07:00
Pun
3bfdc932c2 chore: update app description
👍👍 Patch your favourite apps, right on your device.
2023-07-10 21:27:20 +07:00
Ushie
48c878af21 chore: merge dev branch to main branch (#996) 2023-07-10 16:56:50 +03:00
Pun Butrach
490a7a58fc build: update app version to v1.3.9
ReVanced Manager, 1.3.9 (10030009)

See PR #996
2023-07-10 20:40:40 +07:00
Pun Butrach
567b1a3ace refactor: improve code readability according to linter 2023-07-10 19:45:50 +07:00
Pun Butrach
6a45db8a38 refactor: improve code readability according to formatter 2023-07-10 19:36:50 +07:00
Pun
b272988929 build: always compile with the latest SDK supported by Flutter
`targetSdkVersion` is still the same, we want to test the application first before bumping up to latest.
2023-07-10 18:43:07 +07:00
Aabed Khan
9828857570 fix: fixed typo 2023-07-10 12:16:51 +05:45
KobeW50
ecb54d8e44 docs: improve clarity of speech in issue template (#1005)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-07-09 23:15:20 +02:00
Aabed Khan
344717b021 fix: app crash after custom source (#1003) 2023-07-08 23:07:19 +05:45
Aabed Khan
da6cf585c0 fix: app crash after custom source 2023-07-08 22:26:31 +05:45
Pun Butrach
9e93177afd feat: show warning dialog when resetting stored patches
This prevent user from accidentally resetting stored patches by showing
them warning dialog.
2023-07-08 11:01:10 +07:00
Pun Butrach
16318efb01 refactor: seperate translation string by context 2023-07-08 10:45:13 +07:00
Pun Butrach
e83e13b6d4 refactor: fix more problem with analyser
Missing trailing comma in app_selector_view
2023-07-07 22:21:22 +07:00
Pun Butrach
7c2c695d88 refactor: apply changes from analyser 2023-07-07 22:15:12 +07:00
Pun Butrach
c7b227529d chore: disable unnecessary tooltip
Remove tooltip in Navigation View, there's no impact to accessibility.

Tested using: Android TalkBack
2023-07-07 22:11:13 +07:00
oSumAtrIX
14f49e9d30 docs: fix description for next page 2023-07-05 15:43:40 +02:00
Aabed Khan
1875c4ee73 fix: update button being clickable when offline (#987) 2023-07-05 19:59:53 +07:00
Pun Butrach
76c68baa1f build: update gradle to v7.6.2 2023-07-01 18:21:49 +07:00
Aunali321
68876a4414 build: bump version to v1.3.8 and patcher dep 2023-07-01 14:33:25 +05:30
Ushie
26d7e5b60f build: bump version to v1.3.7 and patcher dep 2023-07-01 02:46:43 +03:00
Ushie
e78af6ae99 chore: merge dev to main (#976) 2023-07-01 02:41:57 +03:00
Aabed Khan
6fe05cd86e feat: show all the unseen changelogs on changelog section (#970) 2023-07-01 02:41:03 +03:00
Aabed Khan
4100d7a391 fix: different message when trying to patch spilt apk (#973) 2023-07-01 02:40:30 +03:00
Ushie
c1cc812ea4 build: bump version to v1.3.6 2023-06-24 19:17:59 +03:00
Ushie
9663e3f0f4 chore: merge dev branch to main branch (#945) 2023-06-24 19:16:22 +03:00
Aabed Khan
941f618153 fix(app-selector): remove direct use of strings (#944) 2023-06-23 16:39:12 +03:00
Aabed Khan
716a30bf7b fix: experimental patches stay selected when toggled off (#946) 2023-06-23 16:37:23 +03:00
Aabed Khan
d051ae576b feat(updater): download successful dialog (#938) 2023-06-23 16:36:36 +03:00
ponces
35e99cb014 feat(mount): use /data/adb/revanced again and ensure migration scenario (#948) 2023-06-23 01:03:03 +03:00
taku
af054fba49 docs: improve clarity of footnotes [skip ci] (#950) 2023-06-17 14:48:57 +02:00
Aabed Khan
58d837d641 feat(app-selector): Improve app item UI to avoid overflow issues (#943) 2023-06-16 10:04:55 +03:00
Aabed Khan
6cc1bd21cd fix(updater): ability to start again after cancelling (#937) 2023-06-16 10:04:07 +03:00
oSumAtrIX
cebfa7c8ae docs: simplify steps 2023-06-16 05:09:52 +02:00
oSumAtrIX
e2d7ab8f8f chore: fix broken docs link 2023-06-15 16:42:09 +02:00
Aabed Khan
ec77987fcd feat(app-selector): improve skeleton UI (#939) 2023-06-15 12:57:39 +03:00
ponces
b161608d02 feat(patches-selector): improve disabled card UI (#941) 2023-06-15 12:54:49 +03:00
Aabed Khan
5e7458ff1c fix: import patches selects unsupported patches (#942) 2023-06-14 21:34:11 +07:00
Pun
ed06aaa1f5 docs(readme): fix invalid url for building manager from source
📜 fix invalid URL for building manager from source.

Old: https://github.com/revanced/revanced-manager/blob/docs/docs/5_building-from-source.md
New: https://github.com/revanced/revanced-manager/blob/main/docs/4_building.md
2023-06-14 19:52:10 +07:00
Aunali321
13b7179941 fix: fix not asking for permission 2023-06-12 09:56:49 +05:30
Aunali321
da0d88d86f build: bump patcher 2023-06-12 09:08:29 +05:30
Aunali321
b7347c312a build: bump version to v1.3.4 2023-06-12 08:59:49 +05:30
Aunali321
c876f2f7e3 feat: add permission to manage storage 2023-06-12 08:59:14 +05:30
Aunali321
adad5fd8ff build: bump version to v1.3.3 2023-06-12 07:02:49 +05:30
Aunali321
2aaa7ae8c9 chore: merge dev to main (#935) 2023-06-12 07:01:12 +05:30
Aunali321
1f64ea37bd fix: using wrong string 2023-06-12 06:59:43 +05:30
Aunali321
cac1525da0 build: bump patcher 2023-06-12 06:02:16 +05:30
Aunali321
1ad906fedc refactor: improve code 2023-06-12 06:01:57 +05:30
Aabed Khan
20ffef39a3 fix: update button being shown as clickable on launch (#932) 2023-06-12 05:55:53 +05:30
Aabed Khan
185460c054 chore(fastlane): update description (#933)
Co-authored-by: Ushie <ushiekane@gmail.com>
2023-06-12 03:21:33 +03:00
Aabed Khan
0079e74d77 feat: clarify suggested version in app list (#934)
Co-authored-by: Aunali321 <48486084+Aunali321@users.noreply.github.com>
2023-06-12 05:35:02 +05:30
oSumAtrIX
a8e019482f ci: add workflow to update documentation repository 2023-06-10 23:41:36 +02:00
Yaros
f01b8e47aa fix: aborting message changed (#928)
Change aborting message from "aborting..." to "aborted..."

----------------------
Co-authored-by: Ushie <github@ushie.dev>
Co-authored-by: Ushie <ushiekane@gmail.com>
2023-06-09 17:34:55 +07:00
Pun
e43dfb7599 docs(troubleshooting): fix markdown styling (#929)
`docs`: `84a9168` - Self-explanatory, fix markdown styling issue
2023-06-09 17:24:31 +07:00
Ushie
6b8cfe2b49 build: bump version to v1.3.2 2023-06-09 11:42:06 +03:00
Ushie
7f7b14bae3 fix: use correct variable name for armv7 check 2023-06-09 11:40:54 +03:00
Ushie
810b02d9fd build: bump version to v1.3.1 2023-06-09 10:45:22 +03:00
Ushie
62813145b2 chore: merge dev to main (#926) 2023-06-09 01:59:18 +03:00
Ushie
4877058253 chore(fastlane): add banner 2023-06-09 01:58:02 +03:00
Ushie
2a9fd3abb8 chore(fastlane): add missing directory 2023-06-09 01:57:49 +03:00
Ushie
a244f7b598 chore: merge dev to main 2023-06-08 21:31:41 +03:00
Ushie
5396457ad5 chore: move fastlane to correct directory 2023-06-08 21:30:44 +03:00
Ushie
0186b6ea61 chore: merge dev to main (#924) 2023-06-07 20:18:21 +03:00
fe
f6e99f7e88 fix: return fetched patch version if non default patch repo is used (#922) 2023-06-07 20:16:25 +03:00
Pun
c24a3828be ci(analyze): don't run when pushed to repository (#920) 2023-06-07 20:15:43 +03:00
Pun
2e38a4567a feat: clarify architecture in about section
This commit changes `Arch` to `Supported Arch(s)`
2023-06-07 20:13:42 +03:00
Yaros
67c5d67a61 feat: update icons for the new logo
fixed #918
2023-06-07 20:10:14 +03:00
Aunali321
9592dde534 feat: add fastlane for F-Droid (#889)
Co-authored-by: Ushie <ushiekane@gmail.com>
2023-06-07 19:59:17 +03:00
oSumAtrIX
d030b0af70 docs: init (#911)
Co-authored-by: afn <_@afn.lol>
2023-06-07 12:01:36 +02:00
MrAngelos6
4ccb9ac94d fix: remove redundant "v" in the downloader screen (#895) 2023-05-26 13:54:52 +03:00
Ushie
8af62b917c build: bump version to 1.3.0 (#892) 2023-05-24 23:33:04 +03:00
Steven
311f114132 chore: update v1.3.0 2023-05-24 21:46:00 +02:00
Ushie
d015bd03f7 chore: merge dev to main (#891) 2023-05-24 22:17:16 +03:00
oSumAtrIX
a61b9de0fa chore(deps): bump revanced-patcher to 9.0.0 2023-05-24 02:02:59 +02:00
Ushie
ef1b283917 chore(deps): bump revanced-patcher to 8.0.0 (#880) 2023-05-24 01:07:22 +05:30
Ushie
c677f00105 build: bump version to v1.2.0 2023-05-20 02:30:18 +03:00
Ushie
8d2f778dfe chore: merge dev to main (#881) 2023-05-20 02:28:58 +03:00
Aunali321
c549d102f6 build: migrate to dart 3 (#871) 2023-05-20 04:07:53 +05:30
Aunali321
39a9ee4e9d chore: remove coreLibraryDesugaring (#873) 2023-05-20 04:05:46 +05:30
Sangam Shrestha
a27dc6ad1c feat: migrate to dart3 2023-05-19 14:23:48 +05:45
kitadai31
8ccb75fc8d chore: remove coreLibraryDesugaring 2023-05-17 15:38:03 +09:00
Ushie
8fc86dbe02 feat: allow selecting installed if app is full apk 2023-05-13 04:54:35 +03:00
Sebok Andras
359f052608 fix: export keystore not working in some conditions (#862) 2023-05-12 19:36:47 +03:00
Hokora Yinphine
4150e2265c fix: use correct version in update download dialog (#859) 2023-05-10 13:23:02 +03:00
Dhruvan Bhalara
b803ce7435 fix: system navigation overlapping UI (#853) 2023-05-10 13:18:51 +03:00
Aunali321
289c6cd7a9 chore: merge dev to main (#857) 2023-05-08 21:46:33 +05:30
Aunali321
31fc7b74c2 build: bump version to v1.1.0 2023-05-08 21:38:19 +05:30
Aunali321
3e565f25be fix(appselector): closing dialog closes app selector 2023-05-08 21:27:07 +05:30
Aunali321
e509be4e21 chore(deps): bump patcher to 7.1.1 2023-05-08 21:19:45 +05:30
Aunali321
170fc537ac fix: fix armv7 dialog shown for x86, x86_64 2023-05-07 04:14:57 +05:30
Aunali321
3fe5882145 feat: remove cronet 2023-05-06 05:39:46 +05:30
Aunali321
a290791410 chore: merge dev to main (#844) 2023-05-06 03:26:14 +05:30
Pun
2ebd38ff68 feat: add checksums verification to Gradle (#813) 2023-05-03 21:38:47 +03:00
Dhruvan Bhalara
cd987a5b19 fix: broken filename when saving files with the same name (#837) 2023-05-03 21:34:30 +03:00
Ushie
7f1dab7ee1 ci: temporarily restore old release workflow 2023-05-02 17:50:07 +03:00
SodaWithoutSparkles
bed3945aa5 feat: clarify warning and consequences for ARMv7 users (#836) 2023-05-02 16:41:11 +07:00
Aunali321
15a32a18b7 fix: fix broken manager update implmentation 2023-04-30 17:38:08 +07:00
Palm
d2e8e7dd5d chore: comply with review changes 2023-04-30 01:03:36 +07:00
Palm
ce12ec89c4 ci(release): automatically bump version codes 2023-04-29 20:53:54 +07:00
EvadeMaster
b286444ad9 fix(i18n): update translation for refreshSucess 2023-04-29 20:43:02 +07:00
EvadeMaster
941263102d refactor: change name from "recommendedVersion" to "suggestedVersion" 2023-04-29 20:43:02 +07:00
Palm
e2ed296dc7 chore(deps): constrain get_it to 7.2.0 2023-04-29 19:46:07 +07:00
Ushie
cfc866bef2 feat: change continue anyways to cancel 2023-04-29 15:37:30 +03:00
Sebok Andras
affba669ce feat: add continue anyway button to select from storage dialog (#810) 2023-04-29 15:36:25 +03:00
Palm
7230152ab8 chore: fix issues with gitignore [skip ci] 2023-04-29 17:42:19 +07:00
Palm
21fee7171f chore: update pubspec version
skip-checks: true
2023-04-29 15:40:25 +07:00
SodaWithoutSparkles
ad17995f28 feat: improve suggested app version text (#822) 2023-04-28 17:41:28 +03:00
Yaros
ac830cbe7f fix: resized monochrome icon to match the original (#789)
cherry-pick from 6281ae82876c69ff4194a782e4b08b398a1285d6
2023-04-27 18:12:48 +07:00
Aunali321
65da6af3f9 fix: update pubspec version 2023-04-21 14:56:31 +03:00
oSumAtrIX
3d90bf7588 ci: bypass push permission on protected branches with owner PAT 2023-04-21 14:55:29 +03:00
EvadeMaster
62ef1c88fe feat: resetting source to default dismiss the sources pop-up (#797)
* feat: resetting source to default dismiss the sources pop-up

* chore: format using `dart format`
2023-04-21 00:29:37 +05:30
Aunali321
d6918920b6 chore: add missing translations 2023-04-20 23:53:24 +05:30
Aunali321
cdfb09fbfa feat: warning for armv7 devices 2023-04-20 23:20:30 +05:30
Aunali321
bb681e31c9 feat: disable selecting installed apps for nonroot 2023-04-20 22:25:29 +05:30
Aunali321
c7483936ec docs: remove alpha disclaimer 2023-04-20 05:07:46 +05:30
Aunali321
0a1f2da33d feat: appreciation message for new contributors 2023-04-20 05:04:37 +05:30
Aunali321
f5aafdb7d6 feat: progress bar for manager updates 2023-04-20 04:45:46 +05:30
Aunali321
c9adf1c492 style: sort imports 2023-04-19 01:32:43 +05:30
Aunali321
4c9cb560e3 feat: auto select default patches 2023-04-19 01:21:08 +05:30
Yaros
f0b028279c fix: open contributor links externally (#791) 2023-04-18 19:46:16 +05:30
Aman Sikarwar
197770b68b chore: update dependencies (#772)
* chore: updated some dependencies

* refactor: reimplemented cache interceptor

* Revert "Updated dependencies & migrated breaking changes"

This reverts commit e6743b0d6b2552fdbf1c99d23e158e682362dd5d.

* chore: migrated flutter_local_notifications

* revert: reimplemented cache interceptor
2023-04-18 19:45:29 +05:30
EvadeMaster
37b583f560 feat: trim extra space when setting custom source (#771) 2023-04-18 17:15:04 +07:00
Sebok Andras
dca2d4fe12 feat: add option to import/export keystore (#776)
* feat: add option to import/export keystore

* change the order of import/export keystore buttons

* feat: add option to change the keystore password
2023-04-18 15:08:10 +05:30
Aunali321
3b677f8ae3 feat: improve ux (#752)
* feat: restart app toast when changing sources, api url

* fix: potentially fix manager stuck on black screen

* feat: remove select all patches chip

* feat: show all apps and recommended versions

* chore(i18n): remove unused strings

remove unused strings left out in 7e05bca

* feat: select install type before patching

* feat: update patches button (#782)

* feat: update patches button

* feat: show toast when force refresh

* chore: don't translate "ReVanced Manager" and "ReVanced Patches"

* Revert "feat: select install type before patching"

This reverts commit 74e0c09b54.

* feat: rename recommended patches to default patches

* feat: add missing localization

* feat: display restart app toast for resetting source

---------

Co-authored-by: EvadeMaster <93124920+EvadeMaster@users.noreply.github.com>
2023-04-18 13:27:26 +05:30
Palm
0b952578d1 ci(release): update semantic-release 2023-04-02 02:37:49 +07:00
EvadeMaster
054afbbedd feat: confirmation dialog for deleting keystore (#764)
* feat: confirmation dialog for deleting keystore

* refactor(i18n): apply suggestion from code-reviewer

Co-authored-by: Ushie <github@ushie.dev>

* refactor: apply suggestion from code-reviewer

Co-authored-by: Mipirakas <borismichiels@gmail.com>

---------

Co-authored-by: Ushie <github@ushie.dev>
Co-authored-by: Mipirakas <borismichiels@gmail.com>
2023-04-01 21:02:28 +07:00
Palm
866a6e4a44 chore(CHANGELOG): reset changelog 2023-03-30 23:29:26 +07:00
Palm
8ea7dd478b ci(release): update node dependencies 2023-03-30 23:20:31 +07:00
EvadeMaster
7839252934 ci(analyze): only run when necessary (#766)
* ci(analyser): only run on lib/`.dart` changes

* ci(analyser): runs on workflow changes

* ci(analyze): run on all dart file changes

---------

Co-authored-by: Palm <palmpasuthorn@gmail.com>
2023-03-29 20:51:08 +03:00
EvadeMaster
fa4063220f ci: dart analyser (#761)
* ci: dart analyser

* ci(analyser): clarify the dart analysing step

* refactor: ignore generated files

* ci(analyser): apply suggestion from code-reviewer

Co-Authored-By: Palm <palmpasuthorn@gmail.com>

* ci(analyser): apply suggestion from code-reviewer

Co-Authored-By: Palm <palmpasuthorn@gmail.com>

* ci(analyser): apply suggestion from code-reviewer

Co-authored-by: Palm <palmpasuthorn@gmail.com>

---------

Co-authored-by: Palm <palmpasuthorn@gmail.com>
2023-03-28 15:47:34 +07:00
Palm
d214a02abd ci(release): fix argument parsing of npm exec 2023-03-26 23:02:57 +07:00
Palm
d1c12edd1b ci(release): use appropriate npm commands for ci environment 2023-03-26 23:02:57 +07:00
Palm
ded1a44c37 ci(release): fix step not moving artifact to accessible path 2023-03-26 23:02:57 +07:00
Ushie
790a6cd1e3 ci(release): remove unnecessary variables in flutter build step 2023-03-26 18:57:27 +03:00
EvadeMaster
a79f883a0f ci: use caching to speed up workflows (#760)
Use caching to speed up workflows: 9-14 minutes (ish) to 6-8 minutes (ish)

Commits:
* ci(release): use GitHub cache

* ci(release): restore signing
2023-03-26 20:02:56 +07:00
Palm
d9c5a540a3 ci(release): fix wrong artifact name and ci not uploading build 2023-03-24 01:01:44 +07:00
Palm
276f33b9ec ci: use semantic-release (#746) 2023-03-23 17:34:52 +01:00
Ushie
ded59d2da0 feat(ci): update crowdin workflow to use new main branch 2023-03-20 22:39:29 +03:00
Ushie
62f7a820d8 feat: remove notice about stale development [skip ci] 2023-03-20 18:03:58 +03:00
Ushie
7063ffa013 build: bump version to v0.0.57 2023-03-14 21:00:48 +03:00
Ushie
bf4dc3c095 chore: bump stacked
stacked: ^3.0.0 -> ^3.2.0
stacked_generator: ^0.8.0 -> ^1.0.0
stacked_services: ^0.9.3 -> ^1.0.0
2023-03-14 21:00:28 +03:00
EvadeMaster
c10e5848bf Merge pull request #707 from revanced/dev
chore: merge branch `dev` to `flutter`
2023-03-14 22:07:35 +07:00
EvadeMaster
92a3b0d6e0 feat(style): use native switch & chip (#732)
* chore: remove useless themedata

* feat(style): new switch

* feat(style): use native chip components

* chore: remove unused import

* feat(accessibility): set tooltip

* chore: remove unneeded themedata

* chore: fix theme

* feat(i18n): add 3 new strings

* feat(style): correct material 3 theme on nondynamic
2023-03-14 21:53:42 +07:00
Aunali321
b475bd25c8 build: remove env setup step 2023-03-11 23:01:26 +05:30
Aunali321
d318224a6f fix: black screen after resetting custom sources 2023-03-06 18:08:48 +05:30
Aunali321
0074fee865 build: new ci (#731)
New Build CI

Commits:
* buid: re-do ci

* build: ignore tags

* build: get the latest flutter version automatically && formatting

---------

Co-authored-by: EvadeMaster <93124920+EvadeMaster@users.noreply.github.com>
2023-03-05 16:23:51 +07:00
Aunali321
5617535a63 refactor: remove sentry and crowdin (#730)
We no longer use sentry and crowdin.
2023-03-05 16:12:46 +07:00
EvadeMaster
68ccefc59f revert: "refactor: update deprecated and minor code refactors (#710)"
This reverts commit 6829d3cdea.

Signed-off-by: EvadeMaster <93124920+EvadeMaster@users.noreply.github.com>
2023-03-03 18:06:24 +07:00
Ushie
6d60541626 chore(deps): meet patcher breaking changes 2023-03-03 03:11:44 +03:00
EvadeMaster
a635e5b8d0 chore: addFiles -> addIntegrations (#725)
fix #721
2023-03-02 14:51:35 +07:00
EvadeMaster
48a10440fe ci(build): remove environment on PR build 2023-03-02 11:06:15 +07:00
EvadeMaster
8e3ba88318 chore: bump gradle 7.5-rc.1 -> 7.6.1 (#717)
* chore: upgrade gradle from 7.5-rc.1 -> 7.6.1

* chore: remove unrelated changes
2023-02-27 19:26:10 +07:00
EvadeMaster
ab8fccc544 chore(deps): bump patcher version from 6.4.3 -> 7.0.0 2023-02-27 19:19:19 +07:00
EvadeMaster
8319dc9164 fix: improperly sized monochrome icon (#715) 2023-02-27 19:07:44 +07:00
Sailesh Dahal
6829d3cdea refactor: update deprecated and minor code refactors (#710)
Improve code readability & additional refactoring

Commits:
chore: exclude generated from analyzer

refactor: add SharedPreferences to locator

refactor: access shared pref from locator, and code refactor

refactor: remove unwanted `await`

refactor: remove `const` from `CacheConfig`
2023-02-27 19:06:05 +07:00
EvadeMaster
3ae4d69110 chore: migrate deprecation code && code cleanup (#708)
Fixes all issues in `flutter analyze`.
<Reviewed>

Commits:
* chore: migrate deprecated text style

* chore: migrate `toggleableActiveColor` to individual theme

* chore: don't use 'BuildContext's across async gaps
2023-02-20 16:53:53 +07:00
LisoUseInAIKyrios
dc665f227e fix: use high resolution adaptive icons (#675)
Use high-resolution icons instead of the low-resolution ones on ReVanced Manager.

Commits:
* High resolution adaptive icons, built using revanced-logo-no-background.svg

Same icons currently used for ReVanced YouTube.

* tweak background color to match revanced-logo-no-background.svg

* recreated foreground using 'revanced-logo-shape.svg'

* updated full resolution icons, using same ratio as original SVG

* updated icons with gradient border
2023-02-17 19:28:01 +07:00
EvadeMaster
a83496568f chore: code cleanup (#681)
Improve the readability of the code.

Commits:
* chore: correct typos `fragement` to `fragment`

* chore: put a single newline at end of file.
2023-02-17 18:53:23 +07:00
Alex
12d25570af fix: Long patch description truncated (#702)
fix: long patch description truncated (#702)

Allow flexible height
2023-02-14 18:42:24 +07:00
EvadeMaster
378c947654 chore: bump version to v0.0.56 2023-02-12 13:04:34 +07:00
EvadeMaster
bd39a3140e feat: fix patch bundle version no longer displayed (#686) 2023-02-12 00:02:30 +07:00
Boris Michiels
7d3ca3dec1 fix: display patches version on first load (#687) 2023-02-12 00:00:01 +07:00
oSumAtrIX
1cb556c8f8 chore: bump version to 0.0.55 2023-02-11 23:59:53 +07:00
oSumAtrIX
8c8f96de1c build: bump patcher version 2023-02-11 23:59:47 +07:00
EvadeMaster
318cd87a9a feat(style): use the correct m3 theming (partially) (#680) 2023-02-07 15:46:29 +03:00
Aunali321
5d63d5c2d3 feat: potentially fix apps disappearing when update is available (#674) 2023-01-31 15:42:00 +03:00
Ushie
7d347fccc6 build: bump version to v0.0.54 2023-01-30 15:57:06 +03:00
Jay Gajjar
a54ca799b9 feat: update rules of analysis_options.yaml. and solved all problems (#665)
* update rules of analysis_options.yaml. and solved all problems

* refactor: fix remaining problems

---------

Co-authored-by: Ushie <ushiekane@gmail.com>
2023-01-30 15:35:06 +03:00
Mipirakas
f5bc1a996f feat: remove select all icon from searchbar (#669) 2023-01-30 15:13:25 +03:00
Mipirakas
8591bc4d01 chore: update cr_file_saver (#668)
Co-authored-by: Ushie <github@ushie.dev>
2023-01-30 15:11:31 +03:00
EvadeMaster
40888c07f3 feat: fix overflow text & separate version from patch name (#666)
* chore: Add note

* feat: Fix overflow text & seperate version from patch title

* feat: Fix overflow text & separate version from patch name
2023-01-30 15:07:25 +03:00
Mipirakas
1c965c3788 refactor: cleanup remember patches feature (#630) 2023-01-30 15:03:55 +03:00
Bennett
4df690c2a2 feat: monochrome icon + predictive back gesture (#591)
* Add monochrome icon

* Enable predictive back gesture

* feat: monochrome icon + predictive back gesture
2023-01-30 01:23:56 +03:00
Abhiram
d6abb61e2b ci(build): update workflow actions (#662)
- Bump upload-artifact to v3

- Update crowdin/github-action according to new versioning format [https://github.com/crowdin/github-action/releases/tag/v1.6.0]
2023-01-29 23:56:13 +03:00
oSumAtrIX
3434c862e9 feat: improve note [skip ci] 2023-01-28 07:49:57 +01:00
EvadeMaster
ea8af926fa chore: update broken documentation link (#659)
* chorus: fix invalid documentation link

* chorus: Update broken documentation link
2023-01-22 16:18:41 +03:00
EvadeMaster
c3df48174c feat: warn user for selecting all patches (#649) 2023-01-21 16:37:28 +01:00
oSumAtrIX
f1e60f96c4 chore: bump version to 0.0.53 2023-01-18 22:07:00 +01:00
oSumAtrIX
cdd852678b build: bump patcher version 2023-01-18 22:07:00 +01:00
Ushie
bf518b5467 bump: kotlin gradle plugin 2023-01-18 22:07:00 +01:00
oSumAtrIX
ffd53fab26 feat: clarify acknowledgement label (#608) 2023-01-14 20:23:49 +03:00
oSumAtrIX
5aad7dad35 chore: fix incorrect wording 2023-01-12 21:03:11 +01:00
oSumAtrIX
b1c1a9f4e1 feat: stale development notice [skip ci] 2023-01-07 14:24:43 +01:00
oSumAtrIX
d847a8e0b2 build: bump version to v0.0.52 2022-12-19 01:39:48 +01:00
oSumAtrIX
9668730b5d build: bump patcher version (#610) 2022-12-19 01:35:58 +01:00
Ushie
dc049cf26a New Crowdin translations by Github Action (#601)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-12-16 22:41:26 +03:00
Ushie
82c2b2f128 build: bump version to v0.0.51 2022-12-15 21:24:06 +03:00
Ushie
5f81d65911 feat: sort by amount of patches, display patches count, setting to enable universal patches (#593)
* feat: sort by amount of patches

* feat: display patches count in application card

* feat: setting to enable universal patches
2022-12-15 23:35:45 +05:30
Ushie
19f990c564 build: bump version to v0.0.50 2022-12-14 14:17:38 +03:00
Ushie
62467007b2 Revert "feat: display app's patch count in appcard"
This reverts commit 8d4e4ba6c9.
2022-12-14 13:20:17 +03:00
Ushie
d7624e5e1f Revert "feat: filter apps by patch count"
This reverts commit d78868b462.
2022-12-14 13:19:59 +03:00
oSumAtrIX
4505f10e50 build: bump version number 2022-12-14 06:04:42 +01:00
oSumAtrIX
3ce3df5e19 build: bump patcher version 2022-12-14 06:04:10 +01:00
Ushie
8d4e4ba6c9 feat: display app's patch count in appcard 2022-12-14 02:12:57 +03:00
Ushie
d78868b462 feat: filter apps by patch count 2022-12-14 01:52:06 +03:00
Canny
01a681ad00 build: bump version to v0.0.48 2022-12-12 22:34:39 +03:00
Canny
adfeb61eab fix: print patch fail cause if message is null 2022-12-12 22:32:11 +03:00
394 changed files with 19644 additions and 15441 deletions

3
.env
View File

@@ -1,3 +0,0 @@
sentryDSN=
apiKey=
appId=

View File

@@ -1,120 +1,61 @@
name: 🐞 Bug report
description: Report a very clearly broken issue.
title: 'bug: <title>'
labels: [bug]
body:
- type: markdown
attributes:
value: |
# ReVanced Manager bug report
Important to note that your issue may have already been reported before. Please check for existing issues [here](https://github.com/revanced/revanced-manager/labels/bug).
- type: dropdown
attributes:
label: Type
options:
- Error while running the manager
- Error at runtime
- Cosmetic
- Other
validations:
required: true
- type: textarea
attributes:
label: Bug description
description: How did you find the bug? Any additional details that might help?
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Add the steps to reproduce this bug including your environment.
placeholder: Step 1. Download some files. Step 2. ...
validations:
required: true
- type: textarea
attributes:
label: Android version
description: Android version used.
validations:
required: true
- type: textarea
attributes:
label: Manager version
description: Manager version used.
validations:
required: true
- type: textarea
attributes:
label: Target package name
description: App you tried to patch.
validations:
required: true
- type: textarea
attributes:
label: Target package version.
description: Version of the app you tried to patch.
validations:
required: true
- type: dropdown
attributes:
label: Installation type
options:
- Non-root
- Root
validations:
required: true
- type: textarea
attributes:
label: Patches selected.
description: Patches you selected for the app.
validations:
required: true
- type: textarea
attributes:
label: Device logs (exported using Manager settings).
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
validations:
required: true
- type: textarea
attributes:
label: Installer logs (exported using Installer menu option) [unneeded if issue is not during patching].
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
validations:
required: false
- type: textarea
attributes:
label: Screenshots or videos
description: Add screenshots or videos that show the bug here.
placeholder: Drag and drop the screenshots/videos into this box.
validations:
required: false
- type: textarea
attributes:
label: Solution
description: If applicable, add a possible solution.
validations:
required: false
- type: textarea
attributes:
label: Additional context
description: Add additional context here.
validations:
required: false
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your issue will be closed if you haven't done these steps.
options:
- label: I have searched the existing issues and this is a new and no duplicate or related to another open issue.
required: true
- label: I have written a short but informative title.
required: true
- label: I filled out all of the requested information in this issue properly.
required: true
- label: The issue is related solely to the ReVanced Manager
required: true
name: 🐞 Bug report
description: Create a new bug report.
title: 'bug: <title>'
labels: [bug]
body:
- type: markdown
attributes:
value: |
# ReVanced Manager bug report
Please check for existing issues [here](https://github.com/revanced/revanced-manager/labels/bug) before creating a new one.
- type: textarea
attributes:
label: Bug description
description: |
- Describe your bug in detail
- Add steps to reproduce the bug if possible (Step 1. Download some files. Step 2. ...)
- Add images and videos if possible
- List selected patches if applicable
validations:
required: true
- type: textarea
attributes:
label: Version of ReVanced Manager and version & name of application you tried to patch
validations:
required: true
- type: dropdown
attributes:
label: Installation type
options:
- Non-root
- Root
validations:
required: false
- type: textarea
attributes:
label: Device logs
description: Export logs in ReVanced Manager settings.
render: shell
validations:
required: true
- type: textarea
attributes:
label: Patcher logs
description: Export logs in "Patcher" screen.
render: shell
validations:
required: false
- type: checkboxes
attributes:
label: Acknowledgements
description: Your issue will be closed if you don't follow the checklist below!
options:
- label: This request is not a duplicate of an existing issue.
required: true
- label: I have chosen an appropriate title.
required: true
- label: All requested information has been provided properly.
required: true
- label: The issue is solely related to the ReVanced Manager
required: true

View File

@@ -1,52 +1,42 @@
name: ⭐ Feature request
description: Create a detailed feature request.
title: 'feat: <title>'
labels: [feature-request]
body:
- type: dropdown
attributes:
label: Type
options:
- Functionality
- Cosmetic
- Other
validations:
required: true
- type: textarea
attributes:
label: Issue
description: What is the current problem. Why does it require a feature request?
validations:
required: true
- type: textarea
attributes:
label: Feature
description: Describe your feature in detail. How does it solve the issue?
validations:
required: true
- type: textarea
attributes:
label: Motivation
description: Why should your feature should be considered?
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: Add additional context here.
validations:
required: false
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your issue will be closed if you haven't done these steps.
options:
- label: I have searched the existing issues and this is a new and no duplicate or related to another open issue.
required: true
- label: I have written a short but informative title.
required: true
- label: I filled out all of the requested information in this issue properly.
required: true
- label: The issue is related solely to the ReVanced Manager
required: true
name: ⭐ Feature request
description: Create a new feature request.
title: 'feat: <title>'
labels: [feature request]
body:
- type: markdown
attributes:
value: |
# ReVanced Manager feature request
Please check for existing feature requests [here](https://github.com/revanced/revanced-manager/labels/bug) before creating a new one.
- type: textarea
attributes:
label: Feature description
description: Describe your feature in detail.
validations:
required: true
- type: textarea
attributes:
label: Motivation
description: Explain why the lack of it is a problem.
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: In case there is something else you want to add.
validations:
required: false
- type: checkboxes
attributes:
label: Acknowledgements
description: Your issue will be closed if you don't follow the checklist below!
options:
- label: This request is not a duplicate of an existing issue.
required: true
- label: I have chosen an appropriate title.
required: true
- label: All requested information has been provided properly.
required: true
- label: The issue is solely related to the ReVanced Manager
required: true

2
.github/config.yaml vendored Normal file
View File

@@ -0,0 +1,2 @@
firstPRMergeComment: >
❤️ Thank you for contributing to ReVanced Manager. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.

View File

@@ -1,55 +0,0 @@
name: "Android CI Actions"
on:
push:
branches:
- "**"
tags-ignore:
- "v*" # Ignore tags that start with "v" (e.g. v1.0.0) because they are handled by release-build.yml
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up JDK 12
uses: actions/setup-java@v3
with:
java-version: '12'
distribution: 'zulu'
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- name: Set environment variables
run: echo $SECRETS | base64 -d > lib/utils/environment.dart
env:
SECRETS: ${{ secrets.SECRETS }}
- name: Set up Flutter
run: flutter pub get
- name: Generate files with Builder
run: flutter packages pub run build_runner build --delete-conflicting-outputs
- name: Build with Flutter
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
run: flutter build apk
- name: Sign APK
id: sign_apk
uses: ilharp/sign-android-release@v1
with:
releaseDir: build/app/outputs/apk/release
signingKey: ${{ secrets.SIGNING_KEYSTORE }}
keyStorePassword: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
keyAlias: ${{ secrets.SIGNING_KEY_ALIAS }}
keyPassword: ${{ secrets.SIGNING_KEY_PASSWORD }}
- name: Add version to APK
run: mv ${{ steps.sign_apk.outputs.signedFile }} revanced-manager-${{ env.RELEASE_VERSION }}.apk
- name: Upload APK
uses: actions/upload-artifact@v2
with:
name: revanced-manager-${{ env.RELEASE_VERSION }}
path: revanced-manager-${{ env.RELEASE_VERSION }}.apk

View File

@@ -1,46 +0,0 @@
name: Sync Crowdin translations
on:
push:
branches:
- "flutter"
paths:
- "assets/i18n/en_US.json"
- ".github/workflows/crowdin.yml"
schedule:
- cron: "0 0 * * *" # daily
workflow_dispatch:
jobs:
sync-crowdin:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Crowdin
uses: crowdin/github-action@1.5.0
with:
config: crowdin.yml
upload_sources: true
upload_translations: false
download_translations: true
push_translations: true
create_pull_request: false
localization_branch_name: i18n_flutter
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
# commented due to Manager not being ready for the translated files to be in the main branch
# - name: GitHub is so dumb i just cant
# run: |
# sudo chmod -R ugo+rwX .
# - name: Merge
# run: |
# git checkout flutter
# git add *
# git merge i18n_flutter
# git push

44
.github/workflows/pr-build.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: Build pull request
on:
pull_request:
paths:
- ".github/workflows/pr-build.yml"
- "app/**"
- "gradle/**"
- "*.properties"
- ".kts"
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build with Gradle
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew assembleRelease --no-daemon -PnoProguard -PsignAsDebug
- name: Set env
run: echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Add hash to APK
run: mv app/build/outputs/apk/release/app-release.apk revanced-manager-${{ env.COMMIT_HASH }}.apk
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: revanced-manager
path: revanced-manager-${{ env.COMMIT_HASH }}.apk

View File

@@ -1,41 +0,0 @@
name: "Android CI PR Build"
on:
pull_request:
branches:
- "**"
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up JDK 12
uses: actions/setup-java@v3
with:
java-version: '12'
distribution: 'zulu'
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- name: Set environment variables
run: echo $SECRETS | base64 -d > lib/utils/environment.dart
env:
SECRETS: ${{ secrets.SECRETS }}
- name: Set up Flutter
run: flutter pub get
- name: Generate files with Builder
run: flutter packages pub run build_runner build --delete-conflicting-outputs
- name: Build with Flutter
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: flutter build apk
- name: Add version to APK
run: mv build/app/outputs/flutter-apk/app-release.apk revanced-manager-${{ env.RELEASE_VERSION }}.apk
- name: Upload APK
uses: actions/upload-artifact@v2
with:
name: revanced-manager-${{ env.RELEASE_VERSION }}
path: revanced-manager-${{ env.RELEASE_VERSION }}.apk

View File

@@ -1,4 +1,4 @@
name: "Release Build"
name: Release Build
on:
push:
@@ -6,46 +6,49 @@ on:
- "v*"
jobs:
release:
build:
name: Build
runs-on: ubuntu-latest
permissions:
id-token: write
attestations: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up JDK 12
uses: actions/setup-java@v3
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '12'
distribution: 'zulu'
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- name: Set environment variables
run: echo $SECRETS | base64 -d > lib/utils/environment.dart
env:
SECRETS: ${{ secrets.SECRETS }}
- name: Set up Flutter
run: flutter pub get
- name: Generate files with Builder
run: flutter packages pub run build_runner build --delete-conflicting-outputs
- name: Build with Flutter
java-version: '17'
distribution: 'temurin'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build with Gradle
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
run: flutter build apk
run: ./gradlew assembleRelease --no-daemon
- name: Sign APK
id: sign_apk
uses: ilharp/sign-android-release@v1
with:
releaseDir: build/app/outputs/apk/release
releaseDir: ./app/build/outputs/apk/release/
signingKey: ${{ secrets.SIGNING_KEYSTORE }}
keyStorePassword: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
keyAlias: ${{ secrets.SIGNING_KEY_ALIAS }}
keyPassword: ${{ secrets.SIGNING_KEY_PASSWORD }}
- name: Add version to APK
run: mv ${{steps.sign_apk.outputs.signedFile}} revanced-manager-${{ env.RELEASE_VERSION }}.apk
run: mv ${{ steps.sign_apk.outputs.signedFile }} revanced-manager-${{ env.RELEASE_VERSION }}.apk
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
with:
subject-path: revanced-manager-${{ env.RELEASE_VERSION }}.apk
- name: Publish release APK
uses: "marvinpinto/action-automatic-releases@latest"
with:

View File

@@ -0,0 +1,19 @@
name: Update documentation
on:
push:
paths:
- docs/**
jobs:
trigger:
runs-on: ubuntu-latest
name: Dispatch event to documentation repository
if: github.ref == 'refs/heads/main'
steps:
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }}
repository: revanced/revanced-documentation
event-type: update-documentation
client-payload: '{"repo": "${{ github.event.repository.name }}", "ref": "${{ github.ref }}"}'

146
.gitignore vendored
View File

@@ -1,138 +1,12 @@
# Miscellaneous
*.class
*.lock
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
.gradle
/local.properties
/.idea
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
# Visual Studio Code related
.classpath
.project
.settings/
# Flutter repo-specific
/bin/cache/
/bin/mingit/
/dev/benchmarks/mega_gallery/
/dev/bots/.recipe_deps
/dev/bots/android_tools/
/dev/docs/doc/
/dev/docs/flutter.docs.zip
/dev/docs/lib/
/dev/docs/pubspec.yaml
/dev/integration_tests/**/xcuserdata
/dev/integration_tests/**/Pods
/packages/flutter/coverage/
version
# packages file containing multi-root paths
.packages.generated
# Flutter/Dart/Pub related
**/doc/api/
**/*.g.dart
**/*.locator.dart
**/*.router.dart
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
**/generated_plugin_registrant.dart
.packages
.pub-cache/
.pub/
build/
flutter_*.png
linked_*.ds
unlinked.ds
unlinked_spec.ds
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
*.jks
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/.last_build_id
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# macOS related
**/macos/Flutter/GeneratedPluginRegistrant.swift
**/macos/Flutter/Flutter-Debug.xcconfig
**/macos/Flutter/Flutter-Release.xcconfig
**/macos/Flutter/Flutter-Profile.xcconfig
# Windows related
**/windows/flutter/ephemeral/
**/windows/**/*.suo
**/windows/**/*.user
**/windows/**/*.userosscache
**/windows/**/*.sln.docstates
**/windows/x64/
**/windows/x86/
**/windows/**/*.[Cc]ache
**/windows/**/!*.[Cc]ache/
# Web related
lib/generated_plugin_registrant.dart
# Coverage
coverage/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
Firebase related
.firebase
.kotlin/

View File

@@ -1,45 +0,0 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: 85684f9300908116a78138ea4c6036c35c9a1236
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
- platform: android
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
- platform: ios
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
- platform: linux
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
- platform: macos
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
- platform: web
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
- platform: windows
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View File

@@ -1,6 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
<option name="filePath" value="$PROJECT_DIR$/lib/main.dart" />
<method v="2" />
</configuration>
</component>

91
.vscode/tasks.json vendored
View File

@@ -1,91 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Generate (Builder)",
"type": "shell",
"command": "flutter packages pub run build_runner build --delete-conflicting-outputs",
"problemMatcher": []
},
{
"label": "Build (Android)",
"type": "shell",
"command": "flutter build apk",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Install (Android)",
"type": "shell",
"command": "adb install build\\app\\outputs\\flutter-apk\\app-release.apk",
"problemMatcher": []
},
{
"label": "Clean (Flutter)",
"type": "shell",
"command": "flutter clean && flutter pub get",
"problemMatcher": []
},
{
"label": "Clean (Builder)",
"type": "shell",
"command": "flutter packages pub run build_runner clean",
"problemMatcher": []
},
{
"label": "Build all (Android)",
"dependsOrder": "sequence",
"dependsOn": [
"Generate (Builder)",
"Build (Android)"
],
"problemMatcher": []
},
{
"label": "Clean all",
"dependsOrder": "sequence",
"dependsOn": [
"Clean (Flutter)",
"Clean (Builder)"
],
"problemMatcher": []
},
{
"label": "Clean all & Build all (Android)",
"dependsOrder": "sequence",
"dependsOn": [
"Clean all",
"Build all (Android)"
],
"problemMatcher": []
},
{
"label": "Clean all & Install (Android)",
"dependsOrder": "sequence",
"dependsOn": [
"Clean all",
"Build all (Android)",
"Install (Android)",
],
"problemMatcher": []
},
{
"label": "Build & Install (Android)",
"dependsOrder": "sequence",
"dependsOn": [
"Build (Android)",
"Install (Android)"
],
"problemMatcher": []
},
{
"label": "Validate translations",
"type": "shell",
"command": "flutter pub run flutter_i18n diff en.json pt.json",
"problemMatcher": []
}
]
}

View File

@@ -1,35 +1,55 @@
# 💊 ReVanced Manager
# ReVanced Manager (Compose Rewrite)
The official ReVanced Manager based on Flutter.
[![GitHub license](https://img.shields.io/github/license/revanced/revanced-manager)](../../blob/main/LICENSE)
[![GitHub last commit](https://img.shields.io/github/last-commit/revanced/revanced-manager/compose-dev)](https://github.com/ReVanced/revanced-manager/commits/compose-dev)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/w/revanced/revanced-manager/compose-dev)](https://github.com/ReVanced/revanced-manager/commits/compose-dev)
_(Yet another)_ rewrite of the ReVanced Manager using Kotlin and Jetpack Compose.
## Design system
In this rewrite, we are adopting the latest Material Design principles and guidelines by using Material 3 and Material You.
Material Design is a design system developed by Google that provides a unified visual language for building beautiful and consistent user interfaces across all platforms and devices. Material You is an extension of Material Design that provides even more customization options for users, making it possible for them to personalize their device and create a unique look and feel.
### Why Material 3?
* **Consistent design language**
* **Improved accessibility**
* **Better user experience**
By using Material 3 and Material You, we are ensuring that the app's user interface is consistent, customizable, accessible, and engaging for our users. This will help to improve the overall user experience and increase user satisfaction with the the manager.
## Technology stack
* Kotlin: Kotlin is a modern and concise programming language that is fully interoperable with Java and provides improved safety, readability, and maintainability compared to Java.
* Jetpack Compose: Jetpack Compose is a modern UI toolkit for Android development that allows developers to build beautiful and performant user interfaces using declarative programming. It provides a unified and efficient way of building UI that is well-integrated with the Android framework.
## Why Kotlin and Compose?
* **Improved safety:** Kotlin provides improved safety compared to Java, which reduces the likelihood of common programming mistakes that can cause security vulnerabilities or crashes.
* **Concise and readable code:** Kotlin's concise syntax and expressive type system make the code more readable, which makes it easier for developers to understand and maintain the codebase.
* **Better performance:** Jetpack Compose uses the power of the Android framework to provide smooth and fast performance, which enhances the user experience.
* **Modern and efficient UI development:** Jetpack Compose provides a modern and efficient way of building UI, which makes it easier for developers to create beautiful and performant user interfaces.
## 🔽 Download
To download the Alpha version of Manager, go [here](https://github.com/revanced/revanced-manager/releases/latest) and install the provided APK file.
You can obtain ReVanced Manager by downloading it from either [revanced.app/download](https://revanced.app/download) or [GitHub Releases](https://github.com/ReVanced/revanced-manager/releases)
## 📝 Prerequisites
1. Android 8 or higher
2. Does not work on some armv7 devices
3. [Vanced MicroG](https://github.com/TeamVanced/VancedMicroG/releases) required for YouTube and YouTube Music (Only for non-root)
## ⚠️ Disclaimer
*Please note that even though we're releasing the Manager, it is an ALPHA version. There's a big chance that the Manager might not work at all for you.*
For a list of prerequisites, refer to [docs/0_prerequisites.md](docs/0_prerequisites.md)
## 🔴 Issues
For suggestions and bug reports, open an issue [here](https://github.com/revanced/revanced-manager/issues/new/choose).
## 💭 Discussion
If you wish to discuss the Manager, a thread has been made under the [#development](https://discord.com/channels/952946952348270622/1002922226443632761) channel in the Discord server, please note that this thread may be temporary and may be removed in the future.
## 🌐 Translation
[![Crowdin](https://badges.crowdin.net/revanced/localized.svg)](https://crowdin.com/project/revanced)
If you wish to translate ReVanced Manager, we're accepting translations on [Crowdin](https://translate.revanced.app)
We're accepting translations on [Crowdin](https://translate.revanced.app)
## 🛠️ Building Manager from source
1. Setup flutter environment for your [platform](https://docs.flutter.dev/get-started/install)
2. Clone the repository locally
3. Add your github token in gradle.properties like [this](https://github.com/revanced/revanced-documentation/blob/main/docs/revanced-development/2_building_from_source.md)
4. Open the project in terminal
5. Run `flutter pub get` in terminal
6. Then `flutter packages pub run build_runner build --delete-conflicting-outputs` (Must be done on each git pull)
7. To build release apk run `flutter build apk`
For instructions on how to build ReVanced Manager from source, refer to [docs/4_building.md](docs/4_building.md)

77
SECURITY.md Normal file
View File

@@ -0,0 +1,77 @@
<p align="center">
<picture>
<source
width="256px"
media="(prefers-color-scheme: dark)"
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
>
<img
width="256px"
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
>
</picture>
<br>
<a href="https://revanced.app/">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="assets/revanced-logo/revanced-logo.svg" />
<img height="24px" src="assets/revanced-logo/revanced-logo.svg" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://x.com/revancedapp">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a>
<br>
<br>
Continuing the legacy of Vanced
</p>
# 🔒 Security Policy
This document describes how to report security vulnerabilities for ReVanced Manager.
## 🚨 Reporting a Vulnerability
Please open an issue in our [advisory tracker](https://github.com/ReVanced/revanced-manager/security/advisories/new) or reach out privately to us on [Discord](https://discord.gg/revanced).
If a vulnerability is confirmed and accepted, you can join our [Discord](https://discord.gg/revanced) server to receive a special contributor role.
### ⏳ Supported Versions
| Version | Branch | Supported |
| --------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------------ |
| ![Latest stable release](https://img.shields.io/github/v/release/ReVanced/revanced-manager?style=for-the-badge "Latest stable release") | main | :white_check_mark: |
| ![Latest version](https://img.shields.io/badge/version-latest-brightgreen?style=for-the-badge "Latest version") | dev | :white_check_mark: |
| ![Latest version](https://img.shields.io/badge/version-latest-brightgreen?style=for-the-badge "Latest version") | compose-dev | :white_check_mark: |

View File

@@ -1,33 +0,0 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
analyzer:
exclude:
- lib/utils/env_class.g.dart
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

13
android/.gitignore vendored
View File

@@ -1,13 +0,0 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks

View File

@@ -1,84 +0,0 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 33
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
applicationId "app.revanced.manager.flutter"
minSdkVersion 26
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
shrinkResources false
minifyEnabled false
signingConfig signingConfigs.debug
}
}
packagingOptions {
exclude '/prebuilt/**'
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// ReVanced
implementation "app.revanced:revanced-patcher:6.3.0"
// Signing & aligning
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
implementation("com.android.tools.build:apksig:7.2.2")
// MicroG cronet
implementation("org.microg:cronet-common:$cronetVersion")
implementation("org.microg:cronet-native:$cronetVersion")
}

View File

@@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.revanced.manager.flutter">
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -1,51 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.revanced.manager.flutter">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:label="ReVanced Manager"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:largeHeap="true"
android:extractNativeLibs="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View File

@@ -1,317 +0,0 @@
package app.revanced.manager.flutter
import android.os.Build
import android.os.Handler
import android.os.Looper
import androidx.annotation.NonNull
import app.revanced.manager.flutter.utils.Aapt
import app.revanced.manager.flutter.utils.aligning.ZipAligner
import app.revanced.manager.flutter.utils.signing.Signer
import app.revanced.manager.flutter.utils.zip.ZipFile
import app.revanced.manager.flutter.utils.zip.structures.ZipEntry
import app.revanced.patcher.Patcher
import app.revanced.patcher.PatcherOptions
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.logging.Logger
import app.revanced.patcher.util.patch.PatchBundle
import dalvik.system.DexClassLoader
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File
private const val PATCHER_CHANNEL = "app.revanced.manager.flutter/patcher"
private const val INSTALLER_CHANNEL = "app.revanced.manager.flutter/installer"
class MainActivity : FlutterActivity() {
private val handler = Handler(Looper.getMainLooper())
private lateinit var installerChannel: MethodChannel
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
val mainChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, PATCHER_CHANNEL)
installerChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, INSTALLER_CHANNEL)
mainChannel.setMethodCallHandler { call, result ->
when (call.method) {
"runPatcher" -> {
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")
val originalFilePath = call.argument<String>("originalFilePath")
val inputFilePath = call.argument<String>("inputFilePath")
val patchedFilePath = call.argument<String>("patchedFilePath")
val outFilePath = call.argument<String>("outFilePath")
val integrationsPath = call.argument<String>("integrationsPath")
val selectedPatches = call.argument<List<String>>("selectedPatches")
val cacheDirPath = call.argument<String>("cacheDirPath")
val mergeIntegrations = call.argument<Boolean>("mergeIntegrations")
val keyStoreFilePath = call.argument<String>("keyStoreFilePath")
if (patchBundleFilePath != null &&
originalFilePath != null &&
inputFilePath != null &&
patchedFilePath != null &&
outFilePath != null &&
integrationsPath != null &&
selectedPatches != null &&
cacheDirPath != null &&
mergeIntegrations != null &&
keyStoreFilePath != null
) {
runPatcher(
result,
patchBundleFilePath,
originalFilePath,
inputFilePath,
patchedFilePath,
outFilePath,
integrationsPath,
selectedPatches,
cacheDirPath,
mergeIntegrations,
keyStoreFilePath
)
} else {
result.notImplemented()
}
}
else -> result.notImplemented()
}
}
}
private fun runPatcher(
result: MethodChannel.Result,
patchBundleFilePath: String,
originalFilePath: String,
inputFilePath: String,
patchedFilePath: String,
outFilePath: String,
integrationsPath: String,
selectedPatches: List<String>,
cacheDirPath: String,
mergeIntegrations: Boolean,
keyStoreFilePath: String
) {
val originalFile = File(originalFilePath)
val inputFile = File(inputFilePath)
val patchedFile = File(patchedFilePath)
val outFile = File(outFilePath)
val integrations = File(integrationsPath)
val keyStoreFile = File(keyStoreFilePath)
Thread {
try {
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to 0.1,
"header" to "",
"log" to "Copying original apk"
)
)
}
originalFile.copyTo(inputFile, true)
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to 0.2,
"header" to "Unpacking apk...",
"log" to "Unpacking input apk"
)
)
}
val patcher =
Patcher(
PatcherOptions(
inputFile,
cacheDirPath,
Aapt.binary(applicationContext).absolutePath,
cacheDirPath,
logger = ManagerLogger()
)
)
handler.post {
installerChannel.invokeMethod(
"update",
mapOf("progress" to 0.3, "header" to "", "log" to "")
)
}
if (mergeIntegrations) {
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to 0.4,
"header" to "Merging integrations...",
"log" to "Merging integrations"
)
)
}
patcher.addFiles(listOf(integrations)) {}
}
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to 0.5,
"header" to "Applying patches...",
"log" to ""
)
)
}
val patches = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
PatchBundle.Dex(
patchBundleFilePath,
DexClassLoader(
patchBundleFilePath,
cacheDirPath,
null,
javaClass.classLoader
)
).loadPatches().filter { patch ->
(patch.compatiblePackages?.any { it.name == patcher.context.packageMetadata.packageName } == true || patch.compatiblePackages.isNullOrEmpty()) &&
selectedPatches.any { it == patch.patchName }
}
} else {
TODO("VERSION.SDK_INT < CUPCAKE")
}
patcher.addPatches(patches)
patcher.executePatches().forEach { (patch, res) ->
if (res.isSuccess) {
val msg = "Applied $patch"
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to 0.5,
"header" to "",
"log" to msg
)
)
}
return@forEach
}
val msg = "Failed to apply $patch: " + "${res.exceptionOrNull()!!.message ?: res.exceptionOrNull()!!::class.simpleName}"
handler.post {
installerChannel.invokeMethod(
"update",
mapOf("progress" to 0.5, "header" to "", "log" to msg)
)
}
}
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to 0.7,
"header" to "Repacking apk...",
"log" to "Repacking patched apk"
)
)
}
val res = patcher.save()
ZipFile(patchedFile).use { file ->
res.dexFiles.forEach {
file.addEntryCompressData(
ZipEntry.createWithName(it.name),
it.stream.readBytes()
)
}
res.resourceFile?.let {
file.copyEntriesFromFileAligned(
ZipFile(it),
ZipAligner::getEntryAlignment
)
}
file.copyEntriesFromFileAligned(
ZipFile(inputFile),
ZipAligner::getEntryAlignment
)
}
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to 0.9,
"header" to "Signing apk...",
"log" to ""
)
)
}
// Signer("ReVanced", "s3cur3p@ssw0rd").signApk(patchedFile, outFile, keyStoreFile)
try {
Signer("ReVanced", "s3cur3p@ssw0rd").signApk(patchedFile, outFile, keyStoreFile)
} catch (e: Exception) {
//log to console
print("Error signing apk: ${e.message}")
e.printStackTrace()
}
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to 1.0,
"header" to "Finished!",
"log" to "Finished!"
)
)
}
} catch (ex: Throwable) {
val stack = ex.stackTraceToString()
handler.post {
installerChannel.invokeMethod(
"update",
mapOf(
"progress" to -100.0,
"header" to "Aborting...",
"log" to "An error occurred! Aborting\nError:\n$stack"
)
)
}
}
handler.post { result.success(null) }
}.start()
}
inner class ManagerLogger : Logger {
override fun error(msg: String) {
handler.post {
installerChannel
.invokeMethod(
"update",
mapOf("progress" to -1.0, "header" to "", "log" to msg)
)
}
}
override fun warn(msg: String) {
handler.post {
installerChannel.invokeMethod(
"update",
mapOf("progress" to -1.0, "header" to "", "log" to msg)
)
}
}
override fun info(msg: String) {
handler.post {
installerChannel.invokeMethod(
"update",
mapOf("progress" to -1.0, "header" to "", "log" to msg)
)
}
}
override fun trace(_msg: String) { /* unused */
}
}
}

View File

@@ -1,12 +0,0 @@
package app.revanced.manager.flutter.utils
import android.content.Context
import java.io.File
object Aapt {
fun binary(context: Context): File {
return File(context.applicationInfo.nativeLibraryDir).resolveAapt()
}
}
private fun File.resolveAapt() = resolve(list { _, f -> !File(f).isDirectory && f.contains("aapt") }!!.first())

View File

@@ -1,11 +0,0 @@
package app.revanced.manager.flutter.utils.aligning
import app.revanced.manager.flutter.utils.zip.structures.ZipEntry
internal object ZipAligner {
private const val DEFAULT_ALIGNMENT = 4
private const val LIBRARY_ALIGNMENT = 4096
fun getEntryAlignment(entry: ZipEntry): Int? =
if (entry.compression.toUInt() != 0u) null else if (entry.fileName.endsWith(".so")) LIBRARY_ALIGNMENT else DEFAULT_ALIGNMENT
}

View File

@@ -1,74 +0,0 @@
package app.revanced.manager.flutter.utils.signing
import com.android.apksig.ApkSigner
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import org.bouncycastle.cert.X509v3CertificateBuilder
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.bouncycastle.operator.ContentSigner
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.math.BigInteger
import java.security.*
import java.security.cert.X509Certificate
import java.util.*
internal class Signer(
private val cn: String, password: String
) {
private val passwordCharArray = password.toCharArray()
private fun newKeystore(out: File) {
val (publicKey, privateKey) = createKey()
val privateKS = KeyStore.getInstance("BKS", "BC")
privateKS.load(null, passwordCharArray)
privateKS.setKeyEntry("alias", privateKey, passwordCharArray, arrayOf(publicKey))
privateKS.store(FileOutputStream(out), passwordCharArray)
}
private fun createKey(): Pair<X509Certificate, PrivateKey> {
val gen = KeyPairGenerator.getInstance("RSA")
gen.initialize(2048)
val pair = gen.generateKeyPair()
var serialNumber: BigInteger
do serialNumber =
BigInteger.valueOf(SecureRandom().nextLong()) while (serialNumber < BigInteger.ZERO)
val x500Name = X500Name("CN=$cn")
val builder = X509v3CertificateBuilder(
x500Name,
serialNumber,
Date(System.currentTimeMillis() - 1000L * 60L * 60L * 24L * 30L),
Date(System.currentTimeMillis() + 1000L * 60L * 60L * 24L * 366L * 30L),
Locale.ENGLISH,
x500Name,
SubjectPublicKeyInfo.getInstance(pair.public.encoded)
)
val signer: ContentSigner = JcaContentSignerBuilder("SHA256withRSA").build(pair.private)
return JcaX509CertificateConverter().getCertificate(builder.build(signer)) to pair.private
}
fun signApk(input: File, output: File, ks: File) {
Security.addProvider(BouncyCastleProvider())
if (!ks.exists()) newKeystore(ks)
val keyStore = KeyStore.getInstance("BKS", "BC")
FileInputStream(ks).use { fis -> keyStore.load(fis, null) }
val alias = keyStore.aliases().nextElement()
val config = ApkSigner.SignerConfig.Builder(
cn,
keyStore.getKey(alias, passwordCharArray) as PrivateKey,
listOf(keyStore.getCertificate(alias) as X509Certificate)
).build()
val signer = ApkSigner.Builder(listOf(config))
signer.setCreatedBy(cn)
signer.setInputApk(input)
signer.setOutputApk(output)
signer.build().sign()
}
}

View File

@@ -1,35 +0,0 @@
@file:Suppress("unused")
package app.revanced.manager.flutter.utils.zip
import java.io.DataInput
import java.io.DataOutput
import java.nio.ByteBuffer
fun UInt.toLittleEndian() =
(((this.toInt() and 0xff000000.toInt()) shr 24) or ((this.toInt() and 0x00ff0000) shr 8) or ((this.toInt() and 0x0000ff00) shl 8) or (this.toInt() shl 24)).toUInt()
fun UShort.toLittleEndian() = (this.toUInt() shl 16).toLittleEndian().toUShort()
fun UInt.toBigEndian() = (((this.toInt() and 0xff) shl 24) or ((this.toInt() and 0xff00) shl 8)
or ((this.toInt() and 0x00ff0000) ushr 8) or (this.toInt() ushr 24)).toUInt()
fun UShort.toBigEndian() = (this.toUInt() shl 16).toBigEndian().toUShort()
fun ByteBuffer.getUShort() = this.short.toUShort()
fun ByteBuffer.getUInt() = this.int.toUInt()
fun ByteBuffer.putUShort(ushort: UShort): ByteBuffer = this.putShort(ushort.toShort())
fun ByteBuffer.putUInt(uint: UInt): ByteBuffer = this.putInt(uint.toInt())
fun DataInput.readUShort() = this.readShort().toUShort()
fun DataInput.readUInt() = this.readInt().toUInt()
fun DataOutput.writeUShort(ushort: UShort) = this.writeShort(ushort.toInt())
fun DataOutput.writeUInt(uint: UInt) = this.writeInt(uint.toInt())
fun DataInput.readUShortLE() = this.readUShort().toBigEndian()
fun DataInput.readUIntLE() = this.readUInt().toBigEndian()
fun DataOutput.writeUShortLE(ushort: UShort) = this.writeUShort(ushort.toLittleEndian())
fun DataOutput.writeUIntLE(uint: UInt) = this.writeUInt(uint.toLittleEndian())

View File

@@ -1,176 +0,0 @@
package app.revanced.manager.flutter.utils.zip
import app.revanced.manager.flutter.utils.zip.structures.ZipEndRecord
import app.revanced.manager.flutter.utils.zip.structures.ZipEntry
import java.io.Closeable
import java.io.File
import java.io.RandomAccessFile
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.util.zip.CRC32
import java.util.zip.Deflater
class ZipFile(file: File) : Closeable {
var entries: MutableList<ZipEntry> = mutableListOf()
private val filePointer: RandomAccessFile = RandomAccessFile(file, "rw")
private var CDNeedsRewrite = false
private val compressionLevel = 5
init {
//if file isn't empty try to load entries
if (file.length() > 0) {
val endRecord = findEndRecord()
if (endRecord.diskNumber > 0u || endRecord.totalEntries != endRecord.diskEntries)
throw IllegalArgumentException("Multi-file archives are not supported")
entries = readEntries(endRecord).toMutableList()
}
//seek back to start for writing
filePointer.seek(0)
}
private fun findEndRecord(): ZipEndRecord {
//look from end to start since end record is at the end
for (i in filePointer.length() - 1 downTo 0) {
filePointer.seek(i)
//possible beginning of signature
if (filePointer.readByte() == 0x50.toByte()) {
//seek back to get the full int
filePointer.seek(i)
val possibleSignature = filePointer.readUIntLE()
if (possibleSignature == ZipEndRecord.ECD_SIGNATURE) {
filePointer.seek(i)
return ZipEndRecord.fromECD(filePointer)
}
}
}
throw Exception("Couldn't find end record")
}
private fun readEntries(endRecord: ZipEndRecord): List<ZipEntry> {
filePointer.seek(endRecord.centralDirectoryStartOffset.toLong())
val numberOfEntries = endRecord.diskEntries.toInt()
return buildList(numberOfEntries) {
for (i in 1..numberOfEntries) {
add(
ZipEntry.fromCDE(filePointer).also
{
//for some reason the local extra field can be different from the central one
it.readLocalExtra(
filePointer.channel.map(
FileChannel.MapMode.READ_ONLY,
it.localHeaderOffset.toLong() + 28,
2
)
)
})
}
}
}
private fun writeCD() {
val CDStart = filePointer.channel.position().toUInt()
entries.forEach {
filePointer.channel.write(it.toCDE())
}
val entriesCount = entries.size.toUShort()
val endRecord = ZipEndRecord(
0u,
0u,
entriesCount,
entriesCount,
filePointer.channel.position().toUInt() - CDStart,
CDStart,
""
)
filePointer.channel.write(endRecord.toECD())
}
private fun addEntry(entry: ZipEntry, data: ByteBuffer) {
CDNeedsRewrite = true
entry.localHeaderOffset = filePointer.channel.position().toUInt()
filePointer.channel.write(entry.toLFH())
filePointer.channel.write(data)
entries.add(entry)
}
fun addEntryCompressData(entry: ZipEntry, data: ByteArray) {
val compressor = Deflater(compressionLevel, true)
compressor.setInput(data)
compressor.finish()
val uncompressedSize = data.size
val compressedData =
ByteArray(uncompressedSize) //i'm guessing compression won't make the data bigger
val compressedDataLength = compressor.deflate(compressedData)
val compressedBuffer =
ByteBuffer.wrap(compressedData.take(compressedDataLength).toByteArray())
compressor.end()
val crc = CRC32()
crc.update(data)
entry.compression = 8u //deflate compression
entry.uncompressedSize = uncompressedSize.toUInt()
entry.compressedSize = compressedDataLength.toUInt()
entry.crc32 = crc.value.toUInt()
addEntry(entry, compressedBuffer)
}
private fun addEntryCopyData(entry: ZipEntry, data: ByteBuffer, alignment: Int? = null) {
alignment?.let {
//calculate where data would end up
val dataOffset = filePointer.filePointer + entry.LFHSize
val mod = dataOffset % alignment
//wrong alignment
if (mod != 0L) {
//add padding at end of extra field
entry.localExtraField =
entry.localExtraField.copyOf((entry.localExtraField.size + (alignment - mod)).toInt())
}
}
addEntry(entry, data)
}
fun getDataForEntry(entry: ZipEntry): ByteBuffer {
return filePointer.channel.map(
FileChannel.MapMode.READ_ONLY,
entry.dataOffset.toLong(),
entry.compressedSize.toLong()
)
}
fun copyEntriesFromFileAligned(file: ZipFile, entryAlignment: (entry: ZipEntry) -> Int?) {
for (entry in file.entries) {
if (entries.any { it.fileName == entry.fileName }) continue //don't add duplicates
val data = file.getDataForEntry(entry)
addEntryCopyData(entry, data, entryAlignment(entry))
}
}
override fun close() {
if (CDNeedsRewrite) writeCD()
filePointer.close()
}
}

View File

@@ -1,78 +0,0 @@
package app.revanced.manager.flutter.utils.zip.structures
import app.revanced.manager.flutter.utils.zip.putUInt
import app.revanced.manager.flutter.utils.zip.putUShort
import app.revanced.manager.flutter.utils.zip.readUIntLE
import app.revanced.manager.flutter.utils.zip.readUShortLE
import java.io.DataInput
import java.nio.ByteBuffer
import java.nio.ByteOrder
data class ZipEndRecord(
val diskNumber: UShort,
val startingDiskNumber: UShort,
val diskEntries: UShort,
val totalEntries: UShort,
val centralDirectorySize: UInt,
val centralDirectoryStartOffset: UInt,
val fileComment: String,
) {
companion object {
const val ECD_HEADER_SIZE = 22
const val ECD_SIGNATURE = 0x06054b50u
fun fromECD(input: DataInput): ZipEndRecord {
val signature = input.readUIntLE()
if (signature != ECD_SIGNATURE)
throw IllegalArgumentException("Input doesn't start with end record signature")
val diskNumber = input.readUShortLE()
val startingDiskNumber = input.readUShortLE()
val diskEntries = input.readUShortLE()
val totalEntries = input.readUShortLE()
val centralDirectorySize = input.readUIntLE()
val centralDirectoryStartOffset = input.readUIntLE()
val fileCommentLength = input.readUShortLE()
var fileComment = ""
if (fileCommentLength > 0u) {
val fileCommentBytes = ByteArray(fileCommentLength.toInt())
input.readFully(fileCommentBytes)
fileComment = fileCommentBytes.toString(Charsets.UTF_8)
}
return ZipEndRecord(
diskNumber,
startingDiskNumber,
diskEntries,
totalEntries,
centralDirectorySize,
centralDirectoryStartOffset,
fileComment
)
}
}
fun toECD(): ByteBuffer {
val commentBytes = fileComment.toByteArray(Charsets.UTF_8)
val buffer = ByteBuffer.allocate(ECD_HEADER_SIZE + commentBytes.size)
.also { it.order(ByteOrder.LITTLE_ENDIAN) }
buffer.putUInt(ECD_SIGNATURE)
buffer.putUShort(diskNumber)
buffer.putUShort(startingDiskNumber)
buffer.putUShort(diskEntries)
buffer.putUShort(totalEntries)
buffer.putUInt(centralDirectorySize)
buffer.putUInt(centralDirectoryStartOffset)
buffer.putUShort(commentBytes.size.toUShort())
buffer.put(commentBytes)
buffer.flip()
return buffer
}
}

View File

@@ -1,190 +0,0 @@
package app.revanced.manager.flutter.utils.zip.structures
import app.revanced.manager.flutter.utils.zip.*
import java.io.DataInput
import java.nio.ByteBuffer
import java.nio.ByteOrder
data class ZipEntry(
val version: UShort,
val versionNeeded: UShort,
val flags: UShort,
var compression: UShort,
val modificationTime: UShort,
val modificationDate: UShort,
var crc32: UInt,
var compressedSize: UInt,
var uncompressedSize: UInt,
val diskNumber: UShort,
val internalAttributes: UShort,
val externalAttributes: UInt,
var localHeaderOffset: UInt,
val fileName: String,
val extraField: ByteArray,
val fileComment: String,
var localExtraField: ByteArray = ByteArray(0), //separate for alignment
) {
val LFHSize: Int
get() = LFH_HEADER_SIZE + fileName.toByteArray(Charsets.UTF_8).size + localExtraField.size
val dataOffset: UInt
get() = localHeaderOffset + LFHSize.toUInt()
companion object {
const val CDE_HEADER_SIZE = 46
const val CDE_SIGNATURE = 0x02014b50u
const val LFH_HEADER_SIZE = 30
const val LFH_SIGNATURE = 0x04034b50u
fun createWithName(fileName: String): ZipEntry {
return ZipEntry(
0x1403u, //made by unix, version 20
0u,
0u,
0u,
0x0821u, //seems to be static time google uses, no idea
0x0221u, //same as above
0u,
0u,
0u,
0u,
0u,
0u,
0u,
fileName,
ByteArray(0),
""
)
}
fun fromCDE(input: DataInput): ZipEntry {
val signature = input.readUIntLE()
if (signature != CDE_SIGNATURE)
throw IllegalArgumentException("Input doesn't start with central directory entry signature")
val version = input.readUShortLE()
val versionNeeded = input.readUShortLE()
var flags = input.readUShortLE()
val compression = input.readUShortLE()
val modificationTime = input.readUShortLE()
val modificationDate = input.readUShortLE()
val crc32 = input.readUIntLE()
val compressedSize = input.readUIntLE()
val uncompressedSize = input.readUIntLE()
val fileNameLength = input.readUShortLE()
var fileName = ""
val extraFieldLength = input.readUShortLE()
val extraField = ByteArray(extraFieldLength.toInt())
val fileCommentLength = input.readUShortLE()
var fileComment = ""
val diskNumber = input.readUShortLE()
val internalAttributes = input.readUShortLE()
val externalAttributes = input.readUIntLE()
val localHeaderOffset = input.readUIntLE()
val variableFieldsLength =
fileNameLength.toInt() + extraFieldLength.toInt() + fileCommentLength.toInt()
if (variableFieldsLength > 0) {
val fileNameBytes = ByteArray(fileNameLength.toInt())
input.readFully(fileNameBytes)
fileName = fileNameBytes.toString(Charsets.UTF_8)
input.readFully(extraField)
val fileCommentBytes = ByteArray(fileCommentLength.toInt())
input.readFully(fileCommentBytes)
fileComment = fileCommentBytes.toString(Charsets.UTF_8)
}
flags = (flags and 0b1000u.inv()
.toUShort()) //disable data descriptor flag as they are not used
return ZipEntry(
version,
versionNeeded,
flags,
compression,
modificationTime,
modificationDate,
crc32,
compressedSize,
uncompressedSize,
diskNumber,
internalAttributes,
externalAttributes,
localHeaderOffset,
fileName,
extraField,
fileComment,
)
}
}
fun readLocalExtra(buffer: ByteBuffer) {
buffer.order(ByteOrder.LITTLE_ENDIAN)
localExtraField = ByteArray(buffer.getUShort().toInt())
}
fun toLFH(): ByteBuffer {
val nameBytes = fileName.toByteArray(Charsets.UTF_8)
val buffer = ByteBuffer.allocate(LFH_HEADER_SIZE + nameBytes.size + localExtraField.size)
.also { it.order(ByteOrder.LITTLE_ENDIAN) }
buffer.putUInt(LFH_SIGNATURE)
buffer.putUShort(versionNeeded)
buffer.putUShort(flags)
buffer.putUShort(compression)
buffer.putUShort(modificationTime)
buffer.putUShort(modificationDate)
buffer.putUInt(crc32)
buffer.putUInt(compressedSize)
buffer.putUInt(uncompressedSize)
buffer.putUShort(nameBytes.size.toUShort())
buffer.putUShort(localExtraField.size.toUShort())
buffer.put(nameBytes)
buffer.put(localExtraField)
buffer.flip()
return buffer
}
fun toCDE(): ByteBuffer {
val nameBytes = fileName.toByteArray(Charsets.UTF_8)
val commentBytes = fileComment.toByteArray(Charsets.UTF_8)
val buffer =
ByteBuffer.allocate(CDE_HEADER_SIZE + nameBytes.size + extraField.size + commentBytes.size)
.also { it.order(ByteOrder.LITTLE_ENDIAN) }
buffer.putUInt(CDE_SIGNATURE)
buffer.putUShort(version)
buffer.putUShort(versionNeeded)
buffer.putUShort(flags)
buffer.putUShort(compression)
buffer.putUShort(modificationTime)
buffer.putUShort(modificationDate)
buffer.putUInt(crc32)
buffer.putUInt(compressedSize)
buffer.putUInt(uncompressedSize)
buffer.putUShort(nameBytes.size.toUShort())
buffer.putUShort(extraField.size.toUShort())
buffer.putUShort(commentBytes.size.toUShort())
buffer.putUShort(diskNumber)
buffer.putUShort(internalAttributes)
buffer.putUInt(externalAttributes)
buffer.putUInt(localHeaderOffset)
buffer.put(nameBytes)
buffer.put(extraField)
buffer.put(commentBytes)
buffer.flip()
return buffer
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 814 B

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_launcher_round</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_launcher_round</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#1B1B1B</color>
</resources>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path name="cache" path="." />
</paths>

View File

@@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.revanced.manager.flutter">
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -1,37 +0,0 @@
buildscript {
ext.cronetVersion = '102.5005.125'
ext.kotlin_version = '1.7.20'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials {
username = (project.findProperty("gpr.user") ?: System.getenv("GITHUB_ACTOR")) as String
password = (project.findProperty("gpr.key") ?: System.getenv("GITHUB_TOKEN")) as String
}
}
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@@ -1,3 +0,0 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

View File

@@ -1,11 +0,0 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

1
app/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

211
app/build.gradle.kts Normal file
View File

@@ -0,0 +1,211 @@
import kotlin.random.Random
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.devtools)
alias(libs.plugins.about.libraries)
}
android {
namespace = "app.revanced.manager"
compileSdk = 35
buildToolsVersion = "35.0.1"
defaultConfig {
applicationId = "app.revanced.manager"
minSdk = 26
targetSdk = 35
versionCode = 1
versionName = "0.0.1"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
debug {
applicationIdSuffix = ".debug"
resValue("string", "app_name", "ReVanced Manager (dev)")
isPseudoLocalesEnabled = true
buildConfigField("long", "BUILD_ID", "${Random.nextLong()}L")
}
release {
if (!project.hasProperty("noProguard")) {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
if (project.hasProperty("signAsDebug")) {
applicationIdSuffix = ".debug"
resValue("string", "app_name", "ReVanced Manager Debug")
signingConfig = signingConfigs.getByName("debug")
isPseudoLocalesEnabled = true
}
buildConfigField("long", "BUILD_ID", "0L")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
packaging {
resources.excludes.addAll(listOf(
"/prebuilt/**",
"META-INF/DEPENDENCIES",
"META-INF/**.version",
"DebugProbesKt.bin",
"kotlin-tooling-metadata.json",
"org/bouncycastle/pqc/**.properties",
"org/bouncycastle/x509/**.properties",
))
jniLibs {
useLegacyPackaging = true
}
}
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
compose = true
aidl = true
buildConfig = true
}
android {
androidResources {
generateLocaleConfig = true
}
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}
}
kotlin {
jvmToolchain(17)
}
dependencies {
// AndroidX Core
implementation(libs.androidx.ktx)
implementation(libs.runtime.ktx)
implementation(libs.runtime.compose)
implementation(libs.splash.screen)
implementation(libs.activity.compose)
implementation(libs.work.runtime.ktx)
implementation(libs.preferences.datastore)
implementation(libs.appcompat)
// Compose
implementation(platform(libs.compose.bom))
implementation(libs.compose.ui)
implementation(libs.compose.ui.preview)
implementation(libs.compose.ui.tooling)
implementation(libs.compose.livedata)
implementation(libs.compose.material.icons.extended)
implementation(libs.compose.material3)
implementation(libs.navigation.compose)
// Accompanist
implementation(libs.accompanist.drawablepainter)
// Placeholder
implementation(libs.placeholder.material3)
// HTML Scraper
implementation(libs.skrapeit.dsl)
implementation(libs.skrapeit.parser)
// Coil (async image loading, network image)
implementation(libs.coil.compose)
implementation(libs.coil.appiconloader)
// KotlinX
implementation(libs.kotlinx.serialization.json)
implementation(libs.kotlinx.collection.immutable)
implementation(libs.kotlinx.datetime)
// Room
implementation(libs.room.runtime)
implementation(libs.room.ktx)
annotationProcessor(libs.room.compiler)
ksp(libs.room.compiler)
// ReVanced
implementation(libs.revanced.patcher)
implementation(libs.revanced.library)
// Downloader plugins
implementation(libs.plugin.api)
// Native processes
implementation(libs.kotlin.process)
// HiddenAPI
compileOnly(libs.hidden.api.stub)
// LibSU
implementation(libs.libsu.core)
implementation(libs.libsu.service)
implementation(libs.libsu.nio)
// Koin
implementation(libs.koin.android)
implementation(libs.koin.compose)
implementation(libs.koin.compose.navigation)
implementation(libs.koin.workmanager)
// Licenses
implementation(libs.about.libraries)
// Ktor
implementation(libs.ktor.core)
implementation(libs.ktor.logging)
implementation(libs.ktor.okhttp)
implementation(libs.ktor.content.negotiation)
implementation(libs.ktor.serialization)
// Markdown
implementation(libs.markdown.renderer)
// Fading Edges
implementation(libs.fading.edges)
// Scrollbars
implementation(libs.scrollbars)
// EnumUtil
implementation(libs.enumutil)
ksp(libs.enumutil.ksp)
// Reorderable lists
implementation(libs.reorderable)
// Compose Icons
implementation(libs.compose.icons.fontawesome)
}

63
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,63 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
-dontobfuscate
# Required for serialization to work properly
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
static <1>$Companion Companion;
}
-if @kotlinx.serialization.Serializable class ** {
static **$* *;
}
-keepclassmembers class <2>$<3> {
kotlinx.serialization.KSerializer serializer(...);
}
-if @kotlinx.serialization.Serializable class ** {
public static ** INSTANCE;
}
-keepclassmembers class <1> {
public static <1> INSTANCE;
kotlinx.serialization.KSerializer serializer(...);
}
# This required for the process runtime.
-keep class app.revanced.manager.patcher.runtime.process.* {
*;
}
# Required for the patcher to function correctly
-keep class app.revanced.patcher.** {
*;
}
-keep class brut.** {
*;
}
-keep class org.xmlpull.** {
*;
}
-keep class kotlin.** {
*;
}
-keep class org.jf.** {
*;
}
-keep class com.android.** {
*;
}
-keep class app.revanced.manager.plugin.** {
*;
}
-dontwarn com.google.auto.value.**
-dontwarn java.awt.**
-dontwarn javax.**
-dontwarn org.slf4j.**
-dontwarn it.skrape.fetcher.*
-dontwarn com.google.j2objc.annotations.*
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault

View File

@@ -0,0 +1,429 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "d0119047505da435972c5247181de675",
"entities": [
{
"tableName": "patch_bundles",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER NOT NULL, `name` TEXT NOT NULL, `version` TEXT, `source` TEXT NOT NULL, `auto_update` INTEGER NOT NULL, PRIMARY KEY(`uid`))",
"fields": [
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "autoUpdate",
"columnName": "auto_update",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"uid"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "patch_selections",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER NOT NULL, `patch_bundle` INTEGER NOT NULL, `package_name` TEXT NOT NULL, PRIMARY KEY(`uid`), FOREIGN KEY(`patch_bundle`) REFERENCES `patch_bundles`(`uid`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "patchBundle",
"columnName": "patch_bundle",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "packageName",
"columnName": "package_name",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"uid"
]
},
"indices": [
{
"name": "index_patch_selections_patch_bundle_package_name",
"unique": true,
"columnNames": [
"patch_bundle",
"package_name"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_patch_selections_patch_bundle_package_name` ON `${TABLE_NAME}` (`patch_bundle`, `package_name`)"
}
],
"foreignKeys": [
{
"table": "patch_bundles",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"patch_bundle"
],
"referencedColumns": [
"uid"
]
}
]
},
{
"tableName": "selected_patches",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`selection` INTEGER NOT NULL, `patch_name` TEXT NOT NULL, PRIMARY KEY(`selection`, `patch_name`), FOREIGN KEY(`selection`) REFERENCES `patch_selections`(`uid`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "selection",
"columnName": "selection",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "patchName",
"columnName": "patch_name",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"selection",
"patch_name"
]
},
"indices": [],
"foreignKeys": [
{
"table": "patch_selections",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"selection"
],
"referencedColumns": [
"uid"
]
}
]
},
{
"tableName": "downloaded_app",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `version` TEXT NOT NULL, `directory` TEXT NOT NULL, `last_used` INTEGER NOT NULL, PRIMARY KEY(`package_name`, `version`))",
"fields": [
{
"fieldPath": "packageName",
"columnName": "package_name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "directory",
"columnName": "directory",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastUsed",
"columnName": "last_used",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"package_name",
"version"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "installed_app",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`current_package_name` TEXT NOT NULL, `original_package_name` TEXT NOT NULL, `version` TEXT NOT NULL, `install_type` TEXT NOT NULL, PRIMARY KEY(`current_package_name`))",
"fields": [
{
"fieldPath": "currentPackageName",
"columnName": "current_package_name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "originalPackageName",
"columnName": "original_package_name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "installType",
"columnName": "install_type",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"current_package_name"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "applied_patch",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `bundle` INTEGER NOT NULL, `patch_name` TEXT NOT NULL, PRIMARY KEY(`package_name`, `bundle`, `patch_name`), FOREIGN KEY(`package_name`) REFERENCES `installed_app`(`current_package_name`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`bundle`) REFERENCES `patch_bundles`(`uid`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "packageName",
"columnName": "package_name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "bundle",
"columnName": "bundle",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "patchName",
"columnName": "patch_name",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"package_name",
"bundle",
"patch_name"
]
},
"indices": [
{
"name": "index_applied_patch_bundle",
"unique": false,
"columnNames": [
"bundle"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_applied_patch_bundle` ON `${TABLE_NAME}` (`bundle`)"
}
],
"foreignKeys": [
{
"table": "installed_app",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"package_name"
],
"referencedColumns": [
"current_package_name"
]
},
{
"table": "patch_bundles",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"bundle"
],
"referencedColumns": [
"uid"
]
}
]
},
{
"tableName": "option_groups",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER NOT NULL, `patch_bundle` INTEGER NOT NULL, `package_name` TEXT NOT NULL, PRIMARY KEY(`uid`), FOREIGN KEY(`patch_bundle`) REFERENCES `patch_bundles`(`uid`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "patchBundle",
"columnName": "patch_bundle",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "packageName",
"columnName": "package_name",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"uid"
]
},
"indices": [
{
"name": "index_option_groups_patch_bundle_package_name",
"unique": true,
"columnNames": [
"patch_bundle",
"package_name"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_option_groups_patch_bundle_package_name` ON `${TABLE_NAME}` (`patch_bundle`, `package_name`)"
}
],
"foreignKeys": [
{
"table": "patch_bundles",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"patch_bundle"
],
"referencedColumns": [
"uid"
]
}
]
},
{
"tableName": "options",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`group` INTEGER NOT NULL, `patch_name` TEXT NOT NULL, `key` TEXT NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`group`, `patch_name`, `key`), FOREIGN KEY(`group`) REFERENCES `option_groups`(`uid`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "group",
"columnName": "group",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "patchName",
"columnName": "patch_name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"group",
"patch_name",
"key"
]
},
"indices": [],
"foreignKeys": [
{
"table": "option_groups",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"group"
],
"referencedColumns": [
"uid"
]
}
]
},
{
"tableName": "trusted_downloader_plugins",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `signature` BLOB NOT NULL, PRIMARY KEY(`package_name`))",
"fields": [
{
"fieldPath": "packageName",
"columnName": "package_name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "signature",
"columnName": "signature",
"affinity": "BLOB",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"package_name"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd0119047505da435972c5247181de675')"
]
}
}

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<permission
android:name="app.revanced.manager.permission.PLUGIN_HOST"
android:protectionLevel="signature"
android:label="@string/plugin_host_permission_label"
android:description="@string/plugin_host_permission_description"
/>
<uses-permission android:name="app.revanced.manager.permission.PLUGIN_HOST" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name=".ManagerApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:largeHeap="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.ReVancedManager"
android:enableOnBackInvokedCallback="true"
tools:targetApi="34">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.ReVancedManager">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".plugin.downloader.webview.WebViewActivity" android:exported="false" android:theme="@style/Theme.WebViewActivity" />
<service android:name=".service.InstallService" />
<service android:name=".service.UninstallService" />
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="specialUse"
android:exported="false"
tools:node="merge">
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="patching"
/>
</service>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>
</manifest>

View File

@@ -0,0 +1,8 @@
// IRootService.aidl
package app.revanced.manager;
// Declare any non-default types here with import statements
interface IRootSystemService {
IBinder getFileSystemService();
}

View File

@@ -0,0 +1,11 @@
// IPatcherEvents.aidl
package app.revanced.manager.patcher.runtime.process;
// Interface for sending events back to the main app process.
oneway interface IPatcherEvents {
void log(String level, String msg);
void patchSucceeded();
void progress(String name, String state, String msg);
// The patching process has ended. The exceptionStackTrace is null if it finished successfully.
void finished(String exceptionStackTrace);
}

View File

@@ -0,0 +1,14 @@
// IPatcherProcess.aidl
package app.revanced.manager.patcher.runtime.process;
import app.revanced.manager.patcher.runtime.process.Parameters;
import app.revanced.manager.patcher.runtime.process.IPatcherEvents;
interface IPatcherProcess {
// Returns BuildConfig.BUILD_ID, which is used to ensure the main app and runner process are running the same code.
long buildId();
// Makes the patcher process exit with code 0
oneway void exit();
// Starts patching.
oneway void start(in Parameters parameters, IPatcherEvents events);
}

View File

@@ -0,0 +1,4 @@
// Parameters.aidl
package app.revanced.manager.patcher.runtime.process;
parcelable Parameters;

View File

@@ -0,0 +1,6 @@
id=__PKG_NAME__-ReVanced
name=__LABEL__ ReVanced
version=__VERSION__
versionCode=0
author=ReVanced
description=Mounts the patched APK on top of the original one

View File

@@ -0,0 +1,40 @@
#!/system/bin/sh
DIR=${0%/*}
package_name="__PKG_NAME__"
version="__VERSION__"
rm "$DIR/log"
{
until [ "$(getprop sys.boot_completed)" = 1 ]; do sleep 5; done
sleep 5
base_path="$DIR/$package_name.apk"
stock_path="$(pm path "$package_name" | grep base | sed 's/package://g')"
stock_version="$(dumpsys package "$package_name" | grep versionName | cut -d "=" -f2)"
echo "base_path: $base_path"
echo "stock_path: $stock_path"
echo "base_version: $version"
echo "stock_version: $stock_version"
if mount | grep -q "$stock_path" ; then
echo "Not mounting as stock path is already mounted"
exit 1
fi
if [ "$version" != "$stock_version" ]; then
echo "Not mounting as versions don't match"
exit 1
fi
if [ -z "$stock_path" ]; then
echo "Not mounting as app info could not be loaded"
exit 1
fi
mount -o bind "$base_path" "$stock_path"
} >> "$DIR/log"

View File

@@ -0,0 +1,38 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.
# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("prop_override")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
# is preferred for the same purpose.
#
# In order to load a library into your app from Java/Kotlin, you must call
# System.loadLibrary() and pass the name of the library defined here;
# for GameActivity/NativeActivity derived applications, the same library name must be
# used in the AndroidManifest.xml file.
add_library(${CMAKE_PROJECT_NAME} SHARED
# List C/C++ source files with relative paths to this CMakeLists.txt.
prop_override.cpp)
# Specifies libraries CMake should link to your target library. You
# can link libraries from various origins, such as libraries defined in this
# build script, prebuilt third-party libraries, or Android system libraries.
target_link_libraries(${CMAKE_PROJECT_NAME}
# List libraries link to the target library
android
log)

View File

@@ -0,0 +1,62 @@
// Library for overriding Android system properties via environment variables.
//
// Usage: LD_PRELOAD=prop_override.so PROP_dalvik.vm.heapsize=123M getprop dalvik.vm.heapsize
// Output: 123M
#include <string>
#include <cstring>
#include <cstdlib>
#include <dlfcn.h>
// Source: https://android.googlesource.com/platform/system/core/+/100b08a848d018eeb1caa5d5e7c7c2aaac65da15/libcutils/include/cutils/properties.h
#define PROP_VALUE_MAX 92
// This is the mangled name of "android::base::GetProperty".
#define GET_PROPERTY_MANGLED_NAME "_ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_"
extern "C" typedef int (*property_get_ptr)(const char *, char *, const char *);
typedef std::string (*GetProperty_ptr)(const std::string &, const std::string &);
char *GetPropOverride(const std::string &key) {
auto envKey = "PROP_" + key;
return getenv(envKey.c_str());
}
// See: https://android.googlesource.com/platform/system/core/+/100b08a848d018eeb1caa5d5e7c7c2aaac65da15/libcutils/properties.cpp
extern "C" int property_get(const char *key, char *value, const char *default_value) {
auto replacement = GetPropOverride(std::string(key));
if (replacement) {
int len = strnlen(replacement, PROP_VALUE_MAX);
strncpy(value, replacement, len);
return len;
}
static property_get_ptr original = NULL;
if (!original) {
// Get the address of the original function.
original = reinterpret_cast<property_get_ptr>(dlsym(RTLD_NEXT, "property_get"));
}
return original(key, value, default_value);
}
// Defining android::base::GetProperty ourselves won't work because std::string has a slightly different "path" in the NDK version of the C++ standard library.
// We can get around this by forcing the function to adopt a specific name using the asm keyword.
std::string GetProperty(const std::string &, const std::string &) asm(GET_PROPERTY_MANGLED_NAME);
// See: https://android.googlesource.com/platform/system/libbase/+/1a34bb67c4f3ba0a1ea6f4f20ac9fe117ba4fe64/properties.cpp
// This isn't used for the properties we want to override, but property_get is deprecated so that could change in the future.
std::string GetProperty(const std::string &key, const std::string &default_value) {
auto replacement = GetPropOverride(key);
if (replacement) {
return std::string(replacement);
}
static GetProperty_ptr original = NULL;
if (!original) {
original = reinterpret_cast<GetProperty_ptr>(dlsym(RTLD_NEXT, GET_PROPERTY_MANGLED_NAME));
}
return original(key, default_value);
}

View File

@@ -0,0 +1,335 @@
package app.revanced.manager
import android.content.ActivityNotFoundException
import android.os.Bundle
import android.os.Parcelable
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import app.revanced.manager.ui.model.navigation.AppSelector
import app.revanced.manager.ui.model.navigation.ComplexParameter
import app.revanced.manager.ui.model.navigation.Dashboard
import app.revanced.manager.ui.model.navigation.InstalledApplicationInfo
import app.revanced.manager.ui.model.navigation.Patcher
import app.revanced.manager.ui.model.navigation.SelectedApplicationInfo
import app.revanced.manager.ui.model.navigation.Settings
import app.revanced.manager.ui.model.navigation.Update
import app.revanced.manager.ui.screen.AppSelectorScreen
import app.revanced.manager.ui.screen.DashboardScreen
import app.revanced.manager.ui.screen.InstalledAppInfoScreen
import app.revanced.manager.ui.screen.PatcherScreen
import app.revanced.manager.ui.screen.PatchesSelectorScreen
import app.revanced.manager.ui.screen.RequiredOptionsScreen
import app.revanced.manager.ui.screen.SelectedAppInfoScreen
import app.revanced.manager.ui.screen.SettingsScreen
import app.revanced.manager.ui.screen.UpdateScreen
import app.revanced.manager.ui.screen.settings.AboutSettingsScreen
import app.revanced.manager.ui.screen.settings.AdvancedSettingsScreen
import app.revanced.manager.ui.screen.settings.ContributorScreen
import app.revanced.manager.ui.screen.settings.DeveloperOptionsScreen
import app.revanced.manager.ui.screen.settings.DownloadsSettingsScreen
import app.revanced.manager.ui.screen.settings.GeneralSettingsScreen
import app.revanced.manager.ui.screen.settings.ImportExportSettingsScreen
import app.revanced.manager.ui.screen.settings.LicensesScreen
import app.revanced.manager.ui.screen.settings.update.ChangelogsScreen
import app.revanced.manager.ui.screen.settings.update.UpdatesSettingsScreen
import app.revanced.manager.ui.theme.ReVancedManagerTheme
import app.revanced.manager.ui.theme.Theme
import app.revanced.manager.ui.viewmodel.MainViewModel
import app.revanced.manager.ui.viewmodel.SelectedAppInfoViewModel
import app.revanced.manager.util.EventEffect
import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel
import org.koin.androidx.compose.navigation.koinNavViewModel
import org.koin.core.parameter.parametersOf
import org.koin.androidx.viewmodel.ext.android.getViewModel as getActivityViewModel
class MainActivity : ComponentActivity() {
@ExperimentalAnimationApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
enableEdgeToEdge()
installSplashScreen()
val vm: MainViewModel = getActivityViewModel()
setContent {
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.StartActivityForResult(),
onResult = vm::applyLegacySettings
)
val theme by vm.prefs.theme.getAsState()
val dynamicColor by vm.prefs.dynamicColor.getAsState()
EventEffect(vm.legacyImportActivityFlow) {
try {
launcher.launch(it)
} catch (_: ActivityNotFoundException) {
}
}
ReVancedManagerTheme(
darkTheme = theme == Theme.SYSTEM && isSystemInDarkTheme() || theme == Theme.DARK,
dynamicColor = dynamicColor
) {
ReVancedManager(vm)
}
}
}
}
@Composable
private fun ReVancedManager(vm: MainViewModel) {
val navController = rememberNavController()
EventEffect(vm.appSelectFlow) { app ->
navController.navigateComplex(
SelectedApplicationInfo,
SelectedApplicationInfo.ViewModelParams(app)
)
}
NavHost(
navController = navController,
startDestination = Dashboard,
enterTransition = { slideInHorizontally(initialOffsetX = { it }) },
exitTransition = { slideOutHorizontally(targetOffsetX = { -it / 3 }) },
popEnterTransition = { slideInHorizontally(initialOffsetX = { -it / 3 }) },
popExitTransition = { slideOutHorizontally(targetOffsetX = { it }) },
) {
composable<Dashboard> {
DashboardScreen(
onSettingsClick = { navController.navigate(Settings) },
onAppSelectorClick = {
navController.navigate(AppSelector)
},
onUpdateClick = {
navController.navigate(Update())
},
onDownloaderPluginClick = {
navController.navigate(Settings.Downloads)
},
onAppClick = { packageName ->
navController.navigate(InstalledApplicationInfo(packageName))
}
)
}
composable<InstalledApplicationInfo> {
val data = it.toRoute<InstalledApplicationInfo>()
InstalledAppInfoScreen(
onPatchClick = vm::selectApp,
onBackClick = navController::popBackStack,
viewModel = koinViewModel { parametersOf(data.packageName) }
)
}
composable<AppSelector> {
AppSelectorScreen(
onSelect = vm::selectApp,
onStorageSelect = vm::selectApp,
onBackClick = navController::popBackStack
)
}
composable<Patcher> {
PatcherScreen(
onBackClick = {
navController.navigate(route = Dashboard) {
launchSingleTop = true
popUpTo<Dashboard> {
inclusive = false
}
}
},
vm = koinViewModel { parametersOf(it.getComplexArg<Patcher.ViewModelParams>()) }
)
}
composable<Update> {
val data = it.toRoute<Update>()
UpdateScreen(
onBackClick = navController::popBackStack,
vm = koinViewModel { parametersOf(data.downloadOnScreenEntry) }
)
}
navigation<SelectedApplicationInfo>(startDestination = SelectedApplicationInfo.Main) {
composable<SelectedApplicationInfo.Main> {
val parentBackStackEntry = navController.navGraphEntry(it)
val data =
parentBackStackEntry.getComplexArg<SelectedApplicationInfo.ViewModelParams>()
val viewModel =
koinNavViewModel<SelectedAppInfoViewModel>(viewModelStoreOwner = parentBackStackEntry) {
parametersOf(data)
}
SelectedAppInfoScreen(
onBackClick = navController::popBackStack,
onPatchClick = {
it.lifecycleScope.launch {
navController.navigateComplex(
Patcher,
viewModel.getPatcherParams()
)
}
},
onPatchSelectorClick = { app, patches, options ->
navController.navigateComplex(
SelectedApplicationInfo.PatchesSelector,
SelectedApplicationInfo.PatchesSelector.ViewModelParams(
app,
patches,
options
)
)
},
onRequiredOptions = { app, patches, options ->
navController.navigateComplex(
SelectedApplicationInfo.RequiredOptions,
SelectedApplicationInfo.PatchesSelector.ViewModelParams(
app,
patches,
options
)
)
},
vm = viewModel
)
}
composable<SelectedApplicationInfo.PatchesSelector> {
val data =
it.getComplexArg<SelectedApplicationInfo.PatchesSelector.ViewModelParams>()
val selectedAppInfoVm = koinNavViewModel<SelectedAppInfoViewModel>(
viewModelStoreOwner = navController.navGraphEntry(it)
)
PatchesSelectorScreen(
onBackClick = navController::popBackStack,
onSave = { patches, options ->
selectedAppInfoVm.updateConfiguration(patches, options)
navController.popBackStack()
},
vm = koinViewModel { parametersOf(data) }
)
}
composable<SelectedApplicationInfo.RequiredOptions> {
val data =
it.getComplexArg<SelectedApplicationInfo.PatchesSelector.ViewModelParams>()
val selectedAppInfoVm = koinNavViewModel<SelectedAppInfoViewModel>(
viewModelStoreOwner = navController.navGraphEntry(it)
)
RequiredOptionsScreen(
onBackClick = navController::popBackStack,
onContinue = { patches, options ->
selectedAppInfoVm.updateConfiguration(patches, options)
it.lifecycleScope.launch {
navController.navigateComplex(
Patcher,
selectedAppInfoVm.getPatcherParams()
)
}
},
vm = koinViewModel { parametersOf(data) }
)
}
}
navigation<Settings>(startDestination = Settings.Main) {
composable<Settings.Main> {
SettingsScreen(
onBackClick = navController::popBackStack,
navigate = navController::navigate
)
}
composable<Settings.General> {
GeneralSettingsScreen(onBackClick = navController::popBackStack)
}
composable<Settings.Advanced> {
AdvancedSettingsScreen(onBackClick = navController::popBackStack)
}
composable<Settings.Updates> {
UpdatesSettingsScreen(
onBackClick = navController::popBackStack,
onChangelogClick = { navController.navigate(Settings.Changelogs) },
onUpdateClick = { navController.navigate(Update()) }
)
}
composable<Settings.Downloads> {
DownloadsSettingsScreen(onBackClick = navController::popBackStack)
}
composable<Settings.ImportExport> {
ImportExportSettingsScreen(onBackClick = navController::popBackStack)
}
composable<Settings.About> {
AboutSettingsScreen(
onBackClick = navController::popBackStack,
navigate = navController::navigate
)
}
composable<Settings.Changelogs> {
ChangelogsScreen(onBackClick = navController::popBackStack)
}
composable<Settings.Contributors> {
ContributorScreen(onBackClick = navController::popBackStack)
}
composable<Settings.Licenses> {
LicensesScreen(onBackClick = navController::popBackStack)
}
composable<Settings.DeveloperOptions> {
DeveloperOptionsScreen(onBackClick = navController::popBackStack)
}
}
}
}
@Composable
private fun NavController.navGraphEntry(entry: NavBackStackEntry) =
remember(entry) { getBackStackEntry(entry.destination.parent!!.id) }
// Androidx Navigation does not support storing complex types in route objects, so we have to store them inside the saved state handle of the back stack entry instead.
private fun <T : Parcelable, R : ComplexParameter<T>> NavController.navigateComplex(
route: R,
data: T
) {
navigate(route)
getBackStackEntry(route).savedStateHandle["args"] = data
}
private fun <T : Parcelable> NavBackStackEntry.getComplexArg() = savedStateHandle.get<T>("args")!!

View File

@@ -0,0 +1,110 @@
package app.revanced.manager
import android.app.Activity
import android.app.Application
import android.os.Bundle
import android.util.Log
import app.revanced.manager.data.platform.Filesystem
import app.revanced.manager.di.*
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.domain.repository.DownloaderPluginRepository
import app.revanced.manager.domain.repository.PatchBundleRepository
import app.revanced.manager.util.tag
import kotlinx.coroutines.Dispatchers
import coil.Coil
import coil.ImageLoader
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.BuilderImpl
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
import org.koin.android.ext.android.inject
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.androidx.workmanager.koin.workManagerFactory
import org.koin.core.context.startKoin
class ManagerApplication : Application() {
private val scope = MainScope()
private val prefs: PreferencesManager by inject()
private val patchBundleRepository: PatchBundleRepository by inject()
private val downloaderPluginRepository: DownloaderPluginRepository by inject()
private val fs: Filesystem by inject()
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@ManagerApplication)
androidLogger()
workManagerFactory()
modules(
httpModule,
preferencesModule,
repositoryModule,
serviceModule,
managerModule,
workerModule,
viewModelModule,
databaseModule,
rootModule
)
}
val pixels = 512
Coil.setImageLoader(
ImageLoader.Builder(this)
.components {
add(AppIconKeyer())
add(AppIconFetcher.Factory(pixels, true, this@ManagerApplication))
}
.build()
)
val shellBuilder = BuilderImpl.create().setFlags(Shell.FLAG_MOUNT_MASTER)
Shell.setDefaultBuilder(shellBuilder)
scope.launch {
prefs.preload()
}
scope.launch(Dispatchers.Default) {
downloaderPluginRepository.reload()
}
scope.launch(Dispatchers.Default) {
with(patchBundleRepository) {
reload()
updateCheck()
}
}
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
private var firstActivityCreated = false
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
if (firstActivityCreated) return
firstActivityCreated = true
// We do not want to call onFreshProcessStart() if there is state to restore.
// This can happen on system-initiated process death.
if (savedInstanceState == null) {
Log.d(tag, "Fresh process created")
onFreshProcessStart()
} else Log.d(tag, "System-initiated process death detected")
}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
})
}
private fun onFreshProcessStart() {
fs.uiTempDir.apply {
deleteRecursively()
mkdirs()
}
}
}

View File

@@ -0,0 +1,51 @@
package app.revanced.manager.data.platform
import android.Manifest
import android.app.Application
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Environment
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.result.contract.ActivityResultContracts
import app.revanced.manager.util.RequestManageStorageContract
import java.io.File
import java.nio.file.Path
class Filesystem(private val app: Application) {
val contentResolver = app.contentResolver // TODO: move Content Resolver operations to here.
/**
* A directory that gets cleared when the app restarts.
* Do not store paths to this directory in a parcel.
*/
val tempDir: File = app.getDir("ephemeral", Context.MODE_PRIVATE).apply {
deleteRecursively()
mkdirs()
}
/**
* A directory for storing temporary files related to UI.
* This is the same as [tempDir], but does not get cleared on system-initiated process death.
* Paths to this directory can be safely stored in parcels.
*/
val uiTempDir: File = app.getDir("ui_ephemeral", Context.MODE_PRIVATE)
fun externalFilesDir(): Path = Environment.getExternalStorageDirectory().toPath()
private fun usesManagePermission() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
private val storagePermissionName =
if (usesManagePermission()) Manifest.permission.MANAGE_EXTERNAL_STORAGE else Manifest.permission.READ_EXTERNAL_STORAGE
fun permissionContract(): Pair<ActivityResultContract<String, Boolean>, String> {
val contract =
if (usesManagePermission()) RequestManageStorageContract() else ActivityResultContracts.RequestPermission()
return contract to storagePermissionName
}
fun hasStoragePermission() =
if (usesManagePermission()) Environment.isExternalStorageManager() else app.checkSelfPermission(
storagePermissionName
) == PackageManager.PERMISSION_GRANTED
}

View File

@@ -0,0 +1,19 @@
package app.revanced.manager.data.platform
import android.app.Application
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import androidx.core.content.getSystemService
class NetworkInfo(app: Application) {
private val connectivityManager = app.getSystemService<ConnectivityManager>()!!
private fun getCapabilities() = connectivityManager.activeNetwork?.let { connectivityManager.getNetworkCapabilities(it) }
fun isConnected() = connectivityManager.activeNetwork != null
fun isUnmetered() = getCapabilities()?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) ?: true
/**
* Returns true if it is safe to download large files.
*/
fun isSafe() = isConnected() && isUnmetered()
}

View File

@@ -0,0 +1,39 @@
package app.revanced.manager.data.room
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import app.revanced.manager.data.room.apps.downloaded.DownloadedAppDao
import app.revanced.manager.data.room.apps.downloaded.DownloadedApp
import app.revanced.manager.data.room.apps.installed.AppliedPatch
import app.revanced.manager.data.room.apps.installed.InstalledApp
import app.revanced.manager.data.room.apps.installed.InstalledAppDao
import app.revanced.manager.data.room.selection.PatchSelection
import app.revanced.manager.data.room.selection.SelectedPatch
import app.revanced.manager.data.room.selection.SelectionDao
import app.revanced.manager.data.room.bundles.PatchBundleDao
import app.revanced.manager.data.room.bundles.PatchBundleEntity
import app.revanced.manager.data.room.options.Option
import app.revanced.manager.data.room.options.OptionDao
import app.revanced.manager.data.room.options.OptionGroup
import app.revanced.manager.data.room.plugins.TrustedDownloaderPlugin
import app.revanced.manager.data.room.plugins.TrustedDownloaderPluginDao
import kotlin.random.Random
@Database(
entities = [PatchBundleEntity::class, PatchSelection::class, SelectedPatch::class, DownloadedApp::class, InstalledApp::class, AppliedPatch::class, OptionGroup::class, Option::class, TrustedDownloaderPlugin::class],
version = 1
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun patchBundleDao(): PatchBundleDao
abstract fun selectionDao(): SelectionDao
abstract fun downloadedAppDao(): DownloadedAppDao
abstract fun installedAppDao(): InstalledAppDao
abstract fun optionDao(): OptionDao
abstract fun trustedDownloaderPluginDao(): TrustedDownloaderPluginDao
companion object {
fun generateUid() = Random.Default.nextInt()
}
}

View File

@@ -0,0 +1,26 @@
package app.revanced.manager.data.room
import androidx.room.TypeConverter
import app.revanced.manager.data.room.bundles.Source
import app.revanced.manager.data.room.options.Option.SerializedValue
import java.io.File
class Converters {
@TypeConverter
fun sourceFromString(value: String) = Source.from(value)
@TypeConverter
fun sourceToString(value: Source) = value.toString()
@TypeConverter
fun fileFromString(value: String) = File(value)
@TypeConverter
fun fileToString(file: File): String = file.path
@TypeConverter
fun serializedOptionFromString(value: String) = SerializedValue.fromJsonString(value)
@TypeConverter
fun serializedOptionToString(value: SerializedValue) = value.toJsonString()
}

View File

@@ -0,0 +1,16 @@
package app.revanced.manager.data.room.apps.downloaded
import androidx.room.ColumnInfo
import androidx.room.Entity
import java.io.File
@Entity(
tableName = "downloaded_app",
primaryKeys = ["package_name", "version"]
)
data class DownloadedApp(
@ColumnInfo(name = "package_name") val packageName: String,
@ColumnInfo(name = "version") val version: String,
@ColumnInfo(name = "directory") val directory: File,
@ColumnInfo(name = "last_used") val lastUsed: Long = System.currentTimeMillis()
)

View File

@@ -0,0 +1,26 @@
package app.revanced.manager.data.room.apps.downloaded
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Upsert
import kotlinx.coroutines.flow.Flow
@Dao
interface DownloadedAppDao {
@Query("SELECT * FROM downloaded_app")
fun getAllApps(): Flow<List<DownloadedApp>>
@Query("SELECT * FROM downloaded_app WHERE package_name = :packageName AND version = :version")
suspend fun get(packageName: String, version: String): DownloadedApp?
@Upsert
suspend fun upsert(downloadedApp: DownloadedApp)
@Query("UPDATE downloaded_app SET last_used = :newValue WHERE package_name = :packageName AND version = :version")
suspend fun markUsed(packageName: String, version: String, newValue: Long = System.currentTimeMillis())
@Delete
suspend fun delete(downloadedApps: Collection<DownloadedApp>)
}

View File

@@ -0,0 +1,35 @@
package app.revanced.manager.data.room.apps.installed
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import app.revanced.manager.data.room.bundles.PatchBundleEntity
import kotlinx.parcelize.Parcelize
@Parcelize
@Entity(
tableName = "applied_patch",
primaryKeys = ["package_name", "bundle", "patch_name"],
foreignKeys = [
ForeignKey(
InstalledApp::class,
parentColumns = ["current_package_name"],
childColumns = ["package_name"],
onDelete = ForeignKey.CASCADE
),
ForeignKey(
PatchBundleEntity::class,
parentColumns = ["uid"],
childColumns = ["bundle"],
onDelete = ForeignKey.CASCADE
)
],
indices = [Index(value = ["bundle"], unique = false)]
)
data class AppliedPatch(
@ColumnInfo(name = "package_name") val packageName: String,
@ColumnInfo(name = "bundle") val bundle: Int,
@ColumnInfo(name = "patch_name") val patchName: String
) : Parcelable

View File

@@ -0,0 +1,20 @@
package app.revanced.manager.data.room.apps.installed
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import app.revanced.manager.R
enum class InstallType(val stringResource: Int) {
DEFAULT(R.string.default_install),
MOUNT(R.string.mount_install)
}
@Entity(tableName = "installed_app")
data class InstalledApp(
@PrimaryKey
@ColumnInfo(name = "current_package_name") val currentPackageName: String,
@ColumnInfo(name = "original_package_name") val originalPackageName: String,
@ColumnInfo(name = "version") val version: String,
@ColumnInfo(name = "install_type") val installType: InstallType
)

View File

@@ -0,0 +1,46 @@
package app.revanced.manager.data.room.apps.installed
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.MapColumn
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Upsert
import kotlinx.coroutines.flow.Flow
@Dao
interface InstalledAppDao {
@Query("SELECT * FROM installed_app")
fun getAll(): Flow<List<InstalledApp>>
@Query("SELECT * FROM installed_app WHERE current_package_name = :packageName")
suspend fun get(packageName: String): InstalledApp?
@Query(
"SELECT bundle, patch_name FROM applied_patch" +
" WHERE package_name = :packageName"
)
suspend fun getPatchesSelection(packageName: String): Map<@MapColumn("bundle") Int, List<@MapColumn(
"patch_name"
) String>>
@Transaction
suspend fun upsertApp(installedApp: InstalledApp, appliedPatches: List<AppliedPatch>) {
upsertApp(installedApp)
deleteAppliedPatches(installedApp.currentPackageName)
insertAppliedPatches(appliedPatches)
}
@Upsert
suspend fun upsertApp(installedApp: InstalledApp)
@Insert
suspend fun insertAppliedPatches(appliedPatches: List<AppliedPatch>)
@Query("DELETE FROM applied_patch WHERE package_name = :packageName")
suspend fun deleteAppliedPatches(packageName: String)
@Delete
suspend fun delete(installedApp: InstalledApp)
}

View File

@@ -0,0 +1,37 @@
package app.revanced.manager.data.room.bundles
import androidx.room.*
import kotlinx.coroutines.flow.Flow
@Dao
interface PatchBundleDao {
@Query("SELECT * FROM patch_bundles")
suspend fun all(): List<PatchBundleEntity>
@Query("SELECT version, auto_update FROM patch_bundles WHERE uid = :uid")
fun getPropsById(uid: Int): Flow<BundleProperties?>
@Query("UPDATE patch_bundles SET version = :patches WHERE uid = :uid")
suspend fun updateVersion(uid: Int, patches: String?)
@Query("UPDATE patch_bundles SET auto_update = :value WHERE uid = :uid")
suspend fun setAutoUpdate(uid: Int, value: Boolean)
@Query("UPDATE patch_bundles SET name = :value WHERE uid = :uid")
suspend fun setName(uid: Int, value: String)
@Query("DELETE FROM patch_bundles WHERE uid != 0")
suspend fun purgeCustomBundles()
@Transaction
suspend fun reset() {
purgeCustomBundles()
updateVersion(0, null) // Reset the main source
}
@Query("DELETE FROM patch_bundles WHERE uid = :uid")
suspend fun remove(uid: Int)
@Insert
suspend fun add(source: PatchBundleEntity)
}

View File

@@ -0,0 +1,44 @@
package app.revanced.manager.data.room.bundles
import androidx.room.*
import io.ktor.http.*
sealed class Source {
object Local : Source() {
const val SENTINEL = "local"
override fun toString() = SENTINEL
}
object API : Source() {
const val SENTINEL = "api"
override fun toString() = SENTINEL
}
data class Remote(val url: Url) : Source() {
override fun toString() = url.toString()
}
companion object {
fun from(value: String) = when (value) {
Local.SENTINEL -> Local
API.SENTINEL -> API
else -> Remote(Url(value))
}
}
}
@Entity(tableName = "patch_bundles")
data class PatchBundleEntity(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "version") val version: String? = null,
@ColumnInfo(name = "source") val source: Source,
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean
)
data class BundleProperties(
@ColumnInfo(name = "version") val version: String? = null,
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean
)

View File

@@ -0,0 +1,116 @@
package app.revanced.manager.data.room.options
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import app.revanced.manager.patcher.patch.Option
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.add
import kotlinx.serialization.json.boolean
import kotlinx.serialization.json.buildJsonArray
import kotlinx.serialization.json.float
import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.long
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.typeOf
@Entity(
tableName = "options",
primaryKeys = ["group", "patch_name", "key"],
foreignKeys = [ForeignKey(
OptionGroup::class,
parentColumns = ["uid"],
childColumns = ["group"],
onDelete = ForeignKey.CASCADE
)]
)
data class Option(
@ColumnInfo(name = "group") val group: Int,
@ColumnInfo(name = "patch_name") val patchName: String,
@ColumnInfo(name = "key") val key: String,
// Encoded as Json.
@ColumnInfo(name = "value") val value: SerializedValue,
) {
@Serializable
data class SerializedValue(val raw: JsonElement) {
fun toJsonString() = json.encodeToString(raw)
fun deserializeFor(option: Option<*>): Any? {
if (raw is JsonNull) return null
val errorMessage = "Cannot deserialize value as ${option.type}"
try {
if (option.type.classifier == List::class) {
val elementType = option.type.arguments.first().type!!
return raw.jsonArray.map { deserializeBasicType(elementType, it.jsonPrimitive) }
}
return deserializeBasicType(option.type, raw.jsonPrimitive)
} catch (e: IllegalArgumentException) {
throw SerializationException(errorMessage, e)
} catch (e: IllegalStateException) {
throw SerializationException(errorMessage, e)
} catch (e: kotlinx.serialization.SerializationException) {
throw SerializationException(errorMessage, e)
}
}
companion object {
private val json = Json {
// Patcher does not forbid the use of these values, so we should support them.
allowSpecialFloatingPointValues = true
}
private fun deserializeBasicType(type: KType, value: JsonPrimitive) = when (type) {
typeOf<Boolean>() -> value.boolean
typeOf<Int>() -> value.int
typeOf<Long>() -> value.long
typeOf<Float>() -> value.float
typeOf<String>() -> value.content.also {
if (!value.isString) throw SerializationException(
"Expected value to be a string: $value"
)
}
else -> throw SerializationException("Unknown type: $type")
}
fun fromJsonString(value: String) = SerializedValue(json.decodeFromString(value))
fun fromValue(value: Any?) = SerializedValue(when (value) {
null -> JsonNull
is Number -> JsonPrimitive(value)
is Boolean -> JsonPrimitive(value)
is String -> JsonPrimitive(value)
is List<*> -> buildJsonArray {
var elementClass: KClass<out Any>? = null
value.forEach {
when (it) {
null -> throw SerializationException("List elements must not be null")
is Number -> add(it)
is Boolean -> add(it)
is String -> add(it)
else -> throw SerializationException("Unknown element type: ${it::class.simpleName}")
}
if (elementClass == null) elementClass = it::class
else if (elementClass != it::class) throw SerializationException("List elements must have the same type")
}
}
else -> throw SerializationException("Unknown type: ${value::class.simpleName}")
})
}
}
class SerializationException(message: String, cause: Throwable? = null) :
Exception(message, cause)
}

View File

@@ -0,0 +1,50 @@
package app.revanced.manager.data.room.options
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.MapColumn
import androidx.room.Query
import androidx.room.Transaction
import kotlinx.coroutines.flow.Flow
@Dao
abstract class OptionDao {
@Transaction
@Query(
"SELECT patch_bundle, `group`, patch_name, `key`, value FROM option_groups" +
" LEFT JOIN options ON uid = options.`group`" +
" WHERE package_name = :packageName"
)
abstract suspend fun getOptions(packageName: String): Map<@MapColumn("patch_bundle") Int, List<Option>>
@Query("SELECT uid FROM option_groups WHERE patch_bundle = :bundleUid AND package_name = :packageName")
abstract suspend fun getGroupId(bundleUid: Int, packageName: String): Int?
@Query("SELECT package_name FROM option_groups")
abstract fun getPackagesWithOptions(): Flow<List<String>>
@Insert
abstract suspend fun createOptionGroup(group: OptionGroup)
@Query("DELETE FROM option_groups WHERE patch_bundle = :uid")
abstract suspend fun clearForPatchBundle(uid: Int)
@Query("DELETE FROM option_groups WHERE package_name = :packageName")
abstract suspend fun clearForPackage(packageName: String)
@Query("DELETE FROM option_groups")
abstract suspend fun reset()
@Insert
protected abstract suspend fun insertOptions(patches: List<Option>)
@Query("DELETE FROM options WHERE `group` = :groupId")
protected abstract suspend fun clearGroup(groupId: Int)
@Transaction
open suspend fun updateOptions(options: Map<Int, List<Option>>) =
options.forEach { (groupId, options) ->
clearGroup(groupId)
insertOptions(options)
}
}

View File

@@ -0,0 +1,24 @@
package app.revanced.manager.data.room.options
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import app.revanced.manager.data.room.bundles.PatchBundleEntity
@Entity(
tableName = "option_groups",
foreignKeys = [ForeignKey(
PatchBundleEntity::class,
parentColumns = ["uid"],
childColumns = ["patch_bundle"],
onDelete = ForeignKey.CASCADE
)],
indices = [Index(value = ["patch_bundle", "package_name"], unique = true)]
)
data class OptionGroup(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "patch_bundle") val patchBundle: Int,
@ColumnInfo(name = "package_name") val packageName: String
)

View File

@@ -0,0 +1,11 @@
package app.revanced.manager.data.room.plugins
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "trusted_downloader_plugins")
class TrustedDownloaderPlugin(
@PrimaryKey @ColumnInfo(name = "package_name") val packageName: String,
@ColumnInfo(name = "signature") val signature: ByteArray
)

View File

@@ -0,0 +1,22 @@
package app.revanced.manager.data.room.plugins
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Upsert
@Dao
interface TrustedDownloaderPluginDao {
@Query("SELECT signature FROM trusted_downloader_plugins WHERE package_name = :packageName")
suspend fun getTrustedSignature(packageName: String): ByteArray?
@Upsert
suspend fun upsertTrust(plugin: TrustedDownloaderPlugin)
@Query("DELETE FROM trusted_downloader_plugins WHERE package_name = :packageName")
suspend fun remove(packageName: String)
@Transaction
@Query("DELETE FROM trusted_downloader_plugins WHERE package_name IN (:packageNames)")
suspend fun removeAll(packageNames: Set<String>)
}

View File

@@ -0,0 +1,24 @@
package app.revanced.manager.data.room.selection
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import app.revanced.manager.data.room.bundles.PatchBundleEntity
@Entity(
tableName = "patch_selections",
foreignKeys = [ForeignKey(
PatchBundleEntity::class,
parentColumns = ["uid"],
childColumns = ["patch_bundle"],
onDelete = ForeignKey.CASCADE
)],
indices = [Index(value = ["patch_bundle", "package_name"], unique = true)]
)
data class PatchSelection(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "patch_bundle") val patchBundle: Int,
@ColumnInfo(name = "package_name") val packageName: String
)

View File

@@ -0,0 +1,20 @@
package app.revanced.manager.data.room.selection
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
@Entity(
tableName = "selected_patches",
primaryKeys = ["selection", "patch_name"],
foreignKeys = [ForeignKey(
PatchSelection::class,
parentColumns = ["uid"],
childColumns = ["selection"],
onDelete = ForeignKey.CASCADE
)]
)
data class SelectedPatch(
@ColumnInfo(name = "selection") val selection: Int,
@ColumnInfo(name = "patch_name") val patchName: String
)

View File

@@ -0,0 +1,58 @@
package app.revanced.manager.data.room.selection
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.MapColumn
import androidx.room.Query
import androidx.room.Transaction
@Dao
abstract class SelectionDao {
@Transaction
@Query(
"SELECT patch_bundle, patch_name FROM patch_selections" +
" LEFT JOIN selected_patches ON uid = selected_patches.selection" +
" WHERE package_name = :packageName"
)
abstract suspend fun getSelectedPatches(packageName: String): Map<@MapColumn("patch_bundle") Int, List<@MapColumn(
"patch_name"
) String>>
@Transaction
@Query(
"SELECT package_name, patch_name FROM patch_selections" +
" LEFT JOIN selected_patches ON uid = selected_patches.selection" +
" WHERE patch_bundle = :bundleUid"
)
abstract suspend fun exportSelection(bundleUid: Int): Map<@MapColumn("package_name") String, List<@MapColumn(
"patch_name"
) String>>
@Query("SELECT uid FROM patch_selections WHERE patch_bundle = :bundleUid AND package_name = :packageName")
abstract suspend fun getSelectionId(bundleUid: Int, packageName: String): Int?
@Insert
abstract suspend fun createSelection(selection: PatchSelection)
@Query("DELETE FROM patch_selections WHERE patch_bundle = :uid")
abstract suspend fun clearForPatchBundle(uid: Int)
@Query("DELETE FROM patch_selections WHERE package_name = :packageName")
abstract suspend fun clearForPackage(packageName: String)
@Query("DELETE FROM patch_selections")
abstract suspend fun reset()
@Insert
protected abstract suspend fun selectPatches(patches: List<SelectedPatch>)
@Query("DELETE FROM selected_patches WHERE selection = :selectionId")
protected abstract suspend fun clearSelection(selectionId: Int)
@Transaction
open suspend fun updateSelections(selections: Map<Int, Set<String>>) =
selections.forEach { (selectionUid, patches) ->
clearSelection(selectionUid)
selectPatches(patches.map { SelectedPatch(selectionUid, it) })
}
}

View File

@@ -0,0 +1,15 @@
package app.revanced.manager.di
import android.content.Context
import androidx.room.Room
import app.revanced.manager.data.room.AppDatabase
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
val databaseModule = module {
fun provideAppDatabase(context: Context) = Room.databaseBuilder(context, AppDatabase::class.java, "manager").build()
single {
provideAppDatabase(androidContext())
}
}

View File

@@ -0,0 +1,60 @@
package app.revanced.manager.di
import android.content.Context
import app.revanced.manager.BuildConfig
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.plugins.UserAgent
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
import okhttp3.Cache
import okhttp3.Dns
import org.koin.android.ext.koin.androidContext
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
import java.net.Inet4Address
import java.net.InetAddress
val httpModule = module {
fun provideHttpClient(context: Context, json: Json) = HttpClient(OkHttp) {
engine {
config {
dns(object : Dns {
override fun lookup(hostname: String): List<InetAddress> {
val addresses = Dns.SYSTEM.lookup(hostname)
return if (hostname == "raw.githubusercontent.com") {
addresses.filterIsInstance<Inet4Address>()
} else {
addresses
}
}
})
cache(Cache(context.cacheDir.resolve("cache").also { it.mkdirs() }, 1024 * 1024 * 100))
followRedirects(true)
followSslRedirects(true)
}
}
install(ContentNegotiation) {
json(json)
}
install(HttpTimeout) {
socketTimeoutMillis = 10000
}
install(UserAgent) {
agent = "ReVanced-Manager/${BuildConfig.VERSION_CODE}"
}
}
fun provideJson() = Json {
encodeDefaults = true
isLenient = true
ignoreUnknownKeys = true
}
single {
provideHttpClient(androidContext(), get())
}
singleOf(::provideJson)
}

View File

@@ -0,0 +1,11 @@
package app.revanced.manager.di
import app.revanced.manager.domain.manager.KeystoreManager
import app.revanced.manager.util.PM
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
val managerModule = module {
singleOf(::KeystoreManager)
singleOf(::PM)
}

View File

@@ -0,0 +1,9 @@
package app.revanced.manager.di
import app.revanced.manager.domain.manager.PreferencesManager
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
val preferencesModule = module {
singleOf(::PreferencesManager)
}

View File

@@ -0,0 +1,29 @@
package app.revanced.manager.di
import app.revanced.manager.data.platform.Filesystem
import app.revanced.manager.data.platform.NetworkInfo
import app.revanced.manager.domain.repository.*
import app.revanced.manager.domain.worker.WorkerRepository
import app.revanced.manager.network.api.ReVancedAPI
import org.koin.core.module.dsl.createdAtStart
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
val repositoryModule = module {
singleOf(::ReVancedAPI)
singleOf(::Filesystem) {
createdAtStart()
}
singleOf(::NetworkInfo)
singleOf(::PatchBundlePersistenceRepository)
singleOf(::PatchSelectionRepository)
singleOf(::PatchOptionsRepository)
singleOf(::PatchBundleRepository) {
// It is best to load patch bundles ASAP
createdAtStart()
}
singleOf(::DownloaderPluginRepository)
singleOf(::WorkerRepository)
singleOf(::DownloadedAppRepository)
singleOf(::InstalledAppRepository)
}

View File

@@ -0,0 +1,9 @@
package app.revanced.manager.di
import app.revanced.manager.domain.installer.RootInstaller
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
val rootModule = module {
singleOf(::RootInstaller)
}

View File

@@ -0,0 +1,9 @@
package app.revanced.manager.di
import app.revanced.manager.network.service.HttpService
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
val serviceModule = module {
singleOf(::HttpService)
}

View File

@@ -0,0 +1,26 @@
package app.revanced.manager.di
import app.revanced.manager.ui.viewmodel.*
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.dsl.module
val viewModelModule = module {
viewModelOf(::MainViewModel)
viewModelOf(::DashboardViewModel)
viewModelOf(::SelectedAppInfoViewModel)
viewModelOf(::PatchesSelectorViewModel)
viewModelOf(::GeneralSettingsViewModel)
viewModelOf(::AdvancedSettingsViewModel)
viewModelOf(::AppSelectorViewModel)
viewModelOf(::PatcherViewModel)
viewModelOf(::UpdateViewModel)
viewModelOf(::ChangelogsViewModel)
viewModelOf(::ImportExportViewModel)
viewModelOf(::AboutViewModel)
viewModelOf(::DeveloperOptionsViewModel)
viewModelOf(::ContributorViewModel)
viewModelOf(::DownloadsViewModel)
viewModelOf(::InstalledAppsViewModel)
viewModelOf(::InstalledAppInfoViewModel)
viewModelOf(::UpdatesSettingsViewModel)
}

View File

@@ -0,0 +1,9 @@
package app.revanced.manager.di
import app.revanced.manager.patcher.worker.PatcherWorker
import org.koin.androidx.workmanager.dsl.workerOf
import org.koin.dsl.module
val workerModule = module {
workerOf(::PatcherWorker)
}

View File

@@ -0,0 +1,21 @@
package app.revanced.manager.domain.bundles
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.io.InputStream
class LocalPatchBundle(name: String, id: Int, directory: File) :
PatchBundleSource(name, id, directory) {
suspend fun replace(patches: InputStream) {
withContext(Dispatchers.IO) {
patchBundleOutputStream().use { outputStream ->
patches.copyTo(outputStream)
}
}
reload()?.also {
saveVersion(it.readManifestAttribute("Version"))
}
}
}

View File

@@ -0,0 +1,114 @@
package app.revanced.manager.domain.bundles
import android.app.Application
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import app.revanced.manager.R
import app.revanced.manager.domain.repository.PatchBundlePersistenceRepository
import app.revanced.manager.patcher.patch.PatchBundle
import app.revanced.manager.util.tag
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
import java.io.OutputStream
/**
* A [PatchBundle] source.
*/
@Stable
sealed class PatchBundleSource(initialName: String, val uid: Int, directory: File) : KoinComponent {
protected val configRepository: PatchBundlePersistenceRepository by inject()
private val app: Application by inject()
protected val patchesFile = directory.resolve("patches.jar")
private val _state = MutableStateFlow(load())
val state = _state.asStateFlow()
private val _nameFlow = MutableStateFlow(initialName)
val nameFlow =
_nameFlow.map { it.ifEmpty { app.getString(if (isDefault) R.string.bundle_name_default else R.string.bundle_name_fallback) } }
suspend fun getName() = nameFlow.first()
/**
* Returns true if the bundle has been downloaded to local storage.
*/
fun hasInstalled() = patchesFile.exists()
protected fun patchBundleOutputStream(): OutputStream = with(patchesFile) {
// Android 14+ requires dex containers to be readonly.
try {
setWritable(true, true)
outputStream()
} finally {
setReadOnly()
}
}
private fun load(): State {
if (!hasInstalled()) return State.Missing
return try {
State.Loaded(PatchBundle(patchesFile))
} catch (t: Throwable) {
Log.e(tag, "Failed to load patch bundle with UID $uid", t)
State.Failed(t)
}
}
suspend fun reload(): PatchBundle? {
val newState = load()
_state.value = newState
val bundle = newState.patchBundleOrNull()
// Try to read the name from the patch bundle manifest if the bundle does not have a name.
if (bundle != null && _nameFlow.value.isEmpty()) {
bundle.readManifestAttribute("Name")?.let { setName(it) }
}
return bundle
}
/**
* Create a flow that emits the [app.revanced.manager.data.room.bundles.BundleProperties] of this [PatchBundleSource].
* The flow will emit null if the associated [PatchBundleSource] is deleted.
*/
fun propsFlow() = configRepository.getProps(uid).flowOn(Dispatchers.Default)
suspend fun getProps() = propsFlow().first()!!
suspend fun currentVersion() = getProps().version
protected suspend fun saveVersion(version: String?) =
configRepository.updateVersion(uid, version)
suspend fun setName(name: String) {
configRepository.setName(uid, name)
_nameFlow.value = name
}
sealed interface State {
fun patchBundleOrNull(): PatchBundle? = null
data object Missing : State
data class Failed(val throwable: Throwable) : State
data class Loaded(val bundle: PatchBundle) : State {
override fun patchBundleOrNull() = bundle
}
}
companion object Extensions {
val PatchBundleSource.isDefault inline get() = uid == 0
val PatchBundleSource.asRemoteOrNull inline get() = this as? RemotePatchBundle
val PatchBundleSource.nameState
@Composable inline get() = nameFlow.collectAsStateWithLifecycle(
""
)
}
}

View File

@@ -0,0 +1,71 @@
package app.revanced.manager.domain.bundles
import androidx.compose.runtime.Stable
import app.revanced.manager.network.api.ReVancedAPI
import app.revanced.manager.network.dto.ReVancedAsset
import app.revanced.manager.network.service.HttpService
import app.revanced.manager.network.utils.getOrThrow
import io.ktor.client.request.url
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koin.core.component.inject
import java.io.File
@Stable
sealed class RemotePatchBundle(name: String, id: Int, directory: File, val endpoint: String) :
PatchBundleSource(name, id, directory) {
protected val http: HttpService by inject()
protected abstract suspend fun getLatestInfo(): ReVancedAsset
private suspend fun download(info: ReVancedAsset) = withContext(Dispatchers.IO) {
patchBundleOutputStream().use {
http.streamTo(it) {
url(info.downloadUrl)
}
}
saveVersion(info.version)
reload()
}
suspend fun downloadLatest() {
download(getLatestInfo())
}
suspend fun update(): Boolean = withContext(Dispatchers.IO) {
val info = getLatestInfo()
if (hasInstalled() && info.version == currentVersion())
return@withContext false
download(info)
true
}
suspend fun deleteLocalFiles() = withContext(Dispatchers.Default) {
patchesFile.delete()
reload()
}
suspend fun setAutoUpdate(value: Boolean) = configRepository.setAutoUpdate(uid, value)
companion object {
const val updateFailMsg = "Failed to update patch bundle(s)"
}
}
class JsonPatchBundle(name: String, id: Int, directory: File, endpoint: String) :
RemotePatchBundle(name, id, directory, endpoint) {
override suspend fun getLatestInfo() = withContext(Dispatchers.IO) {
http.request<ReVancedAsset> {
url(endpoint)
}.getOrThrow()
}
}
class APIPatchBundle(name: String, id: Int, directory: File, endpoint: String) :
RemotePatchBundle(name, id, directory, endpoint) {
private val api: ReVancedAPI by inject()
override suspend fun getLatestInfo() = api.getPatchesUpdate().getOrThrow()
}

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