Compare commits

...

28 Commits

Author SHA1 Message Date
7104d6d6dd chore(release): 1.19.0-dev.2 [skip ci]
# [1.19.0-dev.2](https://github.com/ReVanced/revanced-manager/compare/v1.19.0-dev.1...v1.19.0-dev.2) (2024-01-22)

### Bug Fixes

* Use correct version code & name ([#1647](https://github.com/ReVanced/revanced-manager/issues/1647)) ([d933997](d933997c89))
2024-01-22 22:34:38 +00:00
d933997c89 fix: Use correct version code & name (#1647) 2024-01-23 05:27:33 +07:00
bea99bb4c6 chore(release): 1.19.0-dev.1 [skip ci]
# [1.19.0-dev.1](https://github.com/ReVanced/revanced-manager/compare/v1.18.0...v1.19.0-dev.1) (2024-01-22)

### Bug Fixes

* added a trailing comma ([975180b](975180b075))
* Allow mounting without Magisk ([3f96608](3f96608398))
* fix redundant buttons on dialog ([079c0de](079c0defaf))
* Incorrect strings and logics ([#1619](https://github.com/ReVanced/revanced-manager/issues/1619)) ([4f22e88](4f22e88e42))
* **Keystore Password:** textfield title display ([8e52abd](8e52abda9a))
* Mount script causes build to fail ([#1613](https://github.com/ReVanced/revanced-manager/issues/1613)) ([f3c78c2](f3c78c2c24))
* **Patch Option:** Set text colour on dropdown menu ([acb1e24](acb1e2434b))
* **Release CI:** truncate the "v" from version ([8595099](85950991ab))
* use lowercase repo names ([#1626](https://github.com/ReVanced/revanced-manager/issues/1626)) ([edd8602](edd86024b9))

### Features

* Add API migration code ([#1615](https://github.com/ReVanced/revanced-manager/issues/1615)) ([28ae276](28ae2766f0))
* add haptic feedback ([#1459](https://github.com/ReVanced/revanced-manager/issues/1459)) ([7911459](7911459817))
* Improve app selector and patcher UI ([#1616](https://github.com/ReVanced/revanced-manager/issues/1616)) ([efb2d5e](efb2d5ef32))
* Improve Split APK warning readability ([#1625](https://github.com/ReVanced/revanced-manager/issues/1625)) ([6fd740f](6fd740f8c0))
* Simplify settings strings ([#1618](https://github.com/ReVanced/revanced-manager/issues/1618)) ([0d45fe4](0d45fe4a97))
* use native TextField ([9ed43ef](9ed43efe5d))

### Performance Improvements

* Load patched apps as soon as possible ([c94eb7a](c94eb7a48e))
2024-01-22 11:41:51 +00:00
f38a593434 ci(Release Build): Use correct syntax in getting the version 2024-01-22 18:34:35 +07:00
85950991ab fix(Release CI): truncate the "v" from version
ci: cleanup

force push soon™️
2024-01-22 18:30:16 +07:00
6fd740f8c0 feat: Improve Split APK warning readability (#1625)
Co-authored-by: Pun Butrach <pun.butrach@gmail.com>
2024-01-22 12:20:09 +01:00
ec2c2d8ccb ci: Build pre-release versions (#1606) 2024-01-22 09:29:57 +01:00
efb2d5ef32 feat: Improve app selector and patcher UI (#1616) 2024-01-22 09:20:17 +01:00
acb1e2434b fix(Patch Option): Set text colour on dropdown menu
Signed-off-by: validcube <pun.butrach@gmail.com>
2024-01-21 20:36:23 +07:00
8e52abda9a fix(Keystore Password): textfield title display
Signed-off-by: validcube <pun.butrach@gmail.com>
2024-01-21 16:58:00 +07:00
9764326242 chore(patch_item): Remove import directive
Signed-off-by: validcube <pun.butrach@gmail.com>
2024-01-21 15:15:37 +07:00
97c33d6c54 chore: Remove deprecated lint rules
Signed-off-by: validcube <pun.butrach@gmail.com>
2024-01-21 15:10:03 +07:00
30d5f3ad3f docs(security): Prepare for v1.19.0 2024-01-21 15:02:52 +07:00
079c0defaf fix: fix redundant buttons on dialog
Signed-off-by: validcube <pun.butrach@gmail.com>
2024-01-21 14:45:25 +07:00
cf1afddb9e chore: remove unused dependencies (#1603) 2024-01-21 14:07:30 +07:00
b07b9351c4 docs(security): init (#1599)
Co-authored-by: Ax333l <main@axelen.xyz>
2024-01-21 13:59:57 +07:00
7911459817 feat: add haptic feedback (#1459)
Co-authored-by: Ushie <ushiekane@gmail.com>
Co-authored-by: Pun Butrach <pun.butrach@gmail.com>
2024-01-14 14:29:24 -08:00
ef9b1d5c2d refactor: Replace deprecated WillPopScope (#1604) 2024-01-13 19:34:04 -08:00
fd2780624a chore: remove unused import 2024-01-12 09:49:26 -08:00
4f22e88e42 fix: Incorrect strings and logics (#1619) 2024-01-12 05:15:37 +07:00
0d45fe4a97 feat: Simplify settings strings (#1618) 2024-01-09 20:23:54 +01:00
28ae2766f0 feat: Add API migration code (#1615) 2024-01-09 20:23:26 +01:00
edd86024b9 fix: use lowercase repo names (#1626) 2024-01-09 05:07:18 +07:00
f3c78c2c24 fix: Mount script causes build to fail (#1613) 2024-01-01 00:32:57 +03:00
3f96608398 fix: Allow mounting without Magisk 2023-12-31 03:32:04 +03:00
9ed43efe5d feat: use native TextField
Signed-off-by: validcube <pun.butrach@gmail.com>
2023-12-30 14:37:46 +07:00
975180b075 fix: added a trailing comma 2023-12-28 13:17:25 -08:00
c94eb7a48e perf: Load patched apps as soon as possible 2023-12-24 00:12:33 +01:00
49 changed files with 7369 additions and 548 deletions

View File

@ -1,36 +1,61 @@
name: "Release Build"
on:
workflow_dispatch:
push:
tags:
- "v*"
branches:
- main
- dev
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "zulu"
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- name: Set up Flutter
run: flutter pub get
- name: Generate files with Builder
run: dart run build_runner build --delete-conflicting-outputs
- name: Build with Flutter
- name: Cache Node modules
uses: actions/cache@v3
with:
path: |
node_modules
key: npm-${{ hashFiles('package-lock.json') }}
- name: Setup semantic-release
run: npm install
- name: Get version code
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
run: |
npx semantic-release --extends ./.releaserc.getversion.json --no-ci --dry-run
echo "RELEASE_VERSION=v$(cat .VERSION)" >> $GITHUB_ENV
- name: Bump pubspec version
run: |
VERSION=$(echo "${RELEASE_VERSION}" | sed 's/v//')
IFS='.' read -r -a nums <<< "${VERSION/-dev/}.0"
VERSIONCODE=$((nums[0] * 100000000 + nums[1] * 100000 + nums[2] * 100 + nums[3]))
sed -i "/^version/c\\version: $VERSION+$VERSIONCODE" pubspec.yaml
- name: Set up Flutter
run: flutter pub get
- name: Generate files with Builder
run: dart run build_runner build --delete-conflicting-outputs
- name: Build with Flutter
run: flutter build apk
- name: Sign APK
id: sign_apk
uses: ilharp/sign-android-release@v1
@ -40,11 +65,11 @@ jobs:
keyStorePassword: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
keyAlias: ${{ secrets.SIGNING_KEY_ALIAS }}
keyPassword: ${{ secrets.SIGNING_KEY_PASSWORD }}
- name: Add version to APK
- name: Rename APK
run: mv ${{steps.sign_apk.outputs.signedFile}} revanced-manager-${{ env.RELEASE_VERSION }}.apk
- name: Publish release APK
uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
files: revanced-manager-${{ env.RELEASE_VERSION }}.apk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release --extends ./.releaserc.release.json

View File

@ -0,0 +1,24 @@
{
"branches": [
"main",
{
"name": "dev",
"prerelease": true
}
],
"plugins": [
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],
[
"@semantic-release/exec",
{
"verifyReleaseCmd": "echo ${nextRelease.version} > .VERSION"
}
]
]
}

46
.releaserc.release.json Normal file
View File

@ -0,0 +1,46 @@
{
"branches": [
"main",
{
"name": "dev",
"prerelease": true
}
],
"plugins": [
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],
"@semantic-release/changelog",
"@semantic-release/release-notes-generator",
[
"@semantic-release/git",
{
"assets": [
"pubspec.yaml"
]
}
],
[
"@semantic-release/github",
{
"assets": [
{
"path": "revanced-manager-v*.apk"
}
],
"successComment": false
}
],
[
"@saithodev/semantic-release-backmerge",
{
"backmergeBranches": [{"from": "main", "to": "dev"}],
"clearWorkspace": true
}
]
]
}

78
SECURITY.md Normal file
View File

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

View File

@ -21,7 +21,6 @@ linter:
- always_declare_return_types
- require_trailing_commas
- always_put_control_body_on_new_line
- always_require_non_null_named_parameters
- always_use_package_imports # we do this commonly
- annotate_overrides
- avoid_bool_literals_in_conditional_expressions
@ -40,8 +39,6 @@ linter:
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_future
- avoid_returning_null_for_void
- avoid_setters_without_getters
- avoid_shadowing_type_parameters
@ -126,6 +123,7 @@ linter:
- slash_for_doc_comments
- sort_child_properties_last
- sort_constructors_first
- sort_pub_dependencies
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally

View File

@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

View File

@ -72,22 +72,21 @@
"widgetTitle": "Patcher",
"patchButton": "Patch",
"armv7WarningDialogText": "Patching on ARMv7 devices is not yet supported and might fail. Proceed anyways?",
"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\nProceed 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 application",
"widgetTitleSelected": "Selected application",
"widgetSubtitle": "No application selected",
"widgetTitle": "Select an app",
"widgetTitleSelected": "Selected app",
"widgetSubtitle": "No app selected",
"noAppsLabel": "No applications found",
"notInstalled":"App not installed",
"currentVersion": "Current",
"suggestedVersion": "Suggested",
"allVersions": "All versions"
"anyVersion": "Any version"
},
"patchSelectorCard": {
"widgetTitle": "Select patches",
@ -101,20 +100,20 @@
"widgetSubtitle": "We are online!"
},
"appSelectorView": {
"viewTitle": "Select an application",
"searchBarHint": "Search applications",
"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. Please select the app that matches the suggested version.\n\nSelected version: v{selected}\nSuggested version: v{suggested}\n\nTo proceed anyway, disable \"Require suggested app version\" in the settings.",
"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 application is a split APK and cannot be selected. Unfortunately, this feature is only available for rooted users at the moment. However, you can still install the application by selecting its APK files from your device's storage instead"
"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",
@ -164,7 +163,7 @@
"installerView": {
"widgetTitle": "Installer",
"installType": "Select install type",
"installTypeDescription": "Select the installation type to proceed with.",
"installTypeDescription": "Select the installation type to continue with.",
"installButton": "Install",
"installRootType": "Mount",
@ -175,7 +174,7 @@
"pressBackAgain": "Press back again to cancel",
"openButton": "Open",
"shareButton": "Share file",
"notificationTitle": "ReVanced Manager is patching",
"notificationText": "Tap to return to the installer",
@ -208,7 +207,7 @@
"englishOption": "English",
"sourcesLabel": "Sources",
"sourcesLabelHint": "Configure your 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?",
@ -216,13 +215,13 @@
"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 your 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",
@ -230,7 +229,7 @@
"logsHint": "Share ReVanced Manager logs",
"enablePatchesSelectionLabel": "Allow changing patch selection",
"enablePatchesSelectionHint": "Allow changing the selection of patches",
"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?",
@ -240,9 +239,10 @@
"universalPatchesHint": "Display all apps and universal patches (may slow down the app list)",
"versionCompatibilityCheckLabel": "Version compatibility check",
"versionCompatibilityCheckHint": "Restricts patches to supported app versions",
"versionCompatibilityCheckHint": "Prevent selecting patches that are not compatible with the selected app version",
"requireSuggestedAppVersionLabel": "Require suggested app version",
"requireSuggestedAppVersionHint": "Enforce selection of 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",
@ -320,7 +320,7 @@
"patchedDateHint": "{date} at {time}",
"appliedPatchesHint": "{quantity} applied patches",
"updateNotImplemented": "This feature has not been implemented yet"
},
"contributorsView": {

View File

@ -15,6 +15,8 @@ import 'package:revanced_manager/services/github_api.dart';
import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/services/revanced_api.dart';
import 'package:revanced_manager/services/root_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_checkbox_list_tile.dart';
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:timeago/timeago.dart';
@ -23,6 +25,7 @@ import 'package:timeago/timeago.dart';
class ManagerAPI {
final RevancedAPI _revancedAPI = locator<RevancedAPI>();
final GithubAPI _githubAPI = locator<GithubAPI>();
final Toast _toast = locator<Toast>();
final RootAPI _rootAPI = RootAPI();
final String patcherRepo = 'revanced-patcher';
final String cliRepo = 'revanced-cli';
@ -50,12 +53,12 @@ class ManagerAPI {
String? integrationsVersion = '';
bool isDefaultPatchesRepo() {
return getPatchesRepo().toLowerCase() == 'revanced/revanced-patches';
return getPatchesRepo().toLowerCase() == defaultPatchesRepo;
}
bool isDefaultIntegrationsRepo() {
return getIntegrationsRepo().toLowerCase() ==
'revanced/revanced-integrations';
defaultIntegrationsRepo;
}
Future<void> initialize() async {
@ -65,6 +68,16 @@ class ManagerAPI {
(await getSdkVersion()) >= 31; // ANDROID_12_SDK_VERSION = 31
storedPatchesFile =
(await getApplicationDocumentsDirectory()).path + storedPatchesFile;
// Migrate to new API URL if not done yet as the old one is sunset.
final bool hasMigrated = _prefs.getBool('migratedToNewApiUrl') ?? false;
if (!hasMigrated) {
final String apiUrl = getApiUrl().toLowerCase();
if (apiUrl.contains('releases.revanced.app')) {
await setApiUrl(''); // Reset to default.
_prefs.setBool('migratedToNewApiUrl', true);
}
}
}
Future<int> getSdkVersion() async {
@ -82,6 +95,7 @@ class ManagerAPI {
}
await _revancedAPI.clearAllCache();
await _prefs.setString('apiUrl', url);
_toast.showBottom('settingsView.restartAppForChanges');
}
String getRepoUrl() {
@ -582,8 +596,8 @@ class ManagerAPI {
return showDialog(
barrierDismissible: false,
context: context,
builder: (context) => WillPopScope(
onWillPop: () async => false,
builder: (context) => PopScope(
canPop: false,
child: AlertDialog(
title: I18nText('warning'),
content: ValueListenableBuilder(
@ -604,7 +618,7 @@ class ManagerAPI {
),
),
const SizedBox(height: 8),
CheckboxListTile(
HapticCheckboxListTile(
value: value,
contentPadding: EdgeInsets.zero,
title: I18nText(
@ -632,7 +646,7 @@ class ManagerAPI {
);
}
Future<void> reAssessSavedApps() async {
Future<void> rePatchedSavedApps() async {
final List<PatchedApplication> patchedApps = getPatchedApps();
// Remove apps that are not installed anymore.

View File

@ -335,13 +335,14 @@ class PatcherAPI {
Navigator.pop(context);
},
child: I18nText('cancelButton'),
)
else
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: I18nText('cancelButton'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: I18nText('cancelButton'),
),
if (isFixable)
FilledButton(
onPressed: () async {

View File

@ -32,7 +32,7 @@ class RevancedAPI {
final response = await _dio.get('/contributors');
final List<dynamic> repositories = response.data['repositories'];
for (final Map<String, dynamic> repo in repositories) {
final String name = repo['name'];
final String name = repo['name'].toLowerCase();
contributors[name] = repo['contributors'];
}
} on Exception catch (e) {
@ -54,7 +54,7 @@ class RevancedAPI {
final List<dynamic> tools = response.data['tools'];
return tools.firstWhereOrNull(
(t) =>
t['repository'] == repoName &&
(t['repository'] as String).toLowerCase() == repoName.toLowerCase() &&
(t['name'] as String).endsWith(extension),
);
} on Exception catch (e) {

View File

@ -144,8 +144,12 @@ class RootAPI {
);
final String mountScript = '''
#!/system/bin/sh
MAGISKTMP="\$(magisk --path)" || MAGISKTMP=/sbin
# Mount using Magisk mirror, if available.
MAGISKTMP="\$( magisk --path )" || MAGISKTMP=/sbin
MIRROR="\$MAGISKTMP/.magisk/mirror"
if [ ! -f \$MIRROR ]; then
MIRROR=""
fi
until [ "\$(getprop sys.boot_completed)" = 1 ]; do sleep 3; done
until [ -d "/sdcard/Android" ]; do sleep 1; done
@ -171,7 +175,7 @@ class RootAPI {
}
Future<void> installPatchedApk(
String packageName, String patchedFilePath) async {
String packageName, String patchedFilePath,) async {
final String newPatchedFilePath = '$_revancedDirPath/$packageName/base.apk';
await Root.exec(
cmd: '''

View File

@ -4,6 +4,7 @@ import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.da
import 'package:revanced_manager/ui/widgets/appSelectorView/app_skeleton_loader.dart';
import 'package:revanced_manager/ui/widgets/appSelectorView/installed_app_item.dart';
import 'package:revanced_manager/ui/widgets/appSelectorView/not_installed_app_item.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_floating_action_button_extended.dart';
import 'package:revanced_manager/ui/widgets/shared/search_bar.dart';
import 'package:stacked/stacked.dart' hide SkeletonLoader;
@ -23,7 +24,7 @@ class _AppSelectorViewState extends State<AppSelectorView> {
onViewModelReady: (model) => model.initialize(),
viewModelBuilder: () => AppSelectorViewModel(),
builder: (context, model, child) => Scaffold(
floatingActionButton: FloatingActionButton.extended(
floatingActionButton: HapticFloatingActionButtonExtended(
label: I18nText('appSelectorView.storageButton'),
icon: const Icon(Icons.sd_storage),
onPressed: () {

View File

@ -76,7 +76,7 @@ class AppSelectorViewModel extends BaseViewModel {
final String suggestedVersion = getSuggestedVersion(packageName);
if (suggestedVersion.isNotEmpty) {
await openDefaultBrowser('$packageName apk version v$suggestedVersion');
await openDefaultBrowser('$packageName apk version $suggestedVersion');
} else {
await openDefaultBrowser('$packageName apk');
}

View File

@ -14,9 +14,9 @@ class ContributorsViewModel extends BaseViewModel {
final Map<String, List<dynamic>> contributors =
await _managerAPI.getContributors();
patcherContributors = contributors[_managerAPI.defaultPatcherRepo] ?? [];
patchesContributors = contributors[_managerAPI.getPatchesRepo()] ?? [];
patchesContributors = contributors[_managerAPI.getPatchesRepo().toLowerCase()] ?? [];
integrationsContributors =
contributors[_managerAPI.getIntegrationsRepo()] ?? [];
contributors[_managerAPI.getIntegrationsRepo().toLowerCase()] ?? [];
cliContributors = contributors[_managerAPI.defaultCliRepo] ?? [];
managerContributors = contributors[_managerAPI.defaultManagerRepo] ?? [];
notifyListeners();

View File

@ -20,6 +20,7 @@ import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/homeView/update_confirmation_dialog.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_checkbox_list_tile.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
@ -38,11 +39,15 @@ class HomeViewModel extends BaseViewModel {
File? downloadedApk;
Future<void> initialize(BuildContext context) async {
_managerAPI.rePatchedSavedApps().then((_) => _getPatchedApps());
_latestManagerVersion = await _managerAPI.getLatestManagerVersion();
if (!_managerAPI.getPatchesConsent()) {
await showPatchesConsent(context);
}
await _patcherAPI.initialize();
await flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(
android: AndroidInitializationSettings('ic_notification'),
@ -63,11 +68,13 @@ class HomeViewModel extends BaseViewModel {
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
final bool isConnected =
await Connectivity().checkConnectivity() != ConnectivityResult.none;
if (!isConnected) {
_toast.showBottom('homeView.noConnection');
}
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
@ -79,8 +86,6 @@ class HomeViewModel extends BaseViewModel {
_toast.showBottom('homeView.errorDownloadMessage');
}
}
_managerAPI.reAssessSavedApps().then((_) => _getPatchedApps());
}
void navigateToAppInfo(PatchedApplication app) {
@ -203,7 +208,7 @@ class HomeViewModel extends BaseViewModel {
),
),
),
CheckboxListTile(
HapticCheckboxListTile(
value: value,
contentPadding: EdgeInsets.zero,
title: I18nText(

View File

@ -5,6 +5,7 @@ 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';
import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_floating_action_button_extended.dart';
import 'package:stacked/stacked.dart';
class InstallerView extends StatelessWidget {
@ -15,14 +16,14 @@ class InstallerView extends StatelessWidget {
return ViewModelBuilder<InstallerViewModel>.reactive(
onViewModelReady: (model) => model.initialize(context),
viewModelBuilder: () => InstallerViewModel(),
builder: (context, model, child) => WillPopScope(
builder: (context, model, child) => PopScope(
child: SafeArea(
top: false,
bottom: model.isPatching,
child: Scaffold(
floatingActionButton: Visibility(
visible: !model.isPatching && !model.hasErrors,
child: FloatingActionButton.extended(
child: HapticFloatingActionButtonExtended(
label: I18nText(
model.isInstalled
? 'installerView.openButton'
@ -111,7 +112,7 @@ class InstallerView extends StatelessWidget {
),
),
),
onWillPop: () => model.onWillPop(context),
onPopInvoked: (bool didPop) => model.onWillPop(context),
),
);
}

View File

@ -220,8 +220,6 @@ class InstallerViewModel extends BaseViewModel {
String suggestedVersion = _patcherAPI.getSuggestedVersion(_app.packageName);
if (suggestedVersion.isEmpty) {
suggestedVersion = 'Any';
} else {
suggestedVersion = 'v$suggestedVersion';
}
return suggestedVersion;
}

View File

@ -13,14 +13,10 @@ class NavigationView extends StatelessWidget {
return ViewModelBuilder<NavigationViewModel>.reactive(
onViewModelReady: (model) => model.initialize(context),
viewModelBuilder: () => locator<NavigationViewModel>(),
builder: (context, model, child) => WillPopScope(
onWillPop: () async {
if (model.currentIndex == 0) {
return true;
} else {
model.setIndex(0);
return false;
}
builder: (context, model, child) => PopScope(
canPop: model.currentIndex == 0,
onPopInvoked: (bool didPop) => {
if (!didPop) model.setIndex(0),
},
child: Scaffold(
body: PageTransitionSwitcher(

View File

@ -4,6 +4,7 @@ import 'package:google_fonts/google_fonts.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';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_floating_action_button_extended.dart';
import 'package:stacked/stacked.dart';
class PatchOptionsView extends StatelessWidget {
@ -17,7 +18,7 @@ class PatchOptionsView extends StatelessWidget {
builder: (context, model, child) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
floatingActionButton: FloatingActionButton.extended(
floatingActionButton: HapticFloatingActionButtonExtended(
onPressed: () async {
final bool saved = model.saveOptions(context);
if (saved && context.mounted) {

View File

@ -184,8 +184,9 @@ class PatchOptionsViewModel extends BaseViewModel {
children: [
Text(
e.title,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(height: 4),

View File

@ -6,6 +6,7 @@ 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';
import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_floating_action_button_extended.dart';
import 'package:stacked/stacked.dart';
class PatcherView extends StatelessWidget {
@ -19,7 +20,7 @@ class PatcherView extends StatelessWidget {
builder: (context, model, child) => Scaffold(
floatingActionButton: Visibility(
visible: model.showPatchButton(),
child: FloatingActionButton.extended(
child: HapticFloatingActionButtonExtended(
label: I18nText('patcherView.patchButton'),
icon: const Icon(Icons.build),
onPressed: () async {

View File

@ -148,52 +148,17 @@ class PatcherViewModel extends BaseViewModel {
}
String getAppSelectionString() {
String text = '${selectedApp!.name} (${selectedApp!.packageName})';
if (text.length > 32) {
text = '${text.substring(0, 32)}...)';
}
return text;
return '${selectedApp!.name} ${selectedApp!.version}';
}
String getCurrentVersionString(BuildContext context) {
return '${FlutterI18n.translate(
context,
'appSelectorCard.currentVersion',
)}: v${selectedApp!.version}';
}
Future<void> searchSuggestedVersionOnWeb() async {
final String suggestedVersion =
_patcherAPI.getSuggestedVersion(selectedApp!.packageName);
if (suggestedVersion.isNotEmpty) {
await openDefaultBrowser(
'${selectedApp!.packageName} apk version v$suggestedVersion',
);
} else {
await openDefaultBrowser('${selectedApp!.packageName} apk');
}
}
String getSuggestedVersion() {
return _patcherAPI.getSuggestedVersion(selectedApp!.packageName);
Future<void> queryVersion(String suggestedVersion) async {
await openDefaultBrowser(
'${selectedApp!.packageName} apk version $suggestedVersion',
);
}
String getSuggestedVersionString(BuildContext context) {
String suggestedVersion =
_patcherAPI.getSuggestedVersion(selectedApp!.packageName);
if (suggestedVersion.isEmpty) {
suggestedVersion = FlutterI18n.translate(
context,
'appSelectorCard.allVersions',
);
} else {
suggestedVersion = 'v$suggestedVersion';
}
return '${FlutterI18n.translate(
context,
'appSelectorCard.suggestedVersion',
)}: $suggestedVersion';
return _patcherAPI.getSuggestedVersion(selectedApp!.packageName);
}
Future<void> openDefaultBrowser(String query) async {

View File

@ -3,6 +3,7 @@ import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.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';
import 'package:revanced_manager/ui/widgets/shared/search_bar.dart';
import 'package:stacked/stacked.dart';
@ -36,7 +37,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
builder: (context, model, child) => Scaffold(
floatingActionButton: Visibility(
visible: model.patches.isNotEmpty,
child: FloatingActionButton.extended(
child: HapticFloatingActionButtonExtended(
label: Row(
children: <Widget>[
I18nText('patchesSelectorView.doneButton'),

View File

@ -4,14 +4,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart';
import 'package:stacked/stacked.dart';
class SManageApiUrl extends BaseViewModel {
final ManagerAPI _managerAPI = locator<ManagerAPI>();
final Toast _toast = locator<Toast>();
final TextEditingController _apiUrlController = TextEditingController();
@ -35,15 +32,22 @@ class SManageApiUrl extends BaseViewModel {
content: SingleChildScrollView(
child: Column(
children: <Widget>[
CustomTextField(
leadingIcon: Icon(
Icons.api_outlined,
color: Theme.of(context).colorScheme.secondary,
),
inputController: _apiUrlController,
label: I18nText('settingsView.selectApiURL'),
hint: apiUrl,
TextField(
controller: _apiUrlController,
autocorrect: false,
onChanged: (value) => notifyListeners(),
decoration: InputDecoration(
icon: Icon(
Icons.api_outlined,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.selectApiURL',
),
hintText: apiUrl,
),
),
],
),
@ -63,7 +67,6 @@ class SManageApiUrl extends BaseViewModel {
apiUrl = 'https://$apiUrl';
}
_managerAPI.setApiUrl(apiUrl);
_toast.showBottom('settingsView.restartAppForChanges');
Navigator.of(context).pop();
},
child: I18nText('okButton'),
@ -87,7 +90,6 @@ class SManageApiUrl extends BaseViewModel {
FilledButton(
onPressed: () {
_managerAPI.setApiUrl('');
_toast.showBottom('settingsView.restartAppForChanges');
Navigator.of(context)
..pop()
..pop();

View File

@ -4,7 +4,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/services/manager_api.dart';
import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart';
import 'package:stacked/stacked.dart';
@ -35,11 +34,18 @@ class SManageKeystorePassword extends BaseViewModel {
content: SingleChildScrollView(
child: Column(
children: <Widget>[
CustomTextField(
inputController: _keystorePasswordController,
label: I18nText('settingsView.selectKeystorePassword'),
hint: '',
TextField(
controller: _keystorePasswordController,
autocorrect: false,
obscureText: true,
onChanged: (value) => notifyListeners(),
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.selectKeystorePassword',
),
),
),
],
),

View File

@ -5,7 +5,6 @@ import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart';
import 'package:stacked/stacked.dart';
@ -45,59 +44,102 @@ class SManageSources extends BaseViewModel {
content: SingleChildScrollView(
child: Column(
children: <Widget>[
CustomTextField(
leadingIcon: const Icon(
Icons.extension_outlined,
color: Colors.transparent,
),
inputController: _hostSourceController,
label: I18nText('settingsView.hostRepositoryLabel'),
hint: hostRepository,
/*
API for accessing the specified repositories
If default is used, will use the ReVanced API
*/
TextField(
controller: _hostSourceController,
autocorrect: false,
onChanged: (value) => notifyListeners(),
),
const SizedBox(height: 20),
CustomTextField(
leadingIcon: Icon(
Icons.extension_outlined,
color: Theme.of(context).colorScheme.secondary,
decoration: InputDecoration(
icon: Icon(
Icons.rocket_launch_outlined,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.hostRepositoryLabel',
),
hintText: hostRepository,
),
inputController: _orgPatSourceController,
label: I18nText('settingsView.orgPatchesLabel'),
hint: patchesRepo.split('/')[0],
onChanged: (value) => notifyListeners(),
),
const SizedBox(height: 8),
CustomTextField(
leadingIcon: const Icon(
Icons.extension_outlined,
color: Colors.transparent,
),
inputController: _patSourceController,
label: I18nText('settingsView.sourcesPatchesLabel'),
hint: patchesRepo.split('/')[1],
// Patches owner's name
TextField(
controller: _orgPatSourceController,
autocorrect: false,
onChanged: (value) => notifyListeners(),
),
const SizedBox(height: 20),
CustomTextField(
leadingIcon: Icon(
Icons.merge_outlined,
color: Theme.of(context).colorScheme.secondary,
decoration: InputDecoration(
icon: Icon(
Icons.extension_outlined,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.orgPatchesLabel',
),
hintText: patchesRepo.split('/')[0],
),
inputController: _orgIntSourceController,
label: I18nText('settingsView.orgIntegrationsLabel'),
hint: integrationsRepo.split('/')[0],
onChanged: (value) => notifyListeners(),
),
const SizedBox(height: 8),
CustomTextField(
leadingIcon: const Icon(
Icons.merge_outlined,
color: Colors.transparent,
),
inputController: _intSourceController,
label: I18nText('settingsView.sourcesIntegrationsLabel'),
hint: integrationsRepo.split('/')[1],
// Patches repository's name
TextField(
controller: _patSourceController,
autocorrect: false,
onChanged: (value) => notifyListeners(),
decoration: InputDecoration(
icon: const Icon(
Icons.extension_outlined,
color: Colors.transparent,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.sourcesPatchesLabel',
),
hintText: patchesRepo.split('/')[1],
),
),
const SizedBox(height: 8),
// Integrations owner's name
TextField(
controller: _orgIntSourceController,
autocorrect: false,
onChanged: (value) => notifyListeners(),
decoration: InputDecoration(
icon: Icon(
Icons.merge_outlined,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.orgIntegrationsLabel',
),
hintText: integrationsRepo.split('/')[0],
),
),
const SizedBox(height: 8),
// Integrations repository's name
TextField(
controller: _intSourceController,
autocorrect: false,
onChanged: (value) => notifyListeners(),
decoration: InputDecoration(
icon: const Icon(
Icons.merge_outlined,
color: Colors.transparent,
),
border: const OutlineInputBorder(),
labelText: FlutterI18n.translate(
context,
'settingsView.sourcesIntegrationsLabel',
),
hintText: integrationsRepo.split('/')[1],
),
),
const SizedBox(height: 20),
I18nText('settingsView.sourcesUpdateNote'),

View File

@ -7,6 +7,8 @@ import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/app/app.locator.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';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
class SUpdateThemeUI extends StatefulWidget {
const SUpdateThemeUI({super.key});
@ -42,7 +44,7 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
onTap: () => {showThemeDialog(context)},
),
if (managerAPI.isDynamicThemeAvailable)
SwitchListTile(
HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.dynamicThemeLabel',
@ -129,7 +131,7 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
RadioListTile(
HapticRadioListTile(
title: I18nText('settingsView.systemThemeLabel'),
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
value: 0,
@ -138,7 +140,7 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
newTheme.value = value!;
},
),
RadioListTile(
HapticRadioListTile(
title: I18nText('settingsView.lightThemeLabel'),
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
value: 1,
@ -147,7 +149,7 @@ class _SUpdateThemeUIState extends State<SUpdateThemeUI> {
newTheme.value = value!;
},
),
RadioListTile(
HapticRadioListTile(
title: I18nText('settingsView.darkThemeLabel'),
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
value: 2,

View File

@ -54,25 +54,43 @@ class _InstalledAppItemState extends State<InstalledAppItem> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
children: [
Text(
widget.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 16,
),
),
Text(
widget.installedVersion,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 16,
),
),
Text(
widget.patchesCount == 1
? '${widget.patchesCount} patch'
: '${widget.patchesCount} patches',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.secondary,
),
),
],
),
Text(
widget.name,
maxLines: 2,
overflow: TextOverflow.visible,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
Text(widget.pkgName),
I18nText(
FlutterI18n.translate(
context,
'installed',
translationParams: {
'version': 'v${widget.installedVersion}',
},
),
widget.pkgName,
),
const SizedBox(height: 4),
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
@ -85,7 +103,7 @@ class _InstalledAppItemState extends State<InstalledAppItem> {
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: Container(
padding: const EdgeInsets.all(4),
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
@ -95,18 +113,10 @@ class _InstalledAppItemState extends State<InstalledAppItem> {
'version': widget.suggestedVersion.isEmpty
? FlutterI18n.translate(
context,
'appSelectorCard.allVersions',
'appSelectorCard.anyVersion',
)
: 'v${widget.suggestedVersion}',
: widget.suggestedVersion,
},
child: Text(
'',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
),
),
),
const SizedBox(width: 4),
Icon(
@ -121,17 +131,6 @@ class _InstalledAppItemState extends State<InstalledAppItem> {
),
),
),
const SizedBox(width: 4),
Text(
widget.patchesCount == 1
? '${widget.patchesCount} patch'
: '${widget.patchesCount} patches',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
),
),
],
),
],

View File

@ -33,103 +33,91 @@ class _NotInstalledAppItem extends State<NotInstalledAppItem> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
width: 48,
height: 48,
padding: const EdgeInsets.symmetric(vertical: 4.0),
alignment: Alignment.center,
child: const CircleAvatar(
backgroundColor: Colors.transparent,
child: Icon(
Icons.square_rounded,
color: Colors.grey,
size: 44,
size: 48,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.name,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
children: [
Text(
widget.name,
style: const TextStyle(
fontSize: 16,
),
),
Text(
widget.patchesCount == 1
? '${widget.patchesCount} patch'
: '${widget.patchesCount} patches',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.secondary,
),
),
],
),
),
const SizedBox(height: 4),
I18nText(
'appSelectorCard.notInstalled',
child: Text(
'',
style: TextStyle(
color: Theme.of(context).textTheme.titleLarge!.color,
),
),
),
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Material(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: InkWell(
onTap: widget.onLinkTap,
const SizedBox(height: 4),
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Material(
color:
Theme.of(context).colorScheme.secondaryContainer,
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: Container(
padding: const EdgeInsets.all(4),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
I18nText(
'suggested',
translationParams: {
'version': widget.suggestedVersion.isEmpty
? FlutterI18n.translate(
context,
'appSelectorCard.allVersions',
)
: 'v${widget.suggestedVersion}',
},
child: Text(
'',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
),
child: InkWell(
onTap: widget.onLinkTap,
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: Container(
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
I18nText(
'suggested',
translationParams: {
'version': widget.suggestedVersion.isEmpty
? FlutterI18n.translate(
context,
'appSelectorCard.anyVersion',
)
: widget.suggestedVersion,
},
),
),
const SizedBox(width: 4),
Icon(
Icons.search,
size: 16,
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
),
],
const SizedBox(width: 4),
Icon(
Icons.search,
size: 16,
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
),
],
),
),
),
),
),
const SizedBox(width: 4),
Text(
widget.patchesCount == 1
? '${widget.patchesCount} patch'
: '${widget.patchesCount} patches',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
),
),
],
),
],
),
],
),
]),
),
],
),

View File

@ -15,13 +15,21 @@ class AppSelectorCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final vm = locator<PatcherViewModel>();
String? suggestedVersion;
if (vm.selectedApp != null) {
suggestedVersion = vm.getSuggestedVersionString(context);
}
return CustomCard(
onTap: onPressed,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
I18nText(
locator<PatcherViewModel>().selectedApp == null
vm.selectedApp == null
? 'appSelectorCard.widgetTitle'
: 'appSelectorCard.widgetTitleSelected',
child: const Text(
@ -33,7 +41,7 @@ class AppSelectorCard extends StatelessWidget {
),
),
const SizedBox(height: 8),
if (locator<PatcherViewModel>().selectedApp == null)
if (vm.selectedApp == null)
I18nText('appSelectorCard.widgetSubtitle')
else
Row(
@ -42,9 +50,9 @@ class AppSelectorCard extends StatelessWidget {
height: 18.0,
child: ClipOval(
child: Image.memory(
locator<PatcherViewModel>().selectedApp == null
vm.selectedApp == null
? Uint8List(0)
: locator<PatcherViewModel>().selectedApp!.icon,
: vm.selectedApp!.icon,
fit: BoxFit.cover,
),
),
@ -52,13 +60,13 @@ class AppSelectorCard extends StatelessWidget {
const SizedBox(width: 6),
Flexible(
child: Text(
locator<PatcherViewModel>().getAppSelectionString(),
vm.getAppSelectionString(),
style: const TextStyle(fontWeight: FontWeight.w600),
),
),
],
),
if (locator<PatcherViewModel>().selectedApp == null)
if (vm.selectedApp == null)
Container()
else
Column(
@ -66,49 +74,50 @@ class AppSelectorCard extends StatelessWidget {
children: [
const SizedBox(height: 4),
Text(
locator<PatcherViewModel>().getCurrentVersionString(context),
vm.selectedApp!.packageName,
),
Row(
children: [
Material(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: InkWell(
onTap: () {
locator<PatcherViewModel>()
.searchSuggestedVersionOnWeb();
},
if (suggestedVersion!.isNotEmpty &&
suggestedVersion != vm.selectedApp!.version) ...[
const SizedBox(height: 4),
Row(
children: [
Material(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: Container(
padding: const EdgeInsets.all(4),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
locator<PatcherViewModel>()
.getSuggestedVersionString(context),
style: TextStyle(
child: InkWell(
onTap: () {
vm.queryVersion(suggestedVersion!);
},
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: Container(
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
I18nText(
'suggested',
translationParams: {
'version': suggestedVersion,
},
),
const SizedBox(width: 4),
Icon(
Icons.search,
size: 16,
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
),
),
const SizedBox(width: 4),
Icon(
Icons.search,
size: 16,
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
),
],
],
),
),
),
),
),
],
),
],
),
]
],
),
],

View File

@ -4,7 +4,8 @@ import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_checkbox.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_custom_card.dart';
// ignore: must_be_immutable
class PatchItem extends StatefulWidget {
@ -56,7 +57,7 @@ class _PatchItemState extends State<PatchItem> {
widget._managerAPI.isVersionCompatibilityCheckEnabled() == true
? 0.5
: 1,
child: CustomCard(
child: HapticCustomCard(
padding: EdgeInsets.only(
top: 12,
bottom: 16,
@ -88,7 +89,7 @@ class _PatchItemState extends State<PatchItem> {
children: [
Transform.scale(
scale: 1.2,
child: Checkbox(
child: HapticCheckbox(
value: widget.isSelected,
activeColor: Theme.of(context).colorScheme.primary,
checkColor: Theme.of(context).colorScheme.secondaryContainer,

View File

@ -426,8 +426,11 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
child: RichText(
text: TextSpan(
text: e.key,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
),
children: [
TextSpan(

View File

@ -1,63 +0,0 @@
import 'package:flutter/material.dart';
class CustomSwitch extends StatelessWidget {
const CustomSwitch({
super.key,
required this.onChanged,
required this.value,
});
final ValueChanged<bool> onChanged;
final bool value;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => onChanged(!value),
child: SizedBox(
height: 25,
width: 50,
child: Stack(
children: <Widget>[
AnimatedContainer(
height: 25,
width: 50,
curve: Curves.ease,
duration: const Duration(milliseconds: 400),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(25.0),
),
color: value
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.secondary,
),
),
AnimatedAlign(
curve: Curves.ease,
duration: const Duration(milliseconds: 400),
alignment: !value ? Alignment.centerLeft : Alignment.centerRight,
child: Container(
height: 20,
width: 20,
margin: const EdgeInsets.symmetric(horizontal: 3),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: value
? Theme.of(context).colorScheme.primaryContainer
: Theme.of(context).colorScheme.surface,
boxShadow: [
BoxShadow(
color: Colors.black12.withOpacity(0.1),
spreadRadius: 0.5,
blurRadius: 1,
),
],
),
),
),
],
),
),
);
}
}

View File

@ -1,32 +0,0 @@
import 'package:flutter/material.dart';
import 'package:revanced_manager/ui/widgets/settingsView/custom_switch.dart';
class CustomSwitchTile extends StatelessWidget {
const CustomSwitchTile({
super.key,
required this.title,
required this.subtitle,
required this.value,
required this.onTap,
this.padding,
});
final Widget title;
final Widget subtitle;
final bool value;
final Function(bool) onTap;
final EdgeInsetsGeometry? padding;
@override
Widget build(BuildContext context) {
return ListTile(
contentPadding: padding ?? EdgeInsets.zero,
title: title,
subtitle: subtitle,
onTap: () => onTap(!value),
trailing: CustomSwitch(
value: value,
onChanged: onTap,
),
);
}
}

View File

@ -1,73 +0,0 @@
import 'package:flutter/material.dart';
class CustomTextField extends StatelessWidget {
const CustomTextField({
super.key,
required this.inputController,
required this.label,
required this.hint,
this.leadingIcon,
required this.onChanged,
});
final TextEditingController inputController;
final Widget label;
final String hint;
final Widget? leadingIcon;
final Function(String)? onChanged;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 4.0),
child: TextField(
controller: inputController,
onChanged: onChanged,
keyboardType: TextInputType.text,
decoration: InputDecoration(
icon: leadingIcon,
label: label,
filled: true,
fillColor: Theme.of(context).colorScheme.secondaryContainer,
hintText: hint,
hintStyle: TextStyle(
color: Theme.of(context).colorScheme.secondary,
),
floatingLabelStyle: MaterialStateTextStyle.resolveWith(
(states) => states.contains(MaterialState.focused)
? TextStyle(color: Theme.of(context).colorScheme.primary)
: TextStyle(color: Theme.of(context).colorScheme.secondary),
),
contentPadding: const EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 16.0,
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary,
),
borderRadius: BorderRadius.circular(10),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary,
width: 2.0,
),
borderRadius: BorderRadius.circular(10),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.error,
),
borderRadius: BorderRadius.circular(10),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary,
),
borderRadius: BorderRadius.circular(10),
),
),
),
);
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
class SAutoUpdatePatches extends StatefulWidget {
const SAutoUpdatePatches({super.key});
@ -14,7 +15,7 @@ final _settingsViewModel = SettingsViewModel();
class _SAutoUpdatePatchesState extends State<SAutoUpdatePatches> {
@override
Widget build(BuildContext context) {
return SwitchListTile(
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.autoUpdatePatchesLabel',

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
class SEnablePatchesSelection extends StatefulWidget {
const SEnablePatchesSelection({super.key});
@ -15,7 +16,7 @@ final _settingsViewModel = SettingsViewModel();
class _SEnablePatchesSelectionState extends State<SEnablePatchesSelection> {
@override
Widget build(BuildContext context) {
return SwitchListTile(
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.enablePatchesSelectionLabel',

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
class SRequireSuggestedAppVersion extends StatefulWidget {
const SRequireSuggestedAppVersion({super.key});
@ -16,7 +17,7 @@ class _SRequireSuggestedAppVersionState
extends State<SRequireSuggestedAppVersion> {
@override
Widget build(BuildContext context) {
return SwitchListTile(
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.requireSuggestedAppVersionLabel',

View File

@ -3,6 +3,7 @@ import 'package:flutter_i18n/widgets/I18nText.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';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
class SUniversalPatches extends StatefulWidget {
const SUniversalPatches({super.key});
@ -18,7 +19,7 @@ final _patcherViewModel = PatcherViewModel();
class _SUniversalPatchesState extends State<SUniversalPatches> {
@override
Widget build(BuildContext context) {
return SwitchListTile(
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.universalPatchesLabel',

View File

@ -3,6 +3,7 @@ import 'package:flutter_i18n/widgets/I18nText.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';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
class SVersionCompatibilityCheck extends StatefulWidget {
@ -21,7 +22,7 @@ class _SVersionCompatibilityCheckState
extends State<SVersionCompatibilityCheck> {
@override
Widget build(BuildContext context) {
return SwitchListTile(
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.versionCompatibilityCheckLabel',

View File

@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class HapticCheckbox extends StatelessWidget {
const HapticCheckbox({
super.key,
required this.value,
required this.onChanged,
this.activeColor,
this.checkColor,
this.side,
});
final bool value;
final Function(bool?)? onChanged;
final Color? activeColor;
final Color? checkColor;
final BorderSide? side;
@override
Widget build(BuildContext context) {
return Checkbox(
value: value,
onChanged: (value) => {
HapticFeedback.selectionClick(),
if (onChanged != null) onChanged!(value),
},
activeColor: activeColor,
checkColor: checkColor,
side: side,
);
}
}

View File

@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class HapticCheckboxListTile extends StatelessWidget {
const HapticCheckboxListTile({
super.key,
required this.value,
required this.onChanged,
this.title,
this.subtitle,
this.contentPadding,
});
final bool value;
final Function(bool?)? onChanged;
final Widget? title;
final Widget? subtitle;
final EdgeInsetsGeometry? contentPadding;
@override
Widget build(BuildContext context) {
return CheckboxListTile(
contentPadding: contentPadding ?? EdgeInsets.zero,
title: title,
subtitle: subtitle,
value: value,
onChanged: (value) => {
HapticFeedback.lightImpact(),
if (onChanged != null) onChanged!(value),
},
);
}
}

View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
class HapticCustomCard extends StatelessWidget {
const HapticCustomCard({
super.key,
this.isFilled = true,
required this.child,
this.onTap,
this.padding,
this.backgroundColor,
});
final bool isFilled;
final Widget child;
final Function()? onTap;
final EdgeInsetsGeometry? padding;
final Color? backgroundColor;
@override
Widget build(BuildContext context) {
return CustomCard(
isFilled: isFilled,
onTap: () => {
HapticFeedback.selectionClick(),
if (onTap != null) onTap!(),
},
padding: padding,
backgroundColor: backgroundColor,
child: child,
);
}
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class HapticFloatingActionButtonExtended extends StatelessWidget {
const HapticFloatingActionButtonExtended({
super.key,
required this.onPressed,
required this.label,
this.icon,
this.elevation,
});
final Function()? onPressed;
final Widget label;
final Widget? icon;
final double? elevation;
@override
Widget build(BuildContext context) {
return FloatingActionButton.extended(
onPressed: () => {
HapticFeedback.lightImpact(),
if (onPressed != null) onPressed!(),
},
label: label,
icon: icon,
elevation: elevation,
);
}
}

View File

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class HapticRadioListTile extends StatelessWidget {
const HapticRadioListTile({
super.key,
required this.title,
required this.value,
required this.groupValue,
this.subtitle,
this.onChanged,
this.contentPadding,
});
final Widget title;
final Widget? subtitle;
final int value;
final Function(int?)? onChanged;
final int groupValue;
final EdgeInsetsGeometry? contentPadding;
@override
Widget build(BuildContext context) {
return RadioListTile(
contentPadding: contentPadding ?? EdgeInsets.zero,
title: title,
subtitle: subtitle,
value: value,
groupValue: groupValue,
onChanged: (val) => {
if (val == value) {
HapticFeedback.lightImpact(),
},
if (onChanged != null) onChanged!(val),
},
);
}
}

View File

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class HapticSwitchListTile extends StatelessWidget {
const HapticSwitchListTile({
super.key,
required this.value,
required this.onChanged,
this.title,
this.subtitle,
this.contentPadding,
});
final bool value;
final Function(bool)? onChanged;
final Widget? title;
final Widget? subtitle;
final EdgeInsetsGeometry? contentPadding;
@override
Widget build(BuildContext context) {
return SwitchListTile(
contentPadding: contentPadding ?? EdgeInsets.zero,
title: title,
subtitle: subtitle,
value: value,
onChanged: (value) => {
if (value) {
HapticFeedback.mediumImpact(),
} else {
HapticFeedback.lightImpact(),
},
if (onChanged != null) onChanged!(value),
},
);
}
}

6573
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

9
package.json Normal file
View File

@ -0,0 +1,9 @@
{
"devDependencies": {
"@saithodev/semantic-release-backmerge": "^4.0.1",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"semantic-release": "^22.0.12"
}
}

View File

@ -4,7 +4,7 @@ homepage: https://github.com/ReVanced/revanced-manager
publish_to: 'none'
version: 1.18.0+101800000
version: 1.19.0-dev.2+101900002
environment:
sdk: '>=3.0.0 <4.0.0'
@ -12,16 +12,17 @@ environment:
dependencies:
animations: ^2.0.7
collection: ^1.17.0
connectivity_plus: ^5.0.1
device_apps:
git: # switch back to ponces fork once https://github.com/ponces/flutter_plugin_device_apps/pull/1 is merged
url: https://github.com/BenjaminHalko/flutter_plugin_device_apps
ref: 0efbeba41657158a66bbc92c55d1226df56d0f1b # Branch: revanced-manager
device_info_plus: ^9.1.0
dynamic_color: ^1.6.3
dio: ^5.0.0
dio_cache_interceptor: ^3.4.0
dynamic_color: ^1.6.3
dynamic_themes: ^1.1.0
expandable: ^5.0.1
flex_color_scheme: ^7.0.1
flutter:
sdk: flutter
flutter_background:
@ -29,16 +30,15 @@ dependencies:
url: https://github.com/BenjaminHalko/flutter_background
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
flutter_svg: ^2.0.4
flutter_markdown: ^0.6.14
fluttertoast: ^8.2.4
font_awesome_flutter: ^10.4.0
get_it: ^7.6.4
google_fonts: ^6.1.0
http: ^1.1.0
injectable: ^2.1.1
intl: ^0.18.0
json_annotation: ^4.8.0
@ -49,42 +49,31 @@ dependencies:
package_info_plus: ^5.0.1
path_provider: ^2.0.14
permission_handler: ^11.0.1
pull_to_refresh: ^2.0.0
root:
git:
url: https://github.com/validcube/root
ref: 68e5678a535a2a3344828a14a39017fa74b9098c # Branch: libsu-521
screenshot_callback:
git: # remove once https://github.com/flutter-moum/flutter_screenshot_callback/pull/81 is merged
url: https://github.com/BenjaminHalko/flutter_screenshot_callback
ref: 1a1616ac91e16cd1f3dd170a81febf27ffce3587 # Branch: master
share_plus: ^7.2.1
shared_preferences: ^2.1.0
skeletons: ^0.0.3
stacked: ^3.2.0
stacked_generator: ^1.1.0
stacked_services: ^1.0.0
synchronized: ^3.1.0
timeago: ^3.3.0
timezone: ^0.9.0
url_launcher: ^6.1.10
flutter_dotenv: ^5.0.2
flutter_markdown: ^0.6.14
dio_cache_interceptor: ^3.4.0
screenshot_callback:
git: # remove once https://github.com/flutter-moum/flutter_screenshot_callback/pull/81 is merged
url: https://github.com/BenjaminHalko/flutter_screenshot_callback
ref: 1a1616ac91e16cd1f3dd170a81febf27ffce3587 # Branch: master
synchronized: ^3.1.0
connectivity_plus: ^5.0.1
flutter_file_dialog: ^3.0.2
wakelock_plus: ^1.1.3
share_plus: ^7.2.1
dev_dependencies:
json_serializable: ^6.6.1
build_runner: any
flutter_launcher_icons: ^0.13.0
flutter_lints: ^3.0.1
flutter_test:
sdk: flutter
injectable_generator: ^2.1.5
json_serializable: ^6.6.1
flutter:
uses-material-design: true