Merge branch 'develop'
This commit is contained in:
commit
ce3afd87a0
92 changed files with 1327 additions and 1058 deletions
2
.flutter
2
.flutter
|
@ -1 +1 @@
|
||||||
Subproject commit 5874a72aa4c779a02553007c47dacbefba2374dc
|
Subproject commit 2663184aa79047d0a33a14a3b607954f8fdd8730
|
36
.github/workflows/check.yml
vendored
36
.github/workflows/check.yml
vendored
|
@ -1,36 +0,0 @@
|
||||||
name: Quality check
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- develop
|
|
||||||
pull_request:
|
|
||||||
types: [ opened, synchronize, reopened ]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Check code quality.
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Clone the repository.
|
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
|
||||||
|
|
||||||
- name: Get packages for the Flutter project.
|
|
||||||
run: scripts/pub_get_all.sh
|
|
||||||
|
|
||||||
- name: Update the flutter version file.
|
|
||||||
run: scripts/update_flutter_version.sh
|
|
||||||
|
|
||||||
- name: Static analysis.
|
|
||||||
run: ./flutterw analyze
|
|
||||||
|
|
||||||
- name: Unit tests.
|
|
||||||
run: ./flutterw test
|
|
2
.github/workflows/dependency-review.yml
vendored
2
.github/workflows/dependency-review.yml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|
88
.github/workflows/quality-check.yml
vendored
Normal file
88
.github/workflows/quality-check.yml
vendored
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
name: Quality check
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "develop", "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "develop", "main" ]
|
||||||
|
types: [ opened, synchronize, reopened ]
|
||||||
|
schedule:
|
||||||
|
- cron: '17 8 * * 3'
|
||||||
|
|
||||||
|
# Declare default permissions as read only.
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze_flutter:
|
||||||
|
name: Flutter analysis
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
|
- name: Get Flutter packages
|
||||||
|
run: scripts/pub_get_all.sh
|
||||||
|
|
||||||
|
- name: Static analysis.
|
||||||
|
run: ./flutterw analyze
|
||||||
|
|
||||||
|
- name: Unit tests.
|
||||||
|
run: ./flutterw test
|
||||||
|
|
||||||
|
analyze_codeql:
|
||||||
|
name: CodeQL analysis (${{ matrix.language }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
# required for all workflows
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
# required to fetch internal or private CodeQL packs
|
||||||
|
packages: read
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- language: java-kotlin
|
||||||
|
build-mode: manual
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
# Building relies on the Android Gradle plugin,
|
||||||
|
# which requires a modern Java version (not the default one).
|
||||||
|
- name: Set up JDK for Android Gradle plugin
|
||||||
|
uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '21'
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
build-mode: ${{ matrix.build-mode }}
|
||||||
|
|
||||||
|
- if: matrix.build-mode == 'manual'
|
||||||
|
shell: bash
|
||||||
|
# build in profile mode, instead of release,
|
||||||
|
# so that setting up signing environment variables is not required
|
||||||
|
run: |
|
||||||
|
scripts/apply_flavor_play.sh
|
||||||
|
./flutterw build apk --profile -t lib/main_play.dart --flavor play
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7
|
||||||
|
with:
|
||||||
|
category: "/language:${{matrix.language}}"
|
51
.github/workflows/release.yml
vendored
51
.github/workflows/release.yml
vendored
|
@ -5,37 +5,39 @@ on:
|
||||||
tags:
|
tags:
|
||||||
- v*
|
- v*
|
||||||
|
|
||||||
|
# Declare default permissions as read only.
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
release_github:
|
||||||
name: Build and release artifacts.
|
name: GitHub release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2
|
# Building relies on the Android Gradle plugin,
|
||||||
|
# which requires a modern Java version (not the default one).
|
||||||
|
- name: Set up JDK for Android Gradle plugin
|
||||||
|
uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'temurin'
|
||||||
java-version: '17'
|
java-version: '21'
|
||||||
|
|
||||||
- name: Clone the repository.
|
- name: Checkout repository
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Get packages for the Flutter project.
|
- name: Get Flutter packages
|
||||||
run: scripts/pub_get_all.sh
|
run: scripts/pub_get_all.sh
|
||||||
|
|
||||||
- name: Update the flutter version file.
|
- name: Update Flutter version file
|
||||||
run: scripts/update_flutter_version.sh
|
run: scripts/update_flutter_version.sh
|
||||||
|
|
||||||
- name: Static analysis.
|
- name: Build signed artifacts
|
||||||
run: ./flutterw analyze
|
|
||||||
|
|
||||||
- name: Unit tests.
|
|
||||||
run: ./flutterw test
|
|
||||||
|
|
||||||
- name: Build signed artifacts.
|
|
||||||
# `KEY_JKS` should contain the result of:
|
# `KEY_JKS` should contain the result of:
|
||||||
# gpg -c --armor keystore.jks
|
# gpg -c --armor keystore.jks
|
||||||
# `KEY_JKS_PASSPHRASE` should contain the passphrase used for the command above
|
# `KEY_JKS_PASSPHRASE` should contain the passphrase used for the command above
|
||||||
|
@ -70,7 +72,7 @@ jobs:
|
||||||
AVES_KEY_PASSWORD: ${{ secrets.AVES_KEY_PASSWORD }}
|
AVES_KEY_PASSWORD: ${{ secrets.AVES_KEY_PASSWORD }}
|
||||||
AVES_GOOGLE_API_KEY: ${{ secrets.AVES_GOOGLE_API_KEY }}
|
AVES_GOOGLE_API_KEY: ${{ secrets.AVES_GOOGLE_API_KEY }}
|
||||||
|
|
||||||
- name: Create a release with the APK and App Bundle.
|
- name: Create GitHub release
|
||||||
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0
|
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0
|
||||||
with:
|
with:
|
||||||
artifacts: "outputs/*"
|
artifacts: "outputs/*"
|
||||||
|
@ -78,29 +80,30 @@ jobs:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Upload app bundle
|
- name: Upload app bundle
|
||||||
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||||
with:
|
with:
|
||||||
name: appbundle
|
name: appbundle
|
||||||
path: outputs/app-play-release.aab
|
path: outputs/app-play-release.aab
|
||||||
|
|
||||||
release:
|
release_play:
|
||||||
name: Create beta release on Play Store.
|
name: Play Store beta release
|
||||||
needs: [ build ]
|
needs: [ build ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Get appbundle from artifacts.
|
- name: Get appbundle from artifacts
|
||||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||||
with:
|
with:
|
||||||
name: appbundle
|
name: appbundle
|
||||||
|
|
||||||
- name: Release app to beta channel.
|
- name: Release to beta channel
|
||||||
uses: r0adkll/upload-google-play@935ef9c68bb393a8e6116b1575626a7f5be3a7fb # v1.1.3
|
uses: r0adkll/upload-google-play@935ef9c68bb393a8e6116b1575626a7f5be3a7fb # v1.1.3
|
||||||
with:
|
with:
|
||||||
serviceAccountJsonPlainText: ${{ secrets.PLAYSTORE_ACCOUNT_KEY }}
|
serviceAccountJsonPlainText: ${{ secrets.PLAYSTORE_ACCOUNT_KEY }}
|
||||||
|
|
6
.github/workflows/scorecards.yml
vendored
6
.github/workflows/scorecards.yml
vendored
|
@ -31,7 +31,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ jobs:
|
||||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||||
# format to the repository Actions tab.
|
# format to the repository Actions tab.
|
||||||
- name: "Upload artifact"
|
- name: "Upload artifact"
|
||||||
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||||
with:
|
with:
|
||||||
name: SARIF file
|
name: SARIF file
|
||||||
path: results.sarif
|
path: results.sarif
|
||||||
|
@ -71,6 +71,6 @@ jobs:
|
||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6
|
uses: github/codeql-action/upload-sarif@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## <a id="unreleased"></a>[Unreleased]
|
## <a id="unreleased"></a>[Unreleased]
|
||||||
|
|
||||||
|
## <a id="v1.11.11"></a>[v1.11.11] - 2024-09-16
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- support opening from the lock screen
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- upgraded Flutter to stable v3.24.3
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- crash when cataloguing some malformed MP4 files
|
||||||
|
- inconsistent launch screen
|
||||||
|
|
||||||
## <a id="v1.11.10"></a>[v1.11.10] - 2024-09-01
|
## <a id="v1.11.10"></a>[v1.11.10] - 2024-09-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -49,8 +49,8 @@ android {
|
||||||
ndkVersion '26.1.10909125'
|
ndkVersion '26.1.10909125'
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_17
|
sourceCompatibility JavaVersion.VERSION_21
|
||||||
targetCompatibility JavaVersion.VERSION_17
|
targetCompatibility JavaVersion.VERSION_21
|
||||||
}
|
}
|
||||||
|
|
||||||
lint {
|
lint {
|
||||||
|
@ -156,12 +156,12 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(KotlinCompile).configureEach {
|
tasks.withType(KotlinCompile).configureEach {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_21
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_21
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvmToolchain(17)
|
jvmToolchain(21)
|
||||||
}
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
|
@ -189,11 +189,11 @@ dependencies {
|
||||||
|
|
||||||
implementation "androidx.appcompat:appcompat:1.7.0"
|
implementation "androidx.appcompat:appcompat:1.7.0"
|
||||||
implementation 'androidx.core:core-ktx:1.13.1'
|
implementation 'androidx.core:core-ktx:1.13.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-process:2.8.4'
|
implementation 'androidx.lifecycle:lifecycle-process:2.8.5'
|
||||||
implementation 'androidx.media:media:1.7.0'
|
implementation 'androidx.media:media:1.7.0'
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
||||||
implementation 'androidx.work:work-runtime-ktx:2.9.0'
|
implementation 'androidx.work:work-runtime-ktx:2.9.1'
|
||||||
|
|
||||||
implementation 'com.caverock:androidsvg-aar:1.4'
|
implementation 'com.caverock:androidsvg-aar:1.4'
|
||||||
implementation 'com.commonsware.cwac:document:0.5.0'
|
implementation 'com.commonsware.cwac:document:0.5.0'
|
||||||
|
@ -208,14 +208,14 @@ dependencies {
|
||||||
// - https://jitpack.io/p/deckerst/mp4parser
|
// - https://jitpack.io/p/deckerst/mp4parser
|
||||||
// - https://jitpack.io/p/deckerst/pixymeta-android
|
// - https://jitpack.io/p/deckerst/pixymeta-android
|
||||||
implementation 'com.github.deckerst:Android-TiffBitmapFactory:90c06eebf4'
|
implementation 'com.github.deckerst:Android-TiffBitmapFactory:90c06eebf4'
|
||||||
implementation 'com.github.deckerst.mp4parser:isoparser:4cc0c5d06c'
|
implementation 'com.github.deckerst.mp4parser:isoparser:86d4b6baa1'
|
||||||
implementation 'com.github.deckerst.mp4parser:muxer:4cc0c5d06c'
|
implementation 'com.github.deckerst.mp4parser:muxer:86d4b6baa1'
|
||||||
implementation 'com.github.deckerst:pixymeta-android:9ec7097f17'
|
implementation 'com.github.deckerst:pixymeta-android:9ec7097f17'
|
||||||
implementation project(':exifinterface')
|
implementation project(':exifinterface')
|
||||||
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.3'
|
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.3'
|
||||||
|
|
||||||
kapt 'androidx.annotation:annotation:1.8.1'
|
kapt 'androidx.annotation:annotation:1.8.2'
|
||||||
ksp "com.github.bumptech.glide:ksp:$glide_version"
|
ksp "com.github.bumptech.glide:ksp:$glide_version"
|
||||||
|
|
||||||
compileOnly rootProject.findProject(':streams_channel')
|
compileOnly rootProject.findProject(':streams_channel')
|
||||||
|
|
|
@ -128,6 +128,7 @@
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
|
android:showWhenLocked="true"
|
||||||
android:supportsPictureInPicture="true"
|
android:supportsPictureInPicture="true"
|
||||||
android:theme="@style/NormalTheme"
|
android:theme="@style/NormalTheme"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
||||||
import android.app.SearchManager
|
import android.app.SearchManager
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
@ -229,6 +230,7 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
intentStreamHandler.notifyNewIntent(extractIntentData(intent))
|
intentStreamHandler.notifyNewIntent(extractIntentData(intent))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
|
@ -316,6 +318,13 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
INTENT_DATA_KEY_URI to uri.toString(),
|
INTENT_DATA_KEY_URI to uri.toString(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as android.app.KeyguardManager
|
||||||
|
val isLocked = keyguardManager.isKeyguardLocked
|
||||||
|
if (isLocked) {
|
||||||
|
// device is locked, so access to content is limited to intent URI by default
|
||||||
|
fields[INTENT_DATA_KEY_SECURE_URIS] = listOf(uri.toString())
|
||||||
|
}
|
||||||
|
|
||||||
if (action == MediaStore.ACTION_REVIEW_SECURE) {
|
if (action == MediaStore.ACTION_REVIEW_SECURE) {
|
||||||
val uris = ArrayList<String>()
|
val uris = ArrayList<String>()
|
||||||
intent.clipData?.let { clipData ->
|
intent.clipData?.let { clipData ->
|
||||||
|
@ -323,8 +332,10 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
clipData.getItemAt(i).uri?.let { uris.add(it.toString()) }
|
clipData.getItemAt(i).uri?.let { uris.add(it.toString()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (uris.isNotEmpty()) {
|
||||||
fields[INTENT_DATA_KEY_SECURE_URIS] = uris
|
fields[INTENT_DATA_KEY_SECURE_URIS] = uris
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && intent.hasExtra(MediaStore.EXTRA_BRIGHTNESS)) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && intent.hasExtra(MediaStore.EXTRA_BRIGHTNESS)) {
|
||||||
fields[INTENT_DATA_KEY_BRIGHTNESS] = intent.getFloatExtra(MediaStore.EXTRA_BRIGHTNESS, 0f)
|
fields[INTENT_DATA_KEY_BRIGHTNESS] = intent.getFloatExtra(MediaStore.EXTRA_BRIGHTNESS, 0f)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
||||||
"getDefaultTimeZoneRawOffsetMillis" -> safe(call, result, ::getDefaultTimeZoneRawOffsetMillis)
|
"getDefaultTimeZoneRawOffsetMillis" -> safe(call, result, ::getDefaultTimeZoneRawOffsetMillis)
|
||||||
"getLocales" -> safe(call, result, ::getLocales)
|
"getLocales" -> safe(call, result, ::getLocales)
|
||||||
"getPerformanceClass" -> safe(call, result, ::getPerformanceClass)
|
"getPerformanceClass" -> safe(call, result, ::getPerformanceClass)
|
||||||
|
"isLocked" -> safe(call, result, ::isLocked)
|
||||||
"isSystemFilePickerEnabled" -> safe(call, result, ::isSystemFilePickerEnabled)
|
"isSystemFilePickerEnabled" -> safe(call, result, ::isSystemFilePickerEnabled)
|
||||||
"requestMediaManagePermission" -> safe(call, result, ::requestMediaManagePermission)
|
"requestMediaManagePermission" -> safe(call, result, ::requestMediaManagePermission)
|
||||||
"getAvailableHeapSize" -> safe(call, result, ::getAvailableHeapSize)
|
"getAvailableHeapSize" -> safe(call, result, ::getAvailableHeapSize)
|
||||||
|
@ -49,13 +50,11 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
||||||
val sdkInt = Build.VERSION.SDK_INT
|
val sdkInt = Build.VERSION.SDK_INT
|
||||||
result.success(
|
result.success(
|
||||||
hashMapOf(
|
hashMapOf(
|
||||||
"canGrantDirectoryAccess" to (sdkInt >= Build.VERSION_CODES.LOLLIPOP),
|
|
||||||
"canPinShortcut" to ShortcutManagerCompat.isRequestPinShortcutSupported(context),
|
"canPinShortcut" to ShortcutManagerCompat.isRequestPinShortcutSupported(context),
|
||||||
"canRenderFlagEmojis" to (sdkInt >= Build.VERSION_CODES.M),
|
"canRenderFlagEmojis" to (sdkInt >= Build.VERSION_CODES.M),
|
||||||
"canRenderSubdivisionFlagEmojis" to (sdkInt >= Build.VERSION_CODES.O),
|
"canRenderSubdivisionFlagEmojis" to (sdkInt >= Build.VERSION_CODES.O),
|
||||||
"canRequestManageMedia" to (sdkInt >= Build.VERSION_CODES.S),
|
"canRequestManageMedia" to (sdkInt >= Build.VERSION_CODES.S),
|
||||||
"canSetLockScreenWallpaper" to (sdkInt >= Build.VERSION_CODES.N),
|
"canSetLockScreenWallpaper" to (sdkInt >= Build.VERSION_CODES.N),
|
||||||
"canUseCrypto" to (sdkInt >= Build.VERSION_CODES.LOLLIPOP),
|
|
||||||
"hasGeocoder" to Geocoder.isPresent(),
|
"hasGeocoder" to Geocoder.isPresent(),
|
||||||
"isDynamicColorAvailable" to DynamicColors.isDynamicColorAvailable(),
|
"isDynamicColorAvailable" to DynamicColors.isDynamicColorAvailable(),
|
||||||
"showPinShortcutFeedback" to (sdkInt >= Build.VERSION_CODES.O),
|
"showPinShortcutFeedback" to (sdkInt >= Build.VERSION_CODES.O),
|
||||||
|
@ -100,6 +99,12 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
||||||
result.success(Build.VERSION.SDK_INT)
|
result.success(Build.VERSION.SDK_INT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isLocked(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as android.app.KeyguardManager
|
||||||
|
val isLocked = keyguardManager.isKeyguardLocked
|
||||||
|
result.success(isLocked)
|
||||||
|
}
|
||||||
|
|
||||||
private fun isSystemFilePickerEnabled(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
private fun isSystemFilePickerEnabled(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
||||||
val enabled = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).resolveActivity(context.packageManager) != null
|
val enabled = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).resolveActivity(context.packageManager) != null
|
||||||
result.success(enabled)
|
result.success(enabled)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<style name="NormalTheme" parent="Theme.AppCompat.NoActionBar">
|
<style name="NormalTheme" parent="Theme.AppCompat.NoActionBar">
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
<item name="android:windowBackground">@color/window_background_night</item>
|
||||||
|
<item name="android:windowSplashScreenBackground" tools:targetApi="s">@color/window_background_night</item>
|
||||||
|
<item name="android:windowSplashScreenAnimatedIcon" tools:targetApi="s">@mipmap/ic_launcher</item>
|
||||||
|
|
||||||
<!-- API28+, draws next to the notch in fullscreen -->
|
<!-- API28+, draws next to the notch in fullscreen -->
|
||||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="28">shortEdges</item>
|
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="28">shortEdges</item>
|
||||||
|
|
12
android/app/src/main/res/values-sr/strings.xml
Normal file
12
android/app/src/main/res/values-sr/strings.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_widget_label">Okvir Slike</string>
|
||||||
|
<string name="wallpaper">Pozadina</string>
|
||||||
|
<string name="safe_mode_shortcut_short_label">Siguran režim</string>
|
||||||
|
<string name="videos_shortcut_short_label">Snimci</string>
|
||||||
|
<string name="analysis_channel_name">Pretraga medija</string>
|
||||||
|
<string name="analysis_notification_default_title">Skeniranje medija</string>
|
||||||
|
<string name="analysis_notification_action_stop">Stop</string>
|
||||||
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="search_shortcut_short_label">Pretraga</string>
|
||||||
|
</resources>
|
|
@ -4,4 +4,6 @@
|
||||||
<color name="ic_shortcut_background">#FFFFFF</color>
|
<color name="ic_shortcut_background">#FFFFFF</color>
|
||||||
<color name="ic_shortcut_foreground">#455A64</color>
|
<color name="ic_shortcut_foreground">#455A64</color>
|
||||||
<color name="ic_launcher_flavour">#1cc8eb</color>
|
<color name="ic_launcher_flavour">#1cc8eb</color>
|
||||||
|
<color name="window_background_day">#FFFFFF</color>
|
||||||
|
<color name="window_background_night">#262626</color>
|
||||||
</resources>
|
</resources>
|
|
@ -1,7 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<style name="NormalTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="NormalTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
<item name="android:windowBackground">@color/window_background_day</item>
|
||||||
|
<item name="android:windowSplashScreenBackground" tools:targetApi="s">@color/window_background_day</item>
|
||||||
|
<item name="android:windowSplashScreenAnimatedIcon" tools:targetApi="s">@mipmap/ic_launcher</item>
|
||||||
|
|
||||||
<!-- API28+, draws next to the notch in fullscreen -->
|
<!-- API28+, draws next to the notch in fullscreen -->
|
||||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="28">shortEdges</item>
|
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="28">shortEdges</item>
|
||||||
|
|
|
@ -4,10 +4,10 @@ plugins {
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'androidx.exifinterface.media'
|
namespace 'androidx.exifinterface.media'
|
||||||
compileSdk 34
|
compileSdk 35
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk 19
|
minSdk 21
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles "consumer-rules.pro"
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
|
@ -20,11 +20,11 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_17
|
sourceCompatibility JavaVersion.VERSION_21
|
||||||
targetCompatibility JavaVersion.VERSION_17
|
targetCompatibility JavaVersion.VERSION_21
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.annotation:annotation:1.8.0'
|
implementation 'androidx.annotation:annotation:1.8.2'
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ pluginManagement {
|
||||||
|
|
||||||
settings.ext.kotlin_version = '1.9.24'
|
settings.ext.kotlin_version = '1.9.24'
|
||||||
settings.ext.ksp_version = "$kotlin_version-1.0.20"
|
settings.ext.ksp_version = "$kotlin_version-1.0.20"
|
||||||
settings.ext.agp_version = '8.5.1'
|
settings.ext.agp_version = '8.6.0'
|
||||||
|
|
||||||
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
|
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
|
||||||
|
|
||||||
|
|
3
fastlane/metadata/android/en-US/changelogs/130.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/130.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
In v1.11.11:
|
||||||
|
- review photos from the lock screen
|
||||||
|
Full changelog available on GitHub
|
3
fastlane/metadata/android/en-US/changelogs/13001.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/13001.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
In v1.11.11:
|
||||||
|
- review photos from the lock screen
|
||||||
|
Full changelog available on GitHub
|
5
fastlane/metadata/android/sr/full_description.txt
Normal file
5
fastlane/metadata/android/sr/full_description.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<i>Aves</i> can handle all sorts of images and videos, including your typical JPEGs and MP4s, but also more exotic things like <b>multi-page TIFFs, SVGs, old AVIs and more</b>! It scans your media collection to identify <b>motion photos</b>, <b>panoramas</b> (aka photo spheres), <b>360° videos</b>, as well as <b>GeoTIFF</b> files.
|
||||||
|
|
||||||
|
<b>Navigation and search</b> is an important part of <i>Aves</i>. The goal is for users to easily flow from albums to photos to tags to maps, etc.
|
||||||
|
|
||||||
|
<i>Aves</i> integrates with Android (from KitKat to Android 14, including Android TV) with features such as <b>widgets</b>, <b>app shortcuts</b>, <b>screen saver</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.
|
1
fastlane/metadata/android/sr/short_description.txt
Normal file
1
fastlane/metadata/android/sr/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Gallery and metadata explorer
|
|
@ -1 +1,119 @@
|
||||||
{}
|
{
|
||||||
|
"welcomeMessage": "Velkommen til Aves",
|
||||||
|
"@welcomeMessage": {},
|
||||||
|
"welcomeOptional": "Valgfri",
|
||||||
|
"@welcomeOptional": {},
|
||||||
|
"appName": "Aves",
|
||||||
|
"@appName": {},
|
||||||
|
"welcomeTermsToggle": "Jeg accepterer vilkårene og betingelserne",
|
||||||
|
"@welcomeTermsToggle": {},
|
||||||
|
"itemCount": "{count, plural, =1{{count} fil} other{{count} filer}}",
|
||||||
|
"@itemCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"columnCount": "{count, plural, =1{{count} kolonne} other{{count} kolonner}}",
|
||||||
|
"@columnCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timeMinutes": "{count, plural, =1{{count} minut} other{{count} minutter}}",
|
||||||
|
"@timeMinutes": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timeDays": "{count, plural, =1{{count} dag} other{{count} dage}}",
|
||||||
|
"@timeDays": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"focalLength": "{length} mm",
|
||||||
|
"@focalLength": {
|
||||||
|
"placeholders": {
|
||||||
|
"length": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "5.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"applyButtonLabel": "UDFØR",
|
||||||
|
"@applyButtonLabel": {},
|
||||||
|
"deleteButtonLabel": "SLET",
|
||||||
|
"@deleteButtonLabel": {},
|
||||||
|
"nextButtonLabel": "NÆSTE",
|
||||||
|
"@nextButtonLabel": {},
|
||||||
|
"showButtonLabel": "VIS",
|
||||||
|
"@showButtonLabel": {},
|
||||||
|
"hideButtonLabel": "SKJUL",
|
||||||
|
"@hideButtonLabel": {},
|
||||||
|
"saveCopyButtonLabel": "GEM KOPI",
|
||||||
|
"@saveCopyButtonLabel": {},
|
||||||
|
"applyTooltip": "Udfør",
|
||||||
|
"@applyTooltip": {},
|
||||||
|
"cancelTooltip": "Fortryd",
|
||||||
|
"@cancelTooltip": {},
|
||||||
|
"nextTooltip": "Næste",
|
||||||
|
"@nextTooltip": {},
|
||||||
|
"showTooltip": "Vis",
|
||||||
|
"@showTooltip": {},
|
||||||
|
"hideTooltip": "Skjul",
|
||||||
|
"@hideTooltip": {},
|
||||||
|
"actionRemove": "Fjern",
|
||||||
|
"@actionRemove": {},
|
||||||
|
"resetTooltip": "Nulstil",
|
||||||
|
"@resetTooltip": {},
|
||||||
|
"saveTooltip": "Gem",
|
||||||
|
"@saveTooltip": {},
|
||||||
|
"chipActionDelete": "Slet",
|
||||||
|
"@chipActionDelete": {},
|
||||||
|
"chipActionGoToAlbumPage": "Vis i Album",
|
||||||
|
"@chipActionGoToAlbumPage": {},
|
||||||
|
"chipActionGoToCountryPage": "Vis i Lande",
|
||||||
|
"@chipActionGoToCountryPage": {},
|
||||||
|
"chipActionGoToPlacePage": "Vis i Steder",
|
||||||
|
"@chipActionGoToPlacePage": {},
|
||||||
|
"chipActionGoToTagPage": "Vis i Tags",
|
||||||
|
"@chipActionGoToTagPage": {},
|
||||||
|
"timeSeconds": "{count, plural, =1{{count} sekund} other{{count} sekunder}}",
|
||||||
|
"@timeSeconds": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"continueButtonLabel": "FORTSÆT",
|
||||||
|
"@continueButtonLabel": {},
|
||||||
|
"clearTooltip": "Ryd",
|
||||||
|
"@clearTooltip": {},
|
||||||
|
"previousTooltip": "Forrige",
|
||||||
|
"@previousTooltip": {},
|
||||||
|
"stopTooltip": "Stop",
|
||||||
|
"@stopTooltip": {},
|
||||||
|
"pickTooltip": "Vælg",
|
||||||
|
"@pickTooltip": {},
|
||||||
|
"chipActionShowCollection": "Vis i Samling",
|
||||||
|
"@chipActionShowCollection": {},
|
||||||
|
"doubleBackExitMessage": "Tryk \"tilbage\" igen for at gå ud.",
|
||||||
|
"@doubleBackExitMessage": {},
|
||||||
|
"doNotAskAgain": "Spørg ikke igen",
|
||||||
|
"@doNotAskAgain": {},
|
||||||
|
"sourceStateLoading": "Loader",
|
||||||
|
"@sourceStateLoading": {},
|
||||||
|
"sourceStateLocatingCountries": "Lokaliserer lande",
|
||||||
|
"@sourceStateLocatingCountries": {},
|
||||||
|
"sourceStateLocatingPlaces": "Lokaliserer steder",
|
||||||
|
"@sourceStateLocatingPlaces": {}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"welcomeOptional": "वैकल्पिक",
|
"welcomeOptional": "वैकल्पिक",
|
||||||
"@welcomeOptional": {},
|
"@welcomeOptional": {},
|
||||||
"welcomeTermsToggle": "मैं नियमों और शर्तों पर सहमत हुं",
|
"welcomeTermsToggle": "मैं नियमों और शर्तों से सहमत हूं",
|
||||||
"@welcomeTermsToggle": {},
|
"@welcomeTermsToggle": {},
|
||||||
"columnCount": "{count, plural, other{{count} कॉलम}}",
|
"columnCount": "{count, plural, other{{count} कॉलम}}",
|
||||||
"@columnCount": {
|
"@columnCount": {
|
||||||
|
@ -246,7 +246,7 @@
|
||||||
"@displayRefreshRatePreferLowest": {},
|
"@displayRefreshRatePreferLowest": {},
|
||||||
"nameConflictStrategyRename": "नाम बदलें",
|
"nameConflictStrategyRename": "नाम बदलें",
|
||||||
"@nameConflictStrategyRename": {},
|
"@nameConflictStrategyRename": {},
|
||||||
"unitSystemMetric": "Metric",
|
"unitSystemMetric": "मात्रिक",
|
||||||
"@unitSystemMetric": {},
|
"@unitSystemMetric": {},
|
||||||
"viewerTransitionSlide": "स्लाइड",
|
"viewerTransitionSlide": "स्लाइड",
|
||||||
"@viewerTransitionSlide": {},
|
"@viewerTransitionSlide": {},
|
||||||
|
@ -262,9 +262,9 @@
|
||||||
"@filterTaggedLabel": {},
|
"@filterTaggedLabel": {},
|
||||||
"mapStyleGoogleTerrain": "गूगल मैप्स (टेरेन)",
|
"mapStyleGoogleTerrain": "गूगल मैप्स (टेरेन)",
|
||||||
"@mapStyleGoogleTerrain": {},
|
"@mapStyleGoogleTerrain": {},
|
||||||
"themeBrightnessDark": "Dark",
|
"themeBrightnessDark": "डार्क",
|
||||||
"@themeBrightnessDark": {},
|
"@themeBrightnessDark": {},
|
||||||
"themeBrightnessBlack": "Black",
|
"themeBrightnessBlack": "काला",
|
||||||
"@themeBrightnessBlack": {},
|
"@themeBrightnessBlack": {},
|
||||||
"videoControlsPlaySeek": "पिछड़े / आगे की तलाश करें",
|
"videoControlsPlaySeek": "पिछड़े / आगे की तलाश करें",
|
||||||
"@videoControlsPlaySeek": {},
|
"@videoControlsPlaySeek": {},
|
||||||
|
@ -284,7 +284,7 @@
|
||||||
"@mapStyleGoogleHybrid": {},
|
"@mapStyleGoogleHybrid": {},
|
||||||
"mapStyleStamenWatercolor": "Stamen Watercolor",
|
"mapStyleStamenWatercolor": "Stamen Watercolor",
|
||||||
"@mapStyleStamenWatercolor": {},
|
"@mapStyleStamenWatercolor": {},
|
||||||
"unitSystemImperial": "Imperial",
|
"unitSystemImperial": "इम्पीरियल",
|
||||||
"@unitSystemImperial": {},
|
"@unitSystemImperial": {},
|
||||||
"passwordDialogEnter": "पासवर्ड दर्ज करें",
|
"passwordDialogEnter": "पासवर्ड दर्ज करें",
|
||||||
"@passwordDialogEnter": {},
|
"@passwordDialogEnter": {},
|
||||||
|
@ -298,7 +298,7 @@
|
||||||
"@albumTierRegular": {},
|
"@albumTierRegular": {},
|
||||||
"coordinateFormatDms": "DMS",
|
"coordinateFormatDms": "DMS",
|
||||||
"@coordinateFormatDms": {},
|
"@coordinateFormatDms": {},
|
||||||
"coordinateFormatDecimal": "Decimal degrees",
|
"coordinateFormatDecimal": "दशमलव डिग्री",
|
||||||
"@coordinateFormatDecimal": {},
|
"@coordinateFormatDecimal": {},
|
||||||
"coordinateDms": "{coordinate} {direction}",
|
"coordinateDms": "{coordinate} {direction}",
|
||||||
"@coordinateDms": {
|
"@coordinateDms": {
|
||||||
|
@ -491,7 +491,7 @@
|
||||||
"@lengthUnitPercent": {},
|
"@lengthUnitPercent": {},
|
||||||
"nameConflictStrategyReplace": "बदलें",
|
"nameConflictStrategyReplace": "बदलें",
|
||||||
"@nameConflictStrategyReplace": {},
|
"@nameConflictStrategyReplace": {},
|
||||||
"themeBrightnessLight": "Light",
|
"themeBrightnessLight": "लाइट",
|
||||||
"@themeBrightnessLight": {},
|
"@themeBrightnessLight": {},
|
||||||
"vaultLockTypePassword": "पासवर्ड",
|
"vaultLockTypePassword": "पासवर्ड",
|
||||||
"@vaultLockTypePassword": {},
|
"@vaultLockTypePassword": {},
|
||||||
|
@ -554,5 +554,421 @@
|
||||||
"videoActionABRepeat": "A-B दोहराव",
|
"videoActionABRepeat": "A-B दोहराव",
|
||||||
"@videoActionABRepeat": {},
|
"@videoActionABRepeat": {},
|
||||||
"videoRepeatActionSetStart": "स्टार्ट सेट करे",
|
"videoRepeatActionSetStart": "स्टार्ट सेट करे",
|
||||||
"@videoRepeatActionSetStart": {}
|
"@videoRepeatActionSetStart": {},
|
||||||
|
"keepScreenOnNever": "कभी नहीं",
|
||||||
|
"@keepScreenOnNever": {},
|
||||||
|
"editEntryDialogCopyFromItem": "अन्य आइटम से कॉपी करें",
|
||||||
|
"@editEntryDialogCopyFromItem": {},
|
||||||
|
"durationDialogSeconds": "सेकंड",
|
||||||
|
"@durationDialogSeconds": {},
|
||||||
|
"entryInfoActionEditTitleDescription": "शीर्षक और विवरण संपादित करें",
|
||||||
|
"@entryInfoActionEditTitleDescription": {},
|
||||||
|
"widgetOpenPageCollection": "संग्रह खोलें",
|
||||||
|
"@widgetOpenPageCollection": {},
|
||||||
|
"vaultBinUsageDialogMessage": "कुछ वॉल्ट्स रीसायकल बिन का उपयोग कर रहे हैं।।",
|
||||||
|
"@vaultBinUsageDialogMessage": {},
|
||||||
|
"editEntryLocationDialogSetCustom": "कस्टम स्थान सेट करें",
|
||||||
|
"@editEntryLocationDialogSetCustom": {},
|
||||||
|
"editEntryLocationDialogChooseOnMap": "मानचित्र पर चुनें",
|
||||||
|
"@editEntryLocationDialogChooseOnMap": {},
|
||||||
|
"sourceStateCataloguing": "Cataloguing",
|
||||||
|
"@sourceStateCataloguing": {},
|
||||||
|
"editEntryLocationDialogLongitude": "देशांतर",
|
||||||
|
"@editEntryLocationDialogLongitude": {},
|
||||||
|
"videoStreamSelectionDialogVideo": "वीडियो",
|
||||||
|
"@videoStreamSelectionDialogVideo": {},
|
||||||
|
"keepScreenOnViewerOnly": "केवल व्यूअर पेज",
|
||||||
|
"@keepScreenOnViewerOnly": {},
|
||||||
|
"keepScreenOnAlways": "हमेशा",
|
||||||
|
"@keepScreenOnAlways": {},
|
||||||
|
"renameEntrySetPageInsertTooltip": "फ़ील्ड डालें",
|
||||||
|
"@renameEntrySetPageInsertTooltip": {},
|
||||||
|
"renameEntrySetPagePreviewSectionTitle": "पूर्वावलोकन",
|
||||||
|
"@renameEntrySetPagePreviewSectionTitle": {},
|
||||||
|
"setCoverDialogAuto": "ऑटो",
|
||||||
|
"@setCoverDialogAuto": {},
|
||||||
|
"exportEntryDialogWidth": "चौड़ाई",
|
||||||
|
"@exportEntryDialogWidth": {},
|
||||||
|
"editEntryDialogTargetFieldsHeader": "संशोधित करने के लिए फ़ील्ड",
|
||||||
|
"@editEntryDialogTargetFieldsHeader": {},
|
||||||
|
"editEntryDateDialogTitle": "तारीख और समय",
|
||||||
|
"@editEntryDateDialogTitle": {},
|
||||||
|
"editEntryDateDialogSetCustom": "कस्टम तिथि सेट करें",
|
||||||
|
"@editEntryDateDialogSetCustom": {},
|
||||||
|
"durationDialogHours": "घंटे",
|
||||||
|
"@durationDialogHours": {},
|
||||||
|
"editEntryLocationDialogTitle": "स्थान",
|
||||||
|
"@editEntryLocationDialogTitle": {},
|
||||||
|
"renameProcessorHash": "हैश",
|
||||||
|
"@renameProcessorHash": {},
|
||||||
|
"renameProcessorName": "नाम",
|
||||||
|
"@renameProcessorName": {},
|
||||||
|
"exportEntryDialogFormat": "फॉर्मेट:",
|
||||||
|
"@exportEntryDialogFormat": {},
|
||||||
|
"removeEntryMetadataMotionPhotoXmpWarningDialogMessage": "मोशन फोटो के अंदर वीडियो चलाने के लिए XMP की जरूरत है\n\nक्या आप वास्तव में इसे हटाना चाहते हैं?",
|
||||||
|
"@removeEntryMetadataMotionPhotoXmpWarningDialogMessage": {},
|
||||||
|
"videoSpeedDialogLabel": "चलाने की गति",
|
||||||
|
"@videoSpeedDialogLabel": {},
|
||||||
|
"editEntryLocationDialogLatitude": "अक्षांश",
|
||||||
|
"@editEntryLocationDialogLatitude": {},
|
||||||
|
"removeEntryMetadataDialogTitle": "मेटाडाटा हटाना",
|
||||||
|
"@removeEntryMetadataDialogTitle": {},
|
||||||
|
"filterNoLocationLabel": "लॉकेट नही किया गया",
|
||||||
|
"@filterNoLocationLabel": {},
|
||||||
|
"accessibilityAnimationsRemove": "स्क्रीन प्रभाव को रोकें",
|
||||||
|
"@accessibilityAnimationsRemove": {},
|
||||||
|
"maxBrightnessNever": "कभी नहीं",
|
||||||
|
"@maxBrightnessNever": {},
|
||||||
|
"maxBrightnessAlways": "हमेशा",
|
||||||
|
"@maxBrightnessAlways": {},
|
||||||
|
"widgetTapUpdateWidget": "विजेट अपडेट करें",
|
||||||
|
"@widgetTapUpdateWidget": {},
|
||||||
|
"storageVolumeDescriptionFallbackPrimary": "आंतरिक भंडारण",
|
||||||
|
"@storageVolumeDescriptionFallbackPrimary": {},
|
||||||
|
"editEntryDateDialogExtractFromTitle": "शीर्षक से निकालें",
|
||||||
|
"@editEntryDateDialogExtractFromTitle": {},
|
||||||
|
"editEntryRatingDialogTitle": "रेटिंग",
|
||||||
|
"@editEntryRatingDialogTitle": {},
|
||||||
|
"removeEntryMetadataDialogMore": "अधिक",
|
||||||
|
"@removeEntryMetadataDialogMore": {},
|
||||||
|
"filterLocatedLabel": "लोकेट किया गया",
|
||||||
|
"@filterLocatedLabel": {},
|
||||||
|
"locationPickerUseThisLocationButton": "इस स्थान का उपयोग करें",
|
||||||
|
"@locationPickerUseThisLocationButton": {},
|
||||||
|
"viewerActionLock": "व्यूअर को लॉक करे",
|
||||||
|
"@viewerActionLock": {},
|
||||||
|
"renameEntrySetPagePatternFieldLabel": "नामकरण पैटर्न",
|
||||||
|
"@renameEntrySetPagePatternFieldLabel": {},
|
||||||
|
"videoResumptionModeNever": "कभी नहीं",
|
||||||
|
"@videoResumptionModeNever": {},
|
||||||
|
"videoResumptionModeAlways": "हमेशा",
|
||||||
|
"@videoResumptionModeAlways": {},
|
||||||
|
"renameProcessorCounter": "काउंटर",
|
||||||
|
"@renameProcessorCounter": {},
|
||||||
|
"editEntryDateDialogCopyField": "अन्य तारीख से कॉपी करें",
|
||||||
|
"@editEntryDateDialogCopyField": {},
|
||||||
|
"viewerActionUnlock": "व्यूअर को अनलॉक करे",
|
||||||
|
"@viewerActionUnlock": {},
|
||||||
|
"editorTransformCrop": "क्रॉप",
|
||||||
|
"@editorTransformCrop": {},
|
||||||
|
"cropAspectRatioFree": "फ्री",
|
||||||
|
"@cropAspectRatioFree": {},
|
||||||
|
"nameConflictStrategySkip": "छोड़े",
|
||||||
|
"@nameConflictStrategySkip": {},
|
||||||
|
"albumTierPinned": "पिन किया गया",
|
||||||
|
"@albumTierPinned": {},
|
||||||
|
"albumTierSpecial": "कॉमन",
|
||||||
|
"@albumTierSpecial": {},
|
||||||
|
"overlayHistogramNone": "कोई नहीं",
|
||||||
|
"@overlayHistogramNone": {},
|
||||||
|
"overlayHistogramRGB": "RGB",
|
||||||
|
"@overlayHistogramRGB": {},
|
||||||
|
"overlayHistogramLuminance": "चमक",
|
||||||
|
"@overlayHistogramLuminance": {},
|
||||||
|
"widgetOpenPageViewer": "व्यूअर खोलें",
|
||||||
|
"@widgetOpenPageViewer": {},
|
||||||
|
"addShortcutButtonLabel": "ADD",
|
||||||
|
"@addShortcutButtonLabel": {},
|
||||||
|
"setCoverDialogCustom": "कस्टम",
|
||||||
|
"@setCoverDialogCustom": {},
|
||||||
|
"exportEntryDialogHeight": "ऊंचाई",
|
||||||
|
"@exportEntryDialogHeight": {},
|
||||||
|
"exportEntryDialogQuality": "गुणवत्ता",
|
||||||
|
"@exportEntryDialogQuality": {},
|
||||||
|
"exportEntryDialogWriteMetadata": "मेटाडाटा लिखें",
|
||||||
|
"@exportEntryDialogWriteMetadata": {},
|
||||||
|
"renameEntryDialogLabel": "नया नाम",
|
||||||
|
"@renameEntryDialogLabel": {},
|
||||||
|
"editEntryDateDialogShift": "शिफ्ट",
|
||||||
|
"@editEntryDateDialogShift": {},
|
||||||
|
"durationDialogMinutes": "मिनट",
|
||||||
|
"@durationDialogMinutes": {},
|
||||||
|
"videoStreamSelectionDialogText": "उपशीर्षक",
|
||||||
|
"@videoStreamSelectionDialogText": {},
|
||||||
|
"genericFailureFeedback": "असफल",
|
||||||
|
"@genericFailureFeedback": {},
|
||||||
|
"menuActionSlideshow": "स्लाइड शो",
|
||||||
|
"@menuActionSlideshow": {},
|
||||||
|
"viewDialogReverseSortOrder": "क्रम उलटा करे",
|
||||||
|
"@viewDialogReverseSortOrder": {},
|
||||||
|
"tileLayoutMosaic": "मौज़ेक",
|
||||||
|
"@tileLayoutMosaic": {},
|
||||||
|
"cropAspectRatioSquare": "वर्ग",
|
||||||
|
"@cropAspectRatioSquare": {},
|
||||||
|
"widgetOpenPageHome": "घर खोलें",
|
||||||
|
"@widgetOpenPageHome": {},
|
||||||
|
"viewDialogSortSectionTitle": "क्रम से लगाए",
|
||||||
|
"@viewDialogSortSectionTitle": {},
|
||||||
|
"viewDialogGroupSectionTitle": "समूह में रखे",
|
||||||
|
"@viewDialogGroupSectionTitle": {},
|
||||||
|
"videoStreamSelectionDialogAudio": "ऑडियो",
|
||||||
|
"@videoStreamSelectionDialogAudio": {},
|
||||||
|
"videoStreamSelectionDialogTrack": "ट्रैक",
|
||||||
|
"@videoStreamSelectionDialogTrack": {},
|
||||||
|
"genericSuccessFeedback": "हो गया!",
|
||||||
|
"@genericSuccessFeedback": {},
|
||||||
|
"menuActionMap": "मैप",
|
||||||
|
"@menuActionMap": {},
|
||||||
|
"aboutLinkLicense": "लाइसेंस",
|
||||||
|
"@aboutLinkLicense": {},
|
||||||
|
"editEntryDateDialogSourceFileModifiedDate": "फ़ाइल संशोधित दिनांक",
|
||||||
|
"@editEntryDateDialogSourceFileModifiedDate": {},
|
||||||
|
"coverDialogTabApp": "ऐप",
|
||||||
|
"@coverDialogTabApp": {},
|
||||||
|
"coverDialogTabCover": "ढखें",
|
||||||
|
"@coverDialogTabCover": {},
|
||||||
|
"aboutBugReportButton": "रिपोर्ट दे",
|
||||||
|
"@aboutBugReportButton": {},
|
||||||
|
"deleteSingleAlbumConfirmationDialogMessage": "{count, plural, =1{यह एल्बम और इसमें मौजूद आइटम हटाएं?} other{यह एल्बम और इसमें मौजूद {count} हटाएं?}}",
|
||||||
|
"@deleteSingleAlbumConfirmationDialogMessage": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deleteMultiAlbumConfirmationDialogMessage": "{count, plural, =1{ये एल्बम और उनमें मौजूद आइटम हटाएं?} other{ये एल्बम और उनमें मौजूद {count} आइटम हटाएं?}}",
|
||||||
|
"@deleteMultiAlbumConfirmationDialogMessage": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"menuActionSelect": "चूने",
|
||||||
|
"@menuActionSelect": {},
|
||||||
|
"genericDangerWarningDialogMessage": "क्या आपको यकीन है?",
|
||||||
|
"@genericDangerWarningDialogMessage": {},
|
||||||
|
"tooManyItemsErrorDialogMessage": "कम आइटम के साथ पुनः प्रयास करें।",
|
||||||
|
"@tooManyItemsErrorDialogMessage": {},
|
||||||
|
"menuActionSelectAll": "सभी चुने",
|
||||||
|
"@menuActionSelectAll": {},
|
||||||
|
"menuActionSelectNone": "कुछ मत चुने",
|
||||||
|
"@menuActionSelectNone": {},
|
||||||
|
"tileLayoutGrid": "ग्रिड",
|
||||||
|
"@tileLayoutGrid": {},
|
||||||
|
"tileLayoutList": "सूची",
|
||||||
|
"@tileLayoutList": {},
|
||||||
|
"castDialogTitle": "कास्ट डिवाइस",
|
||||||
|
"@castDialogTitle": {},
|
||||||
|
"coverDialogTabColor": "रंग",
|
||||||
|
"@coverDialogTabColor": {},
|
||||||
|
"appPickDialogTitle": "ऐप चुनें",
|
||||||
|
"@appPickDialogTitle": {},
|
||||||
|
"aboutBugCopyInfoButton": "कोपी",
|
||||||
|
"@aboutBugCopyInfoButton": {},
|
||||||
|
"aboutBugReportInstruction": "लॉग और सिस्टम जानकारी के साथ GitHub पर रिपोर्ट करें",
|
||||||
|
"@aboutBugReportInstruction": {},
|
||||||
|
"aboutBugCopyInfoInstruction": "सिस्टम जानकारी कॉपी करें",
|
||||||
|
"@aboutBugCopyInfoInstruction": {},
|
||||||
|
"videoStreamSelectionDialogOff": "बंद",
|
||||||
|
"@videoStreamSelectionDialogOff": {},
|
||||||
|
"aboutBugSectionTitle": "बग रिपोर्ट",
|
||||||
|
"@aboutBugSectionTitle": {},
|
||||||
|
"aboutLinkPolicy": "गोपनीयता नीति",
|
||||||
|
"@aboutLinkPolicy": {},
|
||||||
|
"menuActionConfigureView": "देखें",
|
||||||
|
"@menuActionConfigureView": {},
|
||||||
|
"menuActionStats": "आँकड़े",
|
||||||
|
"@menuActionStats": {},
|
||||||
|
"aboutBugSaveLogInstruction": "ऐप लॉग को फ़ाइल में सहेजें",
|
||||||
|
"@aboutBugSaveLogInstruction": {},
|
||||||
|
"aboutDataUsageSectionTitle": "डेटा उपयोग",
|
||||||
|
"@aboutDataUsageSectionTitle": {},
|
||||||
|
"aboutDataUsageData": "डेटा",
|
||||||
|
"@aboutDataUsageData": {},
|
||||||
|
"aboutDataUsageCache": "कैश",
|
||||||
|
"@aboutDataUsageCache": {},
|
||||||
|
"aboutDataUsageDatabase": "डेटाबेस",
|
||||||
|
"@aboutDataUsageDatabase": {},
|
||||||
|
"editorActionTransform": "परिवर्तन",
|
||||||
|
"@editorActionTransform": {},
|
||||||
|
"videoStreamSelectionDialogNoSelection": "कोई अन्य ट्रैक नहीं हैं।",
|
||||||
|
"@videoStreamSelectionDialogNoSelection": {},
|
||||||
|
"viewDialogLayoutSectionTitle": "लेआउट",
|
||||||
|
"@viewDialogLayoutSectionTitle": {},
|
||||||
|
"appPickDialogNone": "कोई नहीं",
|
||||||
|
"@appPickDialogNone": {},
|
||||||
|
"aboutPageTitle": "बारे में",
|
||||||
|
"@aboutPageTitle": {},
|
||||||
|
"collectionEditFailureFeedback": "{count, plural, =1{1 आइटम एडिट करने में विफल} other{{count} आइटम एडिट करने में विफल}}",
|
||||||
|
"@collectionEditFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"drawerCollectionVideos": "वीडियो",
|
||||||
|
"@drawerCollectionVideos": {},
|
||||||
|
"collectionActionSetHome": "घर के रूप में सेट करें",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"collectionActionMove": "एल्बम पर जाएँ",
|
||||||
|
"@collectionActionMove": {},
|
||||||
|
"collectionActionRescan": "पुन: स्कैन करे",
|
||||||
|
"@collectionActionRescan": {},
|
||||||
|
"collectionGroupDay": "दिन के अनुसार",
|
||||||
|
"@collectionGroupDay": {},
|
||||||
|
"collectionCopySuccessFeedback": "{count, plural, =1{1 आइटम कॉपी किया गया} other{{count} आइटम कॉपी किए गए}}",
|
||||||
|
"@collectionCopySuccessFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionEmptyImages": "कोई इमेज नहीं",
|
||||||
|
"@collectionEmptyImages": {},
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "पहुंच प्रदान करें",
|
||||||
|
"@collectionEmptyGrantAccessButtonLabel": {},
|
||||||
|
"collectionActionAddShortcut": "शॉर्टकट जोड़ें",
|
||||||
|
"@collectionActionAddShortcut": {},
|
||||||
|
"collectionRenameFailureFeedback": "{count, plural, =1{1 आइटम का नाम बदलने में विफल} other{{count} आइटम का नाम बदलने में विफल}}",
|
||||||
|
"@collectionRenameFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"drawerCollectionAnimated": "एनिमेटेड",
|
||||||
|
"@drawerCollectionAnimated": {},
|
||||||
|
"aboutCreditsSectionTitle": "क्रेडिट",
|
||||||
|
"@aboutCreditsSectionTitle": {},
|
||||||
|
"aboutLicensesSectionTitle": "ओपन सोर्स लाइसेंस",
|
||||||
|
"@aboutLicensesSectionTitle": {},
|
||||||
|
"aboutLicensesFlutterPackagesSectionTitle": "फ्लटर पैकेज",
|
||||||
|
"@aboutLicensesFlutterPackagesSectionTitle": {},
|
||||||
|
"aboutLicensesShowAllButtonLabel": "सभी लाइसेंस दिखाएं",
|
||||||
|
"@aboutLicensesShowAllButtonLabel": {},
|
||||||
|
"policyPageTitle": "गोपनीयता नीति",
|
||||||
|
"@policyPageTitle": {},
|
||||||
|
"collectionActionEmptyBin": "बीन खाली करे",
|
||||||
|
"@collectionActionEmptyBin": {},
|
||||||
|
"collectionActionCopy": "एल्बम में कॉपी करें",
|
||||||
|
"@collectionActionCopy": {},
|
||||||
|
"collectionGroupAlbum": "एल्बम के अनुसार",
|
||||||
|
"@collectionGroupAlbum": {},
|
||||||
|
"aboutCreditsWorldAtlas1": "यह ऐप TopoJSON फ़ाइल का उपयोग करता है",
|
||||||
|
"@aboutCreditsWorldAtlas1": {},
|
||||||
|
"aboutCreditsWorldAtlas2": "आईएससी लाइसेंस के तहत।",
|
||||||
|
"@aboutCreditsWorldAtlas2": {},
|
||||||
|
"collectionPageTitle": "संग्रह",
|
||||||
|
"@collectionPageTitle": {},
|
||||||
|
"collectionGroupMonth": "महीने के अनुसार",
|
||||||
|
"@collectionGroupMonth": {},
|
||||||
|
"collectionGroupNone": "समूह न बनाएं",
|
||||||
|
"@collectionGroupNone": {},
|
||||||
|
"sectionUnknown": "अज्ञात",
|
||||||
|
"@sectionUnknown": {},
|
||||||
|
"dateYesterday": "कल",
|
||||||
|
"@dateYesterday": {},
|
||||||
|
"dateThisMonth": "इस महीने",
|
||||||
|
"@dateThisMonth": {},
|
||||||
|
"collectionDeleteFailureFeedback": "{count, plural, =1{1 आइटम हटाने में विफल} other{{count} आइटम हटाने में विफल}}",
|
||||||
|
"@collectionDeleteFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionExportFailureFeedback": "{count, plural, =1{1 पन्ना निर्यात करने में विफल} other{{count} पन्ने निर्यात करने में विफल}}",
|
||||||
|
"@collectionExportFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionRenameSuccessFeedback": "{count, plural, =1{1 आइटम का नाम बदला गया} other{{count} आइटम का नाम बदला गया}}",
|
||||||
|
"@collectionRenameSuccessFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aboutLicensesAndroidLibrariesSectionTitle": "एंड्रॉइड लाइब्रेरीज़",
|
||||||
|
"@aboutLicensesAndroidLibrariesSectionTitle": {},
|
||||||
|
"dateToday": "आज",
|
||||||
|
"@dateToday": {},
|
||||||
|
"collectionActionHideTitleSearch": "शीर्षक फ़िल्टर छुपाएं",
|
||||||
|
"@collectionActionHideTitleSearch": {},
|
||||||
|
"drawerCollectionFavourites": "पसंदीदा",
|
||||||
|
"@drawerCollectionFavourites": {},
|
||||||
|
"drawerCollectionMotionPhotos": "मोशन तस्वीरें",
|
||||||
|
"@drawerCollectionMotionPhotos": {},
|
||||||
|
"collectionMoveFailureFeedback": "{count, plural, =1{1 आइटम ले जाने में विफल} other{{count} आइटम ले जाने में विफल}}",
|
||||||
|
"@collectionMoveFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionEditSuccessFeedback": "{count, plural, =1{1 आइटम संपादित किया गया} other{{count} आइटम संपादित किए गए}}",
|
||||||
|
"@collectionEditSuccessFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionEmptyFavourites": "कोई पसंदीदा नहीं",
|
||||||
|
"@collectionEmptyFavourites": {},
|
||||||
|
"aboutDataUsageClearCache": "कैश साफ़ करें",
|
||||||
|
"@aboutDataUsageClearCache": {},
|
||||||
|
"aboutTranslatorsSectionTitle": "अनुवादक",
|
||||||
|
"@aboutTranslatorsSectionTitle": {},
|
||||||
|
"aboutLicensesBanner": "यह ऐप निम्नलिखित ओपन सोर्स पैकेज और पुस्तकालयों का उपयोग करता है।",
|
||||||
|
"@aboutLicensesBanner": {},
|
||||||
|
"aboutLicensesFlutterPluginsSectionTitle": "फ्लटर प्लगइन्स",
|
||||||
|
"@aboutLicensesFlutterPluginsSectionTitle": {},
|
||||||
|
"aboutLicensesDartPackagesSectionTitle": "डार्ट पैकेज",
|
||||||
|
"@aboutLicensesDartPackagesSectionTitle": {},
|
||||||
|
"collectionCopyFailureFeedback": "{count, plural, =1{1 आइटम कॉपी करने में विफल} other{{count} आइटम कॉपी करने में विफल}}",
|
||||||
|
"@collectionCopyFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aboutDataUsageInternal": "आंतरिक",
|
||||||
|
"@aboutDataUsageInternal": {},
|
||||||
|
"aboutDataUsageExternal": "बाहरी",
|
||||||
|
"@aboutDataUsageExternal": {},
|
||||||
|
"collectionSelectPageTitle": "आइटम चुनें",
|
||||||
|
"@collectionSelectPageTitle": {},
|
||||||
|
"collectionActionShowTitleSearch": "शीर्षक फ़िल्टर दिखाएं",
|
||||||
|
"@collectionActionShowTitleSearch": {},
|
||||||
|
"collectionActionEdit": "एडिट करे",
|
||||||
|
"@collectionActionEdit": {},
|
||||||
|
"collectionSearchTitlesHintText": "शीर्षक खोजें",
|
||||||
|
"@collectionSearchTitlesHintText": {},
|
||||||
|
"collectionMoveSuccessFeedback": "{count, plural, =1{1 आइटम स्थानांतरित किया गया} other{{count} आइटम स्थानांतरित किए गए}}",
|
||||||
|
"@collectionMoveSuccessFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"format": "decimalPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionEmptyVideos": "कोई वीडियो नहीं",
|
||||||
|
"@collectionEmptyVideos": {},
|
||||||
|
"collectionSelectSectionTooltip": "अनुभाग चुनें",
|
||||||
|
"@collectionSelectSectionTooltip": {},
|
||||||
|
"collectionDeselectSectionTooltip": "अनुभाग का चयन रद्द करें",
|
||||||
|
"@collectionDeselectSectionTooltip": {},
|
||||||
|
"drawerAboutButton": "के बारे में",
|
||||||
|
"@drawerAboutButton": {},
|
||||||
|
"drawerSettingsButton": "सेटिंग्स",
|
||||||
|
"@drawerSettingsButton": {},
|
||||||
|
"drawerCollectionAll": "सभी संग्रह",
|
||||||
|
"@drawerCollectionAll": {},
|
||||||
|
"drawerCollectionImages": "इमेजेस",
|
||||||
|
"@drawerCollectionImages": {},
|
||||||
|
"aboutDataUsageMisc": "विविध",
|
||||||
|
"@aboutDataUsageMisc": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1467,7 +1467,7 @@
|
||||||
"@settingsVideoBackgroundModeDialogTitle": {},
|
"@settingsVideoBackgroundModeDialogTitle": {},
|
||||||
"tagEditorDiscardDialogMessage": "Forkast endringer?",
|
"tagEditorDiscardDialogMessage": "Forkast endringer?",
|
||||||
"@tagEditorDiscardDialogMessage": {},
|
"@tagEditorDiscardDialogMessage": {},
|
||||||
"tagPlaceholderState": "Tilstand?",
|
"tagPlaceholderState": "Delstat",
|
||||||
"@tagPlaceholderState": {},
|
"@tagPlaceholderState": {},
|
||||||
"chipActionShowCountryStates": "Vis tilstander",
|
"chipActionShowCountryStates": "Vis tilstander",
|
||||||
"@chipActionShowCountryStates": {},
|
"@chipActionShowCountryStates": {},
|
||||||
|
|
1
lib/l10n/app_sr.arb
Normal file
1
lib/l10n/app_sr.arb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -7,7 +7,7 @@
|
||||||
"@videoActionPlay": {},
|
"@videoActionPlay": {},
|
||||||
"viewerActionSettings": "Inställningar",
|
"viewerActionSettings": "Inställningar",
|
||||||
"@viewerActionSettings": {},
|
"@viewerActionSettings": {},
|
||||||
"albumTierSpecial": "Vanligt förekommande",
|
"albumTierSpecial": "Vanliga",
|
||||||
"@albumTierSpecial": {},
|
"@albumTierSpecial": {},
|
||||||
"displayRefreshRatePreferLowest": "Lägsta intervall",
|
"displayRefreshRatePreferLowest": "Lägsta intervall",
|
||||||
"@displayRefreshRatePreferLowest": {},
|
"@displayRefreshRatePreferLowest": {},
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
"@chipActionRename": {},
|
"@chipActionRename": {},
|
||||||
"chipActionSetCover": "Välj som omslag",
|
"chipActionSetCover": "Välj som omslag",
|
||||||
"@chipActionSetCover": {},
|
"@chipActionSetCover": {},
|
||||||
"chipActionShowCountryStates": "Visa landskap",
|
"chipActionShowCountryStates": "Visa delstater",
|
||||||
"@chipActionShowCountryStates": {},
|
"@chipActionShowCountryStates": {},
|
||||||
"chipActionCreateAlbum": "Skapa album",
|
"chipActionCreateAlbum": "Skapa album",
|
||||||
"@chipActionCreateAlbum": {},
|
"@chipActionCreateAlbum": {},
|
||||||
|
@ -216,7 +216,7 @@
|
||||||
"@entryInfoActionEditDate": {},
|
"@entryInfoActionEditDate": {},
|
||||||
"entryInfoActionEditLocation": "Redigera plats",
|
"entryInfoActionEditLocation": "Redigera plats",
|
||||||
"@entryInfoActionEditLocation": {},
|
"@entryInfoActionEditLocation": {},
|
||||||
"entryInfoActionEditTitleDescription": "Redigera filnamn och beskrivning",
|
"entryInfoActionEditTitleDescription": "Redigera titel & beskrivning",
|
||||||
"@entryInfoActionEditTitleDescription": {},
|
"@entryInfoActionEditTitleDescription": {},
|
||||||
"entryInfoActionEditRating": "Redigera omdöme",
|
"entryInfoActionEditRating": "Redigera omdöme",
|
||||||
"@entryInfoActionEditRating": {},
|
"@entryInfoActionEditRating": {},
|
||||||
|
@ -337,7 +337,7 @@
|
||||||
"@mapStyleGoogleTerrain": {},
|
"@mapStyleGoogleTerrain": {},
|
||||||
"mapStyleStamenWatercolor": "Stamen Watercolor (Akvarell)",
|
"mapStyleStamenWatercolor": "Stamen Watercolor (Akvarell)",
|
||||||
"@mapStyleStamenWatercolor": {},
|
"@mapStyleStamenWatercolor": {},
|
||||||
"maxBrightnessNever": "Alldrig",
|
"maxBrightnessNever": "Aldrig",
|
||||||
"@maxBrightnessNever": {},
|
"@maxBrightnessNever": {},
|
||||||
"maxBrightnessAlways": "Alltid",
|
"maxBrightnessAlways": "Alltid",
|
||||||
"@maxBrightnessAlways": {},
|
"@maxBrightnessAlways": {},
|
||||||
|
@ -395,7 +395,7 @@
|
||||||
"@videoPlaybackMuted": {},
|
"@videoPlaybackMuted": {},
|
||||||
"videoPlaybackWithSound": "Spela med ljud",
|
"videoPlaybackWithSound": "Spela med ljud",
|
||||||
"@videoPlaybackWithSound": {},
|
"@videoPlaybackWithSound": {},
|
||||||
"videoResumptionModeNever": "Alldrig",
|
"videoResumptionModeNever": "Aldrig",
|
||||||
"@videoResumptionModeNever": {},
|
"@videoResumptionModeNever": {},
|
||||||
"viewerTransitionSlide": "Glid",
|
"viewerTransitionSlide": "Glid",
|
||||||
"@viewerTransitionSlide": {},
|
"@viewerTransitionSlide": {},
|
||||||
|
@ -407,7 +407,7 @@
|
||||||
"@wallpaperTargetHome": {},
|
"@wallpaperTargetHome": {},
|
||||||
"widgetDisplayedItemRandom": "Slumpartat",
|
"widgetDisplayedItemRandom": "Slumpartat",
|
||||||
"@widgetDisplayedItemRandom": {},
|
"@widgetDisplayedItemRandom": {},
|
||||||
"widgetDisplayedItemMostRecent": "Senaste",
|
"widgetDisplayedItemMostRecent": "Det senaste",
|
||||||
"@widgetDisplayedItemMostRecent": {},
|
"@widgetDisplayedItemMostRecent": {},
|
||||||
"widgetOpenPageHome": "Öppna startsida",
|
"widgetOpenPageHome": "Öppna startsida",
|
||||||
"@widgetOpenPageHome": {},
|
"@widgetOpenPageHome": {},
|
||||||
|
@ -449,7 +449,7 @@
|
||||||
"@hideFilterConfirmationDialogMessage": {},
|
"@hideFilterConfirmationDialogMessage": {},
|
||||||
"newAlbumDialogTitle": "Nytt Album",
|
"newAlbumDialogTitle": "Nytt Album",
|
||||||
"@newAlbumDialogTitle": {},
|
"@newAlbumDialogTitle": {},
|
||||||
"newAlbumDialogNameLabelAlreadyExistsHelper": "Mappen existerar redan",
|
"newAlbumDialogNameLabelAlreadyExistsHelper": "Katalogen existerar redan",
|
||||||
"@newAlbumDialogNameLabelAlreadyExistsHelper": {},
|
"@newAlbumDialogNameLabelAlreadyExistsHelper": {},
|
||||||
"newAlbumDialogStorageLabel": "Lagring:",
|
"newAlbumDialogStorageLabel": "Lagring:",
|
||||||
"@newAlbumDialogStorageLabel": {},
|
"@newAlbumDialogStorageLabel": {},
|
||||||
|
@ -475,7 +475,7 @@
|
||||||
"@welcomeMessage": {},
|
"@welcomeMessage": {},
|
||||||
"nextButtonLabel": "NÄSTA",
|
"nextButtonLabel": "NÄSTA",
|
||||||
"@nextButtonLabel": {},
|
"@nextButtonLabel": {},
|
||||||
"nextTooltip": "Nästs",
|
"nextTooltip": "Nästa",
|
||||||
"@nextTooltip": {},
|
"@nextTooltip": {},
|
||||||
"doNotAskAgain": "Fråga inte igen",
|
"doNotAskAgain": "Fråga inte igen",
|
||||||
"@doNotAskAgain": {},
|
"@doNotAskAgain": {},
|
||||||
|
@ -546,7 +546,7 @@
|
||||||
"@patternDialogEnter": {},
|
"@patternDialogEnter": {},
|
||||||
"patternDialogConfirm": "Bekräfta mönster",
|
"patternDialogConfirm": "Bekräfta mönster",
|
||||||
"@patternDialogConfirm": {},
|
"@patternDialogConfirm": {},
|
||||||
"renameEntrySetPagePatternFieldLabel": "Namnge mönster",
|
"renameEntrySetPagePatternFieldLabel": "Namngivningsmönster",
|
||||||
"@renameEntrySetPagePatternFieldLabel": {},
|
"@renameEntrySetPagePatternFieldLabel": {},
|
||||||
"renameEntrySetPageInsertTooltip": "Infoga fällt",
|
"renameEntrySetPageInsertTooltip": "Infoga fällt",
|
||||||
"@renameEntrySetPageInsertTooltip": {},
|
"@renameEntrySetPageInsertTooltip": {},
|
||||||
|
@ -570,7 +570,7 @@
|
||||||
"@editEntryDialogCopyFromItem": {},
|
"@editEntryDialogCopyFromItem": {},
|
||||||
"editEntryDateDialogTitle": "Datum & Tid",
|
"editEntryDateDialogTitle": "Datum & Tid",
|
||||||
"@editEntryDateDialogTitle": {},
|
"@editEntryDateDialogTitle": {},
|
||||||
"editEntryDateDialogExtractFromTitle": "Kopiera från filnamn",
|
"editEntryDateDialogExtractFromTitle": "Extrahera från titel",
|
||||||
"@editEntryDateDialogExtractFromTitle": {},
|
"@editEntryDateDialogExtractFromTitle": {},
|
||||||
"editEntryDateDialogShift": "Förskjut",
|
"editEntryDateDialogShift": "Förskjut",
|
||||||
"@editEntryDateDialogShift": {},
|
"@editEntryDateDialogShift": {},
|
||||||
|
@ -654,7 +654,7 @@
|
||||||
"@collectionActionMove": {},
|
"@collectionActionMove": {},
|
||||||
"viewDialogSortSectionTitle": "Sortera",
|
"viewDialogSortSectionTitle": "Sortera",
|
||||||
"@viewDialogSortSectionTitle": {},
|
"@viewDialogSortSectionTitle": {},
|
||||||
"viewDialogGroupSectionTitle": "Grupp",
|
"viewDialogGroupSectionTitle": "Gruppera",
|
||||||
"@viewDialogGroupSectionTitle": {},
|
"@viewDialogGroupSectionTitle": {},
|
||||||
"viewDialogLayoutSectionTitle": "Layout",
|
"viewDialogLayoutSectionTitle": "Layout",
|
||||||
"@viewDialogLayoutSectionTitle": {},
|
"@viewDialogLayoutSectionTitle": {},
|
||||||
|
@ -682,7 +682,7 @@
|
||||||
"@aboutLinkLicense": {},
|
"@aboutLinkLicense": {},
|
||||||
"aboutLinkPolicy": "IntegritetsPolicy",
|
"aboutLinkPolicy": "IntegritetsPolicy",
|
||||||
"@aboutLinkPolicy": {},
|
"@aboutLinkPolicy": {},
|
||||||
"aboutBugSectionTitle": "FelRapport",
|
"aboutBugSectionTitle": "Felrapport",
|
||||||
"@aboutBugSectionTitle": {},
|
"@aboutBugSectionTitle": {},
|
||||||
"aboutBugSaveLogInstruction": "Spara appens log till en fil",
|
"aboutBugSaveLogInstruction": "Spara appens log till en fil",
|
||||||
"@aboutBugSaveLogInstruction": {},
|
"@aboutBugSaveLogInstruction": {},
|
||||||
|
@ -692,7 +692,7 @@
|
||||||
"@aboutLicensesShowAllButtonLabel": {},
|
"@aboutLicensesShowAllButtonLabel": {},
|
||||||
"policyPageTitle": "IntegritetsPolicy",
|
"policyPageTitle": "IntegritetsPolicy",
|
||||||
"@policyPageTitle": {},
|
"@policyPageTitle": {},
|
||||||
"collectionActionHideTitleSearch": "Göm filnamnsfilter",
|
"collectionActionHideTitleSearch": "Göm titelfilter",
|
||||||
"@collectionActionHideTitleSearch": {},
|
"@collectionActionHideTitleSearch": {},
|
||||||
"collectionActionAddShortcut": "Lägg till genväg",
|
"collectionActionAddShortcut": "Lägg till genväg",
|
||||||
"@collectionActionAddShortcut": {},
|
"@collectionActionAddShortcut": {},
|
||||||
|
@ -746,7 +746,7 @@
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"filterTaggedLabel": "Taggad",
|
"filterTaggedLabel": "Taggad",
|
||||||
"@filterTaggedLabel": {},
|
"@filterTaggedLabel": {},
|
||||||
"keepScreenOnNever": "Alldrig",
|
"keepScreenOnNever": "Aldrig",
|
||||||
"@keepScreenOnNever": {},
|
"@keepScreenOnNever": {},
|
||||||
"viewerTransitionFade": "Tona ut",
|
"viewerTransitionFade": "Tona ut",
|
||||||
"@viewerTransitionFade": {},
|
"@viewerTransitionFade": {},
|
||||||
|
@ -905,7 +905,7 @@
|
||||||
"@editEntryDateDialogCopyField": {},
|
"@editEntryDateDialogCopyField": {},
|
||||||
"castDialogTitle": "Uppspelningsenheter",
|
"castDialogTitle": "Uppspelningsenheter",
|
||||||
"@castDialogTitle": {},
|
"@castDialogTitle": {},
|
||||||
"renameEntrySetPageTitle": "Döpa om",
|
"renameEntrySetPageTitle": "Ändra namn",
|
||||||
"@renameEntrySetPageTitle": {},
|
"@renameEntrySetPageTitle": {},
|
||||||
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Vill du ta bort denna fil?} other{Vill du ta bort dessa {count} filer?}}",
|
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Vill du ta bort denna fil?} other{Vill du ta bort dessa {count} filer?}}",
|
||||||
"@deleteEntriesConfirmationDialogMessage": {
|
"@deleteEntriesConfirmationDialogMessage": {
|
||||||
|
@ -921,7 +921,7 @@
|
||||||
"@renameAlbumDialogLabelAlreadyExistsHelper": {},
|
"@renameAlbumDialogLabelAlreadyExistsHelper": {},
|
||||||
"aboutLicensesDartPackagesSectionTitle": "Dart-paket",
|
"aboutLicensesDartPackagesSectionTitle": "Dart-paket",
|
||||||
"@aboutLicensesDartPackagesSectionTitle": {},
|
"@aboutLicensesDartPackagesSectionTitle": {},
|
||||||
"collectionActionShowTitleSearch": "Filtrera på filnamn",
|
"collectionActionShowTitleSearch": "Visa titelfilter",
|
||||||
"@collectionActionShowTitleSearch": {},
|
"@collectionActionShowTitleSearch": {},
|
||||||
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Flytta denna fil tillpapperskorgen?} other{Flytta dessa {count} filer till papperskorgen?}}",
|
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Flytta denna fil tillpapperskorgen?} other{Flytta dessa {count} filer till papperskorgen?}}",
|
||||||
"@binEntriesConfirmationDialogMessage": {
|
"@binEntriesConfirmationDialogMessage": {
|
||||||
|
@ -991,11 +991,11 @@
|
||||||
"@albumPickPageTitleMove": {},
|
"@albumPickPageTitleMove": {},
|
||||||
"albumPickPageTitlePick": "Välj Album",
|
"albumPickPageTitlePick": "Välj Album",
|
||||||
"@albumPickPageTitlePick": {},
|
"@albumPickPageTitlePick": {},
|
||||||
"statePageTitle": "Landskap",
|
"statePageTitle": "Delstater",
|
||||||
"@statePageTitle": {},
|
"@statePageTitle": {},
|
||||||
"countryEmpty": "Inga länder",
|
"countryEmpty": "Inga länder",
|
||||||
"@countryEmpty": {},
|
"@countryEmpty": {},
|
||||||
"stateEmpty": "Inga landskap",
|
"stateEmpty": "Inga delstater",
|
||||||
"@stateEmpty": {},
|
"@stateEmpty": {},
|
||||||
"placePageTitle": "Platser",
|
"placePageTitle": "Platser",
|
||||||
"@placePageTitle": {},
|
"@placePageTitle": {},
|
||||||
|
@ -1057,9 +1057,9 @@
|
||||||
"@tagEmpty": {},
|
"@tagEmpty": {},
|
||||||
"binPageTitle": "Papperskorgen",
|
"binPageTitle": "Papperskorgen",
|
||||||
"@binPageTitle": {},
|
"@binPageTitle": {},
|
||||||
"explorerActionSelectStorageVolume": "Välj lagringsplatts",
|
"explorerActionSelectStorageVolume": "Välj lagringsplats",
|
||||||
"@explorerActionSelectStorageVolume": {},
|
"@explorerActionSelectStorageVolume": {},
|
||||||
"selectStorageVolumeDialogTitle": "Välj Lagringsplatts",
|
"selectStorageVolumeDialogTitle": "Välj Lagringsplats",
|
||||||
"@selectStorageVolumeDialogTitle": {},
|
"@selectStorageVolumeDialogTitle": {},
|
||||||
"collectionEditSuccessFeedback": "{count, plural, =1{Ändrat 1 objekt} other{Ändrat {count} objekt}}",
|
"collectionEditSuccessFeedback": "{count, plural, =1{Ändrat 1 objekt} other{Ändrat {count} objekt}}",
|
||||||
"@collectionEditSuccessFeedback": {
|
"@collectionEditSuccessFeedback": {
|
||||||
|
@ -1089,7 +1089,7 @@
|
||||||
"@searchDateSectionTitle": {},
|
"@searchDateSectionTitle": {},
|
||||||
"searchAlbumsSectionTitle": "Album",
|
"searchAlbumsSectionTitle": "Album",
|
||||||
"@searchAlbumsSectionTitle": {},
|
"@searchAlbumsSectionTitle": {},
|
||||||
"searchStatesSectionTitle": "Landskap",
|
"searchStatesSectionTitle": "Delstater",
|
||||||
"@searchStatesSectionTitle": {},
|
"@searchStatesSectionTitle": {},
|
||||||
"albumPickPageTitleExport": "Exportera till Album",
|
"albumPickPageTitleExport": "Exportera till Album",
|
||||||
"@albumPickPageTitleExport": {},
|
"@albumPickPageTitleExport": {},
|
||||||
|
@ -1201,9 +1201,9 @@
|
||||||
"@settingsViewerShowMinimap": {},
|
"@settingsViewerShowMinimap": {},
|
||||||
"settingsViewerShowInformation": "Visa information",
|
"settingsViewerShowInformation": "Visa information",
|
||||||
"@settingsViewerShowInformation": {},
|
"@settingsViewerShowInformation": {},
|
||||||
"settingsViewerShowInformationSubtitle": "Visa filnamn, datum, plats osv …",
|
"settingsViewerShowInformationSubtitle": "Visa titel, datum, plats, etc.",
|
||||||
"@settingsViewerShowInformationSubtitle": {},
|
"@settingsViewerShowInformationSubtitle": {},
|
||||||
"settingsViewerShowOverlayThumbnails": "Visa minityrbilder",
|
"settingsViewerShowOverlayThumbnails": "Visa miniatyrbilder",
|
||||||
"@settingsViewerShowOverlayThumbnails": {},
|
"@settingsViewerShowOverlayThumbnails": {},
|
||||||
"settingsViewerShowDescription": "Visa beskrivning",
|
"settingsViewerShowDescription": "Visa beskrivning",
|
||||||
"@settingsViewerShowDescription": {},
|
"@settingsViewerShowDescription": {},
|
||||||
|
@ -1287,7 +1287,7 @@
|
||||||
"@settingsWidgetDisplayedItem": {},
|
"@settingsWidgetDisplayedItem": {},
|
||||||
"statsPageTitle": "Statistik",
|
"statsPageTitle": "Statistik",
|
||||||
"@statsPageTitle": {},
|
"@statsPageTitle": {},
|
||||||
"statsTopCountriesSectionTitle": "Vanligast Länder",
|
"statsTopCountriesSectionTitle": "Populära Länder",
|
||||||
"@statsTopCountriesSectionTitle": {},
|
"@statsTopCountriesSectionTitle": {},
|
||||||
"settingsCollectionTile": "Samling",
|
"settingsCollectionTile": "Samling",
|
||||||
"@settingsCollectionTile": {},
|
"@settingsCollectionTile": {},
|
||||||
|
@ -1301,7 +1301,7 @@
|
||||||
"@viewerErrorDoesNotExist": {},
|
"@viewerErrorDoesNotExist": {},
|
||||||
"viewerInfoPageTitle": "Info",
|
"viewerInfoPageTitle": "Info",
|
||||||
"@viewerInfoPageTitle": {},
|
"@viewerInfoPageTitle": {},
|
||||||
"viewerInfoLabelTitle": "Filnamn",
|
"viewerInfoLabelTitle": "Titel",
|
||||||
"@viewerInfoLabelTitle": {},
|
"@viewerInfoLabelTitle": {},
|
||||||
"viewerInfoLabelDate": "Datum",
|
"viewerInfoLabelDate": "Datum",
|
||||||
"@viewerInfoLabelDate": {},
|
"@viewerInfoLabelDate": {},
|
||||||
|
@ -1391,9 +1391,9 @@
|
||||||
"@settingsCollectionQuickActionEditorPageTitle": {},
|
"@settingsCollectionQuickActionEditorPageTitle": {},
|
||||||
"settingsCollectionSelectionQuickActionEditorBanner": "Tryck och håll nere för att flytta knappar och välj på så vis vilka åtgärder som skall visas när objekt väljs.",
|
"settingsCollectionSelectionQuickActionEditorBanner": "Tryck och håll nere för att flytta knappar och välj på så vis vilka åtgärder som skall visas när objekt väljs.",
|
||||||
"@settingsCollectionSelectionQuickActionEditorBanner": {},
|
"@settingsCollectionSelectionQuickActionEditorBanner": {},
|
||||||
"settingsCollectionBurstPatternsTile": "Namngivningsmönster",
|
"settingsCollectionBurstPatternsTile": "Seriefotograferingsmönster",
|
||||||
"@settingsCollectionBurstPatternsTile": {},
|
"@settingsCollectionBurstPatternsTile": {},
|
||||||
"settingsCollectionBurstPatternsNone": "Ingen",
|
"settingsCollectionBurstPatternsNone": "Inget",
|
||||||
"@settingsCollectionBurstPatternsNone": {},
|
"@settingsCollectionBurstPatternsNone": {},
|
||||||
"settingsViewerSectionTitle": "Bildvisare",
|
"settingsViewerSectionTitle": "Bildvisare",
|
||||||
"@settingsViewerSectionTitle": {},
|
"@settingsViewerSectionTitle": {},
|
||||||
|
@ -1403,7 +1403,7 @@
|
||||||
"@settingsViewerUseCutout": {},
|
"@settingsViewerUseCutout": {},
|
||||||
"settingsViewerMaximumBrightness": "Maximal ljusstyrka",
|
"settingsViewerMaximumBrightness": "Maximal ljusstyrka",
|
||||||
"@settingsViewerMaximumBrightness": {},
|
"@settingsViewerMaximumBrightness": {},
|
||||||
"settingsMotionPhotoAutoPlay": "Spela automatiskt upp Rörelsefoton",
|
"settingsMotionPhotoAutoPlay": "Spela automatiskt upp rörelsefoton",
|
||||||
"@settingsMotionPhotoAutoPlay": {},
|
"@settingsMotionPhotoAutoPlay": {},
|
||||||
"settingsImageBackground": "Bakgrund för bilder",
|
"settingsImageBackground": "Bakgrund för bilder",
|
||||||
"@settingsImageBackground": {},
|
"@settingsImageBackground": {},
|
||||||
|
@ -1419,7 +1419,7 @@
|
||||||
"@settingsViewerQuickActionEditorAvailableButtonsSectionTitle": {},
|
"@settingsViewerQuickActionEditorAvailableButtonsSectionTitle": {},
|
||||||
"settingsViewerQuickActionEmpty": "Inga knappar",
|
"settingsViewerQuickActionEmpty": "Inga knappar",
|
||||||
"@settingsViewerQuickActionEmpty": {},
|
"@settingsViewerQuickActionEmpty": {},
|
||||||
"settingsViewerOverlayTile": "Överblick",
|
"settingsViewerOverlayTile": "Overlay",
|
||||||
"@settingsViewerOverlayTile": {},
|
"@settingsViewerOverlayTile": {},
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Effekt för oskärpa",
|
"settingsViewerEnableOverlayBlurEffect": "Effekt för oskärpa",
|
||||||
"@settingsViewerEnableOverlayBlurEffect": {},
|
"@settingsViewerEnableOverlayBlurEffect": {},
|
||||||
|
@ -1467,7 +1467,7 @@
|
||||||
"@settingsHiddenItemsTabFilters": {},
|
"@settingsHiddenItemsTabFilters": {},
|
||||||
"settingsHiddenFiltersEmpty": "Inga dolda filter",
|
"settingsHiddenFiltersEmpty": "Inga dolda filter",
|
||||||
"@settingsHiddenFiltersEmpty": {},
|
"@settingsHiddenFiltersEmpty": {},
|
||||||
"addPathTooltip": "Lägg till katalog",
|
"addPathTooltip": "Lägg till sökväg",
|
||||||
"@addPathTooltip": {},
|
"@addPathTooltip": {},
|
||||||
"settingsRemoveAnimationsTile": "Inaktivera animationer",
|
"settingsRemoveAnimationsTile": "Inaktivera animationer",
|
||||||
"@settingsRemoveAnimationsTile": {},
|
"@settingsRemoveAnimationsTile": {},
|
||||||
|
@ -1507,7 +1507,7 @@
|
||||||
"@settingsEnableBin": {},
|
"@settingsEnableBin": {},
|
||||||
"settingsEnableBinSubtitle": "Behåll borttagna objekt i 30 dagar",
|
"settingsEnableBinSubtitle": "Behåll borttagna objekt i 30 dagar",
|
||||||
"@settingsEnableBinSubtitle": {},
|
"@settingsEnableBinSubtitle": {},
|
||||||
"settingsViewerOverlayPageTitle": "Överblick",
|
"settingsViewerOverlayPageTitle": "Overlay",
|
||||||
"@settingsViewerOverlayPageTitle": {},
|
"@settingsViewerOverlayPageTitle": {},
|
||||||
"settingsHomeTile": "Startsida",
|
"settingsHomeTile": "Startsida",
|
||||||
"@settingsHomeTile": {},
|
"@settingsHomeTile": {},
|
||||||
|
@ -1531,13 +1531,13 @@
|
||||||
"@settingsUnitSystemDialogTitle": {},
|
"@settingsUnitSystemDialogTitle": {},
|
||||||
"settingsScreenSaverPageTitle": "Skärmsläckare",
|
"settingsScreenSaverPageTitle": "Skärmsläckare",
|
||||||
"@settingsScreenSaverPageTitle": {},
|
"@settingsScreenSaverPageTitle": {},
|
||||||
"statsTopStatesSectionTitle": "Vanligast Delstater",
|
"statsTopStatesSectionTitle": "Populära Delstater",
|
||||||
"@statsTopStatesSectionTitle": {},
|
"@statsTopStatesSectionTitle": {},
|
||||||
"statsTopPlacesSectionTitle": "Vanligast Platser",
|
"statsTopPlacesSectionTitle": "Populära Platser",
|
||||||
"@statsTopPlacesSectionTitle": {},
|
"@statsTopPlacesSectionTitle": {},
|
||||||
"statsTopTagsSectionTitle": "Vanligast Etiketter",
|
"statsTopTagsSectionTitle": "Populära Etiketter",
|
||||||
"@statsTopTagsSectionTitle": {},
|
"@statsTopTagsSectionTitle": {},
|
||||||
"statsTopAlbumsSectionTitle": "Vanligast Album",
|
"statsTopAlbumsSectionTitle": "Populära Album",
|
||||||
"@statsTopAlbumsSectionTitle": {},
|
"@statsTopAlbumsSectionTitle": {},
|
||||||
"viewerInfoLabelResolution": "Upplösning",
|
"viewerInfoLabelResolution": "Upplösning",
|
||||||
"@viewerInfoLabelResolution": {},
|
"@viewerInfoLabelResolution": {},
|
||||||
|
@ -1569,6 +1569,6 @@
|
||||||
"@tagEditorDiscardDialogMessage": {},
|
"@tagEditorDiscardDialogMessage": {},
|
||||||
"tagPlaceholderCountry": "Land",
|
"tagPlaceholderCountry": "Land",
|
||||||
"@tagPlaceholderCountry": {},
|
"@tagPlaceholderCountry": {},
|
||||||
"tagPlaceholderState": "Delstat",
|
"tagPlaceholderState": "Stat",
|
||||||
"@tagPlaceholderState": {}
|
"@tagPlaceholderState": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,18 +105,21 @@ class Contributors {
|
||||||
// Contributor('Htet Oo Hlaing', 'htetoh2006@outlook.com'), // Burmese
|
// Contributor('Htet Oo Hlaing', 'htetoh2006@outlook.com'), // Burmese
|
||||||
// Contributor('Khant', 'khant@users.noreply.hosted.weblate.org'), // Burmese
|
// Contributor('Khant', 'khant@users.noreply.hosted.weblate.org'), // Burmese
|
||||||
// Contributor('Grooty12', 'Rasmus@rosendahl-kaa.name'), // Danish
|
// Contributor('Grooty12', 'Rasmus@rosendahl-kaa.name'), // Danish
|
||||||
|
// Contributor('Victor M', 'victormorita@tuta.io'), // Danish
|
||||||
// Contributor('Åzze', 'laitinen.jere222@gmail.com'), // Finnish
|
// Contributor('Åzze', 'laitinen.jere222@gmail.com'), // Finnish
|
||||||
// Contributor('Olli', 'ollinen@ollit.dev'), // Finnish
|
// Contributor('Olli', 'ollinen@ollit.dev'), // Finnish
|
||||||
// Contributor('Idj', 'joneltmp+goahn@gmail.com'), // Hebrew
|
// Contributor('Idj', 'joneltmp+goahn@gmail.com'), // Hebrew
|
||||||
// Contributor('Rohit Burman', 'rohitburman31p@rediffmail.com'), // Hindi
|
// Contributor('Rohit Burman', 'rohitburman31p@rediffmail.com'), // Hindi
|
||||||
// Contributor('AJ07', 'ajaykumarmeena676@gmail.com'), // Hindi
|
// Contributor('AJ07', 'ajaykumarmeena676@gmail.com'), // Hindi
|
||||||
// Contributor('Sartaj', 'ssaarrttaajj111@gmail.com'), // Hindi
|
// Contributor('Sartaj', 'ssaarrttaajj111@gmail.com'), // Hindi
|
||||||
|
// Contributor('Anurag Samota', 'anuragsamotasamota@gmail.com'), // Hindi
|
||||||
// Contributor('Chethan', 'chethan@users.noreply.hosted.weblate.org'), // Kannada
|
// Contributor('Chethan', 'chethan@users.noreply.hosted.weblate.org'), // Kannada
|
||||||
// Contributor('GoRaN', 'gorangharib.909@gmail.com'), // Kurdish (Central)
|
// Contributor('GoRaN', 'gorangharib.909@gmail.com'), // Kurdish (Central)
|
||||||
// Contributor('Rasti K5', 'rasti.khdhr@gmail.com'), // Kurdish (Central)
|
// Contributor('Rasti K5', 'rasti.khdhr@gmail.com'), // Kurdish (Central)
|
||||||
// Contributor('Raman', 'xysed@tutanota.com'), // Malayalam
|
// Contributor('Raman', 'xysed@tutanota.com'), // Malayalam
|
||||||
// Contributor('Subham Jena', 'subhamjena8465@gmail.com'), // Odia
|
// Contributor('Subham Jena', 'subhamjena8465@gmail.com'), // Odia
|
||||||
// Contributor('Prasanta-Hembram', 'Prasantahembram720@gmail.com'), // Santali
|
// Contributor('Prasanta-Hembram', 'Prasantahembram720@gmail.com'), // Santali
|
||||||
|
// Contributor('Enenra', 'nnra2210@gmail.com'), // Serbian
|
||||||
// Contributor('mytja', 'mamnju21@gmail.com'), // Slovenian
|
// Contributor('mytja', 'mamnju21@gmail.com'), // Slovenian
|
||||||
// Contributor('Nattapong K', 'mixer5056@gmail.com'), // Thai
|
// Contributor('Nattapong K', 'mixer5056@gmail.com'), // Thai
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,8 +6,12 @@ import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
abstract class AvesAvailability {
|
abstract class AvesAvailability {
|
||||||
|
Future<void> onNewIntent();
|
||||||
|
|
||||||
void onResume();
|
void onResume();
|
||||||
|
|
||||||
|
bool get isLocked;
|
||||||
|
|
||||||
Future<bool> get isConnected;
|
Future<bool> get isConnected;
|
||||||
|
|
||||||
Future<bool> get canLocatePlaces;
|
Future<bool> get canLocatePlaces;
|
||||||
|
@ -16,15 +20,24 @@ abstract class AvesAvailability {
|
||||||
}
|
}
|
||||||
|
|
||||||
class LiveAvesAvailability implements AvesAvailability {
|
class LiveAvesAvailability implements AvesAvailability {
|
||||||
bool? _isConnected;
|
bool? _isConnected, _isLocked;
|
||||||
|
|
||||||
LiveAvesAvailability() {
|
LiveAvesAvailability() {
|
||||||
Connectivity().onConnectivityChanged.listen(_updateConnectivityFromResult);
|
Connectivity().onConnectivityChanged.listen(_updateConnectivityFromResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onNewIntent() async {
|
||||||
|
_isLocked = await deviceService.isLocked();
|
||||||
|
debugPrint('Device is locked=$_isLocked');
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onResume() => _isConnected = null;
|
void onResume() => _isConnected = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isLocked => _isLocked ?? false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> get isConnected async {
|
Future<bool> get isConnected async {
|
||||||
if (_isConnected != null) return SynchronousFuture(_isConnected!);
|
if (_isConnected != null) return SynchronousFuture(_isConnected!);
|
||||||
|
|
|
@ -9,8 +9,8 @@ final Device device = Device._private();
|
||||||
|
|
||||||
class Device {
|
class Device {
|
||||||
late final String _packageName, _packageVersion, _userAgent;
|
late final String _packageName, _packageVersion, _userAgent;
|
||||||
late final bool _canAuthenticateUser, _canGrantDirectoryAccess, _canPinShortcut;
|
late final bool _canAuthenticateUser, _canPinShortcut;
|
||||||
late final bool _canRenderFlagEmojis, _canRenderSubdivisionFlagEmojis, _canRequestManageMedia, _canSetLockScreenWallpaper, _canUseCrypto;
|
late final bool _canRenderFlagEmojis, _canRenderSubdivisionFlagEmojis, _canRequestManageMedia, _canSetLockScreenWallpaper;
|
||||||
late final bool _hasGeocoder, _isDynamicColorAvailable, _isTelevision, _showPinShortcutFeedback, _supportEdgeToEdgeUIMode, _supportPictureInPicture;
|
late final bool _hasGeocoder, _isDynamicColorAvailable, _isTelevision, _showPinShortcutFeedback, _supportEdgeToEdgeUIMode, _supportPictureInPicture;
|
||||||
|
|
||||||
String get packageName => _packageName;
|
String get packageName => _packageName;
|
||||||
|
@ -21,8 +21,6 @@ class Device {
|
||||||
|
|
||||||
bool get canAuthenticateUser => _canAuthenticateUser;
|
bool get canAuthenticateUser => _canAuthenticateUser;
|
||||||
|
|
||||||
bool get canGrantDirectoryAccess => _canGrantDirectoryAccess;
|
|
||||||
|
|
||||||
bool get canPinShortcut => _canPinShortcut;
|
bool get canPinShortcut => _canPinShortcut;
|
||||||
|
|
||||||
bool get canRenderFlagEmojis => _canRenderFlagEmojis;
|
bool get canRenderFlagEmojis => _canRenderFlagEmojis;
|
||||||
|
@ -33,10 +31,6 @@ class Device {
|
||||||
|
|
||||||
bool get canSetLockScreenWallpaper => _canSetLockScreenWallpaper;
|
bool get canSetLockScreenWallpaper => _canSetLockScreenWallpaper;
|
||||||
|
|
||||||
bool get canUseCrypto => _canUseCrypto;
|
|
||||||
|
|
||||||
bool get canUseVaults => canAuthenticateUser || canUseCrypto;
|
|
||||||
|
|
||||||
bool get hasGeocoder => _hasGeocoder;
|
bool get hasGeocoder => _hasGeocoder;
|
||||||
|
|
||||||
bool get isDynamicColorAvailable => _isDynamicColorAvailable;
|
bool get isDynamicColorAvailable => _isDynamicColorAvailable;
|
||||||
|
@ -71,13 +65,11 @@ class Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
final capabilities = await deviceService.getCapabilities();
|
final capabilities = await deviceService.getCapabilities();
|
||||||
_canGrantDirectoryAccess = capabilities['canGrantDirectoryAccess'] ?? false;
|
|
||||||
_canPinShortcut = capabilities['canPinShortcut'] ?? false;
|
_canPinShortcut = capabilities['canPinShortcut'] ?? false;
|
||||||
_canRenderFlagEmojis = capabilities['canRenderFlagEmojis'] ?? false;
|
_canRenderFlagEmojis = capabilities['canRenderFlagEmojis'] ?? false;
|
||||||
_canRenderSubdivisionFlagEmojis = capabilities['canRenderSubdivisionFlagEmojis'] ?? false;
|
_canRenderSubdivisionFlagEmojis = capabilities['canRenderSubdivisionFlagEmojis'] ?? false;
|
||||||
_canRequestManageMedia = capabilities['canRequestManageMedia'] ?? false;
|
_canRequestManageMedia = capabilities['canRequestManageMedia'] ?? false;
|
||||||
_canSetLockScreenWallpaper = capabilities['canSetLockScreenWallpaper'] ?? false;
|
_canSetLockScreenWallpaper = capabilities['canSetLockScreenWallpaper'] ?? false;
|
||||||
_canUseCrypto = capabilities['canUseCrypto'] ?? false;
|
|
||||||
_hasGeocoder = capabilities['hasGeocoder'] ?? false;
|
_hasGeocoder = capabilities['hasGeocoder'] ?? false;
|
||||||
_isDynamicColorAvailable = capabilities['isDynamicColorAvailable'] ?? false;
|
_isDynamicColorAvailable = capabilities['isDynamicColorAvailable'] ?? false;
|
||||||
_showPinShortcutFeedback = capabilities['showPinShortcutFeedback'] ?? false;
|
_showPinShortcutFeedback = capabilities['showPinShortcutFeedback'] ?? false;
|
||||||
|
|
|
@ -9,22 +9,24 @@ class PathFilter extends CollectionFilter {
|
||||||
static const type = 'path';
|
static const type = 'path';
|
||||||
|
|
||||||
// including trailing separator
|
// including trailing separator
|
||||||
final String path;
|
late final String path;
|
||||||
|
|
||||||
// without trailing separator
|
// without trailing separator
|
||||||
final String _rootAlbum;
|
late final String _rootAlbum;
|
||||||
|
|
||||||
late final EntryFilter _test;
|
late final EntryFilter _test;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [path, reversed];
|
List<Object?> get props => [path, reversed];
|
||||||
|
|
||||||
PathFilter(this.path, {super.reversed = false}) : _rootAlbum = path.substring(0, path.length - 1) {
|
PathFilter(String path, {super.reversed = false}) {
|
||||||
|
this.path = path.endsWith(pContext.separator) ? path : '$path${pContext.separator}';
|
||||||
|
_rootAlbum = this.path.substring(0, this.path.length - 1);
|
||||||
_test = (entry) {
|
_test = (entry) {
|
||||||
final dir = entry.directory;
|
final dir = entry.directory;
|
||||||
if (dir == null) return false;
|
if (dir == null) return false;
|
||||||
// avoid string building in most cases
|
// avoid string building in most cases
|
||||||
return dir.startsWith(_rootAlbum) && '$dir${pContext.separator}'.startsWith(path);
|
return dir.startsWith(_rootAlbum) && '$dir${pContext.separator}'.startsWith(this.path);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
bool loadTopEntriesFirst = false,
|
bool loadTopEntriesFirst = false,
|
||||||
bool canAnalyze = true,
|
bool canAnalyze = true,
|
||||||
}) async {
|
}) async {
|
||||||
|
await reportService.log('$runtimeType init directory=$directory');
|
||||||
if (_initState == SourceInitializationState.none) {
|
if (_initState == SourceInitializationState.none) {
|
||||||
await _loadEssentials();
|
await _loadEssentials();
|
||||||
}
|
}
|
||||||
|
@ -81,7 +82,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
required bool loadTopEntriesFirst,
|
required bool loadTopEntriesFirst,
|
||||||
required bool canAnalyze,
|
required bool canAnalyze,
|
||||||
}) async {
|
}) async {
|
||||||
debugPrint('$runtimeType refresh start');
|
unawaited(reportService.log('$runtimeType load start'));
|
||||||
final stopwatch = Stopwatch()..start();
|
final stopwatch = Stopwatch()..start();
|
||||||
state = SourceState.loading;
|
state = SourceState.loading;
|
||||||
clearEntries();
|
clearEntries();
|
||||||
|
@ -90,17 +91,17 @@ class MediaStoreSource extends CollectionSource {
|
||||||
if (loadTopEntriesFirst) {
|
if (loadTopEntriesFirst) {
|
||||||
final topIds = settings.topEntryIds?.toSet();
|
final topIds = settings.topEntryIds?.toSet();
|
||||||
if (topIds != null) {
|
if (topIds != null) {
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} load ${topIds.length} top entries');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} load ${topIds.length} top entries');
|
||||||
topEntries.addAll(await localMediaDb.loadEntriesById(topIds));
|
topEntries.addAll(await localMediaDb.loadEntriesById(topIds));
|
||||||
addEntries(topEntries);
|
addEntries(topEntries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} fetch known entries');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} fetch known entries');
|
||||||
final knownEntries = await localMediaDb.loadEntries(origin: EntryOrigins.mediaStoreContent, directory: directory);
|
final knownEntries = await localMediaDb.loadEntries(origin: EntryOrigins.mediaStoreContent, directory: directory);
|
||||||
final knownLiveEntries = knownEntries.where((entry) => !entry.trashed).toSet();
|
final knownLiveEntries = knownEntries.where((entry) => !entry.trashed).toSet();
|
||||||
|
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} check obsolete entries');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} check obsolete entries');
|
||||||
final knownDateByContentId = Map.fromEntries(knownLiveEntries.map((entry) => MapEntry(entry.contentId, entry.dateModifiedSecs)));
|
final knownDateByContentId = Map.fromEntries(knownLiveEntries.map((entry) => MapEntry(entry.contentId, entry.dateModifiedSecs)));
|
||||||
final knownContentIds = knownDateByContentId.keys.toList();
|
final knownContentIds = knownDateByContentId.keys.toList();
|
||||||
final removedContentIds = (await mediaStoreService.checkObsoleteContentIds(knownContentIds)).toSet();
|
final removedContentIds = (await mediaStoreService.checkObsoleteContentIds(knownContentIds)).toSet();
|
||||||
|
@ -112,14 +113,14 @@ class MediaStoreSource extends CollectionSource {
|
||||||
knownEntries.removeAll(removedEntries);
|
knownEntries.removeAll(removedEntries);
|
||||||
|
|
||||||
// show known entries
|
// show known entries
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} add known entries');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} add known entries');
|
||||||
// add entries without notifying, so that the collection is not refreshed
|
// add entries without notifying, so that the collection is not refreshed
|
||||||
// with items that may be hidden right away because of their metadata
|
// with items that may be hidden right away because of their metadata
|
||||||
addEntries(knownEntries, notify: false);
|
addEntries(knownEntries, notify: false);
|
||||||
|
|
||||||
await _loadVaultEntries(directory);
|
await _loadVaultEntries(directory);
|
||||||
|
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} load metadata');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} load metadata');
|
||||||
if (directory != null) {
|
if (directory != null) {
|
||||||
final ids = knownLiveEntries.map((entry) => entry.id).toSet();
|
final ids = knownLiveEntries.map((entry) => entry.id).toSet();
|
||||||
await loadCatalogMetadata(ids: ids);
|
await loadCatalogMetadata(ids: ids);
|
||||||
|
@ -144,12 +145,12 @@ class MediaStoreSource extends CollectionSource {
|
||||||
|
|
||||||
// clean up obsolete entries
|
// clean up obsolete entries
|
||||||
if (removedEntries.isNotEmpty) {
|
if (removedEntries.isNotEmpty) {
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} remove obsolete entries');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} remove obsolete entries');
|
||||||
await localMediaDb.removeIds(removedEntries.map((entry) => entry.id).toSet());
|
await localMediaDb.removeIds(removedEntries.map((entry) => entry.id).toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify paths because some apps move files without updating their `last modified date`
|
// verify paths because some apps move files without updating their `last modified date`
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} check obsolete paths');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} check obsolete paths');
|
||||||
final knownPathByContentId = Map.fromEntries(knownLiveEntries.map((entry) => MapEntry(entry.contentId, entry.path)));
|
final knownPathByContentId = Map.fromEntries(knownLiveEntries.map((entry) => MapEntry(entry.contentId, entry.path)));
|
||||||
final movedContentIds = (await mediaStoreService.checkObsoletePaths(knownPathByContentId)).toSet();
|
final movedContentIds = (await mediaStoreService.checkObsoletePaths(knownPathByContentId)).toSet();
|
||||||
movedContentIds.forEach((contentId) {
|
movedContentIds.forEach((contentId) {
|
||||||
|
@ -161,13 +162,13 @@ class MediaStoreSource extends CollectionSource {
|
||||||
final newEntries = <AvesEntry>{};
|
final newEntries = <AvesEntry>{};
|
||||||
|
|
||||||
// recover untracked trash items
|
// recover untracked trash items
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} recover untracked entries');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} recover untracked entries');
|
||||||
if (directory == null) {
|
if (directory == null) {
|
||||||
newEntries.addAll(await recoverUntrackedTrashItems());
|
newEntries.addAll(await recoverUntrackedTrashItems());
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch new & modified entries
|
// fetch new & modified entries
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} fetch new entries');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} fetch new entries');
|
||||||
mediaStoreService.getEntries(_safeMode, knownDateByContentId, directory: directory).listen(
|
mediaStoreService.getEntries(_safeMode, knownDateByContentId, directory: directory).listen(
|
||||||
(entry) {
|
(entry) {
|
||||||
// when discovering modified entry with known content ID,
|
// when discovering modified entry with known content ID,
|
||||||
|
@ -180,7 +181,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
},
|
},
|
||||||
onDone: () async {
|
onDone: () async {
|
||||||
if (newEntries.isNotEmpty) {
|
if (newEntries.isNotEmpty) {
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} save new entries');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} save new entries');
|
||||||
await localMediaDb.insertEntries(newEntries);
|
await localMediaDb.insertEntries(newEntries);
|
||||||
|
|
||||||
// TODO TLAD find duplication cause
|
// TODO TLAD find duplication cause
|
||||||
|
@ -203,7 +204,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
updateDirectories();
|
updateDirectories();
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} analyze');
|
debugPrint('$runtimeType load ${stopwatch.elapsed} analyze');
|
||||||
Set<AvesEntry>? analysisEntries;
|
Set<AvesEntry>? analysisEntries;
|
||||||
final analysisIds = analysisController?.entryIds;
|
final analysisIds = analysisController?.entryIds;
|
||||||
if (analysisIds != null) {
|
if (analysisIds != null) {
|
||||||
|
@ -220,8 +221,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
// so we manually notify change for potential home screen filters
|
// so we manually notify change for potential home screen filters
|
||||||
notifyAlbumsChanged();
|
notifyAlbumsChanged();
|
||||||
|
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} done');
|
unawaited(reportService.log('$runtimeType load done in ${stopwatch.elapsed.inSeconds}s for ${knownEntries.length} known, ${newEntries.length} new, ${removedEntries.length} removed'));
|
||||||
unawaited(reportService.log('Source refresh complete in ${stopwatch.elapsed.inSeconds}s for ${knownEntries.length} known, ${newEntries.length} new, ${removedEntries.length} removed'));
|
|
||||||
},
|
},
|
||||||
onError: (error) => debugPrint('$runtimeType stream error=$error'),
|
onError: (error) => debugPrint('$runtimeType stream error=$error'),
|
||||||
);
|
);
|
||||||
|
@ -238,7 +238,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
|
|
||||||
state = SourceState.loading;
|
state = SourceState.loading;
|
||||||
|
|
||||||
debugPrint('$runtimeType refreshUris ${changedUris.length} uris');
|
unawaited(reportService.log('$runtimeType refresh start for ${changedUris.length} uris'));
|
||||||
final changedUriByContentId = Map.fromEntries(changedUris.map((uri) {
|
final changedUriByContentId = Map.fromEntries(changedUris.map((uri) {
|
||||||
final pathSegments = Uri.parse(uri).pathSegments;
|
final pathSegments = Uri.parse(uri).pathSegments;
|
||||||
// e.g. URI `content://media/` has no path segment
|
// e.g. URI `content://media/` has no path segment
|
||||||
|
@ -297,8 +297,6 @@ class MediaStoreSource extends CollectionSource {
|
||||||
|
|
||||||
invalidateAlbumFilterSummary(directories: existingDirectories);
|
invalidateAlbumFilterSummary(directories: existingDirectories);
|
||||||
|
|
||||||
state = SourceState.ready;
|
|
||||||
|
|
||||||
if (newEntries.isNotEmpty) {
|
if (newEntries.isNotEmpty) {
|
||||||
await localMediaDb.insertEntries(newEntries);
|
await localMediaDb.insertEntries(newEntries);
|
||||||
|
|
||||||
|
@ -323,6 +321,10 @@ class MediaStoreSource extends CollectionSource {
|
||||||
await refreshEntries(entriesToRefresh, EntryDataType.values.toSet());
|
await refreshEntries(entriesToRefresh, EntryDataType.values.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unawaited(reportService.log('$runtimeType refresh end for ${changedUris.length} uris'));
|
||||||
|
|
||||||
|
state = SourceState.ready;
|
||||||
|
|
||||||
return tempUris;
|
return tempUris;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ abstract class DeviceService {
|
||||||
|
|
||||||
Future<int> getPerformanceClass();
|
Future<int> getPerformanceClass();
|
||||||
|
|
||||||
|
Future<bool> isLocked();
|
||||||
|
|
||||||
Future<bool> isSystemFilePickerEnabled();
|
Future<bool> isSystemFilePickerEnabled();
|
||||||
|
|
||||||
Future<void> requestMediaManagePermission();
|
Future<void> requestMediaManagePermission();
|
||||||
|
@ -89,6 +91,17 @@ class PlatformDeviceService implements DeviceService {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> isLocked() async {
|
||||||
|
try {
|
||||||
|
final result = await _platform.invokeMethod('isLocked');
|
||||||
|
if (result != null) return result as bool;
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isSystemFilePickerEnabled() async {
|
Future<bool> isSystemFilePickerEnabled() async {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -5,10 +5,11 @@ class ADurations {
|
||||||
static const transitionMarginMillis = 20;
|
static const transitionMarginMillis = 20;
|
||||||
|
|
||||||
// page transition duration also available via `ModalRoute.of(context)!.transitionDuration * timeDilation`
|
// page transition duration also available via `ModalRoute.of(context)!.transitionDuration * timeDilation`
|
||||||
static const pageTransitionAnimation = Duration(milliseconds: 300 + transitionMarginMillis); // ref `transitionDuration` used in `MaterialRouteTransitionMixin`
|
static const pageTransitionExact = Duration(milliseconds: 300); // ref `transitionDuration` used in `MaterialRouteTransitionMixin`
|
||||||
static const dialogTransitionAnimation = Duration(milliseconds: 150 + transitionMarginMillis); // ref `transitionDuration` used in `DialogRoute`
|
static const pageTransitionLoose = Duration(milliseconds: 300 + transitionMarginMillis); // ref `transitionDuration` used in `MaterialRouteTransitionMixin`
|
||||||
static const drawerTransitionAnimation = Duration(milliseconds: 246 + transitionMarginMillis); // ref `_kBaseSettleDuration` used in `DrawerControllerState`
|
static const dialogTransitionLoose = Duration(milliseconds: 150 + transitionMarginMillis); // ref `transitionDuration` used in `DialogRoute`
|
||||||
static const toggleableTransitionAnimation = Duration(milliseconds: 200 + transitionMarginMillis); // ref `_kToggleDuration` used in `ToggleableStateMixin`
|
static const drawerTransitionLoose = Duration(milliseconds: 246 + transitionMarginMillis); // ref `_kBaseSettleDuration` used in `DrawerControllerState`
|
||||||
|
static const toggleableTransitionLoose = Duration(milliseconds: 200 + transitionMarginMillis); // ref `_kToggleDuration` used in `ToggleableStateMixin`
|
||||||
|
|
||||||
// common animations
|
// common animations
|
||||||
static const sweeperOpacityAnimation = Duration(milliseconds: 150);
|
static const sweeperOpacityAnimation = Duration(milliseconds: 150);
|
||||||
|
|
|
@ -32,6 +32,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/providers/durations_provider.dart';
|
import 'package:aves/widgets/common/providers/durations_provider.dart';
|
||||||
import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
|
import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
|
||||||
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
|
import 'package:aves/widgets/common/providers/viewer_entry_provider.dart';
|
||||||
import 'package:aves/widgets/home_page.dart';
|
import 'package:aves/widgets/home_page.dart';
|
||||||
import 'package:aves/widgets/navigation/tv_page_transitions.dart';
|
import 'package:aves/widgets/navigation/tv_page_transitions.dart';
|
||||||
import 'package:aves/widgets/navigation/tv_rail.dart';
|
import 'package:aves/widgets/navigation/tv_rail.dart';
|
||||||
|
@ -224,6 +225,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
Provider<TvRailController>.value(value: _tvRailController),
|
Provider<TvRailController>.value(value: _tvRailController),
|
||||||
DurationsProvider(),
|
DurationsProvider(),
|
||||||
HighlightInfoProvider(),
|
HighlightInfoProvider(),
|
||||||
|
ViewerEntryProvider(),
|
||||||
],
|
],
|
||||||
child: NotificationListener<PopExitNotification>(
|
child: NotificationListener<PopExitNotification>(
|
||||||
onNotification: (notification) {
|
onNotification: (notification) {
|
||||||
|
@ -411,7 +413,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
@override
|
@override
|
||||||
void didHaveMemoryPressure() {
|
void didHaveMemoryPressure() {
|
||||||
super.didHaveMemoryPressure();
|
super.didHaveMemoryPressure();
|
||||||
reportService.log('App memory pressure');
|
debugPrint('App memory pressure');
|
||||||
imageCache.clear();
|
imageCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -691,7 +691,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
|
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
|
||||||
);
|
);
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.dialogTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.dialogTransitionLoose * timeDilation);
|
||||||
if (value != null && initialValue != value) {
|
if (value != null && initialValue != value) {
|
||||||
settings.collectionSortFactor = value.$1!;
|
settings.collectionSortFactor = value.$1!;
|
||||||
settings.collectionSectionFactor = value.$2!;
|
settings.collectionSectionFactor = value.$2!;
|
||||||
|
|
|
@ -40,6 +40,7 @@ import 'package:aves/widgets/common/identity/buttons/outlined_button.dart';
|
||||||
import 'package:aves/widgets/common/identity/empty.dart';
|
import 'package:aves/widgets/common/identity/empty.dart';
|
||||||
import 'package:aves/widgets/common/identity/scroll_thumb.dart';
|
import 'package:aves/widgets/common/identity/scroll_thumb.dart';
|
||||||
import 'package:aves/widgets/common/providers/tile_extent_controller_provider.dart';
|
import 'package:aves/widgets/common/providers/tile_extent_controller_provider.dart';
|
||||||
|
import 'package:aves/widgets/common/providers/viewer_entry_provider.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/decorated.dart';
|
import 'package:aves/widgets/common/thumbnail/decorated.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/image.dart';
|
import 'package:aves/widgets/common/thumbnail/image.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/notifications.dart';
|
import 'package:aves/widgets/common/thumbnail/notifications.dart';
|
||||||
|
@ -49,6 +50,7 @@ import 'package:aves/widgets/viewer/entry_viewer_page.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
@ -116,6 +118,12 @@ class _CollectionGridContentState extends State<_CollectionGridContent> {
|
||||||
final ValueNotifier<bool> _isScrollingNotifier = ValueNotifier(false);
|
final ValueNotifier<bool> _isScrollingNotifier = ValueNotifier(false);
|
||||||
final ValueNotifier<AppMode> _selectingAppModeNotifier = ValueNotifier(AppMode.pickFilteredMediaInternal);
|
final ValueNotifier<AppMode> _selectingAppModeNotifier = ValueNotifier(AppMode.pickFilteredMediaInternal);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => context.read<ViewerEntryNotifier>().value = null);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_focusedItemNotifier.dispose();
|
_focusedItemNotifier.dispose();
|
||||||
|
@ -238,9 +246,12 @@ class _CollectionGridContentState extends State<_CollectionGridContent> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _goToViewer(CollectionLens collection, AvesEntry entry) {
|
Future<void> _goToViewer(CollectionLens collection, AvesEntry entry) async {
|
||||||
|
// track viewer entry for dynamic hero placeholder
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => context.read<ViewerEntryNotifier>().value = entry);
|
||||||
|
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
final selection = context.read<Selection<AvesEntry>>();
|
||||||
Navigator.maybeOf(context)?.push(
|
await Navigator.maybeOf(context)?.push(
|
||||||
TransparentMaterialPageRoute(
|
TransparentMaterialPageRoute(
|
||||||
settings: const RouteSettings(name: EntryViewerPage.routeName),
|
settings: const RouteSettings(name: EntryViewerPage.routeName),
|
||||||
pageBuilder: (context, a, sa) {
|
pageBuilder: (context, a, sa) {
|
||||||
|
@ -266,6 +277,14 @@ class _CollectionGridContentState extends State<_CollectionGridContent> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// reset track viewer entry
|
||||||
|
final animate = context.read<Settings>().animate;
|
||||||
|
if (animate) {
|
||||||
|
// TODO TLAD fix timing when transition is incomplete, e.g. when going back while going to the viewer
|
||||||
|
await Future.delayed(ADurations.pageTransitionExact * timeDilation);
|
||||||
|
}
|
||||||
|
context.read<ViewerEntryNotifier>().value = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -510,7 +510,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
if (confirmed == null || !confirmed) return null;
|
if (confirmed == null || !confirmed) return null;
|
||||||
|
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.dialogTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.dialogTransitionLoose * timeDilation);
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,10 @@ import 'package:aves/services/intent_service.dart';
|
||||||
import 'package:aves/widgets/collection/grid/list_details.dart';
|
import 'package:aves/widgets/collection/grid/list_details.dart';
|
||||||
import 'package:aves/widgets/collection/grid/list_details_theme.dart';
|
import 'package:aves/widgets/collection/grid/list_details_theme.dart';
|
||||||
import 'package:aves/widgets/common/grid/scaling.dart';
|
import 'package:aves/widgets/common/grid/scaling.dart';
|
||||||
|
import 'package:aves/widgets/common/providers/viewer_entry_provider.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/decorated.dart';
|
import 'package:aves/widgets/common/thumbnail/decorated.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/notifications.dart';
|
import 'package:aves/widgets/common/thumbnail/notifications.dart';
|
||||||
|
import 'package:aves/widgets/viewer/hero.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
@ -62,10 +64,7 @@ class InteractiveTile extends StatelessWidget {
|
||||||
selectable: true,
|
selectable: true,
|
||||||
highlightable: true,
|
highlightable: true,
|
||||||
isScrollingNotifier: isScrollingNotifier,
|
isScrollingNotifier: isScrollingNotifier,
|
||||||
// hero tag should include a collection identifier, so that it animates
|
heroTagger: () => EntryHeroInfo(collection, entry).tag,
|
||||||
// between different views of the entry in the same collection (e.g. thumbnails <-> viewer)
|
|
||||||
// but not between different collection instances, even with the same attributes (e.g. reloading collection page via drawer)
|
|
||||||
heroTagger: () => Object.hashAll([collection.id, entry.id]),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -126,5 +125,20 @@ class Tile extends StatelessWidget {
|
||||||
selectable: selectable,
|
selectable: selectable,
|
||||||
highlightable: highlightable,
|
highlightable: highlightable,
|
||||||
heroTagger: heroTagger,
|
heroTagger: heroTagger,
|
||||||
|
// do not use a hero placeholder but hide the thumbnail matching the viewer entry,
|
||||||
|
// so that it can hero out on an entry and come back with a hero to a different entry
|
||||||
|
heroPlaceholderBuilder: (context, heroSize, child) => child,
|
||||||
|
imageDecorator: (context, child) {
|
||||||
|
return Selector<ViewerEntryNotifier, bool>(
|
||||||
|
selector: (context, v) => v.value == entry,
|
||||||
|
builder: (context, isViewerEntry, child) {
|
||||||
|
return Visibility.maintain(
|
||||||
|
visible: !isViewerEntry,
|
||||||
|
child: child!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ mixin FeedbackMixin {
|
||||||
final margin = (marginComputer ?? snackBarMarginDefault).call(context);
|
final margin = (marginComputer ?? snackBarMarginDefault).call(context);
|
||||||
return AnimatedPadding(
|
return AnimatedPadding(
|
||||||
padding: margin,
|
padding: margin,
|
||||||
duration: ADurations.pageTransitionAnimation,
|
duration: ADurations.pageTransitionLoose,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
17
lib/widgets/common/providers/viewer_entry_provider.dart
Normal file
17
lib/widgets/common/providers/viewer_entry_provider.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:aves/model/entry/entry.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ViewerEntryProvider extends ListenableProvider<ViewerEntryNotifier> {
|
||||||
|
ViewerEntryProvider({
|
||||||
|
super.key,
|
||||||
|
super.child,
|
||||||
|
}) : super(
|
||||||
|
create: (context) => ViewerEntryNotifier(null),
|
||||||
|
dispose: (context, value) => value.dispose(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewerEntryNotifier extends ValueNotifier<AvesEntry?> {
|
||||||
|
ViewerEntryNotifier(super.value);
|
||||||
|
}
|
|
@ -76,7 +76,7 @@ class _SearchPageState extends State<SearchPage> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
widget.animation.removeStatusListener(_onAnimationStatusChanged);
|
widget.animation.removeStatusListener(_onAnimationStatusChanged);
|
||||||
Future.delayed(ADurations.pageTransitionAnimation * timeDilation).then((_) {
|
Future.delayed(ADurations.pageTransitionLoose * timeDilation).then((_) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
_searchFieldFocusNode.requestFocus();
|
_searchFieldFocusNode.requestFocus();
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,6 +13,8 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
final ValueNotifier<bool>? cancellableNotifier;
|
final ValueNotifier<bool>? cancellableNotifier;
|
||||||
final bool isMosaic, selectable, highlightable;
|
final bool isMosaic, selectable, highlightable;
|
||||||
final Object? Function()? heroTagger;
|
final Object? Function()? heroTagger;
|
||||||
|
final HeroPlaceholderBuilder? heroPlaceholderBuilder;
|
||||||
|
final TransitionBuilder? imageDecorator;
|
||||||
|
|
||||||
static Color borderColor(BuildContext context) => Theme.of(context).dividerColor;
|
static Color borderColor(BuildContext context) => Theme.of(context).dividerColor;
|
||||||
|
|
||||||
|
@ -27,6 +29,8 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
this.selectable = true,
|
this.selectable = true,
|
||||||
this.highlightable = true,
|
this.highlightable = true,
|
||||||
this.heroTagger,
|
this.heroTagger,
|
||||||
|
this.heroPlaceholderBuilder,
|
||||||
|
this.imageDecorator,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -50,12 +54,13 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
isMosaic: isMosaic,
|
isMosaic: isMosaic,
|
||||||
cancellableNotifier: cancellableNotifier,
|
cancellableNotifier: cancellableNotifier,
|
||||||
heroTag: heroTagger?.call(),
|
heroTag: heroTagger?.call(),
|
||||||
|
heroPlaceholderBuilder: heroPlaceholderBuilder,
|
||||||
);
|
);
|
||||||
|
|
||||||
child = Stack(
|
child = Stack(
|
||||||
fit: StackFit.passthrough,
|
fit: StackFit.passthrough,
|
||||||
children: [
|
children: [
|
||||||
child,
|
imageDecorator?.call(context, child) ?? child,
|
||||||
ThumbnailEntryOverlay(entry: entry),
|
ThumbnailEntryOverlay(entry: entry),
|
||||||
if (selectable) ...[
|
if (selectable) ...[
|
||||||
GridItemSelectionOverlay<AvesEntry>(
|
GridItemSelectionOverlay<AvesEntry>(
|
||||||
|
|
|
@ -25,6 +25,7 @@ class ThumbnailImage extends StatefulWidget {
|
||||||
final bool showLoadingBackground;
|
final bool showLoadingBackground;
|
||||||
final ValueNotifier<bool>? cancellableNotifier;
|
final ValueNotifier<bool>? cancellableNotifier;
|
||||||
final Object? heroTag;
|
final Object? heroTag;
|
||||||
|
final HeroPlaceholderBuilder? heroPlaceholderBuilder;
|
||||||
|
|
||||||
const ThumbnailImage({
|
const ThumbnailImage({
|
||||||
super.key,
|
super.key,
|
||||||
|
@ -37,6 +38,7 @@ class ThumbnailImage extends StatefulWidget {
|
||||||
this.showLoadingBackground = true,
|
this.showLoadingBackground = true,
|
||||||
this.cancellableNotifier,
|
this.cancellableNotifier,
|
||||||
this.heroTag,
|
this.heroTag,
|
||||||
|
this.heroPlaceholderBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -261,11 +263,12 @@ class _ThumbnailImageState extends State<ThumbnailImage> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (animate && widget.heroTag != null) {
|
final heroTag = widget.heroTag;
|
||||||
|
if (animate && heroTag != null) {
|
||||||
final background = settings.imageBackground;
|
final background = settings.imageBackground;
|
||||||
final backgroundColor = background.isColor ? background.color : null;
|
final backgroundColor = background.isColor ? background.color : null;
|
||||||
image = Hero(
|
image = Hero(
|
||||||
tag: widget.heroTag!,
|
tag: heroTag,
|
||||||
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {
|
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {
|
||||||
Widget child = TransitionImage(
|
Widget child = TransitionImage(
|
||||||
image: entry.bestCachedThumbnail,
|
image: entry.bestCachedThumbnail,
|
||||||
|
@ -282,6 +285,7 @@ class _ThumbnailImageState extends State<ThumbnailImage> {
|
||||||
}
|
}
|
||||||
return child;
|
return child;
|
||||||
},
|
},
|
||||||
|
placeholderBuilder: widget.heroPlaceholderBuilder,
|
||||||
transitionOnUserGestures: true,
|
transitionOnUserGestures: true,
|
||||||
child: image,
|
child: image,
|
||||||
);
|
);
|
||||||
|
@ -296,9 +300,10 @@ class _ThumbnailImageState extends State<ThumbnailImage> {
|
||||||
extent: extent,
|
extent: extent,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (animate && widget.heroTag != null) {
|
final heroTag = widget.heroTag;
|
||||||
|
if (animate && heroTag != null) {
|
||||||
child = Hero(
|
child = Hero(
|
||||||
tag: widget.heroTag!,
|
tag: heroTag,
|
||||||
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {
|
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {
|
||||||
return MediaQueryDataProvider(
|
return MediaQueryDataProvider(
|
||||||
child: DefaultTextStyle(
|
child: DefaultTextStyle(
|
||||||
|
|
|
@ -25,14 +25,11 @@ class _DebugDeviceSectionState extends State<DebugDeviceSection> with AutomaticK
|
||||||
'packageVersion': device.packageVersion,
|
'packageVersion': device.packageVersion,
|
||||||
'userAgent': device.userAgent,
|
'userAgent': device.userAgent,
|
||||||
'canAuthenticateUser': '${device.canAuthenticateUser}',
|
'canAuthenticateUser': '${device.canAuthenticateUser}',
|
||||||
'canGrantDirectoryAccess': '${device.canGrantDirectoryAccess}',
|
|
||||||
'canPinShortcut': '${device.canPinShortcut}',
|
'canPinShortcut': '${device.canPinShortcut}',
|
||||||
'canRenderFlagEmojis': '${device.canRenderFlagEmojis}',
|
'canRenderFlagEmojis': '${device.canRenderFlagEmojis}',
|
||||||
'canRenderSubdivisionFlagEmojis': '${device.canRenderSubdivisionFlagEmojis}',
|
'canRenderSubdivisionFlagEmojis': '${device.canRenderSubdivisionFlagEmojis}',
|
||||||
'canRequestManageMedia': '${device.canRequestManageMedia}',
|
'canRequestManageMedia': '${device.canRequestManageMedia}',
|
||||||
'canSetLockScreenWallpaper': '${device.canSetLockScreenWallpaper}',
|
'canSetLockScreenWallpaper': '${device.canSetLockScreenWallpaper}',
|
||||||
'canUseCrypto': '${device.canUseCrypto}',
|
|
||||||
'canUseVaults': '${device.canUseVaults}',
|
|
||||||
'hasGeocoder': '${device.hasGeocoder}',
|
'hasGeocoder': '${device.hasGeocoder}',
|
||||||
'isDynamicColorAvailable': '${device.isDynamicColorAvailable}',
|
'isDynamicColorAvailable': '${device.isDynamicColorAvailable}',
|
||||||
'isTelevision': '${device.isTelevision}',
|
'isTelevision': '${device.isTelevision}',
|
||||||
|
|
|
@ -42,11 +42,9 @@ class _EditVaultDialogState extends State<EditVaultDialog> with FeedbackMixin, V
|
||||||
|
|
||||||
final List<VaultLockType> _lockTypeOptions = [
|
final List<VaultLockType> _lockTypeOptions = [
|
||||||
if (device.canAuthenticateUser) VaultLockType.system,
|
if (device.canAuthenticateUser) VaultLockType.system,
|
||||||
if (device.canUseCrypto) ...[
|
|
||||||
VaultLockType.pattern,
|
VaultLockType.pattern,
|
||||||
VaultLockType.pin,
|
VaultLockType.pin,
|
||||||
VaultLockType.password,
|
VaultLockType.password,
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
VaultDetails? get initialDetails => widget.initialDetails;
|
VaultDetails? get initialDetails => widget.initialDetails;
|
||||||
|
|
|
@ -248,7 +248,7 @@ class _AlbumPickPageState extends State<_AlbumPickPage> {
|
||||||
if (directory == null) return;
|
if (directory == null) return;
|
||||||
|
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.dialogTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.dialogTransitionLoose * timeDilation);
|
||||||
|
|
||||||
_pickAlbum(directory);
|
_pickAlbum(directory);
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,7 @@ class _AlbumPickPageState extends State<_AlbumPickPage> {
|
||||||
if (details == null) return;
|
if (details == null) return;
|
||||||
|
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.dialogTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.dialogTransitionLoose * timeDilation);
|
||||||
|
|
||||||
await vaults.create(details);
|
await vaults.create(details);
|
||||||
_pickAlbum(details.path);
|
_pickAlbum(details.path);
|
||||||
|
|
|
@ -77,7 +77,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
||||||
|
|
||||||
if (ExtraEntryMapStyle.isHeavy(settings.mapStyle)) {
|
if (ExtraEntryMapStyle.isHeavy(settings.mapStyle)) {
|
||||||
_isPageAnimatingNotifier = ValueNotifier(true);
|
_isPageAnimatingNotifier = ValueNotifier(true);
|
||||||
Future.delayed(ADurations.pageTransitionAnimation * timeDilation).then((_) {
|
Future.delayed(ADurations.pageTransitionLoose * timeDilation).then((_) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
_isPageAnimatingNotifier.value = false;
|
_isPageAnimatingNotifier.value = false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,7 +14,7 @@ Future<void> showSelectionDialog<T>({
|
||||||
routeSettings: const RouteSettings(name: AvesSingleSelectionDialog.routeName),
|
routeSettings: const RouteSettings(name: AvesSingleSelectionDialog.routeName),
|
||||||
);
|
);
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.dialogTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.dialogTransitionLoose * timeDilation);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
onSelection(value);
|
onSelection(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:aves/app_mode.dart';
|
import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/device.dart';
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/filters/album.dart';
|
import 'package:aves/model/filters/album.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
|
@ -78,12 +77,10 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
|
||||||
final selectedSingleItem = selectedFilters.length == 1;
|
final selectedSingleItem = selectedFilters.length == 1;
|
||||||
final isMain = appMode == AppMode.main;
|
final isMain = appMode == AppMode.main;
|
||||||
|
|
||||||
final canCreate = !settings.isReadOnly && appMode.canCreateFilter && !isSelecting;
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case ChipSetAction.createAlbum:
|
case ChipSetAction.createAlbum:
|
||||||
return canCreate;
|
|
||||||
case ChipSetAction.createVault:
|
case ChipSetAction.createVault:
|
||||||
return canCreate && device.canUseVaults;
|
return !settings.isReadOnly && appMode.canCreateFilter && !isSelecting;
|
||||||
case ChipSetAction.delete:
|
case ChipSetAction.delete:
|
||||||
case ChipSetAction.rename:
|
case ChipSetAction.rename:
|
||||||
return isMain && isSelecting && !settings.isReadOnly;
|
return isMain && isSelecting && !settings.isReadOnly;
|
||||||
|
@ -190,7 +187,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
|
||||||
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
|
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
|
||||||
);
|
);
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.dialogTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.dialogTransitionLoose * timeDilation);
|
||||||
if (value != null && initialValue != value) {
|
if (value != null && initialValue != value) {
|
||||||
sortFactor = value.$1!;
|
sortFactor = value.$1!;
|
||||||
settings.albumGroupFactor = value.$2!;
|
settings.albumGroupFactor = value.$2!;
|
||||||
|
|
|
@ -250,7 +250,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
|
||||||
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
|
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
|
||||||
);
|
);
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.dialogTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.dialogTransitionLoose * timeDilation);
|
||||||
if (value != null && initialValue != value) {
|
if (value != null && initialValue != value) {
|
||||||
sortFactor = value.$1!;
|
sortFactor = value.$1!;
|
||||||
tileLayout = value.$3!;
|
tileLayout = value.$3!;
|
||||||
|
|
|
@ -90,13 +90,15 @@ class _HomePageState extends State<HomePage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
var appMode = AppMode.main;
|
var appMode = AppMode.main;
|
||||||
|
var error = false;
|
||||||
final intentData = widget.intentData ?? await IntentService.getIntentData();
|
final intentData = widget.intentData ?? await IntentService.getIntentData();
|
||||||
final safeMode = intentData[IntentDataKeys.safeMode] ?? false;
|
final safeMode = (intentData[IntentDataKeys.safeMode] as bool?) ?? false;
|
||||||
final intentAction = intentData[IntentDataKeys.action];
|
final intentAction = intentData[IntentDataKeys.action] as String?;
|
||||||
_initialFilters = null;
|
_initialFilters = null;
|
||||||
_initialExplorerPath = null;
|
_initialExplorerPath = null;
|
||||||
_secureUris = null;
|
_secureUris = null;
|
||||||
|
|
||||||
|
await availability.onNewIntent();
|
||||||
await androidFileUtils.init();
|
await androidFileUtils.init();
|
||||||
if (!{
|
if (!{
|
||||||
IntentActions.edit,
|
IntentActions.edit,
|
||||||
|
@ -109,61 +111,22 @@ class _HomePageState extends State<HomePage> {
|
||||||
|
|
||||||
if (intentData.values.whereNotNull().isNotEmpty) {
|
if (intentData.values.whereNotNull().isNotEmpty) {
|
||||||
await reportService.log('Intent data=$intentData');
|
await reportService.log('Intent data=$intentData');
|
||||||
|
var intentUri = intentData[IntentDataKeys.uri] as String?;
|
||||||
|
final intentMimeType = intentData[IntentDataKeys.mimeType] as String?;
|
||||||
|
|
||||||
switch (intentAction) {
|
switch (intentAction) {
|
||||||
case IntentActions.view:
|
case IntentActions.view:
|
||||||
case IntentActions.widgetOpen:
|
|
||||||
String? uri, mimeType;
|
|
||||||
final widgetId = intentData[IntentDataKeys.widgetId];
|
|
||||||
if (widgetId != null) {
|
|
||||||
// widget settings may be modified in a different process after channel setup
|
|
||||||
await settings.reload();
|
|
||||||
final page = settings.getWidgetOpenPage(widgetId);
|
|
||||||
switch (page) {
|
|
||||||
case WidgetOpenPage.home:
|
|
||||||
case WidgetOpenPage.updateWidget:
|
|
||||||
break;
|
|
||||||
case WidgetOpenPage.collection:
|
|
||||||
_initialFilters = settings.getWidgetCollectionFilters(widgetId);
|
|
||||||
case WidgetOpenPage.viewer:
|
|
||||||
uri = settings.getWidgetUri(widgetId);
|
|
||||||
}
|
|
||||||
unawaited(WidgetService.update(widgetId));
|
|
||||||
} else {
|
|
||||||
uri = intentData[IntentDataKeys.uri];
|
|
||||||
mimeType = intentData[IntentDataKeys.mimeType];
|
|
||||||
}
|
|
||||||
_secureUris = intentData[IntentDataKeys.secureUris];
|
|
||||||
if (uri != null) {
|
|
||||||
_viewerEntry = await _initViewerEntry(
|
|
||||||
uri: uri,
|
|
||||||
mimeType: mimeType,
|
|
||||||
);
|
|
||||||
if (_viewerEntry != null) {
|
|
||||||
appMode = AppMode.view;
|
appMode = AppMode.view;
|
||||||
}
|
_secureUris = (intentData[IntentDataKeys.secureUris] as List?)?.cast<String>();
|
||||||
}
|
|
||||||
case IntentActions.edit:
|
case IntentActions.edit:
|
||||||
_viewerEntry = await _initViewerEntry(
|
|
||||||
uri: intentData[IntentDataKeys.uri],
|
|
||||||
mimeType: intentData[IntentDataKeys.mimeType],
|
|
||||||
);
|
|
||||||
if (_viewerEntry != null) {
|
|
||||||
appMode = AppMode.edit;
|
appMode = AppMode.edit;
|
||||||
}
|
|
||||||
case IntentActions.setWallpaper:
|
case IntentActions.setWallpaper:
|
||||||
_viewerEntry = await _initViewerEntry(
|
|
||||||
uri: intentData[IntentDataKeys.uri],
|
|
||||||
mimeType: intentData[IntentDataKeys.mimeType],
|
|
||||||
);
|
|
||||||
if (_viewerEntry != null) {
|
|
||||||
appMode = AppMode.setWallpaper;
|
appMode = AppMode.setWallpaper;
|
||||||
}
|
|
||||||
case IntentActions.pickItems:
|
case IntentActions.pickItems:
|
||||||
// TODO TLAD apply pick mimetype(s)
|
// TODO TLAD apply pick mimetype(s)
|
||||||
// some apps define multiple types, separated by a space (maybe other signs too, like `,` `;`?)
|
// some apps define multiple types, separated by a space (maybe other signs too, like `,` `;`?)
|
||||||
String? pickMimeTypes = intentData[IntentDataKeys.mimeType];
|
final multiple = (intentData[IntentDataKeys.allowMultiple] as bool?) ?? false;
|
||||||
final multiple = intentData[IntentDataKeys.allowMultiple] ?? false;
|
debugPrint('pick mimeType=$intentMimeType multiple=$multiple');
|
||||||
debugPrint('pick mimeType=$pickMimeTypes multiple=$multiple');
|
|
||||||
appMode = multiple ? AppMode.pickMultipleMediaExternal : AppMode.pickSingleMediaExternal;
|
appMode = multiple ? AppMode.pickMultipleMediaExternal : AppMode.pickSingleMediaExternal;
|
||||||
case IntentActions.pickCollectionFilters:
|
case IntentActions.pickCollectionFilters:
|
||||||
appMode = AppMode.pickCollectionFiltersExternal;
|
appMode = AppMode.pickCollectionFiltersExternal;
|
||||||
|
@ -174,23 +137,64 @@ class _HomePageState extends State<HomePage> {
|
||||||
_initialRouteName = ScreenSaverSettingsPage.routeName;
|
_initialRouteName = ScreenSaverSettingsPage.routeName;
|
||||||
case IntentActions.search:
|
case IntentActions.search:
|
||||||
_initialRouteName = SearchPage.routeName;
|
_initialRouteName = SearchPage.routeName;
|
||||||
_initialSearchQuery = intentData[IntentDataKeys.query];
|
_initialSearchQuery = intentData[IntentDataKeys.query] as String?;
|
||||||
case IntentActions.widgetSettings:
|
case IntentActions.widgetSettings:
|
||||||
_initialRouteName = HomeWidgetSettingsPage.routeName;
|
_initialRouteName = HomeWidgetSettingsPage.routeName;
|
||||||
_widgetId = intentData[IntentDataKeys.widgetId] ?? 0;
|
_widgetId = (intentData[IntentDataKeys.widgetId] as int?) ?? 0;
|
||||||
|
case IntentActions.widgetOpen:
|
||||||
|
final widgetId = intentData[IntentDataKeys.widgetId] as int?;
|
||||||
|
if (widgetId == null) {
|
||||||
|
error = true;
|
||||||
|
} else {
|
||||||
|
// widget settings may be modified in a different process after channel setup
|
||||||
|
await settings.reload();
|
||||||
|
final page = settings.getWidgetOpenPage(widgetId);
|
||||||
|
switch (page) {
|
||||||
|
case WidgetOpenPage.collection:
|
||||||
|
_initialFilters = settings.getWidgetCollectionFilters(widgetId);
|
||||||
|
case WidgetOpenPage.viewer:
|
||||||
|
appMode = AppMode.view;
|
||||||
|
intentUri = settings.getWidgetUri(widgetId);
|
||||||
|
case WidgetOpenPage.home:
|
||||||
|
case WidgetOpenPage.updateWidget:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unawaited(WidgetService.update(widgetId));
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// do not use 'route' as extra key, as the Flutter framework acts on it
|
// do not use 'route' as extra key, as the Flutter framework acts on it
|
||||||
final extraRoute = intentData[IntentDataKeys.page];
|
final extraRoute = intentData[IntentDataKeys.page] as String?;
|
||||||
if (allowedShortcutRoutes.contains(extraRoute)) {
|
if (allowedShortcutRoutes.contains(extraRoute)) {
|
||||||
_initialRouteName = extraRoute;
|
_initialRouteName = extraRoute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_initialFilters == null) {
|
if (_initialFilters == null) {
|
||||||
final extraFilters = intentData[IntentDataKeys.filters];
|
final extraFilters = (intentData[IntentDataKeys.filters] as List?)?.cast<String>();
|
||||||
_initialFilters = extraFilters != null ? (extraFilters as List).cast<String>().map(CollectionFilter.fromJson).whereNotNull().toSet() : null;
|
_initialFilters = extraFilters?.map(CollectionFilter.fromJson).whereNotNull().toSet();
|
||||||
}
|
}
|
||||||
_initialExplorerPath = intentData[IntentDataKeys.explorerPath];
|
_initialExplorerPath = intentData[IntentDataKeys.explorerPath] as String?;
|
||||||
|
|
||||||
|
switch (appMode) {
|
||||||
|
case AppMode.view:
|
||||||
|
case AppMode.edit:
|
||||||
|
case AppMode.setWallpaper:
|
||||||
|
if (intentUri != null) {
|
||||||
|
_viewerEntry = await _initViewerEntry(
|
||||||
|
uri: intentUri,
|
||||||
|
mimeType: intentMimeType,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
error = _viewerEntry == null;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
debugPrint('Failed to init app mode=$appMode for intent data=$intentData. Fallback to main mode.');
|
||||||
|
appMode = AppMode.main;
|
||||||
|
}
|
||||||
|
|
||||||
context.read<ValueNotifier<AppMode>>().value = appMode;
|
context.read<ValueNotifier<AppMode>>().value = appMode;
|
||||||
unawaited(reportService.setCustomKey('app_mode', appMode.toString()));
|
unawaited(reportService.setCustomKey('app_mode', appMode.toString()));
|
||||||
debugPrint('Storage check complete in ${stopwatch.elapsed.inMilliseconds}ms');
|
debugPrint('Storage check complete in ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
|
|
@ -118,7 +118,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
||||||
|
|
||||||
if (ExtraEntryMapStyle.isHeavy(settings.mapStyle)) {
|
if (ExtraEntryMapStyle.isHeavy(settings.mapStyle)) {
|
||||||
_isPageAnimatingNotifier.value = true;
|
_isPageAnimatingNotifier.value = true;
|
||||||
Future.delayed(ADurations.pageTransitionAnimation * timeDilation).then((_) {
|
Future.delayed(ADurations.pageTransitionLoose * timeDilation).then((_) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
_isPageAnimatingNotifier.value = false;
|
_isPageAnimatingNotifier.value = false;
|
||||||
});
|
});
|
||||||
|
@ -142,7 +142,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
||||||
_subscriptions.add(openingCollection.source.eventBus.on<CatalogMetadataChangedEvent>().listen((e) => _updateRegionCollection()));
|
_subscriptions.add(openingCollection.source.eventBus.on<CatalogMetadataChangedEvent>().listen((e) => _updateRegionCollection()));
|
||||||
|
|
||||||
_selectedIndexNotifier.addListener(_onThumbnailIndexChanged);
|
_selectedIndexNotifier.addListener(_onThumbnailIndexChanged);
|
||||||
Future.delayed(ADurations.pageTransitionAnimation * timeDilation + const Duration(seconds: 1), () {
|
Future.delayed(ADurations.pageTransitionLoose * timeDilation + const Duration(seconds: 1), () {
|
||||||
final regionEntries = regionCollection?.sortedEntries ?? [];
|
final regionEntries = regionCollection?.sortedEntries ?? [];
|
||||||
final initialEntry = widget.initialEntry ?? regionEntries.firstOrNull;
|
final initialEntry = widget.initialEntry ?? regionEntries.firstOrNull;
|
||||||
if (initialEntry != null) {
|
if (initialEntry != null) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/empty.dart';
|
import 'package:aves/widgets/common/identity/empty.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/scroller.dart';
|
import 'package:aves/widgets/common/thumbnail/scroller.dart';
|
||||||
import 'package:aves/widgets/map/info_row.dart';
|
import 'package:aves/widgets/map/info_row.dart';
|
||||||
|
import 'package:aves/widgets/viewer/hero.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class MapEntryScroller extends StatefulWidget {
|
class MapEntryScroller extends StatefulWidget {
|
||||||
|
@ -85,7 +86,7 @@ class _MapEntryScrollerState extends State<MapEntryScroller> {
|
||||||
entryBuilder: (index) => index < regionEntries.length ? regionEntries[index] : null,
|
entryBuilder: (index) => index < regionEntries.length ? regionEntries[index] : null,
|
||||||
indexNotifier: widget.selectedIndexNotifier,
|
indexNotifier: widget.selectedIndexNotifier,
|
||||||
onTap: widget.onTap,
|
onTap: widget.onTap,
|
||||||
heroTagger: (entry) => Object.hashAll([regionCollection?.id, entry.id]),
|
heroTagger: (entry) => EntryHeroInfo(regionCollection, entry).tag,
|
||||||
highlightable: true,
|
highlightable: true,
|
||||||
showLocation: false,
|
showLocation: false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -115,7 +115,7 @@ class _AppDrawerState extends State<AppDrawer> {
|
||||||
|
|
||||||
Future<void> goTo(String routeName, WidgetBuilder pageBuilder) async {
|
Future<void> goTo(String routeName, WidgetBuilder pageBuilder) async {
|
||||||
Navigator.maybeOf(context)?.pop();
|
Navigator.maybeOf(context)?.pop();
|
||||||
await Future.delayed(ADurations.drawerTransitionAnimation);
|
await Future.delayed(ADurations.drawerTransitionLoose);
|
||||||
await Navigator.maybeOf(context)?.push(MaterialPageRoute(
|
await Navigator.maybeOf(context)?.push(MaterialPageRoute(
|
||||||
settings: RouteSettings(name: routeName),
|
settings: RouteSettings(name: routeName),
|
||||||
builder: pageBuilder,
|
builder: pageBuilder,
|
||||||
|
|
|
@ -68,7 +68,7 @@ class SettingsSwitchListTile extends StatelessWidget {
|
||||||
Expanded(child: titleWidget),
|
Expanded(child: titleWidget),
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
opacity: current ? 1 : disabledOpacity,
|
opacity: current ? 1 : disabledOpacity,
|
||||||
duration: ADurations.toggleableTransitionAnimation,
|
duration: ADurations.toggleableTransitionLoose,
|
||||||
child: trailing,
|
child: trailing,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -32,7 +32,7 @@ class LocaleTile extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.pageTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.pageTransitionLoose * timeDilation);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
settings.locale = value == systemLocaleOption ? null : value;
|
settings.locale = value == systemLocaleOption ? null : value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ class _FilePickerPageState extends State<FilePickerPage> {
|
||||||
title: Text(v.getDescription(context)),
|
title: Text(v.getDescription(context)),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.maybeOf(context)?.pop();
|
Navigator.maybeOf(context)?.pop();
|
||||||
await Future.delayed(ADurations.drawerTransitionAnimation);
|
await Future.delayed(ADurations.drawerTransitionLoose);
|
||||||
_goTo(v.path);
|
_goTo(v.path);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
|
|
|
@ -185,7 +185,7 @@ class _HiddenPaths extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.pageTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.pageTransitionLoose * timeDilation);
|
||||||
if (path != null && path.isNotEmpty) {
|
if (path != null && path.isNotEmpty) {
|
||||||
settings.changeFilterVisibility({PathFilter(path)}, false);
|
settings.changeFilterVisibility({PathFilter(path)}, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ class PrivacySection extends SettingsSection {
|
||||||
SettingsTilePrivacySaveSearchHistory(),
|
SettingsTilePrivacySaveSearchHistory(),
|
||||||
if (!settings.useTvLayout) SettingsTilePrivacyEnableBin(),
|
if (!settings.useTvLayout) SettingsTilePrivacyEnableBin(),
|
||||||
SettingsTilePrivacyHiddenItems(),
|
SettingsTilePrivacyHiddenItems(),
|
||||||
if (!settings.useTvLayout && device.canGrantDirectoryAccess) SettingsTilePrivacyStorageAccess(),
|
if (!settings.useTvLayout) SettingsTilePrivacyStorageAccess(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_isPageAnimatingNotifier = ValueNotifier(true);
|
_isPageAnimatingNotifier = ValueNotifier(true);
|
||||||
Future.delayed(ADurations.pageTransitionAnimation * timeDilation).then((_) {
|
Future.delayed(ADurations.pageTransitionLoose * timeDilation).then((_) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
_isPageAnimatingNotifier.value = false;
|
_isPageAnimatingNotifier.value = false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -159,6 +159,10 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
case EntryAction.convertMotionPhotoToStillImage:
|
case EntryAction.convertMotionPhotoToStillImage:
|
||||||
case EntryAction.viewMotionPhotoVideo:
|
case EntryAction.viewMotionPhotoVideo:
|
||||||
return _metadataActionDelegate.canApply(targetEntry, action);
|
return _metadataActionDelegate.canApply(targetEntry, action);
|
||||||
|
case EntryAction.convert:
|
||||||
|
case EntryAction.copy:
|
||||||
|
case EntryAction.move:
|
||||||
|
return !availability.isLocked;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -471,7 +475,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
if (newName == null || newName.isEmpty || newName == targetEntry.filenameWithoutExtension) return;
|
if (newName == null || newName.isEmpty || newName == targetEntry.filenameWithoutExtension) return;
|
||||||
|
|
||||||
// wait for the dialog to hide as applying the change may block the UI
|
// wait for the dialog to hide as applying the change may block the UI
|
||||||
await Future.delayed(ADurations.dialogTransitionAnimation * timeDilation);
|
await Future.delayed(ADurations.dialogTransitionLoose * timeDilation);
|
||||||
await rename(
|
await rename(
|
||||||
context,
|
context,
|
||||||
entriesToNewName: {targetEntry: '$newName${targetEntry.extension}'},
|
entriesToNewName: {targetEntry: '$newName${targetEntry.extension}'},
|
||||||
|
|
|
@ -18,6 +18,7 @@ import 'package:aves/widgets/aves_app.dart';
|
||||||
import 'package:aves/widgets/collection/collection_page.dart';
|
import 'package:aves/widgets/collection/collection_page.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
||||||
import 'package:aves/widgets/common/basic/insets.dart';
|
import 'package:aves/widgets/common/basic/insets.dart';
|
||||||
|
import 'package:aves/widgets/common/providers/viewer_entry_provider.dart';
|
||||||
import 'package:aves/widgets/viewer/action/video_action_delegate.dart';
|
import 'package:aves/widgets/viewer/action/video_action_delegate.dart';
|
||||||
import 'package:aves/widgets/viewer/controls/controller.dart';
|
import 'package:aves/widgets/viewer/controls/controller.dart';
|
||||||
import 'package:aves/widgets/viewer/controls/notifications.dart';
|
import 'package:aves/widgets/viewer/controls/notifications.dart';
|
||||||
|
@ -75,7 +76,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
late Animation<Offset> _overlayTopOffset;
|
late Animation<Offset> _overlayTopOffset;
|
||||||
EdgeInsets? _frozenViewInsets, _frozenViewPadding;
|
EdgeInsets? _frozenViewInsets, _frozenViewPadding;
|
||||||
late VideoActionDelegate _videoActionDelegate;
|
late VideoActionDelegate _videoActionDelegate;
|
||||||
final ValueNotifier<HeroInfo?> _heroInfoNotifier = ValueNotifier(null);
|
final ValueNotifier<EntryHeroInfo?> _heroInfoNotifier = ValueNotifier(null);
|
||||||
bool _isEntryTracked = true;
|
bool _isEntryTracked = true;
|
||||||
Timer? _overlayHidingTimer, _appInactiveReactionTimer;
|
Timer? _overlayHidingTimer, _appInactiveReactionTimer;
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
final initialEntry = widget.initialEntry;
|
final initialEntry = widget.initialEntry;
|
||||||
final entry = entries.firstWhereOrNull((entry) => entry.id == initialEntry.id) ?? entries.firstOrNull;
|
final entry = entries.firstWhereOrNull((entry) => entry.id == initialEntry.id) ?? entries.firstOrNull;
|
||||||
// opening hero, with viewer as target
|
// opening hero, with viewer as target
|
||||||
_heroInfoNotifier.value = HeroInfo(collection?.id, entry);
|
_heroInfoNotifier.value = EntryHeroInfo(collection, entry);
|
||||||
entryNotifier = viewerController.entryNotifier;
|
entryNotifier = viewerController.entryNotifier;
|
||||||
entryNotifier.value = entry;
|
entryNotifier.value = entry;
|
||||||
_currentEntryIndex = max(0, entry != null ? entries.indexOf(entry) : -1);
|
_currentEntryIndex = max(0, entry != null ? entries.indexOf(entry) : -1);
|
||||||
|
@ -224,7 +225,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
|
|
||||||
_onPopInvoked();
|
_onPopInvoked();
|
||||||
},
|
},
|
||||||
child: ValueListenableProvider<HeroInfo?>.value(
|
child: ValueListenableProvider<EntryHeroInfo?>.value(
|
||||||
value: _heroInfoNotifier,
|
value: _heroInfoNotifier,
|
||||||
child: NotificationListener(
|
child: NotificationListener(
|
||||||
onNotification: _handleNotification,
|
onNotification: _handleNotification,
|
||||||
|
@ -412,17 +413,17 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSlideshowBottomOverlay(Size availableSize) {
|
Widget _buildSlideshowBottomOverlay(Size availableSize) {
|
||||||
return SizedBox.fromSize(
|
return TooltipTheme(
|
||||||
size: availableSize,
|
|
||||||
child: Align(
|
|
||||||
alignment: AlignmentDirectional.bottomEnd,
|
|
||||||
child: TooltipTheme(
|
|
||||||
data: TooltipTheme.of(context).copyWith(
|
data: TooltipTheme.of(context).copyWith(
|
||||||
preferBelow: false,
|
preferBelow: false,
|
||||||
),
|
),
|
||||||
child: SlideshowButtons(
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional.bottomEnd,
|
||||||
|
child: SlideshowBottomOverlay(
|
||||||
animationController: _overlayAnimationController,
|
animationController: _overlayAnimationController,
|
||||||
),
|
availableSize: availableSize,
|
||||||
|
viewInsets: _frozenViewInsets,
|
||||||
|
viewPadding: _frozenViewPadding,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -867,7 +868,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing hero, with viewer as source
|
// closing hero, with viewer as source
|
||||||
final heroInfo = HeroInfo(collection?.id, entryNotifier.value);
|
final heroInfo = EntryHeroInfo(collection, entryNotifier.value);
|
||||||
if (_heroInfoNotifier.value != heroInfo) {
|
if (_heroInfoNotifier.value != heroInfo) {
|
||||||
_heroInfoNotifier.value = heroInfo;
|
_heroInfoNotifier.value = heroInfo;
|
||||||
// we post closing the viewer page so that hero animation source is ready
|
// we post closing the viewer page so that hero animation source is ready
|
||||||
|
@ -900,6 +901,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
predicate: (v) => v < 1,
|
predicate: (v) => v < 1,
|
||||||
animate: false,
|
animate: false,
|
||||||
);
|
);
|
||||||
|
context.read<ViewerEntryNotifier>().value = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class HeroInfo extends Equatable {
|
class EntryHeroInfo extends Equatable {
|
||||||
// hero tag should include a collection identifier, so that it animates
|
// hero tag should include a collection identifier, so that it animates
|
||||||
// between different views of the entry in the same collection (e.g. thumbnails <-> viewer)
|
// between different views of the entry in the same collection (e.g. thumbnails <-> viewer)
|
||||||
// but not between different collection instances, even with the same attributes (e.g. reloading collection page via drawer)
|
// but not between different collection instances, even with the same attributes (e.g. reloading collection page via drawer)
|
||||||
final int? collectionId;
|
final CollectionLens? collection;
|
||||||
final AvesEntry? entry;
|
final AvesEntry? entry;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [collectionId, entry?.uri];
|
List<Object?> get props => [collection?.id, entry?.uri];
|
||||||
|
|
||||||
const HeroInfo(this.collectionId, this.entry);
|
const EntryHeroInfo(this.collection, this.entry);
|
||||||
|
|
||||||
|
int get tag => Object.hashAll([collection?.id, entry?.uri]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ class _InfoPageState extends State<InfoPage> {
|
||||||
ShowImageNotification().dispatch(context);
|
ShowImageNotification().dispatch(context);
|
||||||
_scrollController.animateTo(
|
_scrollController.animateTo(
|
||||||
0,
|
0,
|
||||||
duration: ADurations.pageTransitionAnimation,
|
duration: ADurations.pageTransitionLoose,
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ class _InfoPageContentState extends State<_InfoPageContent> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onActionDelegateEvent(ActionEvent<EntryAction> event) {
|
void _onActionDelegateEvent(ActionEvent<EntryAction> event) {
|
||||||
Future.delayed(ADurations.dialogTransitionAnimation).then((_) {
|
Future.delayed(ADurations.dialogTransitionLoose).then((_) {
|
||||||
if (event is ActionStartedEvent) {
|
if (event is ActionStartedEvent) {
|
||||||
_isEditingMetadataNotifier.value = event.action;
|
_isEditingMetadataNotifier.value = event.action;
|
||||||
} else if (event is ActionEndedEvent) {
|
} else if (event is ActionEndedEvent) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class ViewerBottomOverlay extends StatefulWidget {
|
class ViewerBottomOverlay extends StatelessWidget {
|
||||||
final List<AvesEntry> entries;
|
final List<AvesEntry> entries;
|
||||||
final int index;
|
final int index;
|
||||||
final CollectionLens? collection;
|
final CollectionLens? collection;
|
||||||
|
@ -33,6 +33,10 @@ class ViewerBottomOverlay extends StatefulWidget {
|
||||||
// always keep action buttons in the lower right corner, even with RTL locales
|
// always keep action buttons in the lower right corner, even with RTL locales
|
||||||
static const actionsDirection = TextDirection.ltr;
|
static const actionsDirection = TextDirection.ltr;
|
||||||
|
|
||||||
|
AvesEntry? get entry {
|
||||||
|
return index < entries.length ? entries[index] : null;
|
||||||
|
}
|
||||||
|
|
||||||
const ViewerBottomOverlay({
|
const ViewerBottomOverlay({
|
||||||
super.key,
|
super.key,
|
||||||
required this.entries,
|
required this.entries,
|
||||||
|
@ -45,27 +49,6 @@ class ViewerBottomOverlay extends StatefulWidget {
|
||||||
required this.multiPageController,
|
required this.multiPageController,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => _ViewerBottomOverlayState();
|
|
||||||
|
|
||||||
static double actionSafeHeight(BuildContext context) {
|
|
||||||
final mqPaddingBottom = context.select<MediaQueryData, double>((mq) => max(mq.effectiveBottomPadding, mq.systemGestureInsets.bottom));
|
|
||||||
final buttonHeight = ViewerButtons.preferredHeight(context);
|
|
||||||
final thumbnailHeight = (settings.showOverlayThumbnailPreview ? ViewerThumbnailPreview.preferredHeight : 0);
|
|
||||||
return mqPaddingBottom + buttonHeight + thumbnailHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ViewerBottomOverlayState extends State<ViewerBottomOverlay> {
|
|
||||||
List<AvesEntry> get entries => widget.entries;
|
|
||||||
|
|
||||||
AvesEntry? get entry {
|
|
||||||
final index = widget.index;
|
|
||||||
return index < entries.length ? entries[index] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiPageController? get multiPageController => widget.multiPageController;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final mainEntry = entry;
|
final mainEntry = entry;
|
||||||
|
@ -73,15 +56,15 @@ class _ViewerBottomOverlayState extends State<ViewerBottomOverlay> {
|
||||||
|
|
||||||
Widget _buildContent({AvesEntry? pageEntry}) => _BottomOverlayContent(
|
Widget _buildContent({AvesEntry? pageEntry}) => _BottomOverlayContent(
|
||||||
entries: entries,
|
entries: entries,
|
||||||
index: widget.index,
|
index: index,
|
||||||
mainEntry: mainEntry,
|
mainEntry: mainEntry,
|
||||||
pageEntry: pageEntry ?? mainEntry,
|
pageEntry: pageEntry ?? mainEntry,
|
||||||
collection: widget.collection,
|
collection: collection,
|
||||||
availableSize: widget.availableSize,
|
availableSize: availableSize,
|
||||||
viewInsets: widget.viewInsets,
|
viewInsets: viewInsets,
|
||||||
viewPadding: widget.viewPadding,
|
viewPadding: viewPadding,
|
||||||
multiPageController: multiPageController,
|
multiPageController: multiPageController,
|
||||||
animationController: widget.animationController,
|
animationController: animationController,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget child = multiPageController != null
|
Widget child = multiPageController != null
|
||||||
|
@ -102,6 +85,13 @@ class _ViewerBottomOverlayState extends State<ViewerBottomOverlay> {
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double actionSafeHeight(BuildContext context) {
|
||||||
|
final mqPaddingBottom = context.select<MediaQueryData, double>((mq) => max(mq.effectiveBottomPadding, mq.systemGestureInsets.bottom));
|
||||||
|
final buttonHeight = ViewerButtons.preferredHeight(context);
|
||||||
|
final thumbnailHeight = (settings.showOverlayThumbnailPreview ? ViewerThumbnailPreview.preferredHeight : 0);
|
||||||
|
return mqPaddingBottom + buttonHeight + thumbnailHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BottomOverlayContent extends StatefulWidget {
|
class _BottomOverlayContent extends StatefulWidget {
|
||||||
|
|
|
@ -221,7 +221,7 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
rows.add(_buildRatingTagsFullRow(context));
|
rows.add(_buildRatingTagsFullRow(context));
|
||||||
}
|
}
|
||||||
if (showDescription) {
|
if (showDescription) {
|
||||||
rows.add(_buildDescriptionFullRow(context));
|
rows.add(_buildDescriptionFullRow(context, infoMaxWidth));
|
||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
@ -243,13 +243,18 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildDescriptionFullRow(BuildContext context) => _buildFullRowSwitcher(
|
Widget _buildDescriptionFullRow(BuildContext context, double infoMaxWidth) => _buildFullRowSwitcher(
|
||||||
context: context,
|
context: context,
|
||||||
visible: details.description != null,
|
visible: details.description != null,
|
||||||
builder: (context) => OverlayRowExpander(
|
builder: (context) => SizedBox(
|
||||||
|
// size it so that a long description with multiple short lines
|
||||||
|
// expands to the full width and the scroll bar is at the edge
|
||||||
|
width: infoMaxWidth,
|
||||||
|
child: OverlayRowExpander(
|
||||||
expandedNotifier: expandedNotifier,
|
expandedNotifier: expandedNotifier,
|
||||||
child: OverlayDescriptionRow(description: details.description!),
|
child: OverlayDescriptionRow(description: details.description!),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildShootingFullRow(BuildContext context, double subRowWidth) => _buildFullRowSwitcher(
|
Widget _buildShootingFullRow(BuildContext context, double subRowWidth) => _buildFullRowSwitcher(
|
||||||
|
@ -286,8 +291,14 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
required double subRowWidth,
|
required double subRowWidth,
|
||||||
required bool visible,
|
required bool visible,
|
||||||
required WidgetBuilder builder,
|
required WidgetBuilder builder,
|
||||||
}) =>
|
}) {
|
||||||
AnimatedSwitcher(
|
final child = visible
|
||||||
|
? SizedBox(
|
||||||
|
width: subRowWidth,
|
||||||
|
child: builder(context),
|
||||||
|
)
|
||||||
|
: const SizedBox();
|
||||||
|
return AnimatedSwitcher(
|
||||||
duration: context.select<DurationsData, Duration>((v) => v.viewerOverlayChangeAnimation),
|
duration: context.select<DurationsData, Duration>((v) => v.viewerOverlayChangeAnimation),
|
||||||
switchInCurve: Curves.easeInOutCubic,
|
switchInCurve: Curves.easeInOutCubic,
|
||||||
switchOutCurve: Curves.easeInOutCubic,
|
switchOutCurve: Curves.easeInOutCubic,
|
||||||
|
@ -295,36 +306,34 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
opacity: animation,
|
opacity: animation,
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
child: visible
|
child: child,
|
||||||
? SizedBox(
|
|
||||||
width: subRowWidth,
|
|
||||||
child: builder(context),
|
|
||||||
)
|
|
||||||
: const SizedBox(),
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildFullRowSwitcher({
|
Widget _buildFullRowSwitcher({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required bool visible,
|
required bool visible,
|
||||||
required WidgetBuilder builder,
|
required WidgetBuilder builder,
|
||||||
}) =>
|
}) {
|
||||||
AnimatedSwitcher(
|
final child = visible
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsets.only(top: _interRowPadding),
|
||||||
|
child: builder(context),
|
||||||
|
)
|
||||||
|
: const SizedBox();
|
||||||
|
return AnimatedSwitcher(
|
||||||
duration: context.select<DurationsData, Duration>((v) => v.viewerOverlayChangeAnimation),
|
duration: context.select<DurationsData, Duration>((v) => v.viewerOverlayChangeAnimation),
|
||||||
switchInCurve: Curves.easeInOutCubic,
|
switchInCurve: Curves.easeInOutCubic,
|
||||||
switchOutCurve: Curves.easeInOutCubic,
|
switchOutCurve: Curves.easeInOutCubic,
|
||||||
transitionBuilder: (child, animation) => FadeTransition(
|
transitionBuilder: (child, animation) => FadeTransition(
|
||||||
opacity: animation,
|
opacity: animation,
|
||||||
child: SizeTransition(
|
child: SizeTransition(
|
||||||
axisAlignment: 1,
|
|
||||||
sizeFactor: animation,
|
sizeFactor: animation,
|
||||||
|
axisAlignment: 1,
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: visible
|
child: child,
|
||||||
? Padding(
|
|
||||||
padding: const EdgeInsets.only(top: _interRowPadding),
|
|
||||||
child: builder(context),
|
|
||||||
)
|
|
||||||
: const SizedBox(),
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,64 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/view/view.dart';
|
import 'package:aves/view/view.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/media_query.dart';
|
||||||
import 'package:aves/widgets/common/identity/buttons/captioned_button.dart';
|
import 'package:aves/widgets/common/identity/buttons/captioned_button.dart';
|
||||||
import 'package:aves/widgets/common/identity/buttons/overlay_button.dart';
|
import 'package:aves/widgets/common/identity/buttons/overlay_button.dart';
|
||||||
import 'package:aves/widgets/viewer/controls/intents.dart';
|
import 'package:aves/widgets/viewer/controls/intents.dart';
|
||||||
import 'package:aves/widgets/viewer/controls/notifications.dart';
|
import 'package:aves/widgets/viewer/controls/notifications.dart';
|
||||||
|
import 'package:aves/widgets/viewer/overlay/bottom.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/viewer_buttons.dart';
|
import 'package:aves/widgets/viewer/overlay/viewer_buttons.dart';
|
||||||
import 'package:aves/widgets/viewer/slideshow_page.dart';
|
import 'package:aves/widgets/viewer/slideshow_page.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class SlideshowBottomOverlay extends StatelessWidget {
|
||||||
|
final AnimationController animationController;
|
||||||
|
final Size availableSize;
|
||||||
|
final EdgeInsets? viewInsets, viewPadding;
|
||||||
|
|
||||||
|
const SlideshowBottomOverlay({
|
||||||
|
super.key,
|
||||||
|
required this.animationController,
|
||||||
|
required this.availableSize,
|
||||||
|
this.viewInsets,
|
||||||
|
this.viewPadding,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Selector<MediaQueryData, double>(
|
||||||
|
selector: (context, mq) => max(mq.effectiveBottomPadding, mq.systemGestureInsets.bottom),
|
||||||
|
builder: (context, mqPaddingBottom, child) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: mqPaddingBottom),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: SlideshowButtons(
|
||||||
|
availableSize: availableSize,
|
||||||
|
viewInsets: viewInsets,
|
||||||
|
viewPadding: viewPadding,
|
||||||
|
animationController: animationController,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SlideshowButtons extends StatefulWidget {
|
class SlideshowButtons extends StatefulWidget {
|
||||||
|
final Size availableSize;
|
||||||
|
final EdgeInsets? viewInsets, viewPadding;
|
||||||
final AnimationController animationController;
|
final AnimationController animationController;
|
||||||
|
|
||||||
const SlideshowButtons({
|
const SlideshowButtons({
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.availableSize,
|
||||||
|
required this.viewInsets,
|
||||||
|
required this.viewPadding,
|
||||||
required this.animationController,
|
required this.animationController,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -70,7 +113,8 @@ class _SlideshowButtonsState extends State<SlideshowButtons> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FocusableActionDetector(
|
final viewInsetsPadding = (widget.viewInsets ?? EdgeInsets.zero) + (widget.viewPadding ?? EdgeInsets.zero);
|
||||||
|
final viewerButtonRow = FocusableActionDetector(
|
||||||
focusNode: _buttonRowFocusScopeNode,
|
focusNode: _buttonRowFocusScopeNode,
|
||||||
shortcuts: settings.useTvLayout
|
shortcuts: settings.useTvLayout
|
||||||
? const {
|
? const {
|
||||||
|
@ -80,26 +124,53 @@ class _SlideshowButtonsState extends State<SlideshowButtons> {
|
||||||
actions: {
|
actions: {
|
||||||
TvShowLessInfoIntent: CallbackAction<Intent>(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context)),
|
TvShowLessInfoIntent: CallbackAction<Intent>(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context)),
|
||||||
},
|
},
|
||||||
child: settings.useTvLayout
|
child: SafeArea(
|
||||||
? Row(
|
top: false,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
bottom: false,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
minimum: EdgeInsets.only(
|
||||||
children: _actions.map((action) {
|
left: viewInsetsPadding.left,
|
||||||
return CaptionedButton(
|
right: viewInsetsPadding.right,
|
||||||
scale: _buttonScale,
|
),
|
||||||
icon: action.getIcon(),
|
child: _buildButtons(context),
|
||||||
caption: action.getText(context),
|
),
|
||||||
onPressed: () => _onAction(context, action),
|
|
||||||
);
|
);
|
||||||
}).toList(),
|
|
||||||
)
|
final availableWidth = widget.availableSize.width;
|
||||||
: SafeArea(
|
return SizedBox(
|
||||||
|
width: availableWidth,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
viewerButtonRow,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildButtons(BuildContext context) {
|
||||||
|
if (settings.useTvLayout) {
|
||||||
|
return _buildTvButtonRowContent(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: false,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: _padding / 2, right: _padding / 2, bottom: _padding),
|
padding: const EdgeInsets.only(left: _padding / 2, right: _padding / 2, bottom: _padding),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
textDirection: ViewerBottomOverlay.actionsDirection,
|
||||||
children: _actions
|
children: [
|
||||||
.map((action) => Padding(
|
const Spacer(),
|
||||||
|
..._actions.map((action) => _buildOverlayButton(context, action)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildOverlayButton(BuildContext context, SlideshowAction action) {
|
||||||
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: _padding / 2),
|
padding: const EdgeInsets.symmetric(horizontal: _padding / 2),
|
||||||
child: OverlayButton(
|
child: OverlayButton(
|
||||||
scale: _buttonScale,
|
scale: _buttonScale,
|
||||||
|
@ -109,11 +180,22 @@ class _SlideshowButtonsState extends State<SlideshowButtons> {
|
||||||
tooltip: action.getText(context),
|
tooltip: action.getText(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
))
|
);
|
||||||
.toList(),
|
}
|
||||||
),
|
|
||||||
),
|
Widget _buildTvButtonRowContent(BuildContext context) {
|
||||||
),
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
textDirection: ViewerBottomOverlay.actionsDirection,
|
||||||
|
children: _actions.map((action) {
|
||||||
|
return CaptionedButton(
|
||||||
|
scale: _buttonScale,
|
||||||
|
icon: action.getIcon(),
|
||||||
|
caption: action.getText(context),
|
||||||
|
onPressed: () => _onAction(context, action),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/view/view.dart';
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/move_button.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/move_button.dart';
|
||||||
|
@ -278,6 +279,7 @@ class _ViewerButtonRowContentState extends State<ViewerButtonRowContent> {
|
||||||
...topLevelActions.map((action) => _buildPopupMenuItem(context, action, videoController)),
|
...topLevelActions.map((action) => _buildPopupMenuItem(context, action, videoController)),
|
||||||
if (exportActions.isNotEmpty)
|
if (exportActions.isNotEmpty)
|
||||||
PopupMenuExpansionPanel<EntryAction>(
|
PopupMenuExpansionPanel<EntryAction>(
|
||||||
|
enabled: !availability.isLocked,
|
||||||
value: 'export',
|
value: 'export',
|
||||||
expandedNotifier: _popupExpandedNotifier,
|
expandedNotifier: _popupExpandedNotifier,
|
||||||
icon: AIcons.export,
|
icon: AIcons.export,
|
||||||
|
@ -345,18 +347,18 @@ class _ViewerButtonRowContentState extends State<ViewerButtonRowContent> {
|
||||||
}
|
}
|
||||||
|
|
||||||
PopupMenuItem<EntryAction> _buildPopupMenuItem(BuildContext context, EntryAction action, AvesVideoController? videoController) {
|
PopupMenuItem<EntryAction> _buildPopupMenuItem(BuildContext context, EntryAction action, AvesVideoController? videoController) {
|
||||||
late final bool enabled;
|
var enabled = widget.actionDelegate.canApply(action);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case EntryAction.videoCaptureFrame:
|
case EntryAction.videoCaptureFrame:
|
||||||
enabled = videoController?.canCaptureFrameNotifier.value ?? false;
|
enabled &= videoController?.canCaptureFrameNotifier.value ?? false;
|
||||||
case EntryAction.videoToggleMute:
|
case EntryAction.videoToggleMute:
|
||||||
enabled = videoController?.canMuteNotifier.value ?? false;
|
enabled &= videoController?.canMuteNotifier.value ?? false;
|
||||||
case EntryAction.videoSelectStreams:
|
case EntryAction.videoSelectStreams:
|
||||||
enabled = videoController?.canSelectStreamNotifier.value ?? false;
|
enabled &= videoController?.canSelectStreamNotifier.value ?? false;
|
||||||
case EntryAction.videoSetSpeed:
|
case EntryAction.videoSetSpeed:
|
||||||
enabled = videoController?.canSetSpeedNotifier.value ?? false;
|
enabled &= videoController?.canSetSpeedNotifier.value ?? false;
|
||||||
default:
|
default:
|
||||||
enabled = true;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? child;
|
Widget? child;
|
||||||
|
|
|
@ -150,9 +150,9 @@ class _EntryPageViewState extends State<EntryPageView> with TickerProviderStateM
|
||||||
|
|
||||||
final animate = context.select<Settings, bool>((v) => v.animate);
|
final animate = context.select<Settings, bool>((v) => v.animate);
|
||||||
if (animate) {
|
if (animate) {
|
||||||
child = Consumer<HeroInfo?>(
|
child = Consumer<EntryHeroInfo?>(
|
||||||
builder: (context, info, child) => Hero(
|
builder: (context, info, child) => Hero(
|
||||||
tag: info != null && info.entry == mainEntry ? Object.hashAll([info.collectionId, mainEntry.id]) : hashCode,
|
tag: info != null && info.entry == mainEntry ? info.tag : hashCode,
|
||||||
transitionOnUserGestures: true,
|
transitionOnUserGestures: true,
|
||||||
child: child!,
|
child: child!,
|
||||||
),
|
),
|
||||||
|
@ -414,7 +414,11 @@ class _EntryPageViewState extends State<EntryPageView> with TickerProviderStateM
|
||||||
onScaleUpdate: onScaleUpdate,
|
onScaleUpdate: onScaleUpdate,
|
||||||
onScaleEnd: onScaleEnd,
|
onScaleEnd: onScaleEnd,
|
||||||
onFling: _onFling,
|
onFling: _onFling,
|
||||||
onTap: (c, s, a, p) => _onTap(alignment: a),
|
onTap: (c, s, a, p) {
|
||||||
|
if (c.mounted) {
|
||||||
|
_onTap(alignment: a);
|
||||||
|
}
|
||||||
|
},
|
||||||
onDoubleTap: onDoubleTap,
|
onDoubleTap: onDoubleTap,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
|
20
plugins/aves_platform_meta/android/.gitignore
vendored
20
plugins/aves_platform_meta/android/.gitignore
vendored
|
@ -1,9 +1,13 @@
|
||||||
*.iml
|
gradle-wrapper.jar
|
||||||
.gradle
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
/local.properties
|
/local.properties
|
||||||
/.idea/workspace.xml
|
GeneratedPluginRegistrant.java
|
||||||
/.idea/libraries
|
|
||||||
.DS_Store
|
# Remember to never publicly share your keystore.
|
||||||
/build
|
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||||
/captures
|
key.properties
|
||||||
.cxx
|
**/*.keystore
|
||||||
|
**/*.jks
|
||||||
|
|
|
@ -33,8 +33,8 @@ android {
|
||||||
compileSdk 34
|
compileSdk 34
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_17
|
sourceCompatibility JavaVersion.VERSION_21
|
||||||
targetCompatibility JavaVersion.VERSION_17
|
targetCompatibility JavaVersion.VERSION_21
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
|
|
Binary file not shown.
160
plugins/aves_platform_meta/android/gradlew
vendored
160
plugins/aves_platform_meta/android/gradlew
vendored
|
@ -1,160 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## Gradle start up script for UN*X
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS=""
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn ( ) {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die ( ) {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="java"
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
ulimit -n $MAX_FD
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
(0) set -- ;;
|
|
||||||
(1) set -- "$args0" ;;
|
|
||||||
(2) set -- "$args0" "$args1" ;;
|
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
|
||||||
function splitJvmOpts() {
|
|
||||||
JVM_OPTS=("$@")
|
|
||||||
}
|
|
||||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
|
||||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
|
||||||
|
|
||||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
|
90
plugins/aves_platform_meta/android/gradlew.bat
vendored
90
plugins/aves_platform_meta/android/gradlew.bat
vendored
|
@ -1,90 +0,0 @@
|
||||||
@if "%DEBUG%" == "" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS=
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windowz variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
goto execute
|
|
||||||
|
|
||||||
:4NT_args
|
|
||||||
@rem Get arguments from the 4NT Shell from JP Software
|
|
||||||
set CMD_LINE_ARGS=%$
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
|
@ -5,10 +5,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _flutterfire_internals
|
name: _flutterfire_internals
|
||||||
sha256: "9371d13b8ee442e3bfc08a24e3a1b3742c839abbfaf5eef11b79c4b862c89bf7"
|
sha256: ddc6f775260b89176d329dee26f88b9469ef46aa3228ff6a0b91caf2b2989692
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.41"
|
version: "1.3.42"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -68,10 +68,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_core
|
name: firebase_core
|
||||||
sha256: "06537da27db981947fa535bb91ca120b4e9cb59cb87278dbdde718558cafc9ff"
|
sha256: "40921de9795fbf5887ed5c0adfdf4972d5a8d7ae7e1b2bb98dea39bc02626a88"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.0"
|
version: "3.4.1"
|
||||||
firebase_core_platform_interface:
|
firebase_core_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -84,26 +84,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core_web
|
name: firebase_core_web
|
||||||
sha256: "362e52457ed2b7b180964769c1e04d1e0ea0259fdf7025fdfedd019d4ae2bd88"
|
sha256: f4ee170441ca141c5f9ee5ad8737daba3ee9c8e7efb6902aee90b4fbd178ce25
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.17.5"
|
version: "2.18.0"
|
||||||
firebase_crashlytics:
|
firebase_crashlytics:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics
|
name: firebase_crashlytics
|
||||||
sha256: "4c9872020c0d97a161362ee6af7000cfdb8666234ddc290a15252ad379bb235a"
|
sha256: c4fdbb14ba6f36794f89dc27fb5c759c9cc67ecbaeb079edc4dba515bbf9f555
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.1.1"
|
||||||
firebase_crashlytics_platform_interface:
|
firebase_crashlytics_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics_platform_interface
|
name: firebase_crashlytics_platform_interface
|
||||||
sha256: ede8a199ff03378857d3c8cbb7fa58d37c27bb5a6b75faf8415ff6925dcaae2a
|
sha256: "891d6f7ba4b93672d0e1265f27b6a9dccd56ba2cc30ce6496586b32d1d8770ac"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.6.41"
|
version: "3.6.42"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -272,10 +272,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "1.0.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.5.0 <4.0.0"
|
dart: ">=3.5.0 <4.0.0"
|
||||||
flutter: ">=3.18.0-18.0.pre.54"
|
flutter: ">=3.22.0"
|
||||||
|
|
20
plugins/aves_screen_state/android/.gitignore
vendored
20
plugins/aves_screen_state/android/.gitignore
vendored
|
@ -1,9 +1,13 @@
|
||||||
*.iml
|
gradle-wrapper.jar
|
||||||
.gradle
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
/local.properties
|
/local.properties
|
||||||
/.idea/workspace.xml
|
GeneratedPluginRegistrant.java
|
||||||
/.idea/libraries
|
|
||||||
.DS_Store
|
# Remember to never publicly share your keystore.
|
||||||
/build
|
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||||
/captures
|
key.properties
|
||||||
.cxx
|
**/*.keystore
|
||||||
|
**/*.jks
|
||||||
|
|
|
@ -4,7 +4,7 @@ version '1.0-SNAPSHOT'
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlin_version = '1.9.24'
|
kotlin_version = '1.9.24'
|
||||||
agp_version = '8.5.1'
|
agp_version = '8.6.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -30,11 +30,11 @@ apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'deckers.thibault.aves.aves_screen_state'
|
namespace 'deckers.thibault.aves.aves_screen_state'
|
||||||
compileSdk 34
|
compileSdk 35
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_17
|
sourceCompatibility JavaVersion.VERSION_21
|
||||||
targetCompatibility JavaVersion.VERSION_17
|
targetCompatibility JavaVersion.VERSION_21
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
|
|
Binary file not shown.
234
plugins/aves_screen_state/android/gradlew
vendored
234
plugins/aves_screen_state/android/gradlew
vendored
|
@ -1,234 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright © 2015-2021 the original authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
|
||||||
#
|
|
||||||
# Important for running:
|
|
||||||
#
|
|
||||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
|
||||||
# noncompliant, but you have some other compliant shell such as ksh or
|
|
||||||
# bash, then to run this script, type that shell name before the whole
|
|
||||||
# command line, like:
|
|
||||||
#
|
|
||||||
# ksh Gradle
|
|
||||||
#
|
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
|
||||||
# requires all of these POSIX shell features:
|
|
||||||
# * functions;
|
|
||||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
|
||||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
|
||||||
# * compound commands having a testable exit status, especially «case»;
|
|
||||||
# * various built-in commands including «command», «set», and «ulimit».
|
|
||||||
#
|
|
||||||
# Important for patching:
|
|
||||||
#
|
|
||||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
|
||||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
|
||||||
#
|
|
||||||
# The "traditional" practice of packing multiple parameters into a
|
|
||||||
# space-separated string is a well documented source of bugs and security
|
|
||||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
|
||||||
# options in "$@", and eventually passing that to Java.
|
|
||||||
#
|
|
||||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
|
||||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
|
||||||
# see the in-line comments for details.
|
|
||||||
#
|
|
||||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
|
||||||
# Darwin, MinGW, and NonStop.
|
|
||||||
#
|
|
||||||
# (3) This script is generated from the Groovy template
|
|
||||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
|
||||||
# within the Gradle project.
|
|
||||||
#
|
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
app_path=$0
|
|
||||||
|
|
||||||
# Need this for daisy-chained symlinks.
|
|
||||||
while
|
|
||||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
|
||||||
[ -h "$app_path" ]
|
|
||||||
do
|
|
||||||
ls=$( ls -ld "$app_path" )
|
|
||||||
link=${ls#*' -> '}
|
|
||||||
case $link in #(
|
|
||||||
/*) app_path=$link ;; #(
|
|
||||||
*) app_path=$APP_HOME$link ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=${0##*/}
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD=maximum
|
|
||||||
|
|
||||||
warn () {
|
|
||||||
echo "$*"
|
|
||||||
} >&2
|
|
||||||
|
|
||||||
die () {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
} >&2
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
nonstop=false
|
|
||||||
case "$( uname )" in #(
|
|
||||||
CYGWIN* ) cygwin=true ;; #(
|
|
||||||
Darwin* ) darwin=true ;; #(
|
|
||||||
MSYS* | MINGW* ) msys=true ;; #(
|
|
||||||
NONSTOP* ) nonstop=true ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
|
||||||
else
|
|
||||||
JAVACMD=$JAVA_HOME/bin/java
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD=java
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|
||||||
case $MAX_FD in #(
|
|
||||||
max*)
|
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
|
||||||
warn "Could not query maximum file descriptor limit"
|
|
||||||
esac
|
|
||||||
case $MAX_FD in #(
|
|
||||||
'' | soft) :;; #(
|
|
||||||
*)
|
|
||||||
ulimit -n "$MAX_FD" ||
|
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Collect all arguments for the java command, stacking in reverse order:
|
|
||||||
# * args from the command line
|
|
||||||
# * the main class name
|
|
||||||
# * -classpath
|
|
||||||
# * -D...appname settings
|
|
||||||
# * --module-path (only if needed)
|
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if "$cygwin" || "$msys" ; then
|
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
|
||||||
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
for arg do
|
|
||||||
if
|
|
||||||
case $arg in #(
|
|
||||||
-*) false ;; # don't mess with options #(
|
|
||||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
|
||||||
[ -e "$t" ] ;; #(
|
|
||||||
*) false ;;
|
|
||||||
esac
|
|
||||||
then
|
|
||||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
|
||||||
fi
|
|
||||||
# Roll the args list around exactly as many times as the number of
|
|
||||||
# args, so each arg winds up back in the position where it started, but
|
|
||||||
# possibly modified.
|
|
||||||
#
|
|
||||||
# NB: a `for` loop captures its iteration list before it begins, so
|
|
||||||
# changing the positional parameters here affects neither the number of
|
|
||||||
# iterations, nor the values presented in `arg`.
|
|
||||||
shift # remove old arg
|
|
||||||
set -- "$@" "$arg" # push replacement arg
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
|
||||||
# double quotes to make sure that they get re-expanded; and
|
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
|
||||||
|
|
||||||
set -- \
|
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
|
||||||
-classpath "$CLASSPATH" \
|
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
|
||||||
|
|
||||||
# Use "xargs" to parse quoted args.
|
|
||||||
#
|
|
||||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
|
||||||
#
|
|
||||||
# In Bash we could simply go:
|
|
||||||
#
|
|
||||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
|
||||||
# set -- "${ARGS[@]}" "$@"
|
|
||||||
#
|
|
||||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
|
||||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
|
||||||
# character that might be a shell metacharacter, then use eval to reverse
|
|
||||||
# that process (while maintaining the separation between arguments), and wrap
|
|
||||||
# the whole thing up as a single "set" statement.
|
|
||||||
#
|
|
||||||
# This will of course break if any of these variables contains a newline or
|
|
||||||
# an unmatched quote.
|
|
||||||
#
|
|
||||||
|
|
||||||
eval "set -- $(
|
|
||||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
|
||||||
xargs -n1 |
|
|
||||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
|
||||||
tr '\n' ' '
|
|
||||||
)" '"$@"'
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
|
89
plugins/aves_screen_state/android/gradlew.bat
vendored
89
plugins/aves_screen_state/android/gradlew.bat
vendored
|
@ -1,89 +0,0 @@
|
||||||
@rem
|
|
||||||
@rem Copyright 2015 the original author or authors.
|
|
||||||
@rem
|
|
||||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
@rem you may not use this file except in compliance with the License.
|
|
||||||
@rem You may obtain a copy of the License at
|
|
||||||
@rem
|
|
||||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
@rem
|
|
||||||
@rem Unless required by applicable law or agreed to in writing, software
|
|
||||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
@rem See the License for the specific language governing permissions and
|
|
||||||
@rem limitations under the License.
|
|
||||||
@rem
|
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
|
||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if "%ERRORLEVEL%" == "0" goto execute
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
|
@ -211,10 +211,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_android
|
name: google_maps_flutter_android
|
||||||
sha256: "60a005bf1ba8d178144e442f6e2d734b0ffc2cc800a05415388472f934ad6d6a"
|
sha256: "36e75af1d0bd4c7391eacdaedf9ca7632c5b9709c5ec618b04489b79ea2b3f82"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.14.4"
|
version: "2.14.6"
|
||||||
google_maps_flutter_ios:
|
google_maps_flutter_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -227,10 +227,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_platform_interface
|
name: google_maps_flutter_platform_interface
|
||||||
sha256: "4f6930fd668bf5d40feb2695d5695dbc0c35e5542b557a34ad35be491686d2ba"
|
sha256: "099874463dc4c9bff04fe4b2b8cf7284d2455c2deead8f9a59a87e1b9f028c69"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.9.0"
|
version: "2.9.2"
|
||||||
google_maps_flutter_web:
|
google_maps_flutter_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -385,10 +385,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
|
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.2"
|
version: "4.5.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
62
pubspec.lock
62
pubspec.lock
|
@ -13,10 +13,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _flutterfire_internals
|
name: _flutterfire_internals
|
||||||
sha256: "9371d13b8ee442e3bfc08a24e3a1b3742c839abbfaf5eef11b79c4b862c89bf7"
|
sha256: ddc6f775260b89176d329dee26f88b9469ef46aa3228ff6a0b91caf2b2989692
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.41"
|
version: "1.3.42"
|
||||||
_macros:
|
_macros:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: dart
|
description: dart
|
||||||
|
@ -239,18 +239,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: country_code
|
name: country_code
|
||||||
sha256: f69ccd5163b1ca43011be9632e33ebe7ffac65e49ce2afcd3e3e5228af5d91fc
|
sha256: af9f06f6ccf873ff447214c7820509867ee6f791780cc3061f0e51f7f358ee2b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.0"
|
||||||
coverage:
|
coverage:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: coverage
|
name: coverage
|
||||||
sha256: "7b594a150942e0d3be99cd45a1d0b5caff27ba5a27f292ed8e8d904ba3f167b5"
|
sha256: c1fb2dce3c0085f39dc72668e85f8e0210ec7de05345821ff58530567df345a5
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.9.2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -401,10 +401,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core
|
name: firebase_core
|
||||||
sha256: "06537da27db981947fa535bb91ca120b4e9cb59cb87278dbdde718558cafc9ff"
|
sha256: "40921de9795fbf5887ed5c0adfdf4972d5a8d7ae7e1b2bb98dea39bc02626a88"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.0"
|
version: "3.4.1"
|
||||||
firebase_core_platform_interface:
|
firebase_core_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -417,26 +417,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core_web
|
name: firebase_core_web
|
||||||
sha256: "362e52457ed2b7b180964769c1e04d1e0ea0259fdf7025fdfedd019d4ae2bd88"
|
sha256: f4ee170441ca141c5f9ee5ad8737daba3ee9c8e7efb6902aee90b4fbd178ce25
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.17.5"
|
version: "2.18.0"
|
||||||
firebase_crashlytics:
|
firebase_crashlytics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics
|
name: firebase_crashlytics
|
||||||
sha256: "4c9872020c0d97a161362ee6af7000cfdb8666234ddc290a15252ad379bb235a"
|
sha256: c4fdbb14ba6f36794f89dc27fb5c759c9cc67ecbaeb079edc4dba515bbf9f555
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.1.1"
|
||||||
firebase_crashlytics_platform_interface:
|
firebase_crashlytics_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics_platform_interface
|
name: firebase_crashlytics_platform_interface
|
||||||
sha256: ede8a199ff03378857d3c8cbb7fa58d37c27bb5a6b75faf8415ff6925dcaae2a
|
sha256: "891d6f7ba4b93672d0e1265f27b6a9dccd56ba2cc30ce6496586b32d1d8770ac"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.6.41"
|
version: "3.6.42"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -457,10 +457,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flex_seed_scheme
|
name: flex_seed_scheme
|
||||||
sha256: "86470c8dc470f55dd3e28a6d30e3253a1c176df32903263d7daeabfc0c77dbd4"
|
sha256: "7d97ba5c20f0e5cb1e3e2c17c865e1f797d129de31fc1f75d2dcce9470d6373c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.0"
|
version: "3.3.0"
|
||||||
floating:
|
floating:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -648,10 +648,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_android
|
name: google_maps_flutter_android
|
||||||
sha256: "60a005bf1ba8d178144e442f6e2d734b0ffc2cc800a05415388472f934ad6d6a"
|
sha256: "36e75af1d0bd4c7391eacdaedf9ca7632c5b9709c5ec618b04489b79ea2b3f82"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.14.4"
|
version: "2.14.6"
|
||||||
google_maps_flutter_ios:
|
google_maps_flutter_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -664,10 +664,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_platform_interface
|
name: google_maps_flutter_platform_interface
|
||||||
sha256: "4f6930fd668bf5d40feb2695d5695dbc0c35e5542b557a34ad35be491686d2ba"
|
sha256: "099874463dc4c9bff04fe4b2b8cf7284d2455c2deead8f9a59a87e1b9f028c69"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.9.0"
|
version: "2.9.2"
|
||||||
google_maps_flutter_web:
|
google_maps_flutter_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1154,10 +1154,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_platform_interface
|
name: permission_handler_platform_interface
|
||||||
sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea
|
sha256: e9c8eadee926c4532d0305dff94b85bf961f16759c3af791486613152af4b4f9
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.2"
|
version: "4.2.3"
|
||||||
permission_handler_windows:
|
permission_handler_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1218,10 +1218,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: printing
|
name: printing
|
||||||
sha256: cc4b256a5a89d5345488e3318897b595867f5181b8c5ed6fc63bfa5f2044aec3
|
sha256: de1889f30b34029fc46e5de6a9841498850b23d32942a9ee810ca36b0cb1b234
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.13.1"
|
version: "5.13.2"
|
||||||
process:
|
process:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1402,10 +1402,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf_static
|
name: shelf_static
|
||||||
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
|
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.3"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1672,10 +1672,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
|
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.2"
|
version: "4.5.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -1728,10 +1728,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "1.0.0"
|
||||||
web_socket:
|
web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1814,4 +1814,4 @@ packages:
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.5.0 <4.0.0"
|
dart: ">=3.5.0 <4.0.0"
|
||||||
flutter: ">=3.24.1"
|
flutter: ">=3.24.3"
|
||||||
|
|
|
@ -7,13 +7,13 @@ repository: https://github.com/deckerst/aves
|
||||||
# - play changelog: /whatsnew/whatsnew-en-US
|
# - play changelog: /whatsnew/whatsnew-en-US
|
||||||
# - izzy changelog: /fastlane/metadata/android/en-US/changelogs/XXX01.txt
|
# - izzy changelog: /fastlane/metadata/android/en-US/changelogs/XXX01.txt
|
||||||
# - libre changelog: /fastlane/metadata/android/en-US/changelogs/XXX.txt
|
# - libre changelog: /fastlane/metadata/android/en-US/changelogs/XXX.txt
|
||||||
version: 1.11.10+129
|
version: 1.11.11+130
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
# this project bundles Flutter SDK via `flutter_wrapper`
|
# this project bundles Flutter SDK via `flutter_wrapper`
|
||||||
# cf https://github.com/passsy/flutter_wrapper
|
# cf https://github.com/passsy/flutter_wrapper
|
||||||
flutter: 3.24.1
|
flutter: 3.24.3
|
||||||
sdk: '>=3.5.0 <4.0.0'
|
sdk: '>=3.5.0 <4.0.0'
|
||||||
|
|
||||||
# use `scripts/apply_flavor_{flavor}.sh` to set the right dependencies for the flavor
|
# use `scripts/apply_flavor_{flavor}.sh` to set the right dependencies for the flavor
|
||||||
|
@ -119,10 +119,6 @@ dependency_overrides:
|
||||||
# media_kit_video v1.2.4 depends on a specific old version of screen_brightness
|
# media_kit_video v1.2.4 depends on a specific old version of screen_brightness
|
||||||
media_kit_video: ^1.0.0
|
media_kit_video: ^1.0.0
|
||||||
screen_brightness: ^1.0.0
|
screen_brightness: ^1.0.0
|
||||||
# Because printing >=5.13.2 depends on web ^1.0.0 and firebase_core_web >=2.12.0 depends on web ^0.5.1, printing >=5.13.2 is incompatible with firebase_core_web >=2.12.0.
|
|
||||||
# And because firebase_core 3.3.0 depends on firebase_core_web ^2.17.4, printing >=5.13.2 is incompatible with firebase_core 3.3.0.
|
|
||||||
# So, because aves depends on both firebase_core 3.3.0 and printing 5.13.2, version solving failed.
|
|
||||||
printing: "5.13.1"
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -93,9 +93,14 @@ void main() {
|
||||||
final subImage = FakeMediaStoreService.newImage(subAlbum, 'image1');
|
final subImage = FakeMediaStoreService.newImage(subAlbum, 'image1');
|
||||||
final siblingImage = FakeMediaStoreService.newImage(siblingAlbum, 'image1');
|
final siblingImage = FakeMediaStoreService.newImage(siblingAlbum, 'image1');
|
||||||
|
|
||||||
final path = PathFilter('$rootAlbum/');
|
final untrailedPath = PathFilter(rootAlbum);
|
||||||
expect(path.test(rootImage), true);
|
expect(untrailedPath.test(rootImage), true);
|
||||||
expect(path.test(subImage), true);
|
expect(untrailedPath.test(subImage), true);
|
||||||
expect(path.test(siblingImage), false);
|
expect(untrailedPath.test(siblingImage), false);
|
||||||
|
|
||||||
|
final trailedPath = PathFilter('$rootAlbum/');
|
||||||
|
expect(trailedPath.test(rootImage), true);
|
||||||
|
expect(trailedPath.test(subImage), true);
|
||||||
|
expect(trailedPath.test(siblingImage), false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
In v1.11.10:
|
In v1.11.11:
|
||||||
- enjoy the app in Swedish
|
- review photos from the lock screen
|
||||||
Full changelog available on GitHub
|
Full changelog available on GitHub
|
Loading…
Reference in a new issue