Merge branch 'develop'
This commit is contained in:
commit
a02131c7c8
89 changed files with 747 additions and 391 deletions
2
.flutter
2
.flutter
|
@ -1 +1 @@
|
||||||
Subproject commit abb292a07e20d696c4568099f918f6c5f330e6b0
|
Subproject commit ba393198430278b6595976de84fe170f553cc728
|
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
||||||
name: Build and release artifacts.
|
name: Build and release artifacts.
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
@ -75,7 +75,7 @@ jobs:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Upload app bundle
|
- name: Upload app bundle
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: appbundle
|
name: appbundle
|
||||||
path: outputs/app-play-release.aab
|
path: outputs/app-play-release.aab
|
||||||
|
@ -85,15 +85,15 @@ jobs:
|
||||||
needs: [ build ]
|
needs: [ build ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Get appbundle from artifacts.
|
- name: Get appbundle from artifacts.
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: appbundle
|
name: appbundle
|
||||||
|
|
||||||
- name: Release app to beta channel.
|
- name: Release app to beta channel.
|
||||||
uses: r0adkll/upload-google-play@v1.1.1
|
uses: r0adkll/upload-google-play@v1.1.3
|
||||||
with:
|
with:
|
||||||
serviceAccountJsonPlainText: ${{ secrets.PLAYSTORE_ACCOUNT_KEY }}
|
serviceAccountJsonPlainText: ${{ secrets.PLAYSTORE_ACCOUNT_KEY }}
|
||||||
packageName: deckers.thibault.aves
|
packageName: deckers.thibault.aves
|
||||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -4,6 +4,22 @@ 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.10.6"></a>[v1.10.6] - 2024-03-11
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Cataloguing: detect/filter HDR videos
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- check Media Store changes when resuming app
|
||||||
|
- disabling animations also applies to pop up menus
|
||||||
|
- upgraded Flutter to stable v3.19.3
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- engine leak from analysis worker
|
||||||
|
|
||||||
## <a id="v1.10.5"></a>[v1.10.5] - 2024-02-22
|
## <a id="v1.10.5"></a>[v1.10.5] - 2024-02-22
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -44,11 +44,22 @@ class AnalysisWorker(context: Context, parameters: WorkerParameters) : Coroutine
|
||||||
workCont = cont
|
workCont = cont
|
||||||
onStart()
|
onStart()
|
||||||
}
|
}
|
||||||
|
dispose()
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun dispose() {
|
||||||
|
Log.i(LOG_TAG, "Clean analysis worker $id")
|
||||||
|
flutterEngine?.let {
|
||||||
|
FlutterUtils.runOnUiThread {
|
||||||
|
it.destroy()
|
||||||
|
}
|
||||||
|
flutterEngine = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun onStart() {
|
private fun onStart() {
|
||||||
Log.i(LOG_TAG, "Start analysis worker")
|
Log.i(LOG_TAG, "Start analysis worker $id")
|
||||||
runBlocking {
|
runBlocking {
|
||||||
FlutterUtils.initFlutterEngine(applicationContext, SHARED_PREFERENCES_KEY, CALLBACK_HANDLE_KEY) {
|
FlutterUtils.initFlutterEngine(applicationContext, SHARED_PREFERENCES_KEY, CALLBACK_HANDLE_KEY) {
|
||||||
flutterEngine = it
|
flutterEngine = it
|
||||||
|
|
|
@ -175,6 +175,18 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
mediaStoreChangeStreamHandler.onAppResume()
|
||||||
|
settingsChangeStreamHandler.onAppResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
mediaStoreChangeStreamHandler.onAppPause()
|
||||||
|
settingsChangeStreamHandler.onAppPause()
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
Log.i(LOG_TAG, "onStop")
|
Log.i(LOG_TAG, "onStop")
|
||||||
super.onStop()
|
super.onStop()
|
||||||
|
|
|
@ -15,8 +15,12 @@ import android.util.Log
|
||||||
import androidx.exifinterface.media.ExifInterface
|
import androidx.exifinterface.media.ExifInterface
|
||||||
import com.drew.metadata.file.FileTypeDirectory
|
import com.drew.metadata.file.FileTypeDirectory
|
||||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||||
import deckers.thibault.aves.metadata.*
|
import deckers.thibault.aves.metadata.ExifInterfaceHelper
|
||||||
|
import deckers.thibault.aves.metadata.MediaMetadataRetrieverHelper
|
||||||
|
import deckers.thibault.aves.metadata.Metadata
|
||||||
|
import deckers.thibault.aves.metadata.Mp4ParserHelper
|
||||||
import deckers.thibault.aves.metadata.Mp4ParserHelper.dumpBoxes
|
import deckers.thibault.aves.metadata.Mp4ParserHelper.dumpBoxes
|
||||||
|
import deckers.thibault.aves.metadata.PixyMetaHelper
|
||||||
import deckers.thibault.aves.metadata.metadataextractor.Helper
|
import deckers.thibault.aves.metadata.metadataextractor.Helper
|
||||||
import deckers.thibault.aves.model.FieldMap
|
import deckers.thibault.aves.model.FieldMap
|
||||||
import deckers.thibault.aves.utils.LogUtils
|
import deckers.thibault.aves.utils.LogUtils
|
||||||
|
|
|
@ -12,7 +12,7 @@ import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import com.google.android.material.color.DynamicColors
|
import com.google.android.material.color.DynamicColors
|
||||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||||
import deckers.thibault.aves.model.FieldMap
|
import deckers.thibault.aves.model.FieldMap
|
||||||
import deckers.thibault.aves.utils.MimeTypes
|
import deckers.thibault.aves.utils.MemoryUtils
|
||||||
import io.flutter.plugin.common.MethodCall
|
import io.flutter.plugin.common.MethodCall
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||||
|
@ -35,6 +35,8 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
||||||
"getPerformanceClass" -> safe(call, result, ::getPerformanceClass)
|
"getPerformanceClass" -> safe(call, result, ::getPerformanceClass)
|
||||||
"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)
|
||||||
|
"requestGarbageCollection" -> safe(call, result, ::requestGarbageCollection)
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +125,15 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getAvailableHeapSize(@Suppress("unused_parameter") methodCall: MethodCall, result: MethodChannel.Result) {
|
||||||
|
result.success(MemoryUtils.getAvailableHeapSize())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestGarbageCollection(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
Runtime.getRuntime().gc()
|
||||||
|
result.success(true)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val CHANNEL = "deckers.thibault/aves/device"
|
const val CHANNEL = "deckers.thibault/aves/device"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package deckers.thibault.aves.channel.calls
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.MediaStore
|
||||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||||
import deckers.thibault.aves.model.provider.MediaStoreImageProvider
|
import deckers.thibault.aves.model.provider.MediaStoreImageProvider
|
||||||
import io.flutter.plugin.common.MethodCall
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
@ -20,13 +22,15 @@ class MediaStoreHandler(private val context: Context) : MethodCallHandler {
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"checkObsoleteContentIds" -> ioScope.launch { safe(call, result, ::checkObsoleteContentIds) }
|
"checkObsoleteContentIds" -> ioScope.launch { safe(call, result, ::checkObsoleteContentIds) }
|
||||||
"checkObsoletePaths" -> ioScope.launch { safe(call, result, ::checkObsoletePaths) }
|
"checkObsoletePaths" -> ioScope.launch { safe(call, result, ::checkObsoletePaths) }
|
||||||
|
"getChangedUris" -> ioScope.launch { safe(call, result, ::getChangedUris) }
|
||||||
|
"getGeneration" -> ioScope.launch { safe(call, result, ::getGeneration) }
|
||||||
"scanFile" -> ioScope.launch { safe(call, result, ::scanFile) }
|
"scanFile" -> ioScope.launch { safe(call, result, ::scanFile) }
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkObsoleteContentIds(call: MethodCall, result: MethodChannel.Result) {
|
private fun checkObsoleteContentIds(call: MethodCall, result: MethodChannel.Result) {
|
||||||
val knownContentIds = call.argument<List<Int?>>("knownContentIds")
|
val knownContentIds = call.argument<List<Number?>>("knownContentIds")?.map { it?.toLong() }
|
||||||
if (knownContentIds == null) {
|
if (knownContentIds == null) {
|
||||||
result.error("checkObsoleteContentIds-args", "missing arguments", null)
|
result.error("checkObsoleteContentIds-args", "missing arguments", null)
|
||||||
return
|
return
|
||||||
|
@ -35,7 +39,7 @@ class MediaStoreHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkObsoletePaths(call: MethodCall, result: MethodChannel.Result) {
|
private fun checkObsoletePaths(call: MethodCall, result: MethodChannel.Result) {
|
||||||
val knownPathById = call.argument<Map<Int?, String?>>("knownPathById")
|
val knownPathById = call.argument<Map<Number?, String?>>("knownPathById")?.mapKeys { it.key?.toLong() }
|
||||||
if (knownPathById == null) {
|
if (knownPathById == null) {
|
||||||
result.error("checkObsoletePaths-args", "missing arguments", null)
|
result.error("checkObsoletePaths-args", "missing arguments", null)
|
||||||
return
|
return
|
||||||
|
@ -43,6 +47,25 @@ class MediaStoreHandler(private val context: Context) : MethodCallHandler {
|
||||||
result.success(MediaStoreImageProvider().checkObsoletePaths(context, knownPathById))
|
result.success(MediaStoreImageProvider().checkObsoletePaths(context, knownPathById))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getChangedUris(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
val sinceGeneration = call.argument<Int>("sinceGeneration")
|
||||||
|
if (sinceGeneration == null) {
|
||||||
|
result.error("getChangedUris-args", "missing arguments", null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val uris = MediaStoreImageProvider().getChangedUris(context, sinceGeneration)
|
||||||
|
result.success(uris)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getGeneration(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
val generation = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
MediaStore.getGeneration(context, MediaStore.VOLUME_EXTERNAL_PRIMARY)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
result.success(generation)
|
||||||
|
}
|
||||||
|
|
||||||
private fun scanFile(call: MethodCall, result: MethodChannel.Result) {
|
private fun scanFile(call: MethodCall, result: MethodChannel.Result) {
|
||||||
val path = call.argument<String>("path")
|
val path = call.argument<String>("path")
|
||||||
val mimeType = call.argument<String>("mimeType")
|
val mimeType = call.argument<String>("mimeType")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package deckers.thibault.aves.channel.calls
|
package deckers.thibault.aves.channel.calls
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.media.MediaFormat
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
@ -559,7 +560,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
|
|
||||||
// identification of embedded gain map
|
// identification of embedded gain map
|
||||||
if (xmpMeta.hasHdrGainMap()) {
|
if (xmpMeta.hasHdrGainMap()) {
|
||||||
flags = flags or MASK_HAS_HDR_GAIN_MAP
|
flags = flags or MASK_IS_HDR
|
||||||
}
|
}
|
||||||
} catch (e: XMPException) {
|
} catch (e: XMPException) {
|
||||||
Log.w(LOG_TAG, "failed to read XMP directory for uri=$uri", e)
|
Log.w(LOG_TAG, "failed to read XMP directory for uri=$uri", e)
|
||||||
|
@ -797,6 +798,14 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
retriever.getSafeInt(MediaMetadataRetriever.METADATA_KEY_COLOR_TRANSFER) {
|
||||||
|
if (it == MediaFormat.COLOR_TRANSFER_ST2084 || it == MediaFormat.COLOR_TRANSFER_HLG) {
|
||||||
|
flags = flags or MASK_IS_HDR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
metadataMap[KEY_FLAGS] = flags
|
metadataMap[KEY_FLAGS] = flags
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(LOG_TAG, "failed to get catalog metadata by MediaMetadataRetriever for uri=$uri", e)
|
Log.w(LOG_TAG, "failed to get catalog metadata by MediaMetadataRetriever for uri=$uri", e)
|
||||||
|
@ -1300,7 +1309,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
private const val MASK_IS_360 = 1 shl 3
|
private const val MASK_IS_360 = 1 shl 3
|
||||||
private const val MASK_IS_MULTIPAGE = 1 shl 4
|
private const val MASK_IS_MULTIPAGE = 1 shl 4
|
||||||
private const val MASK_IS_MOTION_PHOTO = 1 shl 5
|
private const val MASK_IS_MOTION_PHOTO = 1 shl 5
|
||||||
private const val MASK_HAS_HDR_GAIN_MAP = 1 shl 6
|
private const val MASK_IS_HDR = 1 shl 6 // for images: embedded HDR gainmap, for videos: HDR color transfer
|
||||||
private const val XMP_SUBJECTS_SEPARATOR = ";"
|
private const val XMP_SUBJECTS_SEPARATOR = ";"
|
||||||
|
|
||||||
// overlay metadata
|
// overlay metadata
|
||||||
|
|
|
@ -135,7 +135,7 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
val trashDirs = context.getExternalFilesDirs(null).mapNotNull { StorageUtils.trashDirFor(context, it.path) }
|
val trashDirs = context.getExternalFilesDirs(null).mapNotNull { StorageUtils.trashDirFor(context, it.path) }
|
||||||
val trashItemPaths = trashDirs.flatMap { dir -> dir.listFiles()?.map { file -> file.path } ?: listOf() }
|
val trashItemPaths = trashDirs.flatMap { dir -> dir.listFiles()?.mapNotNull { file -> file?.path } ?: listOf() }
|
||||||
val untrackedPaths = trashItemPaths.filterNot(knownPaths::contains).toList()
|
val untrackedPaths = trashItemPaths.filterNot(knownPaths::contains).toList()
|
||||||
|
|
||||||
result.success(untrackedPaths)
|
result.success(untrackedPaths)
|
||||||
|
@ -150,7 +150,7 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
val vaultDir = File(StorageUtils.getVaultRoot(context), vault)
|
val vaultDir = File(StorageUtils.getVaultRoot(context), vault)
|
||||||
val vaultItemPaths = vaultDir.listFiles()?.map { file -> file.path } ?: listOf()
|
val vaultItemPaths = vaultDir.listFiles()?.mapNotNull { file -> file?.path } ?: listOf()
|
||||||
val untrackedPaths = vaultItemPaths.filterNot(knownPaths::contains).toList()
|
val untrackedPaths = vaultItemPaths.filterNot(knownPaths::contains).toList()
|
||||||
|
|
||||||
result.success(untrackedPaths)
|
result.success(untrackedPaths)
|
||||||
|
|
|
@ -30,12 +30,26 @@ class MediaStoreChangeStreamHandler(private val context: Context) : EventChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
onAppResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dispose() {
|
||||||
|
onAppPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAppResume() {
|
||||||
|
Log.i(LOG_TAG, "start listening to Media Store")
|
||||||
context.contentResolver.apply {
|
context.contentResolver.apply {
|
||||||
registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, contentObserver)
|
registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, contentObserver)
|
||||||
registerContentObserver(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true, contentObserver)
|
registerContentObserver(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true, contentObserver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onAppPause() {
|
||||||
|
Log.i(LOG_TAG, "stop listening to Media Store")
|
||||||
|
context.contentResolver.unregisterContentObserver(contentObserver)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onListen(arguments: Any?, eventSink: EventSink) {
|
override fun onListen(arguments: Any?, eventSink: EventSink) {
|
||||||
this.eventSink = eventSink
|
this.eventSink = eventSink
|
||||||
handler = Handler(Looper.getMainLooper())
|
handler = Handler(Looper.getMainLooper())
|
||||||
|
@ -45,10 +59,6 @@ class MediaStoreChangeStreamHandler(private val context: Context) : EventChannel
|
||||||
Log.i(LOG_TAG, "onCancel arguments=$arguments")
|
Log.i(LOG_TAG, "onCancel arguments=$arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dispose() {
|
|
||||||
context.contentResolver.unregisterContentObserver(contentObserver)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun success(uri: String?) {
|
private fun success(uri: String?) {
|
||||||
handler?.post {
|
handler?.post {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -19,13 +19,12 @@ class MediaStoreStreamHandler(private val context: Context, arguments: Any?) : E
|
||||||
private lateinit var eventSink: EventSink
|
private lateinit var eventSink: EventSink
|
||||||
private lateinit var handler: Handler
|
private lateinit var handler: Handler
|
||||||
|
|
||||||
private var knownEntries: Map<Int?, Int?>? = null
|
private var knownEntries: Map<Long?, Int?>? = null
|
||||||
private var directory: String? = null
|
private var directory: String? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (arguments is Map<*, *>) {
|
if (arguments is Map<*, *>) {
|
||||||
@Suppress("unchecked_cast")
|
knownEntries = (arguments["knownEntries"] as? Map<*, *>?)?.map { (it.key as Number?)?.toLong() to it.value as Int? }?.toMap()
|
||||||
knownEntries = arguments["knownEntries"] as Map<Int?, Int?>?
|
|
||||||
directory = arguments["directory"] as String?
|
directory = arguments["directory"] as String?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,9 +62,21 @@ class SettingsChangeStreamHandler(private val context: Context) : EventChannel.S
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
context.contentResolver.apply {
|
onAppResume()
|
||||||
registerContentObserver(Settings.System.CONTENT_URI, true, contentObserver)
|
}
|
||||||
}
|
|
||||||
|
fun dispose() {
|
||||||
|
onAppPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAppResume() {
|
||||||
|
Log.i(LOG_TAG, "start listening to system settings")
|
||||||
|
context.contentResolver.registerContentObserver(Settings.System.CONTENT_URI, true, contentObserver)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAppPause() {
|
||||||
|
Log.i(LOG_TAG, "stop listening to system settings")
|
||||||
|
context.contentResolver.unregisterContentObserver(contentObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onListen(arguments: Any?, eventSink: EventSink) {
|
override fun onListen(arguments: Any?, eventSink: EventSink) {
|
||||||
|
@ -76,10 +88,6 @@ class SettingsChangeStreamHandler(private val context: Context) : EventChannel.S
|
||||||
Log.i(LOG_TAG, "onCancel arguments=$arguments")
|
Log.i(LOG_TAG, "onCancel arguments=$arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dispose() {
|
|
||||||
context.contentResolver.unregisterContentObserver(contentObserver)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun success(settings: FieldMap) {
|
private fun success(settings: FieldMap) {
|
||||||
handler?.post {
|
handler?.post {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -166,7 +166,7 @@ object Helper {
|
||||||
|
|
||||||
// This seems to cover all known Exif and Xmp date strings
|
// This seems to cover all known Exif and Xmp date strings
|
||||||
// Note that " : : : : " is a valid date string according to the Exif spec (which means 'unknown date'): http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/datetimeoriginal.html
|
// Note that " : : : : " is a valid date string according to the Exif spec (which means 'unknown date'): http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/datetimeoriginal.html
|
||||||
private val datePatterns = arrayOf(
|
private val dateFormats = arrayOf(
|
||||||
"yyyy:MM:dd HH:mm:ss",
|
"yyyy:MM:dd HH:mm:ss",
|
||||||
"yyyy:MM:dd HH:mm",
|
"yyyy:MM:dd HH:mm",
|
||||||
"yyyy-MM-dd HH:mm:ss",
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
|
@ -179,7 +179,7 @@ object Helper {
|
||||||
"yyyy-MM",
|
"yyyy-MM",
|
||||||
"yyyyMMdd", // as used in IPTC data
|
"yyyyMMdd", // as used in IPTC data
|
||||||
"yyyy"
|
"yyyy"
|
||||||
)
|
).map { SimpleDateFormat(it, Locale.ROOT) }.toTypedArray()
|
||||||
private val subsecondPattern = Pattern.compile("(\\d\\d:\\d\\d:\\d\\d)(\\.\\d+)")
|
private val subsecondPattern = Pattern.compile("(\\d\\d:\\d\\d:\\d\\d)(\\.\\d+)")
|
||||||
private val timeZonePattern = Pattern.compile("(Z|[+-]\\d\\d:\\d\\d|[+-]\\d\\d\\d\\d)$")
|
private val timeZonePattern = Pattern.compile("(Z|[+-]\\d\\d:\\d\\d|[+-]\\d\\d\\d\\d)$")
|
||||||
private val calendar: Calendar = GregorianCalendar()
|
private val calendar: Calendar = GregorianCalendar()
|
||||||
|
@ -210,11 +210,10 @@ object Helper {
|
||||||
effectiveTimeZone = TimeZone.getTimeZone("GMT" + timeZoneMatcher.group().replace("Z".toRegex(), ""))
|
effectiveTimeZone = TimeZone.getTimeZone("GMT" + timeZoneMatcher.group().replace("Z".toRegex(), ""))
|
||||||
dateString = timeZoneMatcher.replaceAll("")
|
dateString = timeZoneMatcher.replaceAll("")
|
||||||
}
|
}
|
||||||
for (datePattern in datePatterns) {
|
for (dateFormat in dateFormats) {
|
||||||
try {
|
try {
|
||||||
val parsed = SimpleDateFormat(datePattern, Locale.ROOT).apply {
|
dateFormat.timeZone = effectiveTimeZone ?: TimeZone.getTimeZone("GMT") // don't interpret zone time
|
||||||
this.timeZone = effectiveTimeZone ?: TimeZone.getTimeZone("GMT") // don't interpret zone time
|
val parsed = dateFormat.parse(dateString)
|
||||||
}.parse(dateString)
|
|
||||||
if (parsed != null) {
|
if (parsed != null) {
|
||||||
calendar.time = parsed
|
calendar.time = parsed
|
||||||
if (calendar.get(Calendar.YEAR) < PARSED_DATE_YEAR_MAX) {
|
if (calendar.get(Calendar.YEAR) < PARSED_DATE_YEAR_MAX) {
|
||||||
|
|
|
@ -3,7 +3,11 @@ package deckers.thibault.aves.model.provider
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.RecoverableSecurityException
|
import android.app.RecoverableSecurityException
|
||||||
import android.content.*
|
import android.content.ContentResolver
|
||||||
|
import android.content.ContentUris
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -35,7 +39,7 @@ import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.io.SyncFailedException
|
import java.io.SyncFailedException
|
||||||
import java.util.*
|
import java.util.Locale
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
@ -45,11 +49,11 @@ import kotlin.coroutines.suspendCoroutine
|
||||||
class MediaStoreImageProvider : ImageProvider() {
|
class MediaStoreImageProvider : ImageProvider() {
|
||||||
fun fetchAll(
|
fun fetchAll(
|
||||||
context: Context,
|
context: Context,
|
||||||
knownEntries: Map<Int?, Int?>,
|
knownEntries: Map<Long?, Int?>,
|
||||||
directory: String?,
|
directory: String?,
|
||||||
handleNewEntry: NewEntryHandler,
|
handleNewEntry: NewEntryHandler,
|
||||||
) {
|
) {
|
||||||
val isModified = fun(contentId: Int, dateModifiedSecs: Int): Boolean {
|
val isModified = fun(contentId: Long, dateModifiedSecs: Int): Boolean {
|
||||||
val knownDate = knownEntries[contentId]
|
val knownDate = knownEntries[contentId]
|
||||||
return knownDate == null || knownDate < dateModifiedSecs
|
return knownDate == null || knownDate < dateModifiedSecs
|
||||||
}
|
}
|
||||||
|
@ -89,7 +93,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
var found = false
|
var found = false
|
||||||
val fetched = arrayListOf<FieldMap>()
|
val fetched = arrayListOf<FieldMap>()
|
||||||
val id = uri.tryParseId()
|
val id = uri.tryParseId()
|
||||||
val alwaysValid: NewEntryChecker = fun(_: Int, _: Int): Boolean = true
|
val alwaysValid: NewEntryChecker = fun(_: Long, _: Int): Boolean = true
|
||||||
val onSuccess: NewEntryHandler = fun(entry: FieldMap) { fetched.add(entry) }
|
val onSuccess: NewEntryHandler = fun(entry: FieldMap) { fetched.add(entry) }
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
if (sourceMimeType == null || isImage(sourceMimeType)) {
|
if (sourceMimeType == null || isImage(sourceMimeType)) {
|
||||||
|
@ -119,8 +123,8 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkObsoleteContentIds(context: Context, knownContentIds: List<Int?>): List<Int> {
|
fun checkObsoleteContentIds(context: Context, knownContentIds: List<Long?>): List<Long> {
|
||||||
val foundContentIds = HashSet<Int>()
|
val foundContentIds = HashSet<Long>()
|
||||||
fun check(context: Context, contentUri: Uri) {
|
fun check(context: Context, contentUri: Uri) {
|
||||||
val projection = arrayOf(MediaStore.MediaColumns._ID)
|
val projection = arrayOf(MediaStore.MediaColumns._ID)
|
||||||
try {
|
try {
|
||||||
|
@ -128,7 +132,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)
|
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
foundContentIds.add(cursor.getInt(idColumn))
|
foundContentIds.add(cursor.getLong(idColumn))
|
||||||
}
|
}
|
||||||
cursor.close()
|
cursor.close()
|
||||||
}
|
}
|
||||||
|
@ -141,8 +145,8 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
return knownContentIds.subtract(foundContentIds).filterNotNull().toList()
|
return knownContentIds.subtract(foundContentIds).filterNotNull().toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkObsoletePaths(context: Context, knownPathById: Map<Int?, String?>): List<Int> {
|
fun checkObsoletePaths(context: Context, knownPathById: Map<Long?, String?>): List<Long> {
|
||||||
val obsoleteIds = ArrayList<Int>()
|
val obsoleteIds = ArrayList<Long>()
|
||||||
fun check(context: Context, contentUri: Uri) {
|
fun check(context: Context, contentUri: Uri) {
|
||||||
val projection = arrayOf(MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DATA)
|
val projection = arrayOf(MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DATA)
|
||||||
try {
|
try {
|
||||||
|
@ -151,7 +155,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)
|
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)
|
||||||
val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
|
val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
val id = cursor.getInt(idColumn)
|
val id = cursor.getLong(idColumn)
|
||||||
val path = cursor.getString(pathColumn)
|
val path = cursor.getString(pathColumn)
|
||||||
if (knownPathById.containsKey(id) && knownPathById[id] != path) {
|
if (knownPathById.containsKey(id) && knownPathById[id] != path) {
|
||||||
obsoleteIds.add(id)
|
obsoleteIds.add(id)
|
||||||
|
@ -168,6 +172,31 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
return obsoleteIds
|
return obsoleteIds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getChangedUris(context: Context, sinceGeneration: Int): List<String> {
|
||||||
|
val changedUris = ArrayList<String>()
|
||||||
|
fun check(context: Context, contentUri: Uri) {
|
||||||
|
val projection = arrayOf(MediaStore.MediaColumns._ID)
|
||||||
|
val selection = "${MediaStore.MediaColumns.GENERATION_MODIFIED} > ?"
|
||||||
|
val selectionArgs = arrayOf(sinceGeneration.toString())
|
||||||
|
try {
|
||||||
|
val cursor = context.contentResolver.query(contentUri, projection, selection, selectionArgs, null)
|
||||||
|
if (cursor != null) {
|
||||||
|
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
val id = cursor.getLong(idColumn)
|
||||||
|
changedUris.add(ContentUris.withAppendedId(contentUri, id).toString())
|
||||||
|
}
|
||||||
|
cursor.close()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(LOG_TAG, "failed to get content IDs for contentUri=$contentUri", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check(context, IMAGE_CONTENT_URI)
|
||||||
|
check(context, VIDEO_CONTENT_URI)
|
||||||
|
return changedUris
|
||||||
|
}
|
||||||
|
|
||||||
private fun fetchFrom(
|
private fun fetchFrom(
|
||||||
context: Context,
|
context: Context,
|
||||||
isValidEntry: NewEntryChecker,
|
isValidEntry: NewEntryChecker,
|
||||||
|
@ -207,12 +236,12 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
val needDuration = projection.contentEquals(VIDEO_PROJECTION)
|
val needDuration = projection.contentEquals(VIDEO_PROJECTION)
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
val contentId = cursor.getInt(idColumn)
|
val id = cursor.getLong(idColumn)
|
||||||
val dateModifiedSecs = cursor.getInt(dateModifiedColumn)
|
val dateModifiedSecs = cursor.getInt(dateModifiedColumn)
|
||||||
if (isValidEntry(contentId, dateModifiedSecs)) {
|
if (isValidEntry(id, dateModifiedSecs)) {
|
||||||
// for multiple items, `contentUri` is the root without ID,
|
// for multiple items, `contentUri` is the root without ID,
|
||||||
// but for single items, `contentUri` already contains the ID
|
// but for single items, `contentUri` already contains the ID
|
||||||
val itemUri = if (contentUriContainsId) contentUri else ContentUris.withAppendedId(contentUri, contentId.toLong())
|
val itemUri = if (contentUriContainsId) contentUri else ContentUris.withAppendedId(contentUri, id)
|
||||||
// `mimeType` can be registered as null for file media URIs with unsupported media types (e.g. TIFF on old devices)
|
// `mimeType` can be registered as null for file media URIs with unsupported media types (e.g. TIFF on old devices)
|
||||||
// in that case we try to use the MIME type provided along the URI
|
// in that case we try to use the MIME type provided along the URI
|
||||||
val mimeType: String? = cursor.getString(mimeTypeColumn) ?: fileMimeType
|
val mimeType: String? = cursor.getString(mimeTypeColumn) ?: fileMimeType
|
||||||
|
@ -237,7 +266,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
"sourceDateTakenMillis" to if (dateTakenColumn != -1) cursor.getLong(dateTakenColumn) else null,
|
"sourceDateTakenMillis" to if (dateTakenColumn != -1) cursor.getLong(dateTakenColumn) else null,
|
||||||
"durationMillis" to durationMillis,
|
"durationMillis" to durationMillis,
|
||||||
// only for map export
|
// only for map export
|
||||||
"contentId" to contentId,
|
"contentId" to id,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (MimeTypes.isHeic(mimeType)) {
|
if (MimeTypes.isHeic(mimeType)) {
|
||||||
|
@ -930,8 +959,10 @@ class MediaStoreImageProvider : ImageProvider() {
|
||||||
try {
|
try {
|
||||||
val cursor = context.contentResolver.query(contentUri, projection, selection, selectionArgs, null)
|
val cursor = context.contentResolver.query(contentUri, projection, selection, selectionArgs, null)
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
cursor.getColumnIndex(MediaStore.MediaColumns._ID).let {
|
val idColumn = cursor.getColumnIndex(MediaStore.MediaColumns._ID)
|
||||||
if (it != -1) mediaContentUri = ContentUris.withAppendedId(contentUri, cursor.getLong(it))
|
if (idColumn != -1) {
|
||||||
|
val id = cursor.getLong(idColumn)
|
||||||
|
mediaContentUri = ContentUris.withAppendedId(contentUri, id)
|
||||||
}
|
}
|
||||||
cursor.close()
|
cursor.close()
|
||||||
}
|
}
|
||||||
|
@ -994,4 +1025,4 @@ object MediaColumns {
|
||||||
|
|
||||||
typealias NewEntryHandler = (entry: FieldMap) -> Unit
|
typealias NewEntryHandler = (entry: FieldMap) -> Unit
|
||||||
|
|
||||||
private typealias NewEntryChecker = (contentId: Int, dateModifiedSecs: Int) -> Boolean
|
private typealias NewEntryChecker = (contentId: Long, dateModifiedSecs: Int) -> Boolean
|
|
@ -7,11 +7,13 @@ object MemoryUtils {
|
||||||
|
|
||||||
fun canAllocate(byteSize: Number?): Boolean {
|
fun canAllocate(byteSize: Number?): Boolean {
|
||||||
byteSize ?: return true
|
byteSize ?: return true
|
||||||
val availableHeapSize = Runtime.getRuntime().let { it.maxMemory() - (it.totalMemory() - it.freeMemory()) }
|
val availableHeapSize = getAvailableHeapSize()
|
||||||
val danger = byteSize.toLong() > availableHeapSize
|
val danger = byteSize.toLong() > availableHeapSize
|
||||||
if (danger) {
|
if (danger) {
|
||||||
Log.e(LOG_TAG, "trying to handle $byteSize bytes, with only $availableHeapSize free bytes")
|
Log.e(LOG_TAG, "trying to handle $byteSize bytes, with only $availableHeapSize free bytes")
|
||||||
}
|
}
|
||||||
return !danger
|
return !danger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAvailableHeapSize() = Runtime.getRuntime().let { it.maxMemory() - (it.totalMemory() - it.freeMemory()) }
|
||||||
}
|
}
|
|
@ -8,4 +8,5 @@
|
||||||
<string name="analysis_notification_action_stop">توقف کردن</string>
|
<string name="analysis_notification_action_stop">توقف کردن</string>
|
||||||
<string name="app_widget_label">قاب عکس</string>
|
<string name="app_widget_label">قاب عکس</string>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="safe_mode_shortcut_short_label">حالت امن</string>
|
||||||
</resources>
|
</resources>
|
4
fastlane/metadata/android/en-US/changelogs/115.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/115.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
In v1.10.6:
|
||||||
|
- detect HDR videos (but do not play them in their full HDR glory)
|
||||||
|
- removing animations also applies to pop up menus
|
||||||
|
Full changelog available on GitHub
|
4
fastlane/metadata/android/en-US/changelogs/11501.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/11501.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
In v1.10.6:
|
||||||
|
- detect HDR videos (but do not play them in their full HDR glory)
|
||||||
|
- removing animations also applies to pop up menus
|
||||||
|
Full changelog available on GitHub
|
|
@ -228,7 +228,7 @@
|
||||||
"@filterTypeSphericalVideoLabel": {},
|
"@filterTypeSphericalVideoLabel": {},
|
||||||
"filterNoTitleLabel": "Без назвы",
|
"filterNoTitleLabel": "Без назвы",
|
||||||
"@filterNoTitleLabel": {},
|
"@filterNoTitleLabel": {},
|
||||||
"filterOnThisDayLabel": "У гэты дзень",
|
"filterOnThisDayLabel": "Ў гэты дзень",
|
||||||
"@filterOnThisDayLabel": {},
|
"@filterOnThisDayLabel": {},
|
||||||
"filterRatingRejectedLabel": "Адхілена",
|
"filterRatingRejectedLabel": "Адхілена",
|
||||||
"@filterRatingRejectedLabel": {},
|
"@filterRatingRejectedLabel": {},
|
||||||
|
@ -263,7 +263,7 @@
|
||||||
"@nameConflictStrategyReplace": {},
|
"@nameConflictStrategyReplace": {},
|
||||||
"filterAspectRatioLandscapeLabel": "Ландшафтныя",
|
"filterAspectRatioLandscapeLabel": "Ландшафтныя",
|
||||||
"@filterAspectRatioLandscapeLabel": {},
|
"@filterAspectRatioLandscapeLabel": {},
|
||||||
"filterBinLabel": "Кошык",
|
"filterBinLabel": "Сметніца",
|
||||||
"@filterBinLabel": {},
|
"@filterBinLabel": {},
|
||||||
"filterFavouriteLabel": "Выбранае",
|
"filterFavouriteLabel": "Выбранае",
|
||||||
"@filterFavouriteLabel": {},
|
"@filterFavouriteLabel": {},
|
||||||
|
@ -551,7 +551,7 @@
|
||||||
"@mapPointNorthUpTooltip": {},
|
"@mapPointNorthUpTooltip": {},
|
||||||
"viewerInfoLabelCoordinates": "Каардынаты",
|
"viewerInfoLabelCoordinates": "Каардынаты",
|
||||||
"@viewerInfoLabelCoordinates": {},
|
"@viewerInfoLabelCoordinates": {},
|
||||||
"viewerInfoLabelOwner": "Уладальнік",
|
"viewerInfoLabelOwner": "Ўладальнік",
|
||||||
"@viewerInfoLabelOwner": {},
|
"@viewerInfoLabelOwner": {},
|
||||||
"viewerInfoLabelDuration": "Працягласць",
|
"viewerInfoLabelDuration": "Працягласць",
|
||||||
"@viewerInfoLabelDuration": {},
|
"@viewerInfoLabelDuration": {},
|
||||||
|
@ -625,7 +625,7 @@
|
||||||
"@mapZoomOutTooltip": {},
|
"@mapZoomOutTooltip": {},
|
||||||
"openMapPageTooltip": "Паглядзець на старонцы карты",
|
"openMapPageTooltip": "Паглядзець на старонцы карты",
|
||||||
"@openMapPageTooltip": {},
|
"@openMapPageTooltip": {},
|
||||||
"mapEmptyRegion": "У гэтым рэгіёне няма малюнкаў",
|
"mapEmptyRegion": "Ў гэтым рэгіёне няма малюнкаў",
|
||||||
"@mapEmptyRegion": {},
|
"@mapEmptyRegion": {},
|
||||||
"viewerInfoSearchEmpty": "Няма адпаведных ключоў",
|
"viewerInfoSearchEmpty": "Няма адпаведных ключоў",
|
||||||
"@viewerInfoSearchEmpty": {},
|
"@viewerInfoSearchEmpty": {},
|
||||||
|
@ -683,7 +683,7 @@
|
||||||
"@setCoverDialogCustom": {},
|
"@setCoverDialogCustom": {},
|
||||||
"aboutBugCopyInfoInstruction": "Скапіяваць сістэмную інфармацыю",
|
"aboutBugCopyInfoInstruction": "Скапіяваць сістэмную інфармацыю",
|
||||||
"@aboutBugCopyInfoInstruction": {},
|
"@aboutBugCopyInfoInstruction": {},
|
||||||
"vaultBinUsageDialogMessage": "Некаторыя сховішчы выкарыстоўваюць кошык.",
|
"vaultBinUsageDialogMessage": "Некаторыя сховішчы выкарыстоўваюць сметніцу.",
|
||||||
"@vaultBinUsageDialogMessage": {},
|
"@vaultBinUsageDialogMessage": {},
|
||||||
"aboutBugSaveLogInstruction": "Захаваць журналы праграмы ў файл",
|
"aboutBugSaveLogInstruction": "Захаваць журналы праграмы ў файл",
|
||||||
"@aboutBugSaveLogInstruction": {},
|
"@aboutBugSaveLogInstruction": {},
|
||||||
|
@ -707,7 +707,7 @@
|
||||||
"@aboutBugSectionTitle": {},
|
"@aboutBugSectionTitle": {},
|
||||||
"aboutBugCopyInfoButton": "Скапіяваць",
|
"aboutBugCopyInfoButton": "Скапіяваць",
|
||||||
"@aboutBugCopyInfoButton": {},
|
"@aboutBugCopyInfoButton": {},
|
||||||
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Перамясціць гэты элемент у кошык?} few{Перамясціць гэтыя {count} элемента у кошык?} other{Перамясціць гэтыя {count} элементаў у кошык?}}",
|
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Перамясціць гэты элемент ў сметніцу?} few{Перамясціць гэтыя {count} элемента ў сметніцу?} other{Перамясціць гэтыя {count} элементаў ў сметніцу?}}",
|
||||||
"@binEntriesConfirmationDialogMessage": {
|
"@binEntriesConfirmationDialogMessage": {
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"count": {}
|
"count": {}
|
||||||
|
@ -937,7 +937,7 @@
|
||||||
"@settingsActionImportDialogTitle": {},
|
"@settingsActionImportDialogTitle": {},
|
||||||
"albumGroupTier": "Па ўзроўні",
|
"albumGroupTier": "Па ўзроўні",
|
||||||
"@albumGroupTier": {},
|
"@albumGroupTier": {},
|
||||||
"drawerCollectionAll": "Уся калекцыя",
|
"drawerCollectionAll": "Ўся калекцыя",
|
||||||
"@drawerCollectionAll": {},
|
"@drawerCollectionAll": {},
|
||||||
"sortByItemCount": "Па колькасці элементаў",
|
"sortByItemCount": "Па колькасці элементаў",
|
||||||
"@sortByItemCount": {},
|
"@sortByItemCount": {},
|
||||||
|
@ -985,7 +985,7 @@
|
||||||
"@searchMetadataSectionTitle": {},
|
"@searchMetadataSectionTitle": {},
|
||||||
"settingsShowBottomNavigationBar": "Паказаць ніжнюю панэль навігацыі",
|
"settingsShowBottomNavigationBar": "Паказаць ніжнюю панэль навігацыі",
|
||||||
"@settingsShowBottomNavigationBar": {},
|
"@settingsShowBottomNavigationBar": {},
|
||||||
"collectionActionEmptyBin": "Ачысціць кошык",
|
"collectionActionEmptyBin": "Ачысціць сметніцу",
|
||||||
"@collectionActionEmptyBin": {},
|
"@collectionActionEmptyBin": {},
|
||||||
"sortOrderAtoZ": "Ад А да Я",
|
"sortOrderAtoZ": "Ад А да Я",
|
||||||
"@sortOrderAtoZ": {},
|
"@sortOrderAtoZ": {},
|
||||||
|
@ -1127,7 +1127,7 @@
|
||||||
"@viewDialogLayoutSectionTitle": {},
|
"@viewDialogLayoutSectionTitle": {},
|
||||||
"searchStatesSectionTitle": "Штаты",
|
"searchStatesSectionTitle": "Штаты",
|
||||||
"@searchStatesSectionTitle": {},
|
"@searchStatesSectionTitle": {},
|
||||||
"dateThisMonth": "У гэтым месяцы",
|
"dateThisMonth": "Ў гэтым месяцы",
|
||||||
"@dateThisMonth": {},
|
"@dateThisMonth": {},
|
||||||
"aboutPageTitle": "Пра нас",
|
"aboutPageTitle": "Пра нас",
|
||||||
"@aboutPageTitle": {},
|
"@aboutPageTitle": {},
|
||||||
|
@ -1165,7 +1165,7 @@
|
||||||
"@sortOrderHighestFirst": {},
|
"@sortOrderHighestFirst": {},
|
||||||
"aboutLicensesAndroidLibrariesSectionTitle": "Бібліятэкі Android",
|
"aboutLicensesAndroidLibrariesSectionTitle": "Бібліятэкі Android",
|
||||||
"@aboutLicensesAndroidLibrariesSectionTitle": {},
|
"@aboutLicensesAndroidLibrariesSectionTitle": {},
|
||||||
"binPageTitle": "Кошык",
|
"binPageTitle": "Сметніца",
|
||||||
"@binPageTitle": {},
|
"@binPageTitle": {},
|
||||||
"sortByAlbumFileName": "Па назве альбома і файла",
|
"sortByAlbumFileName": "Па назве альбома і файла",
|
||||||
"@sortByAlbumFileName": {},
|
"@sortByAlbumFileName": {},
|
||||||
|
@ -1183,9 +1183,9 @@
|
||||||
"@settingsConfirmationBeforeDeleteItems": {},
|
"@settingsConfirmationBeforeDeleteItems": {},
|
||||||
"settingsConfirmationBeforeMoveUndatedItems": "Спытаць, перш чым перамяшчаць прадметы без даты",
|
"settingsConfirmationBeforeMoveUndatedItems": "Спытаць, перш чым перамяшчаць прадметы без даты",
|
||||||
"@settingsConfirmationBeforeMoveUndatedItems": {},
|
"@settingsConfirmationBeforeMoveUndatedItems": {},
|
||||||
"settingsConfirmationAfterMoveToBinItems": "Паказваць паведамленне пасля перамяшчэння элементаў у кошык",
|
"settingsConfirmationAfterMoveToBinItems": "Паказваць паведамленне пасля перамяшчэння элементаў ў сметніцу",
|
||||||
"@settingsConfirmationAfterMoveToBinItems": {},
|
"@settingsConfirmationAfterMoveToBinItems": {},
|
||||||
"settingsConfirmationBeforeMoveToBinItems": "Спытаць, перш чым перамяшчаць элементы ў кошык",
|
"settingsConfirmationBeforeMoveToBinItems": "Спытаць перад тым, як пераносіць элементы ў сметніцу",
|
||||||
"@settingsConfirmationBeforeMoveToBinItems": {},
|
"@settingsConfirmationBeforeMoveToBinItems": {},
|
||||||
"settingsNavigationDrawerAddAlbum": "Дадаць альбом",
|
"settingsNavigationDrawerAddAlbum": "Дадаць альбом",
|
||||||
"@settingsNavigationDrawerAddAlbum": {},
|
"@settingsNavigationDrawerAddAlbum": {},
|
||||||
|
@ -1289,7 +1289,7 @@
|
||||||
"@settingsVideoGestureDoubleTapTogglePlay": {},
|
"@settingsVideoGestureDoubleTapTogglePlay": {},
|
||||||
"addPathTooltip": "Дадаць шлях",
|
"addPathTooltip": "Дадаць шлях",
|
||||||
"@addPathTooltip": {},
|
"@addPathTooltip": {},
|
||||||
"settingsEnableBin": "Выкарыстоўваць кошык",
|
"settingsEnableBin": "Выкарыстоўваць сметніцу",
|
||||||
"@settingsEnableBin": {},
|
"@settingsEnableBin": {},
|
||||||
"collectionMoveSuccessFeedback": "{count, plural, =1{Перамяшчаны 1 элемент} few{Перамяшчаны {count} элементы} other{Перамяшчаны {count} элементаў}}",
|
"collectionMoveSuccessFeedback": "{count, plural, =1{Перамяшчаны 1 элемент} few{Перамяшчаны {count} элементы} other{Перамяшчаны {count} элементаў}}",
|
||||||
"@collectionMoveSuccessFeedback": {
|
"@collectionMoveSuccessFeedback": {
|
||||||
|
@ -1377,7 +1377,7 @@
|
||||||
"@settingsViewerShowDescription": {},
|
"@settingsViewerShowDescription": {},
|
||||||
"settingsViewerQuickActionEditorBanner": "Націсніце і ўтрымлівайце, каб перамяшчаць кнопкі і выбіраць дзеянні для адлюстравання ў праглядніку.",
|
"settingsViewerQuickActionEditorBanner": "Націсніце і ўтрымлівайце, каб перамяшчаць кнопкі і выбіраць дзеянні для адлюстравання ў праглядніку.",
|
||||||
"@settingsViewerQuickActionEditorBanner": {},
|
"@settingsViewerQuickActionEditorBanner": {},
|
||||||
"settingsDisablingBinWarningDialogMessage": "Элементы ў кошыку будуць выдалены назаўжды.",
|
"settingsDisablingBinWarningDialogMessage": "Элементы ў сметніцы будуць выдалены назаўсёды.",
|
||||||
"@settingsDisablingBinWarningDialogMessage": {},
|
"@settingsDisablingBinWarningDialogMessage": {},
|
||||||
"settingsViewerQuickActionEditorDisplayedButtonsSectionTitle": "Адлюстраваныя кнопкі",
|
"settingsViewerQuickActionEditorDisplayedButtonsSectionTitle": "Адлюстраваныя кнопкі",
|
||||||
"@settingsViewerQuickActionEditorDisplayedButtonsSectionTitle": {},
|
"@settingsViewerQuickActionEditorDisplayedButtonsSectionTitle": {},
|
||||||
|
@ -1521,7 +1521,7 @@
|
||||||
},
|
},
|
||||||
"collectionActionSetHome": "Ўсталяваць як галоўную",
|
"collectionActionSetHome": "Ўсталяваць як галоўную",
|
||||||
"@collectionActionSetHome": {},
|
"@collectionActionSetHome": {},
|
||||||
"setHomeCustomCollection": "Уласная калекцыя",
|
"setHomeCustomCollection": "Ўласная калекцыя",
|
||||||
"@setHomeCustomCollection": {},
|
"@setHomeCustomCollection": {},
|
||||||
"settingsThumbnailShowHdrIcon": "Паказаць значок HDR",
|
"settingsThumbnailShowHdrIcon": "Паказаць значок HDR",
|
||||||
"@settingsThumbnailShowHdrIcon": {}
|
"@settingsThumbnailShowHdrIcon": {}
|
||||||
|
|
|
@ -1354,5 +1354,17 @@
|
||||||
"aboutDataUsageClearCache": "Cache leeren",
|
"aboutDataUsageClearCache": "Cache leeren",
|
||||||
"@aboutDataUsageClearCache": {},
|
"@aboutDataUsageClearCache": {},
|
||||||
"settingsViewerShowHistogram": "Histogramm anzeigen",
|
"settingsViewerShowHistogram": "Histogramm anzeigen",
|
||||||
"@settingsViewerShowHistogram": {}
|
"@settingsViewerShowHistogram": {},
|
||||||
|
"overlayHistogramNone": "Keines",
|
||||||
|
"@overlayHistogramNone": {},
|
||||||
|
"collectionActionSetHome": "Als Startseite setzen",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "Benutzerdefinierte Sammlung",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "HDR-Symbol anzeigen",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"entryActionCast": "Übertragen",
|
||||||
|
"@entryActionCast": {},
|
||||||
|
"castDialogTitle": "Geräte zur Übertragung",
|
||||||
|
"@castDialogTitle": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
"@chipActionGoToAlbumPage": {},
|
"@chipActionGoToAlbumPage": {},
|
||||||
"filterNoTagLabel": "بدون برچسب",
|
"filterNoTagLabel": "بدون برچسب",
|
||||||
"@filterNoTagLabel": {},
|
"@filterNoTagLabel": {},
|
||||||
"appName": "اِیوْز",
|
"appName": "اِیوز",
|
||||||
"@appName": {},
|
"@appName": {},
|
||||||
"entryActionRestore": "برگرداندن",
|
"entryActionRestore": "برگرداندن",
|
||||||
"@entryActionRestore": {},
|
"@entryActionRestore": {},
|
||||||
|
@ -544,5 +544,41 @@
|
||||||
"wallpaperTargetHomeLock": "صفحهٔ خانه و صفحهٔ قفل",
|
"wallpaperTargetHomeLock": "صفحهٔ خانه و صفحهٔ قفل",
|
||||||
"@wallpaperTargetHomeLock": {},
|
"@wallpaperTargetHomeLock": {},
|
||||||
"viewDialogSortSectionTitle": "ترتیب بندی",
|
"viewDialogSortSectionTitle": "ترتیب بندی",
|
||||||
"@viewDialogSortSectionTitle": {}
|
"@viewDialogSortSectionTitle": {},
|
||||||
|
"filterRatingRejectedLabel": "رد شده",
|
||||||
|
"@filterRatingRejectedLabel": {},
|
||||||
|
"filterLocatedLabel": "واقع شده",
|
||||||
|
"@filterLocatedLabel": {},
|
||||||
|
"setCoverDialogAuto": "خودکار",
|
||||||
|
"@setCoverDialogAuto": {},
|
||||||
|
"albumTierSpecial": "مشترک",
|
||||||
|
"@albumTierSpecial": {},
|
||||||
|
"viewerTransitionParallax": "انطباق",
|
||||||
|
"@viewerTransitionParallax": {},
|
||||||
|
"coordinateFormatDecimal": "درجه های اعشاری",
|
||||||
|
"@coordinateFormatDecimal": {},
|
||||||
|
"videoResumeButtonLabel": "ادامه",
|
||||||
|
"@videoResumeButtonLabel": {},
|
||||||
|
"addShortcutDialogLabel": "عنوان میانبر",
|
||||||
|
"@addShortcutDialogLabel": {},
|
||||||
|
"overlayHistogramNone": "هیچکدام",
|
||||||
|
"@overlayHistogramNone": {},
|
||||||
|
"overlayHistogramLuminance": "درخشش",
|
||||||
|
"@overlayHistogramLuminance": {},
|
||||||
|
"videoPlaybackSkip": "رد کردن",
|
||||||
|
"@videoPlaybackSkip": {},
|
||||||
|
"addShortcutButtonLabel": "",
|
||||||
|
"@addShortcutButtonLabel": {},
|
||||||
|
"setCoverDialogCustom": "شخصی",
|
||||||
|
"@setCoverDialogCustom": {},
|
||||||
|
"nameConflictDialogSingleSourceMessage": "برخی از پرونده های موجود در پوشه مقصد به همین نام هستند.",
|
||||||
|
"@nameConflictDialogSingleSourceMessage": {},
|
||||||
|
"missingSystemFilePickerDialogMessage": "انتخابگر پرونده سیستم وجود ندارد یا غیرفعال است. لطفا آن را فعال کنید و دوباره امتحان کنید",
|
||||||
|
"@missingSystemFilePickerDialogMessage": {},
|
||||||
|
"nameConflictDialogMultipleSourceMessage": "برخی پرونده ها نام های یکسانی دارند",
|
||||||
|
"@nameConflictDialogMultipleSourceMessage": {},
|
||||||
|
"noMatchingAppDialogMessage": "هیچ کاره ای وجود ندارد که بتواند این موضوع را مدیریت کند.",
|
||||||
|
"@noMatchingAppDialogMessage": {},
|
||||||
|
"filterTaggedLabel": "نشان شده",
|
||||||
|
"@filterTaggedLabel": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1356,5 +1356,15 @@
|
||||||
"settingsViewerShowHistogram": "Tampilkan histogram",
|
"settingsViewerShowHistogram": "Tampilkan histogram",
|
||||||
"@settingsViewerShowHistogram": {},
|
"@settingsViewerShowHistogram": {},
|
||||||
"aboutDataUsageClearCache": "Bersihkan cache",
|
"aboutDataUsageClearCache": "Bersihkan cache",
|
||||||
"@aboutDataUsageClearCache": {}
|
"@aboutDataUsageClearCache": {},
|
||||||
|
"entryActionCast": "Siarkan",
|
||||||
|
"@entryActionCast": {},
|
||||||
|
"setHomeCustomCollection": "Koleksi kustom",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"collectionActionSetHome": "Tetapkan sebagai beranda",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Tampilkan ikon HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"castDialogTitle": "Siarkan Perangkat",
|
||||||
|
"@castDialogTitle": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1232,5 +1232,19 @@
|
||||||
"lengthUnitPixel": "px",
|
"lengthUnitPixel": "px",
|
||||||
"@lengthUnitPixel": {},
|
"@lengthUnitPixel": {},
|
||||||
"lengthUnitPercent": "%",
|
"lengthUnitPercent": "%",
|
||||||
"@lengthUnitPercent": {}
|
"@lengthUnitPercent": {},
|
||||||
|
"saveCopyButtonLabel": "コピーを保存",
|
||||||
|
"@saveCopyButtonLabel": {},
|
||||||
|
"columnCount": "{count, plural, =1{1 列} other{{count} 列}}",
|
||||||
|
"@columnCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chipActionShowCountryStates": "地域を表示",
|
||||||
|
"@chipActionShowCountryStates": {},
|
||||||
|
"entryActionCast": "キャスト",
|
||||||
|
"@entryActionCast": {},
|
||||||
|
"editorTransformRotate": "回転",
|
||||||
|
"@editorTransformRotate": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1492,5 +1492,37 @@
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives": "顯示多點觸控手勢的備選方案",
|
"settingsAccessibilityShowPinchGestureAlternatives": "顯示多點觸控手勢的備選方案",
|
||||||
"@settingsAccessibilityShowPinchGestureAlternatives": {},
|
"@settingsAccessibilityShowPinchGestureAlternatives": {},
|
||||||
"overlayHistogramRGB": "RGB",
|
"overlayHistogramRGB": "RGB",
|
||||||
"@overlayHistogramRGB": {}
|
"@overlayHistogramRGB": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "顯示 HDR 圖示",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"aboutDataUsageSectionTitle": "資料用量",
|
||||||
|
"@aboutDataUsageSectionTitle": {},
|
||||||
|
"aboutDataUsageData": "資料",
|
||||||
|
"@aboutDataUsageData": {},
|
||||||
|
"aboutDataUsageCache": "快取記憶體",
|
||||||
|
"@aboutDataUsageCache": {},
|
||||||
|
"aboutDataUsageDatabase": "資料庫",
|
||||||
|
"@aboutDataUsageDatabase": {},
|
||||||
|
"aboutDataUsageMisc": "雜項",
|
||||||
|
"@aboutDataUsageMisc": {},
|
||||||
|
"aboutDataUsageInternal": "內部儲存",
|
||||||
|
"@aboutDataUsageInternal": {},
|
||||||
|
"aboutDataUsageExternal": "外部儲存",
|
||||||
|
"@aboutDataUsageExternal": {},
|
||||||
|
"overlayHistogramNone": "無",
|
||||||
|
"@overlayHistogramNone": {},
|
||||||
|
"overlayHistogramLuminance": "亮度",
|
||||||
|
"@overlayHistogramLuminance": {},
|
||||||
|
"collectionActionSetHome": "設為首頁",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "自訂收藏品",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"aboutDataUsageClearCache": "清除快取",
|
||||||
|
"@aboutDataUsageClearCache": {},
|
||||||
|
"settingsViewerShowHistogram": "顯示直方圖",
|
||||||
|
"@settingsViewerShowHistogram": {},
|
||||||
|
"entryActionCast": "投放",
|
||||||
|
"@entryActionCast": {},
|
||||||
|
"castDialogTitle": "投放裝置",
|
||||||
|
"@castDialogTitle": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ class Contributors {
|
||||||
Contributor('minh', 'teaminh@skiff.com'),
|
Contributor('minh', 'teaminh@skiff.com'),
|
||||||
Contributor('luckris25', 'lk1thebestl@gmail.com'),
|
Contributor('luckris25', 'lk1thebestl@gmail.com'),
|
||||||
Contributor('Marc Amorós', 'marquitus99@gmail.com'),
|
Contributor('Marc Amorós', 'marquitus99@gmail.com'),
|
||||||
|
Contributor('elea11', 'p.manuel.warnecke@gmail.com'),
|
||||||
// Contributor('Alvi Khan', 'aveenalvi@gmail.com'), // Bengali
|
// Contributor('Alvi Khan', 'aveenalvi@gmail.com'), // Bengali
|
||||||
// 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
|
||||||
|
@ -94,6 +95,7 @@ class Contributors {
|
||||||
// Contributor('امیر جهانگرد', 'ijahangard.a@gmail.com'), // Persian
|
// Contributor('امیر جهانگرد', 'ijahangard.a@gmail.com'), // Persian
|
||||||
// Contributor('slasb37', 'p84haghi@gmail.com'), // Persian
|
// Contributor('slasb37', 'p84haghi@gmail.com'), // Persian
|
||||||
// Contributor('mimvahedi', 'vahedi0vahedi@gmail.com'), // Persian
|
// Contributor('mimvahedi', 'vahedi0vahedi@gmail.com'), // Persian
|
||||||
|
// Contributor('Alireza Rashidi', 'alirezarashidigoorabi@gmail.com'), // Persian
|
||||||
// Contributor('Prasanta-Hembram', 'Prasantahembram720@gmail.com'), // Santali
|
// Contributor('Prasanta-Hembram', 'Prasantahembram720@gmail.com'), // Santali
|
||||||
// Contributor('mytja', 'mamnju21@gmail.com'), // Slovenian
|
// Contributor('mytja', 'mamnju21@gmail.com'), // Slovenian
|
||||||
// Contributor('Shift18', 'bribable.lawyer@posteo.net'), // Swedish
|
// Contributor('Shift18', 'bribable.lawyer@posteo.net'), // Swedish
|
||||||
|
|
|
@ -242,6 +242,11 @@ class AvesEntry with AvesEntryBase {
|
||||||
return _bestDate;
|
return _bestDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isAnimated => catalogMetadata?.isAnimated ?? false;
|
||||||
|
|
||||||
|
bool get isHdr => _catalogMetadata?.isHdr ?? false;
|
||||||
|
|
||||||
int get rating => _catalogMetadata?.rating ?? 0;
|
int get rating => _catalogMetadata?.rating ?? 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -303,9 +308,6 @@ class AvesEntry with AvesEntryBase {
|
||||||
return d == null ? null : DateTime(d.year, d.month, d.day);
|
return d == null ? null : DateTime(d.year, d.month, d.day);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
bool get isAnimated => catalogMetadata?.isAnimated ?? false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int? get durationMillis => _durationMillis;
|
int? get durationMillis => _durationMillis;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/geotiff.dart';
|
import 'package:aves/model/geotiff.dart';
|
||||||
|
@ -6,10 +8,14 @@ import 'package:aves/model/video/metadata.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
import 'package:aves/ref/mime_types.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/services/metadata/svg_metadata_service.dart';
|
import 'package:aves/services/metadata/svg_metadata_service.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
extension ExtraAvesEntryCatalog on AvesEntry {
|
extension ExtraAvesEntryCatalog on AvesEntry {
|
||||||
Future<void> catalog({required bool background, required bool force, required bool persist}) async {
|
Future<void> catalog({required bool background, required bool force, required bool persist}) async {
|
||||||
if (isCatalogued && !force) return;
|
if (isCatalogued && !force) return;
|
||||||
|
|
||||||
|
final beforeAvailableHeapSize = await deviceService.getAvailableHeapSize();
|
||||||
|
|
||||||
if (isSvg) {
|
if (isSvg) {
|
||||||
// vector image sizing is not essential, so we should not spend time for it during loading
|
// vector image sizing is not essential, so we should not spend time for it during loading
|
||||||
// but it is useful anyway (for aspect ratios etc.) so we size them during cataloguing
|
// but it is useful anyway (for aspect ratios etc.) so we size them during cataloguing
|
||||||
|
@ -53,5 +59,14 @@ extension ExtraAvesEntryCatalog on AvesEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final afterAvailableHeapSize = await deviceService.getAvailableHeapSize();
|
||||||
|
final diff = beforeAvailableHeapSize - afterAvailableHeapSize;
|
||||||
|
const largeHeapUsageThreshold = 15 * (1 << 20); // MB
|
||||||
|
|
||||||
|
if (diff > largeHeapUsageThreshold) {
|
||||||
|
debugPrint('Large heap usage (${diff}B) from cataloguing entry=$this size=$sizeBytes');
|
||||||
|
await deviceService.requestGarbageCollection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,6 @@ extension ExtraAvesEntryMultipage on AvesEntry {
|
||||||
|
|
||||||
bool get isMotionPhoto => catalogMetadata?.isMotionPhoto ?? false;
|
bool get isMotionPhoto => catalogMetadata?.isMotionPhoto ?? false;
|
||||||
|
|
||||||
bool get isHdr => catalogMetadata?.hasHdrGainMap ?? false;
|
|
||||||
|
|
||||||
String? getBurstKey(List<String> patterns) {
|
String? getBurstKey(List<String> patterns) {
|
||||||
final key = BurstPatterns.getKeyForName(filenameWithoutExtension, patterns);
|
final key = BurstPatterns.getKeyForName(filenameWithoutExtension, patterns);
|
||||||
return key != null ? '$directory/$key' : null;
|
return key != null ? '$directory/$key' : null;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart';
|
||||||
class CatalogMetadata {
|
class CatalogMetadata {
|
||||||
final int id;
|
final int id;
|
||||||
final int? dateMillis;
|
final int? dateMillis;
|
||||||
final bool isAnimated, isGeotiff, is360, isMultiPage, isMotionPhoto, hasHdrGainMap;
|
final bool isAnimated, isGeotiff, is360, isMultiPage, isMotionPhoto, isHdr;
|
||||||
bool isFlipped;
|
bool isFlipped;
|
||||||
int? rotationDegrees;
|
int? rotationDegrees;
|
||||||
final String? mimeType, xmpSubjects, xmpTitle;
|
final String? mimeType, xmpSubjects, xmpTitle;
|
||||||
|
@ -21,7 +21,7 @@ class CatalogMetadata {
|
||||||
static const _is360Mask = 1 << 3;
|
static const _is360Mask = 1 << 3;
|
||||||
static const _isMultiPageMask = 1 << 4;
|
static const _isMultiPageMask = 1 << 4;
|
||||||
static const _isMotionPhotoMask = 1 << 5;
|
static const _isMotionPhotoMask = 1 << 5;
|
||||||
static const _hasHdrGainMapMask = 1 << 6;
|
static const _isHdr = 1 << 6; // for images: embedded HDR gainmap, for videos: HDR color transfer
|
||||||
|
|
||||||
CatalogMetadata({
|
CatalogMetadata({
|
||||||
required this.id,
|
required this.id,
|
||||||
|
@ -33,7 +33,7 @@ class CatalogMetadata {
|
||||||
this.is360 = false,
|
this.is360 = false,
|
||||||
this.isMultiPage = false,
|
this.isMultiPage = false,
|
||||||
this.isMotionPhoto = false,
|
this.isMotionPhoto = false,
|
||||||
this.hasHdrGainMap = false,
|
this.isHdr = false,
|
||||||
this.rotationDegrees,
|
this.rotationDegrees,
|
||||||
this.xmpSubjects,
|
this.xmpSubjects,
|
||||||
this.xmpTitle,
|
this.xmpTitle,
|
||||||
|
@ -75,7 +75,7 @@ class CatalogMetadata {
|
||||||
is360: is360,
|
is360: is360,
|
||||||
isMultiPage: isMultiPage ?? this.isMultiPage,
|
isMultiPage: isMultiPage ?? this.isMultiPage,
|
||||||
isMotionPhoto: isMotionPhoto,
|
isMotionPhoto: isMotionPhoto,
|
||||||
hasHdrGainMap: hasHdrGainMap,
|
isHdr: isHdr,
|
||||||
rotationDegrees: rotationDegrees ?? this.rotationDegrees,
|
rotationDegrees: rotationDegrees ?? this.rotationDegrees,
|
||||||
xmpSubjects: xmpSubjects,
|
xmpSubjects: xmpSubjects,
|
||||||
xmpTitle: xmpTitle,
|
xmpTitle: xmpTitle,
|
||||||
|
@ -97,7 +97,7 @@ class CatalogMetadata {
|
||||||
is360: flags & _is360Mask != 0,
|
is360: flags & _is360Mask != 0,
|
||||||
isMultiPage: flags & _isMultiPageMask != 0,
|
isMultiPage: flags & _isMultiPageMask != 0,
|
||||||
isMotionPhoto: flags & _isMotionPhotoMask != 0,
|
isMotionPhoto: flags & _isMotionPhotoMask != 0,
|
||||||
hasHdrGainMap: flags & _hasHdrGainMapMask != 0,
|
isHdr: flags & _isHdr != 0,
|
||||||
// `rotationDegrees` should default to `sourceRotationDegrees`, not 0
|
// `rotationDegrees` should default to `sourceRotationDegrees`, not 0
|
||||||
rotationDegrees: map['rotationDegrees'],
|
rotationDegrees: map['rotationDegrees'],
|
||||||
xmpSubjects: map['xmpSubjects'] ?? '',
|
xmpSubjects: map['xmpSubjects'] ?? '',
|
||||||
|
@ -112,7 +112,7 @@ class CatalogMetadata {
|
||||||
'id': id,
|
'id': id,
|
||||||
'mimeType': mimeType,
|
'mimeType': mimeType,
|
||||||
'dateMillis': dateMillis,
|
'dateMillis': dateMillis,
|
||||||
'flags': (isAnimated ? _isAnimatedMask : 0) | (isFlipped ? _isFlippedMask : 0) | (isGeotiff ? _isGeotiffMask : 0) | (is360 ? _is360Mask : 0) | (isMultiPage ? _isMultiPageMask : 0) | (isMotionPhoto ? _isMotionPhotoMask : 0) | (hasHdrGainMap ? _hasHdrGainMapMask : 0),
|
'flags': (isAnimated ? _isAnimatedMask : 0) | (isFlipped ? _isFlippedMask : 0) | (isGeotiff ? _isGeotiffMask : 0) | (is360 ? _is360Mask : 0) | (isMultiPage ? _isMultiPageMask : 0) | (isMotionPhoto ? _isMotionPhotoMask : 0) | (isHdr ? _isHdr : 0),
|
||||||
'rotationDegrees': rotationDegrees,
|
'rotationDegrees': rotationDegrees,
|
||||||
'xmpSubjects': xmpSubjects,
|
'xmpSubjects': xmpSubjects,
|
||||||
'xmpTitle': xmpTitle,
|
'xmpTitle': xmpTitle,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraAccessibilityAnimations on AccessibilityAnimations {
|
extension ExtraAccessibilityAnimations on AccessibilityAnimations {
|
||||||
bool get animate {
|
bool get animate {
|
||||||
|
@ -14,4 +16,17 @@ extension ExtraAccessibilityAnimations on AccessibilityAnimations {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Duration get popUpAnimationDuration => animate ? ADurations.popupMenuAnimation : Duration.zero;
|
||||||
|
|
||||||
|
Duration get popUpAnimationDelay => popUpAnimationDuration + const Duration(milliseconds: ADurations.transitionMarginMillis);
|
||||||
|
|
||||||
|
AnimationStyle get popUpAnimationStyle {
|
||||||
|
return animate
|
||||||
|
? AnimationStyle(
|
||||||
|
curve: Curves.easeInOutCubic,
|
||||||
|
duration: popUpAnimationDuration,
|
||||||
|
)
|
||||||
|
: AnimationStyle.noAnimation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,6 +449,8 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataTypes.contains(EntryDataType.catalog)) {
|
if (dataTypes.contains(EntryDataType.catalog)) {
|
||||||
|
// explicit GC before cataloguing multiple items
|
||||||
|
await deviceService.requestGarbageCollection();
|
||||||
await Future.forEach(entries, (entry) async {
|
await Future.forEach(entries, (entry) async {
|
||||||
await entry.catalog(background: background, force: dataTypes.contains(EntryDataType.catalog), persist: persist);
|
await entry.catalog(background: background, force: dataTypes.contains(EntryDataType.catalog), persist: persist);
|
||||||
await metadataDb.updateCatalogMetadata(entry.id, entry.catalogMetadata);
|
await metadataDb.updateCatalogMetadata(entry.id, entry.catalogMetadata);
|
||||||
|
@ -499,6 +501,8 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
|
||||||
entryIds: entries?.map((entry) => entry.id).toList(),
|
entryIds: entries?.map((entry) => entry.id).toList(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
// explicit GC before cataloguing multiple items
|
||||||
|
await deviceService.requestGarbageCollection();
|
||||||
await catalogEntries(_analysisController, todoEntries);
|
await catalogEntries(_analysisController, todoEntries);
|
||||||
updateDerivedFilters(todoEntries);
|
updateDerivedFilters(todoEntries);
|
||||||
await locateEntries(_analysisController, todoEntries);
|
await locateEntries(_analysisController, todoEntries);
|
||||||
|
|
|
@ -11,12 +11,17 @@ import 'package:aves/model/source/analysis_controller.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:aves/utils/debouncer.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/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
class MediaStoreSource extends CollectionSource {
|
class MediaStoreSource extends CollectionSource {
|
||||||
|
final Debouncer _changeDebouncer = Debouncer(delay: ADurations.mediaContentChangeDebounceDelay);
|
||||||
|
final Set<String> _changedUris = {};
|
||||||
|
int? _lastGeneration;
|
||||||
SourceInitializationState _initState = SourceInitializationState.none;
|
SourceInitializationState _initState = SourceInitializationState.none;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -36,6 +41,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
_initState = directory != null ? SourceInitializationState.directory : SourceInitializationState.full;
|
_initState = directory != null ? SourceInitializationState.directory : SourceInitializationState.full;
|
||||||
}
|
}
|
||||||
addDirectories(albums: settings.pinnedFilters.whereType<AlbumFilter>().map((v) => v.album).toSet());
|
addDirectories(albums: settings.pinnedFilters.whereType<AlbumFilter>().map((v) => v.album).toSet());
|
||||||
|
await updateGeneration();
|
||||||
unawaited(_loadEntries(
|
unawaited(_loadEntries(
|
||||||
analysisController: analysisController,
|
analysisController: analysisController,
|
||||||
directory: directory,
|
directory: directory,
|
||||||
|
@ -305,6 +311,34 @@ class MediaStoreSource extends CollectionSource {
|
||||||
return tempUris;
|
return tempUris;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onStoreChanged(String? uri) {
|
||||||
|
if (uri != null) _changedUris.add(uri);
|
||||||
|
if (_changedUris.isNotEmpty) {
|
||||||
|
_changeDebouncer(() async {
|
||||||
|
final todo = _changedUris.toSet();
|
||||||
|
_changedUris.clear();
|
||||||
|
final tempUris = await refreshUris(todo);
|
||||||
|
if (tempUris.isNotEmpty) {
|
||||||
|
_changedUris.addAll(tempUris);
|
||||||
|
onStoreChanged(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> checkForChanges() async {
|
||||||
|
final sinceGeneration = _lastGeneration;
|
||||||
|
if (sinceGeneration != null) {
|
||||||
|
_changedUris.addAll(await mediaStoreService.getChangedUris(sinceGeneration));
|
||||||
|
onStoreChanged(null);
|
||||||
|
}
|
||||||
|
await updateGeneration();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateGeneration() async {
|
||||||
|
_lastGeneration = await mediaStoreService.getGeneration();
|
||||||
|
}
|
||||||
|
|
||||||
// vault
|
// vault
|
||||||
|
|
||||||
Future<void> _loadVaultEntries(String? directory) async {
|
Future<void> _loadVaultEntries(String? directory) async {
|
||||||
|
|
|
@ -17,6 +17,10 @@ abstract class DeviceService {
|
||||||
Future<bool> isSystemFilePickerEnabled();
|
Future<bool> isSystemFilePickerEnabled();
|
||||||
|
|
||||||
Future<void> requestMediaManagePermission();
|
Future<void> requestMediaManagePermission();
|
||||||
|
|
||||||
|
Future<int> getAvailableHeapSize();
|
||||||
|
|
||||||
|
Future<void> requestGarbageCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlatformDeviceService implements DeviceService {
|
class PlatformDeviceService implements DeviceService {
|
||||||
|
@ -104,4 +108,24 @@ class PlatformDeviceService implements DeviceService {
|
||||||
await reportService.recordError(e, stack);
|
await reportService.recordError(e, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> getAvailableHeapSize() async {
|
||||||
|
try {
|
||||||
|
final result = await _platform.invokeMethod('getAvailableHeapSize');
|
||||||
|
if (result != null) return result as int;
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> requestGarbageCollection() async {
|
||||||
|
try {
|
||||||
|
await _platform.invokeMethod('requestGarbageCollection');
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,10 @@ abstract class MediaStoreService {
|
||||||
|
|
||||||
Future<List<int>> checkObsoletePaths(Map<int?, String?> knownPathById);
|
Future<List<int>> checkObsoletePaths(Map<int?, String?> knownPathById);
|
||||||
|
|
||||||
|
Future<List<String>> getChangedUris(int sinceGeneration);
|
||||||
|
|
||||||
|
Future<int?> getGeneration();
|
||||||
|
|
||||||
// knownEntries: map of contentId -> dateModifiedSecs
|
// knownEntries: map of contentId -> dateModifiedSecs
|
||||||
Stream<AvesEntry> getEntries(Map<int?, int?> knownEntries, {String? directory});
|
Stream<AvesEntry> getEntries(Map<int?, int?> knownEntries, {String? directory});
|
||||||
|
|
||||||
|
@ -47,6 +51,29 @@ class PlatformMediaStoreService implements MediaStoreService {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<String>> getChangedUris(int sinceGeneration) async {
|
||||||
|
try {
|
||||||
|
final result = await _platform.invokeMethod('getChangedUris', <String, dynamic>{
|
||||||
|
'sinceGeneration': sinceGeneration,
|
||||||
|
});
|
||||||
|
return (result as List).cast<String>();
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int?> getGeneration() async {
|
||||||
|
try {
|
||||||
|
return await _platform.invokeMethod('getGeneration');
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<AvesEntry> getEntries(Map<int?, int?> knownEntries, {String? directory}) {
|
Stream<AvesEntry> getEntries(Map<int?, int?> knownEntries, {String? directory}) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:aves/image_providers/app_icon_image_provider.dart';
|
import 'package:aves/image_providers/app_icon_image_provider.dart';
|
||||||
import 'package:aves/model/covers.dart';
|
import 'package:aves/model/covers.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -32,7 +33,7 @@ class AvesColorsProvider extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ProxyProvider<Settings, AvesColorsData>(
|
return ProxyProvider<Settings, AvesColorsData>(
|
||||||
update: (context, settings, __) {
|
update: (context, settings, __) {
|
||||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
final isDark = Theme.of(context).isDark;
|
||||||
var mode = settings.themeColorMode;
|
var mode = settings.themeColorMode;
|
||||||
if (!allowMonochrome && mode == AvesThemeColorMode.monochrome) {
|
if (!allowMonochrome && mode == AvesThemeColorMode.monochrome) {
|
||||||
mode = AvesThemeColorMode.polychrome;
|
mode = AvesThemeColorMode.polychrome;
|
||||||
|
|
|
@ -2,12 +2,13 @@ import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
class ADurations {
|
class ADurations {
|
||||||
// Flutter animations (with margin)
|
// Flutter animations (with margin)
|
||||||
static const popupMenuAnimation = Duration(milliseconds: 300 + 20); // ref `_kMenuDuration` used in `_PopupMenuRoute`
|
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 + 20); // ref `transitionDuration` used in `MaterialRouteTransitionMixin`
|
static const pageTransitionAnimation = Duration(milliseconds: 300 + transitionMarginMillis); // ref `transitionDuration` used in `MaterialRouteTransitionMixin`
|
||||||
static const dialogTransitionAnimation = Duration(milliseconds: 150 + 20); // ref `transitionDuration` used in `DialogRoute`
|
static const dialogTransitionAnimation = Duration(milliseconds: 150 + transitionMarginMillis); // ref `transitionDuration` used in `DialogRoute`
|
||||||
static const drawerTransitionAnimation = Duration(milliseconds: 246 + 20); // ref `_kBaseSettleDuration` used in `DrawerControllerState`
|
static const drawerTransitionAnimation = Duration(milliseconds: 246 + transitionMarginMillis); // ref `_kBaseSettleDuration` used in `DrawerControllerState`
|
||||||
static const toggleableTransitionAnimation = Duration(milliseconds: 200 + 20); // ref `_kToggleDuration` used in `ToggleableStateMixin`
|
static const toggleableTransitionAnimation = 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);
|
||||||
|
@ -16,6 +17,7 @@ class ADurations {
|
||||||
|
|
||||||
static const appBarTitleAnimation = Duration(milliseconds: 300);
|
static const appBarTitleAnimation = Duration(milliseconds: 300);
|
||||||
static const appBarActionChangeAnimation = Duration(milliseconds: 200);
|
static const appBarActionChangeAnimation = Duration(milliseconds: 200);
|
||||||
|
static const popupMenuAnimation = Duration(milliseconds: 300);
|
||||||
|
|
||||||
// filter grids animations
|
// filter grids animations
|
||||||
static const chipDecorationAnimation = Duration(milliseconds: 200);
|
static const chipDecorationAnimation = Duration(milliseconds: 200);
|
||||||
|
|
|
@ -19,11 +19,9 @@ import 'package:aves/model/source/media_store_source.dart';
|
||||||
import 'package:aves/services/accessibility_service.dart';
|
import 'package:aves/services/accessibility_service.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/theme/styles.dart';
|
import 'package:aves/theme/styles.dart';
|
||||||
import 'package:aves/theme/themes.dart';
|
import 'package:aves/theme/themes.dart';
|
||||||
import 'package:aves/utils/debouncer.dart';
|
|
||||||
import 'package:aves/widgets/collection/collection_grid.dart';
|
import 'package:aves/widgets/collection/collection_grid.dart';
|
||||||
import 'package:aves/widgets/collection/collection_page.dart';
|
import 'package:aves/widgets/collection/collection_page.dart';
|
||||||
import 'package:aves/widgets/common/basic/scaffold.dart';
|
import 'package:aves/widgets/common/basic/scaffold.dart';
|
||||||
|
@ -154,9 +152,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
late final Future<void> _appSetup;
|
late final Future<void> _appSetup;
|
||||||
late final Future<bool> _shouldUseBoldFontLoader;
|
late final Future<bool> _shouldUseBoldFontLoader;
|
||||||
final TvRailController _tvRailController = TvRailController();
|
final TvRailController _tvRailController = TvRailController();
|
||||||
final CollectionSource _mediaStoreSource = MediaStoreSource();
|
final MediaStoreSource _mediaStoreSource = MediaStoreSource();
|
||||||
final Debouncer _mediaStoreChangeDebouncer = Debouncer(delay: ADurations.mediaContentChangeDebounceDelay);
|
|
||||||
final Set<String> _changedUris = {};
|
|
||||||
Size? _screenSize;
|
Size? _screenSize;
|
||||||
|
|
||||||
final ValueNotifier<PageTransitionsBuilder> _pageTransitionsBuilderNotifier = ValueNotifier(defaultPageTransitionsBuilder);
|
final ValueNotifier<PageTransitionsBuilder> _pageTransitionsBuilderNotifier = ValueNotifier(defaultPageTransitionsBuilder);
|
||||||
|
@ -184,7 +180,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
EquatableConfig.stringify = true;
|
EquatableConfig.stringify = true;
|
||||||
_appSetup = _setup();
|
_appSetup = _setup();
|
||||||
_shouldUseBoldFontLoader = AccessibilityService.shouldUseBoldFont();
|
_shouldUseBoldFontLoader = AccessibilityService.shouldUseBoldFont();
|
||||||
_subscriptions.add(_mediaStoreChangeChannel.receiveBroadcastStream().listen((event) => _onMediaStoreChanged(event as String?)));
|
_subscriptions.add(_mediaStoreChangeChannel.receiveBroadcastStream().listen((event) => _mediaStoreSource.onStoreChanged(event as String?)));
|
||||||
_subscriptions.add(_newIntentChannel.receiveBroadcastStream().listen((event) => _onNewIntent(event as Map?)));
|
_subscriptions.add(_newIntentChannel.receiveBroadcastStream().listen((event) => _onNewIntent(event as Map?)));
|
||||||
_subscriptions.add(_analysisCompletionChannel.receiveBroadcastStream().listen((event) => _onAnalysisCompletion()));
|
_subscriptions.add(_analysisCompletionChannel.receiveBroadcastStream().listen((event) => _onAnalysisCompletion()));
|
||||||
_subscriptions.add(_errorChannel.receiveBroadcastStream().listen((event) => _onError(event as String?)));
|
_subscriptions.add(_errorChannel.receiveBroadcastStream().listen((event) => _onError(event as String?)));
|
||||||
|
@ -399,6 +395,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
}
|
}
|
||||||
case AppLifecycleState.resumed:
|
case AppLifecycleState.resumed:
|
||||||
RecentlyAddedFilter.updateNow();
|
RecentlyAddedFilter.updateNow();
|
||||||
|
_mediaStoreSource.checkForChanges();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -614,21 +611,6 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
_mediaStoreSource.updateDerivedFilters();
|
_mediaStoreSource.updateDerivedFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onMediaStoreChanged(String? uri) {
|
|
||||||
if (uri != null) _changedUris.add(uri);
|
|
||||||
if (_changedUris.isNotEmpty) {
|
|
||||||
_mediaStoreChangeDebouncer(() async {
|
|
||||||
final todo = _changedUris.toSet();
|
|
||||||
_changedUris.clear();
|
|
||||||
final tempUris = await _mediaStoreSource.refreshUris(todo);
|
|
||||||
if (tempUris.isNotEmpty) {
|
|
||||||
_changedUris.addAll(tempUris);
|
|
||||||
_onMediaStoreChanged(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onError(String? error) => reportService.recordError(error, null);
|
void _onError(String? error) => reportService.recordError(error, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:aves/model/filters/query.dart';
|
||||||
import 'package:aves/model/filters/trash.dart';
|
import 'package:aves/model/filters/trash.dart';
|
||||||
import 'package:aves/model/query.dart';
|
import 'package:aves/model/query.dart';
|
||||||
import 'package:aves/model/selection.dart';
|
import 'package:aves/model/selection.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/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
|
@ -382,6 +383,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
(action) => _buildButtonIcon(context, action, enabled: canApply(action), selection: selection),
|
(action) => _buildButtonIcon(context, action, enabled: canApply(action), selection: selection),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return [
|
return [
|
||||||
...quickActionButtons,
|
...quickActionButtons,
|
||||||
PopupMenuButton<EntrySetAction>(
|
PopupMenuButton<EntrySetAction>(
|
||||||
|
@ -432,9 +434,10 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
},
|
},
|
||||||
onSelected: (action) async {
|
onSelected: (action) async {
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
await _onActionSelected(action);
|
await _onActionSelected(action);
|
||||||
},
|
},
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import 'package:aves/widgets/common/action_mixins/overlay_snack_bar.dart';
|
||||||
import 'package:aves/widgets/common/basic/circle.dart';
|
import 'package:aves/widgets/common/basic/circle.dart';
|
||||||
import 'package:aves/widgets/common/basic/text/change_highlight.dart';
|
import 'package:aves/widgets/common/basic/text/change_highlight.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/viewer/entry_viewer_page.dart';
|
import 'package:aves/widgets/viewer/entry_viewer_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
@ -202,7 +203,8 @@ class _ReportOverlayState<T> extends State<ReportOverlay<T>> with SingleTickerPr
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final colorScheme = Theme.of(context).colorScheme;
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
final progressColor = colorScheme.primary;
|
final progressColor = colorScheme.primary;
|
||||||
final animate = context.select<Settings, bool>((v) => v.accessibilityAnimations.animate);
|
final animate = context.select<Settings, bool>((v) => v.accessibilityAnimations.animate);
|
||||||
return PopScope(
|
return PopScope(
|
||||||
|
@ -223,7 +225,7 @@ class _ReportOverlayState<T> extends State<ReportOverlay<T>> with SingleTickerPr
|
||||||
width: diameter + 2,
|
width: diameter + 2,
|
||||||
height: diameter + 2,
|
height: diameter + 2,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: colorScheme.brightness == Brightness.dark ? const Color(0xBB000000) : const Color(0xEEFFFFFF),
|
color: theme.isDark ? const Color(0xBB000000) : const Color(0xEEFFFFFF),
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
// adapted from Flutter `SnackBar` in `/material/snack_bar.dart`
|
// adapted from Flutter `SnackBar` in `/material/snack_bar.dart`
|
||||||
|
@ -115,7 +116,7 @@ class _OverlaySnackBarState extends State<OverlaySnackBar> {
|
||||||
final ThemeData theme = Theme.of(context);
|
final ThemeData theme = Theme.of(context);
|
||||||
final ColorScheme colorScheme = theme.colorScheme;
|
final ColorScheme colorScheme = theme.colorScheme;
|
||||||
final SnackBarThemeData snackBarTheme = theme.snackBarTheme;
|
final SnackBarThemeData snackBarTheme = theme.snackBarTheme;
|
||||||
final bool isThemeDark = theme.brightness == Brightness.dark;
|
final bool isThemeDark = theme.isDark;
|
||||||
final Color buttonColor = isThemeDark ? colorScheme.primary : colorScheme.secondary;
|
final Color buttonColor = isThemeDark ? colorScheme.primary : colorScheme.secondary;
|
||||||
final SnackBarThemeData defaults = _SnackbarDefaultsM3(context);
|
final SnackBarThemeData defaults = _SnackbarDefaultsM3(context);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:aves/model/source/events.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/view/view.dart';
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.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';
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ class SourceStateSubtitle extends StatelessWidget {
|
||||||
const WidgetSpan(child: SizedBox(width: 8)),
|
const WidgetSpan(child: SizedBox(width: 8)),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: '${progress.done}/${progress.total}',
|
text: '${progress.done}/${progress.total}',
|
||||||
style: TextStyle(color: theme.brightness == Brightness.dark ? Colors.white30 : Colors.black26),
|
style: TextStyle(color: theme.isDark ? Colors.white30 : Colors.black26),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
|
@ -21,6 +21,7 @@ class AvesPopupMenuButton<T> extends PopupMenuButton<T> {
|
||||||
super.enableFeedback,
|
super.enableFeedback,
|
||||||
super.iconSize,
|
super.iconSize,
|
||||||
this.onMenuOpened,
|
this.onMenuOpened,
|
||||||
|
super.popUpAnimationStyle,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
5
lib/widgets/common/extensions/theme.dart
Normal file
5
lib/widgets/common/extensions/theme.dart
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
extension ExtraThemeData on ThemeData {
|
||||||
|
bool get isDark => brightness == Brightness.dark;
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AvesBorder {
|
class AvesBorder {
|
||||||
static Color _borderColor(BuildContext context) => Theme.of(context).brightness == Brightness.dark ? Colors.white30 : Colors.black26;
|
static Color _borderColor(BuildContext context) => Theme.of(context).isDark ? Colors.white30 : Colors.black26;
|
||||||
|
|
||||||
// 1 device pixel for straight lines is fine
|
// 1 device pixel for straight lines is fine
|
||||||
static double straightBorderWidth(BuildContext context) => 1 / View.of(context).devicePixelRatio;
|
static double straightBorderWidth(BuildContext context) => 1 / View.of(context).devicePixelRatio;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.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_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:aves_utils/aves_utils.dart';
|
import 'package:aves_utils/aves_utils.dart';
|
||||||
|
@ -99,7 +100,7 @@ class _OverlayBackgroundState extends State<_OverlayBackground> {
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxDecoration _buildBackgroundDecoration(BuildContext context) {
|
BoxDecoration _buildBackgroundDecoration(BuildContext context) {
|
||||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
final isDark = Theme.of(context).isDark;
|
||||||
final gradientCenter = widget.gradientCenter;
|
final gradientCenter = widget.gradientCenter;
|
||||||
return _initialized
|
return _initialized
|
||||||
? BoxDecoration(
|
? BoxDecoration(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/mosaic/scale_grid.dart';
|
import 'package:aves/widgets/common/grid/sections/mosaic/scale_grid.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_utils/aves_utils.dart';
|
import 'package:aves_utils/aves_utils.dart';
|
||||||
|
@ -104,7 +105,7 @@ class _OverlayBackgroundState extends State<_OverlayBackground> {
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxDecoration _buildBackgroundDecoration(BuildContext context) {
|
BoxDecoration _buildBackgroundDecoration(BuildContext context) {
|
||||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
final isDark = Theme.of(context).isDark;
|
||||||
return _initialized
|
return _initialized
|
||||||
? BoxDecoration(
|
? BoxDecoration(
|
||||||
color: isDark ? Colors.black87 : const Color(0xDDFFFFFF),
|
color: isDark ? Colors.black87 : const Color(0xDDFFFFFF),
|
||||||
|
|
|
@ -91,12 +91,12 @@ class GridThemeData {
|
||||||
if (located && showLocated) LocationIcon.located(),
|
if (located && showLocated) LocationIcon.located(),
|
||||||
if (!located && showUnlocated) LocationIcon.unlocated(),
|
if (!located && showUnlocated) LocationIcon.unlocated(),
|
||||||
if (entry.rating != 0 && showRating) RatingIcon(entry: entry),
|
if (entry.rating != 0 && showRating) RatingIcon(entry: entry),
|
||||||
|
if (entry.isHdr && showHdr) const HdrIcon(),
|
||||||
if (entry.isPureVideo)
|
if (entry.isPureVideo)
|
||||||
VideoIcon(entry: entry)
|
VideoIcon(entry: entry)
|
||||||
else if (entry.isAnimated)
|
else if (entry.isAnimated)
|
||||||
const AnimatedImageIcon()
|
const AnimatedImageIcon()
|
||||||
else ...[
|
else ...[
|
||||||
if (entry.isHdr && showHdr) const HdrIcon(),
|
|
||||||
if (entry.isRaw && showRaw) const RawIcon(),
|
if (entry.isRaw && showRaw) const RawIcon(),
|
||||||
if (entry.is360) const PanoramaIcon(),
|
if (entry.is360) const PanoramaIcon(),
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,7 +11,6 @@ import 'package:aves/model/filters/tag.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/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/durations.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/collection/filter_bar.dart';
|
import 'package:aves/widgets/collection/filter_bar.dart';
|
||||||
|
@ -117,6 +116,7 @@ class AvesFilterChip extends StatefulWidget {
|
||||||
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
const touchArea = Size(kMinInteractiveDimension, kMinInteractiveDimension);
|
const touchArea = Size(kMinInteractiveDimension, kMinInteractiveDimension);
|
||||||
final actionDelegate = ChipActionDelegate();
|
final actionDelegate = ChipActionDelegate();
|
||||||
|
final animations = context.read<Settings>().accessibilityAnimations;
|
||||||
final selectedAction = await showMenu<ChipAction>(
|
final selectedAction = await showMenu<ChipAction>(
|
||||||
context: context,
|
context: context,
|
||||||
position: RelativeRect.fromRect(tapPosition & touchArea, Offset.zero & overlay.size),
|
position: RelativeRect.fromRect(tapPosition & touchArea, Offset.zero & overlay.size),
|
||||||
|
@ -149,10 +149,11 @@ class AvesFilterChip extends StatefulWidget {
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
);
|
);
|
||||||
if (selectedAction != null) {
|
if (selectedAction != null) {
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
actionDelegate.onActionSelected(context, filter, selectedAction);
|
actionDelegate.onActionSelected(context, filter, selectedAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/common/grid/theme.dart';
|
import 'package:aves/widgets/common/grid/theme.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';
|
||||||
|
@ -295,7 +296,7 @@ class OverlayIcon extends StatelessWidget {
|
||||||
margin: margin,
|
margin: margin,
|
||||||
padding: text != null ? EdgeInsetsDirectional.only(end: size / 4) : null,
|
padding: text != null ? EdgeInsetsDirectional.only(end: size / 4) : null,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).brightness == Brightness.dark ? const Color(0xAA000000) : const Color(0xCCFFFFFF),
|
color: Theme.of(context).isDark ? const Color(0xAA000000) : const Color(0xCCFFFFFF),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(size)),
|
borderRadius: BorderRadius.all(Radius.circular(size)),
|
||||||
),
|
),
|
||||||
child: text == null
|
child: text == null
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/themes.dart';
|
import 'package:aves/theme/themes.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/common/fx/blurred.dart';
|
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||||
import 'package:aves/widgets/common/fx/borders.dart';
|
import 'package:aves/widgets/common/fx/borders.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -174,7 +175,7 @@ class OverlayTextButton extends StatelessWidget {
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
backgroundColor: MaterialStateProperty.all<Color>(Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred)),
|
backgroundColor: MaterialStateProperty.all<Color>(Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred)),
|
||||||
foregroundColor: MaterialStateProperty.all<Color>(theme.colorScheme.onSurface),
|
foregroundColor: MaterialStateProperty.all<Color>(theme.colorScheme.onSurface),
|
||||||
overlayColor: theme.brightness == Brightness.dark ? MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.12)) : null,
|
overlayColor: theme.isDark ? MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.12)) : null,
|
||||||
minimumSize: _minSize,
|
minimumSize: _minSize,
|
||||||
side: MaterialStateProperty.all<BorderSide>(AvesBorder.curvedSide(context)),
|
side: MaterialStateProperty.all<BorderSide>(AvesBorder.curvedSide(context)),
|
||||||
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder(
|
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder(
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/widgets/common/basic/text/outlined.dart';
|
import 'package:aves/widgets/common/basic/text/outlined.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/common/fx/highlight_decoration.dart';
|
import 'package:aves/widgets/common/fx/highlight_decoration.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';
|
||||||
|
@ -27,7 +28,7 @@ class HighlightTitle extends StatelessWidget {
|
||||||
|
|
||||||
static List<Shadow> shadows(BuildContext context) => [
|
static List<Shadow> shadows(BuildContext context) => [
|
||||||
Shadow(
|
Shadow(
|
||||||
color: Theme.of(context).brightness == Brightness.dark ? Colors.black : Colors.white,
|
color: Theme.of(context).isDark ? Colors.black : Colors.white,
|
||||||
offset: const Offset(0, 1),
|
offset: const Offset(0, 1),
|
||||||
blurRadius: 2,
|
blurRadius: 2,
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,9 +4,9 @@ import 'package:aves/model/favourites.dart';
|
||||||
import 'package:aves/model/filters/location.dart';
|
import 'package:aves/model/filters/location.dart';
|
||||||
import 'package:aves/model/filters/path.dart';
|
import 'package:aves/model/filters/path.dart';
|
||||||
import 'package:aves/model/filters/tag.dart';
|
import 'package:aves/model/filters/tag.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_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
|
||||||
import 'package:aves/widgets/common/basic/font_size_icon_theme.dart';
|
import 'package:aves/widgets/common/basic/font_size_icon_theme.dart';
|
||||||
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
|
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
|
||||||
import 'package:aves/widgets/common/basic/scaffold.dart';
|
import 'package:aves/widgets/common/basic/scaffold.dart';
|
||||||
|
@ -25,6 +25,7 @@ import 'package:aves/widgets/debug/media_store_scan_dialog.dart';
|
||||||
import 'package:aves/widgets/debug/report.dart';
|
import 'package:aves/widgets/debug/report.dart';
|
||||||
import 'package:aves/widgets/debug/settings.dart';
|
import 'package:aves/widgets/debug/settings.dart';
|
||||||
import 'package:aves/widgets/debug/storage.dart';
|
import 'package:aves/widgets/debug/storage.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
@ -36,6 +37,7 @@ class AppDebugPage extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return Directionality(
|
return Directionality(
|
||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
child: AvesScaffold(
|
child: AvesScaffold(
|
||||||
|
@ -56,9 +58,10 @@ class AppDebugPage extends StatelessWidget {
|
||||||
.toList(),
|
.toList(),
|
||||||
onSelected: (action) async {
|
onSelected: (action) async {
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
unawaited(_onActionSelected(context, action));
|
unawaited(_onActionSelected(context, action));
|
||||||
},
|
},
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/naming_pattern.dart';
|
import 'package:aves/model/naming_pattern.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/theme/durations.dart';
|
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/theme/styles.dart';
|
import 'package:aves/theme/styles.dart';
|
||||||
import 'package:aves/widgets/collection/collection_grid.dart';
|
import 'package:aves/widgets/collection/collection_grid.dart';
|
||||||
|
@ -14,8 +14,10 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/grid/theme.dart';
|
import 'package:aves/widgets/common/grid/theme.dart';
|
||||||
import 'package:aves/widgets/common/identity/buttons/outlined_button.dart';
|
import 'package:aves/widgets/common/identity/buttons/outlined_button.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/decorated.dart';
|
import 'package:aves/widgets/common/thumbnail/decorated.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class RenameEntrySetPage extends StatefulWidget {
|
class RenameEntrySetPage extends StatefulWidget {
|
||||||
static const routeName = '/rename_entry_set';
|
static const routeName = '/rename_entry_set';
|
||||||
|
@ -62,6 +64,7 @@ class _RenameEntrySetPageState extends State<RenameEntrySetPage> {
|
||||||
final l10n = context.l10n;
|
final l10n = context.l10n;
|
||||||
final textScaler = MediaQuery.textScalerOf(context);
|
final textScaler = MediaQuery.textScalerOf(context);
|
||||||
final effectiveThumbnailExtent = max(thumbnailExtent, textScaler.scale(thumbnailExtent));
|
final effectiveThumbnailExtent = max(thumbnailExtent, textScaler.scale(thumbnailExtent));
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return AvesScaffold(
|
return AvesScaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(l10n.renameEntrySetPageTitle),
|
title: Text(l10n.renameEntrySetPageTitle),
|
||||||
|
@ -104,11 +107,12 @@ class _RenameEntrySetPageState extends State<RenameEntrySetPage> {
|
||||||
},
|
},
|
||||||
onSelected: (key) async {
|
onSelected: (key) async {
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
_insertProcessor(key);
|
_insertProcessor(key);
|
||||||
},
|
},
|
||||||
tooltip: l10n.renameEntrySetPageInsertTooltip,
|
tooltip: l10n.renameEntrySetPageInsertTooltip,
|
||||||
icon: const Icon(AIcons.add),
|
icon: const Icon(AIcons.add),
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:math';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/common/fx/borders.dart';
|
import 'package:aves/widgets/common/fx/borders.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/image.dart';
|
import 'package:aves/widgets/common/thumbnail/image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -50,7 +51,7 @@ class ItemPicker extends StatelessWidget {
|
||||||
bottom: -1,
|
bottom: -1,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).brightness == Brightness.dark ? const Color(0xAA000000) : const Color(0xCCFFFFFF),
|
color: Theme.of(context).isDark ? const Color(0xAA000000) : const Color(0xCCFFFFFF),
|
||||||
border: AvesBorder.border(context),
|
border: AvesBorder.border(context),
|
||||||
borderRadius: actionBoxBorderRadius,
|
borderRadius: actionBoxBorderRadius,
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:aves/app_mode.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';
|
||||||
import 'package:aves/model/selection.dart';
|
import 'package:aves/model/selection.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/album.dart';
|
import 'package:aves/model/source/album.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
|
@ -205,6 +206,7 @@ class _AlbumPickPageState extends State<_AlbumPickPage> {
|
||||||
required bool Function(ChipSetAction action) isVisible,
|
required bool Function(ChipSetAction action) isVisible,
|
||||||
required void Function(ChipSetAction action) onActionSelected,
|
required void Function(ChipSetAction action) onActionSelected,
|
||||||
}) {
|
}) {
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return [
|
return [
|
||||||
if (widget.moveType != null)
|
if (widget.moveType != null)
|
||||||
..._quickActions.where(isVisible).map(
|
..._quickActions.where(isVisible).map(
|
||||||
|
@ -227,9 +229,10 @@ class _AlbumPickPageState extends State<_AlbumPickPage> {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
onActionSelected(action);
|
onActionSelected(action);
|
||||||
},
|
},
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/query.dart';
|
import 'package:aves/model/query.dart';
|
||||||
import 'package:aves/model/selection.dart';
|
import 'package:aves/model/selection.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_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
|
@ -329,6 +330,7 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
|
||||||
(action) => _buildButtonIcon(context, actionDelegate, action, enabled: canApply(action)),
|
(action) => _buildButtonIcon(context, actionDelegate, action, enabled: canApply(action)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return [
|
return [
|
||||||
...quickActionButtons,
|
...quickActionButtons,
|
||||||
PopupMenuButton<ChipSetAction>(
|
PopupMenuButton<ChipSetAction>(
|
||||||
|
@ -366,9 +368,10 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
_onActionSelected(context, action, actionDelegate);
|
_onActionSelected(context, action, actionDelegate);
|
||||||
},
|
},
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:aves/model/filters/coordinate.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/geotiff.dart';
|
import 'package:aves/model/geotiff.dart';
|
||||||
import 'package:aves/model/highlight.dart';
|
import 'package:aves/model/highlight.dart';
|
||||||
|
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||||
import 'package:aves/model/settings/enums/map_style.dart';
|
import 'package:aves/model/settings/enums/map_style.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';
|
||||||
|
@ -462,6 +463,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
||||||
) async {
|
) async {
|
||||||
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
const touchArea = Size(kMinInteractiveDimension, kMinInteractiveDimension);
|
const touchArea = Size(kMinInteractiveDimension, kMinInteractiveDimension);
|
||||||
|
final animations = context.read<Settings>().accessibilityAnimations;
|
||||||
final selectedAction = await showMenu<MapClusterAction>(
|
final selectedAction = await showMenu<MapClusterAction>(
|
||||||
context: context,
|
context: context,
|
||||||
position: RelativeRect.fromRect(tapLocalPosition & touchArea, Offset.zero & overlay.size),
|
position: RelativeRect.fromRect(tapLocalPosition & touchArea, Offset.zero & overlay.size),
|
||||||
|
@ -482,10 +484,11 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
||||||
MapClusterAction.removeLocation,
|
MapClusterAction.removeLocation,
|
||||||
].map(_buildMenuItem),
|
].map(_buildMenuItem),
|
||||||
],
|
],
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
);
|
);
|
||||||
if (selectedAction != null) {
|
if (selectedAction != null) {
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
final delegate = EntrySetActionDelegate();
|
final delegate = EntrySetActionDelegate();
|
||||||
switch (selectedAction) {
|
switch (selectedAction) {
|
||||||
case MapClusterAction.editLocation:
|
case MapClusterAction.editLocation:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/styles.dart';
|
import 'package:aves/theme/styles.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
||||||
import 'package:decorated_icon/decorated_icon.dart';
|
import 'package:decorated_icon/decorated_icon.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -16,7 +17,8 @@ class SettingsTileLeading extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final colorScheme = Theme.of(context).colorScheme;
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
return AnimatedContainer(
|
return AnimatedContainer(
|
||||||
padding: const EdgeInsets.all(6),
|
padding: const EdgeInsets.all(6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -32,7 +34,7 @@ class SettingsTileLeading extends StatelessWidget {
|
||||||
icon,
|
icon,
|
||||||
size: 18,
|
size: 18,
|
||||||
color: DefaultTextStyle.of(context).style.color,
|
color: DefaultTextStyle.of(context).style.color,
|
||||||
shadows: colorScheme.brightness == Brightness.dark ? AStyles.embossShadows : null,
|
shadows: theme.isDark ? AStyles.embossShadows : null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
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/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
|
@ -18,6 +19,7 @@ import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class FilePickerPage extends StatefulWidget {
|
class FilePickerPage extends StatefulWidget {
|
||||||
static const routeName = '/file_picker';
|
static const routeName = '/file_picker';
|
||||||
|
@ -57,6 +59,7 @@ class _FilePickerPageState extends State<FilePickerPage> {
|
||||||
return !isHidden;
|
return !isHidden;
|
||||||
}
|
}
|
||||||
}).toList();
|
}).toList();
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return PopScope(
|
return PopScope(
|
||||||
canPop: _directory.relativeDir.isEmpty,
|
canPop: _directory.relativeDir.isEmpty,
|
||||||
onPopInvoked: (didPop) {
|
onPopInvoked: (didPop) {
|
||||||
|
@ -82,13 +85,14 @@ class _FilePickerPageState extends State<FilePickerPage> {
|
||||||
},
|
},
|
||||||
onSelected: (action) async {
|
onSelected: (action) async {
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case _PickerAction.toggleHiddenView:
|
case _PickerAction.toggleHiddenView:
|
||||||
settings.filePickerShowHiddenFiles = !showHidden;
|
settings.filePickerShowHiddenFiles = !showHidden;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||||
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
import 'package:aves/ref/mime_types.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/theme/themes.dart';
|
import 'package:aves/theme/themes.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
||||||
|
@ -45,6 +46,7 @@ class _SettingsMobilePageState extends State<SettingsMobilePage> with FeedbackMi
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return AvesScaffold(
|
return AvesScaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: InteractiveAppBarTitle(
|
title: InteractiveAppBarTitle(
|
||||||
|
@ -72,9 +74,10 @@ class _SettingsMobilePageState extends State<SettingsMobilePage> with FeedbackMi
|
||||||
},
|
},
|
||||||
onSelected: (action) async {
|
onSelected: (action) async {
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
_onActionSelected(action);
|
_onActionSelected(action);
|
||||||
},
|
},
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
].map((v) => FontSizeIconTheme(child: v)).toList(),
|
].map((v) => FontSizeIconTheme(child: v)).toList(),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:aves/theme/styles.dart';
|
import 'package:aves/theme/styles.dart';
|
||||||
import 'package:aves/widgets/common/basic/text/outlined.dart';
|
import 'package:aves/widgets/common/basic/text/outlined.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ class LinearPercentIndicatorText extends StatelessWidget {
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: percentFormat.format(percent),
|
text: percentFormat.format(percent),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
shadows: theme.brightness == Brightness.dark ? AStyles.embossShadows : null,
|
shadows: theme.isDark ? AStyles.embossShadows : null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/multipage.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/widgets/viewer/controls/cast.dart';
|
import 'package:aves/widgets/viewer/controls/cast.dart';
|
||||||
|
|
|
@ -11,6 +11,7 @@ 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/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/widgets/common/behaviour/springy_scroll_physics.dart';
|
import 'package:aves/widgets/common/behaviour/springy_scroll_physics.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/viewer/action/entry_action_delegate.dart';
|
import 'package:aves/widgets/viewer/action/entry_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/intents.dart';
|
import 'package:aves/widgets/viewer/controls/intents.dart';
|
||||||
|
@ -171,7 +172,7 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
|
||||||
return ValueListenableBuilder<double>(
|
return ValueListenableBuilder<double>(
|
||||||
valueListenable: widget.overlayOpacity,
|
valueListenable: widget.overlayOpacity,
|
||||||
builder: (context, overlayOpacity, child) {
|
builder: (context, overlayOpacity, child) {
|
||||||
final background = Theme.of(context).brightness == Brightness.dark ? Colors.black : Color.lerp(Colors.black, Colors.white, overlayOpacity)!;
|
final background = Theme.of(context).isDark ? Colors.black : Color.lerp(Colors.black, Colors.white, overlayOpacity)!;
|
||||||
return Container(
|
return Container(
|
||||||
color: background.withOpacity(backgroundOpacity),
|
color: background.withOpacity(backgroundOpacity),
|
||||||
child: child,
|
child: child,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:aves/widgets/common/basic/scaffold.dart';
|
import 'package:aves/widgets/common/basic/scaffold.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/viewer/controls/controller.dart';
|
import 'package:aves/widgets/viewer/controls/controller.dart';
|
||||||
import 'package:aves/widgets/viewer/entry_viewer_stack.dart';
|
import 'package:aves/widgets/viewer/entry_viewer_stack.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/bottom.dart';
|
import 'package:aves/widgets/viewer/overlay/bottom.dart';
|
||||||
|
@ -26,6 +27,8 @@ class EntryViewerPage extends StatefulWidget {
|
||||||
static EdgeInsets snackBarMargin(BuildContext context) {
|
static EdgeInsets snackBarMargin(BuildContext context) {
|
||||||
return EdgeInsets.only(bottom: ViewerBottomOverlay.actionSafeHeight(context));
|
return EdgeInsets.only(bottom: ViewerBottomOverlay.actionSafeHeight(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Color getBackground(BuildContext context) => Theme.of(context).isDark ? Colors.black : Colors.white;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EntryViewerPageState extends State<EntryViewerPage> {
|
class _EntryViewerPageState extends State<EntryViewerPage> {
|
||||||
|
@ -56,11 +59,7 @@ class _EntryViewerPageState extends State<EntryViewerPage> {
|
||||||
viewerController: _viewerController,
|
viewerController: _viewerController,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: Navigator.canPop(context)
|
backgroundColor: Navigator.canPop(context) ? Colors.transparent : EntryViewerPage.getBackground(context),
|
||||||
? Colors.transparent
|
|
||||||
: Theme.of(context).brightness == Brightness.dark
|
|
||||||
? Colors.black
|
|
||||||
: Colors.white,
|
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/selection.dart';
|
import 'package:aves/model/selection.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/theme/durations.dart';
|
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/theme/themes.dart';
|
import 'package:aves/theme/themes.dart';
|
||||||
import 'package:aves/view/view.dart';
|
import 'package:aves/view/view.dart';
|
||||||
|
@ -49,6 +49,7 @@ class InfoAppBar extends StatelessWidget {
|
||||||
final commonActions = EntryActions.commonMetadataActions.where(isVisible);
|
final commonActions = EntryActions.commonMetadataActions.where(isVisible);
|
||||||
final formatSpecificActions = EntryActions.formatSpecificMetadataActions.where(isVisible);
|
final formatSpecificActions = EntryActions.formatSpecificMetadataActions.where(isVisible);
|
||||||
final useTvLayout = settings.useTvLayout;
|
final useTvLayout = settings.useTvLayout;
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return SliverAppBar(
|
return SliverAppBar(
|
||||||
leading: useTvLayout
|
leading: useTvLayout
|
||||||
? null
|
? null
|
||||||
|
@ -91,9 +92,10 @@ class InfoAppBar extends StatelessWidget {
|
||||||
],
|
],
|
||||||
onSelected: (action) async {
|
onSelected: (action) async {
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
actionDelegate.onActionSelected(context, entry, collection, action);
|
actionDelegate.onActionSelected(context, entry, collection, action);
|
||||||
},
|
},
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
].map((v) => FontSizeIconTheme(child: v)).toList(),
|
].map((v) => FontSizeIconTheme(child: v)).toList(),
|
||||||
floating: true,
|
floating: true,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/styles.dart';
|
import 'package:aves/theme/styles.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/viewer/multipage/controller.dart';
|
import 'package:aves/widgets/viewer/multipage/controller.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/details/date.dart';
|
import 'package:aves/widgets/viewer/overlay/details/date.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/details/description.dart';
|
import 'package:aves/widgets/viewer/overlay/details/description.dart';
|
||||||
|
@ -136,7 +137,7 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
static const double iconPadding = 8.0;
|
static const double iconPadding = 8.0;
|
||||||
static const double iconSize = 16.0;
|
static const double iconSize = 16.0;
|
||||||
|
|
||||||
static List<Shadow>? shadows(BuildContext context) => Theme.of(context).brightness == Brightness.dark ? AStyles.embossShadows : null;
|
static List<Shadow>? shadows(BuildContext context) => Theme.of(context).isDark ? AStyles.embossShadows : null;
|
||||||
|
|
||||||
const ViewerDetailOverlayContent({
|
const ViewerDetailOverlayContent({
|
||||||
super.key,
|
super.key,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:aves/theme/format.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/theme/styles.dart';
|
import 'package:aves/theme/styles.dart';
|
||||||
import 'package:aves/theme/themes.dart';
|
import 'package:aves/theme/themes.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.dart';
|
||||||
import 'package:aves/widgets/common/fx/blurred.dart';
|
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||||
import 'package:aves/widgets/common/fx/borders.dart';
|
import 'package:aves/widgets/common/fx/borders.dart';
|
||||||
import 'package:aves_video/aves_video.dart';
|
import 'package:aves_video/aves_video.dart';
|
||||||
|
@ -39,9 +40,9 @@ class _VideoProgressBarState extends State<VideoProgressBar> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final blurred = settings.enableBlurEffect;
|
final blurred = settings.enableBlurEffect;
|
||||||
final brightness = Theme.of(context).brightness;
|
final theme = Theme.of(context);
|
||||||
final textStyle = TextStyle(
|
final textStyle = TextStyle(
|
||||||
shadows: brightness == Brightness.dark ? AStyles.embossShadows : null,
|
shadows: theme.isDark ? AStyles.embossShadows : null,
|
||||||
);
|
);
|
||||||
const strutStyle = StrutStyle(
|
const strutStyle = StrutStyle(
|
||||||
forceStrutHeight: true,
|
forceStrutHeight: true,
|
||||||
|
@ -71,7 +72,7 @@ class _VideoProgressBarState extends State<VideoProgressBar> {
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
|
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Themes.overlayBackgroundColor(brightness: brightness, blurred: blurred),
|
color: Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred),
|
||||||
border: AvesBorder.border(context),
|
border: AvesBorder.border(context),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(radius)),
|
borderRadius: const BorderRadius.all(Radius.circular(radius)),
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,9 +4,9 @@ import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/multipage.dart';
|
import 'package:aves/model/entry/extensions/multipage.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.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/theme/durations.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';
|
||||||
|
@ -250,6 +250,7 @@ class _ViewerButtonRowContentState extends State<ViewerButtonRowContent> {
|
||||||
final exportActions = widget.exportActions;
|
final exportActions = widget.exportActions;
|
||||||
final videoActions = widget.videoActions;
|
final videoActions = widget.videoActions;
|
||||||
final hasOverflowMenu = pageEntry.canRotate || pageEntry.canFlip || topLevelActions.isNotEmpty || exportActions.isNotEmpty || videoActions.isNotEmpty;
|
final hasOverflowMenu = pageEntry.canRotate || pageEntry.canFlip || topLevelActions.isNotEmpty || exportActions.isNotEmpty || videoActions.isNotEmpty;
|
||||||
|
final animations = context.select<Settings, AccessibilityAnimations>((s) => s.accessibilityAnimations);
|
||||||
return Selector<VideoConductor, AvesVideoController?>(
|
return Selector<VideoConductor, AvesVideoController?>(
|
||||||
selector: (context, vc) => vc.getController(pageEntry),
|
selector: (context, vc) => vc.getController(pageEntry),
|
||||||
builder: (context, videoController, child) {
|
builder: (context, videoController, child) {
|
||||||
|
@ -301,10 +302,11 @@ class _ViewerButtonRowContentState extends State<ViewerButtonRowContent> {
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
onSelected: (action) {
|
onSelected: (action) async {
|
||||||
_popupExpandedNotifier.value = null;
|
_popupExpandedNotifier.value = null;
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
Future.delayed(ADurations.popupMenuAnimation * timeDilation, () => widget.actionDelegate.onActionSelected(context, action));
|
await Future.delayed(animations.popUpAnimationDelay * timeDilation);
|
||||||
|
widget.actionDelegate.onActionSelected(context, action);
|
||||||
},
|
},
|
||||||
onCanceled: () {
|
onCanceled: () {
|
||||||
_popupExpandedNotifier.value = null;
|
_popupExpandedNotifier.value = null;
|
||||||
|
@ -316,6 +318,7 @@ class _ViewerButtonRowContentState extends State<ViewerButtonRowContent> {
|
||||||
// so we make sure overlay stays visible
|
// so we make sure overlay stays visible
|
||||||
const ToggleOverlayNotification(visible: true).dispatch(context);
|
const ToggleOverlayNotification(visible: true).dispatch(context);
|
||||||
},
|
},
|
||||||
|
popUpAnimationStyle: animations.popUpAnimationStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
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/viewer/entry_viewer_page.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ class _ErrorViewState extends State<ErrorView> {
|
||||||
// use container to expand constraints, so that the user can tap anywhere
|
// use container to expand constraints, so that the user can tap anywhere
|
||||||
child: Container(
|
child: Container(
|
||||||
// opaque to cover potential lower quality layer below
|
// opaque to cover potential lower quality layer below
|
||||||
color: Colors.black,
|
color: EntryViewerPage.getBackground(context),
|
||||||
child: FutureBuilder<bool>(
|
child: FutureBuilder<bool>(
|
||||||
future: _exists,
|
future: _exists,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/widgets/aves_app.dart';
|
import 'package:aves/widgets/aves_app.dart';
|
||||||
import 'package:aves/widgets/common/basic/insets.dart';
|
import 'package:aves/widgets/common/basic/insets.dart';
|
||||||
import 'package:aves/widgets/common/basic/scaffold.dart';
|
import 'package:aves/widgets/common/basic/scaffold.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/theme.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';
|
||||||
|
@ -50,7 +51,7 @@ class WallpaperPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
backgroundColor: Theme.of(context).brightness == Brightness.dark ? Colors.black : Colors.white,
|
backgroundColor: Theme.of(context).isDark ? Colors.black : Colors.white,
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,10 +81,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.1.2"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
@ -137,10 +137,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: logger
|
name: logger
|
||||||
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
|
sha256: b3ff55aeb08d9d8901b767650285872cb1bb8f508373b3e348d60268b0c7f770
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2+1"
|
version: "2.1.0"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -201,10 +201,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.1.2"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -262,10 +262,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad"
|
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.5.1"
|
||||||
wkt_parser:
|
wkt_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -5,10 +5,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _flutterfire_internals
|
name: _flutterfire_internals
|
||||||
sha256: "737321f9be522620ed3794937298fb0027a48a402624fa2500f7532f94aea810"
|
sha256: "4eec93681221723a686ad580c2e7d960e1017cf1a4e0a263c2573c2c6b0bf5cd"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.22"
|
version: "1.3.25"
|
||||||
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: "7e049e32a9d347616edb39542cf92cd53fdb4a99fb6af0a0bff327c14cd76445"
|
sha256: "53316975310c8af75a96e365f9fccb67d1c544ef0acdbf0d88bbe30eedd1c4f9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.25.4"
|
version: "2.27.0"
|
||||||
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: "57e61d6010e253b36d38191cefd6199d7849152cdcd234b61ca290cdb278a0ba"
|
sha256: c8e1d59385eee98de63c92f961d2a7062c5d9a65e7f45bdc7f1b0b205aab2492
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.4"
|
version: "2.11.5"
|
||||||
firebase_crashlytics:
|
firebase_crashlytics:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics
|
name: firebase_crashlytics
|
||||||
sha256: "4c754db28a7daabe03c4cbf1079dbe81e6f0681284fed6d07e0e640b7f1027c4"
|
sha256: c4f1b723d417bc9c4774810e774ff91df8fb0032d33fb2888b2c887e865581b8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.15"
|
version: "3.4.18"
|
||||||
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: "08c5d7b5f93dbad7306d26702935abd8b579313ea256eb27006562a1867df249"
|
sha256: c5a11fca3df76a98e3fa68fde8b10a08aacb9a7639f619fbfd4dad6c67a08643
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.6.22"
|
version: "3.6.25"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
@ -144,10 +144,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: logger
|
name: logger
|
||||||
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
|
sha256: b3ff55aeb08d9d8901b767650285872cb1bb8f508373b3e348d60268b0c7f770
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2+1"
|
version: "2.1.0"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -208,10 +208,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.1.2"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -269,10 +269,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad"
|
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.5.1"
|
||||||
wkt_parser:
|
wkt_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -53,7 +53,7 @@ class EntryGoogleMap<T> extends StatefulWidget {
|
||||||
State<StatefulWidget> createState() => _EntryGoogleMapState<T>();
|
State<StatefulWidget> createState() => _EntryGoogleMapState<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindingObserver {
|
class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> {
|
||||||
GoogleMapController? _serviceMapController;
|
GoogleMapController? _serviceMapController;
|
||||||
final List<StreamSubscription> _subscriptions = [];
|
final List<StreamSubscription> _subscriptions = [];
|
||||||
Map<MarkerKey<T>, GeoEntry<T>> _geoEntryByMarkerKey = {};
|
Map<MarkerKey<T>, GeoEntry<T>> _geoEntryByMarkerKey = {};
|
||||||
|
@ -72,7 +72,6 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
|
||||||
_sizeNotifier.addListener(_onSizeChanged);
|
_sizeNotifier.addListener(_onSizeChanged);
|
||||||
_registerWidget(widget);
|
_registerWidget(widget);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +87,6 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_unregisterWidget(widget);
|
_unregisterWidget(widget);
|
||||||
_serviceMapController?.dispose();
|
_serviceMapController?.dispose();
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
|
||||||
_sizeNotifier.dispose();
|
_sizeNotifier.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
@ -109,15 +107,6 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
..clear();
|
..clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
|
||||||
if (state == AppLifecycleState.resumed) {
|
|
||||||
// workaround for blank map when resuming app
|
|
||||||
// cf https://github.com/flutter/flutter/issues/40284
|
|
||||||
_serviceMapController?.setMapStyle(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return Stack(
|
||||||
|
|
|
@ -187,50 +187,50 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps
|
name: google_maps
|
||||||
sha256: "555d5d736339b0478e821167ac521c810d7b51c3b2734e6802a9f046b64ea37a"
|
sha256: "47eef3836b49bb030d5cb3afc60b8451408bf34cf753e571b645d6529eb4251a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.0"
|
version: "7.1.0"
|
||||||
google_maps_flutter:
|
google_maps_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter
|
name: google_maps_flutter
|
||||||
sha256: ae66fef3e71261d7df2eff29b2a119e190b2884325ecaa55321b1e17b5504066
|
sha256: "982c2e22ec78d32701bfbd351311e8579a4952035381ac66462c0af11003107b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.3"
|
version: "2.6.0"
|
||||||
google_maps_flutter_android:
|
google_maps_flutter_android:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_android
|
name: google_maps_flutter_android
|
||||||
sha256: "714530f865f13bb3b9505c58821c3baed5d247a871724acf5d2ea5808fbed02c"
|
sha256: "256b3c974e415bd17555ceff76a5d0badd2cbfd29febfc23070993358f639550"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.2"
|
version: "2.7.0"
|
||||||
google_maps_flutter_ios:
|
google_maps_flutter_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_ios
|
name: google_maps_flutter_ios
|
||||||
sha256: "29503b5159da2308a66212c3827963998bfb943ba073e2114fb2d486b47fd2c8"
|
sha256: "0997f99d8bd8712f648a49bfc96a3cf2713cfdaf73a005c719aab74eaef94030"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.2"
|
version: "2.5.0"
|
||||||
google_maps_flutter_platform_interface:
|
google_maps_flutter_platform_interface:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_platform_interface
|
name: google_maps_flutter_platform_interface
|
||||||
sha256: "6060779f020638a8eedeb0fb14234818e5fa32ec45a4653d6428ab436e2bbc64"
|
sha256: "167af879da4d004cd58771f1469b91dcc3b9b0a2c5334cc6bf71fd41d4b35403"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.3"
|
version: "2.6.0"
|
||||||
google_maps_flutter_web:
|
google_maps_flutter_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_web
|
name: google_maps_flutter_web
|
||||||
sha256: "6245721c160d6f531c1ef568cf9bef8d660cd585a982aa75121269030163785a"
|
sha256: "861c6dd430123e58bb1154342345c5bfa36064120c8ec3dbc0d0b7522add1861"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.4+3"
|
version: "0.5.6+2"
|
||||||
html:
|
html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -307,10 +307,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: logger
|
name: logger
|
||||||
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
|
sha256: b3ff55aeb08d9d8901b767650285872cb1bb8f508373b3e348d60268b0c7f770
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2+1"
|
version: "2.1.0"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -379,10 +379,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.1.2"
|
||||||
sanitize_html:
|
sanitize_html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -456,18 +456,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad"
|
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.5.1"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.2.0"
|
version: "5.3.0"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -486,4 +486,4 @@ packages:
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.3.0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.16.6"
|
flutter: ">=3.19.0"
|
||||||
|
|
|
@ -183,10 +183,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: logger
|
name: logger
|
||||||
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
|
sha256: b3ff55aeb08d9d8901b767650285872cb1bb8f508373b3e348d60268b0c7f770
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2+1"
|
version: "2.1.0"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -255,10 +255,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.1.2"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -316,10 +316,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad"
|
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.5.1"
|
||||||
wkt_parser:
|
wkt_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -151,10 +151,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: logger
|
name: logger
|
||||||
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
|
sha256: b3ff55aeb08d9d8901b767650285872cb1bb8f508373b3e348d60268b0c7f770
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2+1"
|
version: "2.1.0"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -215,10 +215,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.1.2"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -276,10 +276,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad"
|
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.5.1"
|
||||||
wkt_parser:
|
wkt_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -441,10 +441,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.2.0"
|
version: "5.3.0"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
70
pubspec.lock
70
pubspec.lock
|
@ -13,10 +13,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _flutterfire_internals
|
name: _flutterfire_internals
|
||||||
sha256: "737321f9be522620ed3794937298fb0027a48a402624fa2500f7532f94aea810"
|
sha256: "4eec93681221723a686ad580c2e7d960e1017cf1a4e0a263c2573c2c6b0bf5cd"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.22"
|
version: "1.3.25"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -314,10 +314,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: dynamic_color
|
name: dynamic_color
|
||||||
sha256: a866f1f8947bfdaf674d7928e769eac7230388a2e7a2542824fad4bb5b87be3b
|
sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.9"
|
version: "1.7.0"
|
||||||
equatable:
|
equatable:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -388,10 +388,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core
|
name: firebase_core
|
||||||
sha256: "7e049e32a9d347616edb39542cf92cd53fdb4a99fb6af0a0bff327c14cd76445"
|
sha256: "53316975310c8af75a96e365f9fccb67d1c544ef0acdbf0d88bbe30eedd1c4f9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.25.4"
|
version: "2.27.0"
|
||||||
firebase_core_platform_interface:
|
firebase_core_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -404,26 +404,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core_web
|
name: firebase_core_web
|
||||||
sha256: "57e61d6010e253b36d38191cefd6199d7849152cdcd234b61ca290cdb278a0ba"
|
sha256: c8e1d59385eee98de63c92f961d2a7062c5d9a65e7f45bdc7f1b0b205aab2492
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.4"
|
version: "2.11.5"
|
||||||
firebase_crashlytics:
|
firebase_crashlytics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics
|
name: firebase_crashlytics
|
||||||
sha256: "4c754db28a7daabe03c4cbf1079dbe81e6f0681284fed6d07e0e640b7f1027c4"
|
sha256: c4f1b723d417bc9c4774810e774ff91df8fb0032d33fb2888b2c887e865581b8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.15"
|
version: "3.4.18"
|
||||||
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: "08c5d7b5f93dbad7306d26702935abd8b579313ea256eb27006562a1867df249"
|
sha256: c5a11fca3df76a98e3fa68fde8b10a08aacb9a7639f619fbfd4dad6c67a08643
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.6.22"
|
version: "3.6.25"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -436,10 +436,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flex_color_picker
|
name: flex_color_picker
|
||||||
sha256: "0871edc170153cfc3de316d30625f40a85daecfa76ce541641f3cc0ec7757cbf"
|
sha256: "904373c7b0531fd4a92d29705a80ab4594b7647da2d93044487aaec4614cb6ed"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.1"
|
version: "3.4.0"
|
||||||
flex_seed_scheme:
|
flex_seed_scheme:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -452,10 +452,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: floating
|
name: floating
|
||||||
sha256: d9d563089e34fbd714ffdcdd2df447ec41b40c9226dacae6b4f78847aef8b991
|
sha256: "04c3c96909b94dd6d2d121c69707739825e1f3dceca5ae451a9b8c0e652d246b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.2"
|
||||||
fluster:
|
fluster:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -532,10 +532,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: a64c5323ac83ed2b7940d2b6288d160aa1753ff271ba9d9b2a86770414aa3eab
|
sha256: cb44f7831b23a6bdd0f501718b0d2e8045cbc625a15f668af37ddb80314821db
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.20+1"
|
version: "0.6.21"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -635,26 +635,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_android
|
name: google_maps_flutter_android
|
||||||
sha256: "714530f865f13bb3b9505c58821c3baed5d247a871724acf5d2ea5808fbed02c"
|
sha256: "256b3c974e415bd17555ceff76a5d0badd2cbfd29febfc23070993358f639550"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.2"
|
version: "2.7.0"
|
||||||
google_maps_flutter_ios:
|
google_maps_flutter_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_ios
|
name: google_maps_flutter_ios
|
||||||
sha256: "29503b5159da2308a66212c3827963998bfb943ba073e2114fb2d486b47fd2c8"
|
sha256: "0997f99d8bd8712f648a49bfc96a3cf2713cfdaf73a005c719aab74eaef94030"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.2"
|
version: "2.5.0"
|
||||||
google_maps_flutter_platform_interface:
|
google_maps_flutter_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_platform_interface
|
name: google_maps_flutter_platform_interface
|
||||||
sha256: "6060779f020638a8eedeb0fb14234818e5fa32ec45a4653d6428ab436e2bbc64"
|
sha256: "167af879da4d004cd58771f1469b91dcc3b9b0a2c5334cc6bf71fd41d4b35403"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.3"
|
version: "2.6.0"
|
||||||
google_maps_flutter_web:
|
google_maps_flutter_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -835,10 +835,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: logger
|
name: logger
|
||||||
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
|
sha256: b3ff55aeb08d9d8901b767650285872cb1bb8f508373b3e348d60268b0c7f770
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2+1"
|
version: "2.1.0"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -851,10 +851,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: markdown
|
name: markdown
|
||||||
sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90"
|
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.1"
|
version: "7.2.2"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1237,10 +1237,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.1.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1619,10 +1619,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_ios
|
name: url_launcher_ios
|
||||||
sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03"
|
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.4"
|
version: "6.2.5"
|
||||||
url_launcher_linux:
|
url_launcher_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1755,10 +1755,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.2.0"
|
version: "5.3.0"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1801,4 +1801,4 @@ packages:
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.3.0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.19.1"
|
flutter: ">=3.19.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.10.5+114
|
version: 1.10.6+115
|
||||||
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.19.1
|
flutter: 3.19.3
|
||||||
sdk: '>=3.3.0 <4.0.0'
|
sdk: '>=3.3.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
|
||||||
|
|
|
@ -7,37 +7,37 @@ cd /d %sdk%\platform-tools
|
||||||
|
|
||||||
@echo on
|
@echo on
|
||||||
|
|
||||||
adb.exe shell setprop log.tag.ACodec WARN
|
adb.exe shell setprop persist.log.tag.ACodec WARN
|
||||||
adb.exe shell setprop log.tag.AHierarchicalStateMachine ERROR
|
adb.exe shell setprop persist.log.tag.AHierarchicalStateMachine ERROR
|
||||||
adb.exe shell setprop log.tag.AudioCapabilities ERROR
|
adb.exe shell setprop persist.log.tag.AudioCapabilities ERROR
|
||||||
adb.exe shell setprop log.tag.AudioTrack INFO
|
adb.exe shell setprop persist.log.tag.AudioTrack INFO
|
||||||
adb.exe shell setprop log.tag.BufferPoolAccessor2.0 INFO
|
adb.exe shell setprop persist.log.tag.BufferPoolAccessor2.0 INFO
|
||||||
adb.exe shell setprop log.tag.CCodec INFO
|
adb.exe shell setprop persist.log.tag.CCodec INFO
|
||||||
adb.exe shell setprop log.tag.CCodecBufferChannel INFO
|
adb.exe shell setprop persist.log.tag.CCodecBufferChannel INFO
|
||||||
adb.exe shell setprop log.tag.CCodecBuffers INFO
|
adb.exe shell setprop persist.log.tag.CCodecBuffers INFO
|
||||||
adb.exe shell setprop log.tag.CCodecConfig INFO
|
adb.exe shell setprop persist.log.tag.CCodecConfig INFO
|
||||||
adb.exe shell setprop log.tag.Codec2Client INFO
|
adb.exe shell setprop persist.log.tag.Codec2Client INFO
|
||||||
adb.exe shell setprop log.tag.CompatibilityChangeReporter INFO
|
adb.exe shell setprop persist.log.tag.CompatibilityChangeReporter INFO
|
||||||
adb.exe shell setprop log.tag.Counters WARN
|
adb.exe shell setprop persist.log.tag.Counters WARN
|
||||||
adb.exe shell setprop log.tag.CustomizedTextParser INFO
|
adb.exe shell setprop persist.log.tag.CustomizedTextParser INFO
|
||||||
adb.exe shell setprop log.tag.EGL_emulation INFO
|
adb.exe shell setprop persist.log.tag.EGL_emulation INFO
|
||||||
adb.exe shell setprop log.tag.HostConnection INFO
|
adb.exe shell setprop persist.log.tag.HostConnection INFO
|
||||||
adb.exe shell setprop log.tag.InputMethodManager WARN
|
adb.exe shell setprop persist.log.tag.InputMethodManager WARN
|
||||||
adb.exe shell setprop log.tag.InsetsSourceConsumer INFO
|
adb.exe shell setprop persist.log.tag.InsetsSourceConsumer INFO
|
||||||
adb.exe shell setprop log.tag.InputTransport INFO
|
adb.exe shell setprop persist.log.tag.InputTransport INFO
|
||||||
adb.exe shell setprop log.tag.J4A INFO
|
adb.exe shell setprop persist.log.tag.J4A INFO
|
||||||
adb.exe shell setprop log.tag.MediaCodec WARN
|
adb.exe shell setprop persist.log.tag.MediaCodec WARN
|
||||||
adb.exe shell setprop log.tag.MediaMetadataRetriever INFO
|
adb.exe shell setprop persist.log.tag.MediaMetadataRetriever INFO
|
||||||
adb.exe shell setprop log.tag.MediaMetadataRetrieverJNI INFO
|
adb.exe shell setprop persist.log.tag.MediaMetadataRetrieverJNI INFO
|
||||||
adb.exe shell setprop log.tag.NativeTiffDecoder INFO
|
adb.exe shell setprop persist.log.tag.NativeTiffDecoder INFO
|
||||||
adb.exe shell setprop log.tag.NuMediaExtractor INFO
|
adb.exe shell setprop persist.log.tag.NuMediaExtractor INFO
|
||||||
adb.exe shell setprop log.tag.PipelineWatcher INFO
|
adb.exe shell setprop persist.log.tag.PipelineWatcher INFO
|
||||||
adb.exe shell setprop log.tag.ReflectedParamUpdater INFO
|
adb.exe shell setprop persist.log.tag.ReflectedParamUpdater INFO
|
||||||
adb.exe shell setprop log.tag.skia INFO
|
adb.exe shell setprop persist.log.tag.skia INFO
|
||||||
adb.exe shell setprop log.tag.SurfaceControl WARN
|
adb.exe shell setprop persist.log.tag.SurfaceControl WARN
|
||||||
adb.exe shell setprop log.tag.SurfaceUtils INFO
|
adb.exe shell setprop persist.log.tag.SurfaceUtils INFO
|
||||||
adb.exe shell setprop log.tag.SurfaceView WARN
|
adb.exe shell setprop persist.log.tag.SurfaceView WARN
|
||||||
adb.exe shell setprop log.tag.VideoCapabilities ERROR
|
adb.exe shell setprop persist.log.tag.VideoCapabilities ERROR
|
||||||
|
|
||||||
@echo off
|
@echo off
|
||||||
endlocal
|
endlocal
|
||||||
|
|
|
@ -1,32 +1,36 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
adb shell setprop log.tag.ACodec WARN
|
adb shell setprop persist.log.tag.ACodec WARN
|
||||||
adb shell setprop log.tag.AHierarchicalStateMachine ERROR
|
adb shell setprop persist.log.tag.AHierarchicalStateMachine ERROR
|
||||||
adb shell setprop log.tag.AudioCapabilities ERROR
|
adb shell setprop persist.log.tag.AudioCapabilities ERROR
|
||||||
adb shell setprop log.tag.AudioTrack INFO
|
adb shell setprop persist.log.tag.AudioTrack INFO
|
||||||
adb shell setprop log.tag.BufferPoolAccessor2.0 INFO
|
adb shell setprop persist.log.tag.BufferPoolAccessor2.0 INFO
|
||||||
adb shell setprop log.tag.CCodec INFO
|
adb shell setprop persist.log.tag.CCodec INFO
|
||||||
adb shell setprop log.tag.CCodecBufferChannel INFO
|
adb shell setprop persist.log.tag.CCodecBufferChannel INFO
|
||||||
adb shell setprop log.tag.CCodecBuffers INFO
|
adb shell setprop persist.log.tag.CCodecBuffers INFO
|
||||||
adb shell setprop log.tag.CCodecConfig INFO
|
adb shell setprop persist.log.tag.CCodecConfig INFO
|
||||||
adb shell setprop log.tag.Codec2Client INFO
|
adb shell setprop persist.log.tag.Codec2Client INFO
|
||||||
adb shell setprop log.tag.CompatibilityChangeReporter INFO
|
adb shell setprop persist.log.tag.CompatibilityChangeReporter INFO
|
||||||
adb shell setprop log.tag.Counters WARN
|
adb shell setprop persist.log.tag.ConnectivityManager INFO
|
||||||
adb shell setprop log.tag.CustomizedTextParser INFO
|
adb shell setprop persist.log.tag.Counters WARN
|
||||||
adb shell setprop log.tag.EGL_emulation INFO
|
adb shell setprop persist.log.tag.CustomizedTextParser INFO
|
||||||
adb shell setprop log.tag.HostConnection INFO
|
adb shell setprop persist.log.tag.EGL_emulation INFO
|
||||||
adb shell setprop log.tag.InputMethodManager WARN
|
adb shell setprop persist.log.tag.ffmpeg-kit-flutter INFO
|
||||||
adb shell setprop log.tag.InsetsSourceConsumer INFO
|
adb shell setprop persist.log.tag.HostConnection INFO
|
||||||
adb shell setprop log.tag.InputTransport INFO
|
adb shell setprop persist.log.tag.InputMethodManager WARN
|
||||||
adb shell setprop log.tag.J4A INFO
|
adb shell setprop persist.log.tag.InsetsSourceConsumer INFO
|
||||||
adb shell setprop log.tag.MediaCodec WARN
|
adb shell setprop persist.log.tag.InputTransport INFO
|
||||||
adb shell setprop log.tag.MediaMetadataRetriever INFO
|
adb shell setprop persist.log.tag.J4A INFO
|
||||||
adb shell setprop log.tag.MediaMetadataRetrieverJNI INFO
|
adb shell setprop persist.log.tag.MediaCodec WARN
|
||||||
adb shell setprop log.tag.NativeTiffDecoder INFO
|
adb shell setprop persist.log.tag.MediaMetadataRetriever INFO
|
||||||
adb shell setprop log.tag.NuMediaExtractor INFO
|
adb shell setprop persist.log.tag.MediaMetadataRetrieverJNI INFO
|
||||||
adb shell setprop log.tag.PipelineWatcher INFO
|
adb shell setprop persist.log.tag.NativeTiffDecoder INFO
|
||||||
adb shell setprop log.tag.ReflectedParamUpdater INFO
|
adb shell setprop persist.log.tag.NuMediaExtractor INFO
|
||||||
adb shell setprop log.tag.skia INFO
|
adb shell setprop persist.log.tag.OpenGLRenderer INFO
|
||||||
adb shell setprop log.tag.SurfaceControl WARN
|
adb shell setprop persist.log.tag.PipelineWatcher INFO
|
||||||
adb shell setprop log.tag.SurfaceUtils INFO
|
adb shell setprop persist.log.tag.ReflectedParamUpdater INFO
|
||||||
adb shell setprop log.tag.SurfaceView WARN
|
adb shell setprop persist.log.tag.skia INFO
|
||||||
adb shell setprop log.tag.VideoCapabilities ERROR
|
adb shell setprop persist.log.tag.SurfaceControl WARN
|
||||||
|
adb shell setprop persist.log.tag.SurfaceUtils INFO
|
||||||
|
adb shell setprop persist.log.tag.SurfaceView WARN
|
||||||
|
adb shell setprop persist.log.tag.VideoCapabilities ERROR
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,4 +5,10 @@ import 'package:test/fake.dart';
|
||||||
class FakeDeviceService extends Fake implements DeviceService {
|
class FakeDeviceService extends Fake implements DeviceService {
|
||||||
@override
|
@override
|
||||||
Future<int> getDefaultTimeZoneRawOffsetMillis() => SynchronousFuture(3600000);
|
Future<int> getDefaultTimeZoneRawOffsetMillis() => SynchronousFuture(3600000);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> getAvailableHeapSize() => SynchronousFuture(0x7fffffff);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> requestGarbageCollection() => SynchronousFuture(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,12 @@ class FakeMediaStoreService extends Fake implements MediaStoreService {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int?> getGeneration() async {
|
||||||
|
if (latency != null) await Future.delayed(latency!);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<AvesEntry> getEntries(Map<int?, int?> knownEntries, {String? directory}) => Stream.fromIterable(entries);
|
Stream<AvesEntry> getEntries(Map<int?, int?> knownEntries, {String? directory}) => Stream.fromIterable(entries);
|
||||||
|
|
||||||
|
|
|
@ -1889,15 +1889,6 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
"de": [
|
|
||||||
"entryActionCast",
|
|
||||||
"overlayHistogramNone",
|
|
||||||
"castDialogTitle",
|
|
||||||
"collectionActionSetHome",
|
|
||||||
"setHomeCustomCollection",
|
|
||||||
"settingsThumbnailShowHdrIcon"
|
|
||||||
],
|
|
||||||
|
|
||||||
"el": [
|
"el": [
|
||||||
"entryActionCast",
|
"entryActionCast",
|
||||||
"castDialogTitle",
|
"castDialogTitle",
|
||||||
|
@ -1916,37 +1907,19 @@
|
||||||
],
|
],
|
||||||
|
|
||||||
"fa": [
|
"fa": [
|
||||||
"filterLocatedLabel",
|
|
||||||
"filterTaggedLabel",
|
|
||||||
"filterRatingRejectedLabel",
|
|
||||||
"albumTierSpecial",
|
|
||||||
"coordinateFormatDms",
|
"coordinateFormatDms",
|
||||||
"coordinateFormatDecimal",
|
|
||||||
"coordinateDms",
|
"coordinateDms",
|
||||||
"coordinateDmsNorth",
|
"coordinateDmsNorth",
|
||||||
"coordinateDmsSouth",
|
"coordinateDmsSouth",
|
||||||
"coordinateDmsEast",
|
"coordinateDmsEast",
|
||||||
"coordinateDmsWest",
|
"coordinateDmsWest",
|
||||||
"overlayHistogramNone",
|
|
||||||
"overlayHistogramRGB",
|
"overlayHistogramRGB",
|
||||||
"overlayHistogramLuminance",
|
|
||||||
"videoPlaybackSkip",
|
|
||||||
"viewerTransitionParallax",
|
|
||||||
"missingSystemFilePickerDialogMessage",
|
|
||||||
"unsupportedTypeDialogMessage",
|
"unsupportedTypeDialogMessage",
|
||||||
"nameConflictDialogSingleSourceMessage",
|
|
||||||
"nameConflictDialogMultipleSourceMessage",
|
|
||||||
"addShortcutDialogLabel",
|
|
||||||
"addShortcutButtonLabel",
|
|
||||||
"noMatchingAppDialogMessage",
|
|
||||||
"binEntriesConfirmationDialogMessage",
|
"binEntriesConfirmationDialogMessage",
|
||||||
"deleteEntriesConfirmationDialogMessage",
|
"deleteEntriesConfirmationDialogMessage",
|
||||||
"moveUndatedConfirmationDialogMessage",
|
"moveUndatedConfirmationDialogMessage",
|
||||||
"moveUndatedConfirmationDialogSetDate",
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"videoResumeButtonLabel",
|
|
||||||
"setCoverDialogLatest",
|
"setCoverDialogLatest",
|
||||||
"setCoverDialogAuto",
|
|
||||||
"setCoverDialogCustom",
|
|
||||||
"hideFilterConfirmationDialogMessage",
|
"hideFilterConfirmationDialogMessage",
|
||||||
"newAlbumDialogTitle",
|
"newAlbumDialogTitle",
|
||||||
"newAlbumDialogNameLabel",
|
"newAlbumDialogNameLabel",
|
||||||
|
@ -4795,14 +4768,6 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
"id": [
|
|
||||||
"entryActionCast",
|
|
||||||
"castDialogTitle",
|
|
||||||
"collectionActionSetHome",
|
|
||||||
"setHomeCustomCollection",
|
|
||||||
"settingsThumbnailShowHdrIcon"
|
|
||||||
],
|
|
||||||
|
|
||||||
"it": [
|
"it": [
|
||||||
"collectionActionSetHome",
|
"collectionActionSetHome",
|
||||||
"setHomeCustomCollection",
|
"setHomeCustomCollection",
|
||||||
|
@ -4810,18 +4775,13 @@
|
||||||
],
|
],
|
||||||
|
|
||||||
"ja": [
|
"ja": [
|
||||||
"columnCount",
|
|
||||||
"saveCopyButtonLabel",
|
|
||||||
"applyTooltip",
|
"applyTooltip",
|
||||||
"chipActionShowCountryStates",
|
|
||||||
"chipActionCreateVault",
|
"chipActionCreateVault",
|
||||||
"chipActionConfigureVault",
|
"chipActionConfigureVault",
|
||||||
"entryActionCast",
|
|
||||||
"viewerActionLock",
|
"viewerActionLock",
|
||||||
"viewerActionUnlock",
|
"viewerActionUnlock",
|
||||||
"editorActionTransform",
|
"editorActionTransform",
|
||||||
"editorTransformCrop",
|
"editorTransformCrop",
|
||||||
"editorTransformRotate",
|
|
||||||
"cropAspectRatioFree",
|
"cropAspectRatioFree",
|
||||||
"cropAspectRatioOriginal",
|
"cropAspectRatioOriginal",
|
||||||
"cropAspectRatioSquare",
|
"cropAspectRatioSquare",
|
||||||
|
@ -9274,24 +9234,5 @@
|
||||||
"filePickerOpenFrom",
|
"filePickerOpenFrom",
|
||||||
"filePickerNoItems",
|
"filePickerNoItems",
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
|
||||||
|
|
||||||
"zh_Hant": [
|
|
||||||
"entryActionCast",
|
|
||||||
"overlayHistogramNone",
|
|
||||||
"overlayHistogramLuminance",
|
|
||||||
"castDialogTitle",
|
|
||||||
"aboutDataUsageSectionTitle",
|
|
||||||
"aboutDataUsageData",
|
|
||||||
"aboutDataUsageCache",
|
|
||||||
"aboutDataUsageDatabase",
|
|
||||||
"aboutDataUsageMisc",
|
|
||||||
"aboutDataUsageInternal",
|
|
||||||
"aboutDataUsageExternal",
|
|
||||||
"aboutDataUsageClearCache",
|
|
||||||
"collectionActionSetHome",
|
|
||||||
"setHomeCustomCollection",
|
|
||||||
"settingsThumbnailShowHdrIcon",
|
|
||||||
"settingsViewerShowHistogram"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
In v1.10.5:
|
In v1.10.6:
|
||||||
- enjoy the app in Catalan
|
- detect HDR videos (but do not play them in their full HDR glory)
|
||||||
|
- removing animations also applies to pop up menus
|
||||||
Full changelog available on GitHub
|
Full changelog available on GitHub
|
Loading…
Reference in a new issue