Compare commits

...

47 commits

Author SHA1 Message Date
Juan Gilsanz Polo
a4bf4cd3c5 Merge branch 'beta' 2025-03-23 19:52:20 +01:00
Juan Gilsanz Polo
61b0f724ba Updated app version 2025-03-23 19:51:58 +01:00
Juan Gilsanz Polo
52945b04ff Removed flutter displaymode 2025-03-23 19:46:52 +01:00
Juan Gilsanz Polo
8e5bbdbd4b Fixed update screen header color 2025-03-23 19:18:51 +01:00
Juan Gilsanz Polo
e6a01ac546 Disabled predictive back gesture 2025-03-23 19:18:43 +01:00
Juan Gilsanz Polo
e8440f7d1d Merge branch 'beta' 2025-03-17 19:13:25 +01:00
Juan Gilsanz Polo
6cc212751b Updated app version 2025-03-17 19:11:41 +01:00
Juan Gilsanz Polo
ae9d23d4a8 Support multiple subdomains 2025-03-17 19:10:06 +01:00
Juan
566254e617
Merge pull request #164 from mikropsoft/patch-1
Update app_tr.arb
2025-03-17 18:55:58 +01:00
𝗛𝗼𝗹𝗶
88339d1c40
Update app_tr.arb 2025-03-09 23:07:05 +03:00
𝗛𝗼𝗹𝗶
254bbcef57
Update app_tr.arb 2025-03-09 23:05:28 +03:00
𝗛𝗼𝗹𝗶
e7aacfbec1
Update app_tr.arb 2025-03-09 23:04:45 +03:00
Juan Gilsanz Polo
7a75a67701 Merge branch 'beta' 2025-03-09 20:37:16 +01:00
Juan Gilsanz Polo
7632d9ef87 Updated app version 2025-03-09 20:36:45 +01:00
Juan Gilsanz Polo
eded494024 Support TLD greater than 6 characters on domains 2025-03-09 20:28:00 +01:00
Juan Gilsanz Polo
e5979edf63 Added upstream dns timeout 2025-03-09 20:17:19 +01:00
Juan Gilsanz Polo
f27b17aad0 Fix filter logs by added client 2025-03-09 19:58:24 +01:00
Juan Gilsanz Polo
fd4daba2aa Merge branch 'master' into beta 2025-03-09 19:45:58 +01:00
Juan Gilsanz Polo
ce7a8e8cc5 Extracted some regexps to external file 2025-03-09 19:45:48 +01:00
Juan Gilsanz Polo
4282792ebd Updated stuff 2025-03-09 19:45:37 +01:00
Juan Gilsanz Polo
4766d1907f Merge branch 'beta' 2025-01-22 14:45:52 +01:00
Juan Gilsanz Polo
7f6f686b2b Updated app version 2025-01-22 14:45:38 +01:00
Juan Gilsanz Polo
02b659c1bc Changed my other apps text 2025-01-22 14:43:20 +01:00
Juan Gilsanz Polo
db6e63c4aa Fix bad performance debug mode 2025-01-22 14:41:04 +01:00
Juan Gilsanz Polo
a666d109d9 Bug fixes 2025-01-22 14:40:39 +01:00
Juan Gilsanz Polo
1f23f1f3ca Merge branch 'beta' 2025-01-22 00:00:36 +01:00
Juan Gilsanz Polo
51b8a6b610 Updated app version 2025-01-22 00:00:26 +01:00
Juan Gilsanz Polo
28034d4b74 Updated app version 2025-01-21 22:00:06 +01:00
Juan Gilsanz Polo
10ff5183f1 Added sorting options custom rules 2025-01-21 21:54:04 +01:00
Juan Gilsanz Polo
47b5313bf3 Removed unused imports 2025-01-21 20:56:56 +01:00
Juan Gilsanz Polo
791400f565 Added settings links 2025-01-21 20:55:54 +01:00
Juan Gilsanz Polo
06c9f7c771 Added support for custom time in logs settings 2025-01-21 20:47:24 +01:00
Juan Gilsanz Polo
2a0db84959 Updated libraries and other stuff 2025-01-21 20:47:10 +01:00
Juan Gilsanz Polo
74cade6553 Merge branch 'beta' 2024-10-01 18:50:46 +02:00
Juan Gilsanz Polo
1b5f258c96 Fixed windows installer builder 2024-10-01 18:50:37 +02:00
Juan Gilsanz Polo
aa511f8c42 Updated macos pods 2024-10-01 16:21:00 +02:00
Juan Gilsanz Polo
c28d2440b1 Merge branch 'beta' 2024-10-01 15:00:27 +02:00
Juan Gilsanz Polo
9d4c002813 Updated app version 2024-10-01 15:00:18 +02:00
Juan Gilsanz Polo
d7392e4b8d Updated compileSdkVersion to 35 2024-10-01 14:59:24 +02:00
Juan
4dc54794bd
Merge pull request #152 from navhaxs/master
Fix for not working 'path' parameter for reverse proxy
2024-09-29 22:26:37 +02:00
Jeremy Wong
a36335ef92 Fix missing 'path' in serverObj 2024-09-29 08:41:07 +10:00
Juan Gilsanz Polo
9096367843 Merge branch 'beta' 2024-09-12 14:47:31 +02:00
Juan Gilsanz Polo
0d0321a5ab Updated app version 2024-09-12 14:47:21 +02:00
Juan Gilsanz Polo
d903da0051 Removed app updates notifier due to a bug on the library 2024-09-12 14:33:32 +02:00
Juan Gilsanz Polo
b65dc35cb7 Exclude some sentry logs 2024-09-11 22:43:26 +02:00
Juan Gilsanz Polo
7bb7ad40c4 Fixed some bugs 2024-09-11 22:32:26 +02:00
Juan Gilsanz Polo
7579e2d580 Updated workflows 2024-09-11 21:14:58 +02:00
63 changed files with 991 additions and 1129 deletions

View file

@ -1,121 +0,0 @@
name: Compile and release beta build
on:
workflow_dispatch:
jobs:
build-android:
name: Build Android .apk and .aab
runs-on: ubuntu-latest
env:
ANDROID_AAB_RELEASE_PATH: build/app/outputs/bundle/release
ANDROID_APK_RELEASE_PATH: build/app/outputs/apk/release
outputs:
VERSION_NAME: ${{ steps.save_version.outputs.version_name }}
VERSION_NUMBER: ${{ steps.save_version.outputs.version_number }}
steps:
- uses: actions/checkout@v3
with:
ref: beta
- name: Decode android/app/keystore.jks
run: echo "${{ secrets.KEYSTORE_JKS }}" | base64 --decode > android/app/keystore.jks
- name: Decode android/key.properties
run: echo "${{ secrets.KEY_PROPERTIES }}" | base64 --decode > android/key.properties
- name: Decode .env
run: echo "${{ secrets.ENV }}" | base64 --decode > .env
- name: Read pubspec.yaml
uses: adore-me/read-yaml@v1.0.0
id: read_pubspec
with:
file: './pubspec.yaml'
key-path: '["version"]'
- name: Save version on env variable
id: save_version
run: |
version=${{ steps.read_pubspec.outputs.data }}
IFS='+'
read -r -a split <<< "$version"
echo "VERSION_NAME=$(echo ${split[0]})" >> $GITHUB_ENV
echo "version_name=${split[0]}" >> $GITHUB_OUTPUT
echo "version_number=${split[1]}" >> $GITHUB_OUTPUT
- name: Update KeyStore password in gradle properties
run: sed -i 's/#{KEYSTORE_PASS}#/${{ secrets.KEYSTORE_PASS }}/g' android/key.properties
- name: Update KeyStore key password in gradle properties
run: sed -i 's/#{KEYSTORE_KEY_PASS}#/${{ secrets.KEYSTORE_KEY_PASS }}/g' android/key.properties
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '18.x'
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- run: flutter clean
- run: flutter pub get
- run: flutter build apk --release
- run: flutter build appbundle --release
- name: Rename apk
run: mv $ANDROID_APK_RELEASE_PATH/app-release.apk $ANDROID_APK_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.apk
- name: Rename aab
run: mv $ANDROID_AAB_RELEASE_PATH/app-release.aab $ANDROID_AAB_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab
- name: Copy apk to project root
run: cp $ANDROID_APK_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.apk AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.apk
- name: Copy aab to project root
run: cp $ANDROID_AAB_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: android
path: |
AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab
AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.apk
release-builds-github:
name: Release beta build to GitHub
runs-on: ubuntu-latest
needs: [build-android]
env:
VERSION_NAME: ${{ needs.build-android.outputs.VERSION_NAME }}
VERSION_NUMBER: ${{ needs.build-android.outputs.VERSION_NUMBER }}
steps:
- uses: actions/checkout@v3
with:
ref: beta
- name: Create builds directory
run: mkdir releases
- name: Download Android artifacts
uses: actions/download-artifact@v3
with:
name: android
path: releases/
- name: Release to GitHub
uses: ncipollo/release-action@v1
with:
artifacts: "releases/*"
token: ${{ secrets.GH_TOKEN }}
tag: '${{ env.VERSION_NAME }}_(${{ env.VERSION_NUMBER }})'
name: v${{ env.VERSION_NAME }}
draft: true
prerelease: true
commit: ${{ github.sha }}
release-build-google-play:
name: Release Android beta build to the Google Play Store
runs-on: ubuntu-latest
needs: [build-android]
env:
VERSION_NAME: ${{ needs.build-android.outputs.VERSION_NAME }}
steps:
- uses: actions/checkout@v3
with:
ref: beta
- name: Download Android artifacts
uses: actions/download-artifact@v3
with:
name: android
- name: Release app to Google Play
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAYSTORE_ACCOUNT_KEY }}
packageName: com.jgeek00.adguard_home_manager
releaseFiles: AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab
track: beta
status: draft
releaseName: ${{ env.VERSION_NAME }}

View file

@ -1,300 +0,0 @@
name: Compile and release production build
on:
workflow_dispatch:
jobs:
build-android:
name: Build Android .apk and .aab
runs-on: ubuntu-latest
env:
ANDROID_AAB_RELEASE_PATH: build/app/outputs/bundle/release
ANDROID_APK_RELEASE_PATH: build/app/outputs/apk/release
outputs:
VERSION_NAME: ${{ steps.save_version.outputs.version_name }}
VERSION_NUMBER: ${{ steps.save_version.outputs.version_number }}
steps:
- uses: actions/checkout@v3
- name: Decode android/app/keystore.jks
run: echo "${{ secrets.KEYSTORE_JKS }}" | base64 --decode > android/app/keystore.jks
- name: Decode android/key.properties
run: echo "${{ secrets.KEY_PROPERTIES }}" | base64 --decode > android/key.properties
- name: Decode .env
run: echo "${{ secrets.ENV }}" | base64 --decode > .env
- name: Read pubspec.yaml
uses: jbutcher5/read-yaml@1.6
id: read_pubspec
with:
file: './pubspec.yaml' # File to read from
key-path: '["version"]'
- name: Save version on env variable
id: save_version
run: |
version=${{ steps.read_pubspec.outputs.data }}
IFS='+'
read -r -a split <<< "$version"
echo "VERSION_NAME=$(echo ${split[0]})" >> $GITHUB_ENV
echo "version_name=${split[0]}" >> $GITHUB_OUTPUT
echo "version_number=${split[1]}" >> $GITHUB_OUTPUT
- name: Update KeyStore password in gradle properties
run: sed -i 's/#{KEYSTORE_PASS}#/${{ secrets.KEYSTORE_PASS }}/g' android/key.properties
- name: Update KeyStore key password in gradle properties
run: sed -i 's/#{KEYSTORE_KEY_PASS}#/${{ secrets.KEYSTORE_KEY_PASS }}/g' android/key.properties
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '18.x'
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- run: flutter clean
- run: flutter pub get
- run: flutter build apk --release
- run: flutter build appbundle --release
- name: Rename apk
run: mv $ANDROID_APK_RELEASE_PATH/app-release.apk $ANDROID_APK_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.apk
- name: Rename aab
run: mv $ANDROID_AAB_RELEASE_PATH/app-release.aab $ANDROID_AAB_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab
- name: Copy apk to project root
run: cp $ANDROID_APK_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.apk AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.apk
- name: Copy aab to project root
run: cp $ANDROID_AAB_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: android
path: |
AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab
AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.apk
build-macos:
name: Build macOS .dmg
runs-on: macos-latest
env:
MACOS_APP_RELEASE_PATH: build/macos/Build/Products/Release
outputs:
VERSION_NAME: ${{ steps.save_version.outputs.version_name }}
VERSION_NUMBER: ${{ steps.save_version.outputs.version_number }}
steps:
- uses: actions/checkout@v3
- name: Decode .env
run: echo "${{ secrets.ENV }}" | base64 --decode > .env
- name: Read pubspec.yaml
uses: jbutcher5/read-yaml@1.6
id: read_pubspec
with:
file: './pubspec.yaml'
key-path: '["version"]'
- name: Save version on env variable
id: save_version
run: |
version=${{ steps.read_pubspec.outputs.data }}
IFS='+'
read -r -a split <<< "$version"
echo "VERSION_NAME=$(echo ${split[0]})" >> $GITHUB_ENV
echo "version_name=${split[0]}" >> $GITHUB_OUTPUT
echo "version_number=${split[1]}" >> $GITHUB_OUTPUT
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- run: flutter clean
- run: flutter pub get
- run: flutter build macos --release
- name: Install the Apple certificate and sign the application
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PWD: ${{ secrets.APPLE_CERTIFICATE_PWD }}
APPLE_KEYCHAIN_PWD: ${{ secrets.APPLE_KEYCHAIN_PWD }}
APPLE_IDENTITY_ID: ${{ secrets.APPLE_IDENTITY_ID }}
run: |
echo "$APPLE_CERTIFICATE" | base64 --decode > certificate.p12
security create-keychain -p $APPLE_KEYCHAIN_PWD build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p $APPLE_KEYCHAIN_PWD build.keychain
security import certificate.p12 -k build.keychain -P $APPLE_CERTIFICATE_PWD -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $APPLE_KEYCHAIN_PWD build.keychain
/usr/bin/codesign --force -s "$APPLE_IDENTITY_ID" $MACOS_APP_RELEASE_PATH/AdGuard\ Home\ Manager.app -v
- name: Create folder to build dmg
run: mkdir $MACOS_APP_RELEASE_PATH/AdGuard\ Home\ Manager
- name: Copy app into folder
run: cp -r $MACOS_APP_RELEASE_PATH/AdGuard\ Home\ Manager.app $MACOS_APP_RELEASE_PATH/AdGuard\ Home\ Manager/AdGuard\ Home\ Manager.app
- name: Generate symbolic link to Applications dir
run: ln -s /Applications $MACOS_APP_RELEASE_PATH/AdGuard\ Home\ Manager
- name: Generate dmg
run: hdiutil create -srcfolder $MACOS_APP_RELEASE_PATH/AdGuard\ Home\ Manager $MACOS_APP_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_macOS_Universal.dmg
- name: Copy dmg to project root
run: cp $MACOS_APP_RELEASE_PATH/AdGuardHomeManager_${{ env.VERSION_NAME }}_macOS_Universal.dmg AdGuardHomeManager_${{ env.VERSION_NAME }}_macOS_Universal.dmg
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: macos
path: AdGuardHomeManager_${{ env.VERSION_NAME }}_macOS_Universal.dmg
build-linux:
name: Build Linux .tar.gz and .deb
runs-on: ubuntu-latest
outputs:
VERSION_NAME: ${{ steps.save_version.outputs.version_name }}
VERSION_NUMBER: ${{ steps.save_version.outputs.version_number }}
steps:
- uses: actions/checkout@v3
- name: Decode .env
run: echo "${{ secrets.ENV }}" | base64 --decode > .env
- name: Read pubspec.yaml
uses: jbutcher5/read-yaml@1.6
id: read_pubspec
with:
file: './pubspec.yaml'
key-path: '["version"]'
- name: Save version on env variable
id: save_version
run: |
version=${{ steps.read_pubspec.outputs.data }}
IFS='+'
read -r -a split <<< "$version"
echo "VERSION_NAME=$(echo ${split[0]})" >> $GITHUB_ENV
echo "version_name=${split[0]}" >> $GITHUB_OUTPUT
echo "version_number=${split[1]}" >> $GITHUB_OUTPUT
- name: Update version in debian.yaml
run: sed -i 's/<REPLACE_VERSION_NUMBER_ACTIONS>/${{ env.VERSION_NAME }}/g' debian/debian.yaml
- name: Update dependencies list
run: sudo apt-get update
- name: Install dependencies
run: sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- run: flutter clean
- run: flutter pub get
- run: flutter build linux --release
- name: Install flutter_to_debian
run: dart pub global activate flutter_to_debian
- name: Generate .deb package
run: flutter_to_debian
- name: Move .deb package to project root
run: mv build/linux/x64/release/debian/AdGuardHomeManager_${{ env.VERSION_NAME }}_amd64.deb AdGuardHomeManager_${{ env.VERSION_NAME }}_Linux_amd64.deb
- name: Generate .tar.gz package
uses: a7ul/tar-action@v1.1.3
id: compress
with:
command: c
cwd: build/linux/x64/release/bundle
files: |
./data
./lib
./AdGuardHomeManager
outPath: AdGuardHomeManager_${{ env.VERSION_NAME }}_Linux.tar.gz
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: linux
path: |
AdGuardHomeManager_${{ env.VERSION_NAME }}_Linux_amd64.deb
AdGuardHomeManager_${{ env.VERSION_NAME }}_Linux.tar.gz
build-windows:
name: Build Windows installer
runs-on: windows-latest
outputs:
VERSION_NAME: ${{ steps.save_version.outputs.version_name }}
VERSION_NUMBER: ${{ steps.save_version.outputs.version_number }}
steps:
- uses: actions/checkout@v3
- name: Decode .env
shell: pwsh
run: |
[IO.File]::WriteAllBytes('.env', [Convert]::FromBase64String('${{ secrets.ENV }}'))
- name: Read pubspec.yaml
uses: jbutcher5/read-yaml@1.6
id: read_pubspec
with:
file: './pubspec.yaml'
key-path: '["version"]'
- name: Save version on env variable
shell: bash
id: save_version
run: |
version=${{ steps.read_pubspec.outputs.data }}
IFS='+'
read -r -a split <<< "$version"
echo "VERSION_NAME=$(echo ${split[0]})" >> $GITHUB_ENV
echo "version_name=${split[0]}" >> $GITHUB_OUTPUT
echo "version_number=${split[1]}" >> $GITHUB_OUTPUT
- name: Update version in innosetup config file
shell: pwsh
run: |
(Get-Content windows/innosetup_installer_builder.iss) -replace '<REPLACE_VERSION_ACTIONS>', '${{ env.VERSION_NAME }}' | Out-File -encoding ASCII windows/innosetup_installer_builder.iss
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- run: flutter clean
- run: flutter pub get
- run: flutter build windows --release
- name: Build installer witn innosetup
run: iscc /Q windows/innosetup_installer_builder.iss
- name: Move installer file to root directory
run: move build/windows/aghm_installer.exe AdGuardHomeManager_${{ env.VERSION_NAME }}_Windows_x64.exe
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: windows
path: AdGuardHomeManager_${{ env.VERSION_NAME }}_Windows_x64.exe
release-builds-github:
name: Release builds to GitHub
runs-on: ubuntu-latest
needs: [build-android, build-macos, build-linux, build-windows]
env:
VERSION_NAME: ${{ needs.build-android.outputs.VERSION_NAME }}
VERSION_NUMBER: ${{ needs.build-android.outputs.VERSION_NUMBER }}
steps:
- uses: actions/checkout@v3
- name: Create builds directory
run: mkdir releases
- name: Download Android artifacts
uses: actions/download-artifact@v3
with:
name: android
path: releases/
- name: Download macOS artifacts
uses: actions/download-artifact@v3
with:
name: macos
path: releases/
- name: Download Linux artifacts
uses: actions/download-artifact@v3
with:
name: linux
path: releases/
- name: Download Windows artifacts
uses: actions/download-artifact@v3
with:
name: windows
path: releases/
- name: Release to GitHub
uses: ncipollo/release-action@v1
with:
artifacts: "releases/*"
token: ${{ secrets.GH_TOKEN }}
tag: '${{ env.VERSION_NAME }}_(${{ env.VERSION_NUMBER }})'
name: v${{ env.VERSION_NAME }}
draft: true
prerelease: false
commit: ${{ github.sha }}
release-build-google-play:
name: Release Android build to the Google Play Store
runs-on: ubuntu-latest
needs: [build-android, build-macos, build-linux, build-windows]
env:
VERSION_NAME: ${{ needs.build-android.outputs.VERSION_NAME }}
steps:
- uses: actions/checkout@v3
- name: Download Android artifacts
uses: actions/download-artifact@v3
with:
name: android
- name: Release app to Google Play
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAYSTORE_ACCOUNT_KEY }}
packageName: com.jgeek00.adguard_home_manager
releaseFiles: AdGuardHomeManager_${{ env.VERSION_NAME }}_Android.aab
track: production
status: draft
releaseName: ${{ env.VERSION_NAME }}

4
.gitignore vendored
View file

@ -5,9 +5,11 @@
*.swp *.swp
.DS_Store .DS_Store
.atom/ .atom/
.build/
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
.swiftpm/
migrate_working_dir/ migrate_working_dir/
# Env # Env
@ -49,3 +51,5 @@ app.*.map.json
/debian/packages /debian/packages
untranslated.json untranslated.json
android/app/.cxx

View file

@ -12,5 +12,9 @@
"editor.formatOnSave": false, "editor.formatOnSave": false,
"editor.formatOnPaste": false, "editor.formatOnPaste": false,
"editor.formatOnType": false "editor.formatOnType": false
} },
"cSpell.ignorePaths": [
"/pubspec.yaml",
"/.github/workflows"
],
} }

View file

@ -113,7 +113,6 @@ If you like the project and you want to contribute with the development, you can
- [expandable](https://pub.dev/packages/expandable) - [expandable](https://pub.dev/packages/expandable)
- [package info plus](https://pub.dev/packages/package_info_plus) - [package info plus](https://pub.dev/packages/package_info_plus)
- [flutter phoenix](https://pub.dev/packages/flutter_phoenix) - [flutter phoenix](https://pub.dev/packages/flutter_phoenix)
- [flutter displaymode](https://pub.dev/packages/flutter_displaymode)
- [flutter launcher icons](https://pub.dev/packages/flutter_launcher_icons) - [flutter launcher icons](https://pub.dev/packages/flutter_launcher_icons)
- [flutter native splash](https://pub.dev/packages/flutter_native_splash) - [flutter native splash](https://pub.dev/packages/flutter_native_splash)
- [intl](https://pub.dev/packages/intl) - [intl](https://pub.dev/packages/intl)
@ -142,7 +141,6 @@ If you like the project and you want to contribute with the development, you can
- [flutter custom tabs](https://pub.dev/packages/flutter_custom_tabs) - [flutter custom tabs](https://pub.dev/packages/flutter_custom_tabs)
- [shared preferences](https://pub.dev/packages/shared_preferences) - [shared preferences](https://pub.dev/packages/shared_preferences)
- [window manager](https://pub.dev/packages/window_manager) - [window manager](https://pub.dev/packages/window_manager)
- [install referrer](https://pub.dev/packages/install_referrer)
<br> <br>

View file

@ -29,8 +29,9 @@ if (keystorePropertiesFile.exists()) {
} }
android { android {
compileSdkVersion 34 namespace "com.jgeek00.adguard_home_manager"
ndkVersion flutter.ndkVersion compileSdkVersion 35
ndkVersion "26.1.10909125"
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
@ -46,12 +47,9 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.jgeek00.adguard_home_manager" applicationId "com.jgeek00.adguard_home_manager"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 26 minSdkVersion 26
targetSdkVersion 34 targetSdkVersion 35
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

View file

@ -19,7 +19,7 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version '7.4.2' apply false id "com.android.application" version '8.6.0' apply false
id "org.jetbrains.kotlin.android" version "1.8.20" apply false id "org.jetbrains.kotlin.android" version "1.8.20" apply false
} }

2
debian/debian.yaml vendored
View file

@ -5,7 +5,7 @@ flutter_app:
control: control:
Package: AdGuardHomeManager Package: AdGuardHomeManager
Version: <REPLACE_VERSION_NUMBER_ACTIONS> Version: 2.20.1
Architecture: amd64 Architecture: amd64
Essential: no Essential: no
Priority: optional Priority: optional

View file

@ -27,11 +27,12 @@ ThemeData lightTheme(ColorScheme? dynamicColorScheme) => ThemeData(
dialogTheme: DialogTheme( dialogTheme: DialogTheme(
surfaceTintColor: dynamicColorScheme?.surfaceTint surfaceTintColor: dynamicColorScheme?.surfaceTint
), ),
pageTransitionsTheme: const PageTransitionsTheme( // DISABLE PREDICTIVE BACK GESTURE
builders: { // pageTransitionsTheme: const PageTransitionsTheme(
TargetPlatform.android: PredictiveBackPageTransitionsBuilder() // builders: {
} // TargetPlatform.android: PredictiveBackPageTransitionsBuilder()
) // }
// )
); );
ThemeData darkTheme(ColorScheme? dynamicColorScheme) => ThemeData( ThemeData darkTheme(ColorScheme? dynamicColorScheme) => ThemeData(
@ -62,11 +63,12 @@ ThemeData darkTheme(ColorScheme? dynamicColorScheme) => ThemeData(
dialogTheme: DialogTheme( dialogTheme: DialogTheme(
surfaceTintColor: dynamicColorScheme?.surfaceTint surfaceTintColor: dynamicColorScheme?.surfaceTint
), ),
pageTransitionsTheme: const PageTransitionsTheme( // DISABLE PREDICTIVE BACK GESTURE
builders: { // pageTransitionsTheme: const PageTransitionsTheme(
TargetPlatform.android: PredictiveBackPageTransitionsBuilder() // builders: {
} // TargetPlatform.android: PredictiveBackPageTransitionsBuilder()
) // }
// )
); );
ThemeData lightThemeOldVersions(MaterialColor primaryColor) => ThemeData( ThemeData lightThemeOldVersions(MaterialColor primaryColor) => ThemeData(
@ -85,11 +87,12 @@ ThemeData lightThemeOldVersions(MaterialColor primaryColor) => ThemeData(
iconColor: Color.fromRGBO(117, 117, 117, 1), iconColor: Color.fromRGBO(117, 117, 117, 1),
), ),
brightness: Brightness.light, brightness: Brightness.light,
pageTransitionsTheme: const PageTransitionsTheme( // DISABLE PREDICTIVE BACK GESTURE
builders: { // pageTransitionsTheme: const PageTransitionsTheme(
TargetPlatform.android: PredictiveBackPageTransitionsBuilder() // builders: {
} // TargetPlatform.android: PredictiveBackPageTransitionsBuilder()
) // }
// )
); );
ThemeData darkThemeOldVersions(MaterialColor primaryColor) => ThemeData( ThemeData darkThemeOldVersions(MaterialColor primaryColor) => ThemeData(
@ -111,9 +114,10 @@ ThemeData darkThemeOldVersions(MaterialColor primaryColor) => ThemeData(
iconColor: Color.fromRGBO(187, 187, 187, 1), iconColor: Color.fromRGBO(187, 187, 187, 1),
), ),
brightness: Brightness.dark, brightness: Brightness.dark,
pageTransitionsTheme: const PageTransitionsTheme( // DISABLE PREDICTIVE BACK GESTURE
builders: { // pageTransitionsTheme: const PageTransitionsTheme(
TargetPlatform.android: PredictiveBackPageTransitionsBuilder() // builders: {
} // TargetPlatform.android: PredictiveBackPageTransitionsBuilder()
) // }
// )
); );

View file

@ -1,2 +1,3 @@
enum LoadStatus { loading, loaded, error } enum LoadStatus { loading, loaded, error }
enum HomeTopItems { queriedDomains, blockedDomains, recurrentClients, topUpstreams, avgUpstreamResponseTime } enum HomeTopItems { queriedDomains, blockedDomains, recurrentClients, topUpstreams, avgUpstreamResponseTime }
enum CustomRulesSorting { topBottom, bottomTop }

View file

@ -0,0 +1,12 @@
class Regexps {
static final wildcardDomain = RegExp(r'^(\*\.)?(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,10}$');
static final domain = RegExp(r'^((?:(?:[a-zA-Z]{1})|(?:[a-zA-Z]{1}[a-zA-Z]{1})|(?:[a-zA-Z]{1}[0-9]{1})|(?:[0-9]{1}[a-zA-Z]{1})|(?:[a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.)+([a-zA-Z]{2,10}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,10})$');
static final ipv4Address = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$');
static final ipv6Address = RegExp(r'(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))');
static final subroute = RegExp(r'^\/\b([A-Za-z0-9_\-~/]*)[^\/|\.|\:]$');
static final macAddress = RegExp(r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$');
static final url = RegExp(r'^(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})$');
static final certificate = RegExp(r'(-{3,}(\bBEGIN CERTIFICATE\b))|(-{3,}-{3,}(\END CERTIFICATE\b)-{3,})', multiLine: true);
static final privateKey = RegExp(r'(-{3,}(\bBEGIN\b).*(PRIVATE KEY\b))|(-{3,}-{3,}(\bEND\b).*(PRIVATE KEY\b)-{3,})', multiLine: true);
static final path = RegExp(r'^(\/{0,1}(?!\/))[A-Za-z0-9\/\-_]+(\.([a-zA-Z]+))?$');
}

View file

@ -7,4 +7,6 @@ class Urls {
static const String adGuardHomeReleasesTags = "https://api.github.com/repos/AdGuardTeam/AdGuardHome/releases/tags"; static const String adGuardHomeReleasesTags = "https://api.github.com/repos/AdGuardTeam/AdGuardHome/releases/tags";
static const String googleSearchUrl = "https://www.google.com/search"; static const String googleSearchUrl = "https://www.google.com/search";
static const String connectionInstructions = "https://github.com/JGeek00/adguard-home-manager/wiki/Create-a-connection"; static const String connectionInstructions = "https://github.com/JGeek00/adguard-home-manager/wiki/Create-a-connection";
static const String appDetailsWebpage = "https://apps.jgeek00.com/jlfed8mcgyz6laf";
static const String jgeek00AppsWebpage = "https://apps.jgeek00.com";
} }

View file

@ -1,57 +0,0 @@
import 'dart:io';
import 'package:install_referrer/install_referrer.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/services/external_requests.dart';
import 'package:adguard_home_manager/models/github_release.dart';
Future<GitHubRelease?> checkAppUpdates({
required String currentBuildNumber,
required void Function(GitHubRelease?) setUpdateAvailable,
required InstallationAppReferrer? installationSource,
required bool isBeta
}) async {
var result = isBeta
? await ExternalRequests.getReleasesGitHub()
: await ExternalRequests.getReleaseData();
if (result.successful == true) {
late GitHubRelease gitHubRelease;
if (isBeta) {
gitHubRelease = (result.content as List<GitHubRelease>).firstWhere((r) => r.prerelease == true);
}
else {
gitHubRelease = result.content as GitHubRelease;
}
final update = gitHubUpdateExists(
currentBuildNumber: currentBuildNumber,
gitHubRelease: gitHubRelease,
isBeta: isBeta
);
if (update == true) {
setUpdateAvailable(gitHubRelease);
if (Platform.isAndroid) {
if (installationSource == InstallationAppReferrer.androidManually) {
return gitHubRelease;
}
else {
return null;
}
}
else if (Platform.isIOS) {
return null;
}
else {
return gitHubRelease;
}
}
else {
setUpdateAvailable(null);
}
}
return null;
}

View file

@ -1,7 +1,7 @@
import 'package:adguard_home_manager/constants/regexps.dart';
bool isIpAddress(String value) { bool isIpAddress(String value) {
final ipv4Regexp = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$'); if (Regexps.ipv4Address.hasMatch(value) || Regexps.ipv6Address.hasMatch(value)) {
final ipv6Regexp = RegExp(r'(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))');
if (ipv4Regexp.hasMatch(value) || ipv6Regexp.hasMatch(value)) {
return true; return true;
} }
else { else {

View file

@ -5,6 +5,15 @@ import 'package:url_launcher/url_launcher.dart' as url_launcher;
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
void openUrl(String url) async { void openUrl(String url) async {
if (!(url.startsWith("http") || url.startsWith("https"))) {
try {
url_launcher.launchUrl(Uri.parse(url));
} catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace);
}
return;
}
if (Platform.isAndroid || Platform.isIOS) { if (Platform.isAndroid || Platform.isIOS) {
try { try {
await flutter_custom_tabs.launchUrl( await flutter_custom_tabs.launchUrl(
@ -20,6 +29,7 @@ void openUrl(String url) async {
), ),
); );
} catch (e, stackTrace) { } catch (e, stackTrace) {
url_launcher.launchUrl(Uri.parse(url));
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
} }
} }

View file

@ -797,5 +797,14 @@
"dnsServerAddressCopied": "DNS server address copied to the clipboard", "dnsServerAddressCopied": "DNS server address copied to the clipboard",
"select": "Select", "select": "Select",
"liveLogs": "Live logs", "liveLogs": "Live logs",
"hereWillAppearRealtimeLogs": "Here there will appear the logs on realtime." "hereWillAppearRealtimeLogs": "Here there will appear the logs on realtime.",
"applicationDetails": "Application details",
"applicationDetailsDescription": "App repository, stores where it's available, and more",
"myOtherApps": "My other apps",
"myOtherAppsDescription": "Check my other apps, make a donation, contact support, and more",
"topToBottom": "From top to bottom",
"bottomToTop": "From bottom to top",
"upstreamTimeout": "Upstream timeout",
"upstreamTimeoutHelper": "Specifies the number of seconds to wait for a response from the upstream server",
"fieldCannotBeEmpty": "This field cannot be empty"
} }

View file

@ -403,7 +403,7 @@
"dnsRewriteRuleDeleted": "Reescritura DNS eliminada correctamente", "dnsRewriteRuleDeleted": "Reescritura DNS eliminada correctamente",
"dnsRewriteRuleNotDeleted": "La reescritura DNS no pudo ser eliminada", "dnsRewriteRuleNotDeleted": "La reescritura DNS no pudo ser eliminada",
"addDnsRewrite": "Añadir reescritura DNS", "addDnsRewrite": "Añadir reescritura DNS",
"addingRewrite": "Añadiend reescritura...", "addingRewrite": "Añadiendo reescritura...",
"dnsRewriteRuleAdded": "Regla de reescritura DNS añadida correctamente", "dnsRewriteRuleAdded": "Regla de reescritura DNS añadida correctamente",
"dnsRewriteRuleNotAdded": "La regla de reescritura DNS no ha podido ser añadida", "dnsRewriteRuleNotAdded": "La regla de reescritura DNS no ha podido ser añadida",
"logsSettings": "Ajustes de registros", "logsSettings": "Ajustes de registros",
@ -797,5 +797,14 @@
"dnsServerAddressCopied": "Dirección del servidor DNS copiada al portapapeles", "dnsServerAddressCopied": "Dirección del servidor DNS copiada al portapapeles",
"select": "Seleccionar", "select": "Seleccionar",
"liveLogs": "Registros en directo", "liveLogs": "Registros en directo",
"hereWillAppearRealtimeLogs": "Aquí aparecerán los registros en tiempo real." "hereWillAppearRealtimeLogs": "Aquí aparecerán los registros en tiempo real.",
"applicationDetails": "Detalles de la aplicación",
"applicationDetailsDescription": "Repositorio de la app, tiendas donde está disponible, y más",
"myOtherApps": "Mis otras apps",
"myOtherAppsDescription": "Comprueba mis otras apps, hacer una donación, contactar al soporte, y más",
"topToBottom": "Desde arriba hacia abajo",
"bottomToTop": "Desde abajo hacia arriba",
"upstreamTimeout": "Tiempo de espera del upstream",
"upstreamTimeoutHelper": "Especifica el número de segundos que se debe esperar para recibir una respuesta del servidor upstream",
"fieldCannotBeEmpty": "El campo no puede estar vacío"
} }

View file

@ -791,5 +791,20 @@
"clientDisallowedSuccessfully": "İstemci başarıyla reddedildi", "clientDisallowedSuccessfully": "İstemci başarıyla reddedildi",
"changesNotSaved": "Değişiklikler kaydedilemedi", "changesNotSaved": "Değişiklikler kaydedilemedi",
"allowingClient": "İstemciye izin veriliyor...", "allowingClient": "İstemciye izin veriliyor...",
"disallowingClient": "İstemci reddediliyor..." "disallowingClient": "İstemci reddediliyor...",
"clientIpCopied": "İstemci IP'si panoya kopyalandı",
"clientNameCopied": "İstemci adı panoya kopyalandı",
"dnsServerAddressCopied": "DNS sunucu adresi panoya kopyalandı",
"select": "Seç",
"liveLogs": "Canlı günlükler",
"hereWillAppearRealtimeLogs": "Burada gerçek zamanlı günlükler görünecek.",
"applicationDetails": "Uygulama detayları",
"applicationDetailsDescription": "Uygulama deposu, mevcut olduğu mağazalar ve daha fazlası",
"myOtherApps": "Diğer uygulamalarım",
"myOtherAppsDescription": "Diğer uygulamalarımı kontrol et, bağış yap, destekle iletişime geç ve daha fazlası",
"topToBottom": "Yukarıdan aşağıya",
"bottomToTop": "Aşağıdan yukarıya",
"upstreamTimeout": "Üst sunucu zaman aşımı",
"upstreamTimeoutHelper": "Üst DNS sunucusundan yanıt bekleme süresini saniye cinsinden belirtir",
"fieldCannotBeEmpty": "Bu alan boş olamaz"
} }

View file

@ -4,9 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:install_referrer/install_referrer.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
@ -79,11 +77,6 @@ void main() async {
HttpOverrides.global = MyHttpOverrides(); HttpOverrides.global = MyHttpOverrides();
} }
if (Platform.isAndroid || Platform.isIOS) {
InstallationAppReferrer installationSource = await InstallReferrer.referrer;
appConfigProvider.setInstallationSource(installationSource);
}
final dbData = await loadDb(); final dbData = await loadDb();
serversProvider.setDbInstance(dbData['dbInstance']); serversProvider.setDbInstance(dbData['dbInstance']);
serversProvider.saveFromDb(dbData['servers']); serversProvider.saveFromDb(dbData['servers']);
@ -169,6 +162,31 @@ void main() async {
(options) { (options) {
options.dsn = dotenv.env['SENTRY_DSN']; options.dsn = dotenv.env['SENTRY_DSN'];
options.sendDefaultPii = false; options.sendDefaultPii = false;
options.beforeSend = (event, hint) {
if (event.throwable is HttpException) {
return null;
}
if (event.message?.formatted.contains("HttpException") == true) {
return null;
}
if (
event.message?.formatted.contains("Unexpected character") ?? false ||
(event.throwable != null && event.throwable!.toString().contains("Unexpected character"))
) {
return null;
}
if (
event.message?.formatted.contains("Unexpected end of input") ?? false ||
(event.throwable != null && event.throwable!.toString().contains("Unexpected end of input"))
) {
return null;
}
return event;
};
}, },
appRunner: () => startApp() appRunner: () => startApp()
); );
@ -178,37 +196,9 @@ void main() async {
} }
} }
class Main extends StatefulWidget { class Main extends StatelessWidget {
const Main({super.key}); const Main({super.key});
@override
State<Main> createState() => _MainState();
}
class _MainState extends State<Main> {
List<DisplayMode> modes = <DisplayMode>[];
DisplayMode? active;
DisplayMode? preferred;
Future<void> displayMode() async {
try {
modes = await FlutterDisplayMode.supported;
preferred = await FlutterDisplayMode.preferred;
active = await FlutterDisplayMode.active;
await FlutterDisplayMode.setHighRefreshRate();
setState(() {});
} catch (_) {
// ---- //
}
}
@override
void initState() {
displayMode();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);

View file

@ -26,6 +26,7 @@ class DnsInfo {
int? ratelimitSubnetLenIpv4; int? ratelimitSubnetLenIpv4;
int? ratelimitSubnetLenIpv6; int? ratelimitSubnetLenIpv6;
List<String>? ratelimitWhitelist; List<String>? ratelimitWhitelist;
int? upstreamTimeout;
DnsInfo({ DnsInfo({
required this.upstreamDns, required this.upstreamDns,
@ -55,6 +56,7 @@ class DnsInfo {
required this.ratelimitSubnetLenIpv4, required this.ratelimitSubnetLenIpv4,
required this.ratelimitSubnetLenIpv6, required this.ratelimitSubnetLenIpv6,
required this.ratelimitWhitelist, required this.ratelimitWhitelist,
required this.upstreamTimeout,
}); });
factory DnsInfo.fromJson(Map<String, dynamic> json) => DnsInfo( factory DnsInfo.fromJson(Map<String, dynamic> json) => DnsInfo(
@ -85,6 +87,7 @@ class DnsInfo {
ratelimitSubnetLenIpv4: json["ratelimit_subnet_len_ipv4"], ratelimitSubnetLenIpv4: json["ratelimit_subnet_len_ipv4"],
ratelimitSubnetLenIpv6: json["ratelimit_subnet_len_ipv6"], ratelimitSubnetLenIpv6: json["ratelimit_subnet_len_ipv6"],
ratelimitWhitelist: json["ratelimit_whitelist"] != null ? List<String>.from(json["ratelimit_whitelist"].map((x) => x)) : [], ratelimitWhitelist: json["ratelimit_whitelist"] != null ? List<String>.from(json["ratelimit_whitelist"].map((x) => x)) : [],
upstreamTimeout: json["upstream_timeout"],
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -115,5 +118,6 @@ class DnsInfo {
"ratelimit_subnet_len_ipv4": ratelimitSubnetLenIpv4, "ratelimit_subnet_len_ipv4": ratelimitSubnetLenIpv4,
"ratelimit_subnet_len_ipv6": ratelimitSubnetLenIpv6, "ratelimit_subnet_len_ipv6": ratelimitSubnetLenIpv6,
"ratelimit_whitelist": ratelimitWhitelist != null ? List<String>.from(ratelimitWhitelist!.map((x) => x)) : null, "ratelimit_whitelist": ratelimitWhitelist != null ? List<String>.from(ratelimitWhitelist!.map((x) => x)) : null,
"upstream_timeout": upstreamTimeout,
}; };
} }

View file

@ -5,7 +5,7 @@ DnsStatistics dnsStatisticsFromJson(String str) => DnsStatistics.fromJson(json.d
String dnsStatisticsToJson(DnsStatistics data) => json.encode(data.toJson()); String dnsStatisticsToJson(DnsStatistics data) => json.encode(data.toJson());
class DnsStatistics { class DnsStatistics {
final String timeUnits; final String? timeUnits;
final List<Map<String, int>> topQueriedDomains; final List<Map<String, int>> topQueriedDomains;
final List<Map<String, int>> topClients; final List<Map<String, int>> topClients;
final List<Map<String, int>> topBlockedDomains; final List<Map<String, int>> topBlockedDomains;
@ -43,9 +43,9 @@ class DnsStatistics {
factory DnsStatistics.fromJson(Map<String, dynamic> json) => DnsStatistics( factory DnsStatistics.fromJson(Map<String, dynamic> json) => DnsStatistics(
timeUnits: json["time_units"], timeUnits: json["time_units"],
topQueriedDomains: List<Map<String, int>>.from(json["top_queried_domains"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))), topQueriedDomains: json["top_queried_domains"] != null ? List<Map<String, int>>.from(json["top_queried_domains"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))) : [],
topClients: List<Map<String, int>>.from(json["top_clients"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))), topClients: json["top_clients"] != null ? List<Map<String, int>>.from(json["top_clients"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))) : [],
topBlockedDomains: List<Map<String, int>>.from(json["top_blocked_domains"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))), topBlockedDomains: json["top_blocked_domains"] != null ? List<Map<String, int>>.from(json["top_blocked_domains"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))): [],
topUpstreamResponses: json["top_upstreams_responses"] != null ? List<Map<String, int>>.from(json["top_upstreams_responses"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))) : null, topUpstreamResponses: json["top_upstreams_responses"] != null ? List<Map<String, int>>.from(json["top_upstreams_responses"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))) : null,
topUpstreamsAvgTime: json["top_upstreams_avg_time"] != null ? List<Map<String, double>>.from(json["top_upstreams_avg_time"].map((x) => Map.from(x).map((k, v) => MapEntry<String, double>(k, v)))) : null, topUpstreamsAvgTime: json["top_upstreams_avg_time"] != null ? List<Map<String, double>>.from(json["top_upstreams_avg_time"].map((x) => Map.from(x).map((k, v) => MapEntry<String, double>(k, v)))) : null,
dnsQueries: List<int>.from(json["dns_queries"].map((x) => x)), dnsQueries: List<int>.from(json["dns_queries"].map((x) => x)),

View file

@ -2,7 +2,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:install_referrer/install_referrer.dart';
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
@ -58,8 +57,6 @@ class AppConfigProvider with ChangeNotifier {
GitHubRelease? _appUpdatesAvailable; GitHubRelease? _appUpdatesAvailable;
InstallationAppReferrer? _installationSource;
PackageInfo? get getAppInfo { PackageInfo? get getAppInfo {
return _appInfo; return _appInfo;
} }
@ -162,10 +159,6 @@ class AppConfigProvider with ChangeNotifier {
return _appUpdatesAvailable; return _appUpdatesAvailable;
} }
InstallationAppReferrer? get installationSource {
return _installationSource;
}
List<HomeTopItems> get homeTopItemsOrder { List<HomeTopItems> get homeTopItemsOrder {
return _homeTopItemsOrder; return _homeTopItemsOrder;
} }
@ -227,11 +220,6 @@ class AppConfigProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void setInstallationSource(InstallationAppReferrer value) {
_installationSource = value;
notifyListeners();
}
Future<bool> setOverrideSslCheck(bool status) async { Future<bool> setOverrideSslCheck(bool status) async {
try { try {
sharedPreferencesInstance.setBool('overrideSslCheck', status); sharedPreferencesInstance.setBool('overrideSslCheck', status);

View file

@ -152,19 +152,25 @@ class DnsProvider with ChangeNotifier {
data: value data: value
); );
void updateValue(dynamic parameter, dynamic value) {
if (value != null) {
parameter = value;
}
}
if (result.successful == true) { if (result.successful == true) {
DnsInfo data = dnsInfo!; DnsInfo data = dnsInfo!;
data.ratelimit = value['ratelimit']; updateValue(data.ratelimit, value['ratelimit']);
data.ednsCsEnabled = value['edns_cs_enabled']; updateValue(data.ednsCsEnabled, value['edns_cs_enabled']);
data.dnssecEnabled = value['dnssec_enabled']; updateValue(data.dnssecEnabled, value['dnssec_enabled']);
data.disableIpv6 = value['disable_ipv6']; updateValue(data.disableIpv6, value['disable_ipv6']);
data.blockingMode = value['blocking_mode']; updateValue(data.blockingMode, value['blocking_mode']);
data.blockingIpv4 = value['blocking_ipv4']; updateValue(data.blockingIpv4, value['blocking_ipv4']);
data.blockingIpv6 = value['blocking_ipv6']; updateValue(data.blockingIpv6, value['blocking_ipv6']);
data.blockedResponseTtl = value['blocked_response_ttl']; updateValue(data.blockedResponseTtl, value['blocked_response_ttl']);
data.ratelimitSubnetLenIpv4 = value['ratelimit_subnet_len_ipv4']; updateValue(data.ratelimitSubnetLenIpv4, value['ratelimit_subnet_len_ipv4']);
data.ratelimitSubnetLenIpv6 = value['ratelimit_subnet_len_ipv6']; updateValue(data.ratelimitSubnetLenIpv6, value['ratelimit_subnet_len_ipv6']);
data.ratelimitWhitelist = value['ratelimit_whitelist']; updateValue(data.ratelimitWhitelist, value['ratelimit_whitelist']);
setDnsInfoData(data); setDnsInfoData(data);
return result; return result;
} }

View file

@ -25,11 +25,15 @@ class ClientsFab extends StatelessWidget {
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
void confirmAddClient(Client client) async { void confirmAddClient(Client client) async {
if (!context.mounted) return;
ProcessModal processModal = ProcessModal(); ProcessModal processModal = ProcessModal();
processModal.open(AppLocalizations.of(context)!.addingClient); processModal.open(AppLocalizations.of(context)!.addingClient);
final result = await clientsProvider.addClient(client); final result = await clientsProvider.addClient(client);
if (!context.mounted) return;
processModal.close(); processModal.close();
if (result == true) { if (result == true) {

View file

@ -33,6 +33,8 @@ class AddFiltersButton extends StatelessWidget {
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
void confirmAddRule(String rule) async { void confirmAddRule(String rule) async {
if (!context.mounted) return;
ProcessModal processModal = ProcessModal(); ProcessModal processModal = ProcessModal();
processModal.open(AppLocalizations.of(context)!.addingRule); processModal.open(AppLocalizations.of(context)!.addingRule);
@ -58,6 +60,8 @@ class AddFiltersButton extends StatelessWidget {
} }
void confirmEditCustomRules(List<String> rules) async { void confirmEditCustomRules(List<String> rules) async {
if (!context.mounted) return;
ProcessModal processModal = ProcessModal(); ProcessModal processModal = ProcessModal();
processModal.open(AppLocalizations.of(context)!.savingCustomRules); processModal.open(AppLocalizations.of(context)!.savingCustomRules);
@ -137,6 +141,8 @@ class AddFiltersButton extends StatelessWidget {
} }
void confirmAddList({required String name, required String url, required String type}) async { void confirmAddList({required String name, required String url, required String type}) async {
if (!context.mounted) return;
ProcessModal processModal = ProcessModal(); ProcessModal processModal = ProcessModal();
processModal.open(AppLocalizations.of(context)!.addingList); processModal.open(AppLocalizations.of(context)!.addingList);

View file

@ -6,6 +6,7 @@ import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/filters/add_button.dart'; import 'package:adguard_home_manager/screens/filters/add_button.dart';
import 'package:adguard_home_manager/screens/filters/modals/custom_rules/sort_rules.dart';
import 'package:adguard_home_manager/widgets/tab_content_list.dart'; import 'package:adguard_home_manager/widgets/tab_content_list.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
@ -34,6 +35,8 @@ class CustomRulesList extends StatefulWidget {
class _CustomRulesListState extends State<CustomRulesList> { class _CustomRulesListState extends State<CustomRulesList> {
late bool isVisible; late bool isVisible;
CustomRulesSorting _sortingMethod = CustomRulesSorting.topBottom;
@override @override
initState(){ initState(){
super.initState(); super.initState();
@ -60,6 +63,8 @@ class _CustomRulesListState extends State<CustomRulesList> {
final filteringProvider = Provider.of<FilteringProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final renderData = _sortingMethod == CustomRulesSorting.bottomTop ? widget.data.reversed.toList() : widget.data.toList();
bool checkIfComment(String value) { bool checkIfComment(String value) {
final regex = RegExp(r'^(!|#).*$'); final regex = RegExp(r'^(!|#).*$');
if (regex.hasMatch(value)) { if (regex.hasMatch(value)) {
@ -104,6 +109,16 @@ class _CustomRulesListState extends State<CustomRulesList> {
} }
} }
void showSortingMethodModal() {
showDialog(
context: context,
builder: (ctx) => SortCustomRulesModal(
sortingMethod: _sortingMethod,
onSelect: (value) => setState(() => _sortingMethod = value),
),
);
}
return CustomTabContentList( return CustomTabContentList(
loadingGenerator: () => SizedBox( loadingGenerator: () => SizedBox(
width: double.maxFinite, width: double.maxFinite,
@ -124,10 +139,10 @@ class _CustomRulesListState extends State<CustomRulesList> {
], ],
), ),
), ),
itemsCount: widget.data.length, itemsCount: renderData.length,
contentWidget: (index) => ListTile( contentWidget: (index) => ListTile(
title: Text( title: Text(
widget.data[index], renderData[index],
style: TextStyle( style: TextStyle(
color: checkIfComment(widget.data[index]) == true color: checkIfComment(widget.data[index]) == true
? Theme.of(context).colorScheme.onSurface.withOpacity(0.6) ? Theme.of(context).colorScheme.onSurface.withOpacity(0.6)
@ -135,9 +150,9 @@ class _CustomRulesListState extends State<CustomRulesList> {
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
), ),
), ),
subtitle: generateSubtitle(widget.data[index]), subtitle: generateSubtitle(renderData[index]),
trailing: IconButton( trailing: IconButton(
onPressed: () => widget.onRemoveCustomRule(widget.data[index]), onPressed: () => widget.onRemoveCustomRule(renderData[index]),
icon: const Icon(Icons.delete) icon: const Icon(Icons.delete)
), ),
), ),
@ -162,7 +177,7 @@ class _CustomRulesListState extends State<CustomRulesList> {
TextButton.icon( TextButton.icon(
onPressed: () async { onPressed: () async {
final result = await filteringProvider.fetchFilters(); final result = await filteringProvider.fetchFilters();
if (result == false) { if (result == false && context.mounted) {
showSnackbar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters, label: AppLocalizations.of(context)!.errorLoadFilters,
@ -212,6 +227,11 @@ class _CustomRulesListState extends State<CustomRulesList> {
}, },
fab: Column( fab: Column(
children: [ children: [
FloatingActionButton.small(
onPressed: showSortingMethodModal,
child: Icon(Icons.sort_rounded),
),
const SizedBox(height: 16),
AddFiltersButton( AddFiltersButton(
type: 'edit_custom_rule', type: 'edit_custom_rule',
widget: (fn) => FloatingActionButton.small( widget: (fn) => FloatingActionButton.small(
@ -229,7 +249,7 @@ class _CustomRulesListState extends State<CustomRulesList> {
), ),
], ],
), ),
heightFabHidden: -120, heightFabHidden: -180,
fabVisible: isVisible, fabVisible: isVisible,
); );
} }

View file

@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -97,8 +98,7 @@ class _ContentState extends State<_Content> {
} }
void validateUrl(String value) { void validateUrl(String value) {
final urlRegex = RegExp(r'^(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})$'); if (Regexps.url.hasMatch(value)) {
if (urlRegex.hasMatch(value)) {
setState(() => urlError = null); setState(() => urlError = null);
} }
else { else {

View file

@ -1,5 +1,6 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -63,8 +64,7 @@ class _ContentState extends State<_Content> {
Widget? resultWidget; Widget? resultWidget;
void validateDomain(String value) { void validateDomain(String value) {
final domainRegex = RegExp(r'^([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$'); if (Regexps.domain.hasMatch(value)) {
if (domainRegex.hasMatch(value)) {
setState(() => domainError = null); setState(() => domainError = null);
} }
else { else {

View file

@ -1,3 +1,4 @@
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:segmented_button_slide/segmented_button_slide.dart'; import 'package:segmented_button_slide/segmented_button_slide.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -41,8 +42,7 @@ class _AddCustomRuleState extends State<AddCustomRule> {
} }
void validateDomain(String value) { void validateDomain(String value) {
final domainRegex = RegExp(r'^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$'); if (Regexps.domain.hasMatch(value)) {
if (domainRegex.hasMatch(value)) {
setState(() => _domainError = null); setState(() => _domainError = null);
} }
else { else {

View file

@ -0,0 +1,128 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/constants/enums.dart';
class SortCustomRulesModal extends StatelessWidget {
final CustomRulesSorting sortingMethod;
final void Function(CustomRulesSorting) onSelect;
const SortCustomRulesModal({
super.key,
required this.sortingMethod,
required this.onSelect,
});
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: const EdgeInsets.symmetric(vertical: 16),
scrollable: true,
title: Column(
children: [
Icon(
Icons.sort_rounded,
size: 24,
color: Theme.of(context).listTileTheme.iconColor
),
const SizedBox(height: 16),
Text(
AppLocalizations.of(context)!.sortingOptions,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface
),
)
],
),
content: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: Column(
children: [
_CustomListTileDialog(
title: AppLocalizations.of(context)!.topToBottom,
icon: Icons.arrow_downward_rounded,
onTap: () {
Navigator.pop(context);
onSelect(CustomRulesSorting.topBottom);
},
isSelected: sortingMethod == CustomRulesSorting.topBottom
),
_CustomListTileDialog(
title: AppLocalizations.of(context)!.bottomToTop,
icon: Icons.arrow_upward_rounded,
onTap: () {
Navigator.pop(context);
onSelect(CustomRulesSorting.bottomTop);
},
isSelected: sortingMethod == CustomRulesSorting.bottomTop
),
]
),
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(AppLocalizations.of(context)!.close)
)
],
)
],
);
}
}
class _CustomListTileDialog extends StatelessWidget {
final String title;
final IconData? icon;
final void Function()? onTap;
final bool isSelected;
const _CustomListTileDialog({
required this.title,
required this.icon,
required this.onTap,
required this.isSelected,
});
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Icon(
icon,
color: Theme.of(context).colorScheme.onSurface,
),
const SizedBox(width: 24),
Flexible(
child: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Theme.of(context).colorScheme.onSurface,
),
),
),
const SizedBox(width: 24),
Icon(
isSelected == true ? Icons.radio_button_checked_rounded : Icons.radio_button_unchecked_rounded,
color: Theme.of(context).colorScheme.primary,
)
],
),
),
),
);
}
}

View file

@ -34,6 +34,7 @@ class HomeAppBar extends StatelessWidget {
void navigateServers() { void navigateServers() {
Future.delayed(const Duration(milliseconds: 0), (() { Future.delayed(const Duration(milliseconds: 0), (() {
if (!context.mounted) return;
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const Servers()) MaterialPageRoute(builder: (context) => const Servers())
); );

View file

@ -114,10 +114,12 @@ class _ClientsModalState extends State<ClientsModal> {
} }
void searchAddedClient(_ClientLog client) { void searchAddedClient(_ClientLog client) {
final notIps = client.ids?.where((e) => isIpAddress(e) == false).toList(); final ips = client.ids?.where((e) => isIpAddress(e) == true).toList();
if (notIps == null) return; if (ips == null || ips.isEmpty) return;
logsProvider.setSearchText('"${notIps[0]}"'); logsProvider.setSearchText(ips[0]);
logsProvider.filterLogs();
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.pop(context);
} }
if (widget.dialog == true) { if (widget.dialog == true) {
@ -302,7 +304,7 @@ class _ClientsModalState extends State<ClientsModal> {
subtitle: _selectedList == 0 ? _filteredClients[index].name : _filteredClients[index].ids?.join(", "), subtitle: _selectedList == 0 ? _filteredClients[index].name : _filteredClients[index].ids?.join(", "),
checkboxActive: logsProvider.selectedClients.contains(_filteredClients[index].ip), checkboxActive: logsProvider.selectedClients.contains(_filteredClients[index].ip),
isAddedClient: _selectedList == 1, isAddedClient: _selectedList == 1,
onSearchAddedClient: () => searchAddedClient(_filteredClients[index]), onSearchAddedClient: _filteredClients[index].ids != null && _filteredClients[index].ids!.where((e) => isIpAddress(e) == true).isNotEmpty ? () => searchAddedClient(_filteredClients[index]) : null,
onChanged: (isSelected) { onChanged: (isSelected) {
if (isSelected == true) { if (isSelected == true) {
logsProvider.setSelectedClients([ logsProvider.setSelectedClients([
@ -376,7 +378,7 @@ class _ListItem extends StatelessWidget {
final bool checkboxActive; final bool checkboxActive;
final void Function(bool) onChanged; final void Function(bool) onChanged;
final bool isAddedClient; final bool isAddedClient;
final void Function() onSearchAddedClient; final void Function()? onSearchAddedClient;
const _ListItem({ const _ListItem({
required this.title, required this.title,

View file

@ -96,6 +96,8 @@ class LogTile extends StatelessWidget {
} }
void blockUnblock({required String domain, required String newStatus}) async { void blockUnblock({required String domain, required String newStatus}) async {
if (!context.mounted) return;
final ProcessModal processModal = ProcessModal(); final ProcessModal processModal = ProcessModal();
processModal.open(AppLocalizations.of(context)!.savingUserFilters); processModal.open(AppLocalizations.of(context)!.savingUserFilters);
@ -124,6 +126,8 @@ class LogTile extends StatelessWidget {
} }
void confirmAddClient(Client client) async { void confirmAddClient(Client client) async {
if (!context.mounted) return;
ProcessModal processModal = ProcessModal(); ProcessModal processModal = ProcessModal();
processModal.open(AppLocalizations.of(context)!.addingClient); processModal.open(AppLocalizations.of(context)!.addingClient);
@ -150,6 +154,8 @@ class LogTile extends StatelessWidget {
} }
void blockUnblockRuleClient() async { void blockUnblockRuleClient() async {
if (!context.mounted) return;
ProcessModal processModal = ProcessModal(); ProcessModal processModal = ProcessModal();
processModal.open(AppLocalizations.of(context)!.addingRule); processModal.open(AppLocalizations.of(context)!.addingRule);

View file

@ -89,6 +89,7 @@ class LogsListAppBar extends StatelessWidget {
} }
void openLiveLogsScreen() { void openLiveLogsScreen() {
if (!context.mounted) return;
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => MultiProvider( builder: (context) => MultiProvider(

View file

@ -1,3 +1,4 @@
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -67,8 +68,7 @@ class __ContentState extends State<_Content> {
bool validData = false; bool validData = false;
void validateMac(String value) { void validateMac(String value) {
final RegExp macRegex = RegExp(r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$'); if (Regexps.macAddress.hasMatch(value)) {
if (macRegex.hasMatch(value)) {
setState(() => macError = null); setState(() => macError = null);
} }
else { else {
@ -78,8 +78,7 @@ class __ContentState extends State<_Content> {
} }
void validateIp(String value) { void validateIp(String value) {
RegExp ipAddress = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$'); if (Regexps.ipv4Address.hasMatch(value) == true) {
if (ipAddress.hasMatch(value) == true) {
setState(() => ipError = null); setState(() => ipError = null);
} }
else { else {

View file

@ -2,6 +2,7 @@
import 'dart:io'; import 'dart:io';
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -100,8 +101,8 @@ class _DhcpScreenState extends State<DhcpScreen> {
break; break;
} }
} }
final regex = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$');
if (regex.hasMatch(value)) { if (Regexps.ipv4Address.hasMatch(value)) {
setValue(null); setValue(null);
} }
else { else {
@ -126,8 +127,8 @@ class _DhcpScreenState extends State<DhcpScreen> {
break; break;
} }
} }
final regex = RegExp(r'^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$');
if (regex.hasMatch(value)) { if (Regexps.ipv6Address.hasMatch(value)) {
setValue(null); setValue(null);
} }
else { else {

View file

@ -1,5 +1,6 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart'; import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -23,8 +24,7 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
bool validValues = false; bool validValues = false;
void validateIp(Map<String, dynamic> field, String value) { void validateIp(Map<String, dynamic> field, String value) {
RegExp ipAddress = RegExp(r'(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$)'); if (Regexps.ipv4Address.hasMatch(value) == true || Regexps.ipv6Address.hasMatch(value) == true) {
if (ipAddress.hasMatch(value) == true) {
setState(() => field['error'] = null); setState(() => field['error'] = null);
} }
else { else {

View file

@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:adguard_home_manager/screens/settings/dns/comment_modal.dart'; import 'package:adguard_home_manager/screens/settings/dns/comment_modal.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -24,9 +25,7 @@ class _FallbackDnsScreenState extends State<FallbackDnsScreen> {
bool validValues = false; bool validValues = false;
void validateIp(Map<String, dynamic> field, String value) { void validateIp(Map<String, dynamic> field, String value) {
RegExp ipAddress = RegExp(r'(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$)'); if (Regexps.ipv4Address.hasMatch(value) == true || Regexps.ipv6Address.hasMatch(value) || Regexps.url.hasMatch(value) == true) {
RegExp url = RegExp(r'(https?|tls):\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)');
if (ipAddress.hasMatch(value) == true || url.hasMatch(value) == true) {
setState(() => field['error'] = null); setState(() => field['error'] = null);
} }
else { else {

View file

@ -1,3 +1,4 @@
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -33,8 +34,7 @@ class _RateLimitAllowlistModalState extends State<RateLimitAllowlistModal> {
List<_IpListItemController> _controllersList = []; List<_IpListItemController> _controllersList = [];
void _validateIp(String value, _IpListItemController item) { void _validateIp(String value, _IpListItemController item) {
final regexp = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$'); if (Regexps.ipv4Address.hasMatch(value)) {
if (regexp.hasMatch(value)) {
setState(() => _controllersList = _controllersList.map((e) { setState(() => _controllersList = _controllersList.map((e) {
if (e.id == item.id) { if (e.id == item.id) {
return _IpListItemController( return _IpListItemController(

View file

@ -1,5 +1,3 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -30,6 +28,9 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
bool validValues = false; bool validValues = false;
final upstreamTimeoutController = TextEditingController();
String? upstreamTimeoutError = null;
checkValidValues() { checkValidValues() {
if ( if (
dnsServers.isNotEmpty && dnsServers.isNotEmpty &&
@ -61,6 +62,7 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
} }
} }
upstreamMode = dnsProvider.dnsInfo!.upstreamMode ?? ""; upstreamMode = dnsProvider.dnsInfo!.upstreamMode ?? "";
upstreamTimeoutController.text = dnsProvider.dnsInfo!.upstreamTimeout != null ? dnsProvider.dnsInfo!.upstreamTimeout.toString() : "";
validValues = true; validValues = true;
super.initState(); super.initState();
} }
@ -72,6 +74,23 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
void validateTimeout(String value) {
if (value != '' && int.tryParse(value) != null && int.parse(value) > 0) {
setState(() {
upstreamTimeoutError = null;
validValues = true;
});
}
else {
setState(() {
upstreamTimeoutError = value == ''
? AppLocalizations.of(context)!.fieldCannotBeEmpty
: AppLocalizations.of(context)!.invalidValue;
validValues = false;
});
}
}
void openAddCommentModal() { void openAddCommentModal() {
if (width > 900 || !(Platform.isAndroid || Platform.isIOS)) { if (width > 900 || !(Platform.isAndroid || Platform.isIOS)) {
showDialog( showDialog(
@ -146,11 +165,13 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
final result = await dnsProvider.saveUpstreamDnsConfig({ final result = await dnsProvider.saveUpstreamDnsConfig({
"upstream_dns": dnsServers.map((e) => e['controller'] != null ? e['controller'].text : e['comment']).toList(), "upstream_dns": dnsServers.map((e) => e['controller'] != null ? e['controller'].text : e['comment']).toList(),
"upstream_mode": upstreamMode "upstream_mode": upstreamMode,
"upstream_timeout": int.tryParse(upstreamTimeoutController.text)
}); });
processModal.close(); processModal.close();
if (!context.mounted) return;
if (result.successful == true) { if (result.successful == true) {
showSnackbar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
@ -312,6 +333,27 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
subtitle: AppLocalizations.of(context)!.fastestIpAddressDescription, subtitle: AppLocalizations.of(context)!.fastestIpAddressDescription,
onChanged: (value) => setState(() => upstreamMode = value), onChanged: (value) => setState(() => upstreamMode = value),
), ),
const SizedBox(height: 16),
SectionLabel(label: AppLocalizations.of(context)!.others),
Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
controller: upstreamTimeoutController,
onChanged: validateTimeout,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.timer_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
labelText: AppLocalizations.of(context)!.upstreamTimeout,
helperText: AppLocalizations.of(context)!.upstreamTimeoutHelper,
helperMaxLines: 2,
errorText: upstreamTimeoutError
)
),
),
], ],
), ),
), ),

View file

@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -82,8 +83,7 @@ class _ContentState extends State<_Content> {
bool validData = false; bool validData = false;
void validateDomain(String value) { void validateDomain(String value) {
final domainRegex = RegExp(r'^([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$'); if (Regexps.wildcardDomain.hasMatch(value)) {
if (domainRegex.hasMatch(value)) {
setState(() => domainError = null); setState(() => domainError = null);
} }
else { else {

View file

@ -1,11 +1,11 @@
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
String? validateDomain(BuildContext context, String domain) { String? validateDomain(BuildContext context, String domain) {
RegExp regExp = RegExp(r'^([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$'); if (Regexps.domain.hasMatch(domain)) {
if (regExp.hasMatch(domain)) {
return null; return null;
} }
else { else {
@ -23,8 +23,7 @@ String? validatePort(BuildContext context, String value) {
} }
String? validateCertificate(BuildContext context, String cert) { String? validateCertificate(BuildContext context, String cert) {
final regExp = RegExp(r'(-{3,}(\bBEGIN CERTIFICATE\b))|(-{3,}-{3,}(\END CERTIFICATE\b)-{3,})', multiLine: true); if (Regexps.certificate.hasMatch(cert.replaceAll('\n', ''))) {
if (regExp.hasMatch(cert.replaceAll('\n', ''))) {
return null; return null;
} }
else { else {
@ -33,8 +32,7 @@ String? validateCertificate(BuildContext context, String cert) {
} }
String? validatePrivateKey(BuildContext context, String cert) { String? validatePrivateKey(BuildContext context, String cert) {
final regExp = RegExp(r'(-{3,}(\bBEGIN\b).*(PRIVATE KEY\b))|(-{3,}-{3,}(\bEND\b).*(PRIVATE KEY\b)-{3,})', multiLine: true); if (Regexps.privateKey.hasMatch(cert.replaceAll('\n', ''))) {
if (regExp.hasMatch(cert.replaceAll('\n', ''))) {
return null; return null;
} }
else { else {
@ -43,8 +41,7 @@ String? validatePrivateKey(BuildContext context, String cert) {
} }
String? validatePath(BuildContext context, String cert) { String? validatePath(BuildContext context, String cert) {
final regExp = RegExp(r'^(\/{0,1}(?!\/))[A-Za-z0-9\/\-_]+(\.([a-zA-Z]+))?$'); if (Regexps.path.hasMatch(cert)) {
if (regExp.hasMatch(cert)) {
return null; return null;
} }
else { else {

View file

@ -1,9 +1,4 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:install_referrer/install_referrer.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -13,11 +8,8 @@ import 'package:adguard_home_manager/screens/settings/general_settings/top_items
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/widgets/section_label.dart'; import 'package:adguard_home_manager/widgets/section_label.dart';
import 'package:adguard_home_manager/functions/check_app_updates.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart'; import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/functions/app_update_download_link.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
class GeneralSettings extends StatefulWidget { class GeneralSettings extends StatefulWidget {
@ -48,6 +40,7 @@ class _GeneralSettingsState extends State<GeneralSettings> {
required Future Function(bool) function required Future Function(bool) function
}) async { }) async {
final result = await function(newStatus); final result = await function(newStatus);
if (!context.mounted) return;
if (result == true) { if (result == true) {
showSnackbar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
@ -64,60 +57,60 @@ class _GeneralSettingsState extends State<GeneralSettings> {
} }
} }
Future checkUpdatesAvailable() async { // Future checkUpdatesAvailable() async {
setState(() => appUpdatesStatus = AppUpdatesStatus.checking); // setState(() => appUpdatesStatus = AppUpdatesStatus.checking);
final res = await checkAppUpdates( // final res = await checkAppUpdates(
currentBuildNumber: appConfigProvider.getAppInfo!.buildNumber, // currentBuildNumber: appConfigProvider.getAppInfo!.buildNumber,
setUpdateAvailable: appConfigProvider.setAppUpdatesAvailable, // setUpdateAvailable: appConfigProvider.setAppUpdatesAvailable,
installationSource: appConfigProvider.installationSource, // installationSource: appConfigProvider.installationSource,
isBeta: appConfigProvider.getAppInfo!.version.contains('beta'), // isBeta: appConfigProvider.getAppInfo!.version.contains('beta'),
); // );
if (!mounted) return; // if (!mounted) return;
if (res != null) { // if (res != null) {
setState(() => appUpdatesStatus = AppUpdatesStatus.available); // setState(() => appUpdatesStatus = AppUpdatesStatus.available);
} // }
else { // else {
setState(() => appUpdatesStatus = AppUpdatesStatus.recheck); // setState(() => appUpdatesStatus = AppUpdatesStatus.recheck);
} // }
} // }
Widget generateAppUpdateStatus() { // Widget generateAppUpdateStatus() {
if (appUpdatesStatus == AppUpdatesStatus.available) { // if (appUpdatesStatus == AppUpdatesStatus.available) {
return IconButton( // return IconButton(
onPressed: appConfigProvider.appUpdatesAvailable != null // onPressed: appConfigProvider.appUpdatesAvailable != null
? () async { // ? () async {
final link = getAppUpdateDownloadLink(appConfigProvider.appUpdatesAvailable!); // final link = getAppUpdateDownloadLink(appConfigProvider.appUpdatesAvailable!);
if (link != null) { // if (link != null) {
openUrl(link); // openUrl(link);
} // }
} // }
: null, // : null,
icon: const Icon(Icons.download_rounded), // icon: const Icon(Icons.download_rounded),
tooltip: AppLocalizations.of(context)!.downloadUpdate, // tooltip: AppLocalizations.of(context)!.downloadUpdate,
); // );
} // }
else if (appUpdatesStatus == AppUpdatesStatus.checking) { // else if (appUpdatesStatus == AppUpdatesStatus.checking) {
return const Padding( // return const Padding(
padding: EdgeInsets.only(right: 16), // padding: EdgeInsets.only(right: 16),
child: SizedBox( // child: SizedBox(
width: 24, // width: 24,
height: 24, // height: 24,
child: CircularProgressIndicator( // child: CircularProgressIndicator(
strokeWidth: 3, // strokeWidth: 3,
) // )
), // ),
); // );
} // }
else { // else {
return IconButton( // return IconButton(
onPressed: checkUpdatesAvailable, // onPressed: checkUpdatesAvailable,
icon: const Icon(Icons.refresh_rounded), // icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.checkUpdates, // tooltip: AppLocalizations.of(context)!.checkUpdates,
); // );
} // }
} // }
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
@ -253,17 +246,17 @@ class _GeneralSettingsState extends State<GeneralSettings> {
right: 10 right: 10
) )
), ),
if (!(Platform.isAndroid || Platform.isIOS) || (Platform.isAndroid && (appConfigProvider.installationSource == InstallationAppReferrer.androidManually ))) ...[ // if (!(Platform.isAndroid || Platform.isIOS) || (Platform.isAndroid && (appConfigProvider.installationSource == InstallationAppReferrer.androidManually ))) ...[
SectionLabel(label: AppLocalizations.of(context)!.application), // SectionLabel(label: AppLocalizations.of(context)!.application),
CustomListTile( // CustomListTile(
icon: Icons.system_update_rounded, // icon: Icons.system_update_rounded,
title: AppLocalizations.of(context)!.appUpdates, // title: AppLocalizations.of(context)!.appUpdates,
subtitle: appConfigProvider.appUpdatesAvailable != null // subtitle: appConfigProvider.appUpdatesAvailable != null
? AppLocalizations.of(context)!.updateAvailable // ? AppLocalizations.of(context)!.updateAvailable
: AppLocalizations.of(context)!.usingLatestVersion, // : AppLocalizations.of(context)!.usingLatestVersion,
trailing: generateAppUpdateStatus() // trailing: generateAppUpdateStatus()
) // )
] // ]
], ],
), ),
) )

View file

@ -1,3 +1,4 @@
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -12,13 +13,16 @@ class LogsConfigOptions extends StatelessWidget {
final void Function(bool) updateGeneralSwitch; final void Function(bool) updateGeneralSwitch;
final bool anonymizeClientIp; final bool anonymizeClientIp;
final void Function(bool) updateAnonymizeClientIp; final void Function(bool) updateAnonymizeClientIp;
final List<int> retentionItems; final List<String> retentionItems;
final double? retentionTime; final String? retentionTime;
final void Function(double?) updateRetentionTime; final void Function(String?) updateRetentionTime;
final void Function() onClear; final void Function() onClear;
final void Function() onConfirm; final void Function() onConfirm;
final List<DomainListItemController> ignoredDomainsControllers; final List<DomainListItemController> ignoredDomainsControllers;
final void Function(List<DomainListItemController>) updateIgnoredDomainsControllers; final void Function(List<DomainListItemController>) updateIgnoredDomainsControllers;
final TextEditingController customTimeController;
final String? customTimeError;
final void Function(String) validateCustomTime;
const LogsConfigOptions({ const LogsConfigOptions({
super.key, super.key,
@ -32,7 +36,10 @@ class LogsConfigOptions extends StatelessWidget {
required this.onClear, required this.onClear,
required this.onConfirm, required this.onConfirm,
required this.ignoredDomainsControllers, required this.ignoredDomainsControllers,
required this.updateIgnoredDomainsControllers required this.updateIgnoredDomainsControllers,
required this.customTimeController,
required this.customTimeError,
required this.validateCustomTime,
}); });
@override @override
@ -40,6 +47,7 @@ class LogsConfigOptions extends StatelessWidget {
const Uuid uuid = Uuid(); const Uuid uuid = Uuid();
final List<String> dropdownItemTranslation = [ final List<String> dropdownItemTranslation = [
AppLocalizations.of(context)!.custom,
AppLocalizations.of(context)!.hours6, AppLocalizations.of(context)!.hours6,
AppLocalizations.of(context)!.hours24, AppLocalizations.of(context)!.hours24,
AppLocalizations.of(context)!.days7, AppLocalizations.of(context)!.days7,
@ -48,9 +56,8 @@ class LogsConfigOptions extends StatelessWidget {
]; ];
void validateDomain(String value, String id) { void validateDomain(String value, String id) {
final domainRegex = RegExp(r'^([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$');
bool error = false; bool error = false;
if (domainRegex.hasMatch(value)) { if (Regexps.domain.hasMatch(value)) {
error = false; error = false;
} }
else { else {
@ -67,7 +74,7 @@ class LogsConfigOptions extends StatelessWidget {
}).toList() }).toList()
); );
} }
print(retentionTime);
return ListView( return ListView(
children: [ children: [
const SizedBox(height: 16), const SizedBox(height: 16),
@ -92,7 +99,7 @@ class LogsConfigOptions extends StatelessWidget {
child: Text(dropdownItemTranslation[item.key]), child: Text(dropdownItemTranslation[item.key]),
)).toList(), )).toList(),
value: retentionTime, value: retentionTime,
onChanged: (value) => updateRetentionTime(double.tryParse(value.toString())), onChanged: (value) => updateRetentionTime(value.toString()),
decoration: InputDecoration( decoration: InputDecoration(
border: const OutlineInputBorder( border: const OutlineInputBorder(
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
@ -104,6 +111,24 @@ class LogsConfigOptions extends StatelessWidget {
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
), ),
if (retentionTime == "custom") Padding(
padding: const EdgeInsets.only(top: 24, left: 16, right: 16),
child: TextFormField(
controller: customTimeController,
onChanged: validateCustomTime,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.schedule_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
labelText: AppLocalizations.of(context)!.customTimeInHours,
errorText: customTimeError
),
keyboardType: TextInputType.number,
),
),
Padding( Padding(
padding: const EdgeInsets.only(top: 24, bottom: 8), padding: const EdgeInsets.only(top: 24, bottom: 8),
child: Row( child: Row(

View file

@ -37,15 +37,18 @@ class _LogsSettingsState extends State<LogsSettings> {
bool generalSwitch = false; bool generalSwitch = false;
bool anonymizeClientIp = false; bool anonymizeClientIp = false;
double? retentionTime; String? retentionTime;
List<DomainListItemController> _ignoredDomainsControllers = []; List<DomainListItemController> _ignoredDomainsControllers = [];
final _customTimeController = TextEditingController();
String? _customTimeError = null;
List<int> retentionItems = [ List<String> retentionItems = [
21600000, "custom",
86400000, "21600000",
604800000, "86400000",
2592000000, "604800000",
7776000000 "2592000000",
"7776000000"
]; ];
LoadStatus loadStatus = LoadStatus.loading; LoadStatus loadStatus = LoadStatus.loading;
@ -61,9 +64,10 @@ class _LogsSettingsState extends State<LogsSettings> {
setState(() { setState(() {
generalSwitch = data.enabled ?? false; generalSwitch = data.enabled ?? false;
anonymizeClientIp = data.anonymizeClientIp ?? false; anonymizeClientIp = data.anonymizeClientIp ?? false;
retentionTime = data.interval != null retentionTime = retentionItems.contains(data.interval.toString()) ? data.interval.toString() : "custom";
? double.parse(data.interval.toString()) if (data.interval != null && !retentionItems.contains(data.interval.toString())) {
: null; _customTimeController.text = (data.interval!/3.6e+6).toInt().toString();
}
if (data.ignored != null) { if (data.ignored != null) {
_ignoredDomainsControllers = data.ignored!.map((e) => DomainListItemController( _ignoredDomainsControllers = data.ignored!.map((e) => DomainListItemController(
id: uuid.v4(), id: uuid.v4(),
@ -79,6 +83,34 @@ class _LogsSettingsState extends State<LogsSettings> {
} }
} }
void validateCustomTime(String value) {
try {
final regex = RegExp(r'^\d+$');
final parsed = int.parse(value);
if (!regex.hasMatch(value)) {
setState(() => _customTimeError = AppLocalizations.of(context)!.invalidTime);
}
else if (parsed < 1) {
setState(() => _customTimeError = AppLocalizations.of(context)!.notLess1Hour);
}
else {
setState(() => _customTimeError = null);
}
} catch (_) {
setState(() => _customTimeError = AppLocalizations.of(context)!.invalidTime);
}
}
bool checkValidValues() {
if (_ignoredDomainsControllers.where((d) => d.controller.text == "" || d.error == true).isNotEmpty) {
return false;
}
if (retentionTime == "custom" && (_customTimeError != null || _customTimeController.text == "")) {
return false;
}
return true;
}
@override @override
void initState() { void initState() {
loadData(); loadData();
@ -90,9 +122,7 @@ class _LogsSettingsState extends State<LogsSettings> {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final validValues = _ignoredDomainsControllers.where( final validValues = checkValidValues();
(d) => d.controller.text == "" || d.error == true
).isEmpty;
void clearQueries() async { void clearQueries() async {
ProcessModal processModal = ProcessModal(); ProcessModal processModal = ProcessModal();
@ -127,7 +157,7 @@ class _LogsSettingsState extends State<LogsSettings> {
final result = await serversProvider.apiClient2!.updateQueryLogParameters( final result = await serversProvider.apiClient2!.updateQueryLogParameters(
data: { data: {
"enabled": generalSwitch, "enabled": generalSwitch,
"interval": retentionTime, "interval": retentionTime == "custom" ? int.parse(_customTimeController.text)*3.6e+6 : int.parse(retentionTime!) ,
"anonymize_client_ip": anonymizeClientIp, "anonymize_client_ip": anonymizeClientIp,
"ignored": _ignoredDomainsControllers.map((e) => e.controller.text).toList() "ignored": _ignoredDomainsControllers.map((e) => e.controller.text).toList()
} }
@ -198,6 +228,9 @@ class _LogsSettingsState extends State<LogsSettings> {
onConfirm: updateConfig, onConfirm: updateConfig,
ignoredDomainsControllers: _ignoredDomainsControllers, ignoredDomainsControllers: _ignoredDomainsControllers,
updateIgnoredDomainsControllers: (v) => setState(() => _ignoredDomainsControllers = v), updateIgnoredDomainsControllers: (v) => setState(() => _ignoredDomainsControllers = v),
customTimeController: _customTimeController,
customTimeError: _customTimeError,
validateCustomTime: validateCustomTime,
); );
case LoadStatus.error: case LoadStatus.error:

View file

@ -1,8 +1,6 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/server_info/server_info.dart'; import 'package:adguard_home_manager/screens/settings/server_info/server_info.dart';
@ -25,7 +23,6 @@ import 'package:adguard_home_manager/widgets/section_label.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart'; import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/constants/strings.dart';
import 'package:adguard_home_manager/functions/open_url.dart'; import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/constants/urls.dart'; import 'package:adguard_home_manager/constants/urls.dart';
import 'package:adguard_home_manager/providers/status_provider.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
@ -273,37 +270,18 @@ class _SettingsWidgetState extends State<_SettingsWidget> {
subtitle: appConfigProvider.getAppInfo!.version, subtitle: appConfigProvider.getAppInfo!.version,
), ),
CustomListTile( CustomListTile(
title: AppLocalizations.of(context)!.createdBy, title: AppLocalizations.of(context)!.applicationDetails,
subtitle: Strings.createdBy, subtitle: AppLocalizations.of(context)!.applicationDetailsDescription,
trailing: Icon(Icons.open_in_new_rounded),
onTap: () => openUrl(Urls.appDetailsWebpage),
), ),
Padding( CustomListTile(
padding: const EdgeInsets.all(15), title: AppLocalizations.of(context)!.myOtherApps,
child: Row( subtitle: AppLocalizations.of(context)!.myOtherAppsDescription,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, trailing: Icon(Icons.open_in_new_rounded),
children: [ onTap: () => openUrl(Urls.jgeek00AppsWebpage),
if (Platform.isAndroid) IconButton(
onPressed: () => openUrl(Urls.playStore),
icon: SvgPicture.asset(
'assets/resources/google-play.svg',
color: Theme.of(context).colorScheme.onSurfaceVariant,
width: 30,
height: 30,
), ),
tooltip: AppLocalizations.of(context)!.visitGooglePlay, SizedBox(height: 16)
),
IconButton(
onPressed: () => openUrl(Urls.gitHub),
icon: SvgPicture.asset(
'assets/resources/github.svg',
color: Theme.of(context).colorScheme.onSurfaceVariant,
width: 30,
height: 30,
),
tooltip: AppLocalizations.of(context)!.gitHub,
),
],
),
)
], ],
) )
], ],

View file

@ -1,3 +1,4 @@
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -91,9 +92,8 @@ class _StatisticsSettingsState extends State<StatisticsSettings> {
void validateDomain(String value, String id) { void validateDomain(String value, String id) {
final domainRegex = RegExp(r'^([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$');
bool error = false; bool error = false;
if (domainRegex.hasMatch(value)) { if (Regexps.domain.hasMatch(value)) {
error = false; error = false;
} }
else { else {
@ -138,7 +138,7 @@ class _StatisticsSettingsState extends State<StatisticsSettings> {
"enabled": _generalSwitch, "enabled": _generalSwitch,
"interval": _retentionTime == "custom" "interval": _retentionTime == "custom"
? Duration(hours: int.parse(_customTimeController.text)).inMilliseconds ? Duration(hours: int.parse(_customTimeController.text)).inMilliseconds
: int.parse(_retentionTime!), : int.parse(_retentionTime ?? _retentionItems[0]),
"ignored": _ignoredDomainsControllers.map((e) => e.controller.text).toList() "ignored": _ignoredDomainsControllers.map((e) => e.controller.text).toList()
} }
); );

View file

@ -218,9 +218,16 @@ class _Header extends SliverPersistentHeaderDelegate {
final iconBottom = _iconMinBottomPositionExent + (iconMaxBottomPositionExent-iconMinBottomPositionExent)*(1-iconPercentage); final iconBottom = _iconMinBottomPositionExent + (iconMaxBottomPositionExent-iconMinBottomPositionExent)*(1-iconPercentage);
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) => Container( builder: (context, constraints) => Stack(
children: [
Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest, color: Theme.of(context).colorScheme.surface,
),
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceTint.withOpacity(0.075),
), ),
child: Align( child: Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
@ -314,6 +321,8 @@ class _Header extends SliverPersistentHeaderDelegate {
), ),
), ),
), ),
],
),
); );
} }

View file

@ -1,3 +1,4 @@
import 'package:adguard_home_manager/constants/regexps.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -49,8 +50,7 @@ String? validateSubroute({
required String? value required String? value
}) { }) {
if (value != null && value != '') { if (value != null && value != '') {
RegExp subrouteRegexp = RegExp(r'^\/\b([A-Za-z0-9_\-~/]*)[^\/|\.|\:]$'); if (Regexps.subroute.hasMatch(value) == true) {
if (subrouteRegexp.hasMatch(value) == true) {
return null; return null;
} }
else { else {
@ -67,9 +67,7 @@ String? validateAddress({
required String? value required String? value
}) { }) {
if (value != null && value != '') { if (value != null && value != '') {
RegExp ipAddress = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$'); if (Regexps.ipv4Address.hasMatch(value) == true || Regexps.domain.hasMatch(value) == true) {
RegExp domain = RegExp(r'^(([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+)$');
if (ipAddress.hasMatch(value) == true || domain.hasMatch(value) == true) {
return null; return null;
} }
else { else {

View file

@ -142,6 +142,7 @@ class _AddServerModalState extends State<AddServerModal> {
port: portController.text != '' ? int.parse(portController.text) : null, port: portController.text != '' ? int.parse(portController.text) : null,
user: userController.text != "" ? userController.text : null, user: userController.text != "" ? userController.text : null,
password: passwordController.text != "" ? passwordController.text : null, password: passwordController.text != "" ? passwordController.text : null,
path: pathController.text != "" ? pathController.text : null,
defaultServer: defaultServer, defaultServer: defaultServer,
authToken: homeAssistant == true authToken: homeAssistant == true
? encodeBase64UserPass(userController.text, passwordController.text) ? encodeBase64UserPass(userController.text, passwordController.text)
@ -174,6 +175,8 @@ class _AddServerModalState extends State<AddServerModal> {
final ApiClientV2 apiClient2 = ApiClientV2(server: serverObj); final ApiClientV2 apiClient2 = ApiClientV2(server: serverObj);
final serverStatus = await apiClient2.getServerStatus(); final serverStatus = await apiClient2.getServerStatus();
if (!context.mounted) return;
// If something goes wrong when fetching server status // If something goes wrong when fetching server status
if (serverStatus.successful == false) { if (serverStatus.successful == false) {
statusProvider.setServerStatusLoad(LoadStatus.error); statusProvider.setServerStatusLoad(LoadStatus.error);
@ -202,16 +205,16 @@ class _AddServerModalState extends State<AddServerModal> {
final serverCreated = await serversProvider.createServer(serverObj); final serverCreated = await serversProvider.createServer(serverObj);
if (!context.mounted) return;
// If something goes wrong when saving the connection on the db // If something goes wrong when saving the connection on the db
if (serverCreated != null) { if (serverCreated != null) {
if (mounted) setState(() => isConnecting = false); setState(() => isConnecting = false);
if (mounted) {
showSnackbar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionNotCreated, label: AppLocalizations.of(context)!.connectionNotCreated,
color: Colors.red color: Colors.red
); );
}
return; return;
} }
@ -295,9 +298,11 @@ class _AddServerModalState extends State<AddServerModal> {
final serverSaved = await serversProvider.editServer(serverObj); final serverSaved = await serversProvider.editServer(serverObj);
if (!mounted) return;
// If something goes wrong when saving the connection on the db // If something goes wrong when saving the connection on the db
if (serverSaved != null) { if (serverSaved != null) {
if (mounted) setState(() => isConnecting = false); setState(() => isConnecting = false);
appConfigProvider.addLog( appConfigProvider.addLog(
AppLog( AppLog(
type: 'save_connection_db', type: 'save_connection_db',
@ -305,13 +310,11 @@ class _AddServerModalState extends State<AddServerModal> {
message: serverSaved.toString() message: serverSaved.toString()
) )
); );
if (mounted) {
showSnackbar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionNotCreated, label: AppLocalizations.of(context)!.connectionNotCreated,
color: Colors.red color: Colors.red
); );
}
return; return;
} }

View file

@ -1,14 +1,10 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/update_modal.dart';
import 'package:adguard_home_manager/widgets/system_ui_overlay_style.dart'; import 'package:adguard_home_manager/widgets/system_ui_overlay_style.dart';
import 'package:adguard_home_manager/functions/check_app_updates.dart';
import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/config/app_screens.dart'; import 'package:adguard_home_manager/config/app_screens.dart';
import 'package:adguard_home_manager/config/sizes.dart'; import 'package:adguard_home_manager/config/sizes.dart';
@ -37,23 +33,23 @@ class _LayoutState extends State<Layout> with WidgetsBindingObserver {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
if (kDebugMode) return; // Don't check for app updates on debug mode // if (kDebugMode) return; // Don't check for app updates on debug mode
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false); // final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
final result = await checkAppUpdates( // final result = await checkAppUpdates(
currentBuildNumber: appConfigProvider.getAppInfo!.buildNumber, // currentBuildNumber: appConfigProvider.getAppInfo!.buildNumber,
installationSource: appConfigProvider.installationSource, // installationSource: appConfigProvider.installationSource,
setUpdateAvailable: appConfigProvider.setAppUpdatesAvailable, // setUpdateAvailable: appConfigProvider.setAppUpdatesAvailable,
isBeta: appConfigProvider.getAppInfo!.version.contains('beta'), // isBeta: appConfigProvider.getAppInfo!.version.contains('beta'),
); // );
if (result != null && appConfigProvider.doNotRememberVersion != result.tagName && mounted) { // if (result != null && appConfigProvider.doNotRememberVersion != result.tagName && mounted) {
await showDialog( // await showDialog(
context: context, // context: context,
builder: (context) => UpdateModal( // builder: (context) => UpdateModal(
gitHubRelease: result, // gitHubRelease: result,
onDownload: (link, version) => openUrl(link), // onDownload: (link, version) => openUrl(link),
), // ),
); // );
} // }
}); });
} }

View file

@ -7,7 +7,7 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <dynamic_color/dynamic_color_plugin.h> #include <dynamic_color/dynamic_color_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h> #include <screen_retriever_linux/screen_retriever_linux_plugin.h>
#include <sentry_flutter/sentry_flutter_plugin.h> #include <sentry_flutter/sentry_flutter_plugin.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h> #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
@ -17,9 +17,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) dynamic_color_registrar = g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin");
dynamic_color_plugin_register_with_registrar(dynamic_color_registrar); dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);
g_autoptr(FlPluginRegistrar) screen_retriever_registrar = g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);
g_autoptr(FlPluginRegistrar) sentry_flutter_registrar = g_autoptr(FlPluginRegistrar) sentry_flutter_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin");
sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar); sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar);

View file

@ -4,7 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
dynamic_color dynamic_color
screen_retriever screen_retriever_linux
sentry_flutter sentry_flutter
sqlite3_flutter_libs sqlite3_flutter_libs
url_launcher_linux url_launcher_linux

View file

@ -8,10 +8,10 @@ import Foundation
import device_info_plus import device_info_plus
import dynamic_color import dynamic_color
import package_info_plus import package_info_plus
import screen_retriever import screen_retriever_macos
import sentry_flutter import sentry_flutter
import shared_preferences_foundation import shared_preferences_foundation
import sqflite import sqflite_darwin
import sqlite3_flutter_libs import sqlite3_flutter_libs
import url_launcher_macos import url_launcher_macos
import window_manager import window_manager
@ -20,7 +20,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin")) SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))

View file

@ -6,39 +6,38 @@ PODS:
- FlutterMacOS (1.0.0) - FlutterMacOS (1.0.0)
- package_info_plus (0.0.1): - package_info_plus (0.0.1):
- FlutterMacOS - FlutterMacOS
- screen_retriever (0.0.1): - screen_retriever_macos (0.0.1):
- FlutterMacOS - FlutterMacOS
- Sentry/HybridSDK (8.35.1) - Sentry/HybridSDK (8.44.0)
- sentry_flutter (8.8.0): - sentry_flutter (8.13.2):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- Sentry/HybridSDK (= 8.35.1) - Sentry/HybridSDK (= 8.44.0)
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- sqflite (0.0.3): - sqflite_darwin (0.0.4):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- "sqlite3 (3.46.1+1)": - sqlite3 (3.49.1):
- "sqlite3/common (= 3.46.1+1)" - sqlite3/common (= 3.49.1)
- "sqlite3/common (3.46.1+1)" - sqlite3/common (3.49.1)
- "sqlite3/dbstatvtab (3.46.1+1)": - sqlite3/dbstatvtab (3.49.1):
- sqlite3/common - sqlite3/common
- "sqlite3/fts5 (3.46.1+1)": - sqlite3/fts5 (3.49.1):
- sqlite3/common - sqlite3/common
- "sqlite3/perf-threadsafe (3.46.1+1)": - sqlite3/perf-threadsafe (3.49.1):
- sqlite3/common - sqlite3/common
- "sqlite3/rtree (3.46.1+1)": - sqlite3/rtree (3.49.1):
- sqlite3/common - sqlite3/common
- sqlite3_flutter_libs (0.0.1): - sqlite3_flutter_libs (0.0.1):
- Flutter
- FlutterMacOS - FlutterMacOS
- "sqlite3 (~> 3.46.0+1)" - sqlite3 (~> 3.49.1)
- sqlite3/dbstatvtab - sqlite3/dbstatvtab
- sqlite3/fts5 - sqlite3/fts5
- sqlite3/perf-threadsafe - sqlite3/perf-threadsafe
- sqlite3/rtree - sqlite3/rtree
- store_checker (0.0.1):
- FlutterMacOS
- url_launcher_macos (0.0.1): - url_launcher_macos (0.0.1):
- FlutterMacOS - FlutterMacOS
- window_manager (0.2.0): - window_manager (0.2.0):
@ -49,12 +48,11 @@ DEPENDENCIES:
- dynamic_color (from `Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos`) - dynamic_color (from `Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos`)
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
- sentry_flutter (from `Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos`) - sentry_flutter (from `Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`) - sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`) - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`)
- store_checker (from `Flutter/ephemeral/.symlinks/plugins/store_checker/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
@ -72,37 +70,34 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral :path: Flutter/ephemeral
package_info_plus: package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
screen_retriever: screen_retriever_macos:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
sentry_flutter: sentry_flutter:
:path: Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos :path: Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos
shared_preferences_foundation: shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
sqflite: sqflite_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/darwin :path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin
sqlite3_flutter_libs: sqlite3_flutter_libs:
:path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin
store_checker:
:path: Flutter/ephemeral/.symlinks/plugins/store_checker/macos
url_launcher_macos: url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
window_manager: window_manager:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
SPEC CHECKSUMS: SPEC CHECKSUMS:
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720 device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215
dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1 Sentry: 0f9bc9adfc0b960e7f3bb5ec67e9a3d8193f3bdb
sentry_flutter: a39c2a2d67d5e5b9cb0b94a4985c76dd5b3fc737 sentry_flutter: 64a43fb39ab4c7f67d8a4cad52b49e22439e58b7
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983
sqlite3_flutter_libs: 5ca46c1a04eddfbeeb5b16566164aa7ad1616e7b sqlite3_flutter_libs: cc304edcb8e1d8c595d1b08c7aeb46a47691d9db
store_checker: 387169de0dffe57b6370d54cc027e9f95051b57f url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7

View file

@ -48,6 +48,7 @@
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">

View file

@ -6,4 +6,8 @@ class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true return true
} }
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
} }

View file

@ -29,42 +29,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: archive name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d sha256: "7dcbd0f87fe5f61cb28da39a1a8b70dbc106e2fe0516f7836eb7bb2948481a12"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.6.1" version: "4.0.5"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.7.0"
async: async:
dependency: "direct main" dependency: "direct main"
description: description:
name: async name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.11.0" version: "2.12.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.4.0"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
@ -77,26 +77,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cli_util name: cli_util
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.1" version: "0.4.2"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.2"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.18.0" version: "1.19.1"
contextmenu: contextmenu:
dependency: "direct main" dependency: "direct main"
description: description:
@ -109,18 +109,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.5" version: "3.0.6"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
name: csslib name: csslib
sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f" sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.17.3" version: "1.0.2"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -133,18 +133,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: device_info_plus name: device_info_plus
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 sha256: "306b78788d1bb569edb7c55d622953c2414ca12445b41c9117963e03afc5c513"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.1.2" version: "11.3.3"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_platform_interface name: device_info_plus_platform_interface
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.1" version: "7.0.2"
dynamic_color: dynamic_color:
dependency: "direct main" dependency: "direct main"
description: description:
@ -157,10 +157,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: equatable name: equatable
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.5" version: "2.0.7"
expandable: expandable:
dependency: "direct main" dependency: "direct main"
description: description:
@ -173,42 +173,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.3.2"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.3" version: "2.1.4"
file: file:
dependency: transitive dependency: transitive
description: description:
name: file name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.0.1"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
name: fixnum name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
fl_chart: fl_chart:
dependency: "direct main" dependency: "direct main"
description: description:
name: fl_chart name: fl_chart
sha256: "94307bef3a324a0d329d3ab77b2f0c6e5ed739185ffc029ed28c0f9b019ea7ef" sha256: "5276944c6ffc975ae796569a826c38a62d2abcf264e26b88fa6f482e107f4237"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.69.0" version: "0.70.2"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -254,46 +254,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
flutter_displaymode:
dependency: "direct main"
description:
name: flutter_displaymode
sha256: "42c5e9abd13d28ed74f701b60529d7f8416947e58256e6659c5550db719c57ef"
url: "https://pub.dev"
source: hosted
version: "0.6.0"
flutter_dotenv: flutter_dotenv:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_dotenv name: flutter_dotenv
sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77" sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.0" version: "5.2.1"
flutter_html: flutter_html:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_html name: flutter_html
sha256: "02ad69e813ecfc0728a455e4bf892b9379983e050722b1dce00192ee2e41d1ee" sha256: "38a2fd702ffdf3243fb7441ab58aa1bc7e6922d95a50db76534de8260638558d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0-beta.2" version: "3.0.0"
flutter_launcher_icons: flutter_launcher_icons:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_launcher_icons name: flutter_launcher_icons
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.1" version: "0.14.3"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "5.0.0"
flutter_localizations: flutter_localizations:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -303,18 +295,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_markdown name: flutter_markdown
sha256: a23c41ee57573e62fc2190a1f36a0480c4d90bde3a8a8d7126e5d5992fb53fb7 sha256: e7bbc718adc9476aa14cfddc1ef048d2e21e4e8f18311aaac723266db9f9e7b5
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.3+1" version: "0.7.6+2"
flutter_native_splash: flutter_native_splash:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_native_splash name: flutter_native_splash
sha256: aa06fec78de2190f3db4319dd60fdc8d12b2626e93ef9828633928c2dcaea840 sha256: edb09c35ee9230c4b03f13dd45bb3a276d0801865f0a4650b7e2a3bba61a803a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.5"
flutter_reorderable_list: flutter_reorderable_list:
dependency: "direct main" dependency: "direct main"
description: description:
@ -327,10 +319,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_svg name: flutter_svg
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.10+1" version: "2.0.17"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -345,42 +337,34 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: html name: html
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.15.4" version: "0.15.5"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.2" version: "1.3.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
name: http_parser name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.1.2"
image: image:
dependency: transitive dependency: transitive
description: description:
name: image name: image
sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.0" version: "4.5.4"
install_referrer:
dependency: "direct main"
description:
name: install_referrer
sha256: "901c56d24ee3c3010dfd0bbebf305ed6b4b0f3fe969192081c167590a64cd78b"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@ -401,18 +385,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.5" version: "10.0.8"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.5" version: "3.0.9"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
@ -425,10 +409,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "5.1.1"
list_counter: list_counter:
dependency: transitive dependency: transitive
description: description:
@ -441,18 +425,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: markdown name: markdown
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.2.2" version: "7.3.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.16+1" version: "0.12.17"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
@ -465,10 +449,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.15.0" version: "1.16.0"
nested: nested:
dependency: transitive dependency: transitive
description: description:
@ -481,34 +465,34 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918 sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.0.2" version: "8.3.0"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_platform_interface name: package_info_plus_platform_interface
sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "3.2.0"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.0" version: "1.9.1"
path_parsing: path_parsing:
dependency: transitive dependency: transitive
description: description:
name: path_parsing name: path_parsing
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.1.0"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@ -537,18 +521,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: percent_indicator name: percent_indicator
sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c sha256: "0d77d5c6fa9b7f60202cedf748b568ba9ba38d3f30405d6ceae4da76f5185462"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.3" version: "4.2.4"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
name: petitparser name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.2" version: "6.1.0"
pie_chart: pie_chart:
dependency: "direct main" dependency: "direct main"
description: description:
@ -561,10 +545,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.5" version: "3.1.6"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -573,6 +557,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
posix:
dependency: transitive
description:
name: posix
sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
url: "https://pub.dev"
source: hosted
version: "6.0.1"
provider: provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -585,10 +577,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: screen_retriever name: screen_retriever
sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90" sha256: "570dbc8e4f70bac451e0efc9c9bb19fa2d6799a11e6ef04f946d7886d2e23d0c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.9" version: "0.2.0"
screen_retriever_linux:
dependency: transitive
description:
name: screen_retriever_linux
sha256: f7f8120c92ef0784e58491ab664d01efda79a922b025ff286e29aa123ea3dd18
url: "https://pub.dev"
source: hosted
version: "0.2.0"
screen_retriever_macos:
dependency: transitive
description:
name: screen_retriever_macos
sha256: "71f956e65c97315dd661d71f828708bd97b6d358e776f1a30d5aa7d22d78a149"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
screen_retriever_platform_interface:
dependency: transitive
description:
name: screen_retriever_platform_interface
sha256: ee197f4581ff0d5608587819af40490748e1e39e648d7680ecf95c05197240c0
url: "https://pub.dev"
source: hosted
version: "0.2.0"
screen_retriever_windows:
dependency: transitive
description:
name: screen_retriever_windows
sha256: "449ee257f03ca98a57288ee526a301a430a344a161f9202b4fcc38576716fe13"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
segmented_button_slide: segmented_button_slide:
dependency: "direct main" dependency: "direct main"
description: description:
@ -601,42 +625,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: sentry name: sentry
sha256: "1af8308298977259430d118ab25be8e1dda626cdefa1e6ce869073d530d39271" sha256: "3a64dd001bff768ce5ab6fc3608deef4dde22acd4b5d947763557b20db9e2a32"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.8.0" version: "8.14.0"
sentry_flutter: sentry_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
name: sentry_flutter name: sentry_flutter
sha256: "18fe4d125c2d529bd6127200f0d2895768266a8c60b4fb50b2086fd97e1a4ab2" sha256: "3d361f2d5f805783e2e4ed1bd475ef126b36cf525b359dc3627a765a3fb7424d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.8.0" version: "8.14.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences name: shared_preferences
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.5.2"
shared_preferences_android: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" sha256: "3ec7210872c4ba945e3244982918e502fa2bfb5230dff6832459ca0e1879b7ad"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.8"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.2" version: "2.5.4"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
@ -657,10 +681,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.4.3"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
@ -673,15 +697,15 @@ packages:
dependency: transitive dependency: transitive
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.0"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.10.1"
sprintf: sprintf:
dependency: transitive dependency: transitive
description: description:
@ -694,106 +718,130 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: sqflite name: sqflite
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.3+1" version: "2.4.2"
sqflite_android:
dependency: transitive
description:
name: sqflite_android
sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
sqflite_common: sqflite_common:
dependency: transitive dependency: transitive
description: description:
name: sqflite_common name: sqflite_common
sha256: "7b41b6c3507854a159e24ae90a8e3e9cc01eb26a477c118d6dca065b5f55453e" sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.4+2" version: "2.5.5"
sqflite_common_ffi: sqflite_common_ffi:
dependency: "direct main" dependency: "direct main"
description: description:
name: sqflite_common_ffi name: sqflite_common_ffi
sha256: "4d6137c29e930d6e4a8ff373989dd9de7bac12e3bc87bce950f6e844e8ad3bb5" sha256: "1f3ef3888d3bfbb47785cc1dda0dc7dd7ebd8c1955d32a9e8e9dae1e38d1c4c1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.3" version: "2.3.5"
sqflite_darwin:
dependency: transitive
description:
name: sqflite_darwin
sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
url: "https://pub.dev"
source: hosted
version: "2.4.2"
sqflite_platform_interface:
dependency: transitive
description:
name: sqflite_platform_interface
sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
sqlite3: sqlite3:
dependency: transitive dependency: transitive
description: description:
name: sqlite3 name: sqlite3
sha256: "45f168ae2213201b54e09429ed0c593dc2c88c924a1488d6f9c523a255d567cb" sha256: "310af39c40dd0bb2058538333c9d9840a2725ae0b9f77e4fd09ad6696aa8f66e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.6" version: "2.7.5"
sqlite3_flutter_libs: sqlite3_flutter_libs:
dependency: "direct main" dependency: "direct main"
description: description:
name: sqlite3_flutter_libs name: sqlite3_flutter_libs
sha256: "62bbb4073edbcdf53f40c80775f33eea01d301b7b81417e5b3fb7395416258c1" sha256: "1a96b59227828d9eb1463191d684b37a27d66ee5ed7597fcf42eee6452c88a14"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.24" version: "0.5.32"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.1" version: "1.12.1"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.4"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.4.1"
synchronized: synchronized:
dependency: transitive dependency: transitive
description: description:
name: synchronized name: synchronized
sha256: a824e842b8a054f91a728b783c177c1e4731f6b124f9192468457a8913371255 sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "3.3.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.2.2"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.2" version: "0.7.4"
timezone: timezone:
dependency: "direct main" dependency: "direct main"
description: description:
name: timezone name: timezone
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" sha256: ffc9d5f4d1193534ef051f9254063fa53d588609418c84299956c3db9383587d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.4" version: "0.10.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.4.0"
universal_io: universal_io:
dependency: transitive dependency: transitive
description: description:
@ -806,42 +854,42 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.0" version: "6.3.1"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab sha256: "1d0eae19bd7606ef60fe69ef3b312a437a16549476c42321d5dc1506c9ca3bf4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.10" version: "6.3.15"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.1" version: "6.3.2"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_linux name: url_launcher_linux
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "3.2.1"
url_launcher_macos: url_launcher_macos:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_macos name: url_launcher_macos
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "3.2.2"
url_launcher_platform_interface: url_launcher_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -854,50 +902,50 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.3" version: "2.4.0"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_windows name: url_launcher_windows
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "3.1.4"
uuid: uuid:
dependency: "direct main" dependency: "direct main"
description: description:
name: uuid name: uuid
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77 sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.5.0" version: "4.5.1"
vector_graphics: vector_graphics:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics name: vector_graphics
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.11+1" version: "1.1.18"
vector_graphics_codec: vector_graphics_codec:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics_codec name: vector_graphics_codec
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.11+1" version: "1.1.13"
vector_graphics_compiler: vector_graphics_compiler:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics_compiler name: vector_graphics_compiler
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.11+1" version: "1.1.16"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -910,50 +958,50 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.5" version: "14.3.1"
web: web:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.1.1"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.5.4" version: "5.12.0"
win32_registry: win32_registry:
dependency: transitive dependency: transitive
description: description:
name: win32_registry name: win32_registry
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6" sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.4" version: "2.1.0"
window_manager: window_manager:
dependency: "direct main" dependency: "direct main"
description: description:
name: window_manager name: window_manager
sha256: ab8b2a7f97543d3db2b506c9d875e637149d48ee0c6a5cb5f5fd6e0dac463792 sha256: "732896e1416297c63c9e3fb95aea72d0355f61390263982a47fd519169dc5059"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.2" version: "0.4.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.1.0"
xml: xml:
dependency: transitive dependency: transitive
description: description:
@ -966,10 +1014,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: yaml name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "3.1.3"
sdks: sdks:
dart: ">=3.5.0 <4.0.0" dart: ">=3.7.0 <4.0.0"
flutter: ">=3.24.0" flutter: ">=3.27.0"

View file

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 2.19.0+143 version: 2.20.4+151
environment: environment:
sdk: '>=2.18.1 <3.0.0' sdk: '>=2.18.1 <3.0.0'
@ -42,13 +42,12 @@ dependencies:
provider: ^6.1.1 provider: ^6.1.1
sqflite: ^2.3.0 sqflite: ^2.3.0
package_info_plus: ^8.0.0 package_info_plus: ^8.0.0
flutter_displaymode: ^0.6.0
dynamic_color: ^1.7.0 dynamic_color: ^1.7.0
animations: ^2.0.10 animations: ^2.0.10
device_info_plus: ^10.1.0 device_info_plus: ^11.2.1
uuid: ^4.2.1 uuid: ^4.2.1
expandable: ^5.0.1 expandable: ^5.0.1
fl_chart: ^0.69.0 fl_chart: ^0.70.2
flutter_svg: ^2.0.9 flutter_svg: ^2.0.9
percent_indicator: ^4.2.3 percent_indicator: ^4.2.3
flutter_markdown: ^0.7.1 flutter_markdown: ^0.7.1
@ -65,12 +64,11 @@ dependencies:
pie_chart: ^5.4.0 pie_chart: ^5.4.0
segmented_button_slide: ^2.0.0 segmented_button_slide: ^2.0.0
http: ^1.1.2 http: ^1.1.2
timezone: ^0.9.2 timezone: ^0.10.0
flutter_custom_tabs: ^2.0.0+1 flutter_custom_tabs: ^2.0.0+1
url_launcher: ^6.2.4 url_launcher: ^6.2.4
shared_preferences: ^2.2.2 shared_preferences: ^2.2.2
window_manager: ^0.4.2 window_manager: ^0.4.2
install_referrer: ^1.2.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -81,8 +79,8 @@ dev_dependencies:
# activated in the `analysis_options.yaml` file located at the root of your # activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint # package. See that file for information about deactivating specific lint
# rules and activating additional ones. # rules and activating additional ones.
flutter_lints: ^4.0.0 flutter_lints: ^5.0.0
flutter_launcher_icons: ^0.13.1 flutter_launcher_icons: ^0.14.1
flutter_native_splash: ^2.3.8 flutter_native_splash: ^2.3.8
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the

View file

@ -7,7 +7,7 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <dynamic_color/dynamic_color_plugin_c_api.h> #include <dynamic_color/dynamic_color_plugin_c_api.h>
#include <screen_retriever/screen_retriever_plugin.h> #include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
#include <sentry_flutter/sentry_flutter_plugin.h> #include <sentry_flutter/sentry_flutter_plugin.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h> #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
@ -16,8 +16,8 @@
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
DynamicColorPluginCApiRegisterWithRegistrar( DynamicColorPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
ScreenRetrieverPluginRegisterWithRegistrar( ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi"));
SentryFlutterPluginRegisterWithRegistrar( SentryFlutterPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SentryFlutterPlugin")); registry->GetRegistrarForPlugin("SentryFlutterPlugin"));
Sqlite3FlutterLibsPluginRegisterWithRegistrar( Sqlite3FlutterLibsPluginRegisterWithRegistrar(

View file

@ -4,7 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
dynamic_color dynamic_color
screen_retriever screen_retriever_windows
sentry_flutter sentry_flutter
sqlite3_flutter_libs sqlite3_flutter_libs
url_launcher_windows url_launcher_windows

View file

@ -41,7 +41,6 @@ Source: "..\build\windows\x64\runner\Release\{#MyAppExeName}"; DestDir: "{app}";
Source: "..\build\windows\x64\runner\Release\dynamic_color_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "..\build\windows\x64\runner\Release\dynamic_color_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\x64\runner\Release\flutter_windows.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "..\build\windows\x64\runner\Release\flutter_windows.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\x64\runner\Release\screen_retriever_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "..\build\windows\x64\runner\Release\screen_retriever_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\x64\runner\Release\sentry_flutter_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\x64\runner\Release\sqlite3.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "..\build\windows\x64\runner\Release\sqlite3.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\x64\runner\Release\sqlite3_flutter_libs_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "..\build\windows\x64\runner\Release\sqlite3_flutter_libs_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\x64\runner\Release\url_launcher_windows_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "..\build\windows\x64\runner\Release\url_launcher_windows_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion