Export UI first screen initial commit

This commit is contained in:
Vitaliy 2020-11-16 08:25:49 +02:00
parent 21ccac8d78
commit 058c7414f5
15 changed files with 996 additions and 941 deletions

View file

@ -32,34 +32,46 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small">
android:orientation="horizontal">
<FrameLayout
<LinearLayout
android:id="@+id/file_size_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/bottom_sheet_title_padding_bottom"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/bottom_sheet_title_padding_bottom">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/select_button"
android:id="@+id/file_size"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="start|center_vertical"
android:letterSpacing="@dimen/description_letter_spacing"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding_small"
android:text="@string/shared_string_select_all"
android:textColor="?attr/active_color_basic"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Select all" />
osmand:typeface="@string/font_roboto_regular"
tools:text="567 MB" />
</FrameLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/file_size_descr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="start|center_vertical"
android:letterSpacing="@dimen/description_letter_spacing"
android:maxLines="1"
android:text="@string/approximate_file_size"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular" />
</LinearLayout>
<View
android:layout_width="@dimen/content_padding"
@ -68,6 +80,10 @@
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/content_padding_half"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:layout_marginBottom="@dimen/content_padding_half"
android:layout_weight="1"
android:background="?attr/dlg_btn_primary">
@ -79,8 +95,6 @@
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding_small"
android:text="@string/shared_string_continue"
android:textColor="?attr/dlg_btn_primary_text"
android:textSize="@dimen/default_desc_text_size"
@ -95,8 +109,8 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent">
<com.google.android.material.appbar.CollapsingToolbarLayout
@ -104,24 +118,24 @@
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height_expanded"
android:background="?attr/actionModeBackground"
osmand:collapsedTitleTextAppearance="@style/AppBarTitle"
osmand:expandedTitleGravity="start|bottom"
osmand:expandedTitleMarginBottom="@dimen/content_padding_small"
osmand:expandedTitleMarginEnd="@dimen/content_padding"
osmand:expandedTitleMarginStart="@dimen/content_padding"
osmand:collapsedTitleTextAppearance="@style/AppBarTitle"
osmand:expandedTitleGravity="start|bottom"
osmand:expandedTitleTextAppearance="@style/AppBarTitle"
osmand:layout_scrollFlags="scroll|exitUntilCollapsed">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
osmand:titleMarginEnd="0dp"
osmand:titleMarginStart="0dp"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:minHeight="@dimen/toolbar_height"
osmand:layout_collapseMode="pin"
osmand:layout_scrollFlags="scroll|enterAlways|exitUntilCollapsed"
osmand:title="@string/shared_string_import">
osmand:title="@string/shared_string_import"
osmand:titleMarginEnd="0dp"
osmand:titleMarginStart="0dp">
</androidx.appcompat.widget.Toolbar>
@ -132,8 +146,8 @@
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:visibility="gone"
android:indeterminate="true"
android:visibility="gone"
osmand:mpb_progressStyle="horizontal"
osmand:mpb_setBothDrawables="true"
osmand:mpb_useIntrinsicPadding="false"

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -22,7 +22,7 @@
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="66dp"
android:minHeight="@dimen/setting_list_item_large_height"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
@ -72,11 +72,11 @@
<FrameLayout
android:id="@+id/check_box_container"
style="@style/Widget.AppCompat.Toolbar.Button.Navigation"
android:layout_width="@dimen/acceptable_touch_radius"
android:layout_height="@dimen/acceptable_touch_radius"
android:layout_marginEnd="@dimen/text_margin_small"
android:layout_marginRight="@dimen/text_margin_small"
android:background="?attr/selectableItemBackgroundBorderless">
android:layout_marginRight="@dimen/text_margin_small">
<net.osmand.view.ThreeStateCheckbox
android:id="@+id/check_box"

View file

@ -11,6 +11,10 @@
Thx - Hardy
-->
<string name="file_size_needed_for_import">Needed for import</string>
<string name="select_data_to_export">Select the data to be exported to the file.</string>
<string name="approximate_file_size">Approximate file size</string>
<string name="shared_string_resources">Resources</string>
<string name="register_opr_have_account">I already have an account</string>
<string name="register_opr_create_new_account">Create new account</string>
<string name="register_on_openplacereviews_desc">Photos are provided by open data project OpenPlaceReviews.org. In order to upload your photos you need to sign up on website.</string>

View file

@ -2312,7 +2312,7 @@ public class OsmandAidlApi {
File exportDir = app.getSettings().getExternalStorageDirectory();
String fileName = appMode.toHumanString();
SettingsHelper settingsHelper = app.getSettingsHelper();
settingsItems.addAll(settingsHelper.getFilteredSettingsItems(settingsHelper.getAdditionalData(false), settingsTypes));
settingsItems.addAll(settingsHelper.getFilteredSettingsItems(settingsTypes, false));
settingsHelper.exportSettings(exportDir, fileName, null, settingsItems, true);
return true;
}

View file

@ -0,0 +1,22 @@
package net.osmand.plus.settings.backend;
import androidx.annotation.StringRes;
import net.osmand.plus.R;
public enum ExportSettingsCategory {
SETTINGS(R.string.shared_string_settings),
MY_PLACES(R.string.shared_string_my_places),
RESOURCES(R.string.shared_string_resources);
@StringRes
private final int titleId;
ExportSettingsCategory(@StringRes int titleId) {
this.titleId = titleId;
}
public int getTitleId() {
return titleId;
}
}

View file

@ -1,22 +1,61 @@
package net.osmand.plus.settings.backend;
import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes;
import net.osmand.plus.R;
public enum ExportSettingsType {
PROFILE,
QUICK_ACTIONS,
POI_TYPES,
MAP_SOURCES,
CUSTOM_RENDER_STYLE,
CUSTOM_ROUTING,
AVOID_ROADS,
TRACKS,
MULTIMEDIA_NOTES,
GLOBAL,
OSM_NOTES,
OSM_EDITS,
OFFLINE_MAPS,
FAVORITES,
TTS_VOICE,
VOICE,
ACTIVE_MARKERS,
HISTORY_MARKERS
}
PROFILE(R.string.shared_string_profiles, R.drawable.ic_action_manage_profiles),
QUICK_ACTIONS(R.string.configure_screen_quick_action, R.drawable.ic_quick_action),
POI_TYPES(R.string.poi_dialog_poi_type, R.drawable.ic_action_info_dark),
MAP_SOURCES(R.string.quick_action_map_source_title, R.drawable.ic_map),
CUSTOM_RENDER_STYLE(R.string.shared_string_rendering_style, R.drawable.ic_action_map_style),
CUSTOM_ROUTING(R.string.shared_string_routing, R.drawable.ic_action_route_distance),
AVOID_ROADS(R.string.avoid_road, R.drawable.ic_action_alert),
TRACKS(R.string.shared_string_tracks, R.drawable.ic_action_route_distance),
MULTIMEDIA_NOTES(R.string.audionotes_plugin_name, R.drawable.ic_action_photo_dark),
GLOBAL(R.string.general_settings_2, R.drawable.ic_action_settings),
OSM_NOTES(R.string.osm_notes, R.drawable.ic_action_openstreetmap_logo),
OSM_EDITS(R.string.osm_edits, R.drawable.ic_action_openstreetmap_logo),
OFFLINE_MAPS(R.string.shared_string_maps, R.drawable.ic_map),
FAVORITES(R.string.shared_string_favorites, R.drawable.ic_action_favorite),
TTS_VOICE(R.string.local_indexes_cat_tts, R.drawable.ic_action_volume_up),
VOICE(R.string.local_indexes_cat_voice, R.drawable.ic_action_volume_up),
ACTIVE_MARKERS(R.string.map_markers, R.drawable.ic_action_flag),
HISTORY_MARKERS(R.string.markers_history, R.drawable.ic_action_flag);
@StringRes
private final int titleId;
@DrawableRes
private final int drawableRes;
ExportSettingsType(@StringRes int titleId, @DrawableRes int drawableRes) {
this.titleId = titleId;
this.drawableRes = drawableRes;
}
@StringRes
public int getTitleId() {
return titleId;
}
@DrawableRes
public int getIconRes() {
return drawableRes;
}
public boolean isSettingsCategory() {
return this == PROFILE || this == GLOBAL || this == QUICK_ACTIONS || this == POI_TYPES;
}
public boolean isMyPlacesCategory() {
return this == FAVORITES || this == TRACKS || this == OSM_EDITS || this == OSM_NOTES
|| this == MULTIMEDIA_NOTES || this == ACTIVE_MARKERS || this == HISTORY_MARKERS;
}
public boolean isResourcesCategory() {
return this == CUSTOM_RENDER_STYLE || this == CUSTOM_ROUTING || this == MAP_SOURCES
|| this == OFFLINE_MAPS || this == VOICE || this == TTS_VOICE;
}
}

View file

@ -39,7 +39,9 @@ import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.quickaction.QuickActionRegistry;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean;
import net.osmand.plus.settings.backend.ExportSettingsCategory;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.fragments.ExportDataObject;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -52,6 +54,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -465,6 +468,17 @@ public class SettingsHelper {
exportSettings(fileDir, fileName, listener, new ArrayList<>(Arrays.asList(items)), exportItemsFiles);
}
public List<SettingsItem> getFilteredSettingsItems(List<ExportSettingsType> settingsTypes, boolean globalExport) {
Map<ExportSettingsCategory, List<ExportDataObject>> dataList = getAdditionalData(globalExport);
Map<ExportSettingsType, List<?>> typesMap = new HashMap<>();
for (List<ExportDataObject> objects : dataList.values()) {
for (ExportDataObject exportObject : objects) {
typesMap.put(exportObject.getType(), exportObject.getItems());
}
}
return getFilteredSettingsItems(typesMap, settingsTypes);
}
public List<SettingsItem> getFilteredSettingsItems(Map<ExportSettingsType, List<?>> additionalData,
List<ExportSettingsType> settingsTypes) {
List<SettingsItem> settingsItems = new ArrayList<>();
@ -482,20 +496,129 @@ public class SettingsHelper {
return settingsItems;
}
public Map<ExportSettingsType, List<?>> getAdditionalData(boolean globalExport) {
Map<ExportSettingsType, List<?>> dataList = new HashMap<>();
public Map<ExportSettingsCategory, List<ExportDataObject>> getAdditionalData(boolean globalExport) {
Map<ExportSettingsCategory, List<ExportDataObject>> dataList = new LinkedHashMap<>();
List<ExportDataObject> settingsItems = getSettingsItems(globalExport);
List<ExportDataObject> myPlacesItems = getMyPlacesItems();
List<ExportDataObject> resourcesItems = getResourcesItems();
if (!settingsItems.isEmpty()) {
dataList.put(ExportSettingsCategory.SETTINGS, settingsItems);
}
if (!myPlacesItems.isEmpty()) {
dataList.put(ExportSettingsCategory.MY_PLACES, myPlacesItems);
}
if (!resourcesItems.isEmpty()) {
dataList.put(ExportSettingsCategory.RESOURCES, resourcesItems);
}
return dataList;
}
private List<ExportDataObject> getSettingsItems(boolean globalExport) {
List<ExportDataObject> settingsItems = new ArrayList<>();
if (globalExport) {
List<ApplicationModeBean> appModeBeans = new ArrayList<>();
for (ApplicationMode mode : ApplicationMode.allPossibleValues()) {
appModeBeans.add(mode.toModeBean());
}
settingsItems.add(new ExportDataObject(ExportSettingsType.PROFILE, appModeBeans));
}
settingsItems.add(new ExportDataObject(ExportSettingsType.GLOBAL, Collections.singletonList(new GlobalSettingsItem(app.getSettings()))));
QuickActionRegistry registry = app.getQuickActionRegistry();
List<QuickAction> actionsList = registry.getQuickActions();
if (!actionsList.isEmpty()) {
dataList.put(ExportSettingsType.QUICK_ACTIONS, actionsList);
settingsItems.add(new ExportDataObject(ExportSettingsType.QUICK_ACTIONS, actionsList));
}
List<PoiUIFilter> poiList = app.getPoiFilters().getUserDefinedPoiFilters(false);
if (!poiList.isEmpty()) {
dataList.put(ExportSettingsType.POI_TYPES, poiList);
settingsItems.add(new ExportDataObject(ExportSettingsType.POI_TYPES, poiList));
}
return settingsItems;
}
private List<ExportDataObject> getMyPlacesItems() {
List<ExportDataObject> myPlacesItems = new ArrayList<>();
List<FavoriteGroup> favoriteGroups = app.getFavorites().getFavoriteGroups();
if (!favoriteGroups.isEmpty()) {
myPlacesItems.add(new ExportDataObject(ExportSettingsType.FAVORITES, favoriteGroups));
}
File gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
List<GPXInfo> gpxInfoList = GpxUiHelper.getSortedGPXFilesInfo(gpxDir, null, true);
if (!gpxInfoList.isEmpty()) {
List<File> files = new ArrayList<>();
for (GPXInfo gpxInfo : gpxInfoList) {
File file = new File(gpxInfo.getFileName());
if (file.exists()) {
files.add(file);
}
}
if (!files.isEmpty()) {
myPlacesItems.add(new ExportDataObject(ExportSettingsType.TRACKS, files));
}
}
OsmEditingPlugin osmEditingPlugin = OsmandPlugin.getPlugin(OsmEditingPlugin.class);
if (osmEditingPlugin != null) {
List<OsmNotesPoint> notesPointList = osmEditingPlugin.getDBBug().getOsmbugsPoints();
if (!notesPointList.isEmpty()) {
myPlacesItems.add(new ExportDataObject(ExportSettingsType.OSM_NOTES, notesPointList));
}
List<OpenstreetmapPoint> editsPointList = osmEditingPlugin.getDBPOI().getOpenstreetmapPoints();
if (!editsPointList.isEmpty()) {
myPlacesItems.add(new ExportDataObject(ExportSettingsType.OSM_EDITS, editsPointList));
}
}
AudioVideoNotesPlugin plugin = OsmandPlugin.getPlugin(AudioVideoNotesPlugin.class);
if (plugin != null) {
List<File> files = new ArrayList<>();
for (Recording rec : plugin.getAllRecordings()) {
File file = rec.getFile();
if (file != null && file.exists()) {
files.add(file);
}
}
if (!files.isEmpty()) {
myPlacesItems.add(new ExportDataObject(ExportSettingsType.MULTIMEDIA_NOTES, files));
}
}
List<MapMarker> mapMarkers = app.getMapMarkersHelper().getMapMarkersFromDefaultGroups(false);
if (!mapMarkers.isEmpty()) {
String name = app.getString(R.string.map_markers);
String groupId = ExportSettingsType.ACTIVE_MARKERS.name();
MapMarkersGroup markersGroup = new MapMarkersGroup(groupId, name, MapMarkersGroup.ANY_TYPE);
markersGroup.setMarkers(mapMarkers);
myPlacesItems.add(new ExportDataObject(ExportSettingsType.ACTIVE_MARKERS, Collections.singletonList(markersGroup)));
}
List<MapMarker> markersHistory = app.getMapMarkersHelper().getMapMarkersFromDefaultGroups(true);
if (!markersHistory.isEmpty()) {
String name = app.getString(R.string.shared_string_history);
String groupId = ExportSettingsType.HISTORY_MARKERS.name();
MapMarkersGroup markersGroup = new MapMarkersGroup(groupId, name, MapMarkersGroup.ANY_TYPE);
markersGroup.setMarkers(markersHistory);
myPlacesItems.add(new ExportDataObject(ExportSettingsType.HISTORY_MARKERS, Collections.singletonList(markersGroup)));
}
return myPlacesItems;
}
private List<ExportDataObject> getResourcesItems() {
List<ExportDataObject> resourcesItems = new ArrayList<>();
Map<String, File> externalRenderers = app.getRendererRegistry().getExternalRenderers();
if (!externalRenderers.isEmpty()) {
resourcesItems.add(new ExportDataObject(ExportSettingsType.CUSTOM_RENDER_STYLE, new ArrayList<>(externalRenderers.values())));
}
File routingProfilesFolder = app.getAppPath(IndexConstants.ROUTING_PROFILES_DIR);
if (routingProfilesFolder.exists() && routingProfilesFolder.isDirectory()) {
File[] fl = routingProfilesFolder.listFiles();
if (fl != null && fl.length > 0) {
resourcesItems.add(new ExportDataObject(ExportSettingsType.CUSTOM_ROUTING, Arrays.asList(fl)));
}
}
List<ITileSource> iTileSources = new ArrayList<>();
Set<String> tileSourceNames = app.getSettings().getTileSourceEntries(true).keySet();
for (String name : tileSourceNames) {
@ -513,107 +636,29 @@ public class SettingsHelper {
}
}
if (!iTileSources.isEmpty()) {
dataList.put(ExportSettingsType.MAP_SOURCES, iTileSources);
}
Map<String, File> externalRenderers = app.getRendererRegistry().getExternalRenderers();
if (!externalRenderers.isEmpty()) {
dataList.put(ExportSettingsType.CUSTOM_RENDER_STYLE, new ArrayList<>(externalRenderers.values()));
}
File routingProfilesFolder = app.getAppPath(IndexConstants.ROUTING_PROFILES_DIR);
if (routingProfilesFolder.exists() && routingProfilesFolder.isDirectory()) {
File[] fl = routingProfilesFolder.listFiles();
if (fl != null && fl.length > 0) {
dataList.put(ExportSettingsType.CUSTOM_ROUTING, Arrays.asList(fl));
}
}
Map<LatLon, AvoidRoadInfo> impassableRoads = app.getAvoidSpecificRoads().getImpassableRoads();
if (!impassableRoads.isEmpty()) {
dataList.put(ExportSettingsType.AVOID_ROADS, new ArrayList<>(impassableRoads.values()));
}
AudioVideoNotesPlugin plugin = OsmandPlugin.getPlugin(AudioVideoNotesPlugin.class);
if (plugin != null) {
List<File> files = new ArrayList<>();
for (Recording rec : plugin.getAllRecordings()) {
File file = rec.getFile();
if (file != null && file.exists()) {
files.add(file);
}
}
if (!files.isEmpty()) {
dataList.put(ExportSettingsType.MULTIMEDIA_NOTES, files);
}
}
File gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
List<GPXInfo> gpxInfoList = GpxUiHelper.getSortedGPXFilesInfo(gpxDir, null, true);
if (!gpxInfoList.isEmpty()) {
List<File> files = new ArrayList<>();
for (GPXInfo gpxInfo : gpxInfoList) {
File file = new File(gpxInfo.getFileName());
if (file.exists()) {
files.add(file);
}
}
if (!files.isEmpty()) {
dataList.put(ExportSettingsType.TRACKS, files);
}
}
if (globalExport) {
List<ApplicationModeBean> appModeBeans = new ArrayList<>();
for (ApplicationMode mode : ApplicationMode.allPossibleValues()) {
appModeBeans.add(mode.toModeBean());
}
dataList.put(ExportSettingsType.PROFILE, appModeBeans);
}
OsmEditingPlugin osmEditingPlugin = OsmandPlugin.getPlugin(OsmEditingPlugin.class);
if (osmEditingPlugin != null) {
List<OsmNotesPoint> notesPointList = osmEditingPlugin.getDBBug().getOsmbugsPoints();
if (!notesPointList.isEmpty()) {
dataList.put(ExportSettingsType.OSM_NOTES, notesPointList);
}
List<OpenstreetmapPoint> editsPointList = osmEditingPlugin.getDBPOI().getOpenstreetmapPoints();
if (!editsPointList.isEmpty()) {
dataList.put(ExportSettingsType.OSM_EDITS, editsPointList);
}
}
List<FavoriteGroup> favoriteGroups = app.getFavorites().getFavoriteGroups();
if (!favoriteGroups.isEmpty()) {
dataList.put(ExportSettingsType.FAVORITES, favoriteGroups);
resourcesItems.add(new ExportDataObject(ExportSettingsType.MAP_SOURCES, iTileSources));
}
List<LocalIndexInfo> localIndexInfoList = getLocalIndexData();
List<File> files = getFilesByType(localIndexInfoList, LocalIndexType.MAP_DATA, LocalIndexType.TILES_DATA,
LocalIndexType.SRTM_DATA, LocalIndexType.WIKI_DATA);
if (!files.isEmpty()) {
sortLocalFiles(files);
dataList.put(ExportSettingsType.OFFLINE_MAPS, files);
resourcesItems.add(new ExportDataObject(ExportSettingsType.OFFLINE_MAPS, files));
}
files = getFilesByType(localIndexInfoList, LocalIndexType.TTS_VOICE_DATA);
if (!files.isEmpty()) {
dataList.put(ExportSettingsType.TTS_VOICE, files);
resourcesItems.add(new ExportDataObject(ExportSettingsType.TTS_VOICE, files));
}
files = getFilesByType(localIndexInfoList, LocalIndexType.VOICE_DATA);
if (!files.isEmpty()) {
dataList.put(ExportSettingsType.VOICE, files);
resourcesItems.add(new ExportDataObject(ExportSettingsType.VOICE, files));
}
List<MapMarker> mapMarkers = app.getMapMarkersHelper().getMapMarkersFromDefaultGroups(false);
if (!mapMarkers.isEmpty()) {
String name = app.getString(R.string.map_markers);
String groupId = ExportSettingsType.ACTIVE_MARKERS.name();
MapMarkersGroup markersGroup = new MapMarkersGroup(groupId, name, MapMarkersGroup.ANY_TYPE);
markersGroup.setMarkers(mapMarkers);
dataList.put(ExportSettingsType.ACTIVE_MARKERS, Collections.singletonList(markersGroup));
Map<LatLon, AvoidRoadInfo> impassableRoads = app.getAvoidSpecificRoads().getImpassableRoads();
if (!impassableRoads.isEmpty()) {
resourcesItems.add(new ExportDataObject(ExportSettingsType.AVOID_ROADS, new ArrayList<>(impassableRoads.values())));
}
List<MapMarker> markersHistory = app.getMapMarkersHelper().getMapMarkersFromDefaultGroups(true);
if (!markersHistory.isEmpty()) {
String name = app.getString(R.string.shared_string_history);
String groupId = ExportSettingsType.HISTORY_MARKERS.name();
MapMarkersGroup markersGroup = new MapMarkersGroup(groupId, name, MapMarkersGroup.ANY_TYPE);
markersGroup.setMarkers(markersHistory);
dataList.put(ExportSettingsType.HISTORY_MARKERS, Collections.singletonList(markersGroup));
}
return dataList;
return resourcesItems;
}
private List<LocalIndexInfo> getLocalIndexData() {
@ -733,6 +778,37 @@ public class SettingsHelper {
return settingsItems;
}
public static Map<ExportSettingsCategory, List<ExportDataObject>> getSettingsToOperateByCategory(List<SettingsItem> items, boolean importComplete) {
Map<ExportSettingsCategory, List<ExportDataObject>> exportMap = new LinkedHashMap<>();
Map<ExportSettingsType, List<?>> settingsToOperate = getSettingsToOperate(items, importComplete);
List<ExportDataObject> settingsItems = new ArrayList<>();
List<ExportDataObject> myPlacesItems = new ArrayList<>();
List<ExportDataObject> resourcesItems = new ArrayList<>();
for (Map.Entry<ExportSettingsType, List<?>> entry : settingsToOperate.entrySet()) {
ExportSettingsType type = entry.getKey();
if (type.isSettingsCategory()) {
settingsItems.add(new ExportDataObject(type, entry.getValue()));
} else if (type.isMyPlacesCategory()) {
myPlacesItems.add(new ExportDataObject(type, entry.getValue()));
} else if (type.isResourcesCategory()) {
resourcesItems.add(new ExportDataObject(type, entry.getValue()));
}
}
if (!settingsItems.isEmpty()) {
exportMap.put(ExportSettingsCategory.SETTINGS, settingsItems);
}
if (!myPlacesItems.isEmpty()) {
exportMap.put(ExportSettingsCategory.MY_PLACES, myPlacesItems);
}
if (!resourcesItems.isEmpty()) {
exportMap.put(ExportSettingsCategory.RESOURCES, resourcesItems);
}
return exportMap;
}
public static Map<ExportSettingsType, List<?>> getSettingsToOperate(List<SettingsItem> settingsItems, boolean importComplete) {
Map<ExportSettingsType, List<?>> settingsToOperate = new HashMap<>();
List<ApplicationModeBean> profiles = new ArrayList<>();

View file

@ -31,12 +31,9 @@ import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.settings.backend.backup.SettingsHelper;
import net.osmand.plus.settings.backend.backup.SettingsHelper.SettingsCollectListener;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
@ -44,6 +41,9 @@ import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.openseamapsplugin.NauticalMapsPlugin;
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet;
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.backup.SettingsHelper;
import net.osmand.plus.settings.backend.backup.SettingsHelper.SettingsCollectListener;
import net.osmand.plus.settings.backend.backup.SettingsItem;
import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet;
import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet.ResetAppModePrefsListener;
@ -433,10 +433,7 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co
} else if (EXPORT_PROFILE.equals(prefId)) {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) {
ExportProfileBottomSheet.showInstance(
fragmentManager,
this,
getSelectedAppMode(), false);
ExportSettingsFragment.showInstance(fragmentManager, getSelectedAppMode(), false);
}
} else if (DELETE_PROFILE.equals(prefId)) {
onDeleteProfileClick();

View file

@ -0,0 +1,24 @@
package net.osmand.plus.settings.fragments;
import net.osmand.plus.settings.backend.ExportSettingsType;
import java.util.List;
public class ExportDataObject {
private ExportSettingsType type;
private List<?> items;
public ExportDataObject(ExportSettingsType type, List<?> items) {
this.type = type;
this.items = items;
}
public ExportSettingsType getType() {
return type;
}
public List<?> getItems() {
return items;
}
}

View file

@ -4,8 +4,6 @@ import android.content.res.ColorStateList;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@ -13,32 +11,16 @@ import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.map.ITileSource;
import net.osmand.plus.FavouritesDbHelper.FavoriteGroup;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
import net.osmand.plus.audionotes.AudioVideoNotesPlugin;
import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.osmedit.OpenstreetmapPoint;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.osmedit.OsmNotesPoint;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.profiles.ProfileIconColors;
import net.osmand.plus.profiles.RoutingProfileDataObject.RoutingProfilesResources;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.settings.backend.ExportSettingsCategory;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.backup.FileSettingsItem;
import net.osmand.plus.settings.backend.backup.GlobalSettingsItem;
import net.osmand.util.Algorithms;
import net.osmand.view.ThreeStateCheckbox;
import org.apache.commons.logging.Log;
@ -47,11 +29,10 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static net.osmand.plus.settings.backend.ExportSettingsType.OFFLINE_MAPS;
import static net.osmand.plus.settings.backend.backup.FileSettingsItem.FileSubtype;
import static net.osmand.view.ThreeStateCheckbox.State.CHECKED;
import static net.osmand.view.ThreeStateCheckbox.State.MISC;
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
@ -59,91 +40,94 @@ import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
private static final Log LOG = PlatformUtil.getLog(ExportImportSettingsAdapter.class.getName());
private OsmandApplication app;
private UiUtilities uiUtilities;
private List<? super Object> data;
private Map<ExportSettingsType, List<?>> itemsMap;
private List<ExportSettingsType> itemsTypes;
private boolean nightMode;
private boolean importState;
private int activeColorRes;
private int secondaryColorRes;
ExportImportSettingsAdapter(OsmandApplication app, boolean nightMode, boolean importState) {
private final OsmandApplication app;
private final UiUtilities uiUtilities;
private List<ExportSettingsCategory> itemsTypes = new ArrayList<>();
private Map<ExportSettingsType, List<Object>> selectedItemsMap = new HashMap<>();
private Map<ExportSettingsCategory, List<ExportDataObject>> itemsMap = new LinkedHashMap<>();
private final OnItemSelectedListener listener;
private final LayoutInflater themedInflater;
private final boolean nightMode;
private final int activeColorRes;
private final int secondaryColorRes;
ExportImportSettingsAdapter(OsmandApplication app, OnItemSelectedListener listener, boolean nightMode) {
this.app = app;
this.listener = listener;
this.nightMode = nightMode;
this.importState = importState;
this.itemsMap = new HashMap<>();
this.itemsTypes = new ArrayList<>();
this.data = new ArrayList<>();
uiUtilities = app.getUIUtilities();
activeColorRes = nightMode
? R.color.icon_color_active_dark
: R.color.icon_color_active_light;
secondaryColorRes = nightMode
? R.color.icon_color_secondary_dark
: R.color.icon_color_secondary_light;
themedInflater = UiUtilities.getInflater(app, nightMode);
activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View group = convertView;
if (group == null) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
group = inflater.inflate(R.layout.profile_data_list_item_group, parent, false);
group = themedInflater.inflate(R.layout.profile_data_list_item_group, parent, false);
}
final ExportSettingsCategory category = itemsTypes.get(groupPosition);
final List<ExportDataObject> items = itemsMap.get(category);
boolean isLastGroup = groupPosition == getGroupCount() - 1;
final ExportSettingsType type = itemsTypes.get(groupPosition);
String title = app.getString(category.getTitleId());
TextView titleTv = group.findViewById(R.id.title_tv);
titleTv.setText(UiUtilities.createCustomFontSpannable(FontCache.getRobotoMedium(app), title, title));
TextView subTextTv = group.findViewById(R.id.sub_text_tv);
final ThreeStateCheckbox checkBox = group.findViewById(R.id.check_box);
FrameLayout checkBoxContainer = group.findViewById(R.id.check_box_container);
ImageView expandIv = group.findViewById(R.id.explist_indicator);
View lineDivider = group.findViewById(R.id.divider);
View cardTopDivider = group.findViewById(R.id.card_top_divider);
View cardBottomDivider = group.findViewById(R.id.card_bottom_divider);
subTextTv.setText(getCategoryDescr(category));
titleTv.setText(getGroupTitle(type));
lineDivider.setVisibility(importState || isExpanded || isLastGroup ? View.GONE : View.VISIBLE);
cardTopDivider.setVisibility(importState ? View.VISIBLE : View.GONE);
cardBottomDivider.setVisibility(importState && !isExpanded ? View.VISIBLE : View.GONE);
final List<?> listItems = itemsMap.get(type);
subTextTv.setText(getSelectedItemsAmount(listItems, type));
if (data.containsAll(listItems)) {
checkBox.setState(CHECKED);
} else {
boolean contains = false;
for (Object object : listItems) {
if (data.contains(object)) {
contains = true;
break;
}
int selectedTypes = 0;
for (int i = 0; i < items.size(); i++) {
ExportDataObject object = items.get(i);
if (selectedItemsMap.containsKey(object.getType())) {
selectedTypes++;
}
checkBox.setState(contains ? MISC : UNCHECKED);
}
final ThreeStateCheckbox checkBox = group.findViewById(R.id.check_box);
if (selectedTypes == 0) {
checkBox.setState(UNCHECKED);
} else {
checkBox.setState(selectedTypes == items.size() ? CHECKED : MISC);
}
int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes;
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor)));
checkBoxContainer.setOnClickListener(new View.OnClickListener() {
group.findViewById(R.id.check_box_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkBox.performClick();
if (checkBox.getState() == CHECKED) {
for (Object object : listItems) {
if (!data.contains(object)) {
data.add(object);
boolean selected = checkBox.getState() == CHECKED;
if (selected) {
for (ExportDataObject object : items) {
if (!selectedItemsMap.containsKey(object.getType())) {
selectedItemsMap.put(object.getType(), (List<Object>) object.getItems());
}
}
} else {
data.removeAll(listItems);
for (ExportDataObject object : items) {
selectedItemsMap.remove(object.getType());
}
}
if (listener != null) {
listener.onCategorySelected(category, selected);
}
notifyDataSetChanged();
}
});
adjustIndicator(app, groupPosition, isExpanded, group, nightMode);
AndroidUiHelper.updateVisibility(group.findViewById(R.id.divider), isExpanded);
AndroidUiHelper.updateVisibility(group.findViewById(R.id.card_top_divider), true);
AndroidUiHelper.updateVisibility(group.findViewById(R.id.vertical_divider), false);
AndroidUiHelper.updateVisibility(group.findViewById(R.id.card_bottom_divider), !isExpanded);
return group;
}
@ -151,168 +135,57 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View child = convertView;
if (child == null) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
child = inflater.inflate(R.layout.profile_data_list_item_child, parent, false);
child = themedInflater.inflate(R.layout.profile_data_list_item_group, parent, false);
}
final Object currentItem = itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition);
final ExportDataObject currentItem = itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition);
List<Object> selectedItems = selectedItemsMap.get(currentItem.getType());
boolean isLastGroup = groupPosition == getGroupCount() - 1;
boolean itemSelected = data.contains(currentItem);
final ExportSettingsType type = itemsTypes.get(groupPosition);
TextView titleTv = child.findViewById(R.id.title_tv);
titleTv.setText(currentItem.getType().getTitleId());
TextView title = child.findViewById(R.id.title_tv);
TextView subText = child.findViewById(R.id.sub_title_tv);
subText.setVisibility(View.GONE);
final CheckBox checkBox = child.findViewById(R.id.check_box);
ImageView icon = child.findViewById(R.id.icon);
View lineDivider = child.findViewById(R.id.divider);
View cardBottomDivider = child.findViewById(R.id.card_bottom_divider);
TextView subTextTv = child.findViewById(R.id.sub_text_tv);
subTextTv.setText(getSelectedTypeDescr(currentItem));
lineDivider.setVisibility(!importState && isLastChild && !isLastGroup ? View.VISIBLE : View.GONE);
cardBottomDivider.setVisibility(importState && isLastChild ? View.VISIBLE : View.GONE);
int checkBoxColor = itemSelected ? activeColorRes : secondaryColorRes;
ImageView icon = child.findViewById(R.id.explist_indicator);
setupIcon(icon, currentItem.getType().getIconRes(), selectedItems != null);
final ThreeStateCheckbox checkBox = child.findViewById(R.id.check_box);
if (selectedItems == null) {
checkBox.setState(UNCHECKED);
} else if (selectedItems.containsAll(currentItem.getItems())) {
checkBox.setState(CHECKED);
} else {
boolean contains = false;
for (Object object : currentItem.getItems()) {
if (selectedItems.contains(object)) {
contains = true;
break;
}
}
checkBox.setState(contains ? MISC : UNCHECKED);
}
int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes;
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor)));
checkBox.setChecked(itemSelected);
checkBox.setClickable(false);
child.setOnClickListener(new View.OnClickListener() {
child.findViewById(R.id.check_box_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (data.contains(currentItem)) {
data.remove(currentItem);
checkBox.performClick();
boolean selected = checkBox.getState() == CHECKED;
if (selected) {
selectedItemsMap.put(currentItem.getType(), (List<Object>) currentItem.getItems());
} else {
data.add(currentItem);
selectedItemsMap.remove(currentItem.getType());
}
if (listener != null) {
listener.onTypeSelected(currentItem.getType(), selected);
}
notifyDataSetChanged();
}
});
switch (type) {
case PROFILE:
ApplicationModeBean modeBean = (ApplicationModeBean) currentItem;
String profileName = modeBean.userProfileName;
if (Algorithms.isEmpty(profileName)) {
ApplicationMode appMode = ApplicationMode.valueOfStringKey(modeBean.stringKey, null);
profileName = app.getString(appMode.getNameKeyResource());
}
title.setText(profileName);
String routingProfile = "";
String routingProfileValue = modeBean.routingProfile;
if (!routingProfileValue.isEmpty()) {
try {
routingProfile = app.getString(RoutingProfilesResources.valueOf(routingProfileValue.toUpperCase()).getStringRes());
routingProfile = Algorithms.capitalizeFirstLetterAndLowercase(routingProfile);
} catch (IllegalArgumentException e) {
routingProfile = Algorithms.capitalizeFirstLetterAndLowercase(routingProfileValue);
LOG.error("Error trying to get routing resource for " + routingProfileValue + "\n" + e);
}
}
if (!Algorithms.isEmpty(routingProfile)) {
subText.setText(String.format(
app.getString(R.string.ltr_or_rtl_combine_via_colon),
app.getString(R.string.nav_type_hint),
routingProfile));
subText.setVisibility(View.VISIBLE);
}
int profileIconRes = AndroidUtils.getDrawableId(app, modeBean.iconName);
ProfileIconColors iconColor = modeBean.iconColor;
icon.setImageDrawable(uiUtilities.getIcon(profileIconRes, iconColor.getColor(nightMode)));
break;
case QUICK_ACTIONS:
title.setText(((QuickAction) currentItem).getName(app.getApplicationContext()));
setupIcon(icon, ((QuickAction) currentItem).getIconRes(), itemSelected);
break;
case POI_TYPES:
title.setText(((PoiUIFilter) currentItem).getName());
int iconRes = RenderingIcons.getBigIconResourceId(((PoiUIFilter) currentItem).getIconId());
setupIcon(icon, iconRes != 0 ? iconRes : R.drawable.ic_action_user, itemSelected);
break;
case MAP_SOURCES:
title.setText(((ITileSource) currentItem).getName());
setupIcon(icon, R.drawable.ic_map, itemSelected);
break;
case CUSTOM_RENDER_STYLE:
String renderName = ((File) currentItem).getName();
renderName = renderName.replace('_', ' ').replaceAll(IndexConstants.RENDERER_INDEX_EXT, "");
title.setText(renderName);
setupIcon(icon, R.drawable.ic_action_map_style, itemSelected);
break;
case CUSTOM_ROUTING:
String routingName = ((File) currentItem).getName();
routingName = routingName.replace('_', ' ').replaceAll(".xml", "");
title.setText(routingName);
setupIcon(icon, R.drawable.ic_action_route_distance, itemSelected);
break;
case AVOID_ROADS:
AvoidRoadInfo avoidRoadInfo = (AvoidRoadInfo) currentItem;
title.setText(avoidRoadInfo.name);
setupIcon(icon, R.drawable.ic_action_alert, itemSelected);
break;
case MULTIMEDIA_NOTES:
File file = (File) currentItem;
title.setText(file.getName());
int iconId = AudioVideoNotesPlugin.getIconIdForRecordingFile(file);
if (iconId == -1) {
iconId = R.drawable.ic_action_photo_dark;
}
setupIcon(icon, iconId, itemSelected);
break;
case TRACKS:
String fileName = ((File) currentItem).getName();
title.setText(GpxUiHelper.getGpxTitle(fileName));
setupIcon(icon, R.drawable.ic_action_route_distance, itemSelected);
break;
case GLOBAL:
String name = ((GlobalSettingsItem) currentItem).getPublicName(app);
title.setText(name);
setupIcon(icon, R.drawable.ic_action_settings, itemSelected);
break;
case OSM_NOTES:
title.setText(((OsmNotesPoint) currentItem).getText());
setupIcon(icon, R.drawable.ic_action_osm_note_add, itemSelected);
break;
case OSM_EDITS:
title.setText(OsmEditingPlugin.getTitle((OpenstreetmapPoint) currentItem, app));
setupIcon(icon, R.drawable.ic_action_info_dark, itemSelected);
break;
case OFFLINE_MAPS:
long size;
if (currentItem instanceof FileSettingsItem) {
FileSettingsItem currentFileItem = (FileSettingsItem) currentItem;
file = currentFileItem.getFile();
size = currentFileItem.getSize();
} else {
file = (File) currentItem;
size = file.length();
}
title.setText(FileNameTranslationHelper.getFileNameWithRegion(app, file.getName()));
FileSubtype subtype = FileSubtype.getSubtypeByPath(app, file.getPath());
setupIcon(icon, subtype.getIconId(), itemSelected);
subText.setText(AndroidUtils.formatSize(app, size));
subText.setVisibility(View.VISIBLE);
break;
case FAVORITES:
FavoriteGroup favoriteGroup = (FavoriteGroup) currentItem;
title.setText(favoriteGroup.getDisplayName(app));
setupIcon(icon, R.drawable.ic_action_favorite, itemSelected);
break;
case TTS_VOICE:
case VOICE:
file = (File) currentItem;
title.setText(FileNameTranslationHelper.getFileNameWithRegion(app, file.getName()));
setupIcon(icon, R.drawable.ic_action_volume_up, itemSelected);
break;
case ACTIVE_MARKERS:
title.setText(R.string.map_markers);
setupIcon(icon, R.drawable.ic_action_flag, itemSelected);
break;
case HISTORY_MARKERS:
title.setText(R.string.markers_history);
setupIcon(icon, R.drawable.ic_action_flag, itemSelected);
break;
default:
return child;
}
AndroidUiHelper.updateVisibility(child.findViewById(R.id.card_bottom_divider), isLastChild);
return child;
}
@ -356,78 +229,16 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
return true;
}
private String getSelectedItemsAmount(List<?> listItems, ExportSettingsType type) {
int amount = 0;
long amountSize = 0;
for (Object item : listItems) {
if (data.contains(item)) {
amount++;
if (type == OFFLINE_MAPS) {
if (item instanceof FileSettingsItem) {
amountSize += ((FileSettingsItem) item).getSize();
} else {
amountSize += ((File) item).length();
}
}
}
}
String itemsOf = app.getString(R.string.n_items_of_z, String.valueOf(amount), String.valueOf(listItems.size()));
return amountSize == 0 ? itemsOf : app.getString(R.string.ltr_or_rtl_combine_via_bold_point, itemsOf,
AndroidUtils.formatSize(app, amountSize));
}
private int getGroupTitle(ExportSettingsType type) {
switch (type) {
case PROFILE:
return R.string.shared_string_profiles;
case QUICK_ACTIONS:
return R.string.configure_screen_quick_action;
case POI_TYPES:
return R.string.poi_dialog_poi_type;
case MAP_SOURCES:
return R.string.quick_action_map_source_title;
case CUSTOM_RENDER_STYLE:
return R.string.shared_string_rendering_style;
case CUSTOM_ROUTING:
return R.string.shared_string_routing;
case AVOID_ROADS:
return R.string.avoid_road;
case TRACKS:
return R.string.shared_string_tracks;
case MULTIMEDIA_NOTES:
return R.string.audionotes_plugin_name;
case GLOBAL:
return R.string.general_settings_2;
case OSM_NOTES:
return R.string.osm_notes;
case OSM_EDITS:
return R.string.osm_edits;
case OFFLINE_MAPS:
return R.string.shared_string_maps;
case FAVORITES:
return R.string.shared_string_favorites;
case TTS_VOICE:
return R.string.local_indexes_cat_tts;
case VOICE:
return R.string.local_indexes_cat_voice;
case ACTIVE_MARKERS:
return R.string.map_markers;
case HISTORY_MARKERS:
return R.string.markers_history;
default:
return R.string.access_empty_list;
}
}
private void setupIcon(ImageView icon, int iconRes, boolean itemSelected) {
if (itemSelected) {
icon.setImageDrawable(uiUtilities.getIcon(iconRes, activeColorRes));
int colorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_osmand_light;
icon.setImageDrawable(uiUtilities.getIcon(iconRes, colorRes));
} else {
icon.setImageDrawable(uiUtilities.getIcon(iconRes, nightMode));
icon.setImageDrawable(uiUtilities.getIcon(iconRes, secondaryColorRes));
}
}
public void updateSettingsList(Map<ExportSettingsType, List<?>> itemsMap) {
public void updateSettingsList(Map<ExportSettingsCategory, List<ExportDataObject>> itemsMap) {
this.itemsMap = itemsMap;
this.itemsTypes = new ArrayList<>(itemsMap.keySet());
Collections.sort(itemsTypes);
@ -440,17 +251,90 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
notifyDataSetChanged();
}
public void selectAll(boolean selectAll) {
data.clear();
if (selectAll) {
for (List<?> values : itemsMap.values()) {
data.addAll(values);
}
public List<? super Object> getData() {
List<Object> selectedItems = new ArrayList<>();
for (List<?> items : selectedItemsMap.values()) {
selectedItems.addAll(items);
}
notifyDataSetChanged();
return selectedItems;
}
List<? super Object> getData() {
return this.data;
private String getCategoryDescr(ExportSettingsCategory category) {
long itemsSize = 0;
int selectedTypes = 0;
List<ExportDataObject> items = itemsMap.get(category);
for (int i = 0; i < items.size(); i++) {
ExportDataObject object = items.get(i);
if (selectedItemsMap.containsKey(object.getType())) {
selectedTypes++;
itemsSize += calculateItemsSize(object.getItems());
}
}
String description;
if (selectedTypes == 0) {
description = app.getString(R.string.shared_string_none);
} else if (selectedTypes == items.size()) {
description = app.getString(R.string.shared_string_all);
} else {
description = app.getString(R.string.ltr_or_rtl_combine_via_slash, String.valueOf(selectedTypes), String.valueOf(items.size()));
}
String formattedSize = AndroidUtils.formatSize(app, itemsSize);
return itemsSize == 0 ? description : app.getString(R.string.ltr_or_rtl_combine_via_comma, description, formattedSize);
}
public static long calculateItemsSize(List<?> items) {
long itemsSize = 0;
for (Object item : items) {
if (item instanceof FileSettingsItem) {
itemsSize += ((FileSettingsItem) item).getSize();
} else if (item instanceof File) {
itemsSize += ((File) item).length();
}
}
return itemsSize;
}
private String getSelectedTypeDescr(ExportDataObject dataObject) {
long itemsSize = 0;
int selectedTypes = 0;
List<?> items = dataObject.getItems();
List<Object> selectedItems = selectedItemsMap.get(dataObject.getType());
if (selectedItems != null) {
for (int i = 0; i < items.size(); i++) {
Object object = items.get(i);
if (selectedItems.contains(object)) {
selectedTypes++;
if (object instanceof FileSettingsItem) {
itemsSize += ((FileSettingsItem) object).getSize();
} else if (object instanceof File) {
itemsSize += ((File) object).length();
}
}
}
}
String description;
if (selectedTypes == 0) {
description = app.getString(R.string.shared_string_none);
} else if (selectedTypes == items.size()) {
description = app.getString(R.string.shared_string_all);
if (itemsSize == 0) {
description = app.getString(R.string.ltr_or_rtl_combine_via_comma, description, String.valueOf(items.size()));
}
} else {
description = app.getString(R.string.ltr_or_rtl_combine_via_slash, String.valueOf(selectedTypes), String.valueOf(items.size()));
}
String formattedSize = AndroidUtils.formatSize(app, itemsSize);
return itemsSize == 0 ? description : app.getString(R.string.ltr_or_rtl_combine_via_comma, description, formattedSize);
}
interface OnItemSelectedListener {
void onCategorySelected(ExportSettingsCategory type, boolean selected);
void onTypeSelected(ExportSettingsType type, boolean selected);
}
}

View file

@ -1,429 +0,0 @@
package net.osmand.plus.settings.fragments;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.FileUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.backup.FileSettingsItem;
import net.osmand.plus.settings.backend.backup.GlobalSettingsItem;
import net.osmand.plus.settings.backend.backup.ProfileSettingsItem;
import net.osmand.plus.settings.backend.backup.SettingsHelper.SettingsExportListener;
import net.osmand.plus.settings.backend.backup.SettingsItem;
import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet;
import org.apache.commons.logging.Log;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class ExportProfileBottomSheet extends BasePreferenceBottomSheet {
public static final String TAG = ExportProfileBottomSheet.class.getSimpleName();
private static final Log LOG = PlatformUtil.getLog(ExportProfileBottomSheet.class);
private static final String GLOBAL_EXPORT_KEY = "global_export_key";
private static final String EXPORT_START_TIME_KEY = "export_start_time_key";
private static final String EXPORTING_PROFILE_KEY = "exporting_profile_key";
private static final String INCLUDE_ADDITIONAL_DATA_KEY = "include_additional_data_key";
private static final String INCLUDE_GLOBAL_SETTINGS_KEY = "include_global_settings_key";
private static final String PROGRESS_MAX_KEY = "progress_max_key";
private static final String PROGRESS_VALUE_KEY = "progress_value_key";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yy", Locale.US);
private OsmandApplication app;
private Map<ExportSettingsType, List<?>> dataList = new HashMap<>();
private ExportImportSettingsAdapter adapter;
private SettingsExportListener exportListener;
private ProgressDialog progress;
private int progressMax;
private int progressValue;
private long exportStartTime;
private boolean globalExport = false;
private boolean exportingProfile = false;
private boolean includeAdditionalData = false;
private boolean includeGlobalSettings = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = requiredMyApplication();
if (savedInstanceState != null) {
globalExport = savedInstanceState.getBoolean(GLOBAL_EXPORT_KEY);
exportingProfile = savedInstanceState.getBoolean(EXPORTING_PROFILE_KEY);
includeAdditionalData = savedInstanceState.getBoolean(INCLUDE_ADDITIONAL_DATA_KEY);
includeGlobalSettings = savedInstanceState.getBoolean(INCLUDE_GLOBAL_SETTINGS_KEY);
exportStartTime = savedInstanceState.getLong(EXPORT_START_TIME_KEY);
progressMax = savedInstanceState.getInt(PROGRESS_MAX_KEY);
progressValue = savedInstanceState.getInt(PROGRESS_VALUE_KEY);
}
dataList = app.getSettingsHelper().getAdditionalData(globalExport);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(GLOBAL_EXPORT_KEY, globalExport);
outState.putBoolean(EXPORTING_PROFILE_KEY, exportingProfile);
outState.putBoolean(INCLUDE_ADDITIONAL_DATA_KEY, includeAdditionalData);
outState.putBoolean(INCLUDE_GLOBAL_SETTINGS_KEY, includeGlobalSettings);
outState.putLong(EXPORT_START_TIME_KEY, exportStartTime);
outState.putInt(PROGRESS_MAX_KEY, progress.getMax());
outState.putInt(PROGRESS_VALUE_KEY, progress.getProgress());
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
final Context context = getContext();
if (context == null) {
return;
}
if (globalExport) {
items.add(new TitleItem(getString(R.string.shared_string_export)));
final BottomSheetItemWithCompoundButton[] globalSettingsItem = new BottomSheetItemWithCompoundButton[1];
globalSettingsItem[0] = (BottomSheetItemWithCompoundButton) new BottomSheetItemWithCompoundButton.Builder()
.setChecked(includeGlobalSettings)
.setTitle(getString(R.string.general_settings_2))
.setLayoutId(R.layout.bottom_sheet_item_with_switch_no_icon)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = !globalSettingsItem[0].isChecked();
globalSettingsItem[0].setChecked(checked);
includeGlobalSettings = checked;
}
})
.create();
items.add(globalSettingsItem[0]);
} else {
items.add(new TitleItem(getString(R.string.export_profile)));
ApplicationMode profile = getAppMode();
int profileColor = profile.getIconColorInfo().getColor(nightMode);
int colorNoAlpha = ContextCompat.getColor(context, profileColor);
Drawable backgroundIcon = UiUtilities.getColoredSelectableDrawable(context, colorNoAlpha, 0.3f);
Drawable[] layers = {new ColorDrawable(UiUtilities.getColorWithAlpha(colorNoAlpha, 0.10f)), backgroundIcon};
BaseBottomSheetItem profileItem = new BottomSheetItemWithCompoundButton.Builder()
.setChecked(true)
.setCompoundButtonColorId(profileColor)
.setButtonTintList(ColorStateList.valueOf(getResolvedColor(profileColor)))
.setDescription(BaseSettingsFragment.getAppModeDescription(context, profile))
.setIcon(getIcon(profile.getIconRes(), profileColor))
.setTitle(profile.toHumanString())
.setBackground(new LayerDrawable(layers))
.setLayoutId(R.layout.preference_profile_item_with_radio_btn)
.create();
items.add(profileItem);
}
setupAdditionalItems();
}
private void setupAdditionalItems() {
if (!dataList.isEmpty()) {
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
View additionalDataView = inflater.inflate(R.layout.bottom_sheet_item_additional_data, null);
ExpandableListView listView = additionalDataView.findViewById(R.id.list);
adapter = new ExportImportSettingsAdapter(app, nightMode, false);
View listHeader = inflater.inflate(R.layout.item_header_export_expand_list, null);
final View topSwitchDivider = listHeader.findViewById(R.id.topSwitchDivider);
final View bottomSwitchDivider = listHeader.findViewById(R.id.bottomSwitchDivider);
final SwitchCompat switchItem = listHeader.findViewById(R.id.switchItem);
switchItem.setTextColor(getResources().getColor(nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light));
switchItem.setChecked(includeAdditionalData);
switchItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
includeAdditionalData = !includeAdditionalData;
topSwitchDivider.setVisibility(includeAdditionalData ? View.VISIBLE : View.GONE);
bottomSwitchDivider.setVisibility(includeAdditionalData ? View.VISIBLE : View.GONE);
if (includeAdditionalData) {
adapter.updateSettingsList(app.getSettingsHelper().getAdditionalData(globalExport));
adapter.selectAll(true);
} else {
adapter.selectAll(false);
adapter.clearSettingsList();
}
updateSwitch(switchItem);
setupHeightAndBackground(getView());
}
});
listView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int i) {
setupHeightAndBackground(getView());
}
});
updateSwitch(switchItem);
listView.addHeaderView(listHeader);
listView.setAdapter(adapter);
final SimpleBottomSheetItem titleItem = (SimpleBottomSheetItem) new SimpleBottomSheetItem.Builder()
.setCustomView(additionalDataView)
.create();
items.add(titleItem);
}
}
private void updateSwitch(View view) {
if (includeAdditionalData) {
UiUtilities.setMargins(view, 0, 0, 0, 0);
view.setPadding(AndroidUtils.dpToPx(app, 32), 0, AndroidUtils.dpToPx(app, 32), 0);
} else {
UiUtilities.setMargins(view, AndroidUtils.dpToPx(app, 16), 0, AndroidUtils.dpToPx(app, 16), 0);
view.setPadding(AndroidUtils.dpToPx(app, 16), 0, AndroidUtils.dpToPx(app, 16), 0);
}
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.shared_string_export;
}
@Override
protected void onRightBottomButtonClick() {
prepareFile();
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_cancel;
}
@Override
protected boolean useScrollableItemsContainer() {
return false;
}
@Override
protected boolean useExpandableList() {
return true;
}
@Override
public void onResume() {
super.onResume();
checkExportingFile();
}
@Override
public void onPause() {
super.onPause();
if (exportingProfile) {
File file = getExportFile();
app.getSettingsHelper().updateExportListener(file, null);
}
}
private void setGlobalExport(boolean globalExport) {
this.globalExport = globalExport;
}
private List<SettingsItem> prepareSettingsItemsForExport() {
List<SettingsItem> settingsItems = new ArrayList<>();
if (!globalExport) {
settingsItems.add(new ProfileSettingsItem(app, getAppMode()));
}
if (includeGlobalSettings) {
settingsItems.add(new GlobalSettingsItem(app.getSettings()));
}
if (includeAdditionalData) {
settingsItems.addAll(app.getSettingsHelper().prepareAdditionalSettingsItems(adapter.getData()));
}
return settingsItems;
}
private void prepareFile() {
if (app != null) {
exportingProfile = true;
exportStartTime = System.currentTimeMillis();
showExportProgressDialog();
File tempDir = FileUtils.getTempDir(app);
String fileName = getFileName();
List<SettingsItem> items = prepareSettingsItemsForExport();
progress.setMax(getMaxProgress(items));
app.getSettingsHelper().exportSettings(tempDir, fileName, getSettingsExportListener(), items, true);
}
}
private int getMaxProgress(List<SettingsItem> items) {
long maxProgress = 0;
for (SettingsItem item : items) {
if (item instanceof FileSettingsItem) {
maxProgress += ((FileSettingsItem) item).getSize();
}
}
return (int) maxProgress / (1 << 20);
}
private String getFileName() {
if (globalExport) {
if (exportStartTime == 0) {
exportStartTime = System.currentTimeMillis();
}
return "Export_" + DATE_FORMAT.format(new Date(exportStartTime));
} else {
return getAppMode().toHumanString();
}
}
private void showExportProgressDialog() {
Context context = getContext();
if (context == null) {
return;
}
if (progress != null) {
progress.dismiss();
}
progress = new ProgressDialog(context);
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setCancelable(true);
progress.setTitle(app.getString(R.string.shared_string_export));
progress.setMessage(app.getString(R.string.shared_string_preparing));
progress.setButton(DialogInterface.BUTTON_NEGATIVE, app.getString(R.string.shared_string_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
cancelExport();
}
});
progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
cancelExport();
}
});
progress.show();
}
private void cancelExport() {
app.getSettingsHelper().cancelExportForFile(getExportFile());
progress.dismiss();
dismiss();
}
private SettingsExportListener getSettingsExportListener() {
if (exportListener == null) {
exportListener = new SettingsExportListener() {
@Override
public void onSettingsExportFinished(@NonNull File file, boolean succeed) {
dismissExportProgressDialog();
exportingProfile = false;
if (succeed) {
shareProfile(file);
} else {
app.showToastMessage(R.string.export_profile_failed);
}
}
@Override
public void onSettingsExportProgressUpdate(int value) {
progress.setProgress(value);
}
};
}
return exportListener;
}
private void checkExportingFile() {
if (exportingProfile) {
File file = getExportFile();
boolean fileExporting = app.getSettingsHelper().isFileExporting(file);
if (fileExporting) {
showExportProgressDialog();
progress.setMax(progressMax);
progress.setProgress(progressValue);
app.getSettingsHelper().updateExportListener(file, getSettingsExportListener());
} else if (file.exists()) {
dismissExportProgressDialog();
shareProfile(file);
}
}
}
private void dismissExportProgressDialog() {
FragmentActivity activity = getActivity();
if (progress != null && activity != null && AndroidUtils.isActivityNotDestroyed(activity)) {
progress.dismiss();
}
}
private File getExportFile() {
File tempDir = FileUtils.getTempDir(app);
String fileName = getFileName();
return new File(tempDir, fileName + IndexConstants.OSMAND_SETTINGS_FILE_EXT);
}
private void shareProfile(@NonNull File file) {
try {
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, file.getName());
sendIntent.putExtra(Intent.EXTRA_STREAM, AndroidUtils.getUriForFile(getMyApplication(), file));
sendIntent.setType("*/*");
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(sendIntent);
dismiss();
} catch (Exception e) {
Toast.makeText(requireContext(), R.string.export_profile_failed, Toast.LENGTH_SHORT).show();
LOG.error("Share profile error", e);
}
}
public static boolean showInstance(@NonNull FragmentManager fragmentManager,
Fragment target, @NonNull ApplicationMode appMode,
boolean globalExport) {
try {
ExportProfileBottomSheet fragment = new ExportProfileBottomSheet();
fragment.setAppMode(appMode);
fragment.setGlobalExport(globalExport);
fragment.setTargetFragment(target, 0);
fragment.show(fragmentManager, TAG);
return true;
} catch (RuntimeException e) {
return false;
}
}
}

View file

@ -0,0 +1,405 @@
package net.osmand.plus.settings.fragments;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ExpandableListView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import net.osmand.AndroidUtils;
import net.osmand.FileUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.ExportSettingsCategory;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.backup.FileSettingsItem;
import net.osmand.plus.settings.backend.backup.SettingsHelper.SettingsExportListener;
import net.osmand.plus.settings.backend.backup.SettingsItem;
import net.osmand.plus.settings.fragments.ExportImportSettingsAdapter.OnItemSelectedListener;
import net.osmand.plus.widgets.TextViewEx;
import org.apache.commons.logging.Log;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static net.osmand.plus.settings.fragments.BaseSettingsFragment.APP_MODE_KEY;
public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItemSelectedListener {
public static final String TAG = ImportSettingsFragment.class.getSimpleName();
public static final Log LOG = PlatformUtil.getLog(ImportSettingsFragment.class.getSimpleName());
private static final String EXPORT_SETTINGS_TAG = "import_settings_tag";
private static final String GLOBAL_EXPORT_KEY = "global_export_key";
private static final String EXPORT_START_TIME_KEY = "export_start_time_key";
private static final String EXPORTING_STARTED_KEY = "exporting_started_key";
private static final String INCLUDE_ADDITIONAL_DATA_KEY = "include_additional_data_key";
private static final String INCLUDE_GLOBAL_SETTINGS_KEY = "include_global_settings_key";
private static final String PROGRESS_MAX_KEY = "progress_max_key";
private static final String PROGRESS_VALUE_KEY = "progress_value_key";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yy", Locale.US);
private OsmandApplication app;
private Map<ExportSettingsCategory, List<ExportDataObject>> dataList;
private ProgressDialog progress;
private ApplicationMode appMode;
private SettingsExportListener exportListener;
private TextViewEx fileSize;
private LinearLayout buttonsContainer;
private ExpandableListView expandableList;
private ExportImportSettingsAdapter adapter;
private int progressMax;
private int progressValue;
private long exportStartTime;
private boolean nightMode;
private boolean globalExport;
private boolean exportingStarted;
@Override
public int getStatusBarColorId() {
return nightMode ? R.color.status_bar_color_dark : R.color.status_bar_color_light;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = requireMyApplication();
nightMode = !app.getSettings().isLightContent();
if (savedInstanceState != null) {
appMode = ApplicationMode.valueOfStringKey(savedInstanceState.getString(APP_MODE_KEY), null);
globalExport = savedInstanceState.getBoolean(GLOBAL_EXPORT_KEY);
exportingStarted = savedInstanceState.getBoolean(EXPORTING_STARTED_KEY);
exportStartTime = savedInstanceState.getLong(EXPORT_START_TIME_KEY);
progressMax = savedInstanceState.getInt(PROGRESS_MAX_KEY);
progressValue = savedInstanceState.getInt(PROGRESS_VALUE_KEY);
}
dataList = app.getSettingsHelper().getAdditionalData(globalExport);
requireActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
showExitDialog();
}
});
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
LayoutInflater themedInflater = UiUtilities.getInflater(app, nightMode);
View root = themedInflater.inflate(R.layout.fragment_import, container, false);
AndroidUtils.addStatusBarPadding21v(app, root);
fileSize = root.findViewById(R.id.file_size);
expandableList = root.findViewById(R.id.list);
buttonsContainer = root.findViewById(R.id.buttons_container);
Toolbar toolbar = root.findViewById(R.id.toolbar);
setupToolbar(toolbar);
ViewCompat.setNestedScrollingEnabled(expandableList, true);
View header = themedInflater.inflate(R.layout.list_item_description_header, null);
expandableList.addHeaderView(header);
TextViewEx continueBtn = root.findViewById(R.id.continue_button);
continueBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
prepareFile();
}
});
ViewTreeObserver treeObserver = buttonsContainer.getViewTreeObserver();
treeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (buttonsContainer != null) {
ViewTreeObserver vts = buttonsContainer.getViewTreeObserver();
int height = buttonsContainer.getMeasuredHeight();
expandableList.setPadding(0, 0, 0, height);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
vts.removeOnGlobalLayoutListener(this);
} else {
vts.removeGlobalOnLayoutListener(this);
}
}
}
});
adapter = new ExportImportSettingsAdapter(app, this, nightMode);
adapter.updateSettingsList(dataList);
expandableList.setAdapter(adapter);
CollapsingToolbarLayout toolbarLayout = root.findViewById(R.id.toolbar_layout);
toolbarLayout.setTitle(getString(R.string.shared_string_export));
TextView description = header.findViewById(R.id.description);
description.setText(R.string.select_data_to_export);
return root;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(GLOBAL_EXPORT_KEY, globalExport);
outState.putBoolean(EXPORTING_STARTED_KEY, exportingStarted);
outState.putLong(EXPORT_START_TIME_KEY, exportStartTime);
outState.putString(APP_MODE_KEY, appMode.getStringKey());
if (progress != null) {
outState.putInt(PROGRESS_MAX_KEY, progress.getMax());
outState.putInt(PROGRESS_VALUE_KEY, progress.getProgress());
}
}
@Override
public void onResume() {
super.onResume();
checkExportingFile();
}
@Override
public void onPause() {
super.onPause();
if (exportingStarted) {
File file = getExportFile();
app.getSettingsHelper().updateExportListener(file, null);
}
}
private void dismissFragment() {
FragmentManager fm = getFragmentManager();
if (fm != null && !fm.isStateSaved()) {
getFragmentManager().popBackStack(EXPORT_SETTINGS_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
public void showExitDialog() {
Context themedContext = UiUtilities.getThemedContext(getActivity(), nightMode);
AlertDialog.Builder dismissDialog = new AlertDialog.Builder(themedContext);
dismissDialog.setTitle(getString(R.string.shared_string_dismiss));
dismissDialog.setMessage(getString(R.string.exit_without_saving));
dismissDialog.setNegativeButton(R.string.shared_string_cancel, null);
dismissDialog.setPositiveButton(R.string.shared_string_exit, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismissFragment();
}
});
dismissDialog.show();
}
private void setupToolbar(Toolbar toolbar) {
int color = ContextCompat.getColor(app, nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light);
toolbar.setNavigationIcon(getPaintedContentIcon(R.drawable.ic_action_close, color));
toolbar.setNavigationContentDescription(R.string.shared_string_close);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showExitDialog();
}
});
}
private void updateFileSize() {
long itemsSize = ExportImportSettingsAdapter.calculateItemsSize(adapter.getData());
String size = itemsSize != 0 ? AndroidUtils.formatSize(app, itemsSize) : "";
fileSize.setText(size);
}
@Override
public void onCategorySelected(ExportSettingsCategory type, boolean selected) {
updateFileSize();
}
@Override
public void onTypeSelected(ExportSettingsType type, boolean selected) {
updateFileSize();
}
private void prepareFile() {
if (app != null) {
exportingStarted = true;
exportStartTime = System.currentTimeMillis();
showExportProgressDialog();
File tempDir = FileUtils.getTempDir(app);
String fileName = getFileName();
List<SettingsItem> items = app.getSettingsHelper().prepareAdditionalSettingsItems(adapter.getData());
progress.setMax(getMaxProgress(items));
app.getSettingsHelper().exportSettings(tempDir, fileName, getSettingsExportListener(), items, true);
}
}
private int getMaxProgress(List<SettingsItem> items) {
long maxProgress = 0;
for (SettingsItem item : items) {
if (item instanceof FileSettingsItem) {
maxProgress += ((FileSettingsItem) item).getSize();
}
}
return (int) maxProgress / (1 << 20);
}
private String getFileName() {
if (globalExport) {
if (exportStartTime == 0) {
exportStartTime = System.currentTimeMillis();
}
return "Export_" + DATE_FORMAT.format(new Date(exportStartTime));
} else {
return appMode.toHumanString();
}
}
private void showExportProgressDialog() {
Context context = getContext();
if (context == null) {
return;
}
if (progress != null) {
progress.dismiss();
}
progress = new ProgressDialog(context);
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setCancelable(true);
progress.setTitle(app.getString(R.string.shared_string_export));
progress.setMessage(app.getString(R.string.shared_string_preparing));
progress.setButton(DialogInterface.BUTTON_NEGATIVE, app.getString(R.string.shared_string_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
cancelExport();
}
});
progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
cancelExport();
}
});
progress.show();
}
private void cancelExport() {
app.getSettingsHelper().cancelExportForFile(getExportFile());
progress.dismiss();
dismissFragment();
}
private SettingsExportListener getSettingsExportListener() {
if (exportListener == null) {
exportListener = new SettingsExportListener() {
@Override
public void onSettingsExportFinished(@NonNull File file, boolean succeed) {
dismissExportProgressDialog();
exportingStarted = false;
if (succeed) {
shareProfile(file);
} else {
app.showToastMessage(R.string.export_profile_failed);
}
}
@Override
public void onSettingsExportProgressUpdate(int value) {
progress.setProgress(value);
}
};
}
return exportListener;
}
private void checkExportingFile() {
if (exportingStarted) {
File file = getExportFile();
boolean fileExporting = app.getSettingsHelper().isFileExporting(file);
if (fileExporting) {
showExportProgressDialog();
progress.setMax(progressMax);
progress.setProgress(progressValue);
app.getSettingsHelper().updateExportListener(file, getSettingsExportListener());
} else if (file.exists()) {
dismissExportProgressDialog();
shareProfile(file);
}
}
}
private void dismissExportProgressDialog() {
FragmentActivity activity = getActivity();
if (progress != null && activity != null && AndroidUtils.isActivityNotDestroyed(activity)) {
progress.dismiss();
}
}
private File getExportFile() {
File tempDir = FileUtils.getTempDir(app);
String fileName = getFileName();
return new File(tempDir, fileName + IndexConstants.OSMAND_SETTINGS_FILE_EXT);
}
private void shareProfile(@NonNull File file) {
try {
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, file.getName());
sendIntent.putExtra(Intent.EXTRA_STREAM, AndroidUtils.getUriForFile(getMyApplication(), file));
sendIntent.setType("*/*");
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(sendIntent);
dismissFragment();
} catch (Exception e) {
Toast.makeText(requireContext(), R.string.export_profile_failed, Toast.LENGTH_SHORT).show();
LOG.error("Share profile error", e);
}
}
public static boolean showInstance(@NonNull FragmentManager fragmentManager, @NonNull ApplicationMode appMode, boolean globalExport) {
try {
ExportSettingsFragment fragment = new ExportSettingsFragment();
fragment.appMode = appMode;
fragment.globalExport = globalExport;
fragmentManager.beginTransaction().
replace(R.id.fragmentContainer, fragment, TAG)
.addToBackStack(EXPORT_SETTINGS_TAG)
.commitAllowingStateLoss();
return true;
} catch (RuntimeException e) {
return false;
}
}
}

View file

@ -22,13 +22,13 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import net.osmand.AndroidUtils;
import net.osmand.IProgress;
import net.osmand.PlatformUtil;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager.TileSourceTemplate;
@ -48,6 +48,7 @@ import net.osmand.plus.osmedit.OsmNotesPoint;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean;
import net.osmand.plus.settings.backend.ExportSettingsCategory;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.backup.AvoidRoadsSettingsItem;
import net.osmand.plus.settings.backend.backup.FavoritesSettingsItem;
@ -66,38 +67,44 @@ import net.osmand.plus.settings.backend.backup.SettingsHelper.ImportAsyncTask;
import net.osmand.plus.settings.backend.backup.SettingsHelper.ImportType;
import net.osmand.plus.settings.backend.backup.SettingsItem;
import net.osmand.plus.settings.backend.backup.SettingsItemType;
import net.osmand.plus.settings.fragments.ExportImportSettingsAdapter.OnItemSelectedListener;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ImportSettingsFragment extends BaseOsmAndFragment {
public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItemSelectedListener {
public static final String TAG = ImportSettingsFragment.class.getSimpleName();
public static final Log LOG = PlatformUtil.getLog(ImportSettingsFragment.class.getSimpleName());
protected static final String IMPORT_SETTINGS_TAG = "import_settings_tag";
private static final String DUPLICATES_START_TIME_KEY = "duplicates_start_time";
private static final long MIN_DELAY_TIME_MS = 500;
static final String IMPORT_SETTINGS_TAG = "import_settings_tag";
private OsmandApplication app;
private File file;
private SettingsHelper settingsHelper;
private List<SettingsItem> settingsItems;
private Map<ExportSettingsCategory, List<ExportDataObject>> dataList;
private ExportImportSettingsAdapter adapter;
private ExpandableListView expandableList;
private TextViewEx selectBtn;
private TextView description;
private List<SettingsItem> settingsItems;
private File file;
private boolean allSelected;
private boolean nightMode;
private LinearLayout buttonsContainer;
private ProgressBar progressBar;
private TextViewEx fileSize;
private TextViewEx fileSizeDescr;
private CollapsingToolbarLayout toolbarLayout;
private SettingsHelper settingsHelper;
private boolean nightMode;
private long duplicateStartTime;
public static void showInstance(@NonNull FragmentManager fm, @NonNull List<SettingsItem> settingsItems, @NonNull File file) {
@ -134,11 +141,13 @@ public class ImportSettingsFragment extends BaseOsmAndFragment {
View root = inflater.inflate(R.layout.fragment_import, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
TextViewEx continueBtn = root.findViewById(R.id.continue_button);
fileSize = root.findViewById(R.id.file_size);
toolbarLayout = root.findViewById(R.id.toolbar_layout);
selectBtn = root.findViewById(R.id.select_button);
expandableList = root.findViewById(R.id.list);
buttonsContainer = root.findViewById(R.id.buttons_container);
progressBar = root.findViewById(R.id.progress_bar);
fileSizeDescr = root.findViewById(R.id.file_size_descr);
fileSizeDescr.setText(R.string.file_size_needed_for_import);
setupToolbar(toolbar);
ViewCompat.setNestedScrollingEnabled(expandableList, true);
View header = inflater.inflate(R.layout.list_item_description_header, null);
@ -155,14 +164,6 @@ public class ImportSettingsFragment extends BaseOsmAndFragment {
}
}
});
selectBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
allSelected = !allSelected;
selectBtn.setText(allSelected ? R.string.shared_string_deselect_all : R.string.shared_string_select_all);
adapter.selectAll(allSelected);
}
});
if (Build.VERSION.SDK_INT >= 21) {
AndroidUtils.addStatusBarPadding21v(app, root);
}
@ -207,10 +208,10 @@ public class ImportSettingsFragment extends BaseOsmAndFragment {
}
}
adapter = new ExportImportSettingsAdapter(app, nightMode, true);
Map<ExportSettingsType, List<?>> itemsMap = new HashMap<>();
adapter = new ExportImportSettingsAdapter(app, this, nightMode);
Map<ExportSettingsCategory, List<ExportDataObject>> itemsMap = new HashMap<>();
if (settingsItems != null) {
itemsMap = SettingsHelper.getSettingsToOperate(settingsItems, false);
itemsMap = SettingsHelper.getSettingsToOperateByCategory(settingsItems, false);
adapter.updateSettingsList(itemsMap);
}
expandableList.setAdapter(adapter);
@ -224,7 +225,7 @@ public class ImportSettingsFragment extends BaseOsmAndFragment {
} else {
toolbarLayout.setTitle(getString(R.string.shared_string_import));
}
if (itemsMap.size() == 1 && itemsMap.containsKey(ExportSettingsType.PROFILE)) {
if (itemsMap.size() == 1 && itemsMap.containsKey(ExportSettingsCategory.SETTINGS)) {
expandableList.expandGroup(0);
}
}
@ -235,15 +236,6 @@ public class ImportSettingsFragment extends BaseOsmAndFragment {
outState.putLong(DUPLICATES_START_TIME_KEY, duplicateStartTime);
}
@Override
public void onResume() {
super.onResume();
Activity activity = getActivity();
if (activity instanceof MapActivity) {
((MapActivity) activity).closeDrawer();
}
}
private void updateUi(int toolbarTitleRes, int descriptionRes) {
if (file != null) {
String fileName = file.getName();
@ -296,31 +288,6 @@ public class ImportSettingsFragment extends BaseOsmAndFragment {
}
}
private static class ReloadIndexesTack extends AsyncTask<Void, Void, Void> {
private final WeakReference<MapActivity> mapActivityRef;
private final OsmandApplication app;
ReloadIndexesTack(@NonNull MapActivity mapActivity) {
this.mapActivityRef = new WeakReference<>(mapActivity);
this.app = mapActivity.getMyApplication();
}
@Override
protected Void doInBackground(Void[] params) {
app.getResourceManager().reloadIndexes(IProgress.EMPTY_PROGRESS, new ArrayList<String>());
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
MapActivity mapActivity = mapActivityRef.get();
if (mapActivity != null) {
mapActivity.refreshMap();
}
}
}
private SettingsHelper.CheckDuplicatesListener getDuplicatesListener() {
return new SettingsHelper.CheckDuplicatesListener() {
@Override
@ -544,9 +511,8 @@ public class ImportSettingsFragment extends BaseOsmAndFragment {
}
private void setupToolbar(Toolbar toolbar) {
toolbar.setNavigationIcon(getPaintedContentIcon(R.drawable.ic_action_close, nightMode
? getResources().getColor(R.color.active_buttons_and_links_text_dark)
: getResources().getColor(R.color.active_buttons_and_links_text_light)));
int color = ContextCompat.getColor(app, nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light);
toolbar.setNavigationIcon(getPaintedContentIcon(R.drawable.ic_action_close, color));
toolbar.setNavigationContentDescription(R.string.shared_string_close);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
@ -559,4 +525,20 @@ public class ImportSettingsFragment extends BaseOsmAndFragment {
public void setFile(File file) {
this.file = file;
}
private void updateFileSize() {
long itemsSize = ExportImportSettingsAdapter.calculateItemsSize(adapter.getData());
String size = itemsSize != 0 ? AndroidUtils.formatSize(app, itemsSize) : "";
fileSize.setText(size);
}
@Override
public void onCategorySelected(ExportSettingsCategory type, boolean selected) {
updateFileSize();
}
@Override
public void onTypeSelected(ExportSettingsType type, boolean selected) {
updateFileSize();
}
}

View file

@ -153,7 +153,7 @@ public class MainSettingsFragment extends BaseSettingsFragment {
if (mapActivity != null) {
ApplicationMode mode = getSelectedAppMode();
FragmentManager fragmentManager = mapActivity.getSupportFragmentManager();
ExportProfileBottomSheet.showInstance(fragmentManager, this, mode, true);
ExportSettingsFragment.showInstance(fragmentManager, mode, true);
}
}
return super.onPreferenceClick(preference);

View file

@ -0,0 +1,37 @@
package net.osmand.plus.settings.fragments;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import net.osmand.IProgress;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.activities.MapActivity;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
class ReloadIndexesTack extends AsyncTask<Void, Void, Void> {
private final WeakReference<MapActivity> mapActivityRef;
private final OsmandApplication app;
ReloadIndexesTack(@NonNull MapActivity mapActivity) {
this.mapActivityRef = new WeakReference<>(mapActivity);
this.app = mapActivity.getMyApplication();
}
@Override
protected Void doInBackground(Void[] params) {
app.getResourceManager().reloadIndexes(IProgress.EMPTY_PROGRESS, new ArrayList<String>());
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
MapActivity mapActivity = mapActivityRef.get();
if (mapActivity != null) {
mapActivity.refreshMap();
}
}
}