Merge branch 'develop'
This commit is contained in:
commit
6f7f70babe
108 changed files with 3083 additions and 674 deletions
2
.flutter
2
.flutter
|
@ -1 +1 @@
|
||||||
Subproject commit 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
|
Subproject commit 41456452f29d64e8deb623a3c927524bcf9f111b
|
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -4,6 +4,27 @@ 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.3"></a>[v1.10.3] - 2024-01-29
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Viewer: optional histogram (for real this time)
|
||||||
|
- Collection: allow hiding thumbnail overlay HDR icon
|
||||||
|
- Collection: allow setting any filtered collection as home page
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Viewer: lift format control for tiling, allowing large DNG tiling if supported
|
||||||
|
- Info: strip `unlocated` filter from context collection when editing location via map
|
||||||
|
- Slideshow: keep playing when losing focus but app is still visible (e.g. split screen)
|
||||||
|
- upgraded Flutter to stable v3.16.9
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- crash when loading some large DNG in viewer
|
||||||
|
- searching from drawer on mobile
|
||||||
|
- resizing TIFF during conversion
|
||||||
|
|
||||||
## <a id="v1.10.2"></a>[v1.10.2] - 2023-12-24
|
## <a id="v1.10.2"></a>[v1.10.2] - 2023-12-24
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -16,6 +37,8 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## <a id="v1.10.1"></a>[v1.10.1] - 2023-12-21
|
## <a id="v1.10.1"></a>[v1.10.1] - 2023-12-21
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
- Cataloguing: detect/filter `Ultra HDR`
|
- Cataloguing: detect/filter `Ultra HDR`
|
||||||
- Viewer: show JPEG MPF dependent images (except thumbnails and HDR gain maps)
|
- Viewer: show JPEG MPF dependent images (except thumbnails and HDR gain maps)
|
||||||
- Info: show metadata from JPEG MPF
|
- Info: show metadata from JPEG MPF
|
||||||
|
|
|
@ -41,7 +41,7 @@ It scans your media collection to identify **motion photos**, **panoramas** (aka
|
||||||
|
|
||||||
**Navigation and search** is an important part of Aves. The goal is for users to easily flow from albums to photos to tags to maps, etc.
|
**Navigation and search** is an important part of Aves. The goal is for users to easily flow from albums to photos to tags to maps, etc.
|
||||||
|
|
||||||
Aves integrates with Android (from KitKat to Android 13, including Android TV) with features such as **widgets**, **app shortcuts**, **screen saver** and **global search** handling. It also works as a **media viewer and picker**.
|
Aves integrates with Android (from KitKat to Android 14, including Android TV) with features such as **widgets**, **app shortcuts**, **screen saver** and **global search** handling. It also works as a **media viewer and picker**.
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
|
|
|
@ -50,24 +50,27 @@ if (keystorePropertiesFile.exists()) {
|
||||||
android {
|
android {
|
||||||
namespace 'deckers.thibault.aves'
|
namespace 'deckers.thibault.aves'
|
||||||
compileSdk 34
|
compileSdk 34
|
||||||
ndkVersion flutter.ndkVersion
|
// cf https://developer.android.com/studio/projects/install-ndk#default-ndk-per-agp
|
||||||
|
ndkVersion '25.1.8937393'
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lint {
|
||||||
checkAllWarnings true
|
checkAllWarnings true
|
||||||
warningsAsErrors true
|
warningsAsErrors true
|
||||||
disable 'InvalidPackage'
|
disable 'InvalidPackage'
|
||||||
}
|
}
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
|
jniLibs {
|
||||||
// The Amazon Developer console mistakenly considers the app to not be 64-bit compatible
|
// The Amazon Developer console mistakenly considers the app to not be 64-bit compatible
|
||||||
// if there are some libs in `lib/armeabi-v7a` unmatched by libs in `lib/arm64-v8a`,
|
// if there are some libs in `lib/armeabi-v7a` unmatched by libs in `lib/arm64-v8a`,
|
||||||
// so we exclude the extra `neon` libs bundled by `FFmpegKit`.
|
// so we exclude the extra `neon` libs bundled by `FFmpegKit`.
|
||||||
exclude 'lib/armeabi-v7a/*_neon.so'
|
excludes += ['lib/armeabi-v7a/*_neon.so']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
@ -77,12 +80,9 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId packageName
|
applicationId packageName
|
||||||
// minSdk constraints:
|
// minSdk constraints:
|
||||||
// - Flutter & other plugins: 16
|
// - Flutter & other plugins: 19 (cf `flutter.minSdkVersion`)
|
||||||
// - google_maps_flutter v2.1.1: 20
|
// - google_maps_flutter v2.1.1: 20
|
||||||
// - to build XML documents from XMP data, `metadata-extractor` and `PixyMeta` rely on `DocumentBuilder`,
|
minSdk flutter.minSdkVersion
|
||||||
// which implementation `DocumentBuilderImpl` is provided by the OS and is not customizable on Android,
|
|
||||||
// but the implementation on API <19 is not robust enough and fails to build XMP documents
|
|
||||||
minSdk 19
|
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
@ -215,7 +215,7 @@ dependencies {
|
||||||
implementation "androidx.appcompat:appcompat:1.6.1"
|
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||||
implementation 'androidx.core:core-ktx:1.12.0'
|
implementation 'androidx.core:core-ktx:1.12.0'
|
||||||
implementation 'androidx.exifinterface:exifinterface:1.3.7'
|
implementation 'androidx.exifinterface:exifinterface:1.3.7'
|
||||||
implementation 'androidx.lifecycle:lifecycle-process:2.6.2'
|
implementation 'androidx.lifecycle:lifecycle-process:2.7.0'
|
||||||
implementation 'androidx.media:media:1.7.0'
|
implementation 'androidx.media:media:1.7.0'
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
||||||
|
@ -227,7 +227,7 @@ dependencies {
|
||||||
implementation "com.github.bumptech.glide:glide:$glide_version"
|
implementation "com.github.bumptech.glide:glide:$glide_version"
|
||||||
implementation 'com.google.android.material:material:1.11.0'
|
implementation 'com.google.android.material:material:1.11.0'
|
||||||
// SLF4J implementation for `mp4parser`
|
// SLF4J implementation for `mp4parser`
|
||||||
implementation 'org.slf4j:slf4j-simple:2.0.9'
|
implementation 'org.slf4j:slf4j-simple:2.0.11'
|
||||||
|
|
||||||
// forked, built by JitPack:
|
// forked, built by JitPack:
|
||||||
// - https://jitpack.io/p/deckerst/Android-TiffBitmapFactory
|
// - https://jitpack.io/p/deckerst/Android-TiffBitmapFactory
|
||||||
|
@ -236,7 +236,7 @@ dependencies {
|
||||||
implementation 'com.github.deckerst:Android-TiffBitmapFactory:90c06eebf4'
|
implementation 'com.github.deckerst:Android-TiffBitmapFactory:90c06eebf4'
|
||||||
implementation 'com.github.deckerst.mp4parser:isoparser:4cc0c5d06c'
|
implementation 'com.github.deckerst.mp4parser:isoparser:4cc0c5d06c'
|
||||||
implementation 'com.github.deckerst.mp4parser:muxer:4cc0c5d06c'
|
implementation 'com.github.deckerst.mp4parser:muxer:4cc0c5d06c'
|
||||||
implementation 'com.github.deckerst:pixymeta-android:706bd73d6e'
|
implementation 'com.github.deckerst:pixymeta-android:9ec7097f17'
|
||||||
|
|
||||||
// huawei flavor only
|
// huawei flavor only
|
||||||
huaweiImplementation "com.huawei.agconnect:agconnect-core:$huawei_agconnect_version"
|
huaweiImplementation "com.huawei.agconnect:agconnect-core:$huawei_agconnect_version"
|
||||||
|
|
|
@ -12,6 +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 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
|
||||||
|
|
|
@ -109,7 +109,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"getAllMetadata" -> ioScope.launch { safe(call, result, ::getAllMetadata) }
|
"getAllMetadata" -> ioScope.launch { safe(call, result, ::getAllMetadata) }
|
||||||
"getCatalogMetadata" -> ioScope.launch { safe(call, result, ::getCatalogMetadata) }
|
"getCatalogMetadata" -> ioScope.launch { safe(call, result, ::getCatalogMetadata) }
|
||||||
"getOverlayMetadata" -> ioScope.launch { safe(call, result, ::getOverlayMetadata) }
|
"getFields" -> ioScope.launch { safe(call, result, ::getFields) }
|
||||||
"getGeoTiffInfo" -> ioScope.launch { safe(call, result, ::getGeoTiffInfo) }
|
"getGeoTiffInfo" -> ioScope.launch { safe(call, result, ::getGeoTiffInfo) }
|
||||||
"getMultiPageInfo" -> ioScope.launch { safe(call, result, ::getMultiPageInfo) }
|
"getMultiPageInfo" -> ioScope.launch { safe(call, result, ::getMultiPageInfo) }
|
||||||
"getPanoramaInfo" -> ioScope.launch { safe(call, result, ::getPanoramaInfo) }
|
"getPanoramaInfo" -> ioScope.launch { safe(call, result, ::getPanoramaInfo) }
|
||||||
|
@ -118,7 +118,6 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
"hasContentResolverProp" -> ioScope.launch { safe(call, result, ::hasContentProp) }
|
"hasContentResolverProp" -> ioScope.launch { safe(call, result, ::hasContentProp) }
|
||||||
"getContentResolverProp" -> ioScope.launch { safe(call, result, ::getContentPropValue) }
|
"getContentResolverProp" -> ioScope.launch { safe(call, result, ::getContentPropValue) }
|
||||||
"getDate" -> ioScope.launch { safe(call, result, ::getDate) }
|
"getDate" -> ioScope.launch { safe(call, result, ::getDate) }
|
||||||
"getDescription" -> ioScope.launch { safe(call, result, ::getDescription) }
|
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,17 +806,18 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getOverlayMetadata(call: MethodCall, result: MethodChannel.Result) {
|
private fun getFields(call: MethodCall, result: MethodChannel.Result) {
|
||||||
val mimeType = call.argument<String>("mimeType")
|
val mimeType = call.argument<String>("mimeType")
|
||||||
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
||||||
val sizeBytes = call.argument<Number>("sizeBytes")?.toLong()
|
val sizeBytes = call.argument<Number>("sizeBytes")?.toLong()
|
||||||
if (mimeType == null || uri == null) {
|
val fields = call.argument<List<String>>("fields")
|
||||||
|
if (mimeType == null || uri == null || fields == null) {
|
||||||
result.error("getOverlayMetadata-args", "missing arguments", null)
|
result.error("getOverlayMetadata-args", "missing arguments", null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val metadataMap = HashMap<String, Any>()
|
val metadataMap = HashMap<String, Any>()
|
||||||
if (isVideo(mimeType)) {
|
if (fields.isEmpty() || isVideo(mimeType)) {
|
||||||
result.success(metadataMap)
|
result.success(metadataMap)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -842,12 +842,23 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
val metadata = Helper.safeRead(input)
|
val metadata = Helper.safeRead(input)
|
||||||
for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) {
|
for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) {
|
||||||
foundExif = true
|
foundExif = true
|
||||||
|
if (fields.contains(KEY_APERTURE)) {
|
||||||
dir.getSafeRational(ExifDirectoryBase.TAG_FNUMBER) { metadataMap[KEY_APERTURE] = it.numerator.toDouble() / it.denominator }
|
dir.getSafeRational(ExifDirectoryBase.TAG_FNUMBER) { metadataMap[KEY_APERTURE] = it.numerator.toDouble() / it.denominator }
|
||||||
|
}
|
||||||
|
if (fields.contains(KEY_DESCRIPTION)) {
|
||||||
|
getDescriptionByMetadataExtractor(metadata)?.let { metadataMap[KEY_DESCRIPTION] = it }
|
||||||
|
}
|
||||||
|
if (fields.contains(KEY_EXPOSURE_TIME)) {
|
||||||
dir.getSafeRational(ExifDirectoryBase.TAG_EXPOSURE_TIME, saveExposureTime)
|
dir.getSafeRational(ExifDirectoryBase.TAG_EXPOSURE_TIME, saveExposureTime)
|
||||||
|
}
|
||||||
|
if (fields.contains(KEY_FOCAL_LENGTH)) {
|
||||||
dir.getSafeRational(ExifDirectoryBase.TAG_FOCAL_LENGTH) { metadataMap[KEY_FOCAL_LENGTH] = it.numerator.toDouble() / it.denominator }
|
dir.getSafeRational(ExifDirectoryBase.TAG_FOCAL_LENGTH) { metadataMap[KEY_FOCAL_LENGTH] = it.numerator.toDouble() / it.denominator }
|
||||||
|
}
|
||||||
|
if (fields.contains(KEY_ISO)) {
|
||||||
dir.getSafeInt(ExifDirectoryBase.TAG_ISO_EQUIVALENT) { metadataMap[KEY_ISO] = it }
|
dir.getSafeInt(ExifDirectoryBase.TAG_ISO_EQUIVALENT) { metadataMap[KEY_ISO] = it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||||
} catch (e: NoClassDefFoundError) {
|
} catch (e: NoClassDefFoundError) {
|
||||||
|
@ -862,11 +873,19 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val exif = ExifInterface(input)
|
val exif = ExifInterface(input)
|
||||||
|
if (fields.contains(KEY_APERTURE)) {
|
||||||
exif.getSafeDouble(ExifInterface.TAG_F_NUMBER) { metadataMap[KEY_APERTURE] = it }
|
exif.getSafeDouble(ExifInterface.TAG_F_NUMBER) { metadataMap[KEY_APERTURE] = it }
|
||||||
|
}
|
||||||
|
if (fields.contains(KEY_EXPOSURE_TIME)) {
|
||||||
exif.getSafeRational(ExifInterface.TAG_EXPOSURE_TIME, saveExposureTime)
|
exif.getSafeRational(ExifInterface.TAG_EXPOSURE_TIME, saveExposureTime)
|
||||||
|
}
|
||||||
|
if (fields.contains(KEY_FOCAL_LENGTH)) {
|
||||||
exif.getSafeDouble(ExifInterface.TAG_FOCAL_LENGTH) { metadataMap[KEY_FOCAL_LENGTH] = it }
|
exif.getSafeDouble(ExifInterface.TAG_FOCAL_LENGTH) { metadataMap[KEY_FOCAL_LENGTH] = it }
|
||||||
|
}
|
||||||
|
if (fields.contains(KEY_ISO)) {
|
||||||
exif.getSafeInt(ExifInterface.TAG_PHOTOGRAPHIC_SENSITIVITY) { metadataMap[KEY_ISO] = it }
|
exif.getSafeInt(ExifInterface.TAG_PHOTOGRAPHIC_SENSITIVITY) { metadataMap[KEY_ISO] = it }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// ExifInterface initialization can fail with a RuntimeException
|
// ExifInterface initialization can fail with a RuntimeException
|
||||||
// caused by an internal MediaMetadataRetriever failure
|
// caused by an internal MediaMetadataRetriever failure
|
||||||
|
@ -877,6 +896,47 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
result.success(metadataMap)
|
result.success(metadataMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return description from these fields (by precedence):
|
||||||
|
// - XMP / dc:description
|
||||||
|
// - IPTC / caption-abstract
|
||||||
|
// - Exif / UserComment
|
||||||
|
// - Exif / ImageDescription
|
||||||
|
private fun getDescriptionByMetadataExtractor(metadata: com.drew.metadata.Metadata): String? {
|
||||||
|
var description: String? = null
|
||||||
|
for (dir in metadata.getDirectoriesOfType(XmpDirectory::class.java)) {
|
||||||
|
val xmpMeta = dir.xmpMeta
|
||||||
|
try {
|
||||||
|
if (xmpMeta.doesPropExist(XMP.DC_DESCRIPTION_PROP_NAME)) {
|
||||||
|
xmpMeta.getSafeLocalizedText(XMP.DC_DESCRIPTION_PROP_NAME, acceptBlank = false) { description = it }
|
||||||
|
}
|
||||||
|
} catch (e: XMPException) {
|
||||||
|
Log.w(LOG_TAG, "failed to read XMP directory", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (description == null) {
|
||||||
|
for (dir in metadata.getDirectoriesOfType(IptcDirectory::class.java)) {
|
||||||
|
dir.getSafeString(IptcDirectory.TAG_CAPTION, acceptBlank = false) { description = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (description == null) {
|
||||||
|
for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) {
|
||||||
|
// user comment field specifies encoding, unlike other string fields
|
||||||
|
if (dir.containsTag(ExifSubIFDDirectory.TAG_USER_COMMENT)) {
|
||||||
|
val string = dir.getDescription(ExifSubIFDDirectory.TAG_USER_COMMENT)
|
||||||
|
if (string.isNotBlank()) {
|
||||||
|
description = string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (description == null) {
|
||||||
|
for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) {
|
||||||
|
dir.getSafeString(ExifIFD0Directory.TAG_IMAGE_DESCRIPTION, acceptBlank = false) { description = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return description
|
||||||
|
}
|
||||||
|
|
||||||
private fun getGeoTiffInfo(call: MethodCall, result: MethodChannel.Result) {
|
private fun getGeoTiffInfo(call: MethodCall, result: MethodChannel.Result) {
|
||||||
val mimeType = call.argument<String>("mimeType")
|
val mimeType = call.argument<String>("mimeType")
|
||||||
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
||||||
|
@ -1191,70 +1251,6 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
result.success(dateMillis)
|
result.success(dateMillis)
|
||||||
}
|
}
|
||||||
|
|
||||||
// return description from these fields (by precedence):
|
|
||||||
// - XMP / dc:description
|
|
||||||
// - IPTC / caption-abstract
|
|
||||||
// - Exif / UserComment
|
|
||||||
// - Exif / ImageDescription
|
|
||||||
private fun getDescription(call: MethodCall, result: MethodChannel.Result) {
|
|
||||||
val mimeType = call.argument<String>("mimeType")
|
|
||||||
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
|
||||||
val sizeBytes = call.argument<Number>("sizeBytes")?.toLong()
|
|
||||||
if (mimeType == null || uri == null) {
|
|
||||||
result.error("getDescription-args", "missing arguments", null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var description: String? = null
|
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
|
||||||
try {
|
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
|
||||||
val metadata = Helper.safeRead(input)
|
|
||||||
|
|
||||||
for (dir in metadata.getDirectoriesOfType(XmpDirectory::class.java)) {
|
|
||||||
val xmpMeta = dir.xmpMeta
|
|
||||||
try {
|
|
||||||
if (xmpMeta.doesPropExist(XMP.DC_DESCRIPTION_PROP_NAME)) {
|
|
||||||
xmpMeta.getSafeLocalizedText(XMP.DC_DESCRIPTION_PROP_NAME, acceptBlank = false) { description = it }
|
|
||||||
}
|
|
||||||
} catch (e: XMPException) {
|
|
||||||
Log.w(LOG_TAG, "failed to read XMP directory for uri=$uri", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (description == null) {
|
|
||||||
for (dir in metadata.getDirectoriesOfType(IptcDirectory::class.java)) {
|
|
||||||
dir.getSafeString(IptcDirectory.TAG_CAPTION, acceptBlank = false) { description = it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (description == null) {
|
|
||||||
for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) {
|
|
||||||
// user comment field specifies encoding, unlike other string fields
|
|
||||||
if (dir.containsTag(ExifSubIFDDirectory.TAG_USER_COMMENT)) {
|
|
||||||
val string = dir.getDescription(ExifSubIFDDirectory.TAG_USER_COMMENT)
|
|
||||||
if (string.isNotBlank()) {
|
|
||||||
description = string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (description == null) {
|
|
||||||
for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) {
|
|
||||||
dir.getSafeString(ExifIFD0Directory.TAG_IMAGE_DESCRIPTION, acceptBlank = false) { description = it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
|
||||||
} catch (e: NoClassDefFoundError) {
|
|
||||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
|
||||||
} catch (e: AssertionError) {
|
|
||||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.success(description)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val LOG_TAG = LogUtils.createTag<MetadataFetchHandler>()
|
private val LOG_TAG = LogUtils.createTag<MetadataFetchHandler>()
|
||||||
const val CHANNEL = "deckers.thibault/aves/metadata_fetch"
|
const val CHANNEL = "deckers.thibault/aves/metadata_fetch"
|
||||||
|
@ -1319,6 +1315,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
|
|
||||||
// overlay metadata
|
// overlay metadata
|
||||||
private const val KEY_APERTURE = "aperture"
|
private const val KEY_APERTURE = "aperture"
|
||||||
|
private const val KEY_DESCRIPTION = "description"
|
||||||
private const val KEY_EXPOSURE_TIME = "exposureTime"
|
private const val KEY_EXPOSURE_TIME = "exposureTime"
|
||||||
private const val KEY_FOCAL_LENGTH = "focalLength"
|
private const val KEY_FOCAL_LENGTH = "focalLength"
|
||||||
private const val KEY_ISO = "iso"
|
private const val KEY_ISO = "iso"
|
||||||
|
|
|
@ -18,6 +18,9 @@ import deckers.thibault.aves.utils.StorageUtils
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
// As of Android 14 (API 34), `BitmapRegionDecoder` documentation states
|
||||||
|
// that "only the JPEG, PNG, WebP and HEIF formats are supported"
|
||||||
|
// but in practice it successfully decodes some others.
|
||||||
class RegionFetcher internal constructor(
|
class RegionFetcher internal constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package deckers.thibault.aves.channel.calls.window
|
package deckers.thibault.aves.channel.calls.window
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import deckers.thibault.aves.utils.getDisplayCompat
|
import deckers.thibault.aves.utils.getDisplayCompat
|
||||||
|
@ -75,4 +76,21 @@ class ActivityWindowHandler(private val activity: Activity) : WindowHandler(acti
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun supportsHdr(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
result.success(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && activity.getDisplayCompat()?.isHdr ?: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setHdrColorMode(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
val on = call.argument<Boolean>("on")
|
||||||
|
if (on == null) {
|
||||||
|
result.error("setHdrColorMode-args", "missing arguments", null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
activity.window.colorMode = if (on) ActivityInfo.COLOR_MODE_HDR else ActivityInfo.COLOR_MODE_DEFAULT
|
||||||
|
}
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -28,4 +28,12 @@ class ServiceWindowHandler(service: Service) : WindowHandler(service) {
|
||||||
override fun getCutoutInsets(call: MethodCall, result: MethodChannel.Result) {
|
override fun getCutoutInsets(call: MethodCall, result: MethodChannel.Result) {
|
||||||
result.success(HashMap<String, Any>())
|
result.success(HashMap<String, Any>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun supportsHdr(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
result.success(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setHdrColorMode(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,8 @@ abstract class WindowHandler(private val contextWrapper: ContextWrapper) : Metho
|
||||||
"requestOrientation" -> Coresult.safe(call, result, ::requestOrientation)
|
"requestOrientation" -> Coresult.safe(call, result, ::requestOrientation)
|
||||||
"isCutoutAware" -> Coresult.safe(call, result, ::isCutoutAware)
|
"isCutoutAware" -> Coresult.safe(call, result, ::isCutoutAware)
|
||||||
"getCutoutInsets" -> Coresult.safe(call, result, ::getCutoutInsets)
|
"getCutoutInsets" -> Coresult.safe(call, result, ::getCutoutInsets)
|
||||||
|
"supportsHdr" -> Coresult.safe(call, result, ::supportsHdr)
|
||||||
|
"setHdrColorMode" -> Coresult.safe(call, result, ::setHdrColorMode)
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +46,10 @@ abstract class WindowHandler(private val contextWrapper: ContextWrapper) : Metho
|
||||||
|
|
||||||
abstract fun getCutoutInsets(call: MethodCall, result: MethodChannel.Result)
|
abstract fun getCutoutInsets(call: MethodCall, result: MethodChannel.Result)
|
||||||
|
|
||||||
|
abstract fun supportsHdr(call: MethodCall, result: MethodChannel.Result)
|
||||||
|
|
||||||
|
abstract fun setHdrColorMode(call: MethodCall, result: MethodChannel.Result)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val LOG_TAG = LogUtils.createTag<WindowHandler>()
|
private val LOG_TAG = LogUtils.createTag<WindowHandler>()
|
||||||
const val CHANNEL = "deckers.thibault/aves/window"
|
const val CHANNEL = "deckers.thibault/aves/window"
|
||||||
|
|
|
@ -48,7 +48,8 @@ internal class TiffFetcher(val model: TiffImage, val width: Int, val height: Int
|
||||||
val page = model.page ?: 0
|
val page = model.page ?: 0
|
||||||
|
|
||||||
var sampleSize = 1
|
var sampleSize = 1
|
||||||
if (width > 0 && height > 0) {
|
val customSize = width > 0 && height > 0
|
||||||
|
if (customSize) {
|
||||||
// determine sample size
|
// determine sample size
|
||||||
val fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
|
val fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
|
||||||
if (fd == null) {
|
if (fd == null) {
|
||||||
|
@ -63,7 +64,7 @@ internal class TiffFetcher(val model: TiffImage, val width: Int, val height: Int
|
||||||
val imageWidth = options.outWidth
|
val imageWidth = options.outWidth
|
||||||
val imageHeight = options.outHeight
|
val imageHeight = options.outHeight
|
||||||
if (imageHeight > height || imageWidth > width) {
|
if (imageHeight > height || imageWidth > width) {
|
||||||
while (imageHeight / (sampleSize * 2) > height && imageWidth / (sampleSize * 2) > width) {
|
while (imageHeight / (sampleSize * 2) >= height && imageWidth / (sampleSize * 2) >= width) {
|
||||||
sampleSize *= 2
|
sampleSize *= 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +85,18 @@ internal class TiffFetcher(val model: TiffImage, val width: Int, val height: Int
|
||||||
val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
|
val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
|
||||||
if (bitmap == null) {
|
if (bitmap == null) {
|
||||||
callback.onLoadFailed(Exception("Decoding full TIFF yielded null bitmap"))
|
callback.onLoadFailed(Exception("Decoding full TIFF yielded null bitmap"))
|
||||||
|
} else if (customSize) {
|
||||||
|
val dstWidth: Int
|
||||||
|
val dstHeight: Int
|
||||||
|
val aspectRatio = bitmap.width.toFloat() / bitmap.height
|
||||||
|
if (aspectRatio > 1) {
|
||||||
|
dstWidth = (height * aspectRatio).toInt()
|
||||||
|
dstHeight = height
|
||||||
|
} else {
|
||||||
|
dstWidth = width
|
||||||
|
dstHeight = (width / aspectRatio).toInt()
|
||||||
|
}
|
||||||
|
callback.onDataReady(Bitmap.createScaledBitmap(bitmap, dstWidth, dstHeight, true))
|
||||||
} else {
|
} else {
|
||||||
callback.onDataReady(bitmap)
|
callback.onDataReady(bitmap)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package deckers.thibault.aves.metadata
|
package deckers.thibault.aves.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
import deckers.thibault.aves.metadata.Metadata.TYPE_COMMENT
|
import deckers.thibault.aves.metadata.Metadata.TYPE_COMMENT
|
||||||
import deckers.thibault.aves.metadata.Metadata.TYPE_EXIF
|
import deckers.thibault.aves.metadata.Metadata.TYPE_EXIF
|
||||||
import deckers.thibault.aves.metadata.Metadata.TYPE_ICC_PROFILE
|
import deckers.thibault.aves.metadata.Metadata.TYPE_ICC_PROFILE
|
||||||
|
@ -10,6 +12,8 @@ import deckers.thibault.aves.metadata.Metadata.TYPE_JPEG_DUCKY
|
||||||
import deckers.thibault.aves.metadata.Metadata.TYPE_PHOTOSHOP_IRB
|
import deckers.thibault.aves.metadata.Metadata.TYPE_PHOTOSHOP_IRB
|
||||||
import deckers.thibault.aves.metadata.Metadata.TYPE_XMP
|
import deckers.thibault.aves.metadata.Metadata.TYPE_XMP
|
||||||
import deckers.thibault.aves.model.FieldMap
|
import deckers.thibault.aves.model.FieldMap
|
||||||
|
import deckers.thibault.aves.utils.MimeTypes
|
||||||
|
import deckers.thibault.aves.utils.StorageUtils
|
||||||
import pixy.meta.meta.Metadata
|
import pixy.meta.meta.Metadata
|
||||||
import pixy.meta.meta.MetadataEntry
|
import pixy.meta.meta.MetadataEntry
|
||||||
import pixy.meta.meta.MetadataType
|
import pixy.meta.meta.MetadataType
|
||||||
|
@ -19,6 +23,7 @@ import pixy.meta.meta.iptc.IPTCRecord
|
||||||
import pixy.meta.meta.jpeg.JPGMeta
|
import pixy.meta.meta.jpeg.JPGMeta
|
||||||
import pixy.meta.meta.xmp.XMP
|
import pixy.meta.meta.xmp.XMP
|
||||||
import pixy.meta.string.XMLUtils
|
import pixy.meta.string.XMLUtils
|
||||||
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -105,6 +110,48 @@ object PixyMetaHelper {
|
||||||
|
|
||||||
fun XMP.extendedXmpDocString(): String = XMLUtils.serializeToString(extendedXmpDocument)
|
fun XMP.extendedXmpDocString(): String = XMLUtils.serializeToString(extendedXmpDocument)
|
||||||
|
|
||||||
|
fun copyIptcXmp(
|
||||||
|
context: Context,
|
||||||
|
sourceMimeType: String,
|
||||||
|
sourceUri: Uri,
|
||||||
|
targetMimeType: String,
|
||||||
|
targetUri: Uri,
|
||||||
|
editableFile: File,
|
||||||
|
) {
|
||||||
|
var pixyIptc: IPTC? = null
|
||||||
|
var pixyXmp: XMP? = null
|
||||||
|
if (MimeTypes.canReadWithPixyMeta(sourceMimeType)) {
|
||||||
|
StorageUtils.openInputStream(context, sourceUri)?.use { input ->
|
||||||
|
val metadata = Metadata.readMetadata(input)
|
||||||
|
if (MimeTypes.canEditIptc(targetMimeType)) {
|
||||||
|
pixyIptc = metadata[MetadataType.IPTC] as IPTC?
|
||||||
|
}
|
||||||
|
if (MimeTypes.canEditXmp(targetMimeType)) {
|
||||||
|
pixyXmp = metadata[MetadataType.XMP] as XMP?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pixyIptc != null || pixyXmp != null) {
|
||||||
|
editableFile.outputStream().use { output ->
|
||||||
|
if (pixyIptc != null) {
|
||||||
|
// reopen input to read from start
|
||||||
|
StorageUtils.openInputStream(context, targetUri)?.use { input ->
|
||||||
|
val iptcs = pixyIptc!!.dataSets.flatMap { it.value }
|
||||||
|
Metadata.insertIPTC(input, output, iptcs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pixyXmp != null) {
|
||||||
|
// reopen input to read from start
|
||||||
|
StorageUtils.openInputStream(context, targetUri)?.use { input ->
|
||||||
|
val xmpString = pixyXmp!!.xmpDocString()
|
||||||
|
val extendedXmp = if (pixyXmp!!.hasExtendedXmp()) pixyXmp!!.extendedXmpDocString() else null
|
||||||
|
setXmp(input, output, xmpString, if (targetMimeType == MimeTypes.JPEG) extendedXmp else null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun removeMetadata(input: InputStream, output: OutputStream, metadataTypes: Set<String>) {
|
fun removeMetadata(input: InputStream, output: OutputStream, metadataTypes: Set<String>) {
|
||||||
val types = metadataTypes.map(::toMetadataType).toTypedArray()
|
val types = metadataTypes.map(::toMetadataType).toTypedArray()
|
||||||
Metadata.removeMetadata(input, output, *types)
|
Metadata.removeMetadata(input, output, *types)
|
||||||
|
|
|
@ -18,6 +18,12 @@ class AvesEntry(map: FieldMap) {
|
||||||
val isRotated: Boolean
|
val isRotated: Boolean
|
||||||
get() = rotationDegrees % 180 == 90
|
get() = rotationDegrees % 180 == 90
|
||||||
|
|
||||||
|
val displayWidth: Int
|
||||||
|
get() = if (isRotated) height else width
|
||||||
|
|
||||||
|
val displayHeight: Int
|
||||||
|
get() = if (isRotated) width else height
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// convenience method
|
// convenience method
|
||||||
private fun toLong(o: Any?): Long? = when (o) {
|
private fun toLong(o: Any?): Long? = when (o) {
|
||||||
|
|
|
@ -53,15 +53,12 @@ import deckers.thibault.aves.utils.MimeTypes.canEditExif
|
||||||
import deckers.thibault.aves.utils.MimeTypes.canEditIptc
|
import deckers.thibault.aves.utils.MimeTypes.canEditIptc
|
||||||
import deckers.thibault.aves.utils.MimeTypes.canEditXmp
|
import deckers.thibault.aves.utils.MimeTypes.canEditXmp
|
||||||
import deckers.thibault.aves.utils.MimeTypes.canReadWithExifInterface
|
import deckers.thibault.aves.utils.MimeTypes.canReadWithExifInterface
|
||||||
import deckers.thibault.aves.utils.MimeTypes.canReadWithPixyMeta
|
|
||||||
import deckers.thibault.aves.utils.MimeTypes.canRemoveMetadata
|
import deckers.thibault.aves.utils.MimeTypes.canRemoveMetadata
|
||||||
import deckers.thibault.aves.utils.MimeTypes.extensionFor
|
import deckers.thibault.aves.utils.MimeTypes.extensionFor
|
||||||
import deckers.thibault.aves.utils.MimeTypes.isVideo
|
import deckers.thibault.aves.utils.MimeTypes.isVideo
|
||||||
import deckers.thibault.aves.utils.StorageUtils
|
import deckers.thibault.aves.utils.StorageUtils
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import pixy.meta.meta.Metadata
|
|
||||||
import pixy.meta.meta.MetadataType
|
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
@ -301,11 +298,18 @@ abstract class ImageProvider {
|
||||||
sourceDocFile.copyTo(output)
|
sourceDocFile.copyTo(output)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var targetWidthPx: Int = if (sourceEntry.isRotated) height else width
|
val targetWidthPx: Int
|
||||||
var targetHeightPx: Int = if (sourceEntry.isRotated) width else height
|
val targetHeightPx: Int
|
||||||
if (lengthUnit == LENGTH_UNIT_PERCENT) {
|
when (lengthUnit) {
|
||||||
targetWidthPx = sourceEntry.width * targetWidthPx / 100
|
LENGTH_UNIT_PERCENT -> {
|
||||||
targetHeightPx = sourceEntry.height * targetHeightPx / 100
|
targetWidthPx = sourceEntry.displayWidth * width / 100
|
||||||
|
targetHeightPx = sourceEntry.displayHeight * height / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
targetWidthPx = width
|
||||||
|
targetHeightPx = height
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val model: Any = if (pageId != null && MultiPageImage.isSupported(sourceMimeType)) {
|
val model: Any = if (pageId != null && MultiPageImage.isSupported(sourceMimeType)) {
|
||||||
|
@ -405,39 +409,7 @@ abstract class ImageProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy IPTC / XMP via PixyMeta
|
// copy IPTC / XMP via PixyMeta
|
||||||
|
PixyMetaHelper.copyIptcXmp(context, sourceMimeType, sourceUri, targetMimeType, targetUri, editableFile)
|
||||||
var pixyIptc: pixy.meta.meta.iptc.IPTC? = null
|
|
||||||
var pixyXmp: pixy.meta.meta.xmp.XMP? = null
|
|
||||||
if (canReadWithPixyMeta(sourceMimeType)) {
|
|
||||||
StorageUtils.openInputStream(context, sourceUri)?.use { input ->
|
|
||||||
val metadata = Metadata.readMetadata(input)
|
|
||||||
if (canEditIptc(targetMimeType)) {
|
|
||||||
pixyIptc = metadata[MetadataType.IPTC] as pixy.meta.meta.iptc.IPTC?
|
|
||||||
}
|
|
||||||
if (canEditXmp(targetMimeType)) {
|
|
||||||
pixyXmp = metadata[MetadataType.XMP] as pixy.meta.meta.xmp.XMP?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pixyIptc != null || pixyXmp != null) {
|
|
||||||
editableFile.outputStream().use { output ->
|
|
||||||
if (pixyIptc != null) {
|
|
||||||
// reopen input to read from start
|
|
||||||
StorageUtils.openInputStream(context, targetUri)?.use { input ->
|
|
||||||
val iptcs = pixyIptc!!.dataSets.flatMap { it.value }
|
|
||||||
Metadata.insertIPTC(input, output, iptcs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pixyXmp != null) {
|
|
||||||
// reopen input to read from start
|
|
||||||
StorageUtils.openInputStream(context, targetUri)?.use { input ->
|
|
||||||
val xmpString = pixyXmp!!.xmpDocString()
|
|
||||||
val extendedXmp = if (pixyXmp!!.hasExtendedXmp()) pixyXmp!!.extendedXmpDocString() else null
|
|
||||||
PixyMetaHelper.setXmp(input, output, xmpString, if (targetMimeType == MimeTypes.JPEG) extendedXmp else null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy Exif via ExifInterface
|
// copy Exif via ExifInterface
|
||||||
|
|
||||||
|
|
5
android/app/src/main/res/values-sat/strings.xml
Normal file
5
android/app/src/main/res/values-sat/strings.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">ᱮᱣᱥ</string>
|
||||||
|
<string name="app_widget_label">ᱪᱤᱛᱟᱹᱨ ᱯᱷᱨᱮᱢ</string>
|
||||||
|
</resources>
|
12
android/app/src/main/res/values-sv/strings.xml
Normal file
12
android/app/src/main/res/values-sv/strings.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="app_widget_label">Foto Ram</string>
|
||||||
|
<string name="wallpaper">Bakgrund</string>
|
||||||
|
<string name="safe_mode_shortcut_short_label">Felsäkert läge</string>
|
||||||
|
<string name="videos_shortcut_short_label">Videor</string>
|
||||||
|
<string name="analysis_channel_name">Media scanning</string>
|
||||||
|
<string name="analysis_notification_default_title">Scannar media</string>
|
||||||
|
<string name="analysis_notification_action_stop">Stop</string>
|
||||||
|
<string name="search_shortcut_short_label">Sök</string>
|
||||||
|
</resources>
|
|
@ -2,7 +2,7 @@ buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlin_version = '1.9.21'
|
kotlin_version = '1.9.21'
|
||||||
ksp_version = "$kotlin_version-1.0.15"
|
ksp_version = "$kotlin_version-1.0.15"
|
||||||
agp_version = '8.1.4'
|
agp_version = '8.2.2'
|
||||||
glide_version = '4.16.0'
|
glide_version = '4.16.0'
|
||||||
// AppGallery Connect plugin versions: https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-sdk-changenotes-0000001058732550
|
// AppGallery Connect plugin versions: https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-sdk-changenotes-0000001058732550
|
||||||
huawei_agconnect_version = '1.9.1.300'
|
huawei_agconnect_version = '1.9.1.300'
|
||||||
|
|
4
fastlane/metadata/android/en-US/changelogs/112.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/112.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
In v1.10.3:
|
||||||
|
- customize your home page
|
||||||
|
- analyze your images with the histogram (for real this time)
|
||||||
|
Full changelog available on GitHub
|
4
fastlane/metadata/android/en-US/changelogs/11201.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/11201.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
In v1.10.3:
|
||||||
|
- customize your home page
|
||||||
|
- analyze your images with the histogram (for real this time)
|
||||||
|
Full changelog available on GitHub
|
|
@ -1,5 +1,5 @@
|
||||||
<i>Aves</i> can handle all sorts of images and videos, including your typical JPEGs and MP4s, but also more exotic things like <b>multi-page TIFFs, SVGs, old AVIs and more</b>! It scans your media collection to identify <b>motion photos</b>, <b>panoramas</b> (aka photo spheres), <b>360° videos</b>, as well as <b>GeoTIFF</b> files.
|
<i>Aves</i> getur meðhöndlað allar algengar gerðir mynda og myndskeiða, þar með talið JPEG og MP4, en einnig sjaldgæfari skrár á borð við <b>marg-síðna TIFF-myndir, SVG-línuteikningar, eldri gerðir AVI-skráa og margt fleira</b>! Forritið skannar safnið þitt til að greina <b>hreyfiljósmyndir</b>, <b>víðmyndir</b> (t.d. myndahnetti), <b>360° myndskeið</b>, auk <b>GeoTIFF-skráa</b>.
|
||||||
|
|
||||||
<b>Navigation and search</b> is an important part of <i>Aves</i>. The goal is for users to easily flow from albums to photos to tags to maps, etc.
|
<b>Flakk og leit</b> eru mikilvægir hlutar <i>Aves</i>. Markmiðið er að notendur eigi auðvelt með að flæða úr albúmum yfir í ljósmyndir yfir í merki eða landakort, o.s.frv.
|
||||||
|
|
||||||
<i>Aves</i> integrates with Android (from KitKat to Android 14, including Android TV) with features such as <b>widgets</b>, <b>app shortcuts</b>, <b>screen saver</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.
|
<i>Aves</i> samtvinnast við Android (frá KitKat til Android 14, að meðtöldu Android TV) með eiginleikum á borð við <b>viðmótshluta</b>, <b>flýtileiðir í forrit</b>, <b>skjáhvílu</b> og <b>víðværa leit</b>. Það virkar einnig sem <b>margmiðlunarskoðari og veljari</b>.
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
@ -1 +1 @@
|
||||||
Gallery and metadata explorer
|
Myndasafn og skoðun lýsigagna
|
5
fastlane/metadata/android/sat/full_description.txt
Normal file
5
fastlane/metadata/android/sat/full_description.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<i>Aves</i> can handle all sorts of images and videos, including your typical JPEGs and MP4s, but also more exotic things like <b>multi-page TIFFs, SVGs, old AVIs and more</b>! It scans your media collection to identify <b>motion photos</b>, <b>panoramas</b> (aka photo spheres), <b>360° videos</b>, as well as <b>GeoTIFF</b> files.
|
||||||
|
|
||||||
|
<b>Navigation and search</b> is an important part of <i>Aves</i>. The goal is for users to easily flow from albums to photos to tags to maps, etc.
|
||||||
|
|
||||||
|
<i>Aves</i> integrates with Android (from KitKat to Android 14, including Android TV) with features such as <b>widgets</b>, <b>app shortcuts</b>, <b>screen saver</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.
|
1
fastlane/metadata/android/sat/short_description.txt
Normal file
1
fastlane/metadata/android/sat/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Gallery and metadata explorer
|
5
fastlane/metadata/android/sv/full_description.txt
Normal file
5
fastlane/metadata/android/sv/full_description.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<i>Aves</i> kan hantera alla typer av bilder och videor, inklusive vanliga JPEG- och MP4-filer, men även mer exotiska filer som <b>flersidiga TIFF-filer, SVG-filer, gamla AVI-filer och mycket mer</b>! Den skannar din mediasamling för att identifiera <b>rörelsefoton</b>, <b>panoramor</b> (även kallade fotosfärer), <b>360° videor</b>, samnt <b>GeoTIFF</b> filer.
|
||||||
|
|
||||||
|
<b>Navigering och sökhantering</b> är än viktigt del av <i>Aves</i>. Målet är att användarna på ett smidigt sätt ska kunna gå från album till foton till taggar till kartor, osv.
|
||||||
|
|
||||||
|
<i>Aves</i> integrerar med Android (från KitKat till Android 14, inklusive Android TV) med funktioner som <b>widgetar</b>, <b>appgenvägar</b>, <b>skärmsläckare</b> och <b>global sökhantering.</b> Den fungerar också som en <b>mediavisare och mediaväljare</b>.
|
1
fastlane/metadata/android/sv/short_description.txt
Normal file
1
fastlane/metadata/android/sv/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Galleri och metadatautforskare
|
|
@ -1,5 +1,9 @@
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
||||||
|
extension ExtraMetadataSyntheticFieldConvert on MetadataSyntheticField {
|
||||||
|
String? get toPlatform => name;
|
||||||
|
}
|
||||||
|
|
||||||
extension ExtraMetadataFieldConvert on MetadataField {
|
extension ExtraMetadataFieldConvert on MetadataField {
|
||||||
MetadataType get type {
|
MetadataType get type {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves_report/aves_report.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
@ -46,14 +47,14 @@ class ThumbnailProvider extends ImageProvider<ThumbnailProviderKey> {
|
||||||
taskKey: key,
|
taskKey: key,
|
||||||
);
|
);
|
||||||
if (bytes.isEmpty) {
|
if (bytes.isEmpty) {
|
||||||
throw StateError('$uri ($mimeType) loading failed');
|
throw UnreportedStateError('$uri ($mimeType) loading failed');
|
||||||
}
|
}
|
||||||
final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
|
final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
|
||||||
return await decode(buffer);
|
return await decode(buffer);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// loading may fail if the provided MIME type is incorrect (e.g. the Media Store may report a JPEG as a TIFF)
|
// loading may fail if the provided MIME type is incorrect (e.g. the Media Store may report a JPEG as a TIFF)
|
||||||
debugPrint('$runtimeType _loadAsync failed with mimeType=$mimeType, uri=$uri, error=$error');
|
debugPrint('$runtimeType _loadAsync failed with mimeType=$mimeType, uri=$uri, error=$error');
|
||||||
throw StateError('$mimeType decoding failed (page $pageId)');
|
throw UnreportedStateError('$mimeType decoding failed (page $pageId)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves_report/aves_report.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
@ -64,14 +65,14 @@ class UriImage extends ImageProvider<UriImage> with EquatableMixin {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (bytes.isEmpty) {
|
if (bytes.isEmpty) {
|
||||||
throw StateError('$uri ($mimeType) loading failed');
|
throw UnreportedStateError('$uri ($mimeType) loading failed');
|
||||||
}
|
}
|
||||||
final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
|
final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
|
||||||
return await decode(buffer);
|
return await decode(buffer);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// loading may fail if the provided MIME type is incorrect (e.g. the Media Store may report a JPEG as a TIFF)
|
// loading may fail if the provided MIME type is incorrect (e.g. the Media Store may report a JPEG as a TIFF)
|
||||||
debugPrint('$runtimeType _loadAsync failed with mimeType=$mimeType, uri=$uri, error=$error');
|
debugPrint('$runtimeType _loadAsync failed with mimeType=$mimeType, uri=$uri, error=$error');
|
||||||
throw StateError('$mimeType decoding failed (page $pageId)');
|
throw UnreportedStateError('$mimeType decoding failed (page $pageId)');
|
||||||
} finally {
|
} finally {
|
||||||
unawaited(chunkEvents.close());
|
unawaited(chunkEvents.close());
|
||||||
}
|
}
|
||||||
|
|
|
@ -479,7 +479,7 @@
|
||||||
"@statsTopCountriesSectionTitle": {},
|
"@statsTopCountriesSectionTitle": {},
|
||||||
"settingsActionImport": "إستيراد",
|
"settingsActionImport": "إستيراد",
|
||||||
"@settingsActionImport": {},
|
"@settingsActionImport": {},
|
||||||
"viewerInfoLabelSize": "المقاس",
|
"viewerInfoLabelSize": "الحجم",
|
||||||
"@viewerInfoLabelSize": {},
|
"@viewerInfoLabelSize": {},
|
||||||
"locationPickerUseThisLocationButton": "استخدم هذا الموقع",
|
"locationPickerUseThisLocationButton": "استخدم هذا الموقع",
|
||||||
"@locationPickerUseThisLocationButton": {},
|
"@locationPickerUseThisLocationButton": {},
|
||||||
|
@ -1518,5 +1518,11 @@
|
||||||
"filterNoDateLabel": "غير مؤرخ",
|
"filterNoDateLabel": "غير مؤرخ",
|
||||||
"@filterNoDateLabel": {},
|
"@filterNoDateLabel": {},
|
||||||
"exportEntryDialogWriteMetadata": "كتابة البيانات الوصفية",
|
"exportEntryDialogWriteMetadata": "كتابة البيانات الوصفية",
|
||||||
"@exportEntryDialogWriteMetadata": {}
|
"@exportEntryDialogWriteMetadata": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "إظهار أيقونة HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"collectionActionSetHome": "تعيين كخلفية",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "مجموعة مخصصة",
|
||||||
|
"@setHomeCustomCollection": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -649,7 +649,7 @@
|
||||||
"@viewerTransitionSlide": {},
|
"@viewerTransitionSlide": {},
|
||||||
"overlayHistogramRGB": "RGB",
|
"overlayHistogramRGB": "RGB",
|
||||||
"@overlayHistogramRGB": {},
|
"@overlayHistogramRGB": {},
|
||||||
"overlayHistogramNone": "Няма",
|
"overlayHistogramNone": "Не",
|
||||||
"@overlayHistogramNone": {},
|
"@overlayHistogramNone": {},
|
||||||
"overlayHistogramLuminance": "Яркасць",
|
"overlayHistogramLuminance": "Яркасць",
|
||||||
"@overlayHistogramLuminance": {},
|
"@overlayHistogramLuminance": {},
|
||||||
|
@ -931,7 +931,7 @@
|
||||||
"@collectionGroupNone": {},
|
"@collectionGroupNone": {},
|
||||||
"searchRatingSectionTitle": "Рэйтынгі",
|
"searchRatingSectionTitle": "Рэйтынгі",
|
||||||
"@searchRatingSectionTitle": {},
|
"@searchRatingSectionTitle": {},
|
||||||
"settingsDisabled": "Адключана",
|
"settingsDisabled": "Адкл.",
|
||||||
"@settingsDisabled": {},
|
"@settingsDisabled": {},
|
||||||
"settingsActionImportDialogTitle": "Імпарт",
|
"settingsActionImportDialogTitle": "Імпарт",
|
||||||
"@settingsActionImportDialogTitle": {},
|
"@settingsActionImportDialogTitle": {},
|
||||||
|
@ -1518,5 +1518,11 @@
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"minutes": {}
|
"minutes": {}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"collectionActionSetHome": "Усталяваць як галоўную",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "Уласная калекцыя",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Паказаць значок HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -570,6 +570,7 @@
|
||||||
"collectionActionShowTitleSearch": "Show title filter",
|
"collectionActionShowTitleSearch": "Show title filter",
|
||||||
"collectionActionHideTitleSearch": "Hide title filter",
|
"collectionActionHideTitleSearch": "Hide title filter",
|
||||||
"collectionActionAddShortcut": "Add shortcut",
|
"collectionActionAddShortcut": "Add shortcut",
|
||||||
|
"collectionActionSetHome": "Set as home",
|
||||||
"collectionActionEmptyBin": "Empty bin",
|
"collectionActionEmptyBin": "Empty bin",
|
||||||
"collectionActionCopy": "Copy to album",
|
"collectionActionCopy": "Copy to album",
|
||||||
"collectionActionMove": "Move to album",
|
"collectionActionMove": "Move to album",
|
||||||
|
@ -757,6 +758,7 @@
|
||||||
"settingsNavigationSectionTitle": "Navigation",
|
"settingsNavigationSectionTitle": "Navigation",
|
||||||
"settingsHomeTile": "Home",
|
"settingsHomeTile": "Home",
|
||||||
"settingsHomeDialogTitle": "Home",
|
"settingsHomeDialogTitle": "Home",
|
||||||
|
"setHomeCustomCollection": "Custom collection",
|
||||||
"settingsShowBottomNavigationBar": "Show bottom navigation bar",
|
"settingsShowBottomNavigationBar": "Show bottom navigation bar",
|
||||||
"settingsKeepScreenOnTile": "Keep screen on",
|
"settingsKeepScreenOnTile": "Keep screen on",
|
||||||
"settingsKeepScreenOnDialogTitle": "Keep Screen On",
|
"settingsKeepScreenOnDialogTitle": "Keep Screen On",
|
||||||
|
@ -781,6 +783,7 @@
|
||||||
"settingsThumbnailSectionTitle": "Thumbnails",
|
"settingsThumbnailSectionTitle": "Thumbnails",
|
||||||
"settingsThumbnailOverlayTile": "Overlay",
|
"settingsThumbnailOverlayTile": "Overlay",
|
||||||
"settingsThumbnailOverlayPageTitle": "Overlay",
|
"settingsThumbnailOverlayPageTitle": "Overlay",
|
||||||
|
"settingsThumbnailShowHdrIcon": "Show HDR icon",
|
||||||
"settingsThumbnailShowFavouriteIcon": "Show favorite icon",
|
"settingsThumbnailShowFavouriteIcon": "Show favorite icon",
|
||||||
"settingsThumbnailShowTagIcon": "Show tag icon",
|
"settingsThumbnailShowTagIcon": "Show tag icon",
|
||||||
"settingsThumbnailShowLocationIcon": "Show location icon",
|
"settingsThumbnailShowLocationIcon": "Show location icon",
|
||||||
|
|
|
@ -1360,5 +1360,11 @@
|
||||||
"entryActionCast": "Echar",
|
"entryActionCast": "Echar",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "Dispositivos Cast",
|
"castDialogTitle": "Dispositivos Cast",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Mostrar el icono del HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"collectionActionSetHome": "Fijar como inicio",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "Colección personalizada",
|
||||||
|
"@setHomeCustomCollection": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -959,15 +959,15 @@
|
||||||
"@settingsNavigationDrawerAddAlbum": {},
|
"@settingsNavigationDrawerAddAlbum": {},
|
||||||
"settingsThumbnailSectionTitle": "Miniaturak",
|
"settingsThumbnailSectionTitle": "Miniaturak",
|
||||||
"@settingsThumbnailSectionTitle": {},
|
"@settingsThumbnailSectionTitle": {},
|
||||||
"settingsThumbnailShowFavouriteIcon": "Gogokoen ikonoa erakutsi",
|
"settingsThumbnailShowFavouriteIcon": "Erakutsi gogokoen ikonoa",
|
||||||
"@settingsThumbnailShowFavouriteIcon": {},
|
"@settingsThumbnailShowFavouriteIcon": {},
|
||||||
"settingsThumbnailShowTagIcon": "Etiketaren ikonoa erakutsi",
|
"settingsThumbnailShowTagIcon": "Erakutsi etiketaren ikonoa",
|
||||||
"@settingsThumbnailShowTagIcon": {},
|
"@settingsThumbnailShowTagIcon": {},
|
||||||
"settingsThumbnailShowMotionPhotoIcon": "Mugimendu-argazkiaren ikonoa erakutsi",
|
"settingsThumbnailShowMotionPhotoIcon": "Erakutsi mugimendu-argazkiaren ikonoa",
|
||||||
"@settingsThumbnailShowMotionPhotoIcon": {},
|
"@settingsThumbnailShowMotionPhotoIcon": {},
|
||||||
"settingsThumbnailShowRawIcon": "Raw ikonoa erakutsi",
|
"settingsThumbnailShowRawIcon": "Erakutsi raw ikonoa",
|
||||||
"@settingsThumbnailShowRawIcon": {},
|
"@settingsThumbnailShowRawIcon": {},
|
||||||
"settingsThumbnailShowVideoDuration": "Bideoaren iraupena erakutsi",
|
"settingsThumbnailShowVideoDuration": "Erakutsi bideoaren iraupena",
|
||||||
"@settingsThumbnailShowVideoDuration": {},
|
"@settingsThumbnailShowVideoDuration": {},
|
||||||
"settingsCollectionQuickActionEditorPageTitle": "Ekintza azkarrak",
|
"settingsCollectionQuickActionEditorPageTitle": "Ekintza azkarrak",
|
||||||
"@settingsCollectionQuickActionEditorPageTitle": {},
|
"@settingsCollectionQuickActionEditorPageTitle": {},
|
||||||
|
@ -975,13 +975,13 @@
|
||||||
"@settingsCollectionQuickActionTabBrowsing": {},
|
"@settingsCollectionQuickActionTabBrowsing": {},
|
||||||
"settingsThumbnailOverlayPageTitle": "Inkrustazioak",
|
"settingsThumbnailOverlayPageTitle": "Inkrustazioak",
|
||||||
"@settingsThumbnailOverlayPageTitle": {},
|
"@settingsThumbnailOverlayPageTitle": {},
|
||||||
"settingsThumbnailShowLocationIcon": "Kokapenaren ikonoa erakutsi",
|
"settingsThumbnailShowLocationIcon": "Erakutsi kokalekuaren ikonoa",
|
||||||
"@settingsThumbnailShowLocationIcon": {},
|
"@settingsThumbnailShowLocationIcon": {},
|
||||||
"settingsThumbnailShowRating": "Balorazioa erakutsi",
|
"settingsThumbnailShowRating": "Erakutsi balorazioa",
|
||||||
"@settingsThumbnailShowRating": {},
|
"@settingsThumbnailShowRating": {},
|
||||||
"settingsCollectionQuickActionsTile": "Ekintza azkarrak",
|
"settingsCollectionQuickActionsTile": "Ekintza azkarrak",
|
||||||
"@settingsCollectionQuickActionsTile": {},
|
"@settingsCollectionQuickActionsTile": {},
|
||||||
"settingsCollectionQuickActionTabSelecting": "Aukeraketa",
|
"settingsCollectionQuickActionTabSelecting": "Hautapena",
|
||||||
"@settingsCollectionQuickActionTabSelecting": {},
|
"@settingsCollectionQuickActionTabSelecting": {},
|
||||||
"searchMetadataSectionTitle": "Metadatuak",
|
"searchMetadataSectionTitle": "Metadatuak",
|
||||||
"@searchMetadataSectionTitle": {},
|
"@searchMetadataSectionTitle": {},
|
||||||
|
@ -1025,7 +1025,7 @@
|
||||||
"@settingsViewerSectionTitle": {},
|
"@settingsViewerSectionTitle": {},
|
||||||
"settingsViewerGestureSideTapNext": "Pantailaren ertzetan sakatu aurreko/hurrengo elementua bistaratzeko",
|
"settingsViewerGestureSideTapNext": "Pantailaren ertzetan sakatu aurreko/hurrengo elementua bistaratzeko",
|
||||||
"@settingsViewerGestureSideTapNext": {},
|
"@settingsViewerGestureSideTapNext": {},
|
||||||
"settingsViewerUseCutout": "Moztutako eremua erabili",
|
"settingsViewerUseCutout": "Erabili moztutako eremua",
|
||||||
"@settingsViewerUseCutout": {},
|
"@settingsViewerUseCutout": {},
|
||||||
"settingsImageBackground": "Atzeko irudia",
|
"settingsImageBackground": "Atzeko irudia",
|
||||||
"@settingsImageBackground": {},
|
"@settingsImageBackground": {},
|
||||||
|
@ -1043,15 +1043,15 @@
|
||||||
"@settingsViewerQuickActionEmpty": {},
|
"@settingsViewerQuickActionEmpty": {},
|
||||||
"settingsViewerOverlayPageTitle": "Inkrustazioak",
|
"settingsViewerOverlayPageTitle": "Inkrustazioak",
|
||||||
"@settingsViewerOverlayPageTitle": {},
|
"@settingsViewerOverlayPageTitle": {},
|
||||||
"settingsViewerShowMinimap": "Bistaratu minimapa",
|
"settingsViewerShowMinimap": "Erakutsi minimapa",
|
||||||
"@settingsViewerShowMinimap": {},
|
"@settingsViewerShowMinimap": {},
|
||||||
"settingsViewerShowInformation": "Bistaratu informazioa",
|
"settingsViewerShowInformation": "Erakutsi informazioa",
|
||||||
"@settingsViewerShowInformation": {},
|
"@settingsViewerShowInformation": {},
|
||||||
"settingsViewerShowInformationSubtitle": "Bistaratu izenburua, data, kokapena, etab.",
|
"settingsViewerShowInformationSubtitle": "Erakutsi izenburua, data, kokalekua, etab.",
|
||||||
"@settingsViewerShowInformationSubtitle": {},
|
"@settingsViewerShowInformationSubtitle": {},
|
||||||
"settingsViewerShowDescription": "Bistaratu deskribapena",
|
"settingsViewerShowDescription": "Erakutsi azalpena",
|
||||||
"@settingsViewerShowDescription": {},
|
"@settingsViewerShowDescription": {},
|
||||||
"settingsViewerShowOverlayThumbnails": "Bistaratu miniaturak",
|
"settingsViewerShowOverlayThumbnails": "Erakutsi miniaturak",
|
||||||
"@settingsViewerShowOverlayThumbnails": {},
|
"@settingsViewerShowOverlayThumbnails": {},
|
||||||
"settingsSlideshowTransitionTile": "Trantsizioa",
|
"settingsSlideshowTransitionTile": "Trantsizioa",
|
||||||
"@settingsSlideshowTransitionTile": {},
|
"@settingsSlideshowTransitionTile": {},
|
||||||
|
@ -1141,13 +1141,13 @@
|
||||||
"@settingsMotionPhotoAutoPlay": {},
|
"@settingsMotionPhotoAutoPlay": {},
|
||||||
"settingsViewerOverlayTile": "Inkrustazioak",
|
"settingsViewerOverlayTile": "Inkrustazioak",
|
||||||
"@settingsViewerOverlayTile": {},
|
"@settingsViewerOverlayTile": {},
|
||||||
"settingsViewerShowOverlayOnOpening": "Bistaratu hasieran",
|
"settingsViewerShowOverlayOnOpening": "Erakutsi irekitzean",
|
||||||
"@settingsViewerShowOverlayOnOpening": {},
|
"@settingsViewerShowOverlayOnOpening": {},
|
||||||
"settingsViewerShowRatingTags": "Bistaratu balorazioa eta etiketak",
|
"settingsViewerShowRatingTags": "Erakutsi balorazioa eta etiketak",
|
||||||
"@settingsViewerShowRatingTags": {},
|
"@settingsViewerShowRatingTags": {},
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Lausotze efektua",
|
"settingsViewerEnableOverlayBlurEffect": "Lausotze efektua",
|
||||||
"@settingsViewerEnableOverlayBlurEffect": {},
|
"@settingsViewerEnableOverlayBlurEffect": {},
|
||||||
"settingsViewerShowShootingDetails": "Bistaratu hartualdiaren xehetasunak",
|
"settingsViewerShowShootingDetails": "Erakutsi hartualdiaren xehetasunak",
|
||||||
"@settingsViewerShowShootingDetails": {},
|
"@settingsViewerShowShootingDetails": {},
|
||||||
"settingsViewerSlideshowPageTitle": "Aurkezpena",
|
"settingsViewerSlideshowPageTitle": "Aurkezpena",
|
||||||
"@settingsViewerSlideshowPageTitle": {},
|
"@settingsViewerSlideshowPageTitle": {},
|
||||||
|
@ -1155,7 +1155,7 @@
|
||||||
"@settingsViewerSlideshowTile": {},
|
"@settingsViewerSlideshowTile": {},
|
||||||
"settingsSlideshowShuffle": "Nahastu",
|
"settingsSlideshowShuffle": "Nahastu",
|
||||||
"@settingsSlideshowShuffle": {},
|
"@settingsSlideshowShuffle": {},
|
||||||
"settingsSlideshowFillScreen": "Pantaila bete",
|
"settingsSlideshowFillScreen": "Bete pantaila",
|
||||||
"@settingsSlideshowFillScreen": {},
|
"@settingsSlideshowFillScreen": {},
|
||||||
"settingsSlideshowRepeat": "Errepikatu",
|
"settingsSlideshowRepeat": "Errepikatu",
|
||||||
"@settingsSlideshowRepeat": {},
|
"@settingsSlideshowRepeat": {},
|
||||||
|
@ -1165,11 +1165,11 @@
|
||||||
"@settingsSlideshowVideoPlaybackTile": {},
|
"@settingsSlideshowVideoPlaybackTile": {},
|
||||||
"settingsSubtitleThemeTextPositionTile": "Testuaren posizioa",
|
"settingsSubtitleThemeTextPositionTile": "Testuaren posizioa",
|
||||||
"@settingsSubtitleThemeTextPositionTile": {},
|
"@settingsSubtitleThemeTextPositionTile": {},
|
||||||
"settingsVideoShowVideos": "Bideoak erakutsi",
|
"settingsVideoShowVideos": "Erakutsi bideoak",
|
||||||
"@settingsVideoShowVideos": {},
|
"@settingsVideoShowVideos": {},
|
||||||
"settingsVideoPageTitle": "Bideoen ezarpenak",
|
"settingsVideoPageTitle": "Bideoaren ezarpenak",
|
||||||
"@settingsVideoPageTitle": {},
|
"@settingsVideoPageTitle": {},
|
||||||
"settingsVideoSectionTitle": "Bideo",
|
"settingsVideoSectionTitle": "Bideoa",
|
||||||
"@settingsVideoSectionTitle": {},
|
"@settingsVideoSectionTitle": {},
|
||||||
"settingsVideoEnableHardwareAcceleration": "Hardwarearen azelerazioa",
|
"settingsVideoEnableHardwareAcceleration": "Hardwarearen azelerazioa",
|
||||||
"@settingsVideoEnableHardwareAcceleration": {},
|
"@settingsVideoEnableHardwareAcceleration": {},
|
||||||
|
@ -1427,13 +1427,13 @@
|
||||||
"@patternDialogConfirm": {},
|
"@patternDialogConfirm": {},
|
||||||
"settingsVideoEnablePip": "Bideoa leihotxoan",
|
"settingsVideoEnablePip": "Bideoa leihotxoan",
|
||||||
"@settingsVideoEnablePip": {},
|
"@settingsVideoEnablePip": {},
|
||||||
"settingsVideoBackgroundMode": "Erreprodukzioa atzeko planoan",
|
"settingsVideoBackgroundMode": "Atzeko planoko modua",
|
||||||
"@settingsVideoBackgroundMode": {},
|
"@settingsVideoBackgroundMode": {},
|
||||||
"settingsVideoBackgroundModeDialogTitle": "Atzeko planoko modua",
|
"settingsVideoBackgroundModeDialogTitle": "Atzeko planoko modua",
|
||||||
"@settingsVideoBackgroundModeDialogTitle": {},
|
"@settingsVideoBackgroundModeDialogTitle": {},
|
||||||
"settingsCollectionBurstPatternsNone": "Bat ere ez",
|
"settingsCollectionBurstPatternsNone": "Bat ere ez",
|
||||||
"@settingsCollectionBurstPatternsNone": {},
|
"@settingsCollectionBurstPatternsNone": {},
|
||||||
"settingsCollectionBurstPatternsTile": "Segida moduak",
|
"settingsCollectionBurstPatternsTile": "Segida ereduak",
|
||||||
"@settingsCollectionBurstPatternsTile": {},
|
"@settingsCollectionBurstPatternsTile": {},
|
||||||
"tagPlaceholderState": "Egoera",
|
"tagPlaceholderState": "Egoera",
|
||||||
"@tagPlaceholderState": {},
|
"@tagPlaceholderState": {},
|
||||||
|
@ -1518,5 +1518,11 @@
|
||||||
"entryActionCast": "Igorri",
|
"entryActionCast": "Igorri",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "Igortzeko gailuak",
|
"castDialogTitle": "Igortzeko gailuak",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Erakutsi HDR ikonoa",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"collectionActionSetHome": "Ezarri hasiera gisa",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "Bilduma pertsonalizatua",
|
||||||
|
"@setHomeCustomCollection": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1360,5 +1360,11 @@
|
||||||
"entryActionCast": "Caster",
|
"entryActionCast": "Caster",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "Appareils",
|
"castDialogTitle": "Appareils",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"collectionActionSetHome": "Définir comme page d’accueil",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "Collection personnalisée",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Afficher l’icône HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1518,5 +1518,11 @@
|
||||||
"entryActionCast": "Kivetítés",
|
"entryActionCast": "Kivetítés",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "Kivetítő eszközök",
|
"castDialogTitle": "Kivetítő eszközök",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "HDR ikon megjelenítése",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"setHomeCustomCollection": "Egyéni gyűjtemény",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"collectionActionSetHome": "Kezdőlapnak beállít",
|
||||||
|
"@collectionActionSetHome": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1518,5 +1518,11 @@
|
||||||
"settingsStorageAccessBanner": "Sumar möppur krefjast þess að gefin sé sérstök heimild til að breyta skrám í þeim. Þú getur yfirfarið hér þær möppur sem þú hefur gefið aðgangaheimildir fyrir.",
|
"settingsStorageAccessBanner": "Sumar möppur krefjast þess að gefin sé sérstök heimild til að breyta skrám í þeim. Þú getur yfirfarið hér þær möppur sem þú hefur gefið aðgangaheimildir fyrir.",
|
||||||
"@settingsStorageAccessBanner": {},
|
"@settingsStorageAccessBanner": {},
|
||||||
"settingsCollectionBurstPatternsTile": "Mynstur runu",
|
"settingsCollectionBurstPatternsTile": "Mynstur runu",
|
||||||
"@settingsCollectionBurstPatternsTile": {}
|
"@settingsCollectionBurstPatternsTile": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Birta HDR-táknmynd",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"collectionActionSetHome": "Setja sem upphafsskjá",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "Sérsniðið safn",
|
||||||
|
"@setHomeCustomCollection": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1360,5 +1360,11 @@
|
||||||
"entryActionCast": "전송",
|
"entryActionCast": "전송",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "전송 대상",
|
"castDialogTitle": "전송 대상",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "HDR 아이콘 표시",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"collectionActionSetHome": "홈으로 설정",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "지정 미디어",
|
||||||
|
"@setHomeCustomCollection": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1518,5 +1518,11 @@
|
||||||
"entryActionCast": "Cast",
|
"entryActionCast": "Cast",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "Urządzenia Cast",
|
"castDialogTitle": "Urządzenia Cast",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Pokaż ikonę HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"setHomeCustomCollection": "Własna kolekcja",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"collectionActionSetHome": "Ustaw jako stronę główną",
|
||||||
|
"@collectionActionSetHome": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1360,5 +1360,11 @@
|
||||||
"entryActionCast": "Трансляция",
|
"entryActionCast": "Трансляция",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "Устройства трансляции",
|
"castDialogTitle": "Устройства трансляции",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Показать значок HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"setHomeCustomCollection": "Собственная коллекция",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"collectionActionSetHome": "Установить как главную",
|
||||||
|
"@collectionActionSetHome": {}
|
||||||
}
|
}
|
||||||
|
|
7
lib/l10n/app_sat.arb
Normal file
7
lib/l10n/app_sat.arb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"@@locale": "sat",
|
||||||
|
"welcomeMessage": "ᱮᱣᱥ ᱨᱮ ᱥᱟᱹᱜᱩᱱ ᱫᱟᱨᱟᱢ",
|
||||||
|
"@welcomeMessage": {},
|
||||||
|
"appName": "ᱮᱣᱥ",
|
||||||
|
"@appName": {}
|
||||||
|
}
|
|
@ -1518,5 +1518,11 @@
|
||||||
"aboutDataUsageClearCache": "Vymazať cache",
|
"aboutDataUsageClearCache": "Vymazať cache",
|
||||||
"@aboutDataUsageClearCache": {},
|
"@aboutDataUsageClearCache": {},
|
||||||
"castDialogTitle": "Cast zariadenia",
|
"castDialogTitle": "Cast zariadenia",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"collectionActionSetHome": "Nastaviť ako doma",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "Kolekcia na mieru",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Zobraziť ikonu HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {}
|
||||||
}
|
}
|
||||||
|
|
839
lib/l10n/app_sv.arb
Normal file
839
lib/l10n/app_sv.arb
Normal file
|
@ -0,0 +1,839 @@
|
||||||
|
{
|
||||||
|
"viewerActionLock": "Lås",
|
||||||
|
"@viewerActionLock": {},
|
||||||
|
"entryInfoActionEditTags": "Redigera taggar",
|
||||||
|
"@entryInfoActionEditTags": {},
|
||||||
|
"videoActionPlay": "Spela",
|
||||||
|
"@videoActionPlay": {},
|
||||||
|
"viewerActionSettings": "Inställningar",
|
||||||
|
"@viewerActionSettings": {},
|
||||||
|
"albumTierSpecial": "Vanlig",
|
||||||
|
"@albumTierSpecial": {},
|
||||||
|
"displayRefreshRatePreferLowest": "Lägsta intervall",
|
||||||
|
"@displayRefreshRatePreferLowest": {},
|
||||||
|
"keepScreenOnViewerOnly": "Visningssidan bara",
|
||||||
|
"@keepScreenOnViewerOnly": {},
|
||||||
|
"mapStyleHuaweiTerrain": "Petal Maps (Terrain)",
|
||||||
|
"@mapStyleHuaweiTerrain": {},
|
||||||
|
"mapStyleHuaweiNormal": "Petal Maps",
|
||||||
|
"@mapStyleHuaweiNormal": {},
|
||||||
|
"mapStyleOsmHot": "Humanitarian OSM",
|
||||||
|
"@mapStyleOsmHot": {},
|
||||||
|
"videoResumptionModeAlways": "Alltid",
|
||||||
|
"@videoResumptionModeAlways": {},
|
||||||
|
"storageVolumeDescriptionFallbackPrimary": "Intern lagring",
|
||||||
|
"@storageVolumeDescriptionFallbackPrimary": {},
|
||||||
|
"widgetOpenPageCollection": "Öppen insamling",
|
||||||
|
"@widgetOpenPageCollection": {},
|
||||||
|
"widgetTapUpdateWidget": "Uppdatera widgeten",
|
||||||
|
"@widgetTapUpdateWidget": {},
|
||||||
|
"storageVolumeDescriptionFallbackNonPrimary": "SD kort",
|
||||||
|
"@storageVolumeDescriptionFallbackNonPrimary": {},
|
||||||
|
"welcomeTermsToggle": "Jag godkäner användar villkoren",
|
||||||
|
"@welcomeTermsToggle": {},
|
||||||
|
"focalLength": "{length} mm",
|
||||||
|
"@focalLength": {
|
||||||
|
"placeholders": {
|
||||||
|
"length": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "5.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deleteButtonLabel": "Ta bort",
|
||||||
|
"@deleteButtonLabel": {},
|
||||||
|
"showButtonLabel": "Visa",
|
||||||
|
"@showButtonLabel": {},
|
||||||
|
"hideButtonLabel": "Göm",
|
||||||
|
"@hideButtonLabel": {},
|
||||||
|
"continueButtonLabel": "Fortsätt",
|
||||||
|
"@continueButtonLabel": {},
|
||||||
|
"saveCopyButtonLabel": "Spara kopia",
|
||||||
|
"@saveCopyButtonLabel": {},
|
||||||
|
"changeTooltip": "Ändra",
|
||||||
|
"@changeTooltip": {},
|
||||||
|
"clearTooltip": "Rensa",
|
||||||
|
"@clearTooltip": {},
|
||||||
|
"previousTooltip": "Föregående",
|
||||||
|
"@previousTooltip": {},
|
||||||
|
"showTooltip": "Visa",
|
||||||
|
"@showTooltip": {},
|
||||||
|
"hideTooltip": "Göm",
|
||||||
|
"@hideTooltip": {},
|
||||||
|
"actionRemove": "Ta bort",
|
||||||
|
"@actionRemove": {},
|
||||||
|
"resetTooltip": "Återställ",
|
||||||
|
"@resetTooltip": {},
|
||||||
|
"saveTooltip": "Spara",
|
||||||
|
"@saveTooltip": {},
|
||||||
|
"pickTooltip": "Välj",
|
||||||
|
"@pickTooltip": {},
|
||||||
|
"sourceStateLocatingCountries": "Lokaliserar länder",
|
||||||
|
"@sourceStateLocatingCountries": {},
|
||||||
|
"sourceStateLocatingPlaces": "Lokaliserar platser",
|
||||||
|
"@sourceStateLocatingPlaces": {},
|
||||||
|
"chipActionDelete": "Ta bort",
|
||||||
|
"@chipActionDelete": {},
|
||||||
|
"chipActionGoToAlbumPage": "Visa i album",
|
||||||
|
"@chipActionGoToAlbumPage": {},
|
||||||
|
"welcomeOptional": "Valfritt",
|
||||||
|
"@welcomeOptional": {},
|
||||||
|
"applyButtonLabel": "TILLÄMPA",
|
||||||
|
"@applyButtonLabel": {},
|
||||||
|
"applyTooltip": "Tillämpa",
|
||||||
|
"@applyTooltip": {},
|
||||||
|
"cancelTooltip": "Avbryt",
|
||||||
|
"@cancelTooltip": {},
|
||||||
|
"doubleBackExitMessage": "Tryck \"bakåt\" igen för att stänga.",
|
||||||
|
"@doubleBackExitMessage": {},
|
||||||
|
"chipActionGoToCountryPage": "Visa i länder",
|
||||||
|
"@chipActionGoToCountryPage": {},
|
||||||
|
"chipActionGoToPlacePage": "Visa på Platser",
|
||||||
|
"@chipActionGoToPlacePage": {},
|
||||||
|
"chipActionGoToTagPage": "Visa i Taggar",
|
||||||
|
"@chipActionGoToTagPage": {},
|
||||||
|
"chipActionFilterOut": "Filtrera ut",
|
||||||
|
"@chipActionFilterOut": {},
|
||||||
|
"chipActionFilterIn": "Filtrera fram",
|
||||||
|
"@chipActionFilterIn": {},
|
||||||
|
"chipActionHide": "Göm",
|
||||||
|
"@chipActionHide": {},
|
||||||
|
"chipActionLock": "Lås",
|
||||||
|
"@chipActionLock": {},
|
||||||
|
"itemCount": "{count, plural, other{{count} objekt}}",
|
||||||
|
"@itemCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"columnCount": "{count, plural, =1{1 kolumn} other{{count} kolumner}}",
|
||||||
|
"@columnCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timeSeconds": "{seconds, plural, =1{1 sekund} other{{seconds} sekunder}}",
|
||||||
|
"@timeSeconds": {
|
||||||
|
"placeholders": {
|
||||||
|
"seconds": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timeMinutes": "{minutes, plural, =1{1 minut} other{{minutes} minuter}}",
|
||||||
|
"@timeMinutes": {
|
||||||
|
"placeholders": {
|
||||||
|
"minutes": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timeDays": "{days, plural, =1{1 dag} other{{days} dagar}}",
|
||||||
|
"@timeDays": {
|
||||||
|
"placeholders": {
|
||||||
|
"days": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chipActionPin": "Fäst överst",
|
||||||
|
"@chipActionPin": {},
|
||||||
|
"chipActionRename": "Byt namn",
|
||||||
|
"@chipActionRename": {},
|
||||||
|
"chipActionSetCover": "Välj som omslag",
|
||||||
|
"@chipActionSetCover": {},
|
||||||
|
"chipActionShowCountryStates": "Visa delstater",
|
||||||
|
"@chipActionShowCountryStates": {},
|
||||||
|
"chipActionCreateAlbum": "Skapa album",
|
||||||
|
"@chipActionCreateAlbum": {},
|
||||||
|
"chipActionCreateVault": "Skapa valv",
|
||||||
|
"@chipActionCreateVault": {},
|
||||||
|
"chipActionConfigureVault": "Konfigurera valv",
|
||||||
|
"@chipActionConfigureVault": {},
|
||||||
|
"entryActionConvert": "Konvertera",
|
||||||
|
"@entryActionConvert": {},
|
||||||
|
"entryActionExport": "Exportera",
|
||||||
|
"@entryActionExport": {},
|
||||||
|
"entryActionInfo": "Info",
|
||||||
|
"@entryActionInfo": {},
|
||||||
|
"entryActionRename": "Byt namn",
|
||||||
|
"@entryActionRename": {},
|
||||||
|
"entryActionRestore": "Återställ",
|
||||||
|
"@entryActionRestore": {},
|
||||||
|
"entryActionRotateCCW": "Rotera moturs",
|
||||||
|
"@entryActionRotateCCW": {},
|
||||||
|
"entryActionRotateCW": "Rotera medurs",
|
||||||
|
"@entryActionRotateCW": {},
|
||||||
|
"entryActionFlip": "Vrid horisontellt",
|
||||||
|
"@entryActionFlip": {},
|
||||||
|
"entryActionPrint": "Skriv ut",
|
||||||
|
"@entryActionPrint": {},
|
||||||
|
"entryActionShare": "Dela",
|
||||||
|
"@entryActionShare": {},
|
||||||
|
"entryActionShareImageOnly": "Dela endast bild",
|
||||||
|
"@entryActionShareImageOnly": {},
|
||||||
|
"entryActionShareVideoOnly": "Dela endast video",
|
||||||
|
"@entryActionShareVideoOnly": {},
|
||||||
|
"entryActionViewSource": "Visa källa",
|
||||||
|
"@entryActionViewSource": {},
|
||||||
|
"entryActionShowGeoTiffOnMap": "Visa som kartöverlägg",
|
||||||
|
"@entryActionShowGeoTiffOnMap": {},
|
||||||
|
"entryActionConvertMotionPhotoToStillImage": "Konvertera till stillbild",
|
||||||
|
"@entryActionConvertMotionPhotoToStillImage": {},
|
||||||
|
"entryActionViewMotionPhotoVideo": "Öppna video",
|
||||||
|
"@entryActionViewMotionPhotoVideo": {},
|
||||||
|
"entryActionEdit": "Redigera",
|
||||||
|
"@entryActionEdit": {},
|
||||||
|
"entryActionOpen": "Öppna med",
|
||||||
|
"@entryActionOpen": {},
|
||||||
|
"entryActionSetAs": "Välj som",
|
||||||
|
"@entryActionSetAs": {},
|
||||||
|
"entryActionOpenMap": "Visa i kartappen",
|
||||||
|
"@entryActionOpenMap": {},
|
||||||
|
"entryActionRotateScreen": "Rotera skärmen",
|
||||||
|
"@entryActionRotateScreen": {},
|
||||||
|
"entryActionAddFavourite": "Lägg till i favoritlistan",
|
||||||
|
"@entryActionAddFavourite": {},
|
||||||
|
"entryActionRemoveFavourite": "Lägg från favoritlistan",
|
||||||
|
"@entryActionRemoveFavourite": {},
|
||||||
|
"videoActionCaptureFrame": "Fånga stillbild",
|
||||||
|
"@videoActionCaptureFrame": {},
|
||||||
|
"videoActionMute": "Ljudlös",
|
||||||
|
"@videoActionMute": {},
|
||||||
|
"videoActionUnmute": "Ljud",
|
||||||
|
"@videoActionUnmute": {},
|
||||||
|
"videoActionPause": "Pausa",
|
||||||
|
"@videoActionPause": {},
|
||||||
|
"videoActionReplay10": "Spola tillbaks 10 sekunder",
|
||||||
|
"@videoActionReplay10": {},
|
||||||
|
"videoActionSkip10": "Spola framåt 10 sekunder",
|
||||||
|
"@videoActionSkip10": {},
|
||||||
|
"videoActionSelectStreams": "Välj spår",
|
||||||
|
"@videoActionSelectStreams": {},
|
||||||
|
"videoActionSetSpeed": "Uppspelningshastighet",
|
||||||
|
"@videoActionSetSpeed": {},
|
||||||
|
"entryActionDelete": "Radera",
|
||||||
|
"@entryActionDelete": {},
|
||||||
|
"entryActionCopyToClipboard": "Spara till urklipp",
|
||||||
|
"@entryActionCopyToClipboard": {},
|
||||||
|
"viewerActionUnlock": "Öppna",
|
||||||
|
"@viewerActionUnlock": {},
|
||||||
|
"slideshowActionResume": "Återuppta",
|
||||||
|
"@slideshowActionResume": {},
|
||||||
|
"slideshowActionShowInCollection": "Visa i samling",
|
||||||
|
"@slideshowActionShowInCollection": {},
|
||||||
|
"entryInfoActionEditDate": "Redigera datum & tid",
|
||||||
|
"@entryInfoActionEditDate": {},
|
||||||
|
"entryInfoActionEditLocation": "Redigera plats",
|
||||||
|
"@entryInfoActionEditLocation": {},
|
||||||
|
"entryInfoActionEditTitleDescription": "Redigera titel och beskrivning",
|
||||||
|
"@entryInfoActionEditTitleDescription": {},
|
||||||
|
"entryInfoActionEditRating": "Redigera betyg",
|
||||||
|
"@entryInfoActionEditRating": {},
|
||||||
|
"entryInfoActionRemoveMetadata": "Ta bort metadata",
|
||||||
|
"@entryInfoActionRemoveMetadata": {},
|
||||||
|
"entryInfoActionExportMetadata": "Exportera metadata",
|
||||||
|
"@entryInfoActionExportMetadata": {},
|
||||||
|
"entryInfoActionRemoveLocation": "Ta bort plats",
|
||||||
|
"@entryInfoActionRemoveLocation": {},
|
||||||
|
"editorActionTransform": "Transformera",
|
||||||
|
"@editorActionTransform": {},
|
||||||
|
"editorTransformCrop": "Beskär",
|
||||||
|
"@editorTransformCrop": {},
|
||||||
|
"editorTransformRotate": "Rotera",
|
||||||
|
"@editorTransformRotate": {},
|
||||||
|
"cropAspectRatioFree": "Fri",
|
||||||
|
"@cropAspectRatioFree": {},
|
||||||
|
"cropAspectRatioOriginal": "Original",
|
||||||
|
"@cropAspectRatioOriginal": {},
|
||||||
|
"cropAspectRatioSquare": "Fyrkant",
|
||||||
|
"@cropAspectRatioSquare": {},
|
||||||
|
"filterAspectRatioLandscapeLabel": "Liggande",
|
||||||
|
"@filterAspectRatioLandscapeLabel": {},
|
||||||
|
"filterAspectRatioPortraitLabel": "Porträtt",
|
||||||
|
"@filterAspectRatioPortraitLabel": {},
|
||||||
|
"filterBinLabel": "Papperskorg",
|
||||||
|
"@filterBinLabel": {},
|
||||||
|
"filterFavouriteLabel": "Favorit",
|
||||||
|
"@filterFavouriteLabel": {},
|
||||||
|
"filterNoDateLabel": "Odaterat",
|
||||||
|
"@filterNoDateLabel": {},
|
||||||
|
"filterNoAddressLabel": "Ingen adress",
|
||||||
|
"@filterNoAddressLabel": {},
|
||||||
|
"filterLocatedLabel": "Belägen",
|
||||||
|
"@filterLocatedLabel": {},
|
||||||
|
"filterNoLocationLabel": "Ej belägen",
|
||||||
|
"@filterNoLocationLabel": {},
|
||||||
|
"filterNoTagLabel": "otaggad",
|
||||||
|
"@filterNoTagLabel": {},
|
||||||
|
"filterNoTitleLabel": "Obetitlad",
|
||||||
|
"@filterNoTitleLabel": {},
|
||||||
|
"filterOnThisDayLabel": "På den här dagen",
|
||||||
|
"@filterOnThisDayLabel": {},
|
||||||
|
"filterRecentlyAddedLabel": "Nyligen tillagd",
|
||||||
|
"@filterRecentlyAddedLabel": {},
|
||||||
|
"filterRatingRejectedLabel": "Avisad",
|
||||||
|
"@filterRatingRejectedLabel": {},
|
||||||
|
"filterTypeAnimatedLabel": "Animerad",
|
||||||
|
"@filterTypeAnimatedLabel": {},
|
||||||
|
"filterTypeMotionPhotoLabel": "Rörelsefoto",
|
||||||
|
"@filterTypeMotionPhotoLabel": {},
|
||||||
|
"filterTypePanoramaLabel": "Panorama",
|
||||||
|
"@filterTypePanoramaLabel": {},
|
||||||
|
"filterTypeRawLabel": "Raw",
|
||||||
|
"@filterTypeRawLabel": {},
|
||||||
|
"filterTypeSphericalVideoLabel": "360° Video",
|
||||||
|
"@filterTypeSphericalVideoLabel": {},
|
||||||
|
"filterTypeGeotiffLabel": "GeoTIFF",
|
||||||
|
"@filterTypeGeotiffLabel": {},
|
||||||
|
"filterMimeImageLabel": "Bild",
|
||||||
|
"@filterMimeImageLabel": {},
|
||||||
|
"filterMimeVideoLabel": "Video",
|
||||||
|
"@filterMimeVideoLabel": {},
|
||||||
|
"accessibilityAnimationsRemove": "Förhindra skärmeffekter",
|
||||||
|
"@accessibilityAnimationsRemove": {},
|
||||||
|
"accessibilityAnimationsKeep": "Behåll skärmeffekter",
|
||||||
|
"@accessibilityAnimationsKeep": {},
|
||||||
|
"albumTierNew": "Ny",
|
||||||
|
"@albumTierNew": {},
|
||||||
|
"albumTierPinned": "Fastnålad",
|
||||||
|
"@albumTierPinned": {},
|
||||||
|
"albumTierApps": "Appar",
|
||||||
|
"@albumTierApps": {},
|
||||||
|
"albumTierVaults": "Valv",
|
||||||
|
"@albumTierVaults": {},
|
||||||
|
"albumTierRegular": "Andra",
|
||||||
|
"@albumTierRegular": {},
|
||||||
|
"coordinateFormatDms": "DMS",
|
||||||
|
"@coordinateFormatDms": {},
|
||||||
|
"coordinateFormatDecimal": "Decimal degrees",
|
||||||
|
"@coordinateFormatDecimal": {},
|
||||||
|
"coordinateDms": "{coordinate} {direction}",
|
||||||
|
"@coordinateDms": {
|
||||||
|
"placeholders": {
|
||||||
|
"coordinate": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "38° 41′ 47.72″"
|
||||||
|
},
|
||||||
|
"direction": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "S"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"coordinateDmsNorth": "N",
|
||||||
|
"@coordinateDmsNorth": {},
|
||||||
|
"coordinateDmsSouth": "S",
|
||||||
|
"@coordinateDmsSouth": {},
|
||||||
|
"coordinateDmsEast": "Ö",
|
||||||
|
"@coordinateDmsEast": {},
|
||||||
|
"coordinateDmsWest": "V",
|
||||||
|
"@coordinateDmsWest": {},
|
||||||
|
"displayRefreshRatePreferHighest": "Högsta intervall",
|
||||||
|
"@displayRefreshRatePreferHighest": {},
|
||||||
|
"keepScreenOnVideoPlayback": "Under videouppspelning",
|
||||||
|
"@keepScreenOnVideoPlayback": {},
|
||||||
|
"keepScreenOnAlways": "Alltid",
|
||||||
|
"@keepScreenOnAlways": {},
|
||||||
|
"lengthUnitPixel": "px",
|
||||||
|
"@lengthUnitPixel": {},
|
||||||
|
"lengthUnitPercent": "%",
|
||||||
|
"@lengthUnitPercent": {},
|
||||||
|
"mapStyleGoogleNormal": "Google Maps",
|
||||||
|
"@mapStyleGoogleNormal": {},
|
||||||
|
"mapStyleGoogleHybrid": "Google Maps (Hybrid)",
|
||||||
|
"@mapStyleGoogleHybrid": {},
|
||||||
|
"mapStyleGoogleTerrain": "Google Maps (Terrain)",
|
||||||
|
"@mapStyleGoogleTerrain": {},
|
||||||
|
"mapStyleStamenWatercolor": "Stamen Watercolor",
|
||||||
|
"@mapStyleStamenWatercolor": {},
|
||||||
|
"maxBrightnessNever": "Alldrig",
|
||||||
|
"@maxBrightnessNever": {},
|
||||||
|
"maxBrightnessAlways": "Alltid",
|
||||||
|
"@maxBrightnessAlways": {},
|
||||||
|
"nameConflictStrategyRename": "Byt namn",
|
||||||
|
"@nameConflictStrategyRename": {},
|
||||||
|
"nameConflictStrategyReplace": "Ersätt",
|
||||||
|
"@nameConflictStrategyReplace": {},
|
||||||
|
"nameConflictStrategySkip": "Skippa",
|
||||||
|
"@nameConflictStrategySkip": {},
|
||||||
|
"overlayHistogramNone": "Igen",
|
||||||
|
"@overlayHistogramNone": {},
|
||||||
|
"overlayHistogramRGB": "RGB",
|
||||||
|
"@overlayHistogramRGB": {},
|
||||||
|
"overlayHistogramLuminance": "Luminans",
|
||||||
|
"@overlayHistogramLuminance": {},
|
||||||
|
"subtitlePositionBottom": "Nederkant",
|
||||||
|
"@subtitlePositionBottom": {},
|
||||||
|
"subtitlePositionTop": "Överkant",
|
||||||
|
"@subtitlePositionTop": {},
|
||||||
|
"themeBrightnessLight": "Ljus",
|
||||||
|
"@themeBrightnessLight": {},
|
||||||
|
"themeBrightnessDark": "Mörk",
|
||||||
|
"@themeBrightnessDark": {},
|
||||||
|
"themeBrightnessBlack": "Svart",
|
||||||
|
"@themeBrightnessBlack": {},
|
||||||
|
"unitSystemMetric": "Metrisk",
|
||||||
|
"@unitSystemMetric": {},
|
||||||
|
"unitSystemImperial": "Brittiskt",
|
||||||
|
"@unitSystemImperial": {},
|
||||||
|
"vaultLockTypePattern": "Mönster",
|
||||||
|
"@vaultLockTypePattern": {},
|
||||||
|
"vaultLockTypePin": "PIN",
|
||||||
|
"@vaultLockTypePin": {},
|
||||||
|
"vaultLockTypePassword": "Lösenord",
|
||||||
|
"@vaultLockTypePassword": {},
|
||||||
|
"settingsVideoEnablePip": "Bild-i-bild",
|
||||||
|
"@settingsVideoEnablePip": {},
|
||||||
|
"videoControlsPlay": "Spela",
|
||||||
|
"@videoControlsPlay": {},
|
||||||
|
"videoControlsPlaySeek": "Spela & sök bakåt/framåt",
|
||||||
|
"@videoControlsPlaySeek": {},
|
||||||
|
"videoControlsPlayOutside": "Öppna med annan spelare",
|
||||||
|
"@videoControlsPlayOutside": {},
|
||||||
|
"videoControlsNone": "Ingen",
|
||||||
|
"@videoControlsNone": {},
|
||||||
|
"videoLoopModeNever": "Aldrig",
|
||||||
|
"@videoLoopModeNever": {},
|
||||||
|
"videoLoopModeShortOnly": "Bara korta videor",
|
||||||
|
"@videoLoopModeShortOnly": {},
|
||||||
|
"videoLoopModeAlways": "Alltid",
|
||||||
|
"@videoLoopModeAlways": {},
|
||||||
|
"videoPlaybackSkip": "Skippa",
|
||||||
|
"@videoPlaybackSkip": {},
|
||||||
|
"videoPlaybackMuted": "Spela ljudlös",
|
||||||
|
"@videoPlaybackMuted": {},
|
||||||
|
"videoPlaybackWithSound": "Spela med ljud",
|
||||||
|
"@videoPlaybackWithSound": {},
|
||||||
|
"videoResumptionModeNever": "Alldrig",
|
||||||
|
"@videoResumptionModeNever": {},
|
||||||
|
"viewerTransitionSlide": "Glid",
|
||||||
|
"@viewerTransitionSlide": {},
|
||||||
|
"viewerTransitionParallax": "Parallax",
|
||||||
|
"@viewerTransitionParallax": {},
|
||||||
|
"viewerTransitionNone": "Igen",
|
||||||
|
"@viewerTransitionNone": {},
|
||||||
|
"wallpaperTargetHome": "Hemskärm",
|
||||||
|
"@wallpaperTargetHome": {},
|
||||||
|
"widgetDisplayedItemRandom": "Slumpvis",
|
||||||
|
"@widgetDisplayedItemRandom": {},
|
||||||
|
"widgetDisplayedItemMostRecent": "Alldra senast",
|
||||||
|
"@widgetDisplayedItemMostRecent": {},
|
||||||
|
"widgetOpenPageHome": "Öppna hem",
|
||||||
|
"@widgetOpenPageHome": {},
|
||||||
|
"otherDirectoryDescription": "“{name}” map",
|
||||||
|
"@otherDirectoryDescription": {
|
||||||
|
"placeholders": {
|
||||||
|
"name": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "Pictures",
|
||||||
|
"description": "the name of a specific directory"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storageAccessDialogMessage": "Var snäll och välj {directory} av“{volume}” på nästa skärm för att ge appen åtkomst till den.",
|
||||||
|
"@storageAccessDialogMessage": {
|
||||||
|
"placeholders": {
|
||||||
|
"directory": {
|
||||||
|
"type": "String",
|
||||||
|
"description": "the name of a directory, using the output of `rootDirectoryDescription` or `otherDirectoryDescription`"
|
||||||
|
},
|
||||||
|
"volume": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "SD card",
|
||||||
|
"description": "the name of a storage volume"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"videoStartOverButtonLabel": "BÖRJA OM",
|
||||||
|
"@videoStartOverButtonLabel": {},
|
||||||
|
"videoResumeButtonLabel": "Återuppta",
|
||||||
|
"@videoResumeButtonLabel": {},
|
||||||
|
"setCoverDialogLatest": "Senaste objektet",
|
||||||
|
"@setCoverDialogLatest": {},
|
||||||
|
"setCoverDialogAuto": "Auto",
|
||||||
|
"@setCoverDialogAuto": {},
|
||||||
|
"setCoverDialogCustom": "Anpassad",
|
||||||
|
"@setCoverDialogCustom": {},
|
||||||
|
"hideFilterConfirmationDialogMessage": "Matchande foton och videor kommer att döljas från din samling. Du kan välja att visa dem igen från \"sekretessinställningarna\".\n\nÄr du säker på att du vill dölja dem?",
|
||||||
|
"@hideFilterConfirmationDialogMessage": {},
|
||||||
|
"newAlbumDialogTitle": "Nytt Album",
|
||||||
|
"@newAlbumDialogTitle": {},
|
||||||
|
"newAlbumDialogNameLabelAlreadyExistsHelper": "Mappen existerar redan",
|
||||||
|
"@newAlbumDialogNameLabelAlreadyExistsHelper": {},
|
||||||
|
"newAlbumDialogStorageLabel": "Lagring:",
|
||||||
|
"@newAlbumDialogStorageLabel": {},
|
||||||
|
"newVaultDialogTitle": "Nytt Valv",
|
||||||
|
"@newVaultDialogTitle": {},
|
||||||
|
"configureVaultDialogTitle": "Konfigurera Valv",
|
||||||
|
"@configureVaultDialogTitle": {},
|
||||||
|
"vaultDialogLockTypeLabel": "Lås typ",
|
||||||
|
"@vaultDialogLockTypeLabel": {},
|
||||||
|
"pinDialogConfirm": "Bekräfta pinkod",
|
||||||
|
"@pinDialogConfirm": {},
|
||||||
|
"pinDialogEnter": "Ange Pinkod",
|
||||||
|
"@pinDialogEnter": {},
|
||||||
|
"passwordDialogEnter": "Ange lösenord",
|
||||||
|
"@passwordDialogEnter": {},
|
||||||
|
"passwordDialogConfirm": "Bekräfta lösenord",
|
||||||
|
"@passwordDialogConfirm": {},
|
||||||
|
"authenticateToConfigureVault": "Autentisera för att konfigurera valvet",
|
||||||
|
"@authenticateToConfigureVault": {},
|
||||||
|
"appName": "Aves",
|
||||||
|
"@appName": {},
|
||||||
|
"welcomeMessage": "Välkommen till Aves",
|
||||||
|
"@welcomeMessage": {},
|
||||||
|
"nextButtonLabel": "Nästa",
|
||||||
|
"@nextButtonLabel": {},
|
||||||
|
"nextTooltip": "Nästs",
|
||||||
|
"@nextTooltip": {},
|
||||||
|
"doNotAskAgain": "Fråga inte igen",
|
||||||
|
"@doNotAskAgain": {},
|
||||||
|
"sourceStateLoading": "Laddar",
|
||||||
|
"@sourceStateLoading": {},
|
||||||
|
"sourceStateCataloguing": "Katalogiserar",
|
||||||
|
"@sourceStateCataloguing": {},
|
||||||
|
"editEntryLocationDialogLongitude": "Longitud",
|
||||||
|
"@editEntryLocationDialogLongitude": {},
|
||||||
|
"removeEntryMetadataMotionPhotoXmpWarningDialogMessage": "XMP behövs för att spela upp videon i ett Rörelsefoto.\n\nÄr du säker att du vill ta bort det?",
|
||||||
|
"@removeEntryMetadataMotionPhotoXmpWarningDialogMessage": {},
|
||||||
|
"videoStreamSelectionDialogOff": "Av",
|
||||||
|
"@videoStreamSelectionDialogOff": {},
|
||||||
|
"videoStreamSelectionDialogTrack": "Spår",
|
||||||
|
"@videoStreamSelectionDialogTrack": {},
|
||||||
|
"videoStreamSelectionDialogNoSelection": "Det finns inga andra spår.",
|
||||||
|
"@videoStreamSelectionDialogNoSelection": {},
|
||||||
|
"genericSuccessFeedback": "Klar!",
|
||||||
|
"@genericSuccessFeedback": {},
|
||||||
|
"genericFailureFeedback": "Misslyckad",
|
||||||
|
"@genericFailureFeedback": {},
|
||||||
|
"genericDangerWarningDialogMessage": "Är du säker?",
|
||||||
|
"@genericDangerWarningDialogMessage": {},
|
||||||
|
"tooManyItemsErrorDialogMessage": "Försök ingen med färre objekt.",
|
||||||
|
"@tooManyItemsErrorDialogMessage": {},
|
||||||
|
"menuActionConfigureView": "Visa",
|
||||||
|
"@menuActionConfigureView": {},
|
||||||
|
"menuActionSelectAll": "Välj alla",
|
||||||
|
"@menuActionSelectAll": {},
|
||||||
|
"menuActionSelect": "Välj",
|
||||||
|
"@menuActionSelect": {},
|
||||||
|
"menuActionSelectNone": "Välj ingen",
|
||||||
|
"@menuActionSelectNone": {},
|
||||||
|
"menuActionMap": "Karta",
|
||||||
|
"@menuActionMap": {},
|
||||||
|
"menuActionSlideshow": "Bildspel",
|
||||||
|
"@menuActionSlideshow": {},
|
||||||
|
"menuActionStats": "Statistik",
|
||||||
|
"@menuActionStats": {},
|
||||||
|
"filterNoRatingLabel": "Ej betygsatt",
|
||||||
|
"@filterNoRatingLabel": {},
|
||||||
|
"viewerTransitionZoomIn": "Zooma in",
|
||||||
|
"@viewerTransitionZoomIn": {},
|
||||||
|
"nameConflictDialogSingleSourceMessage": "Vissa filer i destinationsmappen har samma namn.",
|
||||||
|
"@nameConflictDialogSingleSourceMessage": {},
|
||||||
|
"nameConflictDialogMultipleSourceMessage": "Vissa filer har samma namn.",
|
||||||
|
"@nameConflictDialogMultipleSourceMessage": {},
|
||||||
|
"noMatchingAppDialogMessage": "Det finns inga appar som kan hantera detta.",
|
||||||
|
"@noMatchingAppDialogMessage": {},
|
||||||
|
"moveUndatedConfirmationDialogSetDate": "Spara datum",
|
||||||
|
"@moveUndatedConfirmationDialogSetDate": {},
|
||||||
|
"videoResumeDialogMessage": "Vill du återuppta uppspelningen vid",
|
||||||
|
"@videoResumeDialogMessage": {
|
||||||
|
"placeholders": {
|
||||||
|
"time": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "13:37"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"newAlbumDialogNameLabel": "Album namn",
|
||||||
|
"@newAlbumDialogNameLabel": {},
|
||||||
|
"newVaultWarningDialogMessage": "Objekt i valv är endast tillgängliga i denna app och inga andra.\n\nOm du avinstallerar den här appen eller rensar appens data kommer du att förlora alla dessa objekt.",
|
||||||
|
"@newVaultWarningDialogMessage": {},
|
||||||
|
"vaultDialogLockModeWhenScreenOff": "Lås när skärmen stängs av",
|
||||||
|
"@vaultDialogLockModeWhenScreenOff": {},
|
||||||
|
"patternDialogEnter": "Ange mönster",
|
||||||
|
"@patternDialogEnter": {},
|
||||||
|
"patternDialogConfirm": "Bekräfta mönster",
|
||||||
|
"@patternDialogConfirm": {},
|
||||||
|
"renameEntrySetPagePatternFieldLabel": "Namnge mönster",
|
||||||
|
"@renameEntrySetPagePatternFieldLabel": {},
|
||||||
|
"renameEntrySetPageInsertTooltip": "Infoga ---",
|
||||||
|
"@renameEntrySetPageInsertTooltip": {},
|
||||||
|
"renameEntrySetPagePreviewSectionTitle": "Förhandsgranska",
|
||||||
|
"@renameEntrySetPagePreviewSectionTitle": {},
|
||||||
|
"renameProcessorName": "Namn",
|
||||||
|
"@renameProcessorName": {},
|
||||||
|
"exportEntryDialogFormat": "Format:",
|
||||||
|
"@exportEntryDialogFormat": {},
|
||||||
|
"exportEntryDialogWidth": "Bredd",
|
||||||
|
"@exportEntryDialogWidth": {},
|
||||||
|
"exportEntryDialogHeight": "Höjd",
|
||||||
|
"@exportEntryDialogHeight": {},
|
||||||
|
"exportEntryDialogQuality": "Kvalitet",
|
||||||
|
"@exportEntryDialogQuality": {},
|
||||||
|
"exportEntryDialogWriteMetadata": "Skriv metadata",
|
||||||
|
"@exportEntryDialogWriteMetadata": {},
|
||||||
|
"renameEntryDialogLabel": "Nytt namn",
|
||||||
|
"@renameEntryDialogLabel": {},
|
||||||
|
"editEntryDialogCopyFromItem": "Kopiera från annat objekt",
|
||||||
|
"@editEntryDialogCopyFromItem": {},
|
||||||
|
"editEntryDateDialogTitle": "Datum & Tid",
|
||||||
|
"@editEntryDateDialogTitle": {},
|
||||||
|
"editEntryDateDialogExtractFromTitle": "Kopiera från titel",
|
||||||
|
"@editEntryDateDialogExtractFromTitle": {},
|
||||||
|
"editEntryDateDialogShift": "Skift",
|
||||||
|
"@editEntryDateDialogShift": {},
|
||||||
|
"editEntryDateDialogSourceFileModifiedDate": "Filens modifieringsdatum",
|
||||||
|
"@editEntryDateDialogSourceFileModifiedDate": {},
|
||||||
|
"durationDialogHours": "Timmar",
|
||||||
|
"@durationDialogHours": {},
|
||||||
|
"durationDialogMinutes": "Minuter",
|
||||||
|
"@durationDialogMinutes": {},
|
||||||
|
"durationDialogSeconds": "Sekunder",
|
||||||
|
"@durationDialogSeconds": {},
|
||||||
|
"editEntryLocationDialogTitle": "Plats",
|
||||||
|
"@editEntryLocationDialogTitle": {},
|
||||||
|
"editEntryLocationDialogChooseOnMap": "Välj på karta",
|
||||||
|
"@editEntryLocationDialogChooseOnMap": {},
|
||||||
|
"editEntryLocationDialogLatitude": "Latitud",
|
||||||
|
"@editEntryLocationDialogLatitude": {},
|
||||||
|
"locationPickerUseThisLocationButton": "Använd den här platsen",
|
||||||
|
"@locationPickerUseThisLocationButton": {},
|
||||||
|
"editEntryRatingDialogTitle": "Betyg",
|
||||||
|
"@editEntryRatingDialogTitle": {},
|
||||||
|
"removeEntryMetadataDialogTitle": "Borttagning av metadata",
|
||||||
|
"@removeEntryMetadataDialogTitle": {},
|
||||||
|
"removeEntryMetadataDialogMore": "Mer",
|
||||||
|
"@removeEntryMetadataDialogMore": {},
|
||||||
|
"videoSpeedDialogLabel": "Uppspelningshastighet",
|
||||||
|
"@videoSpeedDialogLabel": {},
|
||||||
|
"videoStreamSelectionDialogVideo": "Video",
|
||||||
|
"@videoStreamSelectionDialogVideo": {},
|
||||||
|
"videoStreamSelectionDialogAudio": "Ljud",
|
||||||
|
"@videoStreamSelectionDialogAudio": {},
|
||||||
|
"videoStreamSelectionDialogText": "Undertexter",
|
||||||
|
"@videoStreamSelectionDialogText": {},
|
||||||
|
"aboutBugReportInstruction": "Rapportera på GitHub med loggarna och systeminformation.",
|
||||||
|
"@aboutBugReportInstruction": {},
|
||||||
|
"aboutDataUsageInternal": "Internt",
|
||||||
|
"@aboutDataUsageInternal": {},
|
||||||
|
"aboutLicensesBanner": "Den här appen använder följande paket och bibliotek under öppen källkod-licens",
|
||||||
|
"@aboutLicensesBanner": {},
|
||||||
|
"collectionPickPageTitle": "Välj",
|
||||||
|
"@collectionPickPageTitle": {},
|
||||||
|
"aboutBugCopyInfoButton": "Kopiera",
|
||||||
|
"@aboutBugCopyInfoButton": {},
|
||||||
|
"aboutBugReportButton": "Rapportera",
|
||||||
|
"@aboutBugReportButton": {},
|
||||||
|
"aboutDataUsageData": "Data",
|
||||||
|
"@aboutDataUsageData": {},
|
||||||
|
"aboutDataUsageSectionTitle": "DataAnvänding",
|
||||||
|
"@aboutDataUsageSectionTitle": {},
|
||||||
|
"aboutDataUsageCache": "Cache",
|
||||||
|
"@aboutDataUsageCache": {},
|
||||||
|
"aboutDataUsageDatabase": "Databas",
|
||||||
|
"@aboutDataUsageDatabase": {},
|
||||||
|
"aboutDataUsageMisc": "Annat",
|
||||||
|
"@aboutDataUsageMisc": {},
|
||||||
|
"aboutDataUsageExternal": "Externt",
|
||||||
|
"@aboutDataUsageExternal": {},
|
||||||
|
"aboutDataUsageClearCache": "Rensa Cacheminnet",
|
||||||
|
"@aboutDataUsageClearCache": {},
|
||||||
|
"aboutCreditsWorldAtlas1": "Den här appen använder en TopoJSON fil från",
|
||||||
|
"@aboutCreditsWorldAtlas1": {},
|
||||||
|
"aboutCreditsWorldAtlas2": "under ISC Licens.",
|
||||||
|
"@aboutCreditsWorldAtlas2": {},
|
||||||
|
"aboutTranslatorsSectionTitle": "Översättare",
|
||||||
|
"@aboutTranslatorsSectionTitle": {},
|
||||||
|
"aboutLicensesSectionTitle": "Öppen-Källkod Licenser",
|
||||||
|
"@aboutLicensesSectionTitle": {},
|
||||||
|
"aboutLicensesAndroidLibrariesSectionTitle": "Android Biblotek",
|
||||||
|
"@aboutLicensesAndroidLibrariesSectionTitle": {},
|
||||||
|
"aboutLicensesFlutterPluginsSectionTitle": "Flutter Tillägg",
|
||||||
|
"@aboutLicensesFlutterPluginsSectionTitle": {},
|
||||||
|
"collectionPageTitle": "Samling",
|
||||||
|
"@collectionPageTitle": {},
|
||||||
|
"collectionSelectPageTitle": "Välj objekt",
|
||||||
|
"@collectionSelectPageTitle": {},
|
||||||
|
"collectionActionEmptyBin": "Töm papperskorgen",
|
||||||
|
"@collectionActionEmptyBin": {},
|
||||||
|
"collectionActionCopy": "kopiera till album",
|
||||||
|
"@collectionActionCopy": {},
|
||||||
|
"collectionActionMove": "Flytta till album",
|
||||||
|
"@collectionActionMove": {},
|
||||||
|
"viewDialogSortSectionTitle": "Sortera",
|
||||||
|
"@viewDialogSortSectionTitle": {},
|
||||||
|
"viewDialogGroupSectionTitle": "Grupp",
|
||||||
|
"@viewDialogGroupSectionTitle": {},
|
||||||
|
"viewDialogLayoutSectionTitle": "Layout",
|
||||||
|
"@viewDialogLayoutSectionTitle": {},
|
||||||
|
"viewDialogReverseSortOrder": "Omvänd sorteringsordning",
|
||||||
|
"@viewDialogReverseSortOrder": {},
|
||||||
|
"tileLayoutMosaic": "Mosaik",
|
||||||
|
"@tileLayoutMosaic": {},
|
||||||
|
"tileLayoutGrid": "Nät",
|
||||||
|
"@tileLayoutGrid": {},
|
||||||
|
"tileLayoutList": "Lista",
|
||||||
|
"@tileLayoutList": {},
|
||||||
|
"coverDialogTabCover": "Omslag",
|
||||||
|
"@coverDialogTabCover": {},
|
||||||
|
"coverDialogTabApp": "App",
|
||||||
|
"@coverDialogTabApp": {},
|
||||||
|
"coverDialogTabColor": "Färg",
|
||||||
|
"@coverDialogTabColor": {},
|
||||||
|
"appPickDialogTitle": "Välj App",
|
||||||
|
"@appPickDialogTitle": {},
|
||||||
|
"appPickDialogNone": "Igen",
|
||||||
|
"@appPickDialogNone": {},
|
||||||
|
"aboutPageTitle": "Om",
|
||||||
|
"@aboutPageTitle": {},
|
||||||
|
"aboutLinkLicense": "Licens",
|
||||||
|
"@aboutLinkLicense": {},
|
||||||
|
"aboutLinkPolicy": "IntegritetsPolicy",
|
||||||
|
"@aboutLinkPolicy": {},
|
||||||
|
"aboutBugSectionTitle": "FelRapport",
|
||||||
|
"@aboutBugSectionTitle": {},
|
||||||
|
"aboutBugSaveLogInstruction": "Spara appens log till en fil",
|
||||||
|
"@aboutBugSaveLogInstruction": {},
|
||||||
|
"aboutBugCopyInfoInstruction": "Kopiera systemInformation",
|
||||||
|
"@aboutBugCopyInfoInstruction": {},
|
||||||
|
"aboutLicensesShowAllButtonLabel": "Visa alla licenser",
|
||||||
|
"@aboutLicensesShowAllButtonLabel": {},
|
||||||
|
"policyPageTitle": "IntegritetsPolicy",
|
||||||
|
"@policyPageTitle": {},
|
||||||
|
"collectionActionHideTitleSearch": "Göm titelfilter",
|
||||||
|
"@collectionActionHideTitleSearch": {},
|
||||||
|
"collectionActionAddShortcut": "Lägg till genväg",
|
||||||
|
"@collectionActionAddShortcut": {},
|
||||||
|
"collectionActionRescan": "Scanna om",
|
||||||
|
"@collectionActionRescan": {},
|
||||||
|
"collectionActionEdit": "Redigera",
|
||||||
|
"@collectionActionEdit": {},
|
||||||
|
"collectionSearchTitlesHintText": "Sög titlar",
|
||||||
|
"@collectionSearchTitlesHintText": {},
|
||||||
|
"dateYesterday": "Igår",
|
||||||
|
"@dateYesterday": {},
|
||||||
|
"dateThisMonth": "Den här månaden",
|
||||||
|
"@dateThisMonth": {},
|
||||||
|
"collectionDeleteFailureFeedback": "{count, plural, other{Misslyckades med att ta bort {count} objekt}}",
|
||||||
|
"@collectionDeleteFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionCopyFailureFeedback": "{count, plural, =1{Lyckades inte kopiera 1 objekt} other{Lyckades inte kopiera {count} objekt}}",
|
||||||
|
"@collectionCopyFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionMoveFailureFeedback": "{count, plural, =1{Lyckades inte flytta 1 objekt} other{Lyckades inte flytta {count} objekt}}",
|
||||||
|
"@collectionMoveFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionRenameFailureFeedback": "{count, plural, =1{Lyckades inte byta namn på 1 objekt} other{Lyckades inte byta namn på {count} objekt}}",
|
||||||
|
"@collectionRenameFailureFeedback": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectionEmptyFavourites": "Inga favoriter",
|
||||||
|
"@collectionEmptyFavourites": {},
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "Ge åtkomst",
|
||||||
|
"@collectionEmptyGrantAccessButtonLabel": {},
|
||||||
|
"sortOrderLargestFirst": "Störst först",
|
||||||
|
"@sortOrderLargestFirst": {},
|
||||||
|
"sortByDate": "På datum",
|
||||||
|
"@sortByDate": {},
|
||||||
|
"sortOrderSmallestFirst": "Minst först",
|
||||||
|
"@sortOrderSmallestFirst": {},
|
||||||
|
"wallpaperTargetLock": "Låsskärm",
|
||||||
|
"@wallpaperTargetLock": {},
|
||||||
|
"entryActionCast": "Casta",
|
||||||
|
"@entryActionCast": {},
|
||||||
|
"filterTaggedLabel": "Taggad",
|
||||||
|
"@filterTaggedLabel": {},
|
||||||
|
"keepScreenOnNever": "Alldrig",
|
||||||
|
"@keepScreenOnNever": {},
|
||||||
|
"viewerTransitionFade": "Tona ut",
|
||||||
|
"@viewerTransitionFade": {},
|
||||||
|
"wallpaperTargetHomeLock": "Hem och låsskärmar",
|
||||||
|
"@wallpaperTargetHomeLock": {},
|
||||||
|
"missingSystemFilePickerDialogMessage": "systemets filväljare är borta eller avstängd. Var snäll och sätt på den och försök igen.",
|
||||||
|
"@missingSystemFilePickerDialogMessage": {},
|
||||||
|
"renameProcessorCounter": "Räknare",
|
||||||
|
"@renameProcessorCounter": {},
|
||||||
|
"editEntryLocationDialogSetCustom": "Ange anpassad plats",
|
||||||
|
"@editEntryLocationDialogSetCustom": {},
|
||||||
|
"collectionGroupAlbum": "Om album",
|
||||||
|
"@collectionGroupAlbum": {},
|
||||||
|
"collectionGroupMonth": "Om månad",
|
||||||
|
"@collectionGroupMonth": {},
|
||||||
|
"collectionGroupDay": "Om dag",
|
||||||
|
"@collectionGroupDay": {},
|
||||||
|
"collectionGroupNone": "Gruppera inte",
|
||||||
|
"@collectionGroupNone": {},
|
||||||
|
"sectionUnknown": "Okänd",
|
||||||
|
"@sectionUnknown": {},
|
||||||
|
"dateToday": "Idag",
|
||||||
|
"@dateToday": {},
|
||||||
|
"collectionActionSetHome": "Välj som hem",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"collectionEmptyVideos": "Inga Videor",
|
||||||
|
"@collectionEmptyVideos": {},
|
||||||
|
"collectionEmptyImages": "Inga bilder",
|
||||||
|
"@collectionEmptyImages": {},
|
||||||
|
"drawerCollectionMotionPhotos": "Rörelsefoton",
|
||||||
|
"@drawerCollectionMotionPhotos": {},
|
||||||
|
"drawerAboutButton": "Om",
|
||||||
|
"@drawerAboutButton": {},
|
||||||
|
"drawerSettingsButton": "Inställningar",
|
||||||
|
"@drawerSettingsButton": {},
|
||||||
|
"drawerCollectionAll": "Hela samlingen",
|
||||||
|
"@drawerCollectionAll": {},
|
||||||
|
"drawerCollectionFavourites": "Favoriter",
|
||||||
|
"@drawerCollectionFavourites": {},
|
||||||
|
"drawerCollectionImages": "Bilder",
|
||||||
|
"@drawerCollectionImages": {},
|
||||||
|
"drawerCollectionVideos": "Videor",
|
||||||
|
"@drawerCollectionVideos": {},
|
||||||
|
"drawerCollectionAnimated": "Animerad",
|
||||||
|
"@drawerCollectionAnimated": {},
|
||||||
|
"collectionDeselectSectionTooltip": "Avmarkera sektion",
|
||||||
|
"@collectionDeselectSectionTooltip": {},
|
||||||
|
"drawerCollectionPanoramas": "Panoraman",
|
||||||
|
"@drawerCollectionPanoramas": {},
|
||||||
|
"collectionSelectSectionTooltip": "Markera sektion",
|
||||||
|
"@collectionSelectSectionTooltip": {},
|
||||||
|
"drawerCollectionRaws": "Bilder - råformat",
|
||||||
|
"@drawerCollectionRaws": {},
|
||||||
|
"drawerCollectionSphericalVideos": "360° Videor",
|
||||||
|
"@drawerCollectionSphericalVideos": {},
|
||||||
|
"drawerAlbumPage": "Album",
|
||||||
|
"@drawerAlbumPage": {},
|
||||||
|
"drawerCountryPage": "Länder",
|
||||||
|
"@drawerCountryPage": {},
|
||||||
|
"drawerPlacePage": "Platser",
|
||||||
|
"@drawerPlacePage": {},
|
||||||
|
"drawerTagPage": "Taggar",
|
||||||
|
"@drawerTagPage": {},
|
||||||
|
"sortOrderNewestFirst": "Nyast först",
|
||||||
|
"@sortOrderNewestFirst": {},
|
||||||
|
"sortByName": "På namn",
|
||||||
|
"@sortByName": {},
|
||||||
|
"sortByItemCount": "På antal objekt",
|
||||||
|
"@sortByItemCount": {},
|
||||||
|
"sortBySize": "På storlek",
|
||||||
|
"@sortBySize": {},
|
||||||
|
"sortByAlbumFileName": "På album & filnamn",
|
||||||
|
"@sortByAlbumFileName": {},
|
||||||
|
"sortByRating": "På omdöme",
|
||||||
|
"@sortByRating": {},
|
||||||
|
"sortOrderOldestFirst": "Äldst först",
|
||||||
|
"@sortOrderOldestFirst": {},
|
||||||
|
"sortOrderAtoZ": "A till Ö",
|
||||||
|
"@sortOrderAtoZ": {},
|
||||||
|
"sortOrderZtoA": "Ö till A",
|
||||||
|
"@sortOrderZtoA": {},
|
||||||
|
"filePickerUseThisFolder": "Använd den har mappen",
|
||||||
|
"@filePickerUseThisFolder": {},
|
||||||
|
"chipActionUnpin": "Släpp från fästet",
|
||||||
|
"@chipActionUnpin": {}
|
||||||
|
}
|
|
@ -29,7 +29,7 @@
|
||||||
"@hideButtonLabel": {},
|
"@hideButtonLabel": {},
|
||||||
"continueButtonLabel": "DEVAM ET",
|
"continueButtonLabel": "DEVAM ET",
|
||||||
"@continueButtonLabel": {},
|
"@continueButtonLabel": {},
|
||||||
"cancelTooltip": "İptal et",
|
"cancelTooltip": "İptal",
|
||||||
"@cancelTooltip": {},
|
"@cancelTooltip": {},
|
||||||
"changeTooltip": "Değiştir",
|
"changeTooltip": "Değiştir",
|
||||||
"@changeTooltip": {},
|
"@changeTooltip": {},
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
"@chipActionHide": {},
|
"@chipActionHide": {},
|
||||||
"chipActionPin": "Başa sabitle",
|
"chipActionPin": "Başa sabitle",
|
||||||
"@chipActionPin": {},
|
"@chipActionPin": {},
|
||||||
"chipActionUnpin": "Baştan çıkar",
|
"chipActionUnpin": "Sabitlemeyi kaldır",
|
||||||
"@chipActionUnpin": {},
|
"@chipActionUnpin": {},
|
||||||
"chipActionRename": "Yeniden adlandır",
|
"chipActionRename": "Yeniden adlandır",
|
||||||
"@chipActionRename": {},
|
"@chipActionRename": {},
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
"@entryActionInfo": {},
|
"@entryActionInfo": {},
|
||||||
"entryActionRename": "Yeniden adlandır",
|
"entryActionRename": "Yeniden adlandır",
|
||||||
"@entryActionRename": {},
|
"@entryActionRename": {},
|
||||||
"entryActionRestore": "Dışa aktar",
|
"entryActionRestore": "Geri getir",
|
||||||
"@entryActionRestore": {},
|
"@entryActionRestore": {},
|
||||||
"entryActionRotateCCW": "Saat yönünün tersine döndür",
|
"entryActionRotateCCW": "Saat yönünün tersine döndür",
|
||||||
"@entryActionRotateCCW": {},
|
"@entryActionRotateCCW": {},
|
||||||
|
@ -129,11 +129,11 @@
|
||||||
"@entryActionAddFavourite": {},
|
"@entryActionAddFavourite": {},
|
||||||
"entryActionRemoveFavourite": "Favorilerden kaldır",
|
"entryActionRemoveFavourite": "Favorilerden kaldır",
|
||||||
"@entryActionRemoveFavourite": {},
|
"@entryActionRemoveFavourite": {},
|
||||||
"videoActionCaptureFrame": "Çerçeve yakala",
|
"videoActionCaptureFrame": "Kareyi yakala",
|
||||||
"@videoActionCaptureFrame": {},
|
"@videoActionCaptureFrame": {},
|
||||||
"videoActionMute": "Sustur",
|
"videoActionMute": "Sessize al",
|
||||||
"@videoActionMute": {},
|
"@videoActionMute": {},
|
||||||
"videoActionUnmute": "Susturmayı kaldır",
|
"videoActionUnmute": "Sesi aç",
|
||||||
"@videoActionUnmute": {},
|
"@videoActionUnmute": {},
|
||||||
"videoActionPause": "Duraklat",
|
"videoActionPause": "Duraklat",
|
||||||
"@videoActionPause": {},
|
"@videoActionPause": {},
|
||||||
|
@ -143,7 +143,7 @@
|
||||||
"@videoActionReplay10": {},
|
"@videoActionReplay10": {},
|
||||||
"videoActionSkip10": "10 saniye ileri git",
|
"videoActionSkip10": "10 saniye ileri git",
|
||||||
"@videoActionSkip10": {},
|
"@videoActionSkip10": {},
|
||||||
"videoActionSelectStreams": "Parça seç",
|
"videoActionSelectStreams": "Ses parçası seç",
|
||||||
"@videoActionSelectStreams": {},
|
"@videoActionSelectStreams": {},
|
||||||
"videoActionSetSpeed": "Oynatma hızı",
|
"videoActionSetSpeed": "Oynatma hızı",
|
||||||
"@videoActionSetSpeed": {},
|
"@videoActionSetSpeed": {},
|
||||||
|
@ -241,7 +241,7 @@
|
||||||
"@nameConflictStrategySkip": {},
|
"@nameConflictStrategySkip": {},
|
||||||
"keepScreenOnNever": "Asla",
|
"keepScreenOnNever": "Asla",
|
||||||
"@keepScreenOnNever": {},
|
"@keepScreenOnNever": {},
|
||||||
"keepScreenOnViewerOnly": "Yalnızca görüntüleyici sayfası",
|
"keepScreenOnViewerOnly": "Yalnızca görüntüleyici sayfasında",
|
||||||
"@keepScreenOnViewerOnly": {},
|
"@keepScreenOnViewerOnly": {},
|
||||||
"keepScreenOnAlways": "Her zaman",
|
"keepScreenOnAlways": "Her zaman",
|
||||||
"@keepScreenOnAlways": {},
|
"@keepScreenOnAlways": {},
|
||||||
|
@ -367,7 +367,7 @@
|
||||||
"@editEntryDialogCopyFromItem": {},
|
"@editEntryDialogCopyFromItem": {},
|
||||||
"editEntryDateDialogExtractFromTitle": "Başlıktan ayıkla",
|
"editEntryDateDialogExtractFromTitle": "Başlıktan ayıkla",
|
||||||
"@editEntryDateDialogExtractFromTitle": {},
|
"@editEntryDateDialogExtractFromTitle": {},
|
||||||
"editEntryDateDialogShift": "Değişim",
|
"editEntryDateDialogShift": "Değiştir",
|
||||||
"@editEntryDateDialogShift": {},
|
"@editEntryDateDialogShift": {},
|
||||||
"editEntryDateDialogSourceFileModifiedDate": "Dosya değiştirilme tarihi",
|
"editEntryDateDialogSourceFileModifiedDate": "Dosya değiştirilme tarihi",
|
||||||
"@editEntryDateDialogSourceFileModifiedDate": {},
|
"@editEntryDateDialogSourceFileModifiedDate": {},
|
||||||
|
@ -641,7 +641,7 @@
|
||||||
"@tagEmpty": {},
|
"@tagEmpty": {},
|
||||||
"binPageTitle": "Geri Dönüşüm Kutusu",
|
"binPageTitle": "Geri Dönüşüm Kutusu",
|
||||||
"@binPageTitle": {},
|
"@binPageTitle": {},
|
||||||
"searchCollectionFieldHint": "Koleksiyonu ara",
|
"searchCollectionFieldHint": "Koleksiyonda ara",
|
||||||
"@searchCollectionFieldHint": {},
|
"@searchCollectionFieldHint": {},
|
||||||
"searchRecentSectionTitle": "Yakın zamanda",
|
"searchRecentSectionTitle": "Yakın zamanda",
|
||||||
"@searchRecentSectionTitle": {},
|
"@searchRecentSectionTitle": {},
|
||||||
|
@ -1169,7 +1169,7 @@
|
||||||
"@settingsWidgetDisplayedItem": {},
|
"@settingsWidgetDisplayedItem": {},
|
||||||
"settingsSubtitleThemeTextPositionDialogTitle": "Metin Konumu",
|
"settingsSubtitleThemeTextPositionDialogTitle": "Metin Konumu",
|
||||||
"@settingsSubtitleThemeTextPositionDialogTitle": {},
|
"@settingsSubtitleThemeTextPositionDialogTitle": {},
|
||||||
"filterNoAddressLabel": "Adres yok",
|
"filterNoAddressLabel": "Adressiz",
|
||||||
"@filterNoAddressLabel": {},
|
"@filterNoAddressLabel": {},
|
||||||
"filterAspectRatioLandscapeLabel": "Yatay",
|
"filterAspectRatioLandscapeLabel": "Yatay",
|
||||||
"@filterAspectRatioLandscapeLabel": {},
|
"@filterAspectRatioLandscapeLabel": {},
|
||||||
|
@ -1206,5 +1206,165 @@
|
||||||
"tooManyItemsErrorDialogMessage": "Daha az ögeyle tekrar deneyin.",
|
"tooManyItemsErrorDialogMessage": "Daha az ögeyle tekrar deneyin.",
|
||||||
"@tooManyItemsErrorDialogMessage": {},
|
"@tooManyItemsErrorDialogMessage": {},
|
||||||
"settingsVideoGestureVerticalDragBrightnessVolume": "Parlaklığı/ses seviyesini ayarlamak için yukarı veya aşağı kaydırın",
|
"settingsVideoGestureVerticalDragBrightnessVolume": "Parlaklığı/ses seviyesini ayarlamak için yukarı veya aşağı kaydırın",
|
||||||
"@settingsVideoGestureVerticalDragBrightnessVolume": {}
|
"@settingsVideoGestureVerticalDragBrightnessVolume": {},
|
||||||
|
"patternDialogEnter": "Deseninizi çizin",
|
||||||
|
"@patternDialogEnter": {},
|
||||||
|
"saveCopyButtonLabel": "KOPYAYI KAYDET",
|
||||||
|
"@saveCopyButtonLabel": {},
|
||||||
|
"applyTooltip": "Uygula",
|
||||||
|
"@applyTooltip": {},
|
||||||
|
"chipActionConfigureVault": "Kilitli albüm ayarları",
|
||||||
|
"@chipActionConfigureVault": {},
|
||||||
|
"viewerActionLock": "Kontrolleri kilitle",
|
||||||
|
"@viewerActionLock": {},
|
||||||
|
"viewerActionUnlock": "Kontrollerin kilidini aç",
|
||||||
|
"@viewerActionUnlock": {},
|
||||||
|
"editorTransformRotate": "Döndür",
|
||||||
|
"@editorTransformRotate": {},
|
||||||
|
"editorTransformCrop": "Kırp",
|
||||||
|
"@editorTransformCrop": {},
|
||||||
|
"editorActionTransform": "Dönüştür",
|
||||||
|
"@editorActionTransform": {},
|
||||||
|
"cropAspectRatioFree": "Özgür",
|
||||||
|
"@cropAspectRatioFree": {},
|
||||||
|
"cropAspectRatioOriginal": "Orijinal",
|
||||||
|
"@cropAspectRatioOriginal": {},
|
||||||
|
"cropAspectRatioSquare": "Kare",
|
||||||
|
"@cropAspectRatioSquare": {},
|
||||||
|
"settingsCollectionBurstPatternsTile": "Seri fotoğraf çekme biçimleri",
|
||||||
|
"@settingsCollectionBurstPatternsTile": {},
|
||||||
|
"vaultDialogLockTypeLabel": "Kilit türü",
|
||||||
|
"@vaultDialogLockTypeLabel": {},
|
||||||
|
"chipActionShowCountryStates": "Eyaletleri göster",
|
||||||
|
"@chipActionShowCountryStates": {},
|
||||||
|
"aboutDataUsageSectionTitle": "Kullanılan Alan",
|
||||||
|
"@aboutDataUsageSectionTitle": {},
|
||||||
|
"aboutDataUsageData": "Veriler",
|
||||||
|
"@aboutDataUsageData": {},
|
||||||
|
"aboutDataUsageInternal": "Dahili",
|
||||||
|
"@aboutDataUsageInternal": {},
|
||||||
|
"aboutDataUsageExternal": "Harici",
|
||||||
|
"@aboutDataUsageExternal": {},
|
||||||
|
"drawerPlacePage": "Yerler",
|
||||||
|
"@drawerPlacePage": {},
|
||||||
|
"settingsAskEverytime": "Her seferinde sor",
|
||||||
|
"@settingsAskEverytime": {},
|
||||||
|
"settingsVideoBackgroundModeDialogTitle": "Arkaplan Modu",
|
||||||
|
"@settingsVideoBackgroundModeDialogTitle": {},
|
||||||
|
"maxBrightnessNever": "Asla",
|
||||||
|
"@maxBrightnessNever": {},
|
||||||
|
"maxBrightnessAlways": "Her zaman",
|
||||||
|
"@maxBrightnessAlways": {},
|
||||||
|
"videoResumptionModeNever": "Asla",
|
||||||
|
"@videoResumptionModeNever": {},
|
||||||
|
"videoResumptionModeAlways": "Her zaman",
|
||||||
|
"@videoResumptionModeAlways": {},
|
||||||
|
"exportEntryDialogQuality": "Kalite",
|
||||||
|
"@exportEntryDialogQuality": {},
|
||||||
|
"settingsVideoPlaybackTile": "Oynatma",
|
||||||
|
"@settingsVideoPlaybackTile": {},
|
||||||
|
"settingsVideoPlaybackPageTitle": "Oynatma",
|
||||||
|
"@settingsVideoPlaybackPageTitle": {},
|
||||||
|
"settingsVideoResumptionModeTile": "Oynatmaya devam et",
|
||||||
|
"@settingsVideoResumptionModeTile": {},
|
||||||
|
"settingsVideoResumptionModeDialogTitle": "Oynatmaya Devam Et",
|
||||||
|
"@settingsVideoResumptionModeDialogTitle": {},
|
||||||
|
"tagEditorDiscardDialogMessage": "Değişikliklerden vazgeçmek istiyor musunuz?",
|
||||||
|
"@tagEditorDiscardDialogMessage": {},
|
||||||
|
"chipActionGoToPlacePage": "Yerler'de Göster",
|
||||||
|
"@chipActionGoToPlacePage": {},
|
||||||
|
"chipActionLock": "Kilitle",
|
||||||
|
"@chipActionLock": {},
|
||||||
|
"chipActionCreateVault": "Kilitli albüm oluştur",
|
||||||
|
"@chipActionCreateVault": {},
|
||||||
|
"albumTierVaults": "Kilitli albümler",
|
||||||
|
"@albumTierVaults": {},
|
||||||
|
"vaultLockTypePassword": "Şifre",
|
||||||
|
"@vaultLockTypePassword": {},
|
||||||
|
"overlayHistogramNone": "Hiçbiri",
|
||||||
|
"@overlayHistogramNone": {},
|
||||||
|
"overlayHistogramRGB": "RGB",
|
||||||
|
"@overlayHistogramRGB": {},
|
||||||
|
"widgetTapUpdateWidget": "Widget'i güncelle",
|
||||||
|
"@widgetTapUpdateWidget": {},
|
||||||
|
"configureVaultDialogTitle": "Kilitli Albüm Ayarları",
|
||||||
|
"@configureVaultDialogTitle": {},
|
||||||
|
"aboutDataUsageCache": "Önbellek",
|
||||||
|
"@aboutDataUsageCache": {},
|
||||||
|
"aboutDataUsageDatabase": "Veritabanı",
|
||||||
|
"@aboutDataUsageDatabase": {},
|
||||||
|
"aboutDataUsageMisc": "Diğer",
|
||||||
|
"@aboutDataUsageMisc": {},
|
||||||
|
"settingsViewerShowHistogram": "Çubuk grafiğini göster",
|
||||||
|
"@settingsViewerShowHistogram": {},
|
||||||
|
"authenticateToUnlockVault": "Albümün kilidini açmak için kimliğinizi doğrulayın",
|
||||||
|
"@authenticateToUnlockVault": {},
|
||||||
|
"vaultBinUsageDialogMessage": "Bazı kilitli albümler çöp kutusunu kullanıyor.",
|
||||||
|
"@vaultBinUsageDialogMessage": {},
|
||||||
|
"patternDialogConfirm": "Deseninizi tekrar çizin",
|
||||||
|
"@patternDialogConfirm": {},
|
||||||
|
"authenticateToConfigureVault": "Kilitli albümü ayarlamak için kimliğinizi doğrulayın",
|
||||||
|
"@authenticateToConfigureVault": {},
|
||||||
|
"statePageTitle": "Eyaletler",
|
||||||
|
"@statePageTitle": {},
|
||||||
|
"stateEmpty": "Hiç eyalet bulunamadı",
|
||||||
|
"@stateEmpty": {},
|
||||||
|
"searchStatesSectionTitle": "Eyaletler",
|
||||||
|
"@searchStatesSectionTitle": {},
|
||||||
|
"settingsConfirmationVaultDataLoss": "Kilitli albüm veri kaybı uyarısını göster",
|
||||||
|
"@settingsConfirmationVaultDataLoss": {},
|
||||||
|
"settingsCollectionBurstPatternsNone": "Hiçbiri",
|
||||||
|
"@settingsCollectionBurstPatternsNone": {},
|
||||||
|
"settingsDisablingBinWarningDialogMessage": "Çöp kutusundaki ögeler sonsuza dek silinecektir.",
|
||||||
|
"@settingsDisablingBinWarningDialogMessage": {},
|
||||||
|
"lengthUnitPercent": "%",
|
||||||
|
"@lengthUnitPercent": {},
|
||||||
|
"newVaultDialogTitle": "Kilitli Albüm Oluştur",
|
||||||
|
"@newVaultDialogTitle": {},
|
||||||
|
"passwordDialogConfirm": "Şifrenizi tekrar girin",
|
||||||
|
"@passwordDialogConfirm": {},
|
||||||
|
"collectionActionSetHome": "Ana ekran olarak ayarla",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "Kişisel koleksiyon",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"statsTopStatesSectionTitle": "Baş Eyaletler",
|
||||||
|
"@statsTopStatesSectionTitle": {},
|
||||||
|
"pinDialogEnter": "PIN girin",
|
||||||
|
"@pinDialogEnter": {},
|
||||||
|
"vaultDialogLockModeWhenScreenOff": "Ekran kapatıldığında kilitle",
|
||||||
|
"@vaultDialogLockModeWhenScreenOff": {},
|
||||||
|
"pinDialogConfirm": "PIN'inizi tekrar girin",
|
||||||
|
"@pinDialogConfirm": {},
|
||||||
|
"exportEntryDialogWriteMetadata": "Metaverileri ekle",
|
||||||
|
"@exportEntryDialogWriteMetadata": {},
|
||||||
|
"settingsVideoEnablePip": "Resim içinde resim",
|
||||||
|
"@settingsVideoEnablePip": {},
|
||||||
|
"vaultLockTypePattern": "Desen",
|
||||||
|
"@vaultLockTypePattern": {},
|
||||||
|
"aboutDataUsageClearCache": "Önbelleği Temizle",
|
||||||
|
"@aboutDataUsageClearCache": {},
|
||||||
|
"placeEmpty": "Hiç yer bulunamadı",
|
||||||
|
"@placeEmpty": {},
|
||||||
|
"overlayHistogramLuminance": "Parlaklık",
|
||||||
|
"@overlayHistogramLuminance": {},
|
||||||
|
"lengthUnitPixel": "px",
|
||||||
|
"@lengthUnitPixel": {},
|
||||||
|
"passwordDialogEnter": "Şifre girin",
|
||||||
|
"@passwordDialogEnter": {},
|
||||||
|
"placePageTitle": "Yerler",
|
||||||
|
"@placePageTitle": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "HDR simgesini göster",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"settingsVideoBackgroundMode": "Arkaplan modu",
|
||||||
|
"@settingsVideoBackgroundMode": {},
|
||||||
|
"tagPlaceholderState": "Eyalet",
|
||||||
|
"@tagPlaceholderState": {},
|
||||||
|
"vaultLockTypePin": "PIN",
|
||||||
|
"@vaultLockTypePin": {},
|
||||||
|
"entryActionCast": "Yansıt",
|
||||||
|
"@entryActionCast": {},
|
||||||
|
"newVaultWarningDialogMessage": "Kilitli albümlere yalnızca bu uygulama erişebilir, başka herhangi bir uygulama erişemez.\n\nBu uygulamayı kaldırır veya verilerini silerseniz kilitli albümlerdeki bütün ögeleri kaybedersiniz.",
|
||||||
|
"@newVaultWarningDialogMessage": {},
|
||||||
|
"castDialogTitle": "Yakındaki Cihazlar",
|
||||||
|
"@castDialogTitle": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1518,5 +1518,11 @@
|
||||||
"entryActionCast": "Трансляція",
|
"entryActionCast": "Трансляція",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "Пристрої трансляції",
|
"castDialogTitle": "Пристрої трансляції",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Показати іконку HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"setHomeCustomCollection": "Власна колекція",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"collectionActionSetHome": "Встановити як головну",
|
||||||
|
"@collectionActionSetHome": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@
|
||||||
"@filterNoLocationLabel": {},
|
"@filterNoLocationLabel": {},
|
||||||
"videoActionPlay": "Phát",
|
"videoActionPlay": "Phát",
|
||||||
"@videoActionPlay": {},
|
"@videoActionPlay": {},
|
||||||
"entryActionSetAs": "Thiết lập như",
|
"entryActionSetAs": "Đặt làm",
|
||||||
"@entryActionSetAs": {},
|
"@entryActionSetAs": {},
|
||||||
"filterLocatedLabel": "Đã định vị",
|
"filterLocatedLabel": "Đã định vị",
|
||||||
"@filterLocatedLabel": {},
|
"@filterLocatedLabel": {},
|
||||||
|
@ -1518,5 +1518,11 @@
|
||||||
"entryActionCast": "Truyền",
|
"entryActionCast": "Truyền",
|
||||||
"@entryActionCast": {},
|
"@entryActionCast": {},
|
||||||
"castDialogTitle": "Thiết bị truyền",
|
"castDialogTitle": "Thiết bị truyền",
|
||||||
"@castDialogTitle": {}
|
"@castDialogTitle": {},
|
||||||
|
"setHomeCustomCollection": "Bộ sưu tập tùy chỉnh",
|
||||||
|
"@setHomeCustomCollection": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "Hiển thị biểu tượng HDR",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"collectionActionSetHome": "Đặt làm nhà",
|
||||||
|
"@collectionActionSetHome": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
"@sourceStateLoading": {},
|
"@sourceStateLoading": {},
|
||||||
"sourceStateCataloguing": "正在进行编目",
|
"sourceStateCataloguing": "正在进行编目",
|
||||||
"@sourceStateCataloguing": {},
|
"@sourceStateCataloguing": {},
|
||||||
"sourceStateLocatingCountries": "正在定位国家",
|
"sourceStateLocatingCountries": "正在定位地区",
|
||||||
"@sourceStateLocatingCountries": {},
|
"@sourceStateLocatingCountries": {},
|
||||||
"sourceStateLocatingPlaces": "正在定位地点",
|
"sourceStateLocatingPlaces": "正在定位地点",
|
||||||
"@sourceStateLocatingPlaces": {},
|
"@sourceStateLocatingPlaces": {},
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
"@chipActionDelete": {},
|
"@chipActionDelete": {},
|
||||||
"chipActionGoToAlbumPage": "在相册中显示",
|
"chipActionGoToAlbumPage": "在相册中显示",
|
||||||
"@chipActionGoToAlbumPage": {},
|
"@chipActionGoToAlbumPage": {},
|
||||||
"chipActionGoToCountryPage": "在国家中显示",
|
"chipActionGoToCountryPage": "在地区中显示",
|
||||||
"@chipActionGoToCountryPage": {},
|
"@chipActionGoToCountryPage": {},
|
||||||
"chipActionGoToTagPage": "在标签中显示",
|
"chipActionGoToTagPage": "在标签中显示",
|
||||||
"@chipActionGoToTagPage": {},
|
"@chipActionGoToTagPage": {},
|
||||||
|
@ -625,7 +625,7 @@
|
||||||
"@drawerCollectionSphericalVideos": {},
|
"@drawerCollectionSphericalVideos": {},
|
||||||
"drawerAlbumPage": "相册",
|
"drawerAlbumPage": "相册",
|
||||||
"@drawerAlbumPage": {},
|
"@drawerAlbumPage": {},
|
||||||
"drawerCountryPage": "国家",
|
"drawerCountryPage": "地区",
|
||||||
"@drawerCountryPage": {},
|
"@drawerCountryPage": {},
|
||||||
"drawerTagPage": "标签",
|
"drawerTagPage": "标签",
|
||||||
"@drawerTagPage": {},
|
"@drawerTagPage": {},
|
||||||
|
@ -693,9 +693,9 @@
|
||||||
"@createAlbumButtonLabel": {},
|
"@createAlbumButtonLabel": {},
|
||||||
"newFilterBanner": "新的",
|
"newFilterBanner": "新的",
|
||||||
"@newFilterBanner": {},
|
"@newFilterBanner": {},
|
||||||
"countryPageTitle": "国家",
|
"countryPageTitle": "地区",
|
||||||
"@countryPageTitle": {},
|
"@countryPageTitle": {},
|
||||||
"countryEmpty": "无国家",
|
"countryEmpty": "无地区",
|
||||||
"@countryEmpty": {},
|
"@countryEmpty": {},
|
||||||
"tagPageTitle": "标签",
|
"tagPageTitle": "标签",
|
||||||
"@tagPageTitle": {},
|
"@tagPageTitle": {},
|
||||||
|
@ -711,7 +711,7 @@
|
||||||
"@searchDateSectionTitle": {},
|
"@searchDateSectionTitle": {},
|
||||||
"searchAlbumsSectionTitle": "相册",
|
"searchAlbumsSectionTitle": "相册",
|
||||||
"@searchAlbumsSectionTitle": {},
|
"@searchAlbumsSectionTitle": {},
|
||||||
"searchCountriesSectionTitle": "国家",
|
"searchCountriesSectionTitle": "地区",
|
||||||
"@searchCountriesSectionTitle": {},
|
"@searchCountriesSectionTitle": {},
|
||||||
"searchPlacesSectionTitle": "地点",
|
"searchPlacesSectionTitle": "地点",
|
||||||
"@searchPlacesSectionTitle": {},
|
"@searchPlacesSectionTitle": {},
|
||||||
|
@ -1023,7 +1023,7 @@
|
||||||
"@statsPageTitle": {},
|
"@statsPageTitle": {},
|
||||||
"statsWithGps": "{count, plural, other{{count} 项带位置信息}}",
|
"statsWithGps": "{count, plural, other{{count} 项带位置信息}}",
|
||||||
"@statsWithGps": {},
|
"@statsWithGps": {},
|
||||||
"statsTopCountriesSectionTitle": "热门国家",
|
"statsTopCountriesSectionTitle": "热门地区",
|
||||||
"@statsTopCountriesSectionTitle": {},
|
"@statsTopCountriesSectionTitle": {},
|
||||||
"statsTopPlacesSectionTitle": "热门地点",
|
"statsTopPlacesSectionTitle": "热门地点",
|
||||||
"@statsTopPlacesSectionTitle": {},
|
"@statsTopPlacesSectionTitle": {},
|
||||||
|
@ -1197,7 +1197,7 @@
|
||||||
"@chipActionConfigureVault": {},
|
"@chipActionConfigureVault": {},
|
||||||
"chipActionCreateVault": "创建保险库",
|
"chipActionCreateVault": "创建保险库",
|
||||||
"@chipActionCreateVault": {},
|
"@chipActionCreateVault": {},
|
||||||
"chipActionShowCountryStates": "显示状态",
|
"chipActionShowCountryStates": "显示区域",
|
||||||
"@chipActionShowCountryStates": {},
|
"@chipActionShowCountryStates": {},
|
||||||
"viewerActionLock": "锁定查看器",
|
"viewerActionLock": "锁定查看器",
|
||||||
"@viewerActionLock": {},
|
"@viewerActionLock": {},
|
||||||
|
@ -1255,7 +1255,7 @@
|
||||||
"@vaultLockTypePattern": {},
|
"@vaultLockTypePattern": {},
|
||||||
"albumTierVaults": "保险库",
|
"albumTierVaults": "保险库",
|
||||||
"@albumTierVaults": {},
|
"@albumTierVaults": {},
|
||||||
"settingsVideoResumptionModeTile": "恢复回放",
|
"settingsVideoResumptionModeTile": "恢复播放",
|
||||||
"@settingsVideoResumptionModeTile": {},
|
"@settingsVideoResumptionModeTile": {},
|
||||||
"vaultBinUsageDialogMessage": "有些保险库正在使用资源回收站。",
|
"vaultBinUsageDialogMessage": "有些保险库正在使用资源回收站。",
|
||||||
"@vaultBinUsageDialogMessage": {},
|
"@vaultBinUsageDialogMessage": {},
|
||||||
|
@ -1275,9 +1275,9 @@
|
||||||
"@editorTransformCrop": {},
|
"@editorTransformCrop": {},
|
||||||
"filterTaggedLabel": "已标记",
|
"filterTaggedLabel": "已标记",
|
||||||
"@filterTaggedLabel": {},
|
"@filterTaggedLabel": {},
|
||||||
"statePageTitle": "地区",
|
"statePageTitle": "区域",
|
||||||
"@statePageTitle": {},
|
"@statePageTitle": {},
|
||||||
"settingsVideoResumptionModeDialogTitle": "恢复回放",
|
"settingsVideoResumptionModeDialogTitle": "恢复播放",
|
||||||
"@settingsVideoResumptionModeDialogTitle": {},
|
"@settingsVideoResumptionModeDialogTitle": {},
|
||||||
"settingsVideoBackgroundMode": "后台模式",
|
"settingsVideoBackgroundMode": "后台模式",
|
||||||
"@settingsVideoBackgroundMode": {},
|
"@settingsVideoBackgroundMode": {},
|
||||||
|
@ -1305,9 +1305,9 @@
|
||||||
"@newVaultWarningDialogMessage": {},
|
"@newVaultWarningDialogMessage": {},
|
||||||
"settingsDisablingBinWarningDialogMessage": "回收站中的项目将被永久删除。",
|
"settingsDisablingBinWarningDialogMessage": "回收站中的项目将被永久删除。",
|
||||||
"@settingsDisablingBinWarningDialogMessage": {},
|
"@settingsDisablingBinWarningDialogMessage": {},
|
||||||
"statsTopStatesSectionTitle": "最多项的地区",
|
"statsTopStatesSectionTitle": "最多项的区域",
|
||||||
"@statsTopStatesSectionTitle": {},
|
"@statsTopStatesSectionTitle": {},
|
||||||
"settingsVideoPlaybackPageTitle": "回放",
|
"settingsVideoPlaybackPageTitle": "播放",
|
||||||
"@settingsVideoPlaybackPageTitle": {},
|
"@settingsVideoPlaybackPageTitle": {},
|
||||||
"filterLocatedLabel": "位于",
|
"filterLocatedLabel": "位于",
|
||||||
"@filterLocatedLabel": {},
|
"@filterLocatedLabel": {},
|
||||||
|
@ -1337,9 +1337,9 @@
|
||||||
"@cropAspectRatioOriginal": {},
|
"@cropAspectRatioOriginal": {},
|
||||||
"configureVaultDialogTitle": "设置保险库",
|
"configureVaultDialogTitle": "设置保险库",
|
||||||
"@configureVaultDialogTitle": {},
|
"@configureVaultDialogTitle": {},
|
||||||
"searchStatesSectionTitle": "地区",
|
"searchStatesSectionTitle": "区域",
|
||||||
"@searchStatesSectionTitle": {},
|
"@searchStatesSectionTitle": {},
|
||||||
"stateEmpty": "没有地区",
|
"stateEmpty": "没有区域",
|
||||||
"@stateEmpty": {},
|
"@stateEmpty": {},
|
||||||
"aboutDataUsageData": "数据",
|
"aboutDataUsageData": "数据",
|
||||||
"@aboutDataUsageData": {},
|
"@aboutDataUsageData": {},
|
||||||
|
@ -1353,12 +1353,18 @@
|
||||||
"@newVaultDialogTitle": {},
|
"@newVaultDialogTitle": {},
|
||||||
"settingsVideoBackgroundModeDialogTitle": "后台模式",
|
"settingsVideoBackgroundModeDialogTitle": "后台模式",
|
||||||
"@settingsVideoBackgroundModeDialogTitle": {},
|
"@settingsVideoBackgroundModeDialogTitle": {},
|
||||||
"tagPlaceholderState": "地区",
|
"tagPlaceholderState": "区域",
|
||||||
"@tagPlaceholderState": {},
|
"@tagPlaceholderState": {},
|
||||||
"settingsViewerShowHistogram": "显示直方图",
|
"settingsViewerShowHistogram": "显示直方图",
|
||||||
"@settingsViewerShowHistogram": {},
|
"@settingsViewerShowHistogram": {},
|
||||||
"settingsVideoPlaybackTile": "回放",
|
"settingsVideoPlaybackTile": "播放",
|
||||||
"@settingsVideoPlaybackTile": {},
|
"@settingsVideoPlaybackTile": {},
|
||||||
"exportEntryDialogWriteMetadata": "写入元数据",
|
"exportEntryDialogWriteMetadata": "写入元数据",
|
||||||
"@exportEntryDialogWriteMetadata": {}
|
"@exportEntryDialogWriteMetadata": {},
|
||||||
|
"settingsThumbnailShowHdrIcon": "显示 HDR 图标",
|
||||||
|
"@settingsThumbnailShowHdrIcon": {},
|
||||||
|
"collectionActionSetHome": "设置为首页",
|
||||||
|
"@collectionActionSetHome": {},
|
||||||
|
"setHomeCustomCollection": "自定义媒体集",
|
||||||
|
"@setHomeCustomCollection": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Contributors {
|
||||||
Contributor('Tijolinho', 'pedrohenrique29.alfenas@gmail.com'),
|
Contributor('Tijolinho', 'pedrohenrique29.alfenas@gmail.com'),
|
||||||
Contributor('Piotr K', '1337.kelt@gmail.com'),
|
Contributor('Piotr K', '1337.kelt@gmail.com'),
|
||||||
Contributor('rehork', 'cooky@e.email'),
|
Contributor('rehork', 'cooky@e.email'),
|
||||||
Contributor('Eric', 'hamburger2048@users.noreply.hosted.weblate.org'),
|
Contributor('Eric', 'zxmegaxqug@hldrive.com'), // @hamburger2048 / 大王叫我来巡山
|
||||||
Contributor('Aitor Salaberria', 'trslbrr@gmail.com'),
|
Contributor('Aitor Salaberria', 'trslbrr@gmail.com'),
|
||||||
Contributor('Felipe Nogueira', 'contato.fnog@gmail.com'),
|
Contributor('Felipe Nogueira', 'contato.fnog@gmail.com'),
|
||||||
Contributor('kaajjo', 'claymanoff@gmail.com'),
|
Contributor('kaajjo', 'claymanoff@gmail.com'),
|
||||||
|
@ -67,11 +67,15 @@ class Contributors {
|
||||||
Contributor('Reza Almanda', 'rezaalmanda27@gmail.com'),
|
Contributor('Reza Almanda', 'rezaalmanda27@gmail.com'),
|
||||||
Contributor('Sveinn í Felli', 'sv1@fellsnet.is'),
|
Contributor('Sveinn í Felli', 'sv1@fellsnet.is'),
|
||||||
Contributor('Henning Bunk', 'henningtbunk@gmail.com'),
|
Contributor('Henning Bunk', 'henningtbunk@gmail.com'),
|
||||||
Contributor('SAMIRAH AIL', 'samiratalzahrani@gmail.com'),
|
Contributor('Samirah Ail', 'samiratalzahrani@gmail.com'),
|
||||||
Contributor('Salih Ail', 'rrrfff444@gmail.com'),
|
Contributor('Salih Ail', 'rrrfff444@gmail.com'),
|
||||||
Contributor('nasreddineloukriz', 'nasreddineloukriz@gmail.com'),
|
Contributor('nasreddineloukriz', 'nasreddineloukriz@gmail.com'),
|
||||||
Contributor('Mohamed Zeroug', 'mzeroug19@gmail.com'),
|
Contributor('Mohamed Zeroug', 'mzeroug19@gmail.com'),
|
||||||
Contributor('ssantos', 'ssantos@web.de'),
|
Contributor('ssantos', 'ssantos@web.de'),
|
||||||
|
Contributor('Сергій', 'sergiy.goncharuk.1@gmail.com'),
|
||||||
|
Contributor('v1s7', 'v1s7@users.noreply.hosted.weblate.org'),
|
||||||
|
Contributor('fuzfyy', 'egeozce35@gmail.com'),
|
||||||
|
Contributor('minh', 'teaminh@skiff.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
|
||||||
|
@ -86,7 +90,9 @@ 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('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('Nattapong K', 'mixer5056@gmail.com'), // Thai
|
// Contributor('Nattapong K', 'mixer5056@gmail.com'), // Thai
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,9 +74,9 @@ class Dependencies {
|
||||||
sourceUrl: 'https://github.com/material-foundation/flutter-packages/tree/main/packages/dynamic_color',
|
sourceUrl: 'https://github.com/material-foundation/flutter-packages/tree/main/packages/dynamic_color',
|
||||||
),
|
),
|
||||||
Dependency(
|
Dependency(
|
||||||
name: 'FFmpegKit',
|
name: 'FFmpegKit (Aves fork)',
|
||||||
license: lgpl3,
|
license: lgpl3,
|
||||||
sourceUrl: 'https://github.com/arthenica/ffmpeg-kit',
|
sourceUrl: 'https://github.com/deckerst/ffmpeg-kit',
|
||||||
),
|
),
|
||||||
Dependency(
|
Dependency(
|
||||||
name: 'Floating',
|
name: 'Floating',
|
||||||
|
@ -207,9 +207,9 @@ class Dependencies {
|
||||||
|
|
||||||
static const List<Dependency> flutterPackages = [
|
static const List<Dependency> flutterPackages = [
|
||||||
Dependency(
|
Dependency(
|
||||||
name: 'Charts (fzyzcjy fork)',
|
name: 'Charts (Aves fork)',
|
||||||
license: apache2,
|
license: apache2,
|
||||||
sourceUrl: 'https://github.com/fzyzcjy/charts',
|
sourceUrl: 'https://github.com/deckerst/flutter_google_charts',
|
||||||
),
|
),
|
||||||
Dependency(
|
Dependency(
|
||||||
name: 'Custom rounded rectangle border',
|
name: 'Custom rounded rectangle border',
|
||||||
|
@ -271,7 +271,7 @@ class Dependencies {
|
||||||
Dependency(
|
Dependency(
|
||||||
name: 'Panorama (Aves fork)',
|
name: 'Panorama (Aves fork)',
|
||||||
license: apache2,
|
license: apache2,
|
||||||
sourceUrl: 'https://github.com/zesage/panorama',
|
sourceUrl: 'https://github.com/deckerst/aves_panorama',
|
||||||
),
|
),
|
||||||
Dependency(
|
Dependency(
|
||||||
name: 'Pattern Lock',
|
name: 'Pattern Lock',
|
||||||
|
|
|
@ -20,28 +20,6 @@ class AppSupport {
|
||||||
|
|
||||||
static bool canDecode(String mimeType) => !undecodableImages.contains(mimeType);
|
static bool canDecode(String mimeType) => !undecodableImages.contains(mimeType);
|
||||||
|
|
||||||
// Android's `BitmapRegionDecoder` documentation states that "only the JPEG and PNG formats are supported"
|
|
||||||
// but in practice (tested on API 25, 27, 29), it successfully decodes the formats listed below,
|
|
||||||
// and it actually fails to decode GIF, DNG and animated WEBP. Other formats were not tested.
|
|
||||||
static bool _supportedByBitmapRegionDecoder(String mimeType) => [
|
|
||||||
MimeTypes.heic,
|
|
||||||
MimeTypes.heif,
|
|
||||||
MimeTypes.jpeg,
|
|
||||||
MimeTypes.png,
|
|
||||||
MimeTypes.webp,
|
|
||||||
MimeTypes.arw,
|
|
||||||
MimeTypes.cr2,
|
|
||||||
MimeTypes.nef,
|
|
||||||
MimeTypes.nrw,
|
|
||||||
MimeTypes.orf,
|
|
||||||
MimeTypes.pef,
|
|
||||||
MimeTypes.raf,
|
|
||||||
MimeTypes.rw2,
|
|
||||||
MimeTypes.srw,
|
|
||||||
].contains(mimeType);
|
|
||||||
|
|
||||||
static bool canDecodeRegion(String mimeType) => _supportedByBitmapRegionDecoder(mimeType) || mimeType == MimeTypes.tiff;
|
|
||||||
|
|
||||||
// `exifinterface` v1.3.3 declared support for DNG, but it strips non-standard Exif tags when saving attributes,
|
// `exifinterface` v1.3.3 declared support for DNG, but it strips non-standard Exif tags when saving attributes,
|
||||||
// and DNG requires DNG-specific tags saved along standard Exif. So it was actually breaking DNG files.
|
// and DNG requires DNG-specific tags saved along standard Exif. So it was actually breaking DNG files.
|
||||||
static bool canEditExif(String mimeType) {
|
static bool canEditExif(String mimeType) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ extension ExtraAvesEntryProps on AvesEntry {
|
||||||
|
|
||||||
// size
|
// size
|
||||||
|
|
||||||
bool get useTiles => canDecodeRegion && (width > 4096 || height > 4096);
|
bool get useTiles => (width > 4096 || height > 4096) && !isAnimated;
|
||||||
|
|
||||||
bool get isSized => width > 0 && height > 0;
|
bool get isSized => width > 0 && height > 0;
|
||||||
|
|
||||||
|
@ -127,8 +127,6 @@ extension ExtraAvesEntryProps on AvesEntry {
|
||||||
|
|
||||||
bool get canDecode => AppSupport.canDecode(mimeType);
|
bool get canDecode => AppSupport.canDecode(mimeType);
|
||||||
|
|
||||||
bool get canDecodeRegion => AppSupport.canDecodeRegion(mimeType) && !isAnimated;
|
|
||||||
|
|
||||||
bool get canEditExif => AppSupport.canEditExif(mimeType);
|
bool get canEditExif => AppSupport.canEditExif(mimeType);
|
||||||
|
|
||||||
bool get canEditIptc => AppSupport.canEditIptc(mimeType);
|
bool get canEditIptc => AppSupport.canEditIptc(mimeType);
|
||||||
|
|
|
@ -15,6 +15,11 @@ class LocationFilter extends CoveredCollectionFilter {
|
||||||
late final String? _code;
|
late final String? _code;
|
||||||
late final EntryFilter _test;
|
late final EntryFilter _test;
|
||||||
|
|
||||||
|
static final unlocated = LocationFilter(LocationLevel.place, '');
|
||||||
|
static final located = unlocated.reverse();
|
||||||
|
|
||||||
|
bool get _isUnlocated => _location.isEmpty;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [level, _location, _code, reversed];
|
List<Object?> get props => [level, _location, _code, reversed];
|
||||||
|
|
||||||
|
@ -23,7 +28,7 @@ class LocationFilter extends CoveredCollectionFilter {
|
||||||
_location = split.isNotEmpty ? split[0] : location;
|
_location = split.isNotEmpty ? split[0] : location;
|
||||||
_code = split.length > 1 ? split[1] : null;
|
_code = split.length > 1 ? split[1] : null;
|
||||||
|
|
||||||
if (_location.isEmpty) {
|
if (_isUnlocated) {
|
||||||
_test = (entry) => !entry.hasGps;
|
_test = (entry) => !entry.hasGps;
|
||||||
} else {
|
} else {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
|
@ -81,11 +86,11 @@ class LocationFilter extends CoveredCollectionFilter {
|
||||||
String get universalLabel => _location;
|
String get universalLabel => _location;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getLabel(BuildContext context) => _location.isEmpty ? context.l10n.filterNoLocationLabel : _location;
|
String getLabel(BuildContext context) => _isUnlocated ? context.l10n.filterNoLocationLabel : _location;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true}) {
|
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true}) {
|
||||||
if (_location.isEmpty) {
|
if (_isUnlocated) {
|
||||||
return Icon(AIcons.locationUnlocated, size: size);
|
return Icon(AIcons.locationUnlocated, size: size);
|
||||||
}
|
}
|
||||||
switch (level) {
|
switch (level) {
|
||||||
|
|
|
@ -4,18 +4,17 @@ import 'package:flutter/foundation.dart';
|
||||||
@immutable
|
@immutable
|
||||||
class OverlayMetadata extends Equatable {
|
class OverlayMetadata extends Equatable {
|
||||||
final double? aperture, focalLength;
|
final double? aperture, focalLength;
|
||||||
final String? exposureTime;
|
final String? description, exposureTime;
|
||||||
final int? iso;
|
final int? iso;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [aperture, exposureTime, focalLength, iso];
|
List<Object?> get props => [aperture, description, exposureTime, focalLength, iso];
|
||||||
|
|
||||||
bool get isEmpty => aperture == null && exposureTime == null && focalLength == null && iso == null;
|
bool get hasShootingDetails => aperture != null || exposureTime != null || focalLength != null || iso != null;
|
||||||
|
|
||||||
bool get isNotEmpty => !isEmpty;
|
|
||||||
|
|
||||||
const OverlayMetadata({
|
const OverlayMetadata({
|
||||||
this.aperture,
|
this.aperture,
|
||||||
|
this.description,
|
||||||
this.exposureTime,
|
this.exposureTime,
|
||||||
this.focalLength,
|
this.focalLength,
|
||||||
this.iso,
|
this.iso,
|
||||||
|
@ -24,6 +23,7 @@ class OverlayMetadata extends Equatable {
|
||||||
factory OverlayMetadata.fromMap(Map map) {
|
factory OverlayMetadata.fromMap(Map map) {
|
||||||
return OverlayMetadata(
|
return OverlayMetadata(
|
||||||
aperture: map['aperture'] as double?,
|
aperture: map['aperture'] as double?,
|
||||||
|
description: map['description'] as String?,
|
||||||
exposureTime: map['exposureTime'] as String?,
|
exposureTime: map['exposureTime'] as String?,
|
||||||
focalLength: map['focalLength'] as double?,
|
focalLength: map['focalLength'] as double?,
|
||||||
iso: map['iso'] as int?,
|
iso: map['iso'] as int?,
|
||||||
|
|
|
@ -52,6 +52,7 @@ class SettingsDefaults {
|
||||||
EntrySetAction.delete,
|
EntrySetAction.delete,
|
||||||
];
|
];
|
||||||
static const showThumbnailFavourite = true;
|
static const showThumbnailFavourite = true;
|
||||||
|
static const showThumbnailHdr = true;
|
||||||
static const thumbnailLocationIcon = ThumbnailOverlayLocationIcon.none;
|
static const thumbnailLocationIcon = ThumbnailOverlayLocationIcon.none;
|
||||||
static const thumbnailTagIcon = ThumbnailOverlayTagIcon.none;
|
static const thumbnailTagIcon = ThumbnailOverlayTagIcon.none;
|
||||||
static const showThumbnailMotionPhoto = true;
|
static const showThumbnailMotionPhoto = true;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/widgets/viewer/controls/controller.dart';
|
import 'package:aves/widgets/viewer/controls/transitions.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/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
|
@ -30,6 +30,10 @@ mixin CollectionSettings on SettingsAccess {
|
||||||
|
|
||||||
set showThumbnailFavourite(bool newValue) => set(SettingKeys.showThumbnailFavouriteKey, newValue);
|
set showThumbnailFavourite(bool newValue) => set(SettingKeys.showThumbnailFavouriteKey, newValue);
|
||||||
|
|
||||||
|
bool get showThumbnailHdr => getBool(SettingKeys.showThumbnailHdrKey) ?? SettingsDefaults.showThumbnailHdr;
|
||||||
|
|
||||||
|
set showThumbnailHdr(bool newValue) => set(SettingKeys.showThumbnailHdrKey, newValue);
|
||||||
|
|
||||||
ThumbnailOverlayLocationIcon get thumbnailLocationIcon => getEnumOrDefault(SettingKeys.thumbnailLocationIconKey, SettingsDefaults.thumbnailLocationIcon, ThumbnailOverlayLocationIcon.values);
|
ThumbnailOverlayLocationIcon get thumbnailLocationIcon => getEnumOrDefault(SettingKeys.thumbnailLocationIconKey, SettingsDefaults.thumbnailLocationIcon, ThumbnailOverlayLocationIcon.values);
|
||||||
|
|
||||||
set thumbnailLocationIcon(ThumbnailOverlayLocationIcon newValue) => set(SettingKeys.thumbnailLocationIconKey, newValue.toString());
|
set thumbnailLocationIcon(ThumbnailOverlayLocationIcon newValue) => set(SettingKeys.thumbnailLocationIconKey, newValue.toString());
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/settings/defaults.dart';
|
import 'package:aves/model/settings/defaults.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
mixin NavigationSettings on SettingsAccess {
|
mixin NavigationSettings on SettingsAccess {
|
||||||
bool get mustBackTwiceToExit => getBool(SettingKeys.mustBackTwiceToExitKey) ?? SettingsDefaults.mustBackTwiceToExit;
|
bool get mustBackTwiceToExit => getBool(SettingKeys.mustBackTwiceToExitKey) ?? SettingsDefaults.mustBackTwiceToExit;
|
||||||
|
@ -15,6 +16,10 @@ mixin NavigationSettings on SettingsAccess {
|
||||||
|
|
||||||
set homePage(HomePageSetting newValue) => set(SettingKeys.homePageKey, newValue.toString());
|
set homePage(HomePageSetting newValue) => set(SettingKeys.homePageKey, newValue.toString());
|
||||||
|
|
||||||
|
Set<CollectionFilter> get homeCustomCollection => (getStringList(SettingKeys.homeCustomCollectionKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet();
|
||||||
|
|
||||||
|
set homeCustomCollection(Set<CollectionFilter> newValue) => set(SettingKeys.homeCustomCollectionKey, newValue.map((filter) => filter.toJson()).toList());
|
||||||
|
|
||||||
bool get enableBottomNavigationBar => getBool(SettingKeys.enableBottomNavigationBarKey) ?? SettingsDefaults.enableBottomNavigationBar;
|
bool get enableBottomNavigationBar => getBool(SettingKeys.enableBottomNavigationBarKey) ?? SettingsDefaults.enableBottomNavigationBar;
|
||||||
|
|
||||||
set enableBottomNavigationBar(bool newValue) => set(SettingKeys.enableBottomNavigationBarKey, newValue);
|
set enableBottomNavigationBar(bool newValue) => set(SettingKeys.enableBottomNavigationBarKey, newValue);
|
||||||
|
|
|
@ -388,6 +388,7 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
|
||||||
case SettingKeys.setMetadataDateBeforeFileOpKey:
|
case SettingKeys.setMetadataDateBeforeFileOpKey:
|
||||||
case SettingKeys.collectionSortReverseKey:
|
case SettingKeys.collectionSortReverseKey:
|
||||||
case SettingKeys.showThumbnailFavouriteKey:
|
case SettingKeys.showThumbnailFavouriteKey:
|
||||||
|
case SettingKeys.showThumbnailHdrKey:
|
||||||
case SettingKeys.showThumbnailMotionPhotoKey:
|
case SettingKeys.showThumbnailMotionPhotoKey:
|
||||||
case SettingKeys.showThumbnailRatingKey:
|
case SettingKeys.showThumbnailRatingKey:
|
||||||
case SettingKeys.showThumbnailRawKey:
|
case SettingKeys.showThumbnailRawKey:
|
||||||
|
@ -471,6 +472,7 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
|
||||||
} else {
|
} else {
|
||||||
debugPrint('failed to import key=$key, value=$newValue is not a string');
|
debugPrint('failed to import key=$key, value=$newValue is not a string');
|
||||||
}
|
}
|
||||||
|
case SettingKeys.homeCustomCollectionKey:
|
||||||
case SettingKeys.drawerTypeBookmarksKey:
|
case SettingKeys.drawerTypeBookmarksKey:
|
||||||
case SettingKeys.drawerAlbumBookmarksKey:
|
case SettingKeys.drawerAlbumBookmarksKey:
|
||||||
case SettingKeys.drawerPageBookmarksKey:
|
case SettingKeys.drawerPageBookmarksKey:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:aves/services/common/services.dart';
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -22,14 +21,8 @@ class GeocodingService {
|
||||||
'maxResults': 2,
|
'maxResults': 2,
|
||||||
});
|
});
|
||||||
return (result as List).cast<Map>().map(Address.fromMap).toList();
|
return (result as List).cast<Map>().map(Address.fromMap).toList();
|
||||||
} on PlatformException catch (e, stack) {
|
} on PlatformException catch (_) {
|
||||||
if (!{
|
// do not report
|
||||||
'getAddress-empty',
|
|
||||||
'getAddress-network',
|
|
||||||
'getAddress-unavailable',
|
|
||||||
}.contains(e.code)) {
|
|
||||||
await reportService.recordError(e, stack);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ abstract class MetadataFetchService {
|
||||||
|
|
||||||
Future<CatalogMetadata?> getCatalogMetadata(AvesEntry entry, {bool background = false});
|
Future<CatalogMetadata?> getCatalogMetadata(AvesEntry entry, {bool background = false});
|
||||||
|
|
||||||
Future<OverlayMetadata?> getOverlayMetadata(AvesEntry entry);
|
Future<OverlayMetadata> getFields(AvesEntry entry, Set<MetadataSyntheticField> fields);
|
||||||
|
|
||||||
Future<GeoTiffInfo?> getGeoTiffInfo(AvesEntry entry);
|
Future<GeoTiffInfo?> getGeoTiffInfo(AvesEntry entry);
|
||||||
|
|
||||||
|
@ -39,8 +39,6 @@ abstract class MetadataFetchService {
|
||||||
Future<String?> getContentResolverProp(AvesEntry entry, String prop);
|
Future<String?> getContentResolverProp(AvesEntry entry, String prop);
|
||||||
|
|
||||||
Future<DateTime?> getDate(AvesEntry entry, MetadataField field);
|
Future<DateTime?> getDate(AvesEntry entry, MetadataField field);
|
||||||
|
|
||||||
Future<String?> getDescription(AvesEntry entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlatformMetadataFetchService implements MetadataFetchService {
|
class PlatformMetadataFetchService implements MetadataFetchService {
|
||||||
|
@ -112,15 +110,20 @@ class PlatformMetadataFetchService implements MetadataFetchService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<OverlayMetadata?> getOverlayMetadata(AvesEntry entry) async {
|
Future<OverlayMetadata> getFields(AvesEntry entry, Set<MetadataSyntheticField> fields) async {
|
||||||
if (entry.isSvg) return null;
|
if (fields.isNotEmpty && !entry.isSvg) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// returns map with values for: 'aperture' (double), 'exposureTime' (description), 'focalLength' (double), 'iso' (int)
|
// returns fields on demand, with various value types:
|
||||||
final result = await _platform.invokeMethod('getOverlayMetadata', <String, dynamic>{
|
// 'aperture' (double),
|
||||||
|
// 'description' (string)
|
||||||
|
// 'exposureTime' (string),
|
||||||
|
// 'focalLength' (double),
|
||||||
|
// 'iso' (int),
|
||||||
|
final result = await _platform.invokeMethod('getFields', <String, dynamic>{
|
||||||
'mimeType': entry.mimeType,
|
'mimeType': entry.mimeType,
|
||||||
'uri': entry.uri,
|
'uri': entry.uri,
|
||||||
'sizeBytes': entry.sizeBytes,
|
'sizeBytes': entry.sizeBytes,
|
||||||
|
'fields': fields.map((v) => v.toPlatform).toList(),
|
||||||
}) as Map;
|
}) as Map;
|
||||||
return OverlayMetadata.fromMap(result);
|
return OverlayMetadata.fromMap(result);
|
||||||
} on PlatformException catch (e, stack) {
|
} on PlatformException catch (e, stack) {
|
||||||
|
@ -128,7 +131,8 @@ class PlatformMetadataFetchService implements MetadataFetchService {
|
||||||
await reportService.recordError(e, stack);
|
await reportService.recordError(e, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
}
|
||||||
|
return const OverlayMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -280,20 +284,4 @@ class PlatformMetadataFetchService implements MetadataFetchService {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String?> getDescription(AvesEntry entry) async {
|
|
||||||
try {
|
|
||||||
return await _platform.invokeMethod('getDescription', <String, dynamic>{
|
|
||||||
'mimeType': entry.mimeType,
|
|
||||||
'uri': entry.uri,
|
|
||||||
'sizeBytes': entry.sizeBytes,
|
|
||||||
});
|
|
||||||
} on PlatformException catch (e, stack) {
|
|
||||||
if (entry.isValid) {
|
|
||||||
await reportService.recordError(e, stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,17 @@ abstract class WindowService {
|
||||||
Future<bool> isCutoutAware();
|
Future<bool> isCutoutAware();
|
||||||
|
|
||||||
Future<EdgeInsets> getCutoutInsets();
|
Future<EdgeInsets> getCutoutInsets();
|
||||||
|
|
||||||
|
Future<bool> supportsHdr();
|
||||||
|
|
||||||
|
Future<void> setHdrColorMode(bool on);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlatformWindowService implements WindowService {
|
class PlatformWindowService implements WindowService {
|
||||||
static const _platform = MethodChannel('deckers.thibault/aves/window');
|
static const _platform = MethodChannel('deckers.thibault/aves/window');
|
||||||
|
|
||||||
|
bool? _isCutoutAware, _supportsHdr;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isActivity() async {
|
Future<bool> isActivity() async {
|
||||||
try {
|
try {
|
||||||
|
@ -90,8 +96,6 @@ class PlatformWindowService implements WindowService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool? _isCutoutAware;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isCutoutAware() async {
|
Future<bool> isCutoutAware() async {
|
||||||
if (_isCutoutAware != null) return SynchronousFuture(_isCutoutAware!);
|
if (_isCutoutAware != null) return SynchronousFuture(_isCutoutAware!);
|
||||||
|
@ -121,4 +125,28 @@ class PlatformWindowService implements WindowService {
|
||||||
}
|
}
|
||||||
return EdgeInsets.zero;
|
return EdgeInsets.zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> supportsHdr() async {
|
||||||
|
if (_supportsHdr != null) return SynchronousFuture(_supportsHdr!);
|
||||||
|
try {
|
||||||
|
final result = await _platform.invokeMethod('supportsHdr');
|
||||||
|
_supportsHdr = result as bool?;
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
return _supportsHdr ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> setHdrColorMode(bool on) async {
|
||||||
|
// TODO TLAD [hdr] enable when ready
|
||||||
|
// try {
|
||||||
|
// await _platform.invokeMethod('setHdrColorMode', <String, dynamic>{
|
||||||
|
// 'on': on,
|
||||||
|
// });
|
||||||
|
// } on PlatformException catch (e, stack) {
|
||||||
|
// await reportService.recordError(e, stack);
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ extension ExtraEntrySetActionView on EntrySetAction {
|
||||||
// different data depending on toggle state
|
// different data depending on toggle state
|
||||||
context.l10n.collectionActionShowTitleSearch,
|
context.l10n.collectionActionShowTitleSearch,
|
||||||
EntrySetAction.addShortcut => context.l10n.collectionActionAddShortcut,
|
EntrySetAction.addShortcut => context.l10n.collectionActionAddShortcut,
|
||||||
|
EntrySetAction.setHome => context.l10n.collectionActionSetHome,
|
||||||
EntrySetAction.emptyBin => context.l10n.collectionActionEmptyBin,
|
EntrySetAction.emptyBin => context.l10n.collectionActionEmptyBin,
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
EntrySetAction.map => context.l10n.menuActionMap,
|
EntrySetAction.map => context.l10n.menuActionMap,
|
||||||
|
@ -61,6 +62,7 @@ extension ExtraEntrySetActionView on EntrySetAction {
|
||||||
// different data depending on toggle state
|
// different data depending on toggle state
|
||||||
AIcons.filter,
|
AIcons.filter,
|
||||||
EntrySetAction.addShortcut => AIcons.addShortcut,
|
EntrySetAction.addShortcut => AIcons.addShortcut,
|
||||||
|
EntrySetAction.setHome => AIcons.home,
|
||||||
EntrySetAction.emptyBin => AIcons.emptyBin,
|
EntrySetAction.emptyBin => AIcons.emptyBin,
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
EntrySetAction.map => AIcons.map,
|
EntrySetAction.map => AIcons.map,
|
||||||
|
|
|
@ -154,6 +154,7 @@ class _BugReportState extends State<BugReport> with FeedbackMixin {
|
||||||
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||||
final storageVolumes = await storageService.getStorageVolumes();
|
final storageVolumes = await storageService.getStorageVolumes();
|
||||||
final storageGrants = await storageService.getGrantedDirectories();
|
final storageGrants = await storageService.getGrantedDirectories();
|
||||||
|
final supportsHdr = await windowService.supportsHdr();
|
||||||
return [
|
return [
|
||||||
'Package: ${device.packageName}',
|
'Package: ${device.packageName}',
|
||||||
'Installer: ${packageInfo.installerStore}',
|
'Installer: ${packageInfo.installerStore}',
|
||||||
|
@ -162,7 +163,7 @@ class _BugReportState extends State<BugReport> with FeedbackMixin {
|
||||||
'Android version: ${androidInfo.version.release}, API ${androidInfo.version.sdkInt}',
|
'Android version: ${androidInfo.version.release}, API ${androidInfo.version.sdkInt}',
|
||||||
'Android build: ${androidInfo.display}',
|
'Android build: ${androidInfo.display}',
|
||||||
'Device: ${androidInfo.manufacturer} ${androidInfo.model}',
|
'Device: ${androidInfo.manufacturer} ${androidInfo.model}',
|
||||||
'Geocoder: ${device.hasGeocoder ? 'ready' : 'not available'}',
|
'Support: dynamic colors=${device.isDynamicColorAvailable}, geocoder=${device.hasGeocoder}, HDR=$supportsHdr',
|
||||||
'Mobile services: ${mobileServices.isServiceAvailable ? 'ready' : 'not available'}',
|
'Mobile services: ${mobileServices.isServiceAvailable ? 'ready' : 'not available'}',
|
||||||
'System locales: ${WidgetsBinding.instance.platformDispatcher.locales.join(', ')}',
|
'System locales: ${WidgetsBinding.instance.platformDispatcher.locales.join(', ')}',
|
||||||
'Storage volumes: ${storageVolumes.map((v) => v.path).join(', ')}',
|
'Storage volumes: ${storageVolumes.map((v) => v.path).join(', ')}',
|
||||||
|
|
|
@ -68,7 +68,9 @@ class AvesApp extends StatefulWidget {
|
||||||
'ml', // Malayalam
|
'ml', // Malayalam
|
||||||
'my', // Burmese
|
'my', // Burmese
|
||||||
'or', // Odia
|
'or', // Odia
|
||||||
|
'sat', // Santali
|
||||||
'sl', // Slovenian
|
'sl', // Slovenian
|
||||||
|
'sv', // Swedish
|
||||||
'th', // Thai
|
'th', // Thai
|
||||||
}.map(Locale.new).toSet();
|
}.map(Locale.new).toSet();
|
||||||
static final List<Locale> supportedLocales = AppLocalizations.supportedLocales.where((v) => !_unsupportedLocales.contains(v)).toList();
|
static final List<Locale> supportedLocales = AppLocalizations.supportedLocales.where((v) => !_unsupportedLocales.contains(v)).toList();
|
||||||
|
|
|
@ -618,6 +618,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
case EntrySetAction.searchCollection:
|
case EntrySetAction.searchCollection:
|
||||||
case EntrySetAction.toggleTitleSearch:
|
case EntrySetAction.toggleTitleSearch:
|
||||||
case EntrySetAction.addShortcut:
|
case EntrySetAction.addShortcut:
|
||||||
|
case EntrySetAction.setHome:
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
case EntrySetAction.slideshow:
|
case EntrySetAction.slideshow:
|
||||||
|
|
|
@ -75,7 +75,9 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
case EntrySetAction.toggleTitleSearch:
|
case EntrySetAction.toggleTitleSearch:
|
||||||
return !useTvLayout && !isSelecting;
|
return !useTvLayout && !isSelecting;
|
||||||
case EntrySetAction.addShortcut:
|
case EntrySetAction.addShortcut:
|
||||||
return isMain && !isSelecting && device.canPinShortcut && !isTrash;
|
return isMain && !isSelecting && !isTrash && device.canPinShortcut;
|
||||||
|
case EntrySetAction.setHome:
|
||||||
|
return isMain && !isSelecting && !isTrash && !useTvLayout;
|
||||||
case EntrySetAction.emptyBin:
|
case EntrySetAction.emptyBin:
|
||||||
return canWrite && isMain && isTrash;
|
return canWrite && isMain && isTrash;
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
|
@ -131,6 +133,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
case EntrySetAction.searchCollection:
|
case EntrySetAction.searchCollection:
|
||||||
case EntrySetAction.toggleTitleSearch:
|
case EntrySetAction.toggleTitleSearch:
|
||||||
case EntrySetAction.addShortcut:
|
case EntrySetAction.addShortcut:
|
||||||
|
case EntrySetAction.setHome:
|
||||||
return true;
|
return true;
|
||||||
case EntrySetAction.emptyBin:
|
case EntrySetAction.emptyBin:
|
||||||
return !isSelecting && hasItems;
|
return !isSelecting && hasItems;
|
||||||
|
@ -177,6 +180,8 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
context.read<Query>().toggle();
|
context.read<Query>().toggle();
|
||||||
case EntrySetAction.addShortcut:
|
case EntrySetAction.addShortcut:
|
||||||
_addShortcut(context);
|
_addShortcut(context);
|
||||||
|
case EntrySetAction.setHome:
|
||||||
|
_setHome(context);
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
_goToMap(context);
|
_goToMap(context);
|
||||||
|
@ -727,4 +732,10 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
showFeedback(context, FeedbackType.info, context.l10n.genericSuccessFeedback);
|
showFeedback(context, FeedbackType.info, context.l10n.genericSuccessFeedback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _setHome(BuildContext context) async {
|
||||||
|
settings.homeCustomCollection = context.read<CollectionLens>().filters;
|
||||||
|
settings.homePage = HomePageSetting.collection;
|
||||||
|
showFeedback(context, FeedbackType.info, context.l10n.genericSuccessFeedback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,8 @@ mixin EntryEditorMixin {
|
||||||
|
|
||||||
final entry = entries.first;
|
final entry = entries.first;
|
||||||
final initialTitle = entry.catalogMetadata?.xmpTitle ?? '';
|
final initialTitle = entry.catalogMetadata?.xmpTitle ?? '';
|
||||||
final initialDescription = await metadataFetchService.getDescription(entry) ?? '';
|
final fields = await metadataFetchService.getFields(entry, {MetadataSyntheticField.description});
|
||||||
|
final initialDescription = fields.description ?? '';
|
||||||
|
|
||||||
return showDialog<Map<DescriptionField, String?>>(
|
return showDialog<Map<DescriptionField, String?>>(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
|
@ -40,6 +40,7 @@ class GridTheme extends StatelessWidget {
|
||||||
highlightBorderWidth: highlightBorderWidth,
|
highlightBorderWidth: highlightBorderWidth,
|
||||||
interactiveDimension: interactiveDimension,
|
interactiveDimension: interactiveDimension,
|
||||||
showFavourite: settings.showThumbnailFavourite,
|
showFavourite: settings.showThumbnailFavourite,
|
||||||
|
showHdr: settings.showThumbnailHdr,
|
||||||
locationIcon: showLocation ? settings.thumbnailLocationIcon : ThumbnailOverlayLocationIcon.none,
|
locationIcon: showLocation ? settings.thumbnailLocationIcon : ThumbnailOverlayLocationIcon.none,
|
||||||
tagIcon: settings.thumbnailTagIcon,
|
tagIcon: settings.thumbnailTagIcon,
|
||||||
showMotionPhoto: settings.showThumbnailMotionPhoto,
|
showMotionPhoto: settings.showThumbnailMotionPhoto,
|
||||||
|
@ -58,7 +59,7 @@ typedef GridThemeIconBuilder = List<Widget> Function(BuildContext context, AvesE
|
||||||
|
|
||||||
class GridThemeData {
|
class GridThemeData {
|
||||||
final double iconSize, fontSize, highlightBorderWidth, interactiveDimension;
|
final double iconSize, fontSize, highlightBorderWidth, interactiveDimension;
|
||||||
final bool showFavourite, showMotionPhoto, showRating, showRaw, showTrash, showVideoDuration;
|
final bool showFavourite, showHdr, showMotionPhoto, showRating, showRaw, showTrash, showVideoDuration;
|
||||||
final bool showLocated, showUnlocated, showTagged, showUntagged;
|
final bool showLocated, showUnlocated, showTagged, showUntagged;
|
||||||
late final GridThemeIconBuilder iconBuilder;
|
late final GridThemeIconBuilder iconBuilder;
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ class GridThemeData {
|
||||||
required this.highlightBorderWidth,
|
required this.highlightBorderWidth,
|
||||||
required this.interactiveDimension,
|
required this.interactiveDimension,
|
||||||
required this.showFavourite,
|
required this.showFavourite,
|
||||||
|
required this.showHdr,
|
||||||
required ThumbnailOverlayLocationIcon locationIcon,
|
required ThumbnailOverlayLocationIcon locationIcon,
|
||||||
required ThumbnailOverlayTagIcon tagIcon,
|
required ThumbnailOverlayTagIcon tagIcon,
|
||||||
required this.showMotionPhoto,
|
required this.showMotionPhoto,
|
||||||
|
@ -94,10 +96,10 @@ class GridThemeData {
|
||||||
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(),
|
||||||
],
|
],
|
||||||
if (entry.isHdr) const HdrIcon(),
|
|
||||||
if (entry.isMotionPhoto && showMotionPhoto) const MotionPhotoIcon(),
|
if (entry.isMotionPhoto && showMotionPhoto) const MotionPhotoIcon(),
|
||||||
if (entry.isMultiPage && !entry.isMotionPhoto) MultiPageIcon(entry: entry),
|
if (entry.isMultiPage && !entry.isMotionPhoto) MultiPageIcon(entry: entry),
|
||||||
if (entry.isGeotiff) const GeoTiffIcon(),
|
if (entry.isGeotiff) const GeoTiffIcon(),
|
||||||
|
|
|
@ -19,6 +19,7 @@ import 'package:aves/widgets/debug/app_debug_action.dart';
|
||||||
import 'package:aves/widgets/debug/cache.dart';
|
import 'package:aves/widgets/debug/cache.dart';
|
||||||
import 'package:aves/widgets/debug/colors.dart';
|
import 'package:aves/widgets/debug/colors.dart';
|
||||||
import 'package:aves/widgets/debug/database.dart';
|
import 'package:aves/widgets/debug/database.dart';
|
||||||
|
import 'package:aves/widgets/debug/device.dart';
|
||||||
import 'package:aves/widgets/debug/general.dart';
|
import 'package:aves/widgets/debug/general.dart';
|
||||||
import 'package:aves/widgets/debug/media_store_scan_dialog.dart';
|
import 'package:aves/widgets/debug/media_store_scan_dialog.dart';
|
||||||
import 'package:aves/widgets/debug/report.dart';
|
import 'package:aves/widgets/debug/report.dart';
|
||||||
|
@ -75,6 +76,7 @@ class AppDebugPage extends StatelessWidget {
|
||||||
DebugCacheSection(),
|
DebugCacheSection(),
|
||||||
DebugColorSection(),
|
DebugColorSection(),
|
||||||
DebugAppDatabaseSection(),
|
DebugAppDatabaseSection(),
|
||||||
|
DebugDeviceSection(),
|
||||||
DebugErrorReportingSection(),
|
DebugErrorReportingSection(),
|
||||||
DebugSettingsSection(),
|
DebugSettingsSection(),
|
||||||
DebugStorageSection(),
|
DebugStorageSection(),
|
||||||
|
|
51
lib/widgets/debug/device.dart
Normal file
51
lib/widgets/debug/device.dart
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import 'package:aves/model/device.dart';
|
||||||
|
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
||||||
|
import 'package:aves/widgets/viewer/info/common.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class DebugDeviceSection extends StatefulWidget {
|
||||||
|
const DebugDeviceSection({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DebugDeviceSection> createState() => _DebugDeviceSectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DebugDeviceSectionState extends State<DebugDeviceSection> with AutomaticKeepAliveClientMixin {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: 'Device',
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||||
|
child: InfoRowGroup(
|
||||||
|
info: {
|
||||||
|
'packageName': device.packageName,
|
||||||
|
'packageVersion': device.packageVersion,
|
||||||
|
'userAgent': device.userAgent,
|
||||||
|
'canAuthenticateUser': '${device.canAuthenticateUser}',
|
||||||
|
'canGrantDirectoryAccess': '${device.canGrantDirectoryAccess}',
|
||||||
|
'canPinShortcut': '${device.canPinShortcut}',
|
||||||
|
'canRenderFlagEmojis': '${device.canRenderFlagEmojis}',
|
||||||
|
'canRenderSubdivisionFlagEmojis': '${device.canRenderSubdivisionFlagEmojis}',
|
||||||
|
'canRequestManageMedia': '${device.canRequestManageMedia}',
|
||||||
|
'canSetLockScreenWallpaper': '${device.canSetLockScreenWallpaper}',
|
||||||
|
'canUseCrypto': '${device.canUseCrypto}',
|
||||||
|
'canUseVaults': '${device.canUseVaults}',
|
||||||
|
'hasGeocoder': '${device.hasGeocoder}',
|
||||||
|
'isDynamicColorAvailable': '${device.isDynamicColorAvailable}',
|
||||||
|
'isTelevision': '${device.isTelevision}',
|
||||||
|
'showPinShortcutFeedback': '${device.showPinShortcutFeedback}',
|
||||||
|
'supportEdgeToEdgeUIMode': '${device.supportEdgeToEdgeUIMode}',
|
||||||
|
'supportPictureInPicture': '${device.supportPictureInPicture}',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/location.dart';
|
import 'package:aves/model/entry/extensions/location.dart';
|
||||||
import 'package:aves/model/entry/extensions/metadata_edition.dart';
|
import 'package:aves/model/entry/extensions/metadata_edition.dart';
|
||||||
|
import 'package:aves/model/filters/location.dart';
|
||||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
import 'package:aves/model/settings/enums/coordinate_format.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';
|
||||||
|
@ -18,6 +19,7 @@ import 'package:aves/widgets/dialogs/item_picker.dart';
|
||||||
import 'package:aves/widgets/dialogs/pick_dialogs/item_pick_page.dart';
|
import 'package:aves/widgets/dialogs/pick_dialogs/item_pick_page.dart';
|
||||||
import 'package:aves/widgets/dialogs/pick_dialogs/location_pick_page.dart';
|
import 'package:aves/widgets/dialogs/pick_dialogs/location_pick_page.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
|
@ -172,8 +174,10 @@ class _EditEntryLocationDialogState extends State<EditEntryLocationDialog> {
|
||||||
final mapCollection = baseCollection != null
|
final mapCollection = baseCollection != null
|
||||||
? CollectionLens(
|
? CollectionLens(
|
||||||
source: baseCollection.source,
|
source: baseCollection.source,
|
||||||
filters: baseCollection.filters,
|
filters: {
|
||||||
fixedSelection: baseCollection.sortedEntries.where((entry) => entry.hasGps).toList(),
|
...baseCollection.filters.whereNot((filter) => filter == LocationFilter.unlocated),
|
||||||
|
LocationFilter.located,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
final latLng = await Navigator.maybeOf(context)?.push(
|
final latLng = await Navigator.maybeOf(context)?.push(
|
||||||
|
|
|
@ -3,6 +3,8 @@ import 'package:aves/widgets/dialogs/selection_dialogs/common.dart';
|
||||||
import 'package:aves/widgets/dialogs/selection_dialogs/radio_list_tile.dart';
|
import 'package:aves/widgets/dialogs/selection_dialogs/radio_list_tile.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// do not use as `T` a record containing a collection
|
||||||
|
// because radio value comparison will fail without deep equality
|
||||||
class AvesSingleSelectionDialog<T> extends StatefulWidget {
|
class AvesSingleSelectionDialog<T> extends StatefulWidget {
|
||||||
static const routeName = '/dialog/selection';
|
static const routeName = '/dialog/selection';
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ class _HomePageState extends State<HomePage> {
|
||||||
unawaited(AnalysisService.registerCallback());
|
unawaited(AnalysisService.registerCallback());
|
||||||
final source = context.read<CollectionSource>();
|
final source = context.read<CollectionSource>();
|
||||||
await source.init(
|
await source.init(
|
||||||
loadTopEntriesFirst: settings.homePage == HomePageSetting.collection,
|
loadTopEntriesFirst: settings.homePage == HomePageSetting.collection && settings.homeCustomCollection.isEmpty,
|
||||||
canAnalyze: !safeMode,
|
canAnalyze: !safeMode,
|
||||||
);
|
);
|
||||||
case AppMode.screenSaver:
|
case AppMode.screenSaver:
|
||||||
|
@ -338,7 +338,7 @@ class _HomePageState extends State<HomePage> {
|
||||||
case AppMode.screenSaver:
|
case AppMode.screenSaver:
|
||||||
case AppMode.slideshow:
|
case AppMode.slideshow:
|
||||||
routeName = _initialRouteName ?? settings.homePage.routeName;
|
routeName = _initialRouteName ?? settings.homePage.routeName;
|
||||||
filters = _initialFilters ?? {};
|
filters = _initialFilters ?? (settings.homePage == HomePageSetting.collection ? settings.homeCustomCollection : {});
|
||||||
}
|
}
|
||||||
Route buildRoute(WidgetBuilder builder) => DirectMaterialPageRoute(
|
Route buildRoute(WidgetBuilder builder) => DirectMaterialPageRoute(
|
||||||
settings: RouteSettings(name: routeName),
|
settings: RouteSettings(name: routeName),
|
||||||
|
|
|
@ -50,7 +50,7 @@ class PageNavTile extends StatelessWidget {
|
||||||
: null,
|
: null,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.maybeOf(context)?.pop();
|
Navigator.maybeOf(context)?.pop();
|
||||||
final route = routeBuilder(context, routeName);
|
final route = routeBuilder(context, routeName, topLevel);
|
||||||
if (topLevel) {
|
if (topLevel) {
|
||||||
Navigator.maybeOf(context)?.pushAndRemoveUntil(
|
Navigator.maybeOf(context)?.pushAndRemoveUntil(
|
||||||
route,
|
route,
|
||||||
|
@ -65,7 +65,7 @@ class PageNavTile extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Route routeBuilder(BuildContext context, String routeName) {
|
static Route routeBuilder(BuildContext context, String routeName, bool topLevel) {
|
||||||
switch (routeName) {
|
switch (routeName) {
|
||||||
case SearchPage.routeName:
|
case SearchPage.routeName:
|
||||||
final currentCollection = context.read<CollectionLens?>();
|
final currentCollection = context.read<CollectionLens?>();
|
||||||
|
@ -74,7 +74,7 @@ class PageNavTile extends StatelessWidget {
|
||||||
searchFieldLabel: context.l10n.searchCollectionFieldHint,
|
searchFieldLabel: context.l10n.searchCollectionFieldHint,
|
||||||
searchFieldStyle: Themes.searchFieldStyle(context),
|
searchFieldStyle: Themes.searchFieldStyle(context),
|
||||||
source: context.read<CollectionSource>(),
|
source: context.read<CollectionSource>(),
|
||||||
parentCollection: currentCollection?.copyWith(),
|
parentCollection: topLevel ? currentCollection?.copyWith() : currentCollection,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -253,7 +253,7 @@ class _TvRailState extends State<TvRail> {
|
||||||
|
|
||||||
void _goTo(String routeName) {
|
void _goTo(String routeName) {
|
||||||
Navigator.maybeOf(context)?.pushAndRemoveUntil(
|
Navigator.maybeOf(context)?.pushAndRemoveUntil(
|
||||||
PageNavTile.routeBuilder(context, routeName),
|
PageNavTile.routeBuilder(context, routeName, true),
|
||||||
(route) => false,
|
(route) => false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,7 +279,7 @@ class CollectionSearchDelegate extends AvesSearchDelegate with FeedbackMixin, Va
|
||||||
title: context.l10n.searchMetadataSectionTitle,
|
title: context.l10n.searchMetadataSectionTitle,
|
||||||
filters: [
|
filters: [
|
||||||
MissingFilter.date,
|
MissingFilter.date,
|
||||||
LocationFilter(LocationLevel.place, ''),
|
LocationFilter.unlocated,
|
||||||
MissingFilter.fineAddress,
|
MissingFilter.fineAddress,
|
||||||
TagFilter(''),
|
TagFilter(''),
|
||||||
RatingFilter(0),
|
RatingFilter(0),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:aves/model/filters/filters.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/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
|
@ -11,6 +12,7 @@ import 'package:aves/widgets/settings/navigation/confirmation_dialogs.dart';
|
||||||
import 'package:aves/widgets/settings/navigation/drawer.dart';
|
import 'package:aves/widgets/settings/navigation/drawer.dart';
|
||||||
import 'package:aves/widgets/settings/settings_definition.dart';
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -38,16 +40,47 @@ class NavigationSection extends SettingsSection {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _HomeOption {
|
||||||
|
final HomePageSetting page;
|
||||||
|
final Set<CollectionFilter> customCollection;
|
||||||
|
|
||||||
|
const _HomeOption(
|
||||||
|
this.page, {
|
||||||
|
this.customCollection = const {},
|
||||||
|
});
|
||||||
|
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
if (page == HomePageSetting.collection && customCollection.isNotEmpty) {
|
||||||
|
return context.l10n.setHomeCustomCollection;
|
||||||
|
}
|
||||||
|
return page.getName(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || other is _HomeOption && runtimeType == other.runtimeType && page == other.page && const DeepCollectionEquality().equals(customCollection, other.customCollection);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => page.hashCode ^ customCollection.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
class SettingsTileNavigationHomePage extends SettingsTile {
|
class SettingsTileNavigationHomePage extends SettingsTile {
|
||||||
@override
|
@override
|
||||||
String title(BuildContext context) => context.l10n.settingsHomeTile;
|
String title(BuildContext context) => context.l10n.settingsHomeTile;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => SettingsSelectionListTile<HomePageSetting>(
|
Widget build(BuildContext context) => SettingsSelectionListTile<_HomeOption>(
|
||||||
values: HomePageSetting.values,
|
values: [
|
||||||
|
const _HomeOption(HomePageSetting.collection),
|
||||||
|
const _HomeOption(HomePageSetting.albums),
|
||||||
|
const _HomeOption(HomePageSetting.tags),
|
||||||
|
if (settings.homeCustomCollection.isNotEmpty) _HomeOption(HomePageSetting.collection, customCollection: settings.homeCustomCollection),
|
||||||
|
],
|
||||||
getName: (context, v) => v.getName(context),
|
getName: (context, v) => v.getName(context),
|
||||||
selector: (context, s) => s.homePage,
|
selector: (context, s) => _HomeOption(s.homePage, customCollection: s.homeCustomCollection),
|
||||||
onSelection: (v) => settings.homePage = v,
|
onSelection: (v) {
|
||||||
|
settings.homePage = v.page;
|
||||||
|
settings.homeCustomCollection = v.customCollection;
|
||||||
|
},
|
||||||
tileTitle: title(context),
|
tileTitle: title(context),
|
||||||
dialogTitle: context.l10n.settingsHomeDialogTitle,
|
dialogTitle: context.l10n.settingsHomeDialogTitle,
|
||||||
);
|
);
|
||||||
|
|
|
@ -66,6 +66,16 @@ class ThumbnailOverlayPage extends StatelessWidget {
|
||||||
color: iconColor,
|
color: iconColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.showThumbnailHdr,
|
||||||
|
onChanged: (v) => settings.showThumbnailHdr = v,
|
||||||
|
title: context.l10n.settingsThumbnailShowHdrIcon,
|
||||||
|
trailing: Icon(
|
||||||
|
AIcons.hdr,
|
||||||
|
size: iconSize,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
SettingsSwitchListTile(
|
SettingsSwitchListTile(
|
||||||
selector: (context, s) => s.showThumbnailRaw,
|
selector: (context, s) => s.showThumbnailRaw,
|
||||||
onChanged: (v) => settings.showThumbnailRaw = v,
|
onChanged: (v) => settings.showThumbnailRaw = v,
|
||||||
|
|
|
@ -2,6 +2,8 @@ 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/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';
|
||||||
import 'package:aves/widgets/viewer/controls/events.dart';
|
import 'package:aves/widgets/viewer/controls/events.dart';
|
||||||
|
@ -57,6 +59,7 @@ class ViewerController with CastMixin {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_initialScale = initialScale;
|
_initialScale = initialScale;
|
||||||
|
entryNotifier.addListener(_onEntryChanged);
|
||||||
_autopilotNotifier = ValueNotifier(autopilot);
|
_autopilotNotifier = ValueNotifier(autopilot);
|
||||||
_autopilotNotifier.addListener(_onAutopilotChanged);
|
_autopilotNotifier.addListener(_onAutopilotChanged);
|
||||||
_onAutopilotChanged();
|
_onAutopilotChanged();
|
||||||
|
@ -66,12 +69,21 @@ class ViewerController with CastMixin {
|
||||||
if (kFlutterMemoryAllocationsEnabled) {
|
if (kFlutterMemoryAllocationsEnabled) {
|
||||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||||
}
|
}
|
||||||
|
entryNotifier.removeListener(_onEntryChanged);
|
||||||
|
windowService.setHdrColorMode(false);
|
||||||
_autopilotNotifier.dispose();
|
_autopilotNotifier.dispose();
|
||||||
_clearAutopilotAnimations();
|
_clearAutopilotAnimations();
|
||||||
_stopPlayTimer();
|
_stopPlayTimer();
|
||||||
_streamController.close();
|
_streamController.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onEntryChanged() async {
|
||||||
|
if (await windowService.supportsHdr()) {
|
||||||
|
final enabled = entryNotifier.value?.isHdr ?? false;
|
||||||
|
await windowService.setHdrColorMode(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _onAutopilotChanged() {
|
void _onAutopilotChanged() {
|
||||||
_clearAutopilotAnimations();
|
_clearAutopilotAnimations();
|
||||||
_stopPlayTimer();
|
_stopPlayTimer();
|
||||||
|
@ -115,79 +127,3 @@ class ViewerController with CastMixin {
|
||||||
Future.delayed(ADurations.viewerHorizontalPageAnimation).then((_) => _autopilotAnimationControllers[vsync]?.forward());
|
Future.delayed(ADurations.viewerHorizontalPageAnimation).then((_) => _autopilotAnimationControllers[vsync]?.forward());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PageTransitionEffects {
|
|
||||||
static TransitionBuilder fade(
|
|
||||||
PageController pageController,
|
|
||||||
int index, {
|
|
||||||
required bool zoomIn,
|
|
||||||
}) =>
|
|
||||||
(context, child) {
|
|
||||||
double opacity = 0;
|
|
||||||
double dx = 0;
|
|
||||||
double scale = 1;
|
|
||||||
if (pageController.hasClients && pageController.position.haveDimensions) {
|
|
||||||
final position = (pageController.page! - index).clamp(-1.0, 1.0);
|
|
||||||
final width = pageController.position.viewportDimension;
|
|
||||||
opacity = (1 - position.abs()).clamp(0, 1);
|
|
||||||
dx = position * width;
|
|
||||||
if (zoomIn) {
|
|
||||||
scale = 1 + position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Opacity(
|
|
||||||
opacity: opacity,
|
|
||||||
child: Transform.translate(
|
|
||||||
offset: Offset(dx, 0),
|
|
||||||
child: Transform.scale(
|
|
||||||
scale: scale,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
static TransitionBuilder slide(
|
|
||||||
PageController pageController,
|
|
||||||
int index, {
|
|
||||||
required bool parallax,
|
|
||||||
}) =>
|
|
||||||
(context, child) {
|
|
||||||
double dx = 0;
|
|
||||||
if (pageController.hasClients && pageController.position.haveDimensions) {
|
|
||||||
final position = (pageController.page! - index).clamp(-1.0, 1.0);
|
|
||||||
final width = pageController.position.viewportDimension;
|
|
||||||
if (parallax) {
|
|
||||||
dx = position * width / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ClipRect(
|
|
||||||
child: Transform.translate(
|
|
||||||
offset: Offset(dx, 0),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
static TransitionBuilder none(
|
|
||||||
PageController pageController,
|
|
||||||
int index,
|
|
||||||
) =>
|
|
||||||
(context, child) {
|
|
||||||
double opacity = 0;
|
|
||||||
double dx = 0;
|
|
||||||
if (pageController.hasClients && pageController.position.haveDimensions) {
|
|
||||||
final position = (pageController.page! - index).clamp(-1.0, 1.0);
|
|
||||||
final width = pageController.position.viewportDimension;
|
|
||||||
opacity = (1 - position.abs()).roundToDouble().clamp(0, 1);
|
|
||||||
dx = position * width;
|
|
||||||
}
|
|
||||||
return Opacity(
|
|
||||||
opacity: opacity,
|
|
||||||
child: Transform.translate(
|
|
||||||
offset: Offset(dx, 0),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
77
lib/widgets/viewer/controls/transitions.dart
Normal file
77
lib/widgets/viewer/controls/transitions.dart
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
class PageTransitionEffects {
|
||||||
|
static TransitionBuilder fade(
|
||||||
|
PageController pageController,
|
||||||
|
int index, {
|
||||||
|
required bool zoomIn,
|
||||||
|
}) =>
|
||||||
|
(context, child) {
|
||||||
|
double opacity = 0;
|
||||||
|
double dx = 0;
|
||||||
|
double scale = 1;
|
||||||
|
if (pageController.hasClients && pageController.position.haveDimensions) {
|
||||||
|
final position = (pageController.page! - index).clamp(-1.0, 1.0);
|
||||||
|
final width = pageController.position.viewportDimension;
|
||||||
|
opacity = (1 - position.abs()).clamp(0, 1);
|
||||||
|
dx = position * width;
|
||||||
|
if (zoomIn) {
|
||||||
|
scale = 1 + position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Opacity(
|
||||||
|
opacity: opacity,
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: Offset(dx, 0),
|
||||||
|
child: Transform.scale(
|
||||||
|
scale: scale,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
static TransitionBuilder slide(
|
||||||
|
PageController pageController,
|
||||||
|
int index, {
|
||||||
|
required bool parallax,
|
||||||
|
}) =>
|
||||||
|
(context, child) {
|
||||||
|
double dx = 0;
|
||||||
|
if (pageController.hasClients && pageController.position.haveDimensions) {
|
||||||
|
final position = (pageController.page! - index).clamp(-1.0, 1.0);
|
||||||
|
final width = pageController.position.viewportDimension;
|
||||||
|
if (parallax) {
|
||||||
|
dx = position * width / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ClipRect(
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: Offset(dx, 0),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
static TransitionBuilder none(
|
||||||
|
PageController pageController,
|
||||||
|
int index,
|
||||||
|
) =>
|
||||||
|
(context, child) {
|
||||||
|
double opacity = 0;
|
||||||
|
double dx = 0;
|
||||||
|
if (pageController.hasClients && pageController.position.haveDimensions) {
|
||||||
|
final position = (pageController.page! - index).clamp(-1.0, 1.0);
|
||||||
|
final width = pageController.position.viewportDimension;
|
||||||
|
opacity = (1 - position.abs()).roundToDouble().clamp(0, 1);
|
||||||
|
dx = position * width;
|
||||||
|
}
|
||||||
|
return Opacity(
|
||||||
|
opacity: opacity,
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: Offset(dx, 0),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
|
@ -290,19 +290,24 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
void _onAppLifecycleStateChanged() {
|
void _onAppLifecycleStateChanged() {
|
||||||
switch (AvesApp.lifecycleStateNotifier.value) {
|
switch (AvesApp.lifecycleStateNotifier.value) {
|
||||||
case AppLifecycleState.inactive:
|
case AppLifecycleState.inactive:
|
||||||
|
// inactive: when losing focus
|
||||||
_onAppInactive();
|
_onAppInactive();
|
||||||
case AppLifecycleState.hidden:
|
|
||||||
case AppLifecycleState.paused:
|
case AppLifecycleState.paused:
|
||||||
case AppLifecycleState.detached:
|
case AppLifecycleState.detached:
|
||||||
|
// paused: when switching to another app
|
||||||
|
// detached: when app is without a view
|
||||||
|
viewerController.autopilot = false;
|
||||||
pauseVideoControllers();
|
pauseVideoControllers();
|
||||||
case AppLifecycleState.resumed:
|
case AppLifecycleState.resumed:
|
||||||
availability.onResume();
|
availability.onResume();
|
||||||
|
case AppLifecycleState.hidden:
|
||||||
|
// hidden: transient state between `inactive` and `paused`
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onAppInactive() async {
|
Future<void> _onAppInactive() async {
|
||||||
final playingController = context.read<VideoConductor>().getPlayingController();
|
final playingController = context.read<VideoConductor>().getPlayingController();
|
||||||
viewerController.autopilot = false;
|
|
||||||
bool enabledPip = false;
|
bool enabledPip = false;
|
||||||
if (settings.videoBackgroundMode == VideoBackgroundMode.pip) {
|
if (settings.videoBackgroundMode == VideoBackgroundMode.pip) {
|
||||||
enabledPip |= await _enablePictureInPicture();
|
enabledPip |= await _enablePictureInPicture();
|
||||||
|
|
|
@ -15,6 +15,7 @@ import 'package:aves/widgets/viewer/overlay/details/position_title.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/details/rating_tags.dart';
|
import 'package:aves/widgets/viewer/overlay/details/rating_tags.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/details/shooting.dart';
|
import 'package:aves/widgets/viewer/overlay/details/shooting.dart';
|
||||||
import 'package:aves/widgets/viewer/page_entry_builder.dart';
|
import 'package:aves/widgets/viewer/page_entry_builder.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';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
@ -44,14 +45,13 @@ class ViewerDetailOverlay extends StatefulWidget {
|
||||||
class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
List<AvesEntry> get entries => widget.entries;
|
List<AvesEntry> get entries => widget.entries;
|
||||||
|
|
||||||
AvesEntry? get entry {
|
AvesEntry? get entry => entryForIndex(widget.index);
|
||||||
final index = widget.index;
|
|
||||||
return index < entries.length ? entries[index] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
late Future<List<dynamic>?> _detailLoader;
|
AvesEntry? entryForIndex(int index) => index < entries.length ? entries[index] : null;
|
||||||
|
|
||||||
|
late Future<OverlayMetadata> _detailLoader;
|
||||||
AvesEntry? _lastEntry;
|
AvesEntry? _lastEntry;
|
||||||
List<dynamic>? _lastDetails;
|
OverlayMetadata _lastDetails = const OverlayMetadata();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -62,7 +62,8 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant ViewerDetailOverlay oldWidget) {
|
void didUpdateWidget(covariant ViewerDetailOverlay oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
if (entry != _lastEntry) {
|
final newEntry = entryForIndex(widget.index);
|
||||||
|
if (newEntry != entryForIndex(oldWidget.index) && newEntry != _lastEntry) {
|
||||||
_initDetailLoader();
|
_initDetailLoader();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,12 +71,17 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
void _initDetailLoader() {
|
void _initDetailLoader() {
|
||||||
final requestEntry = entry;
|
final requestEntry = entry;
|
||||||
if (requestEntry == null) {
|
if (requestEntry == null) {
|
||||||
_detailLoader = SynchronousFuture(null);
|
_detailLoader = SynchronousFuture(const OverlayMetadata());
|
||||||
} else {
|
} else {
|
||||||
_detailLoader = Future.wait([
|
_detailLoader = metadataFetchService.getFields(requestEntry, {
|
||||||
settings.showOverlayShootingDetails ? metadataFetchService.getOverlayMetadata(requestEntry) : Future.value(null),
|
if (settings.showOverlayShootingDetails) ...{
|
||||||
settings.showOverlayDescription ? metadataFetchService.getDescription(requestEntry) : Future.value(null),
|
MetadataSyntheticField.aperture,
|
||||||
]);
|
MetadataSyntheticField.exposureTime,
|
||||||
|
MetadataSyntheticField.focalLength,
|
||||||
|
MetadataSyntheticField.iso,
|
||||||
|
},
|
||||||
|
if (settings.showOverlayDescription) MetadataSyntheticField.description,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,24 +90,20 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
top: false,
|
top: false,
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: FutureBuilder<List<dynamic>?>(
|
child: FutureBuilder<OverlayMetadata>(
|
||||||
future: _detailLoader,
|
future: _detailLoader,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) {
|
if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) {
|
||||||
_lastDetails = snapshot.data;
|
_lastDetails = snapshot.data!;
|
||||||
_lastEntry = entry;
|
_lastEntry = entry;
|
||||||
}
|
}
|
||||||
if (_lastEntry == null) return const SizedBox();
|
if (_lastEntry == null) return const SizedBox();
|
||||||
final mainEntry = _lastEntry!;
|
final mainEntry = _lastEntry!;
|
||||||
|
|
||||||
final shootingDetails = _lastDetails![0];
|
|
||||||
final description = _lastDetails![1];
|
|
||||||
|
|
||||||
final multiPageController = widget.multiPageController;
|
final multiPageController = widget.multiPageController;
|
||||||
Widget _buildContent({AvesEntry? pageEntry}) => ViewerDetailOverlayContent(
|
Widget _buildContent({AvesEntry? pageEntry}) => ViewerDetailOverlayContent(
|
||||||
pageEntry: pageEntry ?? mainEntry,
|
pageEntry: pageEntry ?? mainEntry,
|
||||||
shootingDetails: shootingDetails,
|
details: _lastDetails,
|
||||||
description: description,
|
|
||||||
position: widget.hasCollection ? '${widget.index + 1}/${entries.length}' : null,
|
position: widget.hasCollection ? '${widget.index + 1}/${entries.length}' : null,
|
||||||
availableWidth: widget.availableSize.width,
|
availableWidth: widget.availableSize.width,
|
||||||
multiPageController: multiPageController,
|
multiPageController: multiPageController,
|
||||||
|
@ -122,8 +124,7 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
|
|
||||||
class ViewerDetailOverlayContent extends StatelessWidget {
|
class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
final AvesEntry pageEntry;
|
final AvesEntry pageEntry;
|
||||||
final OverlayMetadata? shootingDetails;
|
final OverlayMetadata details;
|
||||||
final String? description;
|
|
||||||
final String? position;
|
final String? position;
|
||||||
final double availableWidth;
|
final double availableWidth;
|
||||||
final MultiPageController? multiPageController;
|
final MultiPageController? multiPageController;
|
||||||
|
@ -140,8 +141,7 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
const ViewerDetailOverlayContent({
|
const ViewerDetailOverlayContent({
|
||||||
super.key,
|
super.key,
|
||||||
required this.pageEntry,
|
required this.pageEntry,
|
||||||
required this.shootingDetails,
|
required this.details,
|
||||||
required this.description,
|
|
||||||
required this.position,
|
required this.position,
|
||||||
required this.availableWidth,
|
required this.availableWidth,
|
||||||
required this.multiPageController,
|
required this.multiPageController,
|
||||||
|
@ -244,27 +244,27 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
|
|
||||||
Widget _buildDescriptionFullRow(BuildContext context) => _buildFullRowSwitcher(
|
Widget _buildDescriptionFullRow(BuildContext context) => _buildFullRowSwitcher(
|
||||||
context: context,
|
context: context,
|
||||||
visible: description != null,
|
visible: details.description != null,
|
||||||
builder: (context) => OverlayRowExpander(
|
builder: (context) => OverlayRowExpander(
|
||||||
expandedNotifier: expandedNotifier,
|
expandedNotifier: expandedNotifier,
|
||||||
child: OverlayDescriptionRow(description: description!),
|
child: OverlayDescriptionRow(description: details.description!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildShootingFullRow(BuildContext context, double subRowWidth) => _buildFullRowSwitcher(
|
Widget _buildShootingFullRow(BuildContext context, double subRowWidth) => _buildFullRowSwitcher(
|
||||||
context: context,
|
context: context,
|
||||||
visible: shootingDetails != null && shootingDetails!.isNotEmpty,
|
visible: details.hasShootingDetails,
|
||||||
builder: (context) => SizedBox(
|
builder: (context) => SizedBox(
|
||||||
width: subRowWidth,
|
width: subRowWidth,
|
||||||
child: OverlayShootingRow(details: shootingDetails!),
|
child: OverlayShootingRow(details: details),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildShootingSubRow(BuildContext context, double subRowWidth) => _buildSubRowSwitcher(
|
Widget _buildShootingSubRow(BuildContext context, double subRowWidth) => _buildSubRowSwitcher(
|
||||||
context: context,
|
context: context,
|
||||||
subRowWidth: subRowWidth,
|
subRowWidth: subRowWidth,
|
||||||
visible: shootingDetails != null && shootingDetails!.isNotEmpty,
|
visible: details.hasShootingDetails,
|
||||||
builder: (context) => OverlayShootingRow(details: shootingDetails!),
|
builder: (context) => OverlayShootingRow(details: details),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLocationFullRow(BuildContext context) => _buildFullRowSwitcher(
|
Widget _buildLocationFullRow(BuildContext context) => _buildFullRowSwitcher(
|
||||||
|
|
|
@ -22,7 +22,7 @@ class OverlayRowExpander extends StatelessWidget {
|
||||||
textAlign: parent.textAlign,
|
textAlign: parent.textAlign,
|
||||||
softWrap: expanded,
|
softWrap: expanded,
|
||||||
overflow: parent.overflow,
|
overflow: parent.overflow,
|
||||||
maxLines: expanded ? null : 42,
|
maxLines: expanded ? 16 : 1,
|
||||||
textWidthBasis: parent.textWidthBasis,
|
textWidthBasis: parent.textWidthBasis,
|
||||||
child: child!,
|
child: child!,
|
||||||
);
|
);
|
||||||
|
|
|
@ -42,16 +42,13 @@ mixin HistogramMixin {
|
||||||
final blueLevels = List.filled(bins, 0);
|
final blueLevels = List.filled(bins, 0);
|
||||||
|
|
||||||
final view = Uint8List.view(data.buffer);
|
final view = Uint8List.view(data.buffer);
|
||||||
final pixelCount = view.length / 4;
|
final viewSize = view.length;
|
||||||
for (var i = 0; i < pixelCount; i += 4) {
|
for (var i = 0; i < viewSize; i += 4) {
|
||||||
final a = view[i + 3];
|
final a = view[i + 3];
|
||||||
if (a > 0) {
|
if (a > 0) {
|
||||||
final r = view[i + 0];
|
redLevels[view[i + 0]]++;
|
||||||
final g = view[i + 1];
|
greenLevels[view[i + 1]]++;
|
||||||
final b = view[i + 2];
|
blueLevels[view[i + 2]]++;
|
||||||
redLevels[r]++;
|
|
||||||
greenLevels[g]++;
|
|
||||||
blueLevels[b]++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,14 +72,17 @@ mixin HistogramMixin {
|
||||||
const normMax = bins - 1;
|
const normMax = bins - 1;
|
||||||
|
|
||||||
final view = Uint8List.view(data.buffer);
|
final view = Uint8List.view(data.buffer);
|
||||||
final pixelCount = view.length / 4;
|
final viewSize = view.length;
|
||||||
for (var i = 0; i < pixelCount; i += 4) {
|
for (var i = 0; i < viewSize; i += 4) {
|
||||||
final a = view[i + 3];
|
final a = view[i + 3];
|
||||||
if (a > 0) {
|
if (a > 0) {
|
||||||
final r = view[i + 0];
|
final r = view[i + 0];
|
||||||
final g = view[i + 1];
|
final g = view[i + 1];
|
||||||
final b = view[i + 2];
|
final b = view[i + 2];
|
||||||
lumLevels[(Color.fromARGB(a, r, g, b).computeLuminance() * normMax).round()]++;
|
// `Color.computeLuminance()` is more accurate, but slower
|
||||||
|
// and photo software typically use the simpler formula
|
||||||
|
final luminance = (r * 0.3 + g * 0.59 + b * 0.11) / 255;
|
||||||
|
lumLevels[(luminance * normMax).round()]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,10 +89,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -8,6 +8,7 @@ enum EntrySetAction {
|
||||||
searchCollection,
|
searchCollection,
|
||||||
toggleTitleSearch,
|
toggleTitleSearch,
|
||||||
addShortcut,
|
addShortcut,
|
||||||
|
setHome,
|
||||||
emptyBin,
|
emptyBin,
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
map,
|
map,
|
||||||
|
@ -47,6 +48,7 @@ class EntrySetActions {
|
||||||
EntrySetAction.searchCollection,
|
EntrySetAction.searchCollection,
|
||||||
EntrySetAction.toggleTitleSearch,
|
EntrySetAction.toggleTitleSearch,
|
||||||
EntrySetAction.addShortcut,
|
EntrySetAction.addShortcut,
|
||||||
|
EntrySetAction.setHome,
|
||||||
null,
|
null,
|
||||||
EntrySetAction.map,
|
EntrySetAction.map,
|
||||||
EntrySetAction.slideshow,
|
EntrySetAction.slideshow,
|
||||||
|
@ -60,11 +62,9 @@ class EntrySetActions {
|
||||||
static const collectionEditorBrowsing = [
|
static const collectionEditorBrowsing = [
|
||||||
EntrySetAction.searchCollection,
|
EntrySetAction.searchCollection,
|
||||||
EntrySetAction.toggleTitleSearch,
|
EntrySetAction.toggleTitleSearch,
|
||||||
EntrySetAction.addShortcut,
|
|
||||||
EntrySetAction.map,
|
EntrySetAction.map,
|
||||||
EntrySetAction.slideshow,
|
EntrySetAction.slideshow,
|
||||||
EntrySetAction.stats,
|
EntrySetAction.stats,
|
||||||
EntrySetAction.rescan,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// `null` items are converted to dividers
|
// `null` items are converted to dividers
|
||||||
|
@ -98,7 +98,6 @@ class EntrySetActions {
|
||||||
EntrySetAction.map,
|
EntrySetAction.map,
|
||||||
EntrySetAction.slideshow,
|
EntrySetAction.slideshow,
|
||||||
EntrySetAction.stats,
|
EntrySetAction.stats,
|
||||||
EntrySetAction.rescan,
|
|
||||||
// editing actions are in their subsection
|
// editing actions are in their subsection
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
enum MetadataSyntheticField {
|
||||||
|
aperture,
|
||||||
|
description,
|
||||||
|
exposureTime,
|
||||||
|
focalLength,
|
||||||
|
iso,
|
||||||
|
}
|
||||||
|
|
||||||
enum MetadataField {
|
enum MetadataField {
|
||||||
exifDate,
|
exifDate,
|
||||||
exifDateOriginal,
|
exifDateOriginal,
|
||||||
|
|
|
@ -41,6 +41,7 @@ class SettingKeys {
|
||||||
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
|
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
|
||||||
static const keepScreenOnKey = 'keep_screen_on';
|
static const keepScreenOnKey = 'keep_screen_on';
|
||||||
static const homePageKey = 'home_page';
|
static const homePageKey = 'home_page';
|
||||||
|
static const homeCustomCollectionKey = 'home_custom_collection';
|
||||||
static const enableBottomNavigationBarKey = 'show_bottom_navigation_bar';
|
static const enableBottomNavigationBarKey = 'show_bottom_navigation_bar';
|
||||||
static const confirmCreateVaultKey = 'confirm_create_vault';
|
static const confirmCreateVaultKey = 'confirm_create_vault';
|
||||||
static const confirmDeleteForeverKey = 'confirm_delete_forever';
|
static const confirmDeleteForeverKey = 'confirm_delete_forever';
|
||||||
|
@ -60,6 +61,7 @@ class SettingKeys {
|
||||||
static const collectionBrowsingQuickActionsKey = 'collection_browsing_quick_actions';
|
static const collectionBrowsingQuickActionsKey = 'collection_browsing_quick_actions';
|
||||||
static const collectionSelectionQuickActionsKey = 'collection_selection_quick_actions';
|
static const collectionSelectionQuickActionsKey = 'collection_selection_quick_actions';
|
||||||
static const showThumbnailFavouriteKey = 'show_thumbnail_favourite';
|
static const showThumbnailFavouriteKey = 'show_thumbnail_favourite';
|
||||||
|
static const showThumbnailHdrKey = 'show_thumbnail_hdr';
|
||||||
static const thumbnailLocationIconKey = 'thumbnail_location_icon';
|
static const thumbnailLocationIconKey = 'thumbnail_location_icon';
|
||||||
static const thumbnailTagIconKey = 'thumbnail_tag_icon';
|
static const thumbnailTagIconKey = 'thumbnail_tag_icon';
|
||||||
static const showThumbnailMotionPhotoKey = 'show_thumbnail_motion_photo';
|
static const showThumbnailMotionPhotoKey = 'show_thumbnail_motion_photo';
|
||||||
|
|
|
@ -58,10 +58,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.8"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
@ -35,3 +35,7 @@ abstract class ReportService {
|
||||||
.join('\n'));
|
.join('\n'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnreportedStateError extends StateError {
|
||||||
|
UnreportedStateError(super.message);
|
||||||
|
}
|
|
@ -71,8 +71,10 @@ class PlatformReportService extends ReportService {
|
||||||
if (exception is PlatformException && stack != null) {
|
if (exception is PlatformException && stack != null) {
|
||||||
stack = ReportService.buildReportStack(stack, level: 2);
|
stack = ReportService.buildReportStack(stack, level: 2);
|
||||||
}
|
}
|
||||||
|
if (exception is! UnreportedStateError) {
|
||||||
return _instance?.recordError(exception, stack);
|
return _instance?.recordError(exception, stack);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> recordFlutterError(FlutterErrorDetails flutterErrorDetails) async {
|
Future<void> recordFlutterError(FlutterErrorDetails flutterErrorDetails) async {
|
||||||
|
|
|
@ -92,10 +92,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics
|
name: firebase_crashlytics
|
||||||
sha256: "5ccdf05de039f9544d0ba41c5ae2052ca2425985d32229911b09f69981164518"
|
sha256: "5125b7f3fcef2bfdd7e071afe7edcefd9597968003e44e073456c773d91694ee"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.8"
|
version: "3.4.9"
|
||||||
firebase_crashlytics_platform_interface:
|
firebase_crashlytics_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -179,10 +179,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.8"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
@ -58,10 +58,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.8"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
@ -96,10 +96,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -195,42 +195,42 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter
|
name: google_maps_flutter
|
||||||
sha256: d4914cb38b3dcb62c39c085d968d434de0f8050f00f4d9f5ba4a7c7e004934cb
|
sha256: ae66fef3e71261d7df2eff29b2a119e190b2884325ecaa55321b1e17b5504066
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0"
|
version: "2.5.3"
|
||||||
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: "4279a338b79288fad5c8b03e5ae6ec30888bff210e0bab10b1f31f31e5a90558"
|
sha256: "714530f865f13bb3b9505c58821c3baed5d247a871724acf5d2ea5808fbed02c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.0"
|
version: "2.6.2"
|
||||||
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: "6ad65362aeeeda44b7c2c807e36bf578ef4b1c163882e085bdb040bf2934b246"
|
sha256: b644d205c235f85dc60e22f46172a868b1cd642afd5a52b3808c789e461b025a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.3"
|
version: "2.4.1"
|
||||||
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: a3e9e6896501e566d902c6c69f010834d410ef4b7b5c18b90c77e871c86b7907
|
sha256: "6060779f020638a8eedeb0fb14234818e5fa32ec45a4653d6428ab436e2bbc64"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.4.3"
|
||||||
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: f893d1542c6562bc8299ef768fbbe92ade83c220ab3209b9477ec9f81ad585e4
|
sha256: "6245721c160d6f531c1ef568cf9bef8d660cd585a982aa75121269030163785a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.4+2"
|
version: "0.5.4+3"
|
||||||
html:
|
html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -243,10 +243,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -355,10 +355,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.8"
|
||||||
polylabel:
|
polylabel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -464,10 +464,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.2.0"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -485,5 +485,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0 <4.0.0"
|
dart: ">=3.2.3 <4.0.0"
|
||||||
flutter: ">=3.13.0"
|
flutter: ">=3.16.6"
|
||||||
|
|
|
@ -117,10 +117,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -231,10 +231,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.8"
|
||||||
polylabel:
|
polylabel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -103,10 +103,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -51,10 +51,10 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "flutter/flutter"
|
path: "flutter/flutter"
|
||||||
ref: background-lts
|
ref: background-lts
|
||||||
resolved-ref: "8eb0534b9f74d7242adf68e22a3578d235911466"
|
resolved-ref: "3fc7325f89225110b725cfbbb5e2560542a62e2e"
|
||||||
url: "https://github.com/deckerst/ffmpeg-kit.git"
|
url: "https://github.com/deckerst/ffmpeg-kit.git"
|
||||||
source: git
|
source: git
|
||||||
version: "6.0.2"
|
version: "6.0.3"
|
||||||
ffmpeg_kit_flutter_platform_interface:
|
ffmpeg_kit_flutter_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -104,10 +104,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.8"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
@ -14,12 +14,7 @@ dependencies:
|
||||||
path: ../aves_video
|
path: ../aves_video
|
||||||
# `video` version is necessary, as some videos make the app crash
|
# `video` version is necessary, as some videos make the app crash
|
||||||
# when using only `min` or `https` (the default)
|
# when using only `min` or `https` (the default)
|
||||||
# ffmpeg_kit_flutter_video: 6.0.2-LTS
|
# ffmpeg_kit_flutter_video: 6.0.3-LTS
|
||||||
# ffmpeg_kit_flutter:
|
|
||||||
# git:
|
|
||||||
# url: https://github.com/arthenica/ffmpeg-kit.git
|
|
||||||
# ref: development-flutter
|
|
||||||
# path: flutter/flutter
|
|
||||||
ffmpeg_kit_flutter:
|
ffmpeg_kit_flutter:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/deckerst/ffmpeg-kit.git
|
url: https://github.com/deckerst/ffmpeg-kit.git
|
||||||
|
|
|
@ -5,10 +5,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
|
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.9"
|
version: "3.4.10"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -102,6 +102,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -124,10 +132,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -140,10 +148,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image
|
name: image
|
||||||
sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271"
|
sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.3"
|
version: "4.1.4"
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -244,18 +252,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.8"
|
||||||
pointycastle:
|
pointycastle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pointycastle
|
name: pointycastle
|
||||||
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
|
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.7.3"
|
version: "3.7.4"
|
||||||
safe_local_storage:
|
safe_local_storage:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -385,10 +393,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f"
|
sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.2"
|
version: "4.3.3"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -433,10 +441,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.2.0"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue