Merge branch 'dev' into feat/patch-history

This commit is contained in:
Benjamin Halko 2024-03-05 08:11:25 -08:00
commit d83869da2c
49 changed files with 902 additions and 1214 deletions

View File

@ -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

126
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,126 @@
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>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://x.com/revancedapp">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a>
<br>
<br>
Continuing the legacy of Vanced
</p>
# ReVanced Manager bug report
Before creating a new bug report, please keep the following in mind:
- **Do not submit a duplicate bug report**: You can review existing bug reports [here](https://github.com/ReVanced/revanced-manager/labels/Bug%20report).
- **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 if applicable
validations:
required: true
- type: textarea
attributes:
label: Version of ReVanced Manager and version & name of app you are patching
validations:
required: true
- type: dropdown
attributes:
label: Installation method
options:
- Regular
- Mount
validations:
required: false
- type: textarea
attributes:
label: ReVanced Manager logs
description: Export logs in ReVanced Manager settings.
render: shell
validations:
required: true
- type: textarea
attributes:
label: Patch logs
description: Export logs in "Patcher" screen.
render: shell
validations:
required: false
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your bug report will be closed if you don't follow the checklist below.
options:
- label: This issue is not a duplicate of an existing bug report.
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

View File

@ -1 +1,5 @@
blank_issues_enabled: false 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!

View File

@ -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

View File

@ -0,0 +1,106 @@
name: ⭐ Feature request
description: Create a detailed request for a new feature.
title: "feat: "
labels: ["Feature request"]
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>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://x.com/revancedapp">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a>
<br>
<br>
Continuing the legacy of Vanced
</p>
# ReVanced Manager feature request
Before creating a new feature request, please keep the following in mind:
- **Do not submit a duplicate feature request**: You can review existing feature requests [here](https://github.com/ReVanced/revanced-manager//labels/Feature%20request).
- **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
- Add the target application name in case you request a new patch
- 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: This issue is not a duplicate of an existing feature request.
required: true
- label: I have chosen an appropriate title.
required: true
- label: The feature request is only related to ReVanced Manager
required: true

2
.github/config.yaml vendored
View File

@ -1,2 +1,2 @@
firstPRMergeComment: > firstPRMergeComment: >
Thank you for contributing to ReVanced. 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.

View File

@ -1,23 +1,15 @@
name: PR Build name: Build pull request
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
# Flutter # Enable or disable cache
flutter-branch:
description: Flutter branch
type: choice
default: 'stable'
options:
- stable
- beta
- dev
- master
flutter-cache: flutter-cache:
description: Cache description: Cache
type: boolean type: boolean
default: true default: true
# Application configuration
# Select app flavour
app-flavour: app-flavour:
description: App flavour description: App flavour
default: 'release' default: 'release'
@ -26,22 +18,23 @@ on:
- release - release
- debug - debug
- profile - profile
# Pull Request
# Select pull request
pr-number: pr-number:
description: PR number (No hashtag) description: PR number (Without hashtag)
required: true required: true
run-name: "Build PR ${{ inputs.pr-number }}" run-name: "Build pull request ${{ inputs.pr-number }}"
jobs: jobs:
build: build:
name: Build the application name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: read
pull-requests: write pull-requests: write
steps: steps:
- name: Setup - name: Setup pull request
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
run: | run: |
@ -50,73 +43,74 @@ jobs:
gh repo set-default "${{ github.repository }}" gh repo set-default "${{ github.repository }}"
gh pr checkout "${{ inputs.pr-number }}" gh pr checkout "${{ inputs.pr-number }}"
echo "DATETIME=$( TZ='UTC+0' date --rfc-email )" >> $GITHUB_ENV
echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0
- name: Setup JDK
uses: actions/setup-java@v4 - name: Cache Gradle
with: uses: burrunan/gradle-cache-action@v1
java-version: '17'
distribution: 'zulu' - name: Setup Java
cache: gradle run: echo "JAVA_HOME=$JAVA_HOME_17_X64" >> $GITHUB_ENV
- name: Setup Flutter - name: Set up Flutter
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@v2
with: with:
channel: ${{ inputs.flutter-branch }} channel: "stable"
cache: ${{ inputs.flutter-cache }} cache: ${{ inputs.flutter-cache }}
- name: Install Flutter dependencies - name: Get dependencies
run: flutter pub get run: flutter pub get
- name: Generate translation with Slang
- name: Generate translations
run: dart run slang run: dart run slang
- name: Generate files with Builder
run: dart run build_runner build --delete-conflicting-outputs - name: Generate code files
run: dart run build_runner build --delete-conflicting-outputs
- name: Build with Flutter
- name: Build
continue-on-error: true continue-on-error: true
id: flutter-build id: flutter-build
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
flutter build apk --"${{ inputs.app-flavour }}"; flutter build apk --"${{ inputs.app-flavour }}";
- name: Prepare to comment - name: Prepare comment
run: | run: |
if [[ "${{ steps.flutter-build.outcome }}" == "success" ]]; then if [[ "${{ steps.flutter-build.outcome }}" == "success" ]]; then
echo "MESSAGE=✅ ReVanced Manager ${{ env.COMMIT_HASH }} build succeeded." >> $GITHUB_ENV echo "MESSAGE=✅ Failed build on ${{ env.COMMIT_HASH }}." >> $GITHUB_ENV
else else
echo "MESSAGE=🚫 ReVanced Manager ${{ env.COMMIT_HASH }} build failed." >> $GITHUB_ENV echo "MESSAGE=🚫 Failed build on ${{ env.COMMIT_HASH }}." >> $GITHUB_ENV
fi fi
- name: "Comment to Pull Request #${{ inputs.pr-number }}" - name: "Comment on pull request #${{ inputs.pr-number }}"
uses: thollander/actions-comment-pull-request@v2 uses: thollander/actions-comment-pull-request@v2
with: with:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}
pr_number: ${{ inputs.pr-number }} pr_number: ${{ inputs.pr-number }}
mode: recreate mode: recreate
message: | message: |
## ⚒️ ReVanced PR Build workflow ## ⚒️ Build status
${{ env.MESSAGE }} ${{ env.MESSAGE }}
You can see more details in run [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})! Details: [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})!
### ⚙️ Overview ### ⚙️ Workflow run configuration
- Flutter cache: ${{ inputs.flutter-cache }}
- App flavor: ${{ inputs.app-flavour }} - App flavor: ${{ inputs.app-flavour }}
- Branch: ${{ inputs.flutter-branch }}
- Start time: ${{ env.DATETIME }}
- name: Upload build - name: Upload
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
if-no-files-found: error if-no-files-found: error
name: revanced-manager-(${{ env.COMMIT_HASH }}-${{ inputs.pr-number }}-${{ inputs.app-flavour }})-${{ inputs.flutter-branch }} name: revanced-manager-(${{ env.COMMIT_HASH }}-${{ inputs.pr-number }}-${{ inputs.app-flavour }})
path: | path: |
build/app/outputs/flutter-apk/app-${{ inputs.app-flavour }}.apk build/app/outputs/flutter-apk/app-${{ inputs.app-flavour }}.apk
build/app/outputs/flutter-apk/app-${{ inputs.app-flavour }}.apk.sha1 build/app/outputs/flutter-apk/app-${{ inputs.app-flavour }}.apk.sha1

27
.github/workflows/open_pull_request.yml vendored Normal file
View File

@ -0,0 +1,27 @@
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

View File

@ -1,4 +1,4 @@
name: "Release Build" name: Release
on: on:
workflow_dispatch: workflow_dispatch:
@ -7,7 +7,7 @@ on:
- main - main
- dev - dev
paths: paths:
- ".github/workflows/release-build.yml" - ".github/workflows/release.yml"
- "android/**" - "android/**"
- "assets/**" - "assets/**"
- "lib/**" - "lib/**"
@ -15,45 +15,43 @@ on:
jobs: jobs:
release: release:
name: Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - name: Checkout
uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with: with:
java-version: "17" fetch-depth: 0
distribution: "zulu"
- name: Set up Node.js 20 - name: Setup Java
run: echo "JAVA_HOME=$JAVA_HOME_17_X64" >> $GITHUB_ENV
- name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '20' node-version: "lts/*"
cache: 'npm'
- uses: subosito/flutter-action@v2 - name: Set up Flutter
uses: subosito/flutter-action@v2
with: with:
channel: "stable" channel: "stable"
- name: Cache Node modules - name: Install dependencies
uses: actions/cache@v4
with:
path: |
node_modules
key: npm-${{ hashFiles('package-lock.json') }}
- name: Setup semantic-release
run: npm install run: npm install
- name: Set up Flutter - name: Get dependencies
run: flutter pub get run: flutter pub get
- name: Generate translation with Slang
- name: Generate translations
run: dart run slang run: dart run slang
- name: Generate files with Builder
- name: Generate code files
run: dart run build_runner build --delete-conflicting-outputs run: dart run build_runner build --delete-conflicting-outputs
- name: Build with Flutter - name: Release
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
signingKey: "keystore.jks" signingKey: "keystore.jks"
keyStorePassword: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }} keyStorePassword: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
keyAlias: ${{ secrets.SIGNING_KEY_ALIAS }} keyAlias: ${{ secrets.SIGNING_KEY_ALIAS }}

View File

@ -1,12 +1,14 @@
name: Crowdin Action name: Sync Crowdin
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: [dev] branches:
- dev
jobs: jobs:
synchronize-with-crowdin: sync:
name: Sync
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
@ -17,7 +19,7 @@ jobs:
- name: Set up Dart - name: Set up Dart
uses: dart-lang/setup-dart@v1 uses: dart-lang/setup-dart@v1
- name: Sync translation from Crowdin - name: Sync translations from Crowdin
uses: crowdin/github-action@v1 uses: crowdin/github-action@v1
with: with:
config: crowdin.yml config: crowdin.yml
@ -26,10 +28,10 @@ jobs:
download_translations: true download_translations: true
localization_branch_name: feat/translations localization_branch_name: feat/translations
create_pull_request: true create_pull_request: true
pull_request_title: "chore(i18n): Sync translations" pull_request_title: "chore: Sync translations"
pull_request_body: "Sync translations from [Crowdin/ReVanced](https://crowdin.com/project/revanced)" pull_request_body: "Sync translations from [crowdin.com/project/revanced](https://crowdin.com/project/revanced)"
pull_request_base_branch_name: "dev" pull_request_base_branch_name: "dev"
commit_message: "chore(i18n): Sync translations" commit_message: "chore: Sync translations"
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
@ -41,13 +43,13 @@ jobs:
sudo chmod 777 * sudo chmod 777 *
dart nuke.dart >> $GITHUB_STEP_SUMMARY dart nuke.dart >> $GITHUB_STEP_SUMMARY
- name: Push out changes to i10n - name: Commit translations
run: | run: |
git config user.name revanced-bot git config user.name revanced-bot
git config user.email github@revanced.app git config user.email github@revanced.app
sudo chown -R $USER:$USER .git sudo chown -R $USER:$USER .git
git add assets/i18n/*.json git add assets/i18n/*.json
git commit -m "chore(Translation): Remove empty values from JSON" assets/i18n/*.json git commit -m "chore: Remove empty values from JSON" assets/i18n/*.json
git push origin HEAD:feat/translations git push origin HEAD:feat/translations
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -11,7 +11,7 @@ jobs:
name: Dispatch event to documentation repository name: Dispatch event to documentation repository
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
steps: steps:
- uses: peter-evans/repository-dispatch@v2 - uses: peter-evans/repository-dispatch@v3
with: with:
token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }} token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }}
repository: revanced/revanced-documentation repository: revanced/revanced-documentation

View File

@ -71,33 +71,33 @@ This document describes how to contribute to ReVanced Manager.
## 🙏 Submitting a feature request ## 🙏 Submitting a feature request
Features can be requested by opening an issue using the 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-issue.yml&title=feat%3A+%3Ctitle%3E). [Feature request issue template](https://github.com/ReVanced/revanced-manager/issues/new?assignees=&labels=Feature+request&projects=&template=feature_request.yml&title=feat%3A+).
> [!NOTE] > **Note**
> We may reject your request at the discretion of ReVanced Manager's maintainers, > Requests can be accepted or rejected at the discretion of maintainers of ReVanced Manager.
> please provide good motivation for a request to be accepted. > Good motivation has to be provided for a request to be accepted.
## 🐞 Submitting a bug report ## 🐞 Submitting a bug report
If you encounter a bug while using the ReVanced Manager app, open an issue using the 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&projects=&template=bug-issue.yml&title=bug%3A+%3Ctitle%3E). [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 ## 📝 How to contribute
> [!TIP] 1. Before contributing, it is recommended to open an issue to discuss your change
> We recommend that you discuss your changes with with the maintainers of ReVanced Manager. This will help you determine whether your change is acceptable
> the maintainers of ReVanced Manager before contributing. and whether it is worth your time to implement it
> This will help you determine whether your change is acceptable. 2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
3. Commit your changes
1. Fork the repository and create a new branch based off the `dev` branch 4. Submit a pull request to the `dev` branch of the repository and reference issues
2. Commit your changes that your pull request closes in the description of your pull request
3. Open a pull request to the `dev` branch and reference issues that your pull request closes 5. Our team will review your pull request and provide feedback. Once your pull request is approved,
4. The maintainers of ReVanced Manager will review and provide suggestions. it will be merged into the `dev` branch and will be included in the next release of ReVanced Manager
Once your pull request is approved and merged, it will be included in the next release of ReVanced Manager
## 🤚 I want to contribute but don't know how to code ## 🤚 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 Even if you don't know how to code, you can still contribute by
translating ReVanced Manager on [Crowdin](https://translate.revanced.app/). translating ReVanced Manager on [Crowdin](https://translate.revanced.app/).
❤️ Thank you for considering contributing to ReVanced Manager. ❤️ Thank you for considering contributing to ReVanced Manager,
ReVanced

View File

@ -60,38 +60,50 @@
# 💊 ReVanced Manager # 💊 ReVanced Manager
[![GitHub last commit](https://img.shields.io/github/last-commit/ReVanced/revanced-manager)](https://github.com/ReVanced/revanced-manager/commits "") ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/ReVanced/revanced-manager/release.yml)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/w/ReVanced/revanced-manager)](https://github.com/ReVanced/revanced-manager/commits "") ![GPLv3 License](https://img.shields.io/badge/License-GPL%20v3-yellow.svg)
ReVanced Manager is an Android application that uses ReVanced Patcher to add, remove, and modify existing functionalities in Android applications. Application to use ReVanced on Android
## ❓ About
ReVanced Manager is an application that uses [ReVanced Patcher](https://github.com/revanced/revanced-patcher) to patch Android apps.
## 💪 Features ## 💪 Features
Some of the features we provide are: Some of the features ReVanced Manager provides are:
* 📱 **Portable**: ReVanced Patcher that fit in your pocket; - 💉 **Patch apps**: Apply any patch of your choice to Android apps
* 🤗 **Intuitive UI**: Help you manage your patched applications with easy-to-use interface; - 📱 **Portable**: ReVanced Patcher that fits in your pocket
* 🛠️ **Customization**: Patch with third-party sources; - 🤗 **Simple UI**: Quickly understand the ins and outs of ReVanced Manager
* ✨ And a **lot more!** - 🛠️ **Customization**: Configurable API, custom sources, language, signing keystore, theme and more
## 🔽 Download ## 🔽 Download
You can get ReVanced Manager by downloading from [ReVanced site](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).
Learn how to use ReVanced Manager by following the [documentation](/docs).
## 📚 Everything else ## 📚 Everything else
### 📙 Contributing
Thank you for considering contributing to ReVanced Manager.
You can find the contribution guidelines [here](CONTRIBUTING.md).
### 🛠️ Building
To build a ReVanced Manager, you can follow the [documentation](/docs).
### 📄 Documentation ### 📄 Documentation
Documentation on how to use the application is available [here](/docs/README.md). You can find the documentation for ReVanced Manager [here](/docs).
### 👋 Contributing ### 👋 Contributing
Thank you for considering contributing to ReVanced Manager, you can find the contribution guidelines [here](/CONTRIBUTING.md). Thank you for considering contributing to ReVanced Manager. You can find the contribution guidelines [here](/CONTRIBUTING.md).
### 🔴 Issues
For suggestions and bug reports, open an issue [here](https://github.com/ReVanced/revanced-manager/issues/choose).
## ⚖️ License ## ⚖️ License
ReVanced Manager adopts the [GNU General Public License 3.0](/LICENSE), [tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3): You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions. 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.

View File

@ -113,12 +113,9 @@ flutter {
} }
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.10" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.22"
// ReVanced // ReVanced
implementation "app.revanced:revanced-patcher:19.1.0" implementation "app.revanced:revanced-patcher:19.3.1"
implementation "app.revanced:revanced-library:2.1.0"
// Signing & aligning
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
implementation("com.android.tools.build:apksig:7.2.2")
} }

View File

@ -5,19 +5,15 @@
# For more details, see # For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html # http://developer.android.com/guide/developing/tools/proguard.html
# These packages are referenced by ReVanced Patches -keep class app.revanced.** { *; }
-keep class app.revanced.patcher.** { *; }
-keep class com.android.tools.smali.** { *; } -keep class com.android.tools.smali.** { *; }
-keep class kotlin.** { *; } -keep class kotlin.** { *; }
-keepnames class com.google.common.collect.** -keep class com.google.auto.value.** { *; }
# This package uses reflection internally, so do not remove and rename
-keep class com.android.apksig.internal.** { *; } -keep class com.android.apksig.internal.** { *; }
-keepnames class com.google.common.collect.**
# Fix crash
-keepnames class org.xmlpull.** { *; } -keepnames class org.xmlpull.** { *; }
# Fix build errors -dontwarn com.google.auto.value.**
-dontwarn com.google.j2objc.annotations.*
-dontwarn java.awt.** -dontwarn java.awt.**
-dontwarn javax.** -dontwarn javax.**
-dontwarn com.google.j2objc.annotations.*

View File

@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
@ -17,7 +18,9 @@
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<application <application
android:label="@string/app_name" android:label="@string/app_name"
android:name="${applicationName}" android:name="${applicationName}"

View File

@ -7,23 +7,20 @@ import android.content.pm.PackageInstaller
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import app.revanced.library.ApkUtils
import app.revanced.library.ApkUtils.applyTo
import app.revanced.library.ApkUtils.sign
import app.revanced.manager.flutter.utils.Aapt import app.revanced.manager.flutter.utils.Aapt
import app.revanced.manager.flutter.utils.aligning.ZipAligner
import app.revanced.manager.flutter.utils.packageInstaller.InstallerReceiver import app.revanced.manager.flutter.utils.packageInstaller.InstallerReceiver
import app.revanced.manager.flutter.utils.packageInstaller.UninstallerReceiver import app.revanced.manager.flutter.utils.packageInstaller.UninstallerReceiver
import app.revanced.manager.flutter.utils.signing.Signer
import app.revanced.manager.flutter.utils.zip.ZipFile
import app.revanced.manager.flutter.utils.zip.structures.ZipEntry
import app.revanced.patcher.PatchBundleLoader import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.PatchSet import app.revanced.patcher.PatchSet
import app.revanced.patcher.Patcher import app.revanced.patcher.Patcher
import app.revanced.patcher.PatcherOptions import app.revanced.patcher.PatcherConfig
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.json.JSONArray import org.json.JSONArray
@ -50,7 +47,10 @@ class MainActivity : FlutterActivity() {
val installerChannel = "app.revanced.manager.flutter/installer" val installerChannel = "app.revanced.manager.flutter/installer"
val openBrowserChannel = "app.revanced.manager.flutter/browser" val openBrowserChannel = "app.revanced.manager.flutter/browser"
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, openBrowserChannel).setMethodCallHandler { call, result -> MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
openBrowserChannel
).setMethodCallHandler { call, result ->
if (call.method == "openBrowser") { if (call.method == "openBrowser") {
val searchQuery = call.argument<String>("query") val searchQuery = call.argument<String>("query")
openBrowser(searchQuery) openBrowser(searchQuery)
@ -69,40 +69,34 @@ class MainActivity : FlutterActivity() {
mainChannel.setMethodCallHandler { call, result -> mainChannel.setMethodCallHandler { call, result ->
when (call.method) { when (call.method) {
"runPatcher" -> { "runPatcher" -> {
val originalFilePath = call.argument<String>("originalFilePath") val inFilePath = call.argument<String>("inFilePath")
val inputFilePath = call.argument<String>("inputFilePath")
val patchedFilePath = call.argument<String>("patchedFilePath")
val outFilePath = call.argument<String>("outFilePath") val outFilePath = call.argument<String>("outFilePath")
val integrationsPath = call.argument<String>("integrationsPath") val integrationsPath = call.argument<String>("integrationsPath")
val selectedPatches = call.argument<List<String>>("selectedPatches") val selectedPatches = call.argument<List<String>>("selectedPatches")
val options = call.argument<Map<String, Map<String, Any>>>("options") val options = call.argument<Map<String, Map<String, Any>>>("options")
val cacheDirPath = call.argument<String>("cacheDirPath") val tmpDirPath = call.argument<String>("tmpDirPath")
val keyStoreFilePath = call.argument<String>("keyStoreFilePath") val keyStoreFilePath = call.argument<String>("keyStoreFilePath")
val keystorePassword = call.argument<String>("keystorePassword") val keystorePassword = call.argument<String>("keystorePassword")
if ( if (
originalFilePath != null && inFilePath != null &&
inputFilePath != null &&
patchedFilePath != null &&
outFilePath != null && outFilePath != null &&
integrationsPath != null && integrationsPath != null &&
selectedPatches != null && selectedPatches != null &&
options != null && options != null &&
cacheDirPath != null && tmpDirPath != null &&
keyStoreFilePath != null && keyStoreFilePath != null &&
keystorePassword != null keystorePassword != null
) { ) {
cancel = false cancel = false
runPatcher( runPatcher(
result, result,
originalFilePath, inFilePath,
inputFilePath,
patchedFilePath,
outFilePath, outFilePath,
integrationsPath, integrationsPath,
selectedPatches, selectedPatches,
options, options,
cacheDirPath, tmpDirPath,
keyStoreFilePath, keyStoreFilePath,
keystorePassword keystorePassword
) )
@ -214,28 +208,23 @@ class MainActivity : FlutterActivity() {
startActivity(intent) startActivity(intent)
} }
} }
@OptIn(InternalCoroutinesApi::class)
private fun runPatcher( private fun runPatcher(
result: MethodChannel.Result, result: MethodChannel.Result,
originalFilePath: String, inFilePath: String,
inputFilePath: String,
patchedFilePath: String,
outFilePath: String, outFilePath: String,
integrationsPath: String, integrationsPath: String,
selectedPatches: List<String>, selectedPatches: List<String>,
options: Map<String, Map<String, Any>>, options: Map<String, Map<String, Any>>,
cacheDirPath: String, tmpDirPath: String,
keyStoreFilePath: String, keyStoreFilePath: String,
keystorePassword: String keystorePassword: String
) { ) {
val originalFile = File(originalFilePath) val inFile = File(inFilePath)
val inputFile = File(inputFilePath)
val patchedFile = File(patchedFilePath)
val outFile = File(outFilePath) val outFile = File(outFilePath)
val integrations = File(integrationsPath) val integrations = File(integrationsPath)
val keyStoreFile = File(keyStoreFilePath) val keyStoreFile = File(keyStoreFilePath)
val cacheDir = File(cacheDirPath) val tmpDir = File(tmpDirPath)
Thread { Thread {
fun updateProgress(progress: Double, header: String, log: String) { fun updateProgress(progress: Double, header: String, log: String) {
@ -253,6 +242,16 @@ class MainActivity : FlutterActivity() {
fun postStop() = handler.post { stopResult!!.success(null) } fun postStop() = handler.post { stopResult!!.success(null) }
fun cancel(block: () -> Unit = {}): Boolean {
if (cancel) {
block()
postStop()
}
return cancel
}
// Setup logger // Setup logger
Logger.getLogger("").apply { Logger.getLogger("").apply {
handlers.forEach { handlers.forEach {
@ -273,38 +272,20 @@ class MainActivity : FlutterActivity() {
} }
try { try {
updateProgress(0.0, "", "Copying APK") updateProgress(0.0, "Reading APK...", "Reading APK")
if (cancel) {
postStop()
return@Thread
}
originalFile.copyTo(inputFile, true)
if (cancel) {
postStop()
return@Thread
}
updateProgress(0.05, "Reading APK...", "Reading APK")
val patcher = Patcher( val patcher = Patcher(
PatcherOptions( PatcherConfig(
inputFile, inFile,
cacheDir, tmpDir,
Aapt.binary(applicationContext).absolutePath, Aapt.binary(applicationContext).absolutePath,
cacheDir.path, tmpDir.path,
true // TODO: Add option to disable this true // TODO: Add option to disable this
) )
) )
if (cancel) { if (cancel(patcher::close)) return@Thread
postStop() updateProgress(0.02, "Loading patches...", "Loading patches")
return@Thread
}
updateProgress(0.1, "Loading patches...", "Loading patches")
val patches = patches.filter { patch -> val patches = patches.filter { patch ->
val isCompatible = patch.compatiblePackages?.any { val isCompatible = patch.compatiblePackages?.any {
@ -319,32 +300,25 @@ class MainActivity : FlutterActivity() {
options[patch.name]?.forEach { (key, value) -> options[patch.name]?.forEach { (key, value) ->
patch.options[key] = value patch.options[key] = value
} }
} }.toSet()
if (cancel) { if (cancel(patcher::close)) return@Thread
postStop() updateProgress(0.05, "Executing...", "")
return@Thread
}
updateProgress(0.15, "Executing...", "") val patcherResult = patcher.use {
patcher.apply {
// Update the progress bar every time a patch is executed from 0.15 to 0.7 acceptIntegrations(setOf(integrations))
val totalPatchesCount = patches.size acceptPatches(patches)
val progressStep = 0.55 / totalPatchesCount }
var progress = 0.15
patcher.apply {
acceptIntegrations(listOf(integrations))
acceptPatches(patches)
runBlocking { runBlocking {
apply(false).collect(FlowCollector { patchResult: PatchResult -> // Update the progress bar every time a patch is executed from 0.15 to 0.7
if (cancel) { val totalPatchesCount = patches.size
handler.post { stopResult!!.success(null) } val progressStep = 0.55 / totalPatchesCount
this.cancel() var progress = 0.05
this@apply.close()
return@FlowCollector patcher.apply(false).collect(FlowCollector { patchResult: PatchResult ->
} if (cancel(patcher::close)) return@FlowCollector
val msg = patchResult.exception?.let { val msg = patchResult.exception?.let {
val writer = StringWriter() val writer = StringWriter()
@ -358,50 +332,30 @@ class MainActivity : FlutterActivity() {
progress += progressStep progress += progressStep
}) })
} }
if (cancel(patcher::close)) return@Thread
updateProgress(0.75, "Building...", "")
patcher.get()
} }
if (cancel) { inFile.copyTo(outFile)
postStop()
patcher.close()
return@Thread
}
updateProgress(0.75, "Building...", "") if (cancel(patcher::close)) return@Thread
val res = patcher.get() patcherResult.applyTo(outFile)
patcher.close()
ZipFile(patchedFile).use { file -> if (cancel(patcher::close)) return@Thread
res.dexFiles.forEach { updateProgress(0.8, "Signing...", "")
if (cancel) {
postStop() outFile.sign(
return@Thread ApkUtils.SigningOptions(
} keyStoreFile,
file.addEntryCompressData( keystorePassword,
ZipEntry.createWithName(it.name), "alias",
it.stream.readBytes() keystorePassword
)
}
res.resourceFile?.let {
file.copyEntriesFromFileAligned(
ZipFile(it),
ZipAligner::getEntryAlignment
)
}
file.copyEntriesFromFileAligned(
ZipFile(inputFile),
ZipAligner::getEntryAlignment
) )
} )
if (cancel) {
postStop()
return@Thread
}
updateProgress(0.8, "Signing...", "Signing APK")
Signer("ReVanced", keystorePassword).signApk(patchedFile, outFile, keyStoreFile)
updateProgress(.85, "Patched", "Patched APK") updateProgress(.85, "Patched", "Patched APK")
} catch (ex: Throwable) { } catch (ex: Throwable) {
@ -421,7 +375,8 @@ class MainActivity : FlutterActivity() {
private fun installApk(apkPath: String) { private fun installApk(apkPath: String) {
val packageInstaller: PackageInstaller = applicationContext.packageManager.packageInstaller val packageInstaller: PackageInstaller = applicationContext.packageManager.packageInstaller
val sessionParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) val sessionParams =
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId: Int = packageInstaller.createSession(sessionParams) val sessionId: Int = packageInstaller.createSession(sessionParams)
val session: PackageInstaller.Session = packageInstaller.openSession(sessionId) val session: PackageInstaller.Session = packageInstaller.openSession(sessionId)
session.use { activeSession -> session.use { activeSession ->
@ -436,7 +391,12 @@ class MainActivity : FlutterActivity() {
val receiverIntent = Intent(applicationContext, InstallerReceiver::class.java).apply { val receiverIntent = Intent(applicationContext, InstallerReceiver::class.java).apply {
action = "APP_INSTALL_ACTION" action = "APP_INSTALL_ACTION"
} }
val receiverPendingIntent = PendingIntent.getBroadcast(context, sessionId, receiverIntent, PackageInstallerManager.flags) val receiverPendingIntent = PendingIntent.getBroadcast(
context,
sessionId,
receiverIntent,
PackageInstallerManager.flags
)
session.commit(receiverPendingIntent.intentSender) session.commit(receiverPendingIntent.intentSender)
session.close() session.close()
} }
@ -446,7 +406,8 @@ class MainActivity : FlutterActivity() {
val receiverIntent = Intent(applicationContext, UninstallerReceiver::class.java).apply { val receiverIntent = Intent(applicationContext, UninstallerReceiver::class.java).apply {
action = "APP_UNINSTALL_ACTION" action = "APP_UNINSTALL_ACTION"
} }
val receiverPendingIntent = PendingIntent.getBroadcast(context, 0, receiverIntent, PackageInstallerManager.flags) val receiverPendingIntent =
PendingIntent.getBroadcast(context, 0, receiverIntent, PackageInstallerManager.flags)
packageInstaller.uninstall(packageName, receiverPendingIntent.intentSender) packageInstaller.uninstall(packageName, receiverPendingIntent.intentSender)
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,12 @@ allprojects {
google() google()
mavenCentral() mavenCentral()
maven { maven {
url 'https://jitpack.io' // A repository must be speficied for some reason. "registry" is a dummy.
url = uri("https://maven.pkg.github.com/revanced/registry")
credentials {
username = project.findProperty("gpr.user") as String ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") as String ?: System.getenv("GITHUB_TOKEN")
}
} }
mavenLocal() mavenLocal()
} }

View File

@ -16,7 +16,7 @@
"noShowAgain": "Больш не паказваць", "noShowAgain": "Больш не паказваць",
"add": "Дадаць", "add": "Дадаць",
"remove": "Выдаліць", "remove": "Выдаліць",
"showChangelogButton": "Паказаць журнал змен", "showChangelogButton": "Паказаць журнал змяненняў",
"showUpdateButton": "Паказаць абнаўленне", "showUpdateButton": "Паказаць абнаўленне",
"navigationView": { "navigationView": {
"dashboardTab": "Галоўная", "dashboardTab": "Галоўная",
@ -32,7 +32,7 @@
"noUpdates": "Няма даступных абнаўленняў", "noUpdates": "Няма даступных абнаўленняў",
"WIP": "У працэсе...", "WIP": "У працэсе...",
"noInstallations": "Няма ўсталяваных праграм з выпраўленнямі", "noInstallations": "Няма ўсталяваных праграм з выпраўленнямі",
"installUpdate": "Працягнуць устаноўку абнаўлення?", "installUpdate": "Працягнуць усталяванне абнаўлення?",
"updateSheetTitle": "Абнавіць ReVanced Manager", "updateSheetTitle": "Абнавіць ReVanced Manager",
"updateDialogTitle": "Даступна новае абнаўленне", "updateDialogTitle": "Даступна новае абнаўленне",
"updatePatchesSheetTitle": "Абнавіць выпраўленні ReVanced", "updatePatchesSheetTitle": "Абнавіць выпраўленні ReVanced",
@ -45,20 +45,20 @@
"checkUpdateDialogText": "Вы сапраўды хочаце правяраць абнаўленні ReVanced Manager аўтаматычна?", "checkUpdateDialogText": "Вы сапраўды хочаце правяраць абнаўленні ReVanced Manager аўтаматычна?",
"notificationTitle": "Абнаўленне спампавана", "notificationTitle": "Абнаўленне спампавана",
"notificationText": "Націсніце, каб усталяваць абнаўленне", "notificationText": "Націсніце, каб усталяваць абнаўленне",
"downloadingMessage": "Загружаецца абнаўленне...", "downloadingMessage": "Спампоўваецца абнаўленне...",
"downloadedMessage": "Абнаўленне спампавана", "downloadedMessage": "Абнаўленне спампавана",
"installingMessage": "Усталяванне абнаўлення...", "installingMessage": "Усталяванне абнаўлення...",
"errorDownloadMessage": "Немагчыма спампаваць абнаўленне", "errorDownloadMessage": "Немагчыма спампаваць абнаўленне",
"errorInstallMessage": "Немагчыма ўсталяваць абнаўленне", "errorInstallMessage": "Немагчыма ўсталяваць абнаўленне",
"noConnection": "Няма злучэння з інтэрнэтам", "noConnection": "Няма злучэння з інтэрнэтам",
"updatesDisabled": "Абнаўленне праграмы з выпраўленнем зараз адключана. Неабходна паўторна ўжыць выпраўленне для праграмы." "updatesDisabled": "Абнаўленне выпраўленай праграмы ў цяперашні час адключана. Неабходна паўторна ўжыць выпраўленне для праграмы."
}, },
"applicationItem": { "applicationItem": {
"infoButton": "Інфармацыя" "infoButton": "Звесткі"
}, },
"latestCommitCard": { "latestCommitCard": {
"loadingLabel": "Загрузка...", "loadingLabel": "Загрузка...",
"timeagoLabel": "${time} таму назад", "timeagoLabel": "${time} таму",
"patcherLabel": "Праграма выпраўлення: ", "patcherLabel": "Праграма выпраўлення: ",
"managerLabel": "Менеджар: ", "managerLabel": "Менеджар: ",
"updateButton": "Абнавіць ReVanced Manager" "updateButton": "Абнавіць ReVanced Manager"
@ -80,7 +80,7 @@
"anyVersion": "Любая версія" "anyVersion": "Любая версія"
}, },
"patchSelectorCard": { "patchSelectorCard": {
"widgetTitle": "Выбраць выпраўленні", "widgetTitle": "Выберыце выпраўленні",
"widgetTitleSelected": "Выбраныя выпраўленні", "widgetTitleSelected": "Выбраныя выпраўленні",
"widgetSubtitle": "Спачатку выберыце праграму", "widgetSubtitle": "Спачатку выберыце праграму",
"widgetEmptySubtitle": "Выпраўленні не выбраны" "widgetEmptySubtitle": "Выпраўленні не выбраны"
@ -101,7 +101,7 @@
"featureNotAvailableText": "Гэта праграма з'яўляецца раздзеленым файлам APK і яе можна надзейна выправіць і ўсталяваць толькі падключэннем з правамі суперкарыстальніка. Аднак вы можаце выправіць і ўсталяваць поўны файл APK выбраўшы яго са сховішча." "featureNotAvailableText": "Гэта праграма з'яўляецца раздзеленым файлам APK і яе можна надзейна выправіць і ўсталяваць толькі падключэннем з правамі суперкарыстальніка. Аднак вы можаце выправіць і ўсталяваць поўны файл APK выбраўшы яго са сховішча."
}, },
"patchesSelectorView": { "patchesSelectorView": {
"viewTitle": "Выбраць выпраўленні", "viewTitle": "Выберыце выпраўленні",
"searchBarHint": "Пошук выпраўленняў", "searchBarHint": "Пошук выпраўленняў",
"universalPatches": "Універсальныя выпраўленні", "universalPatches": "Універсальныя выпраўленні",
"newPatches": "Новыя выпраўленні", "newPatches": "Новыя выпраўленні",
@ -124,9 +124,9 @@
"addOptions": "Дадаць параметры", "addOptions": "Дадаць параметры",
"deselectPatch": "Зняць выбар з выпраўлення", "deselectPatch": "Зняць выбар з выпраўлення",
"tooltip": "Больш уваходных параметраў", "tooltip": "Больш уваходных параметраў",
"selectFilePath": "Выберыце шлях файла", "selectFilePath": "Выбраць шлях да файла",
"selectFolder": "Выбраць папку", "selectFolder": "Выбраць папку",
"selectOption": "Выбраць параметр", "selectOption": "Выберыце параметр",
"requiredOption": "Абавязковы параметр", "requiredOption": "Абавязковы параметр",
"unsupportedOption": "Гэты параметр не падтрымліваецца", "unsupportedOption": "Гэты параметр не падтрымліваецца",
"requiredOptionNull": "Наступныя параметры павінны быць зададзены:\n\n${options}" "requiredOptionNull": "Наступныя параметры павінны быць зададзены:\n\n${options}"
@ -149,9 +149,9 @@
"pressBackAgain": "Націсніце назад яшчэ раз, каб скасаваць", "pressBackAgain": "Націсніце назад яшчэ раз, каб скасаваць",
"openButton": "Адкрыць", "openButton": "Адкрыць",
"shareButton": "Абагуліць файл", "shareButton": "Абагуліць файл",
"notificationTitle": "Адбываецца ReVanced Manager выпраўленне праграмы", "notificationTitle": "ReVanced Manager працуе над выпраўленнем",
"notificationText": "Націсніце для вяртання ва ўсталёўшчык праграм", "notificationText": "Націсніце для вяртання ва ўсталёўшчык праграм",
"exportApkButtonTooltip": "Экспартаваць выпраўлены APK", "exportApkButtonTooltip": "Экспартаваць выпраўленыя APK",
"exportLogButtonTooltip": "Экспартаваць журнал", "exportLogButtonTooltip": "Экспартаваць журнал",
"screenshotDetected": "Выяўлены здымак экрана. Калі вы хочаце абагуліць журнал, то замест гэтага адпраўце тэкставую копію\n\nСкапіраваць журнал у буфер абмену?", "screenshotDetected": "Выяўлены здымак экрана. Калі вы хочаце абагуліць журнал, то замест гэтага адпраўце тэкставую копію\n\nСкапіраваць журнал у буфер абмену?",
"copiedToClipboard": "Журнал скапіяваны ў буфер абмену", "copiedToClipboard": "Журнал скапіяваны ў буфер абмену",
@ -170,7 +170,7 @@
"lightThemeLabel": "Светлая", "lightThemeLabel": "Светлая",
"darkThemeLabel": "Цёмная", "darkThemeLabel": "Цёмная",
"dynamicThemeLabel": "Material You", "dynamicThemeLabel": "Material You",
"dynamicThemeHint": "Атрымлівайце асалоду досведу яшчэ бліжэй да сваё прылады", "dynamicThemeHint": "Атрымлівайце асалоду ад тэмы сваёй прылады",
"languageLabel": "Мова", "languageLabel": "Мова",
"languageUpdated": "Мова абноўлена", "languageUpdated": "Мова абноўлена",
"englishOption": "Англійская", "englishOption": "Англійская",
@ -180,8 +180,8 @@
"useAlternativeSources": "Выкарыстоўваць альтэрнатыўныя крыніцы", "useAlternativeSources": "Выкарыстоўваць альтэрнатыўныя крыніцы",
"useAlternativeSourcesHint": "Выкарыстоўваць альтэрнатыўныя крыніцы для ReVanced Patches і ReVanced Integrations замест API", "useAlternativeSourcesHint": "Выкарыстоўваць альтэрнатыўныя крыніцы для ReVanced Patches і ReVanced Integrations замест API",
"sourcesResetDialogTitle": "Скінуць", "sourcesResetDialogTitle": "Скінуць",
"sourcesResetDialogText": "Вы ўпэўнены, што хочаце скінуць свае крыніцы да іх прадвызначаных значэнняў?", "sourcesResetDialogText": "Вы сапраўды хочаце скінуць свае крыніцы да іх прадвызначаных значэнняў?",
"apiURLResetDialogText": "Вы ўпэўнены, што хочаце скінуць свае крыніцы да іх прадвызначаных значэнняў?", "apiURLResetDialogText": "Вы сапраўды хочаце скінуць свае API URL да іх прадвызначаных значэнняў?",
"sourcesUpdateNote": "Нататка: Гэта аўтаматычна спампуе ReVanced Patches і ReVanced Integrations з альтэрнатыўных крыніц.\n\nГэта падключыць вас да альтэрнатыўнай крыніцы.", "sourcesUpdateNote": "Нататка: Гэта аўтаматычна спампуе ReVanced Patches і ReVanced Integrations з альтэрнатыўных крыніц.\n\nГэта падключыць вас да альтэрнатыўнай крыніцы.",
"apiURLLabel": "API URL", "apiURLLabel": "API URL",
"apiURLHint": "Сканфігурыруйце URL API для ReVanced Manager", "apiURLHint": "Сканфігурыруйце URL API для ReVanced Manager",
@ -191,7 +191,7 @@
"orgIntegrationsLabel": "Арганізацыя інтэграцый", "orgIntegrationsLabel": "Арганізацыя інтэграцый",
"contributorsLabel": "Удзельнікі", "contributorsLabel": "Удзельнікі",
"contributorsHint": "Спіс усіх удзельнікаў праекта ReVanced", "contributorsHint": "Спіс усіх удзельнікаў праекта ReVanced",
"logsLabel": "Абагуліць журналы", "logsLabel": "Абагуліць журнал",
"logsHint": "Абагуліць журнал ReVanced Manager", "logsHint": "Абагуліць журнал ReVanced Manager",
"enablePatchesSelectionLabel": "Дазволіць змяненне выбару выпраўлення", "enablePatchesSelectionLabel": "Дазволіць змяненне выбару выпраўлення",
"enablePatchesSelectionHint": "Не прадухіляць выбар або скасаванне выбару выпраўленняў", "enablePatchesSelectionHint": "Не прадухіляць выбар або скасаванне выбару выпраўленняў",
@ -204,25 +204,25 @@
"universalPatchesLabel": "Паказваць універсальныя выпраўленні", "universalPatchesLabel": "Паказваць універсальныя выпраўленні",
"universalPatchesHint": "Адлюстраваць усе праграмы і ўніверсальныя выпраўленні (можа запаволіць спіс праграм)", "universalPatchesHint": "Адлюстраваць усе праграмы і ўніверсальныя выпраўленні (можа запаволіць спіс праграм)",
"versionCompatibilityCheckLabel": "Праверка сумяшчальнасці версіі", "versionCompatibilityCheckLabel": "Праверка сумяшчальнасці версіі",
"versionCompatibilityCheckHint": "Прадухіляць выбар выпраўленняў, якія не сумяшчальныя з выбранай версіяй праграмы", "versionCompatibilityCheckHint": "Прадухіляць выбар выпраўленняў, якія несумяшчальныя з выбранай версіяй праграмы",
"requireSuggestedAppVersionLabel": "Запыт прапанаванай версіі праграмы", "requireSuggestedAppVersionLabel": "Запыт прапанаванай версіі праграмы",
"requireSuggestedAppVersionHint": "Прадухіляць выбар праграмы з не прапанаванай версіяй", "requireSuggestedAppVersionHint": "Прадухіляць выбар праграмы з не прапанаванай версіяй",
"requireSuggestedAppVersionDialogText": "Выбар праграмы не прапанаванай версіі можа стаць прычынай нечаканых праблем.\n\nВы ўсё роўна хочаце працягнуць?", "requireSuggestedAppVersionDialogText": "Выбар праграмы не прапанаванай версіі можа стаць прычынай нечаканых праблем.\n\nВы ўсё роўна хочаце працягнуць?",
"aboutLabel": "Пра праграму", "aboutLabel": "Пра праграму",
"snackbarMessage": "Скапіравана ў буфер абмену", "snackbarMessage": "Скапіявана ў буфер абмену",
"restartAppForChanges": "Перазапусціце праграму, каб ужыць змены", "restartAppForChanges": "Перазапусціце праграму, каб ужыць змены",
"deleteTempDirLabel": "Выдаліць часовыя файлы", "deleteTempDirLabel": "Выдаліць часовыя файлы",
"deleteTempDirHint": "Выдаліць нявыкарыстаныя часовыя файлы", "deleteTempDirHint": "Выдаліць нявыкарыстаныя часовыя файлы",
"deletedTempDir": "Часовыя файлы выдалены", "deletedTempDir": "Часовыя файлы выдалены",
"exportPatchesLabel": "Экспартаваць выбар выпраўлення", "exportPatchesLabel": "Экспартаваць выбар выпраўленняў",
"exportPatchesHint": "Экспартаваць выбар выпраўленняў у файл JSON", "exportPatchesHint": "Экспартаваць выбар выпраўленняў у файл JSON",
"exportedPatches": "Выбар выпраўленняў экспартаваны", "exportedPatches": "Выбар выпраўленняў экспартаваны",
"noExportFileFound": "Адсутнічае выбар выпраўленняў для экспартавання", "noExportFileFound": "Адсутнічае выбар выпраўленняў для экспартавання",
"importPatchesLabel": "Імпартаваць выбар выпраўленняў", "importPatchesLabel": "Імпартаваць выбар выпраўленняў",
"importPatchesHint": "Імпартаваць выбар выпраўленняў у файл JSON", "importPatchesHint": "Імпартаваць выбар выпраўленняў у файл JSON",
"importedPatches": "Выбар выпраўленняў імпартаваны", "importedPatches": "Выбар выпраўленняў імпартаваны",
"resetStoredPatchesLabel": "Скінуць выбар выпраўленняў", "resetStoredPatchesLabel": "Скінуць выбар выпраўлення",
"resetStoredPatchesHint": "Скінуць захаванне выбару выпраўленняў", "resetStoredPatchesHint": "Скінуць захаванне выбару выпраўлення",
"resetStoredPatchesDialogTitle": "Скінуць выбар выпраўленняў?", "resetStoredPatchesDialogTitle": "Скінуць выбар выпраўленняў?",
"resetStoredPatchesDialogText": "Прадвызначаны выбар выпраўленняў будзе адноўлены.", "resetStoredPatchesDialogText": "Прадвызначаны выбар выпраўленняў будзе адноўлены.",
"resetStoredPatches": "Выбар выпраўленняў будзе скінуты", "resetStoredPatches": "Выбар выпраўленняў будзе скінуты",
@ -237,7 +237,7 @@
"regenerateKeystoreLabel": "Перагенерыраваць сховішча ключоў", "regenerateKeystoreLabel": "Перагенерыраваць сховішча ключоў",
"regenerateKeystoreHint": "Паўторна генерыраваць сховішча ключоў, якое выкарыстоўваецца для падпісання праграм", "regenerateKeystoreHint": "Паўторна генерыраваць сховішча ключоў, якое выкарыстоўваецца для падпісання праграм",
"regenerateKeystoreDialogTitle": "Паўторна генерыраваць сховішча ключоў?", "regenerateKeystoreDialogTitle": "Паўторна генерыраваць сховішча ключоў?",
"regenerateKeystoreDialogText": "Выпраўленыя праграмы, якія падпісаны старым сховішчам ключом, больш немагчыма будзе абнавіць.", "regenerateKeystoreDialogText": "Выпраўленыя праграмы, якія падпісаны старым сховішчам ключоў, больш немагчыма будзе абнавіць.",
"regeneratedKeystore": "Сховішча ключоў генерыравана паўторна", "regeneratedKeystore": "Сховішча ключоў генерыравана паўторна",
"exportKeystoreLabel": "Экспартаваць сховішча ключоў", "exportKeystoreLabel": "Экспартаваць сховішча ключоў",
"exportKeystoreHint": "Экспартаваць сховішча ключоў, якое выкарыстоўваецца для падпісання праграм", "exportKeystoreHint": "Экспартаваць сховішча ключоў, якое выкарыстоўваецца для падпісання праграм",
@ -245,7 +245,7 @@
"noKeystoreExportFileFound": "Адсутнічае сховішча ключоў для экспартавання", "noKeystoreExportFileFound": "Адсутнічае сховішча ключоў для экспартавання",
"importKeystoreLabel": "Імпартаваць сховішча ключоў", "importKeystoreLabel": "Імпартаваць сховішча ключоў",
"importKeystoreHint": "Імпартаваць сховішча ключоў, якое выкарыстоўваецца для падпісання праграм", "importKeystoreHint": "Імпартаваць сховішча ключоў, якое выкарыстоўваецца для падпісання праграм",
"importedKeystore": "Сховішча ключоў імпартаваны", "importedKeystore": "Сховішча ключоў імпартавана",
"selectKeystorePassword": "Пароль сховішча ключоў", "selectKeystorePassword": "Пароль сховішча ключоў",
"selectKeystorePasswordHint": "Выбраць пароль сховішча ключоў, які выкарыстоўваецца для падпісання праграм", "selectKeystorePasswordHint": "Выбраць пароль сховішча ключоў, які выкарыстоўваецца для падпісання праграм",
"jsonSelectorErrorMessage": "Немагчыма выкарыстоўваць выбраны файл JSON", "jsonSelectorErrorMessage": "Немагчыма выкарыстоўваць выбраны файл JSON",
@ -259,7 +259,7 @@
"rootDialogTitle": "Памылка", "rootDialogTitle": "Памылка",
"unmountDialogText": "Вы сапраўды хочаце адключыць гэту праграму?", "unmountDialogText": "Вы сапраўды хочаце адключыць гэту праграму?",
"uninstallDialogText": "Вы сапраўды хочаце выдаліць гэту праграму?", "uninstallDialogText": "Вы сапраўды хочаце выдаліць гэту праграму?",
"rootDialogText": "Праграма ўсталявана з правамі суперкарыстальніка, але ў цяперашні час у ReVanced Manager адсутнічаюць правы.\nСпачатку дайце праграме правы суперкарыстальніка.", "rootDialogText": "Праграма ўсталявана з правамі суперкарыстальніка, але ў цяперашні час у ReVanced Manager адсутнічаюць такія правы.\nСпачатку дайце праграме правы суперкарыстальніка.",
"packageNameLabel": "Назва пакета", "packageNameLabel": "Назва пакета",
"installTypeLabel": "Тып усталявання", "installTypeLabel": "Тып усталявання",
"mountTypeLabel": "Падключыць", "mountTypeLabel": "Падключыць",
@ -281,19 +281,19 @@
"installErrorDialog": { "installErrorDialog": {
"mount_version_mismatch": "Неадпаведнасць версій", "mount_version_mismatch": "Неадпаведнасць версій",
"mount_no_root": "Няма праў суперкарыстальніка", "mount_no_root": "Няма праў суперкарыстальніка",
"mount_missing_installation": "Усталёўка не знойдзена", "mount_missing_installation": "Усталяванне не знойдзена",
"status_failure_blocked": "Усталёўка заблакіравана", "status_failure_blocked": "Усталяванне заблакіравана",
"install_failed_verification_failure": "Збой праверкі", "install_failed_verification_failure": "Збой праверкі",
"status_failure_invalid": "Памылковая ўсталёўка", "status_failure_invalid": "Памылковае ўсталяванне",
"install_failed_version_downgrade": "Немагчыма панізіць", "install_failed_version_downgrade": "Немагчыма панізіць",
"status_failure_conflict": "Канфлікт усталявання", "status_failure_conflict": "Канфлікт усталявання",
"status_failure_storage": "Праблема са сховішчам устаноўкі", "status_failure_storage": "Праблема са сховішчам усталявання",
"status_failure_incompatible": "Несумяшчальнае ўсталяванне", "status_failure_incompatible": "Несумяшчальнае ўсталяванне",
"status_failure_timeout": "Час чакання ўсталявання", "status_failure_timeout": "Час чакання ўсталявання",
"status_unknown": "Збой усталявання", "status_unknown": "Збой усталявання",
"mount_version_mismatch_description": "Збой усталявання, бо версія ўсталяванай праграмы адрозніваецца ад версіі выпраўленай праграмы.", "mount_version_mismatch_description": "Збой усталявання, бо версія ўсталяванай праграмы адрозніваецца ад версіі выпраўленай праграмы.",
"mount_no_root_description": "Збой усталявання, бо не атрыманы правы суперкарыстальніка.\n\nДайце правы суперкарыстальніка ReVanced Manager і паспрабуйце яшчэ раз.", "mount_no_root_description": "Збой усталявання, бо не атрыманы правы суперкарыстальніка.\n\nДайце правы суперкарыстальніка ReVanced Manager і паспрабуйце яшчэ раз.",
"mount_missing_installation_description": "Збой усталявання, бо не выпраўленая праграма не ўсталявана на гэтай прыладзе для падключэння паверх яе.\n\nУсталюйце не выпраўленую праграму перад падключэннем і паспрабуйце яшчэ раз.", "mount_missing_installation_description": "Збой усталявання, бо спачатку неабходна ўсталяваць не выпраўленую праграму на гэту прыладу для падключэння паверх яе.\n\nУсталюйце не выпраўленую праграму перад падключэннем і паспрабуйце яшчэ раз.",
"status_failure_timeout_description": "Працэс усталявання адбываўся занадта доўга.\n\nВы сапраўды хочаце паспрабаваць яшчэ раз?", "status_failure_timeout_description": "Працэс усталявання адбываўся занадта доўга.\n\nВы сапраўды хочаце паспрабаваць яшчэ раз?",
"status_failure_storage_description": "Збой усталявання, бо на прыладзе недастаткова памяці.\n\nВызваліце крыху месца і паўтарыце спробу яшчэ раз.", "status_failure_storage_description": "Збой усталявання, бо на прыладзе недастаткова памяці.\n\nВызваліце крыху месца і паўтарыце спробу яшчэ раз.",
"status_failure_invalid_description": "Збой усталявання, бо выпраўленая праграма пашкоджана.\n\nВыдаліць праграму і паспрабаваць яшчэ раз?", "status_failure_invalid_description": "Збой усталявання, бо выпраўленая праграма пашкоджана.\n\nВыдаліць праграму і паспрабаваць яшчэ раз?",

View File

@ -67,12 +67,17 @@
"widgetTitle": "Penambal", "widgetTitle": "Penambal",
"patchButton": "Tambalan", "patchButton": "Tambalan",
"armv7WarningDialogText": "Menambal pada perangkat ARMv7 belum didukung dan mungkin gagal. Lanjutkan saja?", "armv7WarningDialogText": "Menambal pada perangkat ARMv7 belum didukung dan mungkin gagal. Lanjutkan saja?",
"removedPatchesWarningDialogText": "Patch berikut ini telah dihapus sejak terakhir kali Anda menggunakannya.\n\n${patches}\n\nTetap lanjutkan?",
"requiredOptionDialogText": "Beberapa opsi patch harus diatur." "requiredOptionDialogText": "Beberapa opsi patch harus diatur."
}, },
"appSelectorCard": { "appSelectorCard": {
"widgetTitle": "Pilih aplikasi",
"widgetTitleSelected": "Aplikasi yang dipilih",
"widgetSubtitle": "Tidak ada aplikasi yang dipilih",
"noAppsLabel": "Aplikasi tidak ditemukan", "noAppsLabel": "Aplikasi tidak ditemukan",
"currentVersion": "Saat ini", "currentVersion": "Saat ini",
"suggestedVersion": "Disarankan" "suggestedVersion": "Disarankan",
"anyVersion": "Versi apa saja"
}, },
"patchSelectorCard": { "patchSelectorCard": {
"widgetTitle": "Pilih tambalan", "widgetTitle": "Pilih tambalan",
@ -85,11 +90,15 @@
"widgetSubtitle": "Ikuti kami!" "widgetSubtitle": "Ikuti kami!"
}, },
"appSelectorView": { "appSelectorView": {
"viewTitle": "Pilih aplikasi",
"searchBarHint": "Cari aplikasi",
"storageButton": "Penyimpanan", "storageButton": "Penyimpanan",
"selectFromStorageButton": "Pilih dari penyimpanan", "selectFromStorageButton": "Pilih dari penyimpanan",
"errorMessage": "Tidak dapat menggunakan aplikasi yang dipilih", "errorMessage": "Tidak dapat menggunakan aplikasi yang dipilih",
"downloadToast": "Fungsi mengunduh belum tersedia", "downloadToast": "Fungsi mengunduh belum tersedia",
"featureNotAvailable": "Fitur tidak diterapkan" "requireSuggestedAppVersionDialogText": "Versi aplikasi yang Anda pilih tidak sesuai dengan versi yang disarankan yang dapat menyebabkan masalah yang tidak diharapkan. Silakan gunakan versi yang disarankan.\n\nVersi yang dipilih: ${selected}\nVersi yang disarankan: ${suggested}\n\nUntuk melanjutkan, nonaktifkan \"Memerlukan versi aplikasi yang disarankan\" di pengaturan.",
"featureNotAvailable": "Fitur tidak diterapkan",
"featureNotAvailableText": "Aplikasi ini adalah APK terpisah dan hanya dapat ditambal dan dipasang dengan andal dengan memasang dengan izin root. Namun, Anda bisa menambal dan memasang APK lengkap dengan memilihnya dari penyimpanan."
}, },
"patchesSelectorView": { "patchesSelectorView": {
"viewTitle": "Pilih tambalan", "viewTitle": "Pilih tambalan",
@ -98,16 +107,23 @@
"newPatches": "Patch baru", "newPatches": "Patch baru",
"patches": "Patch", "patches": "Patch",
"doneButton": "Selesai", "doneButton": "Selesai",
"defaultChip": "Bawaan",
"defaultTooltip": "Pilih semua tambalan bawaan", "defaultTooltip": "Pilih semua tambalan bawaan",
"noneChip": "Tidak ada",
"noneTooltip": "Batalkan semua tambalan", "noneTooltip": "Batalkan semua tambalan",
"loadPatchesSelection": "Muat patch terpilih", "loadPatchesSelection": "Muat patch terpilih",
"noPatchesFound": "Tidak ada tambalan untuk aplikasi" "noSavedPatches": "Tidak ada pilihan tambalan yang disimpan untuk aplikasi yang dipilih.\nTekan Selesai untuk menyimpan pilihan saat ini.",
"noPatchesFound": "Tidak ada tambalan untuk aplikasi",
"setRequiredOption": "Beberapa patch memerlukan opsi untuk diatur:\n\n${patches}\n\nAturlah sebelum melanjutkan."
}, },
"patchOptionsView": { "patchOptionsView": {
"customValue": "Nilai kustom", "customValue": "Nilai kustom",
"resetOptionsTooltip": "Mengatur ulang opsi tambalan",
"viewTitle": "Opsi tambalan",
"saveOptions": "Simpan", "saveOptions": "Simpan",
"addOptions": "Tambahkan opsi", "addOptions": "Tambahkan opsi",
"deselectPatch": "Lepas tambalan", "deselectPatch": "Lepas tambalan",
"tooltip": "Opsi masukan lainnya",
"selectFilePath": "Pilih lokasi berkas", "selectFilePath": "Pilih lokasi berkas",
"selectFolder": "Pilih folder", "selectFolder": "Pilih folder",
"selectOption": "Pilih opsi", "selectOption": "Pilih opsi",
@ -118,11 +134,14 @@
"patchItem": { "patchItem": {
"unsupportedDialogText": "Memilih tambalan ini akan menyebabkan galat tambal.\n\nVersi apli: ${packageVersion}\nVersi anjuran:\n${supportedVersions}", "unsupportedDialogText": "Memilih tambalan ini akan menyebabkan galat tambal.\n\nVersi apli: ${packageVersion}\nVersi anjuran:\n${supportedVersions}",
"unsupportedPatchVersion": "Tambalan ini tidak mendukung versi aplikasi ini.", "unsupportedPatchVersion": "Tambalan ini tidak mendukung versi aplikasi ini.",
"unsupportedRequiredOption": "Patch ini berisi opsi wajib yang tidak didukung oleh aplikasi ini",
"patchesChangeWarningDialogText": "Direkomendasikan untuk menggunakan pilihan dan opsi tambalan default. Mengubahnya dapat mengakibatkan masalah yang tidak diharapkan.\n\nAnda harus mengaktifkan \"Izinkan perubahan pilihan tambalan\" dalam pengaturan sebelum mengubah pilihan tambalan.",
"patchesChangeWarningDialogButton": "Gunakan pemilihan bawaan" "patchesChangeWarningDialogButton": "Gunakan pemilihan bawaan"
}, },
"installerView": { "installerView": {
"widgetTitle": "Pemasang", "widgetTitle": "Pemasang",
"installType": "Pilih tipe pemasang", "installType": "Pilih tipe pemasang",
"installTypeDescription": "Pilih jenis instalasi untuk melanjutkan.",
"installButton": "Pasang", "installButton": "Pasang",
"installRootType": "Mount", "installRootType": "Mount",
"installNonRootType": "Reguler", "installNonRootType": "Reguler",
@ -132,14 +151,20 @@
"shareButton": "Bagikan berkas", "shareButton": "Bagikan berkas",
"notificationTitle": "ReVanced Manager sedang menambal", "notificationTitle": "ReVanced Manager sedang menambal",
"notificationText": "Ketuk untuk kembali ke pemasang", "notificationText": "Ketuk untuk kembali ke pemasang",
"exportApkButtonTooltip": "Ekspor APK yang ditambal",
"exportLogButtonTooltip": "Log ekspor",
"screenshotDetected": "Tangkapan layar telah terdeteksi. Jika Anda mencoba membagikan log, silakan bagikan salinan teks.\n\nMenyalin log ke papan klip?",
"copiedToClipboard": "Menyalin log ke papan klip",
"noExit": "Pemasangan masih berjalan, tidak bisa keluar..." "noExit": "Pemasangan masih berjalan, tidak bisa keluar..."
}, },
"settingsView": { "settingsView": {
"widgetTitle": "Pengaturan", "widgetTitle": "Pengaturan",
"appearanceSectionTitle": "Tampilan", "appearanceSectionTitle": "Tampilan",
"teamSectionTitle": "Tim", "teamSectionTitle": "Tim",
"debugSectionTitle": "Debugging",
"advancedSectionTitle": "Lanjutan", "advancedSectionTitle": "Lanjutan",
"exportSectionTitle": "Impor & Ekspor", "exportSectionTitle": "Impor & Ekspor",
"dataSectionTitle": "Sumber data",
"themeModeLabel": "Tema aplikasi", "themeModeLabel": "Tema aplikasi",
"systemThemeLabel": "Sistem", "systemThemeLabel": "Sistem",
"lightThemeLabel": "Cahaya", "lightThemeLabel": "Cahaya",
@ -147,22 +172,34 @@
"dynamicThemeLabel": "Material You", "dynamicThemeLabel": "Material You",
"dynamicThemeHint": "Nikmati pengalaman lebih dekat ke perangkat Anda", "dynamicThemeHint": "Nikmati pengalaman lebih dekat ke perangkat Anda",
"languageLabel": "Bahasa", "languageLabel": "Bahasa",
"languageUpdated": "Bahasa diperbaharui",
"englishOption": "Bahasa Inggris", "englishOption": "Bahasa Inggris",
"sourcesLabel": "Sumber-sumber alternatif",
"sourcesLabelHint": "Mengonfigurasi sumber alternatif untuk ReVanced Patches dan ReVanced Integrations",
"sourcesIntegrationsLabel": "Sumber Integrasi", "sourcesIntegrationsLabel": "Sumber Integrasi",
"useAlternativeSources": "Gunakan sumber-sumber alternatif",
"useAlternativeSourcesHint": "Gunakan sumber alternatif untuk ReVanced Patches dan ReVanced Integrations alih-alih API",
"sourcesResetDialogTitle": "Atur ulang", "sourcesResetDialogTitle": "Atur ulang",
"sourcesResetDialogText": "Apakah Anda yakin ingin mengatur ulang sumber kustom ke bawaannya?", "sourcesResetDialogText": "Apakah Anda yakin ingin mengatur ulang sumber kustom ke bawaannya?",
"apiURLResetDialogText": "Apakah Anda yakin ingin mengatur ulang URL API ke bawaan?", "apiURLResetDialogText": "Apakah Anda yakin ingin mengatur ulang URL API ke bawaan?",
"sourcesUpdateNote": "Catatan: Ini akan secara otomatis mengunduh ReVanced Patches dan ReVanced Integrations dari sumber alternatif.\n\nIni akan menghubungkan Anda ke sumber alternatif.",
"apiURLLabel": "URL API", "apiURLLabel": "URL API",
"apiURLHint": "Konfigurasikan URL API dari ReVanced Manager",
"selectApiURL": "URL API", "selectApiURL": "URL API",
"orgPatchesLabel": "Perapihan tambalan", "orgPatchesLabel": "Perapihan tambalan",
"sourcesPatchesLabel": "Sumber tambalan", "sourcesPatchesLabel": "Sumber tambalan",
"orgIntegrationsLabel": "Organisasi Intergrasi", "orgIntegrationsLabel": "Organisasi Intergrasi",
"contributorsLabel": "Kontributor", "contributorsLabel": "Kontributor",
"contributorsHint": "Daftar kontributor ReVanced", "contributorsHint": "Daftar kontributor ReVanced",
"logsLabel": "Bagikan log",
"logsHint": "Bagikan log ReVanced Manager", "logsHint": "Bagikan log ReVanced Manager",
"enablePatchesSelectionLabel": "Izinkan mengubah pemilihan tambalan",
"enablePatchesSelectionHint": "Jangan mencegah pemilihan atau pembatalan pemilihan tambalan",
"enablePatchesSelectionWarningText": "Mengubah pilihan dari tambalan akan menyebabkan isu tak terduga.\n\nAktifkan saja?", "enablePatchesSelectionWarningText": "Mengubah pilihan dari tambalan akan menyebabkan isu tak terduga.\n\nAktifkan saja?",
"disablePatchesSelectionWarningText": "Anda akan menonaktifkan pengubahan pilihan tambalan.\nPilihan tambalan default akan dikembalikan.\n\nMenonaktifkan?",
"autoUpdatePatchesLabel": "Otomatis perbarui tambalan", "autoUpdatePatchesLabel": "Otomatis perbarui tambalan",
"autoUpdatePatchesHint": "Otomatis perbarui tambalan ke versi terkini", "autoUpdatePatchesHint": "Otomatis perbarui tambalan ke versi terkini",
"showUpdateDialogLabel": "Tampilkan dialog pembaruan",
"universalPatchesLabel": "Tampilkan tambalan universal", "universalPatchesLabel": "Tampilkan tambalan universal",
"versionCompatibilityCheckLabel": "Periksa versi kompatibilitas", "versionCompatibilityCheckLabel": "Periksa versi kompatibilitas",
"aboutLabel": "Tentang", "aboutLabel": "Tentang",

View File

@ -27,11 +27,11 @@
"refreshSuccess": "새로고침을 성공했습니다.", "refreshSuccess": "새로고침을 성공했습니다.",
"widgetTitle": "대시보드", "widgetTitle": "대시보드",
"updatesSubtitle": "업데이트", "updatesSubtitle": "업데이트",
"patchedSubtitle": "패치한 앱", "patchedSubtitle": "설치된 앱",
"changeLaterSubtitle": "나중에 설정에서 바꿀 수 있습니다.", "changeLaterSubtitle": "나중에 설정에서 바꿀 수 있습니다.",
"noUpdates": "새 업데이트가 없습니다.", "noUpdates": "새 업데이트가 없습니다.",
"WIP": "개발 중 입니다...", "WIP": "개발 중 입니다...",
"noInstallations": "패치한 앱이 설치되지 않았습니다.", "noInstallations": "아직 설치된 ReVanced 앱이 없습니다.",
"installUpdate": "업데이트를 계속 설치하겠습니까?", "installUpdate": "업데이트를 계속 설치하겠습니까?",
"updateSheetTitle": "ReVanced Manager 업데이트", "updateSheetTitle": "ReVanced Manager 업데이트",
"updateDialogTitle": "새 업데이트가 있습니다.", "updateDialogTitle": "새 업데이트가 있습니다.",
@ -175,14 +175,14 @@
"languageUpdated": "앱 언어를 변경했습니다.", "languageUpdated": "앱 언어를 변경했습니다.",
"englishOption": "영어", "englishOption": "영어",
"sourcesLabel": "대체 소스", "sourcesLabel": "대체 소스",
"sourcesLabelHint": "ReVanced Patches 및 ReVanced Integrations을 위한 대체 소스를 설정할 수 있습니다.", "sourcesLabelHint": "ReVanced Patches 및 ReVanced Integrations 대체 소스를 설정할 수 있습니다.",
"sourcesIntegrationsLabel": "Integrations 소스", "sourcesIntegrationsLabel": "Integrations 소스",
"useAlternativeSources": "대체 소스 사용", "useAlternativeSources": "대체 소스 사용",
"useAlternativeSourcesHint": "API를 대신하여 ReVanced Patches 및 ReVanced Integrations를 위한 대체 소스를 사용합니다.", "useAlternativeSourcesHint": "공식 소스가 아닌 ReVanced Patches 및 ReVanced Integrations 대체 소스를 사용합니다.",
"sourcesResetDialogTitle": "초기화", "sourcesResetDialogTitle": "초기화",
"sourcesResetDialogText": "정말 커스텀 소스를 기본값으로 되돌릴까요?", "sourcesResetDialogText": "정말 커스텀 소스를 기본값으로 되돌릴까요?",
"apiURLResetDialogText": "정말 API URL을 기본값으로 되돌릴까요?", "apiURLResetDialogText": "정말 API URL을 기본값으로 되돌릴까요?",
"sourcesUpdateNote": "알림: 이렇게 하면 대체 소스에서 ReVanced Patches 및 ReVanced Integrations이 자동으로 다운로드됩니다. \n\n그러면 대체 소스로 연결됩니다.", "sourcesUpdateNote": "알림: 변경하면 대체 소스에서 ReVanced Patches 및 ReVanced Integrations이 자동으로 다운로드됩니다. \n\n그 이후에는 대체 소스로 연결됩니다.",
"apiURLLabel": "API URL", "apiURLLabel": "API URL",
"apiURLHint": "ReVanced Manager의 API URL를 설정할 수 있습니다.", "apiURLHint": "ReVanced Manager의 API URL를 설정할 수 있습니다.",
"selectApiURL": "API URL", "selectApiURL": "API URL",
@ -242,7 +242,7 @@
"exportKeystoreLabel": "키스토어 내보내기", "exportKeystoreLabel": "키스토어 내보내기",
"exportKeystoreHint": "앱을 서명할 때 사용한 키스토어를 내보냅니다.", "exportKeystoreHint": "앱을 서명할 때 사용한 키스토어를 내보냅니다.",
"exportedKeystore": "키스토어 내보냄", "exportedKeystore": "키스토어 내보냄",
"noKeystoreExportFileFound": "내보낼 키스토어가 없", "noKeystoreExportFileFound": "내보낼 키스토어가 없습니다.",
"importKeystoreLabel": "키스토어 가져오기", "importKeystoreLabel": "키스토어 가져오기",
"importKeystoreHint": "앱을 서명할 때 사용한 키스토어를 가져옵니다.", "importKeystoreHint": "앱을 서명할 때 사용한 키스토어를 가져옵니다.",
"importedKeystore": "키스토어 가져옴", "importedKeystore": "키스토어 가져옴",
@ -280,11 +280,11 @@
}, },
"installErrorDialog": { "installErrorDialog": {
"mount_version_mismatch": "버전 불일치", "mount_version_mismatch": "버전 불일치",
"mount_no_root": "루트 권한 없음", "mount_no_root": "Root 권한이 없습니다.",
"mount_missing_installation": "설치 대상을 찾을 수 없", "mount_missing_installation": "설치 대상을 찾을 수 없습니다.",
"status_failure_blocked": "설치 차단됨", "status_failure_blocked": "설치 차단됨",
"install_failed_verification_failure": "인증 실패", "install_failed_verification_failure": "인증 실패",
"status_failure_invalid": "설치가 유효하지 않", "status_failure_invalid": "설치가 유효하지 않습니다.",
"install_failed_version_downgrade": "다운그레이드 불가능", "install_failed_version_downgrade": "다운그레이드 불가능",
"status_failure_conflict": "설치 충돌됨", "status_failure_conflict": "설치 충돌됨",
"status_failure_storage": "설치 저장공간 문제", "status_failure_storage": "설치 저장공간 문제",
@ -292,7 +292,7 @@
"status_failure_timeout": "설치 시간 초과", "status_failure_timeout": "설치 시간 초과",
"status_unknown": "설치 실패", "status_unknown": "설치 실패",
"mount_version_mismatch_description": "패치한 앱과 설치된 앱의 버전이 달라 설치에 실패했습니다.\n\n마운트하고 있는 앱의 버전으로 설치한 뒤 다시 시도하세요.", "mount_version_mismatch_description": "패치한 앱과 설치된 앱의 버전이 달라 설치에 실패했습니다.\n\n마운트하고 있는 앱의 버전으로 설치한 뒤 다시 시도하세요.",
"mount_no_root_description": "루트 권한이 주어지지 않아 설치에 실패했습니다.\n\nReVanced Manager에 루트 권한을 부여한 뒤 다시 시도하세요.", "mount_no_root_description": "Root 권한이 주어지지 않아 설치에 실패했습니다.\n\nReVanced Manager에 Root 권한을 부여한 뒤 다시 시도하세요.",
"mount_missing_installation_description": "패치되지 않은 앱이 이 기기에 설치되지 않아서 마운트를 진행할 수 없어 설치에 실패했습니다.\n\n마운트하기 전 패치되지 않은 앱을 설치한 뒤 다시 시도하세요.", "mount_missing_installation_description": "패치되지 않은 앱이 이 기기에 설치되지 않아서 마운트를 진행할 수 없어 설치에 실패했습니다.\n\n마운트하기 전 패치되지 않은 앱을 설치한 뒤 다시 시도하세요.",
"status_failure_timeout_description": "설치하는 데 시간이 너무 오래 걸립니다.\n\n다시 시도할까요?", "status_failure_timeout_description": "설치하는 데 시간이 너무 오래 걸립니다.\n\n다시 시도할까요?",
"status_failure_storage_description": "저장공간이 충분하지 않아 설치에 실패했습니다.\n\n저장공간을 확보한 뒤 다시 시도하세요.", "status_failure_storage_description": "저장공간이 충분하지 않아 설치에 실패했습니다.\n\n저장공간을 확보한 뒤 다시 시도하세요.",

View File

@ -16,6 +16,8 @@
"noShowAgain": "Не показывать снова", "noShowAgain": "Не показывать снова",
"add": "Добавить", "add": "Добавить",
"remove": "Удалить", "remove": "Удалить",
"showChangelogButton": "Показать список изменений",
"showUpdateButton": "Показать обновление",
"navigationView": { "navigationView": {
"dashboardTab": "Панель инструментов", "dashboardTab": "Панель инструментов",
"patcherTab": "Патчер", "patcherTab": "Патчер",
@ -26,14 +28,25 @@
"widgetTitle": "Панель инструментов", "widgetTitle": "Панель инструментов",
"updatesSubtitle": "Обновления", "updatesSubtitle": "Обновления",
"patchedSubtitle": "Пропатченные приложения", "patchedSubtitle": "Пропатченные приложения",
"changeLaterSubtitle": "Вы можете изменить это в настройках позже.",
"noUpdates": "Нет доступных обновлений", "noUpdates": "Нет доступных обновлений",
"WIP": "В процессе...", "WIP": "В процессе...",
"noInstallations": "Пропатченные приложения не установлены", "noInstallations": "Пропатченные приложения не установлены",
"installUpdate": "Продолжить установку обновления?", "installUpdate": "Продолжить установку обновления?",
"updateSheetTitle": "Обновить Revanced Менеджер",
"updateDialogTitle": "Доступно обновление",
"updatePatchesSheetTitle": "Обновить патчи ReVanced",
"updateChangelogTitle": "Список изменений", "updateChangelogTitle": "Список изменений",
"updateDialogText": "Доступно обновление для ${file}.\n\nТекущая установленная версия ${version}.",
"downloadConsentDialogTitle": "Скачать необходимые файлы?",
"downloadConsentDialogText": "Для правильной работы ReVanced Менеджера нужно загрузить необходимые файлы.",
"downloadConsentDialogText2": "Это соединит вас с ${url}.",
"checkUpdateDialogTitle": "Проверить наличие обновлений?",
"checkUpdateDialogText": "Хотите, чтобы ReVanced Менеджер автоматически проверял наличие обновлений?",
"notificationTitle": "Обновление загружено", "notificationTitle": "Обновление загружено",
"notificationText": "Нажмите, чтобы установить обновление", "notificationText": "Нажмите, чтобы установить обновление",
"downloadingMessage": "Загрузка обновления...", "downloadingMessage": "Загрузка обновления...",
"downloadedMessage": "Обновление загружено",
"installingMessage": "Установка обновления...", "installingMessage": "Установка обновления...",
"errorDownloadMessage": "Не удалось загрузить обновление", "errorDownloadMessage": "Не удалось загрузить обновление",
"errorInstallMessage": "Не удалось установить обновление", "errorInstallMessage": "Не удалось установить обновление",
@ -53,12 +66,18 @@
"patcherView": { "patcherView": {
"widgetTitle": "Патчер", "widgetTitle": "Патчер",
"patchButton": "Патч", "patchButton": "Патч",
"armv7WarningDialogText": "Патчинг на устройствах ARMv7 пока не поддерживается и может привести к сбоям. Все равно продолжить?",
"removedPatchesWarningDialogText": "Следующие патчи были удалены с момента их последнего использования.\n\n ${patches}\n\n Все равно продолжить?",
"requiredOptionDialogText": "Некоторые параметры патчей должны быть обязательно установлены." "requiredOptionDialogText": "Некоторые параметры патчей должны быть обязательно установлены."
}, },
"appSelectorCard": { "appSelectorCard": {
"widgetTitle": "Выбрать приложение",
"widgetTitleSelected": "Выбранное приложение",
"widgetSubtitle": "Приложение не выбрано",
"noAppsLabel": "Приложения не найдены", "noAppsLabel": "Приложения не найдены",
"currentVersion": "Текущая", "currentVersion": "Текущая",
"suggestedVersion": "Предложенная" "suggestedVersion": "Предложенная",
"anyVersion": "Любая версия"
}, },
"patchSelectorCard": { "patchSelectorCard": {
"widgetTitle": "Выбор патчей", "widgetTitle": "Выбор патчей",
@ -71,11 +90,15 @@
"widgetSubtitle": "Мы онлайн!" "widgetSubtitle": "Мы онлайн!"
}, },
"appSelectorView": { "appSelectorView": {
"viewTitle": "Выбрать приложение",
"searchBarHint": "Поиск приложения",
"storageButton": "Хранилище", "storageButton": "Хранилище",
"selectFromStorageButton": "Выбрать из хранилища", "selectFromStorageButton": "Выбрать из хранилища",
"errorMessage": "Невозможно использовать выбранное приложение", "errorMessage": "Невозможно использовать выбранное приложение",
"downloadToast": "Функция загрузки пока недоступна", "downloadToast": "Функция загрузки пока недоступна",
"featureNotAvailable": "Функция не реализована" "requireSuggestedAppVersionDialogText": "Выбранная Вами версия приложения не соответствует предлагаемой, что может привести к непредвиденным проблемам. Пожалуйста, используйте предложенную версию.\n\n Выбранная версия: ${selected}\n Предлагаемая версия: ${suggested}.\n\nЧтобы продолжить, отключите в настройках параметр «Требовать рекомендуемую версию приложения».",
"featureNotAvailable": "Функция не реализована",
"featureNotAvailableText": "Это приложение представляет собой разделенный APK-файл, и его можно пропатчить и корректно установить только путем монтирования с правами root. Однако Вы можете пропатчить и установить полный APK-файл, выбрав его из хранилища."
}, },
"patchesSelectorView": { "patchesSelectorView": {
"viewTitle": "Выбор патчей", "viewTitle": "Выбор патчей",
@ -84,7 +107,9 @@
"newPatches": "Новые патчи", "newPatches": "Новые патчи",
"patches": "Патчи", "patches": "Патчи",
"doneButton": "Готово", "doneButton": "Готово",
"defaultChip": "По умолчанию",
"defaultTooltip": "Выбрать все стандартные патчи", "defaultTooltip": "Выбрать все стандартные патчи",
"noneChip": "Никакие",
"noneTooltip": "Снять выбор всех патчей", "noneTooltip": "Снять выбор всех патчей",
"loadPatchesSelection": "Загрузка выборки патчей", "loadPatchesSelection": "Загрузка выборки патчей",
"noSavedPatches": "Нет сохраненной выборки патчей для выбранного приложения.\nНажмите \"Готово\" для сохранения текущего выбора.", "noSavedPatches": "Нет сохраненной выборки патчей для выбранного приложения.\nНажмите \"Готово\" для сохранения текущего выбора.",
@ -110,11 +135,13 @@
"unsupportedDialogText": "Выбор этого патча может привести к ошибкам во время патчинга.\n\nВерсия приложения: ${packageVersion}\nПоддерживаемые версии:\n${supportedVersions}", "unsupportedDialogText": "Выбор этого патча может привести к ошибкам во время патчинга.\n\nВерсия приложения: ${packageVersion}\nПоддерживаемые версии:\n${supportedVersions}",
"unsupportedPatchVersion": "Патч не поддерживается этой версией приложения.", "unsupportedPatchVersion": "Патч не поддерживается этой версией приложения.",
"unsupportedRequiredOption": "Этот патч содержит обязательную опцию, не поддерживаемую этим приложением", "unsupportedRequiredOption": "Этот патч содержит обязательную опцию, не поддерживаемую этим приложением",
"patchesChangeWarningDialogText": "Рекомендуется использовать выборку патчей и параметры по умолчанию. Их изменение может привести к неожиданным проблемам.\n\n Вам необходимо включить «Разрешить изменение выборки патчей» в настройках, прежде чем изменять какие-либо выборки патчей.",
"patchesChangeWarningDialogButton": "Использовать стандартный набор" "patchesChangeWarningDialogButton": "Использовать стандартный набор"
}, },
"installerView": { "installerView": {
"widgetTitle": "Установщик", "widgetTitle": "Установщик",
"installType": "Выберите тип установки", "installType": "Выберите тип установки",
"installTypeDescription": "Выберите тип установки, чтобы продолжить.",
"installButton": "Установить", "installButton": "Установить",
"installRootType": "Монтировать", "installRootType": "Монтировать",
"installNonRootType": "Обычный", "installNonRootType": "Обычный",
@ -137,6 +164,7 @@
"debugSectionTitle": "Отладка", "debugSectionTitle": "Отладка",
"advancedSectionTitle": "Дополнительные", "advancedSectionTitle": "Дополнительные",
"exportSectionTitle": "Импорт и экспорт", "exportSectionTitle": "Импорт и экспорт",
"dataSectionTitle": "Источники данных",
"themeModeLabel": "Тема приложения", "themeModeLabel": "Тема приложения",
"systemThemeLabel": "Системная", "systemThemeLabel": "Системная",
"lightThemeLabel": "Светлая", "lightThemeLabel": "Светлая",
@ -144,12 +172,19 @@
"dynamicThemeLabel": "Material You", "dynamicThemeLabel": "Material You",
"dynamicThemeHint": "Наслаждайтесь темой Вашего устройства", "dynamicThemeHint": "Наслаждайтесь темой Вашего устройства",
"languageLabel": "Язык", "languageLabel": "Язык",
"languageUpdated": "Язык обновлен",
"englishOption": "Английский", "englishOption": "Английский",
"sourcesLabel": "Альтернативные источники",
"sourcesLabelHint": "Настройте альтернативные источники для патчей и интеграций ReVanced",
"sourcesIntegrationsLabel": "Репозиторий интеграций", "sourcesIntegrationsLabel": "Репозиторий интеграций",
"useAlternativeSources": "Использовать альтернативные источники",
"useAlternativeSourcesHint": "Использовать альтернативные источники для патчей и интеграций ReVanced вместо API",
"sourcesResetDialogTitle": "Сброс", "sourcesResetDialogTitle": "Сброс",
"sourcesResetDialogText": "Вы уверены, что хотите сбросить ваши источники до значений по умолчанию?", "sourcesResetDialogText": "Вы уверены, что хотите сбросить ваши источники до значений по умолчанию?",
"apiURLResetDialogText": "Вы уверены, что хотите сбросить API-ссылку до значения по умолчанию?", "apiURLResetDialogText": "Вы уверены, что хотите сбросить API-ссылку до значения по умолчанию?",
"sourcesUpdateNote": "Примечание: при этом будут автоматически загружены патчи и интеграции ReVanced из альтернативных источников.\n\nЭто соединит вас с альтернативным источником.",
"apiURLLabel": "API-ссылка", "apiURLLabel": "API-ссылка",
"apiURLHint": "Настройте URL-адрес API ReVanced Менеджера",
"selectApiURL": "API-ссылка", "selectApiURL": "API-ссылка",
"orgPatchesLabel": "Организация патчей", "orgPatchesLabel": "Организация патчей",
"sourcesPatchesLabel": "Репозиторий патчей", "sourcesPatchesLabel": "Репозиторий патчей",
@ -164,6 +199,8 @@
"disablePatchesSelectionWarningText": "Вы собираетесь выключить измененную выборку патчей.\nБудет восстановлен стандартный выбор патчей.\n\nВсе равно выключить?", "disablePatchesSelectionWarningText": "Вы собираетесь выключить измененную выборку патчей.\nБудет восстановлен стандартный выбор патчей.\n\nВсе равно выключить?",
"autoUpdatePatchesLabel": "Автообновление патчей", "autoUpdatePatchesLabel": "Автообновление патчей",
"autoUpdatePatchesHint": "Автоматически обновлять патчи до последней версии", "autoUpdatePatchesHint": "Автоматически обновлять патчи до последней версии",
"showUpdateDialogLabel": "Показать диалог обновления",
"showUpdateDialogHint": "Показывать диалоговое окно, когда доступно новое обновление",
"universalPatchesLabel": "Показать универсальные патчи", "universalPatchesLabel": "Показать универсальные патчи",
"universalPatchesHint": "Отобразить все приложения и универсальные патчи (может замедлить список отображения приложений)", "universalPatchesHint": "Отобразить все приложения и универсальные патчи (может замедлить список отображения приложений)",
"versionCompatibilityCheckLabel": "Проверка совместимости версий", "versionCompatibilityCheckLabel": "Проверка совместимости версий",
@ -234,7 +271,12 @@
"updateNotImplemented": "Эта возможность ещё не реализована" "updateNotImplemented": "Эта возможность ещё не реализована"
}, },
"contributorsView": { "contributorsView": {
"widgetTitle": "Соучастники проекта" "widgetTitle": "Соучастники проекта",
"patcherContributors": "ReVanced патчер",
"patchesContributors": "ReVanced патчи",
"integrationsContributors": "Интеграции ReVanced",
"cliContributors": "ReVanced CLI",
"managerContributors": "ReVanced Менеджер"
}, },
"installErrorDialog": { "installErrorDialog": {
"mount_version_mismatch": "Несовпадение версий", "mount_version_mismatch": "Несовпадение версий",

View File

@ -35,7 +35,7 @@
"installUpdate": "Güncelleme yüklensin mi?", "installUpdate": "Güncelleme yüklensin mi?",
"updateSheetTitle": "ReVanced Manager'ı güncelle", "updateSheetTitle": "ReVanced Manager'ı güncelle",
"updateDialogTitle": "Yeni güncelleme mevcut", "updateDialogTitle": "Yeni güncelleme mevcut",
"updatePatchesSheetTitle": "ReVanced Yamaları'nı güncelle", "updatePatchesSheetTitle": "ReVanced Patches'ı güncelle",
"updateChangelogTitle": "Değişiklikler", "updateChangelogTitle": "Değişiklikler",
"updateDialogText": "${file} için yeni bir güncelleme mevcut.\n\nŞu anda kurulu olan sürüm: ${version}.", "updateDialogText": "${file} için yeni bir güncelleme mevcut.\n\nŞu anda kurulu olan sürüm: ${version}.",
"downloadConsentDialogTitle": "Gerekli dosyalar indirilsin mi?", "downloadConsentDialogTitle": "Gerekli dosyalar indirilsin mi?",
@ -96,9 +96,9 @@
"selectFromStorageButton": "Depolama alanından seçin", "selectFromStorageButton": "Depolama alanından seçin",
"errorMessage": "Seçilen uygulama kullanılamıyor", "errorMessage": "Seçilen uygulama kullanılamıyor",
"downloadToast": "İndirme özelliği henüz kullanılamıyor", "downloadToast": "İndirme özelliği henüz kullanılamıyor",
"requireSuggestedAppVersionDialogText": "Seçtiğiniz uygulamanın sürümü, önerilen sürümle eşleşmiyor. Lütfen önerilen sürümle eşleşen sürümünü seçin.\n\nSeçilen sürüm: v${selected}\nÖnerilen sürüm: v${suggested}\n\nYine de devam etmek istiyorsanız, ayarlardan \"Önerilen uygulama sürümünü zorunlu kıl\" seçeneğini devre dışı bırakın.", "requireSuggestedAppVersionDialogText": "Seçtiğiniz uygulamanın sürümü, önerilen sürümle eşleşmiyor ve bu durum beklenmeyen sorunlara yol açabilir. Lütfen önerilen sürümü kullanın.\n\nSeçilen sürüm: ${selected}\nÖnerilen sürüm: ${suggested}\n\nYine de devam etmek istiyorsanız, ayarlarda \"Önerilen uygulama sürümünü zorunlu kıl\" seçeneğini devre dışı bırakın.",
"featureNotAvailable": "Özellik henüz etkin değil", "featureNotAvailable": "Özellik henüz etkin değil",
"featureNotAvailableText": "Bu uygulama bir bölünmüş APK ve yalnızca root izinleriyle eksiksizce yamalanıp yüklenebilir. Tam APK'yı depolamadan seçerek yamalayabilir ve yükleyebilirsiniz." "featureNotAvailableText": "Bu uygulama bir split APK'dır ve yalnızca root izinleriyle yamalanıp, mount yöntemiyle kurulabilir. Yine de, bir tam APK'yı depolamadan seçerek yamalayabilir ve kurabilirsiniz."
}, },
"patchesSelectorView": { "patchesSelectorView": {
"viewTitle": "Yamaları seçin", "viewTitle": "Yamaları seçin",
@ -135,7 +135,7 @@
"unsupportedDialogText": "Bu yamayı seçmek yamalama hatalarına sebep olabilir.\n\nUygulama sürümü: ${packageVersion}\nDesteklenen sürümler:\n${supportedVersions}", "unsupportedDialogText": "Bu yamayı seçmek yamalama hatalarına sebep olabilir.\n\nUygulama sürümü: ${packageVersion}\nDesteklenen sürümler:\n${supportedVersions}",
"unsupportedPatchVersion": "Yama, uygulamanın bu sürümü için desteklenmiyor.", "unsupportedPatchVersion": "Yama, uygulamanın bu sürümü için desteklenmiyor.",
"unsupportedRequiredOption": "Bu yama, bu uygulama tarafından desteklenmeyen fakat gerekli olan bir seçenek içeriyor", "unsupportedRequiredOption": "Bu yama, bu uygulama tarafından desteklenmeyen fakat gerekli olan bir seçenek içeriyor",
"patchesChangeWarningDialogText": "Varsayılan yama seçeneklerini kullanmanız önerilir. Bunları değiştirmek beklenmedik sorunlara yol açabilir.\n\nHerhangi bir yama seçimini değiştirmeden önce ayarlarda \"Yama seçimini değiştirmeye izin ver\" seçeneğini açmanız gerekir.", "patchesChangeWarningDialogText": "Varsayılan yama seçimini ve seçeneklerini kullanmanız önerilir. Bunları değiştirmek beklenmedik sorunlara yol açabilir.\n\nHerhangi bir yama seçimini değiştirmeden önce ayarlarda \"Yama seçimini değiştirmeye izin ver\" seçeneğini açmanız gerekir.",
"patchesChangeWarningDialogButton": "Varsayılan seçimi kullan" "patchesChangeWarningDialogButton": "Varsayılan seçimi kullan"
}, },
"installerView": { "installerView": {
@ -175,24 +175,24 @@
"languageUpdated": "Dil güncellendi", "languageUpdated": "Dil güncellendi",
"englishOption": "İngilizce", "englishOption": "İngilizce",
"sourcesLabel": "Alternatif kaynaklar", "sourcesLabel": "Alternatif kaynaklar",
"sourcesLabelHint": "ReVanced Yamaları ve ReVanced Entegrasyonları için alternatif kaynakları yapılandırın", "sourcesLabelHint": "ReVanced Patches ve ReVanced Integrations için alternatif kaynakları ayarlayın",
"sourcesIntegrationsLabel": "Integrations kaynağı", "sourcesIntegrationsLabel": "Integrations source",
"useAlternativeSources": "Alternatif kaynakları kullan", "useAlternativeSources": "Alternatif kaynakları kullan",
"useAlternativeSourcesHint": "ReVanced Yamaları ve ReVanced Entegrasyonları için API yerine alternatif kaynakları kullan", "useAlternativeSourcesHint": "ReVanced Patches ve ReVanced Integrations için API yerine alternatif kaynakları kullanın",
"sourcesResetDialogTitle": "Sıfırla", "sourcesResetDialogTitle": "Sıfırla",
"sourcesResetDialogText": "Kaynaklarınızı varsayılan değerlerine sıfırlamak istediğinizden emin misiniz?", "sourcesResetDialogText": "Kaynaklarınızı varsayılan değerlerine sıfırlamak istediğinizden emin misiniz?",
"apiURLResetDialogText": "API URL'nizi varsayılan değerine sıfırlamak istediğinizden emin misiniz?", "apiURLResetDialogText": "API URL'nizi varsayılan değerine sıfırlamak istediğinizden emin misiniz?",
"sourcesUpdateNote": "Not: Bu, ReVanced Yamalarını ve ReVanced Entegrasyonlarını otomatik olarak alternatif kaynaklardan indirecek.\n\nBu sizi alternatif kaynağa bağlayacaktır.", "sourcesUpdateNote": "Not: Bu, ReVanced Patches'ı ve ReVanced Integrations'ı otomatik olarak alternatif kaynaklardan indirecektir.\n\nBu sizi alternatif kaynağa bağlayacaktır.",
"apiURLLabel": "API URL'si", "apiURLLabel": "API URL'si",
"apiURLHint": "ReVanced Manager'in API URL'sini yapılandırın", "apiURLHint": "ReVanced Manager'in API URL'sini ayarlayın",
"selectApiURL": "API URL'si", "selectApiURL": "API URL'si",
"orgPatchesLabel": "Yama organizasyonu", "orgPatchesLabel": "Patches organization",
"sourcesPatchesLabel": "Yama kaynağı", "sourcesPatchesLabel": "Patches source",
"orgIntegrationsLabel": "Integrations organizasyonu", "orgIntegrationsLabel": "Integrations organization",
"contributorsLabel": "Katkıda bulunanlar", "contributorsLabel": "Katkıda bulunanlar",
"contributorsHint": "ReVanced'a katkıda bulunanların listesi", "contributorsHint": "ReVanced'a katkıda bulunanların listesi",
"logsLabel": "Logları paylaş", "logsLabel": "Logları paylaş",
"logsHint": "ReVanced Manager loglarını paylaş", "logsHint": "ReVanced Manager loglarını paylaşın",
"enablePatchesSelectionLabel": "Yama seçimini değiştirmeye izin ver", "enablePatchesSelectionLabel": "Yama seçimini değiştirmeye izin ver",
"enablePatchesSelectionHint": "Yamaların seçilmesini veya seçiminin kaldırılmasını engelleme", "enablePatchesSelectionHint": "Yamaların seçilmesini veya seçiminin kaldırılmasını engelleme",
"enablePatchesSelectionWarningText": "Yama seçimini değiştirmek beklenmedik sorunlara yol açabilir.\n\nYine de etkinleştirilsin mi?", "enablePatchesSelectionWarningText": "Yama seçimini değiştirmek beklenmedik sorunlara yol açabilir.\n\nYine de etkinleştirilsin mi?",
@ -212,27 +212,27 @@
"snackbarMessage": "Panoya kopyalandı", "snackbarMessage": "Panoya kopyalandı",
"restartAppForChanges": "Değişiklikleri uygulamak için uygulamayı yeniden başlatın", "restartAppForChanges": "Değişiklikleri uygulamak için uygulamayı yeniden başlatın",
"deleteTempDirLabel": "Geçici dosyaları sil", "deleteTempDirLabel": "Geçici dosyaları sil",
"deleteTempDirHint": "Kullanılmayan geçici dosyaları sil", "deleteTempDirHint": "Kullanılmayan geçici dosyaları silin",
"deletedTempDir": "Geçici dosyalar silindi", "deletedTempDir": "Geçici dosyalar silindi",
"exportPatchesLabel": "Yama seçimini dışa aktar", "exportPatchesLabel": "Yama seçimini dışa aktar",
"exportPatchesHint": "Yama seçimini bir JSON dosyasına kaydet", "exportPatchesHint": "Yama seçimini bir JSON dosyasına kaydedin",
"exportedPatches": "Yama seçimi dışa aktarıldı", "exportedPatches": "Yama seçimi dışa aktarıldı",
"noExportFileFound": "Dışa aktarılabilecek yama seçimi yok", "noExportFileFound": "Dışa aktarılabilecek yama seçimi yok",
"importPatchesLabel": "Yama seçimini içe aktar", "importPatchesLabel": "Yama seçimini içe aktar",
"importPatchesHint": "Yama seçimini bir JSON dosyasından içe aktarın", "importPatchesHint": "Yama seçimini bir JSON dosyasından içe aktarın",
"importedPatches": "Yama seçimi içe aktarıldı", "importedPatches": "Yama seçimi içe aktarıldı",
"resetStoredPatchesLabel": "Yama seçimini sıfırla", "resetStoredPatchesLabel": "Yama seçimini sıfırla",
"resetStoredPatchesHint": "Mevcut yama seçimini sıfırla", "resetStoredPatchesHint": "Mevcut yama seçimini sıfırlayın",
"resetStoredPatchesDialogTitle": "Yama seçimi sıfırlansın mı?", "resetStoredPatchesDialogTitle": "Yama seçimi sıfırlansın mı?",
"resetStoredPatchesDialogText": "Varsayılan yama seçimi geri yüklenecektir.", "resetStoredPatchesDialogText": "Varsayılan yama seçimi geri yüklenecektir.",
"resetStoredPatches": "Yama seçimi sıfırlandı", "resetStoredPatches": "Yama seçimi sıfırlandı",
"resetStoredOptionsLabel": "Yama seçeneklerini sıfırla", "resetStoredOptionsLabel": "Yama seçeneklerini sıfırla",
"resetStoredOptionsHint": "Tüm yama seçeneklerini sıfırla", "resetStoredOptionsHint": "Tüm yama seçeneklerini sıfırlayın",
"resetStoredOptionsDialogTitle": "Yama seçenekleri sıfırlansın mı?", "resetStoredOptionsDialogTitle": "Yama seçenekleri sıfırlansın mı?",
"resetStoredOptionsDialogText": "Yama seçeneklerini sıfırlamak, kayıtlı tüm seçenekleri kaldıracaktır.", "resetStoredOptionsDialogText": "Yama seçeneklerini sıfırlamak, kayıtlı tüm seçenekleri kaldıracaktır.",
"resetStoredOptions": "Seçenekler sıfırlandı", "resetStoredOptions": "Seçenekler sıfırlandı",
"deleteLogsLabel": "Logları temizle", "deleteLogsLabel": "Logları temizle",
"deleteLogsHint": "Kayıtlı ReVanced Manager loglarını sil", "deleteLogsHint": "Kayıtlı ReVanced Manager loglarını silin",
"deletedLogs": "Loglar silindi", "deletedLogs": "Loglar silindi",
"regenerateKeystoreLabel": "Keystore'u yeniden oluştur", "regenerateKeystoreLabel": "Keystore'u yeniden oluştur",
"regenerateKeystoreHint": "Uygulamaları imzalamak için kullanılan keystore'u yeniden oluşturun", "regenerateKeystoreHint": "Uygulamaları imzalamak için kullanılan keystore'u yeniden oluşturun",

View File

@ -182,7 +182,7 @@
"sourcesResetDialogTitle": "Скинути", "sourcesResetDialogTitle": "Скинути",
"sourcesResetDialogText": "Ви дійсно бажаєте відновити стандартні значення джерел?", "sourcesResetDialogText": "Ви дійсно бажаєте відновити стандартні значення джерел?",
"apiURLResetDialogText": "Ви дійсно хочете скинути API URL на стандартне значення?", "apiURLResetDialogText": "Ви дійсно хочете скинути API URL на стандартне значення?",
"sourcesUpdateNote": "Примітка: Це буде автоматично завантажувати ReVanced Patches та ReVanced Integrations з альтернативних джерел.\n\nЦе під'єднає вас до альтернативного джерела.", "sourcesUpdateNote": "Примітка. Це автоматично завантажить ReVanced Patches і ReVanced Integrations з альтернативних джерел.\n\nЦе під'єднає вас до альтернативного джерела.",
"apiURLLabel": "URL-адреса API", "apiURLLabel": "URL-адреса API",
"apiURLHint": "Налаштуйте API URL для ReVanced Manager", "apiURLHint": "Налаштуйте API URL для ReVanced Manager",
"selectApiURL": "URL-адреса API", "selectApiURL": "URL-адреса API",

View File

@ -178,9 +178,11 @@
"sourcesLabelHint": "設定 ReVanced 補丁和 ReVanced 整合的替代來源", "sourcesLabelHint": "設定 ReVanced 補丁和 ReVanced 整合的替代來源",
"sourcesIntegrationsLabel": "整合來源", "sourcesIntegrationsLabel": "整合來源",
"useAlternativeSources": "使用替代來源", "useAlternativeSources": "使用替代來源",
"useAlternativeSourcesHint": "改用 ReVanced 修補檔和 ReVanced 整合的替代來源,而不是 API",
"sourcesResetDialogTitle": "重設", "sourcesResetDialogTitle": "重設",
"sourcesResetDialogText": "確定要將來源資訊重設為預設值嗎?", "sourcesResetDialogText": "確定要將來源資訊重設為預設值嗎?",
"apiURLResetDialogText": "確定要重設 API URL 至預設值嗎?", "apiURLResetDialogText": "確定要重設 API URL 至預設值嗎?",
"sourcesUpdateNote": "注意:這將會自動從替代來源下載 ReVanced 修補檔和 ReVanced 整合。\n\n這將連接您到替代來源。",
"apiURLLabel": "API 鏈接", "apiURLLabel": "API 鏈接",
"apiURLHint": "設定 ReVanced 管理器的 API URL", "apiURLHint": "設定 ReVanced 管理器的 API URL",
"selectApiURL": "API 鏈接", "selectApiURL": "API 鏈接",
@ -270,6 +272,7 @@
}, },
"contributorsView": { "contributorsView": {
"widgetTitle": "貢獻者", "widgetTitle": "貢獻者",
"patcherContributors": "ReVanced 修補程式",
"patchesContributors": "ReVanced 補丁", "patchesContributors": "ReVanced 補丁",
"integrationsContributors": "ReVanced 整合", "integrationsContributors": "ReVanced 整合",
"cliContributors": "ReVanced 命令行介面", "cliContributors": "ReVanced 命令行介面",

View File

@ -1,16 +1,16 @@
# 💼 Prerequisites # 💼 Prerequisites
In order to use ReVanced Manager, certain requirements must be met. To use ReVanced Manager, you need to fulfill certain requirements.
## 🤝 Requirements ## 🤝 Requirements
- An Android device running Android 8 or higher - An Android device running Android 8 or higher
- Any device architecture except ARMv7[^1] - Any device architecture except ARMv7[^1]
[^1]: This constraint only applies to patches, that require patching APK resources which is why some patches may or may not work on ARMv7 architecture. You can find out, which architectures your device supports here: [⚙️ Configuring ReVanced Manager](2_4_settings.md#%E2%84%B9%EF%B8%8F-about). [^1]: Patching on ARMv7 is limited to bytecode patching but may work in certain circumstances for resource patching. You can check your device architecture in ReVanced Manager settings.
## ⏭️ What's next ## ⏭️ What's next
The next page will guide you through patching an app. The next page will explain how to install ReVanced Manager.
Continue: [⬇️ Installation](1_installation.md) Continue: [⬇️ Installation](1_installation.md)

View File

@ -1,14 +1,14 @@
# ⬇️ Installation # ⬇️ Installation
In order to use ReVanced on your Android device, ReVanced Manager must be installed. To use ReVanced on your Android device, ReVanced Manager must be first installed.
## ✅ Installation steps ## ✅ Installation steps
1. Download the latest version of ReVanced Manager from [here](https://github.com/revanced/revanced-manager/releases/latest) 1. Download the latest version of ReVanced Manager at [revanced.app/download](https://revanced.app/download) or from [GitHub releases](https://github.com/ReVanced/revanced-manager/releases)
2. Install ReVanced Manager 2. Install ReVanced Manager
## ⏭️ What's next ## ⏭️ What's next
The next page will guide you through using ReVanced Manager. The next page explain how to use ReVanced Manager to update ReVanced Manager and manage or patch apps.
Continue: [🛠️ Usage](2_usage.md) Continue: [🛠️ Usage](2_usage.md)

View File

@ -1,6 +1,6 @@
# 🧩 Patching apps # 🧩 Patching apps
The following pages will guide you through using ReVanced Manager to patch apps. Learn how to use ReVanced Manager to patch apps.
## ✅ Steps to patch apps ## ✅ Steps to patch apps
@ -8,13 +8,13 @@ The following pages will guide you through using ReVanced Manager to patch apps.
2. Tap on the **Select an app** card 2. Tap on the **Select an app** card
3. Choose an app to patch[^1] 3. Choose an app to patch[^1]
> 💡 Tip
> If you are prompted to select an APK file from storage because the selected app is a split APK, tap on the "Suggested version" label to open a search query to obtain said APK file
> Note > Note
> The suggested version is visible on each app's card. > The suggested version is visible on each app's card.
> You can tap on it to open a search query to obtain an APK file for the selected app with the suggested version > You can tap on it to open a search query to obtain an APK file for the selected app with the suggested version
> 💡 Tip
> If you are prompted to select an APK file from storage because the selected app is a split APK, tap on the "Suggested version" label to open a search query to obtain said APK file
4. Tap on the **Select patches** card and select the patches you want to apply[^2]. 4. Tap on the **Select patches** card and select the patches you want to apply[^2].
> Note > Note
@ -25,12 +25,12 @@ The following pages will guide you through using ReVanced Manager to patch apps.
5. Tap on the **Done** then **Patch** button 5. Tap on the **Done** then **Patch** button
> ⚠️ Warning > ⚠️ Warning
> The patching process may take ~5 minutes. Exiting the app may cancel patching or increase the time it takes to patch significantly. > The patching process may take ~5 minutes. Exiting the app may cancel patching or increase the time it takes to patch significantly.
6. Tap on the **Install** button 6. Tap on the **Install** button
> Note > Note
> If you are rooted, you can mount the patched app on top of the original app.[^3] > If you are rooted, you can mount the patched app on top of the original app.[^3]
> Optionally, you may export the patched app to storage using the option in the bottom left corner. > Optionally, you may export the patched app to storage using the option in the bottom left corner.
@ -40,6 +40,6 @@ The following pages will guide you through using ReVanced Manager to patch apps.
## ⏭️ What's next ## ⏭️ What's next
The next page will bring you back to the usage page. The next page will lead back to the usage page.
Continue: [🛠️ Usage](2_usage.md) Continue: [🛠️ Usage](2_usage.md)

View File

@ -1,15 +1,15 @@
# 🧰 Managing patched apps # 🧰 Managing patched apps
After patching an app, you may want to manage it. This page will guide you through managing patched apps. Learn how to view, open and uninstall patched apps.
## ✅ Steps to manage patched apps ## ✅ Steps to view, open and uninstall patched apps
1. Tap on the **Dashboard** tab in the bottom navigation bar 1. Tap on the **Dashboard** tab in the bottom navigation bar
2. Tap on the **Info** button for the app you want to manage 2. Tap on the **Info** button for the app you want to manage
3. Choose one of the options from the menu 3. Choose any of the options from the menu to view, open or uninstall the app
## ⏭️ What's next ## ⏭️ What's next
The next page will bring you back to the usage page. The next page will lead back to the usage page.
Continue: [🛠️ Usage](2_usage.md) Continue: [🛠️ Usage](2_usage.md)

View File

@ -1,6 +1,6 @@
# 🔄 Updating ReVanced Manager # 🔄 Updating ReVanced Manager
In order to keep up with the latest features and bug fixes, it is recommended to keep ReVanced Manager up to date. Learn how to update ReVanced Manager.
## ✅ Updating steps ## ✅ Updating steps
@ -9,6 +9,6 @@ In order to keep up with the latest features and bug fixes, it is recommended to
## ⏭️ What's next ## ⏭️ What's next
The next page will bring you back to the usage page. The next page will lead back to the usage page.
Continue: [🛠️ Usage](2_usage.md) Continue: [🛠️ Usage](2_usage.md)

View File

@ -1,52 +1,65 @@
# ⚙️ Configuring ReVanced Manager # ⚙️ Configuring ReVanced Manager
ReVanced Manager has settings that can be configured to your liking. Learn how to configure ReVanced Manager.
## 🎛️ Essential settings ## 🎛️ Essential settings
- ### 🪛 Allow changing patch selection - ### 🪛 Allow changing patch selection
Allows the user to change the patch selection from the default selection. By default, you can not change the patch selection and the default selection is used. Enabling this will allow you to change the patch selection.
- ### 🔍 Version compatibility check > ⚠️ Warning
> Changing the selection may cause unexpected issues. Unless you know what you are doing, it is recommended to keep this disabled.
Constrains patches to supported app versions. Disable this to patch any version of an app. - ### 📦 Require suggested app version
> [!WARNING] By default, ReVanced Manager allows you to patch an app if the suggested version to patch matches the version of the app you selected. Disabling this will allow you to patch an app even if the suggested version does not match the version of the app you selected.
> Disabling this may cause issues if the patches are not compatible with the app version.
> ⚠️ Warning
> Patches are more likely to fail on versions that are not suggested by ReVanced Manager. Unless you know what you are doing, it is recommended to keep this enabled.
- ### ✅ Version compatibility check
By default, ReVanced Manager does not allow you to select patches that are not compatible with the version of the app you selected. Disabling this will allow you to select patches that are not compatible with the version of the app you selected.
> ⚠️ Warning
> Patches are more likely to fail on versions they are not compatible with. Unless you know what you are doing, it is recommended to keep this enabled.
- ### 🧑‍🔬 Show universal patches - ### 🧑‍🔬 Show universal patches
Reveals patches which can be applied to any app. By default, ReVanced Manager only shows patches that are compatible with specific apps. Enabling this will show patches that are intended to work on all apps.
> [!WARNING] > ⚠️ Warning
> These patches may not work on all apps. > Patches that are intended to may not work on all apps. Unless you know what you are doing, it is recommended to keep this disabled.
- ### 🧬 Sources
Override the API and download patches from a different source.
- ### 🔗 API URL - ### 🔗 API URL
API to use to fetch updates and patches from. Configure the API URL to use. The API is used to download patches and updates.
- ### 💾 Imports & Exports - ### 🧬 Use alternative source
You can import, export or reset the following settings: Use alternative sources for patches and integrations instead of the API.
- 🔑 Keystore > Note
- 📄 Patch selection > ReVanced Manager will still use the API for updates.
- ⚙️ Patch options
> [!NOTE] - ### 💾 Import, export and reset options
> This is particularly useful if you want to backup or reset your settings.
You can import, export or reset saved settings. This includes:
- 🔑 Keystore used to sign patched apps
- 📄 Remembered selection of patches for each app
- ⚙️ Remembered patch options
> Note
> These can be used to backup and restore or reset settings to default in case of issues.
- ### ❓ About - ### ❓ About
View information about your device and ReVanced Manager. This includes the version of ReVanced Manager and supported architectures of your device. View information about your device and ReVanced Manager. This includes the version of ReVanced Manager and architectures your device supports.
## ⏭️ What's next ## ⏭️ What's next
The next page will bring you back to the usage page. The next page will lead back to the usage page.
Continue: [🛠️ Usage](2_usage.md) Continue: [🛠️ Usage](2_usage.md)

View File

@ -1,6 +1,6 @@
# 🛠️ Usage # 🛠️ Usage
The following pages will guide you through using ReVanced Manager to patch apps, manage patched apps, and update ReVanced Manager. Learn how to use ReVanced Manager to manage and patch apps or update ReVanced Manager.
## 📖 Table of contents ## 📖 Table of contents
@ -11,6 +11,6 @@ The following pages will guide you through using ReVanced Manager to patch apps,
## ⏭️ What's next ## ⏭️ What's next
The next page will guide you through troubleshooting ReVanced Manager. The next page will explain how to troubleshoot issues with ReVanced Manager.
Continue: [❔ Troubleshooting](3_troubleshooting.md) Continue: [❔ Troubleshooting](3_troubleshooting.md)

View File

@ -1,26 +1,27 @@
# ❔ Troubleshooting # ❔ Troubleshooting
In case you encounter any issues while using ReVanced Manager, please refer to this page for possible solutions. In case you encounter any issues while using ReVanced Manager, this page will help you troubleshoot them.
- 💉 Patching fails with an error - 💉 Common issues during or after patching
Make sure ReVanced Manager is up to date by following [🔄 Updating ReVanced Manager](2_3_updating.md) and select the **Default** button when choosing patches. - Make sure ReVanced Manager is up to date by following [🔄 Updating ReVanced Manager](2_3_updating.md)
- You may have changed settings in ReVanced Manager that are not recommended to change. Please review the warnings that appear when adjusting these settings and reset them to their default configuration as explained in [⚙️ Configuring ReVanced Manager](2_4_settings.md)
- 🚫 App not installed as package conflicts with an existing package - 🚫 App not installed as package conflicts with an existing package
An existing installation of the app you're trying to patch conflicts with the patched app (i.e., signature mismatch or downgrade). Uninstall the existing app before installing the patched app. An existing installation of the app you're trying to patch conflicts with the patched app (i.e., signature mismatch or downgrade). Uninstall the existing app before installing the patched app.
> 💡 Tip
> This may also be caused by changing settings in ReVanced Manager that are not recommended to change. Please review the warnings that appear when adjusting these settings and reset them to their default configuration as explained in [⚙️ Configuring ReVanced Manager](2_4_settings.md)
- ❗️ Error code `135`, `139` or `1` when patching the app - ❗️ Error code `135`, `139` or `1` when patching the app
You may be trying to patch a split APK[^1]. This may not work under certain circumstances. In such a case, patch a full APK. - You may be trying to patch a split APK[^1]. This can fail under certain circumstances. If that is the case, patch a full APK
- Your device may otherwise be unsupported. Please look at the [Prerequisites](0_prerequisites.md) page to see if your device is supported. Alternatively, you can use [ReVanced CLI](https://github.com/revanced/revanced-cli) to patch the app.
Your device may otherwise be unsupported. Please look at the [Prerequisites](0_prerequisites.md) page for supported devices.
Alternatively, you can use [ReVanced CLI](https://github.com/revanced/revanced-cli) to patch the app.
- 🚨 Patched app crashes on launch - 🚨 Patched app crashes on launch
Select the **Default** button when choosing patches. This may also be caused by changing settings in ReVanced Manager that are not recommended to change. Please review the warnings that appear when adjusting these settings and reset them to their default configuration as explained in [⚙️ Configuring ReVanced Manager](2_4_settings.md)
## ⏭️ What's next ## ⏭️ What's next

View File

@ -1,37 +1,41 @@
# 🛠️ Building from source # 🛠️ Building from source
This page will guide you through building ReVanced Manager from source. Learn how to build ReVanced Manager from source.
1\. Setup the Flutter environment for your [platform](https://docs.flutter.dev/get-started/install) 1. Setup the Flutter environment for your [platform](https://docs.flutter.dev/get-started/install)
2\. Clone the repository 2. Clone the repository
```sh ```sh
git clone https://github.com/revanced/revanced-manager.git && cd revanced-manager git clone https://github.com/revanced/revanced-manager.git && cd revanced-manager
``` ```
3\. Get dependencies
3. Get dependencies
```sh ```sh
flutter pub get flutter pub get
``` ```
4\. Generate translation file 4. Generate temporary files
```sh ```sh
dart run slang dart run slang
```
5\. Delete conflicting outputs
> [!TIP]
> Must be run every time you sync your local repository with the remote repository.
```sh
dart run build_runner build --delete-conflicting-outputs dart run build_runner build --delete-conflicting-outputs
``` ```
6\. Build the APK 5. Build the APK
```sh ```sh
flutter build apk flutter build apk
``` ```
> [!NOTE]
> If the build fails due to authentication, you may need to authenticate to GitHub Packages.
> Create a PAT with the scope `read:packages` [here](https://github.com/settings/tokens/new?scopes=read:packages&description=ReVanced) and add your token to ~/.gradle/gradle.properties.
>
> Example `gradle.properties` file:
>
> ```properties
> gpr.user = user
> gpr.key = key
> ```

View File

@ -705,7 +705,7 @@ class ManagerAPI {
); );
} }
Future<void> rePatchedSavedApps() async { Future<void> reAssessPatchedApps() async {
final List<PatchedApplication> patchedApps = getPatchedApps(); final List<PatchedApplication> patchedApps = getPatchedApps();
// Remove apps that are not installed anymore. // Remove apps that are not installed anymore.

View File

@ -172,25 +172,22 @@ class PatcherAPI {
_dataDir.createSync(); _dataDir.createSync();
_tmpDir.createSync(); _tmpDir.createSync();
final Directory workDir = _tmpDir.createTempSync('tmp-'); final Directory workDir = _tmpDir.createTempSync('tmp-');
final File inputFile = File('${workDir.path}/base.apk');
final File patchedFile = File('${workDir.path}/patched.apk');
outFile = File('${workDir.path}/out.apk'); outFile = File('${workDir.path}/out.apk');
final Directory cacheDir = Directory('${workDir.path}/cache');
cacheDir.createSync(); final Directory tmpDir =
final String originalFilePath = apkFilePath; Directory('${workDir.path}/revanced-temporary-files');
try { try {
await patcherChannel.invokeMethod( await patcherChannel.invokeMethod(
'runPatcher', 'runPatcher',
{ {
'originalFilePath': originalFilePath, 'inFilePath': apkFilePath,
'inputFilePath': inputFile.path,
'patchedFilePath': patchedFile.path,
'outFilePath': outFile!.path, 'outFilePath': outFile!.path,
'integrationsPath': integrationsFile.path, 'integrationsPath': integrationsFile.path,
'selectedPatches': selectedPatches.map((p) => p.name).toList(), 'selectedPatches': selectedPatches.map((p) => p.name).toList(),
'options': options, 'options': options,
'cacheDirPath': cacheDir.path, 'tmpDirPath': tmpDir.path,
'keyStoreFilePath': _keyStoreFile.path, 'keyStoreFilePath': _keyStoreFile.path,
'keystorePassword': _managerAPI.getKeystorePassword(), 'keystorePassword': _managerAPI.getKeystorePassword(),
}, },
@ -462,7 +459,6 @@ enum InstallStatus {
mountNoRoot(1), mountNoRoot(1),
mountVersionMismatch(1.1), mountVersionMismatch(1.1),
mountMissingInstallation(1.2), mountMissingInstallation(1.2),
statusFailureBlocked(2), statusFailureBlocked(2),
installFailedVerificationFailure(3.1), installFailedVerificationFailure(3.1),
statusFailureInvalid(4), statusFailureInvalid(4),
@ -473,6 +469,7 @@ enum InstallStatus {
statusFailureTimeout(8); statusFailureTimeout(8);
const InstallStatus(this.statusCode); const InstallStatus(this.statusCode);
final double statusCode; final double statusCode;
static String byCode(num code) { static String byCode(num code) {

View File

@ -2,13 +2,10 @@ import 'dart:ui';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
import 'package:dynamic_themes/dynamic_themes.dart'; import 'package:dynamic_themes/dynamic_themes.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/app/app.router.dart'; import 'package:revanced_manager/app/app.router.dart';
import 'package:revanced_manager/gen/strings.g.dart'; import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/theme.dart'; import 'package:revanced_manager/theme.dart';
import 'package:stacked_services/stacked_services.dart'; import 'package:stacked_services/stacked_services.dart';

View File

@ -44,7 +44,7 @@ class HomeViewModel extends BaseViewModel {
File? downloadedApk; File? downloadedApk;
Future<void> initialize(BuildContext context) async { Future<void> initialize(BuildContext context) async {
_managerAPI.rePatchedSavedApps().then((_) => _getPatchedApps()); _managerAPI.reAssessPatchedApps().then((_) => getPatchedApps());
_currentManagerVersion = await _managerAPI.getCurrentManagerVersion(); _currentManagerVersion = await _managerAPI.getCurrentManagerVersion();
if (!_managerAPI.getDownloadConsent()) { if (!_managerAPI.getDownloadConsent()) {
await showDownloadConsent(context); await showDownloadConsent(context);
@ -123,7 +123,7 @@ class HomeViewModel extends BaseViewModel {
locator<NavigationViewModel>().setIndex(1); locator<NavigationViewModel>().setIndex(1);
} }
void _getPatchedApps() { void getPatchedApps() {
lastPatchedApp = _managerAPI.getLastPatchedApp(); lastPatchedApp = _managerAPI.getLastPatchedApp();
patchedInstalledApps = _managerAPI.getPatchedApps().toList(); patchedInstalledApps = _managerAPI.getPatchedApps().toList();
notifyListeners(); notifyListeners();

View File

@ -470,7 +470,10 @@ class InstallerViewModel extends BaseViewModel {
_app.packageName = app.packageName; _app.packageName = app.packageName;
} }
await _managerAPI.savePatchedApp(_app); await _managerAPI.savePatchedApp(_app);
await locator<HomeViewModel>().initialize(context);
_managerAPI
.reAssessPatchedApps()
.then((_) => locator<HomeViewModel>().getPatchedApps());
update(1.0, 'Installed', 'Installed'); update(1.0, 'Installed', 'Installed');
} else if (response == 3) { } else if (response == 3) {

View File

@ -37,6 +37,14 @@ class SUpdateLanguage extends BaseViewModel {
final ValueNotifier<String> selectedLanguageCode = ValueNotifier( final ValueNotifier<String> selectedLanguageCode = ValueNotifier(
'${LocaleSettings.currentLocale.languageCode}-${LocaleSettings.currentLocale.countryCode}', '${LocaleSettings.currentLocale.languageCode}-${LocaleSettings.currentLocale.countryCode}',
); );
LanguageCodes getLanguageCode(locale) {
return LanguageCodes.fromCode(
'${locale.languageCode}_${locale.countryCode}',
orElse: () => LanguageCodes.fromCode(locale.languageCode),
);
}
final currentlyUsedLanguage = getLanguageCode(LocaleSettings.currentLocale);
// initLang(); // initLang();
// Return a dialog with list for each language supported by the application. // Return a dialog with list for each language supported by the application.
@ -53,17 +61,29 @@ class SUpdateLanguage extends BaseViewModel {
builder: (context, value, child) { builder: (context, value, child) {
return SingleChildScrollView( return SingleChildScrollView(
child: ListBody( child: ListBody(
children: AppLocale.values.map( children: [
(locale) { RadioListTile(
final LanguageCodes languageCode = LanguageCodes.fromCode( title: Text(currentlyUsedLanguage.englishName),
'${locale.languageCode}_${locale.countryCode}', subtitle: Text(
orElse: () => LanguageCodes.fromCode(locale.languageCode), '${currentlyUsedLanguage.nativeName} (${LocaleSettings.currentLocale.languageCode}${LocaleSettings.currentLocale.countryCode != null ? '-${LocaleSettings.currentLocale.countryCode}' : ''})'),
); value:
'${LocaleSettings.currentLocale.languageCode}-${LocaleSettings.currentLocale.countryCode}' ==
selectedLanguageCode.value,
groupValue: true,
onChanged: (value) {
selectedLanguageCode.value =
'${LocaleSettings.currentLocale.languageCode}-${LocaleSettings.currentLocale.countryCode}';
},
),
...AppLocale.values
.where(
(locale) =>
locale.languageCode != currentlyUsedLanguage.code,
)
.map((locale) {
final languageCode = getLanguageCode(locale);
return RadioListTile( return RadioListTile(
title: Text( title: Text(languageCode.englishName),
languageCode.englishName,
),
subtitle: Text( subtitle: Text(
'${languageCode.nativeName} (${locale.languageCode}${locale.countryCode != null ? '-${locale.countryCode}' : ''})', '${languageCode.nativeName} (${locale.languageCode}${locale.countryCode != null ? '-${locale.countryCode}' : ''})',
), ),
@ -75,8 +95,8 @@ class SUpdateLanguage extends BaseViewModel {
'${locale.languageCode}-${locale.countryCode}'; '${locale.languageCode}-${locale.countryCode}';
}, },
); );
}, }),
).toList(), ],
), ),
); );
}, },

205
package-lock.json generated
View File

@ -4,7 +4,6 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "revanced-manager",
"devDependencies": { "devDependencies": {
"@droidsolutions-oss/semantic-release-update-file": "^1.3.2", "@droidsolutions-oss/semantic-release-update-file": "^1.3.2",
"@saithodev/semantic-release-backmerge": "^4.0.1", "@saithodev/semantic-release-backmerge": "^4.0.1",
@ -163,24 +162,24 @@
} }
}, },
"node_modules/@octokit/openapi-types": { "node_modules/@octokit/openapi-types": {
"version": "19.1.0", "version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==", "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
"dev": true "dev": true
}, },
"node_modules/@octokit/plugin-paginate-rest": { "node_modules/@octokit/plugin-paginate-rest": {
"version": "9.1.5", "version": "9.2.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.5.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz",
"integrity": "sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg==", "integrity": "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/types": "^12.4.0" "@octokit/types": "^12.6.0"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 18"
}, },
"peerDependencies": { "peerDependencies": {
"@octokit/core": ">=5" "@octokit/core": "5"
} }
}, },
"node_modules/@octokit/plugin-retry": { "node_modules/@octokit/plugin-retry": {
@ -201,9 +200,9 @@
} }
}, },
"node_modules/@octokit/plugin-throttling": { "node_modules/@octokit/plugin-throttling": {
"version": "8.1.3", "version": "8.2.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-8.1.3.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-8.2.0.tgz",
"integrity": "sha512-pfyqaqpc0EXh5Cn4HX9lWYsZ4gGbjnSmUILeu4u2gnuM50K/wIk9s1Pxt3lVeVwekmITgN/nJdoh43Ka+vye8A==", "integrity": "sha512-nOpWtLayKFpgqmgD0y3GqXafMFuKcA4tRPZIfu7BArd2lEZeb1988nhWhwx4aZWmjDmUfdgVf7W+Tt4AmvRmMQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/types": "^12.2.0", "@octokit/types": "^12.2.0",
@ -246,12 +245,12 @@
} }
}, },
"node_modules/@octokit/types": { "node_modules/@octokit/types": {
"version": "12.5.0", "version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.5.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-YJEKcb0KkJlIUNU/zjnZwHEP8AoVh/OoIcP/1IyR4UHxExz7fzpe/a8IG4wBtQi7QDEqiomVLX88S6FpxxAJtg==", "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^19.1.0" "@octokit/openapi-types": "^20.0.0"
} }
}, },
"node_modules/@pnpm/config.env-replace": { "node_modules/@pnpm/config.env-replace": {
@ -500,9 +499,9 @@
} }
}, },
"node_modules/@saithodev/semantic-release-backmerge/node_modules/npm-run-path": { "node_modules/@saithodev/semantic-release-backmerge/node_modules/npm-run-path": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"path-key": "^4.0.0" "path-key": "^4.0.0"
@ -865,9 +864,9 @@
} }
}, },
"node_modules/@semantic-release/npm": { "node_modules/@semantic-release/npm": {
"version": "11.0.2", "version": "11.0.3",
"resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-11.0.2.tgz", "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-11.0.3.tgz",
"integrity": "sha512-owtf3RjyPvRE63iUKZ5/xO4uqjRpVQDUB9+nnXj0xwfIeM9pRl+cG+zGDzdftR4m3f2s4Wyf3SexW+kF5DFtWA==", "integrity": "sha512-KUsozQGhRBAnoVg4UMZj9ep436VEGwT536/jwSqB7vcEfA6oncCUU7UIYTRdLx7GvTtqn0kBjnkfLVkcnBa2YQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@semantic-release/error": "^4.0.0", "@semantic-release/error": "^4.0.0",
@ -877,7 +876,7 @@
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"nerf-dart": "^1.0.0", "nerf-dart": "^1.0.0",
"normalize-url": "^8.0.0", "normalize-url": "^8.0.0",
"npm": "^10.0.0", "npm": "^10.5.0",
"rc": "^1.2.8", "rc": "^1.2.8",
"read-pkg": "^9.0.0", "read-pkg": "^9.0.0",
"registry-auth-token": "^5.0.0", "registry-auth-token": "^5.0.0",
@ -1024,9 +1023,9 @@
} }
}, },
"node_modules/@semantic-release/npm/node_modules/npm-run-path": { "node_modules/@semantic-release/npm/node_modules/npm-run-path": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"path-key": "^4.0.0" "path-key": "^4.0.0"
@ -1138,9 +1137,9 @@
} }
}, },
"node_modules/@sindresorhus/merge-streams": { "node_modules/@sindresorhus/merge-streams": {
"version": "2.2.1", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.2.1.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
"integrity": "sha512-255V7MMIKw6aQ43Wbqp9HZ+VHn6acddERTLiiLnlcPLU9PdTq9Aijl12oklAgUEblLWye+vHLzmqBx6f2TGcZw==", "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@ -1808,9 +1807,9 @@
} }
}, },
"node_modules/env-ci/node_modules/npm-run-path": { "node_modules/env-ci/node_modules/npm-run-path": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"path-key": "^4.0.0" "path-key": "^4.0.0"
@ -2903,9 +2902,9 @@
} }
}, },
"node_modules/npm": { "node_modules/npm": {
"version": "10.4.0", "version": "10.5.0",
"resolved": "https://registry.npmjs.org/npm/-/npm-10.4.0.tgz", "resolved": "https://registry.npmjs.org/npm/-/npm-10.5.0.tgz",
"integrity": "sha512-RS7Mx0OVfXlOcQLRePuDIYdFCVBPCNapWHplDK+mh7GDdP/Tvor4ocuybRRPSvfcRb2vjRJt1fHCqw3cr8qACQ==", "integrity": "sha512-Ejxwvfh9YnWVU2yA5FzoYLTW52vxHCz+MHrOFg9Cc8IFgF/6f5AGPAvb5WTay5DIUP1NIfN3VBZ0cLlGO0Ys+A==",
"bundleDependencies": [ "bundleDependencies": [
"@isaacs/string-locale-compare", "@isaacs/string-locale-compare",
"@npmcli/arborist", "@npmcli/arborist",
@ -2979,13 +2978,6 @@
"write-file-atomic" "write-file-atomic"
], ],
"dev": true, "dev": true,
"workspaces": [
"docs",
"smoke-tests",
"mock-globals",
"mock-registry",
"workspaces/*"
],
"dependencies": { "dependencies": {
"@isaacs/string-locale-compare": "^1.1.0", "@isaacs/string-locale-compare": "^1.1.0",
"@npmcli/arborist": "^7.2.1", "@npmcli/arborist": "^7.2.1",
@ -2995,7 +2987,7 @@
"@npmcli/package-json": "^5.0.0", "@npmcli/package-json": "^5.0.0",
"@npmcli/promise-spawn": "^7.0.1", "@npmcli/promise-spawn": "^7.0.1",
"@npmcli/run-script": "^7.0.4", "@npmcli/run-script": "^7.0.4",
"@sigstore/tuf": "^2.3.0", "@sigstore/tuf": "^2.3.1",
"abbrev": "^2.0.0", "abbrev": "^2.0.0",
"archy": "~1.0.0", "archy": "~1.0.0",
"cacache": "^18.0.2", "cacache": "^18.0.2",
@ -3046,7 +3038,7 @@
"proc-log": "^3.0.0", "proc-log": "^3.0.0",
"qrcode-terminal": "^0.12.0", "qrcode-terminal": "^0.12.0",
"read": "^2.1.0", "read": "^2.1.0",
"semver": "^7.5.4", "semver": "^7.6.0",
"spdx-expression-parse": "^3.0.1", "spdx-expression-parse": "^3.0.1",
"ssri": "^10.0.5", "ssri": "^10.0.5",
"supports-color": "^9.4.0", "supports-color": "^9.4.0",
@ -3162,7 +3154,7 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/npm/node_modules/@npmcli/agent": { "node_modules/npm/node_modules/@npmcli/agent": {
"version": "2.2.0", "version": "2.2.1",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -3178,7 +3170,7 @@
} }
}, },
"node_modules/npm/node_modules/@npmcli/arborist": { "node_modules/npm/node_modules/@npmcli/arborist": {
"version": "7.3.1", "version": "7.4.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -3191,7 +3183,7 @@
"@npmcli/name-from-folder": "^2.0.0", "@npmcli/name-from-folder": "^2.0.0",
"@npmcli/node-gyp": "^3.0.0", "@npmcli/node-gyp": "^3.0.0",
"@npmcli/package-json": "^5.0.0", "@npmcli/package-json": "^5.0.0",
"@npmcli/query": "^3.0.1", "@npmcli/query": "^3.1.0",
"@npmcli/run-script": "^7.0.2", "@npmcli/run-script": "^7.0.2",
"bin-links": "^4.0.1", "bin-links": "^4.0.1",
"cacache": "^18.0.0", "cacache": "^18.0.0",
@ -3225,7 +3217,7 @@
} }
}, },
"node_modules/npm/node_modules/@npmcli/config": { "node_modules/npm/node_modules/@npmcli/config": {
"version": "8.1.0", "version": "8.2.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -3396,7 +3388,7 @@
} }
}, },
"node_modules/npm/node_modules/@npmcli/query": { "node_modules/npm/node_modules/@npmcli/query": {
"version": "3.0.1", "version": "3.1.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -3434,19 +3426,19 @@
} }
}, },
"node_modules/npm/node_modules/@sigstore/bundle": { "node_modules/npm/node_modules/@sigstore/bundle": {
"version": "2.1.1", "version": "2.2.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@sigstore/protobuf-specs": "^0.2.1" "@sigstore/protobuf-specs": "^0.3.0"
}, },
"engines": { "engines": {
"node": "^16.14.0 || >=18.0.0" "node": "^16.14.0 || >=18.0.0"
} }
}, },
"node_modules/npm/node_modules/@sigstore/core": { "node_modules/npm/node_modules/@sigstore/core": {
"version": "0.2.0", "version": "1.0.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "Apache-2.0", "license": "Apache-2.0",
@ -3455,7 +3447,7 @@
} }
}, },
"node_modules/npm/node_modules/@sigstore/protobuf-specs": { "node_modules/npm/node_modules/@sigstore/protobuf-specs": {
"version": "0.2.1", "version": "0.3.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "Apache-2.0", "license": "Apache-2.0",
@ -3464,14 +3456,14 @@
} }
}, },
"node_modules/npm/node_modules/@sigstore/sign": { "node_modules/npm/node_modules/@sigstore/sign": {
"version": "2.2.1", "version": "2.2.3",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@sigstore/bundle": "^2.1.1", "@sigstore/bundle": "^2.2.0",
"@sigstore/core": "^0.2.0", "@sigstore/core": "^1.0.0",
"@sigstore/protobuf-specs": "^0.2.1", "@sigstore/protobuf-specs": "^0.3.0",
"make-fetch-happen": "^13.0.0" "make-fetch-happen": "^13.0.0"
}, },
"engines": { "engines": {
@ -3479,12 +3471,12 @@
} }
}, },
"node_modules/npm/node_modules/@sigstore/tuf": { "node_modules/npm/node_modules/@sigstore/tuf": {
"version": "2.3.0", "version": "2.3.1",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@sigstore/protobuf-specs": "^0.2.1", "@sigstore/protobuf-specs": "^0.3.0",
"tuf-js": "^2.2.0" "tuf-js": "^2.2.0"
}, },
"engines": { "engines": {
@ -3492,14 +3484,14 @@
} }
}, },
"node_modules/npm/node_modules/@sigstore/verify": { "node_modules/npm/node_modules/@sigstore/verify": {
"version": "0.1.0", "version": "1.1.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@sigstore/bundle": "^2.1.1", "@sigstore/bundle": "^2.2.0",
"@sigstore/core": "^0.2.0", "@sigstore/core": "^1.0.0",
"@sigstore/protobuf-specs": "^0.2.1" "@sigstore/protobuf-specs": "^0.3.0"
}, },
"engines": { "engines": {
"node": "^16.14.0 || >=18.0.0" "node": "^16.14.0 || >=18.0.0"
@ -3906,7 +3898,7 @@
} }
}, },
"node_modules/npm/node_modules/diff": { "node_modules/npm/node_modules/diff": {
"version": "5.1.0", "version": "5.2.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
@ -4057,7 +4049,7 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/npm/node_modules/hasown": { "node_modules/npm/node_modules/hasown": {
"version": "2.0.0", "version": "2.0.1",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
@ -4087,7 +4079,7 @@
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/npm/node_modules/http-proxy-agent": { "node_modules/npm/node_modules/http-proxy-agent": {
"version": "7.0.0", "version": "7.0.2",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
@ -4100,7 +4092,7 @@
} }
}, },
"node_modules/npm/node_modules/https-proxy-agent": { "node_modules/npm/node_modules/https-proxy-agent": {
"version": "7.0.2", "version": "7.0.4",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
@ -4182,11 +4174,24 @@
"node": "^16.14.0 || >=18.0.0" "node": "^16.14.0 || >=18.0.0"
} }
}, },
"node_modules/npm/node_modules/ip": { "node_modules/npm/node_modules/ip-address": {
"version": "2.0.0", "version": "9.0.5",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT",
"dependencies": {
"jsbn": "1.1.0",
"sprintf-js": "^1.1.3"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/npm/node_modules/ip-address/node_modules/sprintf-js": {
"version": "1.1.3",
"dev": true,
"inBundle": true,
"license": "BSD-3-Clause"
}, },
"node_modules/npm/node_modules/ip-regex": { "node_modules/npm/node_modules/ip-regex": {
"version": "5.0.0", "version": "5.0.0",
@ -4263,6 +4268,12 @@
"@pkgjs/parseargs": "^0.11.0" "@pkgjs/parseargs": "^0.11.0"
} }
}, },
"node_modules/npm/node_modules/jsbn": {
"version": "1.1.0",
"dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/json-parse-even-better-errors": { "node_modules/npm/node_modules/json-parse-even-better-errors": {
"version": "3.0.1", "version": "3.0.1",
"dev": true, "dev": true,
@ -4316,7 +4327,7 @@
} }
}, },
"node_modules/npm/node_modules/libnpmdiff": { "node_modules/npm/node_modules/libnpmdiff": {
"version": "6.0.6", "version": "6.0.7",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -4336,7 +4347,7 @@
} }
}, },
"node_modules/npm/node_modules/libnpmexec": { "node_modules/npm/node_modules/libnpmexec": {
"version": "7.0.7", "version": "7.0.8",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -4358,7 +4369,7 @@
} }
}, },
"node_modules/npm/node_modules/libnpmfund": { "node_modules/npm/node_modules/libnpmfund": {
"version": "5.0.4", "version": "5.0.5",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -4396,7 +4407,7 @@
} }
}, },
"node_modules/npm/node_modules/libnpmpack": { "node_modules/npm/node_modules/libnpmpack": {
"version": "6.0.6", "version": "6.0.7",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -4471,7 +4482,7 @@
} }
}, },
"node_modules/npm/node_modules/lru-cache": { "node_modules/npm/node_modules/lru-cache": {
"version": "10.1.0", "version": "10.2.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -5133,7 +5144,7 @@
"optional": true "optional": true
}, },
"node_modules/npm/node_modules/semver": { "node_modules/npm/node_modules/semver": {
"version": "7.5.4", "version": "7.6.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
@ -5199,17 +5210,17 @@
} }
}, },
"node_modules/npm/node_modules/sigstore": { "node_modules/npm/node_modules/sigstore": {
"version": "2.2.0", "version": "2.2.2",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@sigstore/bundle": "^2.1.1", "@sigstore/bundle": "^2.2.0",
"@sigstore/core": "^0.2.0", "@sigstore/core": "^1.0.0",
"@sigstore/protobuf-specs": "^0.2.1", "@sigstore/protobuf-specs": "^0.3.0",
"@sigstore/sign": "^2.2.1", "@sigstore/sign": "^2.2.3",
"@sigstore/tuf": "^2.3.0", "@sigstore/tuf": "^2.3.1",
"@sigstore/verify": "^0.1.0" "@sigstore/verify": "^1.1.0"
}, },
"engines": { "engines": {
"node": "^16.14.0 || >=18.0.0" "node": "^16.14.0 || >=18.0.0"
@ -5226,16 +5237,16 @@
} }
}, },
"node_modules/npm/node_modules/socks": { "node_modules/npm/node_modules/socks": {
"version": "2.7.1", "version": "2.8.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ip": "^2.0.0", "ip-address": "^9.0.5",
"smart-buffer": "^4.2.0" "smart-buffer": "^4.2.0"
}, },
"engines": { "engines": {
"node": ">= 10.13.0", "node": ">= 16.0.0",
"npm": ">= 3.0.0" "npm": ">= 3.0.0"
} }
}, },
@ -5264,7 +5275,7 @@
} }
}, },
"node_modules/npm/node_modules/spdx-exceptions": { "node_modules/npm/node_modules/spdx-exceptions": {
"version": "2.3.0", "version": "2.5.0",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "CC-BY-3.0" "license": "CC-BY-3.0"
@ -5280,7 +5291,7 @@
} }
}, },
"node_modules/npm/node_modules/spdx-license-ids": { "node_modules/npm/node_modules/spdx-license-ids": {
"version": "3.0.16", "version": "3.0.17",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "CC0-1.0" "license": "CC0-1.0"
@ -5987,9 +5998,9 @@
} }
}, },
"node_modules/read-pkg-up/node_modules/type-fest": { "node_modules/read-pkg-up/node_modules/type-fest": {
"version": "4.10.2", "version": "4.11.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.11.0.tgz",
"integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==", "integrity": "sha512-DPsoHKtnCUqqoB5Y4OPyat7ObSLz1XOkhHTmz+gOkz2p1xs+BBneTvHWriTwc313eozfBWh8b45EpaV3ZrrPPQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=16" "node": ">=16"
@ -6016,9 +6027,9 @@
} }
}, },
"node_modules/read-pkg/node_modules/type-fest": { "node_modules/read-pkg/node_modules/type-fest": {
"version": "4.10.2", "version": "4.11.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.11.0.tgz",
"integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==", "integrity": "sha512-DPsoHKtnCUqqoB5Y4OPyat7ObSLz1XOkhHTmz+gOkz2p1xs+BBneTvHWriTwc313eozfBWh8b45EpaV3ZrrPPQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=16" "node": ">=16"
@ -6296,9 +6307,9 @@
} }
}, },
"node_modules/semantic-release/node_modules/npm-run-path": { "node_modules/semantic-release/node_modules/npm-run-path": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"path-key": "^4.0.0" "path-key": "^4.0.0"

View File

@ -109,10 +109,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: built_value name: built_value
sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.9.0" version: "8.9.1"
characters: characters:
dependency: transitive dependency: transitive
description: description:
@ -205,10 +205,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: dart_style name: dart_style
sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.4" version: "2.3.6"
dbus: dbus:
dependency: transitive dependency: transitive
description: description:
@ -262,10 +262,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: dynamic_color name: dynamic_color
sha256: a866f1f8947bfdaf674d7928e769eac7230388a2e7a2542824fad4bb5b87be3b sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.6.9" version: "1.7.0"
dynamic_themes: dynamic_themes:
dependency: "direct main" dependency: "direct main"
description: description:
@ -385,10 +385,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_markdown name: flutter_markdown
sha256: "21b085a1c185e46701373866144ced56cfb7a0c33f63c916bb8fe2d0c1491278" sha256: a64c5323ac83ed2b7940d2b6288d160aa1753ff271ba9d9b2a86770414aa3eab
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.19" version: "0.6.20+1"
flutter_test: flutter_test:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -459,10 +459,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: google_fonts name: google_fonts
sha256: f0b8d115a13ecf827013ec9fc883390ccc0e87a96ed5347a3114cac177ef18e8 sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.0" version: "6.2.1"
graphs: graphs:
dependency: transitive dependency: transitive
description: description:
@ -562,12 +562,11 @@ packages:
language_code: language_code:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." name: language_code
ref: "21b71892d1ce07fb8ea51ac2b474e435360fb6f7" sha256: cbd50546df7c21857a7cfa35f97943f8759705d0c17f9282593abe654cbbdf38
resolved-ref: "21b71892d1ce07fb8ea51ac2b474e435360fb6f7" url: "https://pub.dev"
url: "https://github.com/Ushie/language_code" source: hosted
source: git version: "0.4.1"
version: "0.4.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
@ -845,10 +844,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: provider name: provider
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.1" version: "6.1.2"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
@ -1004,18 +1003,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: slang name: slang
sha256: "95dee03eb3fd1b36c99f365d4eace270a0d83c6148f8e7d1057806ef60cfaf12" sha256: "5e08ac915ac27a3508863f37734280d30c3713d56746cd2e4a5da77413da4b95"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.29.0" version: "3.30.1"
slang_flutter: slang_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
name: slang_flutter name: slang_flutter
sha256: "34c7cf297c608e24d3957a29e75c6790f4dbbfb1a4783d261a6c1e33ede7ad0f" sha256: "9ee040b0d364d3a4d692e4af536acff6ef513870689403494ebc6d59b0dccea6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.29.0" version: "3.30.0"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -1196,10 +1195,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.4" version: "6.2.5"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
@ -1212,10 +1211,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.4" version: "6.2.5"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@ -1361,5 +1360,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.3.0-279.1.beta <4.0.0" dart: ">=3.3.0 <4.0.0"
flutter: ">=3.16.0" flutter: ">=3.19.2"

View File

@ -4,7 +4,7 @@ homepage: https://github.com/ReVanced/revanced-manager
publish_to: 'none' publish_to: 'none'
version: 1.19.0-dev.17+101900017 version: 1.19.1+101800002
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
@ -37,14 +37,11 @@ dependencies:
flutter_markdown: ^0.6.14 flutter_markdown: ^0.6.14
fluttertoast: ^8.2.4 fluttertoast: ^8.2.4
font_awesome_flutter: ^10.4.0 font_awesome_flutter: ^10.4.0
google_fonts: ^6.1.0 google_fonts: ^6.2.1
injectable: ^2.1.1 injectable: ^2.1.1
intl: ^0.18.0 intl: ^0.18.0
json_annotation: ^4.8.1 json_annotation: ^4.8.1
language_code: language_code: ^0.4.1
git:
url: https://github.com/Ushie/language_code
ref: 21b71892d1ce07fb8ea51ac2b474e435360fb6f7 # Branch: feat/add-Filipino, Upstream PR: https://github.com/lamnhan066/language_code/pull/1
logcat: logcat:
git: git:
url: https://github.com/BenjaminHalko/logcat url: https://github.com/BenjaminHalko/logcat