Merge branch 'develop'
This commit is contained in:
commit
00681cbaee
208 changed files with 2132 additions and 1877 deletions
2
.flutter
2
.flutter
|
@ -1 +1 @@
|
|||
Subproject commit b0850beeb25f6d5b10426284f506557f66181b36
|
||||
Subproject commit 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -53,6 +53,8 @@ jobs:
|
|||
./flutterw build apk -t lib/main_izzy.dart --flavor izzy --split-per-abi
|
||||
cp build/app/outputs/apk/izzy/release/*.apk outputs
|
||||
scripts/apply_flavor_libre.sh
|
||||
./flutterw build appbundle -t lib/main_libre.dart --flavor libre
|
||||
cp build/app/outputs/bundle/libreRelease/*.aab outputs
|
||||
./flutterw build apk -t lib/main_libre.dart --flavor libre --split-per-abi
|
||||
cp build/app/outputs/apk/libre/release/*.apk outputs
|
||||
rm $AVES_STORE_FILE
|
||||
|
|
21
CHANGELOG.md
21
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.11.9"></a>[v1.11.9] - 2024-08-07
|
||||
|
||||
### Added
|
||||
|
||||
- Viewer: display more items in tag/copy/move quick action choosers
|
||||
- Viewer: long descriptions are scrollable when overlay is expanded by tap
|
||||
- Collection: sort by duration
|
||||
- Map: open external map app from map views
|
||||
- Explorer: stats
|
||||
|
||||
### Changed
|
||||
|
||||
- Accessibility: more animations and effects are suppressed when animations are disabled
|
||||
- upgraded Flutter to stable v3.24.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- opening app from launcher always showing home page
|
||||
- collection quick actions not showing in the top bar nor the menu
|
||||
- multiple widget setup after device reboot
|
||||
|
||||
## <a id="v1.11.8"></a>[v1.11.8] - 2024-07-19
|
||||
|
||||
### Added
|
||||
|
|
|
@ -189,7 +189,7 @@ dependencies {
|
|||
|
||||
implementation "androidx.appcompat:appcompat:1.7.0"
|
||||
implementation 'androidx.core:core-ktx:1.13.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.8.3'
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.8.4'
|
||||
implementation 'androidx.media:media:1.7.0'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
||||
|
@ -201,7 +201,7 @@ dependencies {
|
|||
implementation "com.github.bumptech.glide:glide:$glide_version"
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
// SLF4J implementation for `mp4parser`
|
||||
implementation 'org.slf4j:slf4j-simple:2.0.13'
|
||||
implementation 'org.slf4j:slf4j-simple:2.0.14'
|
||||
|
||||
// forked, built by JitPack:
|
||||
// - https://jitpack.io/p/deckerst/Android-TiffBitmapFactory
|
||||
|
@ -213,9 +213,9 @@ dependencies {
|
|||
implementation 'com.github.deckerst:pixymeta-android:9ec7097f17'
|
||||
implementation project(':exifinterface')
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.3'
|
||||
|
||||
kapt 'androidx.annotation:annotation:1.8.0'
|
||||
kapt 'androidx.annotation:annotation:1.8.1'
|
||||
ksp "com.github.bumptech.glide:ksp:$glide_version"
|
||||
|
||||
compileOnly rootProject.findProject(':streams_channel')
|
||||
|
|
|
@ -323,8 +323,10 @@
|
|||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
<!-- as of Flutter v3.22.0 (stable),
|
||||
Impeller fails to render videos (via `ffmpegkit`), and has random glitches -->
|
||||
<!--
|
||||
Impeller is not supported by `media_kit` v1.1.10+1:
|
||||
https://github.com/media-kit/media-kit/issues/707
|
||||
-->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.EnableImpeller"
|
||||
android:value="false" />
|
||||
|
|
|
@ -11,12 +11,18 @@ import android.graphics.Bitmap
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.util.SizeF
|
||||
import android.widget.RemoteViews
|
||||
import app.loup.streams_channel.StreamsChannel
|
||||
import deckers.thibault.aves.channel.AvesByteSendingMethodCodec
|
||||
import deckers.thibault.aves.channel.calls.*
|
||||
import deckers.thibault.aves.channel.calls.DeviceHandler
|
||||
import deckers.thibault.aves.channel.calls.MediaFetchBytesHandler
|
||||
import deckers.thibault.aves.channel.calls.MediaFetchObjectHandler
|
||||
import deckers.thibault.aves.channel.calls.MediaStoreHandler
|
||||
import deckers.thibault.aves.channel.calls.StorageHandler
|
||||
import deckers.thibault.aves.channel.streams.ImageByteStreamHandler
|
||||
import deckers.thibault.aves.channel.streams.MediaStoreStreamHandler
|
||||
import deckers.thibault.aves.model.FieldMap
|
||||
|
@ -26,8 +32,14 @@ import io.flutter.FlutterInjector
|
|||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.embedding.engine.dart.DartExecutor
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
@ -108,14 +120,7 @@ class HomeWidgetProvider : AppWidgetProvider() {
|
|||
|
||||
val isNightModeOn = (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
|
||||
|
||||
initFlutterEngine(context)
|
||||
val messenger = flutterEngine!!.dartExecutor
|
||||
val channel = MethodChannel(messenger, WIDGET_DRAW_CHANNEL)
|
||||
try {
|
||||
val props = suspendCoroutine<Any?> { cont ->
|
||||
defaultScope.launch {
|
||||
FlutterUtils.runOnUiThread {
|
||||
channel.invokeMethod("drawWidget", hashMapOf(
|
||||
val params = hashMapOf(
|
||||
"widgetId" to widgetId,
|
||||
"sizesDip" to sizesDip,
|
||||
"devicePixelRatio" to getDevicePixelRatio(),
|
||||
|
@ -126,19 +131,14 @@ class HomeWidgetProvider : AppWidgetProvider() {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
put("cornerRadiusPx", context.resources.getDimension(android.R.dimen.system_app_widget_background_radius))
|
||||
}
|
||||
}, object : MethodChannel.Result {
|
||||
override fun success(result: Any?) {
|
||||
cont.resume(result)
|
||||
}
|
||||
|
||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
||||
cont.resumeWithException(Exception("$errorCode: $errorMessage\n$errorDetails"))
|
||||
}
|
||||
|
||||
override fun notImplemented() {
|
||||
cont.resumeWithException(Exception("not implemented"))
|
||||
}
|
||||
})
|
||||
initFlutterEngine(context)
|
||||
try {
|
||||
val props = suspendCoroutine { cont ->
|
||||
defaultScope.launch {
|
||||
FlutterUtils.runOnUiThread {
|
||||
tryDrawWidget(params, cont, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +150,30 @@ class HomeWidgetProvider : AppWidgetProvider() {
|
|||
return null
|
||||
}
|
||||
|
||||
private fun tryDrawWidget(params: HashMap<String, Any>, cont: Continuation<Any?>, drawRetry: Int) {
|
||||
val messenger = flutterEngine!!.dartExecutor
|
||||
val channel = MethodChannel(messenger, WIDGET_DRAW_CHANNEL)
|
||||
channel.invokeMethod("drawWidget", params, object : MethodChannel.Result {
|
||||
override fun success(result: Any?) {
|
||||
cont.resume(result)
|
||||
}
|
||||
|
||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
||||
cont.resumeWithException(Exception("$errorCode: $errorMessage\n$errorDetails"))
|
||||
}
|
||||
|
||||
override fun notImplemented() {
|
||||
if (drawRetry > DRAW_RETRY_MAX) {
|
||||
cont.resumeWithException(Exception("not implemented"))
|
||||
} else {
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
tryDrawWidget(params, cont, drawRetry + 1)
|
||||
}, 2000L)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateWidgetImage(
|
||||
context: Context,
|
||||
appWidgetManager: AppWidgetManager,
|
||||
|
@ -271,6 +295,7 @@ class HomeWidgetProvider : AppWidgetProvider() {
|
|||
private val LOG_TAG = LogUtils.createTag<HomeWidgetProvider>()
|
||||
private const val WIDGET_DART_ENTRYPOINT = "widgetMain"
|
||||
private const val WIDGET_DRAW_CHANNEL = "deckers.thibault/aves/widget_draw"
|
||||
private const val DRAW_RETRY_MAX = 5
|
||||
|
||||
private var flutterEngine: FlutterEngine? = null
|
||||
private var imageByteFetchJob: Job? = null
|
||||
|
|
|
@ -59,7 +59,14 @@ class MediaStoreHandler(private val context: Context) : MethodCallHandler {
|
|||
|
||||
private fun getGeneration(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
||||
val generation = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
try {
|
||||
MediaStore.getGeneration(context, MediaStore.VOLUME_EXTERNAL_PRIMARY)
|
||||
} catch (e: Exception) {
|
||||
// may yield `IllegalArgumentException: Volume external_primary not found`
|
||||
val volumes = MediaStore.getExternalVolumeNames(context).joinToString(", ")
|
||||
result.error("getGeneration-primary", e.message + " (available volumes are $volumes)", e)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<string name="search_shortcut_short_label">Zoeken</string>
|
||||
<string name="videos_shortcut_short_label">Video’s</string>
|
||||
<string name="analysis_channel_name">Media indexeren</string>
|
||||
<string name="analysis_notification_default_title">Indexeren van media</string>
|
||||
<string name="analysis_notification_default_title">Media indexeren</string>
|
||||
<string name="analysis_notification_action_stop">Stoppen</string>
|
||||
<string name="safe_mode_shortcut_short_label">Veilige modus</string>
|
||||
</resources>
|
|
@ -7,6 +7,6 @@
|
|||
<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="analysis_notification_action_stop">Stopp</string>
|
||||
<string name="search_shortcut_short_label">Sök</string>
|
||||
</resources>
|
|
@ -1,4 +0,0 @@
|
|||
In v1.11.1:
|
||||
- watch videos with SRT subtitle files
|
||||
- enjoy the app in Persian
|
||||
Full changelog available on GitHub
|
|
@ -1,4 +0,0 @@
|
|||
In v1.11.1:
|
||||
- watch videos with SRT subtitle files
|
||||
- enjoy the app in Persian
|
||||
Full changelog available on GitHub
|
|
@ -1,3 +0,0 @@
|
|||
In v1.11.2:
|
||||
- show selected albums together in Collection
|
||||
Full changelog available on GitHub
|
|
@ -1,3 +0,0 @@
|
|||
In v1.11.2:
|
||||
- show selected albums together in Collection
|
||||
Full changelog available on GitHub
|
|
@ -1,3 +0,0 @@
|
|||
In v1.11.3:
|
||||
- show selected albums together in Collection
|
||||
Full changelog available on GitHub
|
|
@ -1,3 +0,0 @@
|
|||
In v1.11.3:
|
||||
- show selected albums together in Collection
|
||||
Full changelog available on GitHub
|
|
@ -1,4 +0,0 @@
|
|||
In v1.11.4:
|
||||
- explore your collection with the... explorer
|
||||
- convert your motion photos to stills in bulk
|
||||
Full changelog available on GitHub
|
|
@ -1,4 +0,0 @@
|
|||
In v1.11.4:
|
||||
- explore your collection with the... explorer
|
||||
- convert your motion photos to stills in bulk
|
||||
Full changelog available on GitHub
|
5
fastlane/metadata/android/en-US/changelogs/128.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/128.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
In v1.11.9:
|
||||
- peruse more options to tag or move via quick actions
|
||||
- read long descriptions right from the overlay
|
||||
- sort videos by duration
|
||||
Full changelog available on GitHub
|
5
fastlane/metadata/android/en-US/changelogs/12801.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/12801.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
In v1.11.9:
|
||||
- peruse more options to tag or move via quick actions
|
||||
- read long descriptions right from the overlay
|
||||
- sort videos by duration
|
||||
Full changelog available on GitHub
|
|
@ -1536,5 +1536,17 @@
|
|||
"chipActionGoToExplorerPage": "عرض في المستكشف",
|
||||
"@chipActionGoToExplorerPage": {},
|
||||
"explorerPageTitle": "المستكشف",
|
||||
"@explorerPageTitle": {}
|
||||
"@explorerPageTitle": {},
|
||||
"explorerActionSelectStorageVolume": "حدد التخزين",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"setHomeCustom": "مخصص",
|
||||
"@setHomeCustom": {},
|
||||
"selectStorageVolumeDialogTitle": "حدد التَخزين",
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"sortOrderShortestFirst": "الأقصر أولاً",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "الأطول أولاً",
|
||||
"@sortOrderLongestFirst": {},
|
||||
"sortByDuration": "حسب المدة",
|
||||
"@sortByDuration": {}
|
||||
}
|
||||
|
|
|
@ -1536,5 +1536,17 @@
|
|||
"chipActionGoToExplorerPage": "Паказаць у Правадыру",
|
||||
"@chipActionGoToExplorerPage": {},
|
||||
"explorerPageTitle": "Правадыр",
|
||||
"@explorerPageTitle": {}
|
||||
"@explorerPageTitle": {},
|
||||
"sortByDuration": "Па працягласці",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderShortestFirst": "Спачатку самы кароткі",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "Спачатку самы доўгі",
|
||||
"@sortOrderLongestFirst": {},
|
||||
"explorerActionSelectStorageVolume": "Выбраць сховішча",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "Выбраць сховішча",
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"setHomeCustom": "Па-свойму",
|
||||
"@setHomeCustom": {}
|
||||
}
|
||||
|
|
|
@ -723,6 +723,7 @@
|
|||
"sortBySize": "By size",
|
||||
"sortByAlbumFileName": "By album & file name",
|
||||
"sortByRating": "By rating",
|
||||
"sortByDuration": "By duration",
|
||||
|
||||
"sortOrderNewestFirst": "Newest first",
|
||||
"sortOrderOldestFirst": "Oldest first",
|
||||
|
@ -732,6 +733,8 @@
|
|||
"sortOrderLowestFirst": "Lowest first",
|
||||
"sortOrderLargestFirst": "Largest first",
|
||||
"sortOrderSmallestFirst": "Smallest first",
|
||||
"sortOrderShortestFirst": "Shortest first",
|
||||
"sortOrderLongestFirst": "Longest first",
|
||||
|
||||
"albumGroupTier": "By tier",
|
||||
"albumGroupType": "By type",
|
||||
|
|
|
@ -1384,5 +1384,11 @@
|
|||
"setHomeCustom": "Personalizado",
|
||||
"@setHomeCustom": {},
|
||||
"explorerActionSelectStorageVolume": "Seleccionar almacenamiento",
|
||||
"@explorerActionSelectStorageVolume": {}
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"sortByDuration": "Por duración",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderShortestFirst": "El más corto primero",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "El más largo primero",
|
||||
"@sortOrderLongestFirst": {}
|
||||
}
|
||||
|
|
|
@ -1384,5 +1384,11 @@
|
|||
"explorerActionSelectStorageVolume": "Choisir le stockage",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "Volumes de stockage",
|
||||
"@selectStorageVolumeDialogTitle": {}
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"sortByDuration": "par durée",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderShortestFirst": "Plus courts d’abord",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "Plus longs d’abord",
|
||||
"@sortOrderLongestFirst": {}
|
||||
}
|
||||
|
|
|
@ -101,5 +101,448 @@
|
|||
"chipActionGoToCountryPage": "देशों में दिखाएं",
|
||||
"@chipActionGoToCountryPage": {},
|
||||
"chipActionHide": "छिपाए",
|
||||
"@chipActionHide": {}
|
||||
"@chipActionHide": {},
|
||||
"chipActionShowCollection": "कोलेक्शन में दिखाए",
|
||||
"@chipActionShowCollection": {},
|
||||
"chipActionFilterOut": "फिल्टर करें",
|
||||
"@chipActionFilterOut": {},
|
||||
"chipActionLock": "लॉक",
|
||||
"@chipActionLock": {},
|
||||
"chipActionPin": "शीर्ष पर पिन करें",
|
||||
"@chipActionPin": {},
|
||||
"chipActionGoToExplorerPage": "एक्सप्लोरर में दिखाए",
|
||||
"@chipActionGoToExplorerPage": {},
|
||||
"entryActionRotateCW": "दक्षिणावर्त घुमाएं",
|
||||
"@entryActionRotateCW": {},
|
||||
"entryActionViewSource": "सोर्स देखें",
|
||||
"@entryActionViewSource": {},
|
||||
"entryActionShowGeoTiffOnMap": "मैप ओवरले के रूप में देखे",
|
||||
"@entryActionShowGeoTiffOnMap": {},
|
||||
"entryActionViewMotionPhotoVideo": "वीडियो खोलें",
|
||||
"@entryActionViewMotionPhotoVideo": {},
|
||||
"entryActionOpen": "के साथ खोलें",
|
||||
"@entryActionOpen": {},
|
||||
"entryActionRemoveFavourite": "पसंदीदा से निकालें",
|
||||
"@entryActionRemoveFavourite": {},
|
||||
"entryInfoActionRemoveMetadata": "मेटाडाटा हटाएं",
|
||||
"@entryInfoActionRemoveMetadata": {},
|
||||
"entryInfoActionRemoveLocation": "लोकेशन हटाएं",
|
||||
"@entryInfoActionRemoveLocation": {},
|
||||
"entryActionFlip": "क्षैतिज फ्लिप करे",
|
||||
"@entryActionFlip": {},
|
||||
"entryActionShareVideoOnly": "केवल वीडियो शेयर करें",
|
||||
"@entryActionShareVideoOnly": {},
|
||||
"entryActionConvertMotionPhotoToStillImage": "स्थिर छवि में परिवर्तित करें",
|
||||
"@entryActionConvertMotionPhotoToStillImage": {},
|
||||
"entryActionOpenMap": "मैप एप में दिखाएं",
|
||||
"@entryActionOpenMap": {},
|
||||
"entryActionSetAs": "के रूप में सेट करें",
|
||||
"@entryActionSetAs": {},
|
||||
"entryActionRotateScreen": "स्क्रीन घुमाएँ",
|
||||
"@entryActionRotateScreen": {},
|
||||
"videoActionCaptureFrame": "फ्रेम कैप्चर करें",
|
||||
"@videoActionCaptureFrame": {},
|
||||
"chipActionCreateAlbum": "एल्बम बनाएं",
|
||||
"@chipActionCreateAlbum": {},
|
||||
"chipActionCreateVault": "वॉल्ट बनाएं",
|
||||
"@chipActionCreateVault": {},
|
||||
"videoActionPlay": "चलाएं",
|
||||
"@videoActionPlay": {},
|
||||
"videoActionReplay10": "10 सेकंड्स पीछे ले",
|
||||
"@videoActionReplay10": {},
|
||||
"videoActionSkip10": "10 सेकंड्स आगे लें",
|
||||
"@videoActionSkip10": {},
|
||||
"videoActionUnmute": "अनम्यूट करे",
|
||||
"@videoActionUnmute": {},
|
||||
"slideshowActionShowInCollection": "संग्रह में दिखाएं",
|
||||
"@slideshowActionShowInCollection": {},
|
||||
"slideshowActionResume": "रिज्यूम करें",
|
||||
"@slideshowActionResume": {},
|
||||
"filterTypeAnimatedLabel": "एनिमेटेड",
|
||||
"@filterTypeAnimatedLabel": {},
|
||||
"filterTypeMotionPhotoLabel": "मोशन फोटो",
|
||||
"@filterTypeMotionPhotoLabel": {},
|
||||
"filterTypePanoramaLabel": "पैनोरमा",
|
||||
"@filterTypePanoramaLabel": {},
|
||||
"sourceStateLocatingCountries": "देश खोज रहे हैं",
|
||||
"@sourceStateLocatingCountries": {},
|
||||
"sourceStateLocatingPlaces": "स्थान खोज रहें हैं",
|
||||
"@sourceStateLocatingPlaces": {},
|
||||
"chipActionFilterIn": "में फिल्टर करें",
|
||||
"@chipActionFilterIn": {},
|
||||
"chipActionRename": "नाम बदले",
|
||||
"@chipActionRename": {},
|
||||
"chipActionUnpin": "शीर्ष से अनपिन करें",
|
||||
"@chipActionUnpin": {},
|
||||
"entryActionEdit": "एडिट करें",
|
||||
"@entryActionEdit": {},
|
||||
"videoActionMute": "म्यूट करे",
|
||||
"@videoActionMute": {},
|
||||
"videoActionPause": "रोके",
|
||||
"@videoActionPause": {},
|
||||
"entryInfoActionEditTags": "टैग्स एडिट करे",
|
||||
"@entryInfoActionEditTags": {},
|
||||
"filterOnThisDayLabel": "इस दिन पर",
|
||||
"@filterOnThisDayLabel": {},
|
||||
"filterTypeSphericalVideoLabel": "360° वीडियो",
|
||||
"@filterTypeSphericalVideoLabel": {},
|
||||
"filterMimeVideoLabel": "वीडियो",
|
||||
"@filterMimeVideoLabel": {},
|
||||
"viewerActionSettings": "सैटिंग",
|
||||
"@viewerActionSettings": {},
|
||||
"entryActionCast": "कास्ट करें",
|
||||
"@entryActionCast": {},
|
||||
"entryInfoActionExportMetadata": "मेटाडाटा एक्सपोर्ट करें",
|
||||
"@entryInfoActionExportMetadata": {},
|
||||
"chipActionSetCover": "कवर सेट करें",
|
||||
"@chipActionSetCover": {},
|
||||
"entryActionCopyToClipboard": "क्लिपबोर्ड पर कॉपी करें",
|
||||
"@entryActionCopyToClipboard": {},
|
||||
"entryActionDelete": "मिटाएं",
|
||||
"@entryActionDelete": {},
|
||||
"entryActionExport": "एक्सपोर्ट करें",
|
||||
"@entryActionExport": {},
|
||||
"entryActionInfo": "जानकारी",
|
||||
"@entryActionInfo": {},
|
||||
"entryActionConvert": "बदले",
|
||||
"@entryActionConvert": {},
|
||||
"entryActionRename": "नाम बदलें",
|
||||
"@entryActionRename": {},
|
||||
"entryActionRestore": "रिस्टोर करे",
|
||||
"@entryActionRestore": {},
|
||||
"entryActionRotateCCW": "वामावर्त स्थिति में घुमाएं",
|
||||
"@entryActionRotateCCW": {},
|
||||
"entryActionPrint": "प्रिंट करे",
|
||||
"@entryActionPrint": {},
|
||||
"entryActionShare": "शेयर करे",
|
||||
"@entryActionShare": {},
|
||||
"entryActionShareImageOnly": "केवल इमेज शेयर करें",
|
||||
"@entryActionShareImageOnly": {},
|
||||
"entryActionAddFavourite": "पसंदीदा में जोड़े",
|
||||
"@entryActionAddFavourite": {},
|
||||
"videoActionSelectStreams": "ट्रैक्स को चुने",
|
||||
"@videoActionSelectStreams": {},
|
||||
"videoActionSetSpeed": "चलाने की गति",
|
||||
"@videoActionSetSpeed": {},
|
||||
"entryInfoActionEditDate": "दिनांक व समय एडिट करे",
|
||||
"@entryInfoActionEditDate": {},
|
||||
"entryInfoActionEditLocation": "लोकेशन एडिट करे",
|
||||
"@entryInfoActionEditLocation": {},
|
||||
"entryInfoActionEditRating": "रेटिंग एडिट करे",
|
||||
"@entryInfoActionEditRating": {},
|
||||
"editorTransformRotate": "घुमाएं",
|
||||
"@editorTransformRotate": {},
|
||||
"cropAspectRatioOriginal": "ओरिजनल",
|
||||
"@cropAspectRatioOriginal": {},
|
||||
"filterFavouriteLabel": "पसंदीदा",
|
||||
"@filterFavouriteLabel": {},
|
||||
"filterRecentlyAddedLabel": "हाल ही में शामिल की गई",
|
||||
"@filterRecentlyAddedLabel": {},
|
||||
"filterMimeImageLabel": "इमेज",
|
||||
"@filterMimeImageLabel": {},
|
||||
"keepScreenOnVideoPlayback": "वीडियो प्लेबैक के दौरान",
|
||||
"@keepScreenOnVideoPlayback": {},
|
||||
"displayRefreshRatePreferLowest": "न्यूनतम दर",
|
||||
"@displayRefreshRatePreferLowest": {},
|
||||
"nameConflictStrategyRename": "नाम बदलें",
|
||||
"@nameConflictStrategyRename": {},
|
||||
"unitSystemMetric": "Metric",
|
||||
"@unitSystemMetric": {},
|
||||
"viewerTransitionSlide": "स्लाइड",
|
||||
"@viewerTransitionSlide": {},
|
||||
"viewerTransitionFade": "फेड",
|
||||
"@viewerTransitionFade": {},
|
||||
"newAlbumDialogStorageLabel": "स्टोरेज:",
|
||||
"@newAlbumDialogStorageLabel": {},
|
||||
"newVaultDialogTitle": "नया वॉल्ट",
|
||||
"@newVaultDialogTitle": {},
|
||||
"vaultDialogLockModeWhenScreenOff": "लॉक करे,जब स्क्रीन बंद हो जाती है",
|
||||
"@vaultDialogLockModeWhenScreenOff": {},
|
||||
"filterTaggedLabel": "टैग किया गया",
|
||||
"@filterTaggedLabel": {},
|
||||
"mapStyleGoogleTerrain": "गूगल मैप्स (टेरेन)",
|
||||
"@mapStyleGoogleTerrain": {},
|
||||
"themeBrightnessDark": "Dark",
|
||||
"@themeBrightnessDark": {},
|
||||
"themeBrightnessBlack": "Black",
|
||||
"@themeBrightnessBlack": {},
|
||||
"videoControlsPlaySeek": "पिछड़े / आगे की तलाश करें",
|
||||
"@videoControlsPlaySeek": {},
|
||||
"mapStyleOsmHot": "Humanitarian OSM",
|
||||
"@mapStyleOsmHot": {},
|
||||
"filterAspectRatioPortraitLabel": "पोर्ट्रेट",
|
||||
"@filterAspectRatioPortraitLabel": {},
|
||||
"filterNoAddressLabel": "एड्रेस रहित",
|
||||
"@filterNoAddressLabel": {},
|
||||
"filterNoRatingLabel": "रेट नहीं किया गया",
|
||||
"@filterNoRatingLabel": {},
|
||||
"filterRatingRejectedLabel": "अस्वीकृत",
|
||||
"@filterRatingRejectedLabel": {},
|
||||
"mapStyleGoogleNormal": "गूगल मैप्स",
|
||||
"@mapStyleGoogleNormal": {},
|
||||
"mapStyleGoogleHybrid": "गूगल मैप्स (हाइब्रिड)",
|
||||
"@mapStyleGoogleHybrid": {},
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor",
|
||||
"@mapStyleStamenWatercolor": {},
|
||||
"unitSystemImperial": "Imperial",
|
||||
"@unitSystemImperial": {},
|
||||
"passwordDialogEnter": "पासवर्ड दर्ज करें",
|
||||
"@passwordDialogEnter": {},
|
||||
"filterBinLabel": "रीसाइकल बिन",
|
||||
"@filterBinLabel": {},
|
||||
"filterTypeRawLabel": "Raw",
|
||||
"@filterTypeRawLabel": {},
|
||||
"albumTierVaults": "संदूक",
|
||||
"@albumTierVaults": {},
|
||||
"albumTierRegular": "अन्य",
|
||||
"@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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"coordinateDmsSouth": "द",
|
||||
"@coordinateDmsSouth": {},
|
||||
"coordinateDmsWest": "प",
|
||||
"@coordinateDmsWest": {},
|
||||
"displayRefreshRatePreferHighest": "उच्चतम दर",
|
||||
"@displayRefreshRatePreferHighest": {},
|
||||
"lengthUnitPixel": "px",
|
||||
"@lengthUnitPixel": {},
|
||||
"subtitlePositionTop": "शीर्ष",
|
||||
"@subtitlePositionTop": {},
|
||||
"subtitlePositionBottom": "नीचे",
|
||||
"@subtitlePositionBottom": {},
|
||||
"videoLoopModeNever": "कभी नहीं",
|
||||
"@videoLoopModeNever": {},
|
||||
"videoPlaybackMuted": "बिना ध्वनि के चलाएं",
|
||||
"@videoPlaybackMuted": {},
|
||||
"viewerTransitionNone": "कोई नहीं",
|
||||
"@viewerTransitionNone": {},
|
||||
"nameConflictDialogSingleSourceMessage": "गंतव्य फ़ोल्डर में कुछ फ़ाइलों का नाम समान है।।",
|
||||
"@nameConflictDialogSingleSourceMessage": {},
|
||||
"noMatchingAppDialogMessage": "इसमें कोई ऐप नहीं है जो इसे संभाल सकता है।।",
|
||||
"@noMatchingAppDialogMessage": {},
|
||||
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Move this item to the recycle bin?} other{Move these {count} items to the recycle bin?}}",
|
||||
"@binEntriesConfirmationDialogMessage": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"format": "decimalPattern"
|
||||
}
|
||||
}
|
||||
},
|
||||
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Delete this item?} other{Delete these {count} items?}}",
|
||||
"@deleteEntriesConfirmationDialogMessage": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"format": "decimalPattern"
|
||||
}
|
||||
}
|
||||
},
|
||||
"newAlbumDialogTitle": "नया एल्बम",
|
||||
"@newAlbumDialogTitle": {},
|
||||
"newAlbumDialogNameLabel": "एल्बम का नाम",
|
||||
"@newAlbumDialogNameLabel": {},
|
||||
"pinDialogEnter": "पिन दर्ज करें",
|
||||
"@pinDialogEnter": {},
|
||||
"pinDialogConfirm": "पिन कन्फर्म करें",
|
||||
"@pinDialogConfirm": {},
|
||||
"passwordDialogConfirm": "पासवर्ड कन्फर्म करें",
|
||||
"@passwordDialogConfirm": {},
|
||||
"videoLoopModeAlways": "हमेशा",
|
||||
"@videoLoopModeAlways": {},
|
||||
"videoPlaybackSkip": "छोड़े",
|
||||
"@videoPlaybackSkip": {},
|
||||
"newAlbumDialogNameLabelAlreadyExistsHelper": "डायरेक्टरी पहले से मौजूद",
|
||||
"@newAlbumDialogNameLabelAlreadyExistsHelper": {},
|
||||
"coordinateDmsEast": "पू",
|
||||
"@coordinateDmsEast": {},
|
||||
"moveUndatedConfirmationDialogSetDate": "तारीख सहेजें",
|
||||
"@moveUndatedConfirmationDialogSetDate": {},
|
||||
"notEnoughSpaceDialogMessage": "इस ऑपरेशन को पूरा करने के लिए \"{volume}\" पर “{neededSize}” खाली जगह की आवश्यकता है, लेकिन केवल {freeSize} जगह है।।",
|
||||
"@notEnoughSpaceDialogMessage": {
|
||||
"placeholders": {
|
||||
"neededSize": {
|
||||
"type": "String",
|
||||
"example": "314 MB"
|
||||
},
|
||||
"freeSize": {
|
||||
"type": "String",
|
||||
"example": "123 MB"
|
||||
},
|
||||
"volume": {
|
||||
"type": "String",
|
||||
"example": "SD card",
|
||||
"description": "the name of a storage volume"
|
||||
}
|
||||
}
|
||||
},
|
||||
"renameAlbumDialogLabel": "नया नाम",
|
||||
"@renameAlbumDialogLabel": {},
|
||||
"wallpaperTargetLock": "लॉक स्क्रीन",
|
||||
"@wallpaperTargetLock": {},
|
||||
"unsupportedTypeDialogMessage": "{count, plural, =1{This operation is not supported for items of the following type: {types}.} other{This operation is not supported for items of the following types: {types}.}}",
|
||||
"@unsupportedTypeDialogMessage": {
|
||||
"placeholders": {
|
||||
"count": {},
|
||||
"types": {
|
||||
"type": "String",
|
||||
"example": "GIF, TIFF, MP4",
|
||||
"description": "a list of unsupported types"
|
||||
}
|
||||
}
|
||||
},
|
||||
"restrictedAccessDialogMessage": "इस एप्लिकेशन को \"{volume}\" की {directory} में फ़ाइलों को संशोधित करने की अनुमति नहीं है।\n\nकृपया किसी अन्य directory में आइटम स्थानांतरित करने के लिए एक पूर्व-स्थापित फ़ाइल प्रबंधक या गैलरी ऐप का उपयोग करें।।",
|
||||
"@restrictedAccessDialogMessage": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"videoResumeDialogMessage": "क्या आप {time} पर पुन: चलाना चाहते हैं?",
|
||||
"@videoResumeDialogMessage": {
|
||||
"placeholders": {
|
||||
"time": {
|
||||
"type": "String",
|
||||
"example": "13:37"
|
||||
}
|
||||
}
|
||||
},
|
||||
"videoStartOverButtonLabel": "पुन: प्रारंभ करें",
|
||||
"@videoStartOverButtonLabel": {},
|
||||
"vaultDialogLockTypeLabel": "लॉक प्रकार",
|
||||
"@vaultDialogLockTypeLabel": {},
|
||||
"patternDialogConfirm": "पैटर्न कन्फर्म करे",
|
||||
"@patternDialogConfirm": {},
|
||||
"patternDialogEnter": "पैटर्न दर्ज करें",
|
||||
"@patternDialogEnter": {},
|
||||
"authenticateToUnlockVault": "वॉल्ट को अनलॉक करने के लिए प्रमाणीकरण करें",
|
||||
"@authenticateToUnlockVault": {},
|
||||
"settingsVideoEnablePip": "पिक्चर-इन-पिक्चर",
|
||||
"@settingsVideoEnablePip": {},
|
||||
"videoControlsPlay": "चलाएं",
|
||||
"@videoControlsPlay": {},
|
||||
"videoControlsPlayOutside": "अन्य प्लेयर के साथ खोलें",
|
||||
"@videoControlsPlayOutside": {},
|
||||
"videoControlsNone": "कोई नहीं",
|
||||
"@videoControlsNone": {},
|
||||
"videoLoopModeShortOnly": "केवल लघु वीडियो",
|
||||
"@videoLoopModeShortOnly": {},
|
||||
"videoPlaybackWithSound": "ध्वनि के साथ चलाए",
|
||||
"@videoPlaybackWithSound": {},
|
||||
"viewerTransitionParallax": "पैरालैक्स",
|
||||
"@viewerTransitionParallax": {},
|
||||
"viewerTransitionZoomIn": "ज़ूम इन",
|
||||
"@viewerTransitionZoomIn": {},
|
||||
"wallpaperTargetHome": "होम स्क्रीन",
|
||||
"@wallpaperTargetHome": {},
|
||||
"widgetDisplayedItemRandom": "यादृच्छिक",
|
||||
"@widgetDisplayedItemRandom": {},
|
||||
"videoResumeButtonLabel": "पुन: चलाएं",
|
||||
"@videoResumeButtonLabel": {},
|
||||
"filterNoTitleLabel": "शीर्षकहीन",
|
||||
"@filterNoTitleLabel": {},
|
||||
"stopTooltip": "रोके",
|
||||
"@stopTooltip": {},
|
||||
"vaultLockTypePin": "पिन",
|
||||
"@vaultLockTypePin": {},
|
||||
"wallpaperTargetHomeLock": "होम और लॉक स्क्रीन",
|
||||
"@wallpaperTargetHomeLock": {},
|
||||
"widgetDisplayedItemMostRecent": "हाल ही के",
|
||||
"@widgetDisplayedItemMostRecent": {},
|
||||
"filterAspectRatioLandscapeLabel": "लैंडस्केप",
|
||||
"@filterAspectRatioLandscapeLabel": {},
|
||||
"filterNoDateLabel": "अदिनांकित",
|
||||
"@filterNoDateLabel": {},
|
||||
"filterNoTagLabel": "टैग नहीं किया गया",
|
||||
"@filterNoTagLabel": {},
|
||||
"filterTypeGeotiffLabel": "GeoTIFF",
|
||||
"@filterTypeGeotiffLabel": {},
|
||||
"accessibilityAnimationsKeep": "स्क्रीन प्रभाव रखें",
|
||||
"@accessibilityAnimationsKeep": {},
|
||||
"vaultLockTypePattern": "पैटर्न",
|
||||
"@vaultLockTypePattern": {},
|
||||
"coordinateDmsNorth": "उ",
|
||||
"@coordinateDmsNorth": {},
|
||||
"albumTierNew": "नया",
|
||||
"@albumTierNew": {},
|
||||
"albumTierApps": "ऐप्स",
|
||||
"@albumTierApps": {},
|
||||
"lengthUnitPercent": "%",
|
||||
"@lengthUnitPercent": {},
|
||||
"nameConflictStrategyReplace": "बदलें",
|
||||
"@nameConflictStrategyReplace": {},
|
||||
"themeBrightnessLight": "Light",
|
||||
"@themeBrightnessLight": {},
|
||||
"vaultLockTypePassword": "पासवर्ड",
|
||||
"@vaultLockTypePassword": {},
|
||||
"storageVolumeDescriptionFallbackNonPrimary": "एसडी कार्ड",
|
||||
"@storageVolumeDescriptionFallbackNonPrimary": {},
|
||||
"storageAccessDialogMessage": "अगले स्क्रीन में \"{volume}\" के {directory} का चयन करें ताकि यह ऐप इसके लिए पहुंच सके।।",
|
||||
"@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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rootDirectoryDescription": "root directory",
|
||||
"@rootDirectoryDescription": {},
|
||||
"otherDirectoryDescription": "“{name}” directory",
|
||||
"@otherDirectoryDescription": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String",
|
||||
"example": "Pictures",
|
||||
"description": "the name of a specific directory"
|
||||
}
|
||||
}
|
||||
},
|
||||
"missingSystemFilePickerDialogMessage": "सिस्टम फ़ाइल पिकर लापता या अक्षम है। कृपया इसे सक्षम करें और फिर से प्रयास करें।।",
|
||||
"@missingSystemFilePickerDialogMessage": {},
|
||||
"nameConflictDialogMultipleSourceMessage": "कुछ फ़ाइलों का नाम समान है।।",
|
||||
"@nameConflictDialogMultipleSourceMessage": {},
|
||||
"addShortcutDialogLabel": "शॉर्टकट लेबल",
|
||||
"@addShortcutDialogLabel": {},
|
||||
"newVaultWarningDialogMessage": "वॉल्ट में आइटम केवल इस ऐप के लिए व अन्य के लिए नहीं उपलब्ध हैं।\n\nयदि आप इस ऐप को अनइंस्टॉल करते हैं, या इस ऐप डेटा को साफ़ करते हैं, तो आप इन सभी आइटम को खो देंगे।।",
|
||||
"@newVaultWarningDialogMessage": {},
|
||||
"configureVaultDialogTitle": "वॉल्ट को कॉन्फ़िगर करना",
|
||||
"@configureVaultDialogTitle": {},
|
||||
"moveUndatedConfirmationDialogMessage": "आगे बढ़ने से पहले आइटम की तारीख सेव करे?",
|
||||
"@moveUndatedConfirmationDialogMessage": {},
|
||||
"setCoverDialogLatest": "नवीनतम आइटम",
|
||||
"@setCoverDialogLatest": {},
|
||||
"hideFilterConfirmationDialogMessage": "मैचिंग तस्वीरें और वीडियो आपके कलेक्शन से छिपे होंगे। आप उन्हें फिर से \"गोपनीयता\" सेटिंग्स से दिखा सकते हैं।\n\nक्या आप उन्हें छिपाना चाहते हैं?",
|
||||
"@hideFilterConfirmationDialogMessage": {},
|
||||
"renameEntrySetPageTitle": "नाम बदलें",
|
||||
"@renameEntrySetPageTitle": {},
|
||||
"authenticateToConfigureVault": "वॉल्ट को कॉन्फ़िगर करने के लिए प्रमाणीकरण करें",
|
||||
"@authenticateToConfigureVault": {},
|
||||
"renameAlbumDialogLabelAlreadyExistsHelper": "डायरेक्टरी पहले से मौजूद",
|
||||
"@renameAlbumDialogLabelAlreadyExistsHelper": {}
|
||||
}
|
||||
|
|
|
@ -1374,5 +1374,11 @@
|
|||
"renameProcessorHash": "Hash",
|
||||
"@renameProcessorHash": {},
|
||||
"chipActionShowCollection": "Tampilkan di Koleksi",
|
||||
"@chipActionShowCollection": {}
|
||||
"@chipActionShowCollection": {},
|
||||
"explorerActionSelectStorageVolume": "Pilih penyimpanan",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "Pilih Penyimpanan",
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"setHomeCustom": "Kustom",
|
||||
"@setHomeCustom": {}
|
||||
}
|
||||
|
|
|
@ -1384,5 +1384,11 @@
|
|||
"explorerActionSelectStorageVolume": "저장공간 선택",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "저장공간",
|
||||
"@selectStorageVolumeDialogTitle": {}
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"sortByDuration": "길이",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderShortestFirst": "짧은 순",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "긴 순",
|
||||
"@sortOrderLongestFirst": {}
|
||||
}
|
||||
|
|
|
@ -65,11 +65,11 @@
|
|||
"@sourceStateLocatingPlaces": {},
|
||||
"chipActionDelete": "Verwijderen",
|
||||
"@chipActionDelete": {},
|
||||
"chipActionGoToAlbumPage": "Tonen Albums",
|
||||
"chipActionGoToAlbumPage": "In Albums tonen",
|
||||
"@chipActionGoToAlbumPage": {},
|
||||
"chipActionGoToCountryPage": "Tonen in Landen",
|
||||
"chipActionGoToCountryPage": "In Landen tonen",
|
||||
"@chipActionGoToCountryPage": {},
|
||||
"chipActionGoToTagPage": "Tonen in Labels",
|
||||
"chipActionGoToTagPage": "In Labels tonen",
|
||||
"@chipActionGoToTagPage": {},
|
||||
"chipActionFilterOut": "Uitfilteren",
|
||||
"@chipActionFilterOut": {},
|
||||
|
@ -113,7 +113,7 @@
|
|||
"@entryActionShare": {},
|
||||
"entryActionViewSource": "Bron bekijken",
|
||||
"@entryActionViewSource": {},
|
||||
"entryActionShowGeoTiffOnMap": "Tonen als map overlay",
|
||||
"entryActionShowGeoTiffOnMap": "Als kaart-overlay tonen",
|
||||
"@entryActionShowGeoTiffOnMap": {},
|
||||
"entryActionConvertMotionPhotoToStillImage": "Converteren naar stilstaand beeld",
|
||||
"@entryActionConvertMotionPhotoToStillImage": {},
|
||||
|
@ -125,7 +125,7 @@
|
|||
"@entryActionOpen": {},
|
||||
"entryActionSetAs": "Instellen als",
|
||||
"@entryActionSetAs": {},
|
||||
"entryActionOpenMap": "Tonen in map app",
|
||||
"entryActionOpenMap": "In Kaarten-app tonen",
|
||||
"@entryActionOpenMap": {},
|
||||
"entryActionRotateScreen": "Scherm roteren",
|
||||
"@entryActionRotateScreen": {},
|
||||
|
@ -147,7 +147,7 @@
|
|||
"@videoActionReplay10": {},
|
||||
"videoActionSkip10": "10 seconden vooruit",
|
||||
"@videoActionSkip10": {},
|
||||
"videoActionSelectStreams": "Tracks selecteren",
|
||||
"videoActionSelectStreams": "Sporen selecteren",
|
||||
"@videoActionSelectStreams": {},
|
||||
"videoActionSetSpeed": "Afspeelsnelheid",
|
||||
"@videoActionSetSpeed": {},
|
||||
|
@ -155,13 +155,13 @@
|
|||
"@viewerActionSettings": {},
|
||||
"slideshowActionResume": "Hervatten",
|
||||
"@slideshowActionResume": {},
|
||||
"slideshowActionShowInCollection": "Tonen in Collectie",
|
||||
"slideshowActionShowInCollection": "In Collectie tonen",
|
||||
"@slideshowActionShowInCollection": {},
|
||||
"entryInfoActionEditDate": "Bewerk datum & tijd",
|
||||
"entryInfoActionEditDate": "Datum & tijd bewerken",
|
||||
"@entryInfoActionEditDate": {},
|
||||
"entryInfoActionEditLocation": "Bewerk locatie",
|
||||
"entryInfoActionEditLocation": "Locatie bewerken",
|
||||
"@entryInfoActionEditLocation": {},
|
||||
"entryInfoActionEditTitleDescription": "Wijzig titel & omschrijving",
|
||||
"entryInfoActionEditTitleDescription": "Titel & beschrijving bewerken",
|
||||
"@entryInfoActionEditTitleDescription": {},
|
||||
"entryInfoActionEditRating": "Waardering bewerken",
|
||||
"@entryInfoActionEditRating": {},
|
||||
|
@ -221,11 +221,11 @@
|
|||
"@coordinateDmsWest": {},
|
||||
"unitSystemMetric": "Metrisch",
|
||||
"@unitSystemMetric": {},
|
||||
"unitSystemImperial": "Imperiaal",
|
||||
"unitSystemImperial": "Brits-Amerikaans",
|
||||
"@unitSystemImperial": {},
|
||||
"videoLoopModeNever": "Nooit",
|
||||
"@videoLoopModeNever": {},
|
||||
"videoLoopModeShortOnly": "Enkel korte videos",
|
||||
"videoLoopModeShortOnly": "Alleen korte video's",
|
||||
"@videoLoopModeShortOnly": {},
|
||||
"videoLoopModeAlways": "Altijd",
|
||||
"@videoLoopModeAlways": {},
|
||||
|
@ -233,7 +233,7 @@
|
|||
"@videoControlsPlay": {},
|
||||
"videoControlsPlaySeek": "Speel & zoek terug/vooruit",
|
||||
"@videoControlsPlaySeek": {},
|
||||
"videoControlsPlayOutside": "Openen met andere speler",
|
||||
"videoControlsPlayOutside": "Met andere speler openen",
|
||||
"@videoControlsPlayOutside": {},
|
||||
"videoControlsNone": "Geen",
|
||||
"@videoControlsNone": {},
|
||||
|
@ -255,13 +255,13 @@
|
|||
"@nameConflictStrategySkip": {},
|
||||
"keepScreenOnNever": "Nooit",
|
||||
"@keepScreenOnNever": {},
|
||||
"keepScreenOnViewerOnly": "Enkel Viewer pagina",
|
||||
"keepScreenOnViewerOnly": "Alleen Viewerpagina",
|
||||
"@keepScreenOnViewerOnly": {},
|
||||
"keepScreenOnAlways": "Altijd",
|
||||
"@keepScreenOnAlways": {},
|
||||
"accessibilityAnimationsRemove": "Schermeffecten uitschakelen",
|
||||
"@accessibilityAnimationsRemove": {},
|
||||
"accessibilityAnimationsKeep": "Scherm effecten houden",
|
||||
"accessibilityAnimationsKeep": "Schermeffecten behouden",
|
||||
"@accessibilityAnimationsKeep": {},
|
||||
"displayRefreshRatePreferHighest": "Hoogste waardering",
|
||||
"@displayRefreshRatePreferHighest": {},
|
||||
|
@ -269,7 +269,7 @@
|
|||
"@displayRefreshRatePreferLowest": {},
|
||||
"videoPlaybackSkip": "Overslaan",
|
||||
"@videoPlaybackSkip": {},
|
||||
"videoPlaybackMuted": "Gedempte afspelen",
|
||||
"videoPlaybackMuted": "Gedempt afspelen",
|
||||
"@videoPlaybackMuted": {},
|
||||
"videoPlaybackWithSound": "Met geluid afspelen",
|
||||
"@videoPlaybackWithSound": {},
|
||||
|
@ -289,13 +289,13 @@
|
|||
"@viewerTransitionZoomIn": {},
|
||||
"viewerTransitionNone": "Geen",
|
||||
"@viewerTransitionNone": {},
|
||||
"wallpaperTargetHome": "Home scherm",
|
||||
"wallpaperTargetHome": "Startscherm",
|
||||
"@wallpaperTargetHome": {},
|
||||
"wallpaperTargetLock": "Vergrendel scherm",
|
||||
"wallpaperTargetLock": "Vergrendelingsscherm",
|
||||
"@wallpaperTargetLock": {},
|
||||
"wallpaperTargetHomeLock": "Home and Vergrendel schermen",
|
||||
"wallpaperTargetHomeLock": "Start- en vergrendelingsschermen",
|
||||
"@wallpaperTargetHomeLock": {},
|
||||
"widgetOpenPageHome": "Open startscherm",
|
||||
"widgetOpenPageHome": "Startscherm openen",
|
||||
"@widgetOpenPageHome": {},
|
||||
"albumTierNew": "Nieuw",
|
||||
"@albumTierNew": {},
|
||||
|
@ -315,7 +315,7 @@
|
|||
"@rootDirectoryDescription": {},
|
||||
"otherDirectoryDescription": "“{name}” map",
|
||||
"@otherDirectoryDescription": {},
|
||||
"storageAccessDialogMessage": "Selecteer de {directory} van “{volume}”, in het volgende scherm om deze app er toegang toe te geven.",
|
||||
"storageAccessDialogMessage": "Selecteer in het volgende scherm de {directory} van “{volume}” om deze app er toegang toe te geven.",
|
||||
"@storageAccessDialogMessage": {},
|
||||
"restrictedAccessDialogMessage": "Deze applicatie mag geen bestanden wijzigen in de {directory} van “{volume}”,.\n\n Gebruik een vooraf geïnstalleerde filemanager of galerij-app om de items naar een andere map te verplaatsen.",
|
||||
"@restrictedAccessDialogMessage": {},
|
||||
|
@ -335,17 +335,17 @@
|
|||
"@addShortcutButtonLabel": {},
|
||||
"noMatchingAppDialogMessage": "Er zijn geen apps die dit ondersteunen.",
|
||||
"@noMatchingAppDialogMessage": {},
|
||||
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Dit item naar de prullenbak verplaatsen??} other{Verplaats deze {count} items naar de prullenbak?}}",
|
||||
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Dit item naar de prullenbak verplaatsen??} other{Deze {count} items naar de prullenbak verplaatsen?}}",
|
||||
"@binEntriesConfirmationDialogMessage": {},
|
||||
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Verwijder dit item?} other{Verwijder deze {count} items?}}",
|
||||
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Dit item verwijderen?} other{Deze {count} items verwijderen?}}",
|
||||
"@deleteEntriesConfirmationDialogMessage": {},
|
||||
"moveUndatedConfirmationDialogMessage": "Datums opslaan voordat u doorgaat??",
|
||||
"moveUndatedConfirmationDialogMessage": "Datums opslaan alvorens door te gaan?",
|
||||
"@moveUndatedConfirmationDialogMessage": {},
|
||||
"moveUndatedConfirmationDialogSetDate": "Datums opslaan",
|
||||
"@moveUndatedConfirmationDialogSetDate": {},
|
||||
"videoResumeDialogMessage": "Wil je het afspelen hervatten op {time}?",
|
||||
"videoResumeDialogMessage": "Afspelen hervatten om {time}?",
|
||||
"@videoResumeDialogMessage": {},
|
||||
"videoStartOverButtonLabel": "OPNIEUW BEGINNEN",
|
||||
"videoStartOverButtonLabel": "OPNIEUW AFSPELLEN",
|
||||
"@videoStartOverButtonLabel": {},
|
||||
"videoResumeButtonLabel": "HERVATTEN",
|
||||
"@videoResumeButtonLabel": {},
|
||||
|
@ -355,7 +355,7 @@
|
|||
"@setCoverDialogAuto": {},
|
||||
"setCoverDialogCustom": "Aangepast",
|
||||
"@setCoverDialogCustom": {},
|
||||
"hideFilterConfirmationDialogMessage": "Overeenkomende foto’s en video’s worden verborgen binnen jouw verzameling. Je kunt ze opnieuw weergeven via de “Privacy”-instellingen.\n\nWeet je zeker dat je ze wilt verbergen?",
|
||||
"hideFilterConfirmationDialogMessage": "Overeenkomstige foto’s en video’s worden verborgen binnen jouw verzameling. Je kunt ze opnieuw weergeven via de “Privacy”-instellingen.\n\nWeet je zeker dat je ze wilt verbergen?",
|
||||
"@hideFilterConfirmationDialogMessage": {},
|
||||
"newAlbumDialogTitle": "Nieuw Album",
|
||||
"@newAlbumDialogTitle": {},
|
||||
|
@ -381,11 +381,11 @@
|
|||
"@renameProcessorCounter": {},
|
||||
"renameProcessorName": "Naam",
|
||||
"@renameProcessorName": {},
|
||||
"deleteSingleAlbumConfirmationDialogMessage": "{count, plural, =1{Verwijder dit album en het item binnen dit album?} other{Verwijder dit album en de {count} items binnen dit album?}}",
|
||||
"deleteSingleAlbumConfirmationDialogMessage": "{count, plural, =1{Dit album en het item erbinnen verwijderen?} other{Dit album en de {count} items erbinnen verwijderen?}}",
|
||||
"@deleteSingleAlbumConfirmationDialogMessage": {},
|
||||
"deleteMultiAlbumConfirmationDialogMessage": "{count, plural, =1{Verwijder deze albums en het item binnen deze albums?} other{Verwijder deze albums en de {count} items binnen deze albums?}}",
|
||||
"deleteMultiAlbumConfirmationDialogMessage": "{count, plural, =1{Deze albums en de items erbinnen verwijderen?} other{Deze albums en de {count} items erbinnen verwijderen?}}",
|
||||
"@deleteMultiAlbumConfirmationDialogMessage": {},
|
||||
"exportEntryDialogFormat": "Formaat:",
|
||||
"exportEntryDialogFormat": "Type:",
|
||||
"@exportEntryDialogFormat": {},
|
||||
"exportEntryDialogWidth": "Breedte",
|
||||
"@exportEntryDialogWidth": {},
|
||||
|
@ -397,11 +397,11 @@
|
|||
"@editEntryDialogTargetFieldsHeader": {},
|
||||
"editEntryDateDialogTitle": "Datum & Tijd",
|
||||
"@editEntryDateDialogTitle": {},
|
||||
"editEntryDateDialogSetCustom": "Stel een custom datum in",
|
||||
"editEntryDateDialogSetCustom": "Aangepaste datum instellen",
|
||||
"@editEntryDateDialogSetCustom": {},
|
||||
"editEntryDateDialogCopyField": "Kopiëren van andere datum",
|
||||
"editEntryDateDialogCopyField": "Van andere datum kopiëren",
|
||||
"@editEntryDateDialogCopyField": {},
|
||||
"editEntryDialogCopyFromItem": "Kopiëren van ander item",
|
||||
"editEntryDialogCopyFromItem": "Van ander item kopiëren",
|
||||
"@editEntryDialogCopyFromItem": {},
|
||||
"editEntryDateDialogExtractFromTitle": "Uit titel halen",
|
||||
"@editEntryDateDialogExtractFromTitle": {},
|
||||
|
@ -415,7 +415,7 @@
|
|||
"@durationDialogMinutes": {},
|
||||
"editEntryLocationDialogTitle": "Locatie",
|
||||
"@editEntryLocationDialogTitle": {},
|
||||
"editEntryLocationDialogChooseOnMap": "Kies op kaart",
|
||||
"editEntryLocationDialogChooseOnMap": "Op kaart kiezen",
|
||||
"@editEntryLocationDialogChooseOnMap": {},
|
||||
"editEntryLocationDialogLatitude": "Breedtegraad",
|
||||
"@editEntryLocationDialogLatitude": {},
|
||||
|
@ -443,9 +443,9 @@
|
|||
"@videoStreamSelectionDialogText": {},
|
||||
"videoStreamSelectionDialogOff": "Uit",
|
||||
"@videoStreamSelectionDialogOff": {},
|
||||
"videoStreamSelectionDialogTrack": "Nummer",
|
||||
"videoStreamSelectionDialogTrack": "Spoor",
|
||||
"@videoStreamSelectionDialogTrack": {},
|
||||
"videoStreamSelectionDialogNoSelection": "Er zijn geen andere nummers.",
|
||||
"videoStreamSelectionDialogNoSelection": "Er zijn geen andere sporen.",
|
||||
"@videoStreamSelectionDialogNoSelection": {},
|
||||
"genericSuccessFeedback": "Klaar!",
|
||||
"@genericSuccessFeedback": {},
|
||||
|
@ -453,9 +453,9 @@
|
|||
"@genericFailureFeedback": {},
|
||||
"menuActionConfigureView": "Beeld",
|
||||
"@menuActionConfigureView": {},
|
||||
"menuActionSelect": "Selecteer",
|
||||
"menuActionSelect": "Selecteren",
|
||||
"@menuActionSelect": {},
|
||||
"menuActionSelectAll": "Selecteer alles",
|
||||
"menuActionSelectAll": "Alles selecteren",
|
||||
"@menuActionSelectAll": {},
|
||||
"menuActionSelectNone": "Selectie ongedaan maken",
|
||||
"@menuActionSelectNone": {},
|
||||
|
@ -493,17 +493,17 @@
|
|||
"@aboutPageTitle": {},
|
||||
"aboutLinkLicense": "Licentie",
|
||||
"@aboutLinkLicense": {},
|
||||
"aboutBugSectionTitle": "Bug Reporteren",
|
||||
"aboutBugSectionTitle": "Foutmelding",
|
||||
"@aboutBugSectionTitle": {},
|
||||
"aboutBugSaveLogInstruction": "Sla applicatielogs op in een bestand",
|
||||
"@aboutBugSaveLogInstruction": {},
|
||||
"aboutBugCopyInfoInstruction": "Kopieer systeem informatie",
|
||||
"aboutBugCopyInfoInstruction": "Systeeminformatie kopiëren",
|
||||
"@aboutBugCopyInfoInstruction": {},
|
||||
"aboutBugCopyInfoButton": "Kopieer",
|
||||
"@aboutBugCopyInfoButton": {},
|
||||
"aboutBugReportInstruction": "Reporteer op GitHub met de logs en systeeminformatie",
|
||||
"aboutBugReportInstruction": "Melden op GitHub met de logs en systeeminformatie",
|
||||
"@aboutBugReportInstruction": {},
|
||||
"aboutBugReportButton": "Reporteer",
|
||||
"aboutBugReportButton": "Melden",
|
||||
"@aboutBugReportButton": {},
|
||||
"aboutCreditsSectionTitle": "Dankbetuiging",
|
||||
"@aboutCreditsSectionTitle": {},
|
||||
|
@ -531,9 +531,9 @@
|
|||
"@collectionPageTitle": {},
|
||||
"collectionPickPageTitle": "Kies",
|
||||
"@collectionPickPageTitle": {},
|
||||
"collectionSelectPageTitle": "Selecteer items",
|
||||
"collectionSelectPageTitle": "Items selecteren",
|
||||
"@collectionSelectPageTitle": {},
|
||||
"collectionActionShowTitleSearch": "Laat titel filter zien",
|
||||
"collectionActionShowTitleSearch": "Titelfilter weergeven",
|
||||
"@collectionActionShowTitleSearch": {},
|
||||
"collectionActionHideTitleSearch": "Verberg titel filter",
|
||||
"@collectionActionHideTitleSearch": {},
|
||||
|
@ -547,7 +547,7 @@
|
|||
"@collectionActionMove": {},
|
||||
"collectionActionRescan": "Opnieuw indexeren",
|
||||
"@collectionActionRescan": {},
|
||||
"collectionActionEdit": "Wijzigen",
|
||||
"collectionActionEdit": "Bewerken",
|
||||
"@collectionActionEdit": {},
|
||||
"collectionSearchTitlesHintText": "Zoek op titel",
|
||||
"@collectionSearchTitlesHintText": {},
|
||||
|
@ -575,7 +575,7 @@
|
|||
"@collectionMoveFailureFeedback": {},
|
||||
"collectionRenameFailureFeedback": "{count, plural, =1{Kan 1 item niet hernoemen} other{Kan {count} items niet hernoemen}}",
|
||||
"@collectionRenameFailureFeedback": {},
|
||||
"collectionEditFailureFeedback": "{count, plural, =1{Kan 1 item niet wijzigen} other{Kan {count} items niet wijzigen}}",
|
||||
"collectionEditFailureFeedback": "{count, plural, =1{Kan 1 item niet bewerken} other{Kan {count} items niet bewerken}}",
|
||||
"@collectionEditFailureFeedback": {},
|
||||
"collectionExportFailureFeedback": "{count, plural, =1{Kan 1 pagina niet exporteren} other{Kan {count} pagina’s niet exporteren}}",
|
||||
"@collectionExportFailureFeedback": {},
|
||||
|
@ -585,7 +585,7 @@
|
|||
"@collectionMoveSuccessFeedback": {},
|
||||
"collectionRenameSuccessFeedback": "{count, plural, =1{1 item hernoemd} other{{count} items hernoemd}}",
|
||||
"@collectionRenameSuccessFeedback": {},
|
||||
"collectionEditSuccessFeedback": "{count, plural, =1{1 item gewijzigd} other{{count} items gewijzigd}}",
|
||||
"collectionEditSuccessFeedback": "{count, plural, =1{1 item bewerkt} other{{count} items bewerkt}}",
|
||||
"@collectionEditSuccessFeedback": {},
|
||||
"collectionEmptyFavourites": "Geen favourieten",
|
||||
"@collectionEmptyFavourites": {},
|
||||
|
@ -595,9 +595,9 @@
|
|||
"@collectionEmptyImages": {},
|
||||
"collectionEmptyGrantAccessButtonLabel": "Toegang verlenen",
|
||||
"@collectionEmptyGrantAccessButtonLabel": {},
|
||||
"collectionSelectSectionTooltip": "Selecteer sectie",
|
||||
"collectionSelectSectionTooltip": "Sectie selecteren",
|
||||
"@collectionSelectSectionTooltip": {},
|
||||
"collectionDeselectSectionTooltip": "Deselecteer sectie",
|
||||
"collectionDeselectSectionTooltip": "Sectie niet selecteren",
|
||||
"@collectionDeselectSectionTooltip": {},
|
||||
"drawerAboutButton": "Over",
|
||||
"@drawerAboutButton": {},
|
||||
|
@ -677,7 +677,7 @@
|
|||
"@albumCamera": {},
|
||||
"albumDownload": "Opslaan",
|
||||
"@albumDownload": {},
|
||||
"albumScreenshots": "Schermafbeeldingen",
|
||||
"albumScreenshots": "Schermopnames",
|
||||
"@albumScreenshots": {},
|
||||
"albumScreenRecordings": "Schermopnames",
|
||||
"@albumScreenRecordings": {},
|
||||
|
@ -751,25 +751,25 @@
|
|||
"@settingsHomeTile": {},
|
||||
"settingsHomeDialogTitle": "Startscherm",
|
||||
"@settingsHomeDialogTitle": {},
|
||||
"settingsShowBottomNavigationBar": "Laat onderste navigatiebalk zien",
|
||||
"settingsShowBottomNavigationBar": "Onderste navigatiebalk weergeven",
|
||||
"@settingsShowBottomNavigationBar": {},
|
||||
"settingsKeepScreenOnTile": "Houd het scherm aan",
|
||||
"settingsKeepScreenOnTile": "Scherm aan houden",
|
||||
"@settingsKeepScreenOnTile": {},
|
||||
"settingsKeepScreenOnDialogTitle": "Houd het scherm aan",
|
||||
"settingsKeepScreenOnDialogTitle": "Scherm aan houden",
|
||||
"@settingsKeepScreenOnDialogTitle": {},
|
||||
"settingsDoubleBackExit": "Tik twee keer op “terug” om af te sluiten",
|
||||
"settingsDoubleBackExit": "Twee keer op “terug” tikken om af te sluiten",
|
||||
"@settingsDoubleBackExit": {},
|
||||
"settingsConfirmationTile": "Bevestigingsscherm",
|
||||
"settingsConfirmationTile": "Bevestigingsdialogen",
|
||||
"@settingsConfirmationTile": {},
|
||||
"settingsConfirmationDialogTitle": "Bevestigingsschermen",
|
||||
"settingsConfirmationDialogTitle": "Bevestigingsdialogen",
|
||||
"@settingsConfirmationDialogTitle": {},
|
||||
"settingsConfirmationBeforeDeleteItems": "Bevestig voordat je items voor altijd verwijdert",
|
||||
"settingsConfirmationBeforeDeleteItems": "Bevestiging vragen voordat items voor altijd worden verwijderd",
|
||||
"@settingsConfirmationBeforeDeleteItems": {},
|
||||
"settingsConfirmationBeforeMoveToBinItems": "Bevestig voordat u items naar de prullenbak verplaatst",
|
||||
"settingsConfirmationBeforeMoveToBinItems": "Bevestiging vragen voordat items naar de prullenbak worden verplaatst",
|
||||
"@settingsConfirmationBeforeMoveToBinItems": {},
|
||||
"settingsConfirmationBeforeMoveUndatedItems": "Bevestigvoordat u ongedateerde items verplaatst",
|
||||
"settingsConfirmationBeforeMoveUndatedItems": "Bevestiging vragen voordat ongedateerde items worden verplaatst",
|
||||
"@settingsConfirmationBeforeMoveUndatedItems": {},
|
||||
"settingsConfirmationAfterMoveToBinItems": "Toon bevestigingsbericht na het verplaatsen van items naar de prullenbak",
|
||||
"settingsConfirmationAfterMoveToBinItems": "Bevestigingsbericht weergeven na het verplaatsen van items naar de prullenbak",
|
||||
"@settingsConfirmationAfterMoveToBinItems": {},
|
||||
"settingsNavigationDrawerTile": "Navigatiemenu",
|
||||
"@settingsNavigationDrawerTile": {},
|
||||
|
@ -791,35 +791,35 @@
|
|||
"@settingsThumbnailOverlayTile": {},
|
||||
"settingsThumbnailOverlayPageTitle": "Overlay",
|
||||
"@settingsThumbnailOverlayPageTitle": {},
|
||||
"settingsThumbnailShowFavouriteIcon": "Favorieten icoon zichtbaar",
|
||||
"settingsThumbnailShowFavouriteIcon": "Favorieten-pictogram tonen",
|
||||
"@settingsThumbnailShowFavouriteIcon": {},
|
||||
"settingsThumbnailShowTagIcon": "Label-pictogram tonen",
|
||||
"@settingsThumbnailShowTagIcon": {},
|
||||
"settingsThumbnailShowLocationIcon": "Locatie icoon zichtbaar",
|
||||
"settingsThumbnailShowLocationIcon": "Locatie-pictogram tonen",
|
||||
"@settingsThumbnailShowLocationIcon": {},
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Bewegende foto icoon zichtbaar",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Bewegende foto-pictogram tonen",
|
||||
"@settingsThumbnailShowMotionPhotoIcon": {},
|
||||
"settingsThumbnailShowRating": "Waardering tonen",
|
||||
"@settingsThumbnailShowRating": {},
|
||||
"settingsThumbnailShowRawIcon": "RAW icoon zichtbaar",
|
||||
"settingsThumbnailShowRawIcon": "RAW-pictogram tonen",
|
||||
"@settingsThumbnailShowRawIcon": {},
|
||||
"settingsThumbnailShowVideoDuration": "Videoduur zichtbaar",
|
||||
"settingsThumbnailShowVideoDuration": "Videoduur tonen",
|
||||
"@settingsThumbnailShowVideoDuration": {},
|
||||
"settingsCollectionQuickActionsTile": "Snelle bewerkingen",
|
||||
"@settingsCollectionQuickActionsTile": {},
|
||||
"settingsCollectionQuickActionEditorPageTitle": "Snelle bewerkingen",
|
||||
"settingsCollectionQuickActionEditorPageTitle": "Snelle acties",
|
||||
"@settingsCollectionQuickActionEditorPageTitle": {},
|
||||
"settingsCollectionQuickActionTabBrowsing": "Blader",
|
||||
"@settingsCollectionQuickActionTabBrowsing": {},
|
||||
"settingsCollectionQuickActionTabSelecting": "Selecteren",
|
||||
"@settingsCollectionQuickActionTabSelecting": {},
|
||||
"settingsCollectionBrowsingQuickActionEditorBanner": "Houd ingedrukt om knoppen te verplaatsen en te selecteren welke acties worden weergegeven bij het bladeren door items.",
|
||||
"settingsCollectionBrowsingQuickActionEditorBanner": "Houd knoppen ingedrukt om deze te verplaatsen en te selecteren welke acties worden weergegeven bij het bladeren door items.",
|
||||
"@settingsCollectionBrowsingQuickActionEditorBanner": {},
|
||||
"settingsCollectionSelectionQuickActionEditorBanner": "Houd ingedrukt om knoppen te verplaatsen en te selecteren welke acties worden weergegeven bij het selecteren van items.",
|
||||
"settingsCollectionSelectionQuickActionEditorBanner": "Houd knoppen ingedrukt om deze te verplaatsen en te selecteren welke acties worden weergegeven bij het selecteren van items.",
|
||||
"@settingsCollectionSelectionQuickActionEditorBanner": {},
|
||||
"settingsViewerSectionTitle": "Voorbeeld",
|
||||
"@settingsViewerSectionTitle": {},
|
||||
"settingsViewerGestureSideTapNext": "Druk op het scherm om het vorige/volgende item weer te geven",
|
||||
"settingsViewerGestureSideTapNext": "Tik op het scherm om het vorige/volgende item weer te geven",
|
||||
"@settingsViewerGestureSideTapNext": {},
|
||||
"settingsViewerUseCutout": "Uitgesneden gebied gebruiken",
|
||||
"@settingsViewerUseCutout": {},
|
||||
|
@ -831,9 +831,9 @@
|
|||
"@settingsImageBackground": {},
|
||||
"settingsViewerQuickActionsTile": "Snelle bewerkingen",
|
||||
"@settingsViewerQuickActionsTile": {},
|
||||
"settingsViewerQuickActionEditorPageTitle": "Snelle bewerkingen",
|
||||
"settingsViewerQuickActionEditorPageTitle": "Snelle acties",
|
||||
"@settingsViewerQuickActionEditorPageTitle": {},
|
||||
"settingsViewerQuickActionEditorBanner": "Houd ingedrukt om knoppen te verplaatsen en te selecteren welke acties in de viewer worden weergegeven.",
|
||||
"settingsViewerQuickActionEditorBanner": "Houd knoppen ingedrukt om deze te verplaatsen en te selecteren welke acties in de viewer worden weergegeven.",
|
||||
"@settingsViewerQuickActionEditorBanner": {},
|
||||
"settingsViewerQuickActionEditorDisplayedButtonsSectionTitle": "Zichtbare knoppen",
|
||||
"@settingsViewerQuickActionEditorDisplayedButtonsSectionTitle": {},
|
||||
|
@ -845,17 +845,17 @@
|
|||
"@settingsViewerOverlayTile": {},
|
||||
"settingsViewerOverlayPageTitle": "Overlay",
|
||||
"@settingsViewerOverlayPageTitle": {},
|
||||
"settingsViewerShowOverlayOnOpening": "Zichtbaar bij openen",
|
||||
"settingsViewerShowOverlayOnOpening": "Bij openen weergeven",
|
||||
"@settingsViewerShowOverlayOnOpening": {},
|
||||
"settingsViewerShowMinimap": "Laat kleine kaart zien",
|
||||
"settingsViewerShowMinimap": "Kleine kaart tonen",
|
||||
"@settingsViewerShowMinimap": {},
|
||||
"settingsViewerShowInformation": "Laat informatie zien",
|
||||
"settingsViewerShowInformation": "Informatie tonen",
|
||||
"@settingsViewerShowInformation": {},
|
||||
"settingsViewerShowInformationSubtitle": "Laat titel, datum, locatie, etc zien.",
|
||||
"settingsViewerShowInformationSubtitle": "Titel, datum, locatie, etc.",
|
||||
"@settingsViewerShowInformationSubtitle": {},
|
||||
"settingsViewerShowShootingDetails": "Laat opnamedetails zien",
|
||||
"settingsViewerShowShootingDetails": "Opnamedetails tonen",
|
||||
"@settingsViewerShowShootingDetails": {},
|
||||
"settingsViewerShowOverlayThumbnails": "Laat miniaturen zien",
|
||||
"settingsViewerShowOverlayThumbnails": "Miniaturen tonen",
|
||||
"@settingsViewerShowOverlayThumbnails": {},
|
||||
"settingsViewerEnableOverlayBlurEffect": "Vervagingseffect",
|
||||
"@settingsViewerEnableOverlayBlurEffect": {},
|
||||
|
@ -883,9 +883,9 @@
|
|||
"@settingsVideoPageTitle": {},
|
||||
"settingsVideoSectionTitle": "Video",
|
||||
"@settingsVideoSectionTitle": {},
|
||||
"settingsVideoShowVideos": "Videos",
|
||||
"settingsVideoShowVideos": "Video's weergeven",
|
||||
"@settingsVideoShowVideos": {},
|
||||
"settingsVideoEnableHardwareAcceleration": "Hardware acceleratie",
|
||||
"settingsVideoEnableHardwareAcceleration": "Hardware-versnelling",
|
||||
"@settingsVideoEnableHardwareAcceleration": {},
|
||||
"settingsVideoAutoPlay": "Automatisch afspelen",
|
||||
"@settingsVideoAutoPlay": {},
|
||||
|
@ -905,7 +905,7 @@
|
|||
"@settingsSubtitleThemeTextAlignmentDialogTitle": {},
|
||||
"settingsSubtitleThemeTextSize": "Tekstgroote",
|
||||
"@settingsSubtitleThemeTextSize": {},
|
||||
"settingsSubtitleThemeShowOutline": "Laat omtrek en schaduw zien",
|
||||
"settingsSubtitleThemeShowOutline": "Omtrek en schaduw tonen",
|
||||
"@settingsSubtitleThemeShowOutline": {},
|
||||
"settingsSubtitleThemeTextColor": "Tekstkleur",
|
||||
"@settingsSubtitleThemeTextColor": {},
|
||||
|
@ -937,9 +937,9 @@
|
|||
"@settingsAllowInstalledAppAccess": {},
|
||||
"settingsAllowInstalledAppAccessSubtitle": "Gebruikt om de albumweergave te verbeteren",
|
||||
"@settingsAllowInstalledAppAccessSubtitle": {},
|
||||
"settingsAllowErrorReporting": "Anonieme foutrapportage toestaan",
|
||||
"settingsAllowErrorReporting": "Anonieme foutmeldingen toestaan",
|
||||
"@settingsAllowErrorReporting": {},
|
||||
"settingsSaveSearchHistory": "Bewaar zoekgeschiedenis",
|
||||
"settingsSaveSearchHistory": "Zoekgeschiedenis opslaan",
|
||||
"@settingsSaveSearchHistory": {},
|
||||
"settingsEnableBin": "Prullenbak gebruiken",
|
||||
"@settingsEnableBin": {},
|
||||
|
@ -957,7 +957,7 @@
|
|||
"@settingsHiddenFiltersEmpty": {},
|
||||
"settingsHiddenItemsTabPaths": "Verborgen paden",
|
||||
"@settingsHiddenItemsTabPaths": {},
|
||||
"settingsHiddenPathsBanner": "Foto’s en video’s in deze mappen, of een van hun submappen, verschijnen niet in je verzameling.",
|
||||
"settingsHiddenPathsBanner": "Foto’s en video’s in deze mappen en onderliggende mappen, verschijnen niet in je verzameling.",
|
||||
"@settingsHiddenPathsBanner": {},
|
||||
"addPathTooltip": "Pad toevoegen",
|
||||
"@addPathTooltip": {},
|
||||
|
@ -977,7 +977,7 @@
|
|||
"@settingsRemoveAnimationsTile": {},
|
||||
"settingsRemoveAnimationsDialogTitle": "Animaties verwijderen",
|
||||
"@settingsRemoveAnimationsDialogTitle": {},
|
||||
"settingsTimeToTakeActionTile": "Tijd om actie te ondernemen",
|
||||
"settingsTimeToTakeActionTile": "Reactietijd",
|
||||
"@settingsTimeToTakeActionTile": {},
|
||||
"settingsDisplaySectionTitle": "Scherm",
|
||||
"@settingsDisplaySectionTitle": {},
|
||||
|
@ -985,13 +985,13 @@
|
|||
"@settingsThemeBrightnessTile": {},
|
||||
"settingsThemeBrightnessDialogTitle": "Thema",
|
||||
"@settingsThemeBrightnessDialogTitle": {},
|
||||
"settingsThemeColorHighlights": "Kleur highlights",
|
||||
"settingsThemeColorHighlights": "Kleurmarkeringen",
|
||||
"@settingsThemeColorHighlights": {},
|
||||
"settingsThemeEnableDynamicColor": "Dynamische kleur",
|
||||
"settingsThemeEnableDynamicColor": "Dynamische kleuren",
|
||||
"@settingsThemeEnableDynamicColor": {},
|
||||
"settingsDisplayRefreshRateModeTile": "Vernieuwingsfrequentie weergeven",
|
||||
"settingsDisplayRefreshRateModeTile": "Vernieuwingssnelheid weergeven",
|
||||
"@settingsDisplayRefreshRateModeTile": {},
|
||||
"settingsDisplayRefreshRateModeDialogTitle": "Vernieuwingsfrequentie",
|
||||
"settingsDisplayRefreshRateModeDialogTitle": "Vernieuwingssnelheid",
|
||||
"@settingsDisplayRefreshRateModeDialogTitle": {},
|
||||
"settingsLanguageSectionTitle": "Taal & landinstellingen",
|
||||
"@settingsLanguageSectionTitle": {},
|
||||
|
@ -999,9 +999,9 @@
|
|||
"@settingsLanguageTile": {},
|
||||
"settingsLanguagePageTitle": "Taal",
|
||||
"@settingsLanguagePageTitle": {},
|
||||
"settingsCoordinateFormatTile": "Coördinaten format",
|
||||
"settingsCoordinateFormatTile": "Coördinaten-weergave",
|
||||
"@settingsCoordinateFormatTile": {},
|
||||
"settingsCoordinateFormatDialogTitle": "Coördinaten format",
|
||||
"settingsCoordinateFormatDialogTitle": "Coördinaten-weergave",
|
||||
"@settingsCoordinateFormatDialogTitle": {},
|
||||
"settingsUnitSystemTile": "Eenheden",
|
||||
"@settingsUnitSystemTile": {},
|
||||
|
@ -1013,7 +1013,7 @@
|
|||
"@settingsWidgetPageTitle": {},
|
||||
"settingsWidgetShowOutline": "Contour",
|
||||
"@settingsWidgetShowOutline": {},
|
||||
"settingsWidgetOpenPage": "Wanneer u op de widget tikt",
|
||||
"settingsWidgetOpenPage": "Bij het tikken op de widget",
|
||||
"@settingsWidgetOpenPage": {},
|
||||
"settingsCollectionTile": "Verzameling",
|
||||
"@settingsCollectionTile": {},
|
||||
|
@ -1067,7 +1067,7 @@
|
|||
"@viewerInfoLabelAddress": {},
|
||||
"mapStyleDialogTitle": "Kaartstijl",
|
||||
"@mapStyleDialogTitle": {},
|
||||
"mapStyleTooltip": "Selecteer kaart stijl",
|
||||
"mapStyleTooltip": "Kaartstijl selecteren",
|
||||
"@mapStyleTooltip": {},
|
||||
"mapZoomInTooltip": "Inzoomen",
|
||||
"@mapZoomInTooltip": {},
|
||||
|
@ -1079,13 +1079,13 @@
|
|||
"@mapAttributionOsmHot": {},
|
||||
"mapAttributionStamen": "Kaartgegevens © [OpenStreetMap](https://www.openstreetmap.org/copyright) bijdragers • Tegels door [Stamen Design](https://stamen.com), [CC BY 3.0](https://creativecommons.org/licenses/by/3.0)",
|
||||
"@mapAttributionStamen": {},
|
||||
"openMapPageTooltip": "Bekijk op kaartpagina",
|
||||
"openMapPageTooltip": "Op kaartpagina tonen",
|
||||
"@openMapPageTooltip": {},
|
||||
"mapEmptyRegion": "Geen afbeeldingen in de geselecteerde regio",
|
||||
"mapEmptyRegion": "Geen afbeeldingen in dit gebied",
|
||||
"@mapEmptyRegion": {},
|
||||
"viewerInfoOpenEmbeddedFailureFeedback": "Kan ingesloten gegevens niet extraheren",
|
||||
"@viewerInfoOpenEmbeddedFailureFeedback": {},
|
||||
"viewerInfoOpenLinkText": "Open",
|
||||
"viewerInfoOpenLinkText": "Openen",
|
||||
"@viewerInfoOpenLinkText": {},
|
||||
"viewerInfoViewXmlLinkText": "Bekijk XML",
|
||||
"@viewerInfoViewXmlLinkText": {},
|
||||
|
@ -1119,19 +1119,19 @@
|
|||
"@panoramaDisableSensorControl": {},
|
||||
"sourceViewerPageTitle": "Source",
|
||||
"@sourceViewerPageTitle": {},
|
||||
"filePickerShowHiddenFiles": "Verborgen bestanden laten zien",
|
||||
"filePickerShowHiddenFiles": "Verborgen bestanden weergeven",
|
||||
"@filePickerShowHiddenFiles": {},
|
||||
"filePickerDoNotShowHiddenFiles": "Verborgen bestanden niet laten zien",
|
||||
"filePickerDoNotShowHiddenFiles": "Verborgen bestanden niet tonen",
|
||||
"@filePickerDoNotShowHiddenFiles": {},
|
||||
"filePickerOpenFrom": "Openen met",
|
||||
"filePickerOpenFrom": "Openen van",
|
||||
"@filePickerOpenFrom": {},
|
||||
"filePickerNoItems": "Geen items",
|
||||
"@filePickerNoItems": {},
|
||||
"filePickerUseThisFolder": "Deze map gebruiken",
|
||||
"@filePickerUseThisFolder": {},
|
||||
"widgetOpenPageCollection": "Open verzameling",
|
||||
"widgetOpenPageCollection": "Verzameling openen",
|
||||
"@widgetOpenPageCollection": {},
|
||||
"widgetOpenPageViewer": "Open voorbeeld",
|
||||
"widgetOpenPageViewer": "Voorbeeld openen",
|
||||
"@widgetOpenPageViewer": {},
|
||||
"durationDialogSeconds": "Seconden",
|
||||
"@durationDialogSeconds": {},
|
||||
|
@ -1167,9 +1167,9 @@
|
|||
"@filterNoAddressLabel": {},
|
||||
"filterAspectRatioPortraitLabel": "Staand",
|
||||
"@filterAspectRatioPortraitLabel": {},
|
||||
"widgetDisplayedItemRandom": "Willekeurige",
|
||||
"widgetDisplayedItemRandom": "Willekeurig",
|
||||
"@widgetDisplayedItemRandom": {},
|
||||
"widgetDisplayedItemMostRecent": "Meest recente",
|
||||
"widgetDisplayedItemMostRecent": "Laatst gebruikt",
|
||||
"@widgetDisplayedItemMostRecent": {},
|
||||
"keepScreenOnVideoPlayback": "Tijdens het afspelen van video",
|
||||
"@keepScreenOnVideoPlayback": {},
|
||||
|
@ -1191,7 +1191,7 @@
|
|||
"@stopTooltip": {},
|
||||
"chipActionLock": "Vergrendel",
|
||||
"@chipActionLock": {},
|
||||
"chipActionShowCountryStates": "Status tonen",
|
||||
"chipActionShowCountryStates": "Staten tonen",
|
||||
"@chipActionShowCountryStates": {},
|
||||
"chipActionGoToPlacePage": "In Plaatsen tonen",
|
||||
"@chipActionGoToPlacePage": {},
|
||||
|
@ -1199,15 +1199,15 @@
|
|||
"@subtitlePositionTop": {},
|
||||
"subtitlePositionBottom": "Onder",
|
||||
"@subtitlePositionBottom": {},
|
||||
"settingsThumbnailShowHdrIcon": "HDR icoon zichtbaar",
|
||||
"settingsThumbnailShowHdrIcon": "HDR-pictogram tonen",
|
||||
"@settingsThumbnailShowHdrIcon": {},
|
||||
"editorTransformCrop": "Bijsnijden",
|
||||
"@editorTransformCrop": {},
|
||||
"patternDialogConfirm": "Bevestig patroon",
|
||||
"patternDialogConfirm": "Patroon bevestigen",
|
||||
"@patternDialogConfirm": {},
|
||||
"pinDialogEnter": "Voer PIN in",
|
||||
"@pinDialogEnter": {},
|
||||
"settingsAskEverytime": "Vraag elke keer",
|
||||
"settingsAskEverytime": "Elke keer vragen",
|
||||
"@settingsAskEverytime": {},
|
||||
"aboutDataUsageExternal": "Extern",
|
||||
"@aboutDataUsageExternal": {},
|
||||
|
@ -1217,7 +1217,7 @@
|
|||
"@maxBrightnessAlways": {},
|
||||
"patternDialogEnter": "Voer patroon in",
|
||||
"@patternDialogEnter": {},
|
||||
"settingsViewerShowDescription": "Laat beschrijving zien",
|
||||
"settingsViewerShowDescription": "Beschrijving tonen",
|
||||
"@settingsViewerShowDescription": {},
|
||||
"exportEntryDialogQuality": "Kwaliteit",
|
||||
"@exportEntryDialogQuality": {},
|
||||
|
@ -1241,13 +1241,13 @@
|
|||
"@overlayHistogramLuminance": {},
|
||||
"videoResumptionModeNever": "Nooit",
|
||||
"@videoResumptionModeNever": {},
|
||||
"pinDialogConfirm": "Bevestig PIN",
|
||||
"pinDialogConfirm": "PIN bevestigen",
|
||||
"@pinDialogConfirm": {},
|
||||
"passwordDialogEnter": "Voer wachtwoord in",
|
||||
"@passwordDialogEnter": {},
|
||||
"passwordDialogConfirm": "Bevestig wachtwoord",
|
||||
"passwordDialogConfirm": "Wachtwoord bevestigen",
|
||||
"@passwordDialogConfirm": {},
|
||||
"settingsViewerShowHistogram": "Laat histogram zien",
|
||||
"settingsViewerShowHistogram": "Histogram weergeven",
|
||||
"@settingsViewerShowHistogram": {},
|
||||
"settingsVideoGestureVerticalDragBrightnessVolume": "Veeg omhoog of naar beneden om helderheid/volume aan te passen",
|
||||
"@settingsVideoGestureVerticalDragBrightnessVolume": {},
|
||||
|
@ -1271,7 +1271,7 @@
|
|||
"@videoResumptionModeAlways": {},
|
||||
"exportEntryDialogWriteMetadata": "Metadata schrijven",
|
||||
"@exportEntryDialogWriteMetadata": {},
|
||||
"chipActionShowCollection": "Tonen in Collectie",
|
||||
"chipActionShowCollection": "In Collectie tonen",
|
||||
"@chipActionShowCollection": {},
|
||||
"entryActionCast": "Casten",
|
||||
"@entryActionCast": {},
|
||||
|
@ -1329,7 +1329,7 @@
|
|||
"@settingsVideoBackgroundMode": {},
|
||||
"configureVaultDialogTitle": "Kluis configureren",
|
||||
"@configureVaultDialogTitle": {},
|
||||
"settingsWidgetDisplayedItem": "Getoond item",
|
||||
"settingsWidgetDisplayedItem": "Zichtbaar item",
|
||||
"@settingsWidgetDisplayedItem": {},
|
||||
"albumTierVaults": "Kluizen",
|
||||
"@albumTierVaults": {},
|
||||
|
@ -1367,7 +1367,7 @@
|
|||
"@widgetTapUpdateWidget": {},
|
||||
"authenticateToConfigureVault": "Verifieer om de kluis te configureren",
|
||||
"@authenticateToConfigureVault": {},
|
||||
"settingsConfirmationVaultDataLoss": "Waarschuwing voor verlies van kluisgegevens weergeven",
|
||||
"settingsConfirmationVaultDataLoss": "Waarschuwing weergeven voor verlies van kluisgegevens",
|
||||
"@settingsConfirmationVaultDataLoss": {},
|
||||
"newVaultDialogTitle": "Nieuwe kluis",
|
||||
"@newVaultDialogTitle": {},
|
||||
|
@ -1383,8 +1383,14 @@
|
|||
"@collectionActionSetHome": {},
|
||||
"setHomeCustom": "Aangepast",
|
||||
"@setHomeCustom": {},
|
||||
"explorerActionSelectStorageVolume": "Selecteer opslag",
|
||||
"explorerActionSelectStorageVolume": "Opslag selecteren",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "Selecteer opslag",
|
||||
"@selectStorageVolumeDialogTitle": {}
|
||||
"selectStorageVolumeDialogTitle": "Opslag selecteren",
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"sortByDuration": "Op lengte",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderShortestFirst": "Kortste eerst",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "Langste eerst",
|
||||
"@sortOrderLongestFirst": {}
|
||||
}
|
||||
|
|
|
@ -1536,5 +1536,17 @@
|
|||
"chipActionGoToExplorerPage": "Pokaż w przeglądarce",
|
||||
"@chipActionGoToExplorerPage": {},
|
||||
"explorerPageTitle": "Przeglądarka",
|
||||
"@explorerPageTitle": {}
|
||||
"@explorerPageTitle": {},
|
||||
"selectStorageVolumeDialogTitle": "Wybierz pamięć",
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"explorerActionSelectStorageVolume": "Wybierz pamięć",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"setHomeCustom": "Własny",
|
||||
"@setHomeCustom": {},
|
||||
"sortByDuration": "Według czasu trwania",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderShortestFirst": "Najkrótsze najpierw",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "Najdłuższe najpierw",
|
||||
"@sortOrderLongestFirst": {}
|
||||
}
|
||||
|
|
|
@ -1380,5 +1380,15 @@
|
|||
"explorerPageTitle": "Проводник",
|
||||
"@explorerPageTitle": {},
|
||||
"explorerActionSelectStorageVolume": "Выбрать хранилище",
|
||||
"@explorerActionSelectStorageVolume": {}
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "Выбрать хранилище",
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"sortByDuration": "По продолжительности",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderLongestFirst": "Сначала самый длинный",
|
||||
"@sortOrderLongestFirst": {},
|
||||
"setHomeCustom": "По своему",
|
||||
"@setHomeCustom": {},
|
||||
"sortOrderShortestFirst": "Сначала самый короткий",
|
||||
"@sortOrderShortestFirst": {}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"viewerActionLock": "Lås",
|
||||
"viewerActionLock": "Lås visaren",
|
||||
"@viewerActionLock": {},
|
||||
"entryInfoActionEditTags": "Redigera taggar",
|
||||
"@entryInfoActionEditTags": {},
|
||||
|
@ -7,19 +7,19 @@
|
|||
"@videoActionPlay": {},
|
||||
"viewerActionSettings": "Inställningar",
|
||||
"@viewerActionSettings": {},
|
||||
"albumTierSpecial": "Vanlig",
|
||||
"albumTierSpecial": "Vanligt förekommande",
|
||||
"@albumTierSpecial": {},
|
||||
"displayRefreshRatePreferLowest": "Lägsta intervall",
|
||||
"@displayRefreshRatePreferLowest": {},
|
||||
"keepScreenOnViewerOnly": "Visningssidan bara",
|
||||
"keepScreenOnViewerOnly": "Endast visningssidan",
|
||||
"@keepScreenOnViewerOnly": {},
|
||||
"mapStyleOsmHot": "Humanitarian OSM",
|
||||
"mapStyleOsmHot": "Humanitär OSM",
|
||||
"@mapStyleOsmHot": {},
|
||||
"videoResumptionModeAlways": "Alltid",
|
||||
"@videoResumptionModeAlways": {},
|
||||
"storageVolumeDescriptionFallbackPrimary": "Intern lagring",
|
||||
"@storageVolumeDescriptionFallbackPrimary": {},
|
||||
"widgetOpenPageCollection": "Öppen insamling",
|
||||
"widgetOpenPageCollection": "Öppna samling",
|
||||
"@widgetOpenPageCollection": {},
|
||||
"widgetTapUpdateWidget": "Uppdatera widgeten",
|
||||
"@widgetTapUpdateWidget": {},
|
||||
|
@ -206,7 +206,7 @@
|
|||
"@entryActionDelete": {},
|
||||
"entryActionCopyToClipboard": "Spara till urklipp",
|
||||
"@entryActionCopyToClipboard": {},
|
||||
"viewerActionUnlock": "Öppna",
|
||||
"viewerActionUnlock": "Lås upp visaren",
|
||||
"@viewerActionUnlock": {},
|
||||
"slideshowActionResume": "Återuppta",
|
||||
"@slideshowActionResume": {},
|
||||
|
@ -238,9 +238,9 @@
|
|||
"@cropAspectRatioOriginal": {},
|
||||
"cropAspectRatioSquare": "Fyrkant",
|
||||
"@cropAspectRatioSquare": {},
|
||||
"filterAspectRatioLandscapeLabel": "Liggande",
|
||||
"filterAspectRatioLandscapeLabel": "Liggande bilder",
|
||||
"@filterAspectRatioLandscapeLabel": {},
|
||||
"filterAspectRatioPortraitLabel": "Porträtt",
|
||||
"filterAspectRatioPortraitLabel": "Stående bilder",
|
||||
"@filterAspectRatioPortraitLabel": {},
|
||||
"filterBinLabel": "Papperskorg",
|
||||
"@filterBinLabel": {},
|
||||
|
@ -333,9 +333,9 @@
|
|||
"@mapStyleGoogleNormal": {},
|
||||
"mapStyleGoogleHybrid": "Google Maps (Hybrid)",
|
||||
"@mapStyleGoogleHybrid": {},
|
||||
"mapStyleGoogleTerrain": "Google Maps (Terrain)",
|
||||
"mapStyleGoogleTerrain": "Google Maps (Terräng)",
|
||||
"@mapStyleGoogleTerrain": {},
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor",
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor (Akvarell)",
|
||||
"@mapStyleStamenWatercolor": {},
|
||||
"maxBrightnessNever": "Alldrig",
|
||||
"@maxBrightnessNever": {},
|
||||
|
@ -377,11 +377,11 @@
|
|||
"@settingsVideoEnablePip": {},
|
||||
"videoControlsPlay": "Spela",
|
||||
"@videoControlsPlay": {},
|
||||
"videoControlsPlaySeek": "Spela & sök bakåt/framåt",
|
||||
"videoControlsPlaySeek": "Spela & spola bakåt/framåt",
|
||||
"@videoControlsPlaySeek": {},
|
||||
"videoControlsPlayOutside": "Öppna med annan spelare",
|
||||
"@videoControlsPlayOutside": {},
|
||||
"videoControlsNone": "Ingen",
|
||||
"videoControlsNone": "Inga",
|
||||
"@videoControlsNone": {},
|
||||
"videoLoopModeNever": "Aldrig",
|
||||
"@videoLoopModeNever": {},
|
||||
|
@ -409,9 +409,9 @@
|
|||
"@widgetDisplayedItemRandom": {},
|
||||
"widgetDisplayedItemMostRecent": "Alldra senast",
|
||||
"@widgetDisplayedItemMostRecent": {},
|
||||
"widgetOpenPageHome": "Öppna hem",
|
||||
"widgetOpenPageHome": "Öppna startsida",
|
||||
"@widgetOpenPageHome": {},
|
||||
"otherDirectoryDescription": "“{name}” map",
|
||||
"otherDirectoryDescription": "“{name}”-katalogen",
|
||||
"@otherDirectoryDescription": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
|
@ -421,7 +421,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"storageAccessDialogMessage": "Var snäll och välj {directory} av“{volume}” på nästa skärm för att ge appen åtkomst till den.",
|
||||
"storageAccessDialogMessage": "Vänligen välj {directory} i “{volume}” på nästa skärm för att ge appen åtkomst till den.",
|
||||
"@storageAccessDialogMessage": {
|
||||
"placeholders": {
|
||||
"directory": {
|
||||
|
@ -523,7 +523,7 @@
|
|||
"@nameConflictDialogSingleSourceMessage": {},
|
||||
"nameConflictDialogMultipleSourceMessage": "Vissa filer har samma namn.",
|
||||
"@nameConflictDialogMultipleSourceMessage": {},
|
||||
"noMatchingAppDialogMessage": "Det finns inga appar som kan hantera detta.",
|
||||
"noMatchingAppDialogMessage": "Det finns inga applikationer som kan hantera detta.",
|
||||
"@noMatchingAppDialogMessage": {},
|
||||
"moveUndatedConfirmationDialogSetDate": "Spara datum",
|
||||
"@moveUndatedConfirmationDialogSetDate": {},
|
||||
|
@ -752,7 +752,7 @@
|
|||
"@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": "Systemets filväljare saknas eller har inaktiverats. Vänligen aktivera denna och försök igen.",
|
||||
"@missingSystemFilePickerDialogMessage": {},
|
||||
"renameProcessorCounter": "Räknare",
|
||||
"@renameProcessorCounter": {},
|
||||
|
@ -833,5 +833,66 @@
|
|||
"chipActionUnpin": "Släpp från fästet",
|
||||
"@chipActionUnpin": {},
|
||||
"chipActionShowCollection": "Visa i samling",
|
||||
"@chipActionShowCollection": {}
|
||||
"@chipActionShowCollection": {},
|
||||
"videoActionABRepeat": "A-B återupprepa",
|
||||
"@videoActionABRepeat": {},
|
||||
"videoRepeatActionSetStart": "Ange start",
|
||||
"@videoRepeatActionSetStart": {},
|
||||
"restrictedAccessDialogMessage": "Denna applikation har ej tillåtelse att modifiera filer i {directory} i \"{volume}\".\n\nVänligen använd en förinstallerad filhanterare eller galleriapplikation för att flytta filerna till en annan katalog.",
|
||||
"@restrictedAccessDialogMessage": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"widgetOpenPageViewer": "Öppna bildspel",
|
||||
"@widgetOpenPageViewer": {},
|
||||
"rootDirectoryDescription": "grundkatalog",
|
||||
"@rootDirectoryDescription": {},
|
||||
"notEnoughSpaceDialogMessage": "Denna åtgärd behöver {neededSize} ledigt utrymme på \"{volume}\" för att kunna slutföras, men det är enbart {freeSize} kvar.",
|
||||
"@notEnoughSpaceDialogMessage": {
|
||||
"placeholders": {
|
||||
"neededSize": {
|
||||
"type": "String",
|
||||
"example": "314 MB"
|
||||
},
|
||||
"freeSize": {
|
||||
"type": "String",
|
||||
"example": "123 MB"
|
||||
},
|
||||
"volume": {
|
||||
"type": "String",
|
||||
"example": "SD card",
|
||||
"description": "the name of a storage volume"
|
||||
}
|
||||
}
|
||||
},
|
||||
"addShortcutButtonLabel": "LÄGG TILL",
|
||||
"@addShortcutButtonLabel": {},
|
||||
"addShortcutDialogLabel": "Rubrik för genväg",
|
||||
"@addShortcutDialogLabel": {},
|
||||
"unsupportedTypeDialogMessage": "{count, plural, =1{Denna åtgärd stöds ej för filer av denna typ: {types}.} other{Denna åtgärd stöds ej för följande typer av filer: {types}.}}",
|
||||
"@unsupportedTypeDialogMessage": {
|
||||
"placeholders": {
|
||||
"count": {},
|
||||
"types": {
|
||||
"type": "String",
|
||||
"example": "GIF, TIFF, MP4",
|
||||
"description": "a list of unsupported types"
|
||||
}
|
||||
}
|
||||
},
|
||||
"stopTooltip": "Stopp",
|
||||
"@stopTooltip": {},
|
||||
"chipActionGoToExplorerPage": "Visa i utforskaren",
|
||||
"@chipActionGoToExplorerPage": {},
|
||||
"videoRepeatActionSetEnd": "Ange slut",
|
||||
"@videoRepeatActionSetEnd": {}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"@welcomeOptional": {},
|
||||
"welcomeTermsToggle": "Hüküm ve koşulları kabul ediyorum",
|
||||
"@welcomeTermsToggle": {},
|
||||
"itemCount": "{count, plural, other{{count} öğe}}",
|
||||
"itemCount": "{count, plural, other{{count} öge}}",
|
||||
"@itemCount": {},
|
||||
"timeSeconds": "{count, plural, other{{count} saniye}}",
|
||||
"@timeSeconds": {},
|
||||
|
@ -273,7 +273,7 @@
|
|||
"@rootDirectoryDescription": {},
|
||||
"otherDirectoryDescription": "“{name}” dizin",
|
||||
"@otherDirectoryDescription": {},
|
||||
"storageAccessDialogMessage": "Bu uygulamaya erişim sağlamak için lütfen bir sonraki ekranda “{volume}” öğesinin {directory} dizinini seçin.",
|
||||
"storageAccessDialogMessage": "Bir sonraki ekranda \"{volume}\" içindeki {directory} dizinini seçerek bu uygulamaya erişim izni verin.",
|
||||
"@storageAccessDialogMessage": {},
|
||||
"restrictedAccessDialogMessage": "Bu uygulamanın “{volume}” içindeki {directory} dosyaları değiştirmesine izin verilmiyor.\n\nÖğeleri başka bir dizine taşımak için lütfen önceden yüklenmiş bir dosya yöneticisi veya galeri uygulaması kullanın.",
|
||||
"@restrictedAccessDialogMessage": {},
|
||||
|
@ -281,7 +281,7 @@
|
|||
"@notEnoughSpaceDialogMessage": {},
|
||||
"missingSystemFilePickerDialogMessage": "Sistem dosya seçicisi eksik veya devre dışı. Lütfen etkinleştirin ve tekrar deneyin.",
|
||||
"@missingSystemFilePickerDialogMessage": {},
|
||||
"unsupportedTypeDialogMessage": "{count, plural, =1{Bu işlem aşağıdaki türdeki öğeler için desteklenmez: {types}.} other{Bu işlem aşağıdaki türlerdeki öğeler için desteklenmez: {types}.}}",
|
||||
"unsupportedTypeDialogMessage": "{count, plural, =1{Bu işlem şu türdeki ögeler için desteklenmez: {types}.} other{Bu işlem şu türlerdeki ögeler için desteklenmez: {types}.}}",
|
||||
"@unsupportedTypeDialogMessage": {},
|
||||
"nameConflictDialogSingleSourceMessage": "Hedef klasördeki bazı dosyalar aynı ada sahip.",
|
||||
"@nameConflictDialogSingleSourceMessage": {},
|
||||
|
@ -293,11 +293,11 @@
|
|||
"@addShortcutButtonLabel": {},
|
||||
"noMatchingAppDialogMessage": "Bununla ilgilenebilecek bir uygulama yok.",
|
||||
"@noMatchingAppDialogMessage": {},
|
||||
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Bu öğe geri dönüşüm kutusuna taşınsın mı?} other{Bu {count} madde geri dönüşüm kutusuna atılsın mı?}}",
|
||||
"binEntriesConfirmationDialogMessage": "{count, plural, =1{Bu öge geri dönüşüm kutusuna taşınsın mı?} other{Bu {count} öge geri dönüşüm kutusuna atılsın mı?}}",
|
||||
"@binEntriesConfirmationDialogMessage": {},
|
||||
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Bu öğe silinsin mi?} other{Bu {count} öğe silinsin mi?}}",
|
||||
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Bu öge silinsin mi?} other{Bu {count} öge silinsin mi?}}",
|
||||
"@deleteEntriesConfirmationDialogMessage": {},
|
||||
"moveUndatedConfirmationDialogMessage": "Devam etmeden önce öğe tarihleri kaydedilsin mi?",
|
||||
"moveUndatedConfirmationDialogMessage": "Devam etmeden önce öge tarihleri kaydedilsin mi?",
|
||||
"@moveUndatedConfirmationDialogMessage": {},
|
||||
"moveUndatedConfirmationDialogSetDate": "Tarihleri kaydet",
|
||||
"@moveUndatedConfirmationDialogSetDate": {},
|
||||
|
@ -307,7 +307,7 @@
|
|||
"@videoStartOverButtonLabel": {},
|
||||
"videoResumeButtonLabel": "SÜRDÜR",
|
||||
"@videoResumeButtonLabel": {},
|
||||
"setCoverDialogLatest": "Son öğe",
|
||||
"setCoverDialogLatest": "Son öge",
|
||||
"@setCoverDialogLatest": {},
|
||||
"setCoverDialogAuto": "Otomatik",
|
||||
"@setCoverDialogAuto": {},
|
||||
|
@ -359,7 +359,7 @@
|
|||
"@editEntryDateDialogSetCustom": {},
|
||||
"editEntryDateDialogCopyField": "Başka bir tarihten kopyala",
|
||||
"@editEntryDateDialogCopyField": {},
|
||||
"editEntryDialogCopyFromItem": "Başka bir öğeden kopyala",
|
||||
"editEntryDialogCopyFromItem": "Başka bir ögeden kopyala",
|
||||
"@editEntryDialogCopyFromItem": {},
|
||||
"editEntryDateDialogExtractFromTitle": "Başlıktan ayıkla",
|
||||
"@editEntryDateDialogExtractFromTitle": {},
|
||||
|
@ -523,25 +523,25 @@
|
|||
"@dateYesterday": {},
|
||||
"dateThisMonth": "Bu ay",
|
||||
"@dateThisMonth": {},
|
||||
"collectionDeleteFailureFeedback": "{count, plural, =1{1 öğe silinemedi} other{{count} öğe silinemedi}}",
|
||||
"collectionDeleteFailureFeedback": "{count, plural, =1{1 öge silinemedi} other{{count} öge silinemedi}}",
|
||||
"@collectionDeleteFailureFeedback": {},
|
||||
"collectionCopyFailureFeedback": "{count, plural, =1{1 öğe kopyalanamadı} other{{count} öğe kopyalanamadı}}",
|
||||
"collectionCopyFailureFeedback": "{count, plural, =1{1 öge kopyalanamadı} other{{count} öge kopyalanamadı}}",
|
||||
"@collectionCopyFailureFeedback": {},
|
||||
"collectionMoveFailureFeedback": "{count, plural, =1{1 öğe taşınamadı} other{{count} öğe taşınamadı}}",
|
||||
"collectionMoveFailureFeedback": "{count, plural, =1{1 öge taşınamadı} other{{count} öge taşınamadı}}",
|
||||
"@collectionMoveFailureFeedback": {},
|
||||
"collectionRenameFailureFeedback": "{count, plural, =1{1 öğenin adı değiştirilemedi} other{{count} öğenin adı değiştirilemedi}}",
|
||||
"collectionRenameFailureFeedback": "{count, plural, =1{1 ögenin adı değiştirilemedi} other{{count} ögenin adı değiştirilemedi}}",
|
||||
"@collectionRenameFailureFeedback": {},
|
||||
"collectionEditFailureFeedback": "{count, plural, =1{1 öğe düzenlenemedi} other{{count} öğe düzenlenemedi}}",
|
||||
"collectionEditFailureFeedback": "{count, plural, =1{1 öge düzenlenemedi} other{{count} öge düzenlenemedi}}",
|
||||
"@collectionEditFailureFeedback": {},
|
||||
"collectionExportFailureFeedback": "{count, plural, =1{1 sayfa dışa aktarılamadı} other{{count} sayfa dışa aktarılamadı}}",
|
||||
"@collectionExportFailureFeedback": {},
|
||||
"collectionCopySuccessFeedback": "{count, plural, =1{1 öğe kopyalandı} other{{count} öğe kopyalandı}}",
|
||||
"collectionCopySuccessFeedback": "{count, plural, =1{1 öge kopyalandı} other{{count} öge kopyalandı}}",
|
||||
"@collectionCopySuccessFeedback": {},
|
||||
"collectionMoveSuccessFeedback": "{count, plural, =1{1 öğe taşındı} other{{count} öğe taşındı}}",
|
||||
"collectionMoveSuccessFeedback": "{count, plural, =1{1 öge taşındı} other{{count} öge taşındı}}",
|
||||
"@collectionMoveSuccessFeedback": {},
|
||||
"collectionRenameSuccessFeedback": "{count, plural, =1{1 öğenin adı değiştirildi} other{{count} öğenin adı değiştirildi}}",
|
||||
"collectionRenameSuccessFeedback": "{count, plural, =1{1 ögenin adı değiştirildi} other{{count} ögenin adı değiştirildi}}",
|
||||
"@collectionRenameSuccessFeedback": {},
|
||||
"collectionEditSuccessFeedback": "{count, plural, =1{1 öğe düzenlendi} other{{count} öğe düzenlendi}}",
|
||||
"collectionEditSuccessFeedback": "{count, plural, =1{1 öge düzenlendi} other{{count} öge düzenlendi}}",
|
||||
"@collectionEditSuccessFeedback": {},
|
||||
"collectionEmptyFavourites": "Favori yok",
|
||||
"@collectionEmptyFavourites": {},
|
||||
|
@ -705,7 +705,7 @@
|
|||
"@settingsNavigationDrawerTile": {},
|
||||
"settingsNavigationDrawerEditorPageTitle": "Gezinti Menüsü",
|
||||
"@settingsNavigationDrawerEditorPageTitle": {},
|
||||
"settingsNavigationDrawerBanner": "Menü öğelerini taşımak ve yeniden sıralamak için dokunun ve basılı tutun.",
|
||||
"settingsNavigationDrawerBanner": "Menü ögelerini taşımak ve yeniden sıralamak için dokunun ve basılı tutun.",
|
||||
"@settingsNavigationDrawerBanner": {},
|
||||
"settingsNavigationDrawerTabTypes": "Türler",
|
||||
"@settingsNavigationDrawerTabTypes": {},
|
||||
|
@ -743,9 +743,9 @@
|
|||
"@settingsCollectionQuickActionTabBrowsing": {},
|
||||
"settingsCollectionQuickActionTabSelecting": "Seçme",
|
||||
"@settingsCollectionQuickActionTabSelecting": {},
|
||||
"settingsCollectionBrowsingQuickActionEditorBanner": "Düğmeleri hareket ettirmek ve öğelere göz atarken hangi eylemlerin görüntüleneceğini seçmek için dokunun ve basılı tutun.",
|
||||
"settingsCollectionBrowsingQuickActionEditorBanner": "Düğmeleri hareket ettirmek ve ögelere göz atarken hangi eylemlerin görüntüleneceğini seçmek için dokunun ve basılı tutun.",
|
||||
"@settingsCollectionBrowsingQuickActionEditorBanner": {},
|
||||
"settingsCollectionSelectionQuickActionEditorBanner": "Düğmeleri hareket ettirmek ve öğeleri seçerken hangi eylemlerin görüntüleneceğini seçmek için dokunun ve basılı tutun.",
|
||||
"settingsCollectionSelectionQuickActionEditorBanner": "Düğmeleri hareket ettirmek ve ögeleri seçerken hangi eylemlerin görüntüleneceğini seçmek için dokunun ve basılı tutun.",
|
||||
"@settingsCollectionSelectionQuickActionEditorBanner": {},
|
||||
"settingsViewerSectionTitle": "Görüntüleyici",
|
||||
"@settingsViewerSectionTitle": {},
|
||||
|
@ -851,9 +851,9 @@
|
|||
"@settingsSaveSearchHistory": {},
|
||||
"settingsEnableBin": "Geri dönüşüm kutusunu kullan",
|
||||
"@settingsEnableBin": {},
|
||||
"settingsEnableBinSubtitle": "Silinen öğeleri 30 gün boyunca saklar",
|
||||
"settingsEnableBinSubtitle": "Silinen ögeleri 30 gün boyunca saklar",
|
||||
"@settingsEnableBinSubtitle": {},
|
||||
"settingsHiddenItemsTile": "Gizli öğeler",
|
||||
"settingsHiddenItemsTile": "Gizli ögeler",
|
||||
"@settingsHiddenItemsTile": {},
|
||||
"settingsHiddenItemsPageTitle": "Gizli Öğeler",
|
||||
"@settingsHiddenItemsPageTitle": {},
|
||||
|
@ -921,7 +921,7 @@
|
|||
"@settingsCollectionTile": {},
|
||||
"statsPageTitle": "İstatistikler",
|
||||
"@statsPageTitle": {},
|
||||
"statsWithGps": "{count, plural, =1{1 konuma sahip öğe} other{{count} konuma sahip öğe}}",
|
||||
"statsWithGps": "{count, plural, =1{1 öge konuma sahip} other{{count} öge konuma sahip}}",
|
||||
"@statsWithGps": {},
|
||||
"statsTopCountriesSectionTitle": "Öne Çıkan Ülkeler",
|
||||
"@statsTopCountriesSectionTitle": {},
|
||||
|
@ -1019,7 +1019,7 @@
|
|||
"@filePickerDoNotShowHiddenFiles": {},
|
||||
"filePickerOpenFrom": "Şuradan aç",
|
||||
"@filePickerOpenFrom": {},
|
||||
"filePickerNoItems": "Öğe yok",
|
||||
"filePickerNoItems": "Öge yok",
|
||||
"@filePickerNoItems": {},
|
||||
"filePickerUseThisFolder": "Bu klasörü kullan",
|
||||
"@filePickerUseThisFolder": {},
|
||||
|
@ -1049,7 +1049,7 @@
|
|||
"@sortOrderLargestFirst": {},
|
||||
"settingsConfirmationAfterMoveToBinItems": "Öğeleri geri dönüşüm kutusuna taşıdıktan sonra mesaj göster",
|
||||
"@settingsConfirmationAfterMoveToBinItems": {},
|
||||
"settingsViewerGestureSideTapNext": "Önceki/sonraki öğeyi göstermek için ekran kenarlarına dokunun",
|
||||
"settingsViewerGestureSideTapNext": "Önceki/sonraki ögeyi göstermek için ekran kenarlarına dokunun",
|
||||
"@settingsViewerGestureSideTapNext": {},
|
||||
"settingsSlideshowVideoPlaybackTile": "Video oynatma",
|
||||
"@settingsSlideshowVideoPlaybackTile": {},
|
||||
|
@ -1161,7 +1161,7 @@
|
|||
"@widgetDisplayedItemMostRecent": {},
|
||||
"settingsSubtitleThemeTextPositionTile": "Metin konumu",
|
||||
"@settingsSubtitleThemeTextPositionTile": {},
|
||||
"settingsWidgetDisplayedItem": "Görüntülenen öğe",
|
||||
"settingsWidgetDisplayedItem": "Görüntülenen öge",
|
||||
"@settingsWidgetDisplayedItem": {},
|
||||
"settingsSubtitleThemeTextPositionDialogTitle": "Metin Konumu",
|
||||
"@settingsSubtitleThemeTextPositionDialogTitle": {},
|
||||
|
@ -1378,5 +1378,17 @@
|
|||
"chipActionGoToExplorerPage": "Gezginde göster",
|
||||
"@chipActionGoToExplorerPage": {},
|
||||
"explorerPageTitle": "Gezgin",
|
||||
"@explorerPageTitle": {}
|
||||
"@explorerPageTitle": {},
|
||||
"explorerActionSelectStorageVolume": "Depolama alanı seç",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "Depolama Alanı Seç",
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"setHomeCustom": "Özel",
|
||||
"@setHomeCustom": {},
|
||||
"sortByDuration": "Süreye göre",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderShortestFirst": "Önce en kısa",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "Önce en uzun",
|
||||
"@sortOrderLongestFirst": {}
|
||||
}
|
||||
|
|
|
@ -1542,5 +1542,11 @@
|
|||
"explorerActionSelectStorageVolume": "Обрати сховище",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "Оберіть сховище",
|
||||
"@selectStorageVolumeDialogTitle": {}
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"sortByDuration": "За тривалістю",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderShortestFirst": "Спершу найкоротше",
|
||||
"@sortOrderShortestFirst": {},
|
||||
"sortOrderLongestFirst": "Спершу найдовше",
|
||||
"@sortOrderLongestFirst": {}
|
||||
}
|
||||
|
|
|
@ -1378,5 +1378,17 @@
|
|||
"explorerPageTitle": "资源管理器",
|
||||
"@explorerPageTitle": {},
|
||||
"chipActionGoToExplorerPage": "在资源管理器中显示",
|
||||
"@chipActionGoToExplorerPage": {}
|
||||
"@chipActionGoToExplorerPage": {},
|
||||
"setHomeCustom": "自定义",
|
||||
"@setHomeCustom": {},
|
||||
"explorerActionSelectStorageVolume": "选择存储器",
|
||||
"@explorerActionSelectStorageVolume": {},
|
||||
"selectStorageVolumeDialogTitle": "选择存储器",
|
||||
"@selectStorageVolumeDialogTitle": {},
|
||||
"sortByDuration": "按时长",
|
||||
"@sortByDuration": {},
|
||||
"sortOrderLongestFirst": "先长后短",
|
||||
"@sortOrderLongestFirst": {},
|
||||
"sortOrderShortestFirst": "先短后长",
|
||||
"@sortOrderShortestFirst": {}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:aves/app_flavor.dart';
|
||||
import 'package:aves/main_common.dart';
|
||||
import 'package:aves/widgets/intent.dart';
|
||||
import 'package:aves/model/app/intent.dart';
|
||||
|
||||
// https://developer.android.com/studio/command-line/adb.html#IntentSpec
|
||||
// adb shell am start -n deckers.thibault.aves.debug/deckers.thibault.aves.MainActivity -a android.intent.action.EDIT -d content://media/external/images/media/183128 -t image/*
|
||||
|
|
|
@ -95,6 +95,7 @@ class Contributors {
|
|||
Contributor('elfriob', 'elfriob@ya.ru'),
|
||||
Contributor('Stephan Paternotte', 'stephan@paternottes.net'),
|
||||
Contributor('Tung Anh', 'buihuutunganh2007@gmail.com'),
|
||||
Contributor('Adrien N', 'adriennathaniel1999@gmail.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
|
||||
|
@ -113,6 +114,7 @@ class Contributors {
|
|||
// Contributor('Prasanta-Hembram', 'Prasantahembram720@gmail.com'), // Santali
|
||||
// Contributor('mytja', 'mamnju21@gmail.com'), // Slovenian
|
||||
// Contributor('Shift18', 'bribable.lawyer@posteo.net'), // Swedish
|
||||
// Contributor('Andreas Håll', 'ante_skalman@hotmail.com'), // Swedish
|
||||
// Contributor('Nattapong K', 'mixer5056@gmail.com'), // Thai
|
||||
};
|
||||
}
|
||||
|
|
|
@ -338,12 +338,6 @@ class Dependencies {
|
|||
license: apache2,
|
||||
sourceUrl: 'https://github.com/jifalops/dart-latlong',
|
||||
),
|
||||
Dependency(
|
||||
name: 'Material Color Utilities',
|
||||
license: apache2,
|
||||
licenseUrl: 'https://github.com/material-foundation/material-color-utilities/tree/main/dart/LICENSE',
|
||||
sourceUrl: 'https://github.com/material-foundation/material-color-utilities/tree/main/dart',
|
||||
),
|
||||
Dependency(
|
||||
name: 'Memory Leak Tracker',
|
||||
license: bsd3,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/apps.dart';
|
||||
import 'package:aves/model/app_inventory.dart';
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/filters/album.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
|
|
|
@ -6,7 +6,7 @@ import 'package:aves/model/metadata/address.dart';
|
|||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/metadata/trash.dart';
|
||||
import 'package:aves/model/vaults/details.dart';
|
||||
import 'package:aves/model/video_playback.dart';
|
||||
import 'package:aves/model/viewer/video_playback.dart';
|
||||
|
||||
abstract class MetadataDb {
|
||||
int get nextId;
|
||||
|
|
|
@ -10,7 +10,7 @@ import 'package:aves/model/metadata/address.dart';
|
|||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/metadata/trash.dart';
|
||||
import 'package:aves/model/vaults/details.dart';
|
||||
import 'package:aves/model/video_playback.dart';
|
||||
import 'package:aves/model/viewer/video_playback.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
|
|
@ -2,9 +2,9 @@ import 'dart:async';
|
|||
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/entry/extensions/props.dart';
|
||||
import 'package:aves/model/geotiff.dart';
|
||||
import 'package:aves/model/media/geotiff.dart';
|
||||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/video/metadata.dart';
|
||||
import 'package:aves/model/media/video/metadata.dart';
|
||||
import 'package:aves/ref/mime_types.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/services/metadata/svg_metadata_service.dart';
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'dart:collection';
|
|||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/entry/extensions/multipage.dart';
|
||||
import 'package:aves/model/entry/extensions/props.dart';
|
||||
import 'package:aves/model/video/metadata.dart';
|
||||
import 'package:aves/model/media/video/metadata.dart';
|
||||
import 'package:aves/ref/mime_types.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/services/metadata/svg_metadata_service.dart';
|
||||
|
|
|
@ -35,4 +35,12 @@ class AvesEntrySort {
|
|||
final c = (b.sizeBytes ?? 0).compareTo(a.sizeBytes ?? 0);
|
||||
return c != 0 ? c : compareByDate(a, b);
|
||||
}
|
||||
|
||||
// compare by:
|
||||
// 1) duration descending
|
||||
// 2) date descending
|
||||
static int compareByDuration(AvesEntry a, AvesEntry b) {
|
||||
final c = (b.durationMillis ?? 0).compareTo(a.durationMillis ?? 0);
|
||||
return c != 0 ? c : compareByDate(a, b);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ import 'dart:async';
|
|||
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/video/channel_layouts.dart';
|
||||
import 'package:aves/model/video/codecs.dart';
|
||||
import 'package:aves/model/video/profiles/aac.dart';
|
||||
import 'package:aves/model/video/profiles/h264.dart';
|
||||
import 'package:aves/model/video/profiles/hevc.dart';
|
||||
import 'package:aves/model/media/video/channel_layouts.dart';
|
||||
import 'package:aves/model/media/video/codecs.dart';
|
||||
import 'package:aves/model/media/video/profiles/aac.dart';
|
||||
import 'package:aves/model/media/video/profiles/h264.dart';
|
||||
import 'package:aves/model/media/video/profiles/hevc.dart';
|
||||
import 'package:aves/ref/languages.dart';
|
||||
import 'package:aves/ref/locales.dart';
|
||||
import 'package:aves/ref/mime_types.dart';
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/convert/metadata/fields.dart';
|
||||
import 'package:aves/convert/convert.dart';
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
|
|
|
@ -6,7 +6,7 @@ import 'package:collection/collection.dart';
|
|||
import 'package:flutter/widgets.dart';
|
||||
|
||||
mixin AppSettings on SettingsAccess {
|
||||
static const int _recentFilterHistoryMax = 10;
|
||||
static const int recentFilterHistoryMax = 20;
|
||||
|
||||
bool get hasAcceptedTerms => getBool(SettingKeys.hasAcceptedTermsKey) ?? SettingsDefaults.hasAcceptedTerms;
|
||||
|
||||
|
@ -105,9 +105,9 @@ mixin AppSettings on SettingsAccess {
|
|||
|
||||
List<String> get recentDestinationAlbums => getStringList(SettingKeys.recentDestinationAlbumsKey) ?? [];
|
||||
|
||||
set recentDestinationAlbums(List<String> newValue) => set(SettingKeys.recentDestinationAlbumsKey, newValue.take(_recentFilterHistoryMax).toList());
|
||||
set recentDestinationAlbums(List<String> newValue) => set(SettingKeys.recentDestinationAlbumsKey, newValue.take(recentFilterHistoryMax).toList());
|
||||
|
||||
List<CollectionFilter> get recentTags => (getStringList(SettingKeys.recentTagsKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toList();
|
||||
|
||||
set recentTags(List<CollectionFilter> newValue) => set(SettingKeys.recentTagsKey, newValue.take(_recentFilterHistoryMax).map((filter) => filter.toJson()).toList());
|
||||
set recentTags(List<CollectionFilter> newValue) => set(SettingKeys.recentTagsKey, newValue.take(recentFilterHistoryMax).map((filter) => filter.toJson()).toList());
|
||||
}
|
||||
|
|
|
@ -9,17 +9,18 @@ mixin PrivacySettings on SettingsAccess, SearchSettings {
|
|||
set hiddenFilters(Set<CollectionFilter> newValue) => set(SettingKeys.hiddenFiltersKey, newValue.map((filter) => filter.toJson()).toList());
|
||||
|
||||
void changeFilterVisibility(Set<CollectionFilter> filters, bool visible) {
|
||||
final _deactivatedHiddenFilters = deactivatedHiddenFilters;
|
||||
final _hiddenFilters = hiddenFilters;
|
||||
|
||||
_deactivatedHiddenFilters.removeAll(filters);
|
||||
if (visible) {
|
||||
_hiddenFilters.removeAll(filters);
|
||||
} else {
|
||||
_hiddenFilters.addAll(filters);
|
||||
searchHistory = searchHistory..removeWhere(filters.contains);
|
||||
|
||||
final _deactivatedHiddenFilters = deactivatedHiddenFilters;
|
||||
_deactivatedHiddenFilters.removeAll(filters);
|
||||
deactivatedHiddenFilters = _deactivatedHiddenFilters;
|
||||
}
|
||||
|
||||
deactivatedHiddenFilters = _deactivatedHiddenFilters;
|
||||
hiddenFilters = _hiddenFilters;
|
||||
}
|
||||
|
||||
|
@ -29,14 +30,18 @@ mixin PrivacySettings on SettingsAccess, SearchSettings {
|
|||
|
||||
void activateHiddenFilter(CollectionFilter filter, bool active) {
|
||||
final _deactivatedHiddenFilters = deactivatedHiddenFilters;
|
||||
final _hiddenFilters = hiddenFilters;
|
||||
|
||||
if (active) {
|
||||
_deactivatedHiddenFilters.remove(filter);
|
||||
_hiddenFilters.add(filter);
|
||||
searchHistory = searchHistory..remove(filter);
|
||||
} else {
|
||||
_deactivatedHiddenFilters.add(filter);
|
||||
_hiddenFilters.remove(filter);
|
||||
}
|
||||
deactivatedHiddenFilters = _deactivatedHiddenFilters;
|
||||
|
||||
final visible = !active;
|
||||
changeFilterVisibility({filter}, visible);
|
||||
deactivatedHiddenFilters = _deactivatedHiddenFilters;
|
||||
hiddenFilters = _hiddenFilters;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,6 +161,7 @@ class CollectionLens with ChangeNotifier {
|
|||
case EntrySortFactor.rating:
|
||||
return !filters.any((f) => f is RatingFilter);
|
||||
case EntrySortFactor.size:
|
||||
case EntrySortFactor.duration:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -261,6 +262,8 @@ class CollectionLens with ChangeNotifier {
|
|||
_filteredSortedEntries.sort(AvesEntrySort.compareByRating);
|
||||
case EntrySortFactor.size:
|
||||
_filteredSortedEntries.sort(AvesEntrySort.compareBySize);
|
||||
case EntrySortFactor.duration:
|
||||
_filteredSortedEntries.sort(AvesEntrySort.compareByDuration);
|
||||
}
|
||||
if (sortReverse) {
|
||||
_filteredSortedEntries = _filteredSortedEntries.reversed.toList();
|
||||
|
@ -294,6 +297,7 @@ class CollectionLens with ChangeNotifier {
|
|||
case EntrySortFactor.rating:
|
||||
sections = groupBy<AvesEntry, EntryRatingSectionKey>(_filteredSortedEntries, (entry) => EntryRatingSectionKey(entry.rating));
|
||||
case EntrySortFactor.size:
|
||||
case EntrySortFactor.duration:
|
||||
sections = Map.fromEntries([
|
||||
MapEntry(const SectionKey(), _filteredSortedEntries),
|
||||
]);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/apps.dart';
|
||||
import 'package:aves/model/app_inventory.dart';
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/entry/extensions/props.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
|
|
|
@ -118,11 +118,6 @@ class PlatformMediaEditService implements MediaEditService {
|
|||
required String destinationAlbum,
|
||||
required NameConflictStrategy nameConflictStrategy,
|
||||
}) {
|
||||
// TODO TLAD remove log when OOMs are inspected
|
||||
entries.where((v) => (v.sizeBytes ?? 0) > 20000000).forEach((entry) {
|
||||
reportService.log('convert large entry=$entry size=${entry.sizeBytes}');
|
||||
});
|
||||
|
||||
try {
|
||||
return _opStream
|
||||
.receiveBroadcastStream(<String, dynamic>{
|
||||
|
|
|
@ -80,11 +80,6 @@ class PlatformMetadataEditService implements MetadataEditService {
|
|||
Map<MetadataType, dynamic> metadata, {
|
||||
bool autoCorrectTrailerOffset = true,
|
||||
}) async {
|
||||
// TODO TLAD remove log when OOMs are inspected
|
||||
if ((entry.sizeBytes ?? 0) > 20000000) {
|
||||
await reportService.log('edit metadata of large entry=$entry size=${entry.sizeBytes}');
|
||||
}
|
||||
|
||||
try {
|
||||
final result = await _platform.invokeMethod('editMetadata', <String, dynamic>{
|
||||
'entry': entry.toPlatformEntryMap(),
|
||||
|
|
|
@ -2,12 +2,11 @@ import 'package:aves/convert/convert.dart';
|
|||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/entry/extensions/multipage.dart';
|
||||
import 'package:aves/model/entry/extensions/props.dart';
|
||||
import 'package:aves/model/geotiff.dart';
|
||||
import 'package:aves/model/media/geotiff.dart';
|
||||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/metadata/overlay.dart';
|
||||
import 'package:aves/model/multipage.dart';
|
||||
import 'package:aves/model/panorama.dart';
|
||||
import 'package:aves/ref/mime_types.dart';
|
||||
import 'package:aves/model/media/panorama.dart';
|
||||
import 'package:aves/services/common/service_policy.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/services/metadata/xmp.dart';
|
||||
|
@ -69,11 +68,6 @@ class PlatformMetadataFetchService implements MetadataFetchService {
|
|||
Future<CatalogMetadata?> getCatalogMetadata(AvesEntry entry, {bool background = false}) async {
|
||||
if (entry.isSvg) return null;
|
||||
|
||||
// TODO TLAD remove log when MP4/TIFF-related OOMs are fixed
|
||||
if ({MimeTypes.mp4, MimeTypes.tiff}.contains(entry.mimeType) && (entry.sizeBytes ?? 0) > 20000000) {
|
||||
await reportService.log('catalog large entry=$entry size=${entry.sizeBytes}');
|
||||
}
|
||||
|
||||
Future<CatalogMetadata?> call() async {
|
||||
try {
|
||||
// returns map with:
|
||||
|
|
|
@ -29,11 +29,10 @@ class ADurations {
|
|||
// collection animations
|
||||
static const filterBarRemovalAnimation = Duration(milliseconds: 400);
|
||||
static const collectionOpOverlayAnimation = Duration(milliseconds: 300);
|
||||
static const sectionHeaderAnimation = Duration(milliseconds: 200);
|
||||
static const thumbnailOverlayAnimation = Duration(milliseconds: 200);
|
||||
|
||||
// search animations
|
||||
static const filterRowExpandAnimation = Duration(milliseconds: 300);
|
||||
static const searchBodyTransition = Duration(milliseconds: 300);
|
||||
|
||||
// viewer animations
|
||||
static const thumbnailScrollerScrollAnimation = Duration(milliseconds: 200);
|
||||
|
|
|
@ -28,6 +28,7 @@ class AIcons {
|
|||
static const descriptionUntitled = Icons.comments_disabled_outlined;
|
||||
static const disc = Icons.fiber_manual_record;
|
||||
static const display = Icons.light_mode_outlined;
|
||||
static const duration = Icons.timelapse_outlined;
|
||||
static const error = Icons.error_outline;
|
||||
static const explorer = Icons.account_tree_outlined;
|
||||
static const folder = Icons.folder_outlined;
|
||||
|
@ -162,6 +163,8 @@ class AIcons {
|
|||
static const zoomOut = Icons.remove_outlined;
|
||||
static const collapse = Icons.expand_less_outlined;
|
||||
static const expand = Icons.expand_more_outlined;
|
||||
static const up = Icons.keyboard_arrow_up_outlined;
|
||||
static const down = Icons.keyboard_arrow_down_outlined;
|
||||
static const previous = Icons.chevron_left_outlined;
|
||||
static const next = Icons.chevron_right_outlined;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/apps.dart';
|
||||
import 'package:aves/model/app_inventory.dart';
|
||||
import 'package:aves/model/vaults/vaults.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
|
@ -7,6 +7,8 @@ import 'package:flutter/foundation.dart';
|
|||
|
||||
final AndroidFileUtils androidFileUtils = AndroidFileUtils._private();
|
||||
|
||||
enum _State { uninitialized, initializing, initialized }
|
||||
|
||||
class AndroidFileUtils {
|
||||
// cf https://developer.android.com/reference/android/content/ContentResolver#SCHEME_CONTENT
|
||||
static const contentScheme = 'content';
|
||||
|
@ -27,13 +29,19 @@ class AndroidFileUtils {
|
|||
late final String dcimPath, downloadPath, moviesPath, picturesPath, avesVideoCapturesPath;
|
||||
late final Set<String> videoCapturesPaths;
|
||||
Set<StorageVolume> storageVolumes = {};
|
||||
bool _initialized = false;
|
||||
_State _initialized = _State.uninitialized;
|
||||
|
||||
AndroidFileUtils._private();
|
||||
|
||||
Future<void> init() async {
|
||||
if (_initialized) return;
|
||||
if (_initialized == _State.uninitialized) {
|
||||
_initialized = _State.initializing;
|
||||
await _doInit();
|
||||
_initialized = _State.initialized;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _doInit() async {
|
||||
separator = pContext.separator;
|
||||
await _initStorageVolumes();
|
||||
vaultRoot = await storageService.getVaultRoot();
|
||||
|
@ -50,8 +58,6 @@ class AndroidFileUtils {
|
|||
// from Aves
|
||||
avesVideoCapturesPath,
|
||||
};
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
Future<void> _initStorageVolumes() async {
|
||||
|
|
|
@ -9,6 +9,7 @@ extension ExtraExplorerActionView on ExplorerAction {
|
|||
return switch (this) {
|
||||
ExplorerAction.addShortcut => l10n.collectionActionAddShortcut,
|
||||
ExplorerAction.setHome => l10n.collectionActionSetHome,
|
||||
ExplorerAction.stats => l10n.menuActionStats,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -18,6 +19,7 @@ extension ExtraExplorerActionView on ExplorerAction {
|
|||
return switch (this) {
|
||||
ExplorerAction.addShortcut => AIcons.addShortcut,
|
||||
ExplorerAction.setHome => AIcons.home,
|
||||
ExplorerAction.stats => AIcons.stats,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ extension ExtraMapActionView on MapAction {
|
|||
final l10n = context.l10n;
|
||||
return switch (this) {
|
||||
MapAction.selectStyle => l10n.mapStyleTooltip,
|
||||
MapAction.openMapApp => l10n.entryActionOpenMap,
|
||||
MapAction.zoomIn => l10n.mapZoomInTooltip,
|
||||
MapAction.zoomOut => l10n.mapZoomOutTooltip,
|
||||
};
|
||||
|
@ -18,6 +19,7 @@ extension ExtraMapActionView on MapAction {
|
|||
IconData _getIconData() {
|
||||
return switch (this) {
|
||||
MapAction.selectStyle => AIcons.layers,
|
||||
MapAction.openMapApp => AIcons.openOutside,
|
||||
MapAction.zoomIn => AIcons.zoomIn,
|
||||
MapAction.zoomOut => AIcons.zoomOut,
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
|
|||
EntrySortFactor.name => l10n.sortByAlbumFileName,
|
||||
EntrySortFactor.rating => l10n.sortByRating,
|
||||
EntrySortFactor.size => l10n.sortBySize,
|
||||
EntrySortFactor.duration => l10n.sortByDuration,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -20,6 +21,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
|
|||
EntrySortFactor.name => AIcons.name,
|
||||
EntrySortFactor.rating => AIcons.rating,
|
||||
EntrySortFactor.size => AIcons.size,
|
||||
EntrySortFactor.duration => AIcons.duration,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -30,6 +32,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
|
|||
EntrySortFactor.name => reverse ? l10n.sortOrderZtoA : l10n.sortOrderAtoZ,
|
||||
EntrySortFactor.rating => reverse ? l10n.sortOrderLowestFirst : l10n.sortOrderHighestFirst,
|
||||
EntrySortFactor.size => reverse ? l10n.sortOrderSmallestFirst : l10n.sortOrderLargestFirst,
|
||||
EntrySortFactor.duration => reverse ? l10n.sortOrderShortestFirst : l10n.sortOrderLongestFirst,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ export 'src/actions/chip.dart';
|
|||
export 'src/actions/chip_set.dart';
|
||||
export 'src/actions/entry.dart';
|
||||
export 'src/actions/entry_set.dart';
|
||||
export 'src/actions/explorer.dart';
|
||||
export 'src/actions/map.dart';
|
||||
export 'src/actions/map_cluster.dart';
|
||||
export 'src/actions/share.dart';
|
||||
|
|
|
@ -18,11 +18,13 @@ import 'package:flutter/services.dart';
|
|||
const _widgetDrawChannel = MethodChannel('deckers.thibault/aves/widget_draw');
|
||||
|
||||
void widgetMainCommon(AppFlavor flavor) async {
|
||||
debugPrint('Widget main start');
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
initPlatformServices();
|
||||
await settings.init(monitorPlatformSettings: false);
|
||||
await reportService.init();
|
||||
|
||||
debugPrint('Widget channel method handling setup');
|
||||
_widgetDrawChannel.setMethodCallHandler((call) async {
|
||||
// widget settings may be modified in a different process after channel setup
|
||||
await settings.reload();
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'dart:math';
|
|||
import 'package:aves/app_flavor.dart';
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/l10n/l10n.dart';
|
||||
import 'package:aves/model/apps.dart';
|
||||
import 'package:aves/model/app_inventory.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/filters/recent.dart';
|
||||
import 'package:aves/model/settings/defaults.dart';
|
||||
|
@ -345,12 +345,14 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
child: ValueListenableBuilder<PageTransitionsBuilder>(
|
||||
valueListenable: _pageTransitionsBuilderNotifier,
|
||||
builder: (context, pageTransitionsBuilder, child) {
|
||||
final theme = Theme.of(context);
|
||||
return Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
data: theme.copyWith(
|
||||
pageTransitionsTheme: areAnimationsEnabled
|
||||
? PageTransitionsTheme(builders: {TargetPlatform.android: pageTransitionsBuilder})
|
||||
// strip page transitions used by `MaterialPageRoute`
|
||||
: const DirectPageTransitionsTheme(),
|
||||
splashFactory: areAnimationsEnabled ? theme.splashFactory : NoSplash.splashFactory,
|
||||
),
|
||||
child: MediaQueryDataProvider(child: child!),
|
||||
);
|
||||
|
@ -411,6 +413,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
void didHaveMemoryPressure() {
|
||||
super.didHaveMemoryPressure();
|
||||
reportService.log('App memory pressure');
|
||||
imageCache.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -631,7 +634,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
final shouldReset = _exitedMainByPop;
|
||||
_exitedMainByPop = false;
|
||||
|
||||
if (!shouldReset && (intentData ?? {}).isEmpty) {
|
||||
if (!shouldReset && (intentData ?? {}).values.whereNotNull().isEmpty) {
|
||||
reportService.log('Relaunch');
|
||||
return;
|
||||
}
|
||||
|
@ -665,6 +668,9 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
}
|
||||
}
|
||||
|
||||
// Flutter has various overscroll indicator implementations for Android:
|
||||
// - `StretchingOverscrollIndicator`, default when using Material 3
|
||||
// - `GlowingOverscrollIndicator`, default when not using Material 3
|
||||
class AvesScrollBehavior extends MaterialScrollBehavior {
|
||||
@override
|
||||
Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
|
||||
|
@ -674,11 +680,7 @@ class AvesScrollBehavior extends MaterialScrollBehavior {
|
|||
axisDirection: details.direction,
|
||||
child: child,
|
||||
)
|
||||
: GlowingOverscrollIndicator(
|
||||
axisDirection: details.direction,
|
||||
color: Colors.white,
|
||||
child: child,
|
||||
);
|
||||
: child;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
EntrySortFactor.size,
|
||||
EntrySortFactor.name,
|
||||
EntrySortFactor.rating,
|
||||
EntrySortFactor.duration,
|
||||
];
|
||||
|
||||
static const _groupOptions = [
|
||||
|
@ -94,6 +95,11 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
TileLayout.list,
|
||||
];
|
||||
|
||||
static const _trashSelectionQuickActions = [
|
||||
EntrySetAction.delete,
|
||||
EntrySetAction.restore,
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -388,7 +394,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
final hasSelection = selectedItemCount > 0;
|
||||
|
||||
final browsingQuickActions = settings.collectionBrowsingQuickActions;
|
||||
final selectionQuickActions = isTrash ? [EntrySetAction.delete, EntrySetAction.restore] : settings.collectionSelectionQuickActions;
|
||||
final selectionQuickActions = isTrash ? _trashSelectionQuickActions : settings.collectionSelectionQuickActions;
|
||||
final quickActions = (isSelecting ? selectionQuickActions : browsingQuickActions).take(max(0, availableCount - 1)).toList();
|
||||
final quickActionButtons = quickActions.where(isVisible).map(
|
||||
(action) => _buildButtonIcon(context, action, enabled: canApply(action), selection: selection),
|
||||
|
@ -430,7 +436,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
title: context.l10n.collectionActionEdit,
|
||||
items: [
|
||||
_buildRotateAndFlipMenuItems(context, canApply: canApply),
|
||||
...EntrySetActions.edit.where((v) => isVisible(v) && !selectionQuickActions.contains(v)).map((action) => _toMenuItem(action, enabled: canApply(action), selection: selection)),
|
||||
...EntrySetActions.edit.where((v) => isVisible(v) && !quickActions.contains(v)).map((action) => _toMenuItem(action, enabled: canApply(action), selection: selection)),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
|
|
@ -697,6 +697,7 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> with Widge
|
|||
addAlbums(collection, sectionLayouts, crumbs);
|
||||
case EntrySortFactor.rating:
|
||||
case EntrySortFactor.size:
|
||||
case EntrySortFactor.duration:
|
||||
break;
|
||||
}
|
||||
return crumbs;
|
||||
|
|
|
@ -57,6 +57,10 @@ class CollectionDraggableThumbLabel extends StatelessWidget {
|
|||
return [
|
||||
if (entry.sizeBytes != null) formatFileSize(context.locale, entry.sizeBytes!, round: 0),
|
||||
];
|
||||
case EntrySortFactor.duration:
|
||||
return [
|
||||
if (entry.durationMillis != null) entry.durationText,
|
||||
];
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_app_bar.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class FilterBar extends StatefulWidget {
|
||||
static const EdgeInsets chipPadding = EdgeInsets.symmetric(horizontal: 4);
|
||||
|
@ -12,7 +14,7 @@ class FilterBar extends StatefulWidget {
|
|||
|
||||
final List<CollectionFilter> filters;
|
||||
final bool interactive;
|
||||
final FilterCallback? onTap, onRemove;
|
||||
final AFilterCallback? onTap, onRemove;
|
||||
|
||||
FilterBar({
|
||||
super.key,
|
||||
|
@ -45,7 +47,7 @@ class _FilterBarState extends State<FilterBar> {
|
|||
existing.removeAt(index);
|
||||
// only animate item removal when triggered by a user interaction with the chip,
|
||||
// not from automatic chip replacement following chip selection
|
||||
final animate = _userTappedFilter == filter;
|
||||
final animate = context.read<Settings>().animate && _userTappedFilter == filter;
|
||||
listState!.removeItem(
|
||||
index,
|
||||
animate
|
||||
|
@ -123,7 +125,7 @@ class _FilterBarState extends State<FilterBar> {
|
|||
class _Chip extends StatelessWidget {
|
||||
final CollectionFilter filter;
|
||||
final bool single, interactive;
|
||||
final FilterCallback? onTap, onRemove;
|
||||
final AFilterCallback? onTap, onRemove;
|
||||
|
||||
const _Chip({
|
||||
required this.filter,
|
||||
|
@ -142,7 +144,7 @@ class _Chip extends StatelessWidget {
|
|||
key: ValueKey(filter),
|
||||
filter: filter,
|
||||
maxWidth: single
|
||||
? AvesFilterChip.computeMaxWidth(
|
||||
? AvesFilterChip.computeMaxWidthForRow(
|
||||
context,
|
||||
minChipPerRow: 1,
|
||||
chipPadding: FilterBar.chipPadding.horizontal,
|
||||
|
|
|
@ -66,6 +66,7 @@ class CollectionSectionHeader extends StatelessWidget {
|
|||
selectable: selectable,
|
||||
);
|
||||
case EntrySortFactor.size:
|
||||
case EntrySortFactor.duration:
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/filters/album.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/filter_quick_chooser_mixin.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class AlbumQuickChooser extends StatelessWidget {
|
||||
class AlbumQuickChooser extends StatelessWidget with FilterQuickChooserMixin<String> {
|
||||
final ValueNotifier<String?> valueNotifier;
|
||||
@override
|
||||
final List<String> options;
|
||||
final bool blurred;
|
||||
final PopupMenuPosition chooserPosition;
|
||||
|
@ -25,7 +28,6 @@ class AlbumQuickChooser extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final source = context.read<CollectionSource>();
|
||||
return MenuQuickChooser<String>(
|
||||
valueNotifier: valueNotifier,
|
||||
options: options,
|
||||
|
@ -33,10 +35,17 @@ class AlbumQuickChooser extends StatelessWidget {
|
|||
blurred: blurred,
|
||||
chooserPosition: chooserPosition,
|
||||
pointerGlobalPosition: pointerGlobalPosition,
|
||||
itemBuilder: (context, album) => AvesFilterChip(
|
||||
filter: AlbumFilter(album, source.getAlbumDisplayName(context, album)),
|
||||
allowGenericIcon: false,
|
||||
),
|
||||
maxTotalOptionCount: FilterQuickChooserMixin.maxTotalOptionCount,
|
||||
itemHeight: computeItemHeight(context),
|
||||
contentWidth: computeLargestItemWidth,
|
||||
itemBuilder: itemBuilder,
|
||||
emptyBuilder: (context) => Text(context.l10n.albumEmpty),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
CollectionFilter buildFilter(BuildContext context, String option) {
|
||||
final source = context.read<CollectionSource>();
|
||||
return AlbumFilter(option, source.getAlbumDisplayName(context, option));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/quick_chooser.dart';
|
||||
import 'package:aves_ui/aves_ui.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||
|
@ -16,9 +17,13 @@ class MenuQuickChooser<T> extends StatefulWidget {
|
|||
final bool blurred;
|
||||
final PopupMenuPosition chooserPosition;
|
||||
final Stream<Offset> pointerGlobalPosition;
|
||||
final int maxTotalOptionCount;
|
||||
final double itemHeight;
|
||||
final double? Function(BuildContext context)? contentWidth;
|
||||
final Widget Function(BuildContext context, T menuItem) itemBuilder;
|
||||
final WidgetBuilder? emptyBuilder;
|
||||
|
||||
static const int maxOptionCount = 5;
|
||||
static const int maxVisibleOptionCount = 5;
|
||||
|
||||
MenuQuickChooser({
|
||||
super.key,
|
||||
|
@ -28,8 +33,12 @@ class MenuQuickChooser<T> extends StatefulWidget {
|
|||
required this.blurred,
|
||||
required this.chooserPosition,
|
||||
required this.pointerGlobalPosition,
|
||||
this.maxTotalOptionCount = maxVisibleOptionCount,
|
||||
this.itemHeight = kMinInteractiveDimension,
|
||||
this.contentWidth,
|
||||
required this.itemBuilder,
|
||||
}) : options = options.take(maxOptionCount).toList();
|
||||
this.emptyBuilder,
|
||||
}) : options = options.take(maxTotalOptionCount).toList();
|
||||
|
||||
@override
|
||||
State<MenuQuickChooser<T>> createState() => _MenuQuickChooserState<T>();
|
||||
|
@ -38,6 +47,10 @@ class MenuQuickChooser<T> extends StatefulWidget {
|
|||
class _MenuQuickChooserState<T> extends State<MenuQuickChooser<T>> {
|
||||
final List<StreamSubscription> _subscriptions = [];
|
||||
final ValueNotifier<Rect> _selectedRowRect = ValueNotifier(Rect.zero);
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
int _scrollDirection = 0;
|
||||
Timer? _scrollUpdateTimer;
|
||||
Offset _globalPosition = Offset.zero;
|
||||
|
||||
ValueNotifier<T?> get valueNotifier => widget.valueNotifier;
|
||||
|
||||
|
@ -45,12 +58,26 @@ class _MenuQuickChooserState<T> extends State<MenuQuickChooser<T>> {
|
|||
|
||||
bool get reversed => widget.autoReverse && widget.chooserPosition == PopupMenuPosition.over;
|
||||
|
||||
static const double intraPadding = 8;
|
||||
bool get scrollable => options.length > MenuQuickChooser.maxVisibleOptionCount;
|
||||
|
||||
int get visibleOptionCount => min(MenuQuickChooser.maxVisibleOptionCount, options.length);
|
||||
|
||||
double get itemHeight => widget.itemHeight;
|
||||
|
||||
double get contentHeight => max(0, itemHeight * visibleOptionCount + _intraPadding * (visibleOptionCount - 1));
|
||||
|
||||
static const double _selectorMargin = 24;
|
||||
static const double _intraPadding = 8;
|
||||
static const double _nonScrollablePaddingHeight = _intraPadding;
|
||||
static const double _scrollerAreaHeight = kMinInteractiveDimension;
|
||||
static const double scrollMaxPixelPerSecond = 600.0;
|
||||
static const Duration scrollUpdateInterval = Duration(milliseconds: 100);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_registerWidget(widget);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -69,6 +96,9 @@ class _MenuQuickChooserState<T> extends State<MenuQuickChooser<T>> {
|
|||
@override
|
||||
void dispose() {
|
||||
_unregisterWidget(widget);
|
||||
_selectedRowRect.dispose();
|
||||
_scrollController.dispose();
|
||||
_scrollUpdateTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -91,28 +121,11 @@ class _MenuQuickChooserState<T> extends State<MenuQuickChooser<T>> {
|
|||
builder: (context, selectedValue, child) {
|
||||
final durations = context.watch<DurationsData>();
|
||||
|
||||
List<Widget> optionChildren = options.mapIndexed((index, value) {
|
||||
final isFirst = index == (reversed ? options.length - 1 : 0);
|
||||
if (options.isEmpty) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: isFirst ? intraPadding : 0, bottom: intraPadding),
|
||||
child: widget.itemBuilder(context, value),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: widget.emptyBuilder?.call(context) ?? const SizedBox(),
|
||||
);
|
||||
}).toList();
|
||||
|
||||
optionChildren = AnimationConfiguration.toStaggeredList(
|
||||
duration: durations.staggeredAnimation * .5,
|
||||
delay: durations.staggeredAnimationDelay * .5 * timeDilation,
|
||||
childAnimationBuilder: (child) => SlideAnimation(
|
||||
verticalOffset: 50.0 * (widget.chooserPosition == PopupMenuPosition.over ? 1 : -1),
|
||||
child: FadeInAnimation(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
children: optionChildren,
|
||||
);
|
||||
|
||||
if (reversed) {
|
||||
optionChildren = optionChildren.reversed.toList();
|
||||
}
|
||||
|
||||
return Stack(
|
||||
|
@ -137,12 +150,67 @@ class _MenuQuickChooserState<T> extends State<MenuQuickChooser<T>> {
|
|||
return child;
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 24),
|
||||
Container(
|
||||
width: widget.contentWidth?.call(context),
|
||||
margin: const EdgeInsetsDirectional.only(start: _selectorMargin),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: optionChildren,
|
||||
children: [
|
||||
scrollable
|
||||
? ListenableBuilder(
|
||||
listenable: _scrollController,
|
||||
builder: (context, child) => Opacity(
|
||||
opacity: canGoUp ? 1 : .5,
|
||||
child: child,
|
||||
),
|
||||
child: _buildScrollerArea(AIcons.up),
|
||||
)
|
||||
: const SizedBox(height: _nonScrollablePaddingHeight),
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints.tightFor(height: contentHeight),
|
||||
child: ListView.separated(
|
||||
reverse: reversed,
|
||||
controller: _scrollController,
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.zero,
|
||||
itemBuilder: (context, index) {
|
||||
final child = Container(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
constraints: BoxConstraints.tightFor(height: itemHeight),
|
||||
child: widget.itemBuilder(context, options[index]),
|
||||
);
|
||||
if (index < MenuQuickChooser.maxVisibleOptionCount) {
|
||||
// only animate items visible on first render
|
||||
return AnimationConfiguration.staggeredList(
|
||||
position: index,
|
||||
duration: durations.staggeredAnimation * .5,
|
||||
delay: durations.staggeredAnimationDelay * .5 * timeDilation,
|
||||
child: SlideAnimation(
|
||||
verticalOffset: 50.0 * (widget.chooserPosition == PopupMenuPosition.over ? 1 : -1),
|
||||
child: FadeInAnimation(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return child;
|
||||
}
|
||||
},
|
||||
separatorBuilder: (context, index) => const SizedBox(height: _intraPadding),
|
||||
itemCount: options.length,
|
||||
),
|
||||
),
|
||||
scrollable
|
||||
? ListenableBuilder(
|
||||
listenable: _scrollController,
|
||||
builder: (context, child) => Opacity(
|
||||
opacity: canGoDown ? 1 : .5,
|
||||
child: child,
|
||||
),
|
||||
child: _buildScrollerArea(AIcons.down),
|
||||
)
|
||||
: const SizedBox(height: _nonScrollablePaddingHeight),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -152,30 +220,97 @@ class _MenuQuickChooserState<T> extends State<MenuQuickChooser<T>> {
|
|||
);
|
||||
}
|
||||
|
||||
void _onPointerMove(Offset globalPosition) {
|
||||
final padding = QuickChooser.margin.vertical + QuickChooser.padding.vertical;
|
||||
bool get canGoUp {
|
||||
if (!_scrollController.hasClients) return false;
|
||||
final position = _scrollController.position;
|
||||
return reversed ? position.pixels < position.maxScrollExtent : 0 < position.pixels;
|
||||
}
|
||||
|
||||
bool get canGoDown {
|
||||
if (!_scrollController.hasClients) return false;
|
||||
final position = _scrollController.position;
|
||||
return reversed ? 0 < position.pixels : position.pixels < position.maxScrollExtent;
|
||||
}
|
||||
|
||||
Widget _buildScrollerArea(IconData icon) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
height: _scrollerAreaHeight,
|
||||
margin: const EdgeInsetsDirectional.only(end: _selectorMargin),
|
||||
child: Icon(icon),
|
||||
);
|
||||
}
|
||||
|
||||
void _onPointerMove(Offset globalPosition) {
|
||||
_globalPosition = globalPosition;
|
||||
final chooserBox = context.findRenderObject() as RenderBox?;
|
||||
if (chooserBox == null) return;
|
||||
|
||||
final chooserBox = context.findRenderObject() as RenderBox;
|
||||
final chooserSize = chooserBox.size;
|
||||
final contentWidth = chooserSize.width;
|
||||
final contentHeight = chooserSize.height - padding;
|
||||
final chooserBoxEdgeHeight = (QuickChooser.margin.vertical + QuickChooser.padding.vertical) / 2;
|
||||
|
||||
final optionCount = options.length;
|
||||
final itemHeight = (contentHeight - (optionCount + 1) * intraPadding) / optionCount;
|
||||
final localPosition = chooserBox.globalToLocal(globalPosition);
|
||||
final dx = localPosition.dx;
|
||||
if (!(0 < dx && dx < contentWidth)) {
|
||||
valueNotifier.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
final local = chooserBox.globalToLocal(globalPosition);
|
||||
final dx = local.dx;
|
||||
final dy = local.dy - padding / 2;
|
||||
double dy = localPosition.dy - chooserBoxEdgeHeight;
|
||||
int scrollDirection = 0;
|
||||
if (scrollable) {
|
||||
dy -= _scrollerAreaHeight;
|
||||
if (-_scrollerAreaHeight < dy && dy < 0) {
|
||||
scrollDirection = reversed ? 1 : -1;
|
||||
} else if (contentHeight < dy && dy < contentHeight + _scrollerAreaHeight) {
|
||||
scrollDirection = reversed ? -1 : 1;
|
||||
}
|
||||
_scroll(scrollDirection);
|
||||
} else {
|
||||
dy -= _nonScrollablePaddingHeight;
|
||||
}
|
||||
|
||||
T? selectedValue;
|
||||
if (0 < dx && dx < contentWidth && 0 < dy && dy < contentHeight) {
|
||||
final index = (optionCount * dy / contentHeight).floor();
|
||||
if (0 <= index && index < optionCount) {
|
||||
selectedValue = options[reversed ? optionCount - 1 - index : index];
|
||||
final top = index * (itemHeight + intraPadding) + intraPadding;
|
||||
if (scrollDirection == 0 && 0 < dy && dy < contentHeight) {
|
||||
final visibleOffset = reversed ? contentHeight - dy : dy;
|
||||
final fullItemHeight = itemHeight + _intraPadding;
|
||||
final scrollOffset = _scrollController.offset;
|
||||
final index = (visibleOffset + _intraPadding + scrollOffset) ~/ (fullItemHeight);
|
||||
if (0 <= index && index < options.length) {
|
||||
selectedValue = options[index];
|
||||
double fromEdge = fullItemHeight * index;
|
||||
fromEdge += (scrollable ? _scrollerAreaHeight - scrollOffset : _nonScrollablePaddingHeight);
|
||||
final top = reversed ? chooserSize.height - chooserBoxEdgeHeight - fromEdge - fullItemHeight : fromEdge;
|
||||
_selectedRowRect.value = Rect.fromLTWH(0, top, contentWidth, itemHeight);
|
||||
}
|
||||
}
|
||||
valueNotifier.value = selectedValue;
|
||||
}
|
||||
|
||||
void _scroll(int scrollDirection) {
|
||||
if (scrollDirection == _scrollDirection) return;
|
||||
_scrollDirection = scrollDirection;
|
||||
_scrollUpdateTimer?.cancel();
|
||||
|
||||
final current = _scrollController.offset;
|
||||
if (scrollDirection == 0) {
|
||||
_scrollController.jumpTo(current);
|
||||
return;
|
||||
}
|
||||
|
||||
final target = scrollDirection > 0 ? _scrollController.position.maxScrollExtent : .0;
|
||||
if (target != current) {
|
||||
final distance = target - current;
|
||||
final millis = distance * 1000 / scrollMaxPixelPerSecond / scrollDirection;
|
||||
_scrollController.animateTo(
|
||||
target,
|
||||
duration: Duration(milliseconds: millis.round()),
|
||||
curve: Curves.linear,
|
||||
);
|
||||
// use a timer to update the selection, because `_onPointerMove`
|
||||
// is not called when the pointer stays still while the view is scrolling
|
||||
_scrollUpdateTimer = Timer.periodic(scrollUpdateInterval, (_) => _onPointerMove(_globalPosition));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/modules/app.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
mixin FilterQuickChooserMixin<T> {
|
||||
List<T> get options;
|
||||
|
||||
static const int maxTotalOptionCount = AppSettings.recentFilterHistoryMax;
|
||||
static const double _chipPadding = AvesFilterChip.defaultPadding;
|
||||
static const bool _chipAllowGenericIcon = false;
|
||||
|
||||
CollectionFilter buildFilter(BuildContext context, T option);
|
||||
|
||||
Widget itemBuilder(BuildContext context, T option) {
|
||||
return AvesFilterChip(
|
||||
filter: buildFilter(context, option),
|
||||
allowGenericIcon: _chipAllowGenericIcon,
|
||||
padding: _chipPadding,
|
||||
maxWidth: double.infinity,
|
||||
);
|
||||
}
|
||||
|
||||
double computeItemHeight(BuildContext context) => AvesFilterChip.minChipHeight;
|
||||
|
||||
double? computeLargestItemWidth(BuildContext context) {
|
||||
if (options.isEmpty) return null;
|
||||
|
||||
final textStyle = DefaultTextStyle.of(context).style.copyWith(
|
||||
fontSize: AvesFilterChip.fontSize,
|
||||
);
|
||||
final textDirection = Directionality.of(context);
|
||||
final textScaler = MediaQuery.textScalerOf(context);
|
||||
final iconSize = textScaler.scale(AvesFilterChip.iconSize);
|
||||
|
||||
return options.map((option) {
|
||||
final filter = buildFilter(context, option);
|
||||
final icon = filter.iconBuilder(context, iconSize, allowGenericIcon: _chipAllowGenericIcon);
|
||||
final label = filter.getLabel(context);
|
||||
final paragraph = RenderParagraph(
|
||||
TextSpan(text: label, style: textStyle),
|
||||
textDirection: textDirection,
|
||||
textScaler: textScaler,
|
||||
)..layout(const BoxConstraints(), parentUsesSize: true);
|
||||
final labelWidth = paragraph.getMaxIntrinsicWidth(double.infinity);
|
||||
double chipWidth = labelWidth + _chipPadding * 4;
|
||||
if (icon != null) {
|
||||
chipWidth += iconSize + _chipPadding;
|
||||
}
|
||||
return max(AvesFilterChip.minChipWidth, chipWidth);
|
||||
}).reduce(max);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ import 'package:aves/model/source/collection_source.dart';
|
|||
import 'package:aves/view/view.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/album_chooser.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/filter_quick_chooser_mixin.dart';
|
||||
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||
import 'package:aves/widgets/filter_grids/common/filter_nav_page.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
|
@ -42,7 +42,7 @@ class _MoveButtonState extends ChooserQuickButtonState<MoveButton, String> {
|
|||
final source = context.read<CollectionSource>();
|
||||
final rawAlbums = source.rawAlbums;
|
||||
final options = settings.recentDestinationAlbums.where(rawAlbums.contains).toList();
|
||||
final takeCount = MenuQuickChooser.maxOptionCount - options.length;
|
||||
final takeCount = FilterQuickChooserMixin.maxTotalOptionCount - options.length;
|
||||
if (takeCount > 0) {
|
||||
final filters = rawAlbums.whereNot(options.contains).map((album) => AlbumFilter(album, null)).toSet();
|
||||
final allMapEntries = filters.map((filter) => FilterGridItem(filter, source.recentEntry(filter))).toList();
|
||||
|
|
|
@ -51,7 +51,6 @@ class _ShareButtonState extends ChooserQuickButtonState<ShareButton, ShareAction
|
|||
child: ShareQuickChooser(
|
||||
valueNotifier: chooserValueNotifier,
|
||||
options: options,
|
||||
autoReverse: false,
|
||||
blurred: widget.blurred,
|
||||
chooserPosition: chooserPosition,
|
||||
pointerGlobalPosition: pointerGlobalPosition,
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:aves/view/view.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
||||
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
class ShareQuickChooser extends StatelessWidget {
|
||||
final ValueNotifier<ShareAction?> valueNotifier;
|
||||
final List<ShareAction> options;
|
||||
final bool autoReverse;
|
||||
final bool blurred;
|
||||
final PopupMenuPosition chooserPosition;
|
||||
final Stream<Offset> pointerGlobalPosition;
|
||||
|
||||
static const _itemPadding = EdgeInsetsDirectional.only(end: 8);
|
||||
|
||||
const ShareQuickChooser({
|
||||
super.key,
|
||||
required this.valueNotifier,
|
||||
required this.options,
|
||||
required this.autoReverse,
|
||||
required this.blurred,
|
||||
required this.chooserPosition,
|
||||
required this.pointerGlobalPosition,
|
||||
|
@ -29,20 +31,39 @@ class ShareQuickChooser extends StatelessWidget {
|
|||
return MenuQuickChooser<ShareAction>(
|
||||
valueNotifier: valueNotifier,
|
||||
options: options,
|
||||
autoReverse: autoReverse,
|
||||
autoReverse: false,
|
||||
blurred: blurred,
|
||||
chooserPosition: chooserPosition,
|
||||
pointerGlobalPosition: pointerGlobalPosition,
|
||||
itemBuilder: (context, action) => ConstrainedBox(
|
||||
constraints: const BoxConstraints(minHeight: kMinInteractiveDimension),
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 8),
|
||||
itemHeight: kMinInteractiveDimension,
|
||||
contentWidth: _computeLargestItemWidth,
|
||||
itemBuilder: (context, action) => Padding(
|
||||
padding: _itemPadding,
|
||||
child: MenuRow(
|
||||
text: action.getText(context),
|
||||
icon: action.getIcon(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
double? _computeLargestItemWidth(BuildContext context) {
|
||||
if (options.isEmpty) return null;
|
||||
|
||||
final textStyle = DefaultTextStyle.of(context).style;
|
||||
final textDirection = Directionality.of(context);
|
||||
final textScaler = MediaQuery.textScalerOf(context);
|
||||
final iconSize = IconTheme.of(context).size ?? 24;
|
||||
|
||||
return options.map((action) {
|
||||
final text = action.getText(context);
|
||||
final paragraph = RenderParagraph(
|
||||
TextSpan(text: text, style: textStyle),
|
||||
textDirection: textDirection,
|
||||
textScaler: textScaler,
|
||||
)..layout(const BoxConstraints(), parentUsesSize: true);
|
||||
final labelWidth = paragraph.getMaxIntrinsicWidth(double.infinity);
|
||||
return iconSize + MenuRow.leadingPadding.horizontal + labelWidth + _itemPadding.horizontal;
|
||||
}).reduce(max);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:aves/model/settings/settings.dart';
|
|||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/view/view.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/filter_quick_chooser_mixin.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/tag_chooser.dart';
|
||||
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||
import 'package:aves/widgets/filter_grids/common/filter_nav_page.dart';
|
||||
|
@ -38,7 +38,7 @@ class _TagButtonState extends ChooserQuickButtonState<TagButton, CollectionFilte
|
|||
@override
|
||||
Widget buildChooser(Animation<double> animation, PopupMenuPosition chooserPosition) {
|
||||
final options = settings.recentTags;
|
||||
final takeCount = MenuQuickChooser.maxOptionCount - options.length;
|
||||
final takeCount = FilterQuickChooserMixin.maxTotalOptionCount - options.length;
|
||||
if (takeCount > 0) {
|
||||
final source = context.read<CollectionSource>();
|
||||
final filters = source.sortedTags.map(TagFilter.new).whereNot(options.contains).toSet();
|
||||
|
|
|
@ -2,11 +2,13 @@ import 'dart:async';
|
|||
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
||||
import 'package:aves/widgets/common/action_controls/quick_choosers/filter_quick_chooser_mixin.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TagQuickChooser extends StatelessWidget {
|
||||
class TagQuickChooser extends StatelessWidget with FilterQuickChooserMixin<CollectionFilter> {
|
||||
final ValueNotifier<CollectionFilter?> valueNotifier;
|
||||
@override
|
||||
final List<CollectionFilter> options;
|
||||
final bool blurred;
|
||||
final PopupMenuPosition chooserPosition;
|
||||
|
@ -30,10 +32,14 @@ class TagQuickChooser extends StatelessWidget {
|
|||
blurred: blurred,
|
||||
chooserPosition: chooserPosition,
|
||||
pointerGlobalPosition: pointerGlobalPosition,
|
||||
itemBuilder: (context, filter) => AvesFilterChip(
|
||||
filter: filter,
|
||||
allowGenericIcon: false,
|
||||
),
|
||||
maxTotalOptionCount: FilterQuickChooserMixin.maxTotalOptionCount,
|
||||
itemHeight: computeItemHeight(context),
|
||||
contentWidth: computeLargestItemWidth,
|
||||
itemBuilder: itemBuilder,
|
||||
emptyBuilder: (context) => Text(context.l10n.tagEmpty),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
CollectionFilter buildFilter(BuildContext context, CollectionFilter option) => option;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/entry/extensions/favourites.dart';
|
||||
import 'package:aves/model/favourites.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/colors.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
|
||||
|
@ -73,6 +74,7 @@ class _FavouriteTogglerState extends State<FavouriteToggler> {
|
|||
icon: const Icon(isNotFavouriteIcon),
|
||||
);
|
||||
}
|
||||
final animate = context.select<Settings, bool>((v) => v.animate);
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
|
@ -82,6 +84,7 @@ class _FavouriteTogglerState extends State<FavouriteToggler> {
|
|||
focusNode: widget.focusNode,
|
||||
tooltip: isFavourite ? context.l10n.entryActionRemoveFavourite : context.l10n.entryActionAddFavourite,
|
||||
),
|
||||
if (animate)
|
||||
Sweeper(
|
||||
key: ValueKey(entries.length == 1 ? entries.first : entries.length),
|
||||
builder: (context) => Icon(
|
||||
|
|
|
@ -95,9 +95,9 @@ class _PlayTogglerState extends State<PlayToggler> with SingleTickerProviderStat
|
|||
|
||||
void _onStatusChanged(VideoStatus status) {
|
||||
final status = _playPauseAnimation.status;
|
||||
if (isPlaying && status != AnimationStatus.forward && status != AnimationStatus.completed) {
|
||||
if (isPlaying && !status.isForwardOrCompleted) {
|
||||
_playPauseAnimation.forward();
|
||||
} else if (!isPlaying && status != AnimationStatus.reverse && status != AnimationStatus.dismissed) {
|
||||
} else if (!isPlaying && status.isForwardOrCompleted) {
|
||||
_playPauseAnimation.reverse();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ typedef MarginComputer = EdgeInsets Function(BuildContext context);
|
|||
|
||||
mixin FeedbackMixin {
|
||||
static final ValueNotifier<MarginComputer?> snackBarMarginOverrideNotifier = ValueNotifier(null);
|
||||
static OverlaySupportEntry? _overlayNotificationEntry;
|
||||
|
||||
static EdgeInsets snackBarMarginDefault(BuildContext context) {
|
||||
return EdgeInsets.only(
|
||||
|
@ -31,7 +32,11 @@ mixin FeedbackMixin {
|
|||
);
|
||||
}
|
||||
|
||||
void dismissFeedback(BuildContext context) => ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
void dismissFeedback(BuildContext context) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
_overlayNotificationEntry?.dismiss();
|
||||
_overlayNotificationEntry = null;
|
||||
}
|
||||
|
||||
void showFeedback(BuildContext context, FeedbackType type, String message, [SnackBarAction? action]) {
|
||||
ScaffoldMessengerState? scaffoldMessenger;
|
||||
|
@ -67,8 +72,7 @@ mixin FeedbackMixin {
|
|||
// and space under the snack bar `margin` does not receive gestures
|
||||
// (because it is used by the `Dismissible` wrapping the snack bar)
|
||||
// so we use `showOverlayNotification` instead
|
||||
OverlaySupportEntry? notificationOverlayEntry;
|
||||
notificationOverlayEntry = showOverlayNotification(
|
||||
_overlayNotificationEntry = showOverlayNotification(
|
||||
(context) => SafeArea(
|
||||
bottom: false,
|
||||
child: ValueListenableBuilder<MarginComputer?>(
|
||||
|
@ -89,7 +93,7 @@ mixin FeedbackMixin {
|
|||
foregroundColor: WidgetStateProperty.all(snackBarTheme.actionTextColor),
|
||||
),
|
||||
onPressed: () {
|
||||
notificationOverlayEntry?.dismiss();
|
||||
dismissFeedback(context);
|
||||
action.onPressed();
|
||||
},
|
||||
child: Text(action.label),
|
||||
|
@ -97,7 +101,7 @@ mixin FeedbackMixin {
|
|||
: null,
|
||||
animation: kAlwaysCompleteAnimation,
|
||||
dismissDirection: DismissDirection.horizontal,
|
||||
onDismiss: () => notificationOverlayEntry?.dismiss(),
|
||||
onDismiss: () => dismissFeedback(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -135,8 +135,8 @@ class _OverlaySnackBarState extends State<OverlaySnackBar> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
void _onAnimationStatusChanged(AnimationStatus animationStatus) {
|
||||
if (animationStatus == AnimationStatus.completed) {
|
||||
void _onAnimationStatusChanged(AnimationStatus status) {
|
||||
if (status.isCompleted) {
|
||||
if (widget.onVisible != null && !_wasVisible) {
|
||||
widget.onVisible!();
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AvesPopupMenuButton<T> extends PopupMenuButton<T> {
|
||||
final VoidCallback? onMenuOpened;
|
||||
|
||||
const AvesPopupMenuButton({
|
||||
super.key,
|
||||
required super.itemBuilder,
|
||||
super.initialValue,
|
||||
super.onSelected,
|
||||
super.onCanceled,
|
||||
super.tooltip,
|
||||
super.elevation,
|
||||
super.padding = const EdgeInsets.all(8),
|
||||
super.child,
|
||||
super.icon,
|
||||
super.offset = Offset.zero,
|
||||
super.enabled = true,
|
||||
super.shape,
|
||||
super.color,
|
||||
super.enableFeedback,
|
||||
super.iconSize,
|
||||
this.onMenuOpened,
|
||||
super.popUpAnimationStyle,
|
||||
});
|
||||
|
||||
@override
|
||||
PopupMenuButtonState<T> createState() => _AvesPopupMenuButtonState<T>();
|
||||
}
|
||||
|
||||
class _AvesPopupMenuButtonState<T> extends PopupMenuButtonState<T> {
|
||||
@override
|
||||
void showButtonMenu() {
|
||||
(widget as AvesPopupMenuButton).onMenuOpened?.call();
|
||||
super.showButtonMenu();
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@ class MenuRow extends StatelessWidget {
|
|||
this.icon,
|
||||
});
|
||||
|
||||
static const leadingPadding = EdgeInsetsDirectional.only(end: 12);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
|
@ -17,7 +19,7 @@ class MenuRow extends StatelessWidget {
|
|||
children: [
|
||||
if (icon != null)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 12),
|
||||
padding: leadingPadding,
|
||||
child: IconTheme.merge(
|
||||
data: IconThemeData(
|
||||
color: ListTileTheme.of(context).iconColor,
|
||||
|
|
|
@ -17,7 +17,7 @@ class AvesPopScope extends StatelessWidget {
|
|||
final blocker = handlers.firstWhereOrNull((v) => !v.canPop(context));
|
||||
return PopScope(
|
||||
canPop: blocker == null,
|
||||
onPopInvoked: (didPop) {
|
||||
onPopInvokedWithResult: (didPop, result) {
|
||||
if (!didPop) {
|
||||
blocker?.onPopBlocked(context);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ class TitledExpandableFilterRow extends StatelessWidget {
|
|||
final ValueNotifier<String?> expandedNotifier;
|
||||
final bool showGenericIcon;
|
||||
final HeroType Function(CollectionFilter filter)? heroTypeBuilder;
|
||||
final FilterCallback onTap;
|
||||
final AFilterCallback onTap;
|
||||
final OffsetFilterCallback? onLongPress;
|
||||
|
||||
const TitledExpandableFilterRow({
|
||||
|
@ -96,8 +96,8 @@ class ExpandableFilterRow extends StatelessWidget {
|
|||
final bool showGenericIcon;
|
||||
final Widget? Function(CollectionFilter)? leadingBuilder;
|
||||
final HeroType Function(CollectionFilter filter)? heroTypeBuilder;
|
||||
final FilterCallback onTap;
|
||||
final FilterCallback? onRemove;
|
||||
final AFilterCallback onTap;
|
||||
final AFilterCallback? onRemove;
|
||||
final OffsetFilterCallback? onLongPress;
|
||||
|
||||
static const double horizontalPadding = 8;
|
||||
|
|
|
@ -105,7 +105,7 @@ class _SweeperState extends State<Sweeper> with SingleTickerProviderStateMixin {
|
|||
|
||||
void _onAnimationStatusChanged(AnimationStatus status) {
|
||||
setState(() {});
|
||||
if (status == AnimationStatus.completed) {
|
||||
if (status.isCompleted) {
|
||||
widget.onSweepEnd?.call();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,6 +189,7 @@ class _SectionSelectableLeading<T> extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
if (!selectable) return _buildBrowsing(context);
|
||||
|
||||
final duration = context.select<DurationsData, Duration>((v) => v.formTransition);
|
||||
final isSelecting = context.select<Selection<T>, bool>((selection) => selection.isSelecting);
|
||||
final Widget child = isSelecting
|
||||
? _SectionSelectingLeading<T>(
|
||||
|
@ -201,7 +202,7 @@ class _SectionSelectableLeading<T> extends StatelessWidget {
|
|||
descendantsAreFocusable: false,
|
||||
descendantsAreTraversable: false,
|
||||
child: AnimatedSwitcher(
|
||||
duration: ADurations.sectionHeaderAnimation,
|
||||
duration: duration,
|
||||
switchInCurve: Curves.easeInOut,
|
||||
switchOutCurve: Curves.easeInOut,
|
||||
transitionBuilder: (child, animation) {
|
||||
|
@ -240,11 +241,12 @@ class _SectionSelectingLeading<T> extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final duration = context.select<DurationsData, Duration>((v) => v.formTransition);
|
||||
final sectionEntries = context.watch<SectionedListLayout<T>>().sections[sectionKey] ?? [];
|
||||
final selection = context.watch<Selection<T>>();
|
||||
final isSelected = selection.isSelected(sectionEntries);
|
||||
return AnimatedSwitcher(
|
||||
duration: ADurations.sectionHeaderAnimation,
|
||||
duration: duration,
|
||||
switchInCurve: Curves.easeOutBack,
|
||||
switchOutCurve: Curves.easeOutBack,
|
||||
transitionBuilder: (child, animation) => ScaleTransition(
|
||||
|
|
|
@ -10,8 +10,6 @@ class GridItemSelectionOverlay<T> extends StatelessWidget {
|
|||
final BorderRadius? borderRadius;
|
||||
final EdgeInsets? padding;
|
||||
|
||||
static const duration = ADurations.thumbnailOverlayAnimation;
|
||||
|
||||
const GridItemSelectionOverlay({
|
||||
super.key,
|
||||
required this.item,
|
||||
|
@ -21,6 +19,7 @@ class GridItemSelectionOverlay<T> extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final duration = context.select<DurationsData, Duration>((v) => v.formTransition);
|
||||
final isSelecting = context.select<Selection<T>, bool>((selection) => selection.isSelecting);
|
||||
return AnimatedSwitcher(
|
||||
duration: duration,
|
||||
|
|
|
@ -55,9 +55,9 @@ class _GridSelectionGestureDetectorState<T> extends State<GridSelectionGestureDe
|
|||
return scrollableBox.size.width;
|
||||
}
|
||||
|
||||
static const double scrollEdgeRatio = .15;
|
||||
static const double scrollMaxPixelPerSecond = 600.0;
|
||||
static const Duration scrollUpdateInterval = Duration(milliseconds: 100);
|
||||
static const double _scrollEdgeRatio = .15;
|
||||
static const double _scrollMaxPixelPerSecond = 600.0;
|
||||
static const Duration _scrollUpdateInterval = Duration(milliseconds: 100);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -158,7 +158,7 @@ class _GridSelectionGestureDetectorState<T> extends State<GridSelectionGestureDe
|
|||
final top = dy < height / 2;
|
||||
|
||||
final distanceToEdge = max(0, top ? dy - _scrollableInsets.top : height - dy - _scrollableInsets.bottom);
|
||||
final threshold = height * scrollEdgeRatio;
|
||||
final threshold = height * _scrollEdgeRatio;
|
||||
if (distanceToEdge < threshold) {
|
||||
_setScrollSpeed((top ? -1 : 1) * roundToPrecision((threshold - distanceToEdge) / threshold, decimals: 1));
|
||||
} else {
|
||||
|
@ -185,7 +185,7 @@ class _GridSelectionGestureDetectorState<T> extends State<GridSelectionGestureDe
|
|||
final target = speedFactor > 0 ? scrollController.position.maxScrollExtent : .0;
|
||||
if (target != current) {
|
||||
final distance = target - current;
|
||||
final millis = distance * 1000 / scrollMaxPixelPerSecond / speedFactor;
|
||||
final millis = distance * 1000 / _scrollMaxPixelPerSecond / speedFactor;
|
||||
scrollController.animateTo(
|
||||
target,
|
||||
duration: Duration(milliseconds: millis.round()),
|
||||
|
@ -193,7 +193,7 @@ class _GridSelectionGestureDetectorState<T> extends State<GridSelectionGestureDe
|
|||
);
|
||||
// use a timer to update the selection, because `onLongPressMoveUpdate`
|
||||
// is not called when the pointer stays still while the view is scrolling
|
||||
_selectionUpdateTimer = Timer.periodic(scrollUpdateInterval, (_) => _onLongPressUpdate());
|
||||
_selectionUpdateTimer = Timer.periodic(_scrollUpdateInterval, (_) => _onLongPressUpdate());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,50 @@ class AvesAppBar extends StatelessWidget {
|
|||
final colorScheme = theme.colorScheme;
|
||||
final textScaler = MediaQuery.textScalerOf(context);
|
||||
final useTvLayout = settings.useTvLayout;
|
||||
|
||||
Widget? _leading = leading;
|
||||
if (_leading != null) {
|
||||
_leading = FontSizeIconTheme(
|
||||
child: _leading,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _title = FontSizeIconTheme(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Row(
|
||||
key: ValueKey(transitionKey),
|
||||
children: [
|
||||
Expanded(child: title),
|
||||
...(actions(context, max(0, constraints.maxWidth - _titleMinWidth))),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final animate = context.select<Settings, bool>((v) => v.animate);
|
||||
if (animate) {
|
||||
_title = Hero(
|
||||
tag: titleHeroTag,
|
||||
flightShuttleBuilder: _flightShuttleBuilder,
|
||||
transitionOnUserGestures: true,
|
||||
child: AnimatedSwitcher(
|
||||
duration: context.read<DurationsData>().iconAnimation,
|
||||
child: _title,
|
||||
),
|
||||
);
|
||||
|
||||
if (_leading != null) {
|
||||
_leading = Hero(
|
||||
tag: leadingHeroTag,
|
||||
flightShuttleBuilder: _flightShuttleBuilder,
|
||||
transitionOnUserGestures: true,
|
||||
child: _leading,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return SliverPersistentHeader(
|
||||
floating: !useTvLayout,
|
||||
pinned: pinned,
|
||||
|
@ -70,43 +114,16 @@ class AvesAppBar extends StatelessWidget {
|
|||
height: textScaler.scale(kToolbarHeight),
|
||||
child: Row(
|
||||
children: [
|
||||
leading != null
|
||||
_leading != null
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Hero(
|
||||
tag: leadingHeroTag,
|
||||
flightShuttleBuilder: _flightShuttleBuilder,
|
||||
transitionOnUserGestures: true,
|
||||
child: FontSizeIconTheme(
|
||||
child: leading!,
|
||||
),
|
||||
),
|
||||
child: _leading,
|
||||
)
|
||||
: const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: DefaultTextStyle(
|
||||
style: theme.appBarTheme.titleTextStyle!,
|
||||
child: Hero(
|
||||
tag: titleHeroTag,
|
||||
flightShuttleBuilder: _flightShuttleBuilder,
|
||||
transitionOnUserGestures: true,
|
||||
child: AnimatedSwitcher(
|
||||
duration: context.read<DurationsData>().iconAnimation,
|
||||
child: FontSizeIconTheme(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Row(
|
||||
key: ValueKey(transitionKey),
|
||||
children: [
|
||||
Expanded(child: title),
|
||||
...(actions(context, max(0, constraints.maxWidth - _titleMinWidth))),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: _title,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -26,7 +26,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
typedef FilterCallback = void Function(CollectionFilter filter);
|
||||
typedef AFilterCallback = void Function(CollectionFilter filter);
|
||||
typedef OffsetFilterCallback = void Function(BuildContext context, CollectionFilter filter, Offset tapPosition);
|
||||
|
||||
enum HeroType { always, onTap, never }
|
||||
|
@ -56,9 +56,10 @@ class AvesFilterChip extends StatefulWidget {
|
|||
final double padding;
|
||||
final double? maxWidth;
|
||||
final HeroType heroType;
|
||||
final FilterCallback? onTap, onRemove;
|
||||
final AFilterCallback? onTap, onRemove;
|
||||
final OffsetFilterCallback? onLongPress;
|
||||
|
||||
static const double defaultPadding = 6.0;
|
||||
static const double defaultRadius = 32;
|
||||
static const double outlineWidth = 2;
|
||||
static const double minChipHeight = kMinInteractiveDimension;
|
||||
|
@ -79,7 +80,7 @@ class AvesFilterChip extends StatefulWidget {
|
|||
this.banner,
|
||||
this.leadingOverride,
|
||||
this.details,
|
||||
this.padding = 6.0,
|
||||
this.padding = defaultPadding,
|
||||
this.maxWidth,
|
||||
this.heroType = HeroType.onTap,
|
||||
this.onTap,
|
||||
|
@ -87,7 +88,7 @@ class AvesFilterChip extends StatefulWidget {
|
|||
this.onLongPress = showDefaultLongPressMenu,
|
||||
});
|
||||
|
||||
static double computeMaxWidth(
|
||||
static double computeMaxWidthForRow(
|
||||
BuildContext context, {
|
||||
required int minChipPerRow,
|
||||
required double chipPadding,
|
||||
|
@ -347,7 +348,7 @@ class _AvesFilterChipState extends State<AvesFilterChip> {
|
|||
maxWidth: max(
|
||||
AvesFilterChip.minChipWidth,
|
||||
widget.maxWidth ??
|
||||
AvesFilterChip.computeMaxWidth(
|
||||
AvesFilterChip.computeMaxWidthForRow(
|
||||
context,
|
||||
minChipPerRow: 2,
|
||||
chipPadding: FilterBar.chipPadding.horizontal,
|
||||
|
|
|
@ -124,7 +124,13 @@ class MapButtonPanel extends StatelessWidget {
|
|||
Padding(
|
||||
padding: EdgeInsets.only(top: padding),
|
||||
// key is expected by test driver
|
||||
child: _buildButton(context, MapAction.selectStyle, buttonKey: const Key('map-menu-layers')),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildButton(context, MapAction.selectStyle, buttonKey: const Key('map-menu-layers')),
|
||||
SizedBox(height: padding),
|
||||
_buildButton(context, MapAction.openMapApp),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue