mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2026-01-11 21:56:17 +00:00
Compare commits
420 Commits
build/opti
...
fix/instal
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05ace8180e | ||
|
|
0d26df03f4 | ||
|
|
c436a7a100 | ||
|
|
dbb6c01e89 | ||
|
|
e0d529c2df | ||
|
|
0300da9eac | ||
|
|
4e5057ecad | ||
|
|
1ef5c1c5c5 | ||
|
|
39f52c1242 | ||
|
|
0c62837454 | ||
|
|
3d75ffe6a7 | ||
|
|
d188d5a410 | ||
|
|
b43ac8a1af | ||
|
|
2ff70728b4 | ||
|
|
e5097b5ecd | ||
|
|
d5671db3a7 | ||
|
|
a314ba209d | ||
|
|
12d92ba811 | ||
|
|
ffd08c737c | ||
|
|
e1b768c467 | ||
|
|
df6ecd27dd | ||
|
|
2571cb8c11 | ||
|
|
c327857823 | ||
|
|
03160ccef1 | ||
|
|
08cec674bb | ||
|
|
95fb97ec31 | ||
|
|
4753873866 | ||
|
|
ca322f2da8 | ||
|
|
d758964742 | ||
|
|
a592e0b302 | ||
|
|
aeab639b2b | ||
|
|
4016ae732c | ||
|
|
a1cb18f9c8 | ||
|
|
8d9c2439dd | ||
|
|
c1e90a45cd | ||
|
|
775c2d5cde | ||
|
|
de27b4b109 | ||
|
|
b58a11f9f1 | ||
|
|
2297e94cb8 | ||
|
|
a84ab244c7 | ||
|
|
2cdd6d1843 | ||
|
|
3b82767a89 | ||
|
|
af8e2b44c0 | ||
|
|
a8820a4daf | ||
|
|
e1278452b9 | ||
|
|
d4d2056585 | ||
|
|
55524f7284 | ||
|
|
cd2dbcc841 | ||
|
|
9fdca5a0af | ||
|
|
05444d8824 | ||
|
|
59d233e15c | ||
|
|
1fb94b711f | ||
|
|
0096169af8 | ||
|
|
7c410fef45 | ||
|
|
a91ff60533 | ||
|
|
0ce49582f1 | ||
|
|
f32ffbb6f2 | ||
|
|
3851983a44 | ||
|
|
e97b19d2b6 | ||
|
|
24c4cd3f99 | ||
|
|
f2ea00757a | ||
|
|
51132731a4 | ||
|
|
bf311664d5 | ||
|
|
581f7922ed | ||
|
|
83d33e87e3 | ||
|
|
537e0b5bed | ||
|
|
663cf2d6b8 | ||
|
|
0030c7a788 | ||
|
|
eba92e2644 | ||
|
|
2671e68004 | ||
|
|
6e08e9dc39 | ||
|
|
3710675ac0 | ||
|
|
244a8f4e17 | ||
|
|
015a2df457 | ||
|
|
8686c058ce | ||
|
|
5c21ec6eb5 | ||
|
|
f5e1e0b065 | ||
|
|
bb5d414abb | ||
|
|
bd07435d4b | ||
|
|
54c56f1d81 | ||
|
|
5133f02ad6 | ||
|
|
9f7eaa2123 | ||
|
|
9a82b78528 | ||
|
|
cedc6ad49f | ||
|
|
4d95a29a1c | ||
|
|
6f6296b8cd | ||
|
|
f3f8bc4ec2 | ||
|
|
55e7ebf4fc | ||
|
|
26778f57e6 | ||
|
|
7007010f14 | ||
|
|
8b3c4eb91c | ||
|
|
a53a8ba627 | ||
|
|
f07f75a55f | ||
|
|
2697077fc8 | ||
|
|
dc51d6134d | ||
|
|
a9a21fd15a | ||
|
|
cd142a70d3 | ||
|
|
ac0625892d | ||
|
|
7f5a291c99 | ||
|
|
93f4a5bb7c | ||
|
|
2de16e18e8 | ||
|
|
c73fdfdd2d | ||
|
|
bdfb5a9462 | ||
|
|
ca918eea46 | ||
|
|
8dc4e5b89e | ||
|
|
1a54313c1d | ||
|
|
a3604579fe | ||
|
|
3a63e42df9 | ||
|
|
66432764cf | ||
|
|
7ef496b98c | ||
|
|
9863c5161a | ||
|
|
7438f45903 | ||
|
|
5662863a64 | ||
|
|
426b28932f | ||
|
|
83eeeae801 | ||
|
|
4de534094a | ||
|
|
ca38737783 | ||
|
|
7e858a244c | ||
|
|
dbe5c44ec3 | ||
|
|
a5c8a23f9f | ||
|
|
f92cb9e191 | ||
|
|
e55566d3df | ||
|
|
76e0c95187 | ||
|
|
fedaedfda1 | ||
|
|
3bd4f0d8f3 | ||
|
|
43b3743213 | ||
|
|
089f200fe6 | ||
|
|
a3f31ea657 | ||
|
|
a907528a20 | ||
|
|
fa86c1a0bb | ||
|
|
ea29d0f00c | ||
|
|
b93ecc0db2 | ||
|
|
55be7a6a9c | ||
|
|
95efff8b66 | ||
|
|
44f8b1fb6b | ||
|
|
e4f19b0c25 | ||
|
|
3c23d573bf | ||
|
|
61f1ee0627 | ||
|
|
df52a7bdef | ||
|
|
113a74d270 | ||
|
|
15b47f9bb6 | ||
|
|
e2623d6d79 | ||
|
|
79a513f94b | ||
|
|
cc771817cb | ||
|
|
deea682651 | ||
|
|
7dae562819 | ||
|
|
8d939a6669 | ||
|
|
8419f75d59 | ||
|
|
d2119d3643 | ||
|
|
9a01273c43 | ||
|
|
c22e5b4051 | ||
|
|
f6ca4e9555 | ||
|
|
bf049c3c1a | ||
|
|
6ace71b739 | ||
|
|
d889677b29 | ||
|
|
5f2376919b | ||
|
|
5c434137d3 | ||
|
|
7bf89887e4 | ||
|
|
5901372523 | ||
|
|
537b7084e0 | ||
|
|
45d64117bf | ||
|
|
6c3a99a492 | ||
|
|
ea007adecd | ||
|
|
72cd8ebca8 | ||
|
|
7ab191ed2b | ||
|
|
3a05150fa3 | ||
|
|
e5b414e277 | ||
|
|
d3d4c27f6d | ||
|
|
36a1c3f368 | ||
|
|
2a63a6163a | ||
|
|
02ea5c6d4a | ||
|
|
9562d80bfd | ||
|
|
49f851022d | ||
|
|
b18c678354 | ||
|
|
189c993ada | ||
|
|
69c119d545 | ||
|
|
feb0ca4cf3 | ||
|
|
0383bd74f7 | ||
|
|
60fdec9804 | ||
|
|
483be5d722 | ||
|
|
e44d3fdee4 | ||
|
|
b59a16191a | ||
|
|
f4d6c60b9e | ||
|
|
154f036fe9 | ||
|
|
d3417adbeb | ||
|
|
16c4290f05 | ||
|
|
d23d673c47 | ||
|
|
b80f94b77b | ||
|
|
5f4c9584a9 | ||
|
|
9a085f4091 | ||
|
|
8d7886f7eb | ||
|
|
c21076f2fb | ||
|
|
05fe058151 | ||
|
|
752310fe94 | ||
|
|
75500bbc43 | ||
|
|
84013ffca2 | ||
|
|
9da798dac1 | ||
|
|
d622208b17 | ||
|
|
c5cb18a7ea | ||
|
|
0d73e0cd32 | ||
|
|
9d961f6a52 | ||
|
|
7df3350acb | ||
|
|
858dd99ffa | ||
|
|
757e132321 | ||
|
|
413fe980a8 | ||
|
|
1aba6bc874 | ||
|
|
b5c1f6d732 | ||
|
|
ea50e65ab1 | ||
|
|
e1647fdef0 | ||
|
|
0b362e3393 | ||
|
|
159461356e | ||
|
|
b1206cb663 | ||
|
|
b5558ea3ff | ||
|
|
dcaa38c882 | ||
|
|
429b428f67 | ||
|
|
a12cae7299 | ||
|
|
88e860cf01 | ||
|
|
0616666d5e | ||
|
|
2700d45e4d | ||
|
|
c3a32a1142 | ||
|
|
afb0f80de5 | ||
|
|
4aaa88e353 | ||
|
|
359095a6f8 | ||
|
|
e1c3d61ec6 | ||
|
|
72b7d24b33 | ||
|
|
0ccc2c13ac | ||
|
|
fa414ce6ee | ||
|
|
3f362b605f | ||
|
|
a2f9e2f1da | ||
|
|
3af26e7065 | ||
|
|
d5bdc293f3 | ||
|
|
336eed3a95 | ||
|
|
59b4c0b2d2 | ||
|
|
0934b24591 | ||
|
|
bb2164e1a9 | ||
|
|
2a3590ddd2 | ||
|
|
ceb7623794 | ||
|
|
f183b6d8a6 | ||
|
|
a6174eee8f | ||
|
|
f8aafa0503 | ||
|
|
5e35893883 | ||
|
|
90db765c9a | ||
|
|
e61c98ca59 | ||
|
|
c003c3c324 | ||
|
|
5a3a619d16 | ||
|
|
89addf3f78 | ||
|
|
34cf848baa | ||
|
|
a9171e17bd | ||
|
|
2e64022229 | ||
|
|
8aa70d350e | ||
|
|
ca93524be0 | ||
|
|
7fb1e27617 | ||
|
|
1dd6738964 | ||
|
|
4924eaef80 | ||
|
|
56896d6197 | ||
|
|
ee0f342456 | ||
|
|
90edf1ddd0 | ||
|
|
b69a369d4e | ||
|
|
663d21c6af | ||
|
|
dadc5462e3 | ||
|
|
3aea6cbaec | ||
|
|
8425b6fa81 | ||
|
|
c62f772284 | ||
|
|
ad775f3059 | ||
|
|
c199801fb7 | ||
|
|
2ffcaec724 | ||
|
|
08eb995220 | ||
|
|
bf1d628944 | ||
|
|
f6fb534e04 | ||
|
|
686eb40cb0 | ||
|
|
b03f7b18a0 | ||
|
|
e833bf4ad1 | ||
|
|
805d440450 | ||
|
|
e997255cf3 | ||
|
|
cfcabf6ef1 | ||
|
|
7af6c79076 | ||
|
|
a17c2de228 | ||
|
|
3bb071d80d | ||
|
|
9950d85779 | ||
|
|
e7ec239783 | ||
|
|
3246269937 | ||
|
|
85692f8596 | ||
|
|
c879faf2eb | ||
|
|
933a4a3220 | ||
|
|
a269a39aa4 | ||
|
|
cff9c5ed09 | ||
|
|
a811df9547 | ||
|
|
83cdaaee18 | ||
|
|
5b3e9e595c | ||
|
|
97aa8c06c8 | ||
|
|
933e69e21e | ||
|
|
dc73462ac4 | ||
|
|
ad903533f8 | ||
|
|
62e934c403 | ||
|
|
6561e4c97c | ||
|
|
ac98ef834a | ||
|
|
a246863a89 | ||
|
|
39b5b87c40 | ||
|
|
35595fb4bc | ||
|
|
02fb47d3b5 | ||
|
|
eef50888bb | ||
|
|
9b3974414c | ||
|
|
88deadcf08 | ||
|
|
bad847d89b | ||
|
|
3f446f8236 | ||
|
|
31cbab209c | ||
|
|
b14285b2c8 | ||
|
|
8e28f06e26 | ||
|
|
5b46c58af9 | ||
|
|
dccf86163a | ||
|
|
8767f0e99c | ||
|
|
0a1acd24e3 | ||
|
|
a55160e7c6 | ||
|
|
6436483206 | ||
|
|
409c888d52 | ||
|
|
858b0ec5b4 | ||
|
|
8c9fe6989f | ||
|
|
17d1874381 | ||
|
|
e7802ed3d7 | ||
|
|
f547bb7ab1 | ||
|
|
bfcd1fb977 | ||
|
|
1ab1e4682f | ||
|
|
a854221969 | ||
|
|
ab42b946ef | ||
|
|
8ae4e850da | ||
|
|
4d04ae088c | ||
|
|
5c17a78e46 | ||
|
|
3492dc4e83 | ||
|
|
39b08e5201 | ||
|
|
18527999b5 | ||
|
|
fd520bba70 | ||
|
|
59b894dce4 | ||
|
|
6f6476e851 | ||
|
|
37c1754098 | ||
|
|
1f1a480d51 | ||
|
|
6cf51d71c5 | ||
|
|
06ef9dee44 | ||
|
|
49b4bbbf0b | ||
|
|
fc90bbc27c | ||
|
|
86e42449eb | ||
|
|
45142841d5 | ||
|
|
3d59ee51ac | ||
|
|
6dbcd6293e | ||
|
|
a008cf5dd1 | ||
|
|
23162f6233 | ||
|
|
8540d30196 | ||
|
|
f06da2ba56 | ||
|
|
9e1ebb3902 | ||
|
|
2aec6e1e55 | ||
|
|
6134ed78b4 | ||
|
|
e3cb056858 | ||
|
|
eb2270673d | ||
|
|
db070b125b | ||
|
|
a510d59e64 | ||
|
|
0264308b6d | ||
|
|
2ac3d5c483 | ||
|
|
3f54381d30 | ||
|
|
059a72b9dd | ||
|
|
64496bfbe7 | ||
|
|
b07fd2321d | ||
|
|
1efccda3f5 | ||
|
|
b9231b4de0 | ||
|
|
1a164ebe30 | ||
|
|
8d53180d86 | ||
|
|
62bccd1504 | ||
|
|
969ddb7bef | ||
|
|
8b6d32dd7b | ||
|
|
fd0ec6c6a7 | ||
|
|
de1ef23824 | ||
|
|
f30333e753 | ||
|
|
d84e6a3ffc | ||
|
|
5ec97f4a85 | ||
|
|
8c40119609 | ||
|
|
5b6ae800fd | ||
|
|
064a54eaf0 | ||
|
|
41268ca80b | ||
|
|
f0d9def3dd | ||
|
|
44e5dad6e9 | ||
|
|
83eb88170a | ||
|
|
e7599e1386 | ||
|
|
14888f9da7 | ||
|
|
9675a2777b | ||
|
|
d71a4bf3c3 | ||
|
|
57548641e7 | ||
|
|
553af83139 | ||
|
|
1d6b34a39f | ||
|
|
948a6d1440 | ||
|
|
0dd036574f | ||
|
|
4d201f17f2 | ||
|
|
da32ff954a | ||
|
|
70e49aaaa3 | ||
|
|
4e43938f7f | ||
|
|
f620a887ad | ||
|
|
8fa4d1d26d | ||
|
|
925be5a168 | ||
|
|
caeabfc91b | ||
|
|
5c2f9d91a6 | ||
|
|
55e871aa7d | ||
|
|
b7d53cfca8 | ||
|
|
85a03a6472 | ||
|
|
373cc4bbb1 | ||
|
|
a127b959ea | ||
|
|
476a6e5771 | ||
|
|
037a11aeb8 | ||
|
|
45a54d1608 | ||
|
|
ca85b38bdc | ||
|
|
60a5a11c71 | ||
|
|
7fc6ec5c2c | ||
|
|
7fa7b9d53a | ||
|
|
045a5483f1 | ||
|
|
40dd81eba3 | ||
|
|
9f99fcf808 | ||
|
|
1b11a0ad7a | ||
|
|
8f60bf44e5 | ||
|
|
3b459160d7 | ||
|
|
c97e4adace | ||
|
|
875ce6439d | ||
|
|
c45d579406 | ||
|
|
b6b8f4e069 | ||
|
|
21ceadaf7f |
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,3 +1,7 @@
|
||||
name: ⭐ Feature request
|
||||
description: Create a detailed request for a new feature.
|
||||
title: 'feat: '
|
||||
labels: ['Feature request']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
11
.github/workflows/build_pull_request.yml
vendored
11
.github/workflows/build_pull_request.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- compose-dev
|
||||
|
||||
jobs:
|
||||
release:
|
||||
@@ -13,16 +12,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: burrunan/gradle-cache-action@v3
|
||||
uses: burrunan/gradle-cache-action@v1
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
|
||||
2
.github/workflows/open_pull_request.yml
vendored
2
.github/workflows/open_pull_request.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Open pull request
|
||||
uses: repo-sync/pull-request@v2
|
||||
|
||||
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
@@ -12,15 +12,16 @@ jobs:
|
||||
name: Release
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v5
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
@@ -30,11 +31,12 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GITHUB_ACTOR: ${{ github.actor }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew assembleRelease
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v5
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
cache: 'npm'
|
||||
@@ -53,18 +55,26 @@ jobs:
|
||||
run: |
|
||||
echo "${{ secrets.KEYSTORE }}" | base64 --decode > "app/keystore.jks"
|
||||
|
||||
- name: Semantic Release
|
||||
uses: cycjimmy/semantic-release-action@v5
|
||||
id: semantic
|
||||
- name: Release API
|
||||
run: npx multi-semantic-release --tag-format 'api@${version}' --ignore-packages app
|
||||
env:
|
||||
GITHUB_ACTOR: ${{ github.actor }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Release
|
||||
id: release
|
||||
run: |
|
||||
echo "NEW_TAG=$(npx multi-semantic-release --tag-format 'v${version}' --ignore-packages api | tee | grep 'Created tag ' | sed -E 's/.*Created tag ([^ ]+).*/\1/')" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
GITHUB_ACTOR: ${{ github.actor }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||
KEYSTORE_ENTRY_ALIAS: ${{ secrets.KEYSTORE_ENTRY_ALIAS }}
|
||||
KEYSTORE_ENTRY_PASSWORD: ${{ secrets.KEYSTORE_ENTRY_PASSWORD }}
|
||||
|
||||
- name: Attest
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
uses: actions/attest-build-provenance@v3
|
||||
if: steps.release.outputs.NEW_TAG != ''
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-name: 'ReVanced Manager ${{ steps.release.outputs.new_release_git_tag }}'
|
||||
subject-name: 'ReVanced Manager ${{ steps.release.outputs.NEW_TAG }}'
|
||||
subject-path: app/build/outputs/apk/release/revanced-manager*.apk
|
||||
|
||||
8
adsfund.json
Normal file
8
adsfund.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"info": "This is verification file for ads.fund project",
|
||||
"project": {
|
||||
"name": "ReVanced Manager",
|
||||
"walletAddress": "0x7ab4091e00363654bf84B34151225742cd92FCE5",
|
||||
"tokenAddress": "0xadf954bc6f509b3a32fb5e97ed4ba6c000e37155"
|
||||
}
|
||||
}
|
||||
39
api/.releaserc
Normal file
39
api/.releaserc
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"branches": [
|
||||
"main",
|
||||
{
|
||||
"name": "dev",
|
||||
"prerelease": true
|
||||
}
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@semantic-release/commit-analyzer",
|
||||
{
|
||||
"releaseRules": [
|
||||
{ "type": "build", "scope": "Needs bump", "release": "patch" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/changelog",
|
||||
"gradle-semantic-release-plugin",
|
||||
[
|
||||
"@semantic-release/git",
|
||||
{
|
||||
"assets": [
|
||||
"CHANGELOG.md",
|
||||
"gradle.properties"
|
||||
],
|
||||
"message": "chore: Release API v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@saithodev/semantic-release-backmerge",
|
||||
{
|
||||
"backmergeBranches": [{"from": "main", "to": "dev"}],
|
||||
"clearWorkspace": true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import java.io.IOException
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
@@ -20,46 +17,9 @@ dependencies {
|
||||
implementation(libs.appcompat)
|
||||
}
|
||||
|
||||
fun String.runCommand(): String {
|
||||
val process = ProcessBuilder(split("\\s".toRegex()))
|
||||
.redirectErrorStream(true)
|
||||
.directory(rootDir)
|
||||
.start()
|
||||
|
||||
val output = StringBuilder()
|
||||
val reader = process.inputStream.bufferedReader()
|
||||
|
||||
val thread = Thread {
|
||||
reader.forEachLine {
|
||||
output.appendLine(it)
|
||||
}
|
||||
}
|
||||
thread.start()
|
||||
|
||||
if (!process.waitFor(10, TimeUnit.SECONDS)) {
|
||||
process.destroy()
|
||||
throw IOException("Command timed out: $this")
|
||||
}
|
||||
|
||||
thread.join()
|
||||
return output.toString().trim()
|
||||
}
|
||||
|
||||
val projectPath: String = projectDir.relativeTo(rootDir).path
|
||||
val lastTag = "git describe --tags --abbrev=0".runCommand()
|
||||
val hasChangesInThisModule = "git diff --name-only $lastTag..HEAD".runCommand().lineSequence().any {
|
||||
it.startsWith(projectPath)
|
||||
}
|
||||
|
||||
tasks.matching { it.name.startsWith("publish") }.configureEach {
|
||||
onlyIf {
|
||||
hasChangesInThisModule
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.manager.plugin.downloader"
|
||||
compileSdk = 36
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
@@ -82,10 +42,8 @@ android {
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.fromTarget("17")
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
@@ -150,4 +108,4 @@ publishing {
|
||||
signing {
|
||||
useGpgCmd()
|
||||
sign(publishing.publications["Api"])
|
||||
}
|
||||
}
|
||||
|
||||
1
api/gradlew
vendored
Symbolic link
1
api/gradlew
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../gradlew
|
||||
11
api/package.json
Normal file
11
api/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "api",
|
||||
"private": false,
|
||||
"devDependencies": {
|
||||
"@anolilab/multi-semantic-release": "^1.1.10",
|
||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.10.1"
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@semantic-release/commit-analyzer", {
|
||||
"@semantic-release/commit-analyzer",
|
||||
{
|
||||
"releaseRules": [
|
||||
{ "type": "build", "scope": "Needs bump", "release": "patch" }
|
||||
]
|
||||
@@ -22,7 +23,7 @@
|
||||
{
|
||||
"assets": [
|
||||
"CHANGELOG.md",
|
||||
"gradle.properties",
|
||||
"gradle.properties"
|
||||
],
|
||||
"message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||
}
|
||||
@@ -32,17 +33,17 @@
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"path": "app/build/outputs/apk/release/revanced-manager*.apk?(.asc)"
|
||||
},
|
||||
"path": "build/outputs/apk/release/revanced-manager*.apk?(.asc)"
|
||||
}
|
||||
],
|
||||
successComment: false
|
||||
"successComment": false
|
||||
}
|
||||
],
|
||||
[
|
||||
"@saithodev/semantic-release-backmerge",
|
||||
{
|
||||
backmergeBranches: [{"from": "main", "to": "dev"}],
|
||||
clearWorkspace: true
|
||||
"backmergeBranches": [{"from": "main", "to": "dev"}],
|
||||
"clearWorkspace": true
|
||||
}
|
||||
]
|
||||
]
|
||||
359
app/CHANGELOG.md
Normal file
359
app/CHANGELOG.md
Normal file
@@ -0,0 +1,359 @@
|
||||
# app [1.26.0-dev.13](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.12...v1.26.0-dev.13) (2025-12-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Make patcher screen design more consistent with inspiration ([#2805](https://github.com/ReVanced/revanced-manager/issues/2805)) ([dbb6c01](https://github.com/ReVanced/revanced-manager/commit/dbb6c01e89a5e710185ff4304de0ac9e19bed053))
|
||||
|
||||
# app [1.26.0-dev.12](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.11...v1.26.0-dev.12) (2025-12-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Improve trust plugin dialog design ([#2420](https://github.com/ReVanced/revanced-manager/issues/2420)) ([0300da9](https://github.com/ReVanced/revanced-manager/commit/0300da9eac6c0fc29dbbb66622c0d52f4cf68934))
|
||||
|
||||
# app [1.26.0-dev.11](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.10...v1.26.0-dev.11) (2025-10-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add pure black theme ([#2824](https://github.com/ReVanced/revanced-manager/issues/2824)) ([3d75ffe](https://github.com/ReVanced/revanced-manager/commit/3d75ffe6a7a39efdebe13dbd07c937c1de409ead))
|
||||
|
||||
# app [1.26.0-dev.10](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.9...v1.26.0-dev.10) (2025-10-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent back presses during installation ([2ff7072](https://github.com/ReVanced/revanced-manager/commit/2ff70728b490b92f212a82dcf599bc0c23f589e7))
|
||||
|
||||
# app [1.26.0-dev.9](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.8...v1.26.0-dev.9) (2025-10-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Instantly re-fetch patch bundle on pre-release preference update ([d5671db](https://github.com/ReVanced/revanced-manager/commit/d5671db3a77541c07bbbb4c3baca02f3ba0703f2)), closes [#2784](https://github.com/ReVanced/revanced-manager/issues/2784)
|
||||
|
||||
# app [1.26.0-dev.8](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.7...v1.26.0-dev.8) (2025-10-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Offcenter loading indicator in AppSelector ([12d92ba](https://github.com/ReVanced/revanced-manager/commit/12d92ba8110f5d1ac78aeecfa575444b5c53f561))
|
||||
|
||||
# app [1.26.0-dev.7](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.6...v1.26.0-dev.7) (2025-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Improve consistency between pre-release toggles ([e1b768c](https://github.com/ReVanced/revanced-manager/commit/e1b768c4679ecae8bff8007bdab56ff6544b12b6))
|
||||
|
||||
# app [1.26.0-dev.6](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.5...v1.26.0-dev.6) (2025-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Broken version comparison ([c327857](https://github.com/ReVanced/revanced-manager/commit/c3278578237dcddd9e7ab79ee80a02fdeef9604d))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Open contributor's GitHub profile when clicked ([#2775](https://github.com/ReVanced/revanced-manager/issues/2775)) ([2571cb8](https://github.com/ReVanced/revanced-manager/commit/2571cb8c1108e9c1ed84950f17692c09d66e0556))
|
||||
|
||||
# app [1.26.0-dev.5](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.4...v1.26.0-dev.5) (2025-10-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Toggle to use pre-release versions of ReVanced Patches ([08cec67](https://github.com/ReVanced/revanced-manager/commit/08cec674bbbe5297090ac5ee6039569975fbe9e7))
|
||||
|
||||
# app [1.26.0-dev.4](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.3...v1.26.0-dev.4) (2025-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add newlines to debug logs ([4753873](https://github.com/ReVanced/revanced-manager/commit/4753873866b575e2dcb160020df63f63862c8f33))
|
||||
|
||||
# app [1.26.0-dev.3](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.2...v1.26.0-dev.3) (2025-10-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Toggle to use pre-release versions of ReVanced Manager ([#2773](https://github.com/ReVanced/revanced-manager/issues/2773)) ([d758964](https://github.com/ReVanced/revanced-manager/commit/d7589647426b3d3438161a2f0b59bf4f154ac34b))
|
||||
|
||||
# app [1.26.0-dev.2](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.1...v1.26.0-dev.2) (2025-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Migration of keystore, by fixing mislabeling of alias as cn ([#2769](https://github.com/ReVanced/revanced-manager/issues/2769)) ([aeab639](https://github.com/ReVanced/revanced-manager/commit/aeab639b2b09e8bbd2478cfbf5a518586405c0f7))
|
||||
|
||||
# app [1.26.0-dev.1](https://github.com/ReVanced/revanced-manager/compare/v1.25.1...v1.26.0-dev.1) (2025-10-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* `ExtendedFloatingActionButton` not accessible by screen readers ([#2080](https://github.com/ReVanced/revanced-manager/issues/2080)) ([e4f19b0](https://github.com/ReVanced/revanced-manager/commit/e4f19b0c251e818cce59e11362a29dc8f657e065))
|
||||
* add bounds checks in patch selector ([483be5d](https://github.com/ReVanced/revanced-manager/commit/483be5d722db2be2595f6f6dd0c537a6c8487daf))
|
||||
* Add missing header for "Updates" settings ([#2642](https://github.com/ReVanced/revanced-manager/issues/2642)) ([d4d2056](https://github.com/ReVanced/revanced-manager/commit/d4d2056585ccd4a0456318448dc822c0f40c9c50))
|
||||
* Allow different app version when downloading via plugin if setting is off ([#2579](https://github.com/ReVanced/revanced-manager/issues/2579)) ([59d233e](https://github.com/ReVanced/revanced-manager/commit/59d233e15c885104900c7d4129fb4839c4da81e0))
|
||||
* always use default patch selection if customization is disabled ([cc77181](https://github.com/ReVanced/revanced-manager/commit/cc771817cba3dfd8f704cb7ecc9089ad7911c6ce))
|
||||
* android icon not loading in app selector ([deea682](https://github.com/ReVanced/revanced-manager/commit/deea68265157da65ef98986d751e2551797522e0))
|
||||
* automatically focus search views ([d23d673](https://github.com/ReVanced/revanced-manager/commit/d23d673c4703cdfa3be3a292873bbb37bea30ac7))
|
||||
* available updates dialog list item color ([1a54313](https://github.com/ReVanced/revanced-manager/commit/1a54313c1dc4efbb8b274201a79e28661a7ecf64))
|
||||
* Broken header padding in `AlertDialogExtended` when using an Icon ([8d939a6](https://github.com/ReVanced/revanced-manager/commit/8d939a6669909a44382fc7404276f2eeefcf728d))
|
||||
* broken logo in about page on release builds ([ad775f3](https://github.com/ReVanced/revanced-manager/commit/ad775f3059345dd93ff2baf6d018c2beecc413df))
|
||||
* buildfile syntax ([#66](https://github.com/ReVanced/revanced-manager/issues/66)) ([5c17a78](https://github.com/ReVanced/revanced-manager/commit/5c17a78e46db586642d53362267472fbbd47ae8c))
|
||||
* bundles not loading on Android 14 ([56896d6](https://github.com/ReVanced/revanced-manager/commit/56896d6197baa836bcd4a499ea2cee487e3d07c8))
|
||||
* Change the title in the Update screen from "Updates" to "Update" ([5f23769](https://github.com/ReVanced/revanced-manager/commit/5f2376919bd036987eba8188e3a1a2ff53ef6793)), closes [#1960](https://github.com/ReVanced/revanced-manager/issues/1960)
|
||||
* cleanup advanced settings screen ([02ea5c6](https://github.com/ReVanced/revanced-manager/commit/02ea5c6d4a2e6baa7c034b614deb6e4232cf6d0b))
|
||||
* **Compose:** Adjusted universal patches safeguard and warnings ([#2550](https://github.com/ReVanced/revanced-manager/issues/2550)) ([663cf2d](https://github.com/ReVanced/revanced-manager/commit/663cf2d6b86c276c6bb236af8e05a4f69df9eba0))
|
||||
* contributors screen fix ([#1256](https://github.com/ReVanced/revanced-manager/issues/1256)) ([dc73462](https://github.com/ReVanced/revanced-manager/commit/dc73462ac41bd5f1813358eb5e2265a3e2e7c0f9))
|
||||
* contributors screen repository name ([426b289](https://github.com/ReVanced/revanced-manager/commit/426b28932fe37a6d7412685819ffc8e26b69d31c))
|
||||
* Correct preference description ([#2619](https://github.com/ReVanced/revanced-manager/issues/2619)) ([0096169](https://github.com/ReVanced/revanced-manager/commit/0096169af8f9e2db6c22b8e88f0dfe1cab1260be))
|
||||
* Correctly display universal patches warning ([#2570](https://github.com/ReVanced/revanced-manager/issues/2570)) ([24c4cd3](https://github.com/ReVanced/revanced-manager/commit/24c4cd3f991953dd00b5bf5e7c3ec965315a9528))
|
||||
* correctly patch apk files ([c5cb18a](https://github.com/ReVanced/revanced-manager/commit/c5cb18a7eab838ea096577780335a29b9771b43d))
|
||||
* crash caused by compose inlining bug ([05fe058](https://github.com/ReVanced/revanced-manager/commit/05fe0581516a373cc26dd559d3fc7f21fcf16f3f))
|
||||
* crash when removing used bundles ([189c993](https://github.com/ReVanced/revanced-manager/commit/189c993ada6406db6f8c48c4051c5bd9fac98e2b))
|
||||
* delete temporary files ([#1341](https://github.com/ReVanced/revanced-manager/issues/1341)) ([b03f7b1](https://github.com/ReVanced/revanced-manager/commit/b03f7b18a029465142d08fe1ed68e92c81586a5f))
|
||||
* disable `WebView` history ([#1278](https://github.com/ReVanced/revanced-manager/issues/1278)) ([a811df9](https://github.com/ReVanced/revanced-manager/commit/a811df9547da33fc61397cb33ba5fd35ee470ff9))
|
||||
* display version from manifest ([#2634](https://github.com/ReVanced/revanced-manager/issues/2634)) ([1fb94b7](https://github.com/ReVanced/revanced-manager/commit/1fb94b711fdbbbca7d9baaa90c53faf208fc4d0d))
|
||||
* Do not poll battery optimization status ([#2491](https://github.com/ReVanced/revanced-manager/issues/2491)) ([26778f5](https://github.com/ReVanced/revanced-manager/commit/26778f57e6dd185d9aed1086aa03659a2e91d1a9))
|
||||
* don't store app list in parcel ([e7802ed](https://github.com/ReVanced/revanced-manager/commit/e7802ed3d714cbe6e29409d27989c65d4d7ce6a5))
|
||||
* dont crash when the bundle cannot be downloaded ([4d201f1](https://github.com/ReVanced/revanced-manager/commit/4d201f17f2ce01aad6adb456a49c3f03526c5ad3))
|
||||
* **downloader:** versions not loading correctly ([16c4290](https://github.com/ReVanced/revanced-manager/commit/16c4290f05d94cbe53e68cb98307d7be1bfce7af))
|
||||
* handle edge-to-edge properly in fullscreen dialogs ([eba92e2](https://github.com/ReVanced/revanced-manager/commit/eba92e2644663b10e7e17f2cf955afefe260d769))
|
||||
* handle exceptions when checking for bundle updates ([1dd6738](https://github.com/ReVanced/revanced-manager/commit/1dd673896454710094e83789abb585c106ee6bcb))
|
||||
* Handle open source licenses page crash ([#2569](https://github.com/ReVanced/revanced-manager/issues/2569)) ([f2ea007](https://github.com/ReVanced/revanced-manager/commit/f2ea00757a76ed8758bc0d4df54843c89483c986))
|
||||
* hide patch button ([#1284](https://github.com/ReVanced/revanced-manager/issues/1284)) ([dadc546](https://github.com/ReVanced/revanced-manager/commit/dadc5462e352e91cf971395def91d693677701bc))
|
||||
* Ignore long click when already in delete mode ([6f6296b](https://github.com/ReVanced/revanced-manager/commit/6f6296b8cde56d5fc73e00ef671ca7ab431455f4)), closes [#2503](https://github.com/ReVanced/revanced-manager/issues/2503)
|
||||
* import bundles on another thread ([0383bd7](https://github.com/ReVanced/revanced-manager/commit/0383bd74f73a3523d539c44cdf38b0e857c16bdc))
|
||||
* import export screen UX ([69c119d](https://github.com/ReVanced/revanced-manager/commit/69c119d545ac811c605124173e5cbc97a9064c79))
|
||||
* Improve background running notification ([#2614](https://github.com/ReVanced/revanced-manager/issues/2614)) ([05444d8](https://github.com/ReVanced/revanced-manager/commit/05444d8824a429c7e554d0597f8997e670936a63))
|
||||
* improve bundle page strings ([2a63a61](https://github.com/ReVanced/revanced-manager/commit/2a63a6163a8d2e6ee649cb22099b426ed605de8f))
|
||||
* improve keystore import error handling and show toast ([cd142a7](https://github.com/ReVanced/revanced-manager/commit/cd142a70d3f210161d3c1f20d2cb82a70432469f))
|
||||
* Inconsistent padding for battery optimisation warning ([6c3a99a](https://github.com/ReVanced/revanced-manager/commit/6c3a99a4921ab4438a038ad4c4bccd0326fdd565))
|
||||
* **installer:** make the correct column scrollable ([64496bf](https://github.com/ReVanced/revanced-manager/commit/64496bfbe77a9a44f5535fd5f12eee803ac7c26a))
|
||||
* **installer:** progress tracking ([f547bb7](https://github.com/ReVanced/revanced-manager/commit/f547bb7ab1b7149d7290729527714168a2561b23))
|
||||
* **installer:** properly track worker state ([#32](https://github.com/ReVanced/revanced-manager/issues/32)) ([de1ef23](https://github.com/ReVanced/revanced-manager/commit/de1ef23824227796c8583242e624f83d9dae5af3))
|
||||
* **installer:** save step incorrectly being marked as completed ([0264308](https://github.com/ReVanced/revanced-manager/commit/0264308b6dad051db80da6f130e8d28d86b38f04))
|
||||
* **installer:** sign and install on threads ([3d59ee5](https://github.com/ReVanced/revanced-manager/commit/3d59ee51acc5a6ebb17f68c0462d17d7ecb0f07c))
|
||||
* jvm signature clash error ([ee0f342](https://github.com/ReVanced/revanced-manager/commit/ee0f34245636027d55bd5bdfce4d6a5e6c3b3dcd))
|
||||
* library info not being embedded ([8c9fe69](https://github.com/ReVanced/revanced-manager/commit/8c9fe6989fc6d05afd53baa877f1e6dffc067b50))
|
||||
* load patch bundles earlier ([a2f9e2f](https://github.com/ReVanced/revanced-manager/commit/a2f9e2f1da961a13b2b20e2812593031c9339b88))
|
||||
* Match "Installation incompatible" dialog message with Flutter Manager ([#2231](https://github.com/ReVanced/revanced-manager/issues/2231)) ([fedaedf](https://github.com/ReVanced/revanced-manager/commit/fedaedfda112260144b0b9b0776509ddb3438046))
|
||||
* minify crash on building release ([#1245](https://github.com/ReVanced/revanced-manager/issues/1245)) ([6561e4c](https://github.com/ReVanced/revanced-manager/commit/6561e4c97c19134b22b72e19fad3884f99327b9a))
|
||||
* more android 34 fixes ([7fb1e27](https://github.com/ReVanced/revanced-manager/commit/7fb1e27617b69803b3d4463993b2290877502545))
|
||||
* move battery warning to dashboard ([3a05150](https://github.com/ReVanced/revanced-manager/commit/3a05150fa33f119ecdf436f8508862ef81c327a0))
|
||||
* Move temporary files outside of the cache directory ([#2122](https://github.com/ReVanced/revanced-manager/issues/2122)) ([b93ecc0](https://github.com/ReVanced/revanced-manager/commit/b93ecc0db20339393e1296c44ce4b1dbd837b577))
|
||||
* Offset badge ([c73fdfd](https://github.com/ReVanced/revanced-manager/commit/c73fdfdd2d3a1b8552d9c26df575b3019346596d))
|
||||
* only perform haptics on events ([e55566d](https://github.com/ReVanced/revanced-manager/commit/e55566d3df25480260922f0418b4bbee5d7b7a07))
|
||||
* option state crash ([#1456](https://github.com/ReVanced/revanced-manager/issues/1456)) ([f183b6d](https://github.com/ReVanced/revanced-manager/commit/f183b6d8a6b139fe3e84d5ea3a9658ef900453bc))
|
||||
* parcel error for nullable types ([336eed3](https://github.com/ReVanced/revanced-manager/commit/336eed3a95111ebbe456321f5986e6875ded354e))
|
||||
* pass worker inputs without serialization ([#44](https://github.com/ReVanced/revanced-manager/issues/44)) ([059a72b](https://github.com/ReVanced/revanced-manager/commit/059a72b9dd9103d2b3704daa7dbb13ad83971460))
|
||||
* patch count remaining at zero when using process runtime ([#2542](https://github.com/ReVanced/revanced-manager/issues/2542)) ([f5e1e0b](https://github.com/ReVanced/revanced-manager/commit/f5e1e0b0659e5775dd460b8dfc15427eb0175139))
|
||||
* patch options reset button being broken ([e1647fd](https://github.com/ReVanced/revanced-manager/commit/e1647fdef0c9f68e171a2d15e2b6e744da6bbaf5))
|
||||
* Patch process cancelation dialog conditions ([#2554](https://github.com/ReVanced/revanced-manager/issues/2554)) ([e97b19d](https://github.com/ReVanced/revanced-manager/commit/e97b19d2b65dbfc49ed062b123c363e412b9bf8e))
|
||||
* Patch selection screen padding ([#2533](https://github.com/ReVanced/revanced-manager/issues/2533)) ([cd2dbcc](https://github.com/ReVanced/revanced-manager/commit/cd2dbcc841e56dac99230ea6501af87c43e9c572))
|
||||
* **patcher:** add notification and wakelock to worker; chore: add app icon ([8b6d32d](https://github.com/ReVanced/revanced-manager/commit/8b6d32dd7b3ca4c694414a55a1b6202b62636530))
|
||||
* patches not being reloaded ([dccf861](https://github.com/ReVanced/revanced-manager/commit/dccf86163af34341e3e451df9f24356c7294ae1e))
|
||||
* **patches selector:** copy the selected patches list ([70e49aa](https://github.com/ReVanced/revanced-manager/commit/70e49aaaa3a42510cb9ced2209c90cd1da98391d))
|
||||
* perform selected app operations in the correct order ([34cf848](https://github.com/ReVanced/revanced-manager/commit/34cf848baaaa2504d162c515a95240d45bd7092a))
|
||||
* permission error when using installed app ([8767f0e](https://github.com/ReVanced/revanced-manager/commit/8767f0e99c6de5bbb0a690ced40f6e9a486f0828))
|
||||
* Playback Switch's Haptic Feedback ([#2639](https://github.com/ReVanced/revanced-manager/issues/2639)) ([9fdca5a](https://github.com/ReVanced/revanced-manager/commit/9fdca5a0afd6be8a24e2ec09eec0000b0b9cd179))
|
||||
* process death resilience and account for android 11 bug ([#2355](https://github.com/ReVanced/revanced-manager/issues/2355)) ([83eeeae](https://github.com/ReVanced/revanced-manager/commit/83eeeae801827800a0787e9e753c72d2a24d7970))
|
||||
* progress bar not updating ([dcaa38c](https://github.com/ReVanced/revanced-manager/commit/dcaa38c8824f54da7a833c354b247f309d1c9871))
|
||||
* release builds not working properly ([6f6476e](https://github.com/ReVanced/revanced-manager/commit/6f6476e85158cad4e2497e9f72b73c4dc948f0bc))
|
||||
* remove battery optimization notification if user grants the permission ([9863c51](https://github.com/ReVanced/revanced-manager/commit/9863c5161a1bc16941a323e654f80f8cb0122f9f))
|
||||
* remove the unique constraint for patch bundle names ([ea29d0f](https://github.com/ReVanced/revanced-manager/commit/ea29d0f00c3b3b2c137c4849e6c445a6bf9a180f))
|
||||
* Remove unnecessary screen padding ([8419f75](https://github.com/ReVanced/revanced-manager/commit/8419f75d597dd198aa1029fae2109646c5874078)), closes [#2062](https://github.com/ReVanced/revanced-manager/issues/2062)
|
||||
* remove unused function preventing compilation ([2297e94](https://github.com/ReVanced/revanced-manager/commit/2297e94cb81a9a22ea032d8e247769774ca85087))
|
||||
* Reset cached theme on theme change to avoid broken colors ([#2527](https://github.com/ReVanced/revanced-manager/issues/2527)) ([9a82b78](https://github.com/ReVanced/revanced-manager/commit/9a82b785280954973cafc5e6dccb3c90fdb5ef49))
|
||||
* run blocking IO operations in the correct context ([969ddb7](https://github.com/ReVanced/revanced-manager/commit/969ddb7bef321d7aa2a682b8128b1f755f35c28b))
|
||||
* run props flow on correct dispatcher ([#2035](https://github.com/ReVanced/revanced-manager/issues/2035)) ([d3d4c27](https://github.com/ReVanced/revanced-manager/commit/d3d4c27f6d7affceef233a0138ee6c985c7f56bc))
|
||||
* Screen turns off while patching due to wrong WakeLock ([#2147](https://github.com/ReVanced/revanced-manager/issues/2147)) ([4de5340](https://github.com/ReVanced/revanced-manager/commit/4de534094adc0665021d3ba129a648d896718568))
|
||||
* scrolling in patch selector ([154f036](https://github.com/ReVanced/revanced-manager/commit/154f036fe956096bca983fe9d6654ccca38fd8ac))
|
||||
* Selected patch count ([#2559](https://github.com/ReVanced/revanced-manager/issues/2559)) ([a91ff60](https://github.com/ReVanced/revanced-manager/commit/a91ff60533b44629ea60e8cd6acceeb80b0253b7))
|
||||
* serialization not working ([4d04ae0](https://github.com/ReVanced/revanced-manager/commit/4d04ae088c406d84936120cb753cd1f11fb8a8c2))
|
||||
* show available and selected patches in patch selector screen ([61f1ee0](https://github.com/ReVanced/revanced-manager/commit/61f1ee0627d6cbb6b9a4d226eb6c2f9e0b8c6453))
|
||||
* show install button when installation has been cancelled ([93f4a5b](https://github.com/ReVanced/revanced-manager/commit/93f4a5bb7c912ca77bb04e414432922c89d3e2c0))
|
||||
* Show selection warning also on patch option ([#2643](https://github.com/ReVanced/revanced-manager/issues/2643)) ([3b82767](https://github.com/ReVanced/revanced-manager/commit/3b82767a897eeca1dda1d8343f1db4207050e960))
|
||||
* sources screen being misaligned during transitions ([2ac3d5c](https://github.com/ReVanced/revanced-manager/commit/2ac3d5c483d5cc4776681ed3f900550a4e45f616))
|
||||
* specify `multithreadingDexFileWriter` in `PatcherOptions` ([#1402](https://github.com/ReVanced/revanced-manager/issues/1402)) ([3f362b6](https://github.com/ReVanced/revanced-manager/commit/3f362b605fbce3ea72e7c95b7e0bc614443c7d44))
|
||||
* Support patching on ARMv7 by updating AAPT2 ([#2084](https://github.com/ReVanced/revanced-manager/issues/2084)) ([15b47f9](https://github.com/ReVanced/revanced-manager/commit/15b47f9bb6cd6bb0360fda6ac641cd4c75542287))
|
||||
* Transparent status on fullscreen dialog ([#2654](https://github.com/ReVanced/revanced-manager/issues/2654)) ([a8820a4](https://github.com/ReVanced/revanced-manager/commit/a8820a4daf71704f6945b8f794495fe8a8d7589e))
|
||||
* Turn off filters by default ([#2079](https://github.com/ReVanced/revanced-manager/issues/2079)) ([44f8b1f](https://github.com/ReVanced/revanced-manager/commit/44f8b1fb6bffed5866ada356910119465320a9a8))
|
||||
* typo in string name `import_keystore_description` ([#1273](https://github.com/ReVanced/revanced-manager/issues/1273)) ([933e69e](https://github.com/ReVanced/revanced-manager/commit/933e69e21e97fede2183a26dd1645a6eb96c4509))
|
||||
* **ui:** make entire patches view button selectable ([#1271](https://github.com/ReVanced/revanced-manager/issues/1271)) ([83cdaae](https://github.com/ReVanced/revanced-manager/commit/83cdaaee183ff1b6d905977df38fe4e47f7d5973))
|
||||
* Updates popup shows incorrect names ([#1283](https://github.com/ReVanced/revanced-manager/issues/1283)) ([c879faf](https://github.com/ReVanced/revanced-manager/commit/c879faf2eb338476c6abd9f104922b0d49f95cd6))
|
||||
* Use `compatible` rather than `support` when referring to patch compatibility ([#2422](https://github.com/ReVanced/revanced-manager/issues/2422)) ([8b3c4eb](https://github.com/ReVanced/revanced-manager/commit/8b3c4eb91c491a0971e2ccf7d46012437eca5c25))
|
||||
* use correct `getViewModel` ([5b6ae80](https://github.com/ReVanced/revanced-manager/commit/5b6ae800fdfc93ef5058b21b3e48daac2a4e1358))
|
||||
* use correct classes to determine option type ([e833bf4](https://github.com/ReVanced/revanced-manager/commit/e833bf4ad14811bb6880ae2d97055e4ce0de222f))
|
||||
* use correct directory ([9e1ebb3](https://github.com/ReVanced/revanced-manager/commit/9e1ebb390244dcb9af03a9164a32386481ec5691))
|
||||
* Use FAB instead of ListItem to patch in App Overview ([6ace71b](https://github.com/ReVanced/revanced-manager/commit/6ace71b739302466274ce9b46f5f7dd6ab9da05d)), closes [#1995](https://github.com/ReVanced/revanced-manager/issues/1995)
|
||||
* use proper update icon ([b59a161](https://github.com/ReVanced/revanced-manager/commit/b59a16191a61c64275137c4a6145fd30d68aa480))
|
||||
* use ReVanced ring logo in about section ([#1302](https://github.com/ReVanced/revanced-manager/issues/1302)) ([933a4a3](https://github.com/ReVanced/revanced-manager/commit/933a4a32203425e745e05615217a8d0975c2e959))
|
||||
* Use the correct icon in API URL dialog ([c22e5b4](https://github.com/ReVanced/revanced-manager/commit/c22e5b4051515e0f02828a2b30f6af19b48ba55f)), closes [#1972](https://github.com/ReVanced/revanced-manager/issues/1972)
|
||||
* use upsert when modifying installed apps ([90edf1d](https://github.com/ReVanced/revanced-manager/commit/90edf1ddd0de29b299855810402a31828d989d04))
|
||||
* **VersionSelector:** use correct LazyColumn item key ([413fe98](https://github.com/ReVanced/revanced-manager/commit/413fe980a8c0b45e3924c98b2fbd1a3e9b579528))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **about screen:** complete about screen ([1d6b34a](https://github.com/ReVanced/revanced-manager/commit/1d6b34a39f76e8e733649f7fcfeb20eb1009a39a))
|
||||
* Add `isScrollingUp` support for ScrollState ([bf049c3](https://github.com/ReVanced/revanced-manager/commit/bf049c3c1ac12a60c5c6226b5c3fec7f72caa7db))
|
||||
* add ability to share debug logs ([feb0ca4](https://github.com/ReVanced/revanced-manager/commit/feb0ca4cf315e5d332f36039fbb989b3cfb9cf58))
|
||||
* add checkboxes to the downloaded apps page ([ca93524](https://github.com/ReVanced/revanced-manager/commit/ca93524be0b37f38b860d8512c81d2898b2860af))
|
||||
* Add confirm dialogs when toggling dangerous settings ([#2072](https://github.com/ReVanced/revanced-manager/issues/2072)) ([6643276](https://github.com/ReVanced/revanced-manager/commit/66432764cfe8192f4cf8e599a592f27c675f25ec))
|
||||
* Add confirmation dialog to "Reset" options ([#2576](https://github.com/ReVanced/revanced-manager/issues/2576)) ([f32ffbb](https://github.com/ReVanced/revanced-manager/commit/f32ffbb6f2224f886af14205721fb2372f396de2))
|
||||
* Add downloader plugin system ([#2041](https://github.com/ReVanced/revanced-manager/issues/2041)) ([ca38737](https://github.com/ReVanced/revanced-manager/commit/ca3873778307612b93af3273ffe4821c6a5e398d))
|
||||
* add external process runtime ([#1799](https://github.com/ReVanced/revanced-manager/issues/1799)) ([0d73e0c](https://github.com/ReVanced/revanced-manager/commit/0d73e0cd32b6af3526c226ce4695c7e905f65b15))
|
||||
* Add haptic feedback ([#1457](https://github.com/ReVanced/revanced-manager/issues/1457)) ([76e0c95](https://github.com/ReVanced/revanced-manager/commit/76e0c9518746620cd2723a99c310f92f5b3fd996))
|
||||
* Add installer status dialog ([#1473](https://github.com/ReVanced/revanced-manager/issues/1473)) ([43b3743](https://github.com/ReVanced/revanced-manager/commit/43b37432138d7cd8a507efad80827d6f3bdcdf08))
|
||||
* add network checks for features that require it ([f3f8bc4](https://github.com/ReVanced/revanced-manager/commit/f3f8bc4ec2f593ade91324d78f9ce83f60ef65cc))
|
||||
* add patch bundle info screen ([#55](https://github.com/ReVanced/revanced-manager/issues/55)) ([8ae4e85](https://github.com/ReVanced/revanced-manager/commit/8ae4e850dae9cf4df14afe90048ca0b0a48389ac))
|
||||
* add patches selector bottom sheet ([#1360](https://github.com/ReVanced/revanced-manager/issues/1360)) ([f6fb534](https://github.com/ReVanced/revanced-manager/commit/f6fb534e04777b4f0ec2ff2b13768c724c68c028))
|
||||
* add required options screen ([#2378](https://github.com/ReVanced/revanced-manager/issues/2378)) ([3a63e42](https://github.com/ReVanced/revanced-manager/commit/3a63e42df9ce50069a573d98cf44a8abec03b639))
|
||||
* Add reset button to custom API ([#2076](https://github.com/ReVanced/revanced-manager/issues/2076)) ([df52a7b](https://github.com/ReVanced/revanced-manager/commit/df52a7bdef05e1c9f034ae067c3dd183fb8fdffd)), closes [#2051](https://github.com/ReVanced/revanced-manager/issues/2051)
|
||||
* Add sensitivity to `isScrollingUp` ([f6ca4e9](https://github.com/ReVanced/revanced-manager/commit/f6ca4e95551193c8d21afd09872d9bbe6c80c0e8))
|
||||
* add social links ([#1294](https://github.com/ReVanced/revanced-manager/issues/1294)) ([7df3350](https://github.com/ReVanced/revanced-manager/commit/7df3350acb4aae957e2a7c0d2f30faf6cae6ab85))
|
||||
* add toast feedback to the bundle update button ([ea50e65](https://github.com/ReVanced/revanced-manager/commit/ea50e65ab1d626152bdd40c1893cd408b7271472))
|
||||
* add user agent ([#1382](https://github.com/ReVanced/revanced-manager/issues/1382)) ([3aea6cb](https://github.com/ReVanced/revanced-manager/commit/3aea6cbaecc9db103e9a3925b3c4a531de6c5f0e))
|
||||
* advanced settings page with device info ([#51](https://github.com/ReVanced/revanced-manager/issues/51)) ([86e4244](https://github.com/ReVanced/revanced-manager/commit/86e42449eb553417726b95f79f6edd7f526f6d44))
|
||||
* allow bundles to use classes from other bundles ([#1951](https://github.com/ReVanced/revanced-manager/issues/1951)) ([af8e2b4](https://github.com/ReVanced/revanced-manager/commit/af8e2b44c027d978046a0e7926f1425f0348b098))
|
||||
* allow user to save logs ([a008cf5](https://github.com/ReVanced/revanced-manager/commit/a008cf5dd143fafb1f642cd037db29393716f7d5))
|
||||
* animate the arrow button ([db070b1](https://github.com/ReVanced/revanced-manager/commit/db070b125bf08ff251450259045755e6469c2d5e))
|
||||
* app downloader ([#43](https://github.com/ReVanced/revanced-manager/issues/43)) ([1f1a480](https://github.com/ReVanced/revanced-manager/commit/1f1a480d51edb310934523024c52e0c19b066662))
|
||||
* app selector screen ([373cc4b](https://github.com/ReVanced/revanced-manager/commit/373cc4bbb1a8194bf9475d0a13e1c154cd87480b))
|
||||
* **app-selector:** show patchable installed apps first ([#1496](https://github.com/ReVanced/revanced-manager/issues/1496)) ([afb0f80](https://github.com/ReVanced/revanced-manager/commit/afb0f80de5a73c213f77bfde761ea1ea0886abef))
|
||||
* armv7 warning ([2ffcaec](https://github.com/ReVanced/revanced-manager/commit/2ffcaec724d5a13b816e04813d45cde75681eb69))
|
||||
* Automatic language detection ([#2032](https://github.com/ReVanced/revanced-manager/issues/2032)) ([36a1c3f](https://github.com/ReVanced/revanced-manager/commit/36a1c3f36807500fbe820bf4142fef159b138c7d))
|
||||
* backend ([45a54d1](https://github.com/ReVanced/revanced-manager/commit/45a54d1608a77547e06748867d63a452224727b6))
|
||||
* better installer ui ([#29](https://github.com/ReVanced/revanced-manager/issues/29)) ([14888f9](https://github.com/ReVanced/revanced-manager/commit/14888f9da71ecf1c50d770123d1e8dd09aa6c8b1))
|
||||
* **bundles tab:** add BackHandler ([a9171e1](https://github.com/ReVanced/revanced-manager/commit/a9171e17bd628601f1e074a7fcdf74c15cb73709))
|
||||
* Change "Update" to "Show" in Update Available notification ([5c43413](https://github.com/ReVanced/revanced-manager/commit/5c434137d332aabaaca236b6f9616d7727d0b3d2)), closes [#1959](https://github.com/ReVanced/revanced-manager/issues/1959)
|
||||
* change appID and name of debug builds ([5b3e9e5](https://github.com/ReVanced/revanced-manager/commit/5b3e9e595cded277c051cc669d9f29bcb6ce5d18))
|
||||
* **Changelogs:** overall improvement ([#1429](https://github.com/ReVanced/revanced-manager/issues/1429)) ([2a3590d](https://github.com/ReVanced/revanced-manager/commit/2a3590ddd2cc74b746a3f632a93970bfa23cf384))
|
||||
* check for updates on startup ([#1462](https://github.com/ReVanced/revanced-manager/issues/1462)) ([bb2164e](https://github.com/ReVanced/revanced-manager/commit/bb2164e1a95a698b1b0f69e725af5e0e1e45b868))
|
||||
* check if the version being used is the recommended version ([#1675](https://github.com/ReVanced/revanced-manager/issues/1675)) ([9d961f6](https://github.com/ReVanced/revanced-manager/commit/9d961f6a52d15ed6116afc78c7008460347da69a))
|
||||
* Collapse ExtendedFAB on scroll ([#1630](https://github.com/ReVanced/revanced-manager/issues/1630)) ([b5c1f6d](https://github.com/ReVanced/revanced-manager/commit/b5c1f6d732b65c1c9becb7962c51a70a840dea73))
|
||||
* **Compose:** Add confirmation dialog on multiple operations ([#2529](https://github.com/ReVanced/revanced-manager/issues/2529)) ([2671e68](https://github.com/ReVanced/revanced-manager/commit/2671e68004269deebdedaee38a6692b2302ca732))
|
||||
* **Compose:** hide developer settings ([#2551](https://github.com/ReVanced/revanced-manager/issues/2551)) ([0030c7a](https://github.com/ReVanced/revanced-manager/commit/0030c7a7885feee0578ee1423ee2aefc6a0e2c2c))
|
||||
* **Compose:** Improve patches selector tab by adding the bundle version ([#2545](https://github.com/ReVanced/revanced-manager/issues/2545)) ([3710675](https://github.com/ReVanced/revanced-manager/commit/3710675ac0ca77cecfb172b4cf148f41a762bf06))
|
||||
* **Compose:** Move developer options to top level ([#2528](https://github.com/ReVanced/revanced-manager/issues/2528)) ([cedc6ad](https://github.com/ReVanced/revanced-manager/commit/cedc6ad49f23d778a52a8846f9e384fd2106e074))
|
||||
* contributors screen ([#42](https://github.com/ReVanced/revanced-manager/issues/42)) ([3f54381](https://github.com/ReVanced/revanced-manager/commit/3f54381d307fd71296be18e97a1ab870f1cdc297))
|
||||
* **Contributors Screen:** implement design from Figma ([#1465](https://github.com/ReVanced/revanced-manager/issues/1465)) ([d5bdc29](https://github.com/ReVanced/revanced-manager/commit/d5bdc293f308e2a283d744afdc1aed6a165f7166))
|
||||
* Dashboard Screen ([#18](https://github.com/ReVanced/revanced-manager/issues/18)) ([a127b95](https://github.com/ReVanced/revanced-manager/commit/a127b959ead5a9c83a0c4f7e7840aeeb68362c0d))
|
||||
* disable filter chips when there are no patches ([fd520bb](https://github.com/ReVanced/revanced-manager/commit/fd520bba700bae9d8eae745ce23a95b07b7f7d34))
|
||||
* dont ask for root on launch ([9562d80](https://github.com/ReVanced/revanced-manager/commit/9562d80bfdc785fe5ed512a15cfd7c0e09091acc))
|
||||
* download apps in patcher screen ([#73](https://github.com/ReVanced/revanced-manager/issues/73)) ([a854221](https://github.com/ReVanced/revanced-manager/commit/a854221969c363712a0b3de84607092709db291f))
|
||||
* experimental patches setting ([b07fd23](https://github.com/ReVanced/revanced-manager/commit/b07fd2321dd0aecce556f341e2b18f930baa58fd))
|
||||
* filter options for patches ([62bccd1](https://github.com/ReVanced/revanced-manager/commit/62bccd150441747e5cd6de71de304e416922bdda))
|
||||
* finish implementing the sources system ([#70](https://github.com/ReVanced/revanced-manager/issues/70)) ([858b0ec](https://github.com/ReVanced/revanced-manager/commit/858b0ec5b456043fa61b681bbbd195fd9c30a6f0))
|
||||
* get bundle information from jar manifest ([#2027](https://github.com/ReVanced/revanced-manager/issues/2027)) ([60fdec9](https://github.com/ReVanced/revanced-manager/commit/60fdec9804c763ef9308a7a56d245401dbd35d7c))
|
||||
* hide tabs when 1 bundle is used ([41268ca](https://github.com/ReVanced/revanced-manager/commit/41268ca80b71f68dbf9523fa7bac34feeec7d011))
|
||||
* hide unfinished pages in release mode ([c199801](https://github.com/ReVanced/revanced-manager/commit/c199801fb7f91306538391177d240cf1121964d2))
|
||||
* Highlight links in Markdown ([7bf8988](https://github.com/ReVanced/revanced-manager/commit/7bf89887e420a402b30da4796ba3648147f00394)), closes [#1962](https://github.com/ReVanced/revanced-manager/issues/1962)
|
||||
* implement DI ([7fa7b9d](https://github.com/ReVanced/revanced-manager/commit/7fa7b9d53a3217c7e1e4c70a524fd68ae170c832))
|
||||
* implement more patch option types ([#2015](https://github.com/ReVanced/revanced-manager/issues/2015)) ([b18c678](https://github.com/ReVanced/revanced-manager/commit/b18c6783547e910fa2dbd3d7edcc5fe329e6d921))
|
||||
* implement navigation ([7fc6ec5](https://github.com/ReVanced/revanced-manager/commit/7fc6ec5c2cf8eb9ebfc3dda01cdfd80962be1f8f))
|
||||
* implement Submit Issue button ([#1276](https://github.com/ReVanced/revanced-manager/issues/1276)) ([a269a39](https://github.com/ReVanced/revanced-manager/commit/a269a39aa4a34b94aef4e1e85126c571e96be575))
|
||||
* improve accessibility ([#64](https://github.com/ReVanced/revanced-manager/issues/64)) ([39b08e5](https://github.com/ReVanced/revanced-manager/commit/39b08e5201d2cec6bdb67f9386120a7a40c9ccc6))
|
||||
* Improve APK file name formatting on save ([#2421](https://github.com/ReVanced/revanced-manager/issues/2421)) ([a53a8ba](https://github.com/ReVanced/revanced-manager/commit/a53a8ba62734daf9bd80ab79265241a4a22f489c))
|
||||
* improve bundle dialog UI ([409c888](https://github.com/ReVanced/revanced-manager/commit/409c888d523f398505daaaff9d2490dc5a863680))
|
||||
* Improve bundle info screen design ([#2548](https://github.com/ReVanced/revanced-manager/issues/2548)) ([55524f7](https://github.com/ReVanced/revanced-manager/commit/55524f7284a44bbf8e8c782eedd7fc06d54944cf))
|
||||
* Improve custom API URL dialog ([#2033](https://github.com/ReVanced/revanced-manager/issues/2033)) ([7dae562](https://github.com/ReVanced/revanced-manager/commit/7dae56281994942577bac7bf50c59e805672d0e1))
|
||||
* Improve device information in debugging section ([d889677](https://github.com/ReVanced/revanced-manager/commit/d889677b29aeb4a49a025da98060265e88876ddf)), closes [#1977](https://github.com/ReVanced/revanced-manager/issues/1977)
|
||||
* Improve initial update popup wording ([5901372](https://github.com/ReVanced/revanced-manager/commit/5901372523643eef5a605256662c8e1f0a9f2263)), closes [#1956](https://github.com/ReVanced/revanced-manager/issues/1956)
|
||||
* improve keystore UI and UX ([#52](https://github.com/ReVanced/revanced-manager/issues/52)) ([49b4bbb](https://github.com/ReVanced/revanced-manager/commit/49b4bbbf0ba84b006a1694ca95662cf224a84b0f))
|
||||
* Improve patch bundle screen ([#2070](https://github.com/ReVanced/revanced-manager/issues/2070)) ([a907528](https://github.com/ReVanced/revanced-manager/commit/a907528a2096d8de9778efa8f85e0cdc1d7c2b80))
|
||||
* improve patcher screen labels ([f4d6c60](https://github.com/ReVanced/revanced-manager/commit/f4d6c60b9ec4c76e8e3fa233f79e062b802860e5))
|
||||
* improve patcher UI ([#1494](https://github.com/ReVanced/revanced-manager/issues/1494)) ([429b428](https://github.com/ReVanced/revanced-manager/commit/429b428f673dd949289baaf27ed2e08970db83ae))
|
||||
* Improve Settings order ([#2060](https://github.com/ReVanced/revanced-manager/issues/2060)) ([fa86c1a](https://github.com/ReVanced/revanced-manager/commit/fa86c1a0bb039a86e0649eae30c7b33620f98dbe))
|
||||
* improve the safeguards ([#2038](https://github.com/ReVanced/revanced-manager/issues/2038)) ([e5b414e](https://github.com/ReVanced/revanced-manager/commit/e5b414e277341967c7b5a5f071ddac1fdfdb8e63))
|
||||
* Improve unsupported patch warnings ([#2066](https://github.com/ReVanced/revanced-manager/issues/2066)) ([3c23d57](https://github.com/ReVanced/revanced-manager/commit/3c23d573bf3998304cad4485016004a871cf1636)), closes [#2052](https://github.com/ReVanced/revanced-manager/issues/2052)
|
||||
* Improve update screen design ([#2487](https://github.com/ReVanced/revanced-manager/issues/2487)) ([7007010](https://github.com/ReVanced/revanced-manager/commit/7007010f14239452e565736fe7cee7666a682ffb))
|
||||
* Improve update setting tile titles ([e2623d6](https://github.com/ReVanced/revanced-manager/commit/e2623d6d79b3b87e9ba29016e42f1d645b2f9e19)), closes [#1968](https://github.com/ReVanced/revanced-manager/issues/1968)
|
||||
* improve UX for failed or missing bundles ([49f8510](https://github.com/ReVanced/revanced-manager/commit/49f851022db72b110c8597aa1c711461c1b01882))
|
||||
* improved compose stability ([8c40119](https://github.com/ReVanced/revanced-manager/commit/8c40119609c650d1f012d810a4117e84fbe2da52))
|
||||
* improved dashboard screen ([5c2f9d9](https://github.com/ReVanced/revanced-manager/commit/5c2f9d91a6e803d9b3705e2b3aa84176353ba963))
|
||||
* in-app updater ([#25](https://github.com/ReVanced/revanced-manager/issues/25)) ([d71a4bf](https://github.com/ReVanced/revanced-manager/commit/d71a4bf3c3457a02578bb8ad3c7615b074f6e3f1))
|
||||
* **installer:** adjust arrow icon size ([e997255](https://github.com/ReVanced/revanced-manager/commit/e997255cf3c3c5ba777da07752217f99e01dd789))
|
||||
* **installer:** adjust step icon size and alignment ([cfcabf6](https://github.com/ReVanced/revanced-manager/commit/cfcabf6ef1c212f2627d5d02f4d59981bdc276ca))
|
||||
* **installer:** apk signing and installation ([da32ff9](https://github.com/ReVanced/revanced-manager/commit/da32ff954a84cf8ff321bbbf71cc5b544d6e6be9))
|
||||
* **installer:** sign apk in patcher worker ([c003c3c](https://github.com/ReVanced/revanced-manager/commit/c003c3c3245f5a663a0371d4e9df71777ba728b9))
|
||||
* **Installer:** use BottomAppBar ([#1428](https://github.com/ReVanced/revanced-manager/issues/1428)) ([ceb7623](https://github.com/ReVanced/revanced-manager/commit/ceb762379461443e7e62c37511df1c84a6068bb4))
|
||||
* integrate revanced patcher ([#22](https://github.com/ReVanced/revanced-manager/issues/22)) ([caeabfc](https://github.com/ReVanced/revanced-manager/commit/caeabfc91b2aa7e3de9e6a31859049d4b2d37388))
|
||||
* keystore import/export ([#30](https://github.com/ReVanced/revanced-manager/issues/30)) ([fd0ec6c](https://github.com/ReVanced/revanced-manager/commit/fd0ec6c6a7fc8488db859056a95ebe0455e2843b))
|
||||
* **koin:** use the android logger ([f30333e](https://github.com/ReVanced/revanced-manager/commit/f30333e75338dd2c1ef891723ecb834fc1eb10f7))
|
||||
* licenses screen ([#47](https://github.com/ReVanced/revanced-manager/issues/47)) ([e3cb056](https://github.com/ReVanced/revanced-manager/commit/e3cb056858ea8917162c1a421a7a8d03ddaa08e2))
|
||||
* make bundles selectable ([#1237](https://github.com/ReVanced/revanced-manager/issues/1237)) ([a246863](https://github.com/ReVanced/revanced-manager/commit/a246863a89fe8781feaf2a45fcb7ea991d26028f))
|
||||
* Make patch bundles list scrollable ([#2322](https://github.com/ReVanced/revanced-manager/issues/2322)) ([a5c8a23](https://github.com/ReVanced/revanced-manager/commit/a5c8a23f9ffb36543d45b46bb5f01c5dea56bf90))
|
||||
* more info for the select from application screen ([#81](https://github.com/ReVanced/revanced-manager/issues/81)) ([3f446f8](https://github.com/ReVanced/revanced-manager/commit/3f446f8236101755a9d51a2aa759f70a0bd429da))
|
||||
* move plugin api to another repository ([55e7ebf](https://github.com/ReVanced/revanced-manager/commit/55e7ebf4fc5adf8800430ad4aa2579cb6210290d))
|
||||
* Move safeguards above patcher preference group ([9f7eaa2](https://github.com/ReVanced/revanced-manager/commit/9f7eaa212339f2093050087dc7ab0b8237356939))
|
||||
* move update to notification card ([#1917](https://github.com/ReVanced/revanced-manager/issues/1917)) ([b80f94b](https://github.com/ReVanced/revanced-manager/commit/b80f94b77bba89e31608cdb302dab0619bf7c5cc))
|
||||
* **NotificationCard:** rewrite & consistent usage ([#1426](https://github.com/ReVanced/revanced-manager/issues/1426)) ([f8aafa0](https://github.com/ReVanced/revanced-manager/commit/f8aafa050328423b3168a7943f566fce58100cb0))
|
||||
* Open the app-specific manage all files permission dialog ([#2148](https://github.com/ReVanced/revanced-manager/issues/2148)) ([a3f31ea](https://github.com/ReVanced/revanced-manager/commit/a3f31ea65788a43ce57d548e8240e5b1fe3005d0))
|
||||
* Order bundles by number of patches ([bb5d414](https://github.com/ReVanced/revanced-manager/commit/bb5d414abb4f294aa88d795486836a99ade2b388))
|
||||
* patch bundle sources system ([#24](https://github.com/ReVanced/revanced-manager/issues/24)) ([9675a27](https://github.com/ReVanced/revanced-manager/commit/9675a2777b364e5ede0d44b92eb7e551d4f7b3d6))
|
||||
* patch options ([#45](https://github.com/ReVanced/revanced-manager/issues/45)) ([8540d30](https://github.com/ReVanced/revanced-manager/commit/8540d301962669e3d79ca345c852f5b01df641a4))
|
||||
* patch options UI ([#80](https://github.com/ReVanced/revanced-manager/issues/80)) ([0a1acd2](https://github.com/ReVanced/revanced-manager/commit/0a1acd24e3f0d06fde412b8eeecd923d92ee64a9))
|
||||
* **patch-selector:** default patches selection ([#1272](https://github.com/ReVanced/revanced-manager/issues/1272)) ([a17c2de](https://github.com/ReVanced/revanced-manager/commit/a17c2de228cccb4a0bb0ca7497720011bec131fc))
|
||||
* **patch-selector:** remove TODO about an unplanned feature ([4924eae](https://github.com/ReVanced/revanced-manager/commit/4924eaef800c429f2a59b8a15fd48fae0292810c))
|
||||
* **patcher:** Improve installation ([#2185](https://github.com/ReVanced/revanced-manager/issues/2185)) ([3bd4f0d](https://github.com/ReVanced/revanced-manager/commit/3bd4f0d8f3f60d079d4647d42592b10a15f0dae8))
|
||||
* patches selector screen ([55e871a](https://github.com/ReVanced/revanced-manager/commit/55e871aa7d27885e44ef33faab1bb4ae33e7a460))
|
||||
* Progressive AlertDialog for adding bundles ([9a01273](https://github.com/ReVanced/revanced-manager/commit/9a01273c43bd6bcdb0cdfd26c5a467cd3193e5d7)), closes [#1992](https://github.com/ReVanced/revanced-manager/issues/1992)
|
||||
* ProGuard ([d84e6a3](https://github.com/ReVanced/revanced-manager/commit/d84e6a3ffc20d018b2edeb505de20a920785ba5c))
|
||||
* Purple default theme ([#1601](https://github.com/ReVanced/revanced-manager/issues/1601)) ([0616666](https://github.com/ReVanced/revanced-manager/commit/0616666d5ef9b53bef5fd630b1b1a47088097d37))
|
||||
* Redesign the patches screen ([#2381](https://github.com/ReVanced/revanced-manager/issues/2381)) ([8dc4e5b](https://github.com/ReVanced/revanced-manager/commit/8dc4e5b89ee4d36263c8b4187650691b68484688))
|
||||
* remember patch options ([#1449](https://github.com/ReVanced/revanced-manager/issues/1449)) ([90db765](https://github.com/ReVanced/revanced-manager/commit/90db765c9aa014495775a34927904dedf5fef1e3))
|
||||
* remove dead help icons ([3bb071d](https://github.com/ReVanced/revanced-manager/commit/3bb071d80d319d4943b0d4c3048f232f3eb9f5cf))
|
||||
* Remove tag from changelog ([d2119d3](https://github.com/ReVanced/revanced-manager/commit/d2119d36430198151140b469192f76f781df6dd3))
|
||||
* Rename "Patch bundle" to "Patches" ([#2541](https://github.com/ReVanced/revanced-manager/issues/2541)) ([2cdd6d1](https://github.com/ReVanced/revanced-manager/commit/2cdd6d1843f1e49c7c720f8859e11d6a30c0eea6))
|
||||
* rename debug build to `ReVanced Manager (dev)` ([d3417ad](https://github.com/ReVanced/revanced-manager/commit/d3417adbeba0a8e06d3494a2fd108f735f73632c))
|
||||
* rename main bundle to `Default` ([e44d3fd](https://github.com/ReVanced/revanced-manager/commit/e44d3fdee444d915e3e8b8143e55f1353980aad2))
|
||||
* rename package to `app.revanced.manager` ([5ec97f4](https://github.com/ReVanced/revanced-manager/commit/5ec97f4a852a07d0e554bbe1eacc379179ac089e))
|
||||
* Rename strings ([e127845](https://github.com/ReVanced/revanced-manager/commit/e1278452b9c73479cdfb0eb0703db1552b158633))
|
||||
* rename ViewModels for consistency ([064a54e](https://github.com/ReVanced/revanced-manager/commit/064a54eaf0675a1cc9d21f3e1071160deb25c201))
|
||||
* Reorder Import & Export settings ([#2403](https://github.com/ReVanced/revanced-manager/issues/2403)) ([2697077](https://github.com/ReVanced/revanced-manager/commit/2697077fc88bb795027303558c9d52448a4daded))
|
||||
* ReVanced theme colors ([59b894d](https://github.com/ReVanced/revanced-manager/commit/59b894dce4b99c51151a4cccd03a998ceec31778))
|
||||
* revert to blue theme colors ([5f4c958](https://github.com/ReVanced/revanced-manager/commit/5f4c9584a94a1edd1eeaa0b9ecfcd9b281b7cccc))
|
||||
* root installation ([#1243](https://github.com/ReVanced/revanced-manager/issues/1243)) ([62e934c](https://github.com/ReVanced/revanced-manager/commit/62e934c4032096bed36201510fc55304ba48de68))
|
||||
* save patch options and selected patches in bundle ([#50](https://github.com/ReVanced/revanced-manager/issues/50)) ([23162f6](https://github.com/ReVanced/revanced-manager/commit/23162f6233fa6a176514b35feff731f8f28b4d4b))
|
||||
* save patch selection using room db ([#38](https://github.com/ReVanced/revanced-manager/issues/38)) ([1efccda](https://github.com/ReVanced/revanced-manager/commit/1efccda3f55d964fae3bee9ee1f0bd260bb1cc74))
|
||||
* Screen slide transition ([#2396](https://github.com/ReVanced/revanced-manager/issues/2396)) ([2de16e1](https://github.com/ReVanced/revanced-manager/commit/2de16e18e8ba5e84149b377f225693ea35fa2385))
|
||||
* Scrollbars ([#1479](https://github.com/ReVanced/revanced-manager/issues/1479)) ([b5558ea](https://github.com/ReVanced/revanced-manager/commit/b5558ea3ffef40f96b271f8dfe3a5cf95328781e))
|
||||
* Select bundle type before adding bundle ([#1490](https://github.com/ReVanced/revanced-manager/issues/1490)) ([88e860c](https://github.com/ReVanced/revanced-manager/commit/88e860cf0132aed23a3cfd3d9d12e472aa895718))
|
||||
* selected app info page ([#1395](https://github.com/ReVanced/revanced-manager/issues/1395)) ([b69a369](https://github.com/ReVanced/revanced-manager/commit/b69a369d4e304c8a4c8a8db052309b485171e353))
|
||||
* Set app ownership when installing apps ([#2558](https://github.com/ReVanced/revanced-manager/issues/2558)) ([7c410fe](https://github.com/ReVanced/revanced-manager/commit/7c410fef4512087657e3978d5be049c422b25456))
|
||||
* settings migration (compose) ([#1309](https://github.com/ReVanced/revanced-manager/issues/1309)) ([bf1d628](https://github.com/ReVanced/revanced-manager/commit/bf1d628944cb5a439d0bda7c49d820a5fa7576b3))
|
||||
* settings screen ([b7d53cf](https://github.com/ReVanced/revanced-manager/commit/b7d53cfca84d7239bed9189e265a03fd44dc2e45))
|
||||
* **settings screen:** add battery optimization notification ([5754864](https://github.com/ReVanced/revanced-manager/commit/57548641e7ecd06decfc926cb860674ce7443d7a))
|
||||
* **settings screen:** match typography from figma ([948a6d1](https://github.com/ReVanced/revanced-manager/commit/948a6d14404e067907c9e84576cfeba76134aaf6))
|
||||
* **settings:** move experimental patches option to advanced ([805d440](https://github.com/ReVanced/revanced-manager/commit/805d440450d821a26d3ef90a4f97cd796635057d))
|
||||
* **Settings:** use SettingsListItem consistently and overall improvements ([#1427](https://github.com/ReVanced/revanced-manager/issues/1427)) ([5e35893](https://github.com/ReVanced/revanced-manager/commit/5e35893883fa109d74b028478e60b51f97a2e12d))
|
||||
* show installed app in version selector ([1ab1e46](https://github.com/ReVanced/revanced-manager/commit/1ab1e4682ffbfe16c02c438ad833adbfdec58b33))
|
||||
* Show manager update dialog ([#2069](https://github.com/ReVanced/revanced-manager/issues/2069)) ([113a74d](https://github.com/ReVanced/revanced-manager/commit/113a74d270c1c222d4d06049b4edda8f27724a20)), closes [#1963](https://github.com/ReVanced/revanced-manager/issues/1963) [#1958](https://github.com/ReVanced/revanced-manager/issues/1958)
|
||||
* show stacktrace in installer ui ([#36](https://github.com/ReVanced/revanced-manager/issues/36)) ([8d53180](https://github.com/ReVanced/revanced-manager/commit/8d53180d86e6e9d9c8a4056a5fde0603f17e3157))
|
||||
* show toast when no patches are selected ([8aa70d3](https://github.com/ReVanced/revanced-manager/commit/8aa70d350e07aae8b4a22b6bc6fb90c0f6227acd))
|
||||
* splash screen ([60a5a11](https://github.com/ReVanced/revanced-manager/commit/60a5a11c71634aeda414c2ed85f7706ba3deefe1))
|
||||
* store patched apps ([#79](https://github.com/ReVanced/revanced-manager/issues/79)) ([b14285b](https://github.com/ReVanced/revanced-manager/commit/b14285b2c83e60376ad42fa6ea508257cd04d47d))
|
||||
* switch to androidx.navigation ([#2362](https://github.com/ReVanced/revanced-manager/issues/2362)) ([7438f45](https://github.com/ReVanced/revanced-manager/commit/7438f45903ec6ed3436a895d4c32d34d41b00010))
|
||||
* switch to Preferences DataStore ([#60](https://github.com/ReVanced/revanced-manager/issues/60)) ([1852799](https://github.com/ReVanced/revanced-manager/commit/18527999b5f8752faf36c145276d51e2e095c8ee))
|
||||
* switch to revanced api v4 ([7e858a2](https://github.com/ReVanced/revanced-manager/commit/7e858a244cc4038bdb029c4418278700f6a6490f))
|
||||
* switch to the new api ([#75](https://github.com/ReVanced/revanced-manager/issues/75)) ([a55160e](https://github.com/ReVanced/revanced-manager/commit/a55160e7c619ec5541de72fa80f079c9bc94d2d5))
|
||||
* TopAppBar scroll behavior ([#2397](https://github.com/ReVanced/revanced-manager/issues/2397)) ([dc51d61](https://github.com/ReVanced/revanced-manager/commit/dc51d6134dae0fdc415f66e2716c6bffa35dfdb5))
|
||||
* **Update Screen:** changelogs & handle states ([#1464](https://github.com/ReVanced/revanced-manager/issues/1464)) ([3af26e7](https://github.com/ReVanced/revanced-manager/commit/3af26e706571339a3c69688098a51616549c58a8))
|
||||
* **update screen:** complete main update screen ([553af83](https://github.com/ReVanced/revanced-manager/commit/553af831393d7276088ceb0b0a854ec654f72def))
|
||||
* updater changelogs ([#48](https://github.com/ReVanced/revanced-manager/issues/48)) ([6dbcd62](https://github.com/ReVanced/revanced-manager/commit/6dbcd6293e94d8d20cccc401b0edeb1d7047553e))
|
||||
* updater UI and code improvements ([#1597](https://github.com/ReVanced/revanced-manager/issues/1597)) ([a12cae7](https://github.com/ReVanced/revanced-manager/commit/a12cae72998d85138dcf29c0e5d430359e338d5e))
|
||||
* Use "Debug" and "Debug signed" for build names respectively ([5133f02](https://github.com/ReVanced/revanced-manager/commit/5133f02ad61b85af28608c7180b7a2accb4811ab))
|
||||
* Use correct casing in module description ([59b4c0b](https://github.com/ReVanced/revanced-manager/commit/59b4c0b2d2e426dfe66b5a01d219b57bb0df5b8b))
|
||||
* use revanced api for changelogs ([686eb40](https://github.com/ReVanced/revanced-manager/commit/686eb40cb0f8b8d785732dd2bc82d17b5a4fd042))
|
||||
* Use simpler strings ([83d33e8](https://github.com/ReVanced/revanced-manager/commit/83d33e87e3f89cb3efce63dcabcde6478f69b8e7))
|
||||
* View bundle patches ([#2065](https://github.com/ReVanced/revanced-manager/issues/2065)) ([089f200](https://github.com/ReVanced/revanced-manager/commit/089f200fe6ff59020a87883a47ef20a0c4c08565))
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* downgrade Kotlin to 1.8.21 ([fc90bbc](https://github.com/ReVanced/revanced-manager/commit/fc90bbc27ce765e0b55bb5ac9132e58f46aee9aa))
|
||||
@@ -1,4 +1,4 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import io.github.z4kn4fein.semver.toVersion
|
||||
import kotlin.random.Random
|
||||
|
||||
plugins {
|
||||
@@ -53,6 +53,7 @@ dependencies {
|
||||
// Room
|
||||
implementation(libs.room.runtime)
|
||||
implementation(libs.room.ktx)
|
||||
annotationProcessor(libs.room.compiler)
|
||||
ksp(libs.room.compiler)
|
||||
|
||||
// ReVanced
|
||||
@@ -60,7 +61,7 @@ dependencies {
|
||||
implementation(libs.revanced.library)
|
||||
|
||||
// Downloader plugins
|
||||
implementation(projects.api)
|
||||
implementation(project(":api"))
|
||||
|
||||
// Native processes
|
||||
implementation(libs.kotlin.process)
|
||||
@@ -107,25 +108,44 @@ dependencies {
|
||||
|
||||
// Compose Icons
|
||||
implementation(libs.compose.icons.fontawesome)
|
||||
|
||||
// Ackpine
|
||||
implementation(libs.ackpine.core)
|
||||
implementation(libs.ackpine.ktx)
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
// Semantic versioning string parser
|
||||
classpath(libs.semver.parser)
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.manager"
|
||||
compileSdk = 36
|
||||
buildToolsVersion = "36.0.0"
|
||||
compileSdk = 35
|
||||
buildToolsVersion = "35.0.1"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "app.revanced.manager"
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
versionCode = 1
|
||||
versionName = "0.0.1"
|
||||
targetSdk = 35
|
||||
|
||||
val versionStr = if (version == "unspecified") "1.0.0" else version.toString()
|
||||
versionName = versionStr
|
||||
versionCode = with(versionStr.toVersion()) {
|
||||
major * 10_000_000 +
|
||||
minor * 10_000 +
|
||||
patch * 100 +
|
||||
(preRelease?.substringAfterLast('.')?.toInt() ?: 99)
|
||||
}
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
configureEach {
|
||||
}
|
||||
debug {
|
||||
applicationIdSuffix = ".debug"
|
||||
resValue("string", "app_name", "ReVanced Manager (Debug)")
|
||||
@@ -201,11 +221,8 @@ android {
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.fromTarget("17")
|
||||
jvmToolchain(17)
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
@@ -228,6 +245,10 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
}
|
||||
|
||||
tasks {
|
||||
// Needed by gradle-semantic-release-plugin.
|
||||
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435.
|
||||
|
||||
1
app/gradle.properties
Normal file
1
app/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
version = 1.26.0-dev.13
|
||||
1
app/gradlew
vendored
Symbolic link
1
app/gradlew
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../gradlew
|
||||
11
app/package.json
Normal file
11
app/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "app",
|
||||
"private": false,
|
||||
"devDependencies": {
|
||||
"@anolilab/multi-semantic-release": "^1.1.10",
|
||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.10.1"
|
||||
}
|
||||
}
|
||||
@@ -51,9 +51,6 @@
|
||||
|
||||
<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"
|
||||
@@ -75,5 +72,15 @@
|
||||
android:value="androidx.startup"
|
||||
tools:node="remove" />
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
android:exported="false"
|
||||
tools:node="merge">
|
||||
<meta-data
|
||||
android:name="ru.solrudev.ackpine.AckpineInitializer"
|
||||
tools:node="remove" />
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -81,6 +81,7 @@ class MainActivity : ComponentActivity() {
|
||||
)
|
||||
val theme by vm.prefs.theme.getAsState()
|
||||
val dynamicColor by vm.prefs.dynamicColor.getAsState()
|
||||
val pureBlackTheme by vm.prefs.pureBlackTheme.getAsState()
|
||||
|
||||
EventEffect(vm.legacyImportActivityFlow) {
|
||||
try {
|
||||
@@ -91,7 +92,8 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
ReVancedManagerTheme(
|
||||
darkTheme = theme == Theme.SYSTEM && isSystemInDarkTheme() || theme == Theme.DARK,
|
||||
dynamicColor = dynamicColor
|
||||
dynamicColor = dynamicColor,
|
||||
pureBlackTheme = pureBlackTheme
|
||||
) {
|
||||
ReVancedManager(vm)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ class ManagerApplication : Application() {
|
||||
workerModule,
|
||||
viewModelModule,
|
||||
databaseModule,
|
||||
rootModule
|
||||
rootModule,
|
||||
ackpineModule
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
19
app/src/main/java/app/revanced/manager/di/AckpineModule.kt
Normal file
19
app/src/main/java/app/revanced/manager/di/AckpineModule.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package app.revanced.manager.di
|
||||
|
||||
import android.content.Context
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.dsl.module
|
||||
import ru.solrudev.ackpine.installer.PackageInstaller
|
||||
import ru.solrudev.ackpine.uninstaller.PackageUninstaller
|
||||
|
||||
val ackpineModule = module {
|
||||
fun provideInstaller(context: Context) = PackageInstaller.getInstance(context)
|
||||
fun provideUninstaller(context: Context) = PackageUninstaller.getInstance(context)
|
||||
|
||||
single {
|
||||
provideInstaller(androidContext())
|
||||
}
|
||||
single {
|
||||
provideUninstaller(androidContext())
|
||||
}
|
||||
}
|
||||
@@ -27,25 +27,25 @@ class KeystoreManager(app: Application, private val prefs: PreferencesManager) {
|
||||
private val keystorePath =
|
||||
app.getDir("signing", Context.MODE_PRIVATE).resolve("manager.keystore")
|
||||
|
||||
private suspend fun updatePrefs(cn: String, pass: String) = prefs.edit {
|
||||
prefs.keystoreCommonName.value = cn
|
||||
private suspend fun updatePrefs(alias: String, pass: String) = prefs.edit {
|
||||
prefs.keystoreAlias.value = alias
|
||||
prefs.keystorePass.value = pass
|
||||
}
|
||||
|
||||
private suspend fun signingDetails(path: File = keystorePath) = ApkUtils.KeyStoreDetails(
|
||||
keyStore = path,
|
||||
keyStorePassword = null,
|
||||
alias = prefs.keystoreCommonName.get(),
|
||||
alias = prefs.keystoreAlias.get(),
|
||||
password = prefs.keystorePass.get()
|
||||
)
|
||||
|
||||
suspend fun sign(input: File, output: File) = withContext(Dispatchers.Default) {
|
||||
ApkUtils.signApk(input, output, prefs.keystoreCommonName.get(), signingDetails())
|
||||
ApkUtils.signApk(input, output, prefs.keystoreAlias.get(), signingDetails())
|
||||
}
|
||||
|
||||
suspend fun regenerate() = withContext(Dispatchers.Default) {
|
||||
val keyCertPair = ApkSigner.newPrivateKeyCertificatePair(
|
||||
prefs.keystoreCommonName.get(),
|
||||
prefs.keystoreAlias.get(),
|
||||
eightYearsFromNow
|
||||
)
|
||||
val ks = ApkSigner.newKeyStore(
|
||||
@@ -64,13 +64,13 @@ class KeystoreManager(app: Application, private val prefs: PreferencesManager) {
|
||||
updatePrefs(DEFAULT, DEFAULT)
|
||||
}
|
||||
|
||||
suspend fun import(cn: String, pass: String, keystore: InputStream): Boolean {
|
||||
suspend fun import(alias: String, pass: String, keystore: InputStream): Boolean {
|
||||
val keystoreData = withContext(Dispatchers.IO) { keystore.readBytes() }
|
||||
|
||||
try {
|
||||
val ks = ApkSigner.readKeyStore(ByteArrayInputStream(keystoreData), null)
|
||||
|
||||
ApkSigner.readPrivateKeyCertificatePair(ks, cn, pass)
|
||||
ApkSigner.readPrivateKeyCertificatePair(ks, alias, pass)
|
||||
} catch (_: UnrecoverableKeyException) {
|
||||
return false
|
||||
} catch (_: IllegalArgumentException) {
|
||||
@@ -81,7 +81,7 @@ class KeystoreManager(app: Application, private val prefs: PreferencesManager) {
|
||||
Files.write(keystorePath.toPath(), keystoreData)
|
||||
}
|
||||
|
||||
updatePrefs(cn, pass)
|
||||
updatePrefs(alias, pass)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ class PreferencesManager(
|
||||
context: Context
|
||||
) : BasePreferencesManager(context, "settings") {
|
||||
val dynamicColor = booleanPreference("dynamic_color", true)
|
||||
val pureBlackTheme = booleanPreference("pure_black_theme", false)
|
||||
val theme = enumPreference("theme", Theme.SYSTEM)
|
||||
|
||||
val api = stringPreference("api_url", "https://api.revanced.app")
|
||||
@@ -16,12 +17,14 @@ class PreferencesManager(
|
||||
val useProcessRuntime = booleanPreference("use_process_runtime", false)
|
||||
val patcherProcessMemoryLimit = intPreference("process_runtime_memory_limit", 700)
|
||||
|
||||
val keystoreCommonName = stringPreference("keystore_cn", KeystoreManager.DEFAULT)
|
||||
val keystoreAlias = stringPreference("keystore_alias", KeystoreManager.DEFAULT)
|
||||
val keystorePass = stringPreference("keystore_pass", KeystoreManager.DEFAULT)
|
||||
|
||||
val firstLaunch = booleanPreference("first_launch", true)
|
||||
val managerAutoUpdates = booleanPreference("manager_auto_updates", false)
|
||||
val showManagerUpdateDialogOnLaunch = booleanPreference("show_manager_update_dialog_on_launch", true)
|
||||
val useManagerPrereleases = booleanPreference("manager_prereleases", false)
|
||||
val usePatchesPrereleases = booleanPreference("patches_prereleases", false)
|
||||
|
||||
val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false)
|
||||
val disableSelectionWarning = booleanPreference("disable_selection_warning", false)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package app.revanced.manager.network.api
|
||||
|
||||
import android.os.Build
|
||||
import app.revanced.manager.BuildConfig
|
||||
import app.revanced.manager.domain.manager.PreferencesManager
|
||||
import app.revanced.manager.network.dto.ReVancedAsset
|
||||
import app.revanced.manager.network.dto.ReVancedGitRepository
|
||||
@@ -30,11 +30,12 @@ class ReVancedAPI(
|
||||
private suspend inline fun <reified T> request(route: String) = request<T>(apiUrl(), route)
|
||||
|
||||
suspend fun getAppUpdate() =
|
||||
getLatestAppInfo().getOrThrow().takeIf { it.version != Build.VERSION.RELEASE }
|
||||
getLatestAppInfo().getOrThrow().takeIf { it.version.removePrefix("v") != BuildConfig.VERSION_NAME }
|
||||
|
||||
suspend fun getLatestAppInfo() = request<ReVancedAsset>("manager")
|
||||
suspend fun getLatestAppInfo() =
|
||||
request<ReVancedAsset>("manager?prerelease=${prefs.useManagerPrereleases.get()}")
|
||||
|
||||
suspend fun getPatchesUpdate() = request<ReVancedAsset>("patches")
|
||||
suspend fun getPatchesUpdate() = request<ReVancedAsset>("patches?prerelease=${prefs.usePatchesPrereleases.get()}")
|
||||
|
||||
suspend fun getContributors() = request<List<ReVancedGitRepository>>("contributors")
|
||||
|
||||
|
||||
@@ -16,12 +16,8 @@ import io.ktor.http.isSuccess
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import io.ktor.utils.io.core.isNotEmpty
|
||||
import io.ktor.utils.io.core.readBytes
|
||||
import io.ktor.utils.io.core.remaining
|
||||
import io.ktor.utils.io.exhausted
|
||||
import io.ktor.utils.io.readRemaining
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.asSink
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
import java.io.OutputStream
|
||||
@@ -73,14 +69,14 @@ class HttpService(
|
||||
) {
|
||||
http.prepareGet(builder).execute { httpResponse ->
|
||||
if (httpResponse.status.isSuccess()) {
|
||||
val stream = outputStream.asSink()
|
||||
val channel: ByteReadChannel = httpResponse.body()
|
||||
var count = 0L
|
||||
stream.use {
|
||||
while (!channel.exhausted()) {
|
||||
val chunk = channel.readRemaining()
|
||||
count += chunk.remaining
|
||||
chunk.transferTo(stream)
|
||||
withContext(Dispatchers.IO) {
|
||||
while (!channel.isClosedForRead) {
|
||||
val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong())
|
||||
while (packet.isNotEmpty) {
|
||||
val bytes = packet.readBytes()
|
||||
outputStream.write(bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package app.revanced.manager.service
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
class InstallService : Service() {
|
||||
|
||||
override fun onStartCommand(
|
||||
intent: Intent, flags: Int, startId: Int
|
||||
): Int {
|
||||
val extraStatus = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)
|
||||
val extraStatusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
|
||||
val extraPackageName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)
|
||||
when (extraStatus) {
|
||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||
startActivity(if (Build.VERSION.SDK_INT >= 33) {
|
||||
intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
|
||||
} else {
|
||||
intent.getParcelableExtra(Intent.EXTRA_INTENT)
|
||||
}.apply {
|
||||
this?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
})
|
||||
}
|
||||
|
||||
else -> {
|
||||
sendBroadcast(Intent().apply {
|
||||
action = APP_INSTALL_ACTION
|
||||
`package` = packageName
|
||||
putExtra(EXTRA_INSTALL_STATUS, extraStatus)
|
||||
putExtra(EXTRA_INSTALL_STATUS_MESSAGE, extraStatusMessage)
|
||||
putExtra(EXTRA_PACKAGE_NAME, extraPackageName)
|
||||
})
|
||||
}
|
||||
}
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
companion object {
|
||||
const val APP_INSTALL_ACTION = "APP_INSTALL_ACTION"
|
||||
|
||||
const val EXTRA_INSTALL_STATUS = "EXTRA_INSTALL_STATUS"
|
||||
const val EXTRA_INSTALL_STATUS_MESSAGE = "EXTRA_INSTALL_STATUS_MESSAGE"
|
||||
const val EXTRA_PACKAGE_NAME = "EXTRA_PACKAGE_NAME"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package app.revanced.manager.ui.component
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.PackageInstaller
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
@@ -79,7 +80,7 @@ private fun installerStatusDialogButton(
|
||||
enum class DialogKind(
|
||||
val flag: Int,
|
||||
val title: Int,
|
||||
@StringRes val contentStringResId: Int,
|
||||
@param:StringRes val contentStringResId: Int,
|
||||
val icon: ImageVector = Icons.Outlined.ErrorOutline,
|
||||
val confirmButton: InstallerStatusDialogButton = installerStatusDialogButton(R.string.ok),
|
||||
val dismissButton: InstallerStatusDialogButton? = null,
|
||||
@@ -133,10 +134,8 @@ enum class DialogKind(
|
||||
title = R.string.installation_storage_issue_dialog_title,
|
||||
contentStringResId = R.string.installation_storage_issue_description,
|
||||
),
|
||||
|
||||
@RequiresApi(34)
|
||||
FAILURE_TIMEOUT(
|
||||
flag = PackageInstaller.STATUS_FAILURE_TIMEOUT,
|
||||
flag = @SuppressLint("InlinedApi") PackageInstaller.STATUS_FAILURE_TIMEOUT,
|
||||
title = R.string.installation_timeout_dialog_title,
|
||||
contentStringResId = R.string.installation_timeout_description,
|
||||
confirmButton = installerStatusDialogButton(R.string.install_app) { model ->
|
||||
|
||||
@@ -2,9 +2,7 @@ package app.revanced.manager.ui.component
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.text.TextLinkStyles
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import com.mikepenz.markdown.compose.Markdown
|
||||
import com.mikepenz.markdown.m3.markdownColor
|
||||
import com.mikepenz.markdown.m3.markdownTypography
|
||||
@@ -20,29 +18,15 @@ fun Markdown(
|
||||
colors = markdownColor(
|
||||
text = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
codeBackground = MaterialTheme.colorScheme.secondaryContainer,
|
||||
codeText = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
linkText = MaterialTheme.colorScheme.primary
|
||||
),
|
||||
typography = markdownTypography(
|
||||
h1 = MaterialTheme.typography.headlineSmall.copy(fontWeight = FontWeight.Bold),
|
||||
h2 = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold),
|
||||
h3 = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold),
|
||||
text = MaterialTheme.typography.bodyMedium,
|
||||
code = markdownTypography().code.copy(color = MaterialTheme.colorScheme.onSecondaryContainer),
|
||||
list = MaterialTheme.typography.bodyMedium,
|
||||
textLink = TextLinkStyles(
|
||||
style = MaterialTheme.typography.bodyMedium.copy(
|
||||
fontWeight = FontWeight.Bold, textDecoration = TextDecoration.Underline,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
).toSpanStyle(),
|
||||
hoveredStyle = MaterialTheme.typography.bodyMedium.copy(
|
||||
fontWeight = FontWeight.Bold, textDecoration = TextDecoration.Underline,
|
||||
color = MaterialTheme.colorScheme.secondary
|
||||
).toSpanStyle(),
|
||||
pressedStyle = MaterialTheme.typography.bodyMedium.copy(
|
||||
fontWeight = FontWeight.Bold, textDecoration = TextDecoration.Underline,
|
||||
color = MaterialTheme.colorScheme.tertiary
|
||||
).toSpanStyle()
|
||||
|
||||
),
|
||||
list = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import app.revanced.manager.domain.bundles.LocalPatchBundle
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.asRemoteOrNull
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.isDefault
|
||||
import app.revanced.manager.domain.manager.PreferencesManager
|
||||
import app.revanced.manager.domain.repository.PatchBundleRepository
|
||||
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.ExceptionViewerDialog
|
||||
@@ -65,12 +66,14 @@ fun BundleInformationDialog(
|
||||
) {
|
||||
val bundleRepo = koinInject<PatchBundleRepository>()
|
||||
val networkInfo = koinInject<NetworkInfo>()
|
||||
val prefs = koinInject<PreferencesManager>()
|
||||
val hasNetwork = remember { networkInfo.isConnected() }
|
||||
val composableScope = rememberCoroutineScope()
|
||||
var viewCurrentBundlePatches by remember { mutableStateOf(false) }
|
||||
val isLocal = src is LocalPatchBundle
|
||||
val bundleManifestAttributes = src.patchBundle?.manifestAttributes
|
||||
val (autoUpdate, endpoint) = src.asRemoteOrNull?.let { it.autoUpdate to it.endpoint } ?: (null to null)
|
||||
val (autoUpdate, endpoint) = src.asRemoteOrNull?.let { it.autoUpdate to it.endpoint }
|
||||
?: (null to null)
|
||||
|
||||
fun onAutoUpdateChange(new: Boolean) = composableScope.launch {
|
||||
with(bundleRepo) {
|
||||
@@ -173,6 +176,34 @@ fun BundleInformationDialog(
|
||||
)
|
||||
}
|
||||
|
||||
if (src.isDefault) {
|
||||
val useBundlePrerelease by prefs.usePatchesPrereleases.getAsState()
|
||||
|
||||
BundleListItem(
|
||||
headlineText = stringResource(R.string.patches_prereleases),
|
||||
supportingText = stringResource(R.string.patches_prereleases_description, src.name),
|
||||
trailingContent = {
|
||||
HapticSwitch(
|
||||
checked = useBundlePrerelease,
|
||||
onCheckedChange = {
|
||||
composableScope.launch {
|
||||
prefs.usePatchesPrereleases.update(
|
||||
it
|
||||
)
|
||||
onUpdate()
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
modifier = Modifier.clickable {
|
||||
composableScope.launch {
|
||||
prefs.usePatchesPrereleases.update(!useBundlePrerelease)
|
||||
onUpdate()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
endpoint?.takeUnless { src.isDefault }?.let { url ->
|
||||
var showUrlInputDialog by rememberSaveable {
|
||||
mutableStateOf(false)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package app.revanced.manager.ui.component.patcher
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Cancel
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
@@ -21,6 +20,7 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -53,20 +53,11 @@ fun Steps(
|
||||
category: StepCategory,
|
||||
steps: List<Step>,
|
||||
stepCount: Pair<Int, Int>? = null,
|
||||
stepProgressProvider: StepProgressProvider
|
||||
stepProgressProvider: StepProgressProvider,
|
||||
isExpanded: Boolean = false,
|
||||
onExpand: () -> Unit,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
var expanded by rememberSaveable { mutableStateOf(true) }
|
||||
|
||||
val categoryColor by animateColorAsState(
|
||||
if (expanded) MaterialTheme.colorScheme.surfaceContainerHigh else Color.Transparent,
|
||||
label = "category"
|
||||
)
|
||||
|
||||
val cardColor by animateColorAsState(
|
||||
if (expanded) MaterialTheme.colorScheme.surfaceContainer else Color.Transparent,
|
||||
label = "card"
|
||||
)
|
||||
|
||||
val state = remember(steps) {
|
||||
when {
|
||||
steps.all { it.state == State.COMPLETED } -> State.COMPLETED
|
||||
@@ -76,48 +67,52 @@ fun Steps(
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(state) {
|
||||
if (state == State.RUNNING)
|
||||
onExpand()
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.clip(MaterialTheme.shapes.large)
|
||||
.fillMaxWidth()
|
||||
.background(cardColor)
|
||||
.background(MaterialTheme.colorScheme.surfaceContainerLow)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.clickable { expanded = !expanded }
|
||||
.background(categoryColor)
|
||||
.clickable(true, onClick = onClick)
|
||||
.fillMaxWidth()
|
||||
.padding(20.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
StepIcon(state = state, size = 24.dp)
|
||||
StepIcon(state = state, size = 24.dp)
|
||||
|
||||
Text(stringResource(category.displayName))
|
||||
Text(stringResource(category.displayName))
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
val stepProgress = remember(stepCount, steps) {
|
||||
stepCount?.let { (current, total) -> "$current/$total" }
|
||||
?: "${steps.count { it.state == State.COMPLETED }}/${steps.size}"
|
||||
}
|
||||
|
||||
Text(
|
||||
text = stepProgress,
|
||||
style = MaterialTheme.typography.labelSmall
|
||||
)
|
||||
|
||||
ArrowButton(modifier = Modifier.size(24.dp), expanded = expanded, onClick = null)
|
||||
val stepProgress = remember(stepCount, steps) {
|
||||
stepCount?.let { (current, total) -> "$current/$total" }
|
||||
?: "${steps.count { it.state == State.COMPLETED }}/${steps.size}"
|
||||
}
|
||||
|
||||
Text(
|
||||
text = stepProgress,
|
||||
style = MaterialTheme.typography.labelSmall
|
||||
)
|
||||
|
||||
ArrowButton(modifier = Modifier.size(24.dp), expanded = isExpanded, onClick = null)
|
||||
}
|
||||
|
||||
AnimatedVisibility(visible = expanded) {
|
||||
AnimatedVisibility(visible = isExpanded) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.background.copy(0.6f))
|
||||
.fillMaxWidth()
|
||||
.padding(top = 10.dp)
|
||||
) {
|
||||
steps.forEach { step ->
|
||||
steps.forEachIndexed { index, step ->
|
||||
val (progress, progressText) = when (step.progressKey) {
|
||||
null -> null
|
||||
ProgressKey.DOWNLOAD -> stepProgressProvider.downloadProgress?.let { (downloaded, total) ->
|
||||
@@ -131,7 +126,9 @@ fun Steps(
|
||||
state = step.state,
|
||||
message = step.message,
|
||||
progress = progress,
|
||||
progressText = progressText
|
||||
progressText = progressText,
|
||||
isFirst = index == 0,
|
||||
isLast = index == steps.lastIndex,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -145,7 +142,9 @@ fun SubStep(
|
||||
state: State,
|
||||
message: String? = null,
|
||||
progress: Float? = null,
|
||||
progressText: String? = null
|
||||
progressText: String? = null,
|
||||
isFirst: Boolean = false,
|
||||
isLast: Boolean = false,
|
||||
) {
|
||||
var messageExpanded by rememberSaveable { mutableStateOf(true) }
|
||||
|
||||
@@ -156,22 +155,22 @@ fun SubStep(
|
||||
clickable { messageExpanded = !messageExpanded }
|
||||
else this
|
||||
}
|
||||
.padding(top = if (isFirst) 10.dp else 8.dp, bottom = if (isLast) 20.dp else 8.dp)
|
||||
.padding(horizontal = 20.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.size(24.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
StepIcon(state, progress, size = 20.dp)
|
||||
}
|
||||
StepIcon(
|
||||
size = 18.dp,
|
||||
state = state,
|
||||
progress = progress,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = name,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.weight(1f, true),
|
||||
@@ -201,7 +200,7 @@ fun SubStep(
|
||||
text = message.orEmpty(),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
modifier = Modifier.padding(horizontal = 52.dp, vertical = 8.dp)
|
||||
modifier = Modifier.padding(horizontal = 36.dp, vertical = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -211,40 +210,44 @@ fun SubStep(
|
||||
fun StepIcon(state: State, progress: Float? = null, size: Dp) {
|
||||
val strokeWidth = Dp(floor(size.value / 10) + 1)
|
||||
|
||||
when (state) {
|
||||
State.COMPLETED -> Icon(
|
||||
Icons.Filled.CheckCircle,
|
||||
contentDescription = stringResource(R.string.step_completed),
|
||||
tint = MaterialTheme.colorScheme.surfaceTint,
|
||||
modifier = Modifier.size(size)
|
||||
)
|
||||
|
||||
State.FAILED -> Icon(
|
||||
Icons.Filled.Cancel,
|
||||
contentDescription = stringResource(R.string.step_failed),
|
||||
tint = MaterialTheme.colorScheme.error,
|
||||
modifier = Modifier.size(size)
|
||||
)
|
||||
|
||||
State.WAITING -> Icon(
|
||||
Icons.Outlined.Circle,
|
||||
contentDescription = stringResource(R.string.step_waiting),
|
||||
tint = MaterialTheme.colorScheme.surfaceVariant,
|
||||
modifier = Modifier.size(size)
|
||||
)
|
||||
|
||||
State.RUNNING ->
|
||||
LoadingIndicator(
|
||||
modifier = stringResource(R.string.step_running).let { description ->
|
||||
Modifier
|
||||
.size(size)
|
||||
.semantics {
|
||||
contentDescription = description
|
||||
}
|
||||
},
|
||||
progress = { progress },
|
||||
strokeWidth = strokeWidth
|
||||
Crossfade(targetState = state, label = "State CrossFade") { state ->
|
||||
when (state) {
|
||||
State.COMPLETED -> Icon(
|
||||
Icons.Filled.CheckCircle,
|
||||
contentDescription = stringResource(R.string.step_completed),
|
||||
tint = Color(0xFF59B463),
|
||||
modifier = Modifier.size(size)
|
||||
)
|
||||
|
||||
State.FAILED -> Icon(
|
||||
Icons.Filled.Cancel,
|
||||
contentDescription = stringResource(R.string.step_failed),
|
||||
tint = MaterialTheme.colorScheme.error,
|
||||
modifier = Modifier.size(size)
|
||||
)
|
||||
|
||||
State.WAITING -> Icon(
|
||||
Icons.Outlined.Circle,
|
||||
contentDescription = stringResource(R.string.step_waiting),
|
||||
tint = MaterialTheme.colorScheme.onSurface.copy(.2f),
|
||||
modifier = Modifier.size(size)
|
||||
)
|
||||
|
||||
State.RUNNING -> {
|
||||
LoadingIndicator(
|
||||
modifier = stringResource(R.string.step_running).let { description ->
|
||||
Modifier
|
||||
.size(size)
|
||||
.semantics {
|
||||
contentDescription = description
|
||||
}
|
||||
},
|
||||
|
||||
progress = { progress },
|
||||
strokeWidth = strokeWidth
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -234,7 +234,13 @@ fun AppSelectorScreen(
|
||||
|
||||
}
|
||||
} else {
|
||||
item { LoadingIndicator() }
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier.fillParentMaxSize(), contentAlignment = Alignment.Center
|
||||
) {
|
||||
LoadingIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import app.revanced.manager.ui.model.StepCategory
|
||||
import app.revanced.manager.ui.viewmodel.PatcherViewModel
|
||||
import app.revanced.manager.util.APK_MIMETYPE
|
||||
import app.revanced.manager.util.EventEffect
|
||||
import app.revanced.manager.util.toast
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -76,11 +77,10 @@ fun PatcherScreen(
|
||||
var showInstallPicker by rememberSaveable { mutableStateOf(false) }
|
||||
var showDismissConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
fun onPageBack() {
|
||||
if(patcherSucceeded == null)
|
||||
showDismissConfirmationDialog = true
|
||||
else
|
||||
onLeave()
|
||||
fun onPageBack() = when {
|
||||
patcherSucceeded == null -> showDismissConfirmationDialog = true
|
||||
viewModel.isInstalling -> context.toast(context.getString(R.string.patcher_install_in_progress))
|
||||
else -> onLeave()
|
||||
}
|
||||
|
||||
BackHandler(onBack = ::onPageBack)
|
||||
@@ -213,6 +213,12 @@ fun PatcherScreen(
|
||||
.padding(paddingValues)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
var expandedCategory by rememberSaveable { mutableStateOf<StepCategory?>(null) }
|
||||
|
||||
val expandCategory: (StepCategory?) -> Unit = { category ->
|
||||
expandedCategory = category
|
||||
}
|
||||
|
||||
LinearProgressIndicator(
|
||||
progress = { viewModel.progress },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
@@ -231,7 +237,12 @@ fun PatcherScreen(
|
||||
category = category,
|
||||
steps = steps,
|
||||
stepCount = if (category == StepCategory.PATCHING) viewModel.patchesProgress else null,
|
||||
stepProgressProvider = viewModel
|
||||
stepProgressProvider = viewModel,
|
||||
isExpanded = expandedCategory == category,
|
||||
onExpand = { expandCategory(category) },
|
||||
onClick = {
|
||||
expandCategory(if (expandedCategory == category) null else category)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@@ -76,12 +77,12 @@ fun SelectedAppInfoScreen(
|
||||
val bundles by vm.bundleInfoFlow.collectAsStateWithLifecycle(emptyList())
|
||||
|
||||
val allowIncompatiblePatches by vm.prefs.disablePatchVersionCompatCheck.getAsState()
|
||||
val patches = remember(bundles, allowIncompatiblePatches) {
|
||||
vm.getPatches(bundles, allowIncompatiblePatches)
|
||||
}
|
||||
val selectedPatchCount = remember(patches) {
|
||||
patches.values.sumOf { it.size }
|
||||
val patches by remember {
|
||||
derivedStateOf {
|
||||
vm.getPatches(bundles, allowIncompatiblePatches)
|
||||
}
|
||||
}
|
||||
val selectedPatchCount = patches.values.sumOf { it.size }
|
||||
|
||||
val launcher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.StartActivityForResult(),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.manager.ui.screen.settings
|
||||
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
@@ -34,6 +35,8 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.platform.UriHandler
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
@@ -57,6 +60,7 @@ fun ContributorSettingsScreen(
|
||||
) {
|
||||
val repositories = viewModel.repositories
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@@ -93,7 +97,8 @@ fun ContributorSettingsScreen(
|
||||
) {
|
||||
ContributorsCard(
|
||||
title = it.name,
|
||||
contributors = it.contributors
|
||||
contributors = it.contributors,
|
||||
uriHandler = uriHandler
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -115,7 +120,8 @@ fun ContributorsCard(
|
||||
title: String,
|
||||
contributors: List<ReVancedContributor>,
|
||||
itemsPerPage: Int = 12,
|
||||
numberOfRows: Int = 2
|
||||
numberOfRows: Int = 2,
|
||||
uriHandler: UriHandler
|
||||
) {
|
||||
val itemsPerRow = (itemsPerPage / numberOfRows)
|
||||
|
||||
@@ -172,7 +178,11 @@ fun ContributorsCard(
|
||||
contributorsByPage[page].forEach {
|
||||
if (itemSize > 100.dp) {
|
||||
Row(
|
||||
modifier = Modifier.width(itemSize - 1.dp), // we delete 1.dp to account for not-so divisible numbers
|
||||
modifier = Modifier
|
||||
.width(itemSize - 1.dp)
|
||||
.clickable {
|
||||
uriHandler.openUri("https://github.com/${it.username}")
|
||||
}, // we delete 1.dp to account for not-so divisible numbers
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
@@ -203,6 +213,9 @@ fun ContributorsCard(
|
||||
modifier = Modifier
|
||||
.size(size = (itemSize - 1.dp).coerceAtMost(50.dp)) // we delete 1.dp to account for not-so divisible numbers
|
||||
.clip(CircleShape)
|
||||
.clickable {
|
||||
uriHandler.openUri("https://github.com/${it.username}")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package app.revanced.manager.ui.screen.settings
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -10,10 +12,13 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
@@ -28,6 +33,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -36,10 +42,10 @@ import app.revanced.manager.R
|
||||
import app.revanced.manager.network.downloader.DownloaderPluginState
|
||||
import app.revanced.manager.ui.component.AppLabel
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.ConfirmDialog
|
||||
import app.revanced.manager.ui.component.ExceptionViewerDialog
|
||||
import app.revanced.manager.ui.component.GroupHeader
|
||||
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.ConfirmDialog
|
||||
import app.revanced.manager.ui.component.haptics.HapticCheckbox
|
||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
||||
import app.revanced.manager.ui.viewmodel.DownloadsViewModel
|
||||
@@ -52,6 +58,7 @@ fun DownloadsSettingsScreen(
|
||||
onBackClick: () -> Unit,
|
||||
viewModel: DownloadsViewModel = koinViewModel()
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val downloadedApps by viewModel.downloadedApps.collectAsStateWithLifecycle(emptyList())
|
||||
val pluginStates by viewModel.downloaderPluginStates.collectAsStateWithLifecycle()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
@@ -75,7 +82,7 @@ fun DownloadsSettingsScreen(
|
||||
onBackClick = onBackClick,
|
||||
actions = {
|
||||
if (viewModel.appSelection.isNotEmpty()) {
|
||||
IconButton(onClick = { showDeleteConfirmationDialog = true }) {
|
||||
IconButton(onClick = { viewModel.deleteApps() }) {
|
||||
Icon(Icons.Default.Delete, stringResource(R.string.delete))
|
||||
}
|
||||
}
|
||||
@@ -121,6 +128,11 @@ fun DownloadsSettingsScreen(
|
||||
.digest(androidSignature.toByteArray())
|
||||
hash.toHexString(format = HexFormat.UpperCase)
|
||||
}
|
||||
val appName = remember {
|
||||
packageInfo.applicationInfo?.loadLabel(context.packageManager)
|
||||
?.toString()
|
||||
?: packageName
|
||||
}
|
||||
|
||||
when (state) {
|
||||
is DownloaderPluginState.Loaded -> TrustDialog(
|
||||
@@ -130,6 +142,8 @@ fun DownloadsSettingsScreen(
|
||||
packageName,
|
||||
signature
|
||||
),
|
||||
pluginName = appName,
|
||||
signature = signature,
|
||||
onDismiss = ::dismiss,
|
||||
onConfirm = {
|
||||
viewModel.revokePluginTrust(packageName)
|
||||
@@ -147,10 +161,10 @@ fun DownloadsSettingsScreen(
|
||||
is DownloaderPluginState.Untrusted -> TrustDialog(
|
||||
title = R.string.downloader_plugin_trust_dialog_title,
|
||||
body = stringResource(
|
||||
R.string.downloader_plugin_trust_dialog_body,
|
||||
packageName,
|
||||
signature
|
||||
R.string.downloader_plugin_trust_dialog_body
|
||||
),
|
||||
pluginName = appName,
|
||||
signature = signature,
|
||||
onDismiss = ::dismiss,
|
||||
onConfirm = {
|
||||
viewModel.trustPlugin(packageName)
|
||||
@@ -226,6 +240,8 @@ fun DownloadsSettingsScreen(
|
||||
private fun TrustDialog(
|
||||
@StringRes title: Int,
|
||||
body: String,
|
||||
pluginName: String,
|
||||
signature: String,
|
||||
onDismiss: () -> Unit,
|
||||
onConfirm: () -> Unit
|
||||
) {
|
||||
@@ -238,10 +254,39 @@ private fun TrustDialog(
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(R.string.dismiss))
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
title = { Text(stringResource(title)) },
|
||||
text = { Text(body) }
|
||||
text = {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Text(body)
|
||||
Card {
|
||||
Column(
|
||||
Modifier.padding(12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.downloader_plugin_trust_dialog_plugin,
|
||||
pluginName
|
||||
),
|
||||
)
|
||||
OutlinedCard(
|
||||
colors = CardDefaults.outlinedCardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHighest
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.downloader_plugin_trust_dialog_signature,
|
||||
signature.chunked(2).joinToString(" ")
|
||||
), modifier = Modifier.padding(12.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.manager.ui.screen.settings
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -96,6 +97,14 @@ fun GeneralSettingsScreen(
|
||||
description = R.string.dynamic_color_description
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(theme != Theme.LIGHT) {
|
||||
BooleanItem(
|
||||
preference = prefs.pureBlackTheme,
|
||||
coroutineScope = coroutineScope,
|
||||
headline = R.string.pure_black_theme,
|
||||
description = R.string.pure_black_theme_description
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,10 +104,10 @@ fun ImportExportSettingsScreen(
|
||||
if (vm.showCredentialsDialog) {
|
||||
KeystoreCredentialsDialog(
|
||||
onDismissRequest = vm::cancelKeystoreImport,
|
||||
onSubmit = { cn, pass ->
|
||||
onSubmit = { alias, pass ->
|
||||
vm.viewModelScope.launch {
|
||||
uiSafe(context, R.string.failed_to_import_keystore, "Failed to import keystore") {
|
||||
val result = vm.tryKeystoreImport(cn, pass)
|
||||
val result = vm.tryKeystoreImport(alias, pass)
|
||||
if (!result) context.toast(context.getString(R.string.import_keystore_wrong_credentials))
|
||||
}
|
||||
}
|
||||
@@ -382,7 +382,7 @@ fun KeystoreCredentialsDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
onSubmit: (String, String) -> Unit
|
||||
) {
|
||||
var cn by rememberSaveable { mutableStateOf("") }
|
||||
var alias by rememberSaveable { mutableStateOf("") }
|
||||
var pass by rememberSaveable { mutableStateOf("") }
|
||||
|
||||
AlertDialog(
|
||||
@@ -390,7 +390,7 @@ fun KeystoreCredentialsDialog(
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onSubmit(cn, pass)
|
||||
onSubmit(alias, pass)
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.import_keystore_dialog_button))
|
||||
@@ -422,8 +422,8 @@ fun KeystoreCredentialsDialog(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = cn,
|
||||
onValueChange = { cn = it },
|
||||
value = alias,
|
||||
onValueChange = { alias = it },
|
||||
label = { Text(stringResource(R.string.import_keystore_dialog_alias_field)) }
|
||||
)
|
||||
PasswordField(
|
||||
|
||||
@@ -92,6 +92,12 @@ fun UpdatesSettingsScreen(
|
||||
headline = R.string.show_manager_update_dialog_on_launch,
|
||||
description = R.string.show_manager_update_dialog_on_launch_description
|
||||
)
|
||||
|
||||
BooleanItem(
|
||||
preference = vm.useManagerPrereleases,
|
||||
headline = R.string.manager_prereleases,
|
||||
description = R.string.manager_prereleases_description
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,7 @@ private val LightColorScheme = lightColorScheme(
|
||||
fun ReVancedManagerTheme(
|
||||
darkTheme: Boolean,
|
||||
dynamicColor: Boolean,
|
||||
pureBlackTheme: Boolean,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
@@ -93,6 +94,10 @@ fun ReVancedManagerTheme(
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}.let {
|
||||
if (darkTheme && pureBlackTheme)
|
||||
it.copy(background = Color.Black, surface = Color.Black)
|
||||
else it
|
||||
}
|
||||
|
||||
val view = LocalView.current
|
||||
|
||||
@@ -47,7 +47,7 @@ class AdvancedSettingsViewModel(
|
||||
app.contentResolver.openOutputStream(target)!!.bufferedWriter().use { writer ->
|
||||
val consumer = Redirect.Consume { flow ->
|
||||
flow.onEach {
|
||||
writer.write(it)
|
||||
writer.write("${it}\n")
|
||||
}.flowOn(Dispatchers.IO).collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -154,12 +154,12 @@ class ImportExportViewModel(
|
||||
keystoreImportPath = null
|
||||
}
|
||||
|
||||
suspend fun tryKeystoreImport(cn: String, pass: String) =
|
||||
tryKeystoreImport(cn, pass, keystoreImportPath!!)
|
||||
suspend fun tryKeystoreImport(alias: String, pass: String) =
|
||||
tryKeystoreImport(alias, pass, keystoreImportPath!!)
|
||||
|
||||
private suspend fun tryKeystoreImport(cn: String, pass: String, path: Path): Boolean {
|
||||
private suspend fun tryKeystoreImport(alias: String, pass: String, path: Path): Boolean {
|
||||
path.inputStream().use { stream ->
|
||||
if (keystoreManager.import(cn, pass, stream)) {
|
||||
if (keystoreManager.import(alias, pass, stream)) {
|
||||
app.toast(app.getString(R.string.import_keystore_success))
|
||||
cancelKeystoreImport()
|
||||
return true
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
package app.revanced.manager.ui.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.revanced.manager.R
|
||||
@@ -19,7 +13,6 @@ import app.revanced.manager.data.room.apps.installed.InstallType
|
||||
import app.revanced.manager.data.room.apps.installed.InstalledApp
|
||||
import app.revanced.manager.domain.installer.RootInstaller
|
||||
import app.revanced.manager.domain.repository.InstalledAppRepository
|
||||
import app.revanced.manager.service.UninstallService
|
||||
import app.revanced.manager.util.PM
|
||||
import app.revanced.manager.util.PatchSelection
|
||||
import app.revanced.manager.util.simpleMessage
|
||||
@@ -30,6 +23,8 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import ru.solrudev.ackpine.session.Session
|
||||
import ru.solrudev.ackpine.uninstaller.UninstallFailure
|
||||
|
||||
class InstalledAppInfoViewModel(
|
||||
packageName: String
|
||||
@@ -87,51 +82,28 @@ class InstalledAppInfoViewModel(
|
||||
|
||||
fun uninstall() {
|
||||
val app = installedApp ?: return
|
||||
when (app.installType) {
|
||||
InstallType.DEFAULT -> pm.uninstallPackage(app.currentPackageName)
|
||||
|
||||
InstallType.MOUNT -> viewModelScope.launch {
|
||||
rootInstaller.uninstall(app.currentPackageName)
|
||||
installedAppRepository.delete(app)
|
||||
onBackClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val uninstallBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
UninstallService.APP_UNINSTALL_ACTION -> {
|
||||
val extraStatus =
|
||||
intent.getIntExtra(UninstallService.EXTRA_UNINSTALL_STATUS, -999)
|
||||
val extraStatusMessage =
|
||||
intent.getStringExtra(UninstallService.EXTRA_UNINSTALL_STATUS_MESSAGE)
|
||||
|
||||
if (extraStatus == PackageInstaller.STATUS_SUCCESS) {
|
||||
viewModelScope.launch {
|
||||
installedApp?.let {
|
||||
installedAppRepository.delete(it)
|
||||
}
|
||||
onBackClick()
|
||||
viewModelScope.launch {
|
||||
when (app.installType) {
|
||||
InstallType.DEFAULT -> {
|
||||
when (val result = pm.uninstallPackage(app.currentPackageName)) {
|
||||
is Session.State.Failed<UninstallFailure> -> {
|
||||
val msg = result.failure.message.orEmpty()
|
||||
context.toast(
|
||||
this@InstalledAppInfoViewModel.context.getString(
|
||||
R.string.uninstall_app_fail,
|
||||
msg
|
||||
)
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
} else if (extraStatus != PackageInstaller.STATUS_FAILURE_ABORTED) {
|
||||
this@InstalledAppInfoViewModel.context.toast(this@InstalledAppInfoViewModel.context.getString(R.string.uninstall_app_fail, extraStatusMessage))
|
||||
Session.State.Succeeded -> {}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
ContextCompat.registerReceiver(
|
||||
context,
|
||||
it,
|
||||
IntentFilter(UninstallService.APP_UNINSTALL_ACTION),
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
context.unregisterReceiver(uninstallBroadcastReceiver)
|
||||
InstallType.MOUNT -> rootInstaller.uninstall(app.currentPackageName)
|
||||
}
|
||||
installedAppRepository.delete(app)
|
||||
onBackClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +120,10 @@ class MainViewModel(
|
||||
settings.useDynamicTheme?.let { dynamicColor ->
|
||||
prefs.dynamicColor.update(dynamicColor)
|
||||
}
|
||||
settings.usePrereleases?.let { prereleases ->
|
||||
prefs.useManagerPrereleases.update(prereleases)
|
||||
prefs.usePatchesPrereleases.update(prereleases)
|
||||
}
|
||||
settings.apiUrl?.let { api ->
|
||||
prefs.api.update(api.removeSuffix("/"))
|
||||
}
|
||||
@@ -143,7 +147,7 @@ class MainViewModel(
|
||||
settings.keystore?.let { keystore ->
|
||||
val keystoreBytes = Base64.decode(keystore, Base64.DEFAULT)
|
||||
keystoreManager.import(
|
||||
"ReVanced",
|
||||
"alias",
|
||||
settings.keystorePassword,
|
||||
keystoreBytes.inputStream()
|
||||
)
|
||||
@@ -159,6 +163,7 @@ class MainViewModel(
|
||||
val keystorePassword: String,
|
||||
val themeMode: Int? = null,
|
||||
val useDynamicTheme: Boolean? = null,
|
||||
val usePrereleases: Boolean? = null,
|
||||
val apiUrl: String? = null,
|
||||
val experimentalPatchesEnabled: Boolean? = null,
|
||||
val patchesAutoUpdate: Boolean? = null,
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package app.revanced.manager.ui.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.content.pm.PackageInstaller as AndroidPackageInstaller
|
||||
import android.net.Uri
|
||||
import android.os.ParcelUuid
|
||||
import android.util.Log
|
||||
@@ -16,7 +14,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.autoSaver
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.map
|
||||
@@ -37,8 +34,6 @@ import app.revanced.manager.patcher.logger.Logger
|
||||
import app.revanced.manager.patcher.worker.PatcherWorker
|
||||
import app.revanced.manager.plugin.downloader.PluginHostApi
|
||||
import app.revanced.manager.plugin.downloader.UserInteractionException
|
||||
import app.revanced.manager.service.InstallService
|
||||
import app.revanced.manager.service.UninstallService
|
||||
import app.revanced.manager.ui.model.InstallerModel
|
||||
import app.revanced.manager.ui.model.ProgressKey
|
||||
import app.revanced.manager.ui.model.SelectedApp
|
||||
@@ -48,16 +43,19 @@ import app.revanced.manager.ui.model.StepCategory
|
||||
import app.revanced.manager.ui.model.StepProgressProvider
|
||||
import app.revanced.manager.ui.model.navigation.Patcher
|
||||
import app.revanced.manager.util.PM
|
||||
import app.revanced.manager.util.asCode
|
||||
import app.revanced.manager.util.saveableVar
|
||||
import app.revanced.manager.util.saver.snapshotStateListSaver
|
||||
import app.revanced.manager.util.simpleMessage
|
||||
import app.revanced.manager.util.tag
|
||||
import app.revanced.manager.util.toast
|
||||
import app.revanced.manager.util.uiSafe
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -66,6 +64,15 @@ import kotlinx.coroutines.withContext
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import org.koin.core.component.inject
|
||||
import ru.solrudev.ackpine.installer.InstallFailure
|
||||
import ru.solrudev.ackpine.installer.PackageInstaller
|
||||
import ru.solrudev.ackpine.installer.createSession
|
||||
import ru.solrudev.ackpine.installer.getSession
|
||||
import ru.solrudev.ackpine.session.ProgressSession
|
||||
import ru.solrudev.ackpine.session.Session
|
||||
import ru.solrudev.ackpine.session.await
|
||||
import ru.solrudev.ackpine.session.parameters.Confirmation
|
||||
import ru.solrudev.ackpine.uninstaller.UninstallFailure
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.time.Duration
|
||||
@@ -81,6 +88,7 @@ class PatcherViewModel(
|
||||
private val installedAppRepository: InstalledAppRepository by inject()
|
||||
private val rootInstaller: RootInstaller by inject()
|
||||
private val savedStateHandle: SavedStateHandle = get()
|
||||
private val ackpineInstaller: PackageInstaller = get()
|
||||
|
||||
private var installedApp: InstalledApp? = null
|
||||
private val selectedApp = input.selectedApp
|
||||
@@ -95,7 +103,6 @@ class PatcherViewModel(
|
||||
mutableStateOf<String?>(null)
|
||||
}
|
||||
private set
|
||||
private var ongoingPmSession: Boolean by savedStateHandle.saveableVar { false }
|
||||
var packageInstallerStatus: Int? by savedStateHandle.saveable(
|
||||
key = "packageInstallerStatus",
|
||||
stateSaver = autoSaver()
|
||||
@@ -104,7 +111,7 @@ class PatcherViewModel(
|
||||
}
|
||||
private set
|
||||
|
||||
var isInstalling by mutableStateOf(ongoingPmSession)
|
||||
var isInstalling by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
private var currentActivityRequest: Pair<CompletableDeferred<Boolean>, String>? by mutableStateOf(
|
||||
@@ -123,6 +130,18 @@ class PatcherViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This coroutine scope is used to await installations.
|
||||
* It should not be cancelled on system-initiated process death since that would cancel the installation process.
|
||||
*/
|
||||
private val installerCoroutineScope = CoroutineScope(Dispatchers.Main)
|
||||
|
||||
/**
|
||||
* Holds the package name of the Apk we are trying to install.
|
||||
*/
|
||||
private var installerPkgName: String by savedStateHandle.saveableVar { "" }
|
||||
private var installerSessionId: ParcelUuid? by savedStateHandle.saveableVar()
|
||||
|
||||
private var inputFile: File? by savedStateHandle.saveableVar()
|
||||
private val outputFile = tempDir.resolve("output.apk")
|
||||
|
||||
@@ -174,67 +193,68 @@ class PatcherViewModel(
|
||||
private val workManager = WorkManager.getInstance(app)
|
||||
|
||||
private val patcherWorkerId by savedStateHandle.saveable<ParcelUuid> {
|
||||
ParcelUuid(workerRepository.launchExpedited<PatcherWorker, PatcherWorker.Args>(
|
||||
"patching", PatcherWorker.Args(
|
||||
input.selectedApp,
|
||||
outputFile.path,
|
||||
input.selectedPatches,
|
||||
input.options,
|
||||
logger,
|
||||
onDownloadProgress = {
|
||||
withContext(Dispatchers.Main) {
|
||||
downloadProgress = it
|
||||
}
|
||||
},
|
||||
onPatchCompleted = { withContext(Dispatchers.Main) { completedPatchCount += 1 } },
|
||||
setInputFile = { withContext(Dispatchers.Main) { inputFile = it } },
|
||||
handleStartActivityRequest = { plugin, intent ->
|
||||
withContext(Dispatchers.Main) {
|
||||
if (currentActivityRequest != null) throw Exception("Another request is already pending.")
|
||||
try {
|
||||
// Wait for the dialog interaction.
|
||||
val accepted = with(CompletableDeferred<Boolean>()) {
|
||||
currentActivityRequest = this to plugin.name
|
||||
|
||||
await()
|
||||
}
|
||||
if (!accepted) throw UserInteractionException.RequestDenied()
|
||||
|
||||
// Launch the activity and wait for the result.
|
||||
ParcelUuid(
|
||||
workerRepository.launchExpedited<PatcherWorker, PatcherWorker.Args>(
|
||||
"patching", PatcherWorker.Args(
|
||||
input.selectedApp,
|
||||
outputFile.path,
|
||||
input.selectedPatches,
|
||||
input.options,
|
||||
logger,
|
||||
onDownloadProgress = {
|
||||
withContext(Dispatchers.Main) {
|
||||
downloadProgress = it
|
||||
}
|
||||
},
|
||||
onPatchCompleted = { withContext(Dispatchers.Main) { completedPatchCount += 1 } },
|
||||
setInputFile = { withContext(Dispatchers.Main) { inputFile = it } },
|
||||
handleStartActivityRequest = { plugin, intent ->
|
||||
withContext(Dispatchers.Main) {
|
||||
if (currentActivityRequest != null) throw Exception("Another request is already pending.")
|
||||
try {
|
||||
with(CompletableDeferred<ActivityResult>()) {
|
||||
launchedActivity = this
|
||||
launchActivityChannel.send(intent)
|
||||
// Wait for the dialog interaction.
|
||||
val accepted = with(CompletableDeferred<Boolean>()) {
|
||||
currentActivityRequest = this to plugin.name
|
||||
|
||||
await()
|
||||
}
|
||||
if (!accepted) throw UserInteractionException.RequestDenied()
|
||||
|
||||
// Launch the activity and wait for the result.
|
||||
try {
|
||||
with(CompletableDeferred<ActivityResult>()) {
|
||||
launchedActivity = this
|
||||
launchActivityChannel.send(intent)
|
||||
await()
|
||||
}
|
||||
} finally {
|
||||
launchedActivity = null
|
||||
}
|
||||
} finally {
|
||||
launchedActivity = null
|
||||
currentActivityRequest = null
|
||||
}
|
||||
}
|
||||
},
|
||||
onProgress = { name, state, message ->
|
||||
viewModelScope.launch {
|
||||
steps[currentStepIndex] = steps[currentStepIndex].run {
|
||||
copy(
|
||||
name = name ?: this.name,
|
||||
state = state ?: this.state,
|
||||
message = message ?: this.message
|
||||
)
|
||||
}
|
||||
|
||||
if (state == State.COMPLETED && currentStepIndex != steps.lastIndex) {
|
||||
currentStepIndex++
|
||||
|
||||
steps[currentStepIndex] =
|
||||
steps[currentStepIndex].copy(state = State.RUNNING)
|
||||
}
|
||||
} finally {
|
||||
currentActivityRequest = null
|
||||
}
|
||||
}
|
||||
},
|
||||
onProgress = { name, state, message ->
|
||||
viewModelScope.launch {
|
||||
steps[currentStepIndex] = steps[currentStepIndex].run {
|
||||
copy(
|
||||
name = name ?: this.name,
|
||||
state = state ?: this.state,
|
||||
message = message ?: this.message
|
||||
)
|
||||
}
|
||||
|
||||
if (state == State.COMPLETED && currentStepIndex != steps.lastIndex) {
|
||||
currentStepIndex++
|
||||
|
||||
steps[currentStepIndex] =
|
||||
steps[currentStepIndex].copy(state = State.RUNNING)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
))
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
val patcherSucceeded =
|
||||
@@ -246,64 +266,26 @@ class PatcherViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
private val installerBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
InstallService.APP_INSTALL_ACTION -> {
|
||||
val pmStatus = intent.getIntExtra(
|
||||
InstallService.EXTRA_INSTALL_STATUS,
|
||||
PackageInstaller.STATUS_FAILURE
|
||||
)
|
||||
init {
|
||||
// TODO: detect system-initiated process death during the patching process.
|
||||
|
||||
intent.getStringExtra(UninstallService.EXTRA_UNINSTALL_STATUS_MESSAGE)
|
||||
?.let(logger::trace)
|
||||
|
||||
if (pmStatus == PackageInstaller.STATUS_SUCCESS) {
|
||||
app.toast(app.getString(R.string.install_app_success))
|
||||
installedPackageName =
|
||||
intent.getStringExtra(InstallService.EXTRA_PACKAGE_NAME)
|
||||
viewModelScope.launch {
|
||||
installedAppRepository.addOrUpdate(
|
||||
installedPackageName!!,
|
||||
packageName,
|
||||
input.selectedApp.version
|
||||
?: pm.getPackageInfo(outputFile)?.versionName!!,
|
||||
InstallType.DEFAULT,
|
||||
input.selectedPatches
|
||||
)
|
||||
installerSessionId?.uuid?.let { id ->
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
isInstalling = true
|
||||
uiSafe(app, R.string.install_app_fail, "Failed to install") {
|
||||
// The process was killed during installation. Await the session again.
|
||||
withContext(Dispatchers.IO) {
|
||||
ackpineInstaller.getSession(id)
|
||||
}?.let {
|
||||
awaitInstallation(it)
|
||||
}
|
||||
} else packageInstallerStatus = pmStatus
|
||||
|
||||
}
|
||||
} finally {
|
||||
isInstalling = false
|
||||
}
|
||||
|
||||
UninstallService.APP_UNINSTALL_ACTION -> {
|
||||
val pmStatus = intent.getIntExtra(
|
||||
UninstallService.EXTRA_UNINSTALL_STATUS,
|
||||
PackageInstaller.STATUS_FAILURE
|
||||
)
|
||||
|
||||
intent.getStringExtra(UninstallService.EXTRA_UNINSTALL_STATUS_MESSAGE)
|
||||
?.let(logger::trace)
|
||||
|
||||
if (pmStatus != PackageInstaller.STATUS_SUCCESS)
|
||||
packageInstallerStatus = pmStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
// TODO: detect system-initiated process death during the patching process.
|
||||
ContextCompat.registerReceiver(
|
||||
app,
|
||||
installerBroadcastReceiver,
|
||||
IntentFilter().apply {
|
||||
addAction(InstallService.APP_INSTALL_ACTION)
|
||||
addAction(UninstallService.APP_UNINSTALL_ACTION)
|
||||
},
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
)
|
||||
|
||||
viewModelScope.launch {
|
||||
installedApp = installedAppRepository.get(packageName)
|
||||
@@ -313,7 +295,6 @@ class PatcherViewModel(
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
app.unregisterReceiver(installerBroadcastReceiver)
|
||||
workManager.cancelWorkById(patcherWorkerId.uuid)
|
||||
|
||||
if (input.selectedApp is SelectedApp.Installed && installedApp?.installType == InstallType.MOUNT) {
|
||||
@@ -328,6 +309,7 @@ class PatcherViewModel(
|
||||
}
|
||||
|
||||
fun onBack() {
|
||||
installerCoroutineScope.cancel()
|
||||
// tempDir cannot be deleted inside onCleared because it gets called on system-initiated process death.
|
||||
tempDir.deleteRecursively()
|
||||
}
|
||||
@@ -372,44 +354,93 @@ class PatcherViewModel(
|
||||
|
||||
fun open() = installedPackageName?.let(pm::launch)
|
||||
|
||||
fun install(installType: InstallType) = viewModelScope.launch {
|
||||
var pmInstallStarted = false
|
||||
try {
|
||||
isInstalling = true
|
||||
private suspend fun startInstallation(file: File, packageName: String) {
|
||||
val session = withContext(Dispatchers.IO) {
|
||||
ackpineInstaller.createSession(Uri.fromFile(file)) {
|
||||
confirmation = Confirmation.IMMEDIATE
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
installerPkgName = packageName
|
||||
}
|
||||
awaitInstallation(session)
|
||||
}
|
||||
|
||||
val currentPackageInfo = pm.getPackageInfo(outputFile)
|
||||
?: throw Exception("Failed to load application info")
|
||||
|
||||
// If the app is currently installed
|
||||
val existingPackageInfo = pm.getPackageInfo(currentPackageInfo.packageName)
|
||||
if (existingPackageInfo != null) {
|
||||
// Check if the app version is less than the installed version
|
||||
if (pm.getVersionCode(currentPackageInfo) < pm.getVersionCode(existingPackageInfo)) {
|
||||
// Exit if the selected app version is less than the installed version
|
||||
packageInstallerStatus = PackageInstaller.STATUS_FAILURE_CONFLICT
|
||||
return@launch
|
||||
private suspend fun awaitInstallation(session: ProgressSession<InstallFailure>) = withContext(
|
||||
Dispatchers.Main
|
||||
) {
|
||||
val result = installerCoroutineScope.async {
|
||||
try {
|
||||
installerSessionId = ParcelUuid(session.id)
|
||||
withContext(Dispatchers.IO) {
|
||||
session.await()
|
||||
}
|
||||
} finally {
|
||||
installerSessionId = null
|
||||
}
|
||||
}.await()
|
||||
|
||||
when (result) {
|
||||
is Session.State.Failed<InstallFailure> -> {
|
||||
result.failure.message?.let(logger::trace)
|
||||
packageInstallerStatus = result.failure.asCode()
|
||||
}
|
||||
|
||||
when (installType) {
|
||||
InstallType.DEFAULT -> {
|
||||
// Check if the app is mounted as root
|
||||
// If it is, unmount it first, silently
|
||||
if (rootInstaller.hasRootAccess() && rootInstaller.isAppMounted(packageName)) {
|
||||
rootInstaller.unmount(packageName)
|
||||
}
|
||||
Session.State.Succeeded -> {
|
||||
app.toast(app.getString(R.string.install_app_success))
|
||||
installedPackageName = installerPkgName
|
||||
installedAppRepository.addOrUpdate(
|
||||
installerPkgName,
|
||||
packageName,
|
||||
input.selectedApp.version
|
||||
?: withContext(Dispatchers.IO) { pm.getPackageInfo(outputFile)?.versionName!! },
|
||||
InstallType.DEFAULT,
|
||||
input.selectedPatches
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Install regularly
|
||||
pm.installApp(listOf(outputFile))
|
||||
pmInstallStarted = true
|
||||
fun install(installType: InstallType) = viewModelScope.launch {
|
||||
isInstalling = true
|
||||
var needsRootUninstall = false
|
||||
try {
|
||||
uiSafe(app, R.string.install_app_fail, "Failed to install") {
|
||||
val currentPackageInfo =
|
||||
withContext(Dispatchers.IO) { pm.getPackageInfo(outputFile) }
|
||||
?: throw Exception("Failed to load application info")
|
||||
|
||||
// If the app is currently installed
|
||||
val existingPackageInfo =
|
||||
withContext(Dispatchers.IO) { pm.getPackageInfo(currentPackageInfo.packageName) }
|
||||
if (existingPackageInfo != null) {
|
||||
// Check if the app version is less than the installed version
|
||||
if (
|
||||
pm.getVersionCode(currentPackageInfo) < pm.getVersionCode(
|
||||
existingPackageInfo
|
||||
)
|
||||
) {
|
||||
// Exit if the selected app version is less than the installed version
|
||||
packageInstallerStatus = AndroidPackageInstaller.STATUS_FAILURE_CONFLICT
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
InstallType.MOUNT -> {
|
||||
try {
|
||||
val packageInfo = pm.getPackageInfo(outputFile)
|
||||
?: throw Exception("Failed to load application info")
|
||||
when (installType) {
|
||||
InstallType.DEFAULT -> {
|
||||
// Check if the app is mounted as root
|
||||
// If it is, unmount it first, silently
|
||||
if (rootInstaller.hasRootAccess() && rootInstaller.isAppMounted(packageName)) {
|
||||
rootInstaller.unmount(packageName)
|
||||
}
|
||||
|
||||
// Install regularly
|
||||
startInstallation(outputFile, currentPackageInfo.packageName)
|
||||
}
|
||||
|
||||
InstallType.MOUNT -> {
|
||||
val label = with(pm) {
|
||||
packageInfo.label()
|
||||
currentPackageInfo.label()
|
||||
}
|
||||
|
||||
// Check for base APK, first check if the app is already installed
|
||||
@@ -417,15 +448,17 @@ class PatcherViewModel(
|
||||
// If the app is not installed, check if the output file is a base apk
|
||||
if (currentPackageInfo.splitNames.isNotEmpty()) {
|
||||
// Exit if there is no base APK package
|
||||
packageInstallerStatus = PackageInstaller.STATUS_FAILURE_INVALID
|
||||
packageInstallerStatus =
|
||||
AndroidPackageInstaller.STATUS_FAILURE_INVALID
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
val inputVersion = input.selectedApp.version
|
||||
?: inputFile?.let(pm::getPackageInfo)?.versionName
|
||||
?: withContext(Dispatchers.IO) { inputFile?.let(pm::getPackageInfo)?.versionName }
|
||||
?: throw Exception("Failed to determine input APK version")
|
||||
|
||||
needsRootUninstall = true
|
||||
// Install as root
|
||||
rootInstaller.install(
|
||||
outputFile,
|
||||
@@ -436,7 +469,7 @@ class PatcherViewModel(
|
||||
)
|
||||
|
||||
installedAppRepository.addOrUpdate(
|
||||
packageInfo.packageName,
|
||||
currentPackageInfo.packageName,
|
||||
packageName,
|
||||
inputVersion,
|
||||
InstallType.MOUNT,
|
||||
@@ -448,21 +481,20 @@ class PatcherViewModel(
|
||||
installedPackageName = packageName
|
||||
|
||||
app.toast(app.getString(R.string.install_app_success))
|
||||
} catch (e: Exception) {
|
||||
Log.e(tag, "Failed to install as root", e)
|
||||
app.toast(app.getString(R.string.install_app_fail, e.simpleMessage()))
|
||||
try {
|
||||
rootInstaller.uninstall(packageName)
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
needsRootUninstall = false
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(tag, "Failed to install", e)
|
||||
app.toast(app.getString(R.string.install_app_fail, e.simpleMessage()))
|
||||
} finally {
|
||||
if (!pmInstallStarted) isInstalling = false
|
||||
isInstalling = false
|
||||
if (needsRootUninstall) {
|
||||
try {
|
||||
withContext(NonCancellable) {
|
||||
rootInstaller.uninstall(packageName)
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,12 +505,27 @@ class PatcherViewModel(
|
||||
|
||||
override fun reinstall() {
|
||||
viewModelScope.launch {
|
||||
uiSafe(app, R.string.reinstall_app_fail, "Failed to reinstall") {
|
||||
pm.getPackageInfo(outputFile)?.packageName?.let { pm.uninstallPackage(it) }
|
||||
?: throw Exception("Failed to load application info")
|
||||
|
||||
pm.installApp(listOf(outputFile))
|
||||
try {
|
||||
isInstalling = true
|
||||
uiSafe(app, R.string.reinstall_app_fail, "Failed to reinstall") {
|
||||
val pkgName = withContext(Dispatchers.IO) {
|
||||
pm.getPackageInfo(outputFile)?.packageName
|
||||
?: throw Exception("Failed to load application info")
|
||||
}
|
||||
|
||||
when (val result = pm.uninstallPackage(pkgName)) {
|
||||
is Session.State.Failed<UninstallFailure> -> {
|
||||
result.failure.message?.let(logger::trace)
|
||||
packageInstallerStatus = result.failure.asCode()
|
||||
return@launch
|
||||
}
|
||||
|
||||
Session.State.Succeeded -> {}
|
||||
}
|
||||
startInstallation(outputFile, pkgName)
|
||||
}
|
||||
} finally {
|
||||
isInstalling = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.os.Parcelable
|
||||
import android.util.Log
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -129,8 +128,6 @@ class SelectedAppInfoViewModel(
|
||||
}
|
||||
|
||||
var options: Options by savedStateHandle.saveable {
|
||||
val state = mutableStateOf<Options>(emptyMap())
|
||||
|
||||
viewModelScope.launch {
|
||||
if (!persistConfiguration) return@launch // TODO: save options for patched apps.
|
||||
val bundlePatches = bundleInfoFlow.first()
|
||||
@@ -141,7 +138,7 @@ class SelectedAppInfoViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
state
|
||||
mutableStateOf(emptyMap())
|
||||
}
|
||||
private set
|
||||
|
||||
@@ -149,8 +146,6 @@ class SelectedAppInfoViewModel(
|
||||
if (input.patches != null)
|
||||
return@saveable mutableStateOf(SelectionState.Customized(input.patches))
|
||||
|
||||
val selection: MutableState<SelectionState> = mutableStateOf(SelectionState.Default)
|
||||
|
||||
// Try to get the previous selection if customization is enabled.
|
||||
viewModelScope.launch {
|
||||
if (!prefs.disableSelectionWarning.get()) return@launch
|
||||
@@ -160,7 +155,7 @@ class SelectedAppInfoViewModel(
|
||||
selectionState = SelectionState.Customized(previous)
|
||||
}
|
||||
|
||||
selection
|
||||
mutableStateOf(SelectionState.Default)
|
||||
}
|
||||
|
||||
var showSourceSelector by mutableStateOf(false)
|
||||
@@ -311,7 +306,7 @@ class SelectedAppInfoViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
enum class Error(@StringRes val resourceId: Int) {
|
||||
enum class Error(@param:StringRes val resourceId: Int) {
|
||||
NoPlugins(R.string.downloader_no_plugins_available)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
package app.revanced.manager.ui.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.net.Uri
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableLongStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.revanced.manager.R
|
||||
@@ -21,8 +16,6 @@ import app.revanced.manager.data.platform.NetworkInfo
|
||||
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.service.InstallService
|
||||
import app.revanced.manager.util.PM
|
||||
import app.revanced.manager.util.toast
|
||||
import app.revanced.manager.util.uiSafe
|
||||
import io.ktor.client.plugins.onDownload
|
||||
@@ -31,7 +24,14 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import org.koin.core.component.inject
|
||||
import ru.solrudev.ackpine.installer.InstallFailure
|
||||
import ru.solrudev.ackpine.installer.PackageInstaller
|
||||
import ru.solrudev.ackpine.installer.createSession
|
||||
import ru.solrudev.ackpine.session.Session
|
||||
import ru.solrudev.ackpine.session.await
|
||||
import ru.solrudev.ackpine.session.parameters.Confirmation
|
||||
|
||||
class UpdateViewModel(
|
||||
private val downloadOnScreenEntry: Boolean
|
||||
@@ -39,10 +39,11 @@ class UpdateViewModel(
|
||||
private val app: Application by inject()
|
||||
private val reVancedAPI: ReVancedAPI by inject()
|
||||
private val http: HttpService by inject()
|
||||
private val pm: PM by inject()
|
||||
private val networkInfo: NetworkInfo by inject()
|
||||
private val fs: Filesystem by inject()
|
||||
private val ackpineInstaller: PackageInstaller = get()
|
||||
|
||||
// TODO: save state to handle process death.
|
||||
var downloadedSize by mutableLongStateOf(0L)
|
||||
private set
|
||||
var totalSize by mutableLongStateOf(0L)
|
||||
@@ -62,14 +63,17 @@ class UpdateViewModel(
|
||||
private set
|
||||
|
||||
private val location = fs.tempDir.resolve("updater.apk")
|
||||
private val job = viewModelScope.launch {
|
||||
uiSafe(app, R.string.download_manager_failed, "Failed to download ReVanced Manager") {
|
||||
releaseInfo = reVancedAPI.getAppUpdate() ?: throw Exception("No update available")
|
||||
|
||||
if (downloadOnScreenEntry) {
|
||||
downloadUpdate()
|
||||
} else {
|
||||
state = State.CAN_DOWNLOAD
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
uiSafe(app, R.string.download_manager_failed, "Failed to download ReVanced Manager") {
|
||||
releaseInfo = reVancedAPI.getAppUpdate() ?: throw Exception("No update available")
|
||||
|
||||
if (downloadOnScreenEntry) {
|
||||
downloadUpdate()
|
||||
} else {
|
||||
state = State.CAN_DOWNLOAD
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +91,7 @@ class UpdateViewModel(
|
||||
url(release.downloadUrl)
|
||||
onDownload { bytesSentTotal, contentLength ->
|
||||
downloadedSize = bytesSentTotal
|
||||
totalSize = contentLength ?: 0
|
||||
totalSize = contentLength
|
||||
}
|
||||
}
|
||||
installUpdate()
|
||||
@@ -98,50 +102,36 @@ class UpdateViewModel(
|
||||
|
||||
fun installUpdate() = viewModelScope.launch {
|
||||
state = State.INSTALLING
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
ackpineInstaller.createSession(Uri.fromFile(location)) {
|
||||
confirmation = Confirmation.IMMEDIATE
|
||||
}.await()
|
||||
}
|
||||
|
||||
pm.installApp(listOf(location))
|
||||
}
|
||||
|
||||
private val installBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
intent?.let {
|
||||
val pmStatus = intent.getIntExtra(InstallService.EXTRA_INSTALL_STATUS, -999)
|
||||
val extra =
|
||||
intent.getStringExtra(InstallService.EXTRA_INSTALL_STATUS_MESSAGE)!!
|
||||
|
||||
when(pmStatus) {
|
||||
PackageInstaller.STATUS_SUCCESS -> {
|
||||
app.toast(app.getString(R.string.install_app_success))
|
||||
state = State.SUCCESS
|
||||
}
|
||||
PackageInstaller.STATUS_FAILURE_ABORTED -> {
|
||||
state = State.CAN_INSTALL
|
||||
}
|
||||
else -> {
|
||||
app.toast(app.getString(R.string.install_app_fail, extra))
|
||||
installError = extra
|
||||
state = State.FAILED
|
||||
}
|
||||
when (result) {
|
||||
is Session.State.Failed<InstallFailure> -> when (val failure = result.failure) {
|
||||
is InstallFailure.Aborted -> state = State.CAN_INSTALL
|
||||
else -> {
|
||||
val msg = failure.message.orEmpty()
|
||||
app.toast(app.getString(R.string.install_app_fail, msg))
|
||||
installError = msg
|
||||
state = State.FAILED
|
||||
}
|
||||
}
|
||||
|
||||
Session.State.Succeeded -> {
|
||||
app.toast(app.getString(R.string.install_app_success))
|
||||
state = State.SUCCESS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
ContextCompat.registerReceiver(app, installBroadcastReceiver, IntentFilter().apply {
|
||||
addAction(InstallService.APP_INSTALL_ACTION)
|
||||
}, ContextCompat.RECEIVER_NOT_EXPORTED)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
app.unregisterReceiver(installBroadcastReceiver)
|
||||
|
||||
job.cancel()
|
||||
location.delete()
|
||||
}
|
||||
|
||||
enum class State(@StringRes val title: Int) {
|
||||
enum class State(@param:StringRes val title: Int) {
|
||||
CAN_DOWNLOAD(R.string.update_available),
|
||||
DOWNLOADING(R.string.downloading_manager_update),
|
||||
CAN_INSTALL(R.string.ready_to_install_update),
|
||||
|
||||
@@ -17,6 +17,8 @@ class UpdatesSettingsViewModel(
|
||||
) : ViewModel() {
|
||||
val managerAutoUpdates = prefs.managerAutoUpdates
|
||||
val showManagerUpdateDialogOnLaunch = prefs.showManagerUpdateDialogOnLaunch
|
||||
val useManagerPrereleases = prefs.useManagerPrereleases
|
||||
|
||||
|
||||
val isConnected: Boolean
|
||||
get() = network.isConnected()
|
||||
|
||||
30
app/src/main/java/app/revanced/manager/util/Ackpine.kt
Normal file
30
app/src/main/java/app/revanced/manager/util/Ackpine.kt
Normal file
@@ -0,0 +1,30 @@
|
||||
package app.revanced.manager.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.PackageInstaller
|
||||
import ru.solrudev.ackpine.installer.InstallFailure
|
||||
import ru.solrudev.ackpine.uninstaller.UninstallFailure
|
||||
|
||||
/**
|
||||
* Converts an Ackpine installation failure into a PM status code
|
||||
*/
|
||||
fun InstallFailure.asCode() = when (this) {
|
||||
is InstallFailure.Aborted -> PackageInstaller.STATUS_FAILURE_ABORTED
|
||||
is InstallFailure.Blocked -> PackageInstaller.STATUS_FAILURE_BLOCKED
|
||||
is InstallFailure.Conflict -> PackageInstaller.STATUS_FAILURE_CONFLICT
|
||||
is InstallFailure.Incompatible -> PackageInstaller.STATUS_FAILURE_INCOMPATIBLE
|
||||
is InstallFailure.Invalid -> PackageInstaller.STATUS_FAILURE_INVALID
|
||||
is InstallFailure.Storage -> PackageInstaller.STATUS_FAILURE_STORAGE
|
||||
is InstallFailure.Timeout -> @SuppressLint("InlinedApi") PackageInstaller.STATUS_FAILURE_TIMEOUT
|
||||
else -> PackageInstaller.STATUS_FAILURE
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Ackpine uninstallation failure into a PM status code
|
||||
*/
|
||||
fun UninstallFailure.asCode() = when (this) {
|
||||
is UninstallFailure.Aborted -> PackageInstaller.STATUS_FAILURE_ABORTED
|
||||
is UninstallFailure.Blocked -> PackageInstaller.STATUS_FAILURE_BLOCKED
|
||||
is UninstallFailure.Conflict -> PackageInstaller.STATUS_FAILURE_CONFLICT
|
||||
else -> PackageInstaller.STATUS_FAILURE
|
||||
}
|
||||
@@ -2,11 +2,8 @@ package app.revanced.manager.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.PackageInfoFlags
|
||||
import android.content.pm.PackageManager.NameNotFoundException
|
||||
@@ -16,8 +13,6 @@ import android.os.Build
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import app.revanced.manager.domain.repository.PatchBundleRepository
|
||||
import app.revanced.manager.service.InstallService
|
||||
import app.revanced.manager.service.UninstallService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
@@ -25,10 +20,13 @@ import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import ru.solrudev.ackpine.session.await
|
||||
import ru.solrudev.ackpine.session.parameters.Confirmation
|
||||
import ru.solrudev.ackpine.uninstaller.PackageUninstaller
|
||||
import ru.solrudev.ackpine.uninstaller.createSession
|
||||
import ru.solrudev.ackpine.uninstaller.parameters.UninstallParametersDsl
|
||||
import java.io.File
|
||||
|
||||
private const val byteArraySize = 1024 * 1024 // Because 1,048,576 is not readable
|
||||
|
||||
@Immutable
|
||||
@Parcelize
|
||||
data class AppInfo(
|
||||
@@ -40,7 +38,8 @@ data class AppInfo(
|
||||
@SuppressLint("QueryPermissionsNeeded")
|
||||
class PM(
|
||||
private val app: Application,
|
||||
patchBundleRepository: PatchBundleRepository
|
||||
patchBundleRepository: PatchBundleRepository,
|
||||
private val uninstaller: PackageUninstaller
|
||||
) {
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
@@ -145,17 +144,11 @@ class PM(
|
||||
false
|
||||
)
|
||||
|
||||
suspend fun installApp(apks: List<File>) = withContext(Dispatchers.IO) {
|
||||
val packageInstaller = app.packageManager.packageInstaller
|
||||
packageInstaller.openSession(packageInstaller.createSession(sessionParams)).use { session ->
|
||||
apks.forEach { apk -> session.writeApk(apk) }
|
||||
session.commit(app.installIntentSender)
|
||||
}
|
||||
}
|
||||
|
||||
fun uninstallPackage(pkg: String) {
|
||||
val packageInstaller = app.packageManager.packageInstaller
|
||||
packageInstaller.uninstall(pkg, app.uninstallIntentSender)
|
||||
suspend fun uninstallPackage(pkg: String, config: UninstallParametersDsl.() -> Unit = {}) = withContext(Dispatchers.IO) {
|
||||
uninstaller.createSession(pkg) {
|
||||
confirmation = Confirmation.IMMEDIATE
|
||||
config()
|
||||
}.await()
|
||||
}
|
||||
|
||||
fun launch(pkg: String) = app.packageManager.getLaunchIntentForPackage(pkg)?.let {
|
||||
@@ -164,44 +157,4 @@ class PM(
|
||||
}
|
||||
|
||||
fun canInstallPackages() = app.packageManager.canRequestPackageInstalls()
|
||||
|
||||
private fun PackageInstaller.Session.writeApk(apk: File) {
|
||||
apk.inputStream().use { inputStream ->
|
||||
openWrite(apk.name, 0, apk.length()).use { outputStream ->
|
||||
inputStream.copyTo(outputStream, byteArraySize)
|
||||
fsync(outputStream)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val intentFlags
|
||||
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
PendingIntent.FLAG_MUTABLE
|
||||
else
|
||||
0
|
||||
|
||||
private val sessionParams
|
||||
get() = PackageInstaller.SessionParams(
|
||||
PackageInstaller.SessionParams.MODE_FULL_INSTALL
|
||||
).apply {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
setRequestUpdateOwnership(true)
|
||||
setInstallReason(PackageManager.INSTALL_REASON_USER)
|
||||
}
|
||||
|
||||
private val Context.installIntentSender
|
||||
get() = PendingIntent.getService(
|
||||
this,
|
||||
0,
|
||||
Intent(this, InstallService::class.java),
|
||||
intentFlags
|
||||
).intentSender
|
||||
|
||||
private val Context.uninstallIntentSender
|
||||
get() = PendingIntent.getService(
|
||||
this,
|
||||
0,
|
||||
Intent(this, UninstallService::class.java),
|
||||
intentFlags
|
||||
).intentSender
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import app.revanced.manager.R
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -42,6 +43,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.format.MonthNames
|
||||
@@ -52,7 +54,6 @@ import java.util.Locale
|
||||
import kotlin.properties.PropertyDelegateProvider
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
||||
typealias PatchSelection = Map<Int, Set<String>>
|
||||
typealias Options = Map<Int, Map<String, Map<String, Any?>>>
|
||||
@@ -82,6 +83,8 @@ fun Context.toast(string: String, duration: Int = Toast.LENGTH_SHORT) {
|
||||
inline fun uiSafe(context: Context, @StringRes toastMsg: Int, logMsg: String, block: () -> Unit) {
|
||||
try {
|
||||
block()
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (error: Exception) {
|
||||
// You can only toast on the main thread.
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
@@ -141,10 +144,9 @@ suspend fun <T> Flow<Iterable<T>>.collectEach(block: suspend (T) -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
fun LocalDateTime.relativeTime(context: Context): String {
|
||||
try {
|
||||
val now = kotlin.time.Clock.System.now()
|
||||
val now = Clock.System.now()
|
||||
val duration = now - this.toInstant(TimeZone.UTC)
|
||||
|
||||
return when {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<item quantity="other">%d patches</item>
|
||||
</plurals>
|
||||
<plurals name="patches_executed">
|
||||
<item quantity="one">Executed %d patch</item>
|
||||
<item quantity="other">Executed %d patches</item>
|
||||
<item quantity="one">Execute %d patch</item>
|
||||
<item quantity="other">Execute %d patches</item>
|
||||
</plurals>
|
||||
<plurals name="selected_count">
|
||||
<item quantity="other">%d selected</item>
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
<!--
|
||||
Strings with new lines must be raw strings, where the string is wrapped in double quotes and new lines are regular line breaks and not \n
|
||||
Raw strings still require escaping embedded double quotes, but single quote characters can be escaped or used as-is.
|
||||
|
||||
Raw strings are required because Crowdin AI translations regularly gets confused and
|
||||
replace \n with an encoded new line character.
|
||||
|
||||
Bad:
|
||||
<string name="summary_key">First \'item\' text\nSecond \"item\" text</string>
|
||||
Good:
|
||||
<string name="summary_key">"First 'item' text
|
||||
Second \"item\" text"</string>
|
||||
|
||||
-->
|
||||
<resources>
|
||||
<string name="app_name">ReVanced Manager</string>
|
||||
<string name="patcher">Patcher</string>
|
||||
@@ -55,7 +69,7 @@
|
||||
<string name="network_metered_warning">You are currently on a metered connection. Data charges from your service provider may apply.</string>
|
||||
|
||||
<string name="apk_source_selector_item">Select APK source</string>
|
||||
<string name="apk_source_auto">Using all APK downloader</string>
|
||||
<string name="apk_source_auto">Using all APK downloaders</string>
|
||||
<string name="apk_source_downloader">Using %s</string>
|
||||
<string name="apk_source_installed">Using installed APK</string>
|
||||
<string name="apk_source_local">Using a local APK file</string>
|
||||
@@ -86,21 +100,31 @@
|
||||
<string name="contributors_description">View the contributors of ReVanced</string>
|
||||
<string name="dynamic_color">Dynamic color</string>
|
||||
<string name="dynamic_color_description">Adapt colors to the wallpaper</string>
|
||||
<string name="pure_black_theme">Pure black theme</string>
|
||||
<string name="pure_black_theme_description">Use pure black backgrounds for dark theme</string>
|
||||
<string name="theme">Theme</string>
|
||||
<string name="theme_description">Choose between light or dark theme</string>
|
||||
<string name="safeguards">Safeguards</string>
|
||||
<string name="patch_compat_check">Disable version compatibility check</string>
|
||||
<string name="patch_compat_check_description">The check restricts patches to compatible app versions</string>
|
||||
<string name="patch_compat_check_confirmation">Selecting incompatible patches can result in a broken app.\n\nDo you want to proceed anyways?</string>
|
||||
<string name="patch_compat_check_description">Do not restrict patches to compatible app versions</string>
|
||||
<string name="patch_compat_check_confirmation">"Selecting incompatible patches can result in a broken app.
|
||||
|
||||
Do you want to proceed anyways?"</string>
|
||||
<string name="suggested_version_safeguard">Require suggested app version</string>
|
||||
<string name="suggested_version_safeguard_description">Enforce selection of the suggested app version</string>
|
||||
<string name="suggested_version_safeguard_confirmation">Selecting an app that is not the suggested version may cause unexpected issues.\n\nDo you want to proceed anyways?</string>
|
||||
<string name="suggested_version_safeguard_confirmation">"Selecting an app that is not the suggested version may cause unexpected issues.
|
||||
|
||||
Do you want to proceed anyways?"</string>
|
||||
<string name="patch_selection_safeguard">Allow changing patch selection and options</string>
|
||||
<string name="patch_selection_safeguard_description">Do not prevent selecting or deselecting patches and customization of options</string>
|
||||
<string name="patch_selection_safeguard_confirmation">Changing the selection of patches may cause unexpected issues.\n\nEnable anyways?</string>
|
||||
<string name="patch_selection_safeguard_confirmation">"Changing the selection of patches may cause unexpected issues.
|
||||
|
||||
Enable anyways?"</string>
|
||||
<string name="universal_patches_safeguard">Allow using universal patches</string>
|
||||
<string name="universal_patches_safeguard_description">Do not prevent using universal patches</string>
|
||||
<string name="universal_patches_safeguard_confirmation">Universal patches are not as well tested as those that target specific apps.\n\nEnable anyways?</string>
|
||||
<string name="universal_patches_safeguard_confirmation">"Universal patches are not as well tested as those that target specific apps.
|
||||
|
||||
Enable anyways?"</string>
|
||||
<string name="import_keystore">Import keystore</string>
|
||||
<string name="import_keystore_description">Import a custom keystore</string>
|
||||
<string name="import_keystore_dialog_title">Enter keystore credentials</string>
|
||||
@@ -116,7 +140,9 @@
|
||||
<string name="export_keystore_success">Exported keystore</string>
|
||||
<string name="regenerate_keystore">Regenerate keystore</string>
|
||||
<string name="regenerate_keystore_description">Generate a new keystore</string>
|
||||
<string name="regenerate_keystore_dialog_description">You are about to regenerate your keystore the manager will use during the patching process.\n\nYou will not be able to update the previously installed apps from this source.</string>
|
||||
<string name="regenerate_keystore_dialog_description">"You are about to regenerate your keystore the manager will use during the patching process.
|
||||
|
||||
You will not be able to update the previously installed apps from this source."</string>
|
||||
<string name="regenerate_keystore_success">The keystore has been successfully replaced</string>
|
||||
<string name="import_patch_selection">Import patch selection</string>
|
||||
<string name="import_patch_selection_description">Import patch selection from a JSON file</string>
|
||||
@@ -132,8 +158,8 @@
|
||||
<string name="reset_patch_options_description">Reset the stored patch options</string>
|
||||
<string name="reset_patch_selection_success">Patch selection has been reset</string>
|
||||
<string name="patch_selection_reset_all">Reset patch selection globally</string>
|
||||
<string name="patch_selection_reset_all_dialog_description">You are about to reset all the patch selections. You will need to manually select each patch again.</string>
|
||||
<string name="patch_selection_reset_all_description">Resets all the patch selections</string>
|
||||
<string name="patch_selection_reset_all_dialog_description">You are about to reset all patch selections. You will need to manually select each patch again.</string>
|
||||
<string name="patch_selection_reset_all_description">Resets all patch selections</string>
|
||||
<string name="patch_selection_reset_package">Reset patch selection for app</string>
|
||||
<string name="patch_selection_reset_package_dialog_description">You are about to reset the patch selection for the app \"%s\". You will have to manually select each patch again.</string>
|
||||
<string name="patch_selection_reset_package_description">Resets patch selection for a single app</string>
|
||||
@@ -147,7 +173,7 @@
|
||||
<string name="patch_options_reset_patches_dialog_description">You are about to reset the patch options for \"%s\". You will have to reapply each option again.</string>
|
||||
<string name="patch_options_reset_patches_description">Resets the patch options for a specific collection of patches</string>
|
||||
<string name="patch_options_reset_all">Reset patch options globally</string>
|
||||
<string name="patch_options_reset_all_dialog_description">You are about to reset patch options. You will have to reapply each option again.</string>
|
||||
<string name="patch_options_reset_all_dialog_description">You are about to reset all patch options. You will have to reapply each option again.</string>
|
||||
<string name="patch_options_reset_all_description">Resets all patch options</string>
|
||||
<string name="downloader_plugins">Plugins</string>
|
||||
<string name="downloader_plugin_state_trusted">Trusted</string>
|
||||
@@ -155,10 +181,12 @@
|
||||
<string name="downloader_plugin_state_untrusted">Untrusted</string>
|
||||
<string name="downloader_plugin_trust_dialog_title">Trust plugin?</string>
|
||||
<string name="downloader_plugin_revoke_trust_dialog_title">Revoke trust?</string>
|
||||
<string name="downloader_plugin_trust_dialog_body">Package name: %1$s\nSignature (SHA-256): %2$s</string>
|
||||
<string name="downloader_plugin_trust_dialog_body">Continuing will allow this plugin to run on your system.\n\nOnly enable this plugin if you trust it. Plugins can execute arbitrary code and may compromise your device.</string>
|
||||
<string name="downloader_plugin_trust_dialog_signature">Signature:\n\n%s</string>
|
||||
<string name="downloader_plugin_trust_dialog_plugin">Plugin:\n%s</string>
|
||||
<string name="downloader_plugin_delete_apps_title">Delete selected apps</string>
|
||||
<string name="downloader_plugin_delete_apps_description">Are you sure you want to delete the selected apps?</string>
|
||||
<string name="downloader_settings_no_apps">No downloaded apps found</string>
|
||||
<string name="downloader_settings_no_apps">No downloaded apps found.</string>
|
||||
|
||||
<string name="search_apps">Search apps…</string>
|
||||
<string name="loading_body">Loading…</string>
|
||||
@@ -191,7 +219,7 @@
|
||||
<string name="appearance">Appearance</string>
|
||||
<string name="downloaded_apps">Downloaded apps</string>
|
||||
<string name="process_runtime">Run Patcher in another process (experimental)</string>
|
||||
<string name="process_runtime_description">This is faster and allows Patcher to use more memory.</string>
|
||||
<string name="process_runtime_description">This is faster and allows Patcher to use more memory</string>
|
||||
<string name="process_runtime_memory_limit">Patcher process memory limit</string>
|
||||
<string name="process_runtime_memory_limit_description">The max amount of memory that the Patcher process can use (in megabytes)</string>
|
||||
<string name="debug_logs_export">Export debug logs</string>
|
||||
@@ -199,7 +227,7 @@
|
||||
<string name="debug_logs_export_failed">Failed to export logs</string>
|
||||
<string name="debug_logs_export_success">Exported logs</string>
|
||||
<string name="api_url">API URL</string>
|
||||
<string name="api_url_description">The API used to download necessary files.</string>
|
||||
<string name="api_url_description">The API used to download necessary files</string>
|
||||
<string name="api_url_dialog_title">Change API URL</string>
|
||||
<string name="api_url_dialog_description">Change the API URL of ReVanced Manager. ReVanced Manager uses the API to download patches and updates.</string>
|
||||
<string name="api_url_dialog_warning">ReVanced Manager connects to the API to download patches and updates. Make sure that you trust it.</string>
|
||||
@@ -235,14 +263,23 @@
|
||||
<string name="patch_selection_reset_toast">Patch selection and options has been reset to recommended defaults</string>
|
||||
<string name="patch_options_reset_toast">Patch options have been reset</string>
|
||||
<string name="non_suggested_version_warning_title">Non suggested version</string>
|
||||
<string name="non_suggested_version_warning_description">The version of the app you have selected does not match the suggested version.\nPlease use the suggested version: %s\n\nTo continue anyway, disable \"Require suggested app version\" in the advanced settings.</string>
|
||||
<string name="non_suggested_version_warning_description">"The version of the app you have selected does not match the suggested version.
|
||||
Please use the suggested version: %s
|
||||
|
||||
To continue anyway, disable \"Require suggested app version\" in the advanced settings."</string>
|
||||
<string name="selection_warning_title">Stop using defaults?</string>
|
||||
<string name="selection_warning_description">It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou need to turn on \"Allow changing patch selection\" in the advanced settings before toggling patches.</string>
|
||||
<string name="universal_patch_warning_description">Universal patches have a more generalized use and do not work as reliably as patches that target specific apps. You may encounter issues while using them.\n\nYou need to turn on \"Allow using universal patches\" in the advanced settings before using universal patches.</string>
|
||||
<string name="selection_warning_description">"It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.
|
||||
|
||||
You need to turn on \"Allow changing patch selection and options\" in the advanced settings before toggling patches."</string>
|
||||
<string name="universal_patch_warning_description">"Universal patches have a more generalized use and do not work as reliably as patches that target specific apps. You may encounter issues while using them.
|
||||
|
||||
You need to turn on \"Allow using universal patches\" in the advanced settings before using universal patches."</string>
|
||||
<string name="this_version">This version</string>
|
||||
<string name="universal">Any app</string>
|
||||
<string name="search_patches">Search patches</string>
|
||||
<string name="app_version_not_compatible">This patch is not compatible with the selected app version (%1$s).\n\nIt is only compatible with the following version(s): %2$s.</string>
|
||||
<string name="app_version_not_compatible">"This patch is not compatible with the selected app version (%1$s)
|
||||
|
||||
It is only compatible with the following version(s): %2$s"</string>
|
||||
<string name="continue_with_version">Continue with this version?</string>
|
||||
<string name="version_not_compatible">Not all patches are compatible with this version (%s). Do you want to continue anyway?</string>
|
||||
<string name="download_application">Download application?</string>
|
||||
@@ -276,7 +313,7 @@
|
||||
<string name="downloader_app_not_found">Downloader did not find the app</string>
|
||||
<string name="downloader_error">Downloader error: %s</string>
|
||||
<string name="downloader_no_plugins_installed">No downloader installed.</string>
|
||||
<string name="downloader_no_plugins_available">There are downloader installed but none is trusted. Check your settings.</string>
|
||||
<string name="downloader_no_plugins_available">There are downloaders installed but none are trusted. Check your settings.</string>
|
||||
<string name="already_patched">Already patched</string>
|
||||
|
||||
<string name="patch_selector_sheet_filter_title">Filter</string>
|
||||
@@ -318,6 +355,7 @@
|
||||
<string name="patcher_notification_text">Tap to return to the patcher</string>
|
||||
<string name="patcher_stop_confirm_title">Stop patcher</string>
|
||||
<string name="patcher_stop_confirm_description">Are you sure you want to stop the patching process?</string>
|
||||
<string name="patcher_install_in_progress">Installation is in progress. Please wait</string>
|
||||
<string name="execute_patches">Execute patches</string>
|
||||
<string name="executing_patch">Execute %s</string>
|
||||
<string name="failed_to_execute_patch">Failed to execute %s</string>
|
||||
@@ -368,6 +406,8 @@
|
||||
<string name="manual_update_check_description">Manually check for updates</string>
|
||||
<string name="update_checking_manager">Check for updates on launch</string>
|
||||
<string name="update_checking_manager_description">Check for new versions of ReVanced Manager when the application starts</string>
|
||||
<string name="manager_prereleases">Use pre-releases</string>
|
||||
<string name="manager_prereleases_description">Use pre-release versions of ReVanced Manager</string>
|
||||
<string name="changelog">View changelogs</string>
|
||||
<string name="changelog_loading">Loading changelog</string>
|
||||
<string name="changelog_download_fail">Failed to download changelog: %s</string>
|
||||
@@ -381,7 +421,8 @@
|
||||
<string name="save_with_count">Save (%1$s)</string>
|
||||
<string name="update">Update</string>
|
||||
<string name="empty">Empty</string>
|
||||
<string name="installing_message">Tap on <b>Update</b> when prompted.\nReVanced Manager will close when updating.</string>
|
||||
<string name="installing_message">"Tap on <b>Update</b> when prompted.
|
||||
ReVanced Manager will close when updating."</string>
|
||||
<string name="no_changelogs_found">No changelogs found</string>
|
||||
<string name="just_now">Just now</string>
|
||||
<string name="minutes_ago">%sm ago</string>
|
||||
@@ -400,7 +441,9 @@
|
||||
<string name="update_available_dialog_description">A new version of ReVanced Manager (%s) is available.</string>
|
||||
<string name="failed_to_download_update">Failed to download update: %s</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="download_confirmation_metered">You are currently on a metered connection, and data charges from your service provider may apply.\n\nDo you still want to continue?</string>
|
||||
<string name="download_confirmation_metered">"You are currently on a metered connection, and data charges from your service provider may apply.
|
||||
|
||||
Do you still want to continue?"</string>
|
||||
<string name="download_update_confirmation">Download update?</string>
|
||||
<string name="no_contributors_found">No contributors found</string>
|
||||
<string name="select">Select</string>
|
||||
@@ -435,13 +478,17 @@
|
||||
<string name="auto_update">Auto update</string>
|
||||
<string name="add_patches">Add patches</string>
|
||||
<string name="auto_update_description">Automatically update when a new version is available</string>
|
||||
<string name="patches_prereleases">Use pre-releases</string>
|
||||
<string name="patches_prereleases_description">Use pre-release versions of %s</string>
|
||||
<string name="patches_url">Patches URL</string>
|
||||
<string name="incompatible_patches_dialog">These patches are not compatible with the selected app version (%1$s).\n\nClick on the patches to see more details.</string>
|
||||
<string name="incompatible_patches_dialog">"These patches are not compatible with the selected app version (%1$s).
|
||||
|
||||
Click on the patches to see more details."</string>
|
||||
<string name="incompatible_patch">Incompatible patch</string>
|
||||
<string name="any_version">Any</string>
|
||||
<string name="never_show_again">Never show again</string>
|
||||
<string name="show_manager_update_dialog_on_launch">Show update message on launch</string>
|
||||
<string name="show_manager_update_dialog_on_launch_description">Shows a popup notification whenever there is a new update available on launch.</string>
|
||||
<string name="show_manager_update_dialog_on_launch_description">Show a popup notification whenever a new update is available on launch</string>
|
||||
<string name="failed_to_import_keystore">Failed to import keystore</string>
|
||||
<string name="export">Export</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
|
||||
@@ -13,9 +13,9 @@ Learn how to use ReVanced Manager to patch apps.
|
||||
7. Tap on the `Install` button to install the patched app[^4]
|
||||
|
||||
[^1]: Here you can see all the apps that are supported by ReVanced.
|
||||
You can also add custom apps by tapping on the `+` button in the top right corner.
|
||||
You can also add custom apps by tapping on the `Select from storage` button at the top.
|
||||
[^2]: It is recommended to use the default set of patches by tapping on the `Reset` button in the bottom right corner.
|
||||
[^3]: By default, all available downloader will be used to download the app.
|
||||
[^3]: By default, all available downloaders will be used to download the app.
|
||||
If you want to use a specific downloader, you can change it here.
|
||||
[^4]: You can export the patched app or the patch logs in the bottom left corner.
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Learn how to add new, manage existing or remove patches.
|
||||
|
||||
## ⏭️ What's next
|
||||
|
||||
The next page will explain how to update ReVanced Manager.
|
||||
The next page will explain how to manage downloaders.
|
||||
|
||||
Continue: [🔄 Updating ReVanced Manager](2_4_updating.md)
|
||||
Continue: [🔄 Updating ReVanced Manager](2_4_managing_downloaders.md)
|
||||
|
||||
|
||||
15
docs/2_4_managing_downloaders.md
Normal file
15
docs/2_4_managing_downloaders.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 🧩 Managing downloaders
|
||||
|
||||
Learn how to manage downloaders.
|
||||
Refer to the [template](https://github.com/ReVanced/revanced-manager-downloader-template) if you are developer who wants to create a plugin.
|
||||
|
||||
Downloaders are APK files and are installed, updated and uninstalled just like regular Android apps.
|
||||
Downloaders can execute arbitrary code inside ReVanced Manager and must be marked as trusted before use. Manager will show a notification in the dashboard when a new downloader is discovered.
|
||||
Trust can also be granted and revoked under `Settings` > `Downloads`.
|
||||
|
||||
## ⏭️ What's next
|
||||
|
||||
The next page will explain how to update ReVanced Manager.
|
||||
|
||||
Continue: [🔄 Updating ReVanced Manager](2_5_updating.md)
|
||||
|
||||
@@ -9,10 +9,10 @@ Learn how to update ReVanced Manager.
|
||||
3. Configure the update settings accordingly[^1]
|
||||
|
||||
[^1]: By default, ReVanced Manager will check for updates automatically on launch
|
||||
and let you when an update is available.
|
||||
and let you know when an update is available.
|
||||
|
||||
## ⏭️ What's next
|
||||
|
||||
The next page will explain how to configure ReVanced Manager.
|
||||
|
||||
Continue: [⚙️ Configuring ReVanced Manager](2_5_settings.md)
|
||||
Continue: [⚙️ Configuring ReVanced Manager](2_6_settings.md)
|
||||
@@ -4,29 +4,29 @@ Learn how to configure ReVanced Manager.
|
||||
|
||||
## 🔧 Settings
|
||||
|
||||
- **Import & export**: Import or export patch selections, patch options and the signing keystore
|
||||
- **Downloads**: Enable or disable ReVanced Manager downloader and manage past downloaded apps here
|
||||
- **Import & export**: Import or export patch selections, patch options and the signing keystore
|
||||
- **Advanced**:
|
||||
- **API URL**: Set the URL of the ReVanced API, ReVanced Manager will use
|
||||
- **Disable version compatibility check**: Patching versions of apps the patches are explicitly compatible with is enforced.
|
||||
Disabling this will allow patching versions of apps the patches are not explicitly compatible with
|
||||
> ⚠️ Warning
|
||||
> Patches may fail patching versions they are not explicitly compatible with.
|
||||
> Unless you know what you are doing, it is recommended to keep this enabled.
|
||||
- **Allow changing patch selection**: The default selection of patches is enforced.
|
||||
Enabling this will allow you to change the patch selection
|
||||
> ⚠️ Warning
|
||||
> Changing the selection may cause unexpected issues.
|
||||
> Patches may fail on app versions they are not explicitly compatible with.
|
||||
> Unless you know what you are doing, it is recommended to keep this disabled.
|
||||
- **Require suggested app version**: Specific versions of apps is enforced based on the patch selection automatically.
|
||||
Disabling this will allow you to patch any version of apps
|
||||
> ⚠️ Warning
|
||||
> Patches not compatible with the selected version of the app will not be used.
|
||||
> Unless you know what you are doing, it is recommended to keep this enabled.
|
||||
- **Allow universal patches**: Patches that do not specify compatibility with an app explicitly are forcibly disabled.
|
||||
- **Allow changing patch selection and options**: The default selection of patches is enforced.
|
||||
Enabling this will allow you to change the patch selection
|
||||
> ⚠️ Warning
|
||||
> Changing the selection may cause unexpected issues.
|
||||
> Unless you know what you are doing, it is recommended to keep this disabled.
|
||||
- **Allow using universal patches**: Patches that do not specify compatibility with an app are forcibly disabled.
|
||||
Enabling this will allow selecting such patches
|
||||
> ⚠️ Warning
|
||||
> Universal patches do not specify compatibility with an app explicitly may not work on all apps regardless.
|
||||
> Universal patches do not specify compatibility with an app and may not work on all apps regardless.
|
||||
> Unless you know what you are doing, it is recommended to keep this disabled.
|
||||
- **About**: View more information and links about ReVanced and ReVanced Manager.
|
||||
|
||||
@@ -1,28 +1,6 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx3072m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
android.useAndroidX=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
android.nonFinalResIds=false
|
||||
# Task :app:assembleReleaseSignApk fails if this is set to true.
|
||||
org.gradle.configuration-cache=false
|
||||
org.gradle.caching=true
|
||||
version=1.25.0-dev.1
|
||||
@@ -1,32 +1,32 @@
|
||||
[versions]
|
||||
ktx = "1.17.0"
|
||||
ktx = "1.16.0"
|
||||
material3 = "1.3.2"
|
||||
ui-tooling = "1.9.1"
|
||||
viewmodel-lifecycle = "2.9.4"
|
||||
ui-tooling = "1.8.1"
|
||||
viewmodel-lifecycle = "2.9.0"
|
||||
splash-screen = "1.0.1"
|
||||
activity = "1.11.0"
|
||||
appcompat = "1.7.1"
|
||||
preferences-datastore = "1.1.7"
|
||||
work-runtime = "2.10.4"
|
||||
compose-bom = "2025.09.00"
|
||||
navigation = "2.9.4"
|
||||
accompanist = "0.37.3"
|
||||
placeholder = "2.0.0"
|
||||
reorderable = "2.5.1"
|
||||
serialization = "1.9.0"
|
||||
collection = "0.4.0"
|
||||
datetime = "0.7.1"
|
||||
room-version = "2.8.0"
|
||||
activity = "1.10.1"
|
||||
appcompat = "1.7.0"
|
||||
preferences-datastore = "1.1.2"
|
||||
work-runtime = "2.10.1"
|
||||
compose-bom = "2025.05.00"
|
||||
navigation = "2.8.6"
|
||||
accompanist = "0.37.0"
|
||||
placeholder = "1.1.2"
|
||||
reorderable = "2.4.3"
|
||||
serialization = "1.8.0"
|
||||
collection = "0.3.8"
|
||||
datetime = "0.6.1"
|
||||
room-version = "2.7.1"
|
||||
revanced-patcher = "21.0.0"
|
||||
revanced-library = "3.0.2"
|
||||
koin = "4.1.1"
|
||||
ktor = "3.3.0"
|
||||
markdown-renderer = "0.37.0"
|
||||
koin = "3.5.3"
|
||||
ktor = "2.3.9"
|
||||
markdown-renderer = "0.30.0"
|
||||
fading-edges = "1.0.4"
|
||||
kotlin = "2.2.20"
|
||||
android-gradle-plugin = "8.13.0"
|
||||
dev-tools-gradle-plugin = "2.2.20-2.0.2"
|
||||
about-libraries-gradle-plugin = "12.2.4"
|
||||
kotlin = "2.1.10"
|
||||
android-gradle-plugin = "8.9.1"
|
||||
dev-tools-gradle-plugin = "2.1.10-1.0.29"
|
||||
about-libraries-gradle-plugin = "12.1.2"
|
||||
coil = "2.7.0"
|
||||
app-icon-loader-coil = "1.5.0"
|
||||
libsu = "6.0.0"
|
||||
@@ -34,8 +34,10 @@ scrollbars = "1.0.4"
|
||||
enumutil = "1.1.1"
|
||||
compose-icons = "1.2.4"
|
||||
kotlin-process = "1.5.1"
|
||||
hidden-api-stub = "4.4.0"
|
||||
binary-compatibility-validator = "0.18.1"
|
||||
hidden-api-stub = "4.3.3"
|
||||
binary-compatibility-validator = "0.17.0"
|
||||
semver-parser = "3.0.0"
|
||||
ackpine = "0.18.5"
|
||||
|
||||
[libraries]
|
||||
# AndroidX Core
|
||||
@@ -129,6 +131,13 @@ reorderable = { module = "sh.calvin.reorderable:reorderable", version.ref = "reo
|
||||
# switch to br.com.devsrsouza.compose.icons after DevSrSouza/compose-icons#30 is merged
|
||||
compose-icons-fontawesome = { group = "com.github.BenjaminHalko.compose-icons", name = "font-awesome", version.ref = "compose-icons" }
|
||||
|
||||
# Semantic versioning parser
|
||||
semver-parser = { module = "io.github.z4kn4fein:semver", version.ref = "semver-parser" }
|
||||
|
||||
# Ackpine
|
||||
ackpine-core = { module = "ru.solrudev.ackpine:ackpine-core", version.ref = "ackpine" }
|
||||
ackpine-ktx = { module = "ru.solrudev.ackpine:ackpine-ktx", version.ref = "ackpine" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" }
|
||||
android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" }
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
2
gradlew
vendored
2
gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015 the original authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
1589
package-lock.json
generated
1589
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"api",
|
||||
"app"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@anolilab/multi-semantic-release": "^1.1.10",
|
||||
"gradle-semantic-release-plugin": "^1.10.1",
|
||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/exec": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1"
|
||||
"@anolilab/multi-semantic-release": "^2.0.3",
|
||||
"semantic-release": "^24.2.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,5 @@ dependencyResolutionManagement {
|
||||
}
|
||||
}
|
||||
|
||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
|
||||
rootProject.name = "revanced-manager"
|
||||
include(":app", ":api")
|
||||
|
||||
Reference in New Issue
Block a user