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

View file

@ -10,15 +10,25 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/bg_color" android:background="?attr/bg_color"
android:lineSpacingMultiplier="@dimen/line_spacing_multiplier_description"
android:paddingStart="@dimen/content_padding" android:paddingStart="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin" android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingEnd="@dimen/content_padding" android:paddingEnd="@dimen/content_padding"
android:lineSpacingMultiplier="@dimen/line_spacing_multiplier_description"
android:paddingBottom="@dimen/list_header_settings_top_margin" android:paddingBottom="@dimen/list_header_settings_top_margin"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size" android:textSize="@dimen/default_list_text_size"
tools:text="@string/select_data_to_import" /> 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> </LinearLayout>

View file

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

View file

@ -210,6 +210,8 @@
<dimen name="welcome_header_text_size">23sp</dimen> <dimen name="welcome_header_text_size">23sp</dimen>
<dimen name="text_button_text_size">15sp</dimen> <dimen name="text_button_text_size">15sp</dimen>
<dimen name="travel_card_primary_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_overview">13sp</dimen>
<dimen name="default_split_segments_data">13sp</dimen> <dimen name="default_split_segments_data">13sp</dimen>

View file

@ -11,10 +11,15 @@
Thx - Hardy 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="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="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="approximate_file_size">Approximate file size</string>
<string name="shared_string_resources">Resources</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_have_account">I already have an account</string>
<string name="register_opr_create_new_account">Create new 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> <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_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_comment_note">Comment OSM Note</string>
<string name="osm_edit_close_note">Close 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_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. 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_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 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_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 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_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="enter_text_separated">Enter tags separated by comma.</string>
<string name="send_files_to_openstreetmap">Send GPX file to OpenStreetMap</string> <string name="send_files_to_openstreetmap">Send GPX file to OpenStreetMap</string>
<string name="markers_history">Markers history</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_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="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="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_ascending">Name: A Z</string>
<string name="sort_name_descending">Name: Z A</string> <string name="sort_name_descending">Name: Z A</string>
<string name="sort_last_modified">Last modified</string> <string name="sort_last_modified">Last modified</string>
<string name="release_3_8"> <string name="release_3_8">
• Updated "Plan a route" function: allows using different navigation types per segment and the inclusion of tracks\n\n • 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 • Improved visibility of bicycle nodes.\n\n
• Tracks are now tappable, have context menu with basic info.\n\n • Tracks are now tappable, have context menu with basic info.\n\n
• Improved "Search" algorithms\n\n • Improved "Search" algorithms\n\n
@ -104,11 +109,11 @@
<string name="system_default_theme">System default</string> <string name="system_default_theme">System default</string>
<string name="gpx_monitoring_start">Resume trip recording</string> <string name="gpx_monitoring_start">Resume trip recording</string>
<string name="gpx_monitoring_stop">Pause 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="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="monitoring_control_start">REC</string>
<string name="number_of_gpx_files_selected_pattern">%s track files selected</string> <string name="number_of_gpx_files_selected_pattern">%s track files selected</string>
<string name="shared_string_file_name">File name</string> <string name="shared_string_file_name">Filename</string>
<string name="simplified_track_description">Only the route line will be saved, the waypoints will be deleted.</string> <string name="simplified_track_description">Only the route line will be saved, the waypoints will be deleted.</string>
<string name="simplified_track">Simplified track</string> <string name="simplified_track">Simplified track</string>
<string name="plan_route_change_route_type_after">Change route type after</string> <string name="plan_route_change_route_type_after">Change route type after</string>
@ -270,11 +275,11 @@
<string name="quick_action_switch_profile_descr">The action button switches between selected profiles.</string> <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="back_to_editing">Back to editing</string>
<string name="reset_deafult_order">Restore default items order</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="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_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_show">Show public transport</string>
<string name="quick_action_transport_hide">Hide public transport</string> <string name="quick_action_transport_hide">Hide public transport</string>
<string name="release_3_7"> <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_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_show">Show terrain</string>
<string name="quick_action_terrain_hide">Hide 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="download_slope_maps">Slopes</string>
<string name="n_items_of_z">%1$s of %2$s</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> <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="clear_confirmation_msg">Clear %1$s?</string>
<string name="shared_string_revert">Revert</string> <string name="shared_string_revert">Revert</string>
<string name="track_saved">Track saved</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="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="rendering_value_white_name">White</string>
<string name="swap_two_places">Swap %1$s and %2$s</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="first_intermediate_dest_description">Adds initial stop</string>
<string name="subsequent_dest_description">Move destination up, and create it</string> <string name="subsequent_dest_description">Move destination up, and create it</string>
<string name="show_closed_notes">Show closed notes</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="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="osc_file_desc">OSC - suitable for export to OSM.</string>
<string name="shared_string_gpx_file">GPX file</string> <string name="shared_string_gpx_file">GPX file</string>
@ -1335,7 +1340,7 @@
<string name="measurement_tool_save_as_new_track_descr">Save the points either as route points or as a line.</string> <string name="measurement_tool_save_as_new_track_descr">Save the points either as route points or as a line.</string>
<string name="choose_navigation_type">Select navigation profile</string> <string name="choose_navigation_type">Select navigation profile</string>
<string name="none_point_error">Please add at least one point.</string> <string name="none_point_error">Please add at least one point.</string>
<string name="enter_gpx_name">GPX file name:</string> <string name="enter_gpx_name">GPX filename:</string>
<string name="show_on_map_after_saving">Show on map after saving</string> <string name="show_on_map_after_saving">Show on map after saving</string>
<string name="measurement_tool_action_bar">Browse the map and add points</string> <string name="measurement_tool_action_bar">Browse the map and add points</string>
<string name="measurement_tool">Measure distance</string> <string name="measurement_tool">Measure distance</string>
@ -3826,7 +3831,7 @@
<string name="number_of_contributors">Number of contributors</string> <string name="number_of_contributors">Number of contributors</string>
<string name="number_of_edits">Number of edits</string> <string name="number_of_edits">Number of edits</string>
<string name="reports_for">Report for</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="configure_screen_quick_action">Quick action</string>
<string name="quick_action_item_action">Action %d</string> <string name="quick_action_item_action">Action %d</string>
<string name="quick_action_item_screen">Screen %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_name">No cobblestone or sett</string>
<string name="routing_attr_avoid_sett_description">Avoids cobblestone and 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="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_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_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_name">Ski touring</string>
<string name="routing_attr_piste_type_skitour_description">Routes for 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; 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) { public static float getFreeSpaceGb(File dir) {
if (dir.canRead()) { if (dir.canRead()) {
StatFs fs = new StatFs(dir.getAbsolutePath()); StatFs fs = new StatFs(dir.getAbsolutePath());

View file

@ -22,7 +22,6 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.Space; import android.widget.Space;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -36,7 +35,6 @@ import androidx.fragment.app.FragmentActivity;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.IProgress;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.access.AccessibilityAssistant; import net.osmand.access.AccessibilityAssistant;
@ -45,7 +43,6 @@ import net.osmand.data.PointDescription;
import net.osmand.map.WorldRegion; import net.osmand.map.WorldRegion;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.activities.LocalIndexInfo; 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;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType; import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.openseamapsplugin.NauticalMapsPlugin; 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.srtmplugin.SRTMPlugin;
import net.osmand.plus.views.controls.PagerSlidingTabStrip; import net.osmand.plus.views.controls.PagerSlidingTabStrip;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -390,7 +389,6 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
|| application.getSettings().SHOULD_SHOW_FREE_VERSION_BANNER.get(); || application.getSettings().SHOULD_SHOW_FREE_VERSION_BANNER.get();
} }
public static class FreeVersionBanner { public static class FreeVersionBanner {
private final View freeVersionBanner; private final View freeVersionBanner;
private final View freeVersionBannerTitle; private final View freeVersionBannerTitle;
@ -441,7 +439,7 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
freeVersionBanner.setVisibility(View.VISIBLE); freeVersionBanner.setVisibility(View.VISIBLE);
downloadsLeftProgressBar.setMax(DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS); downloadsLeftProgressBar.setMax(DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS);
freeVersionDescriptionTextView.setText(ctx.getString(R.string.free_version_message, freeVersionDescriptionTextView.setText(ctx.getString(R.string.free_version_message,
DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS +"" )); DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS + ""));
LinearLayout marksLinearLayout = (LinearLayout) freeVersionBanner.findViewById(R.id.marksLinearLayout); LinearLayout marksLinearLayout = (LinearLayout) freeVersionBanner.findViewById(R.id.marksLinearLayout);
Space spaceView = new Space(ctx); Space spaceView = new Space(ctx);
@ -493,6 +491,7 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
freeVersionBannerTitle.setVisibility(View.VISIBLE); freeVersionBannerTitle.setVisibility(View.VISIBLE);
} }
} }
private void updateAvailableDownloads() { private void updateAvailableDownloads() {
int activeTasks = ctx.getDownloadThread().getCountedDownloads(); int activeTasks = ctx.getDownloadThread().getCountedDownloads();
OsmandSettings settings = ctx.getMyApplication().getSettings(); OsmandSettings settings = ctx.getMyApplication().getSettings();
@ -570,36 +569,26 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
} }
} }
@SuppressLint("StaticFieldLeak")
public void reloadLocalIndexes() { 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 @Override
protected void onPreExecute() { public void reloadIndexesStarted() {
super.onPreExecute();
setSupportProgressBarIndeterminateVisibility(true); setSupportProgressBarIndeterminateVisibility(true);
} }
@Override @Override
protected List<String> doInBackground(Void... params) { public void reloadIndexesFinished(List<String> warnings) {
return getMyApplication().getResourceManager().reloadIndexes(IProgress.EMPTY_PROGRESS,
new ArrayList<String>()
);
}
@Override
protected void onPostExecute(List<String> warnings) {
setSupportProgressBarIndeterminateVisibility(false); setSupportProgressBarIndeterminateVisibility(false);
if (!warnings.isEmpty()) { if (!Algorithms.isEmpty(warnings)) {
Toast.makeText(DownloadActivity.this, AndroidUtils.formatWarnings(warnings).toString(), Toast.LENGTH_LONG).show(); app.showToastMessage(AndroidUtils.formatWarnings(warnings).toString());
} }
newDownloadIndexes(); newDownloadIndexes();
} }
}; });
task.executeOnExecutor(singleThreadExecutor); reloadIndexesTask.executeOnExecutor(singleThreadExecutor);
} }
public void setDownloadItem(WorldRegion region, String targetFileName) { public void setDownloadItem(WorldRegion region, String targetFileName) {
if (downloadItem == null) { if (downloadItem == null) {
downloadItem = region; downloadItem = region;
@ -666,8 +655,8 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
int percent = 0; int percent = 0;
if (dir.canRead()) { if (dir.canRead()) {
StatFs fs = new StatFs(dir.getAbsolutePath()); StatFs fs = new StatFs(dir.getAbsolutePath());
size = AndroidUtils.formatSize(activity, ((long)fs.getAvailableBlocks()) * fs.getBlockSize()); size = AndroidUtils.formatSize(activity, ((long) fs.getAvailableBlocks()) * fs.getBlockSize());
percent = 100 - (int)((long)fs.getAvailableBlocks() * 100 / fs.getBlockCount()); percent = 100 - (int) ((long) fs.getAvailableBlocks() * 100 / fs.getBlockCount());
} }
sizeProgress.setIndeterminate(false); sizeProgress.setIndeterminate(false);
sizeProgress.setProgress(percent); sizeProgress.setProgress(percent);

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 { public enum ExportSettingsType {
PROFILE(R.string.shared_string_profiles, R.drawable.ic_action_manage_profiles), 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), 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), 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), SEARCH_HISTORY(R.string.shared_string_search_history, R.drawable.ic_action_history),
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), 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), 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_NOTES(R.string.osm_notes, R.drawable.ic_action_openstreetmap_logo),
OSM_EDITS(R.string.osm_edits, 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), MULTIMEDIA_NOTES(R.string.audionotes_plugin_name, R.drawable.ic_grouped_by_type),
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), 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 @StringRes
private final int titleId; private final int titleId;
@ -46,7 +47,8 @@ public enum ExportSettingsType {
} }
public boolean isSettingsCategory() { 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() { 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.FileNameTranslationHelper;
import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo; 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.MapMarker;
import net.osmand.plus.mapmarkers.MapMarkersGroup; import net.osmand.plus.mapmarkers.MapMarkersGroup;
import net.osmand.plus.osmedit.OpenstreetmapPoint; import net.osmand.plus.osmedit.OpenstreetmapPoint;
@ -504,12 +506,15 @@ public class SettingsHelper {
List<ExportDataObject> resourcesItems = getResourcesItems(); List<ExportDataObject> resourcesItems = getResourcesItems();
if (!settingsItems.isEmpty()) { if (!settingsItems.isEmpty()) {
sortExportSettingsObjects(settingsItems);
dataList.put(ExportSettingsCategory.SETTINGS, settingsItems); dataList.put(ExportSettingsCategory.SETTINGS, settingsItems);
} }
if (!myPlacesItems.isEmpty()) { if (!myPlacesItems.isEmpty()) {
sortExportSettingsObjects(myPlacesItems);
dataList.put(ExportSettingsCategory.MY_PLACES, myPlacesItems); dataList.put(ExportSettingsCategory.MY_PLACES, myPlacesItems);
} }
if (!resourcesItems.isEmpty()) { if (!resourcesItems.isEmpty()) {
sortExportSettingsObjects(resourcesItems);
dataList.put(ExportSettingsCategory.RESOURCES, resourcesItems); dataList.put(ExportSettingsCategory.RESOURCES, resourcesItems);
} }
@ -537,7 +542,14 @@ public class SettingsHelper {
if (!poiList.isEmpty()) { if (!poiList.isEmpty()) {
settingsItems.add(new ExportDataObject(ExportSettingsType.POI_TYPES, poiList)); 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; return settingsItems;
} }
@ -653,10 +665,6 @@ public class SettingsHelper {
if (!files.isEmpty()) { if (!files.isEmpty()) {
resourcesItems.add(new ExportDataObject(ExportSettingsType.VOICE, files)); 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; return resourcesItems;
} }
@ -699,6 +707,7 @@ public class SettingsHelper {
List<OpenstreetmapPoint> osmEditsPointList = new ArrayList<>(); List<OpenstreetmapPoint> osmEditsPointList = new ArrayList<>();
List<MapMarkersGroup> markersGroups = new ArrayList<>(); List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>(); List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> historyEntries = new ArrayList<>();
for (Object object : data) { for (Object object : data) {
if (object instanceof QuickAction) { if (object instanceof QuickAction) {
@ -730,6 +739,8 @@ public class SettingsHelper {
} else if (ExportSettingsType.HISTORY_MARKERS.name().equals(markersGroup.getId())) { } else if (ExportSettingsType.HISTORY_MARKERS.name().equals(markersGroup.getId())) {
markersHistoryGroups.add((MapMarkersGroup) object); markersHistoryGroups.add((MapMarkersGroup) object);
} }
} else if (object instanceof HistoryEntry) {
historyEntries.add((HistoryEntry) object);
} }
} }
if (!quickActions.isEmpty()) { if (!quickActions.isEmpty()) {
@ -775,6 +786,9 @@ public class SettingsHelper {
} }
settingsItems.add(new HistoryMarkersSettingsItem(app, mapMarkers)); settingsItems.add(new HistoryMarkersSettingsItem(app, mapMarkers));
} }
if (!historyEntries.isEmpty()) {
settingsItems.add(new SearchHistorySettingsItem(app, historyEntries));
}
return settingsItems; return settingsItems;
} }
@ -797,12 +811,15 @@ public class SettingsHelper {
} }
} }
if (!settingsItems.isEmpty()) { if (!settingsItems.isEmpty()) {
sortExportSettingsObjects(settingsItems);
exportMap.put(ExportSettingsCategory.SETTINGS, settingsItems); exportMap.put(ExportSettingsCategory.SETTINGS, settingsItems);
} }
if (!myPlacesItems.isEmpty()) { if (!myPlacesItems.isEmpty()) {
sortExportSettingsObjects(myPlacesItems);
exportMap.put(ExportSettingsCategory.MY_PLACES, myPlacesItems); exportMap.put(ExportSettingsCategory.MY_PLACES, myPlacesItems);
} }
if (!resourcesItems.isEmpty()) { if (!resourcesItems.isEmpty()) {
sortExportSettingsObjects(resourcesItems);
exportMap.put(ExportSettingsCategory.RESOURCES, resourcesItems); exportMap.put(ExportSettingsCategory.RESOURCES, resourcesItems);
} }
@ -829,6 +846,7 @@ public class SettingsHelper {
List<FavoriteGroup> favoriteGroups = new ArrayList<>(); List<FavoriteGroup> favoriteGroups = new ArrayList<>();
List<MapMarkersGroup> markersGroups = new ArrayList<>(); List<MapMarkersGroup> markersGroups = new ArrayList<>();
List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>(); List<MapMarkersGroup> markersHistoryGroups = new ArrayList<>();
List<HistoryEntry> historyEntries = new ArrayList<>();
for (SettingsItem item : settingsItems) { for (SettingsItem item : settingsItems) {
switch (item.getType()) { switch (item.getType()) {
@ -916,6 +934,10 @@ public class SettingsHelper {
HistoryMarkersSettingsItem historyMarkersSettingsItem = (HistoryMarkersSettingsItem) item; HistoryMarkersSettingsItem historyMarkersSettingsItem = (HistoryMarkersSettingsItem) item;
markersHistoryGroups.add(historyMarkersSettingsItem.getMarkersGroup()); markersHistoryGroups.add(historyMarkersSettingsItem.getMarkersGroup());
break; break;
case SEARCH_HISTORY:
SearchHistorySettingsItem searchHistorySettingsItem = (SearchHistorySettingsItem) item;
historyEntries.addAll(searchHistorySettingsItem.getItems());
break;
default: default:
break; break;
} }
@ -972,9 +994,12 @@ public class SettingsHelper {
if (!markersGroups.isEmpty()) { if (!markersGroups.isEmpty()) {
settingsToOperate.put(ExportSettingsType.ACTIVE_MARKERS, markersGroups); settingsToOperate.put(ExportSettingsType.ACTIVE_MARKERS, markersGroups);
} }
if (!markersGroups.isEmpty()) { if (!markersHistoryGroups.isEmpty()) {
settingsToOperate.put(ExportSettingsType.HISTORY_MARKERS, markersHistoryGroups); settingsToOperate.put(ExportSettingsType.HISTORY_MARKERS, markersHistoryGroups);
} }
if (!historyEntries.isEmpty()) {
settingsToOperate.put(ExportSettingsType.SEARCH_HISTORY, historyEntries);
}
return settingsToOperate; 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; package net.osmand.plus.settings.fragments;
import androidx.annotation.NonNull;
import net.osmand.plus.settings.backend.ExportSettingsType; import net.osmand.plus.settings.backend.ExportSettingsType;
import java.util.List; import java.util.List;
@ -9,7 +11,7 @@ public class ExportDataObject {
private ExportSettingsType type; private ExportSettingsType type;
private List<?> items; private List<?> items;
public ExportDataObject(ExportSettingsType type, List<?> items) { public ExportDataObject(@NonNull ExportSettingsType type, @NonNull List<?> items) {
this.type = type; this.type = type;
this.items = items; this.items = items;
} }

View file

@ -4,6 +4,8 @@ import android.content.res.ColorStateList;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@ -11,16 +13,33 @@ import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat; import androidx.core.widget.CompoundButtonCompat;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.map.ITileSource;
import net.osmand.plus.FavouritesDbHelper.FavoriteGroup;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter; import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.audionotes.AudioVideoNotesPlugin;
import net.osmand.plus.helpers.FontCache; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.settings.backend.ExportSettingsCategory; 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.ExportSettingsType;
import net.osmand.plus.settings.backend.backup.FileSettingsItem; 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 net.osmand.view.ThreeStateCheckbox;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -29,10 +48,11 @@ import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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.CHECKED;
import static net.osmand.view.ThreeStateCheckbox.State.MISC; import static net.osmand.view.ThreeStateCheckbox.State.MISC;
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED; import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
@ -40,94 +60,91 @@ import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
private static final Log LOG = PlatformUtil.getLog(ExportImportSettingsAdapter.class.getName()); 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; ExportImportSettingsAdapter(OsmandApplication app, boolean nightMode, boolean importState) {
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.app = app;
this.listener = listener;
this.nightMode = nightMode; this.nightMode = nightMode;
this.importState = importState;
this.itemsMap = new HashMap<>();
this.itemsTypes = new ArrayList<>();
this.data = new ArrayList<>();
uiUtilities = app.getUIUtilities(); uiUtilities = app.getUIUtilities();
themedInflater = UiUtilities.getInflater(app, nightMode); activeColorRes = nightMode
activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light; ? R.color.icon_color_active_dark
secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light; : R.color.icon_color_active_light;
secondaryColorRes = nightMode
? R.color.icon_color_secondary_dark
: R.color.icon_color_secondary_light;
} }
@Override @Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View group = convertView; View group = convertView;
if (group == null) { 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); 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); 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); final ThreeStateCheckbox checkBox = group.findViewById(R.id.check_box);
if (selectedTypes == 0) { FrameLayout checkBoxContainer = group.findViewById(R.id.check_box_container);
checkBox.setState(UNCHECKED); 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 { } 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; int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes;
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor))); 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 @Override
public void onClick(View view) { public void onClick(View view) {
checkBox.performClick(); checkBox.performClick();
boolean selected = checkBox.getState() == CHECKED; if (checkBox.getState() == CHECKED) {
if (selected) { for (Object object : listItems) {
for (ExportDataObject object : items) { if (!data.contains(object)) {
if (!selectedItemsMap.containsKey(object.getType())) { data.add(object);
selectedItemsMap.put(object.getType(), (List<Object>) object.getItems());
} }
} }
} else { } else {
for (ExportDataObject object : items) { data.removeAll(listItems);
selectedItemsMap.remove(object.getType());
}
}
if (listener != null) {
listener.onCategorySelected(category, selected);
} }
notifyDataSetChanged(); notifyDataSetChanged();
} }
}); });
adjustIndicator(app, groupPosition, isExpanded, group, nightMode); 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; return group;
} }
@ -135,57 +152,172 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View child = convertView; View child = convertView;
if (child == null) { 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); final Object currentItem = itemsMap.get(itemsTypes.get(groupPosition)).get(childPosition);
List<Object> selectedItems = selectedItemsMap.get(currentItem.getType());
TextView titleTv = child.findViewById(R.id.title_tv); boolean isLastGroup = groupPosition == getGroupCount() - 1;
titleTv.setText(currentItem.getType().getTitleId()); boolean itemSelected = data.contains(currentItem);
final ExportSettingsType type = itemsTypes.get(groupPosition);
TextView subTextTv = child.findViewById(R.id.sub_text_tv); TextView title = child.findViewById(R.id.title_tv);
subTextTv.setText(getSelectedTypeDescr(currentItem)); 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); lineDivider.setVisibility(!importState && isLastChild && !isLastGroup ? View.VISIBLE : View.GONE);
setupIcon(icon, currentItem.getType().getIconRes(), selectedItems != null); cardBottomDivider.setVisibility(importState && isLastChild ? View.VISIBLE : View.GONE);
int checkBoxColor = itemSelected ? activeColorRes : secondaryColorRes;
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))); 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 @Override
public void onClick(View view) { public void onClick(View view) {
checkBox.performClick(); if (data.contains(currentItem)) {
boolean selected = checkBox.getState() == CHECKED; data.remove(currentItem);
if (selected) {
selectedItemsMap.put(currentItem.getType(), (List<Object>) currentItem.getItems());
} else { } else {
selectedItemsMap.remove(currentItem.getType()); data.add(currentItem);
}
if (listener != null) {
listener.onTypeSelected(currentItem.getType(), selected);
} }
notifyDataSetChanged(); 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; return child;
} }
@ -229,16 +361,80 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
return true; return true;
} }
private void setupIcon(ImageView icon, int iconRes, boolean itemSelected) { private String getSelectedItemsAmount(List<?> listItems, ExportSettingsType type) {
if (itemSelected) { int amount = 0;
int colorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_osmand_light; long amountSize = 0;
icon.setImageDrawable(uiUtilities.getIcon(iconRes, colorRes)); for (Object item : listItems) {
} else { if (data.contains(item)) {
icon.setImageDrawable(uiUtilities.getIcon(iconRes, secondaryColorRes)); 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;
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.itemsMap = itemsMap;
this.itemsTypes = new ArrayList<>(itemsMap.keySet()); this.itemsTypes = new ArrayList<>(itemsMap.keySet());
Collections.sort(itemsTypes); Collections.sort(itemsTypes);
@ -251,90 +447,17 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter {
notifyDataSetChanged(); notifyDataSetChanged();
} }
public List<? super Object> getData() { public void selectAll(boolean selectAll) {
List<Object> selectedItems = new ArrayList<>(); data.clear();
for (List<?> items : selectedItemsMap.values()) { if (selectAll) {
selectedItems.addAll(items); for (List<?> values : itemsMap.values()) {
} data.addAll(values);
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());
} }
} }
notifyDataSetChanged();
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) { List<? super Object> getData() {
long itemsSize = 0; return this.data;
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

@ -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.R;
import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.BaseOsmAndFragment; 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.ApplicationMode;
import net.osmand.plus.settings.backend.ExportSettingsCategory; import net.osmand.plus.settings.backend.ExportSettingsCategory;
import net.osmand.plus.settings.backend.ExportSettingsType; import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.backup.FileSettingsItem; import net.osmand.plus.settings.backend.backup.FileSettingsItem;
import net.osmand.plus.settings.backend.backup.SettingsHelper.SettingsExportListener; import net.osmand.plus.settings.backend.backup.SettingsHelper.SettingsExportListener;
import net.osmand.plus.settings.backend.backup.SettingsItem; 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 net.osmand.plus.widgets.TextViewEx;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -78,10 +79,15 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
private ApplicationMode appMode; private ApplicationMode appMode;
private SettingsExportListener exportListener; 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 LinearLayout buttonsContainer;
private ExpandableListView expandableList; private ExpandableListView expandableList;
private ExportImportSettingsAdapter adapter; private ExportSettingsAdapter adapter;
private int progressMax; private int progressMax;
private int progressValue; private int progressValue;
@ -127,16 +133,23 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
View root = themedInflater.inflate(R.layout.fragment_import, container, false); View root = themedInflater.inflate(R.layout.fragment_import, container, false);
AndroidUtils.addStatusBarPadding21v(app, root); 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); expandableList = root.findViewById(R.id.list);
buttonsContainer = root.findViewById(R.id.buttons_container); buttonsContainer = root.findViewById(R.id.buttons_container);
Toolbar toolbar = root.findViewById(R.id.toolbar); Toolbar toolbar = root.findViewById(R.id.toolbar);
setupToolbar(toolbar); setupToolbar(toolbar);
ViewCompat.setNestedScrollingEnabled(expandableList, true); ViewCompat.setNestedScrollingEnabled(expandableList, true);
View header = themedInflater.inflate(R.layout.list_item_description_header, null); 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); 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); TextViewEx continueBtn = root.findViewById(R.id.continue_button);
continueBtn.setOnClickListener(new View.OnClickListener() { continueBtn.setOnClickListener(new View.OnClickListener() {
@Override @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); adapter.updateSettingsList(dataList);
expandableList.setAdapter(adapter); expandableList.setAdapter(adapter);
@ -169,6 +182,7 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
toolbarLayout.setTitle(getString(R.string.shared_string_export)); toolbarLayout.setTitle(getString(R.string.shared_string_export));
TextView description = header.findViewById(R.id.description); TextView description = header.findViewById(R.id.description);
description.setText(R.string.select_data_to_export); description.setText(R.string.select_data_to_export);
updateAvailableSpace();
return root; return root;
} }
@ -235,20 +249,50 @@ public class ExportSettingsFragment extends BaseOsmAndFragment implements OnItem
}); });
} }
private void updateFileSize() { private void updateAvailableSpace() {
long itemsSize = ExportImportSettingsAdapter.calculateItemsSize(adapter.getData()); long calculatedSize = ExportSettingsAdapter.calculateItemsSize(adapter.getData());
String size = itemsSize != 0 ? AndroidUtils.formatSize(app, itemsSize) : ""; if (calculatedSize != 0) {
fileSize.setText(size); 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 @Override
public void onCategorySelected(ExportSettingsCategory type, boolean selected) { public void onCategorySelected(ExportSettingsCategory type, boolean selected) {
updateFileSize(); updateAvailableSpace();
} }
@Override @Override
public void onTypeSelected(ExportSettingsType type, boolean selected) { public void onTypeSelected(ExportSettingsType type, boolean selected) {
updateFileSize(); updateAvailableSpace();
} }
private void prepareFile() { private void prepareFile() {

View file

@ -22,13 +22,13 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat; import androidx.core.view.ViewCompat;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.material.appbar.CollapsingToolbarLayout;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.IProgress;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.map.ITileSource; import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager.TileSourceTemplate; 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.poi.PoiUIFilter;
import net.osmand.plus.quickaction.QuickAction; import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean; 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.ExportSettingsType;
import net.osmand.plus.settings.backend.backup.AvoidRoadsSettingsItem; import net.osmand.plus.settings.backend.backup.AvoidRoadsSettingsItem;
import net.osmand.plus.settings.backend.backup.FavoritesSettingsItem; 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.SettingsHelper.ImportType;
import net.osmand.plus.settings.backend.backup.SettingsItem; import net.osmand.plus.settings.backend.backup.SettingsItem;
import net.osmand.plus.settings.backend.backup.SettingsItemType; 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.plus.widgets.TextViewEx;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import java.io.File; import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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 String TAG = ImportSettingsFragment.class.getSimpleName();
public static final Log LOG = PlatformUtil.getLog(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 String DUPLICATES_START_TIME_KEY = "duplicates_start_time";
private static final long MIN_DELAY_TIME_MS = 500; private static final long MIN_DELAY_TIME_MS = 500;
static final String IMPORT_SETTINGS_TAG = "import_settings_tag";
private OsmandApplication app; private OsmandApplication app;
private File file;
private SettingsHelper settingsHelper;
private List<SettingsItem> settingsItems;
private Map<ExportSettingsCategory, List<ExportDataObject>> dataList;
private ExportImportSettingsAdapter adapter; private ExportImportSettingsAdapter adapter;
private ExpandableListView expandableList; private ExpandableListView expandableList;
private TextView description; private TextView description;
private List<SettingsItem> settingsItems;
private File file;
private boolean allSelected;
private boolean nightMode;
private LinearLayout buttonsContainer; private LinearLayout buttonsContainer;
private ProgressBar progressBar; private ProgressBar progressBar;
private TextViewEx fileSize;
private TextViewEx fileSizeDescr;
private CollapsingToolbarLayout toolbarLayout; private CollapsingToolbarLayout toolbarLayout;
private SettingsHelper settingsHelper;
private boolean nightMode;
private long duplicateStartTime; private long duplicateStartTime;
public static void showInstance(@NonNull FragmentManager fm, @NonNull List<SettingsItem> settingsItems, @NonNull File file) { 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); View root = inflater.inflate(R.layout.fragment_import, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar); Toolbar toolbar = root.findViewById(R.id.toolbar);
TextViewEx continueBtn = root.findViewById(R.id.continue_button); TextViewEx continueBtn = root.findViewById(R.id.continue_button);
fileSize = root.findViewById(R.id.file_size);
toolbarLayout = root.findViewById(R.id.toolbar_layout); toolbarLayout = root.findViewById(R.id.toolbar_layout);
expandableList = root.findViewById(R.id.list); expandableList = root.findViewById(R.id.list);
buttonsContainer = root.findViewById(R.id.buttons_container); buttonsContainer = root.findViewById(R.id.buttons_container);
progressBar = root.findViewById(R.id.progress_bar); 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); setupToolbar(toolbar);
ViewCompat.setNestedScrollingEnabled(expandableList, true); ViewCompat.setNestedScrollingEnabled(expandableList, true);
View header = inflater.inflate(R.layout.list_item_description_header, null); 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); adapter = new ExportImportSettingsAdapter(app, nightMode, true);
Map<ExportSettingsCategory, List<ExportDataObject>> itemsMap = new HashMap<>(); Map<ExportSettingsType, List<?>> itemsMap = new HashMap<>();
if (settingsItems != null) { if (settingsItems != null) {
itemsMap = SettingsHelper.getSettingsToOperateByCategory(settingsItems, false); itemsMap = SettingsHelper.getSettingsToOperate(settingsItems, false);
adapter.updateSettingsList(itemsMap); adapter.updateSettingsList(itemsMap);
} }
expandableList.setAdapter(adapter); expandableList.setAdapter(adapter);
@ -227,7 +216,7 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
} else { } else {
toolbarLayout.setTitle(getString(R.string.shared_string_import)); 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); expandableList.expandGroup(0);
} }
} }
@ -238,6 +227,15 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
outState.putLong(DUPLICATES_START_TIME_KEY, duplicateStartTime); 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) { private void updateUi(int toolbarTitleRes, int descriptionRes) {
if (file != null) { if (file != null) {
String fileName = file.getName(); 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() { private SettingsHelper.CheckDuplicatesListener getDuplicatesListener() {
return new SettingsHelper.CheckDuplicatesListener() { return new SettingsHelper.CheckDuplicatesListener() {
@Override @Override
@ -519,8 +542,9 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
} }
private void setupToolbar(Toolbar toolbar) { 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, nightMode
toolbar.setNavigationIcon(getPaintedContentIcon(R.drawable.ic_action_close, color)); ? 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.setNavigationContentDescription(R.string.shared_string_close);
toolbar.setNavigationOnClickListener(new View.OnClickListener() { toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override @Override
@ -533,20 +557,4 @@ public class ImportSettingsFragment extends BaseOsmAndFragment implements OnItem
public void setFile(File file) { public void setFile(File file) {
this.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();
}
}
}