feat: Allow changing languages (#1488)

Co-authored-by: validcube <pun.butrach@gmail.com>
This commit is contained in:
Ushie 2024-02-12 02:22:25 +03:00 committed by GitHub
parent c498cff096
commit f82c439b26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
64 changed files with 1302 additions and 1488 deletions

View File

@ -73,7 +73,8 @@ jobs:
- name: Install Flutter dependencies
run: flutter pub get
- name: Generate translation with Slang
run: dart run slang
- name: Generate files with Builder
run: dart run build_runner build --delete-conflicting-outputs

View File

@ -42,7 +42,8 @@ jobs:
- name: Set up Flutter
run: flutter pub get
- name: Generate translation with Slang
run: dart run slang
- name: Generate files with Builder
run: dart run build_runner build --delete-conflicting-outputs

53
.github/workflows/sync-crowdin.yml vendored Normal file
View File

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

14
assets/i18n/README.md Normal file
View File

@ -0,0 +1,14 @@
# Nuke:tm:
> ![CAUTION]
> Some of the code are licensed under BSD 3-Clause License, please check inside the code file for more information.
## Usage
Move to your desire directory and run
```bash
dart nuke.dart
```
and it will remove all the empty keys from the JSON files in the current folder.

View File

@ -1,373 +0,0 @@
{
"okButton": "OK",
"cancelButton": "Cancel",
"dismissButton": "Dismiss",
"quitButton": "Quit",
"updateButton": "Update",
"enabledLabel": "Enabled",
"disabledLabel": "Disabled",
"installed":"Installed: {version}",
"suggested":"Suggested: {version}",
"yesButton": "Yes",
"noButton": "No",
"warning": "Warning",
"options": "Options",
"notice": "Notice",
"noShowAgain": "Don't show this again",
"add": "Add",
"remove": "Remove",
"showChangelogButton": "Show changelog",
"showUpdateButton": "Show update",
"navigationView": {
"dashboardTab": "Dashboard",
"patcherTab": "Patcher",
"settingsTab": "Settings"
},
"homeView": {
"refreshSuccess": "Refreshed successfully",
"widgetTitle": "Dashboard",
"updatesSubtitle": "Updates",
"patchedSubtitle": "Patched apps",
"changeLaterSubtitle": "You can change this in the settings at a later time.",
"noUpdates": "No updates available",
"WIP": "Work in progress...",
"noInstallations": "No patched apps installed",
"installUpdate": "Continue to install the update?",
"updateSheetTitle": "Update ReVanced Manager",
"updateDialogTitle": "New update available",
"updatePatchesSheetTitle": "Update ReVanced Patches",
"updateChangelogTitle": "Changelog",
"updateDialogText": "A new update is available for {file}.\n\nThe currently installed version is {version}.",
"downloadConsentDialogTitle": "Download necessary files?",
"downloadConsentDialogText": "ReVanced Manager needs to download necessary files to work properly.",
"downloadConsentDialogText2": "This will connect you to {url}.",
"checkUpdateDialogTitle": "Check for updates?",
"checkUpdateDialogText": "Do you want ReVanced Manager to check for updates automatically?",
"notificationTitle": "Update downloaded",
"notificationText": "Tap to install the update",
"downloadingMessage": "Downloading update...",
"downloadedMessage": "Update downloaded",
"installingMessage": "Installing update...",
"errorDownloadMessage": "Unable to download update",
"errorInstallMessage": "Unable to install update",
"noConnection": "No internet connection",
"updatesDisabled": "Updating a patched app is currently disabled. Repatch the app again."
},
"applicationItem": {
"infoButton": "Info"
},
"latestCommitCard": {
"loadingLabel": "Loading...",
"timeagoLabel": "{time} ago",
"patcherLabel": "Patcher: ",
"managerLabel": "Manager: ",
"updateButton": "Update Manager"
},
"patcherView": {
"widgetTitle": "Patcher",
"patchButton": "Patch",
"armv7WarningDialogText": "Patching on ARMv7 devices is not yet supported and might fail. Continue anyways?",
"removedPatchesWarningDialogText": "The following patches have been removed since the last time you used them.\n\n{patches}\n\nContinue anyways?",
"requiredOptionDialogText" : "Some patch options have to be set."
},
"appSelectorCard": {
"widgetTitle": "Select an app",
"widgetTitleSelected": "Selected app",
"widgetSubtitle": "No app selected",
"noAppsLabel": "No applications found",
"currentVersion": "Current",
"suggestedVersion": "Suggested",
"anyVersion": "Any version"
},
"patchSelectorCard": {
"widgetTitle": "Select patches",
"widgetTitleSelected": "Selected patches",
"widgetSubtitle": "Select an application first",
"widgetEmptySubtitle": "No patches selected"
},
"socialMediaCard": {
"widgetTitle": "Socials",
"widgetSubtitle": "We are online!"
},
"appSelectorView": {
"viewTitle": "Select an app",
"searchBarHint": "Search app",
"storageButton": "Storage",
"selectFromStorageButton": "Select from storage",
"errorMessage": "Unable to use selected application",
"downloadToast": "Download function is not available yet",
"requireSuggestedAppVersionDialogText": "The version of the app you have selected does not match the suggested version which can lead to unexpected issues. Please use the suggested version.\n\nSelected version: {selected}\nSuggested version: {suggested}\n\nTo continue anyway, disable \"Require suggested app version\" in the settings.",
"featureNotAvailable": "Feature not implemented",
"featureNotAvailableText": "This app is a split APK and can only be patched and installed reliably by mounting with root permissions. However, you can patch and install a full APK by selecting it from storage."
},
"patchesSelectorView": {
"viewTitle": "Select patches",
"searchBarHint": "Search patches",
"universalPatches": "Universal patches",
"newPatches": "New patches",
"patches": "Patches",
"doneButton": "Done",
"default": "Default",
"defaultTooltip": "Select all default patches",
"none": "None",
"noneTooltip": "Deselect all patches",
"loadPatchesSelection": "Load patch selection",
"noSavedPatches": "No saved patch selection for the selected app.\nPress Done to save the current selection.",
"noPatchesFound": "No patches found for the selected app",
"setRequiredOption": "Some patches require options to be set:\n\n{patches}\n\nPlease set them before continuing."
},
"patchOptionsView": {
"customValue": "Custom value",
"resetOptionsTooltip": "Reset patch options",
"viewTitle": "Patch options",
"saveOptions": "Save",
"addOptions": "Add options",
"deselectPatch": "Deselect patch",
"tooltip": "More input options",
"selectFilePath": "Select file path",
"selectFolder": "Select folder",
"selectOption": "Select option",
"requiredOption": "This option is required",
"unsupportedOption": "This option is not supported",
"requiredOptionNull": "The following options have to be set:\n\n{options}"
},
"patchItem": {
"unsupportedDialogText": "Selecting this patch may result in patching errors.\n\nApp version: {packageVersion}\nSupported versions:\n{supportedVersions}",
"unsupportedPatchVersion": "Patch is not supported for this app version.",
"unsupportedRequiredOption": "This patch contains a required option that is not supported by this app",
"patchesChangeWarningDialogText": "It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou'll need to turn on \"Allow changing patch selection\" in the settings before changing any patch selection.",
"patchesChangeWarningDialogButton": "Use default selection"
},
"installerView": {
"widgetTitle": "Installer",
"installType": "Select install type",
"installTypeDescription": "Select the installation type to continue with.",
"installButton": "Install",
"installRootType": "Mount",
"installNonRootType": "Regular",
"warning": "Disable auto updates for the patched app to avoid unexpected issues.",
"pressBackAgain": "Press back again to cancel",
"openButton": "Open",
"shareButton": "Share file",
"notificationTitle": "ReVanced Manager is patching",
"notificationText": "Tap to return to the installer",
"exportApkButtonTooltip": "Export patched APK",
"exportLogButtonTooltip": "Export log",
"screenshotDetected": "A screenshot has been detected. If you are trying to share the log, please share a text copy instead.\n\nCopy log to clipboard?",
"copiedToClipboard": "Copied log to clipboard",
"noExit": "Installer is still running, cannot exit..."
},
"settingsView": {
"widgetTitle": "Settings",
"appearanceSectionTitle": "Appearance",
"teamSectionTitle": "Team",
"debugSectionTitle": "Debugging",
"advancedSectionTitle": "Advanced",
"exportSectionTitle": "Import & export",
"themeModeLabel": "App theme",
"systemThemeLabel": "System",
"lightThemeLabel": "Light",
"darkThemeLabel": "Dark",
"dynamicThemeLabel": "Material You",
"dynamicThemeHint": "Enjoy an experience closer to your device",
"languageLabel": "Language",
"englishOption": "English",
"sourcesLabel": "Sources",
"sourcesLabelHint": "Configure the source of patches and integrations",
"sourcesIntegrationsLabel": "Integrations source",
"sourcesResetDialogTitle": "Reset",
"sourcesResetDialogText": "Are you sure you want to reset your sources to their default values?",
"apiURLResetDialogText": "Are you sure you want to reset your API URL to its default value?",
"sourcesUpdateNote": "Note: Patches will be updated to the latest version automatically.\n\nThis will reveal your IP address to the server.",
"apiURLLabel": "API URL",
"apiURLHint": "Configure the URL of the API to use",
"selectApiURL": "API URL",
"hostRepositoryLabel": "Repository API",
"orgPatchesLabel": "Patches organization",
"sourcesPatchesLabel": "Patches source",
"orgIntegrationsLabel": "Integrations organization",
"contributorsLabel": "Contributors",
"contributorsHint": "A list of contributors of ReVanced",
"logsLabel": "Share logs",
"logsHint": "Share ReVanced Manager logs",
"enablePatchesSelectionLabel": "Allow changing patch selection",
"enablePatchesSelectionHint": "Do not prevent selecting or deselecting patches",
"enablePatchesSelectionWarningText": "Changing the selection of patches may cause unexpected issues.\n\nEnable anyways?",
"disablePatchesSelectionWarningText": "You are about to disable changing the selection of patches.\nThe default selection of patches will be restored.\n\nDisable anyways?",
"autoUpdatePatchesLabel": "Auto update patches",
"autoUpdatePatchesHint": "Automatically update patches to the latest version",
"showUpdateDialogLabel": "Show update dialog",
"showUpdateDialogHint": "Show a dialog when a new update is available",
"universalPatchesLabel": "Show universal patches",
"universalPatchesHint": "Display all apps and universal patches (may slow down the app list)",
"versionCompatibilityCheckLabel": "Version compatibility check",
"versionCompatibilityCheckHint": "Prevent selecting patches that are not compatible with the selected app version",
"requireSuggestedAppVersionLabel": "Require suggested app version",
"requireSuggestedAppVersionHint": "Prevent selecting an app with a version that is not the suggested",
"requireSuggestedAppVersionDialogText": "Selecting an app that is not the suggested version may cause unexpected issues.\n\nDo you want to proceed anyways?",
"aboutLabel": "About",
"snackbarMessage": "Copied to clipboard",
"restartAppForChanges": "Restart the app to apply changes",
"deleteTempDirLabel": "Delete temporary files",
"deleteTempDirHint": "Delete unused temporary files",
"deletedTempDir": "Temporary files deleted",
"exportPatchesLabel": "Export patch selection",
"exportPatchesHint": "Export patch selection to a JSON file",
"exportedPatches": "Patch selection exported",
"noExportFileFound": "No patch selection to export",
"importPatchesLabel": "Import patch selection",
"importPatchesHint": "Import patch selection from a JSON file",
"importedPatches": "Patch selection imported",
"resetStoredPatchesLabel": "Reset patch selection",
"resetStoredPatchesHint": "Reset the stored patch selection",
"resetStoredPatchesDialogTitle": "Reset patch selection?",
"resetStoredPatchesDialogText": "The default selection of patches will be restored.",
"resetStoredPatches": "Patch selection has been reset",
"resetStoredOptionsLabel": "Reset patch options",
"resetStoredOptionsHint": "Reset all patch options",
"resetStoredOptionsDialogTitle": "Reset patch options?",
"resetStoredOptionsDialogText": "Resetting patch options will remove all saved options.",
"resetStoredOptions": "Options have been reset",
"deleteLogsLabel": "Clear logs",
"deleteLogsHint": "Delete collected ReVanced Manager logs",
"deletedLogs": "Logs deleted",
"regenerateKeystoreLabel": "Regenerate keystore",
"regenerateKeystoreHint": "Regenerate the keystore used to sign apps",
"regenerateKeystoreDialogTitle": "Regenerate keystore?",
"regenerateKeystoreDialogText": "Patched apps signed with the old keystore will no longer be able to be updated.",
"regeneratedKeystore": "Keystore regenerated",
"exportKeystoreLabel": "Export keystore",
"exportKeystoreHint": "Export the keystore used to sign apps",
"exportedKeystore": "Keystore exported",
"noKeystoreExportFileFound": "No keystore to export",
"importKeystoreLabel": "Import keystore",
"importKeystoreHint": "Import a keystore used to sign apps",
"importedKeystore": "Keystore imported",
"selectKeystorePassword": "Keystore password",
"selectKeystorePasswordHint": "Select keystore password used to sign apps",
"jsonSelectorErrorMessage": "Unable to use selected JSON file",
"keystoreSelectorErrorMessage": "Unable to use selected keystore file"
},
"appInfoView": {
"widgetTitle": "App info",
"openButton": "Open",
"uninstallButton": "Uninstall",
"unmountButton": "Unmount",
"rootDialogTitle": "Error",
"unmountDialogText": "Are you sure you want to unmount this app?",
"uninstallDialogText": "Are you sure you want to uninstall this app?",
"rootDialogText": "App was installed with superuser permissions, but currently ReVanced Manager has no permissions.\nPlease grant superuser permissions first.",
"packageNameLabel": "Package name",
"installTypeLabel": "Installation type",
"mountTypeLabel": "Mount",
"regularTypeLabel": "Regular",
"patchedDateLabel": "Patched date",
"appliedPatchesLabel": "Applied patches",
"patchedDateHint": "{date} at {time}",
"appliedPatchesHint": "{quantity} applied patches",
"updateNotImplemented": "This feature has not been implemented yet"
},
"contributorsView": {
"widgetTitle": "Contributors",
"patcherContributors": "Patcher contributors",
"patchesContributors": "Patches contributors",
"integrationsContributors": "Integrations contributors",
"cliContributors": "CLI contributors",
"managerContributors": "Manager contributors"
},
"installErrorDialog": {
"mount_version_mismatch": "Version mismatch",
"mount_no_root": "No root access",
"mount_missing_installation": "Installation not found",
"status_failure_blocked": "Installation blocked",
"install_failed_verification_failure": "Verification failed",
"status_failure_invalid": "Installation invalid",
"install_failed_version_downgrade": "Can't downgrade",
"status_failure_conflict": "Installation conflict",
"status_failure_storage": "Installation storage issue",
"status_failure_incompatible": "Installation incompatible",
"status_failure_timeout": "Installation timeout",
"status_unknown": "Installation failed",
"mount_version_mismatch_description": "The installation failed due to the installed app being a different version than the patched app.\n\nInstall the version of the app you are mounting and try again.",
"mount_no_root_description": "The installation failed due to root access not being granted.\n\nGrant root access to ReVanced Manager and try again.",
"mount_missing_installation_description": "The installation failed due to the unpatched app not being installed on this device in order to mount over it.\n\nInstall the unpatched app before mounting and try again.",
"status_failure_timeout_description": "The installation took too long to finish.\n\nWould you like to try again?",
"status_failure_storage_description": "The installation failed due to insufficient storage.\n\nFree up some space and try again.",
"status_failure_invalid_description": "The installation failed due to the patched app being invalid.\n\nUninstall the app and try again?",
"status_failure_incompatible_description": "The app is incompatible with this device.\n\nContact the developer of the app and ask for support.",
"status_failure_conflict_description": "The installation was prevented by an existing installation of the app.\n\nUninstall the installed app and try again?",
"status_failure_blocked_description": "The installation was blocked by {packageName}.\n\nAdjust your security settings and try again.",
"install_failed_verification_failure_description": "The installation failed due to a verification issue.\n\nAdjust your security settings and try again.",
"install_failed_version_downgrade_description": "The installation failed due to the patched app being a lower version than the installed app.\n\nUninstall the app and try again?",
"status_unknown_description": "The installation failed due to an unknown reason. Please try again."
}
}

79
assets/i18n/nuke.dart Normal file
View File

@ -0,0 +1,79 @@
// ignore_for_file: avoid_print
import 'dart:convert';
import 'dart:io';
T? removeBlankEntries<T>(T? json) {
// This function is protected by BSD 3-Clause License
// Changes made to this section are allow removing of '' values from JSON
/*
https://pub.dev/documentation/swiss_knife/latest/swiss_knife/removeEmptyEntries.html
Copyright 2014, the Dart project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
if (json == null) {
return null;
}
if (json is List) {
json.removeWhere((e) => e == null);
json.forEach(removeBlankEntries);
} else if (json is Map) {
json.removeWhere(
(key, value) => key == null || value == null || value == '',
);
json.values.forEach(removeBlankEntries);
}
return json;
}
Future<void> processJsonFiles() async {
final Directory directory = Directory.current;
final List<FileSystemEntity> files = directory.listSync();
for (final file in files) {
try {
if (file is File && file.path.endsWith('.json')) {
final String contents = await file.readAsString();
final dynamic json = jsonDecode(contents);
final dynamic processedJson = removeBlankEntries(json);
file.writeAsString(
const JsonEncoder.withIndent(' ').convert(processedJson),
);
print('🥞 Task successful on: ${file.path}');
}
} catch (e) {
print('💥 Task failed on: ${file.path}: $e');
}
}
}
void main() async {
processJsonFiles();
}

View File

@ -0,0 +1,305 @@
{
"okButton": "OK",
"cancelButton": "Cancel",
"dismissButton": "Dismiss",
"quitButton": "Quit",
"updateButton": "Update",
"enabledLabel": "Enabled",
"disabledLabel": "Disabled",
"installed": "Installed: ${version}",
"suggested": "Suggested: ${version}",
"yesButton": "Yes",
"noButton": "No",
"warning": "Warning",
"options": "Options",
"notice": "Notice",
"noShowAgain": "Don't show this again",
"add": "Add",
"remove": "Remove",
"showChangelogButton": "Show changelog",
"showUpdateButton": "Show update",
"navigationView": {
"dashboardTab": "Dashboard",
"patcherTab": "Patcher",
"settingsTab": "Settings"
},
"homeView": {
"refreshSuccess": "Refreshed successfully",
"widgetTitle": "Dashboard",
"updatesSubtitle": "Updates",
"patchedSubtitle": "Patched apps",
"changeLaterSubtitle": "You can change this in the settings at a later time.",
"noUpdates": "No updates available",
"WIP": "Work in progress...",
"noInstallations": "No patched apps installed",
"installUpdate": "Continue to install the update?",
"updateSheetTitle": "Update ReVanced Manager",
"updateDialogTitle": "New update available",
"updatePatchesSheetTitle": "Update ReVanced Patches",
"updateChangelogTitle": "Changelog",
"updateDialogText": "A new update is available for ${file}.\n\nThe currently installed version is ${version}.",
"downloadConsentDialogTitle": "Download necessary files?",
"downloadConsentDialogText": "ReVanced Manager needs to download necessary files to work properly.",
"downloadConsentDialogText2": "This will connect you to ${url}.",
"checkUpdateDialogTitle": "Check for updates?",
"checkUpdateDialogText": "Do you want ReVanced Manager to check for updates automatically?",
"notificationTitle": "Update downloaded",
"notificationText": "Tap to install the update",
"downloadingMessage": "Downloading update...",
"downloadedMessage": "Update downloaded",
"installingMessage": "Installing update...",
"errorDownloadMessage": "Unable to download update",
"errorInstallMessage": "Unable to install update",
"noConnection": "No internet connection",
"updatesDisabled": "Updating a patched app is currently disabled. Repatch the app again."
},
"applicationItem": {
"infoButton": "Info"
},
"latestCommitCard": {
"loadingLabel": "Loading...",
"timeagoLabel": "${time} ago",
"patcherLabel": "Patcher: ",
"managerLabel": "Manager: ",
"updateButton": "Update Manager"
},
"patcherView": {
"widgetTitle": "Patcher",
"patchButton": "Patch",
"armv7WarningDialogText": "Patching on ARMv7 devices is not yet supported and might fail. Continue anyways?",
"removedPatchesWarningDialogText": "The following patches have been removed since the last time you used them.\n\n${patches}\n\nContinue anyways?",
"requiredOptionDialogText": "Some patch options have to be set."
},
"appSelectorCard": {
"widgetTitle": "Select an app",
"widgetTitleSelected": "Selected app",
"widgetSubtitle": "No app selected",
"noAppsLabel": "No applications found",
"currentVersion": "Current",
"suggestedVersion": "Suggested",
"anyVersion": "Any version"
},
"patchSelectorCard": {
"widgetTitle": "Select patches",
"widgetTitleSelected": "Selected patches",
"widgetSubtitle": "Select an application first",
"widgetEmptySubtitle": "No patches selected"
},
"socialMediaCard": {
"widgetTitle": "Socials",
"widgetSubtitle": "We are online!"
},
"appSelectorView": {
"viewTitle": "Select an app",
"searchBarHint": "Search app",
"storageButton": "Storage",
"selectFromStorageButton": "Select from storage",
"errorMessage": "Unable to use selected application",
"downloadToast": "Download function is not available yet",
"requireSuggestedAppVersionDialogText": "The version of the app you have selected does not match the suggested version which can lead to unexpected issues. Please use the suggested version.\n\nSelected version: ${selected}\nSuggested version: ${suggested}\n\nTo continue anyway, disable \"Require suggested app version\" in the settings.",
"featureNotAvailable": "Feature not implemented",
"featureNotAvailableText": "This app is a split APK and can only be patched and installed reliably by mounting with root permissions. However, you can patch and install a full APK by selecting it from storage."
},
"patchesSelectorView": {
"viewTitle": "Select patches",
"searchBarHint": "Search patches",
"universalPatches": "Universal patches",
"newPatches": "New patches",
"patches": "Patches",
"doneButton": "Done",
"defaultChip": "Default",
"defaultTooltip": "Select all default patches",
"noneChip": "None",
"noneTooltip": "Deselect all patches",
"loadPatchesSelection": "Load patch selection",
"noSavedPatches": "No saved patch selection for the selected app.\nPress Done to save the current selection.",
"noPatchesFound": "No patches found for the selected app",
"setRequiredOption": "Some patches require options to be set:\n\n${patches}\n\nPlease set them before continuing."
},
"patchOptionsView": {
"customValue": "Custom value",
"resetOptionsTooltip": "Reset patch options",
"viewTitle": "Patch options",
"saveOptions": "Save",
"addOptions": "Add options",
"deselectPatch": "Deselect patch",
"tooltip": "More input options",
"selectFilePath": "Select file path",
"selectFolder": "Select folder",
"selectOption": "Select option",
"requiredOption": "This option is required",
"unsupportedOption": "This option is not supported",
"requiredOptionNull": "The following options have to be set:\n\n${options}"
},
"patchItem": {
"unsupportedDialogText": "Selecting this patch may result in patching errors.\n\nApp version: ${packageVersion}\nSupported versions:\n${supportedVersions}",
"unsupportedPatchVersion": "Patch is not supported for this app version.",
"unsupportedRequiredOption": "This patch contains a required option that is not supported by this app",
"patchesChangeWarningDialogText": "It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou'll need to turn on \"Allow changing patch selection\" in the settings before changing any patch selection.",
"patchesChangeWarningDialogButton": "Use default selection"
},
"installerView": {
"widgetTitle": "Installer",
"installType": "Select install type",
"installTypeDescription": "Select the installation type to continue with.",
"installButton": "Install",
"installRootType": "Mount",
"installNonRootType": "Regular",
"warning": "Disable auto updates for the patched app to avoid unexpected issues.",
"pressBackAgain": "Press back again to cancel",
"openButton": "Open",
"shareButton": "Share file",
"notificationTitle": "ReVanced Manager is patching",
"notificationText": "Tap to return to the installer",
"exportApkButtonTooltip": "Export patched APK",
"exportLogButtonTooltip": "Export log",
"screenshotDetected": "A screenshot has been detected. If you are trying to share the log, please share a text copy instead.\n\nCopy log to clipboard?",
"copiedToClipboard": "Copied log to clipboard",
"noExit": "Installer is still running, cannot exit..."
},
"settingsView": {
"widgetTitle": "Settings",
"appearanceSectionTitle": "Appearance",
"teamSectionTitle": "Team",
"debugSectionTitle": "Debugging",
"advancedSectionTitle": "Advanced",
"exportSectionTitle": "Import & export",
"themeModeLabel": "App theme",
"systemThemeLabel": "System",
"lightThemeLabel": "Light",
"darkThemeLabel": "Dark",
"dynamicThemeLabel": "Material You",
"dynamicThemeHint": "Enjoy an experience closer to your device",
"languageLabel": "Language",
"languageUpdated": "Language updated",
"englishOption": "English",
"sourcesLabel": "Sources",
"sourcesLabelHint": "Configure the source of patches and integrations",
"sourcesIntegrationsLabel": "Integrations source",
"sourcesResetDialogTitle": "Reset",
"sourcesResetDialogText": "Are you sure you want to reset your sources to their default values?",
"apiURLResetDialogText": "Are you sure you want to reset your API URL to its default value?",
"sourcesUpdateNote": "Note: Patches will be updated to the latest version automatically.\n\nThis will reveal your IP address to the server.",
"apiURLLabel": "API URL",
"apiURLHint": "Configure the URL of the API to use",
"selectApiURL": "API URL",
"hostRepositoryLabel": "Repository API",
"orgPatchesLabel": "Patches organization",
"sourcesPatchesLabel": "Patches source",
"orgIntegrationsLabel": "Integrations organization",
"contributorsLabel": "Contributors",
"contributorsHint": "A list of contributors of ReVanced",
"logsLabel": "Share logs",
"logsHint": "Share ReVanced Manager logs",
"enablePatchesSelectionLabel": "Allow changing patch selection",
"enablePatchesSelectionHint": "Do not prevent selecting or deselecting patches",
"enablePatchesSelectionWarningText": "Changing the selection of patches may cause unexpected issues.\n\nEnable anyways?",
"disablePatchesSelectionWarningText": "You are about to disable changing the selection of patches.\nThe default selection of patches will be restored.\n\nDisable anyways?",
"autoUpdatePatchesLabel": "Auto update patches",
"autoUpdatePatchesHint": "Automatically update patches to the latest version",
"showUpdateDialogLabel": "Show update dialog",
"showUpdateDialogHint": "Show a dialog when a new update is available",
"universalPatchesLabel": "Show universal patches",
"universalPatchesHint": "Display all apps and universal patches (may slow down the app list)",
"versionCompatibilityCheckLabel": "Version compatibility check",
"versionCompatibilityCheckHint": "Prevent selecting patches that are not compatible with the selected app version",
"requireSuggestedAppVersionLabel": "Require suggested app version",
"requireSuggestedAppVersionHint": "Prevent selecting an app with a version that is not the suggested",
"requireSuggestedAppVersionDialogText": "Selecting an app that is not the suggested version may cause unexpected issues.\n\nDo you want to proceed anyways?",
"aboutLabel": "About",
"snackbarMessage": "Copied to clipboard",
"restartAppForChanges": "Restart the app to apply changes",
"deleteTempDirLabel": "Delete temporary files",
"deleteTempDirHint": "Delete unused temporary files",
"deletedTempDir": "Temporary files deleted",
"exportPatchesLabel": "Export patch selection",
"exportPatchesHint": "Export patch selection to a JSON file",
"exportedPatches": "Patch selection exported",
"noExportFileFound": "No patch selection to export",
"importPatchesLabel": "Import patch selection",
"importPatchesHint": "Import patch selection from a JSON file",
"importedPatches": "Patch selection imported",
"resetStoredPatchesLabel": "Reset patch selection",
"resetStoredPatchesHint": "Reset the stored patch selection",
"resetStoredPatchesDialogTitle": "Reset patch selection?",
"resetStoredPatchesDialogText": "The default selection of patches will be restored.",
"resetStoredPatches": "Patch selection has been reset",
"resetStoredOptionsLabel": "Reset patch options",
"resetStoredOptionsHint": "Reset all patch options",
"resetStoredOptionsDialogTitle": "Reset patch options?",
"resetStoredOptionsDialogText": "Resetting patch options will remove all saved options.",
"resetStoredOptions": "Options have been reset",
"deleteLogsLabel": "Clear logs",
"deleteLogsHint": "Delete collected ReVanced Manager logs",
"deletedLogs": "Logs deleted",
"regenerateKeystoreLabel": "Regenerate keystore",
"regenerateKeystoreHint": "Regenerate the keystore used to sign apps",
"regenerateKeystoreDialogTitle": "Regenerate keystore?",
"regenerateKeystoreDialogText": "Patched apps signed with the old keystore will no longer be able to be updated.",
"regeneratedKeystore": "Keystore regenerated",
"exportKeystoreLabel": "Export keystore",
"exportKeystoreHint": "Export the keystore used to sign apps",
"exportedKeystore": "Keystore exported",
"noKeystoreExportFileFound": "No keystore to export",
"importKeystoreLabel": "Import keystore",
"importKeystoreHint": "Import a keystore used to sign apps",
"importedKeystore": "Keystore imported",
"selectKeystorePassword": "Keystore password",
"selectKeystorePasswordHint": "Select keystore password used to sign apps",
"jsonSelectorErrorMessage": "Unable to use selected JSON file",
"keystoreSelectorErrorMessage": "Unable to use selected keystore file"
},
"appInfoView": {
"widgetTitle": "App info",
"openButton": "Open",
"uninstallButton": "Uninstall",
"unmountButton": "Unmount",
"rootDialogTitle": "Error",
"unmountDialogText": "Are you sure you want to unmount this app?",
"uninstallDialogText": "Are you sure you want to uninstall this app?",
"rootDialogText": "App was installed with superuser permissions, but currently ReVanced Manager has no permissions.\nPlease grant superuser permissions first.",
"packageNameLabel": "Package name",
"installTypeLabel": "Installation type",
"mountTypeLabel": "Mount",
"regularTypeLabel": "Regular",
"patchedDateLabel": "Patched date",
"appliedPatchesLabel": "Applied patches",
"patchedDateHint": "${date} at ${time}",
"appliedPatchesHint": "${quantity} applied patches",
"updateNotImplemented": "This feature has not been implemented yet"
},
"contributorsView": {
"widgetTitle": "Contributors",
"patcherContributors": "Patcher contributors",
"patchesContributors": "Patches contributors",
"integrationsContributors": "Integrations contributors",
"cliContributors": "CLI contributors",
"managerContributors": "Manager contributors"
},
"installErrorDialog": {
"mount_version_mismatch": "Version mismatch",
"mount_no_root": "No root access",
"mount_missing_installation": "Installation not found",
"status_failure_blocked": "Installation blocked",
"install_failed_verification_failure": "Verification failed",
"status_failure_invalid": "Installation invalid",
"install_failed_version_downgrade": "Can't downgrade",
"status_failure_conflict": "Installation conflict",
"status_failure_storage": "Installation storage issue",
"status_failure_incompatible": "Installation incompatible",
"status_failure_timeout": "Installation timeout",
"status_unknown": "Installation failed",
"mount_version_mismatch_description": "The installation failed due to the installed app being a different version than the patched app.\n\nInstall the version of the app you are mounting and try again.",
"mount_no_root_description": "The installation failed due to root access not being granted.\n\nGrant root access to ReVanced Manager and try again.",
"mount_missing_installation_description": "The installation failed due to the unpatched app not being installed on this device in order to mount over it.\n\nInstall the unpatched app before mounting and try again.",
"status_failure_timeout_description": "The installation took too long to finish.\n\nWould you like to try again?",
"status_failure_storage_description": "The installation failed due to insufficient storage.\n\nFree up some space and try again.",
"status_failure_invalid_description": "The installation failed due to the patched app being invalid.\n\nUninstall the app and try again?",
"status_failure_incompatible_description": "The app is incompatible with this device.\n\nContact the developer of the app and ask for support.",
"status_failure_conflict_description": "The installation was prevented by an existing installation of the app.\n\nUninstall the installed app and try again?",
"status_failure_blocked_description": "The installation was blocked by ${packageName}.\n\nAdjust your security settings and try again.",
"install_failed_verification_failure_description": "The installation failed due to a verification issue.\n\nAdjust your security settings and try again.",
"install_failed_version_downgrade_description": "The installation failed due to the patched app being a lower version than the installed app.\n\nUninstall the app and try again?",
"status_unknown_description": "The installation failed due to an unknown reason. Please try again."
}
}

View File

@ -1,4 +1,8 @@
preserve_hierarchy: 1
project_id_env: "CROWDIN_PROJECT_ID"
api_token_env: "CROWDIN_PERSONAL_TOKEN"
preserve_hierarchy: true
files:
- source: /assets/i18n/en_US.json
translation: /assets/i18n/%locale_with_underscore%.json
- source: /assets/i18n/strings.i18n.json
translation: /assets/i18n/strings_%locale_with_underscore%.i18n.json
skip_untranslated_strings: true

View File

@ -15,7 +15,13 @@ This page will guide you through building ReVanced Manager from source.
flutter pub get
```
4\. Delete conflicting outputs
4\. Generate translation file
```sh
dart run slang
```
5\. Delete conflicting outputs
> [!TIP]
> Must be run every time you sync your local repository with the remote repository.
@ -24,9 +30,7 @@ This page will guide you through building ReVanced Manager from source.
dart run build_runner build --delete-conflicting-outputs
```
5\. Build the APK
6\. Build the APK
```sh
flutter build apk

View File

@ -1,9 +1,6 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/download_manager.dart';
import 'package:revanced_manager/services/github_api.dart';
import 'package:revanced_manager/services/manager_api.dart';
@ -19,6 +16,7 @@ Future main() async {
await setupLocator();
WidgetsFlutterBinding.ensureInitialized();
await locator<ManagerAPI>().initialize();
await locator<DownloadManager>().initialize();
final String apiUrl = locator<ManagerAPI>().getApiUrl();
await locator<RevancedAPI>().initialize(apiUrl);
@ -34,7 +32,11 @@ Future main() async {
prefs = await SharedPreferences.getInstance();
runApp(const MyApp());
final managerAPI = locator<ManagerAPI>();
final locale = managerAPI.getLocale();
LocaleSettings.setLocaleRaw(locale);
runApp(TranslationProvider(child: const MyApp()));
}
class MyApp extends StatelessWidget {
@ -42,32 +44,9 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// String rawLocale = prefs.getString('language') ?? 'en_US';
// String replaceLocale = rawLocale.replaceAll('_', '-');
// List<String> localeList = replaceLocale.split('-');
// Locale locale = Locale(localeList[0], localeList[1]);
const Locale locale = Locale('en', 'US');
return DynamicThemeBuilder(
return const DynamicThemeBuilder(
title: 'ReVanced Manager',
home: const NavigationView(),
localizationsDelegates: [
FlutterI18nDelegate(
translationLoader: FileTranslationLoader(
fallbackFile: 'en_US',
forcedLocale: locale,
basePath: 'assets/i18n',
useCountryCode: true,
),
missingTranslationHandler: (key, locale) {
log(
'--> Missing translation: key: $key, languageCode: ${locale?.languageCode}',
);
},
),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: NavigationView(),
);
}
}

View File

@ -4,11 +4,11 @@ import 'package:device_apps/device_apps.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:injectable/injectable.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/github_api.dart';
@ -58,8 +58,7 @@ class ManagerAPI {
}
bool isDefaultIntegrationsRepo() {
return getIntegrationsRepo().toLowerCase() ==
defaultIntegrationsRepo;
return getIntegrationsRepo().toLowerCase() == defaultIntegrationsRepo;
}
Future<void> initialize() async {
@ -99,7 +98,7 @@ class ManagerAPI {
}
await _revancedAPI.clearAllCache();
await _prefs.setString('apiUrl', url);
_toast.showBottom('settingsView.restartAppForChanges');
_toast.showBottom(t.settingsView.restartAppForChanges);
}
String getRepoUrl() {
@ -302,6 +301,14 @@ class ManagerAPI {
return _prefs.getString('keystorePassword') ?? defaultKeystorePassword;
}
String getLocale() {
return _prefs.getString('locale') ?? 'en';
}
Future<void> setLocale(String value) async {
await _prefs.setString('locale', value);
}
Future<void> deleteTempFolder() async {
final Directory dir = Directory('/data/local/tmp/revanced-manager');
if (await dir.exists()) {
@ -615,7 +622,7 @@ class ManagerAPI {
builder: (context) => PopScope(
canPop: false,
child: AlertDialog(
title: I18nText('warning'),
title: Text(t.warning),
content: ValueListenableBuilder(
valueListenable: noShow,
builder: (context, value, child) {
@ -623,22 +630,19 @@ class ManagerAPI {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'patchItem.patchesChangeWarningDialogText',
child: const Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
Text(
t.patchItem.patchesChangeWarningDialogText,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
HapticCheckboxListTile(
value: value,
contentPadding: EdgeInsets.zero,
title: I18nText(
'noShowAgain',
title: Text(
t.noShowAgain,
),
onChanged: (selected) {
noShow.value = selected!;
@ -654,7 +658,7 @@ class ManagerAPI {
setPatchesChangeWarning(noShow.value);
Navigator.of(context).pop();
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),

View File

@ -6,10 +6,10 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:injectable/injectable.dart';
import 'package:path_provider/path_provider.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/manager_api.dart';
@ -304,18 +304,19 @@ class PatcherAPI {
context: _managerAPI.ctx!,
builder: (context) => AlertDialog(
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
title: I18nText('installErrorDialog.$statusValue'),
title: Text(t['installErrorDialog.$statusValue']),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
I18nText(
'installErrorDialog.${statusValue}_description',
translationParams: statusCode == 2
? {
'packageName': status['otherPackageName'],
}
: null,
Text(
t['installErrorDialog.${statusValue}_description'](
packageName: statusCode == 2
? {
'packageName': status['otherPackageName'],
}
: null,
),
),
],
),
@ -325,7 +326,7 @@ class PatcherAPI {
onPressed: () async {
Navigator.pop(context);
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
]
: <Widget>[
@ -334,14 +335,14 @@ class PatcherAPI {
onPressed: () {
Navigator.pop(context);
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
)
else
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
if (isFixable)
FilledButton(
@ -355,7 +356,7 @@ class PatcherAPI {
Navigator.pop(context);
}
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:fluttertoast/fluttertoast.dart' as t;
class Toast {
@ -12,10 +11,7 @@ class Toast {
void show(String text) {
t.Fluttertoast.showToast(
msg: FlutterI18n.translate(
_fToast.context!,
text,
),
msg: text,
toastLength: t.Toast.LENGTH_LONG,
gravity: t.ToastGravity.CENTER,
);
@ -23,10 +19,7 @@ class Toast {
void showBottom(String text) {
t.Fluttertoast.showToast(
msg: FlutterI18n.translate(
_fToast.context!,
text,
),
msg: text,
toastLength: t.Toast.LENGTH_LONG,
gravity: t.ToastGravity.BOTTOM,
);

View File

@ -3,9 +3,11 @@ import 'package:dynamic_color/dynamic_color.dart';
import 'package:dynamic_themes/dynamic_themes.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.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/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/theme.dart';
import 'package:stacked_services/stacked_services.dart';
@ -15,11 +17,9 @@ class DynamicThemeBuilder extends StatefulWidget {
super.key,
required this.title,
required this.home,
required this.localizationsDelegates,
});
final String title;
final Widget home;
final Iterable<LocalizationsDelegate> localizationsDelegates;
@override
State<DynamicThemeBuilder> createState() => _DynamicThemeBuilderState();
@ -108,7 +108,9 @@ class _DynamicThemeBuilderState extends State<DynamicThemeBuilder>
onGenerateRoute: StackedRouter().onGenerateRoute,
theme: theme,
home: widget.home,
localizationsDelegates: widget.localizationsDelegates,
localizationsDelegates: GlobalMaterialLocalizations.delegates,
locale: TranslationProvider.of(context).flutterLocale,
supportedLocales: AppLocaleUtils.supportedLocales,
),
);
},

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart' hide SearchBar;
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/appSelectorView/app_skeleton_loader.dart';
import 'package:revanced_manager/ui/widgets/appSelectorView/installed_app_item.dart';
@ -25,7 +25,7 @@ class _AppSelectorViewState extends State<AppSelectorView> {
viewModelBuilder: () => AppSelectorViewModel(),
builder: (context, model, child) => Scaffold(
floatingActionButton: HapticFloatingActionButtonExtended(
label: I18nText('appSelectorView.storageButton'),
label: Text(t.appSelectorView.storageButton),
icon: const Icon(Icons.sd_storage),
onPressed: () {
model.selectAppFromStorage(context);
@ -36,8 +36,8 @@ class _AppSelectorViewState extends State<AppSelectorView> {
SliverAppBar(
pinned: true,
floating: true,
title: I18nText(
'appSelectorView.viewTitle',
title: Text(
t.appSelectorView.viewTitle,
),
titleTextStyle: TextStyle(
fontSize: 22.0,
@ -58,10 +58,7 @@ class _AppSelectorViewState extends State<AppSelectorView> {
horizontal: 12.0,
),
child: SearchBar(
hintText: FlutterI18n.translate(
context,
'appSelectorView.searchBarHint',
),
hintText: t.appSelectorView.searchBarHint,
onQueryChanged: (searchQuery) {
setState(() {
_query = searchQuery;
@ -74,14 +71,10 @@ class _AppSelectorViewState extends State<AppSelectorView> {
SliverToBoxAdapter(
child: model.noApps
? Center(
child: I18nText(
'appSelectorCard.noAppsLabel',
child: Text(
'',
style: TextStyle(
color:
Theme.of(context).textTheme.titleLarge!.color,
),
child: Text(
t.appSelectorCard.noAppsLabel,
style: TextStyle(
color: Theme.of(context).textTheme.titleLarge!.color,
),
),
)

View File

@ -5,8 +5,8 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/manager_api.dart';
@ -168,25 +168,22 @@ class AppSelectorViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('warning'),
content: I18nText(
'appSelectorView.requireSuggestedAppVersionDialogText',
translationParams: {
'suggested': suggestedVersion,
'selected': selectedVersion,
},
child: const Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
title: Text(t.warning),
content: Text(
t.appSelectorView.requireSuggestedAppVersionDialogText(
suggested: suggestedVersion,
selected: selectedVersion,
),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
actions: [
FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -208,26 +205,20 @@ class AppSelectorViewModel extends BaseViewModel {
color: Theme.of(innerContext).colorScheme.primary,
),
const SizedBox(height: 20),
I18nText(
'appSelectorView.featureNotAvailable',
child: const Text(
'',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
wordSpacing: 1.5,
),
Text(
t.appSelectorView.featureNotAvailable,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
wordSpacing: 1.5,
),
),
const SizedBox(height: 20),
I18nText(
'appSelectorView.featureNotAvailableText',
child: const Text(
'',
style: TextStyle(
fontSize: 14,
),
Text(
t.appSelectorView.featureNotAvailableText,
style: const TextStyle(
fontSize: 14,
),
),
const SizedBox(height: 30),
@ -241,7 +232,7 @@ class AppSelectorViewModel extends BaseViewModel {
children: [
const Icon(Icons.sd_card),
const SizedBox(width: 10),
I18nText('appSelectorView.selectFromStorageButton'),
Text(t.appSelectorView.selectFromStorageButton),
],
),
),
@ -254,7 +245,7 @@ class AppSelectorViewModel extends BaseViewModel {
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(width: 10),
I18nText('cancelButton'),
Text(t.cancelButton),
],
),
),
@ -295,7 +286,7 @@ class AppSelectorViewModel extends BaseViewModel {
if (kDebugMode) {
print(e);
}
_toast.showBottom('appSelectorView.errorMessage');
_toast.showBottom(t.appSelectorView.errorMessage);
}
}
@ -323,5 +314,5 @@ class AppSelectorViewModel extends BaseViewModel {
}
void showDownloadToast() =>
_toast.showBottom('appSelectorView.downloadToast');
_toast.showBottom(t.appSelectorView.downloadToast);
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/contributors/contributors_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/contributorsView/contributors_card.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart';
@ -18,13 +18,10 @@ class ContributorsView extends StatelessWidget {
body: CustomScrollView(
slivers: <Widget>[
CustomSliverAppBar(
title: I18nText(
'contributorsView.widgetTitle',
child: Text(
'',
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
title: Text(
t.contributorsView.widgetTitle,
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
),
),
@ -34,27 +31,27 @@ class ContributorsView extends StatelessWidget {
delegate: SliverChildListDelegate.fixed(
<Widget>[
ContributorsCard(
title: 'contributorsView.patcherContributors',
title: t.contributorsView.patcherContributors,
contributors: model.patcherContributors,
),
const SizedBox(height: 20),
ContributorsCard(
title: 'contributorsView.patchesContributors',
title: t.contributorsView.patchesContributors,
contributors: model.patchesContributors,
),
const SizedBox(height: 20),
ContributorsCard(
title: 'contributorsView.integrationsContributors',
title: t.contributorsView.integrationsContributors,
contributors: model.integrationsContributors,
),
const SizedBox(height: 20),
ContributorsCard(
title: 'contributorsView.cliContributors',
title: t.contributorsView.cliContributors,
contributors: model.cliContributors,
),
const SizedBox(height: 20),
ContributorsCard(
title: 'contributorsView.managerContributors',
title: t.contributorsView.managerContributors,
contributors: model.managerContributors,
),
SizedBox(height: MediaQuery.viewPaddingOf(context).bottom),

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/homeView/installed_apps_card.dart';
import 'package:revanced_manager/ui/widgets/homeView/latest_commit_card.dart';
@ -25,13 +25,10 @@ class HomeView extends StatelessWidget {
slivers: <Widget>[
CustomSliverAppBar(
isMainView: true,
title: I18nText(
'homeView.widgetTitle',
child: Text(
'',
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
title: Text(
t.homeView.widgetTitle,
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
),
),
@ -40,22 +37,16 @@ class HomeView extends StatelessWidget {
sliver: SliverList(
delegate: SliverChildListDelegate.fixed(
<Widget>[
I18nText(
'homeView.updatesSubtitle',
child: Text(
'',
style: Theme.of(context).textTheme.titleLarge,
),
Text(
t.homeView.updatesSubtitle,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 10),
LatestCommitCard(model: model, parentContext: context),
const SizedBox(height: 23),
I18nText(
'homeView.patchedSubtitle',
child: Text(
'',
style: Theme.of(context).textTheme.titleLarge,
),
Text(
t.homeView.patchedSubtitle,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 10),
InstalledAppsCard(),

View File

@ -1,16 +1,17 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:async';
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:injectable/injectable.dart';
import 'package:path_provider/path_provider.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/app/app.router.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/github_api.dart';
import 'package:revanced_manager/services/manager_api.dart';
@ -68,12 +69,12 @@ class HomeViewModel extends BaseViewModel {
),
onDidReceiveNotificationResponse: (response) async {
if (response.id == 0) {
_toast.showBottom('homeView.installingMessage');
_toast.showBottom(t.homeView.installingMessage);
final File? managerApk = await _managerAPI.downloadManager();
if (managerApk != null) {
await _patcherAPI.installApk(context, managerApk.path);
} else {
_toast.showBottom('homeView.errorDownloadMessage');
_toast.showBottom(t.homeView.errorDownloadMessage);
}
}
},
@ -82,22 +83,21 @@ class HomeViewModel extends BaseViewModel {
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
final bool isConnected =
await Connectivity().checkConnectivity() != ConnectivityResult.none;
if (!isConnected) {
_toast.showBottom('homeView.noConnection');
_toast.showBottom(t.homeView.noConnection);
}
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
_toast.showBottom('homeView.installingMessage');
_toast.showBottom(t.homeView.installingMessage);
final File? managerApk = await _managerAPI.downloadManager();
if (managerApk != null) {
await _patcherAPI.installApk(context, managerApk.path);
} else {
_toast.showBottom('homeView.errorDownloadMessage');
_toast.showBottom(t.homeView.errorDownloadMessage);
}
}
}
@ -183,7 +183,7 @@ class HomeViewModel extends BaseViewModel {
builder: (context) => PopScope(
canPop: false,
child: AlertDialog(
title: I18nText('homeView.downloadConsentDialogTitle'),
title: Text(t.homeView.downloadConsentDialogTitle),
content: ValueListenableBuilder(
valueListenable: autoUpdate,
builder: (context, value, child) {
@ -191,31 +191,24 @@ class HomeViewModel extends BaseViewModel {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'homeView.downloadConsentDialogText',
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
Text(
t.homeView.downloadConsentDialogText,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: I18nText(
'homeView.downloadConsentDialogText2',
translationParams: {
'url': _managerAPI.defaultApiUrl.split('/')[2],
},
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.error,
),
child: Text(
t.homeView.downloadConsentDialogText2(
url: _managerAPI.defaultApiUrl.split('/')[2],
),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.error,
),
),
),
@ -229,7 +222,7 @@ class HomeViewModel extends BaseViewModel {
_managerAPI.setDownloadConsent(false);
SystemNavigator.pop();
},
child: I18nText('quitButton'),
child: Text(t.quitButton),
),
FilledButton(
onPressed: () async {
@ -237,7 +230,7 @@ class HomeViewModel extends BaseViewModel {
_managerAPI.setPatchesAutoUpdate(autoUpdate.value);
Navigator.of(context).pop();
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -251,7 +244,7 @@ class HomeViewModel extends BaseViewModel {
showDialog(
context: context,
builder: (innerContext) => AlertDialog(
title: I18nText('homeView.updateDialogTitle'),
title: Text(t.homeView.updateDialogTitle),
content: ValueListenableBuilder(
valueListenable: noShow,
builder: (context, value, child) {
@ -259,33 +252,25 @@ class HomeViewModel extends BaseViewModel {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'homeView.updateDialogText',
translationParams: {
'file': isPatches ? 'ReVanced Patches' : 'ReVanced Manager',
'version': isPatches
Text(
t.homeView.updateDialogText(
file: isPatches ? 'ReVanced Patches' : 'ReVanced Manager',
version: isPatches
? _currentPatchesVersion
: _currentManagerVersion,
},
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
const SizedBox(height: 10),
HapticCheckboxListTile(
value: value,
contentPadding: EdgeInsets.zero,
title: I18nText(
'noShowAgain',
),
subtitle: I18nText(
'homeView.changeLaterSubtitle',
),
title: Text(t.noShowAgain),
subtitle: Text(t.homeView.changeLaterSubtitle),
onChanged: (selected) {
noShow.value = selected!;
},
@ -300,7 +285,7 @@ class HomeViewModel extends BaseViewModel {
_managerAPI.setShowUpdateDialog(!noShow.value);
Navigator.pop(innerContext);
},
child: I18nText('dismissButton'), // Decide later
child: Text(t.dismissButton), // Decide later
),
FilledButton(
onPressed: () async {
@ -308,7 +293,7 @@ class HomeViewModel extends BaseViewModel {
Navigator.pop(innerContext);
await showUpdateConfirmationDialog(context, isPatches);
},
child: I18nText('showUpdateButton'),
child: Text(t.showUpdateButton),
),
],
),
@ -316,7 +301,7 @@ class HomeViewModel extends BaseViewModel {
}
Future<void> updatePatches(BuildContext context) async {
_toast.showBottom('homeView.downloadingMessage');
_toast.showBottom(t.homeView.downloadingMessage);
final String patchesVersion =
await _managerAPI.getLatestPatchesVersion() ?? '0.0.0';
final String integrationsVersion =
@ -324,27 +309,27 @@ class HomeViewModel extends BaseViewModel {
if (patchesVersion != '0.0.0' && integrationsVersion != '0.0.0') {
await _managerAPI.setCurrentPatchesVersion(patchesVersion);
await _managerAPI.setCurrentIntegrationsVersion(integrationsVersion);
_toast.showBottom('homeView.downloadedMessage');
_toast.showBottom(t.homeView.downloadedMessage);
forceRefresh(context);
} else {
_toast.showBottom('homeView.errorDownloadMessage');
_toast.showBottom(t.homeView.errorDownloadMessage);
}
}
Future<void> updateManager(BuildContext context) async {
final ValueNotifier<bool> downloaded = ValueNotifier(false);
try {
_toast.showBottom('homeView.downloadingMessage');
_toast.showBottom(t.homeView.downloadingMessage);
showDialog(
context: context,
builder: (context) => ValueListenableBuilder(
valueListenable: downloaded,
builder: (context, value, child) {
return AlertDialog(
title: I18nText(
title: Text(
!value
? 'homeView.downloadingMessage'
: 'homeView.downloadedMessage',
? t.homeView.downloadingMessage
: t.homeView.downloadedMessage,
),
content: Column(
mainAxisSize: MainAxisSize.min,
@ -373,7 +358,7 @@ class HomeViewModel extends BaseViewModel {
_revancedAPI.disposeManagerUpdateProgress();
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
),
],
@ -382,15 +367,12 @@ class HomeViewModel extends BaseViewModel {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'homeView.installUpdate',
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
Text(
t.homeView.installUpdate,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
const SizedBox(height: 16.0),
@ -403,7 +385,7 @@ class HomeViewModel extends BaseViewModel {
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
),
const SizedBox(width: 8.0),
@ -416,7 +398,7 @@ class HomeViewModel extends BaseViewModel {
downloadedApk!.path,
);
},
child: I18nText('updateButton'),
child: Text(t.updateButton),
),
),
],
@ -457,21 +439,21 @@ class HomeViewModel extends BaseViewModel {
// uiLocalNotificationDateInterpretation:
// UILocalNotificationDateInterpretation.absoluteTime,
// );
_toast.showBottom('homeView.installingMessage');
_toast.showBottom(t.homeView.installingMessage);
await _patcherAPI.installApk(context, managerApk.path);
} else {
_toast.showBottom('homeView.errorDownloadMessage');
_toast.showBottom(t.homeView.errorDownloadMessage);
}
} on Exception catch (e) {
if (kDebugMode) {
print(e);
}
_toast.showBottom('homeView.errorInstallMessage');
_toast.showBottom(t.homeView.errorInstallMessage);
}
}
void updatesAreDisabled() {
_toast.showBottom('homeView.updatesDisabled');
_toast.showBottom(t.homeView.updatesDisabled);
}
Future<void> showUpdateConfirmationDialog(
@ -510,7 +492,7 @@ class HomeViewModel extends BaseViewModel {
Future<void> forceRefresh(BuildContext context) async {
_managerAPI.clearAllData();
_toast.showBottom('homeView.refreshSuccess');
_toast.showBottom(t.homeView.refreshSuccess);
initialize(context);
}
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/installerView/gradient_progress_indicator.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
@ -26,10 +26,10 @@ class InstallerView extends StatelessWidget {
floatingActionButton: Visibility(
visible: !model.isPatching && !model.hasErrors,
child: HapticFloatingActionButtonExtended(
label: I18nText(
label: Text(
model.isInstalled
? 'installerView.openButton'
: 'installerView.installButton',
? t.installerView.openButton
: t.installerView.installButton,
),
icon: model.isInstalled
? const Icon(Icons.open_in_new)
@ -54,19 +54,13 @@ class InstallerView extends StatelessWidget {
Visibility(
visible: !model.hasErrors,
child: IconButton.filledTonal(
tooltip: FlutterI18n.translate(
context,
'installerView.exportApkButtonTooltip',
),
tooltip: t.installerView.exportApkButtonTooltip,
icon: const Icon(Icons.save),
onPressed: () => model.onButtonPressed(0),
),
),
IconButton.filledTonal(
tooltip: FlutterI18n.translate(
context,
'installerView.exportLogButtonTooltip',
),
tooltip: t.installerView.exportLogButtonTooltip,
icon: const Icon(Icons.post_add),
onPressed: () => model.onButtonPressed(1),
),

View File

@ -4,9 +4,9 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_background/flutter_background.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/manager_api.dart';
@ -49,14 +49,8 @@ class InstallerViewModel extends BaseViewModel {
try {
FlutterBackground.initialize(
androidConfig: FlutterBackgroundAndroidConfig(
notificationTitle: FlutterI18n.translate(
context,
'installerView.notificationTitle',
),
notificationText: FlutterI18n.translate(
context,
'installerView.notificationText',
),
notificationTitle: t.installerView.notificationTitle,
notificationText: t.installerView.notificationText,
notificationIcon: const AndroidResource(
name: 'ic_notification',
),
@ -280,26 +274,26 @@ class InstallerViewModel extends BaseViewModel {
];
Clipboard.setData(ClipboardData(text: formattedLogs.join('\n')));
_toast.showBottom('installerView.copiedToClipboard');
_toast.showBottom(t.installerView.copiedToClipboard);
}
Future<void> screenshotDetected(BuildContext context) async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText(
'warning',
title: Text(
t.warning,
),
icon: const Icon(Icons.warning),
content: SingleChildScrollView(
child: I18nText('installerView.screenshotDetected'),
child: Text(t.installerView.screenshotDetected),
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () {
@ -307,7 +301,7 @@ class InstallerViewModel extends BaseViewModel {
showPopupScreenshotWarning = true;
Navigator.of(context).pop();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),
@ -321,8 +315,8 @@ class InstallerViewModel extends BaseViewModel {
context: context,
barrierDismissible: false,
builder: (innerContext) => AlertDialog(
title: I18nText(
'installerView.installType',
title: Text(
t.installerView.installType,
),
icon: const Icon(Icons.file_download_outlined),
contentPadding: const EdgeInsets.symmetric(vertical: 16),
@ -339,20 +333,17 @@ class InstallerViewModel extends BaseViewModel {
horizontal: 20,
vertical: 10,
),
child: I18nText(
'installerView.installTypeDescription',
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
child: Text(
t.installerView.installTypeDescription,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
),
RadioListTile(
title: I18nText('installerView.installNonRootType'),
title: Text(t.installerView.installNonRootType),
contentPadding:
const EdgeInsets.symmetric(horizontal: 16),
value: 0,
@ -362,7 +353,7 @@ class InstallerViewModel extends BaseViewModel {
},
),
RadioListTile(
title: I18nText('installerView.installRootType'),
title: Text(t.installerView.installRootType),
contentPadding:
const EdgeInsets.symmetric(horizontal: 16),
value: 1,
@ -373,14 +364,11 @@ class InstallerViewModel extends BaseViewModel {
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: I18nText(
'installerView.warning',
child: Text(
'',
style: TextStyle(
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.error,
),
child: Text(
t.installerView.warning,
style: TextStyle(
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.error,
),
),
),
@ -394,14 +382,14 @@ class InstallerViewModel extends BaseViewModel {
onPressed: () {
Navigator.of(innerContext).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
FilledButton(
onPressed: () {
Navigator.of(innerContext).pop();
installResult(context, installType.value == 1);
},
child: I18nText('installerView.installButton'),
child: Text(t.installerView.installButton),
),
],
),
@ -411,24 +399,22 @@ class InstallerViewModel extends BaseViewModel {
context: context,
barrierDismissible: false,
builder: (innerContext) => AlertDialog(
title: I18nText(
'warning',
),
title: Text(t.warning),
contentPadding: const EdgeInsets.all(16),
content: I18nText('installerView.warning'),
content: Text(t.installerView.warning),
actions: [
TextButton(
onPressed: () {
Navigator.of(innerContext).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
FilledButton(
onPressed: () {
Navigator.of(innerContext).pop();
installResult(context, false);
},
child: I18nText('installerView.installButton'),
child: Text(t.installerView.installButton),
),
],
),
@ -544,11 +530,11 @@ class InstallerViewModel extends BaseViewModel {
if (isPatching) {
if (!cancel) {
cancel = true;
_toast.showBottom('installerView.pressBackAgain');
_toast.showBottom(t.installerView.pressBackAgain);
} else if (!isCanceled) {
await stopPatcher();
} else {
_toast.showBottom('installerView.noExit');
_toast.showBottom(t.installerView.noExit);
}
return false;
}

View File

@ -1,7 +1,7 @@
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
import 'package:stacked/stacked.dart';
@ -43,30 +43,21 @@ class NavigationView extends StatelessWidget {
icon: model.isIndexSelected(0)
? const Icon(Icons.dashboard)
: const Icon(Icons.dashboard_outlined),
label: FlutterI18n.translate(
context,
'navigationView.dashboardTab',
),
label: t.navigationView.dashboardTab,
tooltip: '',
),
NavigationDestination(
icon: model.isIndexSelected(1)
? const Icon(Icons.build)
: const Icon(Icons.build_outlined),
label: FlutterI18n.translate(
context,
'navigationView.patcherTab',
),
label: t.navigationView.patcherTab,
tooltip: '',
),
NavigationDestination(
icon: model.isIndexSelected(2)
? const Icon(Icons.settings)
: const Icon(Icons.settings_outlined),
label: FlutterI18n.translate(
context,
'navigationView.settingsTab',
),
label: t.navigationView.settingsTab,
tooltip: '',
),
],

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/ui/views/patch_options/patch_options_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/patchesSelectorView/patch_options_fields.dart';
@ -25,19 +25,16 @@ class PatchOptionsView extends StatelessWidget {
Navigator.pop(context);
}
},
label: I18nText('patchOptionsView.saveOptions'),
label: Text(t.patchOptionsView.saveOptions),
icon: const Icon(Icons.save),
),
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: I18nText(
'patchOptionsView.viewTitle',
child: Text(
'',
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
title: Text(
t.patchOptionsView.viewTitle,
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
),
actions: [
@ -48,10 +45,7 @@ class PatchOptionsView extends StatelessWidget {
icon: const Icon(
Icons.history,
),
tooltip: FlutterI18n.translate(
context,
'patchOptionsView.resetOptionsTooltip',
),
tooltip: t.patchOptionsView.resetOptionsTooltip,
),
],
),
@ -111,7 +105,7 @@ class PatchOptionsView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.add),
I18nText('patchOptionsView.addOptions'),
Text(t.patchOptionsView.addOptions),
],
),
),

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
@ -137,8 +137,8 @@ class PatchOptionsViewModel extends BaseViewModel {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
I18nText(
'patchOptionsView.addOptions',
Text(
t.patchOptionsView.addOptions,
),
Text(
'',
@ -154,7 +154,7 @@ class PatchOptionsViewModel extends BaseViewModel {
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
],
contentPadding: const EdgeInsets.all(8),
@ -224,7 +224,7 @@ Future<void> showRequiredOptionNullDialog(
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('notice'),
title: Text(t.notice),
actions: [
TextButton(
onPressed: () async {
@ -248,20 +248,19 @@ Future<void> showRequiredOptionNullDialog(
PatchesSelectorViewModel().showPatchesChangeDialog(context);
}
},
child: I18nText('patchOptionsView.deselectPatch'),
child: Text(t.patchOptionsView.deselectPatch),
),
FilledButton(
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
content: I18nText(
'patchOptionsView.requiredOptionNull',
translationParams: {
'options': optionsTitles.join('\n'),
},
content: Text(
t.patchOptionsView.requiredOptionNull(
options: optionsTitles.join('\n'),
),
),
),
);

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/patcherView/app_selector_card.dart';
import 'package:revanced_manager/ui/widgets/patcherView/patch_selector_card.dart';
@ -21,7 +21,7 @@ class PatcherView extends StatelessWidget {
floatingActionButton: Visibility(
visible: model.showPatchButton(),
child: HapticFloatingActionButtonExtended(
label: I18nText('patcherView.patchButton'),
label: Text(t.patcherView.patchButton),
icon: const Icon(Icons.build),
onPressed: () async {
if (model.checkRequiredPatchOption(context)) {
@ -37,13 +37,10 @@ class PatcherView extends StatelessWidget {
slivers: <Widget>[
CustomSliverAppBar(
isMainView: true,
title: I18nText(
'patcherView.widgetTitle',
child: Text(
'',
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
title: Text(
t.patcherView.widgetTitle,
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
),
),

View File

@ -5,10 +5,10 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:injectable/injectable.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/app/app.router.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/manager_api.dart';
@ -54,24 +54,25 @@ class PatcherViewModel extends BaseViewModel {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('notice'),
content: I18nText(
'patcherView.removedPatchesWarningDialogText',
translationParams: {'patches': removedPatches.join('\n')},
title: Text(t.notice),
content: Text(
t.patcherView.removedPatchesWarningDialogText(
patches: removedPatches.join('\n'),
),
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () {
Navigator.of(context).pop();
showArmv7WarningDialog(context);
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),
@ -94,21 +95,21 @@ class PatcherViewModel extends BaseViewModel {
showDialog(
context: context ?? ctx,
builder: (context) => AlertDialog(
title: I18nText('notice'),
content: I18nText('patcherView.requiredOptionDialogText'),
title: Text(t.notice),
content: Text(t.patcherView.requiredOptionDialogText),
actions: <Widget>[
TextButton(
onPressed: () => {
Navigator.of(context).pop(),
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
FilledButton(
onPressed: () => {
Navigator.pop(context),
navigateToPatchesSelector(),
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -125,19 +126,19 @@ class PatcherViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('warning'),
content: I18nText('patcherView.armv7WarningDialogText'),
title: Text(t.warning),
content: Text(t.patcherView.armv7WarningDialogText),
actions: <Widget>[
FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('noButton'),
child: Text(t.noButton),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
navigateToInstaller();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart' hide SearchBar;
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_floating_action_button_extended.dart';
@ -40,7 +40,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
child: HapticFloatingActionButtonExtended(
label: Row(
children: <Widget>[
I18nText('patchesSelectorView.doneButton'),
Text(t.patchesSelectorView.doneButton),
Text(' (${model.selectedPatches.length})'),
],
),
@ -58,8 +58,8 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
SliverAppBar(
pinned: true,
floating: true,
title: I18nText(
'patchesSelectorView.viewTitle',
title: Text(
t.patchesSelectorView.viewTitle,
),
titleTextStyle: TextStyle(
fontSize: 22.0,
@ -99,8 +99,8 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
itemBuilder: (BuildContext context) => <PopupMenuEntry>[
PopupMenuItem(
value: 0,
child: I18nText(
'patchesSelectorView.loadPatchesSelection',
child: Text(
t.patchesSelectorView.loadPatchesSelection,
),
),
],
@ -114,10 +114,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
horizontal: 12.0,
),
child: SearchBar(
hintText: FlutterI18n.translate(
context,
'patchesSelectorView.searchBarHint',
),
hintText: t.patchesSelectorView.searchBarHint,
onQueryChanged: (searchQuery) {
setState(() {
_query = searchQuery;
@ -132,12 +129,9 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
? Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: I18nText(
'patchesSelectorView.noPatchesFound',
child: Text(
'',
style: Theme.of(context).textTheme.bodyMedium,
),
child: Text(
t.patchesSelectorView.noPatchesFound,
style: Theme.of(context).textTheme.bodyMedium,
),
),
)
@ -151,11 +145,8 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
Row(
children: [
ActionChip(
label: I18nText('patchesSelectorView.default'),
tooltip: FlutterI18n.translate(
context,
'patchesSelectorView.defaultTooltip',
),
label: Text(t.patchesSelectorView.defaultChip),
tooltip: t.patchesSelectorView.defaultTooltip,
onPressed: () {
if (_managerAPI.isPatchesChangeEnabled()) {
model.selectDefaultPatches();
@ -166,11 +157,8 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
),
const SizedBox(width: 8),
ActionChip(
label: I18nText('patchesSelectorView.none'),
tooltip: FlutterI18n.translate(
context,
'patchesSelectorView.noneTooltip',
),
label: Text(t.patchesSelectorView.noneChip),
tooltip: t.patchesSelectorView.noneTooltip,
onPressed: () {
if (_managerAPI.isPatchesChangeEnabled()) {
model.clearPatches();
@ -189,7 +177,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
children: [
model.getPatchCategory(
context,
'patchesSelectorView.newPatches',
t.patchesSelectorView.newPatches,
),
...model.getQueriedPatches(_query).map((patch) {
if (model.isPatchNew(patch)) {
@ -205,7 +193,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
))
model.getPatchCategory(
context,
'patchesSelectorView.patches',
t.patchesSelectorView.patches,
),
],
),
@ -227,7 +215,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
children: [
model.getPatchCategory(
context,
'patchesSelectorView.universalPatches',
t.patchesSelectorView.universalPatches,
),
...model.getQueriedPatches(_query).map((patch) {
if (patch.compatiblePackages.isEmpty &&

View File

@ -1,8 +1,8 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/app/app.router.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/manager_api.dart';
@ -92,19 +92,18 @@ class PatchesSelectorViewModel extends BaseViewModel {
barrierDismissible: false,
context: context,
builder: (context) => AlertDialog(
title: I18nText('notice'),
content: I18nText(
'patchesSelectorView.setRequiredOption',
translationParams: {
'patches': patches.map((patch) => '$patch').join('\n'),
},
title: Text(t.notice),
content: Text(
t.patchesSelectorView.setRequiredOption(
patches: patches.map((patch) => '$patch').join('\n'),
),
),
actions: <Widget>[
FilledButton(
onPressed: () => {
Navigator.of(context).pop(),
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -128,21 +127,18 @@ class PatchesSelectorViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('warning'),
content: I18nText(
'patchItem.patchesChangeWarningDialogText',
child: const Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
title: Text(t.warning),
content: Text(
t.patchItem.patchesChangeWarningDialogText,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('okButton'),
child: Text(t.okButton),
),
FilledButton(
onPressed: () {
@ -150,7 +146,7 @@ class PatchesSelectorViewModel extends BaseViewModel {
..pop()
..pop();
},
child: I18nText('patchItem.patchesChangeWarningDialogButton'),
child: Text(t.patchItem.patchesChangeWarningDialogButton),
),
],
),
@ -257,13 +253,10 @@ class PatchesSelectorViewModel extends BaseViewModel {
bottom: 10.0,
left: 5.0,
),
child: I18nText(
child: Text(
category,
child: Text(
'',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
),
@ -321,7 +314,7 @@ class PatchesSelectorViewModel extends BaseViewModel {
this.selectedPatches.removeWhere((patch) => !isPatchSupported(patch));
}
} else {
locator<Toast>().showBottom('patchesSelectorView.noSavedPatches');
locator<Toast>().showBottom(t.patchesSelectorView.noSavedPatches);
}
notifyListeners();
} else {

View File

@ -1,8 +1,8 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart';
import 'package:stacked/stacked.dart';
@ -20,7 +20,7 @@ class SManageApiUrl extends BaseViewModel {
builder: (context) => AlertDialog(
title: Row(
children: <Widget>[
I18nText('settingsView.apiURLLabel'),
Text(t.settingsView.apiURLLabel),
const Spacer(),
IconButton(
icon: const Icon(Icons.manage_history_outlined),
@ -42,10 +42,7 @@ class SManageApiUrl extends BaseViewModel {
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.selectApiURL',
),
labelText: t.settingsView.selectApiURL,
hintText: apiUrl,
),
),
@ -58,7 +55,7 @@ class SManageApiUrl extends BaseViewModel {
_apiUrlController.clear();
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
FilledButton(
onPressed: () {
@ -69,7 +66,7 @@ class SManageApiUrl extends BaseViewModel {
_managerAPI.setApiUrl(apiUrl);
Navigator.of(context).pop();
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -80,12 +77,12 @@ class SManageApiUrl extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('settingsView.sourcesResetDialogTitle'),
content: I18nText('settingsView.apiURLResetDialogText'),
title: Text(t.settingsView.sourcesResetDialogTitle),
content: Text(t.settingsView.apiURLResetDialogText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () {
@ -94,7 +91,7 @@ class SManageApiUrl extends BaseViewModel {
..pop()
..pop();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),
@ -111,8 +108,8 @@ class SManageApiUrlUI extends StatelessWidget {
Widget build(BuildContext context) {
return SettingsTileDialog(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
title: 'settingsView.apiURLLabel',
subtitle: 'settingsView.apiURLHint',
title: t.settingsView.apiURLLabel,
subtitle: t.settingsView.apiURLHint,
onTap: () => sManageApiUrl.showApiUrlDialog(context),
);
}

View File

@ -1,8 +1,8 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart';
import 'package:stacked/stacked.dart';
@ -21,7 +21,7 @@ class SManageKeystorePassword extends BaseViewModel {
builder: (context) => AlertDialog(
title: Row(
children: <Widget>[
I18nText('settingsView.selectKeystorePassword'),
Text(t.settingsView.selectKeystorePassword),
const Spacer(),
IconButton(
icon: const Icon(Icons.manage_history_outlined),
@ -41,10 +41,7 @@ class SManageKeystorePassword extends BaseViewModel {
onChanged: (value) => notifyListeners(),
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.selectKeystorePassword',
),
labelText: t.settingsView.selectKeystorePassword,
),
),
],
@ -56,7 +53,7 @@ class SManageKeystorePassword extends BaseViewModel {
_keystorePasswordController.clear();
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
FilledButton(
onPressed: () {
@ -64,7 +61,7 @@ class SManageKeystorePassword extends BaseViewModel {
_managerAPI.setKeystorePassword(passwd);
Navigator.of(context).pop();
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -81,8 +78,8 @@ class SManageKeystorePasswordUI extends StatelessWidget {
Widget build(BuildContext context) {
return SettingsTileDialog(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
title: 'settingsView.selectKeystorePassword',
subtitle: 'settingsView.selectKeystorePasswordHint',
title: t.settingsView.selectKeystorePassword,
subtitle: t.settingsView.selectKeystorePasswordHint,
onTap: () => sManageKeystorePassword.showKeystoreDialog(context),
);
}

View File

@ -1,8 +1,8 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart';
@ -32,7 +32,7 @@ class SManageSources extends BaseViewModel {
builder: (context) => AlertDialog(
title: Row(
children: <Widget>[
I18nText('settingsView.sourcesLabel'),
Text(t.settingsView.sourcesLabel),
const Spacer(),
IconButton(
icon: const Icon(Icons.manage_history_outlined),
@ -58,10 +58,7 @@ class SManageSources extends BaseViewModel {
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.hostRepositoryLabel',
),
labelText: t.settingsView.hostRepositoryLabel,
hintText: hostRepository,
),
),
@ -77,10 +74,7 @@ class SManageSources extends BaseViewModel {
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.orgPatchesLabel',
),
labelText: t.settingsView.orgPatchesLabel,
hintText: patchesRepo.split('/')[0],
),
),
@ -96,10 +90,7 @@ class SManageSources extends BaseViewModel {
color: Colors.transparent,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.sourcesPatchesLabel',
),
labelText: t.settingsView.sourcesPatchesLabel,
hintText: patchesRepo.split('/')[1],
),
),
@ -115,10 +106,7 @@ class SManageSources extends BaseViewModel {
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.orgIntegrationsLabel',
),
labelText: t.settingsView.orgIntegrationsLabel,
hintText: integrationsRepo.split('/')[0],
),
),
@ -134,15 +122,12 @@ class SManageSources extends BaseViewModel {
color: Colors.transparent,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.sourcesIntegrationsLabel',
),
labelText: t.settingsView.sourcesIntegrationsLabel,
hintText: integrationsRepo.split('/')[1],
),
),
const SizedBox(height: 20),
I18nText('settingsView.sourcesUpdateNote'),
Text(t.settingsView.sourcesUpdateNote),
],
),
),
@ -155,7 +140,7 @@ class SManageSources extends BaseViewModel {
_intSourceController.clear();
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
FilledButton(
onPressed: () {
@ -168,10 +153,10 @@ class SManageSources extends BaseViewModel {
);
_managerAPI.setCurrentPatchesVersion('0.0.0');
_managerAPI.setCurrentIntegrationsVersion('0.0.0');
_toast.showBottom('settingsView.restartAppForChanges');
_toast.showBottom(t.settingsView.restartAppForChanges);
Navigator.of(context).pop();
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -182,12 +167,12 @@ class SManageSources extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('settingsView.sourcesResetDialogTitle'),
content: I18nText('settingsView.sourcesResetDialogText'),
title: Text(t.settingsView.sourcesResetDialogTitle),
content: Text(t.settingsView.sourcesResetDialogText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () {
@ -196,12 +181,12 @@ class SManageSources extends BaseViewModel {
_managerAPI.setIntegrationsRepo('');
_managerAPI.setCurrentPatchesVersion('0.0.0');
_managerAPI.setCurrentIntegrationsVersion('0.0.0');
_toast.showBottom('settingsView.restartAppForChanges');
_toast.showBottom(t.settingsView.restartAppForChanges);
Navigator.of(context)
..pop()
..pop();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),
@ -218,8 +203,8 @@ class SManageSourcesUI extends StatelessWidget {
Widget build(BuildContext context) {
return SettingsTileDialog(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
title: 'settingsView.sourcesLabel',
subtitle: 'settingsView.sourcesLabelHint',
title: t.settingsView.sourcesLabel,
subtitle: t.settingsView.sourcesLabelHint,
onTap: () => sManageSources.showSourcesDialog(context),
);
}

View File

@ -1,76 +1,101 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:language_code/language_code.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/main.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stacked/stacked.dart';
import 'package:timeago/timeago.dart' as timeago;
final _settingViewModel = SettingsViewModel();
class SUpdateLanguage extends BaseViewModel {
final Toast _toast = locator<Toast>();
late SharedPreferences _prefs;
String selectedLanguage = 'English';
String selectedLanguageLocale = prefs.getString('language') ?? 'en_US';
List languages = [];
final ManagerAPI _managerAPI = locator<ManagerAPI>();
Future<void> initialize() async {
_prefs = await SharedPreferences.getInstance();
selectedLanguageLocale =
_prefs.getString('language') ?? selectedLanguageLocale;
_prefs.getString('language');
notifyListeners();
}
Future<void> updateLanguage(BuildContext context, String? value) async {
if (value != null) {
selectedLanguageLocale = value;
_prefs = await SharedPreferences.getInstance();
await _prefs.setString('language', value);
await FlutterI18n.refresh(context, Locale(value));
timeago.setLocaleMessages(value, timeago.EnMessages());
locator<NavigationViewModel>().notifyListeners();
notifyListeners();
}
}
Future<void> initLang() async {
languages.sort((a, b) => a['name'].compareTo(b['name']));
notifyListeners();
Future<void> updateLocale(String locale) async {
LocaleSettings.setLocaleRaw(locale);
_managerAPI.setLocale(locale);
Future.delayed(
const Duration(milliseconds: 120),
() => _toast.showBottom(t.settingsView.languageUpdated),
);
}
Future<void> showLanguagesDialog(BuildContext parentContext) {
initLang();
final ValueNotifier<String> selectedLanguageCode =
ValueNotifier(LocaleSettings.currentLocale.languageCode);
// initLang();
// Return a dialog with list for each language supported by the application.
// the dialog will display the english and native name of each languages,
// the current language will be highlighted by selected radio button.
return showDialog(
context: parentContext,
builder: (context) => SimpleDialog(
title: I18nText('settingsView.languageLabel'),
children: [
SizedBox(
height: 500,
child: ListView.builder(
itemCount: languages.length,
itemBuilder: (context, index) {
return RadioListTile<String>(
title: Text(languages[index]['name']),
subtitle: Text(languages[index]['locale']),
value: languages[index]['locale'],
groupValue: selectedLanguageLocale,
onChanged: (value) {
selectedLanguage = languages[index]['name'];
_toast.showBottom('settingsView.restartAppForChanges');
updateLanguage(context, value);
Navigator.pop(context);
builder: (context) => AlertDialog(
title: Text(t.settingsView.languageLabel),
icon: const Icon(Icons.language),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
contentPadding: EdgeInsets.zero,
content: ValueListenableBuilder(
valueListenable: selectedLanguageCode,
builder: (context, value, child) {
return SingleChildScrollView(
child: ListBody(
children: AppLocale.values.map(
(locale) {
LanguageCodes? languageCode;
Text? languageNativeName;
try {
languageCode =
LanguageCodes.fromCode(locale.languageCode);
} catch (e) {}
if (languageCode != null) {
languageNativeName = Text(languageCode.nativeName);
}
return RadioListTile(
title: Text(
languageCode?.englishName ?? locale.languageCode,
),
subtitle: languageNativeName,
value: locale.languageCode == selectedLanguageCode.value,
groupValue: true,
onChanged: (value) {
selectedLanguageCode.value = locale.languageCode;
},
);
},
);
},
),
).toList(),
),
);
},
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(t.cancelButton),
),
TextButton(
onPressed: () {
updateLocale(selectedLanguageCode.value);
Navigator.of(context).pop();
},
child: Text(t.okButton),
),
],
),
@ -85,8 +110,10 @@ class SUpdateLanguageUI extends StatelessWidget {
Widget build(BuildContext context) {
return SettingsTileDialog(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
title: 'settingsView.languageLabel',
subtitle: _settingViewModel.sUpdateLanguage.selectedLanguage,
title: t.settingsView.languageLabel,
subtitle:
LanguageCodes.fromCode(LocaleSettings.currentLocale.languageCode)
.nativeName,
onTap: () =>
_settingViewModel.sUpdateLanguage.showLanguagesDialog(context),
);

View File

@ -3,8 +3,8 @@
import 'package:dynamic_themes/dynamic_themes.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_radio_list_tile.dart';
@ -23,18 +23,15 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
@override
Widget build(BuildContext context) {
return SettingsSection(
title: 'settingsView.appearanceSectionTitle',
title: t.settingsView.appearanceSectionTitle,
children: <Widget>[
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.themeModeLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.themeModeLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
trailing: FilledButton(
@ -46,17 +43,14 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
if (managerAPI.isDynamicThemeAvailable)
HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.dynamicThemeLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.dynamicThemeLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.dynamicThemeHint'),
subtitle: Text(t.settingsView.dynamicThemeHint),
value: getDynamicThemeStatus(),
onChanged: (value) => {
setUseDynamicTheme(
@ -101,16 +95,16 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
setState(() {});
}
I18nText getThemeModeName() {
Text getThemeModeName() {
switch (getThemeMode()) {
case 0:
return I18nText('settingsView.systemThemeLabel');
return Text(t.settingsView.systemThemeLabel);
case 1:
return I18nText('settingsView.lightThemeLabel');
return Text(t.settingsView.lightThemeLabel);
case 2:
return I18nText('settingsView.darkThemeLabel');
return Text(t.settingsView.darkThemeLabel);
default:
return I18nText('settingsView.systemThemeLabel');
return Text(t.settingsView.systemThemeLabel);
}
}
@ -120,7 +114,7 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('settingsView.themeModeLabel'),
title: Text(t.settingsView.themeModeLabel),
icon: const Icon(Icons.palette),
contentPadding: const EdgeInsets.symmetric(vertical: 16),
content: SingleChildScrollView(
@ -132,7 +126,7 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
HapticRadioListTile(
title: I18nText('settingsView.systemThemeLabel'),
title: Text(t.settingsView.systemThemeLabel),
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
value: 0,
groupValue: value,
@ -141,7 +135,7 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
},
),
HapticRadioListTile(
title: I18nText('settingsView.lightThemeLabel'),
title: Text(t.settingsView.lightThemeLabel),
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
value: 1,
groupValue: value,
@ -150,7 +144,7 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
},
),
HapticRadioListTile(
title: I18nText('settingsView.darkThemeLabel'),
title: Text(t.settingsView.darkThemeLabel),
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
value: 2,
groupValue: value,
@ -168,14 +162,14 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
child: Text(t.cancelButton),
),
FilledButton(
onPressed: () {
setThemeMode(context, newTheme.value);
Navigator.of(context).pop();
},
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),

View File

@ -1,8 +1,9 @@
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_update_language.dart';
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_update_theme.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_advanced_section.dart';
@ -27,13 +28,10 @@ class SettingsView extends StatelessWidget {
slivers: <Widget>[
CustomSliverAppBar(
isMainView: true,
title: I18nText(
'settingsView.widgetTitle',
child: Text(
'',
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
title: Text(
t.settingsView.widgetTitle,
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
),
),
@ -47,7 +45,7 @@ class SettingsView extends StatelessWidget {
children: const [
SUpdateThemeUI(),
// _settingsDivider,
// SUpdateLanguageUI(),
SUpdateLanguageUI(),
_settingsDivider,
SAdvancedSection(),
_settingsDivider,

View File

@ -1,12 +1,13 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:logcat/logcat.dart';
import 'package:path_provider/path_provider.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/app/app.router.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
@ -60,15 +61,12 @@ class SettingsViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('warning'),
content: I18nText(
'settingsView.enablePatchesSelectionWarningText',
child: const Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
title: Text(t.warning),
content: Text(
t.settingsView.enablePatchesSelectionWarningText,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
actions: [
@ -78,13 +76,13 @@ class SettingsViewModel extends BaseViewModel {
_managerAPI.setPatchesChangeEnabled(true);
Navigator.of(context).pop();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
FilledButton(
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('noButton'),
child: Text(t.noButton),
),
],
),
@ -93,15 +91,12 @@ class SettingsViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('warning'),
content: I18nText(
'settingsView.disablePatchesSelectionWarningText',
child: const Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
title: Text(t.warning),
content: Text(
t.settingsView.disablePatchesSelectionWarningText,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
actions: [
@ -109,7 +104,7 @@ class SettingsViewModel extends BaseViewModel {
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () {
@ -118,7 +113,7 @@ class SettingsViewModel extends BaseViewModel {
_managerAPI.setPatchesChangeEnabled(false);
Navigator.of(context).pop();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),
@ -156,15 +151,12 @@ class SettingsViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('warning'),
content: I18nText(
'settingsView.requireSuggestedAppVersionDialogText',
child: const Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
title: Text(t.warning),
content: Text(
t.settingsView.requireSuggestedAppVersionDialogText,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
actions: [
@ -173,13 +165,13 @@ class SettingsViewModel extends BaseViewModel {
_managerAPI.enableRequireSuggestedAppVersionStatus(false);
Navigator.of(context).pop();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
FilledButton(
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('noButton'),
child: Text(t.noButton),
),
],
),
@ -197,13 +189,13 @@ class SettingsViewModel extends BaseViewModel {
void deleteKeystore() {
_managerAPI.deleteKeystore();
_toast.showBottom('settingsView.regeneratedKeystore');
_toast.showBottom(t.settingsView.regeneratedKeystore);
notifyListeners();
}
void deleteTempDir() {
_managerAPI.deleteTempFolder();
_toast.showBottom('settingsView.deletedTempDir');
_toast.showBottom(t.settingsView.deletedTempDir);
notifyListeners();
}
@ -219,9 +211,9 @@ class SettingsViewModel extends BaseViewModel {
fileName: 'selected_patches_$dateTime.json',
),
);
_toast.showBottom('settingsView.exportedPatches');
_toast.showBottom(t.settingsView.exportedPatches);
} else {
_toast.showBottom('settingsView.noExportFileFound');
_toast.showBottom(t.settingsView.noExportFileFound);
}
} on Exception catch (e) {
if (kDebugMode) {
@ -245,13 +237,13 @@ class SettingsViewModel extends BaseViewModel {
if (_patcherViewModel.selectedApp != null) {
_patcherViewModel.loadLastSelectedPatches();
}
_toast.showBottom('settingsView.importedPatches');
_toast.showBottom(t.settingsView.importedPatches);
}
} on Exception catch (e) {
if (kDebugMode) {
print(e);
}
_toast.showBottom('settingsView.jsonSelectorErrorMessage');
_toast.showBottom(t.settingsView.jsonSelectorErrorMessage);
}
} else {
_managerAPI.showPatchesChangeWarningDialog(context);
@ -270,9 +262,9 @@ class SettingsViewModel extends BaseViewModel {
fileName: 'keystore_$dateTime.keystore',
),
);
_toast.showBottom('settingsView.exportedKeystore');
_toast.showBottom(t.settingsView.exportedKeystore);
} else {
_toast.showBottom('settingsView.noKeystoreExportFileFound');
_toast.showBottom(t.settingsView.noKeystoreExportFileFound);
}
} on Exception catch (e) {
if (kDebugMode) {
@ -288,24 +280,24 @@ class SettingsViewModel extends BaseViewModel {
final File inFile = File(result);
inFile.copySync(_managerAPI.keystoreFile);
_toast.showBottom('settingsView.importedKeystore');
_toast.showBottom(t.settingsView.importedKeystore);
}
} on Exception catch (e) {
if (kDebugMode) {
print(e);
}
_toast.showBottom('settingsView.keystoreSelectorErrorMessage');
_toast.showBottom(t.settingsView.keystoreSelectorErrorMessage);
}
}
void resetAllOptions() {
_managerAPI.resetAllOptions();
_toast.showBottom('settingsView.resetStoredOptions');
_toast.showBottom(t.settingsView.resetStoredOptions);
}
void resetSelectedPatches() {
_managerAPI.resetLastSelectedPatches();
_toast.showBottom('settingsView.resetStoredPatches');
_toast.showBottom(t.settingsView.resetStoredPatches);
}
Future<void> deleteLogs() async {
@ -314,7 +306,7 @@ class SettingsViewModel extends BaseViewModel {
if (logsDir.existsSync()) {
logsDir.deleteSync(recursive: true);
}
_toast.showBottom('settingsView.deletedLogs');
_toast.showBottom(t.settingsView.deletedLogs);
}
Future<void> exportLogcatLogs() async {

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/ui/widgets/appInfoView/app_info_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
@ -22,13 +22,10 @@ class AppInfoView extends StatelessWidget {
body: CustomScrollView(
slivers: <Widget>[
CustomSliverAppBar(
title: I18nText(
'appInfoView.widgetTitle',
child: Text(
'',
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
title: Text(
t.appInfoView.widgetTitle,
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
),
),
@ -86,16 +83,13 @@ class AppInfoView extends StatelessWidget {
.primary,
),
const SizedBox(height: 10),
I18nText(
'appInfoView.openButton',
child: Text(
'',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontWeight: FontWeight.bold,
),
Text(
t.appInfoView.openButton,
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontWeight: FontWeight.bold,
),
),
],
@ -130,16 +124,13 @@ class AppInfoView extends StatelessWidget {
.primary,
),
const SizedBox(height: 10),
I18nText(
'appInfoView.uninstallButton',
child: Text(
'',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontWeight: FontWeight.bold,
),
Text(
t.appInfoView.uninstallButton,
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontWeight: FontWeight.bold,
),
),
],
@ -183,16 +174,13 @@ class AppInfoView extends StatelessWidget {
.primary,
),
const SizedBox(height: 10),
I18nText(
'appInfoView.unmountButton',
child: Text(
'',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontWeight: FontWeight.bold,
),
Text(
t.appInfoView.unmountButton,
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontWeight: FontWeight.bold,
),
),
],
@ -209,14 +197,11 @@ class AppInfoView extends StatelessWidget {
ListTile(
contentPadding:
const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'appInfoView.packageNameLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.appInfoView.packageNameLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: Text(app.packageName),
@ -225,61 +210,50 @@ class AppInfoView extends StatelessWidget {
ListTile(
contentPadding:
const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'appInfoView.installTypeLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.appInfoView.installTypeLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: app.isRooted
? I18nText('appInfoView.mountTypeLabel')
: I18nText('appInfoView.regularTypeLabel'),
? Text(t.appInfoView.mountTypeLabel)
: Text(t.appInfoView.regularTypeLabel),
),
const SizedBox(height: 4),
ListTile(
contentPadding:
const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'appInfoView.patchedDateLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.appInfoView.patchedDateLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText(
'appInfoView.patchedDateHint',
translationParams: {
'date': model.getPrettyDate(context, app.patchDate),
'time': model.getPrettyTime(context, app.patchDate),
},
subtitle: Text(
t.appInfoView.patchedDateHint(
date: model.getPrettyDate(context, app.patchDate),
time: model.getPrettyTime(context, app.patchDate),
),
),
),
const SizedBox(height: 4),
ListTile(
contentPadding:
const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'appInfoView.appliedPatchesLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.appInfoView.appliedPatchesLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText(
'appInfoView.appliedPatchesHint',
translationParams: {
'quantity': app.appliedPatches.length.toString(),
},
subtitle: Text(
t.appInfoView.appliedPatchesHint(
quantity: app.appliedPatches.length.toString(),
),
),
onTap: () => model.showAppliedPatchesDialog(context, app),
),

View File

@ -1,9 +1,9 @@
// ignore_for_file: use_build_context_synchronously
import 'package:device_apps/device_apps.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:intl/intl.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/patcher_api.dart';
@ -32,7 +32,7 @@ class AppInfoViewModel extends BaseViewModel {
isUninstalled = await DeviceApps.uninstallApp(app.packageName);
}
if (isUninstalled && app.isRooted && await _rootAPI.hasRootPermissions()) {
if (isUninstalled && app.isRooted && await _rootAPI.hasRootPermissions()) {
await _rootAPI.uninstall(app.packageName);
}
@ -51,7 +51,7 @@ class AppInfoViewModel extends BaseViewModel {
}
void updateNotImplemented(BuildContext context) {
_toast.showBottom('appInfoView.updateNotImplemented');
_toast.showBottom(t.appInfoView.updateNotImplemented);
}
Future<void> showUninstallDialog(
@ -64,12 +64,12 @@ class AppInfoViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('appInfoView.rootDialogTitle'),
content: I18nText('appInfoView.rootDialogText'),
title: Text(t.appInfoView.rootDialogTitle),
content: Text(t.appInfoView.rootDialogText),
actions: <Widget>[
FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -79,16 +79,12 @@ class AppInfoViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText(
'appInfoView.unmountButton',
),
content: I18nText(
'appInfoView.unmountDialogText',
),
title: Text(t.appInfoView.unmountButton),
content: Text(t.appInfoView.unmountDialogText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () {
@ -96,7 +92,7 @@ class AppInfoViewModel extends BaseViewModel {
Navigator.of(context).pop();
Navigator.of(context).pop();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),
@ -105,16 +101,12 @@ class AppInfoViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText(
'appInfoView.uninstallButton',
),
content: I18nText(
'appInfoView.uninstallDialogText',
),
title: Text(t.appInfoView.uninstallButton),
content: Text(t.appInfoView.uninstallDialogText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () {
@ -122,7 +114,7 @@ class AppInfoViewModel extends BaseViewModel {
Navigator.of(context).pop();
Navigator.of(context).pop();
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),
@ -148,14 +140,14 @@ class AppInfoViewModel extends BaseViewModel {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('appInfoView.appliedPatchesLabel'),
title: Text(t.appInfoView.appliedPatchesLabel),
content: SingleChildScrollView(
child: Text(getAppliedPatchesString(app.appliedPatches)),
),
actions: <Widget>[
FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),

View File

@ -1,6 +1,6 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
class InstalledAppItem extends StatefulWidget {
@ -107,16 +107,12 @@ class _InstalledAppItemState extends State<InstalledAppItem> {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
I18nText(
'suggested',
translationParams: {
'version': widget.suggestedVersion.isEmpty
? FlutterI18n.translate(
context,
'appSelectorCard.anyVersion',
)
: widget.suggestedVersion,
},
Text(
t.suggested(
version: widget.suggestedVersion.isEmpty
? Text(t.appSelectorCard.anyVersion)
: 'v${widget.suggestedVersion}',
),
),
const SizedBox(width: 4),
Icon(

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
class NotInstalledAppItem extends StatefulWidget {
@ -91,16 +91,12 @@ class _NotInstalledAppItem extends State<NotInstalledAppItem> {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
I18nText(
'suggested',
translationParams: {
'version': widget.suggestedVersion.isEmpty
? FlutterI18n.translate(
context,
'appSelectorCard.anyVersion',
)
: widget.suggestedVersion,
},
Text(
t.suggested(
version: widget.suggestedVersion.isEmpty
? t.appSelectorCard.anyVersion
: 'v${widget.suggestedVersion}',
),
),
const SizedBox(width: 4),
Icon(

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/file.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/services/download_manager.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
import 'package:url_launcher/url_launcher.dart';
@ -26,14 +25,11 @@ class _ContributorsCardState extends State<ContributorsCard> {
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: I18nText(
child: Text(
widget.title,
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
),

View File

@ -1,7 +1,7 @@
import 'package:device_apps/device_apps.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
@ -51,19 +51,15 @@ class InstalledAppsCard extends StatelessWidget {
color: Theme.of(context).colorScheme.secondary,
),
const SizedBox(height: 16),
I18nText(
'homeView.noInstallations',
child: Text(
'',
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(
color:
Theme.of(context).colorScheme.secondary,
),
),
Text(
t.homeView.noInstallations,
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
],
),

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
@ -39,13 +39,13 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
children: <Widget>[
FutureBuilder<String?>(
future: model.getLatestManagerReleaseTime(),
builder: (context, snapshot) => snapshot.hasData &&
snapshot.data!.isNotEmpty
? I18nText(
'latestCommitCard.timeagoLabel',
translationParams: {'time': snapshot.data!},
)
: I18nText('latestCommitCard.loadingLabel'),
builder: (context, snapshot) =>
snapshot.hasData && snapshot.data!.isNotEmpty
? Text(
t.latestCommitCard
.timeagoLabel(time: snapshot.data!),
)
: Text(t.latestCommitCard.loadingLabel),
),
],
),
@ -62,8 +62,8 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
!snapshot.data!,
),
child: (snapshot.hasData && !snapshot.data!)
? I18nText('showChangelogButton')
: I18nText('showUpdateButton'),
? Text(t.showChangelogButton)
: Text(t.showUpdateButton),
),
),
],
@ -89,15 +89,9 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
future: model.getLatestPatchesReleaseTime(),
builder: (context, snapshot) => Text(
snapshot.hasData && snapshot.data!.isNotEmpty
? FlutterI18n.translate(
context,
'latestCommitCard.timeagoLabel',
translationParams: {'time': snapshot.data!},
)
: FlutterI18n.translate(
context,
'latestCommitCard.loadingLabel',
),
? t.latestCommitCard
.timeagoLabel(time: snapshot.data!)
: t.latestCommitCard.loadingLabel,
),
),
],
@ -115,8 +109,8 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
!snapshot.data!,
),
child: (snapshot.hasData && !snapshot.data!)
? I18nText('showChangelogButton')
: I18nText('showUpdateButton'),
? Text(t.showChangelogButton)
: Text(t.showUpdateButton),
),
),
],

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
class UpdateConfirmationSheet extends StatelessWidget {
@ -51,16 +51,13 @@ class UpdateConfirmationSheet extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
Text(
isPatches
? 'homeView.updatePatchesSheetTitle'
: 'homeView.updateSheetTitle',
child: const Text(
'',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
? t.homeView.updatePatchesSheetTitle
: t.homeView.updateSheetTitle,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4.0),
@ -94,40 +91,36 @@ class UpdateConfirmationSheet extends StatelessWidget {
? model.updatePatches(context)
: model.updateManager(context);
},
child: I18nText('updateButton'),
child: Text(t.updateButton),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 12.0, left: 24.0, bottom: 12.0),
child: I18nText(
'homeView.updateChangelogTitle',
child: Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
child: Text(
t.homeView.updateChangelogTitle,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color:
Theme.of(context).colorScheme.onSecondaryContainer,
),
),
),
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 24.0),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(12.0),
Container(
margin: const EdgeInsets.symmetric(horizontal: 24.0),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(12.0),
),
child: Markdown(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(20.0),
data: snapshot.data!['body'] ?? '',
),
),
child: Markdown(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(20.0),
data: snapshot.data!['body'] ?? '',
),
),
],
);
},

View File

@ -1,7 +1,8 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
@ -28,21 +29,18 @@ class AppSelectorCard extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
I18nText(
Text(
vm.selectedApp == null
? 'appSelectorCard.widgetTitle'
: 'appSelectorCard.widgetTitleSelected',
child: const Text(
'',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
),
? t.appSelectorCard.widgetTitle
: t.appSelectorCard.widgetTitleSelected,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
if (vm.selectedApp == null)
I18nText('appSelectorCard.widgetSubtitle')
Text(t.appSelectorCard.widgetSubtitle)
else
Row(
children: <Widget>[
@ -96,11 +94,10 @@ class AppSelectorCard extends StatelessWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
I18nText(
'suggested',
translationParams: {
'version': suggestedVersion,
},
Text(
t.suggested(
version: suggestedVersion,
),
),
const SizedBox(width: 4),
Icon(

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
@ -21,16 +21,13 @@ class PatchSelectorCard extends StatelessWidget {
children: <Widget>[
Row(
children: <Widget>[
I18nText(
Text(
locator<PatcherViewModel>().selectedPatches.isEmpty
? 'patchSelectorCard.widgetTitle'
: 'patchSelectorCard.widgetTitleSelected',
child: const Text(
'',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
),
? t.patchSelectorCard.widgetTitle
: t.patchSelectorCard.widgetTitleSelected,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
Text(
@ -46,10 +43,10 @@ class PatchSelectorCard extends StatelessWidget {
),
const SizedBox(height: 4),
if (locator<PatcherViewModel>().selectedApp == null)
I18nText('patchSelectorCard.widgetSubtitle')
Text(t.patchSelectorCard.widgetSubtitle)
else
locator<PatcherViewModel>().selectedPatches.isEmpty
? I18nText('patchSelectorCard.widgetEmptySubtitle')
? Text(t.patchSelectorCard.widgetEmptySubtitle)
: Text(_getPatchesSelection()),
],
),

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart';
@ -162,7 +162,7 @@ class _PatchItemState extends State<PatchItem> {
Padding(
padding: const EdgeInsets.only(top: 8),
child: TextButton.icon(
label: I18nText('warning'),
label: Text(t.warning),
icon: const Icon(
Icons.warning_amber_outlined,
size: 20.0,
@ -215,19 +215,18 @@ class _PatchItemState extends State<PatchItem> {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('warning'),
content: I18nText(
'patchItem.unsupportedDialogText',
translationParams: {
'packageVersion': widget.packageVersion,
'supportedVersions':
title: Text(t.warning),
content: Text(
t.patchItem.unsupportedDialogText(
packageVersion: widget.packageVersion,
supportedVersions:
'${widget.supportedPackageVersions.reversed.join('\n')}',
},
),
),
actions: <Widget>[
FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),
@ -238,14 +237,14 @@ class _PatchItemState extends State<PatchItem> {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('notice'),
content: I18nText(
'patchItem.unsupportedRequiredOption',
title: Text(t.notice),
content: Text(
t.patchItem.unsupportedRequiredOption,
),
actions: <Widget>[
FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('okButton'),
child: Text(t.okButton),
),
],
),

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
@ -93,13 +93,10 @@ class IntAndStringPatchOption extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
I18nText(
'patchOptionsView.requiredOption',
child: Text(
'',
style: TextStyle(
color: Theme.of(context).colorScheme.error,
),
Text(
t.patchOptionsView.requiredOption,
style: TextStyle(
color: Theme.of(context).colorScheme.error,
),
),
],
@ -240,14 +237,11 @@ class IntStringLongListPatchOption extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.add, size: 20),
I18nText(
'add',
child: const Text(
'',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
Text(
t.add,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
],
@ -279,13 +273,10 @@ class UnsupportedPatchOption extends StatelessWidget {
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: I18nText(
'patchOptionsView.unsupportedOption',
child: const Text(
'',
style: TextStyle(
fontSize: 16,
),
child: Text(
t.patchOptionsView.unsupportedOption,
style: const TextStyle(
fontSize: 16,
),
),
),
@ -452,13 +443,10 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
..add(
DropdownMenuItem(
value: '',
child: I18nText(
'patchOptionsView.customValue',
child: const Text(
'',
style: TextStyle(
fontSize: 16,
),
child: Text(
t.patchOptionsView.customValue,
style: const TextStyle(
fontSize: 16,
),
),
),
@ -491,25 +479,22 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
isStringOption ? TextInputType.text : TextInputType.number,
decoration: InputDecoration(
suffixIcon: PopupMenuButton(
tooltip: FlutterI18n.translate(
context,
'patchOptionsView.tooltip',
),
tooltip: t.patchOptionsView.tooltip,
itemBuilder: (BuildContext context) {
return [
if (isArrayOption)
PopupMenuItem(
value: 'remove',
child: I18nText('remove'),
value: t.remove,
child: Text(t.remove),
),
if (isStringOption) ...[
PopupMenuItem(
value: 'patchOptionsView.selectFilePath',
child: I18nText('patchOptionsView.selectFilePath'),
value: t.patchOptionsView.selectFilePath,
child: Text(t.patchOptionsView.selectFilePath),
),
PopupMenuItem(
value: 'patchOptionsView.selectFolder',
child: I18nText('patchOptionsView.selectFolder'),
value: t.patchOptionsView.selectFolder,
child: Text(t.patchOptionsView.selectFolder),
),
],
];

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/utils/about_info.dart';
class AboutWidget extends StatefulWidget {
@ -34,21 +34,18 @@ class _AboutWidgetState extends State<AboutWidget> {
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: I18nText('settingsView.snackbarMessage'),
content: Text(t.settingsView.snackbarMessage),
backgroundColor:
Theme.of(context).colorScheme.secondary,
),
);
}
: null,
title: I18nText(
'settingsView.aboutLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.aboutLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: snapshot.hasData

View File

@ -1,6 +1,7 @@
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_api_url.dart';
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_sources.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_patches.dart';
@ -17,7 +18,7 @@ class SAdvancedSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SettingsSection(
title: 'settingsView.advancedSectionTitle',
title: t.settingsView.advancedSectionTitle,
children: const <Widget>[
SAutoUpdatePatches(),
SShowUpdateDialog(),

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
@ -17,17 +17,14 @@ class _SAutoUpdatePatchesState extends State<SAutoUpdatePatches> {
Widget build(BuildContext context) {
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.autoUpdatePatchesLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.autoUpdatePatchesLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.autoUpdatePatchesHint'),
subtitle: Text(t.settingsView.autoUpdatePatchesHint),
value: _settingsViewModel.isPatchesAutoUpdate(),
onChanged: (value) {
setState(() {

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/settingsView/about_widget.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
@ -12,51 +12,42 @@ class SDebugSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SettingsSection(
title: 'settingsView.debugSectionTitle',
title: t.settingsView.debugSectionTitle,
children: <Widget>[
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.logsLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.logsLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.logsHint'),
subtitle: Text(t.settingsView.logsHint),
onTap: () => _settingsViewModel.exportLogcatLogs(),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.deleteLogsLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.deleteLogsLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.deleteLogsHint'),
subtitle: Text(t.settingsView.deleteLogsHint),
onTap: () => _settingsViewModel.deleteLogs(),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.deleteTempDirLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.deleteTempDirLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.deleteTempDirHint'),
subtitle: Text(t.settingsView.deleteTempDirHint),
onTap: () => _settingsViewModel.deleteTempDir(),
),
const AboutWidget(

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
@ -18,17 +18,14 @@ class _SEnablePatchesSelectionState extends State<SEnablePatchesSelection> {
Widget build(BuildContext context) {
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.enablePatchesSelectionLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.enablePatchesSelectionLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.enablePatchesSelectionHint'),
subtitle: Text(t.settingsView.enablePatchesSelectionHint),
value: _settingsViewModel.isPatchesChangeEnabled(),
onChanged: (value) async {
await _settingsViewModel.showPatchesChangeEnableDialog(value, context);

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_keystore_password.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
@ -12,106 +12,88 @@ class SExportSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SettingsSection(
title: 'settingsView.exportSectionTitle',
title: t.settingsView.exportSectionTitle,
children: <Widget>[
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.exportPatchesLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.exportPatchesLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.exportPatchesHint'),
subtitle: Text(t.settingsView.exportPatchesHint),
onTap: () => _settingsViewModel.exportPatches(),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.importPatchesLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.importPatchesLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.importPatchesHint'),
subtitle: Text(t.settingsView.importPatchesHint),
onTap: () => _settingsViewModel.importPatches(context),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.resetStoredPatchesLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.resetStoredPatchesLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.resetStoredPatchesHint'),
subtitle: Text(t.settingsView.resetStoredPatchesHint),
onTap: () => _showResetDialog(
context,
'settingsView.resetStoredPatchesDialogTitle',
'settingsView.resetStoredPatchesDialogText',
t.settingsView.resetStoredPatchesDialogTitle,
t.settingsView.resetStoredPatchesDialogText,
_settingsViewModel.resetSelectedPatches,
),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.resetStoredOptionsLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.resetStoredOptionsLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.resetStoredOptionsHint'),
subtitle: Text(t.settingsView.resetStoredOptionsHint),
onTap: () => _showResetDialog(
context,
'settingsView.resetStoredOptionsDialogTitle',
'settingsView.resetStoredOptionsDialogText',
t.settingsView.resetStoredOptionsDialogTitle,
t.settingsView.resetStoredOptionsDialogText,
_settingsViewModel.resetAllOptions,
),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.exportKeystoreLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.exportKeystoreLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.exportKeystoreHint'),
subtitle: Text(t.settingsView.exportKeystoreHint),
onTap: () => _settingsViewModel.exportKeystore(),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.importKeystoreLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.importKeystoreLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.importKeystoreHint'),
subtitle: Text(t.settingsView.importKeystoreHint),
onTap: () async {
await _settingsViewModel.importKeystore();
final sManageKeystorePassword = SManageKeystorePassword();
@ -122,17 +104,14 @@ class SExportSection extends StatelessWidget {
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.regenerateKeystoreLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.regenerateKeystoreLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.regenerateKeystoreHint'),
subtitle: Text(t.settingsView.regenerateKeystoreHint),
onTap: () => _showDeleteKeystoreDialog(context),
),
// SManageKeystorePasswordUI(),
@ -149,19 +128,19 @@ class SExportSection extends StatelessWidget {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText(dialogTitle),
content: I18nText(dialogText),
title: Text(dialogTitle),
content: Text(dialogText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () => {
Navigator.of(context).pop(),
dialogAction(),
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),
@ -172,19 +151,19 @@ class SExportSection extends StatelessWidget {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('settingsView.regenerateKeystoreDialogTitle'),
content: I18nText('settingsView.regenerateKeystoreDialogText'),
title: Text(t.settingsView.regenerateKeystoreDialogTitle),
content: Text(t.settingsView.regenerateKeystoreDialogText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: I18nText('noButton'),
child: Text(t.noButton),
),
FilledButton(
onPressed: () => {
Navigator.of(context).pop(),
_settingsViewModel.deleteKeystore(),
},
child: I18nText('yesButton'),
child: Text(t.yesButton),
),
],
),

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
@ -19,17 +19,14 @@ class _SRequireSuggestedAppVersionState
Widget build(BuildContext context) {
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.requireSuggestedAppVersionLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.requireSuggestedAppVersionLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.requireSuggestedAppVersionHint'),
subtitle: Text(t.settingsView.requireSuggestedAppVersionHint),
value: _settingsViewModel.isRequireSuggestedAppVersionEnabled(),
onChanged: (value) async {
await _settingsViewModel.showRequireSuggestedAppVersionDialog(

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
class SettingsSection extends StatelessWidget {
const SettingsSection({
@ -17,13 +16,10 @@ class SettingsSection extends StatelessWidget {
children: <Widget>[
Container(
padding: const EdgeInsets.only(top: 16.0, bottom: 10.0, left: 20.0),
child: I18nText(
child: Text(
title,
child: Text(
'',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
),

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
@ -17,17 +17,14 @@ class _SShowUpdateDialogState extends State<SShowUpdateDialog> {
Widget build(BuildContext context) {
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.showUpdateDialogLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.showUpdateDialogLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.showUpdateDialogHint'),
subtitle: Text(t.settingsView.showUpdateDialogHint),
value: _settingsViewModel.showUpdateDialog(),
onChanged: (value) {
setState(() {

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
import 'package:revanced_manager/ui/widgets/settingsView/social_media_widget.dart';
@ -12,21 +12,18 @@ class STeamSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SettingsSection(
title: 'settingsView.teamSectionTitle',
title: t.settingsView.teamSectionTitle,
children: <Widget>[
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.contributorsLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.contributorsLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.contributorsHint'),
subtitle: Text(t.settingsView.contributorsHint),
onTap: () => _settingsViewModel.navigateToContributors(),
),
const SocialMediaWidget(

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
class SettingsTileDialog extends StatelessWidget {
const SettingsTileDialog({
@ -18,17 +17,14 @@ class SettingsTileDialog extends StatelessWidget {
Widget build(BuildContext context) {
return ListTile(
contentPadding: padding ?? EdgeInsets.zero,
title: I18nText(
title: Text(
title,
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText(subtitle),
subtitle: Text(subtitle),
onTap: onTap,
);
}

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
@ -21,17 +21,14 @@ class _SUniversalPatchesState extends State<SUniversalPatches> {
Widget build(BuildContext context) {
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.universalPatchesLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.universalPatchesLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.universalPatchesHint'),
subtitle: Text(t.settingsView.universalPatchesHint),
value: _settingsViewModel.areUniversalPatchesEnabled(),
onChanged: (value) {
setState(() {

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
@ -24,17 +24,14 @@ class _SVersionCompatibilityCheckState
Widget build(BuildContext context) {
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.versionCompatibilityCheckLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.settingsView.versionCompatibilityCheckLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('settingsView.versionCompatibilityCheckHint'),
subtitle: Text(t.settingsView.versionCompatibilityCheckHint),
value: _settingsViewModel.isVersionCompatibilityCheckEnabled(),
onChanged: (value) {
setState(() {

View File

@ -1,7 +1,7 @@
import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/widgets/settingsView/social_media_item.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_icon.dart';
@ -26,17 +26,14 @@ class SocialMediaWidget extends StatelessWidget {
),
header: ListTile(
contentPadding: padding ?? EdgeInsets.zero,
title: I18nText(
'socialMediaCard.widgetTitle',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
title: Text(
t.socialMediaCard.widgetTitle,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: I18nText('socialMediaCard.widgetSubtitle'),
subtitle: Text(t.socialMediaCard.widgetSubtitle),
),
expanded: Padding(
padding: padding ?? EdgeInsets.zero,

View File

@ -1,7 +1,7 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/gen/strings.g.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
import 'package:timeago/timeago.dart';
@ -81,7 +81,7 @@ class _ApplicationItemState extends State<ApplicationItem> {
children: <Widget>[
FilledButton(
onPressed: widget.onPressed,
child: I18nText('applicationItem.infoButton'),
child: Text(t.applicationItem.infoButton),
),
],
),

View File

@ -31,7 +31,6 @@ dependencies:
ref: 560d21c4148b53933313573e7eafca0b0eb9aadf # Branch: specify-namespace
flutter_cache_manager: ^3.3.0
flutter_file_dialog: ^3.0.2
flutter_i18n: ^0.34.0
flutter_local_notifications: ^16.1.0
flutter_localizations:
sdk: flutter
@ -68,12 +67,14 @@ dependencies:
timezone: ^0.9.0
url_launcher: ^6.1.10
wakelock_plus: ^1.1.3
slang: ^3.25.0
slang_flutter: ^3.25.0
language_code: ^0.3.1
dev_dependencies:
build_runner: any
flutter_lints: ^3.0.1
injectable_generator: ^2.1.5
json_serializable: ^6.6.1
flutter:
uses-material-design: true
@ -83,3 +84,6 @@ flutter:
- asset: fonts/custom-icons.ttf
assets:
- assets/i18n/
flutter_localizations:
sdk: flutter

5
slang.yaml Normal file
View File

@ -0,0 +1,5 @@
base_locale: en
fallback_strategy: base_locale
input_file_pattern: .i18n.json
input_directory: assets/i18n
output_directory: lib/gen