mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 17:43:06 +02:00
Configurable filename for export: used for all automatic exports after recording, exporting all, and sharing tracks.
Fixes #512.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
package de.dennisguse.opentracks.io.file;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
|
||||
public class TrackFilenameGenerator {
|
||||
|
||||
public static final String UUID_KEY = "{uuid}";
|
||||
public static final String TRACKNAME_KEY = "{name}";
|
||||
public static final String CATEGORY_KEY = "{category}";
|
||||
public static final String STARTTIME_KEY = "{time}";
|
||||
|
||||
public static String getAllOptions() {
|
||||
return Stream.of(UUID_KEY, TRACKNAME_KEY, CATEGORY_KEY, STARTTIME_KEY)
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
private final String template;
|
||||
|
||||
public TrackFilenameGenerator(@NonNull String template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public String format(@NonNull Track track, @NonNull TrackFileFormat trackFileFormat) {
|
||||
Map<String, String> values = new HashMap<>();
|
||||
|
||||
values.put(UUID_KEY, track.getUuid().toString().substring(0, 8));
|
||||
values.put(TRACKNAME_KEY, track.getName());
|
||||
values.put(CATEGORY_KEY, track.getCategory());
|
||||
values.put(STARTTIME_KEY, track.getStartTime().toString());
|
||||
|
||||
return FileUtils.sanitizeFileName(format(template, values)) + "." + trackFileFormat.getExtension();
|
||||
}
|
||||
|
||||
private static String format(String template, Map<String, String> values) {
|
||||
StringBuilder templateCompiler = new StringBuilder(template);
|
||||
List<String> valueList = new ArrayList<>();
|
||||
|
||||
Matcher keyMatcher = Pattern
|
||||
.compile("\\{(\\w+)\\}")
|
||||
.matcher(template);
|
||||
|
||||
while (keyMatcher.find()) {
|
||||
String key = keyMatcher.group();
|
||||
|
||||
if (!values.containsKey(key)) {
|
||||
throw new TemplateInvalidException(key);
|
||||
}
|
||||
|
||||
int index = templateCompiler.indexOf(key);
|
||||
if (index != -1) {
|
||||
templateCompiler.replace(index, index + key.length(), "%s");
|
||||
valueList.add(values.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
String templateCompiled = templateCompiler.toString();
|
||||
if (templateCompiled.contains("{") || templateCompiled.contains("}")) {
|
||||
throw new TemplateInvalidException(template);
|
||||
}
|
||||
|
||||
return String.format(templateCompiled, valueList.toArray());
|
||||
}
|
||||
|
||||
public String getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
try {
|
||||
getExample();
|
||||
return !template.isEmpty();
|
||||
} catch (TemplateInvalidException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getExample() {
|
||||
Track track = new Track();
|
||||
track.setName("Berlin");
|
||||
track.setUuid(UUID.fromString("fefefefefe-0000-1000-8000-00805f9b34fb"));
|
||||
track.getTrackStatistics().setStartTime(Instant.ofEpochMilli(0));
|
||||
|
||||
return format(track, TrackFileFormat.GPX);
|
||||
}
|
||||
|
||||
public static class TemplateInvalidException extends RuntimeException {
|
||||
public TemplateInvalidException(String invalidTemplate) {
|
||||
super(invalidTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
@@ -12,16 +13,20 @@ import java.util.Locale;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.TrackFilenameGenerator;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
|
||||
public class ImportExportSettingsFragment extends PreferenceFragmentCompat {
|
||||
|
||||
private static final String TAG = ImportExportSettingsFragment.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.settings_import_export);
|
||||
|
||||
setExportTrackFileFormatOptions();
|
||||
setExportDirectorySummary();
|
||||
setFilenameTemplate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,4 +82,19 @@ public class ImportExportSettingsFragment extends PreferenceFragmentCompat {
|
||||
return directoryUri + (directory.canWrite() ? "" : getString(R.string.export_dir_not_writable));
|
||||
});
|
||||
}
|
||||
|
||||
private void setFilenameTemplate() {
|
||||
EditTextPreference preference = findPreference(getString(R.string.export_filename_format_key));
|
||||
preference.setOnBindEditTextListener(t -> {
|
||||
t.setHint(getString(R.string.export_filename_format_default));
|
||||
});
|
||||
preference.setDialogMessage(TrackFilenameGenerator.getAllOptions());
|
||||
|
||||
preference.setOnPreferenceChangeListener((p, newValue) -> new TrackFilenameGenerator(newValue.toString()).isValid());
|
||||
|
||||
preference.setSummaryProvider(p ->
|
||||
PreferencesUtils.getTrackFileformatGenerator()
|
||||
.getExample()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.DistanceFormatter;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.TrackFilenameGenerator;
|
||||
import de.dennisguse.opentracks.ui.customRecordingLayout.CsvLayoutUtils;
|
||||
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
@@ -573,6 +574,16 @@ public class PreferencesUtils {
|
||||
return getBoolean(R.string.post_workout_export_enabled_key, INSTANT_POST_WORKOUT_EXPORT_DEFAULT) && isDefaultExportDirectoryUri();
|
||||
}
|
||||
|
||||
public static TrackFilenameGenerator getTrackFileformatGenerator() {
|
||||
String DEFAULT = getString(R.string.export_filename_format_default, null);
|
||||
TrackFilenameGenerator generator = new TrackFilenameGenerator(getString(R.string.export_filename_format_key, DEFAULT));
|
||||
if (generator.isValid()) {
|
||||
return generator;
|
||||
} else {
|
||||
return new TrackFilenameGenerator(DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
public static TrackFileFormat getExportTrackFileFormat() {
|
||||
final String TRACKFILEFORMAT_NAME_DEFAULT = getString(R.string.export_trackfileformat_default, null);
|
||||
String trackFileFormatName = getString(R.string.export_trackfileformat_key, TRACKFILEFORMAT_NAME_DEFAULT);
|
||||
|
||||
@@ -15,8 +15,8 @@ import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.ShareContentProvider;
|
||||
import de.dennisguse.opentracks.data.models.Marker;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
|
||||
public class ShareUtils {
|
||||
|
||||
@@ -54,8 +54,9 @@ public class ShareUtils {
|
||||
continue;
|
||||
}
|
||||
|
||||
String trackName = FileUtils.sanitizeFileName(track.getName());
|
||||
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackId, trackName, PreferencesUtils.getExportTrackFileFormat());
|
||||
TrackFileFormat format = PreferencesUtils.getExportTrackFileFormat();
|
||||
String trackName = PreferencesUtils.getTrackFileformatGenerator().format(track, format);
|
||||
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackId, trackName, format);
|
||||
|
||||
uris.add(uriAndMime.first);
|
||||
mime = uriAndMime.second;
|
||||
|
||||
@@ -108,7 +108,7 @@ public class ExportUtils {
|
||||
}
|
||||
|
||||
private static Uri getExportDocumentFileUri(Context context, Track track, TrackFileFormat trackFileFormat, DocumentFile directory) {
|
||||
String exportFileName = getExportFileNameForTrack(track, trackFileFormat.getExtension());
|
||||
String exportFileName = PreferencesUtils.getTrackFileformatGenerator().format(track, trackFileFormat);
|
||||
Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName);
|
||||
if (exportDocumentFileUri == null) {
|
||||
final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName);
|
||||
@@ -119,10 +119,6 @@ public class ExportUtils {
|
||||
return exportDocumentFileUri;
|
||||
}
|
||||
|
||||
private static String getExportFileNameForTrack(Track track, String trackFileFormatExtension) {
|
||||
return track.getUuid().toString().substring(0, 8) + "_" + FileUtils.sanitizeFileName(track.getName()) + "." + trackFileFormatExtension;
|
||||
}
|
||||
|
||||
private static Uri findFile(Context context, Uri directoryUri, String exportFileName) {
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(directoryUri, DocumentsContract.getDocumentId(directoryUri));
|
||||
|
||||
Reference in New Issue
Block a user