Compare commits
62 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
eca1d5dbfb | ||
![]() |
5726e7bcc0 | ||
![]() |
fafebe799e | ||
![]() |
b9a66a1949 | ||
![]() |
4dd77483cd | ||
![]() |
30f96334eb | ||
![]() |
160544926c | ||
![]() |
12a89782cd | ||
![]() |
ea496e5f52 | ||
![]() |
d4d6b40be5 | ||
![]() |
7bf59106f9 | ||
![]() |
94ad4c01f4 | ||
![]() |
6803dae438 | ||
![]() |
3ebb6e8cbf | ||
![]() |
c5f06baef1 | ||
![]() |
1d7deac84d | ||
![]() |
c62e68399c | ||
![]() |
530bd1a8b0 | ||
![]() |
1c1be8ba1c | ||
![]() |
e6afda2bc9 | ||
![]() |
35aeefe34b | ||
![]() |
53b8e5b37b | ||
![]() |
4688ba01f2 | ||
![]() |
50416ad59a | ||
![]() |
ce3afd87a0 | ||
![]() |
5565ac08f7 | ||
![]() |
00681cbaee | ||
![]() |
9ea43d951c | ||
![]() |
86b0d16ad1 | ||
![]() |
d813a61b9b | ||
![]() |
6d4c765613 | ||
![]() |
a396635639 | ||
![]() |
90fa60df69 | ||
![]() |
ce11587482 | ||
![]() |
07ac7b3fda | ||
![]() |
645c199b33 | ||
![]() |
ed75dba228 | ||
![]() |
2619613ee5 | ||
![]() |
82f070f8a1 | ||
![]() |
42a869908c | ||
![]() |
a02131c7c8 | ||
![]() |
579e7a2db0 | ||
![]() |
283a3eba60 | ||
![]() |
6f7f70babe | ||
![]() |
7cd170baf9 | ||
![]() |
32fff626d2 | ||
![]() |
5b6d7af0ac | ||
![]() |
aa2b4c14e0 | ||
![]() |
bf322c0aa9 | ||
![]() |
1b87fb896d | ||
![]() |
20f6d3f2a7 | ||
![]() |
ffc6201e28 | ||
![]() |
c4e06113b4 | ||
![]() |
271809e189 | ||
![]() |
fb8a97c5c6 | ||
![]() |
cf64527c4b | ||
![]() |
055d341a84 | ||
![]() |
dc34fc6bc2 | ||
![]() |
fa16430063 | ||
![]() |
58e7adecde | ||
![]() |
b8e8e3bfba | ||
![]() |
79c5f5777b |
21 changed files with 70 additions and 201 deletions
4
.github/workflows/quality-check.yml
vendored
4
.github/workflows/quality-check.yml
vendored
|
@ -72,7 +72,7 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
|
||||
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
|
@ -86,6 +86,6 @@ jobs:
|
|||
./flutterw build apk --profile -t lib/main_play.dart --flavor play
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
|
||||
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
|
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
|
@ -71,6 +71,6 @@ jobs:
|
|||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
|
||||
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
|
@ -4,14 +4,6 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## <a id="unreleased"></a>[Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Info: show matching dynamic albums
|
||||
|
||||
### Fixed
|
||||
|
||||
- crash when decoding some large thumbnails
|
||||
|
||||
## <a id="v1.13.2"></a>[v1.13.2] - 2025-06-02
|
||||
|
||||
### Changed
|
||||
|
|
85
README.md
85
README.md
|
@ -111,96 +111,17 @@ Some users have expressed the wish to financially support the project. Thanks!
|
|||
|
||||
## Project Setup
|
||||
|
||||
### Install dependencies
|
||||
|
||||
Before running or building the app, update the dependencies for the desired flavor:
|
||||
```
|
||||
scripts/apply_flavor_play.sh
|
||||
# scripts/apply_flavor_play.sh
|
||||
```
|
||||
|
||||
To build the project, create a file named `<app dir>/android/key.properties`. It should contain a reference to a keystore for app signing, and other necessary credentials. See [key_template.properties](https://github.com/deckerst/aves/blob/develop/android/key_template.properties) for the expected keys.
|
||||
|
||||
### To run the app:
|
||||
To run the app:
|
||||
```
|
||||
./flutterw run -t lib/main_play.dart --flavor play
|
||||
```
|
||||
### To build the app:
|
||||
|
||||
creare file con le tue credenziali file.keystore
|
||||
|
||||
dove YOUR_ALIAS_NAME è il tuo unico alias name
|
||||
|
||||
e YOUR_ALIAS_PWD è la password del tuo alias
|
||||
```sh
|
||||
keytool -genkey -v -keystore file.keystore -alias YOUR_ALIAS_NAME -storepass YOUR_ALIAS_PWD -keypass YOUR_ALIAS_PWD -keyalg RSA -validity 36500
|
||||
```
|
||||
in questo caso ho inserito
|
||||
```sh
|
||||
cd android
|
||||
keytool -genkey -v -keystore file.keystore -alias FabioMich66 -storepass Master66 -keypass Master66 -keyalg RSA -validity 36500
|
||||
```
|
||||
se non puoi eseguire keytool perchè non è nel path di sistema cercalo usando
|
||||
```sh
|
||||
cd /
|
||||
sudo find -name keytool
|
||||
```
|
||||
compilare il file `<app dir>/android/key.properties`
|
||||
```
|
||||
nano android/key.properties
|
||||
```
|
||||
questi i miei dati utilizzando il format key_template.properties
|
||||
```
|
||||
storeFile=/Users/fabio/flutter_apps/aves/android/file.keystore
|
||||
storePassword=Master66
|
||||
keyAlias=FabioMich66
|
||||
keyPassword=Master66
|
||||
googleApiKey=<GOOGLE_API_KEY>
|
||||
```
|
||||
infine compilare l'apk
|
||||
```
|
||||
./flutterw build apk -t lib/main_play.dart --flavor play
|
||||
# ./flutterw run -t lib/main_play.dart --flavor play
|
||||
```
|
||||
|
||||
[Version badge]: https://img.shields.io/github/v/release/deckerst/aves?include_prereleases&sort=semver
|
||||
[Build badge]: https://img.shields.io/github/actions/workflow/status/deckerst/aves/quality-check.yml?branch=develop
|
||||
|
||||
## Android studio
|
||||
|
||||
caricare il file da github selezionando le mnù a tendina File-New-project from Version Control
|
||||
|
||||
selezionare version control tipo: git
|
||||
|
||||
inserire URL di aves
|
||||
|
||||
https://github.com/deckerst/aves
|
||||
|
||||
flaggare shallow clone with history troncated 1 commits
|
||||
|
||||
aprire la console sulla dir aves appena creata e caricare le dipendenze
|
||||
|
||||
```
|
||||
scripts/apply_flavor_izzy.sh
|
||||
```
|
||||
in settings - Languages and Framework - Dart inserire il path
|
||||
|
||||
```
|
||||
/home/fabio/flutter/bin/cache/
|
||||
```
|
||||
e spuntare project aves
|
||||
|
||||
Edit configurations e aggiungere shell script con un nome x es izzi
|
||||
|
||||
poi flaggare script text e inserire
|
||||
|
||||
./flutterw run -t lib/main_izzy.dart --flavor izzy
|
||||
|
||||
la working directory sarà una cosa così
|
||||
|
||||
/home/fabio/StudioProjects/aves
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -33,13 +33,13 @@ kotlin {
|
|||
}
|
||||
|
||||
android {
|
||||
namespace = 'deckers.thibault.aves'
|
||||
compileSdk = 36
|
||||
namespace 'deckers.thibault.aves'
|
||||
compileSdk 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId packageName
|
||||
minSdk flutter.minSdkVersion
|
||||
targetSdk 36
|
||||
targetSdk 35
|
||||
versionCode flutter.versionCode
|
||||
versionName flutter.versionName
|
||||
manifestPlaceholders = [googleApiKey: keystoreProperties["googleApiKey"] ?: "<NONE>"]
|
||||
|
@ -149,14 +149,14 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1'
|
||||
|
||||
implementation "androidx.appcompat:appcompat:1.7.1"
|
||||
implementation "androidx.appcompat:appcompat:1.7.0"
|
||||
implementation 'androidx.core:core-ktx:1.16.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.9.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.9.0'
|
||||
implementation 'androidx.media:media:1.7.0'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.security:security-crypto:1.1.0-beta01'
|
||||
implementation 'androidx.security:security-crypto:1.1.0-alpha07'
|
||||
implementation 'androidx.work:work-runtime-ktx:2.10.1'
|
||||
|
||||
implementation 'com.commonsware.cwac:document:0.5.0'
|
||||
|
@ -164,7 +164,7 @@ dependencies {
|
|||
implementation "com.github.bumptech.glide:glide:$glide_version"
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
// SLF4J implementation for `mp4parser`
|
||||
implementation 'org.slf4j:slf4j-simple:2.0.17'
|
||||
implementation 'org.slf4j:slf4j-simple:2.0.16'
|
||||
|
||||
// forked, built by JitPack:
|
||||
// - https://jitpack.io/p/deckerst/Android-TiffBitmapFactory
|
||||
|
@ -178,7 +178,7 @@ dependencies {
|
|||
implementation 'com.github.deckerst:pixymeta-android:cb1cdc932e'
|
||||
implementation project(':exifinterface')
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.13.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.11.4'
|
||||
|
||||
kapt 'androidx.annotation:annotation:1.9.1'
|
||||
ksp "com.github.bumptech.glide:ksp:$glide_version"
|
||||
|
|
|
@ -2,7 +2,6 @@ package deckers.thibault.aves.channel.calls
|
|||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkInfo
|
||||
|
@ -19,6 +18,7 @@ import kotlinx.coroutines.SupervisorJob
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
|
||||
class AnalysisHandler(private val activity: FlutterFragmentActivity, private val onAnalysisCompleted: () -> Unit) : MethodChannel.MethodCallHandler {
|
||||
private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
|
@ -38,8 +38,9 @@ class AnalysisHandler(private val activity: FlutterFragmentActivity, private val
|
|||
}
|
||||
|
||||
val preferences = activity.getSharedPreferences(AnalysisWorker.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
|
||||
preferences.edit {
|
||||
with(preferences.edit()) {
|
||||
putLong(AnalysisWorker.PREF_CALLBACK_HANDLE_KEY, callbackHandle)
|
||||
apply()
|
||||
}
|
||||
result.success(true)
|
||||
}
|
||||
|
@ -68,8 +69,9 @@ class AnalysisHandler(private val activity: FlutterFragmentActivity, private val
|
|||
// work `Data` cannot occupy more than 10240 bytes when serialized
|
||||
// so we save the possibly long list of entry IDs to shared preferences
|
||||
val preferences = activity.getSharedPreferences(AnalysisWorker.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
|
||||
preferences.edit {
|
||||
with(preferences.edit()) {
|
||||
putStringSet(AnalysisWorker.PREF_ENTRY_IDS_KEY, allEntryIds?.map { it.toString() }?.toSet())
|
||||
apply()
|
||||
}
|
||||
|
||||
val workData = workDataOf(
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package deckers.thibault.aves.channel.calls
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.LocaleConfig
|
||||
import android.app.LocaleManager
|
||||
import android.content.Context
|
||||
|
@ -103,7 +102,6 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
|||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
@SuppressLint("WrongConstant")
|
||||
val lm = context.getSystemService(Context.LOCALE_SERVICE) as? LocaleManager
|
||||
lm?.overrideLocaleConfig = LocaleConfig(LocaleList.forLanguageTags(locales.joinToString(",")))
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class GeocodingHandler(private val context: Context) : MethodCallHandler {
|
|||
private fun getAddress(call: MethodCall, result: MethodChannel.Result) {
|
||||
val latitude = call.argument<Number>("latitude")?.toDouble()
|
||||
val longitude = call.argument<Number>("longitude")?.toDouble()
|
||||
val localeLanguageTag = call.argument<String>("localeLanguageTag")
|
||||
val localeString = call.argument<String>("locale")
|
||||
val maxResults = call.argument<Int>("maxResults") ?: 1
|
||||
if (latitude == null || longitude == null) {
|
||||
result.error("getAddress-args", "missing arguments", null)
|
||||
|
@ -43,8 +43,11 @@ class GeocodingHandler(private val context: Context) : MethodCallHandler {
|
|||
return
|
||||
}
|
||||
|
||||
geocoder = geocoder ?: if (localeLanguageTag != null) {
|
||||
Geocoder(context, Locale.forLanguageTag(localeLanguageTag))
|
||||
geocoder = geocoder ?: if (localeString != null) {
|
||||
val split = localeString.split("_")
|
||||
val language = split[0]
|
||||
val country = if (split.size > 1) split[1] else ""
|
||||
Geocoder(context, Locale(language, country))
|
||||
} else {
|
||||
Geocoder(context)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package deckers.thibault.aves.channel.calls
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import deckers.thibault.aves.SearchSuggestionsProvider
|
||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
|
@ -30,8 +29,9 @@ class GlobalSearchHandler(private val context: Context) : MethodCallHandler {
|
|||
}
|
||||
|
||||
val preferences = context.getSharedPreferences(SearchSuggestionsProvider.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
|
||||
preferences.edit {
|
||||
with(preferences.edit()) {
|
||||
putLong(SearchSuggestionsProvider.CALLBACK_HANDLE_KEY, callbackHandle)
|
||||
apply()
|
||||
}
|
||||
result.success(true)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package deckers.thibault.aves.channel.calls
|
|||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||
|
@ -46,7 +45,7 @@ class SecurityHandler(private val context: Context) : MethodCallHandler {
|
|||
}
|
||||
|
||||
val preferences = getStore()
|
||||
preferences.edit {
|
||||
with(preferences.edit()) {
|
||||
when (value) {
|
||||
is Boolean -> putBoolean(key, value)
|
||||
is Float -> putFloat(key, value)
|
||||
|
@ -59,6 +58,7 @@ class SecurityHandler(private val context: Context) : MethodCallHandler {
|
|||
return
|
||||
}
|
||||
}
|
||||
apply()
|
||||
}
|
||||
result.success(true)
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ import android.graphics.Bitmap
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.util.Size
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.graphics.scale
|
||||
import androidx.core.net.toUri
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.DecodeFormat
|
||||
|
@ -19,7 +17,6 @@ import deckers.thibault.aves.decoder.AvesAppGlideModule
|
|||
import deckers.thibault.aves.decoder.MultiPageImage
|
||||
import deckers.thibault.aves.utils.BitmapUtils
|
||||
import deckers.thibault.aves.utils.BitmapUtils.applyExifOrientation
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import deckers.thibault.aves.utils.MimeTypes
|
||||
import deckers.thibault.aves.utils.MimeTypes.SVG
|
||||
import deckers.thibault.aves.utils.MimeTypes.isVideo
|
||||
|
@ -28,8 +25,6 @@ import deckers.thibault.aves.utils.MimeTypes.needRotationAfterGlide
|
|||
import deckers.thibault.aves.utils.StorageUtils
|
||||
import deckers.thibault.aves.utils.UriUtils.tryParseId
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ThumbnailFetcher internal constructor(
|
||||
private val context: Context,
|
||||
|
@ -82,29 +77,6 @@ class ThumbnailFetcher internal constructor(
|
|||
}
|
||||
}
|
||||
|
||||
if (bitmap != null) {
|
||||
if (bitmap.width > width && bitmap.height > height) {
|
||||
val scalingFactor: Double = min(bitmap.width.toDouble() / width, bitmap.height.toDouble() / height)
|
||||
val dstWidth = (bitmap.width / scalingFactor).roundToInt()
|
||||
val dstHeight = (bitmap.height / scalingFactor).roundToInt()
|
||||
Log.d(
|
||||
LOG_TAG, "rescale thumbnail for mimeType=$mimeType uri=$uri width=$width height=$height" +
|
||||
", with bitmap byteCount=${bitmap.byteCount} size=${bitmap.width}x${bitmap.height}" +
|
||||
", to target=${dstWidth}x${dstHeight}"
|
||||
)
|
||||
bitmap = bitmap.scale(dstWidth, dstHeight)
|
||||
}
|
||||
|
||||
if (bitmap.byteCount > BITMAP_SIZE_DANGER_THRESHOLD) {
|
||||
result.error(
|
||||
"getThumbnail-large", "thumbnail bitmap dangerously large" +
|
||||
" for mimeType=$mimeType uri=$uri pageId=$pageId width=$width height=$height" +
|
||||
", with bitmap byteCount=${bitmap.byteCount} size=${bitmap.width}x${bitmap.height} config=${bitmap.config?.name}", null
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// do not recycle bitmaps fetched from `ContentResolver` or Glide as their lifecycle is unknown
|
||||
val recycle = false
|
||||
val bytes = BitmapUtils.getRawBytes(bitmap, recycle = recycle)
|
||||
|
@ -172,9 +144,4 @@ class ThumbnailFetcher internal constructor(
|
|||
Glide.with(context).clear(target)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG_TAG = LogUtils.createTag<ThumbnailFetcher>()
|
||||
private const val BITMAP_SIZE_DANGER_THRESHOLD = 20 * (1 shl 20) // MB
|
||||
}
|
||||
}
|
|
@ -81,12 +81,12 @@ object PixyMetaHelper {
|
|||
output: OutputStream,
|
||||
iptcDataList: List<FieldMap>?,
|
||||
) {
|
||||
val iptc: List<IPTCDataSet> = iptcDataList?.flatMap {
|
||||
val iptc = iptcDataList?.flatMap {
|
||||
val record = it["record"] as Int
|
||||
val tag = it["tag"] as Int
|
||||
val values = it["values"] as List<*>
|
||||
values.map { data -> IPTCDataSet(IPTCRecord.fromRecordNumber(record), tag, data as ByteArray) }
|
||||
} ?: ArrayList()
|
||||
} ?: ArrayList<IPTCDataSet>()
|
||||
Metadata.insertIPTC(input, output, iptc)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,5 +5,5 @@ import kotlin.math.pow
|
|||
|
||||
object MathUtils {
|
||||
fun highestPowerOf2(x: Int): Int = highestPowerOf2(x.toDouble())
|
||||
fun highestPowerOf2(x: Double): Int = if (x < 1) 0 else 2.toDouble().pow(log2(x).toInt()).toInt()
|
||||
private fun highestPowerOf2(x: Double): Int = if (x < 1) 0 else 2.toDouble().pow(log2(x).toInt()).toInt()
|
||||
}
|
|
@ -18,10 +18,10 @@ pluginManagement {
|
|||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.10.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.1.21" apply false
|
||||
id("com.google.devtools.ksp") version "2.1.21-2.0.1" apply false
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||
id("com.android.application") version "8.8.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.1.10" apply false
|
||||
id("com.google.devtools.ksp") version "2.1.10-1.0.29" apply false
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
|
||||
}
|
||||
|
||||
include(":app")
|
||||
|
|
|
@ -15,7 +15,7 @@ class GeocodingService {
|
|||
final result = await _platform.invokeMethod('getAddress', <String, dynamic>{
|
||||
'latitude': coordinates.latitude,
|
||||
'longitude': coordinates.longitude,
|
||||
'localeLanguageTag': locale.toLanguageTag(),
|
||||
'locale': locale.toString(),
|
||||
// we only really need one address, but sometimes the native geocoder
|
||||
// returns nothing with `maxResults` of 1, but succeeds with `maxResults` of 2+
|
||||
'maxResults': 2,
|
||||
|
|
|
@ -247,7 +247,7 @@ class PlatformMediaFetchService implements MediaFetchService {
|
|||
return InteropDecoding.bytesToCodec(bytes);
|
||||
}
|
||||
} on PlatformException catch (e, stack) {
|
||||
if (_isUnknownVisual(mimeType) || e.code == 'getThumbnail-large') {
|
||||
if (_isUnknownVisual(mimeType)) {
|
||||
await reportService.recordError(e, stack);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import 'package:aves/theme/durations.dart';
|
|||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/themes.dart';
|
||||
import 'package:aves/view/view.dart';
|
||||
import 'package:aves/widgets/aves_app.dart';
|
||||
import 'package:aves/widgets/collection/collection_page.dart';
|
||||
import 'package:aves/widgets/collection/entry_set_action_delegate.dart';
|
||||
import 'package:aves/widgets/collection/filter_bar.dart';
|
||||
|
@ -57,7 +56,7 @@ class CollectionAppBar extends StatefulWidget {
|
|||
State<CollectionAppBar> createState() => _CollectionAppBarState();
|
||||
}
|
||||
|
||||
class _CollectionAppBarState extends State<CollectionAppBar> with RouteAware, SingleTickerProviderStateMixin, WidgetsBindingObserver {
|
||||
class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerProviderStateMixin, WidgetsBindingObserver {
|
||||
final Set<StreamSubscription> _subscriptions = {};
|
||||
final EntrySetActionDelegate _actionDelegate = EntrySetActionDelegate();
|
||||
late AnimationController _browseToSelectAnimation;
|
||||
|
@ -123,15 +122,6 @@ class _CollectionAppBarState extends State<CollectionAppBar> with RouteAware, Si
|
|||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
final route = ModalRoute.of(context);
|
||||
if (route is PageRoute) {
|
||||
AvesApp.pageRouteObserver.subscribe(this, route);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant CollectionAppBar oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
|
@ -150,7 +140,6 @@ class _CollectionAppBarState extends State<CollectionAppBar> with RouteAware, Si
|
|||
..forEach((sub) => sub.cancel())
|
||||
..clear();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
AvesApp.pageRouteObserver.unsubscribe(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -162,13 +151,6 @@ class _CollectionAppBarState extends State<CollectionAppBar> with RouteAware, Si
|
|||
widget.collection.filterChangeNotifier.removeListener(_onFilterChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
void didPushNext() {
|
||||
// unfocus when navigating away, so that when navigating back,
|
||||
// the query bar does not get back focus and bring the keyboard
|
||||
_queryBarFocusNode.unfocus();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
// when top padding or text scale factor change
|
||||
|
|
|
@ -11,7 +11,6 @@ import 'package:aves/model/source/collection_source.dart';
|
|||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/themes.dart';
|
||||
import 'package:aves/view/view.dart';
|
||||
import 'package:aves/widgets/aves_app.dart';
|
||||
import 'package:aves/widgets/common/action_controls/togglers/title_search.dart';
|
||||
import 'package:aves/widgets/common/app_bar/app_bar_subtitle.dart';
|
||||
import 'package:aves/widgets/common/app_bar/app_bar_title.dart';
|
||||
|
@ -79,7 +78,7 @@ class FilterGridAppBar<T extends CollectionFilter, CSAD extends ChipSetActionDel
|
|||
}
|
||||
}
|
||||
|
||||
class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetActionDelegate<T>> extends State<FilterGridAppBar<T, CSAD>> with RouteAware, SingleTickerProviderStateMixin, WidgetsBindingObserver {
|
||||
class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetActionDelegate<T>> extends State<FilterGridAppBar<T, CSAD>> with SingleTickerProviderStateMixin, WidgetsBindingObserver {
|
||||
final Set<StreamSubscription> _subscriptions = {};
|
||||
late AnimationController _browseToSelectAnimation;
|
||||
final ValueNotifier<bool> _isSelectingNotifier = ValueNotifier(false);
|
||||
|
@ -113,15 +112,6 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
|
|||
WidgetsBinding.instance.addPostFrameCallback((_) => _updateAppBarHeight());
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
final route = ModalRoute.of(context);
|
||||
if (route is PageRoute) {
|
||||
AvesApp.pageRouteObserver.subscribe(this, route);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_queryBarFocusNode.dispose();
|
||||
|
@ -132,17 +122,9 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
|
|||
..forEach((sub) => sub.cancel())
|
||||
..clear();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
AvesApp.pageRouteObserver.unsubscribe(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didPushNext() {
|
||||
// unfocus when navigating away, so that when navigating back,
|
||||
// the query bar does not get back focus and bring the keyboard
|
||||
_queryBarFocusNode.unfocus();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
// when text scale factor changes
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/image_providers/app_icon_image_provider.dart';
|
||||
import 'package:aves/model/app_inventory.dart';
|
||||
import 'package:aves/model/dynamic_albums.dart';
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/entry/extensions/favourites.dart';
|
||||
import 'package:aves/model/entry/extensions/multipage.dart';
|
||||
|
@ -134,7 +133,6 @@ class _BasicSectionState extends State<BasicSection> {
|
|||
if (entry.isPureVideo && !entry.is360) MimeFilter.video,
|
||||
if (dateTime != null) ...[DateFilter(DateLevel.ymd, dateTime.date), WeekDayFilter(dateTime.weekday)],
|
||||
if (album != null) StoredAlbumFilter(album, collection?.source.getStoredAlbumDisplayName(context, album)),
|
||||
...dynamicAlbums.all.where((v) => v.test(entry)).toSet(),
|
||||
if (entry.rating != 0) RatingFilter(entry.rating),
|
||||
...tags.map(TagFilter.new),
|
||||
};
|
||||
|
|
|
@ -209,7 +209,7 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> {
|
|||
bitmapScaling: MapBitmapScaling.none,
|
||||
),
|
||||
position: _toServiceLatLng(dotLocation),
|
||||
zIndexInt: 1,
|
||||
zIndex: 1,
|
||||
)
|
||||
},
|
||||
polylines: {
|
||||
|
|
32
pubspec.lock
32
pubspec.lock
|
@ -112,6 +112,14 @@ packages:
|
|||
url: "https://github.com/deckerst/flutter_google_charts.git"
|
||||
source: git
|
||||
version: "0.12.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
cli_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -172,10 +180,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080
|
||||
sha256: "4b8701e48a58f7712492c9b1f7ba0bb9d525644dd66d023b62e1fc8cdb560c8a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.14.1"
|
||||
version: "1.14.0"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -580,10 +588,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: google_maps_flutter_platform_interface
|
||||
sha256: f8293f072ed8b068b092920a72da6693aa8b3d62dc6b5c5f0bc44c969a8a776c
|
||||
sha256: "970c8f766c02909c7be282dea923c971f83a88adaf07f8871d0aacebc3b07bb2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.12.1"
|
||||
version: "2.11.1"
|
||||
google_maps_flutter_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -672,6 +680,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.1"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.0"
|
||||
latlong2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1218,6 +1234,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
qr:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
Loading…
Reference in a new issue