mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-19 04:53:36 +00:00
Compare commits
6 Commits
6a20269819
...
test/2025.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8ddf5a0ae | ||
|
|
1e32df193d | ||
|
|
fca61732b7 | ||
|
|
8053d2f4a5 | ||
|
|
7bfe507e57 | ||
|
|
1e06e46344 |
@@ -44,6 +44,7 @@ import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import app.organicmaps.api.Const;
|
||||
import app.organicmaps.backup.PeriodicBackupRunner;
|
||||
import app.organicmaps.base.BaseMwmFragmentActivity;
|
||||
import app.organicmaps.base.OnBackPressListener;
|
||||
import app.organicmaps.bookmarks.BookmarkCategoriesActivity;
|
||||
@@ -139,6 +140,7 @@ import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_HELP_CODE;
|
||||
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_RECORD_TRACK_CODE;
|
||||
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_SETTINGS_CODE;
|
||||
import static app.organicmaps.util.PowerManagment.POWER_MANAGEMENT_TAG;
|
||||
import static app.organicmaps.util.concurrency.UiThread.runLater;
|
||||
|
||||
public class MwmActivity extends BaseMwmFragmentActivity
|
||||
implements PlacePageActivationListener,
|
||||
@@ -253,6 +255,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
@NonNull
|
||||
private DisplayManager mDisplayManager;
|
||||
|
||||
private PeriodicBackupRunner backupRunner;
|
||||
|
||||
ManageRouteBottomSheet mManageRouteBottomSheet;
|
||||
|
||||
private boolean mRemoveDisplayListener = true;
|
||||
@@ -607,6 +611,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
*/
|
||||
if (Map.isEngineCreated())
|
||||
onRenderingInitializationFinished();
|
||||
|
||||
backupRunner = new PeriodicBackupRunner(this);
|
||||
}
|
||||
|
||||
private void onSettingsResult(ActivityResult activityResult)
|
||||
@@ -1352,6 +1358,11 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
final String backUrl = Framework.nativeGetParsedBackUrl();
|
||||
if (!TextUtils.isEmpty(backUrl))
|
||||
Utils.openUri(this, Uri.parse(backUrl), null);
|
||||
|
||||
if (backupRunner != null && !backupRunner.isAlreadyChecked() && backupRunner.isTimeToBackup())
|
||||
{
|
||||
backupRunner.doBackup();
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package app.organicmaps.backup;
|
||||
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_DEFAULT_COUNT;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_KEY;
|
||||
import static app.organicmaps.util.StorageUtils.isFolderWritable;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.util.UiUtils;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
public class BackupUtils
|
||||
{
|
||||
private static final String BACKUP_PREFIX = "backup_";
|
||||
private static final String BACKUP_EXTENSION = ".kmz";
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").withLocale(Locale.US);
|
||||
private static final String TAG = BackupUtils.class.getSimpleName();
|
||||
|
||||
public static CharSequence formatReadableFolderPath(Context context, @NonNull Uri uri)
|
||||
{
|
||||
String docId = DocumentsContract.getTreeDocumentId(uri);
|
||||
String volumeId;
|
||||
String subPath = "";
|
||||
|
||||
int colonIndex = docId.indexOf(':');
|
||||
if (colonIndex >= 0)
|
||||
{
|
||||
volumeId = docId.substring(0, colonIndex);
|
||||
subPath = docId.substring(colonIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
volumeId = docId;
|
||||
}
|
||||
|
||||
String volumeName;
|
||||
if ("primary".equalsIgnoreCase(volumeId))
|
||||
volumeName = context.getString(R.string.maps_storage_shared);
|
||||
else
|
||||
volumeName = context.getString(R.string.maps_storage_removable);
|
||||
|
||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||
sb.append(volumeName + ": \n", new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_3)), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
sb.append("/" + subPath, new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_4)), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return sb;
|
||||
}
|
||||
|
||||
public static int getMaxBackups(SharedPreferences prefs)
|
||||
{
|
||||
String rawValue = prefs.getString(MAX_BACKUPS_KEY, String.valueOf(MAX_BACKUPS_DEFAULT_COUNT));
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(rawValue);
|
||||
} catch (NumberFormatException e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to parse max backups count, raw value: " + rawValue + " set to default: " + MAX_BACKUPS_DEFAULT_COUNT, e);
|
||||
prefs.edit()
|
||||
.putString(MAX_BACKUPS_KEY, String.valueOf(MAX_BACKUPS_DEFAULT_COUNT))
|
||||
.apply();
|
||||
return MAX_BACKUPS_DEFAULT_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentFile createUniqueBackupFolder(@NonNull DocumentFile parentDir, LocalDateTime backupTime)
|
||||
{
|
||||
String folderName = BACKUP_PREFIX + backupTime.format(DATE_FORMATTER);
|
||||
return parentDir.createDirectory(folderName);
|
||||
}
|
||||
|
||||
public static String getBackupName(LocalDateTime backupTime)
|
||||
{
|
||||
String formattedBackupTime = backupTime.format(DATE_FORMATTER);
|
||||
return BACKUP_PREFIX + formattedBackupTime + BACKUP_EXTENSION;
|
||||
}
|
||||
|
||||
public static DocumentFile[] getBackupFolders(DocumentFile parentDir)
|
||||
{
|
||||
List<DocumentFile> backupFolders = new ArrayList<>();
|
||||
for (DocumentFile file : parentDir.listFiles())
|
||||
{
|
||||
if (file.isDirectory() && file.getName() != null && file.getName().startsWith(BACKUP_PREFIX))
|
||||
backupFolders.add(file);
|
||||
}
|
||||
return backupFolders.toArray(new DocumentFile[0]);
|
||||
}
|
||||
|
||||
public static boolean isBackupFolderAvailable(Context context, String storedFolderPath)
|
||||
{
|
||||
return !TextUtils.isEmpty(storedFolderPath) && isFolderWritable(context, storedFolderPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package app.organicmaps.backup;
|
||||
|
||||
import static app.organicmaps.backup.BackupUtils.getBackupName;
|
||||
import static app.organicmaps.backup.BackupUtils.getBackupFolders;
|
||||
import static app.organicmaps.util.StorageUtils.copyFileToDocumentFile;
|
||||
import static app.organicmaps.util.StorageUtils.deleteDirectoryRecursive;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import app.organicmaps.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.bookmarks.data.BookmarkSharingResult;
|
||||
import app.organicmaps.bookmarks.data.KmlFileType;
|
||||
import app.organicmaps.util.concurrency.ThreadPool;
|
||||
import app.organicmaps.util.concurrency.UiThread;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
public class LocalBackupManager implements BookmarkManager.BookmarksSharingListener
|
||||
{
|
||||
public static final String TAG = LocalBackupManager.class.getSimpleName();
|
||||
|
||||
private final Activity activity;
|
||||
private final String backupFolderPath;
|
||||
private final int maxBackups;
|
||||
private Listener listener;
|
||||
|
||||
public LocalBackupManager(@NonNull Activity activity, @NonNull String backupFolderPath, int maxBackups)
|
||||
{
|
||||
this.activity = activity;
|
||||
this.backupFolderPath = backupFolderPath;
|
||||
this.maxBackups = maxBackups;
|
||||
}
|
||||
|
||||
public void doBackup()
|
||||
{
|
||||
BookmarkManager.INSTANCE.addSharingListener(this);
|
||||
|
||||
prepareBookmarkCategoriesForSharing();
|
||||
|
||||
if (listener != null)
|
||||
listener.onBackupStarted();
|
||||
}
|
||||
|
||||
public void setListener(@NonNull Listener listener)
|
||||
{
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreparedFileForSharing(@NonNull BookmarkSharingResult result)
|
||||
{
|
||||
BookmarkManager.INSTANCE.removeSharingListener(this);
|
||||
|
||||
ThreadPool.getWorker().execute(() -> {
|
||||
ErrorCode errorCode = null;
|
||||
switch (result.getCode())
|
||||
{
|
||||
case BookmarkSharingResult.SUCCESS ->
|
||||
{
|
||||
if (!saveBackup(result))
|
||||
{
|
||||
Logger.e(TAG, "Failed to save backup. See system log above");
|
||||
errorCode = ErrorCode.FILE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.i(TAG, "Backup was created and saved successfully");
|
||||
}
|
||||
}
|
||||
case BookmarkSharingResult.EMPTY_CATEGORY ->
|
||||
{
|
||||
errorCode = ErrorCode.EMPTY_CATEGORY;
|
||||
Logger.e(TAG, "Failed to create backup. Category is empty");
|
||||
}
|
||||
case BookmarkSharingResult.ARCHIVE_ERROR ->
|
||||
{
|
||||
errorCode = ErrorCode.ARCHIVE_ERROR;
|
||||
Logger.e(TAG, "Failed to create archive of bookmarks");
|
||||
}
|
||||
case BookmarkSharingResult.FILE_ERROR ->
|
||||
{
|
||||
errorCode = ErrorCode.FILE_ERROR;
|
||||
Logger.e(TAG, "Failed create file for archive");
|
||||
}
|
||||
default ->
|
||||
{
|
||||
errorCode = ErrorCode.UNSUPPORTED;
|
||||
Logger.e(TAG, "Failed to create backup. Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode finalErrorCode = errorCode;
|
||||
UiThread.run(() -> {
|
||||
if (listener != null)
|
||||
{
|
||||
if (finalErrorCode == null)
|
||||
listener.onBackupFinished();
|
||||
else
|
||||
listener.onBackupFailed(finalErrorCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private boolean saveBackup(@NonNull BookmarkSharingResult result)
|
||||
{
|
||||
boolean isSuccess = false;
|
||||
Uri folderUri = Uri.parse(backupFolderPath);
|
||||
try
|
||||
{
|
||||
DocumentFile parentFolder = DocumentFile.fromTreeUri(activity, folderUri);
|
||||
if (parentFolder != null && parentFolder.canWrite())
|
||||
{
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
DocumentFile backupFolder = BackupUtils.createUniqueBackupFolder(parentFolder, now);
|
||||
if (backupFolder != null)
|
||||
{
|
||||
String backupName = getBackupName(now);
|
||||
DocumentFile backupFile = backupFolder.createFile(result.getMimeType(), backupName);
|
||||
if (backupFile != null && copyFileToDocumentFile(activity, new File(result.getSharingPath()), backupFile))
|
||||
{
|
||||
Logger.i(TAG, "Backup saved to " + backupFile.getUri());
|
||||
isSuccess = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.e(TAG, "Failed to create backup folder");
|
||||
}
|
||||
}
|
||||
cleanOldBackups(parentFolder);
|
||||
|
||||
} catch (Exception e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to save backup", e);
|
||||
}
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
public void cleanOldBackups(DocumentFile parentDir)
|
||||
{
|
||||
DocumentFile[] backupFolders = getBackupFolders(parentDir);
|
||||
if (backupFolders.length > maxBackups)
|
||||
{
|
||||
Arrays.sort(backupFolders, Comparator.comparing(DocumentFile::getName));
|
||||
for (int i = 0; i < backupFolders.length - maxBackups; i++)
|
||||
{
|
||||
Logger.i(TAG, "Delete old backup " + backupFolders[i].getUri());
|
||||
deleteDirectoryRecursive(backupFolders[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareBookmarkCategoriesForSharing()
|
||||
{
|
||||
List<BookmarkCategory> categories = BookmarkManager.INSTANCE.getCategories();
|
||||
long[] categoryIds = new long[categories.size()];
|
||||
for (int i = 0; i < categories.size(); i++)
|
||||
categoryIds[i] = categories.get(i).getId();
|
||||
BookmarkManager.INSTANCE.prepareCategoriesForSharing(categoryIds, KmlFileType.Text);
|
||||
}
|
||||
|
||||
public interface Listener
|
||||
{
|
||||
void onBackupStarted();
|
||||
|
||||
void onBackupFinished();
|
||||
|
||||
void onBackupFailed(ErrorCode errorCode);
|
||||
}
|
||||
|
||||
public enum ErrorCode
|
||||
{
|
||||
EMPTY_CATEGORY,
|
||||
ARCHIVE_ERROR,
|
||||
FILE_ERROR,
|
||||
UNSUPPORTED,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package app.organicmaps.backup;
|
||||
|
||||
import static app.organicmaps.backup.BackupUtils.getMaxBackups;
|
||||
import static app.organicmaps.backup.BackupUtils.isBackupFolderAvailable;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.BACKUP_FOLDER_PATH_KEY;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.BACKUP_INTERVAL_KEY;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.LAST_BACKUP_TIME_KEY;
|
||||
import static app.organicmaps.util.StorageUtils.isFolderWritable;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
public class PeriodicBackupRunner
|
||||
{
|
||||
private final Activity activity;
|
||||
private static final String TAG = PeriodicBackupRunner.class.getSimpleName();
|
||||
private final SharedPreferences prefs;
|
||||
private boolean alreadyChecked = false;
|
||||
|
||||
public PeriodicBackupRunner(Activity activity)
|
||||
{
|
||||
this.activity = activity;
|
||||
this.prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
}
|
||||
|
||||
public boolean isAlreadyChecked()
|
||||
{
|
||||
return alreadyChecked;
|
||||
}
|
||||
|
||||
public boolean isTimeToBackup()
|
||||
{
|
||||
long intervalMs = getBackupIntervalMs();
|
||||
|
||||
if (intervalMs <= 0)
|
||||
return false;
|
||||
|
||||
long lastBackupTime = prefs.getLong(LAST_BACKUP_TIME_KEY, 0);
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
alreadyChecked = true;
|
||||
|
||||
return (now - lastBackupTime) >= intervalMs;
|
||||
}
|
||||
|
||||
public void doBackup()
|
||||
{
|
||||
String storedFolderPath = prefs.getString(BACKUP_FOLDER_PATH_KEY, null);
|
||||
|
||||
if (isBackupFolderAvailable(activity, storedFolderPath))
|
||||
{
|
||||
Logger.i(TAG, "Performing periodic backup");
|
||||
performBackup(storedFolderPath, getMaxBackups(prefs));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.w(TAG, "Backup folder is not writable, passed path: " + storedFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
private long getBackupIntervalMs()
|
||||
{
|
||||
String defaultValue = "0";
|
||||
try
|
||||
{
|
||||
return Long.parseLong(prefs.getString(BACKUP_INTERVAL_KEY, defaultValue));
|
||||
} catch (NumberFormatException e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void performBackup(String backupFolderPath, int maxBackups)
|
||||
{
|
||||
LocalBackupManager backupManager = new LocalBackupManager(activity, backupFolderPath, maxBackups);
|
||||
backupManager.setListener(new LocalBackupManager.Listener()
|
||||
{
|
||||
@Override
|
||||
public void onBackupStarted()
|
||||
{
|
||||
Logger.i(TAG, "Periodic backup started");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackupFinished()
|
||||
{
|
||||
prefs.edit().putLong(LAST_BACKUP_TIME_KEY, System.currentTimeMillis()).apply();
|
||||
Logger.i(TAG, "Periodic backup finished");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackupFailed(LocalBackupManager.ErrorCode errorCode)
|
||||
{
|
||||
Logger.e(TAG, "Periodic backup was failed with code: " + errorCode);
|
||||
}
|
||||
});
|
||||
|
||||
backupManager.doBackup();
|
||||
}
|
||||
}
|
||||
@@ -266,7 +266,8 @@ public class NavigationController implements TrafficManager.TrafficCallback,
|
||||
mSpeedLimit.setSpeedLimit(0, false);
|
||||
return;
|
||||
}
|
||||
final boolean speedLimitExceeded = info.speedLimitMps < location.getSpeed();
|
||||
mSpeedLimit.setSpeedLimit(StringUtils.nativeFormatSpeed(info.speedLimitMps), speedLimitExceeded);
|
||||
final int fSpeedLimit = StringUtils.nativeFormatSpeed(info.speedLimitMps);
|
||||
final boolean speedLimitExceeded = fSpeedLimit < StringUtils.nativeFormatSpeed(location.getSpeed());
|
||||
mSpeedLimit.setSpeedLimit(fSpeedLimit, speedLimitExceeded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
package app.organicmaps.settings;
|
||||
|
||||
import static app.organicmaps.backup.BackupUtils.formatReadableFolderPath;
|
||||
import static app.organicmaps.backup.BackupUtils.getMaxBackups;
|
||||
import static app.organicmaps.backup.BackupUtils.isBackupFolderAvailable;
|
||||
import static app.organicmaps.util.StorageUtils.isFolderWritable;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.text.DateFormat;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.backup.LocalBackupManager;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
|
||||
public class BackupSettingsFragment
|
||||
extends BaseXmlSettingsFragment
|
||||
{
|
||||
private ActivityResultLauncher<Intent> folderPickerLauncher;
|
||||
|
||||
private static final String TAG = LocalBackupManager.class.getSimpleName();
|
||||
public static final String BACKUP_FOLDER_PATH_KEY = "backup_location";
|
||||
public static final String LAST_BACKUP_TIME_KEY = "last_backup_time";
|
||||
private static final String BACKUP_NOW_KEY = "backup_now";
|
||||
public static final String BACKUP_INTERVAL_KEY = "backup_history_interval";
|
||||
public static final String MAX_BACKUPS_KEY = "backup_history_count";
|
||||
public static final int MAX_BACKUPS_DEFAULT_COUNT = 10;
|
||||
public static final String DEFAULT_BACKUP_INTERVAL = "86400000"; // 24 hours in ms
|
||||
|
||||
private LocalBackupManager mBackupManager;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
@Override
|
||||
protected int getXmlResources()
|
||||
{
|
||||
return R.xml.prefs_backup;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
Preference backupLocationOption;
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
ListPreference backupIntervalOption;
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
Preference maxBackupsOption;
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
Preference backupNowOption;
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
Preference advancedCategory;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
folderPickerLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
boolean isSuccess = false;
|
||||
|
||||
String lastFolderPath = prefs.getString(BACKUP_FOLDER_PATH_KEY, null);
|
||||
|
||||
if (result.getResultCode() == Activity.RESULT_OK)
|
||||
{
|
||||
Intent data = result.getData();
|
||||
Logger.i(TAG, "Folder selection result: " + data);
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
Uri uri = data.getData();
|
||||
if (uri != null)
|
||||
{
|
||||
takePersistableUriPermission(uri);
|
||||
Logger.i(TAG, "Backup location changed to " + uri);
|
||||
prefs.edit().putString(BACKUP_FOLDER_PATH_KEY, uri.toString()).apply();
|
||||
setFormattedBackupPath(uri);
|
||||
|
||||
runBackup();
|
||||
|
||||
isSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.w(TAG, "Folder selection result is null");
|
||||
}
|
||||
}
|
||||
else if (result.getResultCode() == Activity.RESULT_CANCELED)
|
||||
{
|
||||
Logger.w(TAG, "User canceled folder selection");
|
||||
if (TextUtils.isEmpty(lastFolderPath))
|
||||
{
|
||||
prefs.edit().putString(BACKUP_FOLDER_PATH_KEY, null).apply();
|
||||
Logger.i(TAG, "Backup settings reset");
|
||||
initBackupLocationOption();
|
||||
}
|
||||
else if (isFolderWritable(requireActivity(), lastFolderPath))
|
||||
{
|
||||
Logger.i(TAG, "Backup location not changed, using previous value " + lastFolderPath);
|
||||
isSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.e(TAG, "Backup location not changed, but last folder is not writable: " + lastFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
resetLastBackupTime();
|
||||
updateStatusSummaryOption();
|
||||
|
||||
Logger.i(TAG, "Folder selection result: " + isSuccess);
|
||||
applyAdvancedSettings(isSuccess);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
|
||||
{
|
||||
super.onCreatePreferences(savedInstanceState, rootKey);
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||
backupLocationOption = findPreference(BACKUP_FOLDER_PATH_KEY);
|
||||
backupIntervalOption = findPreference(BACKUP_INTERVAL_KEY);
|
||||
maxBackupsOption = findPreference(MAX_BACKUPS_KEY);
|
||||
backupNowOption = findPreference(BACKUP_NOW_KEY);
|
||||
|
||||
initBackupLocationOption();
|
||||
initBackupIntervalOption();
|
||||
initMaxBackupsOption();
|
||||
initBackupNowOption();
|
||||
}
|
||||
|
||||
|
||||
private void initBackupLocationOption()
|
||||
{
|
||||
String storedFolderPath = prefs.getString(BACKUP_FOLDER_PATH_KEY, null);
|
||||
boolean isEnabled = false;
|
||||
if (!TextUtils.isEmpty(storedFolderPath))
|
||||
{
|
||||
if (isFolderWritable(requireContext(), storedFolderPath))
|
||||
{
|
||||
setFormattedBackupPath(Uri.parse(storedFolderPath));
|
||||
isEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.e(TAG, "Backup location is not available, path: " + storedFolderPath);
|
||||
showBackupErrorAlertDialog(requireContext().getString(R.string.dialog_report_error_missing_folder));
|
||||
backupLocationOption.setSummary(requireContext().getString(R.string.pref_backup_now_summary_folder_unavailable));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backupLocationOption.setSummary(requireContext().getString(R.string.pref_backup_location_summary_initial));
|
||||
}
|
||||
|
||||
applyAdvancedSettings(isEnabled);
|
||||
|
||||
backupLocationOption.setOnPreferenceClickListener(preference -> {
|
||||
launchFolderPicker();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setFormattedBackupPath(@NonNull Uri uri)
|
||||
{
|
||||
backupLocationOption.setSummary(formatReadableFolderPath(requireContext(), uri));
|
||||
}
|
||||
|
||||
private void initBackupIntervalOption()
|
||||
{
|
||||
String backupInterval = prefs.getString(BACKUP_INTERVAL_KEY, DEFAULT_BACKUP_INTERVAL);
|
||||
|
||||
CharSequence entry = getEntryForValue(backupIntervalOption, backupInterval);
|
||||
if (entry != null)
|
||||
backupIntervalOption.setSummary(entry);
|
||||
|
||||
backupIntervalOption.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
CharSequence newEntry = getEntryForValue(backupIntervalOption, newValue.toString());
|
||||
Logger.i(TAG, "auto backup interval changed to " + newEntry);
|
||||
if (newEntry != null)
|
||||
backupIntervalOption.setSummary(newEntry);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void initMaxBackupsOption()
|
||||
{
|
||||
maxBackupsOption.setSummary(String.valueOf(getMaxBackups(prefs)));
|
||||
|
||||
maxBackupsOption.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
maxBackupsOption.setSummary(newValue.toString());
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void initBackupNowOption()
|
||||
{
|
||||
updateStatusSummaryOption();
|
||||
backupNowOption.setOnPreferenceClickListener(preference -> {
|
||||
runBackup();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void updateStatusSummaryOption()
|
||||
{
|
||||
long lastBackupTime = prefs.getLong(LAST_BACKUP_TIME_KEY, 0L);
|
||||
|
||||
String summary;
|
||||
if (lastBackupTime > 0)
|
||||
{
|
||||
String time = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(lastBackupTime);
|
||||
summary = requireContext().getString(R.string.pref_backup_status_summary_success) + ": " + time;
|
||||
}
|
||||
else
|
||||
{
|
||||
summary = requireContext().getString(R.string.pref_backup_now_summary);
|
||||
}
|
||||
|
||||
backupNowOption.setSummary(summary);
|
||||
}
|
||||
|
||||
private void resetLastBackupTime()
|
||||
{
|
||||
prefs.edit().remove(LAST_BACKUP_TIME_KEY).apply();
|
||||
}
|
||||
|
||||
private void applyAdvancedSettings(boolean isBackupEnabled)
|
||||
{
|
||||
backupIntervalOption.setVisible(isBackupEnabled);
|
||||
maxBackupsOption.setVisible(isBackupEnabled);
|
||||
backupNowOption.setVisible(isBackupEnabled);
|
||||
}
|
||||
|
||||
|
||||
private void runBackup()
|
||||
{
|
||||
String currentFolderPath = prefs.getString(BACKUP_FOLDER_PATH_KEY, null);
|
||||
if (!TextUtils.isEmpty(currentFolderPath))
|
||||
{
|
||||
if (isFolderWritable(requireContext(), currentFolderPath))
|
||||
{
|
||||
mBackupManager = new LocalBackupManager(requireActivity(), currentFolderPath, getMaxBackups(prefs));
|
||||
mBackupManager.setListener(new LocalBackupManager.Listener()
|
||||
{
|
||||
@Override
|
||||
public void onBackupStarted()
|
||||
{
|
||||
Logger.i(TAG, "Manual backup started");
|
||||
|
||||
backupNowOption.setEnabled(false);
|
||||
backupNowOption.setSummary(R.string.pref_backup_now_summary_progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackupFinished()
|
||||
{
|
||||
Logger.i(TAG, "Manual backup successful");
|
||||
|
||||
backupNowOption.setEnabled(true);
|
||||
backupNowOption.setSummary(R.string.pref_backup_now_summary_ok);
|
||||
|
||||
prefs.edit().putLong(LAST_BACKUP_TIME_KEY, System.currentTimeMillis()).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackupFailed(LocalBackupManager.ErrorCode errorCode)
|
||||
{
|
||||
String errorMessage = switch (errorCode)
|
||||
{
|
||||
case EMPTY_CATEGORY -> requireContext().getString(R.string.pref_backup_now_summary_empty_lists);
|
||||
default -> requireContext().getString(R.string.pref_backup_now_summary_failed);
|
||||
};
|
||||
|
||||
Logger.e(TAG, "Manual backup was failed with code: " + errorCode);
|
||||
|
||||
backupNowOption.setEnabled(true);
|
||||
backupNowOption.setSummary(errorMessage);
|
||||
|
||||
showBackupErrorAlertDialog(requireContext().getString(R.string.dialog_report_error_with_logs));
|
||||
}
|
||||
});
|
||||
|
||||
mBackupManager.doBackup();
|
||||
}
|
||||
else
|
||||
{
|
||||
backupNowOption.setSummary(R.string.pref_backup_now_summary_folder_unavailable);
|
||||
showBackupErrorAlertDialog(requireContext().getString(R.string.dialog_report_error_missing_folder));
|
||||
Logger.e(TAG, "Manual backup error: folder " + currentFolderPath + " unavailable");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backupNowOption.setSummary(R.string.pref_backup_now_summary_folder_unavailable);
|
||||
Logger.e(TAG, "Manual backup error: no folder selected");
|
||||
}
|
||||
}
|
||||
|
||||
private void launchFolderPicker()
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
|
||||
|
||||
PackageManager packageManager = requireActivity().getPackageManager();
|
||||
if (intent.resolveActivity(packageManager) != null)
|
||||
folderPickerLauncher.launch(intent);
|
||||
else
|
||||
showNoFileManagerError();
|
||||
}
|
||||
|
||||
private void showNoFileManagerError()
|
||||
{
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setMessage(R.string.error_no_file_manager_app)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showBackupErrorAlertDialog(String message)
|
||||
{
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.pref_backup_now_summary_failed)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
private void takePersistableUriPermission(Uri uri)
|
||||
{
|
||||
requireContext().getContentResolver().takePersistableUriPermission(
|
||||
uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CharSequence getEntryForValue(@NonNull ListPreference listPref, @NonNull CharSequence value)
|
||||
{
|
||||
CharSequence[] entryValues = listPref.getEntryValues();
|
||||
CharSequence[] entries = listPref.getEntries();
|
||||
|
||||
if (entryValues == null || entries == null)
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < entryValues.length; i++)
|
||||
{
|
||||
if (entryValues[i].equals(value))
|
||||
return entries[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -189,6 +189,10 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements La
|
||||
LanguagesFragment langFragment = (LanguagesFragment)getSettingsActivity().stackFragment(LanguagesFragment.class, getString(R.string.change_map_locale), null);
|
||||
langFragment.setListener(this);
|
||||
}
|
||||
else if (key.equals(getString(R.string.pref_backup)))
|
||||
{
|
||||
getSettingsActivity().stackFragment(BackupSettingsFragment.class, getString(R.string.pref_backup_title), null);
|
||||
}
|
||||
}
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package app.organicmaps.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -10,10 +11,13 @@ import android.provider.DocumentsContract;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import app.organicmaps.BuildConfig;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
@@ -323,4 +327,76 @@ public class StorageUtils
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean copyFileToDocumentFile(
|
||||
@NonNull Activity activity,
|
||||
@NonNull File sourceFile,
|
||||
@NonNull DocumentFile targetFile
|
||||
)
|
||||
{
|
||||
try (
|
||||
InputStream in = new FileInputStream(sourceFile);
|
||||
OutputStream out = activity.getContentResolver().openOutputStream(targetFile.getUri())
|
||||
)
|
||||
{
|
||||
if (out == null)
|
||||
{
|
||||
Logger.e(TAG, "Failed to open output stream for " + targetFile.getUri());
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int length;
|
||||
|
||||
while ((length = in.read(buffer)) > 0)
|
||||
out.write(buffer, 0, length);
|
||||
|
||||
out.flush();
|
||||
return true;
|
||||
} catch (IOException e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to copy file from " + sourceFile.getAbsolutePath() + " to " + targetFile.getUri(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteDirectoryRecursive(@NonNull DocumentFile dir)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (DocumentFile file : dir.listFiles())
|
||||
{
|
||||
if (file.isDirectory())
|
||||
deleteDirectoryRecursive(file);
|
||||
else
|
||||
file.delete();
|
||||
}
|
||||
dir.delete();
|
||||
} catch (Exception e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to delete directory: " + dir.getUri(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFolderWritable(Context context, String folderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
Uri folderUri = Uri.parse(folderPath);
|
||||
DocumentFile folder = DocumentFile.fromTreeUri(context, folderUri);
|
||||
if (folder != null && folder.canWrite())
|
||||
{
|
||||
DocumentFile tempFile = folder.createFile("application/octet-stream", "temp_file");
|
||||
if (tempFile != null)
|
||||
{
|
||||
tempFile.delete();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to check if folder is writable: " + folderPath, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,4 +904,29 @@
|
||||
<string name="editor_building_levels">Этажей (вкл. подвалы искл. крышу)</string>
|
||||
<string name="editor_level">Этаж (0 это первый этаж)</string>
|
||||
<string name="error_enter_correct_level">Введите правильный номер этажа</string>
|
||||
<!-- Settings "Backup" category: "Backup" title -->
|
||||
<string name="pref_backup_title">Резервное копирование меток и треков</string>
|
||||
<string name="pref_backup_summary">Автоматически сохранять в папку на устройстве</string>
|
||||
<string name="pref_backup_now_title">Создать резервную копию</string>
|
||||
<string name="pref_backup_now_summary">Запустить резервное копирование вручную</string>
|
||||
<string name="pref_backup_now_summary_progress">Идёт резервное копирование…</string>
|
||||
<string name="pref_backup_now_summary_ok">Копирование успешно завершено</string>
|
||||
<string name="pref_backup_now_summary_empty_lists">Нет данных для копирования</string>
|
||||
<string name="pref_backup_now_summary_failed">Ошибка при копировании</string>
|
||||
<string name="pref_backup_now_summary_folder_unavailable">Папка для копий недоступна</string>
|
||||
<string name="pref_backup_status_summary_success">Последнее успешное копирование</string>
|
||||
<string name="pref_backup_location_title">Папка для резервных копий</string>
|
||||
<string name="pref_backup_location_summary_initial">Сначала выберите папку и дайте доступ</string>
|
||||
<string name="pref_backup_history_title">Хранить количество копий</string>
|
||||
<string name="pref_backup_interval_title">Автозапуск</string>
|
||||
<string name="backup_interval_every_day">Каждый день</string>
|
||||
<string name="backup_interval_every_week">Каждую неделю</string>
|
||||
<string name="backup_interval_manual_only">Выключено (только вручную)</string>
|
||||
<string name="dialog_report_error_missing_folder">Выбранная папка для резервного копирования недоступна или нет права записи в неё. Пожалуйста, выберите другую папку</string>
|
||||
<string name="dialog_report_error_with_logs">Пожалуйста, отправьте нам отчет об ошибке:\n
|
||||
- Включите \"Запись логов\" в настройках\n
|
||||
- воспроизведите проблему\n
|
||||
- на экране \"Справка\" нажмите кнопку \"Сообщить о проблеме\" и отправьте нам отчет по почте или в чат\n
|
||||
- отключите логирование
|
||||
</string>
|
||||
</resources>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<string name="pref_keep_screen_on" translatable="false">KeepScreenOn</string>
|
||||
<string name="pref_show_on_lock_screen" translatable="false">ShowOnLockScreen</string>
|
||||
<string name="pref_map_locale" translatable="false">MapLanguage</string>
|
||||
<string name="pref_backup" translatable="false">Backup</string>
|
||||
<string name="pref_left_button" translatable="false">LeftButton</string>
|
||||
|
||||
<string name="notification_ticker_ltr" translatable="false">%1$s: %2$s</string>
|
||||
|
||||
@@ -23,7 +23,29 @@
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
</string-array>
|
||||
|
||||
|
||||
<string-array name="backup_interval_entries">
|
||||
<item>@string/backup_interval_every_day</item>
|
||||
<item>@string/backup_interval_every_week</item>
|
||||
<item>@string/backup_interval_manual_only</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="backup_interval_values">
|
||||
<item>86400000</item> <!-- Every day -->
|
||||
<item>604800000</item> <!-- Every week -->
|
||||
<item>0</item> <!-- Manual only -->
|
||||
</string-array>
|
||||
|
||||
<string-array name="backup_history_entries">
|
||||
<item>3</item>
|
||||
<item>10</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="backup_history_values">
|
||||
<item>3</item>
|
||||
<item>10</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="map_style">
|
||||
<item>@string/off</item>
|
||||
<item>@string/on</item>
|
||||
|
||||
@@ -936,6 +936,32 @@
|
||||
<string name="codeberg">Codeberg</string>
|
||||
<string name="pref_left_button_title">Left button setup</string>
|
||||
<string name="pref_left_button_disable">Disable</string>
|
||||
|
||||
<!-- Settings "Backup" category: "Backup" title -->
|
||||
<string name="pref_backup_title">Bookmarks and tracks backup</string>
|
||||
<string name="pref_backup_summary">Automatically backup to a folder on your device</string>
|
||||
<string name="pref_backup_now_title">Backup now</string>
|
||||
<string name="pref_backup_now_summary">Create a backup immediately</string>
|
||||
<string name="pref_backup_now_summary_progress">Backup in progress…</string>
|
||||
<string name="pref_backup_now_summary_ok">Backup completed successfully</string>
|
||||
<string name="pref_backup_now_summary_empty_lists">Nothing to back up</string>
|
||||
<string name="pref_backup_now_summary_failed">Backup failed</string>
|
||||
<string name="pref_backup_now_summary_folder_unavailable">The backup folder is not available</string>
|
||||
<string name="pref_backup_status_summary_success">Last successful backup</string>
|
||||
<string name="pref_backup_location_title">Backup location</string>
|
||||
<string name="pref_backup_location_summary_initial">Please select a folder first and grant permission</string>
|
||||
<string name="pref_backup_history_title">Number of backups to keep</string>
|
||||
<string name="pref_backup_interval_title">Automatic backup</string>
|
||||
<string name="backup_interval_every_day">Daily</string>
|
||||
<string name="backup_interval_every_week">Weekly</string>
|
||||
<string name="backup_interval_manual_only">Off (manual only)</string>
|
||||
<string name="dialog_report_error_missing_folder">The selected backup location is not available or writable. Select a different location, please.</string>
|
||||
<string name="dialog_report_error_with_logs">Please send us an error report:\n
|
||||
- \"Enable logging\" in the settings\n
|
||||
- reproduce the problem\n
|
||||
- in the \"Help/About\" screen press a \"Report a bug\" button and send it to us via email or chat\n
|
||||
- disable logging
|
||||
</string>
|
||||
<string name="clear">Clear</string>
|
||||
<string name="route_type">Route type</string>
|
||||
<string name="vehicle">Vehicle</string>
|
||||
|
||||
24
android/app/src/main/res/xml/prefs_backup.xml
Normal file
24
android/app/src/main/res/xml/prefs_backup.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<Preference
|
||||
android:key="backup_location"
|
||||
android:summary="@string/pref_backup_location_summary_initial"
|
||||
android:title="@string/pref_backup_location_title" />
|
||||
<Preference
|
||||
android:key="backup_now"
|
||||
android:summary="@string/pref_backup_now_summary"
|
||||
android:title="@string/pref_backup_now_title" />
|
||||
<ListPreference
|
||||
android:defaultValue="86400000"
|
||||
android:entries="@array/backup_interval_entries"
|
||||
android:entryValues="@array/backup_interval_values"
|
||||
android:key="backup_history_interval"
|
||||
android:title="@string/pref_backup_interval_title" />
|
||||
<ListPreference
|
||||
android:defaultValue="10"
|
||||
android:entries="@array/backup_history_entries"
|
||||
android:entryValues="@array/backup_history_values"
|
||||
android:key="backup_history_count"
|
||||
android:title="@string/pref_backup_history_title" />
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -112,6 +112,13 @@
|
||||
app:singleLineTitle="false"
|
||||
android:persistent="false"
|
||||
android:order="18"/>
|
||||
<Preference
|
||||
android:key="@string/pref_backup"
|
||||
android:title="@string/pref_backup_title"
|
||||
android:summary="@string/pref_backup_summary"
|
||||
app:singleLineTitle="false"
|
||||
android:persistent="false"
|
||||
android:order="19"/>
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
<androidx.preference.PreferenceCategory
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -26904,19 +26904,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720994322
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27049,16 +27036,6 @@ cont {
|
||||
priority: 219
|
||||
cap: BUTTCAP
|
||||
}
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720994322
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.7
|
||||
}
|
||||
priority: 220
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
@@ -27215,19 +27192,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-bridge"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720994322
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 155
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27412,19 +27376,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-difficult"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720994322
|
||||
dashdot {
|
||||
dd: 1.0
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27549,19 +27500,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-expert"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1716665907
|
||||
dashdot {
|
||||
dd: 1.0
|
||||
dd: 4.0
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27686,19 +27624,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-horse"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720994322
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 155
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27823,19 +27748,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-tunnel"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720994322
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 155
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -35974,19 +35886,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717523245
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -36111,19 +36010,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track-area"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717523245
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -36248,19 +36134,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track-bridge"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717523245
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -36445,19 +36318,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track-no-access"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717523245
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -36582,19 +36442,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track-tunnel"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717523245
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -63404,19 +63251,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "piste:type-hike"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 2573352319
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 120
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
|
||||
Binary file not shown.
@@ -26838,19 +26838,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720602141
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -26983,16 +26970,6 @@ cont {
|
||||
priority: 219
|
||||
cap: BUTTCAP
|
||||
}
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720602141
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.7
|
||||
}
|
||||
priority: 220
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
@@ -27149,19 +27126,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-bridge"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720602141
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 155
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27346,19 +27310,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-difficult"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720602141
|
||||
dashdot {
|
||||
dd: 1.0
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27483,19 +27434,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-expert"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1715283479
|
||||
dashdot {
|
||||
dd: 1.0
|
||||
dd: 4.0
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27620,19 +27558,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-horse"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720602141
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 155
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -27757,19 +27682,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-path-tunnel"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 1720602141
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 155
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -35770,19 +35682,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717786416
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -35907,19 +35806,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track-area"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717786416
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -36044,19 +35930,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track-bridge"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717786416
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -36241,19 +36114,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track-no-access"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717786416
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -36378,19 +36238,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "highway-track-tunnel"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 1.1
|
||||
color: 1717786416
|
||||
dashdot {
|
||||
dd: 6.0
|
||||
dd: 2.5
|
||||
}
|
||||
priority: 180
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
@@ -63178,19 +63025,6 @@ cont {
|
||||
}
|
||||
cont {
|
||||
name: "piste:type-hike"
|
||||
element {
|
||||
scale: 14
|
||||
lines {
|
||||
width: 0.9
|
||||
color: 2579790591
|
||||
dashdot {
|
||||
dd: 3.5
|
||||
dd: 2.0
|
||||
}
|
||||
priority: 120
|
||||
cap: BUTTCAP
|
||||
}
|
||||
}
|
||||
element {
|
||||
scale: 15
|
||||
lines {
|
||||
|
||||
@@ -714,7 +714,7 @@ line|z17-[highway=steps][bridge?]::bridgeblack,
|
||||
line|z16-[highway=road][bridge?]::bridgeblack,
|
||||
line|z16-[highway=service][bridge?]::bridgeblack
|
||||
{casing-linecap: butt;casing-color:@bridge_casing;casing-opacity: 0.7;}
|
||||
line|z14-[highway=track],
|
||||
line|z15-[highway=track],
|
||||
{color: @track;opacity: 0.6;}
|
||||
line|z14-[highway=raceway],
|
||||
{color: @track;opacity: 0.7;}
|
||||
@@ -728,11 +728,11 @@ line|z16-[highway=footway],
|
||||
{opacity: 0.95;}
|
||||
line|z15-[highway=steps],
|
||||
{color: @residential;opacity: 1;}
|
||||
line|z14-[highway=path],
|
||||
line|z15-[highway=path],
|
||||
{color: @path;opacity: 0.6;}
|
||||
line|z14-[highway=path][_path_grade=expert],
|
||||
line|z15-[highway=path][_path_grade=expert],
|
||||
{color: @path_expert; opacity: 0.6;}
|
||||
line|z14-[piste:type=hike],
|
||||
line|z15-[piste:type=hike],
|
||||
{color: @piste; opacity: 0.4;}
|
||||
line|z17-[highway=footway][tunnel?]::tunnelBackground,
|
||||
line|z17-[highway=cycleway][tunnel?]::tunnelBackground,
|
||||
@@ -916,8 +916,6 @@ line|z19-[highway=raceway],
|
||||
line|z19-[leisure=track][!area]
|
||||
{width:4; opacity: 0.8;}
|
||||
|
||||
line|z14[highway=track],
|
||||
{width: 1.1; dashes: 6,2.5;}
|
||||
line|z15[highway=track],
|
||||
{width: 1.4; dashes: 6,2.5;}
|
||||
line|z16[highway=track],
|
||||
@@ -929,9 +927,6 @@ line|z18[highway=track],
|
||||
line|z19-[highway=track],
|
||||
{width: 4.2; dashes: 12,3.5; opacity: 0.8;}
|
||||
|
||||
line|z14[highway=path],
|
||||
line|z14[piste:type=hike],
|
||||
{width: 0.9; dashes: 3.5,2;}
|
||||
line|z15[highway=path],
|
||||
line|z15[piste:type=hike],
|
||||
{width: 1.1; dashes: 3.5,2;}
|
||||
@@ -946,8 +941,6 @@ line|z18[highway=path],
|
||||
line|z19-[highway=path],
|
||||
{width: 3.7; dashes: 8,4.5; opacity: 0.8;}
|
||||
|
||||
line|z14[highway=path][bicycle=designated],
|
||||
{width: 0.9; dashes: 3.5,2.7;}
|
||||
line|z15[highway=path][bicycle=designated],
|
||||
{width: 1.1; dashes: 3.5,2.7;}
|
||||
line|z16[highway=path][bicycle=designated],
|
||||
@@ -959,8 +952,6 @@ line|z18[highway=path][bicycle=designated],
|
||||
line|z19-[highway=path][bicycle=designated],
|
||||
{width: 3.7; dashes: 8,6.2; opacity: 0.8;}
|
||||
|
||||
line|z14[highway=path][_path_grade=difficult],
|
||||
{width: 0.9; dashes: 1,2;}
|
||||
line|z15[highway=path][_path_grade=difficult],
|
||||
{width: 1.1; dashes: 1,2;}
|
||||
line|z16[highway=path][_path_grade=difficult],
|
||||
@@ -970,8 +961,6 @@ line|z17[highway=path][_path_grade=difficult],
|
||||
line|z18-[highway=path][_path_grade=difficult],
|
||||
{width: 2.8; dashes: 2.8,3.5;}
|
||||
|
||||
line|z14[highway=path][_path_grade=expert],
|
||||
{width: 0.9; dashes: 1,4;}
|
||||
line|z15[highway=path][_path_grade=expert],
|
||||
{width: 1.1; dashes: 1,4;}
|
||||
line|z16[highway=path][_path_grade=expert],
|
||||
|
||||
@@ -224,11 +224,11 @@ railway-subway-bridge::dash # line::dash z16- (also has
|
||||
=== 221
|
||||
|
||||
highway-footway-bicycle # line z15- (also has line::cycleline z15-, pathtext z15-)
|
||||
highway-path-bicycle # line z14- (also has line::cycleline z14-, pathtext z15-)
|
||||
highway-path-bicycle # line z15- (also has line::cycleline z14-, pathtext z15-)
|
||||
=== 220
|
||||
|
||||
highway-footway-bicycle::cycleline # line::cycleline z15- (also has line z15-, pathtext z15-)
|
||||
highway-path-bicycle::cycleline # line::cycleline z14- (also has line z14-, pathtext z15-)
|
||||
highway-path-bicycle::cycleline # line::cycleline z14- (also has line z15-, pathtext z15-)
|
||||
=== 219
|
||||
|
||||
highway-cycleway # line z13- (also has pathtext z15-)
|
||||
@@ -276,15 +276,15 @@ highway-bridleway-tunnel # line z14- (also has line::
|
||||
highway-footway # line z15- (also has pathtext z15-)
|
||||
highway-footway-area # line z15- and area z14- (also has pathtext z15-)
|
||||
highway-footway-crossing # line z16-
|
||||
highway-path # line z14- (also has pathtext z15-)
|
||||
highway-path-difficult # line z14- (also has pathtext z15-)
|
||||
highway-path-expert # line z14- (also has pathtext z15-)
|
||||
highway-path # line z15- (also has pathtext z15-)
|
||||
highway-path-difficult # line z15- (also has pathtext z15-)
|
||||
highway-path-expert # line z15- (also has pathtext z15-)
|
||||
highway-raceway # line z14- (also has pathtext z16-)
|
||||
highway-track # line z14- (also has pathtext z15-)
|
||||
highway-track-area # line z14- (also has pathtext z15-)
|
||||
highway-track-bridge # line z14- (also has line::bridgeblack z17-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-track-no-access # line z14- (also has pathtext z15-)
|
||||
highway-track-tunnel # line z14- (also has line::tunnelBackground z17-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-track # line z15- (also has pathtext z15-)
|
||||
highway-track-area # line z15- (also has pathtext z15-)
|
||||
highway-track-bridge # line z15- (also has line::bridgeblack z17-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-track-no-access # line z15- (also has pathtext z15-)
|
||||
highway-track-tunnel # line z15- (also has line::tunnelBackground z17-, line::tunnelCasing z17-, pathtext z15-)
|
||||
=== 180
|
||||
|
||||
highway-construction # line z13- (also has pathtext z15-)
|
||||
@@ -302,25 +302,25 @@ railway-preserved-tunnel # line z15-
|
||||
highway-footway-bridge # line z15- (also has line::bridgeblack z17-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-footway-sidewalk # line z16-
|
||||
highway-footway-tunnel # line z15- (also has line::tunnelBackground z17-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-path-bridge # line z14- (also has line::bridgeblack z17-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-path-horse # line z14- (also has pathtext z15-)
|
||||
highway-path-tunnel # line z14- (also has line::tunnelBackground z17-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-path-bridge # line z15- (also has line::bridgeblack z17-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-path-horse # line z15- (also has pathtext z15-)
|
||||
highway-path-tunnel # line z15- (also has line::tunnelBackground z17-, line::tunnelCasing z17-, pathtext z15-)
|
||||
=== 155
|
||||
|
||||
highway-bridleway-tunnel::tunnelBackground # line::tunnelBackground z17- (also has line z14-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-cycleway-tunnel::tunnelBackground # line::tunnelBackground z17- (also has line z13-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-footway-tunnel::tunnelBackground # line::tunnelBackground z17- (also has line z15-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-path-tunnel::tunnelBackground # line::tunnelBackground z17- (also has line z14-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-path-tunnel::tunnelBackground # line::tunnelBackground z17- (also has line z15-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-steps-tunnel::tunnelBackground # line::tunnelBackground z17- (also has line z15-, line::tunnelCasing z17-, pathtext z16-)
|
||||
highway-track-tunnel::tunnelBackground # line::tunnelBackground z17- (also has line z14-, line::tunnelCasing z17-, pathtext z15-)
|
||||
highway-track-tunnel::tunnelBackground # line::tunnelBackground z17- (also has line z15-, line::tunnelCasing z17-, pathtext z15-)
|
||||
=== 154
|
||||
|
||||
highway-bridleway-tunnel::tunnelCasing # line::tunnelCasing z17- (also has line z14-, line::tunnelBackground z17-, pathtext z15-)
|
||||
highway-cycleway-tunnel::tunnelCasing # line::tunnelCasing z17- (also has line z13-, line::tunnelBackground z17-, pathtext z15-)
|
||||
highway-footway-tunnel::tunnelCasing # line::tunnelCasing z17- (also has line z15-, line::tunnelBackground z17-, pathtext z15-)
|
||||
highway-path-tunnel::tunnelCasing # line::tunnelCasing z17- (also has line z14-, line::tunnelBackground z17-, pathtext z15-)
|
||||
highway-path-tunnel::tunnelCasing # line::tunnelCasing z17- (also has line z15-, line::tunnelBackground z17-, pathtext z15-)
|
||||
highway-steps-tunnel::tunnelCasing # line::tunnelCasing z17- (also has line z15-, line::tunnelBackground z17-, pathtext z16-)
|
||||
highway-track-tunnel::tunnelCasing # line::tunnelCasing z17- (also has line z14-, line::tunnelBackground z17-, pathtext z15-)
|
||||
highway-track-tunnel::tunnelCasing # line::tunnelCasing z17- (also has line z15-, line::tunnelBackground z17-, pathtext z15-)
|
||||
=== 153
|
||||
|
||||
highway-bridleway-bridge::bridgewhite # line::bridgewhite z15- (also has line z14-, line::bridgeblack z17-, pathtext z15-)
|
||||
@@ -328,7 +328,7 @@ highway-cycleway-bridge::bridgewhite # line::bridgewhite z15- (al
|
||||
highway-footway-bridge::bridgewhite # line::bridgewhite z15- (also has line z15-, line::bridgeblack z17-, pathtext z15-)
|
||||
highway-motorway-bridge::bridgewhite # line::bridgewhite z13- (also has line z6-, line::bridgeblack z13-, pathtext z10-, shield::shield z10-)
|
||||
highway-motorway_link-bridge::bridgewhite # line::bridgewhite z14- (also has line z10-, line::bridgeblack z14-, pathtext z10-, shield::shield z10-)
|
||||
highway-path-bridge::bridgewhite # line::bridgewhite z15- (also has line z14-, line::bridgeblack z17-, pathtext z15-)
|
||||
highway-path-bridge::bridgewhite # line::bridgewhite z15- (also has line z15-, line::bridgeblack z17-, pathtext z15-)
|
||||
highway-pedestrian-bridge::bridgewhite # line::bridgewhite z13- (also has line z13-, line::bridgeblack z14-, pathtext z14-)
|
||||
highway-primary-bridge::bridgewhite # line::bridgewhite z14- (also has line z8-, line::bridgeblack z14-, pathtext z10-, shield::shield z10-)
|
||||
highway-primary_link-bridge::bridgewhite # line::bridgewhite z14- (also has line z11-, line::bridgeblack z14-, pathtext z11-, shield::shield z11-)
|
||||
@@ -340,7 +340,7 @@ highway-service-bridge::bridgewhite # line::bridgewhite z16- (al
|
||||
highway-steps-bridge::bridgewhite # line::bridgewhite z15- (also has line z15-, line::bridgeblack z17-, pathtext z16-)
|
||||
highway-tertiary-bridge::bridgewhite # line::bridgewhite z14- (also has line z11-, line::bridgeblack z14-, pathtext z12-, shield::shield z13-)
|
||||
highway-tertiary_link-bridge::bridgewhite # line::bridgewhite z14- (also has line z14-, line::bridgeblack z14-, pathtext z18-)
|
||||
highway-track-bridge::bridgewhite # line::bridgewhite z15- (also has line z14-, line::bridgeblack z17-, pathtext z15-)
|
||||
highway-track-bridge::bridgewhite # line::bridgewhite z15- (also has line z15-, line::bridgeblack z17-, pathtext z15-)
|
||||
highway-trunk-bridge::bridgewhite # line::bridgewhite z13- (also has line z6-, line::bridgeblack z13-, pathtext z10-, shield::shield z10-)
|
||||
highway-trunk_link-bridge::bridgewhite # line::bridgewhite z14- (also has line z10-, line::bridgeblack z14-, pathtext z10-, shield::shield z10-)
|
||||
highway-unclassified-bridge::bridgewhite # line::bridgewhite z14- (also has line z11-, line::bridgeblack z14-, pathtext z13-)
|
||||
@@ -363,7 +363,7 @@ highway-cycleway-bridge::bridgeblack # line::bridgeblack z17- (al
|
||||
highway-footway-bridge::bridgeblack # line::bridgeblack z17- (also has line z15-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-motorway-bridge::bridgeblack # line::bridgeblack z13- (also has line z6-, line::bridgewhite z13-, pathtext z10-, shield::shield z10-)
|
||||
highway-motorway_link-bridge::bridgeblack # line::bridgeblack z14- (also has line z10-, line::bridgewhite z14-, pathtext z10-, shield::shield z10-)
|
||||
highway-path-bridge::bridgeblack # line::bridgeblack z17- (also has line z14-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-path-bridge::bridgeblack # line::bridgeblack z17- (also has line z15-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-pedestrian-bridge::bridgeblack # line::bridgeblack z14- (also has line z13-, line::bridgewhite z13-, pathtext z14-)
|
||||
highway-primary-bridge::bridgeblack # line::bridgeblack z14- (also has line z8-, line::bridgewhite z14-, pathtext z10-, shield::shield z10-)
|
||||
highway-primary_link-bridge::bridgeblack # line::bridgeblack z14- (also has line z11-, line::bridgewhite z14-, pathtext z11-, shield::shield z11-)
|
||||
@@ -375,7 +375,7 @@ highway-service-bridge::bridgeblack # line::bridgeblack z16- (al
|
||||
highway-steps-bridge::bridgeblack # line::bridgeblack z17- (also has line z15-, line::bridgewhite z15-, pathtext z16-)
|
||||
highway-tertiary-bridge::bridgeblack # line::bridgeblack z14- (also has line z11-, line::bridgewhite z14-, pathtext z12-, shield::shield z13-)
|
||||
highway-tertiary_link-bridge::bridgeblack # line::bridgeblack z14- (also has line z14-, line::bridgewhite z14-, pathtext z18-)
|
||||
highway-track-bridge::bridgeblack # line::bridgeblack z17- (also has line z14-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-track-bridge::bridgeblack # line::bridgeblack z17- (also has line z15-, line::bridgewhite z15-, pathtext z15-)
|
||||
highway-trunk-bridge::bridgeblack # line::bridgeblack z13- (also has line z6-, line::bridgewhite z13-, pathtext z10-, shield::shield z10-)
|
||||
highway-trunk_link-bridge::bridgeblack # line::bridgeblack z14- (also has line z10-, line::bridgewhite z14-, pathtext z10-, shield::shield z10-)
|
||||
highway-unclassified-bridge::bridgeblack # line::bridgeblack z14- (also has line z11-, line::bridgewhite z14-, pathtext z13-)
|
||||
@@ -407,7 +407,7 @@ piste:type-downhill-expert # line z14- (also has pathte
|
||||
piste:type-downhill-freeride # line z14- (also has pathtext z15-)
|
||||
piste:type-downhill-intermediate # line z14- (also has pathtext z15-)
|
||||
piste:type-downhill-novice # line z14- (also has pathtext z15-)
|
||||
piste:type-hike # line z14- (also has pathtext z15-)
|
||||
piste:type-hike # line z15- (also has pathtext z15-)
|
||||
piste:type-nordic # line z14- (also has pathtext z15-)
|
||||
piste:type-skitour # line z14- (also has pathtext z15-)
|
||||
piste:type-sled # line z14- (also has pathtext z15-)
|
||||
|
||||
@@ -705,13 +705,13 @@ natural-rock # icon z17- (also has captio
|
||||
highway-bridleway # pathtext z15- (also has line z14-)
|
||||
highway-bridleway-bridge # pathtext z15- (also has line z14-, line::bridgeblack z17-, line::bridgewhite z15-)
|
||||
highway-bridleway-tunnel # pathtext z15- (also has line z14-, line::tunnelBackground z17-, line::tunnelCasing z17-)
|
||||
highway-path # pathtext z15- (also has line z14-)
|
||||
highway-path-bicycle # pathtext z15- (also has line z14-, line::cycleline z14-)
|
||||
highway-path-bridge # pathtext z15- (also has line z14-, line::bridgeblack z17-, line::bridgewhite z15-)
|
||||
highway-path-difficult # pathtext z15- (also has line z14-)
|
||||
highway-path-expert # pathtext z15- (also has line z14-)
|
||||
highway-path-horse # pathtext z15- (also has line z14-)
|
||||
highway-path-tunnel # pathtext z15- (also has line z14-, line::tunnelBackground z17-, line::tunnelCasing z17-)
|
||||
highway-path # pathtext z15- (also has line z15-)
|
||||
highway-path-bicycle # pathtext z15- (also has line z15-, line::cycleline z14-)
|
||||
highway-path-bridge # pathtext z15- (also has line z15-, line::bridgeblack z17-, line::bridgewhite z15-)
|
||||
highway-path-difficult # pathtext z15- (also has line z15-)
|
||||
highway-path-expert # pathtext z15- (also has line z15-)
|
||||
highway-path-horse # pathtext z15- (also has line z15-)
|
||||
highway-path-tunnel # pathtext z15- (also has line z15-, line::tunnelBackground z17-, line::tunnelCasing z17-)
|
||||
=== 2820
|
||||
|
||||
highway-steps # pathtext z16- (also has line z15-)
|
||||
@@ -719,11 +719,11 @@ highway-steps-bridge # pathtext z16- (also has li
|
||||
highway-steps-tunnel # pathtext z16- (also has line z15-, line::tunnelBackground z17-, line::tunnelCasing z17-)
|
||||
=== 2810
|
||||
|
||||
highway-track # pathtext z15- (also has line z14-)
|
||||
highway-track-area # pathtext z15- (also has line z14-)
|
||||
highway-track-bridge # pathtext z15- (also has line z14-, line::bridgeblack z17-, line::bridgewhite z15-)
|
||||
highway-track-no-access # pathtext z15- (also has line z14-)
|
||||
highway-track-tunnel # pathtext z15- (also has line z14-, line::tunnelBackground z17-, line::tunnelCasing z17-)
|
||||
highway-track # pathtext z15- (also has line z15-)
|
||||
highway-track-area # pathtext z15- (also has line z15-)
|
||||
highway-track-bridge # pathtext z15- (also has line z15-, line::bridgeblack z17-, line::bridgewhite z15-)
|
||||
highway-track-no-access # pathtext z15- (also has line z15-)
|
||||
highway-track-tunnel # pathtext z15- (also has line z15-, line::tunnelBackground z17-, line::tunnelCasing z17-)
|
||||
=== 2780
|
||||
|
||||
highway-service # pathtext z16- (also has line z15-)
|
||||
@@ -739,7 +739,7 @@ piste:type-downhill-expert # pathtext z15- (also has li
|
||||
piste:type-downhill-freeride # pathtext z15- (also has line z14-)
|
||||
piste:type-downhill-intermediate # pathtext z15- (also has line z14-)
|
||||
piste:type-downhill-novice # pathtext z15- (also has line z14-)
|
||||
piste:type-hike # pathtext z15- (also has line z14-)
|
||||
piste:type-hike # pathtext z15- (also has line z15-)
|
||||
piste:type-nordic # pathtext z15- (also has line z14-)
|
||||
piste:type-skitour # pathtext z15- (also has line z14-)
|
||||
piste:type-sled # pathtext z15- (also has line z14-)
|
||||
|
||||
Reference in New Issue
Block a user