mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2025-05-19 23:46:55 +08:00
Compare commits
22 Commits
feat/sort-
...
feat/hide-
Author | SHA1 | Date | |
---|---|---|---|
4f8fd23a87 | |||
98c0262d10 | |||
f412c99c60 | |||
62d5863846 | |||
e71e6fb797 | |||
111e8808a0 | |||
a30ff45111 | |||
eb03daaebd | |||
9e2a7917ba | |||
88fc639751 | |||
2fc099568e | |||
e641b91e57 | |||
d09e9b79cb | |||
3f5d04a513 | |||
3ad027007f | |||
813ec4dbe2 | |||
9fac5126df | |||
5e03cf2307 | |||
4d522664b6 | |||
0058b5f504 | |||
8fdd5074a0 | |||
5555373deb |
61
.github/ISSUE_TEMPLATE/bug-issue.yml
vendored
61
.github/ISSUE_TEMPLATE/bug-issue.yml
vendored
@ -1,61 +0,0 @@
|
||||
name: 🐞 Bug report
|
||||
description: Create a new bug report.
|
||||
title: 'bug: <title>'
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
# ReVanced Manager bug report
|
||||
|
||||
Please check for existing issues [here](https://github.com/revanced/revanced-manager/labels/bug) before creating a new one.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Bug description
|
||||
description: |
|
||||
- Describe your bug in detail
|
||||
- Add steps to reproduce the bug if possible (Step 1. Download some files. Step 2. ...)
|
||||
- Add images and videos if possible
|
||||
- List selected patches if applicable
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Version of ReVanced Manager and version & name of application you tried to patch
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Installation type
|
||||
options:
|
||||
- Non-root
|
||||
- Root
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Device logs
|
||||
description: Export logs in ReVanced Manager settings.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Patcher logs
|
||||
description: Export logs in "Patcher" screen.
|
||||
render: shell
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
description: Your issue will be closed if you don't follow the checklist below!
|
||||
options:
|
||||
- label: This request is not a duplicate of an existing issue.
|
||||
required: true
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
- label: All requested information has been provided properly.
|
||||
required: true
|
||||
- label: The issue is solely related to the ReVanced Manager
|
||||
required: true
|
109
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
109
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
name: 🐞 Bug report
|
||||
description: Report a bug or an issue.
|
||||
title: 'bug: '
|
||||
labels: ['Bug report']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source
|
||||
width="256px"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
srcset="https://raw.githubusercontent.com/revanced/revanced-manager/main/assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
||||
>
|
||||
<img
|
||||
width="256px"
|
||||
src="https://raw.githubusercontent.com/revanced/revanced-manager/main/assets/revanced-headline/revanced-headline-vertical-light.svg"
|
||||
>
|
||||
</picture>
|
||||
<br>
|
||||
<a href="https://revanced.app/">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/revanced/revanced-manager/main/assets/revanced-logo/revanced-logo.svg" />
|
||||
<img height="24px" src="https://raw.githubusercontent.com/revanced/revanced-manager/main/assets/revanced-logo/revanced-logo.svg" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://github.com/ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="http://revanced.app/discord">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://reddit.com/r/revancedapp">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://t.me/app_revanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://x.com/revancedapp">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/@ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
Continuing the legacy of Vanced
|
||||
</p>
|
||||
|
||||
# ReVanced Manager bug report
|
||||
|
||||
Before creating a new bug report, please keep the following in mind:
|
||||
|
||||
- **Do not submit a duplicate bug report**: Search for existing bug reports [here](https://github.com/ReVanced/revanced-manager/issues?q=label%3A%22Bug+report%22).
|
||||
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-manager/blob/main/CONTRIBUTING.md).
|
||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Bug description
|
||||
description: |
|
||||
- Describe your bug in detail
|
||||
- Add steps to reproduce the bug if possible (Step 1. ... Step 2. ...)
|
||||
- Add images and videos if possible
|
||||
- List used patches, downloader and settings if applicable
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Patch logs
|
||||
description: Patch logs can be exported by clicking on the "Logs" button in the "Patcher" screen, when patching finishes.
|
||||
render: shell
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Debug logs
|
||||
description: Debug logs can be exported by clicking on "Export debug logs" in "Settings" > "Advanced".
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
description: Your bug report will be closed if you don't follow the checklist below.
|
||||
options:
|
||||
- label: I have checked all open and closed bug reports and this is not a duplicate.
|
||||
required: true
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
- label: All requested information has been provided properly.
|
||||
required: true
|
||||
- label: The bug is only related to ReVanced Manager.
|
||||
required: true
|
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 🗨 Discussions
|
||||
url: https://github.com/revanced/revanced-suggestions/discussions
|
||||
about: Have something unspecific to ReVanced Manager in mind? Search for or start a new discussion!
|
42
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
42
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
@ -1,42 +0,0 @@
|
||||
name: ⭐ Feature request
|
||||
description: Create a new feature request.
|
||||
title: 'feat: <title>'
|
||||
labels: [feature request]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
# ReVanced Manager feature request
|
||||
|
||||
Please check for existing feature requests [here](https://github.com/revanced/revanced-manager/labels/bug) before creating a new one.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Feature description
|
||||
description: Describe your feature in detail.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: Explain why the lack of it is a problem.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: In case there is something else you want to add.
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
description: Your issue will be closed if you don't follow the checklist below!
|
||||
options:
|
||||
- label: This request is not a duplicate of an existing issue.
|
||||
required: true
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
- label: All requested information has been provided properly.
|
||||
required: true
|
||||
- label: The issue is solely related to the ReVanced Manager
|
||||
required: true
|
103
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
103
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source
|
||||
width="256px"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
srcset="https://raw.githubusercontent.com/revanced/revanced-manager/main/assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
||||
>
|
||||
<img
|
||||
width="256px"
|
||||
src="https://raw.githubusercontent.com/revanced/revanced-manager/main/assets/revanced-headline/revanced-headline-vertical-light.svg"
|
||||
>
|
||||
</picture>
|
||||
<br>
|
||||
<a href="https://revanced.app/">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/revanced/revanced-manager/main/assets/revanced-logo/revanced-logo.svg" />
|
||||
<img height="24px" src="https://raw.githubusercontent.com/revanced/revanced-manager/main/assets/revanced-logo/revanced-logo.svg" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://github.com/ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="http://revanced.app/discord">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://reddit.com/r/revancedapp">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://t.me/app_revanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://x.com/revancedapp">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/@ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
Continuing the legacy of Vanced
|
||||
</p>
|
||||
|
||||
# ReVanced Manager feature request
|
||||
|
||||
Before creating a new feature request, please keep the following in mind:
|
||||
|
||||
- **Do not submit a duplicate feature request**: Search for existing feature requests [here](https://github.com/ReVanced/revanced-manager/issues?q=label%3A%22Feature+request%22).
|
||||
- **Review the contribution guidelines**: Make sure your feature request adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-manager/blob/main/CONTRIBUTING.md).
|
||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Feature description
|
||||
description: |
|
||||
- Describe your feature in detail
|
||||
- Add images, videos, links, examples, references, etc. if possible
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: |
|
||||
A strong motivation is necessary for a feature request to be considered.
|
||||
|
||||
- Why should this feature be implemented?
|
||||
- What is the explicit use case?
|
||||
- What are the benefits?
|
||||
- What makes this feature important?
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: acknowledgements
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
description: Your feature request will be closed if you don't follow the checklist below.
|
||||
options:
|
||||
- label: I have checked all open and closed feature requests and this is not a duplicate
|
||||
required: true
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
- label: All requested information has been provided properly.
|
||||
required: true
|
||||
- label: The feature request is only related to ReVanced Manager.
|
||||
required: true
|
2
.github/config.yaml
vendored
2
.github/config.yaml
vendored
@ -1,2 +1,2 @@
|
||||
firstPRMergeComment: >
|
||||
❤️ Thank you for contributing to ReVanced Manager. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.
|
||||
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) to receive a role for your contribution.
|
||||
|
25
.github/workflows/build_pull_request.yml
vendored
Normal file
25
.github/workflows/build_pull_request.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Build pull request
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: burrunan/gradle-cache-action@v1
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew build --no-daemon
|
26
.github/workflows/open_pull_request.yml
vendored
Normal file
26
.github/workflows/open_pull_request.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: Open a PR to main
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
MESSAGE: Merge branch `${{ github.head_ref || github.ref_name }}` to `main`
|
||||
|
||||
jobs:
|
||||
pull-request:
|
||||
name: Open pull request
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Open pull request
|
||||
uses: repo-sync/pull-request@v2
|
||||
with:
|
||||
destination_branch: 'main'
|
||||
pr_title: 'chore: ${{ env.MESSAGE }}'
|
||||
pr_body: 'This pull request will ${{ env.MESSAGE }}.'
|
||||
pr_draft: true
|
44
.github/workflows/pr-build.yml
vendored
44
.github/workflows/pr-build.yml
vendored
@ -1,44 +0,0 @@
|
||||
name: Build pull request
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/pr-build.yml"
|
||||
- "app/**"
|
||||
- "gradle/**"
|
||||
- "*.properties"
|
||||
- ".kts"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew assembleRelease --no-daemon -PnoProguard -PsignAsDebug
|
||||
|
||||
- name: Set env
|
||||
run: echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
|
||||
- name: Add hash to APK
|
||||
run: mv app/build/outputs/apk/release/app-release.apk revanced-manager-${{ env.COMMIT_HASH }}.apk
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: revanced-manager
|
||||
path: revanced-manager-${{ env.COMMIT_HASH }}.apk
|
57
.github/workflows/release-build.yml
vendored
57
.github/workflows/release-build.yml
vendored
@ -1,57 +0,0 @@
|
||||
name: Release Build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
attestations: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew assembleRelease --no-daemon
|
||||
|
||||
- name: Sign APK
|
||||
id: sign_apk
|
||||
uses: ilharp/sign-android-release@v1
|
||||
with:
|
||||
releaseDir: ./app/build/outputs/apk/release/
|
||||
signingKey: ${{ secrets.SIGNING_KEYSTORE }}
|
||||
keyStorePassword: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
|
||||
keyAlias: ${{ secrets.SIGNING_KEY_ALIAS }}
|
||||
keyPassword: ${{ secrets.SIGNING_KEY_PASSWORD }}
|
||||
|
||||
- name: Add version to APK
|
||||
run: mv ${{ steps.sign_apk.outputs.signedFile }} revanced-manager-${{ env.RELEASE_VERSION }}.apk
|
||||
|
||||
- name: Generate artifact attestation
|
||||
uses: actions/attest-build-provenance@v1
|
||||
with:
|
||||
subject-path: revanced-manager-${{ env.RELEASE_VERSION }}.apk
|
||||
|
||||
- name: Publish release APK
|
||||
uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
prerelease: false
|
||||
files: revanced-manager-${{ env.RELEASE_VERSION }}.apk
|
64
.github/workflows/release.yml
vendored
Normal file
64
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: burrunan/gradle-cache-action@v1
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew assembleRelease
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Setup keystore
|
||||
run: |
|
||||
echo "${{ secrets.KEYSTORE }}" | base64 --decode > "app/keystore.jks"
|
||||
|
||||
- name: Semantic Release
|
||||
uses: cycjimmy/semantic-release-action@v4
|
||||
id: semantic
|
||||
env:
|
||||
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@v2
|
||||
with:
|
||||
subject-path: build/app/outputs/apk/release/revanced-manager-*.apk
|
@ -58,20 +58,46 @@
|
||||
Continuing the legacy of Vanced
|
||||
</p>
|
||||
|
||||
# 🔒 Security Policy
|
||||
# 👋 Contribution guidelines
|
||||
|
||||
This document describes how to report security vulnerabilities for ReVanced Manager.
|
||||
This document describes how to contribute to ReVanced Manager.
|
||||
|
||||
## 🚨 Reporting a Vulnerability
|
||||
## 📖 Resources to help you get started
|
||||
|
||||
Please open an issue in our [advisory tracker](https://github.com/ReVanced/revanced-manager/security/advisories/new) or reach out privately to us on [Discord](https://discord.gg/revanced).
|
||||
* The [documentation](/docs/README.md) provides steps to build ReVanced Manager from source
|
||||
* Our [backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on
|
||||
* [Issues](https://github.com/ReVanced/revanced-manager/issues) are where we keep track of bugs and feature requests
|
||||
|
||||
If a vulnerability is confirmed and accepted, you can join our [Discord](https://discord.gg/revanced) server to receive a special contributor role.
|
||||
## 🙏 Submitting a feature request
|
||||
|
||||
### ⏳ Supported Versions
|
||||
Features can be requested by opening an issue using the
|
||||
[Feature request issue template](https://github.com/ReVanced/revanced-manager/issues/new?assignees=&labels=Feature+request&projects=&template=feature_request.yml&title=feat%3A+).
|
||||
|
||||
| Version | Branch | Supported |
|
||||
| --------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------------ |
|
||||
|  | main | :white_check_mark: |
|
||||
|  | dev | :white_check_mark: |
|
||||
|  | compose-dev | :white_check_mark: |
|
||||
> **Note**
|
||||
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced Manager.
|
||||
> Good motivation has to be provided for a request to be accepted.
|
||||
|
||||
## 🐞 Submitting a bug report
|
||||
|
||||
If you encounter a bug while using ReVanced Manager, open an issue using the
|
||||
[Bug report issue template](https://github.com/ReVanced/revanced-manager/issues/new?assignees=&labels=Bug+report&projects=&template=bug_report.yml&title=bug%3A+).
|
||||
|
||||
## 📝 How to contribute
|
||||
|
||||
1. Before contributing, it is recommended to open an issue to discuss your change
|
||||
with the maintainers of ReVanced Manager. This will help you determine whether your change is acceptable
|
||||
and whether it is worth your time to implement it
|
||||
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
|
||||
3. Commit your changes
|
||||
4. Submit a pull request to the `dev` branch of the repository and reference issues
|
||||
that your pull request closes in the description of your pull request
|
||||
5. Our team will review your pull request and provide feedback. Once your pull request is approved,
|
||||
it will be merged into the `dev` branch and will be included in the next release of ReVanced Manager
|
||||
|
||||
## 🤚 I want to contribute but don't know how to code
|
||||
|
||||
Even if you don't know how to code, you can still contribute by
|
||||
translating ReVanced Manager on [Crowdin](https://translate.revanced.app/).
|
||||
|
||||
❤️ Thank you for considering contributing to ReVanced Manager,
|
||||
ReVanced
|
119
README.md
119
README.md
@ -1,55 +1,104 @@
|
||||
# ReVanced Manager (Compose Rewrite)
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source
|
||||
width="256px"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
||||
>
|
||||
<img
|
||||
width="256px"
|
||||
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
|
||||
>
|
||||
</picture>
|
||||
<br>
|
||||
<a href="https://revanced.app/">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="assets/revanced-logo/revanced-logo.svg" />
|
||||
<img height="24px" src="assets/revanced-logo/revanced-logo.svg" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://github.com/ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="http://revanced.app/discord">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://reddit.com/r/revancedapp">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://t.me/app_revanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://x.com/revancedapp">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/@ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
Continuing the legacy of Vanced
|
||||
</p>
|
||||
|
||||
[](../../blob/main/LICENSE)
|
||||
[](https://github.com/ReVanced/revanced-manager/commits/compose-dev)
|
||||
[](https://github.com/ReVanced/revanced-manager/commits/compose-dev)
|
||||
# 💊 ReVanced Manager
|
||||
|
||||
_(Yet another)_ rewrite of the ReVanced Manager using Kotlin and Jetpack Compose.
|
||||

|
||||

|
||||
|
||||
## Design system
|
||||
Application to use ReVanced on Android
|
||||
|
||||
In this rewrite, we are adopting the latest Material Design principles and guidelines by using Material 3 and Material You.
|
||||
## ❓ About
|
||||
|
||||
Material Design is a design system developed by Google that provides a unified visual language for building beautiful and consistent user interfaces across all platforms and devices. Material You is an extension of Material Design that provides even more customization options for users, making it possible for them to personalize their device and create a unique look and feel.
|
||||
ReVanced Manager is an application that uses [ReVanced Patcher](https://github.com/revanced/revanced-patcher) to patch Android apps.
|
||||
|
||||
### Why Material 3?
|
||||
## 💪 Features
|
||||
|
||||
* **Consistent design language**
|
||||
* **Improved accessibility**
|
||||
* **Better user experience**
|
||||
Some of the features ReVanced Manager provides are:
|
||||
|
||||
By using Material 3 and Material You, we are ensuring that the app's user interface is consistent, customizable, accessible, and engaging for our users. This will help to improve the overall user experience and increase user satisfaction with the the manager.
|
||||
|
||||
## Technology stack
|
||||
|
||||
* Kotlin: Kotlin is a modern and concise programming language that is fully interoperable with Java and provides improved safety, readability, and maintainability compared to Java.
|
||||
* Jetpack Compose: Jetpack Compose is a modern UI toolkit for Android development that allows developers to build beautiful and performant user interfaces using declarative programming. It provides a unified and efficient way of building UI that is well-integrated with the Android framework.
|
||||
|
||||
## Why Kotlin and Compose?
|
||||
|
||||
* **Improved safety:** Kotlin provides improved safety compared to Java, which reduces the likelihood of common programming mistakes that can cause security vulnerabilities or crashes.
|
||||
* **Concise and readable code:** Kotlin's concise syntax and expressive type system make the code more readable, which makes it easier for developers to understand and maintain the codebase.
|
||||
* **Better performance:** Jetpack Compose uses the power of the Android framework to provide smooth and fast performance, which enhances the user experience.
|
||||
* **Modern and efficient UI development:** Jetpack Compose provides a modern and efficient way of building UI, which makes it easier for developers to create beautiful and performant user interfaces.
|
||||
- ⬇️ **Download**: Automatically download apps using the ReVanced Manager downloader plugin system
|
||||
- 💉 **Patch**: Select and apply patches to any Android app
|
||||
- 🛠️ **Customize**: Manage patches, apps, signing, themes, updates, and many more settings
|
||||
|
||||
## 🔽 Download
|
||||
|
||||
You can obtain ReVanced Manager by downloading it from either [revanced.app/download](https://revanced.app/download) or [GitHub Releases](https://github.com/ReVanced/revanced-manager/releases)
|
||||
You can download the most recent version of ReVanced Manager at [revanced.app/download](https://revanced.app/download) or from [GitHub releases](https://github.com/ReVanced/revanced-manager/releases/latest).
|
||||
Learn how to use ReVanced Manager by following the [documentation](/docs).
|
||||
|
||||
## 📝 Prerequisites
|
||||
## 📚 Everything else
|
||||
|
||||
For a list of prerequisites, refer to [docs/0_prerequisites.md](docs/0_prerequisites.md)
|
||||
### 📙 Contributing
|
||||
|
||||
## 🔴 Issues
|
||||
Thank you for considering contributing to ReVanced Manager.
|
||||
You can find the contribution guidelines [here](CONTRIBUTING.md).
|
||||
|
||||
For suggestions and bug reports, open an issue [here](https://github.com/revanced/revanced-manager/issues/new/choose).
|
||||
### 🛠️ Building
|
||||
|
||||
## 🌐 Translation
|
||||
To build a ReVanced Manager, you can follow the [documentation](/docs).
|
||||
|
||||
[](https://crowdin.com/project/revanced)
|
||||
### 📄 Documentation
|
||||
|
||||
We're accepting translations on [Crowdin](https://translate.revanced.app)
|
||||
You can find the documentation for ReVanced Manager [here](/docs).
|
||||
|
||||
## 🛠️ Building Manager from source
|
||||
## ⚖️ License
|
||||
|
||||
For instructions on how to build ReVanced Manager from source, refer to [docs/4_building.md](docs/4_building.md)
|
||||
ReVanced Manager is licensed under the GPLv3 license. Please see the [license file](LICENSE) for more information.
|
||||
[tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced Manager as long as you track changes/dates in source files.
|
||||
Any modifications to ReVanced Manager must also be made available under the GPL, along with build & install instructions.
|
||||
|
@ -27,7 +27,7 @@ android {
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix = ".debug"
|
||||
resValue("string", "app_name", "ReVanced Manager (dev)")
|
||||
resValue("string", "app_name", "ReVanced Manager (Debug)")
|
||||
isPseudoLocalesEnabled = true
|
||||
|
||||
buildConfigField("long", "BUILD_ID", "${Random.nextLong()}L")
|
||||
@ -40,12 +40,21 @@ android {
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
|
||||
if (project.hasProperty("signAsDebug")) {
|
||||
applicationIdSuffix = ".debug"
|
||||
resValue("string", "app_name", "ReVanced Manager Debug")
|
||||
val keystoreFile = file("keystore.jks")
|
||||
|
||||
if (project.hasProperty("signAsDebug") || !keystoreFile.exists()) {
|
||||
applicationIdSuffix = ".debug_signed"
|
||||
resValue("string", "app_name", "ReVanced Manager (Debug signed)")
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
|
||||
isPseudoLocalesEnabled = true
|
||||
} else {
|
||||
signingConfig = signingConfigs.create("release") {
|
||||
storeFile = keystoreFile
|
||||
storePassword = System.getenv("KEYSTORE_PASSWORD")
|
||||
keyAlias = System.getenv("KEYSTORE_ENTRY_ALIAS")
|
||||
keyPassword = System.getenv("KEYSTORE_ENTRY_PASSWORD")
|
||||
}
|
||||
}
|
||||
|
||||
buildConfigField("long", "BUILD_ID", "0L")
|
||||
@ -63,15 +72,17 @@ android {
|
||||
}
|
||||
|
||||
packaging {
|
||||
resources.excludes.addAll(listOf(
|
||||
"/prebuilt/**",
|
||||
"META-INF/DEPENDENCIES",
|
||||
"META-INF/**.version",
|
||||
"DebugProbesKt.bin",
|
||||
"kotlin-tooling-metadata.json",
|
||||
"org/bouncycastle/pqc/**.properties",
|
||||
"org/bouncycastle/x509/**.properties",
|
||||
))
|
||||
resources.excludes.addAll(
|
||||
listOf(
|
||||
"/prebuilt/**",
|
||||
"META-INF/DEPENDENCIES",
|
||||
"META-INF/**.version",
|
||||
"DebugProbesKt.bin",
|
||||
"kotlin-tooling-metadata.json",
|
||||
"org/bouncycastle/pqc/**.properties",
|
||||
"org/bouncycastle/x509/**.properties",
|
||||
)
|
||||
)
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
|
@ -44,13 +44,13 @@ import app.revanced.manager.ui.screen.SettingsScreen
|
||||
import app.revanced.manager.ui.screen.UpdateScreen
|
||||
import app.revanced.manager.ui.screen.settings.AboutSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.AdvancedSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.ContributorScreen
|
||||
import app.revanced.manager.ui.screen.settings.DeveloperOptionsScreen
|
||||
import app.revanced.manager.ui.screen.settings.ContributorSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.DeveloperSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.DownloadsSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.GeneralSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.ImportExportSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.LicensesScreen
|
||||
import app.revanced.manager.ui.screen.settings.update.ChangelogsScreen
|
||||
import app.revanced.manager.ui.screen.settings.LicensesSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.update.ChangelogsSettingsScreen
|
||||
import app.revanced.manager.ui.screen.settings.update.UpdatesSettingsScreen
|
||||
import app.revanced.manager.ui.theme.ReVancedManagerTheme
|
||||
import app.revanced.manager.ui.theme.Theme
|
||||
@ -164,7 +164,7 @@ private fun ReVancedManager(vm: MainViewModel) {
|
||||
}
|
||||
}
|
||||
},
|
||||
vm = koinViewModel { parametersOf(it.getComplexArg<Patcher.ViewModelParams>()) }
|
||||
viewModel = koinViewModel { parametersOf(it.getComplexArg<Patcher.ViewModelParams>()) }
|
||||
)
|
||||
}
|
||||
|
||||
@ -277,6 +277,10 @@ private fun ReVancedManager(vm: MainViewModel) {
|
||||
AdvancedSettingsScreen(onBackClick = navController::popBackStack)
|
||||
}
|
||||
|
||||
composable<Settings.Developer> {
|
||||
DeveloperSettingsScreen(onBackClick = navController::popBackStack)
|
||||
}
|
||||
|
||||
composable<Settings.Updates> {
|
||||
UpdatesSettingsScreen(
|
||||
onBackClick = navController::popBackStack,
|
||||
@ -301,20 +305,17 @@ private fun ReVancedManager(vm: MainViewModel) {
|
||||
}
|
||||
|
||||
composable<Settings.Changelogs> {
|
||||
ChangelogsScreen(onBackClick = navController::popBackStack)
|
||||
ChangelogsSettingsScreen(onBackClick = navController::popBackStack)
|
||||
}
|
||||
|
||||
composable<Settings.Contributors> {
|
||||
ContributorScreen(onBackClick = navController::popBackStack)
|
||||
ContributorSettingsScreen(onBackClick = navController::popBackStack)
|
||||
}
|
||||
|
||||
composable<Settings.Licenses> {
|
||||
LicensesScreen(onBackClick = navController::popBackStack)
|
||||
LicensesSettingsScreen(onBackClick = navController::popBackStack)
|
||||
}
|
||||
|
||||
composable<Settings.DeveloperOptions> {
|
||||
DeveloperOptionsScreen(onBackClick = navController::popBackStack)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package app.revanced.manager.domain.manager
|
||||
import android.content.Context
|
||||
import app.revanced.manager.domain.manager.base.BasePreferencesManager
|
||||
import app.revanced.manager.ui.theme.Theme
|
||||
import app.revanced.manager.util.isDebuggable
|
||||
|
||||
class PreferencesManager(
|
||||
context: Context
|
||||
@ -28,4 +29,6 @@ class PreferencesManager(
|
||||
val suggestedVersionSafeguard = booleanPreference("suggested_version_safeguard", true)
|
||||
|
||||
val acknowledgedDownloaderPlugins = stringSetPreference("acknowledged_downloader_plugins", emptySet())
|
||||
|
||||
val showDeveloperSettings = booleanPreference("show_developer_settings", context.isDebuggable)
|
||||
}
|
||||
|
@ -111,6 +111,7 @@ class ProcessRuntime(private val context: Context) : Runtime(context) {
|
||||
}
|
||||
|
||||
val patching = CompletableDeferred<Unit>()
|
||||
val scope = this
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
val binder = awaitBinderConnection()
|
||||
@ -124,7 +125,7 @@ class ProcessRuntime(private val context: Context) : Runtime(context) {
|
||||
override fun log(level: String, msg: String) = logger.log(enumValueOf(level), msg)
|
||||
|
||||
override fun patchSucceeded() {
|
||||
launch { onPatchCompleted() }
|
||||
scope.launch { onPatchCompleted() }
|
||||
}
|
||||
|
||||
override fun progress(name: String?, state: String?, msg: String?) =
|
||||
@ -179,7 +180,7 @@ class ProcessRuntime(private val context: Context) : Runtime(context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* An [Exception] occured in the remote process while patching.
|
||||
* An [Exception] occurred in the remote process while patching.
|
||||
*
|
||||
* @param originalStackTrace The stack trace of the original [Exception].
|
||||
*/
|
||||
|
@ -1,8 +1,10 @@
|
||||
package app.revanced.manager.patcher.runtime.process
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActivityThread
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import app.revanced.manager.BuildConfig
|
||||
@ -95,6 +97,10 @@ class PatcherProcess(private val context: Context) : IPatcherProcess.Stub() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val longArrayClass = LongArray::class.java
|
||||
private val emptyLongArray = LongArray(0)
|
||||
|
||||
@SuppressLint("PrivateApi")
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
Looper.prepare()
|
||||
@ -105,6 +111,15 @@ class PatcherProcess(private val context: Context) : IPatcherProcess.Stub() {
|
||||
val systemContext = ActivityThread.systemMain().systemContext as Context
|
||||
val appContext = systemContext.createPackageContext(managerPackageName, 0)
|
||||
|
||||
// Avoid annoying logs. See https://github.com/robolectric/robolectric/blob/ad0484c6b32c7d11176c711abeb3cb4a900f9258/robolectric/src/main/java/org/robolectric/android/internal/AndroidTestEnvironment.java#L376-L388
|
||||
Class.forName("android.app.AppCompatCallbacks").apply {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
getDeclaredMethod("install", longArrayClass, longArrayClass).also { it.isAccessible = true }(null, emptyLongArray, emptyLongArray)
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
getDeclaredMethod("install", longArrayClass).also { it.isAccessible = true }(null, emptyLongArray)
|
||||
}
|
||||
}
|
||||
|
||||
val ipcInterface = PatcherProcess(appContext)
|
||||
|
||||
appContext.sendBroadcast(Intent().apply {
|
||||
|
@ -0,0 +1,41 @@
|
||||
package app.revanced.manager.ui.component
|
||||
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import app.revanced.manager.R
|
||||
|
||||
@Composable
|
||||
fun ConfirmDialog(
|
||||
onDismiss: () -> Unit,
|
||||
onConfirm: () -> Unit,
|
||||
title: String,
|
||||
description: String,
|
||||
icon: ImageVector
|
||||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
dismissButton = {
|
||||
TextButton(onDismiss) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onConfirm()
|
||||
onDismiss()
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
},
|
||||
title = { Text(title) },
|
||||
icon = { Icon(icon, null) },
|
||||
text = { Text(description) }
|
||||
)
|
||||
}
|
@ -16,8 +16,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.ui.component.bundle.BundleTopBar
|
||||
|
||||
@ -26,12 +24,8 @@ import app.revanced.manager.ui.component.bundle.BundleTopBar
|
||||
fun ExceptionViewerDialog(text: String, onDismiss: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Dialog(
|
||||
FullscreenDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnBackPress = true
|
||||
)
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
|
@ -0,0 +1,34 @@
|
||||
package app.revanced.manager.ui.component
|
||||
|
||||
import android.view.WindowManager
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.compose.ui.window.DialogWindowProvider
|
||||
|
||||
private val properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnBackPress = true,
|
||||
decorFitsSystemWindows = false,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun FullscreenDialog(onDismissRequest: () -> Unit, content: @Composable () -> Unit) {
|
||||
Dialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
properties = properties
|
||||
) {
|
||||
val window = (LocalView.current.parent as DialogWindowProvider).window
|
||||
LaunchedEffect(Unit) {
|
||||
window.statusBarColor = Color.Transparent.toArgb()
|
||||
window.navigationBarColor = Color.Transparent.toArgb()
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
||||
}
|
||||
|
||||
content()
|
||||
}
|
||||
}
|
@ -12,8 +12,6 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.data.platform.NetworkInfo
|
||||
@ -23,6 +21,7 @@ import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.asRemote
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.isDefault
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.nameState
|
||||
import app.revanced.manager.ui.component.ExceptionViewerDialog
|
||||
import app.revanced.manager.ui.component.FullscreenDialog
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@ -56,12 +55,8 @@ fun BundleInformationDialog(
|
||||
)
|
||||
}
|
||||
|
||||
Dialog(
|
||||
FullscreenDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnBackPress = true
|
||||
)
|
||||
) {
|
||||
val bundleName by bundle.nameState
|
||||
|
||||
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material.icons.outlined.ErrorOutline
|
||||
import androidx.compose.material.icons.outlined.Warning
|
||||
import androidx.compose.material3.Icon
|
||||
@ -26,8 +27,9 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource
|
||||
import app.revanced.manager.ui.component.haptics.HapticCheckbox
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.nameState
|
||||
import app.revanced.manager.ui.component.ConfirmDialog
|
||||
import app.revanced.manager.ui.component.haptics.HapticCheckbox
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@ -42,6 +44,7 @@ fun BundleItem(
|
||||
toggleSelection: (Boolean) -> Unit,
|
||||
) {
|
||||
var viewBundleDialogPage by rememberSaveable { mutableStateOf(false) }
|
||||
var showDeleteConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
val state by bundle.state.collectAsStateWithLifecycle()
|
||||
|
||||
val version by remember(bundle) {
|
||||
@ -52,15 +55,25 @@ fun BundleItem(
|
||||
if (viewBundleDialogPage) {
|
||||
BundleInformationDialog(
|
||||
onDismissRequest = { viewBundleDialogPage = false },
|
||||
onDeleteRequest = {
|
||||
viewBundleDialogPage = false
|
||||
onDelete()
|
||||
},
|
||||
onDeleteRequest = { showDeleteConfirmationDialog = true },
|
||||
bundle = bundle,
|
||||
onUpdate = onUpdate,
|
||||
)
|
||||
}
|
||||
|
||||
if (showDeleteConfirmationDialog) {
|
||||
ConfirmDialog(
|
||||
onDismiss = { showDeleteConfirmationDialog = false },
|
||||
onConfirm = {
|
||||
onDelete()
|
||||
viewBundleDialogPage = false
|
||||
},
|
||||
title = stringResource(R.string.bundle_delete_single_dialog_title),
|
||||
description = stringResource(R.string.bundle_delete_single_dialog_description, name),
|
||||
icon = Icons.Outlined.Delete
|
||||
)
|
||||
}
|
||||
|
||||
ListItem(
|
||||
modifier = Modifier
|
||||
.height(64.dp)
|
||||
|
@ -22,13 +22,12 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource
|
||||
import app.revanced.manager.patcher.patch.PatchInfo
|
||||
import app.revanced.manager.ui.component.ArrowButton
|
||||
import app.revanced.manager.ui.component.FullscreenDialog
|
||||
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@ -41,12 +40,8 @@ fun BundlePatchesDialog(
|
||||
var showOptions by rememberSaveable { mutableStateOf(false) }
|
||||
val state by bundle.state.collectAsStateWithLifecycle()
|
||||
|
||||
Dialog(
|
||||
FullscreenDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnBackPress = true
|
||||
)
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
|
@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListItemInfo
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
@ -55,13 +56,13 @@ import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.data.platform.Filesystem
|
||||
import app.revanced.manager.patcher.patch.Option
|
||||
import app.revanced.manager.ui.component.AlertDialogExtended
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.FloatInputDialog
|
||||
import app.revanced.manager.ui.component.FullscreenDialog
|
||||
import app.revanced.manager.ui.component.IntInputDialog
|
||||
import app.revanced.manager.ui.component.LongInputDialog
|
||||
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
|
||||
@ -73,16 +74,17 @@ import app.revanced.manager.util.saver.snapshotStateListSaver
|
||||
import app.revanced.manager.util.saver.snapshotStateSetSaver
|
||||
import app.revanced.manager.util.toast
|
||||
import app.revanced.manager.util.transparentListItemColors
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.koin.compose.koinInject
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import sh.calvin.reorderable.ReorderableItem
|
||||
import sh.calvin.reorderable.rememberReorderableLazyColumnState
|
||||
import sh.calvin.reorderable.rememberReorderableLazyListState
|
||||
import java.io.Serializable
|
||||
import kotlin.random.Random
|
||||
import kotlin.reflect.typeOf
|
||||
import androidx.compose.ui.window.Dialog as ComposeDialog
|
||||
|
||||
private class OptionEditorScope<T : Any>(
|
||||
private val editor: OptionEditor<T>,
|
||||
@ -497,7 +499,8 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
|
||||
|
||||
val lazyListState = rememberLazyListState()
|
||||
val reorderableLazyColumnState =
|
||||
rememberReorderableLazyColumnState(lazyListState) { from, to ->
|
||||
// Update the list
|
||||
rememberReorderableLazyListState(lazyListState) { from, to ->
|
||||
// Update the list
|
||||
items.add(to.index, items.removeAt(from.index))
|
||||
}
|
||||
@ -524,12 +527,8 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
|
||||
scope.submitDialog(items.mapNotNull { it.value })
|
||||
}
|
||||
|
||||
ComposeDialog(
|
||||
FullscreenDialog(
|
||||
onDismissRequest = back,
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnBackPress = true
|
||||
),
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
|
@ -23,10 +23,9 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.FullscreenDialog
|
||||
import app.revanced.manager.ui.component.GroupHeader
|
||||
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||
import app.revanced.manager.util.saver.PathSaver
|
||||
@ -48,12 +47,8 @@ fun PathSelectorDialog(root: Path, onSelect: (Path?) -> Unit) {
|
||||
currentDirectory.listDirectoryEntries().filter(Path::isReadable).partition(Path::isDirectory)
|
||||
}
|
||||
|
||||
Dialog(
|
||||
FullscreenDialog(
|
||||
onDismissRequest = { onSelect(null) },
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnBackPress = true
|
||||
)
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
|
@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.map
|
||||
*/
|
||||
data class BundleInfo(
|
||||
val name: String,
|
||||
val version: String?,
|
||||
val uid: Int,
|
||||
val compatible: List<PatchInfo>,
|
||||
val incompatible: List<PatchInfo>,
|
||||
@ -78,7 +79,7 @@ data class BundleInfo(
|
||||
targetList.add(it)
|
||||
}
|
||||
|
||||
BundleInfo(source.getName(), source.uid, compatible, incompatible, universal)
|
||||
BundleInfo(source.getName(), source.currentVersion(), source.uid, compatible, incompatible, universal)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,5 +92,5 @@ object Settings {
|
||||
data object Licenses : Destination
|
||||
|
||||
@Serializable
|
||||
data object DeveloperOptions : Destination
|
||||
data object Developer : Destination
|
||||
}
|
@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -19,8 +20,10 @@ fun BundleListScreen(
|
||||
selectedSources: SnapshotStateList<PatchBundleSource>,
|
||||
bundlesSelectable: Boolean,
|
||||
) {
|
||||
val sortedSources = sources.sortedBy {
|
||||
it.state.value.patchBundleOrNull()?.patches?.size
|
||||
val sortedSources = remember(sources) {
|
||||
sources.sortedByDescending { source ->
|
||||
source.state.value.patchBundleOrNull()?.patches?.size ?: 0
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumnWithScrollbar(
|
||||
|
@ -21,6 +21,7 @@ import androidx.compose.material.icons.filled.BatteryAlert
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.outlined.Apps
|
||||
import androidx.compose.material.icons.outlined.BugReport
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material.icons.outlined.DeleteOutline
|
||||
import androidx.compose.material.icons.outlined.Download
|
||||
import androidx.compose.material.icons.outlined.Refresh
|
||||
@ -62,6 +63,7 @@ import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.AutoUpdatesDialog
|
||||
import app.revanced.manager.ui.component.AvailableUpdateDialog
|
||||
import app.revanced.manager.ui.component.NotificationCard
|
||||
import app.revanced.manager.ui.component.ConfirmDialog
|
||||
import app.revanced.manager.ui.component.bundle.BundleTopBar
|
||||
import app.revanced.manager.ui.component.bundle.ImportPatchBundleDialog
|
||||
import app.revanced.manager.ui.component.haptics.HapticFloatingActionButton
|
||||
@ -154,6 +156,20 @@ fun DashboardScreen(
|
||||
}
|
||||
)
|
||||
|
||||
var showDeleteConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
if (showDeleteConfirmationDialog) {
|
||||
ConfirmDialog(
|
||||
onDismiss = { showDeleteConfirmationDialog = false },
|
||||
onConfirm = {
|
||||
vm.selectedSources.forEach { if (!it.isDefault) vm.delete(it) }
|
||||
vm.cancelSourceSelection()
|
||||
},
|
||||
title = stringResource(R.string.bundle_delete_multiple_dialog_title),
|
||||
description = stringResource(R.string.bundle_delete_multiple_dialog_description),
|
||||
icon = Icons.Outlined.Delete
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
if (bundlesSelectable) {
|
||||
@ -169,8 +185,7 @@ fun DashboardScreen(
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = {
|
||||
vm.selectedSources.forEach { if (!it.isDefault) vm.delete(it) }
|
||||
vm.cancelSourceSelection()
|
||||
showDeleteConfirmationDialog = true
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
|
@ -17,6 +17,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.OpenInNew
|
||||
import androidx.compose.material.icons.outlined.Cancel
|
||||
import androidx.compose.material.icons.outlined.FileDownload
|
||||
import androidx.compose.material.icons.outlined.PostAdd
|
||||
import androidx.compose.material.icons.outlined.Save
|
||||
@ -45,6 +46,7 @@ import app.revanced.manager.R
|
||||
import app.revanced.manager.data.room.apps.installed.InstallType
|
||||
import app.revanced.manager.ui.component.AppScaffold
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.ConfirmDialog
|
||||
import app.revanced.manager.ui.component.InstallerStatusDialog
|
||||
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
|
||||
import app.revanced.manager.ui.component.patcher.InstallPickerDialog
|
||||
@ -58,25 +60,23 @@ import app.revanced.manager.util.EventEffect
|
||||
@Composable
|
||||
fun PatcherScreen(
|
||||
onBackClick: () -> Unit,
|
||||
vm: PatcherViewModel
|
||||
viewModel: PatcherViewModel
|
||||
) {
|
||||
fun leaveScreen() {
|
||||
vm.onBack()
|
||||
onBackClick()
|
||||
}
|
||||
BackHandler(onBack = ::leaveScreen)
|
||||
|
||||
val context = LocalContext.current
|
||||
val exportApkLauncher =
|
||||
rememberLauncherForActivityResult(CreateDocument(APK_MIMETYPE), vm::export)
|
||||
rememberLauncherForActivityResult(CreateDocument(APK_MIMETYPE), viewModel::export)
|
||||
|
||||
val patcherSucceeded by vm.patcherSucceeded.observeAsState(null)
|
||||
val canInstall by remember { derivedStateOf { patcherSucceeded == true && (vm.installedPackageName != null || !vm.isInstalling) } }
|
||||
val patcherSucceeded by viewModel.patcherSucceeded.observeAsState(null)
|
||||
val canInstall by remember { derivedStateOf { patcherSucceeded == true && (viewModel.installedPackageName != null || !viewModel.isInstalling) } }
|
||||
var showInstallPicker by rememberSaveable { mutableStateOf(false) }
|
||||
var showDismissConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
BackHandler(onBack = { showDismissConfirmationDialog = true })
|
||||
|
||||
val steps by remember {
|
||||
derivedStateOf {
|
||||
vm.steps.groupBy { it.category }
|
||||
viewModel.steps.groupBy { it.category }
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,34 +93,47 @@ fun PatcherScreen(
|
||||
if (showInstallPicker)
|
||||
InstallPickerDialog(
|
||||
onDismiss = { showInstallPicker = false },
|
||||
onConfirm = vm::install
|
||||
onConfirm = viewModel::install
|
||||
)
|
||||
|
||||
vm.packageInstallerStatus?.let {
|
||||
InstallerStatusDialog(it, vm, vm::dismissPackageInstallerDialog)
|
||||
if (showDismissConfirmationDialog) {
|
||||
ConfirmDialog(
|
||||
onDismiss = { showDismissConfirmationDialog = false },
|
||||
onConfirm = {
|
||||
viewModel.onBack()
|
||||
onBackClick()
|
||||
},
|
||||
title = stringResource(R.string.patcher_stop_confirm_title),
|
||||
description = stringResource(R.string.patcher_stop_confirm_description),
|
||||
icon = Icons.Outlined.Cancel
|
||||
)
|
||||
}
|
||||
|
||||
viewModel.packageInstallerStatus?.let {
|
||||
InstallerStatusDialog(it, viewModel, viewModel::dismissPackageInstallerDialog)
|
||||
}
|
||||
|
||||
val activityLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.StartActivityForResult(),
|
||||
onResult = vm::handleActivityResult
|
||||
onResult = viewModel::handleActivityResult
|
||||
)
|
||||
EventEffect(flow = vm.launchActivityFlow) { intent ->
|
||||
EventEffect(flow = viewModel.launchActivityFlow) { intent ->
|
||||
activityLauncher.launch(intent)
|
||||
}
|
||||
|
||||
vm.activityPromptDialog?.let { title ->
|
||||
viewModel.activityPromptDialog?.let { title ->
|
||||
AlertDialog(
|
||||
onDismissRequest = vm::rejectInteraction,
|
||||
onDismissRequest = viewModel::rejectInteraction,
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = vm::allowInteraction
|
||||
onClick = viewModel::allowInteraction
|
||||
) {
|
||||
Text(stringResource(R.string.continue_))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = vm::rejectInteraction
|
||||
onClick = viewModel::rejectInteraction
|
||||
) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
@ -137,20 +150,20 @@ fun PatcherScreen(
|
||||
AppTopBar(
|
||||
title = stringResource(R.string.patcher),
|
||||
scrollBehavior = scrollBehavior,
|
||||
onBackClick = ::leaveScreen
|
||||
onBackClick = { showDismissConfirmationDialog = true }
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
BottomAppBar(
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = { exportApkLauncher.launch("${vm.packageName}_${vm.version}_revanced_patched.apk") },
|
||||
onClick = { exportApkLauncher.launch("${viewModel.packageName}_${viewModel.version}_revanced_patched.apk") },
|
||||
enabled = patcherSucceeded == true
|
||||
) {
|
||||
Icon(Icons.Outlined.Save, stringResource(id = R.string.save_apk))
|
||||
}
|
||||
IconButton(
|
||||
onClick = { vm.exportLogs(context) },
|
||||
onClick = { viewModel.exportLogs(context) },
|
||||
enabled = patcherSucceeded != null
|
||||
) {
|
||||
Icon(Icons.Outlined.PostAdd, stringResource(id = R.string.save_logs))
|
||||
@ -161,11 +174,11 @@ fun PatcherScreen(
|
||||
HapticExtendedFloatingActionButton(
|
||||
text = {
|
||||
Text(
|
||||
stringResource(if (vm.installedPackageName == null) R.string.install_app else R.string.open_app)
|
||||
stringResource(if (viewModel.installedPackageName == null) R.string.install_app else R.string.open_app)
|
||||
)
|
||||
},
|
||||
icon = {
|
||||
vm.installedPackageName?.let {
|
||||
viewModel.installedPackageName?.let {
|
||||
Icon(
|
||||
Icons.AutoMirrored.Outlined.OpenInNew,
|
||||
stringResource(R.string.open_app)
|
||||
@ -176,10 +189,10 @@ fun PatcherScreen(
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
if (vm.installedPackageName == null)
|
||||
if (vm.isDeviceRooted()) showInstallPicker = true
|
||||
else vm.install(InstallType.DEFAULT)
|
||||
else vm.open()
|
||||
if (viewModel.installedPackageName == null)
|
||||
if (viewModel.isDeviceRooted()) showInstallPicker = true
|
||||
else viewModel.install(InstallType.DEFAULT)
|
||||
else viewModel.open()
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -193,7 +206,7 @@ fun PatcherScreen(
|
||||
.fillMaxSize()
|
||||
) {
|
||||
LinearProgressIndicator(
|
||||
progress = { vm.progress },
|
||||
progress = { viewModel.progress },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
@ -209,8 +222,8 @@ fun PatcherScreen(
|
||||
Steps(
|
||||
category = category,
|
||||
steps = steps,
|
||||
stepCount = if (category == StepCategory.PATCHING) vm.patchesProgress else null,
|
||||
stepProgressProvider = vm
|
||||
stepCount = if (category == StepCategory.PATCHING) viewModel.patchesProgress else null,
|
||||
stepProgressProvider = viewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -60,14 +60,13 @@ import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.patcher.patch.Option
|
||||
import app.revanced.manager.patcher.patch.PatchInfo
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.CheckedFilterChip
|
||||
import app.revanced.manager.ui.component.FullscreenDialog
|
||||
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.SafeguardDialog
|
||||
import app.revanced.manager.ui.component.SearchBar
|
||||
@ -369,14 +368,22 @@ fun PatchesSelectorScreen(
|
||||
Icon(Icons.Outlined.Restore, stringResource(R.string.reset))
|
||||
}
|
||||
HapticExtendedFloatingActionButton(
|
||||
text = { Text(stringResource(R.string.save_with_count, selectedPatchCount)) },
|
||||
text = {
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.save_with_count,
|
||||
selectedPatchCount
|
||||
)
|
||||
)
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Save,
|
||||
contentDescription = stringResource(R.string.save)
|
||||
)
|
||||
},
|
||||
expanded = patchLazyListStates.getOrNull(pagerState.currentPage)?.isScrollingUp ?: true,
|
||||
expanded = patchLazyListStates.getOrNull(pagerState.currentPage)?.isScrollingUp
|
||||
?: true,
|
||||
onClick = {
|
||||
onSave(vm.getCustomSelection(), vm.getOptions())
|
||||
}
|
||||
@ -405,7 +412,19 @@ fun PatchesSelectorScreen(
|
||||
)
|
||||
}
|
||||
},
|
||||
text = { Text(bundle.name) },
|
||||
text = {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = bundle.name,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Text(
|
||||
text = bundle.version!!,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
},
|
||||
selectedContentColor = MaterialTheme.colorScheme.primary,
|
||||
unselectedContentColor = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
@ -618,13 +637,7 @@ private fun OptionsDialog(
|
||||
reset: () -> Unit,
|
||||
set: (String, Any?) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) = Dialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnBackPress = true
|
||||
)
|
||||
) {
|
||||
) = FullscreenDialog(onDismissRequest = onDismissRequest) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppTopBar(
|
||||
|
@ -1,5 +1,6 @@
|
||||
package app.revanced.manager.ui.screen
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@ -7,50 +8,79 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.domain.manager.PreferencesManager
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
||||
import app.revanced.manager.ui.model.navigation.Settings
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
private val settingsSections = listOf(
|
||||
Triple(
|
||||
R.string.general,
|
||||
R.string.general_description,
|
||||
Icons.Outlined.Settings
|
||||
) to Settings.General,
|
||||
Triple(
|
||||
R.string.updates,
|
||||
R.string.updates_description,
|
||||
Icons.Outlined.Update
|
||||
) to Settings.Updates,
|
||||
Triple(
|
||||
R.string.downloads,
|
||||
R.string.downloads_description,
|
||||
Icons.Outlined.Download
|
||||
) to Settings.Downloads,
|
||||
Triple(
|
||||
R.string.import_export,
|
||||
R.string.import_export_description,
|
||||
Icons.Outlined.SwapVert
|
||||
) to Settings.ImportExport,
|
||||
Triple(
|
||||
R.string.advanced,
|
||||
R.string.advanced_description,
|
||||
Icons.Outlined.Tune
|
||||
) to Settings.Advanced,
|
||||
Triple(
|
||||
R.string.about,
|
||||
R.string.app_name,
|
||||
Icons.Outlined.Info
|
||||
) to Settings.About,
|
||||
private data class Section(
|
||||
@StringRes val name: Int,
|
||||
@StringRes val description: Int,
|
||||
val image: ImageVector,
|
||||
val destination: Settings.Destination,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SettingsScreen(onBackClick: () -> Unit, navigate: (Settings.Destination) -> Unit) {
|
||||
val prefs: PreferencesManager = koinInject()
|
||||
val showDeveloperSettings by prefs.showDeveloperSettings.getAsState()
|
||||
|
||||
val settingsSections = remember(showDeveloperSettings) {
|
||||
listOfNotNull(
|
||||
Section(
|
||||
R.string.general,
|
||||
R.string.general_description,
|
||||
Icons.Outlined.Settings,
|
||||
Settings.General
|
||||
),
|
||||
Section(
|
||||
R.string.updates,
|
||||
R.string.updates_description,
|
||||
Icons.Outlined.Update,
|
||||
Settings.Updates
|
||||
),
|
||||
Section(
|
||||
R.string.downloads,
|
||||
R.string.downloads_description,
|
||||
Icons.Outlined.Download,
|
||||
Settings.Downloads
|
||||
),
|
||||
Section(
|
||||
R.string.import_export,
|
||||
R.string.import_export_description,
|
||||
Icons.Outlined.SwapVert,
|
||||
Settings.ImportExport
|
||||
),
|
||||
Section(
|
||||
R.string.advanced,
|
||||
R.string.advanced_description,
|
||||
Icons.Outlined.Tune,
|
||||
Settings.Advanced
|
||||
),
|
||||
Section(
|
||||
R.string.about,
|
||||
R.string.app_name,
|
||||
Icons.Outlined.Info,
|
||||
Settings.About
|
||||
),
|
||||
Section(
|
||||
R.string.developer_options,
|
||||
R.string.developer_options_description,
|
||||
Icons.Outlined.Code,
|
||||
Settings.Developer
|
||||
).takeIf { showDeveloperSettings }
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppTopBar(
|
||||
@ -64,12 +94,12 @@ fun SettingsScreen(onBackClick: () -> Unit, navigate: (Settings.Destination) ->
|
||||
.padding(paddingValues)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
settingsSections.forEach { (titleDescIcon, destination) ->
|
||||
settingsSections.forEach { (name, description, icon, destination) ->
|
||||
SettingsListItem(
|
||||
modifier = Modifier.clickable { navigate(destination) },
|
||||
headlineContent = stringResource(titleDescIcon.first),
|
||||
supportingContent = stringResource(titleDescIcon.second),
|
||||
leadingContent = { Icon(titleDescIcon.third, null) }
|
||||
headlineContent = stringResource(name),
|
||||
supportingContent = stringResource(description),
|
||||
leadingContent = { Icon(icon, null) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -23,16 +23,26 @@ import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarDuration
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
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.semantics.hideFromAccessibility
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.revanced.manager.BuildConfig
|
||||
import app.revanced.manager.R
|
||||
@ -42,6 +52,7 @@ import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
||||
import app.revanced.manager.ui.model.navigation.Settings
|
||||
import app.revanced.manager.ui.viewmodel.AboutViewModel
|
||||
import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.DEVELOPER_OPTIONS_TAPS
|
||||
import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.getSocialIcon
|
||||
import app.revanced.manager.util.openUrl
|
||||
import app.revanced.manager.util.toast
|
||||
@ -109,7 +120,8 @@ fun AboutSettingsScreen(
|
||||
}
|
||||
|
||||
val listItems = listOfNotNull(
|
||||
Triple(stringResource(R.string.submit_feedback),
|
||||
Triple(
|
||||
stringResource(R.string.submit_feedback),
|
||||
stringResource(R.string.submit_feedback_description),
|
||||
third = {
|
||||
context.openUrl("https://github.com/ReVanced/revanced-manager/issues/new/choose")
|
||||
@ -126,11 +138,6 @@ fun AboutSettingsScreen(
|
||||
navigate(Settings.Contributors)
|
||||
}
|
||||
),
|
||||
Triple(
|
||||
stringResource(R.string.developer_options),
|
||||
stringResource(R.string.developer_options_description),
|
||||
third = { navigate(Settings.DeveloperOptions) }
|
||||
),
|
||||
Triple(
|
||||
stringResource(R.string.opensource_licenses),
|
||||
stringResource(R.string.opensource_licenses_description),
|
||||
@ -139,6 +146,35 @@ fun AboutSettingsScreen(
|
||||
)
|
||||
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val showDeveloperSettings by viewModel.showDeveloperSettings.getAsState()
|
||||
var developerTaps by rememberSaveable { mutableIntStateOf(0) }
|
||||
LaunchedEffect(developerTaps) {
|
||||
if (developerTaps == 0) return@LaunchedEffect
|
||||
if (showDeveloperSettings) {
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.developer_options_already_enabled))
|
||||
developerTaps = 0
|
||||
return@LaunchedEffect
|
||||
}
|
||||
|
||||
val remaining = DEVELOPER_OPTIONS_TAPS - developerTaps
|
||||
if (remaining > 0) {
|
||||
snackbarHostState.showSnackbar(
|
||||
context.getString(
|
||||
R.string.developer_options_taps,
|
||||
remaining
|
||||
),
|
||||
duration = SnackbarDuration.Long
|
||||
)
|
||||
} else if (remaining == 0) {
|
||||
viewModel.showDeveloperSettings.update(true)
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.developer_options_enabled))
|
||||
}
|
||||
|
||||
// Reset the counter
|
||||
developerTaps = 0
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@ -148,6 +184,9 @@ fun AboutSettingsScreen(
|
||||
onBackClick = onBackClick
|
||||
)
|
||||
},
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackbarHostState)
|
||||
},
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) { paddingValues ->
|
||||
ColumnWithScrollbar(
|
||||
@ -158,9 +197,11 @@ fun AboutSettingsScreen(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp)
|
||||
.clickable { developerTaps += 1 },
|
||||
painter = icon,
|
||||
contentDescription = null
|
||||
contentDescription = stringResource(R.string.app_name)
|
||||
)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
@ -168,7 +209,11 @@ fun AboutSettingsScreen(
|
||||
) {
|
||||
Text(
|
||||
stringResource(R.string.app_name),
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
modifier = Modifier.semantics {
|
||||
// Icon already has this information for the purpose of being clickable.
|
||||
hideFromAccessibility()
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.version) + " " + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")",
|
||||
|
@ -112,20 +112,6 @@ fun AdvancedSettingsScreen(
|
||||
}
|
||||
)
|
||||
|
||||
GroupHeader(stringResource(R.string.patcher))
|
||||
BooleanItem(
|
||||
preference = vm.prefs.useProcessRuntime,
|
||||
coroutineScope = vm.viewModelScope,
|
||||
headline = R.string.process_runtime,
|
||||
description = R.string.process_runtime_description,
|
||||
)
|
||||
IntegerItem(
|
||||
preference = vm.prefs.patcherProcessMemoryLimit,
|
||||
coroutineScope = vm.viewModelScope,
|
||||
headline = R.string.process_runtime_memory_limit,
|
||||
description = R.string.process_runtime_memory_limit_description,
|
||||
)
|
||||
|
||||
GroupHeader(stringResource(R.string.safeguards))
|
||||
SafeguardBooleanItem(
|
||||
preference = vm.prefs.disablePatchVersionCompatCheck,
|
||||
@ -156,6 +142,20 @@ fun AdvancedSettingsScreen(
|
||||
confirmationText = R.string.patch_selection_safeguard_confirmation
|
||||
)
|
||||
|
||||
GroupHeader(stringResource(R.string.patcher))
|
||||
BooleanItem(
|
||||
preference = vm.prefs.useProcessRuntime,
|
||||
coroutineScope = vm.viewModelScope,
|
||||
headline = R.string.process_runtime,
|
||||
description = R.string.process_runtime_description,
|
||||
)
|
||||
IntegerItem(
|
||||
preference = vm.prefs.patcherProcessMemoryLimit,
|
||||
coroutineScope = vm.viewModelScope,
|
||||
headline = R.string.process_runtime_memory_limit,
|
||||
description = R.string.process_runtime_memory_limit_description,
|
||||
)
|
||||
|
||||
GroupHeader(stringResource(R.string.debugging))
|
||||
val exportDebugLogsLauncher =
|
||||
rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) {
|
||||
|
@ -51,7 +51,7 @@ import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ContributorScreen(
|
||||
fun ContributorSettingsScreen(
|
||||
onBackClick: () -> Unit,
|
||||
viewModel: ContributorViewModel = koinViewModel()
|
||||
) {
|
@ -12,19 +12,23 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.domain.manager.PreferencesManager
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.GroupHeader
|
||||
import app.revanced.manager.ui.component.settings.BooleanItem
|
||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
||||
import app.revanced.manager.ui.viewmodel.DeveloperOptionsViewModel
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DeveloperOptionsScreen(
|
||||
fun DeveloperSettingsScreen(
|
||||
onBackClick: () -> Unit,
|
||||
vm: DeveloperOptionsViewModel = koinViewModel()
|
||||
) {
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
val prefs: PreferencesManager = koinInject()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@ -37,6 +41,13 @@ fun DeveloperOptionsScreen(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) { paddingValues ->
|
||||
Column(modifier = Modifier.padding(paddingValues)) {
|
||||
GroupHeader(stringResource(R.string.manager))
|
||||
BooleanItem(
|
||||
preference = prefs.showDeveloperSettings,
|
||||
headline = R.string.developer_options,
|
||||
description = R.string.developer_options_description,
|
||||
)
|
||||
|
||||
GroupHeader(stringResource(R.string.patch_bundles_section))
|
||||
SettingsListItem(
|
||||
headlineContent = stringResource(R.string.patch_bundles_force_download),
|
@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.items
|
||||
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.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
@ -43,6 +44,7 @@ import app.revanced.manager.ui.component.AppTopBar
|
||||
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
|
||||
@ -59,6 +61,17 @@ fun DownloadsSettingsScreen(
|
||||
val downloadedApps by viewModel.downloadedApps.collectAsStateWithLifecycle(emptyList())
|
||||
val pluginStates by viewModel.downloaderPluginStates.collectAsStateWithLifecycle()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
var showDeleteConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
if (showDeleteConfirmationDialog) {
|
||||
ConfirmDialog(
|
||||
onDismiss = { showDeleteConfirmationDialog = false },
|
||||
onConfirm = { viewModel.deleteApps() },
|
||||
title = stringResource(R.string.downloader_plugin_delete_apps_title),
|
||||
description = stringResource(R.string.downloader_plugin_delete_apps_description),
|
||||
icon = Icons.Outlined.Delete
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@ -68,7 +81,7 @@ fun DownloadsSettingsScreen(
|
||||
onBackClick = onBackClick,
|
||||
actions = {
|
||||
if (viewModel.appSelection.isNotEmpty()) {
|
||||
IconButton(onClick = { viewModel.deleteApps() }) {
|
||||
IconButton(onClick = { showDeleteConfirmationDialog = true }) {
|
||||
Icon(Icons.Default.Delete, stringResource(R.string.delete))
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun LicensesScreen(
|
||||
fun LicensesSettingsScreen(
|
||||
onBackClick: () -> Unit,
|
||||
) {
|
||||
AppScaffold(
|
@ -27,7 +27,7 @@ import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ChangelogsScreen(
|
||||
fun ChangelogsSettingsScreen(
|
||||
onBackClick: () -> Unit,
|
||||
vm: ChangelogsViewModel = koinViewModel()
|
||||
) {
|
@ -8,6 +8,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.revanced.manager.data.platform.NetworkInfo
|
||||
import app.revanced.manager.domain.manager.PreferencesManager
|
||||
import app.revanced.manager.network.api.ReVancedAPI
|
||||
import app.revanced.manager.network.dto.ReVancedDonationLink
|
||||
import app.revanced.manager.network.dto.ReVancedSocial
|
||||
@ -27,6 +28,7 @@ import kotlinx.coroutines.withContext
|
||||
class AboutViewModel(
|
||||
private val reVancedAPI: ReVancedAPI,
|
||||
private val network: NetworkInfo,
|
||||
prefs: PreferencesManager,
|
||||
) : ViewModel() {
|
||||
var socials by mutableStateOf(emptyList<ReVancedSocial>())
|
||||
private set
|
||||
@ -37,6 +39,8 @@ class AboutViewModel(
|
||||
val isConnected: Boolean
|
||||
get() = network.isConnected()
|
||||
|
||||
val showDeveloperSettings = prefs.showDeveloperSettings
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
if (!isConnected) {
|
||||
@ -53,6 +57,8 @@ class AboutViewModel(
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DEVELOPER_OPTIONS_TAPS = 5
|
||||
|
||||
private val socialIcons = mapOf(
|
||||
"Discord" to FontAwesomeIcons.Brands.Discord,
|
||||
"GitHub" to FontAwesomeIcons.Brands.Github,
|
||||
|
@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.revanced.manager.domain.manager.PreferencesManager
|
||||
import app.revanced.manager.ui.theme.Theme
|
||||
import app.revanced.manager.util.resetListItemColorsCached
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class GeneralSettingsViewModel(
|
||||
@ -11,5 +12,6 @@ class GeneralSettingsViewModel(
|
||||
) : ViewModel() {
|
||||
fun setTheme(theme: Theme) = viewModelScope.launch {
|
||||
prefs.theme.update(theme)
|
||||
resetListItemColorsCached()
|
||||
}
|
||||
}
|
@ -180,6 +180,10 @@ fun LocalDateTime.relativeTime(context: Context): String {
|
||||
|
||||
private var transparentListItemColorsCached: ListItemColors? = null
|
||||
|
||||
fun resetListItemColorsCached() {
|
||||
transparentListItemColorsCached = null
|
||||
}
|
||||
|
||||
/**
|
||||
* The default ListItem colors, but with [ListItemColors.containerColor] set to [Color.Transparent].
|
||||
*/
|
||||
|
@ -143,6 +143,8 @@
|
||||
<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_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="search_apps">Search apps…</string>
|
||||
@ -301,6 +303,8 @@
|
||||
<string name="patcher_step_write_patched">Write patched APK file</string>
|
||||
<string name="patcher_step_sign_apk">Sign patched APK file</string>
|
||||
<string name="patcher_notification_message">Patching in progress…</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="execute_patches">Execute patches</string>
|
||||
<string name="executing_patch">Execute %s</string>
|
||||
<string name="failed_to_execute_patch">Failed to execute %s</string>
|
||||
@ -336,9 +340,17 @@
|
||||
<string name="bundle_view_patches">View patches</string>
|
||||
<string name="bundle_view_patches_any_version">Any version</string>
|
||||
<string name="bundle_view_patches_any_package">Any package</string>
|
||||
<string name="bundle_delete_single_dialog_title">Delete bundle</string>
|
||||
<string name="bundle_delete_multiple_dialog_title">Delete bundles</string>
|
||||
<string name="bundle_delete_single_dialog_description">Are you sure you want to delete the bundle \"%s\"?</string>
|
||||
<string name="bundle_delete_multiple_dialog_description">Are you sure you want to delete the selected bundles?</string>
|
||||
|
||||
|
||||
<string name="about_revanced_manager">About ReVanced Manager</string>
|
||||
<string name="revanced_manager_description">ReVanced Manager is an application designed to work with ReVanced Patcher, which allows for long-lasting patches to be created for Android apps. The patching system is designed to automatically work with new versions of apps with minimal maintenance.</string>
|
||||
<string name="developer_options_taps">%d taps remaining</string>
|
||||
<string name="developer_options_enabled">Developer options enabled</string>
|
||||
<string name="developer_options_already_enabled">Developer options are already enabled</string>
|
||||
<string name="update_available">An update is available</string>
|
||||
<string name="current_version">Current version: %s</string>
|
||||
<string name="new_version">New version: %s</string>
|
||||
@ -425,4 +437,5 @@
|
||||
<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="failed_to_import_keystore">Failed to import keystore</string>
|
||||
<string name="export">Export</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
</resources>
|
||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
@ -1,22 +1,22 @@
|
||||
[versions]
|
||||
ktx = "1.15.0"
|
||||
material3 = "1.3.1"
|
||||
ui-tooling = "1.7.7"
|
||||
viewmodel-lifecycle = "2.8.7"
|
||||
ktx = "1.16.0"
|
||||
material3 = "1.3.2"
|
||||
ui-tooling = "1.8.1"
|
||||
viewmodel-lifecycle = "2.9.0"
|
||||
splash-screen = "1.0.1"
|
||||
activity = "1.10.0"
|
||||
activity = "1.10.1"
|
||||
appcompat = "1.7.0"
|
||||
preferences-datastore = "1.1.2"
|
||||
work-runtime = "2.10.0"
|
||||
compose-bom = "2025.01.01"
|
||||
navigation = "2.8.6"
|
||||
work-runtime = "2.10.1"
|
||||
compose-bom = "2025.05.00"
|
||||
navigation = "2.9.0"
|
||||
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.6.1"
|
||||
room-version = "2.7.1"
|
||||
revanced-patcher = "21.0.0"
|
||||
revanced-library = "3.0.2"
|
||||
plugin-api = "1.0.0"
|
||||
@ -25,7 +25,7 @@ ktor = "2.3.9"
|
||||
markdown-renderer = "0.30.0"
|
||||
fading-edges = "1.0.4"
|
||||
kotlin = "2.1.10"
|
||||
android-gradle-plugin = "8.8.0"
|
||||
android-gradle-plugin = "8.9.1"
|
||||
dev-tools-gradle-plugin = "2.1.10-1.0.29"
|
||||
about-libraries-gradle-plugin = "11.5.0"
|
||||
coil = "2.7.0"
|
||||
|
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=8d97a97984f6cbd2b85fe4c60a743440a347544bf18818048e611f5288d46c94
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
|
||||
distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
6
gradlew
vendored
6
gradlew
vendored
@ -114,7 +114,7 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@ -205,7 +205,7 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@ -70,11 +70,11 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
@ -1,19 +1,16 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
maven("https://jitpack.io")
|
||||
mavenLocal()
|
||||
google()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
google()
|
||||
maven("https://jitpack.io")
|
||||
mavenLocal()
|
||||
maven {
|
||||
// A repository must be specified for some reason. "registry" is a dummy.
|
||||
url = uri("https://maven.pkg.github.com/revanced/registry")
|
||||
@ -24,5 +21,6 @@ dependencyResolutionManagement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "ReVanced Manager"
|
||||
include(":app")
|
||||
|
Reference in New Issue
Block a user