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="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
|
||||
|
||||
### 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
|
||||
|
||||
### Added
|
||||
|
||||
- Cataloguing: detect/filter `Ultra HDR`
|
||||
- Viewer: show JPEG MPF dependent images (except thumbnails and HDR gain maps)
|
||||
- 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.
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -50,24 +50,27 @@ if (keystorePropertiesFile.exists()) {
|
|||
android {
|
||||
namespace 'deckers.thibault.aves'
|
||||
compileSdk 34
|
||||
ndkVersion flutter.ndkVersion
|
||||
// cf https://developer.android.com/studio/projects/install-ndk#default-ndk-per-agp
|
||||
ndkVersion '25.1.8937393'
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
lint {
|
||||
checkAllWarnings true
|
||||
warningsAsErrors true
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
// 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`,
|
||||
// so we exclude the extra `neon` libs bundled by `FFmpegKit`.
|
||||
exclude 'lib/armeabi-v7a/*_neon.so'
|
||||
jniLibs {
|
||||
// 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`,
|
||||
// so we exclude the extra `neon` libs bundled by `FFmpegKit`.
|
||||
excludes += ['lib/armeabi-v7a/*_neon.so']
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
@ -77,12 +80,9 @@ android {
|
|||
defaultConfig {
|
||||
applicationId packageName
|
||||
// minSdk constraints:
|
||||
// - Flutter & other plugins: 16
|
||||
// - Flutter & other plugins: 19 (cf `flutter.minSdkVersion`)
|
||||
// - google_maps_flutter v2.1.1: 20
|
||||
// - to build XML documents from XMP data, `metadata-extractor` and `PixyMeta` rely on `DocumentBuilder`,
|
||||
// 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
|
||||
minSdk flutter.minSdkVersion
|
||||
targetSdk 34
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
|
@ -215,7 +215,7 @@ dependencies {
|
|||
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||
implementation 'androidx.core:core-ktx:1.12.0'
|
||||
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.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
||||
|
@ -227,7 +227,7 @@ dependencies {
|
|||
implementation "com.github.bumptech.glide:glide:$glide_version"
|
||||
implementation 'com.google.android.material:material:1.11.0'
|
||||
// SLF4J implementation for `mp4parser`
|
||||
implementation 'org.slf4j:slf4j-simple:2.0.9'
|
||||
implementation 'org.slf4j:slf4j-simple:2.0.11'
|
||||
|
||||
// forked, built by JitPack:
|
||||
// - https://jitpack.io/p/deckerst/Android-TiffBitmapFactory
|
||||
|
@ -236,7 +236,7 @@ dependencies {
|
|||
implementation 'com.github.deckerst:Android-TiffBitmapFactory:90c06eebf4'
|
||||
implementation 'com.github.deckerst.mp4parser:isoparser: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
|
||||
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 deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||
import deckers.thibault.aves.model.FieldMap
|
||||
import deckers.thibault.aves.utils.MimeTypes
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
|
|
|
@ -109,7 +109,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
when (call.method) {
|
||||
"getAllMetadata" -> ioScope.launch { safe(call, result, ::getAllMetadata) }
|
||||
"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) }
|
||||
"getMultiPageInfo" -> ioScope.launch { safe(call, result, ::getMultiPageInfo) }
|
||||
"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) }
|
||||
"getContentResolverProp" -> ioScope.launch { safe(call, result, ::getContentPropValue) }
|
||||
"getDate" -> ioScope.launch { safe(call, result, ::getDate) }
|
||||
"getDescription" -> ioScope.launch { safe(call, result, ::getDescription) }
|
||||
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 uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
val metadataMap = HashMap<String, Any>()
|
||||
if (isVideo(mimeType)) {
|
||||
if (fields.isEmpty() || isVideo(mimeType)) {
|
||||
result.success(metadataMap)
|
||||
return
|
||||
}
|
||||
|
@ -842,10 +842,21 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
val metadata = Helper.safeRead(input)
|
||||
for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) {
|
||||
foundExif = true
|
||||
dir.getSafeRational(ExifDirectoryBase.TAG_FNUMBER) { metadataMap[KEY_APERTURE] = it.numerator.toDouble() / it.denominator }
|
||||
dir.getSafeRational(ExifDirectoryBase.TAG_EXPOSURE_TIME, saveExposureTime)
|
||||
dir.getSafeRational(ExifDirectoryBase.TAG_FOCAL_LENGTH) { metadataMap[KEY_FOCAL_LENGTH] = it.numerator.toDouble() / it.denominator }
|
||||
dir.getSafeInt(ExifDirectoryBase.TAG_ISO_EQUIVALENT) { metadataMap[KEY_ISO] = it }
|
||||
if (fields.contains(KEY_APERTURE)) {
|
||||
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)
|
||||
}
|
||||
if (fields.contains(KEY_FOCAL_LENGTH)) {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
@ -862,10 +873,18 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
try {
|
||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||
val exif = ExifInterface(input)
|
||||
exif.getSafeDouble(ExifInterface.TAG_F_NUMBER) { metadataMap[KEY_APERTURE] = it }
|
||||
exif.getSafeRational(ExifInterface.TAG_EXPOSURE_TIME, saveExposureTime)
|
||||
exif.getSafeDouble(ExifInterface.TAG_FOCAL_LENGTH) { metadataMap[KEY_FOCAL_LENGTH] = it }
|
||||
exif.getSafeInt(ExifInterface.TAG_PHOTOGRAPHIC_SENSITIVITY) { metadataMap[KEY_ISO] = it }
|
||||
if (fields.contains(KEY_APERTURE)) {
|
||||
exif.getSafeDouble(ExifInterface.TAG_F_NUMBER) { metadataMap[KEY_APERTURE] = it }
|
||||
}
|
||||
if (fields.contains(KEY_EXPOSURE_TIME)) {
|
||||
exif.getSafeRational(ExifInterface.TAG_EXPOSURE_TIME, saveExposureTime)
|
||||
}
|
||||
if (fields.contains(KEY_FOCAL_LENGTH)) {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// ExifInterface initialization can fail with a RuntimeException
|
||||
|
@ -877,6 +896,47 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
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) {
|
||||
val mimeType = call.argument<String>("mimeType")
|
||||
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
||||
|
@ -1191,70 +1251,6 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
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 {
|
||||
private val LOG_TAG = LogUtils.createTag<MetadataFetchHandler>()
|
||||
const val CHANNEL = "deckers.thibault/aves/metadata_fetch"
|
||||
|
@ -1319,6 +1315,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
|
||||
// overlay metadata
|
||||
private const val KEY_APERTURE = "aperture"
|
||||
private const val KEY_DESCRIPTION = "description"
|
||||
private const val KEY_EXPOSURE_TIME = "exposureTime"
|
||||
private const val KEY_FOCAL_LENGTH = "focalLength"
|
||||
private const val KEY_ISO = "iso"
|
||||
|
|
|
@ -18,6 +18,9 @@ import deckers.thibault.aves.utils.StorageUtils
|
|||
import io.flutter.plugin.common.MethodChannel
|
||||
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(
|
||||
private val context: Context,
|
||||
) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package deckers.thibault.aves.channel.calls.window
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Build
|
||||
import android.view.WindowManager
|
||||
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) {
|
||||
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)
|
||||
"isCutoutAware" -> Coresult.safe(call, result, ::isCutoutAware)
|
||||
"getCutoutInsets" -> Coresult.safe(call, result, ::getCutoutInsets)
|
||||
"supportsHdr" -> Coresult.safe(call, result, ::supportsHdr)
|
||||
"setHdrColorMode" -> Coresult.safe(call, result, ::setHdrColorMode)
|
||||
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 supportsHdr(call: MethodCall, result: MethodChannel.Result)
|
||||
|
||||
abstract fun setHdrColorMode(call: MethodCall, result: MethodChannel.Result)
|
||||
|
||||
companion object {
|
||||
private val LOG_TAG = LogUtils.createTag<WindowHandler>()
|
||||
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
|
||||
|
||||
var sampleSize = 1
|
||||
if (width > 0 && height > 0) {
|
||||
val customSize = width > 0 && height > 0
|
||||
if (customSize) {
|
||||
// determine sample size
|
||||
val fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
|
||||
if (fd == null) {
|
||||
|
@ -63,7 +64,7 @@ internal class TiffFetcher(val model: TiffImage, val width: Int, val height: Int
|
|||
val imageWidth = options.outWidth
|
||||
val imageHeight = options.outHeight
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +85,18 @@ internal class TiffFetcher(val model: TiffImage, val width: Int, val height: Int
|
|||
val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
|
||||
if (bitmap == null) {
|
||||
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 {
|
||||
callback.onDataReady(bitmap)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
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_EXIF
|
||||
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_XMP
|
||||
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.MetadataEntry
|
||||
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.xmp.XMP
|
||||
import pixy.meta.string.XMLUtils
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.*
|
||||
|
@ -105,6 +110,48 @@ object PixyMetaHelper {
|
|||
|
||||
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>) {
|
||||
val types = metadataTypes.map(::toMetadataType).toTypedArray()
|
||||
Metadata.removeMetadata(input, output, *types)
|
||||
|
|
|
@ -18,6 +18,12 @@ class AvesEntry(map: FieldMap) {
|
|||
val isRotated: Boolean
|
||||
get() = rotationDegrees % 180 == 90
|
||||
|
||||
val displayWidth: Int
|
||||
get() = if (isRotated) height else width
|
||||
|
||||
val displayHeight: Int
|
||||
get() = if (isRotated) width else height
|
||||
|
||||
companion object {
|
||||
// convenience method
|
||||
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.canEditXmp
|
||||
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.extensionFor
|
||||
import deckers.thibault.aves.utils.MimeTypes.isVideo
|
||||
import deckers.thibault.aves.utils.StorageUtils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import pixy.meta.meta.Metadata
|
||||
import pixy.meta.meta.MetadataType
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
@ -301,11 +298,18 @@ abstract class ImageProvider {
|
|||
sourceDocFile.copyTo(output)
|
||||
}
|
||||
} else {
|
||||
var targetWidthPx: Int = if (sourceEntry.isRotated) height else width
|
||||
var targetHeightPx: Int = if (sourceEntry.isRotated) width else height
|
||||
if (lengthUnit == LENGTH_UNIT_PERCENT) {
|
||||
targetWidthPx = sourceEntry.width * targetWidthPx / 100
|
||||
targetHeightPx = sourceEntry.height * targetHeightPx / 100
|
||||
val targetWidthPx: Int
|
||||
val targetHeightPx: Int
|
||||
when (lengthUnit) {
|
||||
LENGTH_UNIT_PERCENT -> {
|
||||
targetWidthPx = sourceEntry.displayWidth * width / 100
|
||||
targetHeightPx = sourceEntry.displayHeight * height / 100
|
||||
}
|
||||
|
||||
else -> {
|
||||
targetWidthPx = width
|
||||
targetHeightPx = height
|
||||
}
|
||||
}
|
||||
|
||||
val model: Any = if (pageId != null && MultiPageImage.isSupported(sourceMimeType)) {
|
||||
|
@ -405,39 +409,7 @@ abstract class ImageProvider {
|
|||
}
|
||||
|
||||
// copy IPTC / XMP via PixyMeta
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PixyMetaHelper.copyIptcXmp(context, sourceMimeType, sourceUri, targetMimeType, targetUri, editableFile)
|
||||
|
||||
// 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 {
|
||||
kotlin_version = '1.9.21'
|
||||
ksp_version = "$kotlin_version-1.0.15"
|
||||
agp_version = '8.1.4'
|
||||
agp_version = '8.2.2'
|
||||
glide_version = '4.16.0'
|
||||
// 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'
|
||||
|
|
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';
|
||||
|
||||
extension ExtraMetadataSyntheticFieldConvert on MetadataSyntheticField {
|
||||
String? get toPlatform => name;
|
||||
}
|
||||
|
||||
extension ExtraMetadataFieldConvert on MetadataField {
|
||||
MetadataType get type {
|
||||
switch (this) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves_report/aves_report.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
@ -46,14 +47,14 @@ class ThumbnailProvider extends ImageProvider<ThumbnailProviderKey> {
|
|||
taskKey: key,
|
||||
);
|
||||
if (bytes.isEmpty) {
|
||||
throw StateError('$uri ($mimeType) loading failed');
|
||||
throw UnreportedStateError('$uri ($mimeType) loading failed');
|
||||
}
|
||||
final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
|
||||
return await decode(buffer);
|
||||
} catch (error) {
|
||||
// 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');
|
||||
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 'package:aves/services/common/services.dart';
|
||||
import 'package:aves_report/aves_report.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
@ -64,14 +65,14 @@ class UriImage extends ImageProvider<UriImage> with EquatableMixin {
|
|||
},
|
||||
);
|
||||
if (bytes.isEmpty) {
|
||||
throw StateError('$uri ($mimeType) loading failed');
|
||||
throw UnreportedStateError('$uri ($mimeType) loading failed');
|
||||
}
|
||||
final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
|
||||
return await decode(buffer);
|
||||
} catch (error) {
|
||||
// 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');
|
||||
throw StateError('$mimeType decoding failed (page $pageId)');
|
||||
throw UnreportedStateError('$mimeType decoding failed (page $pageId)');
|
||||
} finally {
|
||||
unawaited(chunkEvents.close());
|
||||
}
|
||||
|
|
|
@ -479,7 +479,7 @@
|
|||
"@statsTopCountriesSectionTitle": {},
|
||||
"settingsActionImport": "إستيراد",
|
||||
"@settingsActionImport": {},
|
||||
"viewerInfoLabelSize": "المقاس",
|
||||
"viewerInfoLabelSize": "الحجم",
|
||||
"@viewerInfoLabelSize": {},
|
||||
"locationPickerUseThisLocationButton": "استخدم هذا الموقع",
|
||||
"@locationPickerUseThisLocationButton": {},
|
||||
|
@ -1518,5 +1518,11 @@
|
|||
"filterNoDateLabel": "غير مؤرخ",
|
||||
"@filterNoDateLabel": {},
|
||||
"exportEntryDialogWriteMetadata": "كتابة البيانات الوصفية",
|
||||
"@exportEntryDialogWriteMetadata": {}
|
||||
"@exportEntryDialogWriteMetadata": {},
|
||||
"settingsThumbnailShowHdrIcon": "إظهار أيقونة HDR",
|
||||
"@settingsThumbnailShowHdrIcon": {},
|
||||
"collectionActionSetHome": "تعيين كخلفية",
|
||||
"@collectionActionSetHome": {},
|
||||
"setHomeCustomCollection": "مجموعة مخصصة",
|
||||
"@setHomeCustomCollection": {}
|
||||
}
|
||||
|
|
|
@ -649,7 +649,7 @@
|
|||
"@viewerTransitionSlide": {},
|
||||
"overlayHistogramRGB": "RGB",
|
||||
"@overlayHistogramRGB": {},
|
||||
"overlayHistogramNone": "Няма",
|
||||
"overlayHistogramNone": "Не",
|
||||
"@overlayHistogramNone": {},
|
||||
"overlayHistogramLuminance": "Яркасць",
|
||||
"@overlayHistogramLuminance": {},
|
||||
|
@ -931,7 +931,7 @@
|
|||
"@collectionGroupNone": {},
|
||||
"searchRatingSectionTitle": "Рэйтынгі",
|
||||
"@searchRatingSectionTitle": {},
|
||||
"settingsDisabled": "Адключана",
|
||||
"settingsDisabled": "Адкл.",
|
||||
"@settingsDisabled": {},
|
||||
"settingsActionImportDialogTitle": "Імпарт",
|
||||
"@settingsActionImportDialogTitle": {},
|
||||
|
@ -1518,5 +1518,11 @@
|
|||
"placeholders": {
|
||||
"minutes": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"collectionActionSetHome": "Усталяваць як галоўную",
|
||||
"@collectionActionSetHome": {},
|
||||
"setHomeCustomCollection": "Уласная калекцыя",
|
||||
"@setHomeCustomCollection": {},
|
||||
"settingsThumbnailShowHdrIcon": "Паказаць значок HDR",
|
||||
"@settingsThumbnailShowHdrIcon": {}
|
||||
}
|
||||
|
|
|
@ -570,6 +570,7 @@
|
|||
"collectionActionShowTitleSearch": "Show title filter",
|
||||
"collectionActionHideTitleSearch": "Hide title filter",
|
||||
"collectionActionAddShortcut": "Add shortcut",
|
||||
"collectionActionSetHome": "Set as home",
|
||||
"collectionActionEmptyBin": "Empty bin",
|
||||
"collectionActionCopy": "Copy to album",
|
||||
"collectionActionMove": "Move to album",
|
||||
|
@ -757,6 +758,7 @@
|
|||
"settingsNavigationSectionTitle": "Navigation",
|
||||
"settingsHomeTile": "Home",
|
||||
"settingsHomeDialogTitle": "Home",
|
||||
"setHomeCustomCollection": "Custom collection",
|
||||
"settingsShowBottomNavigationBar": "Show bottom navigation bar",
|
||||
"settingsKeepScreenOnTile": "Keep screen on",
|
||||
"settingsKeepScreenOnDialogTitle": "Keep Screen On",
|
||||
|
@ -781,6 +783,7 @@
|
|||
"settingsThumbnailSectionTitle": "Thumbnails",
|
||||
"settingsThumbnailOverlayTile": "Overlay",
|
||||
"settingsThumbnailOverlayPageTitle": "Overlay",
|
||||
"settingsThumbnailShowHdrIcon": "Show HDR icon",
|
||||
"settingsThumbnailShowFavouriteIcon": "Show favorite icon",
|
||||
"settingsThumbnailShowTagIcon": "Show tag icon",
|
||||
"settingsThumbnailShowLocationIcon": "Show location icon",
|
||||
|
|
|
@ -1360,5 +1360,11 @@
|
|||
"entryActionCast": "Echar",
|
||||
"@entryActionCast": {},
|
||||
"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": {},
|
||||
"settingsThumbnailSectionTitle": "Miniaturak",
|
||||
"@settingsThumbnailSectionTitle": {},
|
||||
"settingsThumbnailShowFavouriteIcon": "Gogokoen ikonoa erakutsi",
|
||||
"settingsThumbnailShowFavouriteIcon": "Erakutsi gogokoen ikonoa",
|
||||
"@settingsThumbnailShowFavouriteIcon": {},
|
||||
"settingsThumbnailShowTagIcon": "Etiketaren ikonoa erakutsi",
|
||||
"settingsThumbnailShowTagIcon": "Erakutsi etiketaren ikonoa",
|
||||
"@settingsThumbnailShowTagIcon": {},
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Mugimendu-argazkiaren ikonoa erakutsi",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Erakutsi mugimendu-argazkiaren ikonoa",
|
||||
"@settingsThumbnailShowMotionPhotoIcon": {},
|
||||
"settingsThumbnailShowRawIcon": "Raw ikonoa erakutsi",
|
||||
"settingsThumbnailShowRawIcon": "Erakutsi raw ikonoa",
|
||||
"@settingsThumbnailShowRawIcon": {},
|
||||
"settingsThumbnailShowVideoDuration": "Bideoaren iraupena erakutsi",
|
||||
"settingsThumbnailShowVideoDuration": "Erakutsi bideoaren iraupena",
|
||||
"@settingsThumbnailShowVideoDuration": {},
|
||||
"settingsCollectionQuickActionEditorPageTitle": "Ekintza azkarrak",
|
||||
"@settingsCollectionQuickActionEditorPageTitle": {},
|
||||
|
@ -975,13 +975,13 @@
|
|||
"@settingsCollectionQuickActionTabBrowsing": {},
|
||||
"settingsThumbnailOverlayPageTitle": "Inkrustazioak",
|
||||
"@settingsThumbnailOverlayPageTitle": {},
|
||||
"settingsThumbnailShowLocationIcon": "Kokapenaren ikonoa erakutsi",
|
||||
"settingsThumbnailShowLocationIcon": "Erakutsi kokalekuaren ikonoa",
|
||||
"@settingsThumbnailShowLocationIcon": {},
|
||||
"settingsThumbnailShowRating": "Balorazioa erakutsi",
|
||||
"settingsThumbnailShowRating": "Erakutsi balorazioa",
|
||||
"@settingsThumbnailShowRating": {},
|
||||
"settingsCollectionQuickActionsTile": "Ekintza azkarrak",
|
||||
"@settingsCollectionQuickActionsTile": {},
|
||||
"settingsCollectionQuickActionTabSelecting": "Aukeraketa",
|
||||
"settingsCollectionQuickActionTabSelecting": "Hautapena",
|
||||
"@settingsCollectionQuickActionTabSelecting": {},
|
||||
"searchMetadataSectionTitle": "Metadatuak",
|
||||
"@searchMetadataSectionTitle": {},
|
||||
|
@ -1025,7 +1025,7 @@
|
|||
"@settingsViewerSectionTitle": {},
|
||||
"settingsViewerGestureSideTapNext": "Pantailaren ertzetan sakatu aurreko/hurrengo elementua bistaratzeko",
|
||||
"@settingsViewerGestureSideTapNext": {},
|
||||
"settingsViewerUseCutout": "Moztutako eremua erabili",
|
||||
"settingsViewerUseCutout": "Erabili moztutako eremua",
|
||||
"@settingsViewerUseCutout": {},
|
||||
"settingsImageBackground": "Atzeko irudia",
|
||||
"@settingsImageBackground": {},
|
||||
|
@ -1043,15 +1043,15 @@
|
|||
"@settingsViewerQuickActionEmpty": {},
|
||||
"settingsViewerOverlayPageTitle": "Inkrustazioak",
|
||||
"@settingsViewerOverlayPageTitle": {},
|
||||
"settingsViewerShowMinimap": "Bistaratu minimapa",
|
||||
"settingsViewerShowMinimap": "Erakutsi minimapa",
|
||||
"@settingsViewerShowMinimap": {},
|
||||
"settingsViewerShowInformation": "Bistaratu informazioa",
|
||||
"settingsViewerShowInformation": "Erakutsi informazioa",
|
||||
"@settingsViewerShowInformation": {},
|
||||
"settingsViewerShowInformationSubtitle": "Bistaratu izenburua, data, kokapena, etab.",
|
||||
"settingsViewerShowInformationSubtitle": "Erakutsi izenburua, data, kokalekua, etab.",
|
||||
"@settingsViewerShowInformationSubtitle": {},
|
||||
"settingsViewerShowDescription": "Bistaratu deskribapena",
|
||||
"settingsViewerShowDescription": "Erakutsi azalpena",
|
||||
"@settingsViewerShowDescription": {},
|
||||
"settingsViewerShowOverlayThumbnails": "Bistaratu miniaturak",
|
||||
"settingsViewerShowOverlayThumbnails": "Erakutsi miniaturak",
|
||||
"@settingsViewerShowOverlayThumbnails": {},
|
||||
"settingsSlideshowTransitionTile": "Trantsizioa",
|
||||
"@settingsSlideshowTransitionTile": {},
|
||||
|
@ -1141,13 +1141,13 @@
|
|||
"@settingsMotionPhotoAutoPlay": {},
|
||||
"settingsViewerOverlayTile": "Inkrustazioak",
|
||||
"@settingsViewerOverlayTile": {},
|
||||
"settingsViewerShowOverlayOnOpening": "Bistaratu hasieran",
|
||||
"settingsViewerShowOverlayOnOpening": "Erakutsi irekitzean",
|
||||
"@settingsViewerShowOverlayOnOpening": {},
|
||||
"settingsViewerShowRatingTags": "Bistaratu balorazioa eta etiketak",
|
||||
"settingsViewerShowRatingTags": "Erakutsi balorazioa eta etiketak",
|
||||
"@settingsViewerShowRatingTags": {},
|
||||
"settingsViewerEnableOverlayBlurEffect": "Lausotze efektua",
|
||||
"@settingsViewerEnableOverlayBlurEffect": {},
|
||||
"settingsViewerShowShootingDetails": "Bistaratu hartualdiaren xehetasunak",
|
||||
"settingsViewerShowShootingDetails": "Erakutsi hartualdiaren xehetasunak",
|
||||
"@settingsViewerShowShootingDetails": {},
|
||||
"settingsViewerSlideshowPageTitle": "Aurkezpena",
|
||||
"@settingsViewerSlideshowPageTitle": {},
|
||||
|
@ -1155,7 +1155,7 @@
|
|||
"@settingsViewerSlideshowTile": {},
|
||||
"settingsSlideshowShuffle": "Nahastu",
|
||||
"@settingsSlideshowShuffle": {},
|
||||
"settingsSlideshowFillScreen": "Pantaila bete",
|
||||
"settingsSlideshowFillScreen": "Bete pantaila",
|
||||
"@settingsSlideshowFillScreen": {},
|
||||
"settingsSlideshowRepeat": "Errepikatu",
|
||||
"@settingsSlideshowRepeat": {},
|
||||
|
@ -1165,11 +1165,11 @@
|
|||
"@settingsSlideshowVideoPlaybackTile": {},
|
||||
"settingsSubtitleThemeTextPositionTile": "Testuaren posizioa",
|
||||
"@settingsSubtitleThemeTextPositionTile": {},
|
||||
"settingsVideoShowVideos": "Bideoak erakutsi",
|
||||
"settingsVideoShowVideos": "Erakutsi bideoak",
|
||||
"@settingsVideoShowVideos": {},
|
||||
"settingsVideoPageTitle": "Bideoen ezarpenak",
|
||||
"settingsVideoPageTitle": "Bideoaren ezarpenak",
|
||||
"@settingsVideoPageTitle": {},
|
||||
"settingsVideoSectionTitle": "Bideo",
|
||||
"settingsVideoSectionTitle": "Bideoa",
|
||||
"@settingsVideoSectionTitle": {},
|
||||
"settingsVideoEnableHardwareAcceleration": "Hardwarearen azelerazioa",
|
||||
"@settingsVideoEnableHardwareAcceleration": {},
|
||||
|
@ -1427,13 +1427,13 @@
|
|||
"@patternDialogConfirm": {},
|
||||
"settingsVideoEnablePip": "Bideoa leihotxoan",
|
||||
"@settingsVideoEnablePip": {},
|
||||
"settingsVideoBackgroundMode": "Erreprodukzioa atzeko planoan",
|
||||
"settingsVideoBackgroundMode": "Atzeko planoko modua",
|
||||
"@settingsVideoBackgroundMode": {},
|
||||
"settingsVideoBackgroundModeDialogTitle": "Atzeko planoko modua",
|
||||
"@settingsVideoBackgroundModeDialogTitle": {},
|
||||
"settingsCollectionBurstPatternsNone": "Bat ere ez",
|
||||
"@settingsCollectionBurstPatternsNone": {},
|
||||
"settingsCollectionBurstPatternsTile": "Segida moduak",
|
||||
"settingsCollectionBurstPatternsTile": "Segida ereduak",
|
||||
"@settingsCollectionBurstPatternsTile": {},
|
||||
"tagPlaceholderState": "Egoera",
|
||||
"@tagPlaceholderState": {},
|
||||
|
@ -1518,5 +1518,11 @@
|
|||
"entryActionCast": "Igorri",
|
||||
"@entryActionCast": {},
|
||||
"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": {},
|
||||
"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": {},
|
||||
"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": {},
|
||||
"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": {},
|
||||
"castDialogTitle": "전송 대상",
|
||||
"@castDialogTitle": {}
|
||||
"@castDialogTitle": {},
|
||||
"settingsThumbnailShowHdrIcon": "HDR 아이콘 표시",
|
||||
"@settingsThumbnailShowHdrIcon": {},
|
||||
"collectionActionSetHome": "홈으로 설정",
|
||||
"@collectionActionSetHome": {},
|
||||
"setHomeCustomCollection": "지정 미디어",
|
||||
"@setHomeCustomCollection": {}
|
||||
}
|
||||
|
|
|
@ -1518,5 +1518,11 @@
|
|||
"entryActionCast": "Cast",
|
||||
"@entryActionCast": {},
|
||||
"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": {},
|
||||
"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": {},
|
||||
"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": {},
|
||||
"continueButtonLabel": "DEVAM ET",
|
||||
"@continueButtonLabel": {},
|
||||
"cancelTooltip": "İptal et",
|
||||
"cancelTooltip": "İptal",
|
||||
"@cancelTooltip": {},
|
||||
"changeTooltip": "Değiştir",
|
||||
"@changeTooltip": {},
|
||||
|
@ -75,7 +75,7 @@
|
|||
"@chipActionHide": {},
|
||||
"chipActionPin": "Başa sabitle",
|
||||
"@chipActionPin": {},
|
||||
"chipActionUnpin": "Baştan çıkar",
|
||||
"chipActionUnpin": "Sabitlemeyi kaldır",
|
||||
"@chipActionUnpin": {},
|
||||
"chipActionRename": "Yeniden adlandır",
|
||||
"@chipActionRename": {},
|
||||
|
@ -95,7 +95,7 @@
|
|||
"@entryActionInfo": {},
|
||||
"entryActionRename": "Yeniden adlandır",
|
||||
"@entryActionRename": {},
|
||||
"entryActionRestore": "Dışa aktar",
|
||||
"entryActionRestore": "Geri getir",
|
||||
"@entryActionRestore": {},
|
||||
"entryActionRotateCCW": "Saat yönünün tersine döndür",
|
||||
"@entryActionRotateCCW": {},
|
||||
|
@ -129,11 +129,11 @@
|
|||
"@entryActionAddFavourite": {},
|
||||
"entryActionRemoveFavourite": "Favorilerden kaldır",
|
||||
"@entryActionRemoveFavourite": {},
|
||||
"videoActionCaptureFrame": "Çerçeve yakala",
|
||||
"videoActionCaptureFrame": "Kareyi yakala",
|
||||
"@videoActionCaptureFrame": {},
|
||||
"videoActionMute": "Sustur",
|
||||
"videoActionMute": "Sessize al",
|
||||
"@videoActionMute": {},
|
||||
"videoActionUnmute": "Susturmayı kaldır",
|
||||
"videoActionUnmute": "Sesi aç",
|
||||
"@videoActionUnmute": {},
|
||||
"videoActionPause": "Duraklat",
|
||||
"@videoActionPause": {},
|
||||
|
@ -143,7 +143,7 @@
|
|||
"@videoActionReplay10": {},
|
||||
"videoActionSkip10": "10 saniye ileri git",
|
||||
"@videoActionSkip10": {},
|
||||
"videoActionSelectStreams": "Parça seç",
|
||||
"videoActionSelectStreams": "Ses parçası seç",
|
||||
"@videoActionSelectStreams": {},
|
||||
"videoActionSetSpeed": "Oynatma hızı",
|
||||
"@videoActionSetSpeed": {},
|
||||
|
@ -241,7 +241,7 @@
|
|||
"@nameConflictStrategySkip": {},
|
||||
"keepScreenOnNever": "Asla",
|
||||
"@keepScreenOnNever": {},
|
||||
"keepScreenOnViewerOnly": "Yalnızca görüntüleyici sayfası",
|
||||
"keepScreenOnViewerOnly": "Yalnızca görüntüleyici sayfasında",
|
||||
"@keepScreenOnViewerOnly": {},
|
||||
"keepScreenOnAlways": "Her zaman",
|
||||
"@keepScreenOnAlways": {},
|
||||
|
@ -367,7 +367,7 @@
|
|||
"@editEntryDialogCopyFromItem": {},
|
||||
"editEntryDateDialogExtractFromTitle": "Başlıktan ayıkla",
|
||||
"@editEntryDateDialogExtractFromTitle": {},
|
||||
"editEntryDateDialogShift": "Değişim",
|
||||
"editEntryDateDialogShift": "Değiştir",
|
||||
"@editEntryDateDialogShift": {},
|
||||
"editEntryDateDialogSourceFileModifiedDate": "Dosya değiştirilme tarihi",
|
||||
"@editEntryDateDialogSourceFileModifiedDate": {},
|
||||
|
@ -641,7 +641,7 @@
|
|||
"@tagEmpty": {},
|
||||
"binPageTitle": "Geri Dönüşüm Kutusu",
|
||||
"@binPageTitle": {},
|
||||
"searchCollectionFieldHint": "Koleksiyonu ara",
|
||||
"searchCollectionFieldHint": "Koleksiyonda ara",
|
||||
"@searchCollectionFieldHint": {},
|
||||
"searchRecentSectionTitle": "Yakın zamanda",
|
||||
"@searchRecentSectionTitle": {},
|
||||
|
@ -1169,7 +1169,7 @@
|
|||
"@settingsWidgetDisplayedItem": {},
|
||||
"settingsSubtitleThemeTextPositionDialogTitle": "Metin Konumu",
|
||||
"@settingsSubtitleThemeTextPositionDialogTitle": {},
|
||||
"filterNoAddressLabel": "Adres yok",
|
||||
"filterNoAddressLabel": "Adressiz",
|
||||
"@filterNoAddressLabel": {},
|
||||
"filterAspectRatioLandscapeLabel": "Yatay",
|
||||
"@filterAspectRatioLandscapeLabel": {},
|
||||
|
@ -1206,5 +1206,165 @@
|
|||
"tooManyItemsErrorDialogMessage": "Daha az ögeyle tekrar deneyin.",
|
||||
"@tooManyItemsErrorDialogMessage": {},
|
||||
"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": {},
|
||||
"castDialogTitle": "Пристрої трансляції",
|
||||
"@castDialogTitle": {}
|
||||
"@castDialogTitle": {},
|
||||
"settingsThumbnailShowHdrIcon": "Показати іконку HDR",
|
||||
"@settingsThumbnailShowHdrIcon": {},
|
||||
"setHomeCustomCollection": "Власна колекція",
|
||||
"@setHomeCustomCollection": {},
|
||||
"collectionActionSetHome": "Встановити як головну",
|
||||
"@collectionActionSetHome": {}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
"@filterNoLocationLabel": {},
|
||||
"videoActionPlay": "Phát",
|
||||
"@videoActionPlay": {},
|
||||
"entryActionSetAs": "Thiết lập như",
|
||||
"entryActionSetAs": "Đặt làm",
|
||||
"@entryActionSetAs": {},
|
||||
"filterLocatedLabel": "Đã định vị",
|
||||
"@filterLocatedLabel": {},
|
||||
|
@ -1518,5 +1518,11 @@
|
|||
"entryActionCast": "Truyền",
|
||||
"@entryActionCast": {},
|
||||
"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": {},
|
||||
"sourceStateCataloguing": "正在进行编目",
|
||||
"@sourceStateCataloguing": {},
|
||||
"sourceStateLocatingCountries": "正在定位国家",
|
||||
"sourceStateLocatingCountries": "正在定位地区",
|
||||
"@sourceStateLocatingCountries": {},
|
||||
"sourceStateLocatingPlaces": "正在定位地点",
|
||||
"@sourceStateLocatingPlaces": {},
|
||||
|
@ -67,7 +67,7 @@
|
|||
"@chipActionDelete": {},
|
||||
"chipActionGoToAlbumPage": "在相册中显示",
|
||||
"@chipActionGoToAlbumPage": {},
|
||||
"chipActionGoToCountryPage": "在国家中显示",
|
||||
"chipActionGoToCountryPage": "在地区中显示",
|
||||
"@chipActionGoToCountryPage": {},
|
||||
"chipActionGoToTagPage": "在标签中显示",
|
||||
"@chipActionGoToTagPage": {},
|
||||
|
@ -625,7 +625,7 @@
|
|||
"@drawerCollectionSphericalVideos": {},
|
||||
"drawerAlbumPage": "相册",
|
||||
"@drawerAlbumPage": {},
|
||||
"drawerCountryPage": "国家",
|
||||
"drawerCountryPage": "地区",
|
||||
"@drawerCountryPage": {},
|
||||
"drawerTagPage": "标签",
|
||||
"@drawerTagPage": {},
|
||||
|
@ -693,9 +693,9 @@
|
|||
"@createAlbumButtonLabel": {},
|
||||
"newFilterBanner": "新的",
|
||||
"@newFilterBanner": {},
|
||||
"countryPageTitle": "国家",
|
||||
"countryPageTitle": "地区",
|
||||
"@countryPageTitle": {},
|
||||
"countryEmpty": "无国家",
|
||||
"countryEmpty": "无地区",
|
||||
"@countryEmpty": {},
|
||||
"tagPageTitle": "标签",
|
||||
"@tagPageTitle": {},
|
||||
|
@ -711,7 +711,7 @@
|
|||
"@searchDateSectionTitle": {},
|
||||
"searchAlbumsSectionTitle": "相册",
|
||||
"@searchAlbumsSectionTitle": {},
|
||||
"searchCountriesSectionTitle": "国家",
|
||||
"searchCountriesSectionTitle": "地区",
|
||||
"@searchCountriesSectionTitle": {},
|
||||
"searchPlacesSectionTitle": "地点",
|
||||
"@searchPlacesSectionTitle": {},
|
||||
|
@ -1023,7 +1023,7 @@
|
|||
"@statsPageTitle": {},
|
||||
"statsWithGps": "{count, plural, other{{count} 项带位置信息}}",
|
||||
"@statsWithGps": {},
|
||||
"statsTopCountriesSectionTitle": "热门国家",
|
||||
"statsTopCountriesSectionTitle": "热门地区",
|
||||
"@statsTopCountriesSectionTitle": {},
|
||||
"statsTopPlacesSectionTitle": "热门地点",
|
||||
"@statsTopPlacesSectionTitle": {},
|
||||
|
@ -1197,7 +1197,7 @@
|
|||
"@chipActionConfigureVault": {},
|
||||
"chipActionCreateVault": "创建保险库",
|
||||
"@chipActionCreateVault": {},
|
||||
"chipActionShowCountryStates": "显示状态",
|
||||
"chipActionShowCountryStates": "显示区域",
|
||||
"@chipActionShowCountryStates": {},
|
||||
"viewerActionLock": "锁定查看器",
|
||||
"@viewerActionLock": {},
|
||||
|
@ -1255,7 +1255,7 @@
|
|||
"@vaultLockTypePattern": {},
|
||||
"albumTierVaults": "保险库",
|
||||
"@albumTierVaults": {},
|
||||
"settingsVideoResumptionModeTile": "恢复回放",
|
||||
"settingsVideoResumptionModeTile": "恢复播放",
|
||||
"@settingsVideoResumptionModeTile": {},
|
||||
"vaultBinUsageDialogMessage": "有些保险库正在使用资源回收站。",
|
||||
"@vaultBinUsageDialogMessage": {},
|
||||
|
@ -1275,9 +1275,9 @@
|
|||
"@editorTransformCrop": {},
|
||||
"filterTaggedLabel": "已标记",
|
||||
"@filterTaggedLabel": {},
|
||||
"statePageTitle": "地区",
|
||||
"statePageTitle": "区域",
|
||||
"@statePageTitle": {},
|
||||
"settingsVideoResumptionModeDialogTitle": "恢复回放",
|
||||
"settingsVideoResumptionModeDialogTitle": "恢复播放",
|
||||
"@settingsVideoResumptionModeDialogTitle": {},
|
||||
"settingsVideoBackgroundMode": "后台模式",
|
||||
"@settingsVideoBackgroundMode": {},
|
||||
|
@ -1305,9 +1305,9 @@
|
|||
"@newVaultWarningDialogMessage": {},
|
||||
"settingsDisablingBinWarningDialogMessage": "回收站中的项目将被永久删除。",
|
||||
"@settingsDisablingBinWarningDialogMessage": {},
|
||||
"statsTopStatesSectionTitle": "最多项的地区",
|
||||
"statsTopStatesSectionTitle": "最多项的区域",
|
||||
"@statsTopStatesSectionTitle": {},
|
||||
"settingsVideoPlaybackPageTitle": "回放",
|
||||
"settingsVideoPlaybackPageTitle": "播放",
|
||||
"@settingsVideoPlaybackPageTitle": {},
|
||||
"filterLocatedLabel": "位于",
|
||||
"@filterLocatedLabel": {},
|
||||
|
@ -1337,9 +1337,9 @@
|
|||
"@cropAspectRatioOriginal": {},
|
||||
"configureVaultDialogTitle": "设置保险库",
|
||||
"@configureVaultDialogTitle": {},
|
||||
"searchStatesSectionTitle": "地区",
|
||||
"searchStatesSectionTitle": "区域",
|
||||
"@searchStatesSectionTitle": {},
|
||||
"stateEmpty": "没有地区",
|
||||
"stateEmpty": "没有区域",
|
||||
"@stateEmpty": {},
|
||||
"aboutDataUsageData": "数据",
|
||||
"@aboutDataUsageData": {},
|
||||
|
@ -1353,12 +1353,18 @@
|
|||
"@newVaultDialogTitle": {},
|
||||
"settingsVideoBackgroundModeDialogTitle": "后台模式",
|
||||
"@settingsVideoBackgroundModeDialogTitle": {},
|
||||
"tagPlaceholderState": "地区",
|
||||
"tagPlaceholderState": "区域",
|
||||
"@tagPlaceholderState": {},
|
||||
"settingsViewerShowHistogram": "显示直方图",
|
||||
"@settingsViewerShowHistogram": {},
|
||||
"settingsVideoPlaybackTile": "回放",
|
||||
"settingsVideoPlaybackTile": "播放",
|
||||
"@settingsVideoPlaybackTile": {},
|
||||
"exportEntryDialogWriteMetadata": "写入元数据",
|
||||
"@exportEntryDialogWriteMetadata": {}
|
||||
"@exportEntryDialogWriteMetadata": {},
|
||||
"settingsThumbnailShowHdrIcon": "显示 HDR 图标",
|
||||
"@settingsThumbnailShowHdrIcon": {},
|
||||
"collectionActionSetHome": "设置为首页",
|
||||
"@collectionActionSetHome": {},
|
||||
"setHomeCustomCollection": "自定义媒体集",
|
||||
"@setHomeCustomCollection": {}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class Contributors {
|
|||
Contributor('Tijolinho', 'pedrohenrique29.alfenas@gmail.com'),
|
||||
Contributor('Piotr K', '1337.kelt@gmail.com'),
|
||||
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('Felipe Nogueira', 'contato.fnog@gmail.com'),
|
||||
Contributor('kaajjo', 'claymanoff@gmail.com'),
|
||||
|
@ -67,11 +67,15 @@ class Contributors {
|
|||
Contributor('Reza Almanda', 'rezaalmanda27@gmail.com'),
|
||||
Contributor('Sveinn í Felli', 'sv1@fellsnet.is'),
|
||||
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('nasreddineloukriz', 'nasreddineloukriz@gmail.com'),
|
||||
Contributor('Mohamed Zeroug', 'mzeroug19@gmail.com'),
|
||||
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('Htet Oo Hlaing', 'htetoh2006@outlook.com'), // Burmese
|
||||
// Contributor('Khant', 'khant@users.noreply.hosted.weblate.org'), // Burmese
|
||||
|
@ -86,7 +90,9 @@ class Contributors {
|
|||
// Contributor('امیر جهانگرد', 'ijahangard.a@gmail.com'), // Persian
|
||||
// Contributor('slasb37', 'p84haghi@gmail.com'), // Persian
|
||||
// Contributor('mimvahedi', 'vahedi0vahedi@gmail.com'), // Persian
|
||||
// Contributor('Prasanta-Hembram', 'Prasantahembram720@gmail.com'), // Santali
|
||||
// Contributor('mytja', 'mamnju21@gmail.com'), // Slovenian
|
||||
// Contributor('Shift18', 'bribable.lawyer@posteo.net'), // Swedish
|
||||
// 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',
|
||||
),
|
||||
Dependency(
|
||||
name: 'FFmpegKit',
|
||||
name: 'FFmpegKit (Aves fork)',
|
||||
license: lgpl3,
|
||||
sourceUrl: 'https://github.com/arthenica/ffmpeg-kit',
|
||||
sourceUrl: 'https://github.com/deckerst/ffmpeg-kit',
|
||||
),
|
||||
Dependency(
|
||||
name: 'Floating',
|
||||
|
@ -207,9 +207,9 @@ class Dependencies {
|
|||
|
||||
static const List<Dependency> flutterPackages = [
|
||||
Dependency(
|
||||
name: 'Charts (fzyzcjy fork)',
|
||||
name: 'Charts (Aves fork)',
|
||||
license: apache2,
|
||||
sourceUrl: 'https://github.com/fzyzcjy/charts',
|
||||
sourceUrl: 'https://github.com/deckerst/flutter_google_charts',
|
||||
),
|
||||
Dependency(
|
||||
name: 'Custom rounded rectangle border',
|
||||
|
@ -271,7 +271,7 @@ class Dependencies {
|
|||
Dependency(
|
||||
name: 'Panorama (Aves fork)',
|
||||
license: apache2,
|
||||
sourceUrl: 'https://github.com/zesage/panorama',
|
||||
sourceUrl: 'https://github.com/deckerst/aves_panorama',
|
||||
),
|
||||
Dependency(
|
||||
name: 'Pattern Lock',
|
||||
|
|
|
@ -20,28 +20,6 @@ class AppSupport {
|
|||
|
||||
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,
|
||||
// and DNG requires DNG-specific tags saved along standard Exif. So it was actually breaking DNG files.
|
||||
static bool canEditExif(String mimeType) {
|
||||
|
|
|
@ -32,7 +32,7 @@ extension ExtraAvesEntryProps on AvesEntry {
|
|||
|
||||
// size
|
||||
|
||||
bool get useTiles => canDecodeRegion && (width > 4096 || height > 4096);
|
||||
bool get useTiles => (width > 4096 || height > 4096) && !isAnimated;
|
||||
|
||||
bool get isSized => width > 0 && height > 0;
|
||||
|
||||
|
@ -127,8 +127,6 @@ extension ExtraAvesEntryProps on AvesEntry {
|
|||
|
||||
bool get canDecode => AppSupport.canDecode(mimeType);
|
||||
|
||||
bool get canDecodeRegion => AppSupport.canDecodeRegion(mimeType) && !isAnimated;
|
||||
|
||||
bool get canEditExif => AppSupport.canEditExif(mimeType);
|
||||
|
||||
bool get canEditIptc => AppSupport.canEditIptc(mimeType);
|
||||
|
|
|
@ -15,6 +15,11 @@ class LocationFilter extends CoveredCollectionFilter {
|
|||
late final String? _code;
|
||||
late final EntryFilter _test;
|
||||
|
||||
static final unlocated = LocationFilter(LocationLevel.place, '');
|
||||
static final located = unlocated.reverse();
|
||||
|
||||
bool get _isUnlocated => _location.isEmpty;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [level, _location, _code, reversed];
|
||||
|
||||
|
@ -23,7 +28,7 @@ class LocationFilter extends CoveredCollectionFilter {
|
|||
_location = split.isNotEmpty ? split[0] : location;
|
||||
_code = split.length > 1 ? split[1] : null;
|
||||
|
||||
if (_location.isEmpty) {
|
||||
if (_isUnlocated) {
|
||||
_test = (entry) => !entry.hasGps;
|
||||
} else {
|
||||
switch (level) {
|
||||
|
@ -81,11 +86,11 @@ class LocationFilter extends CoveredCollectionFilter {
|
|||
String get universalLabel => _location;
|
||||
|
||||
@override
|
||||
String getLabel(BuildContext context) => _location.isEmpty ? context.l10n.filterNoLocationLabel : _location;
|
||||
String getLabel(BuildContext context) => _isUnlocated ? context.l10n.filterNoLocationLabel : _location;
|
||||
|
||||
@override
|
||||
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true}) {
|
||||
if (_location.isEmpty) {
|
||||
if (_isUnlocated) {
|
||||
return Icon(AIcons.locationUnlocated, size: size);
|
||||
}
|
||||
switch (level) {
|
||||
|
|
|
@ -4,18 +4,17 @@ import 'package:flutter/foundation.dart';
|
|||
@immutable
|
||||
class OverlayMetadata extends Equatable {
|
||||
final double? aperture, focalLength;
|
||||
final String? exposureTime;
|
||||
final String? description, exposureTime;
|
||||
final int? iso;
|
||||
|
||||
@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 isNotEmpty => !isEmpty;
|
||||
bool get hasShootingDetails => aperture != null || exposureTime != null || focalLength != null || iso != null;
|
||||
|
||||
const OverlayMetadata({
|
||||
this.aperture,
|
||||
this.description,
|
||||
this.exposureTime,
|
||||
this.focalLength,
|
||||
this.iso,
|
||||
|
@ -24,6 +23,7 @@ class OverlayMetadata extends Equatable {
|
|||
factory OverlayMetadata.fromMap(Map map) {
|
||||
return OverlayMetadata(
|
||||
aperture: map['aperture'] as double?,
|
||||
description: map['description'] as String?,
|
||||
exposureTime: map['exposureTime'] as String?,
|
||||
focalLength: map['focalLength'] as double?,
|
||||
iso: map['iso'] as int?,
|
||||
|
|
|
@ -52,6 +52,7 @@ class SettingsDefaults {
|
|||
EntrySetAction.delete,
|
||||
];
|
||||
static const showThumbnailFavourite = true;
|
||||
static const showThumbnailHdr = true;
|
||||
static const thumbnailLocationIcon = ThumbnailOverlayLocationIcon.none;
|
||||
static const thumbnailTagIcon = ThumbnailOverlayTagIcon.none;
|
||||
static const showThumbnailMotionPhoto = true;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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:collection/collection.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
|
|
@ -30,6 +30,10 @@ mixin CollectionSettings on SettingsAccess {
|
|||
|
||||
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);
|
||||
|
||||
set thumbnailLocationIcon(ThumbnailOverlayLocationIcon newValue) => set(SettingKeys.thumbnailLocationIconKey, newValue.toString());
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/defaults.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
mixin NavigationSettings on SettingsAccess {
|
||||
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<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;
|
||||
|
||||
set enableBottomNavigationBar(bool newValue) => set(SettingKeys.enableBottomNavigationBarKey, newValue);
|
||||
|
|
|
@ -388,6 +388,7 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
|
|||
case SettingKeys.setMetadataDateBeforeFileOpKey:
|
||||
case SettingKeys.collectionSortReverseKey:
|
||||
case SettingKeys.showThumbnailFavouriteKey:
|
||||
case SettingKeys.showThumbnailHdrKey:
|
||||
case SettingKeys.showThumbnailMotionPhotoKey:
|
||||
case SettingKeys.showThumbnailRatingKey:
|
||||
case SettingKeys.showThumbnailRawKey:
|
||||
|
@ -471,6 +472,7 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
|
|||
} else {
|
||||
debugPrint('failed to import key=$key, value=$newValue is not a string');
|
||||
}
|
||||
case SettingKeys.homeCustomCollectionKey:
|
||||
case SettingKeys.drawerTypeBookmarksKey:
|
||||
case SettingKeys.drawerAlbumBookmarksKey:
|
||||
case SettingKeys.drawerPageBookmarksKey:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -22,14 +21,8 @@ class GeocodingService {
|
|||
'maxResults': 2,
|
||||
});
|
||||
return (result as List).cast<Map>().map(Address.fromMap).toList();
|
||||
} on PlatformException catch (e, stack) {
|
||||
if (!{
|
||||
'getAddress-empty',
|
||||
'getAddress-network',
|
||||
'getAddress-unavailable',
|
||||
}.contains(e.code)) {
|
||||
await reportService.recordError(e, stack);
|
||||
}
|
||||
} on PlatformException catch (_) {
|
||||
// do not report
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ abstract class MetadataFetchService {
|
|||
|
||||
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);
|
||||
|
||||
|
@ -39,8 +39,6 @@ abstract class MetadataFetchService {
|
|||
Future<String?> getContentResolverProp(AvesEntry entry, String prop);
|
||||
|
||||
Future<DateTime?> getDate(AvesEntry entry, MetadataField field);
|
||||
|
||||
Future<String?> getDescription(AvesEntry entry);
|
||||
}
|
||||
|
||||
class PlatformMetadataFetchService implements MetadataFetchService {
|
||||
|
@ -112,23 +110,29 @@ class PlatformMetadataFetchService implements MetadataFetchService {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<OverlayMetadata?> getOverlayMetadata(AvesEntry entry) async {
|
||||
if (entry.isSvg) return null;
|
||||
|
||||
try {
|
||||
// returns map with values for: 'aperture' (double), 'exposureTime' (description), 'focalLength' (double), 'iso' (int)
|
||||
final result = await _platform.invokeMethod('getOverlayMetadata', <String, dynamic>{
|
||||
'mimeType': entry.mimeType,
|
||||
'uri': entry.uri,
|
||||
'sizeBytes': entry.sizeBytes,
|
||||
}) as Map;
|
||||
return OverlayMetadata.fromMap(result);
|
||||
} on PlatformException catch (e, stack) {
|
||||
if (entry.isValid) {
|
||||
await reportService.recordError(e, stack);
|
||||
Future<OverlayMetadata> getFields(AvesEntry entry, Set<MetadataSyntheticField> fields) async {
|
||||
if (fields.isNotEmpty && !entry.isSvg) {
|
||||
try {
|
||||
// returns fields on demand, with various value types:
|
||||
// 'aperture' (double),
|
||||
// 'description' (string)
|
||||
// 'exposureTime' (string),
|
||||
// 'focalLength' (double),
|
||||
// 'iso' (int),
|
||||
final result = await _platform.invokeMethod('getFields', <String, dynamic>{
|
||||
'mimeType': entry.mimeType,
|
||||
'uri': entry.uri,
|
||||
'sizeBytes': entry.sizeBytes,
|
||||
'fields': fields.map((v) => v.toPlatform).toList(),
|
||||
}) as Map;
|
||||
return OverlayMetadata.fromMap(result);
|
||||
} on PlatformException catch (e, stack) {
|
||||
if (entry.isValid) {
|
||||
await reportService.recordError(e, stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return const OverlayMetadata();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -280,20 +284,4 @@ class PlatformMetadataFetchService implements MetadataFetchService {
|
|||
}
|
||||
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<EdgeInsets> getCutoutInsets();
|
||||
|
||||
Future<bool> supportsHdr();
|
||||
|
||||
Future<void> setHdrColorMode(bool on);
|
||||
}
|
||||
|
||||
class PlatformWindowService implements WindowService {
|
||||
static const _platform = MethodChannel('deckers.thibault/aves/window');
|
||||
|
||||
bool? _isCutoutAware, _supportsHdr;
|
||||
|
||||
@override
|
||||
Future<bool> isActivity() async {
|
||||
try {
|
||||
|
@ -90,8 +96,6 @@ class PlatformWindowService implements WindowService {
|
|||
}
|
||||
}
|
||||
|
||||
bool? _isCutoutAware;
|
||||
|
||||
@override
|
||||
Future<bool> isCutoutAware() async {
|
||||
if (_isCutoutAware != null) return SynchronousFuture(_isCutoutAware!);
|
||||
|
@ -121,4 +125,28 @@ class PlatformWindowService implements WindowService {
|
|||
}
|
||||
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
|
||||
context.l10n.collectionActionShowTitleSearch,
|
||||
EntrySetAction.addShortcut => context.l10n.collectionActionAddShortcut,
|
||||
EntrySetAction.setHome => context.l10n.collectionActionSetHome,
|
||||
EntrySetAction.emptyBin => context.l10n.collectionActionEmptyBin,
|
||||
// browsing or selecting
|
||||
EntrySetAction.map => context.l10n.menuActionMap,
|
||||
|
@ -61,6 +62,7 @@ extension ExtraEntrySetActionView on EntrySetAction {
|
|||
// different data depending on toggle state
|
||||
AIcons.filter,
|
||||
EntrySetAction.addShortcut => AIcons.addShortcut,
|
||||
EntrySetAction.setHome => AIcons.home,
|
||||
EntrySetAction.emptyBin => AIcons.emptyBin,
|
||||
// browsing or selecting
|
||||
EntrySetAction.map => AIcons.map,
|
||||
|
|
|
@ -154,6 +154,7 @@ class _BugReportState extends State<BugReport> with FeedbackMixin {
|
|||
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||
final storageVolumes = await storageService.getStorageVolumes();
|
||||
final storageGrants = await storageService.getGrantedDirectories();
|
||||
final supportsHdr = await windowService.supportsHdr();
|
||||
return [
|
||||
'Package: ${device.packageName}',
|
||||
'Installer: ${packageInfo.installerStore}',
|
||||
|
@ -162,7 +163,7 @@ class _BugReportState extends State<BugReport> with FeedbackMixin {
|
|||
'Android version: ${androidInfo.version.release}, API ${androidInfo.version.sdkInt}',
|
||||
'Android build: ${androidInfo.display}',
|
||||
'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'}',
|
||||
'System locales: ${WidgetsBinding.instance.platformDispatcher.locales.join(', ')}',
|
||||
'Storage volumes: ${storageVolumes.map((v) => v.path).join(', ')}',
|
||||
|
|
|
@ -68,7 +68,9 @@ class AvesApp extends StatefulWidget {
|
|||
'ml', // Malayalam
|
||||
'my', // Burmese
|
||||
'or', // Odia
|
||||
'sat', // Santali
|
||||
'sl', // Slovenian
|
||||
'sv', // Swedish
|
||||
'th', // Thai
|
||||
}.map(Locale.new).toSet();
|
||||
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.toggleTitleSearch:
|
||||
case EntrySetAction.addShortcut:
|
||||
case EntrySetAction.setHome:
|
||||
// browsing or selecting
|
||||
case EntrySetAction.map:
|
||||
case EntrySetAction.slideshow:
|
||||
|
|
|
@ -75,7 +75,9 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
case EntrySetAction.toggleTitleSearch:
|
||||
return !useTvLayout && !isSelecting;
|
||||
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:
|
||||
return canWrite && isMain && isTrash;
|
||||
// browsing or selecting
|
||||
|
@ -131,6 +133,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
case EntrySetAction.searchCollection:
|
||||
case EntrySetAction.toggleTitleSearch:
|
||||
case EntrySetAction.addShortcut:
|
||||
case EntrySetAction.setHome:
|
||||
return true;
|
||||
case EntrySetAction.emptyBin:
|
||||
return !isSelecting && hasItems;
|
||||
|
@ -177,6 +180,8 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
context.read<Query>().toggle();
|
||||
case EntrySetAction.addShortcut:
|
||||
_addShortcut(context);
|
||||
case EntrySetAction.setHome:
|
||||
_setHome(context);
|
||||
// browsing or selecting
|
||||
case EntrySetAction.map:
|
||||
_goToMap(context);
|
||||
|
@ -727,4 +732,10 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
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 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?>>(
|
||||
context: context,
|
||||
|
|
|
@ -40,6 +40,7 @@ class GridTheme extends StatelessWidget {
|
|||
highlightBorderWidth: highlightBorderWidth,
|
||||
interactiveDimension: interactiveDimension,
|
||||
showFavourite: settings.showThumbnailFavourite,
|
||||
showHdr: settings.showThumbnailHdr,
|
||||
locationIcon: showLocation ? settings.thumbnailLocationIcon : ThumbnailOverlayLocationIcon.none,
|
||||
tagIcon: settings.thumbnailTagIcon,
|
||||
showMotionPhoto: settings.showThumbnailMotionPhoto,
|
||||
|
@ -58,7 +59,7 @@ typedef GridThemeIconBuilder = List<Widget> Function(BuildContext context, AvesE
|
|||
|
||||
class GridThemeData {
|
||||
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;
|
||||
late final GridThemeIconBuilder iconBuilder;
|
||||
|
||||
|
@ -68,6 +69,7 @@ class GridThemeData {
|
|||
required this.highlightBorderWidth,
|
||||
required this.interactiveDimension,
|
||||
required this.showFavourite,
|
||||
required this.showHdr,
|
||||
required ThumbnailOverlayLocationIcon locationIcon,
|
||||
required ThumbnailOverlayTagIcon tagIcon,
|
||||
required this.showMotionPhoto,
|
||||
|
@ -94,10 +96,10 @@ class GridThemeData {
|
|||
else if (entry.isAnimated)
|
||||
const AnimatedImageIcon()
|
||||
else ...[
|
||||
if (entry.isHdr && showHdr) const HdrIcon(),
|
||||
if (entry.isRaw && showRaw) const RawIcon(),
|
||||
if (entry.is360) const PanoramaIcon(),
|
||||
],
|
||||
if (entry.isHdr) const HdrIcon(),
|
||||
if (entry.isMotionPhoto && showMotionPhoto) const MotionPhotoIcon(),
|
||||
if (entry.isMultiPage && !entry.isMotionPhoto) MultiPageIcon(entry: entry),
|
||||
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/colors.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/media_store_scan_dialog.dart';
|
||||
import 'package:aves/widgets/debug/report.dart';
|
||||
|
@ -75,6 +76,7 @@ class AppDebugPage extends StatelessWidget {
|
|||
DebugCacheSection(),
|
||||
DebugColorSection(),
|
||||
DebugAppDatabaseSection(),
|
||||
DebugDeviceSection(),
|
||||
DebugErrorReportingSection(),
|
||||
DebugSettingsSection(),
|
||||
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/extensions/location.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/settings.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/location_pick_page.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
@ -172,8 +174,10 @@ class _EditEntryLocationDialogState extends State<EditEntryLocationDialog> {
|
|||
final mapCollection = baseCollection != null
|
||||
? CollectionLens(
|
||||
source: baseCollection.source,
|
||||
filters: baseCollection.filters,
|
||||
fixedSelection: baseCollection.sortedEntries.where((entry) => entry.hasGps).toList(),
|
||||
filters: {
|
||||
...baseCollection.filters.whereNot((filter) => filter == LocationFilter.unlocated),
|
||||
LocationFilter.located,
|
||||
},
|
||||
)
|
||||
: null;
|
||||
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: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 {
|
||||
static const routeName = '/dialog/selection';
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ class _HomePageState extends State<HomePage> {
|
|||
unawaited(AnalysisService.registerCallback());
|
||||
final source = context.read<CollectionSource>();
|
||||
await source.init(
|
||||
loadTopEntriesFirst: settings.homePage == HomePageSetting.collection,
|
||||
loadTopEntriesFirst: settings.homePage == HomePageSetting.collection && settings.homeCustomCollection.isEmpty,
|
||||
canAnalyze: !safeMode,
|
||||
);
|
||||
case AppMode.screenSaver:
|
||||
|
@ -338,7 +338,7 @@ class _HomePageState extends State<HomePage> {
|
|||
case AppMode.screenSaver:
|
||||
case AppMode.slideshow:
|
||||
routeName = _initialRouteName ?? settings.homePage.routeName;
|
||||
filters = _initialFilters ?? {};
|
||||
filters = _initialFilters ?? (settings.homePage == HomePageSetting.collection ? settings.homeCustomCollection : {});
|
||||
}
|
||||
Route buildRoute(WidgetBuilder builder) => DirectMaterialPageRoute(
|
||||
settings: RouteSettings(name: routeName),
|
||||
|
|
|
@ -50,7 +50,7 @@ class PageNavTile extends StatelessWidget {
|
|||
: null,
|
||||
onTap: () {
|
||||
Navigator.maybeOf(context)?.pop();
|
||||
final route = routeBuilder(context, routeName);
|
||||
final route = routeBuilder(context, routeName, topLevel);
|
||||
if (topLevel) {
|
||||
Navigator.maybeOf(context)?.pushAndRemoveUntil(
|
||||
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) {
|
||||
case SearchPage.routeName:
|
||||
final currentCollection = context.read<CollectionLens?>();
|
||||
|
@ -74,7 +74,7 @@ class PageNavTile extends StatelessWidget {
|
|||
searchFieldLabel: context.l10n.searchCollectionFieldHint,
|
||||
searchFieldStyle: Themes.searchFieldStyle(context),
|
||||
source: context.read<CollectionSource>(),
|
||||
parentCollection: currentCollection?.copyWith(),
|
||||
parentCollection: topLevel ? currentCollection?.copyWith() : currentCollection,
|
||||
),
|
||||
);
|
||||
default:
|
||||
|
|
|
@ -253,7 +253,7 @@ class _TvRailState extends State<TvRail> {
|
|||
|
||||
void _goTo(String routeName) {
|
||||
Navigator.maybeOf(context)?.pushAndRemoveUntil(
|
||||
PageNavTile.routeBuilder(context, routeName),
|
||||
PageNavTile.routeBuilder(context, routeName, true),
|
||||
(route) => false,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -279,7 +279,7 @@ class CollectionSearchDelegate extends AvesSearchDelegate with FeedbackMixin, Va
|
|||
title: context.l10n.searchMetadataSectionTitle,
|
||||
filters: [
|
||||
MissingFilter.date,
|
||||
LocationFilter(LocationLevel.place, ''),
|
||||
LocationFilter.unlocated,
|
||||
MissingFilter.fineAddress,
|
||||
TagFilter(''),
|
||||
RatingFilter(0),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/colors.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/settings_definition.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.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 {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsHomeTile;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSelectionListTile<HomePageSetting>(
|
||||
values: HomePageSetting.values,
|
||||
Widget build(BuildContext context) => SettingsSelectionListTile<_HomeOption>(
|
||||
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),
|
||||
selector: (context, s) => s.homePage,
|
||||
onSelection: (v) => settings.homePage = v,
|
||||
selector: (context, s) => _HomeOption(s.homePage, customCollection: s.homeCustomCollection),
|
||||
onSelection: (v) {
|
||||
settings.homePage = v.page;
|
||||
settings.homeCustomCollection = v.customCollection;
|
||||
},
|
||||
tileTitle: title(context),
|
||||
dialogTitle: context.l10n.settingsHomeDialogTitle,
|
||||
);
|
||||
|
|
|
@ -66,6 +66,16 @@ class ThumbnailOverlayPage extends StatelessWidget {
|
|||
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(
|
||||
selector: (context, s) => s.showThumbnailRaw,
|
||||
onChanged: (v) => settings.showThumbnailRaw = v,
|
||||
|
|
|
@ -2,6 +2,8 @@ import 'dart:async';
|
|||
import 'dart:math';
|
||||
|
||||
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/widgets/viewer/controls/cast.dart';
|
||||
import 'package:aves/widgets/viewer/controls/events.dart';
|
||||
|
@ -57,6 +59,7 @@ class ViewerController with CastMixin {
|
|||
);
|
||||
}
|
||||
_initialScale = initialScale;
|
||||
entryNotifier.addListener(_onEntryChanged);
|
||||
_autopilotNotifier = ValueNotifier(autopilot);
|
||||
_autopilotNotifier.addListener(_onAutopilotChanged);
|
||||
_onAutopilotChanged();
|
||||
|
@ -66,12 +69,21 @@ class ViewerController with CastMixin {
|
|||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||
}
|
||||
entryNotifier.removeListener(_onEntryChanged);
|
||||
windowService.setHdrColorMode(false);
|
||||
_autopilotNotifier.dispose();
|
||||
_clearAutopilotAnimations();
|
||||
_stopPlayTimer();
|
||||
_streamController.close();
|
||||
}
|
||||
|
||||
Future<void> _onEntryChanged() async {
|
||||
if (await windowService.supportsHdr()) {
|
||||
final enabled = entryNotifier.value?.isHdr ?? false;
|
||||
await windowService.setHdrColorMode(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void _onAutopilotChanged() {
|
||||
_clearAutopilotAnimations();
|
||||
_stopPlayTimer();
|
||||
|
@ -115,79 +127,3 @@ class ViewerController with CastMixin {
|
|||
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() {
|
||||
switch (AvesApp.lifecycleStateNotifier.value) {
|
||||
case AppLifecycleState.inactive:
|
||||
// inactive: when losing focus
|
||||
_onAppInactive();
|
||||
case AppLifecycleState.hidden:
|
||||
case AppLifecycleState.paused:
|
||||
case AppLifecycleState.detached:
|
||||
// paused: when switching to another app
|
||||
// detached: when app is without a view
|
||||
viewerController.autopilot = false;
|
||||
pauseVideoControllers();
|
||||
case AppLifecycleState.resumed:
|
||||
availability.onResume();
|
||||
case AppLifecycleState.hidden:
|
||||
// hidden: transient state between `inactive` and `paused`
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onAppInactive() async {
|
||||
final playingController = context.read<VideoConductor>().getPlayingController();
|
||||
viewerController.autopilot = false;
|
||||
bool enabledPip = false;
|
||||
if (settings.videoBackgroundMode == VideoBackgroundMode.pip) {
|
||||
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/shooting.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/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
@ -44,14 +45,13 @@ class ViewerDetailOverlay extends StatefulWidget {
|
|||
class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||
List<AvesEntry> get entries => widget.entries;
|
||||
|
||||
AvesEntry? get entry {
|
||||
final index = widget.index;
|
||||
return index < entries.length ? entries[index] : null;
|
||||
}
|
||||
AvesEntry? get entry => entryForIndex(widget.index);
|
||||
|
||||
late Future<List<dynamic>?> _detailLoader;
|
||||
AvesEntry? entryForIndex(int index) => index < entries.length ? entries[index] : null;
|
||||
|
||||
late Future<OverlayMetadata> _detailLoader;
|
||||
AvesEntry? _lastEntry;
|
||||
List<dynamic>? _lastDetails;
|
||||
OverlayMetadata _lastDetails = const OverlayMetadata();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -62,7 +62,8 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
|||
@override
|
||||
void didUpdateWidget(covariant ViewerDetailOverlay oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (entry != _lastEntry) {
|
||||
final newEntry = entryForIndex(widget.index);
|
||||
if (newEntry != entryForIndex(oldWidget.index) && newEntry != _lastEntry) {
|
||||
_initDetailLoader();
|
||||
}
|
||||
}
|
||||
|
@ -70,12 +71,17 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
|||
void _initDetailLoader() {
|
||||
final requestEntry = entry;
|
||||
if (requestEntry == null) {
|
||||
_detailLoader = SynchronousFuture(null);
|
||||
_detailLoader = SynchronousFuture(const OverlayMetadata());
|
||||
} else {
|
||||
_detailLoader = Future.wait([
|
||||
settings.showOverlayShootingDetails ? metadataFetchService.getOverlayMetadata(requestEntry) : Future.value(null),
|
||||
settings.showOverlayDescription ? metadataFetchService.getDescription(requestEntry) : Future.value(null),
|
||||
]);
|
||||
_detailLoader = metadataFetchService.getFields(requestEntry, {
|
||||
if (settings.showOverlayShootingDetails) ...{
|
||||
MetadataSyntheticField.aperture,
|
||||
MetadataSyntheticField.exposureTime,
|
||||
MetadataSyntheticField.focalLength,
|
||||
MetadataSyntheticField.iso,
|
||||
},
|
||||
if (settings.showOverlayDescription) MetadataSyntheticField.description,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,24 +90,20 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
|||
return SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: FutureBuilder<List<dynamic>?>(
|
||||
child: FutureBuilder<OverlayMetadata>(
|
||||
future: _detailLoader,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) {
|
||||
_lastDetails = snapshot.data;
|
||||
_lastDetails = snapshot.data!;
|
||||
_lastEntry = entry;
|
||||
}
|
||||
if (_lastEntry == null) return const SizedBox();
|
||||
final mainEntry = _lastEntry!;
|
||||
|
||||
final shootingDetails = _lastDetails![0];
|
||||
final description = _lastDetails![1];
|
||||
|
||||
final multiPageController = widget.multiPageController;
|
||||
Widget _buildContent({AvesEntry? pageEntry}) => ViewerDetailOverlayContent(
|
||||
pageEntry: pageEntry ?? mainEntry,
|
||||
shootingDetails: shootingDetails,
|
||||
description: description,
|
||||
details: _lastDetails,
|
||||
position: widget.hasCollection ? '${widget.index + 1}/${entries.length}' : null,
|
||||
availableWidth: widget.availableSize.width,
|
||||
multiPageController: multiPageController,
|
||||
|
@ -122,8 +124,7 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
|||
|
||||
class ViewerDetailOverlayContent extends StatelessWidget {
|
||||
final AvesEntry pageEntry;
|
||||
final OverlayMetadata? shootingDetails;
|
||||
final String? description;
|
||||
final OverlayMetadata details;
|
||||
final String? position;
|
||||
final double availableWidth;
|
||||
final MultiPageController? multiPageController;
|
||||
|
@ -140,8 +141,7 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
|||
const ViewerDetailOverlayContent({
|
||||
super.key,
|
||||
required this.pageEntry,
|
||||
required this.shootingDetails,
|
||||
required this.description,
|
||||
required this.details,
|
||||
required this.position,
|
||||
required this.availableWidth,
|
||||
required this.multiPageController,
|
||||
|
@ -244,27 +244,27 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
|||
|
||||
Widget _buildDescriptionFullRow(BuildContext context) => _buildFullRowSwitcher(
|
||||
context: context,
|
||||
visible: description != null,
|
||||
visible: details.description != null,
|
||||
builder: (context) => OverlayRowExpander(
|
||||
expandedNotifier: expandedNotifier,
|
||||
child: OverlayDescriptionRow(description: description!),
|
||||
child: OverlayDescriptionRow(description: details.description!),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildShootingFullRow(BuildContext context, double subRowWidth) => _buildFullRowSwitcher(
|
||||
context: context,
|
||||
visible: shootingDetails != null && shootingDetails!.isNotEmpty,
|
||||
visible: details.hasShootingDetails,
|
||||
builder: (context) => SizedBox(
|
||||
width: subRowWidth,
|
||||
child: OverlayShootingRow(details: shootingDetails!),
|
||||
child: OverlayShootingRow(details: details),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildShootingSubRow(BuildContext context, double subRowWidth) => _buildSubRowSwitcher(
|
||||
context: context,
|
||||
subRowWidth: subRowWidth,
|
||||
visible: shootingDetails != null && shootingDetails!.isNotEmpty,
|
||||
builder: (context) => OverlayShootingRow(details: shootingDetails!),
|
||||
visible: details.hasShootingDetails,
|
||||
builder: (context) => OverlayShootingRow(details: details),
|
||||
);
|
||||
|
||||
Widget _buildLocationFullRow(BuildContext context) => _buildFullRowSwitcher(
|
||||
|
|
|
@ -22,7 +22,7 @@ class OverlayRowExpander extends StatelessWidget {
|
|||
textAlign: parent.textAlign,
|
||||
softWrap: expanded,
|
||||
overflow: parent.overflow,
|
||||
maxLines: expanded ? null : 42,
|
||||
maxLines: expanded ? 16 : 1,
|
||||
textWidthBasis: parent.textWidthBasis,
|
||||
child: child!,
|
||||
);
|
||||
|
|
|
@ -42,16 +42,13 @@ mixin HistogramMixin {
|
|||
final blueLevels = List.filled(bins, 0);
|
||||
|
||||
final view = Uint8List.view(data.buffer);
|
||||
final pixelCount = view.length / 4;
|
||||
for (var i = 0; i < pixelCount; i += 4) {
|
||||
final viewSize = view.length;
|
||||
for (var i = 0; i < viewSize; i += 4) {
|
||||
final a = view[i + 3];
|
||||
if (a > 0) {
|
||||
final r = view[i + 0];
|
||||
final g = view[i + 1];
|
||||
final b = view[i + 2];
|
||||
redLevels[r]++;
|
||||
greenLevels[g]++;
|
||||
blueLevels[b]++;
|
||||
redLevels[view[i + 0]]++;
|
||||
greenLevels[view[i + 1]]++;
|
||||
blueLevels[view[i + 2]]++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,14 +72,17 @@ mixin HistogramMixin {
|
|||
const normMax = bins - 1;
|
||||
|
||||
final view = Uint8List.view(data.buffer);
|
||||
final pixelCount = view.length / 4;
|
||||
for (var i = 0; i < pixelCount; i += 4) {
|
||||
final viewSize = view.length;
|
||||
for (var i = 0; i < viewSize; i += 4) {
|
||||
final a = view[i + 3];
|
||||
if (a > 0) {
|
||||
final r = view[i + 0];
|
||||
final g = view[i + 1];
|
||||
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
|
||||
description:
|
||||
name: http
|
||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -8,6 +8,7 @@ enum EntrySetAction {
|
|||
searchCollection,
|
||||
toggleTitleSearch,
|
||||
addShortcut,
|
||||
setHome,
|
||||
emptyBin,
|
||||
// browsing or selecting
|
||||
map,
|
||||
|
@ -47,6 +48,7 @@ class EntrySetActions {
|
|||
EntrySetAction.searchCollection,
|
||||
EntrySetAction.toggleTitleSearch,
|
||||
EntrySetAction.addShortcut,
|
||||
EntrySetAction.setHome,
|
||||
null,
|
||||
EntrySetAction.map,
|
||||
EntrySetAction.slideshow,
|
||||
|
@ -60,11 +62,9 @@ class EntrySetActions {
|
|||
static const collectionEditorBrowsing = [
|
||||
EntrySetAction.searchCollection,
|
||||
EntrySetAction.toggleTitleSearch,
|
||||
EntrySetAction.addShortcut,
|
||||
EntrySetAction.map,
|
||||
EntrySetAction.slideshow,
|
||||
EntrySetAction.stats,
|
||||
EntrySetAction.rescan,
|
||||
];
|
||||
|
||||
// `null` items are converted to dividers
|
||||
|
@ -98,7 +98,6 @@ class EntrySetActions {
|
|||
EntrySetAction.map,
|
||||
EntrySetAction.slideshow,
|
||||
EntrySetAction.stats,
|
||||
EntrySetAction.rescan,
|
||||
// editing actions are in their subsection
|
||||
];
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
enum MetadataSyntheticField {
|
||||
aperture,
|
||||
description,
|
||||
exposureTime,
|
||||
focalLength,
|
||||
iso,
|
||||
}
|
||||
|
||||
enum MetadataField {
|
||||
exifDate,
|
||||
exifDateOriginal,
|
||||
|
|
|
@ -41,6 +41,7 @@ class SettingKeys {
|
|||
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
|
||||
static const keepScreenOnKey = 'keep_screen_on';
|
||||
static const homePageKey = 'home_page';
|
||||
static const homeCustomCollectionKey = 'home_custom_collection';
|
||||
static const enableBottomNavigationBarKey = 'show_bottom_navigation_bar';
|
||||
static const confirmCreateVaultKey = 'confirm_create_vault';
|
||||
static const confirmDeleteForeverKey = 'confirm_delete_forever';
|
||||
|
@ -60,6 +61,7 @@ class SettingKeys {
|
|||
static const collectionBrowsingQuickActionsKey = 'collection_browsing_quick_actions';
|
||||
static const collectionSelectionQuickActionsKey = 'collection_selection_quick_actions';
|
||||
static const showThumbnailFavouriteKey = 'show_thumbnail_favourite';
|
||||
static const showThumbnailHdrKey = 'show_thumbnail_hdr';
|
||||
static const thumbnailLocationIconKey = 'thumbnail_location_icon';
|
||||
static const thumbnailTagIconKey = 'thumbnail_tag_icon';
|
||||
static const showThumbnailMotionPhotoKey = 'show_thumbnail_motion_photo';
|
||||
|
|
|
@ -58,10 +58,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.8"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
|
@ -35,3 +35,7 @@ abstract class ReportService {
|
|||
.join('\n'));
|
||||
}
|
||||
}
|
||||
|
||||
class UnreportedStateError extends StateError {
|
||||
UnreportedStateError(super.message);
|
||||
}
|
|
@ -71,7 +71,9 @@ class PlatformReportService extends ReportService {
|
|||
if (exception is PlatformException && stack != null) {
|
||||
stack = ReportService.buildReportStack(stack, level: 2);
|
||||
}
|
||||
return _instance?.recordError(exception, stack);
|
||||
if (exception is! UnreportedStateError) {
|
||||
return _instance?.recordError(exception, stack);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -92,10 +92,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_crashlytics
|
||||
sha256: "5ccdf05de039f9544d0ba41c5ae2052ca2425985d32229911b09f69981164518"
|
||||
sha256: "5125b7f3fcef2bfdd7e071afe7edcefd9597968003e44e073456c773d91694ee"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.8"
|
||||
version: "3.4.9"
|
||||
firebase_crashlytics_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -179,10 +179,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.8"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
|
@ -58,10 +58,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.8"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
|
@ -96,10 +96,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -195,42 +195,42 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: google_maps_flutter
|
||||
sha256: d4914cb38b3dcb62c39c085d968d434de0f8050f00f4d9f5ba4a7c7e004934cb
|
||||
sha256: ae66fef3e71261d7df2eff29b2a119e190b2884325ecaa55321b1e17b5504066
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0"
|
||||
version: "2.5.3"
|
||||
google_maps_flutter_android:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_maps_flutter_android
|
||||
sha256: "4279a338b79288fad5c8b03e5ae6ec30888bff210e0bab10b1f31f31e5a90558"
|
||||
sha256: "714530f865f13bb3b9505c58821c3baed5d247a871724acf5d2ea5808fbed02c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
version: "2.6.2"
|
||||
google_maps_flutter_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: google_maps_flutter_ios
|
||||
sha256: "6ad65362aeeeda44b7c2c807e36bf578ef4b1c163882e085bdb040bf2934b246"
|
||||
sha256: b644d205c235f85dc60e22f46172a868b1cd642afd5a52b3808c789e461b025a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
version: "2.4.1"
|
||||
google_maps_flutter_platform_interface:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_maps_flutter_platform_interface
|
||||
sha256: a3e9e6896501e566d902c6c69f010834d410ef4b7b5c18b90c77e871c86b7907
|
||||
sha256: "6060779f020638a8eedeb0fb14234818e5fa32ec45a4653d6428ab436e2bbc64"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.3"
|
||||
google_maps_flutter_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: google_maps_flutter_web
|
||||
sha256: f893d1542c6562bc8299ef768fbbe92ade83c220ab3209b9477ec9f81ad585e4
|
||||
sha256: "6245721c160d6f531c1ef568cf9bef8d660cd585a982aa75121269030163785a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.4+2"
|
||||
version: "0.5.4+3"
|
||||
html:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -243,10 +243,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -355,10 +355,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.8"
|
||||
polylabel:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -464,10 +464,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
version: "5.2.0"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -485,5 +485,5 @@ packages:
|
|||
source: hosted
|
||||
version: "2.0.0"
|
||||
sdks:
|
||||
dart: ">=3.2.0 <4.0.0"
|
||||
flutter: ">=3.13.0"
|
||||
dart: ">=3.2.3 <4.0.0"
|
||||
flutter: ">=3.16.6"
|
||||
|
|
|
@ -117,10 +117,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -231,10 +231,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.8"
|
||||
polylabel:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -103,10 +103,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -51,10 +51,10 @@ packages:
|
|||
description:
|
||||
path: "flutter/flutter"
|
||||
ref: background-lts
|
||||
resolved-ref: "8eb0534b9f74d7242adf68e22a3578d235911466"
|
||||
resolved-ref: "3fc7325f89225110b725cfbbb5e2560542a62e2e"
|
||||
url: "https://github.com/deckerst/ffmpeg-kit.git"
|
||||
source: git
|
||||
version: "6.0.2"
|
||||
version: "6.0.3"
|
||||
ffmpeg_kit_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -104,10 +104,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.8"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
|
@ -14,12 +14,7 @@ dependencies:
|
|||
path: ../aves_video
|
||||
# `video` version is necessary, as some videos make the app crash
|
||||
# when using only `min` or `https` (the default)
|
||||
# ffmpeg_kit_flutter_video: 6.0.2-LTS
|
||||
# ffmpeg_kit_flutter:
|
||||
# git:
|
||||
# url: https://github.com/arthenica/ffmpeg-kit.git
|
||||
# ref: development-flutter
|
||||
# path: flutter/flutter
|
||||
# ffmpeg_kit_flutter_video: 6.0.3-LTS
|
||||
ffmpeg_kit_flutter:
|
||||
git:
|
||||
url: https://github.com/deckerst/ffmpeg-kit.git
|
||||
|
|
|
@ -5,10 +5,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
|
||||
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.9"
|
||||
version: "3.4.10"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -102,6 +102,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -124,10 +132,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -140,10 +148,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271"
|
||||
sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.3"
|
||||
version: "4.1.4"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -244,18 +252,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.8"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
|
||||
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.3"
|
||||
version: "3.7.4"
|
||||
safe_local_storage:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -385,10 +393,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f"
|
||||
sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.2"
|
||||
version: "4.3.3"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -433,10 +441,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
version: "5.2.0"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue