Merge branch 'develop'
5
.github/workflows/check.yml
vendored
|
@ -17,14 +17,15 @@ jobs:
|
|||
# Available versions may lag behind https://github.com/flutter/flutter.git
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: '2.10.4'
|
||||
flutter-version: '3.0.1'
|
||||
channel: 'stable'
|
||||
|
||||
- name: Clone the repository.
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get packages for the Flutter project.
|
||||
run: flutter pub get
|
||||
working-directory: ${{ github.workspace }}/scripts
|
||||
run: ./pub_get_all.sh
|
||||
|
||||
- name: Update the flutter version file.
|
||||
working-directory: ${{ github.workspace }}/scripts
|
||||
|
|
14
.github/workflows/release.yml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
|||
# Available versions may lag behind https://github.com/flutter/flutter.git
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: '2.10.4'
|
||||
flutter-version: '3.0.1'
|
||||
channel: 'stable'
|
||||
|
||||
# Workaround for this Android Gradle Plugin issue (supposedly fixed in AGP 4.1):
|
||||
|
@ -31,7 +31,8 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get packages for the Flutter project.
|
||||
run: flutter pub get
|
||||
working-directory: ${{ github.workspace }}/scripts
|
||||
run: ./pub_get_all.sh
|
||||
|
||||
- name: Update the flutter version file.
|
||||
working-directory: ${{ github.workspace }}/scripts
|
||||
|
@ -55,12 +56,15 @@ jobs:
|
|||
rm release.keystore.asc
|
||||
mkdir outputs
|
||||
(cd scripts/; ./apply_flavor_play.sh)
|
||||
flutter build appbundle -t lib/main_play.dart --flavor play --bundle-sksl-path shaders_2.10.4.sksl.json
|
||||
flutter build appbundle -t lib/main_play.dart --flavor play --bundle-sksl-path shaders_3.0.1.sksl.json
|
||||
cp build/app/outputs/bundle/playRelease/*.aab outputs
|
||||
flutter build apk -t lib/main_play.dart --flavor play --bundle-sksl-path shaders_2.10.4.sksl.json
|
||||
flutter build apk -t lib/main_play.dart --flavor play --bundle-sksl-path shaders_3.0.1.sksl.json
|
||||
cp build/app/outputs/apk/play/release/*.apk outputs
|
||||
(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
|
||||
cp build/app/outputs/apk/huawei/release/*.apk outputs
|
||||
(cd scripts/; ./apply_flavor_izzy.sh)
|
||||
flutter build apk -t lib/main_izzy.dart --flavor izzy --split-per-abi --bundle-sksl-path shaders_2.10.4.sksl.json
|
||||
flutter build apk -t lib/main_izzy.dart --flavor izzy --split-per-abi --bundle-sksl-path shaders_3.0.1.sksl.json
|
||||
cp build/app/outputs/apk/izzy/release/*.apk outputs
|
||||
rm $AVES_STORE_FILE
|
||||
env:
|
||||
|
|
23
CHANGELOG.md
|
@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## <a id="unreleased"></a>[Unreleased]
|
||||
|
||||
## <a id="v1.6.5"></a>[v1.6.5] - 2022-05-25
|
||||
|
||||
### Added
|
||||
|
||||
- Bottom navigation bar
|
||||
- Collection: thumbnail overlay tag icon
|
||||
- Collection: fast-scrolling shows breadcrumbs from groups
|
||||
- Settings: search
|
||||
- Pick: allow selecting multiple items according to request intent
|
||||
- `huawei` app flavor (Petal Maps, no Crashlytics)
|
||||
|
||||
### Changed
|
||||
|
||||
- upgraded Flutter to stable v3.0.1
|
||||
- stretching overscroll effect
|
||||
- disabled Google Maps layer on Android Lollipop
|
||||
|
||||
### Fixed
|
||||
|
||||
- grey Google Map layer when size changed
|
||||
- Android scrolling screenshot support
|
||||
- Voice Access scrolling support
|
||||
|
||||
## <a id="v1.6.4"></a>[v1.6.4] - 2022-04-19
|
||||
|
||||
### Added
|
||||
|
|
|
@ -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"
|
||||
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)
|
||||
[<img src="https://raw.githubusercontent.com/deckerst/common/main/assets/amazon-appstore-badge-english-black.png"
|
||||
alt='Get it on Amazon Appstore'
|
||||
height="80">](https://www.amazon.com/dp/B09XQHQQ72)
|
||||
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
|
||||
alt='Get it on IzzyOnDroid'
|
||||
height="80">](https://apt.izzysoft.de/fdroid/index/apk/deckers.thibault.aves)
|
||||
|
@ -19,6 +22,8 @@ Aves is a gallery and metadata explorer app. It is built for Android, with Flutt
|
|||
alt='Get it on GitHub'
|
||||
height="80">](https://github.com/deckerst/aves/releases/latest)
|
||||
|
||||
[Compare versions](https://github.com/deckerst/aves/wiki/App-Versions)
|
||||
|
||||
<div align="left">
|
||||
|
||||
## Features
|
||||
|
@ -77,7 +82,7 @@ Aves requires a few permissions to do its job:
|
|||
|
||||
### Issues
|
||||
|
||||
[Bug reports](https://github.com/deckerst/aves/issues/new?assignees=&labels=type%3Abug&template=bug_report.md&title=) and [feature requests](https://github.com/deckerst/aves/issues/new?assignees=&labels=type%3Afeature&template=feature_request.md&title=) are welcome. Questions too, though you could also ask them in [Discussions](https://github.com/deckerst/aves/discussions).
|
||||
[Bug reports](https://github.com/deckerst/aves/issues/new?assignees=&labels=type%3Abug&template=bug_report.md&title=) and [feature requests](https://github.com/deckerst/aves/issues/new?assignees=&labels=type%3Afeature&template=feature_request.md&title=) are welcome, but read the [guidelines](https://github.com/deckerst/aves/issues/234) first. If you have questions, check out the [discussions](https://github.com/deckerst/aves/discussions).
|
||||
|
||||
### Code
|
||||
|
||||
|
|
|
@ -11,6 +11,12 @@ analyzer:
|
|||
|
||||
linter:
|
||||
rules:
|
||||
# from 'flutter_lints', excluded
|
||||
use_build_context_synchronously: false # no alternative
|
||||
|
||||
# from 'lints / recommended', excluded
|
||||
no_leading_underscores_for_local_identifiers: false # useful for null checked variable variants
|
||||
|
||||
# from 'effective dart', excluded
|
||||
avoid_classes_with_only_static_members: false # too strict
|
||||
avoid_function_literals_in_foreach_calls: false # benefit?
|
||||
|
|
75
android/app/agconnect-services.json
Normal file
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"agcgw_all":{
|
||||
"CN":"connect-drcn.dbankcloud.cn",
|
||||
"CN_back":"connect-drcn.hispace.hicloud.com",
|
||||
"DE":"connect-dre.dbankcloud.cn",
|
||||
"DE_back":"connect-dre.hispace.hicloud.com",
|
||||
"RU":"connect-drru.hispace.dbankcloud.ru",
|
||||
"RU_back":"connect-drru.hispace.dbankcloud.ru",
|
||||
"SG":"connect-dra.dbankcloud.cn",
|
||||
"SG_back":"connect-dra.hispace.hicloud.com"
|
||||
},
|
||||
"client":{
|
||||
"cp_id":"2640082000020010713",
|
||||
"product_id":"99536292102197525",
|
||||
"client_id":"874325707927340288",
|
||||
"client_secret":"DCAFAE5C0440ABDBD6DDB2B6EBD7D9B0870C10FCA64759CCD63020D168803AB5",
|
||||
"project_id":"99536292102197525",
|
||||
"app_id":"106014023",
|
||||
"api_key":"DAEDAEzScQA5ri36P2NEiVPSFrOJeYZ0DbEJZMGJrBadW+QudBr5BGHD3vO0tsL1VeBy0RPZefPic3hAWUijcBxCv0zRv0iBjQEptQ==",
|
||||
"package_name":"deckers.thibault.aves"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_id":"106014023",
|
||||
"client_type":1
|
||||
},
|
||||
"app_info":{
|
||||
"app_id":"106014023",
|
||||
"package_name":"deckers.thibault.aves"
|
||||
},
|
||||
"configuration_version":"3.0",
|
||||
"appInfos":[
|
||||
{
|
||||
"package_name":"deckers.thibault.aves.profile",
|
||||
"client":{
|
||||
"app_id":"106031461"
|
||||
},
|
||||
"app_info":{
|
||||
"package_name":"deckers.thibault.aves.profile",
|
||||
"app_id":"106031461"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_type":1,
|
||||
"client_id":"106031461"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package_name":"deckers.thibault.aves.debug",
|
||||
"client":{
|
||||
"app_id":"106014297"
|
||||
},
|
||||
"app_info":{
|
||||
"package_name":"deckers.thibault.aves.debug",
|
||||
"app_id":"106014297"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_type":1,
|
||||
"client_id":"106014297"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package_name":"deckers.thibault.aves",
|
||||
"client":{
|
||||
"app_id":"106014023"
|
||||
},
|
||||
"app_info":{
|
||||
"package_name":"deckers.thibault.aves",
|
||||
"app_id":"106014023"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_type":1,
|
||||
"client_id":"106014023"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -81,6 +81,16 @@ android {
|
|||
// Google Play
|
||||
dimension "store"
|
||||
ext.useCrashlytics = true
|
||||
ext.useHMS = false
|
||||
// generate a universal APK without x86 native libs
|
||||
ext.useNdkAbiFilters = true
|
||||
}
|
||||
|
||||
huawei {
|
||||
// Huawei AppGallery
|
||||
dimension "store"
|
||||
ext.useCrashlytics = false
|
||||
ext.useHMS = true
|
||||
// generate a universal APK without x86 native libs
|
||||
ext.useNdkAbiFilters = true
|
||||
}
|
||||
|
@ -91,6 +101,7 @@ android {
|
|||
// cf https://android.izzysoft.de/articles/named/app-modules-2
|
||||
dimension "store"
|
||||
ext.useCrashlytics = false
|
||||
ext.useHMS = false
|
||||
// generate APK by ABI, but NDK ABI filters are incompatible with split APK generation
|
||||
ext.useNdkAbiFilters = false
|
||||
}
|
||||
|
@ -129,6 +140,7 @@ android {
|
|||
lint {
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
namespace 'deckers.thibault.aves'
|
||||
}
|
||||
|
||||
flutter {
|
||||
|
@ -147,12 +159,15 @@ dependencies {
|
|||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'com.caverock:androidsvg-aar:1.4'
|
||||
implementation 'com.commonsware.cwac:document:0.4.1'
|
||||
implementation 'com.drewnoakes:metadata-extractor:2.17.0'
|
||||
implementation 'com.drewnoakes:metadata-extractor:2.18.0'
|
||||
// forked, built by JitPack, cf https://jitpack.io/p/deckerst/Android-TiffBitmapFactory
|
||||
implementation 'com.github.deckerst:Android-TiffBitmapFactory:876e53870a'
|
||||
// forked, built by JitPack, cf https://jitpack.io/p/deckerst/pixymeta-android
|
||||
implementation 'com.github.deckerst:pixymeta-android:706bd73d6e'
|
||||
implementation 'com.github.bumptech.glide:glide:4.13.1'
|
||||
implementation 'com.github.bumptech.glide:glide:4.13.2'
|
||||
|
||||
// huawei flavor only
|
||||
huaweiImplementation 'com.huawei.agconnect:agconnect-core:1.5.2.300'
|
||||
|
||||
kapt 'androidx.annotation:annotation:1.3.0'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.13.0'
|
||||
|
@ -163,8 +178,12 @@ dependencies {
|
|||
android.productFlavors.each { flavor ->
|
||||
def tasks = gradle.startParameter.taskRequests.toString().toLowerCase()
|
||||
if (tasks.contains(flavor.name) && flavor.ext.useCrashlytics) {
|
||||
println("Building flavor with Crashlytics [${flavor.name}] - applying plugin")
|
||||
println("Building flavor [${flavor.name}] with Crashlytics plugin")
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
}
|
||||
if (tasks.contains(flavor.name) && flavor.ext.useHMS) {
|
||||
println("Building flavor [${flavor.name}] with HMS plugin")
|
||||
apply plugin: 'com.huawei.agconnect'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="deckers.thibault.aves"
|
||||
android:installLocation="auto">
|
||||
|
||||
<!--
|
||||
|
@ -35,6 +34,15 @@
|
|||
<intent>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent>
|
||||
<!--
|
||||
from Android R, `url_launcher` method `canLaunchUrl()` will return false,
|
||||
if appropriate intents are not declared, cf https://pub.dev/packages/url_launcher#configuration=
|
||||
-->
|
||||
<!-- to open https URLs -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
|
|
|
@ -2,6 +2,7 @@ package deckers.thibault.aves
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.SearchManager
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
|
@ -16,7 +17,6 @@ import app.loup.streams_channel.StreamsChannel
|
|||
import deckers.thibault.aves.channel.calls.*
|
||||
import deckers.thibault.aves.channel.streams.*
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import deckers.thibault.aves.utils.PermissionManager
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
|
@ -222,6 +222,7 @@ class MainActivity : FlutterActivity() {
|
|||
return hashMapOf(
|
||||
INTENT_DATA_KEY_ACTION to INTENT_ACTION_PICK,
|
||||
INTENT_DATA_KEY_MIME_TYPE to intent.type,
|
||||
INTENT_DATA_KEY_ALLOW_MULTIPLE to (intent.extras?.getBoolean(Intent.EXTRA_ALLOW_MULTIPLE) ?: false),
|
||||
)
|
||||
}
|
||||
Intent.ACTION_SEARCH -> {
|
||||
|
@ -246,10 +247,20 @@ class MainActivity : FlutterActivity() {
|
|||
}
|
||||
|
||||
private fun pick(call: MethodCall) {
|
||||
val pickedUri = call.argument<String>("uri")
|
||||
if (pickedUri != null) {
|
||||
val pickedUris = call.argument<List<String>>("uris")
|
||||
if (pickedUris != null && pickedUris.isNotEmpty()) {
|
||||
val toUri = { uriString: String -> AppAdapterHandler.getShareableUri(context, Uri.parse(uriString)) }
|
||||
val intent = Intent().apply {
|
||||
data = Uri.parse(pickedUri)
|
||||
val firstUri = toUri(pickedUris.first())
|
||||
if (pickedUris.size == 1) {
|
||||
data = firstUri
|
||||
} else {
|
||||
clipData = ClipData.newUri(contentResolver, null, firstUri).apply {
|
||||
pickedUris.drop(1).forEach {
|
||||
addItem(ClipData.Item(toUri(it)))
|
||||
}
|
||||
}
|
||||
}
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
setResult(RESULT_OK, intent)
|
||||
|
@ -307,6 +318,7 @@ class MainActivity : FlutterActivity() {
|
|||
const val INTENT_DATA_KEY_ACTION = "action"
|
||||
const val INTENT_DATA_KEY_FILTERS = "filters"
|
||||
const val INTENT_DATA_KEY_MIME_TYPE = "mimeType"
|
||||
const val INTENT_DATA_KEY_ALLOW_MULTIPLE = "allowMultiple"
|
||||
const val INTENT_DATA_KEY_PAGE = "page"
|
||||
const val INTENT_DATA_KEY_URI = "uri"
|
||||
const val INTENT_DATA_KEY_QUERY = "query"
|
||||
|
|
|
@ -216,7 +216,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
try {
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
|
||||
if (clipboard != null) {
|
||||
val clip = ClipData.newUri(context.contentResolver, label, getShareableUri(uri))
|
||||
val clip = ClipData.newUri(context.contentResolver, label, getShareableUri(context, uri))
|
||||
clipboard.setPrimaryClip(clip)
|
||||
result.success(true)
|
||||
} else {
|
||||
|
@ -239,7 +239,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
|
||||
val intent = Intent(Intent.ACTION_EDIT)
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
.setDataAndType(getShareableUri(uri), mimeType)
|
||||
.setDataAndType(getShareableUri(context, uri), mimeType)
|
||||
val started = safeStartActivityChooser(title, intent)
|
||||
|
||||
result.success(started)
|
||||
|
@ -256,7 +256,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.setDataAndType(getShareableUri(uri), mimeType)
|
||||
.setDataAndType(getShareableUri(context, uri), mimeType)
|
||||
val started = safeStartActivityChooser(title, intent)
|
||||
|
||||
result.success(started)
|
||||
|
@ -286,7 +286,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
|
||||
val intent = Intent(Intent.ACTION_ATTACH_DATA)
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.setDataAndType(getShareableUri(uri), mimeType)
|
||||
.setDataAndType(getShareableUri(context, uri), mimeType)
|
||||
val started = safeStartActivityChooser(title, intent)
|
||||
|
||||
result.success(started)
|
||||
|
@ -311,7 +311,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
val intent = Intent(Intent.ACTION_SEND)
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.setType(mimeType)
|
||||
.putExtra(Intent.EXTRA_STREAM, getShareableUri(uri))
|
||||
.putExtra(Intent.EXTRA_STREAM, getShareableUri(context, uri))
|
||||
safeStartActivityChooser(title, intent)
|
||||
} else {
|
||||
var mimeType = "*/*"
|
||||
|
@ -368,18 +368,6 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
return false
|
||||
}
|
||||
|
||||
private fun getShareableUri(uri: Uri): Uri? {
|
||||
return when (uri.scheme?.lowercase(Locale.ROOT)) {
|
||||
ContentResolver.SCHEME_FILE -> {
|
||||
uri.path?.let { path ->
|
||||
val authority = "${context.applicationContext.packageName}.file_provider"
|
||||
FileProvider.getUriForFile(context, authority, File(path))
|
||||
}
|
||||
}
|
||||
else -> uri
|
||||
}
|
||||
}
|
||||
|
||||
// shortcuts
|
||||
|
||||
private fun pinShortcut(call: MethodCall, result: MethodChannel.Result) {
|
||||
|
@ -443,5 +431,17 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
companion object {
|
||||
private val LOG_TAG = LogUtils.createTag<AppAdapterHandler>()
|
||||
const val CHANNEL = "deckers.thibault/aves/app"
|
||||
|
||||
fun getShareableUri(context: Context, uri: Uri): Uri? {
|
||||
return when (uri.scheme?.lowercase(Locale.ROOT)) {
|
||||
ContentResolver.SCHEME_FILE -> {
|
||||
uri.path?.let { path ->
|
||||
val authority = "${context.applicationContext.packageName}.file_provider"
|
||||
FileProvider.getUriForFile(context, authority, File(path))
|
||||
}
|
||||
}
|
||||
else -> uri
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -308,6 +308,8 @@ class DebugHandler(private val context: Context) : MethodCallHandler {
|
|||
Log.w(LOG_TAG, "failed to get metadata by metadata-extractor for uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to get metadata by metadata-extractor for uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to get metadata by metadata-extractor for uri=$uri", e)
|
||||
}
|
||||
}
|
||||
result.success(metadataMap)
|
||||
|
|
|
@ -32,10 +32,6 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
|||
"canPinShortcut" to ShortcutManagerCompat.isRequestPinShortcutSupported(context),
|
||||
"canPrint" to (sdkInt >= Build.VERSION_CODES.KITKAT),
|
||||
"canRenderFlagEmojis" to (sdkInt >= Build.VERSION_CODES.LOLLIPOP),
|
||||
// as of google_maps_flutter v2.1.1, minSDK is 20 because of default PlatformView usage,
|
||||
// but using hybrid composition would make it usable on API 19 too,
|
||||
// cf https://github.com/flutter/flutter/issues/23728
|
||||
"canRenderGoogleMaps" to (sdkInt >= Build.VERSION_CODES.KITKAT_WATCH),
|
||||
"showPinShortcutFeedback" to (sdkInt >= Build.VERSION_CODES.O),
|
||||
"supportEdgeToEdgeUIMode" to (sdkInt >= Build.VERSION_CODES.Q),
|
||||
)
|
||||
|
|
|
@ -175,6 +175,8 @@ class EmbeddedDataHandler(private val context: Context) : MethodCallHandler {
|
|||
Log.w(LOG_TAG, "failed to extract file from XMP", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to extract file from XMP", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to extract file from XMP", e)
|
||||
}
|
||||
}
|
||||
result.error("extractXmpDataProp-empty", "failed to extract file from XMP uri=$uri prop=$dataPropPath", null)
|
||||
|
|
|
@ -331,6 +331,8 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -459,14 +461,14 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
// * `context.getContentResolver().getType()` sometimes returns an incorrect value
|
||||
// * `MediaMetadataRetriever.setDataSource()` sometimes fails with `status = 0x80000000`
|
||||
// * file extension is unreliable
|
||||
// In the end, `metadata-extractor` is the most reliable, except for `tiff`/`dvd`/`mov` (false positives, false negatives),
|
||||
// In the end, `metadata-extractor` is the most reliable, except for `tiff`/`dvd`/`mov`/`zip` (false positives, false negatives),
|
||||
// in which case we trust the file extension
|
||||
// cf https://github.com/drewnoakes/metadata-extractor/issues/296
|
||||
if (path?.matches(TIFF_EXTENSION_PATTERN) == true) {
|
||||
metadataMap[KEY_MIME_TYPE] = MimeTypes.TIFF
|
||||
} else {
|
||||
dir.getSafeString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE) {
|
||||
if (it != MimeTypes.TIFF && it != MimeTypes.DVD && it != MimeTypes.MOV) {
|
||||
if (it != MimeTypes.TIFF && it != MimeTypes.DVD && it != MimeTypes.MOV && it != MimeTypes.ZIP) {
|
||||
metadataMap[KEY_MIME_TYPE] = it
|
||||
}
|
||||
}
|
||||
|
@ -601,6 +603,8 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -727,6 +731,8 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -784,6 +790,8 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
}
|
||||
}
|
||||
result.error("getGeoTiffInfo-empty", "failed to get info for mimeType=$mimeType uri=$uri", null)
|
||||
|
@ -844,6 +852,8 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
}
|
||||
}
|
||||
result.error("getPanoramaInfo-empty", "failed to get info for mimeType=$mimeType uri=$uri", null)
|
||||
|
@ -894,7 +904,10 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
result.error("getXmp-exception", "failed to read XMP for mimeType=$mimeType uri=$uri", e.message)
|
||||
return
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
result.error("getXmp-error", "failed to read XMP for mimeType=$mimeType uri=$uri", e.message)
|
||||
result.error("getXmp-noclass", "failed to read XMP for mimeType=$mimeType uri=$uri", e.message)
|
||||
return
|
||||
} catch (e: AssertionError) {
|
||||
result.error("getXmp-assert", "failed to read XMP for mimeType=$mimeType uri=$uri", e.message)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -1031,6 +1044,8 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for mimeType=$mimeType uri=$uri", e)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ class RegionFetcher internal constructor(
|
|||
}
|
||||
}
|
||||
if (newDecoder == null) {
|
||||
result.error("getRegion-read-null", "failed to open file for uri=$uri regionRect=$regionRect", null)
|
||||
result.error("getRegion-read-null", "failed to open file for mimeType=$mimeType uri=$uri regionRect=$regionRect", null)
|
||||
return
|
||||
}
|
||||
currentDecoderRef = LastDecoderRef(uri, newDecoder)
|
||||
|
|
|
@ -167,6 +167,8 @@ object MultiPage {
|
|||
Log.w(LOG_TAG, "failed to get motion photo offset from uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to get motion photo offset from uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to get motion photo offset from uri=$uri", e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -204,6 +204,8 @@ class SourceEntry {
|
|||
// ignore
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
// ignore
|
||||
} catch (e: AssertionError) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ internal class ContentImageProvider : ImageProvider() {
|
|||
Log.w(LOG_TAG, "failed to get MIME type by metadata-extractor for uri=$uri", e)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
Log.w(LOG_TAG, "failed to get MIME type by metadata-extractor for uri=$uri", e)
|
||||
} catch (e: AssertionError) {
|
||||
Log.w(LOG_TAG, "failed to get MIME type by metadata-extractor for uri=$uri", e)
|
||||
}
|
||||
|
||||
val mimeType = extractorMimeType ?: sourceMimeType
|
||||
|
|
|
@ -1045,6 +1045,9 @@ abstract class ImageProvider {
|
|||
// used when skipping a move/creation op because the target file already exists
|
||||
val skippedFieldMap: HashMap<String, Any?> = hashMapOf("skipped" to true)
|
||||
|
||||
// used when deleting instead of moving to bin because the target file no longer exists
|
||||
val deletedFieldMap: HashMap<String, Any?> = hashMapOf("deleted" to true)
|
||||
|
||||
fun isMediaUriPermissionGranted(context: Context, uri: Uri, mimeType: String): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val safeUri = StorageUtils.getMediaStoreScopedStorageSafeUri(uri, mimeType)
|
||||
|
|
|
@ -443,18 +443,23 @@ class MediaStoreImageProvider : ImageProvider() {
|
|||
if (effectiveTargetDir != null) {
|
||||
val newFields = if (isCancelledOp()) skippedFieldMap else {
|
||||
val sourceFile = File(sourcePath)
|
||||
moveSingle(
|
||||
activity = activity,
|
||||
sourceFile = sourceFile,
|
||||
sourceUri = sourceUri,
|
||||
targetDir = effectiveTargetDir,
|
||||
targetDirDocFile = targetDirDocFile,
|
||||
desiredName = desiredName ?: sourceFile.name,
|
||||
nameConflictStrategy = nameConflictStrategy,
|
||||
mimeType = mimeType,
|
||||
copy = copy,
|
||||
toBin = toBin,
|
||||
)
|
||||
if (!sourceFile.exists() && toBin) {
|
||||
delete(activity, sourceUri, sourcePath, mimeType = mimeType)
|
||||
deletedFieldMap
|
||||
} else {
|
||||
moveSingle(
|
||||
activity = activity,
|
||||
sourceFile = sourceFile,
|
||||
sourceUri = sourceUri,
|
||||
targetDir = effectiveTargetDir,
|
||||
targetDirDocFile = targetDirDocFile,
|
||||
desiredName = desiredName ?: sourceFile.name,
|
||||
nameConflictStrategy = nameConflictStrategy,
|
||||
mimeType = mimeType,
|
||||
copy = copy,
|
||||
toBin = toBin,
|
||||
)
|
||||
}
|
||||
}
|
||||
result["newFields"] = newFields
|
||||
result["success"] = true
|
||||
|
|
|
@ -46,6 +46,7 @@ object MimeTypes {
|
|||
// vector
|
||||
const val SVG = "image/svg+xml"
|
||||
|
||||
// video
|
||||
private const val AVI = "video/avi"
|
||||
private const val AVI_VND = "video/vnd.avi"
|
||||
const val DVD = "video/dvd"
|
||||
|
@ -57,6 +58,9 @@ object MimeTypes {
|
|||
private const val OGV = "video/ogg"
|
||||
private const val WEBM = "video/webm"
|
||||
|
||||
// others
|
||||
const val ZIP = "application/zip"
|
||||
|
||||
fun isImage(mimeType: String?) = mimeType != null && mimeType.startsWith("image")
|
||||
|
||||
fun isVideo(mimeType: String?) = mimeType != null && mimeType.startsWith("video")
|
||||
|
|
|
@ -21,7 +21,6 @@ import deckers.thibault.aves.utils.MimeTypes.isVideo
|
|||
import deckers.thibault.aves.utils.PermissionManager.getGrantedDirForPath
|
||||
import deckers.thibault.aves.utils.UriUtils.tryParseId
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.*
|
||||
|
@ -404,37 +403,37 @@ object StorageUtils {
|
|||
// returns the directory `DocumentFile` (from tree URI when scoped storage is required, `File` otherwise)
|
||||
// returns null if directory does not exist and could not be created
|
||||
fun createDirectoryDocIfAbsent(context: Context, dirPath: String): DocumentFileCompat? {
|
||||
val cleanDirPath = ensureTrailingSeparator(dirPath)
|
||||
return if (requireAccessPermission(context, cleanDirPath) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val grantedDir = getGrantedDirForPath(context, cleanDirPath) ?: return null
|
||||
val rootTreeDocumentUri = convertDirPathToTreeDocumentUri(context, grantedDir) ?: return null
|
||||
var parentFile: DocumentFileCompat? = DocumentFileCompat.fromTreeUri(context, rootTreeDocumentUri) ?: return null
|
||||
val pathIterator = getPathStepIterator(context, cleanDirPath, grantedDir)
|
||||
while (pathIterator?.hasNext() == true) {
|
||||
val dirName = pathIterator.next()
|
||||
var dirFile = findDocumentFileIgnoreCase(parentFile, dirName)
|
||||
if (dirFile == null || !dirFile.exists()) {
|
||||
try {
|
||||
try {
|
||||
val cleanDirPath = ensureTrailingSeparator(dirPath)
|
||||
return if (requireAccessPermission(context, cleanDirPath) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val grantedDir = getGrantedDirForPath(context, cleanDirPath) ?: return null
|
||||
val rootTreeDocumentUri = convertDirPathToTreeDocumentUri(context, grantedDir) ?: return null
|
||||
var parentFile: DocumentFileCompat? = DocumentFileCompat.fromTreeUri(context, rootTreeDocumentUri) ?: return null
|
||||
val pathIterator = getPathStepIterator(context, cleanDirPath, grantedDir)
|
||||
while (pathIterator?.hasNext() == true) {
|
||||
val dirName = pathIterator.next()
|
||||
var dirFile = findDocumentFileIgnoreCase(parentFile, dirName)
|
||||
if (dirFile == null || !dirFile.exists()) {
|
||||
dirFile = parentFile?.createDirectory(dirName)
|
||||
if (dirFile == null) {
|
||||
Log.e(LOG_TAG, "failed to create directory with name=$dirName from parent=$parentFile")
|
||||
return null
|
||||
}
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.e(LOG_TAG, "failed to create directory with name=$dirName from parent=$parentFile", e)
|
||||
return null
|
||||
}
|
||||
parentFile = dirFile
|
||||
}
|
||||
parentFile = dirFile
|
||||
parentFile
|
||||
} else {
|
||||
val directory = File(cleanDirPath)
|
||||
if (!directory.exists() && !directory.mkdirs()) {
|
||||
Log.e(LOG_TAG, "failed to create directories at path=$cleanDirPath")
|
||||
return null
|
||||
}
|
||||
DocumentFileCompat.fromFile(directory)
|
||||
}
|
||||
parentFile
|
||||
} else {
|
||||
val directory = File(cleanDirPath)
|
||||
if (!directory.exists() && !directory.mkdirs()) {
|
||||
Log.e(LOG_TAG, "failed to create directories at path=$cleanDirPath")
|
||||
return null
|
||||
}
|
||||
DocumentFileCompat.fromFile(directory)
|
||||
} catch (e: Exception) {
|
||||
Log.e(LOG_TAG, "failed to create directory at path=$dirPath", e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.20'
|
||||
ext.kotlin_version = '1.6.21'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://developer.huawei.com/repo/' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.1.3'
|
||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
// GMS & Firebase Crashlytics are not actually used by all flavors
|
||||
// GMS & Firebase Crashlytics (used by some flavors only)
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
||||
// HMS (used by some flavors only)
|
||||
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +21,7 @@ allprojects {
|
|||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {url 'https://developer.huawei.com/repo/'}
|
||||
}
|
||||
// gradle.projectsEvaluated {
|
||||
// tasks.withType(JavaCompile) {
|
||||
|
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
|
|
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 209 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 338 KiB |
5
fastlane/metadata/android/en-US/changelogs/1071.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
In v1.6.5:
|
||||
- bottom navigation bar
|
||||
- fast scroll with breadcrumbs
|
||||
- settings search
|
||||
Full changelog available on GitHub
|
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 207 KiB |
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 365 KiB After Width: | Height: | Size: 339 KiB |
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 246 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 212 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 338 KiB |
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 210 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 338 KiB |
Before Width: | Height: | Size: 271 KiB After Width: | Height: | Size: 243 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 207 KiB |
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 338 KiB |
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 245 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 210 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 362 KiB After Width: | Height: | Size: 337 KiB |
|
@ -1,7 +1,7 @@
|
|||
<i>Aves</i>はあらゆる画像や動画を扱うことができ、一般的なJPEGやMP4はもちろん、 <b>マルチページTIFF、SVG、古いAVIなどの珍しい形式にも対応しています!</b>
|
||||
<i>Aves</i>はあらゆる画像や動画を扱うことができ、一般的なJPEGやMP4はもちろん、 <b>マルチページTIFF、SVG、古いAVIなどの珍しい形式にも対応</b>しています!
|
||||
|
||||
メディアコレクションをスキャンして、<b>モーションフォト</b>、<b>パノラマ</b>(Photo Sphere)、<b>360°動画</b>、<b>GeoTIFF<b>ファイルなどを識別します。
|
||||
メディアコレクションをスキャンして、<b>モーションフォト</b>、<b>パノラマ</b>(Photo Sphere)、<b>360°動画</b>、<b>GeoTIFF</b>ファイルなどを識別します。
|
||||
|
||||
<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>としても機能します。
|
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 243 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 362 KiB After Width: | Height: | Size: 336 KiB |
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 243 KiB |
Before Width: | Height: | Size: 496 KiB After Width: | Height: | Size: 496 KiB |
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 206 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 363 KiB After Width: | Height: | Size: 337 KiB |
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 246 KiB |
Before Width: | Height: | Size: 495 KiB After Width: | Height: | Size: 495 KiB |
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 214 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 338 KiB |
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 215 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 338 KiB |
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 494 KiB |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 210 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 362 KiB After Width: | Height: | Size: 337 KiB |
|
@ -1,5 +1,13 @@
|
|||
enum AppFlavor { play, izzy }
|
||||
enum AppFlavor { play, huawei, izzy }
|
||||
|
||||
extension ExtraAppFlavor on AppFlavor {
|
||||
bool get canEnableErrorReporting => this == AppFlavor.play;
|
||||
bool get canEnableErrorReporting {
|
||||
switch (this) {
|
||||
case AppFlavor.play:
|
||||
return true;
|
||||
case AppFlavor.huawei:
|
||||
case AppFlavor.izzy:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
enum AppMode { main, pickMediaExternal, pickMediaInternal, pickFilterInternal, view }
|
||||
enum AppMode { main, pickSingleMediaExternal, pickMultipleMediaExternal, pickMediaInternal, pickFilterInternal, view }
|
||||
|
||||
extension ExtraAppMode on AppMode {
|
||||
bool get canSearch => this == AppMode.main || this == AppMode.pickMediaExternal;
|
||||
bool get canSearch => this == AppMode.main || this == AppMode.pickSingleMediaExternal || this == AppMode.pickMultipleMediaExternal;
|
||||
|
||||
bool get canSelect => this == AppMode.main;
|
||||
bool get canSelectMedia => this == AppMode.main || this == AppMode.pickMultipleMediaExternal;
|
||||
|
||||
bool get hasDrawer => this == AppMode.main || this == AppMode.pickMediaExternal;
|
||||
bool get canSelectFilter => this == AppMode.main;
|
||||
|
||||
bool get isPickingMedia => this == AppMode.pickMediaExternal || this == AppMode.pickMediaInternal;
|
||||
bool get hasDrawer => this == AppMode.main || this == AppMode.pickSingleMediaExternal || this == AppMode.pickMultipleMediaExternal;
|
||||
|
||||
bool get isPickingMedia => this == AppMode.pickSingleMediaExternal || this == AppMode.pickMultipleMediaExternal || this == AppMode.pickMediaInternal;
|
||||
}
|
||||
|
|
|
@ -124,6 +124,8 @@
|
|||
"mapStyleGoogleNormal": "Google Maps",
|
||||
"mapStyleGoogleHybrid": "Google Maps (Hybrid)",
|
||||
"mapStyleGoogleTerrain": "Google Maps (Gelände)",
|
||||
"mapStyleHuaweiNormal": "Petal Maps",
|
||||
"mapStyleHuaweiTerrain": "Petal Maps (Gelände)",
|
||||
"mapStyleOsmHot": "Humanitäres OSM",
|
||||
"mapStyleStamenToner": "Stamen Toner (SchwarzWeiß)",
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor (Aquarell)",
|
||||
|
@ -406,6 +408,8 @@
|
|||
"settingsSystemDefault": "System",
|
||||
"settingsDefault": "Standard",
|
||||
|
||||
"settingsSearchFieldLabel": "Einstellungen durchsuchen",
|
||||
"settingsSearchEmpty": "Keine passende Einstellung",
|
||||
"settingsActionExport": "Exportieren",
|
||||
"settingsActionImport": "Importieren",
|
||||
|
||||
|
@ -415,6 +419,7 @@
|
|||
|
||||
"settingsSectionNavigation": "Navigation",
|
||||
"settingsHome": "Startseite",
|
||||
"settingsShowBottomNavigationBar": "Untere Navigationsleiste anzeigen",
|
||||
"settingsKeepScreenOnTile": "Bildschirm eingeschaltet lassen",
|
||||
"settingsKeepScreenOnTitle": "Bildschirm eingeschaltet lassen",
|
||||
"settingsDoubleBackExit": "Zum Verlassen zweimal „zurück“ tippen",
|
||||
|
@ -434,7 +439,10 @@
|
|||
"settingsNavigationDrawerAddAlbum": "Album hinzufügen",
|
||||
|
||||
"settingsSectionThumbnails": "Vorschaubilder",
|
||||
"settingsThumbnailOverlayTile": "Überlagerung",
|
||||
"settingsThumbnailOverlayTitle": "Überlagerung",
|
||||
"settingsThumbnailShowFavouriteIcon": "Favoriten-Symbol anzeigen",
|
||||
"settingsThumbnailShowTagIcon": "Tag-Symbol anzeigen",
|
||||
"settingsThumbnailShowLocationIcon": "Standort-Symbol anzeigen",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Bewegungsfoto-Symbol anzeigen",
|
||||
"settingsThumbnailShowRating": "Bewertung anzeigen",
|
||||
|
|
|
@ -164,6 +164,8 @@
|
|||
"mapStyleGoogleNormal": "Google Maps",
|
||||
"mapStyleGoogleHybrid": "Google Maps (Hybrid)",
|
||||
"mapStyleGoogleTerrain": "Google Maps (Terrain)",
|
||||
"mapStyleHuaweiNormal": "Petal Maps",
|
||||
"mapStyleHuaweiTerrain": "Petal Maps (Terrain)",
|
||||
"mapStyleOsmHot": "Humanitarian OSM",
|
||||
"mapStyleStamenToner": "Stamen Toner",
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor",
|
||||
|
@ -586,6 +588,8 @@
|
|||
"settingsSystemDefault": "System",
|
||||
"settingsDefault": "Default",
|
||||
|
||||
"settingsSearchFieldLabel": "Search settings",
|
||||
"settingsSearchEmpty": "No matching setting",
|
||||
"settingsActionExport": "Export",
|
||||
"settingsActionImport": "Import",
|
||||
|
||||
|
@ -595,6 +599,7 @@
|
|||
|
||||
"settingsSectionNavigation": "Navigation",
|
||||
"settingsHome": "Home",
|
||||
"settingsShowBottomNavigationBar": "Show bottom navigation bar",
|
||||
"settingsKeepScreenOnTile": "Keep screen on",
|
||||
"settingsKeepScreenOnTitle": "Keep Screen On",
|
||||
"settingsDoubleBackExit": "Tap “back” twice to exit",
|
||||
|
@ -614,7 +619,10 @@
|
|||
"settingsNavigationDrawerAddAlbum": "Add album",
|
||||
|
||||
"settingsSectionThumbnails": "Thumbnails",
|
||||
"settingsThumbnailOverlayTile": "Overlay",
|
||||
"settingsThumbnailOverlayTitle": "Overlay",
|
||||
"settingsThumbnailShowFavouriteIcon": "Show favorite icon",
|
||||
"settingsThumbnailShowTagIcon": "Show tag icon",
|
||||
"settingsThumbnailShowLocationIcon": "Show location icon",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Show motion photo icon",
|
||||
"settingsThumbnailShowRating": "Show rating",
|
||||
|
@ -751,7 +759,7 @@
|
|||
"viewerInfoLabelUri": "URI",
|
||||
"viewerInfoLabelPath": "Path",
|
||||
"viewerInfoLabelDuration": "Duration",
|
||||
"viewerInfoLabelOwner": "Owned by",
|
||||
"viewerInfoLabelOwner": "Owner",
|
||||
"viewerInfoLabelCoordinates": "Coordinates",
|
||||
"viewerInfoLabelAddress": "Address",
|
||||
|
||||
|
|
|
@ -58,6 +58,9 @@
|
|||
"entryActionPrint": "Imprimir",
|
||||
"entryActionShare": "Compartir",
|
||||
"entryActionViewSource": "Ver fuente",
|
||||
"entryActionShowGeoTiffOnMap": "Mostrar como mapa superpuesto",
|
||||
"entryActionConvertMotionPhotoToStillImage": "Convertir a imagen fija",
|
||||
"entryActionViewMotionPhotoVideo": "Abrir video",
|
||||
"entryActionEdit": "Editar",
|
||||
"entryActionOpen": "Abrir con",
|
||||
"entryActionSetAs": "Establecer como",
|
||||
|
@ -113,14 +116,16 @@
|
|||
"videoLoopModeShortOnly": "Sólo videos cortos",
|
||||
"videoLoopModeAlways": "Siempre",
|
||||
|
||||
"videoControlsNone": "Ninguno",
|
||||
"videoControlsPlay": "Reproducir",
|
||||
"videoControlsPlaySeek": "Reproducir y buscar",
|
||||
"videoControlsPlayOutside": "Reproducir externamente",
|
||||
"videoControlsNone": "Ninguno",
|
||||
|
||||
"mapStyleGoogleNormal": "Mapas de Google",
|
||||
"mapStyleGoogleHybrid": "Mapas de Google (Híbrido)",
|
||||
"mapStyleGoogleTerrain": "Mapas de Google (Superficie)",
|
||||
"mapStyleGoogleNormal": "Google Maps",
|
||||
"mapStyleGoogleHybrid": "Google Maps (Híbrido)",
|
||||
"mapStyleGoogleTerrain": "Google Maps (Relieve)",
|
||||
"mapStyleHuaweiNormal": "Petal Maps",
|
||||
"mapStyleHuaweiTerrain": "Petal Maps (Relieve)",
|
||||
"mapStyleOsmHot": "OSM Humanitario",
|
||||
"mapStyleStamenToner": "Stamen Toner (Monocromático)",
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor (Acuarela)",
|
||||
|
@ -184,6 +189,7 @@
|
|||
"videoResumeButtonLabel": "REANUDAR",
|
||||
|
||||
"setCoverDialogLatest": "Elemento más reciente",
|
||||
"setCoverDialogAuto": "Automático",
|
||||
"setCoverDialogCustom": "Personalizado",
|
||||
|
||||
"hideFilterConfirmationDialogMessage": "Fotos y videos que concuerden serán ocultados de su colección. Puede volver a mostrarlos desde los ajustes de «Privacidad».\n\n¿Está seguro de que desea ocultarlos?",
|
||||
|
@ -237,6 +243,7 @@
|
|||
"removeEntryMetadataDialogMore": "Más",
|
||||
|
||||
"removeEntryMetadataMotionPhotoXmpWarningDialogMessage": "XMP es necesario para reproducir la animación de una foto en movimiento.\n\n¿Está seguro de que desea removerlo?",
|
||||
"convertMotionPhotoToStillImageWarningDialogMessage": "¿Está seguro?",
|
||||
|
||||
"videoSpeedDialogLabel": "Velocidad de reproducción",
|
||||
|
||||
|
@ -264,6 +271,14 @@
|
|||
"tileLayoutGrid": "Cuadrícula",
|
||||
"tileLayoutList": "Lista",
|
||||
|
||||
"coverDialogTabCover": "Carátula",
|
||||
"coverDialogTabApp": "Aplicación",
|
||||
"coverDialogTabColor": "Color",
|
||||
|
||||
"appPickDialogTitle": "Escoger aplicación",
|
||||
"appPickDialogNone": "Ninguna",
|
||||
|
||||
|
||||
"aboutPageTitle": "Acerca de",
|
||||
"aboutLinkSources": "Fuentes",
|
||||
"aboutLinkLicense": "Licencia",
|
||||
|
@ -280,7 +295,8 @@
|
|||
"aboutCredits": "Créditos",
|
||||
"aboutCreditsWorldAtlas1": "Esta aplicación usa un archivo TopoJSON de",
|
||||
"aboutCreditsWorldAtlas2": "bajo licencia ISC.",
|
||||
"aboutCreditsTranslators": "Traductores",
|
||||
"aboutCreditsTranslators": "Traductores:",
|
||||
"aboutCreditsTranslatorLine": "{language}: {names}",
|
||||
|
||||
"aboutLicenses": "Licencias de código abierto",
|
||||
"aboutLicensesBanner": "Esta aplicación usa los siguientes paquetes y librerías de código abierto.",
|
||||
|
@ -394,6 +410,8 @@
|
|||
"settingsSystemDefault": "Sistema",
|
||||
"settingsDefault": "Restablecer",
|
||||
|
||||
"settingsSearchFieldLabel": "Buscar ajustes",
|
||||
"settingsSearchEmpty": "Sin coincidencias",
|
||||
"settingsActionExport": "Exportar",
|
||||
"settingsActionImport": "Importar",
|
||||
|
||||
|
@ -422,6 +440,8 @@
|
|||
"settingsNavigationDrawerAddAlbum": "Agregar álbum",
|
||||
|
||||
"settingsSectionThumbnails": "Miniaturas",
|
||||
"settingsThumbnailOverlayTile": "Incrustaciones",
|
||||
"settingsThumbnailOverlayTitle": "Incrustaciones",
|
||||
"settingsThumbnailShowFavouriteIcon": "Mostrar icono de favoritos",
|
||||
"settingsThumbnailShowLocationIcon": "Mostrar icono de ubicación",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Mostrar icono de foto en movimiento",
|
||||
|
@ -456,7 +476,7 @@
|
|||
"settingsViewerShowInformation": "Mostrar información",
|
||||
"settingsViewerShowInformationSubtitle": "Mostrar título, fecha, ubicación, etc.",
|
||||
"settingsViewerShowShootingDetails": "Mostrar detalles de toma",
|
||||
"settingsViewerShowOverlayThumbnails": "Mostrar miniaturas",
|
||||
"settingsViewerShowOverlayThumbnails": "Mostrar miniaturas",
|
||||
"settingsViewerEnableOverlayBlurEffect": "Efecto de difuminado",
|
||||
|
||||
"settingsVideoPageTitle": "Ajustes de video",
|
||||
|
@ -466,6 +486,8 @@
|
|||
"settingsVideoEnableAutoPlay": "Reproducción automática",
|
||||
"settingsVideoLoopModeTile": "Modo bucle",
|
||||
"settingsVideoLoopModeTitle": "Modo bucle",
|
||||
"settingsVideoQuickActionsTile": "Acciones rápidas para videos",
|
||||
"settingsVideoQuickActionEditorTitle": "Acciones rápidas",
|
||||
|
||||
"settingsSubtitleThemeTile": "Subtítulos",
|
||||
"settingsSubtitleThemeTitle": "Subtítulos",
|
||||
|
|
|
@ -124,6 +124,8 @@
|
|||
"mapStyleGoogleNormal": "Google Maps",
|
||||
"mapStyleGoogleHybrid": "Google Maps (Satellite)",
|
||||
"mapStyleGoogleTerrain": "Google Maps (Relief)",
|
||||
"mapStyleHuaweiNormal": "Petal Maps",
|
||||
"mapStyleHuaweiTerrain": "Petal Maps (Relief)",
|
||||
"mapStyleOsmHot": "OSM Humanitaire",
|
||||
"mapStyleStamenToner": "Stamen Toner (Monochrome)",
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor (Aquarelle)",
|
||||
|
@ -406,6 +408,8 @@
|
|||
"settingsSystemDefault": "Système",
|
||||
"settingsDefault": "Par défaut",
|
||||
|
||||
"settingsSearchFieldLabel": "Recherche de réglages",
|
||||
"settingsSearchEmpty": "Aucun réglage correspondant",
|
||||
"settingsActionExport": "Exporter",
|
||||
"settingsActionImport": "Importer",
|
||||
|
||||
|
@ -415,6 +419,7 @@
|
|||
|
||||
"settingsSectionNavigation": "Navigation",
|
||||
"settingsHome": "Page d’accueil",
|
||||
"settingsShowBottomNavigationBar": "Afficher la barre de navigation",
|
||||
"settingsKeepScreenOnTile": "Maintenir l’écran allumé",
|
||||
"settingsKeepScreenOnTitle": "Allumage de l’écran",
|
||||
"settingsDoubleBackExit": "Presser «\u00A0retour\u00A0» 2 fois pour quitter",
|
||||
|
@ -434,7 +439,10 @@
|
|||
"settingsNavigationDrawerAddAlbum": "Ajouter un album",
|
||||
|
||||
"settingsSectionThumbnails": "Vignettes",
|
||||
"settingsThumbnailOverlayTile": "Incrustations",
|
||||
"settingsThumbnailOverlayTitle": "Incrustations",
|
||||
"settingsThumbnailShowFavouriteIcon": "Afficher l’icône de favori",
|
||||
"settingsThumbnailShowTagIcon": "Afficher l’icône de libellé",
|
||||
"settingsThumbnailShowLocationIcon": "Afficher l’icône de lieu",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Afficher l’icône de photo animée",
|
||||
"settingsThumbnailShowRating": "Afficher la notation",
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
"hideButtonLabel": "SEMBUNYIKAN",
|
||||
"continueButtonLabel": "SELANJUTNYA",
|
||||
|
||||
"cancelTooltip": "Batalkan",
|
||||
"cancelTooltip": "Batal",
|
||||
"changeTooltip": "Ganti",
|
||||
"clearTooltip": "Hapus",
|
||||
"previousTooltip": "Sebelumnya",
|
||||
|
@ -82,7 +82,7 @@
|
|||
|
||||
"entryInfoActionEditDate": "Ubah tanggal & waktu",
|
||||
"entryInfoActionEditLocation": "Ubah lokasi",
|
||||
"entryInfoActionEditRating": "Ubah peringkat",
|
||||
"entryInfoActionEditRating": "Ubah nilai",
|
||||
"entryInfoActionEditTags": "Ubah label",
|
||||
"entryInfoActionRemoveMetadata": "Hapus metadata",
|
||||
|
||||
|
@ -90,7 +90,7 @@
|
|||
"filterFavouriteLabel": "Favorit",
|
||||
"filterLocationEmptyLabel": "Lokasi yang tidak ditemukan",
|
||||
"filterTagEmptyLabel": "Tidak dilabel",
|
||||
"filterRatingUnratedLabel": "Belum diberi peringkat",
|
||||
"filterRatingUnratedLabel": "Belum diberi nilai",
|
||||
"filterRatingRejectedLabel": "Ditolak",
|
||||
"filterTypeAnimatedLabel": "Teranimasi",
|
||||
"filterTypeMotionPhotoLabel": "Foto bergerak",
|
||||
|
@ -124,6 +124,8 @@
|
|||
"mapStyleGoogleNormal": "Google Maps",
|
||||
"mapStyleGoogleHybrid": "Google Maps (Hybrid)",
|
||||
"mapStyleGoogleTerrain": "Google Maps (Terrain)",
|
||||
"mapStyleHuaweiNormal": "Petal Maps",
|
||||
"mapStyleHuaweiTerrain": "Petal Maps (Terrain)",
|
||||
"mapStyleOsmHot": "Humanitarian OSM",
|
||||
"mapStyleStamenToner": "Stamen Toner",
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor",
|
||||
|
@ -148,7 +150,7 @@
|
|||
|
||||
"albumTierNew": "Baru",
|
||||
"albumTierPinned": "Disemat",
|
||||
"albumTierSpecial": "Umum",
|
||||
"albumTierSpecial": "Biasa",
|
||||
"albumTierApps": "Aplikasi",
|
||||
"albumTierRegular": "Lainnya",
|
||||
|
||||
|
@ -235,7 +237,7 @@
|
|||
|
||||
"locationPickerUseThisLocationButton": "Gunakan lokasi ini",
|
||||
|
||||
"editEntryRatingDialogTitle": "Peringkat",
|
||||
"editEntryRatingDialogTitle": "Nilai",
|
||||
|
||||
"removeEntryMetadataDialogTitle": "Penghapusan Metadata",
|
||||
"removeEntryMetadataDialogMore": "Lebih Banyak",
|
||||
|
@ -247,7 +249,7 @@
|
|||
|
||||
"videoStreamSelectionDialogVideo": "Video",
|
||||
"videoStreamSelectionDialogAudio": "Audio",
|
||||
"videoStreamSelectionDialogText": "Subtitle",
|
||||
"videoStreamSelectionDialogText": "Subjudul",
|
||||
"videoStreamSelectionDialogOff": "Mati",
|
||||
"videoStreamSelectionDialogTrack": "Trek",
|
||||
"videoStreamSelectionDialogNoSelection": "Tidak ada Trek yang lain.",
|
||||
|
@ -322,7 +324,7 @@
|
|||
"collectionSortDate": "Lewat tanggal",
|
||||
"collectionSortSize": "Lewat ukuran",
|
||||
"collectionSortName": "Lewat nama album & file",
|
||||
"collectionSortRating": "Lewat peringkat",
|
||||
"collectionSortRating": "Lewat nilai",
|
||||
|
||||
"collectionGroupAlbum": "Lewat album",
|
||||
"collectionGroupMonth": "Lewat bulan",
|
||||
|
@ -400,12 +402,14 @@
|
|||
"searchSectionCountries": "Negara",
|
||||
"searchSectionPlaces": "Tempat",
|
||||
"searchSectionTags": "Label",
|
||||
"searchSectionRating": "Peringkat",
|
||||
"searchSectionRating": "Nilai",
|
||||
|
||||
"settingsPageTitle": "Pengaturan",
|
||||
"settingsSystemDefault": "Sistem",
|
||||
"settingsDefault": "Default",
|
||||
|
||||
"settingsSearchFieldLabel": "Cari peraturan",
|
||||
"settingsSearchEmpty": "Tidak ada peraturan yang cocok",
|
||||
"settingsActionExport": "Ekspor",
|
||||
"settingsActionImport": "Impor",
|
||||
|
||||
|
@ -415,6 +419,7 @@
|
|||
|
||||
"settingsSectionNavigation": "Navigasi",
|
||||
"settingsHome": "Beranda",
|
||||
"settingsShowBottomNavigationBar": "Tampilkan bilah navigasi bawah",
|
||||
"settingsKeepScreenOnTile": "Biarkan layarnya menyala",
|
||||
"settingsKeepScreenOnTitle": "Biarkan Layarnya Menyala",
|
||||
"settingsDoubleBackExit": "Ketuk “kembali” dua kali untuk keluar",
|
||||
|
@ -434,10 +439,13 @@
|
|||
"settingsNavigationDrawerAddAlbum": "Tambahkan album",
|
||||
|
||||
"settingsSectionThumbnails": "Thumbnail",
|
||||
"settingsThumbnailOverlayTile": "Hamparan",
|
||||
"settingsThumbnailOverlayTitle": "Hamparan",
|
||||
"settingsThumbnailShowFavouriteIcon": "Tampilkan ikon favorit",
|
||||
"settingsThumbnailShowTagIcon": "Tampilkan ikon label",
|
||||
"settingsThumbnailShowLocationIcon": "Tampilkan ikon lokasi",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Tampilkan ikon Foto bergerak",
|
||||
"settingsThumbnailShowRating": "Tampilkan peringkat",
|
||||
"settingsThumbnailShowRating": "Tampilkan nilai",
|
||||
"settingsThumbnailShowRawIcon": "Tampilkan ikon raw",
|
||||
"settingsThumbnailShowVideoDuration": "Tampilkan durasi video",
|
||||
|
||||
|
@ -479,8 +487,8 @@
|
|||
"settingsVideoLoopModeTile": "Putar ulang",
|
||||
"settingsVideoLoopModeTitle": "Putar Ulang",
|
||||
|
||||
"settingsSubtitleThemeTile": "Subtitle",
|
||||
"settingsSubtitleThemeTitle": "Subtitle",
|
||||
"settingsSubtitleThemeTile": "Subjudul",
|
||||
"settingsSubtitleThemeTitle": "Subjudul",
|
||||
"settingsSubtitleThemeSample": "Ini adalah sampel.",
|
||||
"settingsSubtitleThemeTextAlignmentTile": "Perataan teks",
|
||||
"settingsSubtitleThemeTextAlignmentTitle": "Perataan Teks",
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
"chipActionGoToTagPage": "Mostra nelle etichette",
|
||||
"chipActionHide": "Nascondi",
|
||||
"chipActionPin": "Fissa in alto",
|
||||
"chipActionUnpin": "Rimuovi dall'alto",
|
||||
"chipActionUnpin": "Rimuovi dall’alto",
|
||||
"chipActionRename": "Rinomina",
|
||||
"chipActionSetCover": "Imposta copertina",
|
||||
"chipActionCreateAlbum": "Crea album",
|
||||
|
@ -124,6 +124,8 @@
|
|||
"mapStyleGoogleNormal": "Google Maps",
|
||||
"mapStyleGoogleHybrid": "Google Maps (Ibrido)",
|
||||
"mapStyleGoogleTerrain": "Google Maps (Terreno)",
|
||||
"mapStyleHuaweiNormal": "Petal Maps",
|
||||
"mapStyleHuaweiTerrain": "Petal Maps (Terreno)",
|
||||
"mapStyleOsmHot": "OSM umanitario",
|
||||
"mapStyleStamenToner": "Stamen Toner (Monocromatico)",
|
||||
"mapStyleStamenWatercolor": "Stamen Watercolor (Acquerello)",
|
||||
|
@ -193,7 +195,7 @@
|
|||
"hideFilterConfirmationDialogMessage": "Le foto e i video corrispondenti saranno nascosti dalla tua collezione. Puoi mostrarli di nuovo dalle impostazioni della «Privacy». Sei sicuro di volerli nascondere?",
|
||||
|
||||
"newAlbumDialogTitle": "Nuovo album",
|
||||
"newAlbumDialogNameLabel": "Nome dell'album",
|
||||
"newAlbumDialogNameLabel": "Nome dell’album",
|
||||
"newAlbumDialogNameLabelAlreadyExistsHelper": "La cartella esiste già",
|
||||
"newAlbumDialogStorageLabel": "Archiviazione:",
|
||||
|
||||
|
@ -219,7 +221,7 @@
|
|||
|
||||
"editEntryDateDialogTitle": "Data e ora",
|
||||
"editEntryDateDialogSetCustom": "Imposta data personalizzata",
|
||||
"editEntryDateDialogCopyField": "Copia da un'altra data",
|
||||
"editEntryDateDialogCopyField": "Copia da un’altra data",
|
||||
"editEntryDateDialogCopyItem": "Copia da un altro elemento",
|
||||
"editEntryDateDialogExtractFromTitle": "Estrai dal titolo",
|
||||
"editEntryDateDialogShift": "Turno",
|
||||
|
@ -240,7 +242,7 @@
|
|||
"removeEntryMetadataDialogTitle": "Rimozione dei metadati",
|
||||
"removeEntryMetadataDialogMore": "Altro",
|
||||
|
||||
"removeEntryMetadataMotionPhotoXmpWarningDialogMessage": "XMP è richiesto per riprodurre il video all'interno di una foto in movimento.\n\nSei sicuro di volerlo rimuovere?",
|
||||
"removeEntryMetadataMotionPhotoXmpWarningDialogMessage": "XMP è richiesto per riprodurre il video all’interno di una foto in movimento.\n\nSei sicuro di volerlo rimuovere?",
|
||||
"convertMotionPhotoToStillImageWarningDialogMessage": "Sei sicuro?",
|
||||
|
||||
"videoSpeedDialogLabel": "Velocità di riproduzione",
|
||||
|
@ -282,7 +284,7 @@
|
|||
"aboutLinkPolicy": "Informativa sulla privacy",
|
||||
|
||||
"aboutBug": "Segnalazione bug",
|
||||
"aboutBugSaveLogInstruction": "Salva i log dell'app in un file",
|
||||
"aboutBugSaveLogInstruction": "Salva i log dell’app in un file",
|
||||
"aboutBugSaveLogButton": "Salva",
|
||||
"aboutBugCopyInfoInstruction": "Copia le informazioni di sistema",
|
||||
"aboutBugCopyInfoButton": "Copia",
|
||||
|
@ -312,8 +314,8 @@
|
|||
"collectionActionHideTitleSearch": "Nascondi filtro",
|
||||
"collectionActionAddShortcut": "Aggiungi collegamento",
|
||||
"collectionActionEmptyBin": "Svuota cestino",
|
||||
"collectionActionCopy": "Copia nell'album",
|
||||
"collectionActionMove": "Sposta nell'album",
|
||||
"collectionActionCopy": "Copia nell’album",
|
||||
"collectionActionMove": "Sposta nell’album",
|
||||
"collectionActionRescan": "Riscansiona",
|
||||
"collectionActionEdit": "Modifica",
|
||||
|
||||
|
@ -374,8 +376,8 @@
|
|||
"albumPickPageTitleMove": "Sposta",
|
||||
"albumPickPageTitlePick": "Seleziona",
|
||||
|
||||
"albumCamera": "Camera",
|
||||
"albumDownload": "Download",
|
||||
"albumCamera": "Fotocamera",
|
||||
"albumDownload": "Scaricati",
|
||||
"albumScreenshots": "Screenshot",
|
||||
"albumScreenRecordings": "Registrazioni schermo",
|
||||
"albumVideoCaptures": "Scatti nei video",
|
||||
|
@ -406,6 +408,8 @@
|
|||
"settingsSystemDefault": "Sistema",
|
||||
"settingsDefault": "Predefinite",
|
||||
|
||||
"settingsSearchFieldLabel": "Ricerca impostazioni",
|
||||
"settingsSearchEmpty": "Nessuna impostazione corrispondente",
|
||||
"settingsActionExport": "Esporta",
|
||||
"settingsActionImport": "Importa",
|
||||
|
||||
|
@ -415,6 +419,7 @@
|
|||
|
||||
"settingsSectionNavigation": "Navigazione",
|
||||
"settingsHome": "Pagina iniziale",
|
||||
"settingsShowBottomNavigationBar": "Mostra la barra di navigazione in basso",
|
||||
"settingsKeepScreenOnTile": "Mantieni acceso lo schermo",
|
||||
"settingsKeepScreenOnTitle": "Illuminazione schermo",
|
||||
"settingsDoubleBackExit": "Tocca «indietro» due volte per uscire",
|
||||
|
@ -434,11 +439,14 @@
|
|||
"settingsNavigationDrawerAddAlbum": "Aggiungi album",
|
||||
|
||||
"settingsSectionThumbnails": "Miniature",
|
||||
"settingsThumbnailShowFavouriteIcon": "Mostra icona preferita",
|
||||
"settingsThumbnailShowLocationIcon": "Mostra l'icona della posizione",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Mostra l'icona della foto in movimento",
|
||||
"settingsThumbnailOverlayTile": "Sovrapposizione",
|
||||
"settingsThumbnailOverlayTitle": "Sovrapposizione",
|
||||
"settingsThumbnailShowFavouriteIcon": "Mostra l’icona Preferiti",
|
||||
"settingsThumbnailShowTagIcon": "Mostra l’icona Etichetta",
|
||||
"settingsThumbnailShowLocationIcon": "Mostra l’icona Posizione",
|
||||
"settingsThumbnailShowMotionPhotoIcon": "Mostra l’icona Foto in movimento",
|
||||
"settingsThumbnailShowRating": "Mostra la valutazione",
|
||||
"settingsThumbnailShowRawIcon": "Mostra icona raw",
|
||||
"settingsThumbnailShowRawIcon": "Mostra icona Raw",
|
||||
"settingsThumbnailShowVideoDuration": "Mostra la durata del video",
|
||||
|
||||
"settingsCollectionQuickActionsTile": "Azioni rapide",
|
||||
|
@ -463,7 +471,7 @@
|
|||
|
||||
"settingsViewerOverlayTile": "Sovrapposizione",
|
||||
"settingsViewerOverlayTitle": "Sovrapposizione",
|
||||
"settingsViewerShowOverlayOnOpening": "Mostra all'apertura",
|
||||
"settingsViewerShowOverlayOnOpening": "Mostra all’apertura",
|
||||
"settingsViewerShowMinimap": "Mostra la minimappa",
|
||||
"settingsViewerShowInformation": "Mostra informazioni",
|
||||
"settingsViewerShowInformationSubtitle": "Mostra titolo, data, posizione, ecc.",
|
||||
|
@ -502,7 +510,7 @@
|
|||
"settingsVideoGestureSideDoubleTapSeek": "Doppio tocco sui bordi dello schermo per cercare avanti/indietro",
|
||||
|
||||
"settingsSectionPrivacy": "Privacy",
|
||||
"settingsAllowInstalledAppAccess": "Consentire l'accesso all'inventario delle app",
|
||||
"settingsAllowInstalledAppAccess": "Consentire l’accesso all’inventario delle app",
|
||||
"settingsAllowInstalledAppAccessSubtitle": "Utilizzato per migliorare la visualizzazione degli album",
|
||||
"settingsAllowErrorReporting": "Consenti segnalazione anonima degli errori",
|
||||
"settingsSaveSearchHistory": "Salva la cronologia delle ricerche",
|
||||
|
@ -572,15 +580,15 @@
|
|||
|
||||
"mapStyleTitle": "Stile Mappa",
|
||||
"mapStyleTooltip": "Seleziona lo stile della mappa",
|
||||
"mapZoomInTooltip": "Zoom in",
|
||||
"mapZoomOutTooltip": "Zoom out",
|
||||
"mapPointNorthUpTooltip": "Punta a nord verso l'alto",
|
||||
"mapZoomInTooltip": "Ingrandisci",
|
||||
"mapZoomOutTooltip": "Riduci",
|
||||
"mapPointNorthUpTooltip": "Punta a nord verso l’alto",
|
||||
"mapAttributionOsmHot": "Dati della mappa © collaboratori di [OpenStreetMap](https://www.openstreetmap.org/copyright) - Titoli di [HOT](https://www.hotosm.org/) - Ospitato da [OSM France](https://openstreetmap.fr/)",
|
||||
"mapAttributionStamen": "Dati della mappa © collaboratori di [OpenStreetMap](https://www.openstreetmap.org/copyright) - Titoli di [Stamen Design](http://stamen.com), [CC BY 3.0](http://creativecommons.org/licenses/by/3.0)",
|
||||
"openMapPageTooltip": "Visualizza sulla pagina della mappa",
|
||||
"mapEmptyRegion": "Nessuna immagine in questa regione",
|
||||
|
||||
"viewerInfoOpenEmbeddedFailureFeedback": "Fallita l'estrazione dei dati incorporati",
|
||||
"viewerInfoOpenEmbeddedFailureFeedback": "Fallita l’estrazione dei dati incorporati",
|
||||
"viewerInfoOpenLinkText": "Apri",
|
||||
"viewerInfoViewXmlLinkText": "Visualizza XML",
|
||||
|
||||
|
|