improved temp file cleanup
This commit is contained in:
parent
e883be1787
commit
0a482e6ccf
12 changed files with 153 additions and 26 deletions
|
@ -9,6 +9,10 @@ All notable changes to this project will be documented in this file.
|
||||||
- target Android 14 (API 34)
|
- target Android 14 (API 34)
|
||||||
- upgraded Flutter to stable v3.13.8
|
- upgraded Flutter to stable v3.13.8
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- temporary files remaining in the cache directory forever
|
||||||
|
|
||||||
## <a id="v1.9.7"></a>[v1.9.7] - 2023-10-17
|
## <a id="v1.9.7"></a>[v1.9.7] - 2023-10-17
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -33,7 +33,6 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
class EmbeddedDataHandler(private val context: Context) : MethodCallHandler {
|
class EmbeddedDataHandler(private val context: Context) : MethodCallHandler {
|
||||||
|
@ -279,8 +278,7 @@ class EmbeddedDataHandler(private val context: Context) : MethodCallHandler {
|
||||||
embeddedByteLength: Long,
|
embeddedByteLength: Long,
|
||||||
) {
|
) {
|
||||||
val extension = extensionFor(mimeType)
|
val extension = extensionFor(mimeType)
|
||||||
val targetFile = File.createTempFile("aves", extension, context.cacheDir).apply {
|
val targetFile = StorageUtils.createTempFile(context, extension).apply {
|
||||||
deleteOnExit()
|
|
||||||
transferFrom(embeddedByteStream, embeddedByteLength)
|
transferFrom(embeddedByteStream, embeddedByteLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
|
||||||
"getRestrictedDirectories" -> ioScope.launch { safe(call, result, ::getRestrictedDirectories) }
|
"getRestrictedDirectories" -> ioScope.launch { safe(call, result, ::getRestrictedDirectories) }
|
||||||
"revokeDirectoryAccess" -> safe(call, result, ::revokeDirectoryAccess)
|
"revokeDirectoryAccess" -> safe(call, result, ::revokeDirectoryAccess)
|
||||||
"deleteEmptyDirectories" -> ioScope.launch { safe(call, result, ::deleteEmptyDirectories) }
|
"deleteEmptyDirectories" -> ioScope.launch { safe(call, result, ::deleteEmptyDirectories) }
|
||||||
|
"deleteTempDirectory" -> ioScope.launch { safe(call, result, ::deleteTempDirectory) }
|
||||||
"canRequestMediaFileBulkAccess" -> safe(call, result, ::canRequestMediaFileBulkAccess)
|
"canRequestMediaFileBulkAccess" -> safe(call, result, ::canRequestMediaFileBulkAccess)
|
||||||
"canInsertMedia" -> safe(call, result, ::canInsertMedia)
|
"canInsertMedia" -> safe(call, result, ::canInsertMedia)
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
|
@ -200,6 +201,10 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
|
||||||
result.success(deleted)
|
result.success(deleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun deleteTempDirectory(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
result.success(StorageUtils.deleteTempDirectory(context))
|
||||||
|
}
|
||||||
|
|
||||||
private fun canRequestMediaFileBulkAccess(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
private fun canRequestMediaFileBulkAccess(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
||||||
result.success(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
result.success(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import deckers.thibault.aves.utils.BitmapUtils.getBytes
|
||||||
import deckers.thibault.aves.utils.MimeTypes
|
import deckers.thibault.aves.utils.MimeTypes
|
||||||
import deckers.thibault.aves.utils.StorageUtils
|
import deckers.thibault.aves.utils.StorageUtils
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import java.io.File
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class RegionFetcher internal constructor(
|
class RegionFetcher internal constructor(
|
||||||
|
@ -113,8 +112,7 @@ class RegionFetcher internal constructor(
|
||||||
.submit()
|
.submit()
|
||||||
try {
|
try {
|
||||||
val bitmap = target.get()
|
val bitmap = target.get()
|
||||||
val tempFile = File.createTempFile("aves", null, context.cacheDir).apply {
|
val tempFile = StorageUtils.createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
outputStream().use { output ->
|
outputStream().use { output ->
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output)
|
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output)
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,8 +160,7 @@ object Metadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPreviewFile(context: Context, uri: Uri): File {
|
fun createPreviewFile(context: Context, uri: Uri): File {
|
||||||
return File.createTempFile("aves", null, context.cacheDir).apply {
|
return StorageUtils.createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
transferFrom(StorageUtils.openInputStream(context, uri), PREVIEW_SIZE)
|
transferFrom(StorageUtils.openInputStream(context, uri), PREVIEW_SIZE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,8 +381,7 @@ abstract class ImageProvider {
|
||||||
targetUri: Uri,
|
targetUri: Uri,
|
||||||
targetPath: String,
|
targetPath: String,
|
||||||
) {
|
) {
|
||||||
val editableFile = File.createTempFile("aves", null).apply {
|
val editableFile = StorageUtils.createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
// copy original file to a temporary file for editing
|
// copy original file to a temporary file for editing
|
||||||
val inputStream = StorageUtils.openInputStream(context, targetUri)
|
val inputStream = StorageUtils.openInputStream(context, targetUri)
|
||||||
transferFrom(inputStream, File(targetPath).length())
|
transferFrom(inputStream, File(targetPath).length())
|
||||||
|
@ -514,8 +513,7 @@ abstract class ImageProvider {
|
||||||
output.write(bytes)
|
output.write(bytes)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val editableFile = withContext(Dispatchers.IO) { File.createTempFile("aves", null) }.apply {
|
val editableFile = withContext(Dispatchers.IO) { StorageUtils.createTempFile(contextWrapper) }.apply {
|
||||||
deleteOnExit()
|
|
||||||
transferFrom(ByteArrayInputStream(bytes), bytes.size.toLong())
|
transferFrom(ByteArrayInputStream(bytes), bytes.size.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,8 +647,7 @@ abstract class ImageProvider {
|
||||||
val originalFileSize = File(path).length()
|
val originalFileSize = File(path).length()
|
||||||
val videoSize = MultiPage.getMotionPhotoOffset(context, uri, mimeType, originalFileSize)?.let { it.toInt() + trailerDiff }
|
val videoSize = MultiPage.getMotionPhotoOffset(context, uri, mimeType, originalFileSize)?.let { it.toInt() + trailerDiff }
|
||||||
var videoBytes: ByteArray? = null
|
var videoBytes: ByteArray? = null
|
||||||
val editableFile = File.createTempFile("aves", null).apply {
|
val editableFile = StorageUtils.createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
try {
|
try {
|
||||||
if (videoSize != null) {
|
if (videoSize != null) {
|
||||||
// handle motion photo and embedded video separately
|
// handle motion photo and embedded video separately
|
||||||
|
@ -733,8 +730,7 @@ abstract class ImageProvider {
|
||||||
val originalFileSize = File(path).length()
|
val originalFileSize = File(path).length()
|
||||||
val videoSize = MultiPage.getMotionPhotoOffset(context, uri, mimeType, originalFileSize)?.let { it.toInt() + trailerDiff }
|
val videoSize = MultiPage.getMotionPhotoOffset(context, uri, mimeType, originalFileSize)?.let { it.toInt() + trailerDiff }
|
||||||
var videoBytes: ByteArray? = null
|
var videoBytes: ByteArray? = null
|
||||||
val editableFile = File.createTempFile("aves", null).apply {
|
val editableFile = StorageUtils.createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
try {
|
try {
|
||||||
if (videoSize != null) {
|
if (videoSize != null) {
|
||||||
// handle motion photo and embedded video separately
|
// handle motion photo and embedded video separately
|
||||||
|
@ -898,8 +894,7 @@ abstract class ImageProvider {
|
||||||
|
|
||||||
val originalFileSize = File(path).length()
|
val originalFileSize = File(path).length()
|
||||||
val videoSize = MultiPage.getMotionPhotoOffset(context, uri, mimeType, originalFileSize)?.let { it.toInt() + trailerDiff }
|
val videoSize = MultiPage.getMotionPhotoOffset(context, uri, mimeType, originalFileSize)?.let { it.toInt() + trailerDiff }
|
||||||
val editableFile = File.createTempFile("aves", null).apply {
|
val editableFile = StorageUtils.createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
try {
|
try {
|
||||||
editXmpWithPixy(
|
editXmpWithPixy(
|
||||||
context = context,
|
context = context,
|
||||||
|
@ -1275,8 +1270,7 @@ abstract class ImageProvider {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val editableFile = File.createTempFile("aves", null).apply {
|
val editableFile = StorageUtils.createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
try {
|
try {
|
||||||
val inputStream = StorageUtils.openInputStream(context, uri)
|
val inputStream = StorageUtils.openInputStream(context, uri)
|
||||||
// partial copy
|
// partial copy
|
||||||
|
@ -1316,8 +1310,7 @@ abstract class ImageProvider {
|
||||||
|
|
||||||
val originalFileSize = File(path).length()
|
val originalFileSize = File(path).length()
|
||||||
val videoSize = MultiPage.getMotionPhotoOffset(context, uri, mimeType, originalFileSize)?.toInt()
|
val videoSize = MultiPage.getMotionPhotoOffset(context, uri, mimeType, originalFileSize)?.toInt()
|
||||||
val editableFile = File.createTempFile("aves", null).apply {
|
val editableFile = StorageUtils.createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
try {
|
try {
|
||||||
outputStream().use { output ->
|
outputStream().use { output ->
|
||||||
// reopen input to read from start
|
// reopen input to read from start
|
||||||
|
|
|
@ -26,6 +26,7 @@ import deckers.thibault.aves.utils.PermissionManager.getGrantedDirForPath
|
||||||
import deckers.thibault.aves.utils.UriUtils.tryParseId
|
import deckers.thibault.aves.utils.UriUtils.tryParseId
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -593,8 +594,7 @@ object StorageUtils {
|
||||||
uriPath?.contains("/file/") == true -> {
|
uriPath?.contains("/file/") == true -> {
|
||||||
// e.g. `content://media/external/file/...`
|
// e.g. `content://media/external/file/...`
|
||||||
// create an ad-hoc temporary file for decoding only
|
// create an ad-hoc temporary file for decoding only
|
||||||
File.createTempFile("aves", null).apply {
|
createTempFile(context).apply {
|
||||||
deleteOnExit()
|
|
||||||
try {
|
try {
|
||||||
transferFrom(openInputStream(context, uri), sizeBytes)
|
transferFrom(openInputStream(context, uri), sizeBytes)
|
||||||
return Uri.fromFile(this)
|
return Uri.fromFile(this)
|
||||||
|
@ -714,6 +714,25 @@ object StorageUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getTempDirectory(context: Context): File = File(context.cacheDir, "temp")
|
||||||
|
|
||||||
|
fun createTempFile(context: Context, extension: String? = null): File {
|
||||||
|
val directory = getTempDirectory(context)
|
||||||
|
if (!directory.exists() && !directory.mkdirs()) {
|
||||||
|
throw IOException("failed to create directories at path=$directory")
|
||||||
|
}
|
||||||
|
val tempFile = File.createTempFile("aves", extension, directory)
|
||||||
|
// `deleteOnExit` is unreliable, but it does not hurt
|
||||||
|
tempFile.deleteOnExit()
|
||||||
|
return tempFile
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteTempDirectory(context: Context): Boolean {
|
||||||
|
val directory = getTempDirectory(context)
|
||||||
|
if (!directory.exists()) return false
|
||||||
|
return directory.deleteRecursively()
|
||||||
|
}
|
||||||
|
|
||||||
// convenience methods
|
// convenience methods
|
||||||
|
|
||||||
fun getFolderSize(f: File): Long {
|
fun getFolderSize(f: File): Long {
|
||||||
|
|
|
@ -543,6 +543,7 @@
|
||||||
"aboutDataUsageMisc": "Misc",
|
"aboutDataUsageMisc": "Misc",
|
||||||
"aboutDataUsageInternal": "Internal",
|
"aboutDataUsageInternal": "Internal",
|
||||||
"aboutDataUsageExternal": "External",
|
"aboutDataUsageExternal": "External",
|
||||||
|
"aboutDataUsageClearCache": "Clear Cache",
|
||||||
|
|
||||||
"aboutCreditsSectionTitle": "Credits",
|
"aboutCreditsSectionTitle": "Credits",
|
||||||
"aboutCreditsWorldAtlas1": "This app uses a TopoJSON file from",
|
"aboutCreditsWorldAtlas1": "This app uses a TopoJSON file from",
|
||||||
|
|
|
@ -27,6 +27,8 @@ abstract class StorageService {
|
||||||
// returns number of deleted directories
|
// returns number of deleted directories
|
||||||
Future<int> deleteEmptyRegularDirectories(Set<String> dirPaths);
|
Future<int> deleteEmptyRegularDirectories(Set<String> dirPaths);
|
||||||
|
|
||||||
|
Future<bool> deleteTempDirectory();
|
||||||
|
|
||||||
// returns whether user granted access to a directory of his choosing
|
// returns whether user granted access to a directory of his choosing
|
||||||
Future<bool> requestDirectoryAccess(String path);
|
Future<bool> requestDirectoryAccess(String path);
|
||||||
|
|
||||||
|
@ -158,6 +160,17 @@ class PlatformStorageService implements StorageService {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> deleteTempDirectory() async {
|
||||||
|
try {
|
||||||
|
final result = await _platform.invokeMethod('deleteTempDirectory');
|
||||||
|
if (result != null) return result as bool;
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> canRequestMediaFileBulkAccess() async {
|
Future<bool> canRequestMediaFileBulkAccess() async {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:aves/utils/file_utils.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_donut.dart';
|
import 'package:aves/widgets/common/identity/aves_donut.dart';
|
||||||
|
import 'package:aves/widgets/common/identity/buttons/outlined_button.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ class _AboutDataUsageState extends State<AboutDataUsage> with FeedbackMixin {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_loader = storageService.getDataUsage();
|
_reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -81,6 +82,18 @@ class _AboutDataUsageState extends State<AboutDataUsage> with FeedbackMixin {
|
||||||
byTypes: cacheMap,
|
byTypes: cacheMap,
|
||||||
animationDuration: animationDuration,
|
animationDuration: animationDuration,
|
||||||
),
|
),
|
||||||
|
Center(
|
||||||
|
child: AvesOutlinedButton(
|
||||||
|
label: context.l10n.aboutDataUsageClearCache,
|
||||||
|
onPressed: () async {
|
||||||
|
await storageService.deleteTempDirectory();
|
||||||
|
await mediaFetchService.clearSizedThumbnailDiskCache();
|
||||||
|
imageCache.clear();
|
||||||
|
_reload();
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -92,6 +105,10 @@ class _AboutDataUsageState extends State<AboutDataUsage> with FeedbackMixin {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _reload() {
|
||||||
|
_loader = storageService.getDataUsage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataUsageDonut extends StatelessWidget {
|
class DataUsageDonut extends StatelessWidget {
|
||||||
|
|
|
@ -458,6 +458,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
_monitorSettings();
|
_monitorSettings();
|
||||||
videoControllerFactory.init();
|
videoControllerFactory.init();
|
||||||
|
|
||||||
|
unawaited(storageService.deleteTempDirectory());
|
||||||
unawaited(_setupErrorReporting());
|
unawaited(_setupErrorReporting());
|
||||||
|
|
||||||
debugPrint('App setup in ${stopwatch.elapsed.inMilliseconds}ms');
|
debugPrint('App setup in ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
|
|
@ -307,6 +307,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -732,6 +733,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -1331,6 +1333,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -1864,6 +1867,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -2214,13 +2218,15 @@
|
||||||
],
|
],
|
||||||
|
|
||||||
"cs": [
|
"cs": [
|
||||||
"overlayHistogramLuminance"
|
"overlayHistogramLuminance",
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
],
|
],
|
||||||
|
|
||||||
"de": [
|
"de": [
|
||||||
"overlayHistogramNone",
|
"overlayHistogramNone",
|
||||||
"overlayHistogramRGB",
|
"overlayHistogramRGB",
|
||||||
"overlayHistogramLuminance",
|
"overlayHistogramLuminance",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"settingsViewerShowHistogram"
|
"settingsViewerShowHistogram"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -2235,9 +2241,18 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"settingsViewerShowHistogram"
|
"settingsViewerShowHistogram"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"es": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
|
"eu": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
"fa": [
|
"fa": [
|
||||||
"saveCopyButtonLabel",
|
"saveCopyButtonLabel",
|
||||||
"applyTooltip",
|
"applyTooltip",
|
||||||
|
@ -2421,6 +2436,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -2942,6 +2958,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -3291,6 +3308,10 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"fr": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
"gl": [
|
"gl": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"saveCopyButtonLabel",
|
"saveCopyButtonLabel",
|
||||||
|
@ -3489,6 +3510,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -4164,6 +4186,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -4819,6 +4842,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -5168,6 +5192,18 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"hu": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
|
"id": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
|
"it": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
"ja": [
|
"ja": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"saveCopyButtonLabel",
|
"saveCopyButtonLabel",
|
||||||
|
@ -5205,6 +5241,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"stateEmpty",
|
"stateEmpty",
|
||||||
"placeEmpty",
|
"placeEmpty",
|
||||||
"searchStatesSectionTitle",
|
"searchStatesSectionTitle",
|
||||||
|
@ -5529,6 +5566,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -5878,6 +5916,10 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"ko": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
"lt": [
|
"lt": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"saveCopyButtonLabel",
|
"saveCopyButtonLabel",
|
||||||
|
@ -5937,6 +5979,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"drawerPlacePage",
|
"drawerPlacePage",
|
||||||
"statePageTitle",
|
"statePageTitle",
|
||||||
"stateEmpty",
|
"stateEmpty",
|
||||||
|
@ -6295,6 +6338,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -6652,6 +6696,7 @@
|
||||||
"widgetOpenPageCollection",
|
"widgetOpenPageCollection",
|
||||||
"widgetOpenPageViewer",
|
"widgetOpenPageViewer",
|
||||||
"menuActionConfigureView",
|
"menuActionConfigureView",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"newFilterBanner",
|
"newFilterBanner",
|
||||||
"settingsDefault",
|
"settingsDefault",
|
||||||
"settingsNavigationDrawerTile",
|
"settingsNavigationDrawerTile",
|
||||||
|
@ -6767,6 +6812,7 @@
|
||||||
"patternDialogEnter",
|
"patternDialogEnter",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"settingsCollectionBurstPatternsTile",
|
"settingsCollectionBurstPatternsTile",
|
||||||
"settingsCollectionBurstPatternsNone",
|
"settingsCollectionBurstPatternsNone",
|
||||||
"settingsViewerShowHistogram",
|
"settingsViewerShowHistogram",
|
||||||
|
@ -6825,6 +6871,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"drawerPlacePage",
|
"drawerPlacePage",
|
||||||
"statePageTitle",
|
"statePageTitle",
|
||||||
"stateEmpty",
|
"stateEmpty",
|
||||||
|
@ -6875,6 +6922,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutLicensesBanner",
|
"aboutLicensesBanner",
|
||||||
"aboutLicensesAndroidLibrariesSectionTitle",
|
"aboutLicensesAndroidLibrariesSectionTitle",
|
||||||
|
@ -7182,6 +7230,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
"aboutLicensesSectionTitle",
|
"aboutLicensesSectionTitle",
|
||||||
|
@ -7502,6 +7551,14 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"pl": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
|
"pt": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
"ro": [
|
"ro": [
|
||||||
"saveCopyButtonLabel",
|
"saveCopyButtonLabel",
|
||||||
"applyTooltip",
|
"applyTooltip",
|
||||||
|
@ -7527,6 +7584,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"settingsAskEverytime",
|
"settingsAskEverytime",
|
||||||
"settingsViewerShowHistogram",
|
"settingsViewerShowHistogram",
|
||||||
"settingsVideoPlaybackTile",
|
"settingsVideoPlaybackTile",
|
||||||
|
@ -7536,6 +7594,14 @@
|
||||||
"tagEditorDiscardDialogMessage"
|
"tagEditorDiscardDialogMessage"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"ru": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
|
"sk": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
"sl": [
|
"sl": [
|
||||||
"itemCount",
|
"itemCount",
|
||||||
"columnCount",
|
"columnCount",
|
||||||
|
@ -7862,6 +7928,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"aboutCreditsSectionTitle",
|
"aboutCreditsSectionTitle",
|
||||||
"aboutCreditsWorldAtlas1",
|
"aboutCreditsWorldAtlas1",
|
||||||
"aboutCreditsWorldAtlas2",
|
"aboutCreditsWorldAtlas2",
|
||||||
|
@ -8276,6 +8343,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"collectionActionShowTitleSearch",
|
"collectionActionShowTitleSearch",
|
||||||
"collectionActionHideTitleSearch",
|
"collectionActionHideTitleSearch",
|
||||||
"collectionActionAddShortcut",
|
"collectionActionAddShortcut",
|
||||||
|
@ -8664,6 +8732,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"drawerPlacePage",
|
"drawerPlacePage",
|
||||||
"statePageTitle",
|
"statePageTitle",
|
||||||
"stateEmpty",
|
"stateEmpty",
|
||||||
|
@ -8687,6 +8756,14 @@
|
||||||
"tagPlaceholderState"
|
"tagPlaceholderState"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"uk": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
|
"vi": [
|
||||||
|
"aboutDataUsageClearCache"
|
||||||
|
],
|
||||||
|
|
||||||
"zh": [
|
"zh": [
|
||||||
"saveCopyButtonLabel",
|
"saveCopyButtonLabel",
|
||||||
"chipActionGoToPlacePage",
|
"chipActionGoToPlacePage",
|
||||||
|
@ -8728,6 +8805,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"drawerPlacePage",
|
"drawerPlacePage",
|
||||||
"statePageTitle",
|
"statePageTitle",
|
||||||
"stateEmpty",
|
"stateEmpty",
|
||||||
|
@ -8764,6 +8842,7 @@
|
||||||
"aboutDataUsageMisc",
|
"aboutDataUsageMisc",
|
||||||
"aboutDataUsageInternal",
|
"aboutDataUsageInternal",
|
||||||
"aboutDataUsageExternal",
|
"aboutDataUsageExternal",
|
||||||
|
"aboutDataUsageClearCache",
|
||||||
"settingsViewerShowHistogram"
|
"settingsViewerShowHistogram"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue