Clean up UI and code

This commit is contained in:
Vitaliy 2020-11-17 13:12:29 +02:00
parent b1c5f4ae7b
commit e5152aa947
17 changed files with 1023 additions and 369 deletions

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/warning_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/warning_img"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:src="@drawable/ic_action_sdcard_warning_colored" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/measurement_tool_menu_title_padding_top"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/measurement_tool_menu_title_padding_top"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/warning_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:text="@string/export_not_enough_space"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
app:lineHeight="@dimen/default_title_line_height"
app:typeface="@string/font_roboto_medium" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/warning_descr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/description_letter_spacing"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
app:lineHeight="@dimen/default_desc_line_height"
app:typeface="@string/font_roboto_regular"
tools:text="@string/export_not_enough_space_descr" />
</LinearLayout>
</LinearLayout>
<include layout="@layout/card_bottom_divider" />
</LinearLayout>

View file

@ -21,46 +21,49 @@
<LinearLayout
android:id="@+id/buttons_container"
android:layout_width="match_parent"
android:layout_height="@dimen/dialog_button_ex_height"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?attr/bg_color"
android:gravity="center"
android:minHeight="@dimen/bottom_sheet_title_height"
android:orientation="vertical">
<include layout="@layout/divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/file_size_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_height="wrap_content"
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">
android:paddingBottom="@dimen/bottom_sheet_title_padding_bottom"
android:visibility="invisible"
tools:visibility="visible">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/file_size"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="start|center_vertical"
android:letterSpacing="@dimen/description_letter_spacing"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
osmand:lineHeight="@dimen/default_desc_line_height"
osmand:typeface="@string/font_roboto_regular"
tools:text="567 MB" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/file_size_descr"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="start|center_vertical"
@ -69,6 +72,7 @@
android:text="@string/approximate_file_size"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:lineHeight="@dimen/default_desc_line_height"
osmand:typeface="@string/font_roboto_regular" />
</LinearLayout>
@ -78,26 +82,32 @@
android:layout_height="match_parent" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/continue_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:gravity="center"
android:letterSpacing="@dimen/description_letter_spacing"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_half"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_half"
android:text="@string/shared_string_continue"
android:textColor="?attr/dlg_btn_primary_text"
android:textColor="?attr/text_color_tab_active"
android:textSize="@dimen/default_desc_text_size"
osmand:lineHeight="@dimen/default_desc_line_height"
osmand:typeface="@string/font_roboto_medium"
tools:text="Continue" />

View file

@ -10,15 +10,25 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:lineSpacingMultiplier="@dimen/line_spacing_multiplier_description"
android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingEnd="@dimen/content_padding"
android:lineSpacingMultiplier="@dimen/line_spacing_multiplier_description"
android:paddingBottom="@dimen/list_header_settings_top_margin"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="@string/select_data_to_import" />
<include layout="@layout/card_bottom_divider" />
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/list_divider"
android:visibility="gone"
tools:visibility="visible" />
<include
android:id="@+id/card_bottom_divider"
layout="@layout/card_bottom_divider" />
</LinearLayout>

View file

@ -14,12 +14,12 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="@dimen/setting_list_item_large_height"
@ -27,19 +27,19 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/explist_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding"
android:layout_marginEnd="@dimen/list_content_padding_large"
android:layout_marginRight="@dimen/list_content_padding_large"
android:layout_marginBottom="@dimen/content_padding"
android:layout_marginTop="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/bottom_sheet_icon_margin"
osmand:srcCompat="@drawable/ic_action_arrow_down" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
@ -48,16 +48,20 @@
android:id="@+id/title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:lineHeight="@dimen/default_title_line_height"
tools:text="Quick actions" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/sub_text_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/description_letter_spacing"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:lineHeight="@dimen/default_desc_line_height"
tools:text="8 of 4" />
</LinearLayout>
@ -66,8 +70,8 @@
android:id="@+id/vertical_divider"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding"
android:layout_marginTop="@dimen/setting_profile_item_switch_margin"
android:layout_marginBottom="@dimen/setting_profile_item_switch_margin"
android:background="?attr/list_divider" />
<FrameLayout
@ -80,8 +84,8 @@
<net.osmand.view.ThreeStateCheckbox
android:id="@+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center"
android:clickable="false"
android:enabled="false"

View file

@ -210,6 +210,8 @@
<dimen name="welcome_header_text_size">23sp</dimen>
<dimen name="text_button_text_size">15sp</dimen>
<dimen name="travel_card_primary_text_size">15sp</dimen>
<dimen name="default_title_line_height">24sp</dimen>
<dimen name="default_desc_line_height">20sp</dimen>
<dimen name="default_split_segments_overview">13sp</dimen>
<dimen name="default_split_segments_data">13sp</dimen>

View file

@ -11,10 +11,15 @@
Thx - Hardy
-->
<string name="export_not_enough_space">There is not enough space</string>
<string name="export_not_enough_space_descr">OsmAnd is needed %1$s to export a file. Your device only has %2$s free. You can free up space on the device, or skip some items from export.</string>
<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="app_mode_motorboat">Motorboat</string>
<string name="app_mode_kayak">Kayak</string>
<string name="shared_string_search_history">Search history</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>
@ -23,10 +28,10 @@
<string name="osm_login_descr">You can log in using the safe OAuth method or use your login and password.</string>
<string name="osm_edit_comment_note">Comment OSM Note</string>
<string name="osm_edit_close_note">Close OSM Note</string>
<string name="gpx_upload_trackable_visibility_descr">Trackable means that the trace will not show up in any public listings but trackpoints from it will still be available through the public GPS API with timestamps. Other users will only be able to download processed trackpoints from your trace which can\'t be associated with you directly.</string>
<string name="gpx_upload_identifiable_visibility_descr">Identifiable means that the trace will be shown publicly in Your GPS traces and in public GPS trace listings, i.e. other users will be able to download the raw trace and associate it with your username. Data served via the trackpoints API will reference your original trace page. Timestamps of the trace points are available through the public GPS API.</string>
<string name="gpx_upload_private_visibility_descr">Private means that the trace will not show up in any public listings, but trackpoints from it will still be available through the public GPS API without timestamps but will not be chronologically ordered.</string>
<string name="gpx_upload_public_visibility_descr">Public means that the trace will be shown publicly in Your GPS traces and in public GPS trace listings. Data served via the API does not reference your trace page. Timestamps of the trace points are not available through the public GPS API, and the points are not chronologically ordered. However, other users are still able to download the raw trace from the public trace list and any timestamps contained within.</string>
<string name="gpx_upload_trackable_visibility_descr">\"Trackable\" means the trace does not show up in any public listings, but processed trackpoints with timestamps from it (that can\'t be associated with you directly) do through downloads from the public GPS API.</string>
<string name="gpx_upload_identifiable_visibility_descr">\"Identifiable\" means that the trace will be shown publicly in Your GPS traces and in public GPS trace listings, i.e. other users will be able to download the raw trace and associate it with your username. Public timestamped tracepoint data from the GPS API served via the trackpoints API will reference your original trace page.</string>
<string name="gpx_upload_private_visibility_descr">\"Private\" means the trace does not show up in any public listings, but trackpoints from it in unchronological order are available through the public GPS API without timestamps.</string>
<string name="gpx_upload_public_visibility_descr">\"Public\" means the trace is shown publicly in your GPS traces and in public GPS trace listings, and in the public trace list with timestamps in raw form. Data served via the API does not reference your trace page. Tracepoint timestamps are not available through the public GPS API, and tracepoints are not chronologically ordered.</string>
<string name="enter_text_separated">Enter tags separated by comma.</string>
<string name="send_files_to_openstreetmap">Send GPX file to OpenStreetMap</string>
<string name="markers_history">Markers history</string>
@ -78,13 +83,13 @@
<string name="osm_live_payment_subscription_management_hw">Payment will be charged to your AppGallery account at the confirmation of purchase.\n\nSubscription automatically renews unless it is canceled before the renewal date. Your account will be charged for renewal period (month/three month/year) only on the renewal date.\n\nYou can manage and cancel your subscriptions by going to your AppGallery settings.</string>
<string name="osm_live_payment_desc_hw">Subscription charged per selected period. Cancel it on AppGallery at any time.</string>
<string name="contour_lines_thanks">Thank you for purchasing \'Contour lines\'</string>
<string name="start_finish_icons">Start/finish icons</string>
<string name="start_finish_icons">Start and finish icons</string>
<string name="sort_name_ascending">Name: A Z</string>
<string name="sort_name_descending">Name: Z A</string>
<string name="sort_last_modified">Last modified</string>
<string name="release_3_8">
• Updated "Plan a route" function: allows using different navigation types per segment and the inclusion of tracks\n\n
• New "Appearance" menu for tracks: select color, thickness, display direction arrows, start/finish icons\n\n
• New "Appearance" menu for tracks: select color, thickness, display direction arrows, start and finish icons\n\n
• Improved visibility of bicycle nodes.\n\n
• Tracks are now tappable, have context menu with basic info.\n\n
• Improved "Search" algorithms\n\n
@ -104,7 +109,7 @@
<string name="system_default_theme">System default</string>
<string name="gpx_monitoring_start">Resume trip recording</string>
<string name="gpx_monitoring_stop">Pause trip recording</string>
<string name="save_global_track_interval_descr">Specify the logging interval for the general track recording (enabled via the Trip recording widget on the map).</string>
<string name="save_global_track_interval_descr">Specify the logging interval for the general track recording (turned on via the \'Trip recording\' widget on the map).</string>
<string name="disable_recording_once_app_killed_descrp">Will pause track logging when the app is killed (via recent apps). (OsmAnd background indication disappears from the Android notification bar.)</string>
<string name="monitoring_control_start">REC</string>
<string name="number_of_gpx_files_selected_pattern">%s track files selected</string>
@ -270,11 +275,11 @@
<string name="quick_action_switch_profile_descr">The action button switches between selected profiles.</string>
<string name="back_to_editing">Back to editing</string>
<string name="reset_deafult_order">Restore default items order</string>
<string name="add_edit_favorite">Add / Edit Favorite</string>
<string name="add_edit_favorite">Add or edit favorite</string>
<string name="parking_positions">Parking positions</string>
<string name="create_edit_poi">Create / Edit POI</string>
<string name="create_edit_poi">Create or edit POI</string>
<string name="quick_action_transport_descr">Button showing or hiding public transport on the map.</string>
<string name="quick_action_show_hide_transport">Show/hide public transport</string>
<string name="quick_action_show_hide_transport">Show or hide public transport</string>
<string name="quick_action_transport_show">Show public transport</string>
<string name="quick_action_transport_hide">Hide public transport</string>
<string name="release_3_7">
@ -376,7 +381,7 @@
<string name="quick_action_terrain_descr">A button to show or hide terrain layer on the map.</string>
<string name="quick_action_terrain_show">Show terrain</string>
<string name="quick_action_terrain_hide">Hide terrain</string>
<string name="quick_action_show_hide_terrain">Show / hide terrain</string>
<string name="quick_action_show_hide_terrain">Show or hide terrain</string>
<string name="download_slope_maps">Slopes</string>
<string name="n_items_of_z">%1$s of %2$s</string>
<string name="recalculate_route_distance_promo">The route will be recalculated if the distance from the route to the current location is more than selected value.</string>
@ -561,7 +566,7 @@
<string name="clear_confirmation_msg">Clear %1$s?</string>
<string name="shared_string_revert">Revert</string>
<string name="track_saved">Track saved</string>
<string name="empty_filename">File name is empty</string>
<string name="empty_filename">Empty filename</string>
<string name="default_speed_dialog_msg">Estimates arrival time for unknown road types, and limits speed for all roads (may affect routing)</string>
<string name="rendering_value_white_name">White</string>
<string name="swap_two_places">Swap %1$s and %2$s</string>
@ -1173,7 +1178,7 @@
<string name="first_intermediate_dest_description">Adds initial stop</string>
<string name="subsequent_dest_description">Move destination up, and create it</string>
<string name="show_closed_notes">Show closed notes</string>
<string name="switch_osm_notes_visibility_desc">Show/hide OSM notes on the map.</string>
<string name="switch_osm_notes_visibility_desc">Show or hide OSM notes on the map.</string>
<string name="gpx_file_desc">GPX - suitable for export to JOSM or other OSM editors.</string>
<string name="osc_file_desc">OSC - suitable for export to OSM.</string>
<string name="shared_string_gpx_file">GPX file</string>
@ -3826,7 +3831,7 @@
<string name="number_of_contributors">Number of contributors</string>
<string name="number_of_edits">Number of edits</string>
<string name="reports_for">Report for</string>
<string name="file_name_containes_illegal_char">File name contains illegal character</string>
<string name="file_name_containes_illegal_char">Illegal character in filename</string>
<string name="configure_screen_quick_action">Quick action</string>
<string name="quick_action_item_action">Action %d</string>
<string name="quick_action_item_screen">Screen %d</string>
@ -3948,9 +3953,9 @@
<string name="routing_attr_avoid_sett_name">No cobblestone or sett</string>
<string name="routing_attr_avoid_sett_description">Avoids cobblestone and sett</string>
<string name="quick_action_need_to_add_item_to_list">Add at least one item to the list in the \'Quick action\' settings</string>
<string name="routing_attr_piste_type_downhill_name">Alpine/downhill ski</string>
<string name="routing_attr_piste_type_downhill_name">Alpine and downhill skiing</string>
<string name="routing_attr_piste_type_downhill_description">Slopes for alpine or downhill skiing and access to ski lifts.</string>
<string name="routing_attr_piste_type_nordic_name">Cross country/nordic ski</string>
<string name="routing_attr_piste_type_nordic_name">Cross country and nordic skiing</string>
<string name="routing_attr_piste_type_nordic_description">Trails for nordic or cross-country skiing.</string>
<string name="routing_attr_piste_type_skitour_name">Ski touring</string>
<string name="routing_attr_piste_type_skitour_description">Routes for ski touring.</string>

View file

@ -788,6 +788,14 @@ public class AndroidUtils {
return result;
}
public static long getAvailableSpace(@Nullable File dir) {
if (dir != null && dir.canRead()) {
StatFs fs = new StatFs(dir.getAbsolutePath());
return fs.getAvailableBlocksLong() * fs.getBlockSize();
}
return -1;
}
public static float getFreeSpaceGb(File dir) {
if (dir.canRead()) {
StatFs fs = new StatFs(dir.getAbsolutePath());

View file

@ -22,7 +22,6 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Space;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -36,7 +35,6 @@ import androidx.fragment.app.FragmentActivity;
import androidx.viewpager.widget.ViewPager;
import net.osmand.AndroidUtils;
import net.osmand.IProgress;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.access.AccessibilityAssistant;
@ -45,7 +43,6 @@ import net.osmand.data.PointDescription;
import net.osmand.map.WorldRegion;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.activities.LocalIndexInfo;
@ -64,6 +61,8 @@ import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.openseamapsplugin.NauticalMapsPlugin;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.download.ReloadIndexesTask.ReloadIndexesListener;
import net.osmand.plus.srtmplugin.SRTMPlugin;
import net.osmand.plus.views.controls.PagerSlidingTabStrip;
import net.osmand.util.Algorithms;
@ -390,7 +389,6 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
|| application.getSettings().SHOULD_SHOW_FREE_VERSION_BANNER.get();
}
public static class FreeVersionBanner {
private final View freeVersionBanner;
private final View freeVersionBannerTitle;
@ -493,6 +491,7 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
freeVersionBannerTitle.setVisibility(View.VISIBLE);
}
}
private void updateAvailableDownloads() {
int activeTasks = ctx.getDownloadThread().getCountedDownloads();
OsmandSettings settings = ctx.getMyApplication().getSettings();
@ -570,36 +569,26 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
}
}
@SuppressLint("StaticFieldLeak")
public void reloadLocalIndexes() {
AsyncTask<Void, String, List<String>> task = new AsyncTask<Void, String, List<String>>() {
final OsmandApplication app = (OsmandApplication) getApplication();
ReloadIndexesTask reloadIndexesTask = new ReloadIndexesTask(app, new ReloadIndexesListener() {
@Override
protected void onPreExecute() {
super.onPreExecute();
public void reloadIndexesStarted() {
setSupportProgressBarIndeterminateVisibility(true);
}
@Override
protected List<String> doInBackground(Void... params) {
return getMyApplication().getResourceManager().reloadIndexes(IProgress.EMPTY_PROGRESS,
new ArrayList<String>()
);
}
@Override
protected void onPostExecute(List<String> warnings) {
public void reloadIndexesFinished(List<String> warnings) {
setSupportProgressBarIndeterminateVisibility(false);
if (!warnings.isEmpty()) {
Toast.makeText(DownloadActivity.this, AndroidUtils.formatWarnings(warnings).toString(), Toast.LENGTH_LONG).show();
if (!Algorithms.isEmpty(warnings)) {
app.showToastMessage(AndroidUtils.formatWarnings(warnings).toString());
}
newDownloadIndexes();
}
};
task.executeOnExecutor(singleThreadExecutor);
});
reloadIndexesTask.executeOnExecutor(singleThreadExecutor);
}
public void setDownloadItem(WorldRegion region, String targetFileName) {
if (downloadItem == null) {
downloadItem = region;

View file

@ -0,0 +1,49 @@
package net.osmand.plus.download;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.IProgress;
import net.osmand.plus.OsmandApplication;
import java.util.ArrayList;
import java.util.List;
public class ReloadIndexesTask extends AsyncTask<Void, String, List<String>> {
private final OsmandApplication app;
private final ReloadIndexesListener listener;
public ReloadIndexesTask(@NonNull OsmandApplication app, @Nullable ReloadIndexesListener listener) {
this.app = app;
this.listener = listener;
}
@Override
protected void onPreExecute() {
if (listener != null) {
listener.reloadIndexesStarted();
}
}
@Override
protected List<String> doInBackground(Void... params) {
return app.getResourceManager().reloadIndexes(IProgress.EMPTY_PROGRESS, new ArrayList<String>());
}
@Override
protected void onPostExecute(List<String> warnings) {
if (listener != null) {
listener.reloadIndexesFinished(warnings);
}
}
public interface ReloadIndexesListener {
void reloadIndexesStarted();
void reloadIndexesFinished(List<String> warnings);
}
}

View file

@ -7,23 +7,24 @@ import net.osmand.plus.R;
public enum ExportSettingsType {
PROFILE(R.string.shared_string_profiles, R.drawable.ic_action_manage_profiles),
GLOBAL(R.string.general_settings_2, R.drawable.ic_action_settings),
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),
SEARCH_HISTORY(R.string.shared_string_search_history, R.drawable.ic_action_history),
AVOID_ROADS(R.string.avoid_road, R.drawable.ic_action_alert),
FAVORITES(R.string.shared_string_favorites, R.drawable.ic_action_favorite),
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),
MULTIMEDIA_NOTES(R.string.audionotes_plugin_name, R.drawable.ic_grouped_by_type),
ACTIVE_MARKERS(R.string.map_markers, R.drawable.ic_action_flag),
HISTORY_MARKERS(R.string.markers_history, R.drawable.ic_action_flag);
HISTORY_MARKERS(R.string.markers_history, R.drawable.ic_action_flag),
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),
MAP_SOURCES(R.string.quick_action_map_source_title, R.drawable.ic_map),
OFFLINE_MAPS(R.string.shared_string_maps, R.drawable.ic_map),
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);
@StringRes
private final int titleId;
@ -46,7 +47,8 @@ public enum ExportSettingsType {
}
public boolean isSettingsCategory() {
return this == PROFILE || this == GLOBAL || this == QUICK_ACTIONS || this == POI_TYPES;
return this == PROFILE || this == GLOBAL || this == QUICK_ACTIONS || this == POI_TYPES
|| this == SEARCH_HISTORY || this == AVOID_ROADS;
}
public boolean isMyPlacesCategory() {

View file

@ -29,6 +29,8 @@ import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
import net.osmand.plus.helpers.SearchHistoryHelper;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.mapmarkers.MapMarkersGroup;
import net.osmand.plus.osmedit.OpenstreetmapPoint;
@ -504,12 +506,15 @@ public class SettingsHelper {
List<ExportDataObject> resourcesItems = getResourcesItems();
if (!settingsItems.isEmpty()) {
sortExportSettingsObjects(settingsItems);
dataList.put(ExportSettingsCategory.SETTINGS, settingsItems);
}
if (!myPlacesItems.isEmpty()) {
sortExportSettingsObjects(myPlacesItems);
dataList.put(ExportSettingsCategory.MY_PLACES, myPlacesItems);
}
if (!resourcesItems.isEmpty()) {
sortExportSettingsObjects(resourcesItems);
dataList.put(ExportSettingsCategory.RESOURCES, resourcesItems);
}
@ -537,7 +542,14 @@ public class SettingsHelper {
if (!poiList.isEmpty()) {
settingsItems.add(new ExportDataObject(ExportSettingsType.POI_TYPES, poiList));
}
List<HistoryEntry> historyEntries = SearchHistoryHelper.getInstance(app).getHistoryEntries(false);
if (!historyEntries.isEmpty()) {
settingsItems.add(new ExportDataObject(ExportSettingsType.SEARCH_HISTORY, historyEntries));
}
Map<LatLon, AvoidRoadInfo> impassableRoads = app.getAvoidSpecificRoads().getImpassableRoads();
if (!impassableRoads.isEmpty()) {
settingsItems.add(new ExportDataObject(ExportSettingsType.AVOID_ROADS, new ArrayList<>(impassableRoads.values())));
}
return settingsItems;
}
@ -653,10 +665,6 @@ public class SettingsHelper {
if (!files.isEmpty()) {
resourcesItems.add(new ExportDataObject(ExportSettingsType.VOICE, files));
}
Map<LatLon, AvoidRoadInfo> impassableRoads = app.getAvoidSpecificRoads().getImpassableRoads();
if (!impassableRoads.isEmpty()) {
resourcesItems.add(new ExportDataObject(ExportSettingsType.AVOID_ROADS, new ArrayList<>(impassableRoads.values())));
}
return resourcesItems;
}
@ -699,6 +707,7 @@ public class SettingsHelper {
List<OpenstreetmapPoint> osmEditsPointList = new ArrayList<>();
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> historyEntries = new ArrayList<>();
for (Object object : data) {
if (object instanceof QuickAction) {
@ -730,6 +739,8 @@ public class SettingsHelper {
} else if (ExportSettingsType.HISTORY_MARKERS.name().equals(markersGroup.getId())) {
markersHistoryGroups.add((MapMarkersGroup) object);
}
} else if (object instanceof HistoryEntry) {
historyEntries.add((HistoryEntry) object);
}
}
if (!quickActions.isEmpty()) {
@ -775,6 +786,9 @@ public class SettingsHelper {
}
settingsItems.add(new HistoryMarkersSettingsItem(app, mapMarkers));
}
if (!historyEntries.isEmpty()) {
settingsItems.add(new SearchHistorySettingsItem(app, historyEntries));
}
return settingsItems;
}
@ -797,12 +811,15 @@ public class SettingsHelper {
}
}
if (!settingsItems.isEmpty()) {
sortExportSettingsObjects(settingsItems);
exportMap.put(ExportSettingsCategory.SETTINGS, settingsItems);
}
if (!myPlacesItems.isEmpty()) {
sortExportSettingsObjects(myPlacesItems);
exportMap.put(ExportSettingsCategory.MY_PLACES, myPlacesItems);
}
if (!resourcesItems.isEmpty()) {
sortExportSettingsObjects(resourcesItems);
exportMap.put(ExportSettingsCategory.RESOURCES, resourcesItems);
}
@ -829,6 +846,7 @@ public class SettingsHelper {
List<FavoriteGroup> favoriteGroups = new ArrayList<>();
List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> historyEntries = new ArrayList<>();
for (SettingsItem item : settingsItems) {
switch (item.getType()) {
@ -916,6 +934,10 @@ public class SettingsHelper {
HistoryMarkersSettingsItem historyMarkersSettingsItem = (HistoryMarkersSettingsItem) item;
markersHistoryGroups.add(historyMarkersSettingsItem.getMarkersGroup());
break;
case SEARCH_HISTORY:
SearchHistorySettingsItem searchHistorySettingsItem = (SearchHistorySettingsItem) item;
historyEntries.addAll(searchHistorySettingsItem.getItems());
break;
default:
break;
}
@ -972,9 +994,12 @@ public class SettingsHelper {
if (!markersGroups.isEmpty()) {
settingsToOperate.put(ExportSettingsType.ACTIVE_MARKERS, markersGroups);
}
if (!markersGroups.isEmpty()) {
if (!markersHistoryGroups.isEmpty()) {
settingsToOperate.put(ExportSettingsType.HISTORY_MARKERS, markersHistoryGroups);
}
if (!historyEntries.isEmpty()) {
settingsToOperate.put(ExportSettingsType.SEARCH_HISTORY, historyEntries);
}
return settingsToOperate;
}
@ -991,4 +1016,15 @@ public class SettingsHelper {
}
});
}
private static void sortExportSettingsObjects(List<ExportDataObject> items) {
Collections.sort(items, new Comparator<ExportDataObject>() {
@Override
public int compare(ExportDataObject lhs, ExportDataObject rhs) {
int order1 = lhs.getType().ordinal();
int order2 = rhs.getType().ordinal();
return (order1 < order2) ? -1 : ((order1 == order2) ? 0 : 1);
}
});
}
}

View file

@ -1,5 +1,7 @@
package net.osmand.plus.settings.fragments;
import androidx.annotation.NonNull;
import net.osmand.plus.settings.backend.ExportSettingsType;
import java.util.List;
@ -9,7 +11,7 @@ public class ExportDataObject {
private ExportSettingsType type;
private List<?> items;
public ExportDataObject(ExportSettingsType type, List<?> items) {
public ExportDataObject(@NonNull ExportSettingsType type, @NonNull List<?> items) {
this.type = type;
this.items = items;
}

View file

@ -4,6 +4,8 @@ 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;
@ -11,16 +13,33 @@ 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.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.settings.backend.ExportSettingsCategory;
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.helpers.SearchHistoryHelper.HistoryEntry;
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.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;
@ -29,10 +48,11 @@ 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;
@ -40,94 +60,91 @@ 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;
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) {
ExportImportSettingsAdapter(OsmandApplication app, boolean nightMode, boolean importState) {
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();
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;
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) {
group = themedInflater.inflate(R.layout.profile_data_list_item_group, parent, false);
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
group = inflater.inflate(R.layout.profile_data_list_item_group, parent, false);
}
final ExportSettingsCategory category = itemsTypes.get(groupPosition);
final List<ExportDataObject> items = itemsMap.get(category);
String title = app.getString(category.getTitleId());
boolean isLastGroup = groupPosition == getGroupCount() - 1;
final ExportSettingsType type = itemsTypes.get(groupPosition);
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);
subTextTv.setText(getCategoryDescr(category));
int selectedTypes = 0;
for (int i = 0; i < items.size(); i++) {
ExportDataObject object = items.get(i);
if (selectedItemsMap.containsKey(object.getType())) {
selectedTypes++;
}
}
final ThreeStateCheckbox checkBox = group.findViewById(R.id.check_box);
if (selectedTypes == 0) {
checkBox.setState(UNCHECKED);
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);
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 {
checkBox.setState(selectedTypes == items.size() ? CHECKED : MISC);
boolean contains = false;
for (Object object : listItems) {
if (data.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)));
group.findViewById(R.id.check_box_container).setOnClickListener(new View.OnClickListener() {
checkBoxContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkBox.performClick();
boolean selected = checkBox.getState() == CHECKED;
if (selected) {
for (ExportDataObject object : items) {
if (!selectedItemsMap.containsKey(object.getType())) {
selectedItemsMap.put(object.getType(), (List<Object>) object.getItems());
if (checkBox.getState() == CHECKED) {
for (Object object : listItems) {
if (!data.contains(object)) {
data.add(object);
}
}
} else {
for (ExportDataObject object : items) {
selectedItemsMap.remove(object.getType());
}
}
if (listener != null) {
listener.onCategorySelected(category, selected);
data.removeAll(listItems);
}
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;
}
@ -135,57 +152,172 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View child = convertView;
if (child == null) {
child = themedInflater.inflate(R.layout.profile_data_list_item_group, parent, false);
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
child = inflater.inflate(R.layout.profile_data_list_item_child, parent, false);
}
final ExportDataObject currentItem = itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition);
List<Object> selectedItems = selectedItemsMap.get(currentItem.getType());
final Object currentItem = itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition);
TextView titleTv = child.findViewById(R.id.title_tv);
titleTv.setText(currentItem.getType().getTitleId());
boolean isLastGroup = groupPosition == getGroupCount() - 1;
boolean itemSelected = data.contains(currentItem);
final ExportSettingsType type = itemsTypes.get(groupPosition);
TextView subTextTv = child.findViewById(R.id.sub_text_tv);
subTextTv.setText(getSelectedTypeDescr(currentItem));
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);
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;
lineDivider.setVisibility(!importState && isLastChild && !isLastGroup ? View.VISIBLE : View.GONE);
cardBottomDivider.setVisibility(importState && isLastChild ? View.VISIBLE : View.GONE);
int checkBoxColor = itemSelected ? activeColorRes : secondaryColorRes;
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor)));
child.findViewById(R.id.check_box_container).setOnClickListener(new View.OnClickListener() {
checkBox.setChecked(itemSelected);
checkBox.setClickable(false);
child.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkBox.performClick();
boolean selected = checkBox.getState() == CHECKED;
if (selected) {
selectedItemsMap.put(currentItem.getType(), (List<Object>) currentItem.getItems());
if (data.contains(currentItem)) {
data.remove(currentItem);
} else {
selectedItemsMap.remove(currentItem.getType());
}
if (listener != null) {
listener.onTypeSelected(currentItem.getType(), selected);
data.add(currentItem);
}
notifyDataSetChanged();
}
});
AndroidUiHelper.updateVisibility(child.findViewById(R.id.card_bottom_divider), isLastChild);
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;
case SEARCH_HISTORY:
HistoryEntry historyEntry = (HistoryEntry) currentItem;
title.setText(historyEntry.getName().getName());
break;
default:
return child;
}
return child;
}
@ -229,16 +361,80 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
return true;
}
private void setupIcon(ImageView icon, int iconRes, boolean itemSelected) {
if (itemSelected) {
int colorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_osmand_light;
icon.setImageDrawable(uiUtilities.getIcon(iconRes, colorRes));
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 {
icon.setImageDrawable(uiUtilities.getIcon(iconRes, secondaryColorRes));
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;
case SEARCH_HISTORY:
return R.string.shared_string_search_history;
default:
return R.string.access_empty_list;
}
}
public void updateSettingsList(Map<ExportSettingsCategory, List<ExportDataObject>> itemsMap) {
private void setupIcon(ImageView icon, int iconRes, boolean itemSelected) {
if (itemSelected) {
icon.setImageDrawable(uiUtilities.getIcon(iconRes, activeColorRes));
} else {
icon.setImageDrawable(uiUtilities.getIcon(iconRes, nightMode));
}
}
public void updateSettingsList(Map<ExportSettingsType, List<?>> itemsMap) {
this.itemsMap = itemsMap;
this.itemsTypes = new ArrayList<>(itemsMap.keySet());
Collections.sort(itemsTypes);
@ -251,90 +447,17 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
notifyDataSetChanged();
}
public List<? super Object> getData() {
List<Object> selectedItems = new ArrayList<>();
for (List<?> items : selectedItemsMap.values()) {
selectedItems.addAll(items);
public void selectAll(boolean selectAll) {
data.clear();
if (selectAll) {
for (List<?> values : itemsMap.values()) {
data.addAll(values);
}
return selectedItems;
}
notifyDataSetChanged();
}
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);
List<? super Object> getData() {
return this.data;
}
}

View file

@ -0,0 +1,337 @@
package net.osmand.plus.settings.fragments;
import android.content.res.ColorStateList;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
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.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.view.ThreeStateCheckbox;
import org.apache.commons.logging.Log;
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.view.ThreeStateCheckbox.State.CHECKED;
import static net.osmand.view.ThreeStateCheckbox.State.MISC;
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
public class ExportSettingsAdapter extends OsmandBaseExpandableListAdapter {
private static final Log LOG = PlatformUtil.getLog(ExportImportSettingsAdapter.class.getName());
private final OsmandApplication app;
private final UiUtilities uiUtilities;
private List<ExportSettingsCategory> itemsTypes = new ArrayList<>();
private Map<ExportSettingsType, List<?>> 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;
ExportSettingsAdapter(OsmandApplication app, OnItemSelectedListener listener, boolean nightMode) {
this.app = app;
this.listener = listener;
this.nightMode = nightMode;
uiUtilities = app.getUIUtilities();
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) {
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);
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);
subTextTv.setText(getCategoryDescr(category));
int selectedTypes = 0;
for (int i = 0; i < items.size(); i++) {
ExportDataObject object = items.get(i);
if (selectedItemsMap.containsKey(object.getType())) {
selectedTypes++;
}
}
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)));
group.findViewById(R.id.check_box_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkBox.performClick();
boolean selected = checkBox.getState() == CHECKED;
if (selected) {
for (ExportDataObject object : items) {
if (!selectedItemsMap.containsKey(object.getType())) {
selectedItemsMap.put(object.getType(), object.getItems());
}
}
} else {
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;
}
@Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View child = convertView;
if (child == null) {
child = themedInflater.inflate(R.layout.profile_data_list_item_group, parent, false);
}
final ExportDataObject currentItem = itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition);
List<?> selectedItems = selectedItemsMap.get(currentItem.getType());
TextView titleTv = child.findViewById(R.id.title_tv);
titleTv.setText(currentItem.getType().getTitleId());
TextView subTextTv = child.findViewById(R.id.sub_text_tv);
subTextTv.setText(getSelectedTypeDescr(currentItem));
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)));
child.findViewById(R.id.check_box_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkBox.performClick();
boolean selected = checkBox.getState() == CHECKED;
if (selected) {
selectedItemsMap.put(currentItem.getType(), currentItem.getItems());
} else {
selectedItemsMap.remove(currentItem.getType());
}
if (listener != null) {
listener.onTypeSelected(currentItem.getType(), selected);
}
notifyDataSetChanged();
}
});
AndroidUiHelper.updateVisibility(child.findViewById(R.id.card_bottom_divider), isLastChild);
return child;
}
@Override
public int getGroupCount() {
return itemsTypes.size();
}
@Override
public int getChildrenCount(int i) {
return itemsMap.get(itemsTypes.get(i)).size();
}
@Override
public Object getGroup(int i) {
return itemsMap.get(itemsTypes.get(i));
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition);
}
@Override
public long getGroupId(int i) {
return i;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return groupPosition * 10000 + childPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
private void setupIcon(ImageView icon, int iconRes, boolean itemSelected) {
if (itemSelected) {
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, secondaryColorRes));
}
}
public void updateSettingsList(Map<ExportSettingsCategory, List<ExportDataObject>> itemsMap) {
this.itemsMap = itemsMap;
this.itemsTypes = new ArrayList<>(itemsMap.keySet());
Collections.sort(itemsTypes);
notifyDataSetChanged();
}
public void clearSettingsList() {
this.itemsMap.clear();
this.itemsTypes.clear();
notifyDataSetChanged();
}
public List<? super Object> getData() {
List<Object> selectedItems = new ArrayList<>();
for (List<?> items : selectedItemsMap.values()) {
selectedItems.addAll(items);
}
return selectedItems;
}
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<?> 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

@ -35,13 +35,14 @@ 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.helpers.AndroidUiHelper;
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.settings.fragments.ExportSettingsAdapter.OnItemSelectedListener;
import net.osmand.plus.widgets.TextViewEx;
import org.apache.commons.logging.Log;
@ -78,10 +79,15 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
private ApplicationMode appMode;
private SettingsExportListener exportListener;
private TextViewEx fileSize;
private View headerShadow;
private View headerDivider;
private View itemsSizeContainer;
private View availableSpaceContainer;
private TextViewEx selectedItemsSize;
private TextViewEx availableSpaceDescr;
private LinearLayout buttonsContainer;
private ExpandableListView expandableList;
private ExportImportSettingsAdapter adapter;
private ExportSettingsAdapter adapter;
private int progressMax;
private int progressValue;
@ -127,16 +133,23 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
View root = themedInflater.inflate(R.layout.fragment_import, container, false);
AndroidUtils.addStatusBarPadding21v(app, root);
fileSize = root.findViewById(R.id.file_size);
selectedItemsSize = root.findViewById(R.id.file_size);
itemsSizeContainer = root.findViewById(R.id.file_size_container);
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);
headerDivider = header.findViewById(R.id.divider);
headerShadow = header.findViewById(R.id.card_bottom_divider);
expandableList.addHeaderView(header);
availableSpaceContainer = inflater.inflate(R.layout.enough_space_warning_card, null);
availableSpaceDescr = availableSpaceContainer.findViewById(R.id.warning_descr);
TextViewEx continueBtn = root.findViewById(R.id.continue_button);
continueBtn.setOnClickListener(new View.OnClickListener() {
@Override
@ -161,7 +174,7 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
}
});
adapter = new ExportImportSettingsAdapter(app, this, nightMode);
adapter = new ExportSettingsAdapter(app, this, nightMode);
adapter.updateSettingsList(dataList);
expandableList.setAdapter(adapter);
@ -169,6 +182,7 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
toolbarLayout.setTitle(getString(R.string.shared_string_export));
TextView description = header.findViewById(R.id.description);
description.setText(R.string.select_data_to_export);
updateAvailableSpace();
return root;
}
@ -235,20 +249,50 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
});
}
private void updateFileSize() {
long itemsSize = ExportImportSettingsAdapter.calculateItemsSize(adapter.getData());
String size = itemsSize != 0 ? AndroidUtils.formatSize(app, itemsSize) : "";
fileSize.setText(size);
private void updateAvailableSpace() {
long calculatedSize = ExportSettingsAdapter.calculateItemsSize(adapter.getData());
if (calculatedSize != 0) {
String itemsSize = AndroidUtils.formatSize(app, calculatedSize);
selectedItemsSize.setText(itemsSize);
File dir = app.getAppPath("").getParentFile();
long availableSizeBytes = AndroidUtils.getAvailableSpace(dir);
if (calculatedSize > availableSizeBytes) {
String availableSize = AndroidUtils.formatSize(app, availableSizeBytes);
availableSpaceDescr.setText(getString(R.string.export_not_enough_space_descr, itemsSize, availableSize));
updateWarningHeaderVisibility(true);
} else {
updateWarningHeaderVisibility(false);
}
itemsSizeContainer.setVisibility(View.VISIBLE);
} else {
updateWarningHeaderVisibility(false);
itemsSizeContainer.setVisibility(View.INVISIBLE);
}
}
private void updateWarningHeaderVisibility(boolean visible) {
if (visible) {
if (expandableList.getHeaderViewsCount() < 2) {
expandableList.addHeaderView(availableSpaceContainer);
}
AndroidUiHelper.updateVisibility(headerShadow, false);
AndroidUiHelper.updateVisibility(headerDivider, true);
} else {
expandableList.removeHeaderView(availableSpaceContainer);
AndroidUiHelper.updateVisibility(headerShadow, true);
AndroidUiHelper.updateVisibility(headerDivider, false);
}
}
@Override
public void onCategorySelected(ExportSettingsCategory type, boolean selected) {
updateFileSize();
updateAvailableSpace();
}
@Override
public void onTypeSelected(ExportSettingsType type, boolean selected) {
updateFileSize();
updateAvailableSpace();
}
private void prepareFile() {

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;
@ -49,7 +49,6 @@ 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;
@ -69,44 +68,37 @@ 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 implements OnItemSelectedListener {
public class ImportSettingsFragment extends BaseOsmAndFragment {
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 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 boolean nightMode;
private SettingsHelper settingsHelper;
private long duplicateStartTime;
public static void showInstance(@NonNull FragmentManager fm, @NonNull List<SettingsItem> settingsItems, @NonNull File file) {
@ -143,13 +135,10 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
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);
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);
@ -210,10 +199,10 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
}
}
adapter = new ExportImportSettingsAdapter(app, this, nightMode);
Map<ExportSettingsCategory, List<ExportDataObject>> itemsMap = new HashMap<>();
adapter = new ExportImportSettingsAdapter(app, nightMode, true);
Map<ExportSettingsType, List<?>> itemsMap = new HashMap<>();
if (settingsItems != null) {
itemsMap = SettingsHelper.getSettingsToOperateByCategory(settingsItems, false);
itemsMap = SettingsHelper.getSettingsToOperate(settingsItems, false);
adapter.updateSettingsList(itemsMap);
}
expandableList.setAdapter(adapter);
@ -227,7 +216,7 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
} else {
toolbarLayout.setTitle(getString(R.string.shared_string_import));
}
if (itemsMap.size() == 1 && itemsMap.containsKey(ExportSettingsCategory.SETTINGS)) {
if (itemsMap.size() == 1 && itemsMap.containsKey(ExportSettingsType.PROFILE)) {
expandableList.expandGroup(0);
}
}
@ -238,6 +227,15 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
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();
@ -290,6 +288,31 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
}
}
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
@ -519,8 +542,9 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
}
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.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)));
toolbar.setNavigationContentDescription(R.string.shared_string_close);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
@ -533,20 +557,4 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
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

@ -1,37 +0,0 @@
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();
}
}
}