Merge branch 'develop'
2
.github/workflows/check.yml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
||||||
# Available versions may lag behind https://github.com/flutter/flutter.git
|
# Available versions may lag behind https://github.com/flutter/flutter.git
|
||||||
- uses: subosito/flutter-action@v2
|
- uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
flutter-version: '3.0.1'
|
flutter-version: '3.0.2'
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
|
|
||||||
- name: Clone the repository.
|
- name: Clone the repository.
|
||||||
|
|
10
.github/workflows/release.yml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
||||||
# Available versions may lag behind https://github.com/flutter/flutter.git
|
# Available versions may lag behind https://github.com/flutter/flutter.git
|
||||||
- uses: subosito/flutter-action@v2
|
- uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
flutter-version: '3.0.1'
|
flutter-version: '3.0.2'
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
|
|
||||||
# Workaround for this Android Gradle Plugin issue (supposedly fixed in AGP 4.1):
|
# Workaround for this Android Gradle Plugin issue (supposedly fixed in AGP 4.1):
|
||||||
|
@ -56,15 +56,15 @@ jobs:
|
||||||
rm release.keystore.asc
|
rm release.keystore.asc
|
||||||
mkdir outputs
|
mkdir outputs
|
||||||
(cd scripts/; ./apply_flavor_play.sh)
|
(cd scripts/; ./apply_flavor_play.sh)
|
||||||
flutter build appbundle -t lib/main_play.dart --flavor play --bundle-sksl-path shaders_3.0.1.sksl.json
|
flutter build appbundle -t lib/main_play.dart --flavor play --bundle-sksl-path shaders_3.0.2.sksl.json
|
||||||
cp build/app/outputs/bundle/playRelease/*.aab outputs
|
cp build/app/outputs/bundle/playRelease/*.aab outputs
|
||||||
flutter build apk -t lib/main_play.dart --flavor play --bundle-sksl-path shaders_3.0.1.sksl.json
|
flutter build apk -t lib/main_play.dart --flavor play --bundle-sksl-path shaders_3.0.2.sksl.json
|
||||||
cp build/app/outputs/apk/play/release/*.apk outputs
|
cp build/app/outputs/apk/play/release/*.apk outputs
|
||||||
(cd scripts/; ./apply_flavor_huawei.sh)
|
(cd scripts/; ./apply_flavor_huawei.sh)
|
||||||
flutter build apk -t lib/main_huawei.dart --flavor huawei --bundle-sksl-path shaders_3.0.1.sksl.json
|
flutter build apk -t lib/main_huawei.dart --flavor huawei --bundle-sksl-path shaders_3.0.2.sksl.json
|
||||||
cp build/app/outputs/apk/huawei/release/*.apk outputs
|
cp build/app/outputs/apk/huawei/release/*.apk outputs
|
||||||
(cd scripts/; ./apply_flavor_izzy.sh)
|
(cd scripts/; ./apply_flavor_izzy.sh)
|
||||||
flutter build apk -t lib/main_izzy.dart --flavor izzy --split-per-abi --bundle-sksl-path shaders_3.0.1.sksl.json
|
flutter build apk -t lib/main_izzy.dart --flavor izzy --split-per-abi --bundle-sksl-path shaders_3.0.2.sksl.json
|
||||||
cp build/app/outputs/apk/izzy/release/*.apk outputs
|
cp build/app/outputs/apk/izzy/release/*.apk outputs
|
||||||
rm $AVES_STORE_FILE
|
rm $AVES_STORE_FILE
|
||||||
env:
|
env:
|
||||||
|
|
20
CHANGELOG.md
|
@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## <a id="unreleased"></a>[Unreleased]
|
## <a id="unreleased"></a>[Unreleased]
|
||||||
|
|
||||||
|
## <a id="v1.6.9"></a>[v1.6.9] - 2022-06-18
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- slideshow
|
||||||
|
- set wallpaper from any media
|
||||||
|
- optional dynamic accent color on Android 12+
|
||||||
|
- Search: date/dimension/size field equality (undocumented)
|
||||||
|
- support Android 13 (API 33)
|
||||||
|
- Turkish translation (thanks metezd)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- do not force quit on storage permission denial
|
||||||
|
- upgraded Flutter to stable v3.0.2
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- merge ambiguously cased directories
|
||||||
|
|
||||||
## <a id="v1.6.8"></a>[v1.6.8] - 2022-05-27
|
## <a id="v1.6.8"></a>[v1.6.8] - 2022-05-27
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -12,6 +12,9 @@ Aves is a gallery and metadata explorer app. It is built for Android, with Flutt
|
||||||
[<img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png"
|
[<img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png"
|
||||||
alt='Get it on Google Play'
|
alt='Get it on Google Play'
|
||||||
height="80">](https://play.google.com/store/apps/details?id=deckers.thibault.aves&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1)
|
height="80">](https://play.google.com/store/apps/details?id=deckers.thibault.aves&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1)
|
||||||
|
[<img src="https://raw.githubusercontent.com/deckerst/common/main/assets/huawei-appgallery-badge-english-black.png"
|
||||||
|
alt='Get it on Huawei AppGallery'
|
||||||
|
height="80">](https://appgallery.huawei.com/app/C106014023)
|
||||||
[<img src="https://raw.githubusercontent.com/deckerst/common/main/assets/amazon-appstore-badge-english-black.png"
|
[<img src="https://raw.githubusercontent.com/deckerst/common/main/assets/amazon-appstore-badge-english-black.png"
|
||||||
alt='Get it on Amazon Appstore'
|
alt='Get it on Amazon Appstore'
|
||||||
height="80">](https://www.amazon.com/dp/B09XQHQQ72)
|
height="80">](https://www.amazon.com/dp/B09XQHQQ72)
|
||||||
|
@ -90,7 +93,7 @@ At this stage this project does *not* accept PRs, except for translations.
|
||||||
|
|
||||||
### Translations
|
### Translations
|
||||||
|
|
||||||
If you want to translate this app in your language and share the result, [there is a guide](https://github.com/deckerst/aves/wiki/Contributing-to-Translations). English, Korean and French are already handled by me. Russian, German, Spanish, Portuguese, Indonesian, Japanese, Italian & Chinese are handled by generous volunteers.
|
If you want to translate this app in your language and share the result, [there is a guide](https://github.com/deckerst/aves/wiki/Contributing-to-Translations). English, Korean and French are already handled by me. Russian, German, Spanish, Portuguese, Indonesian, Japanese, Italian, Chinese & Turkish are handled by generous volunteers.
|
||||||
|
|
||||||
### Donations
|
### Donations
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ if (keystorePropertiesFile.exists()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 32
|
compileSdkVersion 33
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
@ -57,7 +57,7 @@ android {
|
||||||
// which implementation `DocumentBuilderImpl` is provided by the OS and is not customizable on Android,
|
// which implementation `DocumentBuilderImpl` is provided by the OS and is not customizable on Android,
|
||||||
// but the implementation on API <19 is not robust enough and fails to build XMP documents
|
// but the implementation on API <19 is not robust enough and fails to build XMP documents
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 32
|
targetSdkVersion 33
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
manifestPlaceholders = [googleApiKey: keystoreProperties['googleApiKey']]
|
manifestPlaceholders = [googleApiKey: keystoreProperties['googleApiKey']]
|
||||||
|
@ -154,7 +154,7 @@ repositories {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
|
||||||
implementation 'androidx.core:core-ktx:1.7.0'
|
implementation 'androidx.core:core-ktx:1.8.0'
|
||||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'com.caverock:androidsvg-aar:1.4'
|
implementation 'com.caverock:androidsvg-aar:1.4'
|
||||||
|
|
|
@ -6,16 +6,21 @@
|
||||||
Scoped storage on Android Q is inconvenient because users need to confirm edition on each individual file.
|
Scoped storage on Android Q is inconvenient because users need to confirm edition on each individual file.
|
||||||
So we request `WRITE_EXTERNAL_STORAGE` until Q (29), and enable `requestLegacyExternalStorage`
|
So we request `WRITE_EXTERNAL_STORAGE` until Q (29), and enable `requestLegacyExternalStorage`
|
||||||
-->
|
-->
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
<!-- TODO TLAD [tiramisu] need notification permission? -->
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission
|
||||||
<!-- TODO TLAD [tiramisu] READ_MEDIA_IMAGE, READ_MEDIA_VIDEO instead of READ_EXTERNAL_STORAGE? -->
|
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
android:maxSdkVersion="32" />
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
android:maxSdkVersion="29"
|
android:maxSdkVersion="29"
|
||||||
tools:ignore="ScopedStorage" />
|
tools:ignore="ScopedStorage" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<!-- to show foreground service progress via notification -->
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
|
||||||
<!-- to access media with original metadata with scoped storage (Android Q+) -->
|
<!-- to access media with original metadata with scoped storage (Android Q+) -->
|
||||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||||
|
@ -128,6 +133,26 @@
|
||||||
android:name="android.app.searchable"
|
android:name="android.app.searchable"
|
||||||
android:resource="@xml/searchable" />
|
android:resource="@xml/searchable" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".WallpaperActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="@string/wallpaper"
|
||||||
|
android:theme="@style/NormalTheme">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.ATTACH_DATA" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SET_WALLPAPER" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".AnalysisService"
|
android:name=".AnalysisService"
|
||||||
android:description="@string/analysis_service_description"
|
android:description="@string/analysis_service_description"
|
||||||
|
|
|
@ -159,7 +159,7 @@ class AnalysisService : MethodChannel.MethodCallHandler, Service() {
|
||||||
COMMAND_START -> {
|
COMMAND_START -> {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
FlutterUtils.runOnUiThread {
|
FlutterUtils.runOnUiThread {
|
||||||
val entryIds = data.get(KEY_ENTRY_IDS)?.takeIf { it is IntArray }?.let { (it as IntArray).toList() }
|
val entryIds = data.getIntArray(KEY_ENTRY_IDS)?.toList()
|
||||||
backgroundChannel?.invokeMethod(
|
backgroundChannel?.invokeMethod(
|
||||||
"start", hashMapOf(
|
"start", hashMapOf(
|
||||||
"entryIds" to entryIds,
|
"entryIds" to entryIds,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import app.loup.streams_channel.StreamsChannel
|
||||||
import deckers.thibault.aves.channel.calls.*
|
import deckers.thibault.aves.channel.calls.*
|
||||||
import deckers.thibault.aves.channel.streams.*
|
import deckers.thibault.aves.channel.streams.*
|
||||||
import deckers.thibault.aves.utils.LogUtils
|
import deckers.thibault.aves.utils.LogUtils
|
||||||
|
import deckers.thibault.aves.utils.getParcelableExtraCompat
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.plugin.common.EventChannel
|
import io.flutter.plugin.common.EventChannel
|
||||||
import io.flutter.plugin.common.MethodCall
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
@ -215,7 +216,7 @@ class MainActivity : FlutterActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Intent.ACTION_VIEW, Intent.ACTION_SEND, "com.android.camera.action.REVIEW" -> {
|
Intent.ACTION_VIEW, Intent.ACTION_SEND, "com.android.camera.action.REVIEW" -> {
|
||||||
(intent.data ?: (intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri))?.let { uri ->
|
(intent.data ?: intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM))?.let { uri ->
|
||||||
// MIME type is optional
|
// MIME type is optional
|
||||||
val type = intent.type ?: intent.resolveType(context)
|
val type = intent.type ?: intent.resolveType(context)
|
||||||
return hashMapOf(
|
return hashMapOf(
|
||||||
|
@ -332,6 +333,7 @@ class MainActivity : FlutterActivity() {
|
||||||
|
|
||||||
const val INTENT_ACTION_PICK = "pick"
|
const val INTENT_ACTION_PICK = "pick"
|
||||||
const val INTENT_ACTION_SEARCH = "search"
|
const val INTENT_ACTION_SEARCH = "search"
|
||||||
|
const val INTENT_ACTION_SET_WALLPAPER = "set_wallpaper"
|
||||||
const val INTENT_ACTION_VIEW = "view"
|
const val INTENT_ACTION_VIEW = "view"
|
||||||
|
|
||||||
const val SHORTCUT_KEY_PAGE = "page"
|
const val SHORTCUT_KEY_PAGE = "page"
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
package deckers.thibault.aves
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.*
|
||||||
|
import android.util.Log
|
||||||
|
import app.loup.streams_channel.StreamsChannel
|
||||||
|
import deckers.thibault.aves.channel.calls.*
|
||||||
|
import deckers.thibault.aves.channel.streams.ImageByteStreamHandler
|
||||||
|
import deckers.thibault.aves.utils.LogUtils
|
||||||
|
import deckers.thibault.aves.utils.getParcelableExtraCompat
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
|
||||||
|
class WallpaperActivity : FlutterActivity() {
|
||||||
|
private lateinit var intentDataMap: MutableMap<String, Any?>
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
Log.i(LOG_TAG, "onCreate intent=$intent")
|
||||||
|
intent.extras?.takeUnless { it.isEmpty }?.let {
|
||||||
|
Log.i(LOG_TAG, "onCreate intent extras=$it")
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val messenger = flutterEngine!!.dartExecutor.binaryMessenger
|
||||||
|
|
||||||
|
// dart -> platform -> dart
|
||||||
|
// - need Context
|
||||||
|
MethodChannel(messenger, DeviceHandler.CHANNEL).setMethodCallHandler(DeviceHandler(this))
|
||||||
|
MethodChannel(messenger, EmbeddedDataHandler.CHANNEL).setMethodCallHandler(EmbeddedDataHandler(this))
|
||||||
|
MethodChannel(messenger, MetadataFetchHandler.CHANNEL).setMethodCallHandler(MetadataFetchHandler(this))
|
||||||
|
// - need Activity
|
||||||
|
MethodChannel(messenger, AccessibilityHandler.CHANNEL).setMethodCallHandler(AccessibilityHandler(this))
|
||||||
|
MethodChannel(messenger, MediaFileHandler.CHANNEL).setMethodCallHandler(MediaFileHandler(this))
|
||||||
|
MethodChannel(messenger, WallpaperHandler.CHANNEL).setMethodCallHandler(WallpaperHandler(this))
|
||||||
|
MethodChannel(messenger, WindowHandler.CHANNEL).setMethodCallHandler(WindowHandler(this))
|
||||||
|
|
||||||
|
// result streaming: dart -> platform ->->-> dart
|
||||||
|
// - need Context
|
||||||
|
StreamsChannel(messenger, ImageByteStreamHandler.CHANNEL).setStreamHandlerFactory { args -> ImageByteStreamHandler(this, args) }
|
||||||
|
|
||||||
|
// intent handling
|
||||||
|
// detail fetch: dart -> platform
|
||||||
|
intentDataMap = extractIntentData(intent)
|
||||||
|
MethodChannel(messenger, VIEWER_CHANNEL).setMethodCallHandler { call, result ->
|
||||||
|
when (call.method) {
|
||||||
|
"getIntentData" -> {
|
||||||
|
result.success(intentDataMap)
|
||||||
|
intentDataMap.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
Log.i(LOG_TAG, "onStart")
|
||||||
|
super.onStart()
|
||||||
|
|
||||||
|
// as of Flutter v3.0.1, the window `viewInsets` and `viewPadding`
|
||||||
|
// are incorrect on startup in some environments (e.g. API 29 emulator),
|
||||||
|
// so we manually request to apply the insets to update the window metrics
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
window.decorView.requestApplyInsets()
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
Log.i(LOG_TAG, "onStop")
|
||||||
|
super.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
Log.i(LOG_TAG, "onDestroy")
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractIntentData(intent: Intent?): MutableMap<String, Any?> {
|
||||||
|
when (intent?.action) {
|
||||||
|
Intent.ACTION_ATTACH_DATA, Intent.ACTION_SET_WALLPAPER -> {
|
||||||
|
(intent.data ?: intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM))?.let { uri ->
|
||||||
|
// MIME type is optional
|
||||||
|
val type = intent.type ?: intent.resolveType(context)
|
||||||
|
return hashMapOf(
|
||||||
|
MainActivity.INTENT_DATA_KEY_ACTION to MainActivity.INTENT_ACTION_SET_WALLPAPER,
|
||||||
|
MainActivity.INTENT_DATA_KEY_MIME_TYPE to type,
|
||||||
|
MainActivity.INTENT_DATA_KEY_URI to uri.toString(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Intent.ACTION_RUN -> {
|
||||||
|
// flutter run
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Log.w(LOG_TAG, "unhandled intent action=${intent?.action}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HashMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOG_TAG = LogUtils.createTag<WallpaperActivity>()
|
||||||
|
const val VIEWER_CHANNEL = "deckers.thibault/aves/viewer"
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,8 @@ import deckers.thibault.aves.model.FieldMap
|
||||||
import deckers.thibault.aves.utils.BitmapUtils
|
import deckers.thibault.aves.utils.BitmapUtils
|
||||||
import deckers.thibault.aves.utils.BitmapUtils.getBytes
|
import deckers.thibault.aves.utils.BitmapUtils.getBytes
|
||||||
import deckers.thibault.aves.utils.LogUtils
|
import deckers.thibault.aves.utils.LogUtils
|
||||||
|
import deckers.thibault.aves.utils.getApplicationInfoCompat
|
||||||
|
import deckers.thibault.aves.utils.queryIntentActivitiesCompat
|
||||||
import io.flutter.plugin.common.MethodCall
|
import io.flutter.plugin.common.MethodCall
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||||
|
@ -77,7 +79,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
val pm = context.packageManager
|
val pm = context.packageManager
|
||||||
for (resolveInfo in pm.queryIntentActivities(intent, 0)) {
|
for (resolveInfo in pm.queryIntentActivitiesCompat(intent, 0)) {
|
||||||
val appInfo = resolveInfo.activityInfo.applicationInfo
|
val appInfo = resolveInfo.activityInfo.applicationInfo
|
||||||
val packageName = appInfo.packageName
|
val packageName = appInfo.packageName
|
||||||
if (!packages.containsKey(packageName)) {
|
if (!packages.containsKey(packageName)) {
|
||||||
|
@ -149,7 +151,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
||||||
val size = (sizeDip * density).roundToInt()
|
val size = (sizeDip * density).roundToInt()
|
||||||
var data: ByteArray? = null
|
var data: ByteArray? = null
|
||||||
try {
|
try {
|
||||||
val iconResourceId = context.packageManager.getApplicationInfo(packageName, 0).icon
|
val iconResourceId = context.packageManager.getApplicationInfoCompat(packageName, 0).icon
|
||||||
if (iconResourceId != Resources.ID_NULL) {
|
if (iconResourceId != Resources.ID_NULL) {
|
||||||
val uri = Uri.Builder()
|
val uri = Uri.Builder()
|
||||||
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
|
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
|
||||||
|
|
|
@ -32,6 +32,8 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
||||||
"canPinShortcut" to ShortcutManagerCompat.isRequestPinShortcutSupported(context),
|
"canPinShortcut" to ShortcutManagerCompat.isRequestPinShortcutSupported(context),
|
||||||
"canPrint" to (sdkInt >= Build.VERSION_CODES.KITKAT),
|
"canPrint" to (sdkInt >= Build.VERSION_CODES.KITKAT),
|
||||||
"canRenderFlagEmojis" to (sdkInt >= Build.VERSION_CODES.LOLLIPOP),
|
"canRenderFlagEmojis" to (sdkInt >= Build.VERSION_CODES.LOLLIPOP),
|
||||||
|
"canSetLockScreenWallpaper" to (sdkInt >= Build.VERSION_CODES.N),
|
||||||
|
"isDynamicColorAvailable" to (sdkInt >= Build.VERSION_CODES.S),
|
||||||
"showPinShortcutFeedback" to (sdkInt >= Build.VERSION_CODES.O),
|
"showPinShortcutFeedback" to (sdkInt >= Build.VERSION_CODES.O),
|
||||||
"supportEdgeToEdgeUIMode" to (sdkInt >= Build.VERSION_CODES.Q),
|
"supportEdgeToEdgeUIMode" to (sdkInt >= Build.VERSION_CODES.Q),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
package deckers.thibault.aves.channel.calls
|
package deckers.thibault.aves.channel.calls
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.location.Address
|
||||||
import android.location.Geocoder
|
import android.location.Geocoder
|
||||||
|
import android.os.Build
|
||||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||||
import io.flutter.plugin.common.MethodCall
|
import io.flutter.plugin.common.MethodCall
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -48,36 +53,48 @@ class GeocodingHandler(private val context: Context) : MethodCallHandler {
|
||||||
Geocoder(context)
|
Geocoder(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
val addresses = try {
|
fun processAddresses(addresses: List<Address>) {
|
||||||
geocoder!!.getFromLocation(latitude, longitude, maxResults) ?: ArrayList()
|
if (addresses.isEmpty()) {
|
||||||
} catch (e: IOException) {
|
result.error("getAddress-empty", "failed to find any address for latitude=$latitude, longitude=$longitude", null)
|
||||||
// `grpc failed`, etc.
|
} else {
|
||||||
result.error("getAddress-network", "failed to get address because of network issues", e.message)
|
val addressMapList: ArrayList<Map<String, String?>> = ArrayList(addresses.map { address ->
|
||||||
return
|
hashMapOf(
|
||||||
} catch (e: Exception) {
|
"addressLine" to (0..address.maxAddressLineIndex).joinToString(", ") { i -> address.getAddressLine(i) },
|
||||||
result.error("getAddress-exception", "failed to get address", e.message)
|
"adminArea" to address.adminArea,
|
||||||
return
|
"countryCode" to address.countryCode,
|
||||||
|
"countryName" to address.countryName,
|
||||||
|
"featureName" to address.featureName,
|
||||||
|
"locality" to address.locality,
|
||||||
|
"postalCode" to address.postalCode,
|
||||||
|
"subAdminArea" to address.subAdminArea,
|
||||||
|
"subLocality" to address.subLocality,
|
||||||
|
"subThoroughfare" to address.subThoroughfare,
|
||||||
|
"thoroughfare" to address.thoroughfare,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
result.success(addressMapList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addresses.isEmpty()) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
result.error("getAddress-empty", "failed to find any address for latitude=$latitude, longitude=$longitude", null)
|
geocoder!!.getFromLocation(latitude, longitude, maxResults, object : Geocoder.GeocodeListener {
|
||||||
} else {
|
override fun onGeocode(addresses: List<Address?>) = processAddresses(addresses.filterNotNull())
|
||||||
val addressMapList: ArrayList<Map<String, String?>> = ArrayList(addresses.map { address ->
|
|
||||||
hashMapOf(
|
override fun onError(errorMessage: String?) {
|
||||||
"addressLine" to (0..address.maxAddressLineIndex).joinToString(", ") { i -> address.getAddressLine(i) },
|
result.error("getAddress-asyncerror", "failed to get address", errorMessage)
|
||||||
"adminArea" to address.adminArea,
|
}
|
||||||
"countryCode" to address.countryCode,
|
|
||||||
"countryName" to address.countryName,
|
|
||||||
"featureName" to address.featureName,
|
|
||||||
"locality" to address.locality,
|
|
||||||
"postalCode" to address.postalCode,
|
|
||||||
"subAdminArea" to address.subAdminArea,
|
|
||||||
"subLocality" to address.subLocality,
|
|
||||||
"subThoroughfare" to address.subThoroughfare,
|
|
||||||
"thoroughfare" to address.thoroughfare,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
result.success(addressMapList)
|
} else {
|
||||||
|
try {
|
||||||
|
@Suppress("deprecation")
|
||||||
|
val addresses = geocoder!!.getFromLocation(latitude, longitude, maxResults) ?: ArrayList()
|
||||||
|
processAddresses(addresses)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
// `grpc failed`, etc.
|
||||||
|
result.error("getAddress-network", "failed to get address because of network issues", e.message)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
result.error("getAddress-exception", "failed to get address", e.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package deckers.thibault.aves.channel.calls
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.WallpaperManager
|
||||||
|
import android.app.WallpaperManager.FLAG_LOCK
|
||||||
|
import android.app.WallpaperManager.FLAG_SYSTEM
|
||||||
|
import android.os.Build
|
||||||
|
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||||
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class WallpaperHandler(private val activity: Activity) : MethodCallHandler {
|
||||||
|
private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
|
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
when (call.method) {
|
||||||
|
"setWallpaper" -> ioScope.launch { safe(call, result, ::setWallpaper) }
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setWallpaper(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
val bytes = call.argument<ByteArray>("bytes")
|
||||||
|
val home = call.argument<Boolean>("home")
|
||||||
|
val lock = call.argument<Boolean>("lock")
|
||||||
|
if (bytes == null || home == null || lock == null) {
|
||||||
|
result.error("setWallpaper-args", "failed because of missing arguments", null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val manager = WallpaperManager.getInstance(activity)
|
||||||
|
val supported = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || manager.isWallpaperSupported
|
||||||
|
val allowed = Build.VERSION.SDK_INT < Build.VERSION_CODES.N || manager.isSetWallpaperAllowed
|
||||||
|
if (!supported || !allowed) {
|
||||||
|
result.error("setWallpaper-unsupported", "failed because setting wallpaper is not allowed", null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes.inputStream().use { input ->
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
val flags = (if (home) FLAG_SYSTEM else 0) or (if (lock) FLAG_LOCK else 0)
|
||||||
|
manager.setStream(input, null, true, flags)
|
||||||
|
} else {
|
||||||
|
manager.setStream(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.success(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val CHANNEL = "deckers.thibault/aves/wallpaper"
|
||||||
|
}
|
||||||
|
}
|
|
@ -220,7 +220,7 @@ object ExifInterfaceHelper {
|
||||||
// initialize metadata-extractor directories that we will fill
|
// initialize metadata-extractor directories that we will fill
|
||||||
// by tags converted from the ExifInterface attributes
|
// by tags converted from the ExifInterface attributes
|
||||||
// so that we can rely on metadata-extractor descriptions
|
// so that we can rely on metadata-extractor descriptions
|
||||||
val dirs = DirType.values().associate { Pair(it, it.createDirectory()) }
|
val dirs = DirType.values().associateWith { it.createDirectory() }
|
||||||
|
|
||||||
// exclude Exif directory when it only includes image size
|
// exclude Exif directory when it only includes image size
|
||||||
val isUselessExif = fun(it: Map<String, String>): Boolean {
|
val isUselessExif = fun(it: Map<String, String>): Boolean {
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package deckers.thibault.aves.utils
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Parcelable
|
||||||
|
|
||||||
|
inline fun <reified T> Intent.getParcelableExtraCompat(name: String): T? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
getParcelableExtra(name, T::class.java)
|
||||||
|
} else {
|
||||||
|
@Suppress("deprecation")
|
||||||
|
getParcelableExtra<Parcelable>(name) as? T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): ApplicationInfo {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(flags.toLong()))
|
||||||
|
} else {
|
||||||
|
@Suppress("deprecation")
|
||||||
|
getApplicationInfo(packageName, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PackageManager.queryIntentActivitiesCompat(intent: Intent, flags: Int): List<ResolveInfo> {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(flags.toLong()))
|
||||||
|
} else {
|
||||||
|
@Suppress("deprecation")
|
||||||
|
queryIntentActivities(intent, flags)
|
||||||
|
}
|
||||||
|
}
|
32
android/app/src/main/res/drawable/ic_launcher_mono.xml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="100dp"
|
||||||
|
android:height="100dp"
|
||||||
|
android:viewportWidth="100"
|
||||||
|
android:viewportHeight="100">
|
||||||
|
<group
|
||||||
|
android:scaleX=".44"
|
||||||
|
android:scaleY=".44"
|
||||||
|
android:translateX="28"
|
||||||
|
android:translateY="30">
|
||||||
|
<path
|
||||||
|
android:pathData="M3.925,16.034 L60.825,72.933a2.421,2.421 0.001,0 0,3.423 0l10.604,-10.603a6.789,6.789 90.001,0 0,0 -9.601L34.066,11.942A8.264,8.264 22.5,0 0,28.222 9.522H6.623A3.815,3.815 112.5,0 0,3.925 16.034Z"
|
||||||
|
android:strokeWidth="5"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
<path
|
||||||
|
android:pathData="m36.36,65.907v28.743a2.557,2.557 22.5,0 0,4.364 1.808L53.817,83.364a6.172,6.172 90,0 0,0 -8.729L42.532,63.35a3.616,3.616 157.5,0 0,-6.172 2.557z"
|
||||||
|
android:strokeWidth="5"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
<path
|
||||||
|
android:pathData="M79.653,40.078V11.335A2.557,2.557 22.5,0 0,75.289 9.527L62.195,22.62a6.172,6.172 90,0 0,0 8.729l11.285,11.285a3.616,3.616 157.5,0 0,6.172 -2.557z"
|
||||||
|
android:strokeWidth="5"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
<path
|
||||||
|
android:pathData="M96.613,16.867 L89.085,9.339a1.917,1.917 157.5,0 0,-3.273 1.356v6.172a4.629,4.629 45,0 0,4.629 4.629h4.255a2.712,2.712 112.5,0 0,1.917 -4.629z"
|
||||||
|
android:strokeWidth="5"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
|
@ -2,4 +2,5 @@
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_mono" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
|
@ -2,4 +2,5 @@
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_mono" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Hintergrundbild</string>
|
||||||
<string name="search_shortcut_short_label">Suche</string>
|
<string name="search_shortcut_short_label">Suche</string>
|
||||||
<string name="videos_shortcut_short_label">Videos</string>
|
<string name="videos_shortcut_short_label">Videos</string>
|
||||||
<string name="analysis_channel_name">Analyse von Medien</string>
|
<string name="analysis_channel_name">Analyse von Medien</string>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Fondo de pantalla</string>
|
||||||
<string name="search_shortcut_short_label">Búsqueda</string>
|
<string name="search_shortcut_short_label">Búsqueda</string>
|
||||||
<string name="videos_shortcut_short_label">Videos</string>
|
<string name="videos_shortcut_short_label">Videos</string>
|
||||||
<string name="analysis_channel_name">Explorar medios</string>
|
<string name="analysis_channel_name">Explorar medios</string>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Fond d’écran</string>
|
||||||
<string name="search_shortcut_short_label">Recherche</string>
|
<string name="search_shortcut_short_label">Recherche</string>
|
||||||
<string name="videos_shortcut_short_label">Vidéos</string>
|
<string name="videos_shortcut_short_label">Vidéos</string>
|
||||||
<string name="analysis_channel_name">Analyse des images</string>
|
<string name="analysis_channel_name">Analyse des images</string>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Wallpaper</string>
|
||||||
<string name="search_shortcut_short_label">Cari</string>
|
<string name="search_shortcut_short_label">Cari</string>
|
||||||
<string name="videos_shortcut_short_label">Video</string>
|
<string name="videos_shortcut_short_label">Video</string>
|
||||||
<string name="analysis_channel_name">Pindai media</string>
|
<string name="analysis_channel_name">Pindai media</string>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Sfondo</string>
|
||||||
<string name="search_shortcut_short_label">Ricerca</string>
|
<string name="search_shortcut_short_label">Ricerca</string>
|
||||||
<string name="videos_shortcut_short_label">Video</string>
|
<string name="videos_shortcut_short_label">Video</string>
|
||||||
<string name="analysis_channel_name">Scansione media</string>
|
<string name="analysis_channel_name">Scansione media</string>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
<string name="search_shortcut_short_label">検索</string>
|
<string name="wallpaper">壁紙</string>
|
||||||
<string name="videos_shortcut_short_label">動画</string>
|
<string name="search_shortcut_short_label">検索</string>
|
||||||
<string name="analysis_channel_name">メディアスキャン</string>
|
<string name="videos_shortcut_short_label">動画</string>
|
||||||
<string name="analysis_service_description">画像と動画をスキャン</string>
|
<string name="analysis_channel_name">メディアスキャン</string>
|
||||||
<string name="analysis_notification_default_title">メディアをスキャン中</string>
|
<string name="analysis_service_description">画像と動画をスキャン</string>
|
||||||
<string name="analysis_notification_action_stop">停止</string>
|
<string name="analysis_notification_default_title">メディアをスキャン中</string>
|
||||||
|
<string name="analysis_notification_action_stop">停止</string>
|
||||||
</resources>
|
</resources>
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">아베스</string>
|
<string name="app_name">아베스</string>
|
||||||
|
<string name="wallpaper">배경화면</string>
|
||||||
<string name="search_shortcut_short_label">검색</string>
|
<string name="search_shortcut_short_label">검색</string>
|
||||||
<string name="videos_shortcut_short_label">동영상</string>
|
<string name="videos_shortcut_short_label">동영상</string>
|
||||||
<string name="analysis_channel_name">미디어 분석</string>
|
<string name="analysis_channel_name">미디어 분석</string>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Papel de parede</string>
|
||||||
<string name="search_shortcut_short_label">Procurar</string>
|
<string name="search_shortcut_short_label">Procurar</string>
|
||||||
<string name="videos_shortcut_short_label">Vídeos</string>
|
<string name="videos_shortcut_short_label">Vídeos</string>
|
||||||
<string name="analysis_channel_name">Digitalização de mídia</string>
|
<string name="analysis_channel_name">Digitalização de mídia</string>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Обои</string>
|
||||||
<string name="search_shortcut_short_label">Поиск</string>
|
<string name="search_shortcut_short_label">Поиск</string>
|
||||||
<string name="videos_shortcut_short_label">Видео</string>
|
<string name="videos_shortcut_short_label">Видео</string>
|
||||||
<string name="analysis_channel_name">Сканировать медия</string>
|
<string name="analysis_channel_name">Сканировать медия</string>
|
||||||
|
|
11
android/app/src/main/res/values-tr/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Duvar kağıdı</string>
|
||||||
|
<string name="search_shortcut_short_label">Arama</string>
|
||||||
|
<string name="videos_shortcut_short_label">Videolar</string>
|
||||||
|
<string name="analysis_channel_name">Medya tarama</string>
|
||||||
|
<string name="analysis_service_description">Görüntüleri ve videoları tarayın</string>
|
||||||
|
<string name="analysis_notification_default_title">Medya taranıyor</string>
|
||||||
|
<string name="analysis_notification_action_stop">Durdur</string>
|
||||||
|
</resources>
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">壁纸</string>
|
||||||
<string name="search_shortcut_short_label">搜索</string>
|
<string name="search_shortcut_short_label">搜索</string>
|
||||||
<string name="videos_shortcut_short_label">视频</string>
|
<string name="videos_shortcut_short_label">视频</string>
|
||||||
<string name="analysis_channel_name">媒体扫描</string>
|
<string name="analysis_channel_name">媒体扫描</string>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
|
<string name="wallpaper">Wallpaper</string>
|
||||||
<string name="search_shortcut_short_label">Search</string>
|
<string name="search_shortcut_short_label">Search</string>
|
||||||
<string name="videos_shortcut_short_label">Videos</string>
|
<string name="videos_shortcut_short_label">Videos</string>
|
||||||
<string name="analysis_channel_name">Media scan</string>
|
<string name="analysis_channel_name">Media scan</string>
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.6.21'
|
ext.kotlin_version = '1.7.0'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url 'https://developer.huawei.com/repo/' }
|
maven { url 'https://developer.huawei.com/repo/' }
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
// GMS & Firebase Crashlytics (used by some flavors only)
|
// GMS & Firebase Crashlytics (used by some flavors only)
|
||||||
classpath 'com.google.gms:google-services:4.3.10'
|
classpath 'com.google.gms:google-services:4.3.10'
|
||||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0'
|
||||||
// HMS (used by some flavors only)
|
// HMS (used by some flavors only)
|
||||||
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
|
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
<b>Navigation und Suche</b> ist ein wichtiger Bestandteil von <i>Aves</i>. Das Ziel besteht darin, dass Benutzer problemlos von Alben zu Fotos zu Tags zu Karten usw. wechseln können.
|
<b>Navigation und Suche</b> ist ein wichtiger Bestandteil von <i>Aves</i>. Das Ziel besteht darin, dass Benutzer problemlos von Alben zu Fotos zu Tags zu Karten usw. wechseln können.
|
||||||
|
|
||||||
<i>Aves</i> lässt sich mit Android (von <b>API 19 bis 32</b>, d. h. von KitKat bis Android 12L) mit Funktionen wie <b>App-Verknüpfungen</b> und <b>globaler Suche</b> integrieren. Es funktioniert auch als <b>Medienbetrachter und -auswahl</b>.
|
<i>Aves</i> lässt sich mit Android (von <b>API 19 bis 33</b>, d. h. von KitKat bis Android 13) mit Funktionen wie <b>App-Verknüpfungen</b> und <b>globaler Suche</b> integrieren. Es funktioniert auch als <b>Medienbetrachter und -auswahl</b>.
|
5
fastlane/metadata/android/en-US/changelogs/1075.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
In v1.6.9:
|
||||||
|
- start slideshows
|
||||||
|
- change your wallpaper
|
||||||
|
- enjoy the app in Turkish
|
||||||
|
Full changelog available on GitHub
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
<b>Navigation and search</b> is an important part of <i>Aves</i>. The goal is for users to easily flow from albums to photos to tags to maps, etc.
|
<b>Navigation and search</b> is an important part of <i>Aves</i>. The goal is for users to easily flow from albums to photos to tags to maps, etc.
|
||||||
|
|
||||||
<i>Aves</i> integrates with Android (from <b>API 19 to 32</b>, i.e. from KitKat to Android 12L) with features such as <b>app shortcuts</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.
|
<i>Aves</i> integrates with Android (from <b>API 19 to 33</b>, i.e. from KitKat to Android 13) with features such as <b>app shortcuts</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
La <b>navegación y búsqueda</b> son partes importantes de <i>Aves</i>. Su propósito es que los usuarios puedan fácimente ir de álbumes a fotos, etiquetas, mapas, etc.
|
La <b>navegación y búsqueda</b> son partes importantes de <i>Aves</i>. Su propósito es que los usuarios puedan fácimente ir de álbumes a fotos, etiquetas, mapas, etc.
|
||||||
|
|
||||||
<i>Aves</i> se integra con Android (desde <b>API 19 a 32</b>, por ej. desde KitKat hasta Android 12L) con características como <b>vínculos de aplicación</b> y manejo de <b>búsqueda global</b>. También funciona como un <b>visor y seleccionador multimedia</b>.
|
<i>Aves</i> se integra con Android (desde <b>API 19 a 33</b>, por ej. desde KitKat hasta Android 13) con características como <b>vínculos de aplicación</b> y manejo de <b>búsqueda global</b>. También funciona como un <b>visor y seleccionador multimedia</b>.
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
<b>Navigasi dan pencarian</b> merupakan bagian penting dari <i>Aves</i>. Tujuannya adalah agar pengguna dengan mudah mengalir dari album ke foto ke tag ke peta, dll.
|
<b>Navigasi dan pencarian</b> merupakan bagian penting dari <i>Aves</i>. Tujuannya adalah agar pengguna dengan mudah mengalir dari album ke foto ke tag ke peta, dll.
|
||||||
|
|
||||||
<i>Aves</i> terintegrasi dengan Android (dari <b>API 19 ke 32</b>, yaitu dari KitKat ke Android 12L) dengan fitur-fitur seperti <b>pintasan aplikasi</b> dan <b>pencarian global</b> penanganan. Ini juga berfungsi sebagai <b>penampil dan pemilih media</b>.
|
<i>Aves</i> terintegrasi dengan Android (dari <b>API 19 ke 33</b>, yaitu dari KitKat ke Android 13) dengan fitur-fitur seperti <b>pintasan aplikasi</b> dan <b>pencarian global</b> penanganan. Ini juga berfungsi sebagai <b>penampil dan pemilih media</b>.
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
<b>Navigazione e ricerca</b> sono una parte importante di <i>Aves</i>. L'obiettivo è che gli utenti passino facilmente dagli album alle foto, ai tag, alle mappe, ecc.
|
<b>Navigazione e ricerca</b> sono una parte importante di <i>Aves</i>. L'obiettivo è che gli utenti passino facilmente dagli album alle foto, ai tag, alle mappe, ecc.
|
||||||
|
|
||||||
<i>Aves</i> si integra con Android (da <b>API 19 a 32</b>, cioè da KitKat ad Android 12L) con caratteristiche come <b>collegamenti alle app</b> e la gestione della <b>ricerca globale</b>. Funziona anche come <b>visualizzazione e raccolta di media</b>.
|
<i>Aves</i> si integra con Android (da <b>API 19 a 33</b>, cioè da KitKat ad Android 13) con caratteristiche come <b>collegamenti alle app</b> e la gestione della <b>ricerca globale</b>. Funziona anche come <b>visualizzazione e raccolta di media</b>.
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
|
|
||||||
<b>ナビゲーションと検索</b>は、Avesの重要な部分です。アルバムから写真、タグ、地図などへ簡単に移動できます。
|
<b>ナビゲーションと検索</b>は、Avesの重要な部分です。アルバムから写真、タグ、地図などへ簡単に移動できます。
|
||||||
|
|
||||||
<i>Aves</i>は、<b>アプリショートカット</b>や<b>グローバル検索</b>などの機能を、Android(<b>API 19から32まで</b>、つまりAndroid 4.4から12 Lまで)と統合しています。また、<b>メディアビューワー</b>や<b>メディアピッカー</b>としても機能します。
|
<i>Aves</i>は、<b>アプリショートカット</b>や<b>グローバル検索</b>などの機能を、Android(<b>API 19から33まで</b>、つまりAndroid 4.4から13 Lまで)と統合しています。また、<b>メディアビューワー</b>や<b>メディアピッカー</b>としても機能します。
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
<b>Navegação e pesquisa</b> é uma parte importante do <i>Aves</i>. O objetivo é que os usuários fluam facilmente de álbuns para fotos, etiquetas, mapas, etc.
|
<b>Navegação e pesquisa</b> é uma parte importante do <i>Aves</i>. O objetivo é que os usuários fluam facilmente de álbuns para fotos, etiquetas, mapas, etc.
|
||||||
|
|
||||||
<i>Aves</i> integra com Android (de <b>API 19 para 32</b>, i.e. de KitKat para Android 12L) com recursos como <b>atalhos de apps</b> e <b>pesquisa global</b> manipulação. Também funciona como um <b>visualizador e selecionador de mídia</b>.
|
<i>Aves</i> integra com Android (de <b>API 19 para 33</b>, i.e. de KitKat para Android 13) com recursos como <b>atalhos de apps</b> e <b>pesquisa global</b> manipulação. Também funciona como um <b>visualizador e selecionador de mídia</b>.
|
||||||
|
|
5
fastlane/metadata/android/tr/full_description.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<i>Aves</i> tipik JPEG ve MP4'lerin yanı sıra <b>çok sayfalı TIFF'ler, SVG'ler, eski AVI'ler ve daha fazlası</b> gibi daha egzotik şeyler de dahil olmak üzere her türlü görüntü ve videoyu işleyebilir! <b>Hareketli fotoğrafları</b>, <b>panoramaları</b> (fotoğraf küreleri olarak da bilinir), <b>360° videoları</b> ve <b>GeoTIFF</b> dosyalarını tanımlamak için medya koleksiyonunuzu tarar.
|
||||||
|
|
||||||
|
<b>Gezinme ve arama</b> <i>Aves'in</i> önemli bir parçasıdır. Amaç, kullanıcıların albümlerden fotoğraflara, etiketlerden haritalara vb. kolayca geçmesini sağlamaktır.
|
||||||
|
|
||||||
|
<i>Aves</i>, <b>uygulama kısayolları</b> ve <b>global arama<b> işleme gibi özelliklerle Android (<b>API 19'dan 33'ye</b>, yani KitKat'tan Android 13'ye kadar) ile entegre olur. Ayrıca bir <b>medya görüntüleyici ve alıcı</b> olarak da çalışır.
|
BIN
fastlane/metadata/android/tr/images/featureGraphic.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
fastlane/metadata/android/tr/images/phoneScreenshots/1.png
Normal file
After Width: | Height: | Size: 245 KiB |
BIN
fastlane/metadata/android/tr/images/phoneScreenshots/2.png
Normal file
After Width: | Height: | Size: 494 KiB |
BIN
fastlane/metadata/android/tr/images/phoneScreenshots/3.png
Normal file
After Width: | Height: | Size: 208 KiB |
BIN
fastlane/metadata/android/tr/images/phoneScreenshots/4.png
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
fastlane/metadata/android/tr/images/phoneScreenshots/5.png
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
fastlane/metadata/android/tr/images/phoneScreenshots/6.png
Normal file
After Width: | Height: | Size: 338 KiB |
1
fastlane/metadata/android/tr/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Galeri ve meta veri gezgini
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
<b>导航与搜索</b>是 <i>Aves</i> 的核心功能之一,旨在帮助用户在相册、照片、标签、地图等之间轻松切换。
|
<b>导航与搜索</b>是 <i>Aves</i> 的核心功能之一,旨在帮助用户在相册、照片、标签、地图等之间轻松切换。
|
||||||
|
|
||||||
<i> Aves</i> 与 Android(<b>API 19-32</b>,即从 KitKat 到 Android 12L)集成,具有<b>快捷方式</b>和<b>全局搜索</b>等功能。它还可用作<b>媒体查看器和选择器<b>。
|
<i> Aves</i> 与 Android(<b>API 19-33</b>,即从 KitKat 到 Android 13)集成,具有<b>快捷方式</b>和<b>全局搜索</b>等功能。它还可用作<b>媒体查看器和选择器<b>。
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
enum AppMode { main, pickSingleMediaExternal, pickMultipleMediaExternal, pickMediaInternal, pickFilterInternal, view }
|
enum AppMode {
|
||||||
|
main,
|
||||||
|
pickSingleMediaExternal,
|
||||||
|
pickMultipleMediaExternal,
|
||||||
|
pickMediaInternal,
|
||||||
|
pickFilterInternal,
|
||||||
|
setWallpaper,
|
||||||
|
slideshow,
|
||||||
|
view,
|
||||||
|
}
|
||||||
|
|
||||||
extension ExtraAppMode on AppMode {
|
extension ExtraAppMode on AppMode {
|
||||||
bool get canSearch => this == AppMode.main || this == AppMode.pickSingleMediaExternal || this == AppMode.pickMultipleMediaExternal;
|
bool get canSearch => this == AppMode.main || this == AppMode.pickSingleMediaExternal || this == AppMode.pickMultipleMediaExternal;
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "Löschen",
|
"entryActionDelete": "Löschen",
|
||||||
"entryActionConvert": "Konvertieren",
|
"entryActionConvert": "Konvertieren",
|
||||||
"entryActionExport": "Exportieren",
|
"entryActionExport": "Exportieren",
|
||||||
|
"entryActionInfo": "Info",
|
||||||
"entryActionRename": "Umbenennen",
|
"entryActionRename": "Umbenennen",
|
||||||
"entryActionRestore": "Wiederherstellen",
|
"entryActionRestore": "Wiederherstellen",
|
||||||
"entryActionRotateCCW": "Drehen gegen den Uhrzeigersinn",
|
"entryActionRotateCCW": "Drehen gegen den Uhrzeigersinn",
|
||||||
|
@ -80,6 +81,9 @@
|
||||||
"videoActionSetSpeed": "Wiedergabegeschwindigkeit",
|
"videoActionSetSpeed": "Wiedergabegeschwindigkeit",
|
||||||
"videoActionSettings": "Einstellungen",
|
"videoActionSettings": "Einstellungen",
|
||||||
|
|
||||||
|
"slideshowActionResume": "Wiedergabe",
|
||||||
|
"slideshowActionShowInCollection": "In Sammlung anzeigen",
|
||||||
|
|
||||||
"entryInfoActionEditDate": "Datum & Uhrzeit bearbeiten",
|
"entryInfoActionEditDate": "Datum & Uhrzeit bearbeiten",
|
||||||
"entryInfoActionEditLocation": "Standort bearbeiten",
|
"entryInfoActionEditLocation": "Standort bearbeiten",
|
||||||
"entryInfoActionEditRating": "Bewertung bearbeiten",
|
"entryInfoActionEditRating": "Bewertung bearbeiten",
|
||||||
|
@ -144,10 +148,23 @@
|
||||||
"displayRefreshRatePreferHighest": "Höchste Rate",
|
"displayRefreshRatePreferHighest": "Höchste Rate",
|
||||||
"displayRefreshRatePreferLowest": "Niedrigste Rate",
|
"displayRefreshRatePreferLowest": "Niedrigste Rate",
|
||||||
|
|
||||||
|
"slideshowVideoPlaybackSkip": "Überspringen",
|
||||||
|
"slideshowVideoPlaybackMuted": "Stumm abspielen",
|
||||||
|
"slideshowVideoPlaybackWithSound": "Mit Ton abspielen",
|
||||||
|
|
||||||
"themeBrightnessLight": "Hell",
|
"themeBrightnessLight": "Hell",
|
||||||
"themeBrightnessDark": "Dunkel",
|
"themeBrightnessDark": "Dunkel",
|
||||||
"themeBrightnessBlack": "Schwarz",
|
"themeBrightnessBlack": "Schwarz",
|
||||||
|
|
||||||
|
"viewerTransitionSlide": "Dia",
|
||||||
|
"viewerTransitionParallax": "Parallaxe",
|
||||||
|
"viewerTransitionFade": "Ausblenden",
|
||||||
|
"viewerTransitionZoomIn": "Heranzoomen",
|
||||||
|
|
||||||
|
"wallpaperTargetHome": "Startbildschirm",
|
||||||
|
"wallpaperTargetLock": "Sperrbildschirm",
|
||||||
|
"wallpaperTargetHomeLock": "Start- und Sperrbildschirm",
|
||||||
|
|
||||||
"albumTierNew": "Neu",
|
"albumTierNew": "Neu",
|
||||||
"albumTierPinned": "Angeheftet",
|
"albumTierPinned": "Angeheftet",
|
||||||
"albumTierSpecial": "Häufig verwendet",
|
"albumTierSpecial": "Häufig verwendet",
|
||||||
|
@ -262,6 +279,7 @@
|
||||||
"menuActionSelectAll": "Alle auswählen",
|
"menuActionSelectAll": "Alle auswählen",
|
||||||
"menuActionSelectNone": "Keine auswählen",
|
"menuActionSelectNone": "Keine auswählen",
|
||||||
"menuActionMap": "Karte",
|
"menuActionMap": "Karte",
|
||||||
|
"menuActionSlideshow": "Diashow",
|
||||||
"menuActionStats": "Statistiken",
|
"menuActionStats": "Statistiken",
|
||||||
|
|
||||||
"viewDialogTabSort": "Sortieren",
|
"viewDialogTabSort": "Sortieren",
|
||||||
|
@ -349,6 +367,7 @@
|
||||||
"collectionEmptyFavourites": "Keine Favoriten",
|
"collectionEmptyFavourites": "Keine Favoriten",
|
||||||
"collectionEmptyVideos": "Keine Videos",
|
"collectionEmptyVideos": "Keine Videos",
|
||||||
"collectionEmptyImages": "Keine Bilder",
|
"collectionEmptyImages": "Keine Bilder",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "Zugriff gewähren",
|
||||||
|
|
||||||
"collectionSelectSectionTooltip": "Bereich auswählen",
|
"collectionSelectSectionTooltip": "Bereich auswählen",
|
||||||
"collectionDeselectSectionTooltip": "Bereich abwählen",
|
"collectionDeselectSectionTooltip": "Bereich abwählen",
|
||||||
|
@ -479,6 +498,17 @@
|
||||||
"settingsViewerShowOverlayThumbnails": "Vorschaubilder anzeigen",
|
"settingsViewerShowOverlayThumbnails": "Vorschaubilder anzeigen",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Unschärfe-Effekt",
|
"settingsViewerEnableOverlayBlurEffect": "Unschärfe-Effekt",
|
||||||
|
|
||||||
|
"settingsViewerSlideshowTile": "Diashow",
|
||||||
|
"settingsViewerSlideshowTitle": "Diashow",
|
||||||
|
"settingsSlideshowRepeat": "Wiederholung",
|
||||||
|
"settingsSlideshowShuffle": "Mischen",
|
||||||
|
"settingsSlideshowTransitionTile": "Übergang",
|
||||||
|
"settingsSlideshowTransitionTitle": "Übergang",
|
||||||
|
"settingsSlideshowIntervalTile": "Intervall",
|
||||||
|
"settingsSlideshowIntervalTitle": "Intervall",
|
||||||
|
"settingsSlideshowVideoPlaybackTile": "Videowiedergabe",
|
||||||
|
"settingsSlideshowVideoPlaybackTitle": "Videowiedergabe",
|
||||||
|
|
||||||
"settingsVideoPageTitle": "Video-Einstellungen",
|
"settingsVideoPageTitle": "Video-Einstellungen",
|
||||||
"settingsSectionVideo": "Video",
|
"settingsSectionVideo": "Video",
|
||||||
"settingsVideoShowVideos": "Videos anzeigen",
|
"settingsVideoShowVideos": "Videos anzeigen",
|
||||||
|
@ -543,6 +573,7 @@
|
||||||
"settingsSectionDisplay": "Anzeige",
|
"settingsSectionDisplay": "Anzeige",
|
||||||
"settingsThemeBrightness": "Thema",
|
"settingsThemeBrightness": "Thema",
|
||||||
"settingsThemeColorHighlights": "Farbige Highlights",
|
"settingsThemeColorHighlights": "Farbige Highlights",
|
||||||
|
"settingsThemeEnableDynamicColor": "Dynamische Farben",
|
||||||
"settingsDisplayRefreshRateModeTile": "Bildwiederholrate der Anzeige",
|
"settingsDisplayRefreshRateModeTile": "Bildwiederholrate der Anzeige",
|
||||||
"settingsDisplayRefreshRateModeTitle": "Bildwiederholrate",
|
"settingsDisplayRefreshRateModeTitle": "Bildwiederholrate",
|
||||||
|
|
||||||
|
@ -560,6 +591,7 @@
|
||||||
"statsTopTags": "Top-Tags",
|
"statsTopTags": "Top-Tags",
|
||||||
|
|
||||||
"viewerOpenPanoramaButtonLabel": "ÖFFNE PANORAMA",
|
"viewerOpenPanoramaButtonLabel": "ÖFFNE PANORAMA",
|
||||||
|
"viewerSetWallpaperButtonLabel": "HINTERGRUNDBILD EINSTELLEN",
|
||||||
"viewerErrorUnknown": "Ups!",
|
"viewerErrorUnknown": "Ups!",
|
||||||
"viewerErrorDoesNotExist": "Die Datei existiert nicht mehr.",
|
"viewerErrorDoesNotExist": "Die Datei existiert nicht mehr.",
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
"entryActionDelete": "Delete",
|
"entryActionDelete": "Delete",
|
||||||
"entryActionConvert": "Convert",
|
"entryActionConvert": "Convert",
|
||||||
"entryActionExport": "Export",
|
"entryActionExport": "Export",
|
||||||
|
"entryActionInfo": "Info",
|
||||||
"entryActionRename": "Rename",
|
"entryActionRename": "Rename",
|
||||||
"entryActionRestore": "Restore",
|
"entryActionRestore": "Restore",
|
||||||
"entryActionRotateCCW": "Rotate counterclockwise",
|
"entryActionRotateCCW": "Rotate counterclockwise",
|
||||||
|
@ -108,6 +109,9 @@
|
||||||
"videoActionSetSpeed": "Playback speed",
|
"videoActionSetSpeed": "Playback speed",
|
||||||
"videoActionSettings": "Settings",
|
"videoActionSettings": "Settings",
|
||||||
|
|
||||||
|
"slideshowActionResume": "Resume",
|
||||||
|
"slideshowActionShowInCollection": "Show in Collection",
|
||||||
|
|
||||||
"entryInfoActionEditDate": "Edit date & time",
|
"entryInfoActionEditDate": "Edit date & time",
|
||||||
"entryInfoActionEditLocation": "Edit location",
|
"entryInfoActionEditLocation": "Edit location",
|
||||||
"entryInfoActionEditRating": "Edit rating",
|
"entryInfoActionEditRating": "Edit rating",
|
||||||
|
@ -184,10 +188,23 @@
|
||||||
"displayRefreshRatePreferHighest": "Highest rate",
|
"displayRefreshRatePreferHighest": "Highest rate",
|
||||||
"displayRefreshRatePreferLowest": "Lowest rate",
|
"displayRefreshRatePreferLowest": "Lowest rate",
|
||||||
|
|
||||||
|
"slideshowVideoPlaybackSkip": "Skip",
|
||||||
|
"slideshowVideoPlaybackMuted": "Play muted",
|
||||||
|
"slideshowVideoPlaybackWithSound": "Play with sound",
|
||||||
|
|
||||||
"themeBrightnessLight": "Light",
|
"themeBrightnessLight": "Light",
|
||||||
"themeBrightnessDark": "Dark",
|
"themeBrightnessDark": "Dark",
|
||||||
"themeBrightnessBlack": "Black",
|
"themeBrightnessBlack": "Black",
|
||||||
|
|
||||||
|
"viewerTransitionSlide": "Slide",
|
||||||
|
"viewerTransitionParallax": "Parallax",
|
||||||
|
"viewerTransitionFade": "Fade",
|
||||||
|
"viewerTransitionZoomIn": "Zoom in",
|
||||||
|
|
||||||
|
"wallpaperTargetHome": "Home screen",
|
||||||
|
"wallpaperTargetLock": "Lock screen",
|
||||||
|
"wallpaperTargetHomeLock": "Home and lock screens",
|
||||||
|
|
||||||
"albumTierNew": "New",
|
"albumTierNew": "New",
|
||||||
"albumTierPinned": "Pinned",
|
"albumTierPinned": "Pinned",
|
||||||
"albumTierSpecial": "Common",
|
"albumTierSpecial": "Common",
|
||||||
|
@ -392,6 +409,7 @@
|
||||||
"menuActionSelectAll": "Select all",
|
"menuActionSelectAll": "Select all",
|
||||||
"menuActionSelectNone": "Select none",
|
"menuActionSelectNone": "Select none",
|
||||||
"menuActionMap": "Map",
|
"menuActionMap": "Map",
|
||||||
|
"menuActionSlideshow": "Slideshow",
|
||||||
"menuActionStats": "Stats",
|
"menuActionStats": "Stats",
|
||||||
|
|
||||||
"viewDialogTabSort": "Sort",
|
"viewDialogTabSort": "Sort",
|
||||||
|
@ -529,6 +547,7 @@
|
||||||
"collectionEmptyFavourites": "No favorites",
|
"collectionEmptyFavourites": "No favorites",
|
||||||
"collectionEmptyVideos": "No videos",
|
"collectionEmptyVideos": "No videos",
|
||||||
"collectionEmptyImages": "No images",
|
"collectionEmptyImages": "No images",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "Grant access",
|
||||||
|
|
||||||
"collectionSelectSectionTooltip": "Select section",
|
"collectionSelectSectionTooltip": "Select section",
|
||||||
"collectionDeselectSectionTooltip": "Deselect section",
|
"collectionDeselectSectionTooltip": "Deselect section",
|
||||||
|
@ -659,6 +678,17 @@
|
||||||
"settingsViewerShowOverlayThumbnails": "Show thumbnails",
|
"settingsViewerShowOverlayThumbnails": "Show thumbnails",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Blur effect",
|
"settingsViewerEnableOverlayBlurEffect": "Blur effect",
|
||||||
|
|
||||||
|
"settingsViewerSlideshowTile": "Slideshow",
|
||||||
|
"settingsViewerSlideshowTitle": "Slideshow",
|
||||||
|
"settingsSlideshowRepeat": "Repeat",
|
||||||
|
"settingsSlideshowShuffle": "Shuffle",
|
||||||
|
"settingsSlideshowTransitionTile": "Transition",
|
||||||
|
"settingsSlideshowTransitionTitle": "Transition",
|
||||||
|
"settingsSlideshowIntervalTile": "Interval",
|
||||||
|
"settingsSlideshowIntervalTitle": "Interval",
|
||||||
|
"settingsSlideshowVideoPlaybackTile": "Video playback",
|
||||||
|
"settingsSlideshowVideoPlaybackTitle": "Video Playback",
|
||||||
|
|
||||||
"settingsVideoPageTitle": "Video Settings",
|
"settingsVideoPageTitle": "Video Settings",
|
||||||
"settingsSectionVideo": "Video",
|
"settingsSectionVideo": "Video",
|
||||||
"settingsVideoShowVideos": "Show videos",
|
"settingsVideoShowVideos": "Show videos",
|
||||||
|
@ -723,6 +753,7 @@
|
||||||
"settingsSectionDisplay": "Display",
|
"settingsSectionDisplay": "Display",
|
||||||
"settingsThemeBrightness": "Theme",
|
"settingsThemeBrightness": "Theme",
|
||||||
"settingsThemeColorHighlights": "Color highlights",
|
"settingsThemeColorHighlights": "Color highlights",
|
||||||
|
"settingsThemeEnableDynamicColor": "Dynamic color",
|
||||||
"settingsDisplayRefreshRateModeTile": "Display refresh rate",
|
"settingsDisplayRefreshRateModeTile": "Display refresh rate",
|
||||||
"settingsDisplayRefreshRateModeTitle": "Refresh Rate",
|
"settingsDisplayRefreshRateModeTitle": "Refresh Rate",
|
||||||
|
|
||||||
|
@ -745,6 +776,7 @@
|
||||||
"statsTopTags": "Top Tags",
|
"statsTopTags": "Top Tags",
|
||||||
|
|
||||||
"viewerOpenPanoramaButtonLabel": "OPEN PANORAMA",
|
"viewerOpenPanoramaButtonLabel": "OPEN PANORAMA",
|
||||||
|
"viewerSetWallpaperButtonLabel": "SET WALLPAPER",
|
||||||
"viewerErrorUnknown": "Oops!",
|
"viewerErrorUnknown": "Oops!",
|
||||||
"viewerErrorDoesNotExist": "The file no longer exists.",
|
"viewerErrorDoesNotExist": "The file no longer exists.",
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "Borrar",
|
"entryActionDelete": "Borrar",
|
||||||
"entryActionConvert": "Convertir",
|
"entryActionConvert": "Convertir",
|
||||||
"entryActionExport": "Exportar",
|
"entryActionExport": "Exportar",
|
||||||
|
"entryActionInfo": "Información",
|
||||||
"entryActionRename": "Renombrar",
|
"entryActionRename": "Renombrar",
|
||||||
"entryActionRestore": "Restaurar",
|
"entryActionRestore": "Restaurar",
|
||||||
"entryActionRotateCCW": "Rotar en sentido antihorario",
|
"entryActionRotateCCW": "Rotar en sentido antihorario",
|
||||||
|
@ -80,6 +81,9 @@
|
||||||
"videoActionSetSpeed": "Velocidad de reproducción",
|
"videoActionSetSpeed": "Velocidad de reproducción",
|
||||||
"videoActionSettings": "Ajustes",
|
"videoActionSettings": "Ajustes",
|
||||||
|
|
||||||
|
"slideshowActionResume": "Reanudar",
|
||||||
|
"slideshowActionShowInCollection": "Mostrar en Colección",
|
||||||
|
|
||||||
"entryInfoActionEditDate": "Editar fecha y hora",
|
"entryInfoActionEditDate": "Editar fecha y hora",
|
||||||
"entryInfoActionEditLocation": "Editar ubicación",
|
"entryInfoActionEditLocation": "Editar ubicación",
|
||||||
"entryInfoActionEditRating": "Editar clasificación",
|
"entryInfoActionEditRating": "Editar clasificación",
|
||||||
|
@ -144,10 +148,23 @@
|
||||||
"displayRefreshRatePreferHighest": "Alta tasa",
|
"displayRefreshRatePreferHighest": "Alta tasa",
|
||||||
"displayRefreshRatePreferLowest": "Baja tasa",
|
"displayRefreshRatePreferLowest": "Baja tasa",
|
||||||
|
|
||||||
|
"slideshowVideoPlaybackSkip": "Saltear",
|
||||||
|
"slideshowVideoPlaybackMuted": "Reproducir sin sonido",
|
||||||
|
"slideshowVideoPlaybackWithSound": "Reproducir con sonido",
|
||||||
|
|
||||||
"themeBrightnessLight": "Claro",
|
"themeBrightnessLight": "Claro",
|
||||||
"themeBrightnessDark": "Obscuro",
|
"themeBrightnessDark": "Obscuro",
|
||||||
"themeBrightnessBlack": "Negro",
|
"themeBrightnessBlack": "Negro",
|
||||||
|
|
||||||
|
"viewerTransitionSlide": "Diapositiva",
|
||||||
|
"viewerTransitionParallax": "Paralaje",
|
||||||
|
"viewerTransitionFade": "Desvanecer",
|
||||||
|
"viewerTransitionZoomIn": "Acercar",
|
||||||
|
|
||||||
|
"wallpaperTargetHome": "Pantalla de inicio",
|
||||||
|
"wallpaperTargetLock": "Pantalla de bloqueo",
|
||||||
|
"wallpaperTargetHomeLock": "Pantallas de inicio y bloqueo",
|
||||||
|
|
||||||
"albumTierNew": "Nuevo",
|
"albumTierNew": "Nuevo",
|
||||||
"albumTierPinned": "Fijado",
|
"albumTierPinned": "Fijado",
|
||||||
"albumTierSpecial": "Común",
|
"albumTierSpecial": "Común",
|
||||||
|
@ -262,6 +279,7 @@
|
||||||
"menuActionSelectAll": "Seleccionar todo",
|
"menuActionSelectAll": "Seleccionar todo",
|
||||||
"menuActionSelectNone": "Deseleccionar",
|
"menuActionSelectNone": "Deseleccionar",
|
||||||
"menuActionMap": "Mapa",
|
"menuActionMap": "Mapa",
|
||||||
|
"menuActionSlideshow": "Presentación",
|
||||||
"menuActionStats": "Estadísticas",
|
"menuActionStats": "Estadísticas",
|
||||||
|
|
||||||
"viewDialogTabSort": "Ordenar",
|
"viewDialogTabSort": "Ordenar",
|
||||||
|
@ -278,7 +296,6 @@
|
||||||
"appPickDialogTitle": "Escoger aplicación",
|
"appPickDialogTitle": "Escoger aplicación",
|
||||||
"appPickDialogNone": "Ninguna",
|
"appPickDialogNone": "Ninguna",
|
||||||
|
|
||||||
|
|
||||||
"aboutPageTitle": "Acerca de",
|
"aboutPageTitle": "Acerca de",
|
||||||
"aboutLinkSources": "Fuentes",
|
"aboutLinkSources": "Fuentes",
|
||||||
"aboutLinkLicense": "Licencia",
|
"aboutLinkLicense": "Licencia",
|
||||||
|
@ -296,7 +313,6 @@
|
||||||
"aboutCreditsWorldAtlas1": "Esta aplicación usa un archivo TopoJSON de",
|
"aboutCreditsWorldAtlas1": "Esta aplicación usa un archivo TopoJSON de",
|
||||||
"aboutCreditsWorldAtlas2": "bajo licencia ISC.",
|
"aboutCreditsWorldAtlas2": "bajo licencia ISC.",
|
||||||
"aboutCreditsTranslators": "Traductores:",
|
"aboutCreditsTranslators": "Traductores:",
|
||||||
"aboutCreditsTranslatorLine": "{language}: {names}",
|
|
||||||
|
|
||||||
"aboutLicenses": "Licencias de código abierto",
|
"aboutLicenses": "Licencias de código abierto",
|
||||||
"aboutLicensesBanner": "Esta aplicación usa los siguientes paquetes y librerías de código abierto.",
|
"aboutLicensesBanner": "Esta aplicación usa los siguientes paquetes y librerías de código abierto.",
|
||||||
|
@ -351,6 +367,7 @@
|
||||||
"collectionEmptyFavourites": "Sin favoritos",
|
"collectionEmptyFavourites": "Sin favoritos",
|
||||||
"collectionEmptyVideos": "Sin videos",
|
"collectionEmptyVideos": "Sin videos",
|
||||||
"collectionEmptyImages": "Sin imágenes",
|
"collectionEmptyImages": "Sin imágenes",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "Otorgar accceso",
|
||||||
|
|
||||||
"collectionSelectSectionTooltip": "Seleccionar sección",
|
"collectionSelectSectionTooltip": "Seleccionar sección",
|
||||||
"collectionDeselectSectionTooltip": "Deseleccionar sección",
|
"collectionDeselectSectionTooltip": "Deseleccionar sección",
|
||||||
|
@ -421,6 +438,7 @@
|
||||||
|
|
||||||
"settingsSectionNavigation": "Navegación",
|
"settingsSectionNavigation": "Navegación",
|
||||||
"settingsHome": "Inicio",
|
"settingsHome": "Inicio",
|
||||||
|
"settingsShowBottomNavigationBar": "Mostrar barra de navegación inferior",
|
||||||
"settingsKeepScreenOnTile": "Mantener pantalla encendida",
|
"settingsKeepScreenOnTile": "Mantener pantalla encendida",
|
||||||
"settingsKeepScreenOnTitle": "Mantener pantalla encendida",
|
"settingsKeepScreenOnTitle": "Mantener pantalla encendida",
|
||||||
"settingsDoubleBackExit": "Presione «atrás» dos veces para salir",
|
"settingsDoubleBackExit": "Presione «atrás» dos veces para salir",
|
||||||
|
@ -443,6 +461,7 @@
|
||||||
"settingsThumbnailOverlayTile": "Incrustaciones",
|
"settingsThumbnailOverlayTile": "Incrustaciones",
|
||||||
"settingsThumbnailOverlayTitle": "Incrustaciones",
|
"settingsThumbnailOverlayTitle": "Incrustaciones",
|
||||||
"settingsThumbnailShowFavouriteIcon": "Mostrar icono de favoritos",
|
"settingsThumbnailShowFavouriteIcon": "Mostrar icono de favoritos",
|
||||||
|
"settingsThumbnailShowTagIcon": "Mostrar ícono de etiqueta",
|
||||||
"settingsThumbnailShowLocationIcon": "Mostrar icono de ubicación",
|
"settingsThumbnailShowLocationIcon": "Mostrar icono de ubicación",
|
||||||
"settingsThumbnailShowMotionPhotoIcon": "Mostrar icono de foto en movimiento",
|
"settingsThumbnailShowMotionPhotoIcon": "Mostrar icono de foto en movimiento",
|
||||||
"settingsThumbnailShowRating": "Mostrar clasificación",
|
"settingsThumbnailShowRating": "Mostrar clasificación",
|
||||||
|
@ -476,9 +495,20 @@
|
||||||
"settingsViewerShowInformation": "Mostrar información",
|
"settingsViewerShowInformation": "Mostrar información",
|
||||||
"settingsViewerShowInformationSubtitle": "Mostrar título, fecha, ubicación, etc.",
|
"settingsViewerShowInformationSubtitle": "Mostrar título, fecha, ubicación, etc.",
|
||||||
"settingsViewerShowShootingDetails": "Mostrar detalles de toma",
|
"settingsViewerShowShootingDetails": "Mostrar detalles de toma",
|
||||||
"settingsViewerShowOverlayThumbnails": "Mostrar miniaturas",
|
"settingsViewerShowOverlayThumbnails": "Mostrar miniaturas",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Efecto de difuminado",
|
"settingsViewerEnableOverlayBlurEffect": "Efecto de difuminado",
|
||||||
|
|
||||||
|
"settingsViewerSlideshowTile": "Presentación",
|
||||||
|
"settingsViewerSlideshowTitle": "Presentación",
|
||||||
|
"settingsSlideshowRepeat": "Repetir",
|
||||||
|
"settingsSlideshowShuffle": "Mezclar",
|
||||||
|
"settingsSlideshowTransitionTile": "Transición",
|
||||||
|
"settingsSlideshowTransitionTitle": "Transición",
|
||||||
|
"settingsSlideshowIntervalTile": "Intervalo",
|
||||||
|
"settingsSlideshowIntervalTitle": "Intervalo",
|
||||||
|
"settingsSlideshowVideoPlaybackTile": "Reproducción de video",
|
||||||
|
"settingsSlideshowVideoPlaybackTitle": "Reproducción de video",
|
||||||
|
|
||||||
"settingsVideoPageTitle": "Ajustes de video",
|
"settingsVideoPageTitle": "Ajustes de video",
|
||||||
"settingsSectionVideo": "Video",
|
"settingsSectionVideo": "Video",
|
||||||
"settingsVideoShowVideos": "Mostrar videos",
|
"settingsVideoShowVideos": "Mostrar videos",
|
||||||
|
@ -486,8 +516,6 @@
|
||||||
"settingsVideoEnableAutoPlay": "Reproducción automática",
|
"settingsVideoEnableAutoPlay": "Reproducción automática",
|
||||||
"settingsVideoLoopModeTile": "Modo bucle",
|
"settingsVideoLoopModeTile": "Modo bucle",
|
||||||
"settingsVideoLoopModeTitle": "Modo bucle",
|
"settingsVideoLoopModeTitle": "Modo bucle",
|
||||||
"settingsVideoQuickActionsTile": "Acciones rápidas para videos",
|
|
||||||
"settingsVideoQuickActionEditorTitle": "Acciones rápidas",
|
|
||||||
|
|
||||||
"settingsSubtitleThemeTile": "Subtítulos",
|
"settingsSubtitleThemeTile": "Subtítulos",
|
||||||
"settingsSubtitleThemeTitle": "Subtítulos",
|
"settingsSubtitleThemeTitle": "Subtítulos",
|
||||||
|
@ -545,6 +573,7 @@
|
||||||
"settingsSectionDisplay": "Pantalla",
|
"settingsSectionDisplay": "Pantalla",
|
||||||
"settingsThemeBrightness": "Tema",
|
"settingsThemeBrightness": "Tema",
|
||||||
"settingsThemeColorHighlights": "Acentos de color",
|
"settingsThemeColorHighlights": "Acentos de color",
|
||||||
|
"settingsThemeEnableDynamicColor": "Color dinámico",
|
||||||
"settingsDisplayRefreshRateModeTile": "Tasa de refresco de la pantalla",
|
"settingsDisplayRefreshRateModeTile": "Tasa de refresco de la pantalla",
|
||||||
"settingsDisplayRefreshRateModeTitle": "Tasa de refresco",
|
"settingsDisplayRefreshRateModeTitle": "Tasa de refresco",
|
||||||
|
|
||||||
|
@ -562,6 +591,7 @@
|
||||||
"statsTopTags": "Etiquetas principales",
|
"statsTopTags": "Etiquetas principales",
|
||||||
|
|
||||||
"viewerOpenPanoramaButtonLabel": "ABRIR PANORÁMICA",
|
"viewerOpenPanoramaButtonLabel": "ABRIR PANORÁMICA",
|
||||||
|
"viewerSetWallpaperButtonLabel": "ESTABLECER FONDO",
|
||||||
"viewerErrorUnknown": "¡Ups!",
|
"viewerErrorUnknown": "¡Ups!",
|
||||||
"viewerErrorDoesNotExist": "El archivo no existe.",
|
"viewerErrorDoesNotExist": "El archivo no existe.",
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "Supprimer",
|
"entryActionDelete": "Supprimer",
|
||||||
"entryActionConvert": "Convertir",
|
"entryActionConvert": "Convertir",
|
||||||
"entryActionExport": "Exporter",
|
"entryActionExport": "Exporter",
|
||||||
|
"entryActionInfo": "Détails",
|
||||||
"entryActionRename": "Renommer",
|
"entryActionRename": "Renommer",
|
||||||
"entryActionRestore": "Restaurer",
|
"entryActionRestore": "Restaurer",
|
||||||
"entryActionRotateCCW": "Pivoter à gauche",
|
"entryActionRotateCCW": "Pivoter à gauche",
|
||||||
|
@ -80,6 +81,9 @@
|
||||||
"videoActionSetSpeed": "Vitesse de lecture",
|
"videoActionSetSpeed": "Vitesse de lecture",
|
||||||
"videoActionSettings": "Préférences",
|
"videoActionSettings": "Préférences",
|
||||||
|
|
||||||
|
"slideshowActionResume": "Reprendre",
|
||||||
|
"slideshowActionShowInCollection": "Afficher dans Collection",
|
||||||
|
|
||||||
"entryInfoActionEditDate": "Modifier la date",
|
"entryInfoActionEditDate": "Modifier la date",
|
||||||
"entryInfoActionEditLocation": "Modifier le lieu",
|
"entryInfoActionEditLocation": "Modifier le lieu",
|
||||||
"entryInfoActionEditRating": "Modifier la notation",
|
"entryInfoActionEditRating": "Modifier la notation",
|
||||||
|
@ -144,10 +148,23 @@
|
||||||
"displayRefreshRatePreferHighest": "Fréquence maximale",
|
"displayRefreshRatePreferHighest": "Fréquence maximale",
|
||||||
"displayRefreshRatePreferLowest": "Fréquence minimale",
|
"displayRefreshRatePreferLowest": "Fréquence minimale",
|
||||||
|
|
||||||
|
"slideshowVideoPlaybackSkip": "Passer",
|
||||||
|
"slideshowVideoPlaybackMuted": "Jouer sans son",
|
||||||
|
"slideshowVideoPlaybackWithSound": "Jouer avec son",
|
||||||
|
|
||||||
"themeBrightnessLight": "Clair",
|
"themeBrightnessLight": "Clair",
|
||||||
"themeBrightnessDark": "Sombre",
|
"themeBrightnessDark": "Sombre",
|
||||||
"themeBrightnessBlack": "Noir",
|
"themeBrightnessBlack": "Noir",
|
||||||
|
|
||||||
|
"viewerTransitionSlide": "Défilement",
|
||||||
|
"viewerTransitionParallax": "Parallaxe",
|
||||||
|
"viewerTransitionFade": "Fondu",
|
||||||
|
"viewerTransitionZoomIn": "Zoom",
|
||||||
|
|
||||||
|
"wallpaperTargetHome": "Écran d’accueil",
|
||||||
|
"wallpaperTargetLock": "Écran de verrouillage",
|
||||||
|
"wallpaperTargetHomeLock": "Écrans accueil et verrouillage",
|
||||||
|
|
||||||
"albumTierNew": "Nouveaux",
|
"albumTierNew": "Nouveaux",
|
||||||
"albumTierPinned": "Épinglés",
|
"albumTierPinned": "Épinglés",
|
||||||
"albumTierSpecial": "Standards",
|
"albumTierSpecial": "Standards",
|
||||||
|
@ -262,6 +279,7 @@
|
||||||
"menuActionSelectAll": "Tout sélectionner",
|
"menuActionSelectAll": "Tout sélectionner",
|
||||||
"menuActionSelectNone": "Tout désélectionner",
|
"menuActionSelectNone": "Tout désélectionner",
|
||||||
"menuActionMap": "Carte",
|
"menuActionMap": "Carte",
|
||||||
|
"menuActionSlideshow": "Diaporama",
|
||||||
"menuActionStats": "Statistiques",
|
"menuActionStats": "Statistiques",
|
||||||
|
|
||||||
"viewDialogTabSort": "Tri",
|
"viewDialogTabSort": "Tri",
|
||||||
|
@ -349,6 +367,7 @@
|
||||||
"collectionEmptyFavourites": "Aucun favori",
|
"collectionEmptyFavourites": "Aucun favori",
|
||||||
"collectionEmptyVideos": "Aucune vidéo",
|
"collectionEmptyVideos": "Aucune vidéo",
|
||||||
"collectionEmptyImages": "Aucune image",
|
"collectionEmptyImages": "Aucune image",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "Autoriser l’accès",
|
||||||
|
|
||||||
"collectionSelectSectionTooltip": "Sélectionner la section",
|
"collectionSelectSectionTooltip": "Sélectionner la section",
|
||||||
"collectionDeselectSectionTooltip": "Désélectionner la section",
|
"collectionDeselectSectionTooltip": "Désélectionner la section",
|
||||||
|
@ -479,6 +498,17 @@
|
||||||
"settingsViewerShowOverlayThumbnails": "Afficher les vignettes",
|
"settingsViewerShowOverlayThumbnails": "Afficher les vignettes",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Effets de flou",
|
"settingsViewerEnableOverlayBlurEffect": "Effets de flou",
|
||||||
|
|
||||||
|
"settingsViewerSlideshowTile": "Diaporama",
|
||||||
|
"settingsViewerSlideshowTitle": "Diaporama",
|
||||||
|
"settingsSlideshowRepeat": "Répéter",
|
||||||
|
"settingsSlideshowShuffle": "Aléatoire",
|
||||||
|
"settingsSlideshowTransitionTile": "Transition",
|
||||||
|
"settingsSlideshowTransitionTitle": "Transition",
|
||||||
|
"settingsSlideshowIntervalTile": "Intervalle",
|
||||||
|
"settingsSlideshowIntervalTitle": "Intervalle",
|
||||||
|
"settingsSlideshowVideoPlaybackTile": "Lecture de vidéos",
|
||||||
|
"settingsSlideshowVideoPlaybackTitle": "Lecture de vidéos",
|
||||||
|
|
||||||
"settingsVideoPageTitle": "Réglages vidéo",
|
"settingsVideoPageTitle": "Réglages vidéo",
|
||||||
"settingsSectionVideo": "Vidéo",
|
"settingsSectionVideo": "Vidéo",
|
||||||
"settingsVideoShowVideos": "Afficher les vidéos",
|
"settingsVideoShowVideos": "Afficher les vidéos",
|
||||||
|
@ -543,6 +573,7 @@
|
||||||
"settingsSectionDisplay": "Affichage",
|
"settingsSectionDisplay": "Affichage",
|
||||||
"settingsThemeBrightness": "Thème",
|
"settingsThemeBrightness": "Thème",
|
||||||
"settingsThemeColorHighlights": "Surlignages colorés",
|
"settingsThemeColorHighlights": "Surlignages colorés",
|
||||||
|
"settingsThemeEnableDynamicColor": "Couleur dynamique",
|
||||||
"settingsDisplayRefreshRateModeTile": "Fréquence d’actualisation de l'écran",
|
"settingsDisplayRefreshRateModeTile": "Fréquence d’actualisation de l'écran",
|
||||||
"settingsDisplayRefreshRateModeTitle": "Fréquence d’actualisation",
|
"settingsDisplayRefreshRateModeTitle": "Fréquence d’actualisation",
|
||||||
|
|
||||||
|
@ -560,6 +591,7 @@
|
||||||
"statsTopTags": "Top libellés",
|
"statsTopTags": "Top libellés",
|
||||||
|
|
||||||
"viewerOpenPanoramaButtonLabel": "OUVRIR LE PANORAMA",
|
"viewerOpenPanoramaButtonLabel": "OUVRIR LE PANORAMA",
|
||||||
|
"viewerSetWallpaperButtonLabel": "APPLIQUER",
|
||||||
"viewerErrorUnknown": "Zut !",
|
"viewerErrorUnknown": "Zut !",
|
||||||
"viewerErrorDoesNotExist": "Le fichier n’existe plus.",
|
"viewerErrorDoesNotExist": "Le fichier n’existe plus.",
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "Hapus",
|
"entryActionDelete": "Hapus",
|
||||||
"entryActionConvert": "Ubah",
|
"entryActionConvert": "Ubah",
|
||||||
"entryActionExport": "Ekspor",
|
"entryActionExport": "Ekspor",
|
||||||
|
"entryActionInfo": "Info",
|
||||||
"entryActionRename": "Ganti nama",
|
"entryActionRename": "Ganti nama",
|
||||||
"entryActionRestore": "Pulihkan",
|
"entryActionRestore": "Pulihkan",
|
||||||
"entryActionRotateCCW": "Putar berlawanan arah jarum jam",
|
"entryActionRotateCCW": "Putar berlawanan arah jarum jam",
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "Elimina",
|
"entryActionDelete": "Elimina",
|
||||||
"entryActionConvert": "Converti",
|
"entryActionConvert": "Converti",
|
||||||
"entryActionExport": "Esportazione",
|
"entryActionExport": "Esportazione",
|
||||||
|
"entryActionInfo": "Info",
|
||||||
"entryActionRename": "Rinomina",
|
"entryActionRename": "Rinomina",
|
||||||
"entryActionRestore": "Ripristina",
|
"entryActionRestore": "Ripristina",
|
||||||
"entryActionRotateCCW": "Ruota in senso antiorario",
|
"entryActionRotateCCW": "Ruota in senso antiorario",
|
||||||
|
@ -80,6 +81,9 @@
|
||||||
"videoActionSetSpeed": "Velocità di riproduzione",
|
"videoActionSetSpeed": "Velocità di riproduzione",
|
||||||
"videoActionSettings": "Impostazioni",
|
"videoActionSettings": "Impostazioni",
|
||||||
|
|
||||||
|
"slideshowActionResume": "Riprendi",
|
||||||
|
"slideshowActionShowInCollection": "Mostra nella Collezione",
|
||||||
|
|
||||||
"entryInfoActionEditDate": "Modifica data e ora",
|
"entryInfoActionEditDate": "Modifica data e ora",
|
||||||
"entryInfoActionEditLocation": "Modifica posizione",
|
"entryInfoActionEditLocation": "Modifica posizione",
|
||||||
"entryInfoActionEditRating": "Modifica valutazione",
|
"entryInfoActionEditRating": "Modifica valutazione",
|
||||||
|
@ -144,10 +148,23 @@
|
||||||
"displayRefreshRatePreferHighest": "Frequenza massima",
|
"displayRefreshRatePreferHighest": "Frequenza massima",
|
||||||
"displayRefreshRatePreferLowest": "Frequenza minima",
|
"displayRefreshRatePreferLowest": "Frequenza minima",
|
||||||
|
|
||||||
|
"slideshowVideoPlaybackSkip": "Salta",
|
||||||
|
"slideshowVideoPlaybackMuted": "Riproduci senza audio",
|
||||||
|
"slideshowVideoPlaybackWithSound": "Riproduci con audio",
|
||||||
|
|
||||||
"themeBrightnessLight": "Chiaro",
|
"themeBrightnessLight": "Chiaro",
|
||||||
"themeBrightnessDark": "Scuro",
|
"themeBrightnessDark": "Scuro",
|
||||||
"themeBrightnessBlack": "Nero",
|
"themeBrightnessBlack": "Nero",
|
||||||
|
|
||||||
|
"viewerTransitionSlide": "Diapositiva",
|
||||||
|
"viewerTransitionParallax": "Parallasse",
|
||||||
|
"viewerTransitionFade": "Dissolvenza",
|
||||||
|
"viewerTransitionZoomIn": "Ingrandisci",
|
||||||
|
|
||||||
|
"wallpaperTargetHome": "Schermata iniziale",
|
||||||
|
"wallpaperTargetLock": "Schermata di blocco",
|
||||||
|
"wallpaperTargetHomeLock": "Schermata iniziale e di blocco",
|
||||||
|
|
||||||
"albumTierNew": "Nuovi",
|
"albumTierNew": "Nuovi",
|
||||||
"albumTierPinned": "Fissati",
|
"albumTierPinned": "Fissati",
|
||||||
"albumTierSpecial": "Frequenti",
|
"albumTierSpecial": "Frequenti",
|
||||||
|
@ -262,6 +279,7 @@
|
||||||
"menuActionSelectAll": "Seleziona tutto",
|
"menuActionSelectAll": "Seleziona tutto",
|
||||||
"menuActionSelectNone": "Deseleziona tutto",
|
"menuActionSelectNone": "Deseleziona tutto",
|
||||||
"menuActionMap": "Mappa",
|
"menuActionMap": "Mappa",
|
||||||
|
"menuActionSlideshow": "Presentazione",
|
||||||
"menuActionStats": "Statistiche",
|
"menuActionStats": "Statistiche",
|
||||||
|
|
||||||
"viewDialogTabSort": "Ordina",
|
"viewDialogTabSort": "Ordina",
|
||||||
|
@ -349,6 +367,7 @@
|
||||||
"collectionEmptyFavourites": "Nessun preferito",
|
"collectionEmptyFavourites": "Nessun preferito",
|
||||||
"collectionEmptyVideos": "Nessun video",
|
"collectionEmptyVideos": "Nessun video",
|
||||||
"collectionEmptyImages": "Nessuna immagine",
|
"collectionEmptyImages": "Nessuna immagine",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "Consenti accesso",
|
||||||
|
|
||||||
"collectionSelectSectionTooltip": "Seleziona sezione",
|
"collectionSelectSectionTooltip": "Seleziona sezione",
|
||||||
"collectionDeselectSectionTooltip": "Deseleziona sezione",
|
"collectionDeselectSectionTooltip": "Deseleziona sezione",
|
||||||
|
@ -479,6 +498,17 @@
|
||||||
"settingsViewerShowOverlayThumbnails": "Mostra le miniature",
|
"settingsViewerShowOverlayThumbnails": "Mostra le miniature",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Effetto sfocatura",
|
"settingsViewerEnableOverlayBlurEffect": "Effetto sfocatura",
|
||||||
|
|
||||||
|
"settingsViewerSlideshowTile": "Presentazione",
|
||||||
|
"settingsViewerSlideshowTitle": "Presentazione",
|
||||||
|
"settingsSlideshowRepeat": "Ripeti",
|
||||||
|
"settingsSlideshowShuffle": "Ordine casuale",
|
||||||
|
"settingsSlideshowTransitionTile": "Transizione",
|
||||||
|
"settingsSlideshowTransitionTitle": "Transizione",
|
||||||
|
"settingsSlideshowIntervalTile": "Intervallo",
|
||||||
|
"settingsSlideshowIntervalTitle": "Intervallo",
|
||||||
|
"settingsSlideshowVideoPlaybackTile": "Riproduzione video",
|
||||||
|
"settingsSlideshowVideoPlaybackTitle": "Riproduzione video",
|
||||||
|
|
||||||
"settingsVideoPageTitle": "Impostazioni video",
|
"settingsVideoPageTitle": "Impostazioni video",
|
||||||
"settingsSectionVideo": "Video",
|
"settingsSectionVideo": "Video",
|
||||||
"settingsVideoShowVideos": "Mostra video",
|
"settingsVideoShowVideos": "Mostra video",
|
||||||
|
@ -543,6 +573,7 @@
|
||||||
"settingsSectionDisplay": "Schermo",
|
"settingsSectionDisplay": "Schermo",
|
||||||
"settingsThemeBrightness": "Tema",
|
"settingsThemeBrightness": "Tema",
|
||||||
"settingsThemeColorHighlights": "Colori evidenziati",
|
"settingsThemeColorHighlights": "Colori evidenziati",
|
||||||
|
"settingsThemeEnableDynamicColor": "Colori dinamici",
|
||||||
"settingsDisplayRefreshRateModeTile": "Frequenza di aggiornamento dello schermo",
|
"settingsDisplayRefreshRateModeTile": "Frequenza di aggiornamento dello schermo",
|
||||||
"settingsDisplayRefreshRateModeTitle": "Frequenza di aggiornamento",
|
"settingsDisplayRefreshRateModeTitle": "Frequenza di aggiornamento",
|
||||||
|
|
||||||
|
@ -560,6 +591,7 @@
|
||||||
"statsTopTags": "Etichette più frequenti",
|
"statsTopTags": "Etichette più frequenti",
|
||||||
|
|
||||||
"viewerOpenPanoramaButtonLabel": "APRI PANORAMA",
|
"viewerOpenPanoramaButtonLabel": "APRI PANORAMA",
|
||||||
|
"viewerSetWallpaperButtonLabel": "IMPOSTA SFONDO",
|
||||||
"viewerErrorUnknown": "Ops!",
|
"viewerErrorUnknown": "Ops!",
|
||||||
"viewerErrorDoesNotExist": "Il file non esiste più",
|
"viewerErrorDoesNotExist": "Il file non esiste più",
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "削除",
|
"entryActionDelete": "削除",
|
||||||
"entryActionConvert": "変換",
|
"entryActionConvert": "変換",
|
||||||
"entryActionExport": "エクスポート",
|
"entryActionExport": "エクスポート",
|
||||||
|
"entryActionInfo": "情報",
|
||||||
"entryActionRename": "名前を変更",
|
"entryActionRename": "名前を変更",
|
||||||
"entryActionRestore": "元に戻す",
|
"entryActionRestore": "元に戻す",
|
||||||
"entryActionRotateCCW": "反時計回りに回転",
|
"entryActionRotateCCW": "反時計回りに回転",
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "삭제",
|
"entryActionDelete": "삭제",
|
||||||
"entryActionConvert": "변환",
|
"entryActionConvert": "변환",
|
||||||
"entryActionExport": "내보내기",
|
"entryActionExport": "내보내기",
|
||||||
|
"entryActionInfo": "상세정보",
|
||||||
"entryActionRename": "이름 변경",
|
"entryActionRename": "이름 변경",
|
||||||
"entryActionRestore": "복원",
|
"entryActionRestore": "복원",
|
||||||
"entryActionRotateCCW": "좌회전",
|
"entryActionRotateCCW": "좌회전",
|
||||||
|
@ -80,6 +81,9 @@
|
||||||
"videoActionSetSpeed": "재생 배속",
|
"videoActionSetSpeed": "재생 배속",
|
||||||
"videoActionSettings": "설정",
|
"videoActionSettings": "설정",
|
||||||
|
|
||||||
|
"slideshowActionResume": "이어서",
|
||||||
|
"slideshowActionShowInCollection": "미디어 페이지에서 보기",
|
||||||
|
|
||||||
"entryInfoActionEditDate": "날짜 및 시간 수정",
|
"entryInfoActionEditDate": "날짜 및 시간 수정",
|
||||||
"entryInfoActionEditLocation": "위치 수정",
|
"entryInfoActionEditLocation": "위치 수정",
|
||||||
"entryInfoActionEditRating": "별점 수정",
|
"entryInfoActionEditRating": "별점 수정",
|
||||||
|
@ -144,10 +148,23 @@
|
||||||
"displayRefreshRatePreferHighest": "가장 높은 재생률",
|
"displayRefreshRatePreferHighest": "가장 높은 재생률",
|
||||||
"displayRefreshRatePreferLowest": "가장 낮은 재생률",
|
"displayRefreshRatePreferLowest": "가장 낮은 재생률",
|
||||||
|
|
||||||
|
"slideshowVideoPlaybackSkip": "생략",
|
||||||
|
"slideshowVideoPlaybackMuted": "음소거 재생",
|
||||||
|
"slideshowVideoPlaybackWithSound": "일반 재생",
|
||||||
|
|
||||||
"themeBrightnessLight": "라이트",
|
"themeBrightnessLight": "라이트",
|
||||||
"themeBrightnessDark": "다크",
|
"themeBrightnessDark": "다크",
|
||||||
"themeBrightnessBlack": "검은색",
|
"themeBrightnessBlack": "검은색",
|
||||||
|
|
||||||
|
"viewerTransitionSlide": "좌우",
|
||||||
|
"viewerTransitionParallax": "시차",
|
||||||
|
"viewerTransitionFade": "페이드",
|
||||||
|
"viewerTransitionZoomIn": "확대",
|
||||||
|
|
||||||
|
"wallpaperTargetHome": "홈 화면",
|
||||||
|
"wallpaperTargetLock": "잠금화면",
|
||||||
|
"wallpaperTargetHomeLock": "홈 및 잠금화면",
|
||||||
|
|
||||||
"albumTierNew": "신규",
|
"albumTierNew": "신규",
|
||||||
"albumTierPinned": "고정",
|
"albumTierPinned": "고정",
|
||||||
"albumTierSpecial": "기본",
|
"albumTierSpecial": "기본",
|
||||||
|
@ -262,6 +279,7 @@
|
||||||
"menuActionSelectAll": "모두 선택",
|
"menuActionSelectAll": "모두 선택",
|
||||||
"menuActionSelectNone": "모두 해제",
|
"menuActionSelectNone": "모두 해제",
|
||||||
"menuActionMap": "지도",
|
"menuActionMap": "지도",
|
||||||
|
"menuActionSlideshow": "슬라이드쇼",
|
||||||
"menuActionStats": "통계",
|
"menuActionStats": "통계",
|
||||||
|
|
||||||
"viewDialogTabSort": "정렬",
|
"viewDialogTabSort": "정렬",
|
||||||
|
@ -349,6 +367,7 @@
|
||||||
"collectionEmptyFavourites": "즐겨찾기가 없습니다",
|
"collectionEmptyFavourites": "즐겨찾기가 없습니다",
|
||||||
"collectionEmptyVideos": "동영상이 없습니다",
|
"collectionEmptyVideos": "동영상이 없습니다",
|
||||||
"collectionEmptyImages": "사진이 없습니다",
|
"collectionEmptyImages": "사진이 없습니다",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "접근 허용",
|
||||||
|
|
||||||
"collectionSelectSectionTooltip": "묶음 선택",
|
"collectionSelectSectionTooltip": "묶음 선택",
|
||||||
"collectionDeselectSectionTooltip": "묶음 선택 해제",
|
"collectionDeselectSectionTooltip": "묶음 선택 해제",
|
||||||
|
@ -479,6 +498,17 @@
|
||||||
"settingsViewerShowOverlayThumbnails": "섬네일 표시",
|
"settingsViewerShowOverlayThumbnails": "섬네일 표시",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "흐림 효과",
|
"settingsViewerEnableOverlayBlurEffect": "흐림 효과",
|
||||||
|
|
||||||
|
"settingsViewerSlideshowTile": "슬라이드쇼",
|
||||||
|
"settingsViewerSlideshowTitle": "슬라이드쇼",
|
||||||
|
"settingsSlideshowRepeat": "반복",
|
||||||
|
"settingsSlideshowShuffle": "순서섞기",
|
||||||
|
"settingsSlideshowTransitionTile": "전환 효과",
|
||||||
|
"settingsSlideshowTransitionTitle": "전환 효과",
|
||||||
|
"settingsSlideshowIntervalTile": "교체 주기",
|
||||||
|
"settingsSlideshowIntervalTitle": "교체 주기",
|
||||||
|
"settingsSlideshowVideoPlaybackTile": "동영상 재생",
|
||||||
|
"settingsSlideshowVideoPlaybackTitle": "동영상 재생",
|
||||||
|
|
||||||
"settingsVideoPageTitle": "동영상 설정",
|
"settingsVideoPageTitle": "동영상 설정",
|
||||||
"settingsSectionVideo": "동영상",
|
"settingsSectionVideo": "동영상",
|
||||||
"settingsVideoShowVideos": "미디어에 동영상 표시",
|
"settingsVideoShowVideos": "미디어에 동영상 표시",
|
||||||
|
@ -543,6 +573,7 @@
|
||||||
"settingsSectionDisplay": "디스플레이",
|
"settingsSectionDisplay": "디스플레이",
|
||||||
"settingsThemeBrightness": "테마",
|
"settingsThemeBrightness": "테마",
|
||||||
"settingsThemeColorHighlights": "색 강조",
|
"settingsThemeColorHighlights": "색 강조",
|
||||||
|
"settingsThemeEnableDynamicColor": "동적 색상",
|
||||||
"settingsDisplayRefreshRateModeTile": "화면 재생률",
|
"settingsDisplayRefreshRateModeTile": "화면 재생률",
|
||||||
"settingsDisplayRefreshRateModeTitle": "화면 재생률",
|
"settingsDisplayRefreshRateModeTitle": "화면 재생률",
|
||||||
|
|
||||||
|
@ -560,6 +591,7 @@
|
||||||
"statsTopTags": "태그 랭킹",
|
"statsTopTags": "태그 랭킹",
|
||||||
|
|
||||||
"viewerOpenPanoramaButtonLabel": "파노라마 열기",
|
"viewerOpenPanoramaButtonLabel": "파노라마 열기",
|
||||||
|
"viewerSetWallpaperButtonLabel": "설정",
|
||||||
"viewerErrorUnknown": "아이구!",
|
"viewerErrorUnknown": "아이구!",
|
||||||
"viewerErrorDoesNotExist": "파일이 존재하지 않습니다.",
|
"viewerErrorDoesNotExist": "파일이 존재하지 않습니다.",
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
"entryActionCopyToClipboard": "Copiar para área de transferência",
|
"entryActionCopyToClipboard": "Copiar para área de transferência",
|
||||||
"entryActionDelete": "Excluir",
|
"entryActionDelete": "Excluir",
|
||||||
"entryActionExport": "Exportar",
|
"entryActionExport": "Exportar",
|
||||||
|
"entryActionInfo": "Informações",
|
||||||
"entryActionConvert": "Converter",
|
"entryActionConvert": "Converter",
|
||||||
"entryActionRename": "Renomear",
|
"entryActionRename": "Renomear",
|
||||||
"entryActionRestore": "Restaurar",
|
"entryActionRestore": "Restaurar",
|
||||||
|
@ -80,6 +81,9 @@
|
||||||
"videoActionSetSpeed": "Velocidade de reprodução",
|
"videoActionSetSpeed": "Velocidade de reprodução",
|
||||||
"videoActionSettings": "Configurações",
|
"videoActionSettings": "Configurações",
|
||||||
|
|
||||||
|
"slideshowActionResume": "Retomar",
|
||||||
|
"slideshowActionShowInCollection": "Mostrar na Coleção",
|
||||||
|
|
||||||
"entryInfoActionEditDate": "Editar data e hora",
|
"entryInfoActionEditDate": "Editar data e hora",
|
||||||
"entryInfoActionEditLocation": "Editar localização",
|
"entryInfoActionEditLocation": "Editar localização",
|
||||||
"entryInfoActionEditRating": "Editar classificação",
|
"entryInfoActionEditRating": "Editar classificação",
|
||||||
|
@ -144,10 +148,23 @@
|
||||||
"displayRefreshRatePreferHighest": "Taxa mais alta",
|
"displayRefreshRatePreferHighest": "Taxa mais alta",
|
||||||
"displayRefreshRatePreferLowest": "Taxa mais baixa",
|
"displayRefreshRatePreferLowest": "Taxa mais baixa",
|
||||||
|
|
||||||
|
"slideshowVideoPlaybackSkip": "Pular",
|
||||||
|
"slideshowVideoPlaybackMuted": "Reproduzir sem som",
|
||||||
|
"slideshowVideoPlaybackWithSound": "Reproduzir com som",
|
||||||
|
|
||||||
"themeBrightnessLight": "Claro",
|
"themeBrightnessLight": "Claro",
|
||||||
"themeBrightnessDark": "Escuro",
|
"themeBrightnessDark": "Escuro",
|
||||||
"themeBrightnessBlack": "Preto",
|
"themeBrightnessBlack": "Preto",
|
||||||
|
|
||||||
|
"viewerTransitionSlide": "Deslizar",
|
||||||
|
"viewerTransitionParallax": "Parallax",
|
||||||
|
"viewerTransitionFade": "Desvaneça",
|
||||||
|
"viewerTransitionZoomIn": "Mais zoom",
|
||||||
|
|
||||||
|
"wallpaperTargetHome": "Tela inicial",
|
||||||
|
"wallpaperTargetLock": "Tela de bloqueio",
|
||||||
|
"wallpaperTargetHomeLock": "Telas iniciais e de bloqueio",
|
||||||
|
|
||||||
"albumTierNew": "Novo",
|
"albumTierNew": "Novo",
|
||||||
"albumTierPinned": "Fixada",
|
"albumTierPinned": "Fixada",
|
||||||
"albumTierSpecial": "Comum",
|
"albumTierSpecial": "Comum",
|
||||||
|
@ -262,6 +279,7 @@
|
||||||
"menuActionSelectAll": "Selecionar tudo",
|
"menuActionSelectAll": "Selecionar tudo",
|
||||||
"menuActionSelectNone": "Selecione nenhum",
|
"menuActionSelectNone": "Selecione nenhum",
|
||||||
"menuActionMap": "Mapa",
|
"menuActionMap": "Mapa",
|
||||||
|
"menuActionSlideshow": "Apresentação de slides",
|
||||||
"menuActionStats": "Estatísticas",
|
"menuActionStats": "Estatísticas",
|
||||||
|
|
||||||
"viewDialogTabSort": "Organizar",
|
"viewDialogTabSort": "Organizar",
|
||||||
|
@ -349,6 +367,7 @@
|
||||||
"collectionEmptyFavourites": "Nenhum favorito",
|
"collectionEmptyFavourites": "Nenhum favorito",
|
||||||
"collectionEmptyVideos": "Nenhum video",
|
"collectionEmptyVideos": "Nenhum video",
|
||||||
"collectionEmptyImages": "Nenhuma image",
|
"collectionEmptyImages": "Nenhuma image",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "Garantir acesso",
|
||||||
|
|
||||||
"collectionSelectSectionTooltip": "Selecionar seção",
|
"collectionSelectSectionTooltip": "Selecionar seção",
|
||||||
"collectionDeselectSectionTooltip": "Desmarcar seção",
|
"collectionDeselectSectionTooltip": "Desmarcar seção",
|
||||||
|
@ -479,6 +498,17 @@
|
||||||
"settingsViewerShowOverlayThumbnails": "Mostrar miniaturas",
|
"settingsViewerShowOverlayThumbnails": "Mostrar miniaturas",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Efeito de desfoque",
|
"settingsViewerEnableOverlayBlurEffect": "Efeito de desfoque",
|
||||||
|
|
||||||
|
"settingsViewerSlideshowTile": "Apresentação de slides",
|
||||||
|
"settingsViewerSlideshowTitle": "Apresentação de slides",
|
||||||
|
"settingsSlideshowRepeat": "Repetir",
|
||||||
|
"settingsSlideshowShuffle": "Embaralhar",
|
||||||
|
"settingsSlideshowTransitionTile": "Transição",
|
||||||
|
"settingsSlideshowTransitionTitle": "Transição",
|
||||||
|
"settingsSlideshowIntervalTile": "Intervalo",
|
||||||
|
"settingsSlideshowIntervalTitle": "Intervalo",
|
||||||
|
"settingsSlideshowVideoPlaybackTile": "Reprodução de vídeo",
|
||||||
|
"settingsSlideshowVideoPlaybackTitle": "Reprodução de vídeo",
|
||||||
|
|
||||||
"settingsVideoPageTitle": "Configurações de vídeo",
|
"settingsVideoPageTitle": "Configurações de vídeo",
|
||||||
"settingsSectionVideo": "Vídeo",
|
"settingsSectionVideo": "Vídeo",
|
||||||
"settingsVideoShowVideos": "Mostrar vídeos",
|
"settingsVideoShowVideos": "Mostrar vídeos",
|
||||||
|
@ -543,6 +573,7 @@
|
||||||
"settingsSectionDisplay": "Tela",
|
"settingsSectionDisplay": "Tela",
|
||||||
"settingsThemeBrightness": "Tema",
|
"settingsThemeBrightness": "Tema",
|
||||||
"settingsThemeColorHighlights": "Destaques de cores",
|
"settingsThemeColorHighlights": "Destaques de cores",
|
||||||
|
"settingsThemeEnableDynamicColor": "Cor dinâmica",
|
||||||
"settingsDisplayRefreshRateModeTile": "Taxa de atualização de exibição",
|
"settingsDisplayRefreshRateModeTile": "Taxa de atualização de exibição",
|
||||||
"settingsDisplayRefreshRateModeTitle": "Taxa de atualização",
|
"settingsDisplayRefreshRateModeTitle": "Taxa de atualização",
|
||||||
|
|
||||||
|
@ -560,6 +591,7 @@
|
||||||
"statsTopTags": "Principais Etiquetas",
|
"statsTopTags": "Principais Etiquetas",
|
||||||
|
|
||||||
"viewerOpenPanoramaButtonLabel": "ABRIR PANORAMA",
|
"viewerOpenPanoramaButtonLabel": "ABRIR PANORAMA",
|
||||||
|
"viewerSetWallpaperButtonLabel": "DEFINIR PAPEL DE PAREDE",
|
||||||
"viewerErrorUnknown": "Algo não está certo!",
|
"viewerErrorUnknown": "Algo não está certo!",
|
||||||
"viewerErrorDoesNotExist": "O arquivo não existe mais.",
|
"viewerErrorDoesNotExist": "O arquivo não existe mais.",
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "Удалить",
|
"entryActionDelete": "Удалить",
|
||||||
"entryActionConvert": "Конвертировать",
|
"entryActionConvert": "Конвертировать",
|
||||||
"entryActionExport": "Экспорт",
|
"entryActionExport": "Экспорт",
|
||||||
|
"entryActionInfo": "Информация",
|
||||||
"entryActionRename": "Переименовать",
|
"entryActionRename": "Переименовать",
|
||||||
"entryActionRestore": "Восстановить",
|
"entryActionRestore": "Восстановить",
|
||||||
"entryActionRotateCCW": "Повернуть против часовой стрелки",
|
"entryActionRotateCCW": "Повернуть против часовой стрелки",
|
||||||
|
|
639
lib/l10n/app_tr.arb
Normal file
|
@ -0,0 +1,639 @@
|
||||||
|
{
|
||||||
|
"appName": "Aves",
|
||||||
|
"welcomeMessage": "Aves'e Hoş Geldiniz",
|
||||||
|
"welcomeOptional": "İsteğe bağlı",
|
||||||
|
"welcomeTermsToggle": "Hüküm ve koşulları kabul ediyorum",
|
||||||
|
"itemCount": "{count, plural, =1{1 öğe} other{{count} öğe}}",
|
||||||
|
|
||||||
|
"timeSeconds": "{seconds, plural, =1{1 saniye} other{{seconds} saniye}}",
|
||||||
|
"timeMinutes": "{minutes, plural, =1{1 dakika} other{{minutes} dakika}}",
|
||||||
|
"timeDays": "{days, plural, =1{1 gün} other{{days} gün}}",
|
||||||
|
"focalLength": "{length} mm",
|
||||||
|
|
||||||
|
"applyButtonLabel": "UYGULA",
|
||||||
|
"deleteButtonLabel": "SİL",
|
||||||
|
"nextButtonLabel": "SONRAKİ",
|
||||||
|
"showButtonLabel": "GÖSTER",
|
||||||
|
"hideButtonLabel": "GİZLE",
|
||||||
|
"continueButtonLabel": "DEVAM ET",
|
||||||
|
|
||||||
|
"cancelTooltip": "İptal et",
|
||||||
|
"changeTooltip": "Değiştir",
|
||||||
|
"clearTooltip": "Temizle",
|
||||||
|
"previousTooltip": "Önceki",
|
||||||
|
"nextTooltip": "Sonraki",
|
||||||
|
"showTooltip": "Göster",
|
||||||
|
"hideTooltip": "Gizle",
|
||||||
|
"actionRemove": "Kaldır",
|
||||||
|
"resetButtonTooltip": "Sıfırla",
|
||||||
|
|
||||||
|
"doubleBackExitMessage": "Çıkmak için tekrar “geri”, düğmesine dokunun.",
|
||||||
|
"doNotAskAgain": "Bir daha sorma",
|
||||||
|
|
||||||
|
"sourceStateLoading": "Yükleniyor",
|
||||||
|
"sourceStateCataloguing": "Kataloglanıyor",
|
||||||
|
"sourceStateLocatingCountries": "Ülkeler konumlandırılıyor",
|
||||||
|
"sourceStateLocatingPlaces": "Konum belirleniyor",
|
||||||
|
|
||||||
|
"chipActionDelete": "Sil",
|
||||||
|
"chipActionGoToAlbumPage": "Albümlerde göster",
|
||||||
|
"chipActionGoToCountryPage": "Ülkelerde göster",
|
||||||
|
"chipActionGoToTagPage": "Etiketlerde göster",
|
||||||
|
"chipActionHide": "Gizle",
|
||||||
|
"chipActionPin": "Başa sabitle",
|
||||||
|
"chipActionUnpin": "Baştan çıkar",
|
||||||
|
"chipActionRename": "Yeniden adlandır",
|
||||||
|
"chipActionSetCover": "Kapağı ayarla",
|
||||||
|
"chipActionCreateAlbum": "Albüm oluştur",
|
||||||
|
|
||||||
|
"entryActionCopyToClipboard": "Panoya kopyala",
|
||||||
|
"entryActionDelete": "Sil",
|
||||||
|
"entryActionConvert": "Dönüştür",
|
||||||
|
"entryActionExport": "Dışa aktar",
|
||||||
|
"entryActionInfo": "Bilgi",
|
||||||
|
"entryActionRename": "Yeniden adlandır",
|
||||||
|
"entryActionRestore": "Dışa aktar",
|
||||||
|
"entryActionRotateCCW": "Saat yönünün tersine döndür",
|
||||||
|
"entryActionRotateCW": "Saat yönünde döndür",
|
||||||
|
"entryActionFlip": "Yatay olarak çevir",
|
||||||
|
"entryActionPrint": "Yazdır",
|
||||||
|
"entryActionShare": "Paylaş",
|
||||||
|
"entryActionViewSource": "Kaynağı görüntüle",
|
||||||
|
"entryActionShowGeoTiffOnMap": "Harita katmanı olarak göster",
|
||||||
|
"entryActionConvertMotionPhotoToStillImage": "Hareketsiz görüntüye dönüştür",
|
||||||
|
"entryActionViewMotionPhotoVideo": "Videoyu aç",
|
||||||
|
"entryActionEdit": "Düzenle",
|
||||||
|
"entryActionOpen": "Şununla aç",
|
||||||
|
"entryActionSetAs": "Olarak ayarla",
|
||||||
|
"entryActionOpenMap": "Harita uygulamasında göster",
|
||||||
|
"entryActionRotateScreen": "Ekranı döndür",
|
||||||
|
"entryActionAddFavourite": "Favorilere ekle",
|
||||||
|
"entryActionRemoveFavourite": "Favorilerden kaldır",
|
||||||
|
|
||||||
|
"videoActionCaptureFrame": "Çerçeve yakala",
|
||||||
|
"videoActionMute": "Sustur",
|
||||||
|
"videoActionUnmute": "Susturmayı kaldır",
|
||||||
|
"videoActionPause": "Duraklat",
|
||||||
|
"videoActionPlay": "Oynat",
|
||||||
|
"videoActionReplay10": "10 saniye geri git",
|
||||||
|
"videoActionSkip10": "10 saniye ileri git",
|
||||||
|
"videoActionSelectStreams": "Parça seç",
|
||||||
|
"videoActionSetSpeed": "Oynatma hızı",
|
||||||
|
"videoActionSettings": "Ayarlar",
|
||||||
|
|
||||||
|
"entryInfoActionEditDate": "Tarih ve saati düzenle",
|
||||||
|
"entryInfoActionEditLocation": "Konumu düzenle",
|
||||||
|
"entryInfoActionEditRating": "Derecelendirmeyi düzenle",
|
||||||
|
"entryInfoActionEditTags": "Etiketleri düzenle",
|
||||||
|
"entryInfoActionRemoveMetadata": "Meta verileri kaldır",
|
||||||
|
|
||||||
|
"filterBinLabel": "Geri dönüşüm kutusu",
|
||||||
|
"filterFavouriteLabel": "Favori",
|
||||||
|
"filterLocationEmptyLabel": "Konumsuz",
|
||||||
|
"filterTagEmptyLabel": "Etiketsiz",
|
||||||
|
"filterRatingUnratedLabel": "Derecelendirilmemiş",
|
||||||
|
"filterRatingRejectedLabel": "Reddedilmiş",
|
||||||
|
"filterTypeAnimatedLabel": "Hareketli",
|
||||||
|
"filterTypeMotionPhotoLabel": "Hareketli Fotoğraf",
|
||||||
|
"filterTypePanoramaLabel": "Panorama",
|
||||||
|
"filterTypeRawLabel": "Raw",
|
||||||
|
"filterTypeSphericalVideoLabel": "360° Video",
|
||||||
|
"filterTypeGeotiffLabel": "GeoTIFF",
|
||||||
|
"filterMimeImageLabel": "Resim",
|
||||||
|
"filterMimeVideoLabel": "Video",
|
||||||
|
|
||||||
|
"coordinateFormatDms": "DMS",
|
||||||
|
"coordinateFormatDecimal": "Ondalık dereceler",
|
||||||
|
"coordinateDms": "{coordinate} {direction}",
|
||||||
|
|
||||||
|
"coordinateDmsNorth": "K",
|
||||||
|
"coordinateDmsSouth": "G",
|
||||||
|
"coordinateDmsEast": "D",
|
||||||
|
"coordinateDmsWest": "B",
|
||||||
|
|
||||||
|
"unitSystemMetric": "Metrik",
|
||||||
|
"unitSystemImperial": "İngiliz",
|
||||||
|
|
||||||
|
"videoLoopModeNever": "Asla",
|
||||||
|
"videoLoopModeShortOnly": "Yalnızca kısa videolar",
|
||||||
|
"videoLoopModeAlways": "Her zaman",
|
||||||
|
|
||||||
|
"videoControlsPlay": "Oynat",
|
||||||
|
"videoControlsPlaySeek": "Oynat ve ileri/geri git",
|
||||||
|
"videoControlsPlayOutside": "Başka bir oynatıcı ile aç",
|
||||||
|
"videoControlsNone": "Hiçbiri",
|
||||||
|
|
||||||
|
"mapStyleGoogleNormal": "Google Haritalar",
|
||||||
|
"mapStyleGoogleHybrid": "Google Haritalar (Hibrit)",
|
||||||
|
"mapStyleGoogleTerrain": "Google Haritalar (Arazi)",
|
||||||
|
"mapStyleHuaweiNormal": "Petal Haritalar",
|
||||||
|
"mapStyleHuaweiTerrain": "Petal Haritalar (Arazi)",
|
||||||
|
"mapStyleOsmHot": "İnsancıl OSM",
|
||||||
|
"mapStyleStamenToner": "Stamen Tonik",
|
||||||
|
"mapStyleStamenWatercolor": "Stamen Suluboya",
|
||||||
|
|
||||||
|
"nameConflictStrategyRename": "Yeniden adlandır",
|
||||||
|
"nameConflictStrategyReplace": "Değiştir",
|
||||||
|
"nameConflictStrategySkip": "Atla",
|
||||||
|
|
||||||
|
"keepScreenOnNever": "Asla",
|
||||||
|
"keepScreenOnViewerOnly": "Yalnızca görüntüleyici sayfası",
|
||||||
|
"keepScreenOnAlways": "Her zaman",
|
||||||
|
|
||||||
|
"accessibilityAnimationsRemove": "Ekran efektlerini önle",
|
||||||
|
"accessibilityAnimationsKeep": "Ekran efektlerini koru",
|
||||||
|
|
||||||
|
"displayRefreshRatePreferHighest": "En yüksek oran",
|
||||||
|
"displayRefreshRatePreferLowest": "En düşük oran",
|
||||||
|
|
||||||
|
"themeBrightnessLight": "Açık",
|
||||||
|
"themeBrightnessDark": "Koyu",
|
||||||
|
"themeBrightnessBlack": "Siyah",
|
||||||
|
|
||||||
|
"albumTierNew": "Yeni",
|
||||||
|
"albumTierPinned": "Sabitlenmiş",
|
||||||
|
"albumTierSpecial": "Genel",
|
||||||
|
"albumTierApps": "Uygulamalar",
|
||||||
|
"albumTierRegular": "Diğer",
|
||||||
|
|
||||||
|
"storageVolumeDescriptionFallbackPrimary": "Dahili depolama",
|
||||||
|
"storageVolumeDescriptionFallbackNonPrimary": "SD kart",
|
||||||
|
"rootDirectoryDescription": "kök dizin",
|
||||||
|
"otherDirectoryDescription": "“{name}” dizin",
|
||||||
|
|
||||||
|
"storageAccessDialogTitle": "Depolama Erişimi",
|
||||||
|
"storageAccessDialogMessage": "Bu uygulamaya erişim sağlamak için lütfen bir sonraki ekranda “{volume}” öğesinin {directory} dizinini seçin.",
|
||||||
|
|
||||||
|
"restrictedAccessDialogTitle": "Kısıtlı Erişim",
|
||||||
|
"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.",
|
||||||
|
|
||||||
|
"notEnoughSpaceDialogTitle": "Yeterli Yer Yok",
|
||||||
|
"notEnoughSpaceDialogMessage": "Bu işlemin tamamlanması için “{volume}” üzerinde {needSize} boş alana ihtiyaç var, ancak yalnızca {freeSize} kaldı.",
|
||||||
|
|
||||||
|
"missingSystemFilePickerDialogTitle": "Eksik Sistem Dosya Seçicisi",
|
||||||
|
"missingSystemFilePickerDialogMessage": "Sistem dosya seçicisi eksik veya devre dışı. Lütfen etkinleştirin ve tekrar deneyin.",
|
||||||
|
|
||||||
|
"unsupportedTypeDialogTitle": "Desteklenmeyen Türler",
|
||||||
|
"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}.}}",
|
||||||
|
|
||||||
|
"nameConflictDialogSingleSourceMessage": "Hedef klasördeki bazı dosyalar aynı ada sahip.",
|
||||||
|
"nameConflictDialogMultipleSourceMessage": "Bazı dosyalar aynı ada sahip.",
|
||||||
|
|
||||||
|
"addShortcutDialogLabel": "Kısayol etiketi",
|
||||||
|
"addShortcutButtonLabel": "EKLE",
|
||||||
|
|
||||||
|
"noMatchingAppDialogTitle": "Eşleşen Uygulama Yok",
|
||||||
|
"noMatchingAppDialogMessage": "Bununla ilgilenebilecek bir uygulama yok.",
|
||||||
|
|
||||||
|
"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ı?}}",
|
||||||
|
|
||||||
|
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Bu öğe silinsin mi?} other{Bu {count} öğe silinsin mi?}}",
|
||||||
|
|
||||||
|
"moveUndatedConfirmationDialogMessage": "Devam etmeden önce öğe tarihleri kaydedilsin mi?",
|
||||||
|
"moveUndatedConfirmationDialogSetDate": "Tarihleri kaydet",
|
||||||
|
|
||||||
|
"videoResumeDialogMessage": "{time} itibarıyla oynatmaya devam etmek istiyor musunuz?",
|
||||||
|
|
||||||
|
"videoStartOverButtonLabel": "BAŞTAN BAŞLA",
|
||||||
|
"videoResumeButtonLabel": "SÜRDÜR",
|
||||||
|
|
||||||
|
"setCoverDialogLatest": "Son öğe",
|
||||||
|
"setCoverDialogAuto": "Otomatik",
|
||||||
|
"setCoverDialogCustom": "Özel",
|
||||||
|
|
||||||
|
"hideFilterConfirmationDialogMessage": "Eşleşen fotoğraf ve videolar koleksiyonunuzdan gizlenecektir. Bunları “Gizlilik”, ayarlarından tekrar gösterebilirsiniz.\n\nBunları gizlemek istediğinizden emin misiniz?",
|
||||||
|
|
||||||
|
"newAlbumDialogTitle": "Yeni Albüm",
|
||||||
|
"newAlbumDialogNameLabel": "Albüm adı",
|
||||||
|
"newAlbumDialogNameLabelAlreadyExistsHelper": "Dizin zaten var",
|
||||||
|
"newAlbumDialogStorageLabel": "Depolama:",
|
||||||
|
|
||||||
|
"renameAlbumDialogLabel": "Yeni ad",
|
||||||
|
"renameAlbumDialogLabelAlreadyExistsHelper": "Dizin zaten var",
|
||||||
|
|
||||||
|
"renameEntrySetPageTitle": "Yeniden adlandır",
|
||||||
|
"renameEntrySetPagePatternFieldLabel": "İsimlendirme şekli",
|
||||||
|
"renameEntrySetPageInsertTooltip": "Alan ekle",
|
||||||
|
"renameEntrySetPagePreview": "Önizleme",
|
||||||
|
|
||||||
|
"renameProcessorCounter": "Sayaç",
|
||||||
|
"renameProcessorName": "Ad",
|
||||||
|
|
||||||
|
"deleteSingleAlbumConfirmationDialogMessage": "{count, plural, =1{Bu albüm ve öğesi silinsin mi?} other{Bu albüm ve {count} öğesi silinsin mi?}}",
|
||||||
|
|
||||||
|
"deleteMultiAlbumConfirmationDialogMessage": "{count, plural, =1{Bu albümler ve öğeleri silinsin mi?} other{Bu albümler ve {count} öğesi silinsin mi?}}",
|
||||||
|
|
||||||
|
"exportEntryDialogFormat": "Biçim:",
|
||||||
|
"exportEntryDialogWidth": "Genişlik",
|
||||||
|
"exportEntryDialogHeight": "Yükseklik",
|
||||||
|
|
||||||
|
"renameEntryDialogLabel": "Yeni ad",
|
||||||
|
|
||||||
|
"editEntryDateDialogTitle": "Tarih ve Saat",
|
||||||
|
"editEntryDateDialogSetCustom": "Özel tarih ayarla",
|
||||||
|
"editEntryDateDialogCopyField": "Başka bir tarihten kopyala",
|
||||||
|
"editEntryDateDialogCopyItem": "Başka bir öğeden kopyala",
|
||||||
|
"editEntryDateDialogExtractFromTitle": "Başlıktan ayıkla",
|
||||||
|
"editEntryDateDialogShift": "Değişim",
|
||||||
|
"editEntryDateDialogSourceFileModifiedDate": "Dosya değiştirilme tarihi",
|
||||||
|
"editEntryDateDialogTargetFieldsHeader": "Değiştirilecek alanlar",
|
||||||
|
"editEntryDateDialogHours": "Saat",
|
||||||
|
"editEntryDateDialogMinutes": "Dakika",
|
||||||
|
|
||||||
|
"editEntryLocationDialogTitle": "Konum",
|
||||||
|
"editEntryLocationDialogChooseOnMapTooltip": "Harita üzerinde seç",
|
||||||
|
"editEntryLocationDialogLatitude": "Enlem",
|
||||||
|
"editEntryLocationDialogLongitude": "Boylam",
|
||||||
|
|
||||||
|
"locationPickerUseThisLocationButton": "Bu konumu kullan",
|
||||||
|
|
||||||
|
"editEntryRatingDialogTitle": "Derecelendirme",
|
||||||
|
|
||||||
|
"removeEntryMetadataDialogTitle": "Meta veri kaldırma",
|
||||||
|
"removeEntryMetadataDialogMore": "Daha fazla",
|
||||||
|
|
||||||
|
"removeEntryMetadataMotionPhotoXmpWarningDialogMessage": "Hareketli bir fotoğrafın içindeki videoyu oynatmak için XMP gereklidir.\n\nKaldırmak istediğinizden emin misiniz?",
|
||||||
|
"convertMotionPhotoToStillImageWarningDialogMessage": "Emin misiniz?",
|
||||||
|
|
||||||
|
"videoSpeedDialogLabel": "Oynatma hızı",
|
||||||
|
|
||||||
|
"videoStreamSelectionDialogVideo": "Video",
|
||||||
|
"videoStreamSelectionDialogAudio": "Ses",
|
||||||
|
"videoStreamSelectionDialogText": "Altyazı",
|
||||||
|
"videoStreamSelectionDialogOff": "Kapalı",
|
||||||
|
"videoStreamSelectionDialogTrack": "Parça",
|
||||||
|
"videoStreamSelectionDialogNoSelection": "Başka parça yok.",
|
||||||
|
|
||||||
|
"genericSuccessFeedback": "Başarılı!",
|
||||||
|
"genericFailureFeedback": "Başarısız",
|
||||||
|
|
||||||
|
"menuActionConfigureView": "Görünüm",
|
||||||
|
"menuActionSelect": "Seç",
|
||||||
|
"menuActionSelectAll": "Hepsini seç",
|
||||||
|
"menuActionSelectNone": "Hiçbirini seçme",
|
||||||
|
"menuActionMap": "Harita",
|
||||||
|
"menuActionStats": "İstatistikler",
|
||||||
|
|
||||||
|
"viewDialogTabSort": "Sırala",
|
||||||
|
"viewDialogTabGroup": "Grup",
|
||||||
|
"viewDialogTabLayout": "Düzen",
|
||||||
|
|
||||||
|
"tileLayoutGrid": "Izgara",
|
||||||
|
"tileLayoutList": "Liste",
|
||||||
|
|
||||||
|
"coverDialogTabCover": "Kapak",
|
||||||
|
"coverDialogTabApp": "Uygulama",
|
||||||
|
"coverDialogTabColor": "Renk",
|
||||||
|
|
||||||
|
"appPickDialogTitle": "Uygulama seç",
|
||||||
|
"appPickDialogNone": "Yok",
|
||||||
|
|
||||||
|
"aboutPageTitle": "Hakkında",
|
||||||
|
"aboutLinkSources": "Kaynaklar",
|
||||||
|
"aboutLinkLicense": "Lisans",
|
||||||
|
"aboutLinkPolicy": "Gizlilik Politikası",
|
||||||
|
|
||||||
|
"aboutBug": "Hata Bildirimi",
|
||||||
|
"aboutBugSaveLogInstruction": "Uygulama günlüklerini bir dosyaya kaydet",
|
||||||
|
"aboutBugSaveLogButton": "Kaydet",
|
||||||
|
"aboutBugCopyInfoInstruction": "Sistem bilgilerini kopyala",
|
||||||
|
"aboutBugCopyInfoButton": "Kopyala",
|
||||||
|
"aboutBugReportInstruction": "GitHub'da günlükleri ve sistem bilgilerini içeren bir rapor oluştur",
|
||||||
|
"aboutBugReportButton": "Raporla",
|
||||||
|
|
||||||
|
"aboutCredits": "Kredi",
|
||||||
|
"aboutCreditsWorldAtlas1": "Bu uygulama bir TopoJSON dosyası kullanır",
|
||||||
|
"aboutCreditsWorldAtlas2": "ISC Lisansı kapsamında.",
|
||||||
|
"aboutCreditsTranslators": "Tercümanlar",
|
||||||
|
|
||||||
|
"aboutLicenses": "Açık Kaynak Lisansları",
|
||||||
|
"aboutLicensesBanner": "Bu uygulama aşağıdaki açık kaynaklı paketleri ve kütüphaneleri kullanır.",
|
||||||
|
"aboutLicensesAndroidLibraries": "Android Kütüphaneleri",
|
||||||
|
"aboutLicensesFlutterPlugins": "Flutter Eklentileri",
|
||||||
|
"aboutLicensesFlutterPackages": "Flutter Paketleri",
|
||||||
|
"aboutLicensesDartPackages": "Dart Paketleri",
|
||||||
|
"aboutLicensesShowAllButtonLabel": "Tüm Lisansları Göster",
|
||||||
|
|
||||||
|
"policyPageTitle": "Gizlilik Politikası",
|
||||||
|
|
||||||
|
"collectionPageTitle": "Koleksiyon",
|
||||||
|
"collectionPickPageTitle": "Seç",
|
||||||
|
"collectionSelectPageTitle": "Öğeleri seç",
|
||||||
|
|
||||||
|
"collectionActionShowTitleSearch": "Başlık filtresini göster",
|
||||||
|
"collectionActionHideTitleSearch": "Başlık filtresini gizle",
|
||||||
|
"collectionActionAddShortcut": "Kısayol ekle",
|
||||||
|
"collectionActionEmptyBin": "Boş çöp kutusu",
|
||||||
|
"collectionActionCopy": "Albüme kopyala",
|
||||||
|
"collectionActionMove": "Albüme taşı",
|
||||||
|
"collectionActionRescan": "Yeniden tara",
|
||||||
|
"collectionActionEdit": "Düzenle",
|
||||||
|
|
||||||
|
"collectionSearchTitlesHintText": "Başlıkları ara",
|
||||||
|
|
||||||
|
"collectionSortDate": "Tarihe göre",
|
||||||
|
"collectionSortSize": "Boyuta göre",
|
||||||
|
"collectionSortName": "Albüm ve dosya adına göre",
|
||||||
|
"collectionSortRating": "Derecelendirmeye göre",
|
||||||
|
|
||||||
|
"collectionGroupAlbum": "Albüme göre",
|
||||||
|
"collectionGroupMonth": "Aya göre",
|
||||||
|
"collectionGroupDay": "Güne göre",
|
||||||
|
"collectionGroupNone": "Gruplama",
|
||||||
|
|
||||||
|
"sectionUnknown": "Bilinmeyen",
|
||||||
|
"dateToday": "Bugün",
|
||||||
|
"dateYesterday": "Dün",
|
||||||
|
"dateThisMonth": "Bu ay",
|
||||||
|
"collectionDeleteFailureFeedback": "{count, plural, =1{1 öğe silinemedi} other{{count} öğe silinemedi}}",
|
||||||
|
|
||||||
|
"collectionCopyFailureFeedback": "{count, plural, =1{1 öğe kopyalanamadı} other{{count} öğe kopyalanamadı}}",
|
||||||
|
|
||||||
|
"collectionMoveFailureFeedback": "{count, plural, =1{1 öğe taşınamadı} other{{count} öğe taşınamadı}}",
|
||||||
|
|
||||||
|
"collectionRenameFailureFeedback": "{count, plural, =1{1 öğenin adı değiştirilemedi} other{{count} öğenin adı değiştirilemedi}}",
|
||||||
|
|
||||||
|
"collectionEditFailureFeedback": "{count, plural, =1{1 öğe düzenlenemedi} other{{count} öğe düzenlenemedi}}",
|
||||||
|
|
||||||
|
"collectionExportFailureFeedback": "{count, plural, =1{1 sayfa dışa aktarılamadı} other{{count} sayfa dışa aktarılamadı}",
|
||||||
|
|
||||||
|
"collectionCopySuccessFeedback": "{count, plural, =1{1 öğe kopyalandı} other{{count} öğe kopyalandı}}",
|
||||||
|
|
||||||
|
"collectionMoveSuccessFeedback": "{count, plural, =1{1 öğe taşındı} other{{count} öğe taşındı}}",
|
||||||
|
|
||||||
|
"collectionRenameSuccessFeedback": "{count, plural, =1{1 öğenin adı değiştirildi} other{{count} öğenin adı değiştirildi}}",
|
||||||
|
|
||||||
|
"collectionEditSuccessFeedback": "{count, plural, =1{1 öğe düzenlendi} other{{count} öğe düzenlendi}}",
|
||||||
|
|
||||||
|
"collectionEmptyFavourites": "Favori yok",
|
||||||
|
"collectionEmptyVideos": "Video yok",
|
||||||
|
"collectionEmptyImages": "Resim yok",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "Erişim izni",
|
||||||
|
|
||||||
|
"collectionSelectSectionTooltip": "Bölüm seç",
|
||||||
|
"collectionDeselectSectionTooltip": "Bölüm seçimini kaldır",
|
||||||
|
|
||||||
|
"drawerCollectionAll": "Tüm koleksiyon",
|
||||||
|
"drawerCollectionFavourites": "Favoriler",
|
||||||
|
"drawerCollectionImages": "Resimler",
|
||||||
|
"drawerCollectionVideos": "Videolar",
|
||||||
|
"drawerCollectionAnimated": "Hareketli",
|
||||||
|
"drawerCollectionMotionPhotos": "Hareketli fotoğraflar",
|
||||||
|
"drawerCollectionPanoramas": "Panoramalar",
|
||||||
|
"drawerCollectionRaws": "Raw fotoğraflar",
|
||||||
|
"drawerCollectionSphericalVideos": "360° Videolar",
|
||||||
|
|
||||||
|
"chipSortDate": "Tarihe göre",
|
||||||
|
"chipSortName": "Adına göre",
|
||||||
|
"chipSortCount": "Öğe sayısına göre",
|
||||||
|
|
||||||
|
"albumGroupTier": "Kademeye göre",
|
||||||
|
"albumGroupVolume": "Depolama hacmine göre",
|
||||||
|
"albumGroupNone": "Gruplama",
|
||||||
|
|
||||||
|
"albumPickPageTitleCopy": "Albüme kopyala",
|
||||||
|
"albumPickPageTitleExport": "Albüme aktar",
|
||||||
|
"albumPickPageTitleMove": "Albüme taşı",
|
||||||
|
"albumPickPageTitlePick": "Albüm seç",
|
||||||
|
|
||||||
|
"albumCamera": "Kamera",
|
||||||
|
"albumDownload": "İndir",
|
||||||
|
"albumScreenshots": "Ekran görüntüleri",
|
||||||
|
"albumScreenRecordings": "Ekran kayıtları",
|
||||||
|
"albumVideoCaptures": "Video çekimleri",
|
||||||
|
|
||||||
|
"albumPageTitle": "Albümler",
|
||||||
|
"albumEmpty": "Albüm yok",
|
||||||
|
"createAlbumTooltip": "Albüm oluştur",
|
||||||
|
"createAlbumButtonLabel": "OLUŞTUR",
|
||||||
|
"newFilterBanner": "yeni",
|
||||||
|
|
||||||
|
"countryPageTitle": "Ülkeler",
|
||||||
|
"countryEmpty": "Ülke yok",
|
||||||
|
|
||||||
|
"tagPageTitle": "Etiketler",
|
||||||
|
"tagEmpty": "Etiket yok",
|
||||||
|
|
||||||
|
"binPageTitle": "Geri Dönüşüm Kutusu",
|
||||||
|
|
||||||
|
"searchCollectionFieldHint": "Koleksiyonu ara",
|
||||||
|
"searchSectionRecent": "Yakın zamanda",
|
||||||
|
"searchSectionAlbums": "Albümler",
|
||||||
|
"searchSectionCountries": "Ülkeler",
|
||||||
|
"searchSectionPlaces": "Yerler",
|
||||||
|
"searchSectionTags": "Etiketler",
|
||||||
|
"searchSectionRating": "Derecelendirmeler",
|
||||||
|
|
||||||
|
"settingsPageTitle": "Ayarlar",
|
||||||
|
"settingsSystemDefault": "Sistem",
|
||||||
|
"settingsDefault": "Varsayılan",
|
||||||
|
|
||||||
|
"settingsSearchFieldLabel": "Ayarlarda ara",
|
||||||
|
"settingsSearchEmpty": "Eşleşen ayar bulunamadı",
|
||||||
|
"settingsActionExport": "Dışa aktar",
|
||||||
|
"settingsActionImport": "İçe aktar",
|
||||||
|
|
||||||
|
"appExportCovers": "Kapaklar",
|
||||||
|
"appExportFavourites": "Favoriler",
|
||||||
|
"appExportSettings": "Ayarlar",
|
||||||
|
|
||||||
|
"settingsSectionNavigation": "Gezinti",
|
||||||
|
"settingsHome": "Anasayfa",
|
||||||
|
"settingsShowBottomNavigationBar": "Alt gezinti çubuğunu göster",
|
||||||
|
"settingsKeepScreenOnTile": "Ekranı açık tut",
|
||||||
|
"settingsKeepScreenOnTitle": "Ekranı Açık Tut",
|
||||||
|
"settingsDoubleBackExit": "Çıkmak için iki kez “geri” düğmesine dokunun",
|
||||||
|
|
||||||
|
"settingsConfirmationDialogTile": "Onaylama diyalogları",
|
||||||
|
"settingsConfirmationDialogTitle": "Onaylama Diyalogları",
|
||||||
|
"settingsConfirmationDialogDeleteItems": "Öğeleri sonsuza dek silmeden önce sor",
|
||||||
|
"settingsConfirmationDialogMoveToBinItems": "Eşyaları geri dönüşüm kutusuna atmadan önce sor",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems": "Tarihsiz eşyaları taşımadan önce sor",
|
||||||
|
|
||||||
|
"settingsNavigationDrawerTile": "Gezinti menüsü",
|
||||||
|
"settingsNavigationDrawerEditorTitle": "Gezinti Menüsü",
|
||||||
|
"settingsNavigationDrawerBanner": "Menü öğelerini taşımak ve yeniden sıralamak için dokunun ve basılı tutun.",
|
||||||
|
"settingsNavigationDrawerTabTypes": "Türler",
|
||||||
|
"settingsNavigationDrawerTabAlbums": "Albümler",
|
||||||
|
"settingsNavigationDrawerTabPages": "Sayfalar",
|
||||||
|
"settingsNavigationDrawerAddAlbum": "Albüm ekle",
|
||||||
|
|
||||||
|
"settingsSectionThumbnails": "Küçük resimler",
|
||||||
|
"settingsThumbnailOverlayTile": "Kaplama",
|
||||||
|
"settingsThumbnailOverlayTitle": "Kaplama",
|
||||||
|
"settingsThumbnailShowFavouriteIcon": "Favori simgeyi göster",
|
||||||
|
"settingsThumbnailShowTagIcon": "Etiket simgesini göster",
|
||||||
|
"settingsThumbnailShowLocationIcon": "Konum simgesini göster",
|
||||||
|
"settingsThumbnailShowMotionPhotoIcon": "Hareketli fotoğraf simgesini göster",
|
||||||
|
"settingsThumbnailShowRating": "Derecelendirmeyi göster",
|
||||||
|
"settingsThumbnailShowRawIcon": "Raw simgesini göster",
|
||||||
|
"settingsThumbnailShowVideoDuration": "Video süresini göster",
|
||||||
|
|
||||||
|
"settingsCollectionQuickActionsTile": "Hızlı eylemler",
|
||||||
|
"settingsCollectionQuickActionEditorTitle": "Hızlı Eylemler",
|
||||||
|
"settingsCollectionQuickActionTabBrowsing": "Gözatma",
|
||||||
|
"settingsCollectionQuickActionTabSelecting": "Seçme",
|
||||||
|
"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.",
|
||||||
|
"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.",
|
||||||
|
|
||||||
|
"settingsSectionViewer": "Görüntüleyici",
|
||||||
|
"settingsViewerUseCutout": "Kesim alanını kullan",
|
||||||
|
"settingsViewerMaximumBrightness": "Maksimum parlaklık",
|
||||||
|
"settingsMotionPhotoAutoPlay": "Hareketli fotoğrafları otomatik oynat",
|
||||||
|
"settingsImageBackground": "Resim arka planı",
|
||||||
|
|
||||||
|
"settingsViewerQuickActionsTile": "Hızlı eylemler",
|
||||||
|
"settingsViewerQuickActionEditorTitle": "Hızlı Eylemler",
|
||||||
|
"settingsViewerQuickActionEditorBanner": "Düğmeleri hareket ettirmek ve görüntüleyicide hangi eylemlerin görüntüleneceğini seçmek için dokunun ve basılı tutun.",
|
||||||
|
"settingsViewerQuickActionEditorDisplayedButtons": "Gösterilen Düğmeler",
|
||||||
|
"settingsViewerQuickActionEditorAvailableButtons": "Mevcut Düğmeler",
|
||||||
|
"settingsViewerQuickActionEmpty": "Düğme yok",
|
||||||
|
|
||||||
|
"settingsViewerOverlayTile": "Kaplama",
|
||||||
|
"settingsViewerOverlayTitle": "Kaplama",
|
||||||
|
"settingsViewerShowOverlayOnOpening": "Açılışta göster",
|
||||||
|
"settingsViewerShowMinimap": "Mini haritayı göster",
|
||||||
|
"settingsViewerShowInformation": "Bilgileri göster",
|
||||||
|
"settingsViewerShowInformationSubtitle": "Başlığı, tarihi, konumu vb. göster.",
|
||||||
|
"settingsViewerShowShootingDetails": "Çekim ayrıntılarını göster",
|
||||||
|
"settingsViewerShowOverlayThumbnails": "Küçük resimleri göster",
|
||||||
|
"settingsViewerEnableOverlayBlurEffect": "Bulanıklık efekti",
|
||||||
|
|
||||||
|
"settingsVideoPageTitle": "Video Ayarları",
|
||||||
|
"settingsSectionVideo": "Video",
|
||||||
|
"settingsVideoShowVideos": "Videoları göster",
|
||||||
|
"settingsVideoEnableHardwareAcceleration": "Donanım hızlandırma",
|
||||||
|
"settingsVideoEnableAutoPlay": "Otomatik oynat",
|
||||||
|
"settingsVideoLoopModeTile": "Döngü modu",
|
||||||
|
"settingsVideoLoopModeTitle": "Döngü Modu",
|
||||||
|
|
||||||
|
"settingsSubtitleThemeTile": "Altyazılar",
|
||||||
|
"settingsSubtitleThemeTitle": "Altyazılar",
|
||||||
|
"settingsSubtitleThemeSample": "Bu bir örnek.",
|
||||||
|
"settingsSubtitleThemeTextAlignmentTile": "Metin hizalama",
|
||||||
|
"settingsSubtitleThemeTextAlignmentTitle": "Metin Hizalama",
|
||||||
|
"settingsSubtitleThemeTextSize": "Metin boyutu",
|
||||||
|
"settingsSubtitleThemeShowOutline": "Dış çizgiyi ve gölgeyi göster",
|
||||||
|
"settingsSubtitleThemeTextColor": "Metin rengi",
|
||||||
|
"settingsSubtitleThemeTextOpacity": "Metin opaklığı",
|
||||||
|
"settingsSubtitleThemeBackgroundColor": "Arka plan rengi",
|
||||||
|
"settingsSubtitleThemeBackgroundOpacity": "Arka plan opaklığı",
|
||||||
|
"settingsSubtitleThemeTextAlignmentLeft": "Sol",
|
||||||
|
"settingsSubtitleThemeTextAlignmentCenter": "Merkez",
|
||||||
|
"settingsSubtitleThemeTextAlignmentRight": "Sağ",
|
||||||
|
|
||||||
|
"settingsVideoControlsTile": "Kontroller",
|
||||||
|
"settingsVideoControlsTitle": "Kontroller",
|
||||||
|
"settingsVideoButtonsTile": "Düğmeler",
|
||||||
|
"settingsVideoButtonsTitle": "Düğmeler",
|
||||||
|
"settingsVideoGestureDoubleTapTogglePlay": "Oynatmak/duraklatmak için çift dokunun",
|
||||||
|
"settingsVideoGestureSideDoubleTapSeek": "Geri/ileri aramak için ekran kenarlarına çift dokunun",
|
||||||
|
|
||||||
|
"settingsSectionPrivacy": "Gizlilik",
|
||||||
|
"settingsAllowInstalledAppAccess": "Uygulama envanterine erişime izin ver",
|
||||||
|
"settingsAllowInstalledAppAccessSubtitle": "Albüm görüntüsünü iyileştirmek için kullanılır",
|
||||||
|
"settingsAllowErrorReporting": "Anonim hata raporlamasına izin ver",
|
||||||
|
"settingsSaveSearchHistory": "Arama geçmişini kaydet",
|
||||||
|
"settingsEnableBin": "Geri dönüşüm kutusunu kullan",
|
||||||
|
"settingsEnableBinSubtitle": "Silinen öğeleri 30 gün boyunca saklar",
|
||||||
|
|
||||||
|
"settingsHiddenItemsTile": "Gizli öğeler",
|
||||||
|
"settingsHiddenItemsTitle": "Gizli Öğeler",
|
||||||
|
|
||||||
|
"settingsHiddenFiltersTitle": "Gizli Filtreler",
|
||||||
|
"settingsHiddenFiltersBanner": "Gizli filtrelerle eşleşen fotoğraflar ve videolar koleksiyonunuzda görünmeyecektir.",
|
||||||
|
"settingsHiddenFiltersEmpty": "Gizli filtre yok",
|
||||||
|
|
||||||
|
"settingsHiddenPathsTitle": "Gizli Yollar",
|
||||||
|
"settingsHiddenPathsBanner": "Bu klasörlerdeki veya alt klasörlerindeki fotoğraflar ve videolar koleksiyonunuzda görünmeyecektir.",
|
||||||
|
"addPathTooltip": "Yol ekle",
|
||||||
|
|
||||||
|
"settingsStorageAccessTile": "Depolama erişimi",
|
||||||
|
"settingsStorageAccessTitle": "Depolama Erişimi",
|
||||||
|
"settingsStorageAccessBanner": "Bazı dizinler, içlerindeki dosyaları değiştirmek için açık bir erişim izni gerektirir. Daha önce erişim izni verdiğiniz dizinleri buradan inceleyebilirsiniz.",
|
||||||
|
"settingsStorageAccessEmpty": "Erişim izni yok",
|
||||||
|
"settingsStorageAccessRevokeTooltip": "Geri al",
|
||||||
|
|
||||||
|
"settingsSectionAccessibility": "Erişilebilirlik",
|
||||||
|
"settingsRemoveAnimationsTile": "Animasyonları kaldır",
|
||||||
|
"settingsRemoveAnimationsTitle": "Animasyonları Kaldır",
|
||||||
|
"settingsTimeToTakeActionTile": "Harekete geçme zamanı",
|
||||||
|
"settingsTimeToTakeActionTitle": "Harekete Geçme Zamanı",
|
||||||
|
|
||||||
|
"settingsSectionDisplay": "Ekran",
|
||||||
|
"settingsThemeBrightness": "Tema",
|
||||||
|
"settingsThemeColorHighlights": "Renk vurguları",
|
||||||
|
"settingsThemeEnableDynamicColor": "Dinamik renk",
|
||||||
|
"settingsDisplayRefreshRateModeTile": "Görüntü yenileme hızı",
|
||||||
|
"settingsDisplayRefreshRateModeTitle": "Yenileme Hızı",
|
||||||
|
|
||||||
|
"settingsSectionLanguage": "Dil ve Biçimler",
|
||||||
|
"settingsLanguage": "Dil",
|
||||||
|
"settingsCoordinateFormatTile": "Koordinat formatı",
|
||||||
|
"settingsCoordinateFormatTitle": "Koordinat Formatı",
|
||||||
|
"settingsUnitSystemTile": "Birimler",
|
||||||
|
"settingsUnitSystemTitle": "Birimler",
|
||||||
|
|
||||||
|
"statsPageTitle": "İstatistikler",
|
||||||
|
"statsWithGps": "{count, plural, =1{1 konuma sahip öğe} other{{count} konuma sahip öğe}}",
|
||||||
|
"statsTopCountries": "Başlıca Ülkeler",
|
||||||
|
"statsTopPlaces": "Başlıca Yerler",
|
||||||
|
"statsTopTags": "Başlıca Etiketler",
|
||||||
|
|
||||||
|
"viewerOpenPanoramaButtonLabel": "PANORAMAYI AÇ",
|
||||||
|
"viewerErrorUnknown": "Tüh!",
|
||||||
|
"viewerErrorDoesNotExist": "Dosya artık mevcut değil.",
|
||||||
|
|
||||||
|
"viewerInfoPageTitle": "Bilgi",
|
||||||
|
"viewerInfoBackToViewerTooltip": "Görüntüleyiciye geri dön",
|
||||||
|
|
||||||
|
"viewerInfoUnknown": "bilinmeyen",
|
||||||
|
"viewerInfoLabelTitle": "Başlık",
|
||||||
|
"viewerInfoLabelDate": "Tarih",
|
||||||
|
"viewerInfoLabelResolution": "Çözünürlük",
|
||||||
|
"viewerInfoLabelSize": "Boyut",
|
||||||
|
"viewerInfoLabelUri": "URI",
|
||||||
|
"viewerInfoLabelPath": "Yol",
|
||||||
|
"viewerInfoLabelDuration": "Süre",
|
||||||
|
"viewerInfoLabelOwner": "Sahibi",
|
||||||
|
"viewerInfoLabelCoordinates": "Koordinatlar",
|
||||||
|
"viewerInfoLabelAddress": "Adres",
|
||||||
|
|
||||||
|
"mapStyleTitle": "Harita Şekli",
|
||||||
|
"mapStyleTooltip": "Harita şeklini seç",
|
||||||
|
"mapZoomInTooltip": "Yakınlaştır",
|
||||||
|
"mapZoomOutTooltip": "Uzaklaştır",
|
||||||
|
"mapPointNorthUpTooltip": "Kuzeyi göster",
|
||||||
|
"mapAttributionOsmHot": "Harita verileri © [OpenStreetMap](https://www.openstreetmap.org/copyright) katkıda bulunanlar - Kutucuklar [HOT](https://www.hotosm.org/) tarafından hazırlanmıştır - [OSM France](https://openstreetmap.fr/) tarafından barındırılmaktadır",
|
||||||
|
"mapAttributionStamen": "Harita verileri © [OpenStreetMap](https://www.openstreetmap.org/copyright) katkıda bulunanlar - Döşemeler [Stamen Design](http://stamen.com), [CC BY 3.0](http://creativecommons.org/licenses/by/3.0)",
|
||||||
|
"openMapPageTooltip": "Harita sayfasında görüntüle",
|
||||||
|
"mapEmptyRegion": "Bu bölgede resim yok",
|
||||||
|
|
||||||
|
"viewerInfoOpenEmbeddedFailureFeedback": "Gömülü veriler ayıklanamadı",
|
||||||
|
"viewerInfoOpenLinkText": "Aç",
|
||||||
|
"viewerInfoViewXmlLinkText": "XML'i Görüntüle",
|
||||||
|
|
||||||
|
"viewerInfoSearchFieldLabel": "Meta verileri ara",
|
||||||
|
"viewerInfoSearchEmpty": "Eşleşen anahtar yok",
|
||||||
|
"viewerInfoSearchSuggestionDate": "Tarih ve saat",
|
||||||
|
"viewerInfoSearchSuggestionDescription": "Açıklama",
|
||||||
|
"viewerInfoSearchSuggestionDimensions": "Boyutlar",
|
||||||
|
"viewerInfoSearchSuggestionResolution": "Çözünürlük",
|
||||||
|
"viewerInfoSearchSuggestionRights": "Haklar",
|
||||||
|
|
||||||
|
"tagEditorPageTitle": "Etiketleri Düzenle",
|
||||||
|
"tagEditorPageNewTagFieldLabel": "Yeni etiket",
|
||||||
|
"tagEditorPageAddTagTooltip": "Etiket ekle",
|
||||||
|
"tagEditorSectionRecent": "Yakın zamanda",
|
||||||
|
|
||||||
|
"panoramaEnableSensorControl": "Sensör kontrolünü etkinleştir",
|
||||||
|
"panoramaDisableSensorControl": "Sensör kontrolünü devre dışı bırak",
|
||||||
|
|
||||||
|
"sourceViewerPageTitle": "Kaynak",
|
||||||
|
|
||||||
|
"filePickerShowHiddenFiles": "Gizli dosyaları göster",
|
||||||
|
"filePickerDoNotShowHiddenFiles": "Gizli dosyaları gösterme",
|
||||||
|
"filePickerOpenFrom": "Şuradan aç",
|
||||||
|
"filePickerNoItems": "Öğe yok",
|
||||||
|
"filePickerUseThisFolder": "Bu klasörü kullan"
|
||||||
|
}
|
|
@ -50,6 +50,7 @@
|
||||||
"entryActionDelete": "删除",
|
"entryActionDelete": "删除",
|
||||||
"entryActionConvert": "转换",
|
"entryActionConvert": "转换",
|
||||||
"entryActionExport": "导出",
|
"entryActionExport": "导出",
|
||||||
|
"entryActionInfo": "信息",
|
||||||
"entryActionRename": "重命名",
|
"entryActionRename": "重命名",
|
||||||
"entryActionRestore": "恢复",
|
"entryActionRestore": "恢复",
|
||||||
"entryActionRotateCCW": "逆时针旋转",
|
"entryActionRotateCCW": "逆时针旋转",
|
||||||
|
@ -80,6 +81,9 @@
|
||||||
"videoActionSetSpeed": "播放速度",
|
"videoActionSetSpeed": "播放速度",
|
||||||
"videoActionSettings": "设置",
|
"videoActionSettings": "设置",
|
||||||
|
|
||||||
|
"slideshowActionResume": "继续",
|
||||||
|
"slideshowActionShowInCollection": "在媒体集中显示",
|
||||||
|
|
||||||
"entryInfoActionEditDate": "编辑日期和时间",
|
"entryInfoActionEditDate": "编辑日期和时间",
|
||||||
"entryInfoActionEditLocation": "编辑位置",
|
"entryInfoActionEditLocation": "编辑位置",
|
||||||
"entryInfoActionEditRating": "修改评分",
|
"entryInfoActionEditRating": "修改评分",
|
||||||
|
@ -144,10 +148,23 @@
|
||||||
"displayRefreshRatePreferHighest": "最高刷新率",
|
"displayRefreshRatePreferHighest": "最高刷新率",
|
||||||
"displayRefreshRatePreferLowest": "最低刷新率",
|
"displayRefreshRatePreferLowest": "最低刷新率",
|
||||||
|
|
||||||
|
"slideshowVideoPlaybackSkip": "跳过",
|
||||||
|
"slideshowVideoPlaybackMuted": "静音播放",
|
||||||
|
"slideshowVideoPlaybackWithSound": "带音播放",
|
||||||
|
|
||||||
"themeBrightnessLight": "浅色",
|
"themeBrightnessLight": "浅色",
|
||||||
"themeBrightnessDark": "深色",
|
"themeBrightnessDark": "深色",
|
||||||
"themeBrightnessBlack": "黑色",
|
"themeBrightnessBlack": "黑色",
|
||||||
|
|
||||||
|
"viewerTransitionSlide": "滑动",
|
||||||
|
"viewerTransitionParallax": "视差滚动",
|
||||||
|
"viewerTransitionFade": "淡入淡出",
|
||||||
|
"viewerTransitionZoomIn": "放大",
|
||||||
|
|
||||||
|
"wallpaperTargetHome": "主屏幕",
|
||||||
|
"wallpaperTargetLock": "锁屏界面",
|
||||||
|
"wallpaperTargetHomeLock": "主屏幕 + 锁屏界面",
|
||||||
|
|
||||||
"albumTierNew": "新的",
|
"albumTierNew": "新的",
|
||||||
"albumTierPinned": "钉选",
|
"albumTierPinned": "钉选",
|
||||||
"albumTierSpecial": "普通",
|
"albumTierSpecial": "普通",
|
||||||
|
@ -262,6 +279,7 @@
|
||||||
"menuActionSelectAll": "全选",
|
"menuActionSelectAll": "全选",
|
||||||
"menuActionSelectNone": "全不选",
|
"menuActionSelectNone": "全不选",
|
||||||
"menuActionMap": "地图",
|
"menuActionMap": "地图",
|
||||||
|
"menuActionSlideshow": "幻灯片",
|
||||||
"menuActionStats": "统计",
|
"menuActionStats": "统计",
|
||||||
|
|
||||||
"viewDialogTabSort": "排序",
|
"viewDialogTabSort": "排序",
|
||||||
|
@ -349,6 +367,7 @@
|
||||||
"collectionEmptyFavourites": "无收藏项",
|
"collectionEmptyFavourites": "无收藏项",
|
||||||
"collectionEmptyVideos": "无视频",
|
"collectionEmptyVideos": "无视频",
|
||||||
"collectionEmptyImages": "无图像",
|
"collectionEmptyImages": "无图像",
|
||||||
|
"collectionEmptyGrantAccessButtonLabel": "授予访问权限",
|
||||||
|
|
||||||
"collectionSelectSectionTooltip": "选择部分",
|
"collectionSelectSectionTooltip": "选择部分",
|
||||||
"collectionDeselectSectionTooltip": "取消选择部分",
|
"collectionDeselectSectionTooltip": "取消选择部分",
|
||||||
|
@ -479,6 +498,17 @@
|
||||||
"settingsViewerShowOverlayThumbnails": "显示缩略图",
|
"settingsViewerShowOverlayThumbnails": "显示缩略图",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "模糊特效",
|
"settingsViewerEnableOverlayBlurEffect": "模糊特效",
|
||||||
|
|
||||||
|
"settingsViewerSlideshowTile": "幻灯片",
|
||||||
|
"settingsViewerSlideshowTitle": "幻灯片",
|
||||||
|
"settingsSlideshowRepeat": "重复",
|
||||||
|
"settingsSlideshowShuffle": "随机播放",
|
||||||
|
"settingsSlideshowTransitionTile": "过渡动画",
|
||||||
|
"settingsSlideshowTransitionTitle": "过渡动画",
|
||||||
|
"settingsSlideshowIntervalTile": "时间间隔",
|
||||||
|
"settingsSlideshowIntervalTitle": "时间间隔",
|
||||||
|
"settingsSlideshowVideoPlaybackTile": "视频回放",
|
||||||
|
"settingsSlideshowVideoPlaybackTitle": "视频回放",
|
||||||
|
|
||||||
"settingsVideoPageTitle": "视频设置",
|
"settingsVideoPageTitle": "视频设置",
|
||||||
"settingsSectionVideo": "视频",
|
"settingsSectionVideo": "视频",
|
||||||
"settingsVideoShowVideos": "显示视频",
|
"settingsVideoShowVideos": "显示视频",
|
||||||
|
@ -543,6 +573,7 @@
|
||||||
"settingsSectionDisplay": "显示",
|
"settingsSectionDisplay": "显示",
|
||||||
"settingsThemeBrightness": "主题",
|
"settingsThemeBrightness": "主题",
|
||||||
"settingsThemeColorHighlights": "色彩强调",
|
"settingsThemeColorHighlights": "色彩强调",
|
||||||
|
"settingsThemeEnableDynamicColor": "动态色彩",
|
||||||
"settingsDisplayRefreshRateModeTile": "显示刷新率",
|
"settingsDisplayRefreshRateModeTile": "显示刷新率",
|
||||||
"settingsDisplayRefreshRateModeTitle": "刷新率",
|
"settingsDisplayRefreshRateModeTitle": "刷新率",
|
||||||
|
|
||||||
|
@ -560,6 +591,7 @@
|
||||||
"statsTopTags": "热门标签",
|
"statsTopTags": "热门标签",
|
||||||
|
|
||||||
"viewerOpenPanoramaButtonLabel": "打开全景",
|
"viewerOpenPanoramaButtonLabel": "打开全景",
|
||||||
|
"viewerSetWallpaperButtonLabel": "设置壁纸",
|
||||||
"viewerErrorUnknown": "糟糕!",
|
"viewerErrorUnknown": "糟糕!",
|
||||||
"viewerErrorDoesNotExist": "该文件不存在",
|
"viewerErrorDoesNotExist": "该文件不存在",
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ enum ChipSetAction {
|
||||||
createAlbum,
|
createAlbum,
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
map,
|
map,
|
||||||
|
slideshow,
|
||||||
stats,
|
stats,
|
||||||
// selecting (single/multiple filters)
|
// selecting (single/multiple filters)
|
||||||
delete,
|
delete,
|
||||||
|
@ -36,6 +37,7 @@ class ChipSetActions {
|
||||||
ChipSetAction.search,
|
ChipSetAction.search,
|
||||||
ChipSetAction.createAlbum,
|
ChipSetAction.createAlbum,
|
||||||
ChipSetAction.map,
|
ChipSetAction.map,
|
||||||
|
ChipSetAction.slideshow,
|
||||||
ChipSetAction.stats,
|
ChipSetAction.stats,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -47,6 +49,7 @@ class ChipSetActions {
|
||||||
ChipSetAction.rename,
|
ChipSetAction.rename,
|
||||||
ChipSetAction.hide,
|
ChipSetAction.hide,
|
||||||
ChipSetAction.map,
|
ChipSetAction.map,
|
||||||
|
ChipSetAction.slideshow,
|
||||||
ChipSetAction.stats,
|
ChipSetAction.stats,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -71,6 +74,8 @@ extension ExtraChipSetAction on ChipSetAction {
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
case ChipSetAction.map:
|
case ChipSetAction.map:
|
||||||
return context.l10n.menuActionMap;
|
return context.l10n.menuActionMap;
|
||||||
|
case ChipSetAction.slideshow:
|
||||||
|
return context.l10n.menuActionSlideshow;
|
||||||
case ChipSetAction.stats:
|
case ChipSetAction.stats:
|
||||||
return context.l10n.menuActionStats;
|
return context.l10n.menuActionStats;
|
||||||
// selecting (single/multiple filters)
|
// selecting (single/multiple filters)
|
||||||
|
@ -111,6 +116,8 @@ extension ExtraChipSetAction on ChipSetAction {
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
case ChipSetAction.map:
|
case ChipSetAction.map:
|
||||||
return AIcons.map;
|
return AIcons.map;
|
||||||
|
case ChipSetAction.slideshow:
|
||||||
|
return AIcons.slideshow;
|
||||||
case ChipSetAction.stats:
|
case ChipSetAction.stats:
|
||||||
return AIcons.stats;
|
return AIcons.stats;
|
||||||
// selecting (single/multiple filters)
|
// selecting (single/multiple filters)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
enum EntryAction {
|
enum EntryAction {
|
||||||
|
info,
|
||||||
addShortcut,
|
addShortcut,
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
delete,
|
delete,
|
||||||
|
@ -43,6 +44,7 @@ enum EntryAction {
|
||||||
|
|
||||||
class EntryActions {
|
class EntryActions {
|
||||||
static const topLevel = [
|
static const topLevel = [
|
||||||
|
EntryAction.info,
|
||||||
EntryAction.share,
|
EntryAction.share,
|
||||||
EntryAction.edit,
|
EntryAction.edit,
|
||||||
EntryAction.rename,
|
EntryAction.rename,
|
||||||
|
@ -102,6 +104,8 @@ class EntryActions {
|
||||||
extension ExtraEntryAction on EntryAction {
|
extension ExtraEntryAction on EntryAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
|
case EntryAction.info:
|
||||||
|
return context.l10n.entryActionInfo;
|
||||||
case EntryAction.addShortcut:
|
case EntryAction.addShortcut:
|
||||||
return context.l10n.collectionActionAddShortcut;
|
return context.l10n.collectionActionAddShortcut;
|
||||||
case EntryAction.copyToClipboard:
|
case EntryAction.copyToClipboard:
|
||||||
|
@ -188,6 +192,8 @@ extension ExtraEntryAction on EntryAction {
|
||||||
|
|
||||||
IconData getIconData() {
|
IconData getIconData() {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
|
case EntryAction.info:
|
||||||
|
return AIcons.info;
|
||||||
case EntryAction.addShortcut:
|
case EntryAction.addShortcut:
|
||||||
return AIcons.addShortcut;
|
return AIcons.addShortcut;
|
||||||
case EntryAction.copyToClipboard:
|
case EntryAction.copyToClipboard:
|
||||||
|
|
|
@ -15,6 +15,7 @@ enum EntrySetAction {
|
||||||
emptyBin,
|
emptyBin,
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
map,
|
map,
|
||||||
|
slideshow,
|
||||||
stats,
|
stats,
|
||||||
rescan,
|
rescan,
|
||||||
// selecting
|
// selecting
|
||||||
|
@ -48,6 +49,7 @@ class EntrySetActions {
|
||||||
EntrySetAction.toggleTitleSearch,
|
EntrySetAction.toggleTitleSearch,
|
||||||
EntrySetAction.addShortcut,
|
EntrySetAction.addShortcut,
|
||||||
EntrySetAction.map,
|
EntrySetAction.map,
|
||||||
|
EntrySetAction.slideshow,
|
||||||
EntrySetAction.stats,
|
EntrySetAction.stats,
|
||||||
EntrySetAction.rescan,
|
EntrySetAction.rescan,
|
||||||
EntrySetAction.emptyBin,
|
EntrySetAction.emptyBin,
|
||||||
|
@ -59,6 +61,7 @@ class EntrySetActions {
|
||||||
EntrySetAction.toggleTitleSearch,
|
EntrySetAction.toggleTitleSearch,
|
||||||
EntrySetAction.addShortcut,
|
EntrySetAction.addShortcut,
|
||||||
EntrySetAction.map,
|
EntrySetAction.map,
|
||||||
|
EntrySetAction.slideshow,
|
||||||
EntrySetAction.stats,
|
EntrySetAction.stats,
|
||||||
EntrySetAction.rescan,
|
EntrySetAction.rescan,
|
||||||
];
|
];
|
||||||
|
@ -72,6 +75,7 @@ class EntrySetActions {
|
||||||
EntrySetAction.rename,
|
EntrySetAction.rename,
|
||||||
EntrySetAction.toggleFavourite,
|
EntrySetAction.toggleFavourite,
|
||||||
EntrySetAction.map,
|
EntrySetAction.map,
|
||||||
|
EntrySetAction.slideshow,
|
||||||
EntrySetAction.stats,
|
EntrySetAction.stats,
|
||||||
EntrySetAction.rescan,
|
EntrySetAction.rescan,
|
||||||
// editing actions are in their subsection
|
// editing actions are in their subsection
|
||||||
|
@ -86,6 +90,7 @@ class EntrySetActions {
|
||||||
EntrySetAction.rename,
|
EntrySetAction.rename,
|
||||||
EntrySetAction.toggleFavourite,
|
EntrySetAction.toggleFavourite,
|
||||||
EntrySetAction.map,
|
EntrySetAction.map,
|
||||||
|
EntrySetAction.slideshow,
|
||||||
EntrySetAction.stats,
|
EntrySetAction.stats,
|
||||||
EntrySetAction.rescan,
|
EntrySetAction.rescan,
|
||||||
// editing actions are in their subsection
|
// editing actions are in their subsection
|
||||||
|
@ -125,6 +130,8 @@ extension ExtraEntrySetAction on EntrySetAction {
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
return context.l10n.menuActionMap;
|
return context.l10n.menuActionMap;
|
||||||
|
case EntrySetAction.slideshow:
|
||||||
|
return context.l10n.menuActionSlideshow;
|
||||||
case EntrySetAction.stats:
|
case EntrySetAction.stats:
|
||||||
return context.l10n.menuActionStats;
|
return context.l10n.menuActionStats;
|
||||||
case EntrySetAction.rescan:
|
case EntrySetAction.rescan:
|
||||||
|
@ -190,6 +197,8 @@ extension ExtraEntrySetAction on EntrySetAction {
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
return AIcons.map;
|
return AIcons.map;
|
||||||
|
case EntrySetAction.slideshow:
|
||||||
|
return AIcons.slideshow;
|
||||||
case EntrySetAction.stats:
|
case EntrySetAction.stats:
|
||||||
return AIcons.stats;
|
return AIcons.stats;
|
||||||
case EntrySetAction.rescan:
|
case EntrySetAction.rescan:
|
||||||
|
|
30
lib/model/actions/slideshow_actions.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
enum SlideshowAction {
|
||||||
|
resume,
|
||||||
|
showInCollection,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExtraSlideshowAction on SlideshowAction {
|
||||||
|
String getText(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case SlideshowAction.resume:
|
||||||
|
return context.l10n.slideshowActionResume;
|
||||||
|
case SlideshowAction.showInCollection:
|
||||||
|
return context.l10n.slideshowActionShowInCollection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getIcon() => Icon(_getIconData());
|
||||||
|
|
||||||
|
IconData _getIconData() {
|
||||||
|
switch (this) {
|
||||||
|
case SlideshowAction.resume:
|
||||||
|
return AIcons.play;
|
||||||
|
case SlideshowAction.showInCollection:
|
||||||
|
return AIcons.allCollection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,8 @@ final Device device = Device._private();
|
||||||
|
|
||||||
class Device {
|
class Device {
|
||||||
late final String _userAgent;
|
late final String _userAgent;
|
||||||
late final bool _canGrantDirectoryAccess, _canPinShortcut, _canPrint, _canRenderFlagEmojis;
|
late final bool _canGrantDirectoryAccess, _canPinShortcut, _canPrint, _canRenderFlagEmojis, _canSetLockScreenWallpaper;
|
||||||
late final bool _showPinShortcutFeedback, _supportEdgeToEdgeUIMode;
|
late final bool _isDynamicColorAvailable, _showPinShortcutFeedback, _supportEdgeToEdgeUIMode;
|
||||||
|
|
||||||
String get userAgent => _userAgent;
|
String get userAgent => _userAgent;
|
||||||
|
|
||||||
|
@ -18,6 +18,10 @@ class Device {
|
||||||
|
|
||||||
bool get canRenderFlagEmojis => _canRenderFlagEmojis;
|
bool get canRenderFlagEmojis => _canRenderFlagEmojis;
|
||||||
|
|
||||||
|
bool get canSetLockScreenWallpaper => _canSetLockScreenWallpaper;
|
||||||
|
|
||||||
|
bool get isDynamicColorAvailable => _isDynamicColorAvailable;
|
||||||
|
|
||||||
bool get showPinShortcutFeedback => _showPinShortcutFeedback;
|
bool get showPinShortcutFeedback => _showPinShortcutFeedback;
|
||||||
|
|
||||||
bool get supportEdgeToEdgeUIMode => _supportEdgeToEdgeUIMode;
|
bool get supportEdgeToEdgeUIMode => _supportEdgeToEdgeUIMode;
|
||||||
|
@ -33,6 +37,8 @@ class Device {
|
||||||
_canPinShortcut = capabilities['canPinShortcut'] ?? false;
|
_canPinShortcut = capabilities['canPinShortcut'] ?? false;
|
||||||
_canPrint = capabilities['canPrint'] ?? false;
|
_canPrint = capabilities['canPrint'] ?? false;
|
||||||
_canRenderFlagEmojis = capabilities['canRenderFlagEmojis'] ?? false;
|
_canRenderFlagEmojis = capabilities['canRenderFlagEmojis'] ?? false;
|
||||||
|
_canSetLockScreenWallpaper = capabilities['canSetLockScreenWallpaper'] ?? false;
|
||||||
|
_isDynamicColorAvailable = capabilities['isDynamicColorAvailable'] ?? false;
|
||||||
_showPinShortcutFeedback = capabilities['showPinShortcutFeedback'] ?? false;
|
_showPinShortcutFeedback = capabilities['showPinShortcutFeedback'] ?? false;
|
||||||
_supportEdgeToEdgeUIMode = capabilities['supportEdgeToEdgeUIMode'] ?? false;
|
_supportEdgeToEdgeUIMode = capabilities['supportEdgeToEdgeUIMode'] ?? false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:ui';
|
||||||
|
|
||||||
import 'package:aves/geo/countries.dart';
|
import 'package:aves/geo/countries.dart';
|
||||||
import 'package:aves/model/entry_cache.dart';
|
import 'package:aves/model/entry_cache.dart';
|
||||||
|
import 'package:aves/model/entry_dirs.dart';
|
||||||
import 'package:aves/model/favourites.dart';
|
import 'package:aves/model/favourites.dart';
|
||||||
import 'package:aves/model/geotiff.dart';
|
import 'package:aves/model/geotiff.dart';
|
||||||
import 'package:aves/model/metadata/address.dart';
|
import 'package:aves/model/metadata/address.dart';
|
||||||
|
@ -31,7 +32,8 @@ class AvesEntry {
|
||||||
// `sizeBytes`, `dateModifiedSecs` can be missing in viewer mode
|
// `sizeBytes`, `dateModifiedSecs` can be missing in viewer mode
|
||||||
int id;
|
int id;
|
||||||
String uri;
|
String uri;
|
||||||
String? _path, _directory, _filename, _extension, _sourceTitle;
|
String? _path, _filename, _extension, _sourceTitle;
|
||||||
|
EntryDir? _directory;
|
||||||
int? pageId, contentId;
|
int? pageId, contentId;
|
||||||
final String sourceMimeType;
|
final String sourceMimeType;
|
||||||
int width, height, sourceRotationDegrees;
|
int width, height, sourceRotationDegrees;
|
||||||
|
@ -175,8 +177,8 @@ class AvesEntry {
|
||||||
|
|
||||||
// directory path, without the trailing separator
|
// directory path, without the trailing separator
|
||||||
String? get directory {
|
String? get directory {
|
||||||
_directory ??= path != null ? pContext.dirname(path!) : null;
|
_directory ??= entryDirRepo.getOrCreate(path != null ? pContext.dirname(path!) : null);
|
||||||
return _directory;
|
return _directory!.resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
String? get filenameWithoutExtension {
|
String? get filenameWithoutExtension {
|
||||||
|
|
68
lib/model/entry_dirs.dart
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
|
final entryDirRepo = EntryDirRepo._private();
|
||||||
|
|
||||||
|
class EntryDirRepo {
|
||||||
|
EntryDirRepo._private();
|
||||||
|
|
||||||
|
// mapping between the raw entry directory path to a resolvable directory
|
||||||
|
final Map<String?, EntryDir> _dirs = {};
|
||||||
|
final StreamController<EntryDir> _ambiguousDirStreamController = StreamController.broadcast();
|
||||||
|
|
||||||
|
Stream<EntryDir> get ambiguousDirStream => _ambiguousDirStreamController.stream;
|
||||||
|
|
||||||
|
// get a resolvable directory for a raw entry directory path
|
||||||
|
EntryDir getOrCreate(String? asIs) {
|
||||||
|
var entryDir = _dirs[asIs];
|
||||||
|
if (entryDir != null) return entryDir;
|
||||||
|
|
||||||
|
final asIsLower = asIs?.toLowerCase();
|
||||||
|
entryDir = _dirs.values.firstWhereOrNull((dir) => dir.asIsLower == asIsLower);
|
||||||
|
if (entryDir != null && !entryDir.ambiguous) {
|
||||||
|
entryDir.ambiguous = true;
|
||||||
|
_ambiguousDirStreamController.add(entryDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _dirs.putIfAbsent(asIs, () => entryDir ?? EntryDir(asIs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some directories are ambiguous because they use different cases,
|
||||||
|
// but the OS merge and present them as one directory.
|
||||||
|
// This class resolves ambiguous directories to get the directory path
|
||||||
|
// with the right case, as presented by the OS.
|
||||||
|
class EntryDir {
|
||||||
|
final String? asIs, asIsLower;
|
||||||
|
bool ambiguous = false;
|
||||||
|
String? _resolved;
|
||||||
|
|
||||||
|
EntryDir(this.asIs) : asIsLower = asIs?.toLowerCase();
|
||||||
|
|
||||||
|
String? get resolved {
|
||||||
|
if (!ambiguous) return asIs;
|
||||||
|
if (asIs == null) return null;
|
||||||
|
|
||||||
|
_resolved ??= _resolve();
|
||||||
|
return _resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _resolve() {
|
||||||
|
final vrl = VolumeRelativeDirectory.fromPath(asIs!);
|
||||||
|
if (vrl == null || vrl.relativeDir.isEmpty) return asIs;
|
||||||
|
|
||||||
|
var resolved = vrl.volumePath;
|
||||||
|
final parts = pContext.split(vrl.relativeDir);
|
||||||
|
for (final part in parts) {
|
||||||
|
final partLower = part.toLowerCase();
|
||||||
|
final childrenDirs = Directory(resolved).listSync().where((v) => v.absolute is Directory).toSet();
|
||||||
|
final found = childrenDirs.firstWhereOrNull((v) => pContext.basename(v.path).toLowerCase() == partLower);
|
||||||
|
resolved = found?.path ?? '$resolved${pContext.separator}$part';
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import 'package:aves/image_providers/thumbnail_provider.dart';
|
||||||
import 'package:aves/image_providers/uri_image_provider.dart';
|
import 'package:aves/image_providers/uri_image_provider.dart';
|
||||||
import 'package:aves/model/entry.dart';
|
import 'package:aves/model/entry.dart';
|
||||||
import 'package:aves/model/entry_cache.dart';
|
import 'package:aves/model/entry_cache.dart';
|
||||||
|
import 'package:aves/utils/math_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
@ -63,4 +64,15 @@ extension ExtraAvesEntryImages on AvesEntry {
|
||||||
final sizedThumbnailKey = EntryCache.thumbnailRequestExtents.map(_getThumbnailProviderKey).firstWhereOrNull(_isReady);
|
final sizedThumbnailKey = EntryCache.thumbnailRequestExtents.map(_getThumbnailProviderKey).firstWhereOrNull(_isReady);
|
||||||
return sizedThumbnailKey != null ? ThumbnailProvider(sizedThumbnailKey) : getThumbnail();
|
return sizedThumbnailKey != null ? ThumbnailProvider(sizedThumbnailKey) : getThumbnail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// magic number used to derive sample size from scale
|
||||||
|
static const scaleFactor = 2.0;
|
||||||
|
|
||||||
|
static int sampleSizeForScale(double scale) {
|
||||||
|
var sample = 0;
|
||||||
|
if (0 < scale && scale < 1) {
|
||||||
|
sample = highestPowerOf2((1 / scale) / scaleFactor);
|
||||||
|
}
|
||||||
|
return max<int>(1, sample);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:aves/model/entry.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/utils/file_utils.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
@ -19,11 +20,25 @@ class QueryFilter extends CollectionFilter {
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [query, live];
|
List<Object?> get props => [query, live];
|
||||||
|
|
||||||
|
static final _fieldPattern = RegExp(r'(.+)([=<>])(.+)');
|
||||||
|
static final _fileSizePattern = RegExp(r'(\d+)([KMG])?');
|
||||||
|
static const keyContentId = 'ID';
|
||||||
|
static const keyContentYear = 'YEAR';
|
||||||
|
static const keyContentMonth = 'MONTH';
|
||||||
|
static const keyContentDay = 'DAY';
|
||||||
|
static const keyContentWidth = 'WIDTH';
|
||||||
|
static const keyContentHeight = 'HEIGHT';
|
||||||
|
static const keyContentSize = 'SIZE';
|
||||||
|
static const opEqual = '=';
|
||||||
|
static const opLower = '<';
|
||||||
|
static const opGreater = '>';
|
||||||
|
|
||||||
QueryFilter(this.query, {this.colorful = true, this.live = false}) {
|
QueryFilter(this.query, {this.colorful = true, this.live = false}) {
|
||||||
var upQuery = query.toUpperCase();
|
var upQuery = query.toUpperCase();
|
||||||
if (upQuery.startsWith('ID:')) {
|
|
||||||
final id = int.tryParse(upQuery.substring(3));
|
final test = fieldTest(upQuery);
|
||||||
_test = (entry) => entry.id == id;
|
if (test != null) {
|
||||||
|
_test = test;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,4 +97,114 @@ class QueryFilter extends CollectionFilter {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get key => '$type-$query';
|
String get key => '$type-$query';
|
||||||
|
|
||||||
|
EntryFilter? fieldTest(String upQuery) {
|
||||||
|
var match = _fieldPattern.firstMatch(upQuery);
|
||||||
|
if (match == null) return null;
|
||||||
|
|
||||||
|
final key = match.group(1)?.trim();
|
||||||
|
final op = match.group(2)?.trim();
|
||||||
|
var valueString = match.group(3)?.trim();
|
||||||
|
if (key == null || op == null || valueString == null) return null;
|
||||||
|
|
||||||
|
final valueInt = int.tryParse(valueString);
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case keyContentId:
|
||||||
|
if (valueInt == null) return null;
|
||||||
|
if (op == opEqual) {
|
||||||
|
return (entry) => entry.contentId == valueInt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case keyContentYear:
|
||||||
|
if (valueInt == null) return null;
|
||||||
|
switch (op) {
|
||||||
|
case opEqual:
|
||||||
|
return (entry) => (entry.bestDate?.year ?? 0) == valueInt;
|
||||||
|
case opLower:
|
||||||
|
return (entry) => (entry.bestDate?.year ?? 0) < valueInt;
|
||||||
|
case opGreater:
|
||||||
|
return (entry) => (entry.bestDate?.year ?? 0) > valueInt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case keyContentMonth:
|
||||||
|
if (valueInt == null) return null;
|
||||||
|
switch (op) {
|
||||||
|
case opEqual:
|
||||||
|
return (entry) => (entry.bestDate?.month ?? 0) == valueInt;
|
||||||
|
case opLower:
|
||||||
|
return (entry) => (entry.bestDate?.month ?? 0) < valueInt;
|
||||||
|
case opGreater:
|
||||||
|
return (entry) => (entry.bestDate?.month ?? 0) > valueInt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case keyContentDay:
|
||||||
|
if (valueInt == null) return null;
|
||||||
|
switch (op) {
|
||||||
|
case opEqual:
|
||||||
|
return (entry) => (entry.bestDate?.day ?? 0) == valueInt;
|
||||||
|
case opLower:
|
||||||
|
return (entry) => (entry.bestDate?.day ?? 0) < valueInt;
|
||||||
|
case opGreater:
|
||||||
|
return (entry) => (entry.bestDate?.day ?? 0) > valueInt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case keyContentWidth:
|
||||||
|
if (valueInt == null) return null;
|
||||||
|
switch (op) {
|
||||||
|
case opEqual:
|
||||||
|
return (entry) => entry.displaySize.width == valueInt;
|
||||||
|
case opLower:
|
||||||
|
return (entry) => entry.displaySize.width < valueInt;
|
||||||
|
case opGreater:
|
||||||
|
return (entry) => entry.displaySize.width > valueInt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case keyContentHeight:
|
||||||
|
if (valueInt == null) return null;
|
||||||
|
switch (op) {
|
||||||
|
case opEqual:
|
||||||
|
return (entry) => entry.displaySize.height == valueInt;
|
||||||
|
case opLower:
|
||||||
|
return (entry) => entry.displaySize.height < valueInt;
|
||||||
|
case opGreater:
|
||||||
|
return (entry) => entry.displaySize.height > valueInt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case keyContentSize:
|
||||||
|
match = _fileSizePattern.firstMatch(valueString);
|
||||||
|
if (match == null) return null;
|
||||||
|
|
||||||
|
valueString = match.group(1)?.trim();
|
||||||
|
if (valueString == null) return null;
|
||||||
|
final valueInt = int.tryParse(valueString);
|
||||||
|
if (valueInt == null) return null;
|
||||||
|
|
||||||
|
var bytes = valueInt;
|
||||||
|
final multiplierString = match.group(2)?.trim();
|
||||||
|
switch (multiplierString) {
|
||||||
|
case 'K':
|
||||||
|
bytes *= kilo;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
bytes *= mega;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
bytes *= giga;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case opEqual:
|
||||||
|
return (entry) => (entry.sizeBytes ?? 0) == bytes;
|
||||||
|
case opLower:
|
||||||
|
return (entry) => (entry.sizeBytes ?? 0) < bytes;
|
||||||
|
case opGreater:
|
||||||
|
return (entry) => (entry.sizeBytes ?? 0) > bytes;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,15 @@ class SettingsDefaults {
|
||||||
static const canUseAnalysisService = true;
|
static const canUseAnalysisService = true;
|
||||||
static const isInstalledAppAccessAllowed = false;
|
static const isInstalledAppAccessAllowed = false;
|
||||||
static const isErrorReportingAllowed = false;
|
static const isErrorReportingAllowed = false;
|
||||||
|
static const tileLayout = TileLayout.grid;
|
||||||
|
static const entryRenamingPattern = '<${DateNamingProcessor.key}, yyyyMMdd-HHmmss> <${NameNamingProcessor.key}>';
|
||||||
|
|
||||||
|
// display
|
||||||
static const displayRefreshRateMode = DisplayRefreshRateMode.auto;
|
static const displayRefreshRateMode = DisplayRefreshRateMode.auto;
|
||||||
static const themeBrightness = AvesThemeBrightness.system;
|
static const themeBrightness = AvesThemeBrightness.system;
|
||||||
static const themeColorMode = AvesThemeColorMode.polychrome;
|
static const themeColorMode = AvesThemeColorMode.polychrome;
|
||||||
static const tileLayout = TileLayout.grid;
|
static const enableDynamicColor = false;
|
||||||
static const entryRenamingPattern = '<${DateNamingProcessor.key}, yyyyMMdd-HHmmss> <${NameNamingProcessor.key}>';
|
static const enableBlurEffect = true; // `enableBlurEffect` has a contextual default value
|
||||||
|
|
||||||
// navigation
|
// navigation
|
||||||
static const mustBackTwiceToExit = true;
|
static const mustBackTwiceToExit = true;
|
||||||
|
@ -79,7 +83,6 @@ class SettingsDefaults {
|
||||||
static const showOverlayInfo = true;
|
static const showOverlayInfo = true;
|
||||||
static const showOverlayShootingDetails = false;
|
static const showOverlayShootingDetails = false;
|
||||||
static const showOverlayThumbnailPreview = false;
|
static const showOverlayThumbnailPreview = false;
|
||||||
static const enableOverlayBlurEffect = true; // `enableOverlayBlurEffect` has a contextual default value
|
|
||||||
static const viewerUseCutout = true;
|
static const viewerUseCutout = true;
|
||||||
static const viewerMaxBrightness = false;
|
static const viewerMaxBrightness = false;
|
||||||
static const enableMotionPhotoAutoPlay = false;
|
static const enableMotionPhotoAutoPlay = false;
|
||||||
|
@ -122,6 +125,13 @@ class SettingsDefaults {
|
||||||
// file picker
|
// file picker
|
||||||
static const filePickerShowHiddenFiles = false;
|
static const filePickerShowHiddenFiles = false;
|
||||||
|
|
||||||
|
// slideshow
|
||||||
|
static const slideshowRepeat = false;
|
||||||
|
static const slideshowShuffle = false;
|
||||||
|
static const slideshowTransition = ViewerTransition.fade;
|
||||||
|
static const slideshowVideoPlayback = SlideshowVideoPlayback.playMuted;
|
||||||
|
static const slideshowInterval = SlideshowInterval.s5;
|
||||||
|
|
||||||
// platform settings
|
// platform settings
|
||||||
static const isRotationLocked = false;
|
static const isRotationLocked = false;
|
||||||
static const areAnimationsRemoved = false;
|
static const areAnimationsRemoved = false;
|
||||||
|
|
|
@ -2,24 +2,30 @@ enum AccessibilityAnimations { system, disabled, enabled }
|
||||||
|
|
||||||
enum AccessibilityTimeout { system, appDefault, s3, s10, s30, s60, s120 }
|
enum AccessibilityTimeout { system, appDefault, s3, s10, s30, s60, s120 }
|
||||||
|
|
||||||
enum AvesThemeColorMode { monochrome, polychrome }
|
|
||||||
|
|
||||||
enum AvesThemeBrightness { system, light, dark, black }
|
enum AvesThemeBrightness { system, light, dark, black }
|
||||||
|
|
||||||
|
enum AvesThemeColorMode { monochrome, polychrome }
|
||||||
|
|
||||||
enum ConfirmationDialog { deleteForever, moveToBin, moveUndatedItems }
|
enum ConfirmationDialog { deleteForever, moveToBin, moveUndatedItems }
|
||||||
|
|
||||||
enum CoordinateFormat { dms, decimal }
|
enum CoordinateFormat { dms, decimal }
|
||||||
|
|
||||||
|
enum DisplayRefreshRateMode { auto, highest, lowest }
|
||||||
|
|
||||||
enum EntryBackground { black, white, checkered }
|
enum EntryBackground { black, white, checkered }
|
||||||
|
|
||||||
enum HomePageSetting { collection, albums }
|
enum HomePageSetting { collection, albums }
|
||||||
|
|
||||||
enum KeepScreenOn { never, viewerOnly, always }
|
enum KeepScreenOn { never, viewerOnly, always }
|
||||||
|
|
||||||
enum DisplayRefreshRateMode { auto, highest, lowest }
|
enum SlideshowInterval { s3, s5, s10, s30, s60 }
|
||||||
|
|
||||||
|
enum SlideshowVideoPlayback { skip, playMuted, playWithSound }
|
||||||
|
|
||||||
enum UnitSystem { metric, imperial }
|
enum UnitSystem { metric, imperial }
|
||||||
|
|
||||||
|
enum VideoControls { play, playSeek, playOutside, none }
|
||||||
|
|
||||||
enum VideoLoopMode { never, shortOnly, always }
|
enum VideoLoopMode { never, shortOnly, always }
|
||||||
|
|
||||||
enum VideoControls { play, playSeek, playOutside, none }
|
enum ViewerTransition { slide, parallax, fade, zoomIn }
|
||||||
|
|
36
lib/model/settings/enums/slideshow_interval.dart
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'enums.dart';
|
||||||
|
|
||||||
|
extension ExtraSlideshowInterval on SlideshowInterval {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case SlideshowInterval.s3:
|
||||||
|
return context.l10n.timeSeconds(3);
|
||||||
|
case SlideshowInterval.s5:
|
||||||
|
return context.l10n.timeSeconds(5);
|
||||||
|
case SlideshowInterval.s10:
|
||||||
|
return context.l10n.timeSeconds(10);
|
||||||
|
case SlideshowInterval.s30:
|
||||||
|
return context.l10n.timeSeconds(30);
|
||||||
|
case SlideshowInterval.s60:
|
||||||
|
return context.l10n.timeMinutes(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Duration getDuration() {
|
||||||
|
switch (this) {
|
||||||
|
case SlideshowInterval.s3:
|
||||||
|
return const Duration(seconds: 3);
|
||||||
|
case SlideshowInterval.s5:
|
||||||
|
return const Duration(seconds: 5);
|
||||||
|
case SlideshowInterval.s10:
|
||||||
|
return const Duration(seconds: 10);
|
||||||
|
case SlideshowInterval.s30:
|
||||||
|
return const Duration(seconds: 30);
|
||||||
|
case SlideshowInterval.s60:
|
||||||
|
return const Duration(minutes: 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
lib/model/settings/enums/slideshow_video_playback.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'enums.dart';
|
||||||
|
|
||||||
|
extension ExtraSlideshowVideoPlayback on SlideshowVideoPlayback {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case SlideshowVideoPlayback.skip:
|
||||||
|
return context.l10n.slideshowVideoPlaybackSkip;
|
||||||
|
case SlideshowVideoPlayback.playMuted:
|
||||||
|
return context.l10n.slideshowVideoPlaybackMuted;
|
||||||
|
case SlideshowVideoPlayback.playWithSound:
|
||||||
|
return context.l10n.slideshowVideoPlaybackWithSound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
lib/model/settings/enums/viewer_transition.dart
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/viewer/controller.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'enums.dart';
|
||||||
|
|
||||||
|
extension ExtraViewerTransition on ViewerTransition {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case ViewerTransition.slide:
|
||||||
|
return context.l10n.viewerTransitionSlide;
|
||||||
|
case ViewerTransition.parallax:
|
||||||
|
return context.l10n.viewerTransitionParallax;
|
||||||
|
case ViewerTransition.fade:
|
||||||
|
return context.l10n.viewerTransitionFade;
|
||||||
|
case ViewerTransition.zoomIn:
|
||||||
|
return context.l10n.viewerTransitionZoomIn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionBuilder builder(PageController pageController, int index) {
|
||||||
|
switch (this) {
|
||||||
|
case ViewerTransition.slide:
|
||||||
|
return PageTransitionEffects.slide(pageController, index, parallax: false);
|
||||||
|
case ViewerTransition.parallax:
|
||||||
|
return PageTransitionEffects.slide(pageController, index, parallax: true);
|
||||||
|
case ViewerTransition.fade:
|
||||||
|
return PageTransitionEffects.fade(pageController, index, zoomIn: false);
|
||||||
|
case ViewerTransition.zoomIn:
|
||||||
|
return PageTransitionEffects.fade(pageController, index, zoomIn: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import 'package:aves/model/settings/enums/enums.dart';
|
||||||
import 'package:aves/model/settings/enums/map_style.dart';
|
import 'package:aves/model/settings/enums/map_style.dart';
|
||||||
import 'package:aves/model/source/enums.dart';
|
import 'package:aves/model/source/enums.dart';
|
||||||
import 'package:aves/services/accessibility_service.dart';
|
import 'package:aves/services/accessibility_service.dart';
|
||||||
|
import 'package:aves/services/common/optional_event_channel.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves_map/aves_map.dart';
|
import 'package:aves_map/aves_map.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
@ -19,7 +20,7 @@ import 'package:flutter/services.dart';
|
||||||
final Settings settings = Settings._private();
|
final Settings settings = Settings._private();
|
||||||
|
|
||||||
class Settings extends ChangeNotifier {
|
class Settings extends ChangeNotifier {
|
||||||
final EventChannel _platformSettingsChangeChannel = const EventChannel('deckers.thibault/aves/settings_change');
|
final EventChannel _platformSettingsChangeChannel = const OptionalEventChannel('deckers.thibault/aves/settings_change');
|
||||||
final StreamController<SettingsChangedEvent> _updateStreamController = StreamController.broadcast();
|
final StreamController<SettingsChangedEvent> _updateStreamController = StreamController.broadcast();
|
||||||
|
|
||||||
Stream<SettingsChangedEvent> get updateStream => _updateStreamController.stream;
|
Stream<SettingsChangedEvent> get updateStream => _updateStreamController.stream;
|
||||||
|
@ -42,15 +43,19 @@ class Settings extends ChangeNotifier {
|
||||||
static const isInstalledAppAccessAllowedKey = 'is_installed_app_access_allowed';
|
static const isInstalledAppAccessAllowedKey = 'is_installed_app_access_allowed';
|
||||||
static const isErrorReportingAllowedKey = 'is_crashlytics_enabled';
|
static const isErrorReportingAllowedKey = 'is_crashlytics_enabled';
|
||||||
static const localeKey = 'locale';
|
static const localeKey = 'locale';
|
||||||
static const displayRefreshRateModeKey = 'display_refresh_rate_mode';
|
|
||||||
static const themeBrightnessKey = 'theme_brightness';
|
|
||||||
static const themeColorModeKey = 'theme_color_mode';
|
|
||||||
static const catalogTimeZoneKey = 'catalog_time_zone';
|
static const catalogTimeZoneKey = 'catalog_time_zone';
|
||||||
static const tileExtentPrefixKey = 'tile_extent_';
|
static const tileExtentPrefixKey = 'tile_extent_';
|
||||||
static const tileLayoutPrefixKey = 'tile_layout_';
|
static const tileLayoutPrefixKey = 'tile_layout_';
|
||||||
static const entryRenamingPatternKey = 'entry_renaming_pattern';
|
static const entryRenamingPatternKey = 'entry_renaming_pattern';
|
||||||
static const topEntryIdsKey = 'top_entry_ids';
|
static const topEntryIdsKey = 'top_entry_ids';
|
||||||
|
|
||||||
|
// display
|
||||||
|
static const displayRefreshRateModeKey = 'display_refresh_rate_mode';
|
||||||
|
static const themeBrightnessKey = 'theme_brightness';
|
||||||
|
static const themeColorModeKey = 'theme_color_mode';
|
||||||
|
static const enableDynamicColorKey = 'dynamic_color';
|
||||||
|
static const enableBlurEffectKey = 'enable_overlay_blur_effect';
|
||||||
|
|
||||||
// navigation
|
// navigation
|
||||||
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
|
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
|
||||||
static const keepScreenOnKey = 'keep_screen_on';
|
static const keepScreenOnKey = 'keep_screen_on';
|
||||||
|
@ -92,7 +97,6 @@ class Settings extends ChangeNotifier {
|
||||||
static const showOverlayInfoKey = 'show_overlay_info';
|
static const showOverlayInfoKey = 'show_overlay_info';
|
||||||
static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details';
|
static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details';
|
||||||
static const showOverlayThumbnailPreviewKey = 'show_overlay_thumbnail_preview';
|
static const showOverlayThumbnailPreviewKey = 'show_overlay_thumbnail_preview';
|
||||||
static const enableOverlayBlurEffectKey = 'enable_overlay_blur_effect';
|
|
||||||
static const viewerUseCutoutKey = 'viewer_use_cutout';
|
static const viewerUseCutoutKey = 'viewer_use_cutout';
|
||||||
static const viewerMaxBrightnessKey = 'viewer_max_brightness';
|
static const viewerMaxBrightnessKey = 'viewer_max_brightness';
|
||||||
static const enableMotionPhotoAutoPlayKey = 'motion_photo_auto_play';
|
static const enableMotionPhotoAutoPlayKey = 'motion_photo_auto_play';
|
||||||
|
@ -134,6 +138,13 @@ class Settings extends ChangeNotifier {
|
||||||
// file picker
|
// file picker
|
||||||
static const filePickerShowHiddenFilesKey = 'file_picker_show_hidden_files';
|
static const filePickerShowHiddenFilesKey = 'file_picker_show_hidden_files';
|
||||||
|
|
||||||
|
// slideshow
|
||||||
|
static const slideshowRepeatKey = 'slideshow_loop';
|
||||||
|
static const slideshowShuffleKey = 'slideshow_shuffle';
|
||||||
|
static const slideshowTransitionKey = 'slideshow_transition';
|
||||||
|
static const slideshowVideoPlaybackKey = 'slideshow_video_playback';
|
||||||
|
static const slideshowIntervalKey = 'slideshow_interval';
|
||||||
|
|
||||||
// platform settings
|
// platform settings
|
||||||
// cf Android `Settings.System.ACCELEROMETER_ROTATION`
|
// cf Android `Settings.System.ACCELEROMETER_ROTATION`
|
||||||
static const platformAccelerometerRotationKey = 'accelerometer_rotation';
|
static const platformAccelerometerRotationKey = 'accelerometer_rotation';
|
||||||
|
@ -161,7 +172,7 @@ class Settings extends ChangeNotifier {
|
||||||
Future<void> setContextualDefaults() async {
|
Future<void> setContextualDefaults() async {
|
||||||
// performance
|
// performance
|
||||||
final performanceClass = await deviceService.getPerformanceClass();
|
final performanceClass = await deviceService.getPerformanceClass();
|
||||||
enableOverlayBlurEffect = performanceClass >= 29;
|
enableBlurEffect = performanceClass >= 29;
|
||||||
|
|
||||||
// availability
|
// availability
|
||||||
final defaultMapStyle = mobileServices.defaultMapStyle;
|
final defaultMapStyle = mobileServices.defaultMapStyle;
|
||||||
|
@ -187,8 +198,7 @@ class Settings extends ChangeNotifier {
|
||||||
|
|
||||||
set canUseAnalysisService(bool newValue) => setAndNotify(canUseAnalysisServiceKey, newValue);
|
set canUseAnalysisService(bool newValue) => setAndNotify(canUseAnalysisServiceKey, newValue);
|
||||||
|
|
||||||
// TODO TLAD use `true` for transition (it's unset in v1.5.4), but replace by `SettingsDefaults.isInstalledAppAccessAllowed` in a later release
|
bool get isInstalledAppAccessAllowed => getBoolOrDefault(isInstalledAppAccessAllowedKey, SettingsDefaults.isInstalledAppAccessAllowed);
|
||||||
bool get isInstalledAppAccessAllowed => getBoolOrDefault(isInstalledAppAccessAllowedKey, true);
|
|
||||||
|
|
||||||
set isInstalledAppAccessAllowed(bool newValue) => setAndNotify(isInstalledAppAccessAllowedKey, newValue);
|
set isInstalledAppAccessAllowed(bool newValue) => setAndNotify(isInstalledAppAccessAllowedKey, newValue);
|
||||||
|
|
||||||
|
@ -249,18 +259,6 @@ class Settings extends ChangeNotifier {
|
||||||
return _appliedLocale!;
|
return _appliedLocale!;
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayRefreshRateMode get displayRefreshRateMode => getEnumOrDefault(displayRefreshRateModeKey, SettingsDefaults.displayRefreshRateMode, DisplayRefreshRateMode.values);
|
|
||||||
|
|
||||||
set displayRefreshRateMode(DisplayRefreshRateMode newValue) => setAndNotify(displayRefreshRateModeKey, newValue.toString());
|
|
||||||
|
|
||||||
AvesThemeBrightness get themeBrightness => getEnumOrDefault(themeBrightnessKey, SettingsDefaults.themeBrightness, AvesThemeBrightness.values);
|
|
||||||
|
|
||||||
set themeBrightness(AvesThemeBrightness newValue) => setAndNotify(themeBrightnessKey, newValue.toString());
|
|
||||||
|
|
||||||
AvesThemeColorMode get themeColorMode => getEnumOrDefault(themeColorModeKey, SettingsDefaults.themeColorMode, AvesThemeColorMode.values);
|
|
||||||
|
|
||||||
set themeColorMode(AvesThemeColorMode newValue) => setAndNotify(themeColorModeKey, newValue.toString());
|
|
||||||
|
|
||||||
String get catalogTimeZone => getString(catalogTimeZoneKey) ?? '';
|
String get catalogTimeZone => getString(catalogTimeZoneKey) ?? '';
|
||||||
|
|
||||||
set catalogTimeZone(String newValue) => setAndNotify(catalogTimeZoneKey, newValue);
|
set catalogTimeZone(String newValue) => setAndNotify(catalogTimeZoneKey, newValue);
|
||||||
|
@ -281,6 +279,28 @@ class Settings extends ChangeNotifier {
|
||||||
|
|
||||||
set topEntryIds(List<int>? newValue) => setAndNotify(topEntryIdsKey, newValue?.map((id) => id.toString()).whereNotNull().toList());
|
set topEntryIds(List<int>? newValue) => setAndNotify(topEntryIdsKey, newValue?.map((id) => id.toString()).whereNotNull().toList());
|
||||||
|
|
||||||
|
// display
|
||||||
|
|
||||||
|
DisplayRefreshRateMode get displayRefreshRateMode => getEnumOrDefault(displayRefreshRateModeKey, SettingsDefaults.displayRefreshRateMode, DisplayRefreshRateMode.values);
|
||||||
|
|
||||||
|
set displayRefreshRateMode(DisplayRefreshRateMode newValue) => setAndNotify(displayRefreshRateModeKey, newValue.toString());
|
||||||
|
|
||||||
|
AvesThemeBrightness get themeBrightness => getEnumOrDefault(themeBrightnessKey, SettingsDefaults.themeBrightness, AvesThemeBrightness.values);
|
||||||
|
|
||||||
|
set themeBrightness(AvesThemeBrightness newValue) => setAndNotify(themeBrightnessKey, newValue.toString());
|
||||||
|
|
||||||
|
AvesThemeColorMode get themeColorMode => getEnumOrDefault(themeColorModeKey, SettingsDefaults.themeColorMode, AvesThemeColorMode.values);
|
||||||
|
|
||||||
|
set themeColorMode(AvesThemeColorMode newValue) => setAndNotify(themeColorModeKey, newValue.toString());
|
||||||
|
|
||||||
|
bool get enableDynamicColor => getBoolOrDefault(enableDynamicColorKey, SettingsDefaults.enableDynamicColor);
|
||||||
|
|
||||||
|
set enableDynamicColor(bool newValue) => setAndNotify(enableDynamicColorKey, newValue);
|
||||||
|
|
||||||
|
bool get enableBlurEffect => getBoolOrDefault(enableBlurEffectKey, SettingsDefaults.enableBlurEffect);
|
||||||
|
|
||||||
|
set enableBlurEffect(bool newValue) => setAndNotify(enableBlurEffectKey, newValue);
|
||||||
|
|
||||||
// navigation
|
// navigation
|
||||||
|
|
||||||
bool get mustBackTwiceToExit => getBoolOrDefault(mustBackTwiceToExitKey, SettingsDefaults.mustBackTwiceToExit);
|
bool get mustBackTwiceToExit => getBoolOrDefault(mustBackTwiceToExitKey, SettingsDefaults.mustBackTwiceToExit);
|
||||||
|
@ -441,10 +461,6 @@ class Settings extends ChangeNotifier {
|
||||||
|
|
||||||
set showOverlayThumbnailPreview(bool newValue) => setAndNotify(showOverlayThumbnailPreviewKey, newValue);
|
set showOverlayThumbnailPreview(bool newValue) => setAndNotify(showOverlayThumbnailPreviewKey, newValue);
|
||||||
|
|
||||||
bool get enableOverlayBlurEffect => getBoolOrDefault(enableOverlayBlurEffectKey, SettingsDefaults.enableOverlayBlurEffect);
|
|
||||||
|
|
||||||
set enableOverlayBlurEffect(bool newValue) => setAndNotify(enableOverlayBlurEffectKey, newValue);
|
|
||||||
|
|
||||||
bool get viewerUseCutout => getBoolOrDefault(viewerUseCutoutKey, SettingsDefaults.viewerUseCutout);
|
bool get viewerUseCutout => getBoolOrDefault(viewerUseCutoutKey, SettingsDefaults.viewerUseCutout);
|
||||||
|
|
||||||
set viewerUseCutout(bool newValue) => setAndNotify(viewerUseCutoutKey, newValue);
|
set viewerUseCutout(bool newValue) => setAndNotify(viewerUseCutoutKey, newValue);
|
||||||
|
@ -567,6 +583,28 @@ class Settings extends ChangeNotifier {
|
||||||
|
|
||||||
set filePickerShowHiddenFiles(bool newValue) => setAndNotify(filePickerShowHiddenFilesKey, newValue);
|
set filePickerShowHiddenFiles(bool newValue) => setAndNotify(filePickerShowHiddenFilesKey, newValue);
|
||||||
|
|
||||||
|
// slideshow
|
||||||
|
|
||||||
|
bool get slideshowRepeat => getBoolOrDefault(slideshowRepeatKey, SettingsDefaults.slideshowRepeat);
|
||||||
|
|
||||||
|
set slideshowRepeat(bool newValue) => setAndNotify(slideshowRepeatKey, newValue);
|
||||||
|
|
||||||
|
bool get slideshowShuffle => getBoolOrDefault(slideshowShuffleKey, SettingsDefaults.slideshowShuffle);
|
||||||
|
|
||||||
|
set slideshowShuffle(bool newValue) => setAndNotify(slideshowShuffleKey, newValue);
|
||||||
|
|
||||||
|
ViewerTransition get slideshowTransition => getEnumOrDefault(slideshowTransitionKey, SettingsDefaults.slideshowTransition, ViewerTransition.values);
|
||||||
|
|
||||||
|
set slideshowTransition(ViewerTransition newValue) => setAndNotify(slideshowTransitionKey, newValue.toString());
|
||||||
|
|
||||||
|
SlideshowVideoPlayback get slideshowVideoPlayback => getEnumOrDefault(slideshowVideoPlaybackKey, SettingsDefaults.slideshowVideoPlayback, SlideshowVideoPlayback.values);
|
||||||
|
|
||||||
|
set slideshowVideoPlayback(SlideshowVideoPlayback newValue) => setAndNotify(slideshowVideoPlaybackKey, newValue.toString());
|
||||||
|
|
||||||
|
SlideshowInterval get slideshowInterval => getEnumOrDefault(slideshowIntervalKey, SettingsDefaults.slideshowInterval, SlideshowInterval.values);
|
||||||
|
|
||||||
|
set slideshowInterval(SlideshowInterval newValue) => setAndNotify(slideshowIntervalKey, newValue.toString());
|
||||||
|
|
||||||
// convenience methods
|
// convenience methods
|
||||||
|
|
||||||
int? getInt(String key) => settingsStore.getInt(key);
|
int? getInt(String key) => settingsStore.getInt(key);
|
||||||
|
@ -695,6 +733,8 @@ class Settings extends ChangeNotifier {
|
||||||
break;
|
break;
|
||||||
case isInstalledAppAccessAllowedKey:
|
case isInstalledAppAccessAllowedKey:
|
||||||
case isErrorReportingAllowedKey:
|
case isErrorReportingAllowedKey:
|
||||||
|
case enableDynamicColorKey:
|
||||||
|
case enableBlurEffectKey:
|
||||||
case showBottomNavigationBarKey:
|
case showBottomNavigationBarKey:
|
||||||
case mustBackTwiceToExitKey:
|
case mustBackTwiceToExitKey:
|
||||||
case confirmDeleteForeverKey:
|
case confirmDeleteForeverKey:
|
||||||
|
@ -713,7 +753,6 @@ class Settings extends ChangeNotifier {
|
||||||
case showOverlayInfoKey:
|
case showOverlayInfoKey:
|
||||||
case showOverlayShootingDetailsKey:
|
case showOverlayShootingDetailsKey:
|
||||||
case showOverlayThumbnailPreviewKey:
|
case showOverlayThumbnailPreviewKey:
|
||||||
case enableOverlayBlurEffectKey:
|
|
||||||
case viewerUseCutoutKey:
|
case viewerUseCutoutKey:
|
||||||
case viewerMaxBrightnessKey:
|
case viewerMaxBrightnessKey:
|
||||||
case enableMotionPhotoAutoPlayKey:
|
case enableMotionPhotoAutoPlayKey:
|
||||||
|
@ -724,6 +763,8 @@ class Settings extends ChangeNotifier {
|
||||||
case subtitleShowOutlineKey:
|
case subtitleShowOutlineKey:
|
||||||
case saveSearchHistoryKey:
|
case saveSearchHistoryKey:
|
||||||
case filePickerShowHiddenFilesKey:
|
case filePickerShowHiddenFilesKey:
|
||||||
|
case slideshowRepeatKey:
|
||||||
|
case slideshowShuffleKey:
|
||||||
if (newValue is bool) {
|
if (newValue is bool) {
|
||||||
settingsStore.setBool(key, newValue);
|
settingsStore.setBool(key, newValue);
|
||||||
} else {
|
} else {
|
||||||
|
@ -751,6 +792,9 @@ class Settings extends ChangeNotifier {
|
||||||
case unitSystemKey:
|
case unitSystemKey:
|
||||||
case accessibilityAnimationsKey:
|
case accessibilityAnimationsKey:
|
||||||
case timeToTakeActionKey:
|
case timeToTakeActionKey:
|
||||||
|
case slideshowTransitionKey:
|
||||||
|
case slideshowVideoPlaybackKey:
|
||||||
|
case slideshowIntervalKey:
|
||||||
if (newValue is String) {
|
if (newValue is String) {
|
||||||
settingsStore.setString(key, newValue);
|
settingsStore.setString(key, newValue);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -32,7 +32,7 @@ class CollectionLens with ChangeNotifier {
|
||||||
final AChangeNotifier filterChangeNotifier = AChangeNotifier(), sortSectionChangeNotifier = AChangeNotifier();
|
final AChangeNotifier filterChangeNotifier = AChangeNotifier(), sortSectionChangeNotifier = AChangeNotifier();
|
||||||
final List<StreamSubscription> _subscriptions = [];
|
final List<StreamSubscription> _subscriptions = [];
|
||||||
int? id;
|
int? id;
|
||||||
bool listenToSource, groupBursts;
|
bool listenToSource, groupBursts, fixedSort;
|
||||||
List<AvesEntry>? fixedSelection;
|
List<AvesEntry>? fixedSelection;
|
||||||
|
|
||||||
List<AvesEntry> _filteredSortedEntries = [];
|
List<AvesEntry> _filteredSortedEntries = [];
|
||||||
|
@ -45,6 +45,7 @@ class CollectionLens with ChangeNotifier {
|
||||||
this.id,
|
this.id,
|
||||||
this.listenToSource = true,
|
this.listenToSource = true,
|
||||||
this.groupBursts = true,
|
this.groupBursts = true,
|
||||||
|
this.fixedSort = false,
|
||||||
this.fixedSelection,
|
this.fixedSelection,
|
||||||
}) : filters = (filters ?? {}).whereNotNull().toSet(),
|
}) : filters = (filters ?? {}).whereNotNull().toSet(),
|
||||||
sectionFactor = settings.collectionSectionFactor,
|
sectionFactor = settings.collectionSectionFactor,
|
||||||
|
@ -203,6 +204,8 @@ class CollectionLens with ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _applySort() {
|
void _applySort() {
|
||||||
|
if (fixedSort) return;
|
||||||
|
|
||||||
switch (sortFactor) {
|
switch (sortFactor) {
|
||||||
case EntrySortFactor.date:
|
case EntrySortFactor.date:
|
||||||
_filteredSortedEntries.sort(AvesEntry.compareByDate);
|
_filteredSortedEntries.sort(AvesEntry.compareByDate);
|
||||||
|
@ -220,37 +223,43 @@ class CollectionLens with ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _applySection() {
|
void _applySection() {
|
||||||
switch (sortFactor) {
|
if (fixedSort) {
|
||||||
case EntrySortFactor.date:
|
sections = Map.fromEntries([
|
||||||
switch (sectionFactor) {
|
MapEntry(const SectionKey(), _filteredSortedEntries),
|
||||||
case EntryGroupFactor.album:
|
]);
|
||||||
sections = groupBy<AvesEntry, EntryAlbumSectionKey>(_filteredSortedEntries, (entry) => EntryAlbumSectionKey(entry.directory));
|
} else {
|
||||||
break;
|
switch (sortFactor) {
|
||||||
case EntryGroupFactor.month:
|
case EntrySortFactor.date:
|
||||||
sections = groupBy<AvesEntry, EntryDateSectionKey>(_filteredSortedEntries, (entry) => EntryDateSectionKey(entry.monthTaken));
|
switch (sectionFactor) {
|
||||||
break;
|
case EntryGroupFactor.album:
|
||||||
case EntryGroupFactor.day:
|
sections = groupBy<AvesEntry, EntryAlbumSectionKey>(_filteredSortedEntries, (entry) => EntryAlbumSectionKey(entry.directory));
|
||||||
sections = groupBy<AvesEntry, EntryDateSectionKey>(_filteredSortedEntries, (entry) => EntryDateSectionKey(entry.dayTaken));
|
break;
|
||||||
break;
|
case EntryGroupFactor.month:
|
||||||
case EntryGroupFactor.none:
|
sections = groupBy<AvesEntry, EntryDateSectionKey>(_filteredSortedEntries, (entry) => EntryDateSectionKey(entry.monthTaken));
|
||||||
sections = Map.fromEntries([
|
break;
|
||||||
MapEntry(const SectionKey(), _filteredSortedEntries),
|
case EntryGroupFactor.day:
|
||||||
]);
|
sections = groupBy<AvesEntry, EntryDateSectionKey>(_filteredSortedEntries, (entry) => EntryDateSectionKey(entry.dayTaken));
|
||||||
break;
|
break;
|
||||||
}
|
case EntryGroupFactor.none:
|
||||||
break;
|
sections = Map.fromEntries([
|
||||||
case EntrySortFactor.name:
|
MapEntry(const SectionKey(), _filteredSortedEntries),
|
||||||
final byAlbum = groupBy<AvesEntry, EntryAlbumSectionKey>(_filteredSortedEntries, (entry) => EntryAlbumSectionKey(entry.directory));
|
]);
|
||||||
sections = SplayTreeMap<EntryAlbumSectionKey, List<AvesEntry>>.of(byAlbum, (a, b) => source.compareAlbumsByName(a.directory!, b.directory!));
|
break;
|
||||||
break;
|
}
|
||||||
case EntrySortFactor.rating:
|
break;
|
||||||
sections = groupBy<AvesEntry, EntryRatingSectionKey>(_filteredSortedEntries, (entry) => EntryRatingSectionKey(entry.rating));
|
case EntrySortFactor.name:
|
||||||
break;
|
final byAlbum = groupBy<AvesEntry, EntryAlbumSectionKey>(_filteredSortedEntries, (entry) => EntryAlbumSectionKey(entry.directory));
|
||||||
case EntrySortFactor.size:
|
sections = SplayTreeMap<EntryAlbumSectionKey, List<AvesEntry>>.of(byAlbum, (a, b) => source.compareAlbumsByName(a.directory!, b.directory!));
|
||||||
sections = Map.fromEntries([
|
break;
|
||||||
MapEntry(const SectionKey(), _filteredSortedEntries),
|
case EntrySortFactor.rating:
|
||||||
]);
|
sections = groupBy<AvesEntry, EntryRatingSectionKey>(_filteredSortedEntries, (entry) => EntryRatingSectionKey(entry.rating));
|
||||||
break;
|
break;
|
||||||
|
case EntrySortFactor.size:
|
||||||
|
sections = Map.fromEntries([
|
||||||
|
MapEntry(const SectionKey(), _filteredSortedEntries),
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sections = Map.unmodifiable(sections);
|
sections = Map.unmodifiable(sections);
|
||||||
_sortedEntries = null;
|
_sortedEntries = null;
|
||||||
|
|
|
@ -416,6 +416,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startAnalysisService) {
|
if (startAnalysisService) {
|
||||||
|
// TODO TLAD [tiramisu] explain foreground service and request POST_NOTIFICATIONS permission
|
||||||
await AnalysisService.startService(
|
await AnalysisService.startService(
|
||||||
force: force,
|
force: force,
|
||||||
entryIds: entries?.map((entry) => entry.id).toList(),
|
entryIds: entries?.map((entry) => entry.id).toList(),
|
||||||
|
|
17
lib/model/wallpaper_target.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
enum WallpaperTarget { home, lock, homeLock }
|
||||||
|
|
||||||
|
extension ExtraWallpaperTarget on WallpaperTarget {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case WallpaperTarget.home:
|
||||||
|
return context.l10n.wallpaperTargetHome;
|
||||||
|
case WallpaperTarget.lock:
|
||||||
|
return context.l10n.wallpaperTargetLock;
|
||||||
|
case WallpaperTarget.homeLock:
|
||||||
|
return context.l10n.wallpaperTargetHomeLock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,8 @@ class MimeTypes {
|
||||||
|
|
||||||
static const anyVideo = 'video/*';
|
static const anyVideo = 'video/*';
|
||||||
|
|
||||||
|
static const v3gpp = 'video/3gpp';
|
||||||
|
static const asf = 'video/x-ms-asf';
|
||||||
static const avi = 'video/avi';
|
static const avi = 'video/avi';
|
||||||
static const aviVnd = 'video/vnd.avi';
|
static const aviVnd = 'video/vnd.avi';
|
||||||
static const flv = 'video/flv';
|
static const flv = 'video/flv';
|
||||||
|
@ -56,6 +58,7 @@ class MimeTypes {
|
||||||
static const mpeg = 'video/mpeg';
|
static const mpeg = 'video/mpeg';
|
||||||
static const ogv = 'video/ogg';
|
static const ogv = 'video/ogg';
|
||||||
static const webm = 'video/webm';
|
static const webm = 'video/webm';
|
||||||
|
static const wmv = 'video/x-ms-wmv';
|
||||||
|
|
||||||
static const json = 'application/json';
|
static const json = 'application/json';
|
||||||
static const plainText = 'text/plain';
|
static const plainText = 'text/plain';
|
||||||
|
@ -76,7 +79,7 @@ class MimeTypes {
|
||||||
|
|
||||||
static const Set<String> _knownOpaqueImages = {jpeg};
|
static const Set<String> _knownOpaqueImages = {jpeg};
|
||||||
|
|
||||||
static const Set<String> _knownVideos = {avi, aviVnd, flv, flvX, mkv, mov, mp2t, mp2ts, mp4, mpeg, ogv, webm};
|
static const Set<String> _knownVideos = {v3gpp, asf, avi, aviVnd, flv, flvX, mkv, mov, mp2t, mp2ts, mp4, mpeg, ogv, webm, wmv};
|
||||||
|
|
||||||
static final Set<String> knownMediaTypes = {
|
static final Set<String> knownMediaTypes = {
|
||||||
anyImage,
|
anyImage,
|
||||||
|
|
53
lib/services/common/optional_event_channel.dart
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
// adapted from Flutter `EventChannel` in `/services/platform_channel.dart`
|
||||||
|
// to use an `OptionalMethodChannel` when subscribing to events
|
||||||
|
class OptionalEventChannel extends EventChannel {
|
||||||
|
const OptionalEventChannel(super.name, [super.codec = const StandardMethodCodec(), super.binaryMessenger]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<dynamic> receiveBroadcastStream([dynamic arguments]) {
|
||||||
|
final MethodChannel methodChannel = OptionalMethodChannel(name, codec);
|
||||||
|
late StreamController<dynamic> controller;
|
||||||
|
controller = StreamController<dynamic>.broadcast(onListen: () async {
|
||||||
|
binaryMessenger.setMessageHandler(name, (reply) async {
|
||||||
|
if (reply == null) {
|
||||||
|
await controller.close();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
controller.add(codec.decodeEnvelope(reply));
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
controller.addError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await methodChannel.invokeMethod<void>('listen', arguments);
|
||||||
|
} catch (exception, stack) {
|
||||||
|
FlutterError.reportError(FlutterErrorDetails(
|
||||||
|
exception: exception,
|
||||||
|
stack: stack,
|
||||||
|
library: 'services library',
|
||||||
|
context: ErrorDescription('while activating platform stream on channel $name'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}, onCancel: () async {
|
||||||
|
binaryMessenger.setMessageHandler(name, null);
|
||||||
|
try {
|
||||||
|
await methodChannel.invokeMethod<void>('cancel', arguments);
|
||||||
|
} catch (exception, stack) {
|
||||||
|
FlutterError.reportError(FlutterErrorDetails(
|
||||||
|
exception: exception,
|
||||||
|
stack: stack,
|
||||||
|
library: 'services library',
|
||||||
|
context: ErrorDescription('while de-activating platform stream on channel $name'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return controller.stream;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,11 @@ class GeocodingService {
|
||||||
});
|
});
|
||||||
return (result as List).cast<Map>().map(Address.fromMap).toList();
|
return (result as List).cast<Map>().map(Address.fromMap).toList();
|
||||||
} on PlatformException catch (e, stack) {
|
} on PlatformException catch (e, stack) {
|
||||||
if (e.code != 'getAddress-empty' && e.code != 'getAddress-network') {
|
if (!{
|
||||||
|
'getAddress-empty',
|
||||||
|
'getAddress-network',
|
||||||
|
'getAddress-unavailable',
|
||||||
|
}.contains(e.code)) {
|
||||||
await reportService.recordError(e, stack);
|
await reportService.recordError(e, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
23
lib/services/wallpaper_service.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:aves/model/wallpaper_target.dart';
|
||||||
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class WallpaperService {
|
||||||
|
static const platform = MethodChannel('deckers.thibault/aves/wallpaper');
|
||||||
|
|
||||||
|
static Future<bool> set(Uint8List bytes, WallpaperTarget target) async {
|
||||||
|
try {
|
||||||
|
await platform.invokeMethod('setWallpaper', <String, dynamic>{
|
||||||
|
'bytes': bytes,
|
||||||
|
'home': {WallpaperTarget.home, WallpaperTarget.homeLock}.contains(target),
|
||||||
|
'lock': {WallpaperTarget.lock, WallpaperTarget.homeLock}.contains(target),
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -104,6 +104,7 @@ class AIcons {
|
||||||
static const IconData setCover = MdiIcons.imageEditOutline;
|
static const IconData setCover = MdiIcons.imageEditOutline;
|
||||||
static const IconData share = Icons.share_outlined;
|
static const IconData share = Icons.share_outlined;
|
||||||
static const IconData show = Icons.visibility_outlined;
|
static const IconData show = Icons.visibility_outlined;
|
||||||
|
static const IconData slideshow = Icons.slideshow_outlined;
|
||||||
static const IconData speed = Icons.speed_outlined;
|
static const IconData speed = Icons.speed_outlined;
|
||||||
static const IconData stats = Icons.pie_chart_outline_outlined;
|
static const IconData stats = Icons.pie_chart_outline_outlined;
|
||||||
static const IconData streams = Icons.translate_outlined;
|
static const IconData streams = Icons.translate_outlined;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class Themes {
|
class Themes {
|
||||||
static const _accentColor = Colors.indigoAccent;
|
static const defaultAccent = Colors.indigoAccent;
|
||||||
|
|
||||||
static const _tooltipTheme = TooltipThemeData(
|
static const _tooltipTheme = TooltipThemeData(
|
||||||
verticalOffset: 32,
|
verticalOffset: 32,
|
||||||
|
@ -19,10 +19,10 @@ class Themes {
|
||||||
fontFeatures: [FontFeature.enable('smcp')],
|
fontFeatures: [FontFeature.enable('smcp')],
|
||||||
);
|
);
|
||||||
|
|
||||||
static const _snackBarTheme = SnackBarThemeData(
|
static SnackBarThemeData _snackBarTheme(Color accentColor) => SnackBarThemeData(
|
||||||
actionTextColor: _accentColor,
|
actionTextColor: accentColor,
|
||||||
behavior: SnackBarBehavior.floating,
|
behavior: SnackBarBehavior.floating,
|
||||||
);
|
);
|
||||||
|
|
||||||
static final _typography = Typography.material2018(platform: TargetPlatform.android);
|
static final _typography = Typography.material2018(platform: TargetPlatform.android);
|
||||||
|
|
||||||
|
@ -35,49 +35,49 @@ class Themes {
|
||||||
static const _lightSecondLayer = Color(0xFFF5F5F5); // aka `Colors.grey[100]`
|
static const _lightSecondLayer = Color(0xFFF5F5F5); // aka `Colors.grey[100]`
|
||||||
static const _lightThirdLayer = Color(0xFFEEEEEE); // aka `Colors.grey[200]`
|
static const _lightThirdLayer = Color(0xFFEEEEEE); // aka `Colors.grey[200]`
|
||||||
|
|
||||||
static final lightTheme = ThemeData(
|
static ThemeData lightTheme(Color accentColor) => ThemeData(
|
||||||
colorScheme: ColorScheme.light(
|
colorScheme: ColorScheme.light(
|
||||||
primary: _accentColor,
|
primary: accentColor,
|
||||||
secondary: _accentColor,
|
secondary: accentColor,
|
||||||
onPrimary: _lightBodyColor,
|
onPrimary: _lightBodyColor,
|
||||||
onSecondary: _lightBodyColor,
|
onSecondary: _lightBodyColor,
|
||||||
),
|
),
|
||||||
brightness: Brightness.light,
|
brightness: Brightness.light,
|
||||||
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
|
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
|
||||||
canvasColor: _lightSecondLayer,
|
canvasColor: _lightSecondLayer,
|
||||||
scaffoldBackgroundColor: _lightFirstLayer,
|
scaffoldBackgroundColor: _lightFirstLayer,
|
||||||
// `cardColor` is used by `ExpansionPanel`
|
// `cardColor` is used by `ExpansionPanel`
|
||||||
cardColor: _lightSecondLayer,
|
cardColor: _lightSecondLayer,
|
||||||
dialogBackgroundColor: _lightSecondLayer,
|
dialogBackgroundColor: _lightSecondLayer,
|
||||||
indicatorColor: _accentColor,
|
indicatorColor: accentColor,
|
||||||
toggleableActiveColor: _accentColor,
|
toggleableActiveColor: accentColor,
|
||||||
typography: _typography,
|
typography: _typography,
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
backgroundColor: _lightFirstLayer,
|
backgroundColor: _lightFirstLayer,
|
||||||
// `foregroundColor` is used by icons
|
// `foregroundColor` is used by icons
|
||||||
foregroundColor: _lightActionIconColor,
|
foregroundColor: _lightActionIconColor,
|
||||||
// `titleTextStyle.color` is used by text
|
// `titleTextStyle.color` is used by text
|
||||||
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _lightTitleColor),
|
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _lightTitleColor),
|
||||||
systemOverlayStyle: SystemUiOverlayStyle.dark,
|
systemOverlayStyle: SystemUiOverlayStyle.dark,
|
||||||
),
|
),
|
||||||
listTileTheme: const ListTileThemeData(
|
listTileTheme: const ListTileThemeData(
|
||||||
iconColor: _lightActionIconColor,
|
iconColor: _lightActionIconColor,
|
||||||
),
|
),
|
||||||
popupMenuTheme: const PopupMenuThemeData(
|
popupMenuTheme: const PopupMenuThemeData(
|
||||||
color: _lightSecondLayer,
|
color: _lightSecondLayer,
|
||||||
),
|
),
|
||||||
snackBarTheme: _snackBarTheme,
|
snackBarTheme: _snackBarTheme(accentColor),
|
||||||
tabBarTheme: TabBarTheme(
|
tabBarTheme: TabBarTheme(
|
||||||
labelColor: _lightTitleColor,
|
labelColor: _lightTitleColor,
|
||||||
unselectedLabelColor: Colors.black54,
|
unselectedLabelColor: Colors.black54,
|
||||||
),
|
),
|
||||||
textButtonTheme: TextButtonThemeData(
|
textButtonTheme: TextButtonThemeData(
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
primary: _lightLabelColor,
|
primary: _lightLabelColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
tooltipTheme: _tooltipTheme,
|
tooltipTheme: _tooltipTheme,
|
||||||
);
|
);
|
||||||
|
|
||||||
static final _darkThemeTypo = _typography.white;
|
static final _darkThemeTypo = _typography.white;
|
||||||
static final _darkTitleColor = _darkThemeTypo.titleMedium!.color!;
|
static final _darkTitleColor = _darkThemeTypo.titleMedium!.color!;
|
||||||
|
@ -87,71 +87,74 @@ class Themes {
|
||||||
static const _darkSecondLayer = Color(0xFF363636);
|
static const _darkSecondLayer = Color(0xFF363636);
|
||||||
static const _darkThirdLayer = Color(0xFF424242); // aka `Colors.grey[800]`
|
static const _darkThirdLayer = Color(0xFF424242); // aka `Colors.grey[800]`
|
||||||
|
|
||||||
static final darkTheme = ThemeData(
|
static ThemeData darkTheme(Color accentColor) => ThemeData(
|
||||||
colorScheme: ColorScheme.dark(
|
colorScheme: ColorScheme.dark(
|
||||||
primary: _accentColor,
|
primary: accentColor,
|
||||||
secondary: _accentColor,
|
secondary: accentColor,
|
||||||
// surface color is used by the date/time pickers
|
// surface color is used by the date/time pickers
|
||||||
surface: Colors.grey.shade800,
|
surface: Colors.grey.shade800,
|
||||||
onPrimary: _darkBodyColor,
|
onPrimary: _darkBodyColor,
|
||||||
onSecondary: _darkBodyColor,
|
onSecondary: _darkBodyColor,
|
||||||
),
|
),
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
|
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
|
||||||
canvasColor: _darkSecondLayer,
|
canvasColor: _darkSecondLayer,
|
||||||
scaffoldBackgroundColor: _darkFirstLayer,
|
scaffoldBackgroundColor: _darkFirstLayer,
|
||||||
// `cardColor` is used by `ExpansionPanel`
|
// `cardColor` is used by `ExpansionPanel`
|
||||||
cardColor: _darkSecondLayer,
|
cardColor: _darkSecondLayer,
|
||||||
dialogBackgroundColor: _darkSecondLayer,
|
dialogBackgroundColor: _darkSecondLayer,
|
||||||
indicatorColor: _accentColor,
|
indicatorColor: accentColor,
|
||||||
toggleableActiveColor: _accentColor,
|
toggleableActiveColor: accentColor,
|
||||||
typography: _typography,
|
typography: _typography,
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
backgroundColor: _darkFirstLayer,
|
backgroundColor: _darkFirstLayer,
|
||||||
// `foregroundColor` is used by icons
|
// `foregroundColor` is used by icons
|
||||||
foregroundColor: _darkTitleColor,
|
foregroundColor: _darkTitleColor,
|
||||||
// `titleTextStyle.color` is used by text
|
// `titleTextStyle.color` is used by text
|
||||||
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _darkTitleColor),
|
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _darkTitleColor),
|
||||||
systemOverlayStyle: SystemUiOverlayStyle.light,
|
systemOverlayStyle: SystemUiOverlayStyle.light,
|
||||||
),
|
),
|
||||||
popupMenuTheme: const PopupMenuThemeData(
|
popupMenuTheme: const PopupMenuThemeData(
|
||||||
color: _darkSecondLayer,
|
color: _darkSecondLayer,
|
||||||
),
|
),
|
||||||
snackBarTheme: _snackBarTheme.copyWith(
|
snackBarTheme: _snackBarTheme(accentColor).copyWith(
|
||||||
backgroundColor: Colors.grey.shade800,
|
backgroundColor: Colors.grey.shade800,
|
||||||
contentTextStyle: TextStyle(
|
contentTextStyle: TextStyle(
|
||||||
color: _darkBodyColor,
|
color: _darkBodyColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
tabBarTheme: TabBarTheme(
|
tabBarTheme: TabBarTheme(
|
||||||
labelColor: _darkTitleColor,
|
labelColor: _darkTitleColor,
|
||||||
),
|
),
|
||||||
textButtonTheme: TextButtonThemeData(
|
textButtonTheme: TextButtonThemeData(
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
primary: _darkLabelColor,
|
primary: _darkLabelColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
tooltipTheme: _tooltipTheme,
|
tooltipTheme: _tooltipTheme,
|
||||||
);
|
);
|
||||||
|
|
||||||
static const _blackFirstLayer = Colors.black;
|
static const _blackFirstLayer = Colors.black;
|
||||||
static const _blackSecondLayer = Color(0xFF212121); // aka `Colors.grey[900]`
|
static const _blackSecondLayer = Color(0xFF212121); // aka `Colors.grey[900]`
|
||||||
static const _blackThirdLayer = Color(0xFF303030); // aka `Colors.grey[850]`
|
static const _blackThirdLayer = Color(0xFF303030); // aka `Colors.grey[850]`
|
||||||
|
|
||||||
static final blackTheme = darkTheme.copyWith(
|
static ThemeData blackTheme(Color accentColor) {
|
||||||
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
|
final baseTheme = darkTheme(accentColor);
|
||||||
canvasColor: _blackSecondLayer,
|
return baseTheme.copyWith(
|
||||||
scaffoldBackgroundColor: _blackFirstLayer,
|
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
|
||||||
// `cardColor` is used by `ExpansionPanel`
|
canvasColor: _blackSecondLayer,
|
||||||
cardColor: _blackSecondLayer,
|
scaffoldBackgroundColor: _blackFirstLayer,
|
||||||
dialogBackgroundColor: _blackSecondLayer,
|
// `cardColor` is used by `ExpansionPanel`
|
||||||
appBarTheme: darkTheme.appBarTheme.copyWith(
|
cardColor: _blackSecondLayer,
|
||||||
backgroundColor: _blackFirstLayer,
|
dialogBackgroundColor: _blackSecondLayer,
|
||||||
),
|
appBarTheme: baseTheme.appBarTheme.copyWith(
|
||||||
popupMenuTheme: darkTheme.popupMenuTheme.copyWith(
|
backgroundColor: _blackFirstLayer,
|
||||||
color: _blackSecondLayer,
|
),
|
||||||
),
|
popupMenuTheme: baseTheme.popupMenuTheme.copyWith(
|
||||||
);
|
color: _blackSecondLayer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static Color overlayBackgroundColor({
|
static Color overlayBackgroundColor({
|
||||||
required Brightness brightness,
|
required Brightness brightness,
|
||||||
|
|
|
@ -108,6 +108,11 @@ class Constants {
|
||||||
licenseUrl: 'https://github.com/fluttercommunity/plus_plugins/blob/main/packages/device_info_plus/device_info_plus/LICENSE',
|
licenseUrl: 'https://github.com/fluttercommunity/plus_plugins/blob/main/packages/device_info_plus/device_info_plus/LICENSE',
|
||||||
sourceUrl: 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/device_info_plus',
|
sourceUrl: 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/device_info_plus',
|
||||||
),
|
),
|
||||||
|
Dependency(
|
||||||
|
name: 'Dynamic Color',
|
||||||
|
license: 'BSD 3-Clause',
|
||||||
|
sourceUrl: 'https://github.com/material-foundation/material-dynamic-color-flutter',
|
||||||
|
),
|
||||||
Dependency(
|
Dependency(
|
||||||
name: 'fijkplayer (Aves fork)',
|
name: 'fijkplayer (Aves fork)',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
|
@ -337,6 +342,12 @@ class Constants {
|
||||||
license: 'Apache 2.0',
|
license: 'Apache 2.0',
|
||||||
sourceUrl: 'https://github.com/jifalops/dart-latlong',
|
sourceUrl: 'https://github.com/jifalops/dart-latlong',
|
||||||
),
|
),
|
||||||
|
Dependency(
|
||||||
|
name: 'Material Color Utilities',
|
||||||
|
license: 'Apache 2.0',
|
||||||
|
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(
|
Dependency(
|
||||||
name: 'Path',
|
name: 'Path',
|
||||||
license: 'BSD 3-Clause',
|
license: 'BSD 3-Clause',
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
const _kiloDivider = 1024;
|
const kilo = 1024;
|
||||||
const _megaDivider = _kiloDivider * _kiloDivider;
|
const mega = kilo * kilo;
|
||||||
const _gigaDivider = _megaDivider * _kiloDivider;
|
const giga = mega * kilo;
|
||||||
const _teraDivider = _gigaDivider * _kiloDivider;
|
const tera = giga * kilo;
|
||||||
|
|
||||||
String formatFileSize(String locale, int size, {int round = 2}) {
|
String formatFileSize(String locale, int size, {int round = 2}) {
|
||||||
if (size < _kiloDivider) return '$size B';
|
if (size < kilo) return '$size B';
|
||||||
|
|
||||||
final formatter = NumberFormat('0${round > 0 ? '.${'0' * round}' : ''}', locale);
|
final formatter = NumberFormat('0${round > 0 ? '.${'0' * round}' : ''}', locale);
|
||||||
if (size < _megaDivider) return '${formatter.format(size / _kiloDivider)} KB';
|
if (size < mega) return '${formatter.format(size / kilo)} KB';
|
||||||
if (size < _gigaDivider) return '${formatter.format(size / _megaDivider)} MB';
|
if (size < giga) return '${formatter.format(size / mega)} MB';
|
||||||
if (size < _teraDivider) return '${formatter.format(size / _gigaDivider)} GB';
|
if (size < tera) return '${formatter.format(size / giga)} GB';
|
||||||
return '${formatter.format(size / _teraDivider)} TB';
|
return '${formatter.format(size / tera)} TB';
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ class AboutCredits extends StatelessWidget {
|
||||||
'Español (México)': 'n-berenice',
|
'Español (México)': 'n-berenice',
|
||||||
'Italiano': 'glemco',
|
'Italiano': 'glemco',
|
||||||
'Português (Brasil)': 'Jonatas De Almeida Barros',
|
'Português (Brasil)': 'Jonatas De Almeida Barros',
|
||||||
|
'Türkçe': 'metezd',
|
||||||
'Русский': 'D3ZOXY',
|
'Русский': 'D3ZOXY',
|
||||||
'日本語': 'Maki',
|
'日本語': 'Maki',
|
||||||
'简体中文': '小默, Aerowolf',
|
'简体中文': '小默, Aerowolf',
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:aves/app_flavor.dart';
|
||||||
import 'package:aves/app_mode.dart';
|
import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/l10n/l10n.dart';
|
import 'package:aves/l10n/l10n.dart';
|
||||||
import 'package:aves/model/device.dart';
|
import 'package:aves/model/device.dart';
|
||||||
|
import 'package:aves/model/settings/defaults.dart';
|
||||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||||
import 'package:aves/model/settings/enums/display_refresh_rate_mode.dart';
|
import 'package:aves/model/settings/enums/display_refresh_rate_mode.dart';
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
|
@ -15,6 +16,7 @@ import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/media_store_source.dart';
|
import 'package:aves/model/source/media_store_source.dart';
|
||||||
import 'package:aves/services/accessibility_service.dart';
|
import 'package:aves/services/accessibility_service.dart';
|
||||||
|
import 'package:aves/services/common/optional_event_channel.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
|
@ -30,11 +32,13 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
|
import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
|
||||||
import 'package:aves/widgets/home_page.dart';
|
import 'package:aves/widgets/home_page.dart';
|
||||||
import 'package:aves/widgets/welcome_page.dart';
|
import 'package:aves/widgets/welcome_page.dart';
|
||||||
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:fijkplayer/fijkplayer.dart';
|
import 'package:fijkplayer/fijkplayer.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:material_color_utilities/material_color_utilities.dart';
|
||||||
import 'package:overlay_support/overlay_support.dart';
|
import 'package:overlay_support/overlay_support.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
@ -70,6 +74,7 @@ class AvesApp extends StatefulWidget {
|
||||||
class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
final ValueNotifier<AppMode> appModeNotifier = ValueNotifier(AppMode.main);
|
final ValueNotifier<AppMode> appModeNotifier = ValueNotifier(AppMode.main);
|
||||||
late Future<void> _appSetup;
|
late Future<void> _appSetup;
|
||||||
|
late Future<CorePalette?> _dynamicColorPaletteLoader;
|
||||||
final _mediaStoreSource = MediaStoreSource();
|
final _mediaStoreSource = MediaStoreSource();
|
||||||
final Debouncer _mediaStoreChangeDebouncer = Debouncer(delay: Durations.mediaContentChangeDebounceDelay);
|
final Debouncer _mediaStoreChangeDebouncer = Debouncer(delay: Durations.mediaContentChangeDebounceDelay);
|
||||||
final Set<String> changedUris = {};
|
final Set<String> changedUris = {};
|
||||||
|
@ -77,10 +82,10 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
// observers are not registered when using the same list object with different items
|
// observers are not registered when using the same list object with different items
|
||||||
// the list itself needs to be reassigned
|
// the list itself needs to be reassigned
|
||||||
List<NavigatorObserver> _navigatorObservers = [AvesApp.pageRouteObserver];
|
List<NavigatorObserver> _navigatorObservers = [AvesApp.pageRouteObserver];
|
||||||
final EventChannel _mediaStoreChangeChannel = const EventChannel('deckers.thibault/aves/media_store_change');
|
final EventChannel _mediaStoreChangeChannel = const OptionalEventChannel('deckers.thibault/aves/media_store_change');
|
||||||
final EventChannel _newIntentChannel = const EventChannel('deckers.thibault/aves/intent');
|
final EventChannel _newIntentChannel = const OptionalEventChannel('deckers.thibault/aves/intent');
|
||||||
final EventChannel _analysisCompletionChannel = const EventChannel('deckers.thibault/aves/analysis_events');
|
final EventChannel _analysisCompletionChannel = const OptionalEventChannel('deckers.thibault/aves/analysis_events');
|
||||||
final EventChannel _errorChannel = const EventChannel('deckers.thibault/aves/error');
|
final EventChannel _errorChannel = const OptionalEventChannel('deckers.thibault/aves/error');
|
||||||
|
|
||||||
Widget getFirstPage({Map? intentData}) => settings.hasAcceptedTerms ? HomePage(intentData: intentData) : const WelcomePage();
|
Widget getFirstPage({Map? intentData}) => settings.hasAcceptedTerms ? HomePage(intentData: intentData) : const WelcomePage();
|
||||||
|
|
||||||
|
@ -89,6 +94,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
super.initState();
|
super.initState();
|
||||||
EquatableConfig.stringify = true;
|
EquatableConfig.stringify = true;
|
||||||
_appSetup = _setup();
|
_appSetup = _setup();
|
||||||
|
_dynamicColorPaletteLoader = DynamicColorPlugin.getCorePalette();
|
||||||
_mediaStoreChangeChannel.receiveBroadcastStream().listen((event) => _onMediaStoreChange(event as String?));
|
_mediaStoreChangeChannel.receiveBroadcastStream().listen((event) => _onMediaStoreChange(event as String?));
|
||||||
_newIntentChannel.receiveBroadcastStream().listen((event) => _onNewIntent(event as Map?));
|
_newIntentChannel.receiveBroadcastStream().listen((event) => _onNewIntent(event as Map?));
|
||||||
_analysisCompletionChannel.receiveBroadcastStream().listen((event) => _onAnalysisCompletion());
|
_analysisCompletionChannel.receiveBroadcastStream().listen((event) => _onAnalysisCompletion());
|
||||||
|
@ -120,16 +126,18 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
: Scaffold(
|
: Scaffold(
|
||||||
body: snapshot.hasError ? _buildError(snapshot.error!) : const SizedBox(),
|
body: snapshot.hasError ? _buildError(snapshot.error!) : const SizedBox(),
|
||||||
);
|
);
|
||||||
return Selector<Settings, Tuple3<Locale?, bool, AvesThemeBrightness>>(
|
return Selector<Settings, Tuple4<Locale?, bool, AvesThemeBrightness, bool>>(
|
||||||
selector: (context, s) => Tuple3(
|
selector: (context, s) => Tuple4(
|
||||||
s.locale,
|
s.locale,
|
||||||
s.initialized ? s.accessibilityAnimations.animate : true,
|
s.initialized ? s.accessibilityAnimations.animate : true,
|
||||||
s.initialized ? s.themeBrightness : AvesThemeBrightness.system,
|
s.initialized ? s.themeBrightness : SettingsDefaults.themeBrightness,
|
||||||
|
s.initialized ? s.enableDynamicColor : SettingsDefaults.enableDynamicColor,
|
||||||
),
|
),
|
||||||
builder: (context, s, child) {
|
builder: (context, s, child) {
|
||||||
final settingsLocale = s.item1;
|
final settingsLocale = s.item1;
|
||||||
final areAnimationsEnabled = s.item2;
|
final areAnimationsEnabled = s.item2;
|
||||||
final themeBrightness = s.item3;
|
final themeBrightness = s.item3;
|
||||||
|
final enableDynamicColor = s.item4;
|
||||||
|
|
||||||
final pageTransitionsTheme = areAnimationsEnabled
|
final pageTransitionsTheme = areAnimationsEnabled
|
||||||
// Flutter has various page transition implementations for Android:
|
// Flutter has various page transition implementations for Android:
|
||||||
|
@ -144,27 +152,42 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
// strip page transitions used by `MaterialPageRoute`
|
// strip page transitions used by `MaterialPageRoute`
|
||||||
: const DirectPageTransitionsTheme();
|
: const DirectPageTransitionsTheme();
|
||||||
|
|
||||||
return MaterialApp(
|
return FutureBuilder<CorePalette?>(
|
||||||
navigatorKey: AvesApp.navigatorKey,
|
future: _dynamicColorPaletteLoader,
|
||||||
home: home,
|
builder: (context, snapshot) {
|
||||||
navigatorObservers: _navigatorObservers,
|
const defaultAccent = Themes.defaultAccent;
|
||||||
builder: (context, child) => AvesColorsProvider(
|
Color lightAccent = defaultAccent, darkAccent = defaultAccent;
|
||||||
child: Theme(
|
if (enableDynamicColor) {
|
||||||
data: Theme.of(context).copyWith(
|
// `DynamicColorBuilder` from package `dynamic_color` provides light/dark
|
||||||
pageTransitionsTheme: pageTransitionsTheme,
|
// palettes with a primary color from tones too dark/light (40/80),
|
||||||
|
// so we derive the color with adjusted tones (60/70)
|
||||||
|
final tonalPalette = snapshot.data?.primary;
|
||||||
|
lightAccent = Color(tonalPalette?.get(60) ?? defaultAccent.value);
|
||||||
|
darkAccent = Color(tonalPalette?.get(70) ?? defaultAccent.value);
|
||||||
|
}
|
||||||
|
return MaterialApp(
|
||||||
|
navigatorKey: AvesApp.navigatorKey,
|
||||||
|
home: home,
|
||||||
|
navigatorObservers: _navigatorObservers,
|
||||||
|
builder: (context, child) => AvesColorsProvider(
|
||||||
|
child: Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
pageTransitionsTheme: pageTransitionsTheme,
|
||||||
|
),
|
||||||
|
child: child!,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: child!,
|
onGenerateTitle: (context) => context.l10n.appName,
|
||||||
),
|
theme: Themes.lightTheme(lightAccent),
|
||||||
),
|
darkTheme: themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme(darkAccent) : Themes.darkTheme(darkAccent),
|
||||||
onGenerateTitle: (context) => context.l10n.appName,
|
themeMode: themeBrightness.appThemeMode,
|
||||||
theme: Themes.lightTheme,
|
locale: settingsLocale,
|
||||||
darkTheme: themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme : Themes.darkTheme,
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
themeMode: themeBrightness.appThemeMode,
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
locale: settingsLocale,
|
// TODO TLAD remove custom scroll behavior when this is fixed: https://github.com/flutter/flutter/issues/82906
|
||||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
scrollBehavior: StretchMaterialScrollBehavior(),
|
||||||
supportedLocales: AppLocalizations.supportedLocales,
|
);
|
||||||
// TODO TLAD remove custom scroll behavior when this is fixed: https://github.com/flutter/flutter/issues/82906
|
},
|
||||||
scrollBehavior: StretchMaterialScrollBehavior(),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -207,6 +230,8 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
break;
|
break;
|
||||||
case AppMode.pickMediaInternal:
|
case AppMode.pickMediaInternal:
|
||||||
case AppMode.pickFilterInternal:
|
case AppMode.pickFilterInternal:
|
||||||
|
case AppMode.setWallpaper:
|
||||||
|
case AppMode.slideshow:
|
||||||
case AppMode.view:
|
case AppMode.view:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -223,7 +248,14 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
if (!settings.initialized) return;
|
if (!settings.initialized) return;
|
||||||
|
|
||||||
final stopwatch = Stopwatch()..start();
|
final stopwatch = Stopwatch()..start();
|
||||||
final screenSize = window.physicalSize / window.devicePixelRatio;
|
final Size screenSize;
|
||||||
|
try {
|
||||||
|
screenSize = window.physicalSize / window.devicePixelRatio;
|
||||||
|
} catch (error) {
|
||||||
|
// view may no longer be usable
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var tileExtent = settings.getTileExtent(CollectionPage.routeName);
|
var tileExtent = settings.getTileExtent(CollectionPage.routeName);
|
||||||
if (tileExtent == 0) {
|
if (tileExtent == 0) {
|
||||||
tileExtent = screenSize.shortestSide / CollectionGrid.columnCountDefault;
|
tileExtent = screenSize.shortestSide / CollectionGrid.columnCountDefault;
|
||||||
|
|
|
@ -284,6 +284,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
child: PopupMenuItemExpansionPanel<EntrySetAction>(
|
child: PopupMenuItemExpansionPanel<EntrySetAction>(
|
||||||
enabled: canApplyEditActions,
|
enabled: canApplyEditActions,
|
||||||
|
value: 'edit',
|
||||||
icon: AIcons.edit,
|
icon: AIcons.edit,
|
||||||
title: context.l10n.collectionActionEdit,
|
title: context.l10n.collectionActionEdit,
|
||||||
items: [
|
items: [
|
||||||
|
@ -477,6 +478,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
case EntrySetAction.addShortcut:
|
case EntrySetAction.addShortcut:
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
|
case EntrySetAction.slideshow:
|
||||||
case EntrySetAction.stats:
|
case EntrySetAction.stats:
|
||||||
case EntrySetAction.rescan:
|
case EntrySetAction.rescan:
|
||||||
case EntrySetAction.emptyBin:
|
case EntrySetAction.emptyBin:
|
||||||
|
|
|
@ -29,6 +29,7 @@ import 'package:aves/widgets/common/grid/section_layout.dart';
|
||||||
import 'package:aves/widgets/common/grid/selector.dart';
|
import 'package:aves/widgets/common/grid/selector.dart';
|
||||||
import 'package:aves/widgets/common/grid/sliver.dart';
|
import 'package:aves/widgets/common/grid/sliver.dart';
|
||||||
import 'package:aves/widgets/common/grid/theme.dart';
|
import 'package:aves/widgets/common/grid/theme.dart';
|
||||||
|
import 'package:aves/widgets/common/identity/buttons.dart';
|
||||||
import 'package:aves/widgets/common/identity/empty.dart';
|
import 'package:aves/widgets/common/identity/empty.dart';
|
||||||
import 'package:aves/widgets/common/identity/scroll_thumb.dart';
|
import 'package:aves/widgets/common/identity/scroll_thumb.dart';
|
||||||
import 'package:aves/widgets/common/providers/tile_extent_controller_provider.dart';
|
import 'package:aves/widgets/common/providers/tile_extent_controller_provider.dart';
|
||||||
|
@ -39,6 +40,7 @@ import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
@ -97,6 +99,7 @@ class _CollectionGridContent extends StatelessWidget {
|
||||||
final sectionedListLayoutProvider = ValueListenableBuilder<double>(
|
final sectionedListLayoutProvider = ValueListenableBuilder<double>(
|
||||||
valueListenable: context.select<TileExtentController, ValueNotifier<double>>((controller) => controller.extentNotifier),
|
valueListenable: context.select<TileExtentController, ValueNotifier<double>>((controller) => controller.extentNotifier),
|
||||||
builder: (context, thumbnailExtent, child) {
|
builder: (context, thumbnailExtent, child) {
|
||||||
|
assert(thumbnailExtent > 0);
|
||||||
return Selector<TileExtentController, Tuple4<double, int, double, double>>(
|
return Selector<TileExtentController, Tuple4<double, int, double, double>>(
|
||||||
selector: (context, c) => Tuple4(c.viewportSize.width, c.columnCount, c.spacing, c.horizontalPadding),
|
selector: (context, c) => Tuple4(c.viewportSize.width, c.columnCount, c.spacing, c.horizontalPadding),
|
||||||
builder: (context, c, child) {
|
builder: (context, c, child) {
|
||||||
|
@ -305,13 +308,15 @@ class _CollectionScrollView extends StatefulWidget {
|
||||||
State<_CollectionScrollView> createState() => _CollectionScrollViewState();
|
State<_CollectionScrollView> createState() => _CollectionScrollViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CollectionScrollViewState extends State<_CollectionScrollView> {
|
class _CollectionScrollViewState extends State<_CollectionScrollView> with WidgetsBindingObserver {
|
||||||
Timer? _scrollMonitoringTimer;
|
Timer? _scrollMonitoringTimer;
|
||||||
|
bool _checkingStoragePermission = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_registerWidget(widget);
|
_registerWidget(widget);
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -323,6 +328,7 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
_unregisterWidget(widget);
|
_unregisterWidget(widget);
|
||||||
_stopScrollMonitoringTimer();
|
_stopScrollMonitoringTimer();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
@ -340,6 +346,26 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> {
|
||||||
widget.scrollController.removeListener(_onScrollChange);
|
widget.scrollController.removeListener(_onScrollChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
switch (state) {
|
||||||
|
case AppLifecycleState.inactive:
|
||||||
|
case AppLifecycleState.paused:
|
||||||
|
case AppLifecycleState.detached:
|
||||||
|
break;
|
||||||
|
case AppLifecycleState.resumed:
|
||||||
|
if (_checkingStoragePermission) {
|
||||||
|
_checkingStoragePermission = false;
|
||||||
|
_isStoragePermissionGranted.then((granted) {
|
||||||
|
if (granted) {
|
||||||
|
widget.collection.source.init();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scrollView = _buildScrollView(widget.appBar, widget.collection);
|
final scrollView = _buildScrollView(widget.appBar, widget.collection);
|
||||||
|
@ -423,23 +449,47 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> {
|
||||||
valueListenable: collection.source.stateNotifier,
|
valueListenable: collection.source.stateNotifier,
|
||||||
builder: (context, sourceState, child) {
|
builder: (context, sourceState, child) {
|
||||||
if (sourceState == SourceState.loading) {
|
if (sourceState == SourceState.loading) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
if (collection.filters.any((filter) => filter is FavouriteFilter)) {
|
|
||||||
return EmptyContent(
|
return FutureBuilder<bool>(
|
||||||
icon: AIcons.favourite,
|
future: _isStoragePermissionGranted,
|
||||||
text: context.l10n.collectionEmptyFavourites,
|
builder: (context, snapshot) {
|
||||||
);
|
final granted = snapshot.data ?? true;
|
||||||
}
|
Widget? bottom = granted
|
||||||
if (collection.filters.any((filter) => filter is MimeFilter && filter.mime == MimeTypes.anyVideo)) {
|
? null
|
||||||
return EmptyContent(
|
: Padding(
|
||||||
icon: AIcons.video,
|
padding: const EdgeInsets.only(top: 16),
|
||||||
text: context.l10n.collectionEmptyVideos,
|
child: AvesOutlinedButton(
|
||||||
);
|
label: context.l10n.collectionEmptyGrantAccessButtonLabel,
|
||||||
}
|
onPressed: () async {
|
||||||
return EmptyContent(
|
if (await openAppSettings()) {
|
||||||
icon: AIcons.image,
|
_checkingStoragePermission = true;
|
||||||
text: context.l10n.collectionEmptyImages,
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (collection.filters.any((filter) => filter is FavouriteFilter)) {
|
||||||
|
return EmptyContent(
|
||||||
|
icon: AIcons.favourite,
|
||||||
|
text: context.l10n.collectionEmptyFavourites,
|
||||||
|
bottom: bottom,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (collection.filters.any((filter) => filter is MimeFilter && filter.mime == MimeTypes.anyVideo)) {
|
||||||
|
return EmptyContent(
|
||||||
|
icon: AIcons.video,
|
||||||
|
text: context.l10n.collectionEmptyVideos,
|
||||||
|
bottom: bottom,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return EmptyContent(
|
||||||
|
icon: AIcons.image,
|
||||||
|
text: context.l10n.collectionEmptyImages,
|
||||||
|
bottom: bottom,
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -519,4 +569,6 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> {
|
||||||
}
|
}
|
||||||
return crumbs;
|
return crumbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> get _isStoragePermissionGranted => Permission.storage.status.then((status) => status.isGranted);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import 'package:aves/widgets/dialogs/entry_editors/rename_entry_set_dialog.dart'
|
||||||
import 'package:aves/widgets/map/map_page.dart';
|
import 'package:aves/widgets/map/map_page.dart';
|
||||||
import 'package:aves/widgets/search/search_delegate.dart';
|
import 'package:aves/widgets/search/search_delegate.dart';
|
||||||
import 'package:aves/widgets/stats/stats_page.dart';
|
import 'package:aves/widgets/stats/stats_page.dart';
|
||||||
|
import 'package:aves/widgets/viewer/slideshow_page.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
|
@ -73,6 +74,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
return appMode == AppMode.main && isTrash;
|
return appMode == AppMode.main && isTrash;
|
||||||
// browsing or selecting
|
// browsing or selecting
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
|
case EntrySetAction.slideshow:
|
||||||
case EntrySetAction.stats:
|
case EntrySetAction.stats:
|
||||||
return appMode == AppMode.main;
|
return appMode == AppMode.main;
|
||||||
case EntrySetAction.rescan:
|
case EntrySetAction.rescan:
|
||||||
|
@ -124,6 +126,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
case EntrySetAction.emptyBin:
|
case EntrySetAction.emptyBin:
|
||||||
return !isSelecting && hasItems;
|
return !isSelecting && hasItems;
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
|
case EntrySetAction.slideshow:
|
||||||
case EntrySetAction.stats:
|
case EntrySetAction.stats:
|
||||||
case EntrySetAction.rescan:
|
case EntrySetAction.rescan:
|
||||||
return (!isSelecting && hasItems) || (isSelecting && hasSelection);
|
return (!isSelecting && hasItems) || (isSelecting && hasSelection);
|
||||||
|
@ -169,6 +172,9 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
_goToMap(context);
|
_goToMap(context);
|
||||||
break;
|
break;
|
||||||
|
case EntrySetAction.slideshow:
|
||||||
|
_goToSlideshow(context);
|
||||||
|
break;
|
||||||
case EntrySetAction.stats:
|
case EntrySetAction.stats:
|
||||||
_goToStats(context);
|
_goToStats(context);
|
||||||
break;
|
break;
|
||||||
|
@ -543,6 +549,27 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _goToSlideshow(BuildContext context) {
|
||||||
|
final collection = context.read<CollectionLens>();
|
||||||
|
final entries = _getTargetItems(context);
|
||||||
|
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
settings: const RouteSettings(name: SlideshowPage.routeName),
|
||||||
|
builder: (context) {
|
||||||
|
return SlideshowPage(
|
||||||
|
collection: CollectionLens(
|
||||||
|
source: collection.source,
|
||||||
|
filters: collection.filters,
|
||||||
|
fixedSelection: entries.toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _goToStats(BuildContext context) {
|
void _goToStats(BuildContext context) {
|
||||||
final collection = context.read<CollectionLens>();
|
final collection = context.read<CollectionLens>();
|
||||||
final entries = _getTargetItems(context);
|
final entries = _getTargetItems(context);
|
||||||
|
|
|
@ -54,6 +54,8 @@ class InteractiveTile extends StatelessWidget {
|
||||||
Navigator.pop(context, entry);
|
Navigator.pop(context, entry);
|
||||||
break;
|
break;
|
||||||
case AppMode.pickFilterInternal:
|
case AppMode.pickFilterInternal:
|
||||||
|
case AppMode.setWallpaper:
|
||||||
|
case AppMode.slideshow:
|
||||||
case AppMode.view:
|
case AppMode.view:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ mixin FeedbackMixin {
|
||||||
Future<void> showOpReport<T>({
|
Future<void> showOpReport<T>({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required Stream<T> opStream,
|
required Stream<T> opStream,
|
||||||
required int itemCount,
|
int? itemCount,
|
||||||
VoidCallback? onCancel,
|
VoidCallback? onCancel,
|
||||||
void Function(Set<T> processed)? onDone,
|
void Function(Set<T> processed)? onDone,
|
||||||
}) {
|
}) {
|
||||||
|
@ -144,7 +144,7 @@ mixin FeedbackMixin {
|
||||||
|
|
||||||
class ReportOverlay<T> extends StatefulWidget {
|
class ReportOverlay<T> extends StatefulWidget {
|
||||||
final Stream<T> opStream;
|
final Stream<T> opStream;
|
||||||
final int itemCount;
|
final int? itemCount;
|
||||||
final VoidCallback? onCancel;
|
final VoidCallback? onCancel;
|
||||||
final void Function(Set<T> processed) onDone;
|
final void Function(Set<T> processed) onDone;
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ class _ReportOverlayState<T> extends State<ReportOverlay<T>> with SingleTickerPr
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final processedCount = processed.length.toDouble();
|
final processedCount = processed.length.toDouble();
|
||||||
final total = widget.itemCount;
|
final total = widget.itemCount;
|
||||||
final percent = total != 0 ? min(1.0, processedCount / total) : 1.0;
|
final percent = total == null || total == 0 ? 0.0 : min(1.0, processedCount / total);
|
||||||
return FadeTransition(
|
return FadeTransition(
|
||||||
opacity: _animation,
|
opacity: _animation,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
|
@ -243,10 +243,12 @@ class _ReportOverlayState<T> extends State<ReportOverlay<T>> with SingleTickerPr
|
||||||
backgroundColor: Theme.of(context).colorScheme.onSurface.withOpacity(.2),
|
backgroundColor: Theme.of(context).colorScheme.onSurface.withOpacity(.2),
|
||||||
progressColor: progressColor,
|
progressColor: progressColor,
|
||||||
animation: animate,
|
animation: animate,
|
||||||
center: Text(
|
center: total != null
|
||||||
NumberFormat.percentPattern().format(percent),
|
? Text(
|
||||||
style: const TextStyle(fontSize: fontSize),
|
NumberFormat.percentPattern().format(percent),
|
||||||
),
|
style: const TextStyle(fontSize: fontSize),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
animateFromLastPercent: true,
|
animateFromLastPercent: true,
|
||||||
),
|
),
|
||||||
if (widget.onCancel != null)
|
if (widget.onCancel != null)
|
||||||
|
@ -305,12 +307,13 @@ class _FeedbackMessageState extends State<_FeedbackMessage> with SingleTickerPro
|
||||||
if (start != null && stop != null) {
|
if (start != null && stop != null) {
|
||||||
_totalDurationMillis = stop.difference(start).inMilliseconds;
|
_totalDurationMillis = stop.difference(start).inMilliseconds;
|
||||||
final remainingDuration = stop.difference(DateTime.now());
|
final remainingDuration = stop.difference(DateTime.now());
|
||||||
|
final effectiveDuration = remainingDuration > Duration.zero ? remainingDuration : const Duration(milliseconds: 1);
|
||||||
_animationController = AnimationController(
|
_animationController = AnimationController(
|
||||||
duration: remainingDuration,
|
duration: effectiveDuration,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
_remainingDurationMillis = IntTween(
|
_remainingDurationMillis = IntTween(
|
||||||
begin: remainingDuration.inMilliseconds,
|
begin: effectiveDuration.inMilliseconds,
|
||||||
end: 0,
|
end: 0,
|
||||||
).animate(CurvedAnimation(
|
).animate(CurvedAnimation(
|
||||||
parent: _animationController!,
|
parent: _animationController!,
|
||||||
|
|
|
@ -38,7 +38,7 @@ class AvesHighlightView extends StatelessWidget {
|
||||||
this.padding,
|
this.padding,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
int tabSize = 8, // TODO: https://github.com/flutter/flutter/issues/50087
|
int tabSize = 8, // TODO: https://github.com/flutter/flutter/issues/50087
|
||||||
}) : source = input.replaceAll('\t', ' ' * tabSize);
|
}) : source = input.replaceAll('\t', ' ' * tabSize);
|
||||||
|
|
||||||
List<TextSpan> _convert(List<Node> nodes) {
|
List<TextSpan> _convert(List<Node> nodes) {
|
||||||
final spans = <TextSpan>[];
|
final spans = <TextSpan>[];
|
||||||
|
|
|
@ -55,25 +55,27 @@ class MenuIconTheme extends StatelessWidget {
|
||||||
|
|
||||||
class PopupMenuItemExpansionPanel<T> extends StatefulWidget {
|
class PopupMenuItemExpansionPanel<T> extends StatefulWidget {
|
||||||
final bool enabled;
|
final bool enabled;
|
||||||
|
final String value;
|
||||||
|
final ValueNotifier<String?> expandedNotifier;
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String title;
|
final String title;
|
||||||
final List<PopupMenuEntry<T>> items;
|
final List<PopupMenuEntry<T>> items;
|
||||||
|
|
||||||
const PopupMenuItemExpansionPanel({
|
PopupMenuItemExpansionPanel({
|
||||||
super.key,
|
super.key,
|
||||||
this.enabled = true,
|
this.enabled = true,
|
||||||
|
required this.value,
|
||||||
|
ValueNotifier<String?>? expandedNotifier,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.items,
|
required this.items,
|
||||||
});
|
}) : expandedNotifier = expandedNotifier ?? ValueNotifier(null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<PopupMenuItemExpansionPanel<T>> createState() => _PopupMenuItemExpansionPanelState<T>();
|
State<PopupMenuItemExpansionPanel<T>> createState() => _PopupMenuItemExpansionPanelState<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PopupMenuItemExpansionPanelState<T> extends State<PopupMenuItemExpansionPanel<T>> {
|
class _PopupMenuItemExpansionPanelState<T> extends State<PopupMenuItemExpansionPanel<T>> {
|
||||||
bool _isExpanded = false;
|
|
||||||
|
|
||||||
// ref `_kMenuHorizontalPadding` used in `PopupMenuItem`
|
// ref `_kMenuHorizontalPadding` used in `PopupMenuItem`
|
||||||
static const double _horizontalPadding = 16;
|
static const double _horizontalPadding = 16;
|
||||||
|
|
||||||
|
@ -86,38 +88,43 @@ class _PopupMenuItemExpansionPanelState<T> extends State<PopupMenuItemExpansionP
|
||||||
}
|
}
|
||||||
final animationDuration = context.select<DurationsData, Duration>((v) => v.expansionTileAnimation);
|
final animationDuration = context.select<DurationsData, Duration>((v) => v.expansionTileAnimation);
|
||||||
|
|
||||||
Widget child = ExpansionPanelList(
|
Widget child = ValueListenableBuilder<String?>(
|
||||||
expansionCallback: (index, isExpanded) {
|
valueListenable: widget.expandedNotifier,
|
||||||
setState(() => _isExpanded = !isExpanded);
|
builder: (context, expandedValue, child) {
|
||||||
},
|
return ExpansionPanelList(
|
||||||
animationDuration: animationDuration,
|
expansionCallback: (index, isExpanded) {
|
||||||
expandedHeaderPadding: EdgeInsets.zero,
|
widget.expandedNotifier.value = isExpanded ? null : widget.value;
|
||||||
elevation: 0,
|
},
|
||||||
children: [
|
animationDuration: animationDuration,
|
||||||
ExpansionPanel(
|
expandedHeaderPadding: EdgeInsets.zero,
|
||||||
headerBuilder: (context, isExpanded) => DefaultTextStyle(
|
elevation: 0,
|
||||||
style: style,
|
children: [
|
||||||
child: Padding(
|
ExpansionPanel(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: _horizontalPadding),
|
headerBuilder: (context, isExpanded) => DefaultTextStyle(
|
||||||
child: MenuRow(
|
style: style,
|
||||||
text: widget.title,
|
child: Padding(
|
||||||
icon: Icon(widget.icon),
|
padding: const EdgeInsets.symmetric(horizontal: _horizontalPadding),
|
||||||
|
child: MenuRow(
|
||||||
|
text: widget.title,
|
||||||
|
icon: Icon(widget.icon),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
body: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const PopupMenuDivider(height: 0),
|
||||||
|
...widget.items,
|
||||||
|
const PopupMenuDivider(height: 0),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
isExpanded: expandedValue == widget.value,
|
||||||
|
canTapOnHeader: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
body: Column(
|
);
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
},
|
||||||
children: [
|
|
||||||
const PopupMenuDivider(height: 0),
|
|
||||||
...widget.items,
|
|
||||||
const PopupMenuDivider(height: 0),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
isExpanded: _isExpanded,
|
|
||||||
canTapOnHeader: true,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
if (!widget.enabled) {
|
if (!widget.enabled) {
|
||||||
child = IgnorePointer(child: child);
|
child = IgnorePointer(child: child);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
||||||
class QueryBar extends StatefulWidget {
|
class QueryBar extends StatefulWidget {
|
||||||
final ValueNotifier<String> queryNotifier;
|
final ValueNotifier<String> queryNotifier;
|
||||||
final FocusNode? focusNode;
|
final FocusNode? focusNode;
|
||||||
|
final EdgeInsetsGeometry? leadingPadding;
|
||||||
final IconData? icon;
|
final IconData? icon;
|
||||||
final String? hintText;
|
final String? hintText;
|
||||||
final bool editable;
|
final bool editable;
|
||||||
|
@ -15,6 +16,7 @@ class QueryBar extends StatefulWidget {
|
||||||
super.key,
|
super.key,
|
||||||
required this.queryNotifier,
|
required this.queryNotifier,
|
||||||
this.focusNode,
|
this.focusNode,
|
||||||
|
this.leadingPadding,
|
||||||
this.icon,
|
this.icon,
|
||||||
this.hintText,
|
this.hintText,
|
||||||
this.editable = true,
|
this.editable = true,
|
||||||
|
@ -60,7 +62,7 @@ class _QueryBarState extends State<QueryBar> {
|
||||||
focusNode: widget.focusNode ?? FocusNode(),
|
focusNode: widget.focusNode ?? FocusNode(),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
icon: Padding(
|
icon: Padding(
|
||||||
padding: const EdgeInsetsDirectional.only(start: 16),
|
padding: widget.leadingPadding ?? const EdgeInsetsDirectional.only(start: 16),
|
||||||
child: Icon(widget.icon ?? AIcons.filter),
|
child: Icon(widget.icon ?? AIcons.filter),
|
||||||
),
|
),
|
||||||
hintText: widget.hintText ?? MaterialLocalizations.of(context).searchFieldLabel,
|
hintText: widget.hintText ?? MaterialLocalizations.of(context).searchFieldLabel,
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ReselectableRadioListTile<T> extends StatelessWidget {
|
||||||
this.selected = false,
|
this.selected = false,
|
||||||
this.controlAffinity = ListTileControlAffinity.platform,
|
this.controlAffinity = ListTileControlAffinity.platform,
|
||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
}) : assert(!isThreeLine || subtitle != null);
|
}) : assert(!isThreeLine || subtitle != null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -206,7 +206,7 @@ class _AvesFloatingBarState extends State<AvesFloatingBar> with RouteAware {
|
||||||
return ValueListenableBuilder<bool>(
|
return ValueListenableBuilder<bool>(
|
||||||
valueListenable: _isBlurAllowedNotifier,
|
valueListenable: _isBlurAllowedNotifier,
|
||||||
builder: (context, isBlurAllowed, child) {
|
builder: (context, isBlurAllowed, child) {
|
||||||
final blurred = isBlurAllowed && context.select<Settings, bool>((s) => s.enableOverlayBlurEffect);
|
final blurred = isBlurAllowed && context.select<Settings, bool>((s) => s.enableBlurEffect);
|
||||||
return Container(
|
return Container(
|
||||||
foregroundDecoration: BoxDecoration(
|
foregroundDecoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
|
|