Merge branch 'master' into testing-purchase

This commit is contained in:
cepprice 2021-03-24 12:40:54 +05:00 committed by GitHub
commit 6c31d95649
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
115 changed files with 4933 additions and 1800 deletions

View file

@ -1117,8 +1117,8 @@ public class RouteResultPreparation {
if (UNMATCHED_HIGHWAY_TYPE.equals(rr.getObject().getHighway())) {
bearingDist = RouteSegmentResult.DIST_BEARING_DETECT_UNMATCHED;
}
double mpi = MapUtils.degreesDiff(prev.getBearingEnd(prev.getEndPointIndex(), bearingDist),
rr.getBearingBegin(rr.getStartPointIndex(), bearingDist));
double mpi = MapUtils.degreesDiff(prev.getBearingEnd(prev.getEndPointIndex(), Math.min(prev.getDistance(), bearingDist)),
rr.getBearingBegin(rr.getStartPointIndex(), Math.min(rr.getDistance(), bearingDist)));
if (mpi >= TURN_DEGREE_MIN) {
if (mpi < TURN_DEGREE_MIN) {
// Slight turn detection here causes many false positives where drivers would expect a "normal" TL. Best use limit-angle=TURN_DEGREE_MIN, this reduces TSL to the turn-lanes cases.

View file

@ -457,7 +457,7 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
}
public float getBearingBegin() {
return getBearingBegin(startPointIndex, DIST_BEARING_DETECT);
return getBearingBegin(startPointIndex, distance > 0 && distance < DIST_BEARING_DETECT ? distance : DIST_BEARING_DETECT);
}
public float getBearingBegin(int point, float dist) {
@ -465,7 +465,7 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
}
public float getBearingEnd() {
return getBearingEnd(endPointIndex, DIST_BEARING_DETECT);
return getBearingEnd(endPointIndex, distance > 0 && distance < DIST_BEARING_DETECT ? distance : DIST_BEARING_DETECT);
}
public float getBearingEnd(int point, float dist) {

View file

@ -10,8 +10,6 @@ import net.osmand.router.GeneralRouter.RouteDataObjectAttribute;
public class TransportRoutingConfiguration {
public static final String KEY = "public_transport";
public int ZOOM_TO_LOAD_TILES = 15;
public int walkRadius = 1500; // ? 3000

View file

@ -39,7 +39,7 @@
<string name="shared_string_share">Κοινοποίηση</string>
<string name="shared_string_back">Προηγούμενο</string>
<string name="shared_string_continue">Συνέχεια</string>
<string name="shared_string_cancel">Ακύρωση</string>
<string name="shared_string_cancel">Άκυρο</string>
<string name="shared_string_settings">Επιλογές</string>
<string name="shared_string_enabled">Ενεργοποιημένο</string>
<string name="units_and_formats">Μονάδες μέτρησης &amp; φορμά</string>

View file

@ -213,7 +213,7 @@
<string name="by_group">Par groupe</string>
<string name="by_distance">Par distance</string>
<string name="logout_from_osmand_telegram">Se déconnecter d\'OsmAnd Tracker \?</string>
<string name="logout_from_osmand_telegram_descr">Êtes-vous sûr·e de vouloir vous déconnecter d\'OsmAnd Tracker ; vous ne pourrez pas partager votre position ni vous la position des autres \?</string>
<string name="logout_from_osmand_telegram_descr">Êtes-vous certain de vouloir vous déconnecter d\'OsmAnd Tracker \? Vous ne pourrez pas partager votre position ni voir la position des autres.</string>
<string name="live_now_description">Contacts et groupes partageant leur position avec vous.</string>
<string name="share_location_as">Partager la position comme</string>
<string name="add_device">Ajouter un périphérique</string>

View file

@ -13,7 +13,7 @@
<string name="si_km_m">Kilomter/meter</string>
<string name="si_mi_yard">Miles/yard</string>
<string name="si_mi_feet">Miles/fot</string>
<string name="si_nm_h">Distansminuter per timme (knop)</string>
<string name="si_nm_h">Sjömil per timme (knop)</string>
<string name="si_min_m">Minuter per mile</string>
<string name="si_min_km">Minuter per kilometer</string>
<string name="si_m_s">Meter per sekund</string>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/switch_button_active_light" />
<corners android:radius="4dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/switch_button_active_dark" />
<corners android:radius="4dp" />
</shape>

View file

@ -0,0 +1,63 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M22,2V19C22,20.6569 20.6569,22 19,22H5C3.3431,22 2,20.6569 2,19V2H4V18H20V2H22Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M13,14.2C13,14.0895 13.0895,14 13.2,14H17.8C17.9105,14 18,14.0895 18,14.2V15.8C18,15.9105 17.9105,16 17.8,16H13.2C13.0895,16 13,15.9105 13,15.8V14.2Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M6,6H9V8H6V6Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M11,6H18V8H11V6Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M4,4H20V2H4V4Z"
android:strokeAlpha="0.7"
android:fillColor="#ffffff"
android:fillAlpha="0.7"/>
<path
android:pathData="M4,4H20V18H4V4Z"
android:strokeAlpha="0.1"
android:fillColor="#ffffff"
android:fillAlpha="0.1"/>
<path
android:pathData="M6,9H11V10H6V9Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M6,11H7V12H6V11Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M12,9H14V10H12V9Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M15,9H18V10H15V9Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M8,11H12V12H8V11Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M13,11H18V12H13V11Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M6.2,14C6.0895,14 6,14.0895 6,14.2V15.8C6,15.9105 6.0895,16 6.2,16H10.8C10.9105,16 11,15.9105 11,15.8V14.2C11,14.0895 10.9105,14 10.8,14H6.2Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
</vector>

View file

@ -3,14 +3,13 @@
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
tools:background="@drawable/btn_background_inactive_dark">
<LinearLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="@dimen/bottom_sheet_list_item_height"
android:orientation="horizontal"
@ -20,7 +19,6 @@
android:paddingEnd="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding_small"
android:paddingBottom="@dimen/text_margin_small"
tools:background="@drawable/btn_background_inactive_dark"
tools:ignore="UselessParent">
<LinearLayout

View file

@ -4,80 +4,94 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:baselineAligned="false"
android:gravity="center_vertical"
android:minHeight="@dimen/bottom_sheet_selected_item_title_height">
android:minHeight="@dimen/bottom_sheet_list_item_height">
<LinearLayout
android:id="@+id/basic_item_body"
<androidx.cardview.widget.CardView
android:id="@+id/compound_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
android:gravity="center_vertical"
app:cardCornerRadius="4dp"
app:cardElevation="0dp"
tools:cardBackgroundColor="?attr/switch_button_active">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal">
<TextView
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/context_menu_first_line_top_margin"
android:layout_marginBottom="@dimen/context_menu_first_line_top_margin"
android:layout_weight="1"
android:ellipsize="end"
android:letterSpacing="@dimen/description_letter_spacing"
android:maxLines="1"
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/default_desc_text_size"
app:typeface="@string/font_roboto_medium"
tools:text="Some title" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/compound_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:paddingTop="@dimen/content_padding_small"
android:paddingBottom="@dimen/content_padding"
android:textAppearance="@style/TextAppearance.ListItemTitle"
tools:text="Some title" />
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/bottom_sheet_content_margin"
android:layout_marginLeft="@dimen/bottom_sheet_content_margin"
android:layout_marginEnd="@dimen/bottom_sheet_content_margin"
android:layout_marginRight="@dimen/bottom_sheet_content_margin"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
tools:checked="true" />
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/bottom_sheet_content_margin"
android:layout_marginLeft="@dimen/bottom_sheet_content_margin"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
tools:checked="true" />
</androidx.cardview.widget.CardView>
</LinearLayout>
<LinearLayout
android:id="@+id/additional_button"
<androidx.cardview.widget.CardView
android:id="@+id/additional_button_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
app:cardCornerRadius="4dp"
app:cardElevation="0dp"
tools:cardBackgroundColor="?attr/switch_button_active">
<View
android:layout_width="1dp"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginBottom="@dimen/content_padding_half"
android:background="?attr/divider_color_basic" />
android:background="?android:attr/selectableItemBackground">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon_after_divider"
style="@style/Widget.AppCompat.Toolbar.Button.Navigation"
android:layout_width="@dimen/favorites_icon_right_margin"
android:layout_height="@dimen/favorites_icon_right_margin"
android:layout_gravity="center"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
app:srcCompat="@drawable/ic_action_track_line_bold_color" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/additional_button_icon"
android:layout_width="@dimen/favorites_icon_right_margin"
android:layout_height="@dimen/favorites_icon_right_margin"
android:layout_gravity="center"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
app:srcCompat="@drawable/ic_action_track_line_bold_color"
tools:tint="?attr/active_color_basic" />
</LinearLayout>
</FrameLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>

View file

@ -52,7 +52,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/average_range"
android:id="@+id/top_line_blocks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
@ -171,7 +171,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ascent_descent"
android:id="@+id/bottom_line_blocks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
@ -273,6 +273,7 @@
</LinearLayout>
<View
android:id="@+id/details_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />

View file

@ -52,7 +52,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/distance_time_span"
android:id="@+id/top_line_blocks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
@ -171,7 +171,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/start_end_time"
android:id="@+id/bottom_line_blocks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
@ -291,6 +291,7 @@
</LinearLayout>
<View
android:id="@+id/details_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />

View file

@ -52,7 +52,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/average_max"
android:id="@+id/top_line_blocks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
@ -172,7 +172,7 @@
<LinearLayout
android:id="@+id/time_distance"
android:id="@+id/bottom_line_blocks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
@ -275,6 +275,7 @@
</LinearLayout>
<View
android:id="@+id/details_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />

View file

@ -4,7 +4,9 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/list_item_divider" />
<include
android:id="@+id/list_item_divider"
layout="@layout/list_item_divider" />
<LinearLayout
android:layout_width="match_parent"

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="@dimen/context_menu_top_right_button_min_width"
android:minHeight="@dimen/setting_list_item_large_height"
app:cardCornerRadius="4dp"
app:cardElevation="0dp"
tools:cardBackgroundColor="?attr/switch_button_active">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:minWidth="@dimen/context_menu_top_right_button_min_width"
android:minHeight="@dimen/setting_list_item_large_height"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginTop="@dimen/content_padding_small"
android:layout_marginBottom="@dimen/content_padding_small_half"
tools:srcCompat="@drawable/ic_action_close"
tools:tint="?attr/active_color_basic" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding_small_half"
android:layout_marginLeft="@dimen/content_padding_small_half"
android:layout_marginEnd="@dimen/content_padding_small_half"
android:layout_marginRight="@dimen/content_padding_small_half"
android:layout_marginBottom="@dimen/content_padding_small_half"
android:letterSpacing="@dimen/description_letter_spacing"
app:typeface="@string/font_roboto_medium"
tools:text="Title"
tools:textColor="?attr/active_color_basic" />
</LinearLayout>
</androidx.cardview.widget.CardView>

View file

@ -0,0 +1,57 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:baselineAligned="false"
android:minHeight="@dimen/setting_list_item_large_height"
android:orientation="horizontal">
<include
android:id="@+id/button_left"
layout="@layout/preference_button_with_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:minWidth="@dimen/context_menu_top_right_button_min_width"
android:minHeight="@dimen/setting_list_item_large_height" />
<include
android:id="@+id/button_center_left"
layout="@layout/preference_button_with_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginStart="@dimen/content_padding_half"
android:layout_marginLeft="@dimen/content_padding_half"
android:minWidth="@dimen/context_menu_top_right_button_min_width"
android:minHeight="@dimen/setting_list_item_large_height" />
<include
android:id="@+id/button_center_right"
layout="@layout/preference_button_with_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/content_padding_half"
android:layout_weight="1"
android:layout_marginLeft="@dimen/content_padding_half"
android:minWidth="@dimen/context_menu_top_right_button_min_width"
android:minHeight="@dimen/setting_list_item_large_height" />
<include
android:id="@+id/button_right"
android:layout_weight="1"
layout="@layout/preference_button_with_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/content_padding_half"
android:layout_marginLeft="@dimen/content_padding_half"
android:minWidth="@dimen/context_menu_top_right_button_min_width"
android:minHeight="@dimen/setting_list_item_large_height" />
</LinearLayout>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:baselineAligned="false"
android:minHeight="@dimen/setting_list_item_large_height"
android:orientation="horizontal">
<include
android:id="@+id/button_left"
layout="@layout/preference_button_with_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="@dimen/context_menu_top_right_button_min_width"
android:minHeight="@dimen/setting_list_item_large_height" />
<include
android:id="@+id/button_center"
layout="@layout/preference_button_with_icon"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/content_padding_half"
android:layout_marginLeft="@dimen/content_padding_half"
android:layout_weight="1"
android:minHeight="@dimen/setting_list_item_large_height" />
<include
android:id="@+id/button_right"
layout="@layout/preference_button_with_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/content_padding_half"
android:layout_marginLeft="@dimen/content_padding_half"
android:minWidth="@dimen/context_menu_top_right_button_min_width"
android:minHeight="@dimen/setting_list_item_large_height" />
</LinearLayout>

View file

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_transparent">
<LinearLayout
android:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/context_menu_top_shadow" />
<LinearLayout
android:id="@+id/route_menu_top_shadow_all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:minHeight="@dimen/bottom_sheet_title_height"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<View
android:layout_width="@dimen/content_padding"
android:layout_height="2dp"
android:layout_gravity="center"
android:layout_marginTop="@dimen/context_menu_padding_margin_tiny"
android:layout_marginBottom="@dimen/list_item_button_padding"
android:background="?attr/bg_dash_line" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/header_title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:gravity="center_vertical"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
</LinearLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/bottom_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="@drawable/bg_contextmenu_shadow"
android:foregroundGravity="top|fill_horizontal">
<net.osmand.plus.LockableScrollView
android:id="@+id/route_menu_bottom_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/route_info_bg">
<LinearLayout
android:id="@+id/route_menu_cards_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/route_info_bg"
android:orientation="vertical"
android:paddingBottom="@dimen/dialog_button_ex_height" />
</net.osmand.plus.LockableScrollView>
</FrameLayout>
</LinearLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/context_menu_toolbar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_and_list_background_basic"
android:minHeight="@dimen/toolbar_height"
android:padding="0dp"
osmand:contentInsetEnd="0dp"
osmand:contentInsetLeft="0dp"
osmand:contentInsetRight="0dp"
osmand:contentInsetStart="0dp"
osmand:theme="@style/ThemeOverlay.AppCompat.ActionBar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="@dimen/toolbar_height">
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/close_button"
style="@style/Widget.AppCompat.Toolbar.Button.Navigation"
android:layout_width="@dimen/toolbar_height"
android:layout_height="@dimen/toolbar_height"
android:tint="?android:textColorPrimary"
android:contentDescription="@string/access_shared_string_navigate_up"
osmand:srcCompat="@drawable/ic_arrow_back" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/toolbar_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_weight="1"
android:ellipsize="end"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="2"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/dialog_header_text_size"
osmand:typeface="@string/font_roboto_medium"
android:text="@string/shared_string_route_line" />
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/context_menu_controls" />
<LinearLayout
android:id="@+id/control_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="8dp"
android:layout_gravity="bottom"
android:background="@drawable/shadow" />
<include
layout="@layout/bottom_buttons"
android:layout_width="match_parent"
android:layout_height="@dimen/dialog_button_ex_height"
android:layout_gravity="bottom" />
</LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
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:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:text="@string/shared_string_color"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/color_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Orange" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding_half"
android:paddingLeft="@dimen/content_padding_half"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
tools:itemCount="2"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/point_editor_group_select_item"
tools:orientation="horizontal" />
</LinearLayout>
<FrameLayout
android:id="@+id/theme_toggle_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/content_padding_small" >
<include layout="@layout/custom_radio_buttons" />
</FrameLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="Specify color for map mode: day." />
<FrameLayout
android:id="@+id/colors_card_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/content_padding_small"/>
</LinearLayout>

View file

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<View
android:id="@+id/top_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/divider_color_basic"
android:focusable="false" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:text="@string/select_track_width"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/width_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="21" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="@dimen/context_menu_padding_margin_tiny">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding_half"
android:paddingLeft="@dimen/content_padding_half"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
tools:itemCount="3"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/point_editor_group_select_item"
tools:orientation="horizontal" />
</LinearLayout>
<LinearLayout
android:id="@+id/slider_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/content_padding"
android:paddingBottom="@dimen/favorites_select_group_button_height">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:text="@string/shared_string_custom"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/width_value_tv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
tools:text="1" />
</LinearLayout>
<com.google.android.material.slider.Slider
android:id="@+id/width_slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:stepSize="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/width_value_min"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
tools:text="1" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/width_value_max"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:lineSpacingExtra="@dimen/line_spacing_extra_description"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_list_text_size"
tools:text="24" />
</LinearLayout>
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="Route line would be use width specified on selected map style: OsmAnd." />
</LinearLayout>

View file

@ -1,172 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
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:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:weightSum="2">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:text="@string/monitoring_settings"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/status_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:focusable="true"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/text_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/description_letter_spacing"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/recording_default_name"
tools:textColor="@color/icon_color_osmand_light" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon_status"
android:layout_width="@dimen/map_widget_icon"
android:layout_height="@dimen/map_widget_icon"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
tools:srcCompat="@drawable/ic_action_polygom_dark"
tools:tint="@color/icon_color_osmand_light" />
</LinearLayout>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/block_statistics"
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:layout_marginTop="@dimen/content_padding_small_half"
android:clipToPadding="false"
android:orientation="horizontal"
tools:itemCount="4"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_gpx_stat_block" />
<include
android:id="@+id/show_track_on_map"
layout="@layout/bottom_sheet_with_switch_divider_and_additional_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />
<include
android:id="@+id/button_clear"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding" />
<include
android:id="@+id/button_online"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding"
android:visibility="gone" />
<include
android:id="@+id/button_segment"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding" />
<include
android:id="@+id/button_save"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_small"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding"
android:baselineAligned="false"
android:orientation="horizontal"
android:weightSum="2">
<include
android:id="@+id/button_pause"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<include
android:id="@+id/button_stop"
layout="@layout/bottom_sheet_button_with_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>

View file

@ -1,117 +1,97 @@
<?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:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:orientation="vertical"
android:paddingBottom="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:text="@string/monitoring_settings"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
android:paddingBottom="@dimen/content_padding"
android:weightSum="2">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:text="@string/monitoring_settings"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/status_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:focusable="true"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/text_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/description_letter_spacing"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/recording_default_name"
tools:textColor="@color/icon_color_osmand_light" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon_status"
android:layout_width="@dimen/map_widget_icon"
android:layout_height="@dimen/map_widget_icon"
android:layout_marginStart="@dimen/content_padding_small"
android:layout_marginLeft="@dimen/content_padding_small"
tools:srcCompat="@drawable/ic_action_polygom_dark"
tools:tint="@color/icon_color_osmand_light" />
</LinearLayout>
</LinearLayout>
<include
android:id="@+id/show_track_on_map"
layout="@layout/bottom_sheet_with_switch_divider_and_additional_button" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />
<LinearLayout
android:id="@+id/interval_view_container"
android:background="?attr/selectableItemBackground"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/bottom_sheet_content_margin"
android:paddingBottom="@dimen/bottom_sheet_content_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/interval_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:textSize="@dimen/default_list_text_size"
tools:text="Interval value" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/up_down_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
app:srcCompat="@drawable/ic_action_arrow_down" />
</LinearLayout>
<LinearLayout
android:id="@+id/always_ask_and_range_slider_container"
layout="@layout/bottom_sheet_with_switch_divider_and_additional_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/context_menu_padding_margin_small" />
<com.google.android.material.slider.RangeSlider
android:id="@+id/interval_slider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/save_track_interval_globally"
android:stepSize="1"
app:haloRadius="@dimen/content_padding_small"
app:labelBehavior="gone"
app:thumbColor="@color/profile_icon_color_blue_light"
app:thumbRadius="@dimen/content_padding_small_half"
app:trackColorActive="@color/profile_icon_color_blue_light"
app:trackColorInactive="#4D007EB3"
app:tickColorInactive="#007EB3"
app:trackHeight="@dimen/slider_track_height"
tools:visibility="visible" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/confirm_every_run"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:minHeight="@dimen/context_menu_buttons_bottom_height"
android:paddingLeft="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding_small"
android:text="@string/confirm_every_run"
android:textColor="?attr/color_dialog_buttons"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:visibility="visible" />
</LinearLayout>
<View
android:id="@+id/second_divider"
<LinearLayout
android:id="@+id/segments_container"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider" />
android:layout_height="wrap_content"
android:orientation="vertical" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/block_statistics"
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:layout_marginTop="@dimen/content_padding_small_half"
android:layout_marginBottom="@dimen/dialog_content_margin"
android:clipToPadding="false"
android:orientation="horizontal"
tools:itemCount="4"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_gpx_stat_block" />
<include layout="@layout/preference_button_with_icon_quadruple" />
</LinearLayout>

View file

@ -0,0 +1,111 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small"
android:text="@string/monitoring_settings"
android:textSize="@dimen/default_list_text_size"
app:typeface="@string/font_roboto_medium" />
<include
android:id="@+id/show_track_on_map"
layout="@layout/bottom_sheet_with_switch_divider_and_additional_button" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="@dimen/content_padding"
android:background="?attr/dashboard_divider" />
<LinearLayout
android:id="@+id/interval_view_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/bottom_sheet_content_margin"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/bottom_sheet_content_margin">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/interval_value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:textSize="@dimen/default_list_text_size"
tools:text="Interval value" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/up_down_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
app:srcCompat="@drawable/ic_action_arrow_down" />
</LinearLayout>
<LinearLayout
android:id="@+id/always_ask_and_range_slider_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<com.google.android.material.slider.RangeSlider
android:id="@+id/interval_slider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/save_track_interval_globally"
android:stepSize="1"
app:haloRadius="@dimen/content_padding_small"
app:labelBehavior="gone"
app:thumbColor="@color/profile_icon_color_blue_light"
app:thumbRadius="@dimen/content_padding_small_half"
app:tickColorInactive="#007EB3"
app:trackColorActive="@color/profile_icon_color_blue_light"
app:trackColorInactive="#4D007EB3"
app:trackHeight="@dimen/slider_track_height"
tools:visibility="visible" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/content_padding_small"
android:letterSpacing="@dimen/description_letter_spacing"
android:text="@string/trip_recording_logging_interval_info"
android:textColor="?attr/dialog_text_description_color" />
</LinearLayout>
<Space
android:layout_width="match_parent"
android:layout_height="@dimen/context_menu_first_line_top_margin" />
<include layout="@layout/preference_button_with_icon_triple" />
</LinearLayout>

View file

@ -1873,7 +1873,6 @@
<string name="total_distance">Συνολική απόσταση</string>
<string name="routing_attr_relief_smoothness_factor_name">Επιλέξτε διακύμανση ανύψωσης</string>
<string name="routing_attr_height_obstacles_name">Χρήση υψομετρικών δεδομένων</string>
<string name="rendering_attr_depthContours_description">Εμφάνιση ισοβαθών καμπυλών και σημείων.</string>
<string name="rendering_attr_depthContours_name">Ναυτικές ισοβαθείς καμπύλες</string>
<string name="auto_split_recording_title">Αυτόματος διαχωρισμός καταγραφών μετά από κενό</string>
@ -2516,7 +2515,7 @@
<string name="commit_poi">Υποβολή ΣΕ</string>
<string name="tab_title_basic">Βασικό</string>
<string name="tab_title_advanced">Προχωρημένο</string>
<string name="building_number">Αριθμός κτιρίου</string>
<string name="building_number">Αριθμός κτηρίου</string>
<string name="next_proceed">Επόμενο</string>
<string name="opening_at">Άνοιγμα στις</string>
<string name="closing_at">Κλείσιμο στις</string>

View file

@ -4045,4 +4045,7 @@
<string name="shared_string_interval">Intertempo</string>
<string name="rendering_attr_noNatureReserveBoundaries_description">Kaŝi limojn de naturaj rezervejoj, protektataj areoj kaj naciaj parkoj</string>
<string name="rendering_attr_noNatureReserveBoundaries_name">Limoj de rezervejoj</string>
<string name="trip_recording_logging_interval_info">Agordita periodo de intertempo de registrado, dum kiu OsmAnd petos la nunajn poziciajn datumojn.</string>
<string name="lost_data_warning">Ĉiuj nekonservitaj datumoj perdiĝos.</string>
<string name="trip_recording_save_and_continue">Konservi kaj daŭrigi</string>
</resources>

View file

@ -4052,4 +4052,6 @@
<string name="map_widget_distance_by_tap">Kaugus toksamise järgi</string>
<string name="rendering_attr_noNatureReserveBoundaries_description">Peida (loodus)kaitsealade ja rahvusparkide piirid</string>
<string name="rendering_attr_noNatureReserveBoundaries_name">Looduse piirid</string>
<string name="trip_recording_save_and_continue">Salvesta ja jätka</string>
<string name="lost_data_warning">Kõik salvestamata andmed lähevad kaotsi.</string>
</resources>

View file

@ -1449,4 +1449,7 @@
<string name="poi_protected_area">منطقهٔ حفاظت‌شده</string>
<string name="poi_badminton">بدمینتون</string>
<string name="poi_service_car">خدمات خودرو; مکانیکی</string>
<string name="poi_substation_type">نوع</string>
<string name="poi_mini_roundabout">فلکهٔ کوچک</string>
<string name="poi_square">میدان</string>
</resources>

View file

@ -492,7 +492,7 @@
<string name="safe_mode_description">اجرای برنامه در حالت ایمن (به‌جای کد native از کد Android که کُندتر است استفاده می‌کند).</string>
<string name="native_library_not_running">برنامه در حالت ایمن اجرا شده است (از طریق تنظیمات آن را غیرفعال کنید).</string>
<string name="background_service_is_enabled_question">سرویس پس‌زمینهٔ OsmAnd هنوز در حال اجراست. آن را هم متوقف می‌کنید؟</string>
<string name="close_changeset">بستن بستهٔ تغییرات</string>
<string name="close_changeset">بستن بستهٔ تغییر</string>
<string name="zxing_barcode_scanner_not_found">برنامهٔ اسکنر بارکد ZXing نصب نشده است. در گوگل‌پلی جست‌وجو می‌کنید؟</string>
<string name="rendering_attr_roadColors_description">یکی از رنگ‌بندی‌های راه را انتخاب کنید:</string>
<string name="rendering_attr_roadColors_name">رنگ‌بندی راه</string>
@ -787,8 +787,8 @@
<string name="converting_names">در حال تبدیل اسامی محلی/انگلیسی…</string>
<string name="failed_op">ناموفق</string>
<string name="auth_failed">اجازهٔ دسترسی احراز نشد</string>
<string name="closing_changeset">بستن بستهٔ تغییرات</string>
<string name="opening_changeset">بازکردن بستهٔ تغییرات</string>
<string name="closing_changeset">بستن بستهٔ تغییر…</string>
<string name="opening_changeset">بازکردن بستهٔ تغییر…</string>
<string name="list_index_files_was_not_loaded">دریافت لیست مناطق از https://osmand.net ناموفق بود.</string>
<string name="downloading_list_indexes">در حال دانلود لیست مناطق موجود…</string>
<string name="download_question_exist">دادهٔ آفلاینِ {0} از قبل وجود دارد ({1}). آن را روزآمد می‌کنید ({2})؟</string>
@ -1478,7 +1478,7 @@
<string name="welcome_text">برنامهٔ OsmAnd نقشه‌گردی و ناوبری آفلاین را برایتان به ارمغان می‌آورد.</string>
<string name="welcome_header">خوش آمدید</string>
<string name="current_route">مسیر فعلی</string>
<string name="osm_changes_added_to_local_edits">تغییرات OSM به بستهٔ تغییرات محلی اضافه شد</string>
<string name="osm_changes_added_to_local_edits">تغییرات OSM به بستهٔ تغییر محلی اضافه شد</string>
<string name="mark_to_delete">برای حذف‌کردن علامت بزنید</string>
<string name="local_osm_changes_upload_all_confirm">از آپلود این %1$d تغییر در OSM مطمئن هستید؟</string>
<string name="confirmation_to_clear_history">سوابق را پاک می‌کنید؟</string>
@ -2589,7 +2589,7 @@
<string name="empty_state_markers_history_desc">نشانه‌هایی که به‌عنوان گذرانده مشخص شود در این صفحه نشان داده می‌شود.</string>
<string name="shared_string_more_without_dots">بیشتر</string>
<string name="looking_for_tracks_with_waypoints">در حال جست‌وجوی ردهای دارای راه‌نشان</string>
<string name="empty_state_osm_edits">اشیای OSM را بسازید یا ویرایش کنید</string>
<string name="empty_state_osm_edits">مکان‌های OSM را ایجاد یا ویرایش کنید</string>
<string name="empty_state_osm_edits_descr">POIها را اضافه یا ویرایش کنید، یادداشت‌های OSMای اضافه کنید یا روی آن‌ها نظر بدهید و فایل‌های GPX ضبط‌شده را آپلود کنید.</string>
<string name="shared_string_deleted">حذف‌شده(ها)</string>
<string name="shared_string_edited">ویرایش شد</string>
@ -3479,7 +3479,7 @@
<string name="shared_string_importing">در حال درون‌برد</string>
<string name="shared_string_import_complete">درون‌برد کامل شد</string>
<string name="import_complete_description">همهٔ داده از %1$s درون‌برد شد. با استفاده از دکمه‌های زیر می‌توانید بخش موردنیاز برنامه را برای مدیریت آن باز کنید.</string>
<string name="shared_string_poi_types">انواع POI</string>
<string name="shared_string_poi_types">گونه‌های POI</string>
<string name="listed_exist">%1$s که در زیر آمده، هم‌اکنون در OsmAnd وجود دارد.</string>
<string name="checking_for_duplicate_description">OsmAnd در حال بررسی %1$s برای چیزهای تکراری موجود در برنامه است.
\n
@ -4068,5 +4068,5 @@
<string name="on_pause">مکث کرده</string>
<string name="quick_action_coordinates_widget_descr">دکمه‌ای برای آشکار یا پنهان کردن ابزارک مختصات روی نقشه.</string>
<string name="shared_string_interval">بازه</string>
<string name="map_widget_distance_by_tap">فاصله با لمس دوانگشتی</string>
<string name="map_widget_distance_by_tap">مسافت با لمس</string>
</resources>

View file

@ -3886,4 +3886,10 @@
<string name="poi_piste_status_open">Statut de la piste : ouvert</string>
<string name="poi_piste_name">Nom de la piste</string>
<string name="poi_piste_ski_jump">Saut à ski</string>
<string name="poi_summit_register_no">Livre d\'or au sommet : non</string>
<string name="poi_summit_register_yes">Livre d\'or au sommet : oui</string>
<string name="poi_patrolled_no">Surveillé : non</string>
<string name="poi_patrolled_yes">Surveillé : oui</string>
<string name="poi_local_ref">Référence locale</string>
<string name="poi_geodesist">Géodésien</string>
</resources>

View file

@ -1192,11 +1192,11 @@
<string name="gpx_file_is_empty">Fichier GPX vide</string>
<string name="shared_string_tracks">Traces</string>
<string name="shared_string_my_favorites">Favoris</string>
<string name="shared_string_my_places">Mes lieux favoris</string>
<string name="shared_string_my_places">Lieux favoris</string>
<string name="selected_gpx_info_show">\n\nAppui long pour afficher sur la carte</string>
<string name="delay_navigation_start">Démarrer la navigation pas à pas automatiquement</string>
<string name="shared_string_selected_lowercase">sélectionné(s)</string>
<string name="gpx_split_interval">Intervalle de division</string>
<string name="gpx_split_interval">Intervalle de fractionnement</string>
<string name="local_index_gpx_info_show">\n\nAppui long pour afficher les options</string>
<string name="gpx_info_subtracks">Sections : %1$s </string>
<string name="gpx_info_waypoints">Points de passage : %1$s</string>
@ -4033,4 +4033,9 @@
<string name="select_segments_description">%1$s contient plus d\'un segment, vous devez sélectionner le tronçon nécessaire à la navigation.</string>
<string name="routing_attr_driving_style_description">Sélectionnez le mode de conduite pour avoir l\'itinéraire le plus court, le plus rapide, ou le plus sûr</string>
<string name="quick_action_coordinates_widget_descr">Appuyer pour afficher ou cacher le widget Coordonnées sur la carte.</string>
<string name="snap_to_road_descr">Licône de localisation va se déplacer sur le trajet en cours.</string>
<string name="select_another_colorization">Veuillez sélectionner un autre type de colorisation.</string>
<string name="trip_recording_logging_interval_info">L\'intervalle denregistrement définit la fréquence à laquelle OsmAnd récupérera les données de localisation.</string>
<string name="trip_recording_save_and_continue">Enregistrer et continuer</string>
<string name="lost_data_warning">Toutes les données non enregistrées seront perdues.</string>
</resources>

View file

@ -4039,4 +4039,7 @@
<string name="live_update_frequency_week_variant">Az alkalmazás hetente ellenőrzi a térképfrissítéseket. Következő ellenőrzés: %1$s (ennyi idő múlva: %2$s).</string>
<string name="live_update_frequency_day_variant">Az alkalmazás naponta ellenőrzi a térképfrissítéseket. Következő ellenőrzés: %1$s (ennyi idő múlva: %2$s).</string>
<string name="live_update_frequency_hour_variant">Az alkalmazás óránként ellenőrzi a térképfrissítéseket. Következő ellenőrzés: %1$s (ennyi idő múlva: %2$s).</string>
<string name="trip_recording_logging_interval_info">A naplózási intervallum az az időköz, amelyben az OsmAnd lekéri az aktuális helyadatokat.</string>
<string name="trip_recording_save_and_continue">Mentés és folytatás</string>
<string name="lost_data_warning">Minden nem mentett adat törlődni fog.</string>
</resources>

View file

@ -9,7 +9,7 @@
<string name="map_widget_show_destination_arrow">הצגת הכיוון ליעד</string>
<string name="enable_plugin_monitoring_services">יש להפעיל את תוסף „מעקב הטיול” כדי להשתמש בשירותי רישום מיקום (מעקב חי, רישום GPX)</string>
<string name="non_optimal_route_calculation">יש לחשב מסלול בלתי יעיל למרחקים ארוכים</string>
<string name="gps_not_available">נא להפעיל את רכיב האיכון (GPS) בהגדרות</string>
<string name="gps_not_available">נא להפעיל את ה־GPS בהגדרות</string>
<string name="map_widget_monitoring_services">שירותי רישום</string>
<string name="no_route">אין מסלול</string>
<string name="delete_target_point">הסרת יעד</string>
@ -1881,7 +1881,7 @@
<string name="si_m_s">מטרים לשנייה</string>
<string name="si_min_km">דקות לקילומטר</string>
<string name="si_min_m">דקות למייל</string>
<string name="si_nm_h">מיל ימי לשעה (קשר)</string>
<string name="si_nm_h">מייל ימי לשעה (קשר)</string>
<string name="nm_h">קשר</string>
<string name="m_s">מ/שנ׳</string>
<string name="shared_string_trip_recording">הקלטת טיול</string>
@ -4047,4 +4047,8 @@
<string name="latest_openstreetmap_update">קיים עדכון ל־OpenStreetMap:</string>
<string name="rendering_attr_noNatureReserveBoundaries_description">להסתיר גבולות של שמורות טבע, אזורים מוגנים ופארקים ציבוריים</string>
<string name="rendering_attr_noNatureReserveBoundaries_name">גבולות טבעיים</string>
<string name="live_update_delete_updates_msg">למחוק את כל העדכונים החיים של %s\?</string>
<string name="trip_recording_logging_interval_info">הגדרת הפרש קבוע בין הבקשות של OsmAnd לקבלת נתוני המיקום הנוכחיים.</string>
<string name="trip_recording_save_and_continue">לשמור ולהמשיך</string>
<string name="lost_data_warning">כל הנתונים שלא נשמרו יאבדו.</string>
</resources>

View file

@ -2084,7 +2084,6 @@ POIの更新は利用できません</string>
<string name="shared_string_time">時間</string>
<string name="total_distance">総走行距離</string>
<string name="routing_attr_height_obstacles_name">標高データを使用</string>
<string name="rendering_attr_hideWaterPolygons_description">水域</string>
<string name="rendering_attr_hideWaterPolygons_name">水域ポリゴン</string>
<string name="wiki_around">近隣のWikipedia記事</string>
@ -2133,14 +2132,14 @@ POIの更新は利用できません</string>
<string name="quick_action_take_photo_note_descr">画面中央に写真メモを追加するボタンです。</string>
<string name="quick_action_add_osm_bug_descr">画面中央にOSMメモを追加するボタンです。</string>
<string name="quick_action_add_poi_descr">画面中央にPOIを追加できるボタンです。</string>
<string name="quick_action_navigation_voice_descr">ナビゲーション中の案内音声の有効無効を切り替えることが出来ます。</string>
<string name="quick_action_navigation_voice_descr">ナビゲーション中の案内音声の有効/無効を切り替えます。</string>
<string name="quick_action_add_parking_descr">画面中央に駐車場所を追加するボタンです。</string>
<string name="quick_action_interim_dialog">実行時に入力画面を表示</string>
<string name="favorite_empty_place_name">場所</string>
<string name="quick_action_duplicates">重複を避けるためにクイックアクション名は[%1$s]に変更されました。</string>
<string name="quick_action_duplicate">クイックアクション名の重複</string>
<string name="quick_action_showhide_favorites_descr">マップ画面でのお気に入り地点の表示/非表示の切替が出来ます。</string>
<string name="quick_action_showhide_poi_descr">マップ画面でのPOIの表示/非表示の切替が出来ます。</string>
<string name="quick_action_showhide_favorites_descr">マップ画面でのお気に入り地点の表示/非表示を切り替えます。</string>
<string name="quick_action_showhide_poi_descr">マップ画面でのPOIの表示/非表示を切り替えます。</string>
<string name="quick_action_poi_show">%1$sを表示</string>
<string name="quick_action_poi_hide">%1$sを非表示</string>
<string name="quick_action_add_category">カテゴリーを追加</string>
@ -2546,7 +2545,7 @@ POIの更新は利用できません</string>
<string name="by_type">種類別</string>
<string name="digits_quantity">小数点以下の桁数</string>
<string name="go_to_next_field">次の入力項目へ移動</string>
<string name="tap_on_map_to_hide_interface_descr">マップ画面のタップで操作ボタンやウィジェットの表示と交互に切り替えます。</string>
<string name="tap_on_map_to_hide_interface_descr">マップ画面のタップで操作ボタンやウィジェットの表示切り替えます。</string>
<string name="tap_on_map_to_hide_interface">フルスクリーンモード</string>
<string name="live_monitoring_max_interval_to_send">オンライン追跡用のバッファ指定</string>
<string name="live_monitoring_max_interval_to_send_desrc">送信用現在地データをネット接続せずにどのくらいの時間記録するか、バッファを指定します</string>
@ -2829,7 +2828,7 @@ POIの更新は利用できません</string>
<string name="osm_recipient_stat">編集 %1$s, 合計 %2$s mBTC</string>
<string name="shared_string_launch">起動</string>
<string name="lang_gn_py">グアラニー語</string>
<string name="quick_action_switch_day_night_descr">OsmAndマップ表示の昼/夜モードを切り替えることが出来ます。</string>
<string name="quick_action_switch_day_night_descr">OsmAndマップ表示の昼/夜モードを切り替えます。</string>
<string name="quick_action_switch_day_mode">昼モード</string>
<string name="quick_action_switch_night_mode">夜モード</string>
<string name="quick_action_day_night_switch_mode">昼/夜モードの切り替え</string>
@ -3715,7 +3714,7 @@ POIの更新は利用できません</string>
<string name="vessel_height_warning">低い橋を避けるために船の高さを調整できます。橋が可動式の場合は、開いた状態の高さが参照されます。</string>
<string name="vessel_height_limit_description">低い橋を避けるために船の高さを設定します。注:橋が可動式の場合は、開いた状態の高さが参照されます。</string>
<string name="vessel_width_limit_description">狭い橋を避けるために船の幅を設定します</string>
<string name="quick_action_showhide_mapillary_descr">マップ上のMapillaryレイヤーの表示/非表示を切り替えるトグルボタンです。</string>
<string name="quick_action_showhide_mapillary_descr">マップ上のMapillaryレイヤーの表示/非表示を切り替えす。</string>
<string name="routing_attr_length_description">ルート検索時に指定した車両の長さを考慮します。</string>
<string name="routing_attr_length_name">長さ制限</string>
<string name="shared_string_bearing">ベアリング</string>
@ -3849,4 +3848,109 @@ POIの更新は利用できません</string>
\nグラフは再計算後に利用できるようになります。</string>
<string name="use_dev_url_descr">OSM通知/ POI / GPXのアップロードをテストする場合、openstreetmap.orgではなくdev.openstreetmap.orgを使用するよう切り替えます。</string>
<string name="use_dev_url">dev.openstreetmap.orgを使用</string>
<string name="announcement_time_prepare">次々回案内(中距離)</string>
<string name="announcement_time_prepare_long">次回案内(長距離)</string>
<string name="shared_string_sec"></string>
<string name="announcement_time_passing">通過する</string>
<string name="announcement_time_approach">目標に接近</string>
<string name="shared_string_turn">方向転換</string>
<string name="announcement_time_off_route">ルートからの逸脱</string>
<string name="announcement_time_arrive">目的地に到着</string>
<string name="announcement_time_intervals">タイミングと距離の間隔</string>
<string name="announcement_time_title">案内タイミング</string>
<string name="announcement_time_descr">音声による案内タイミングは、音声形式、現在のナビゲーション速度、および標準のナビゲーション速度によって異なります。</string>
<string name="start_recording">記録の開始</string>
<string name="show_track_on_map">マップ上に経路を表示</string>
<string name="routing_engine_vehicle_type_wheelchair">車椅子</string>
<string name="routing_engine_vehicle_type_hiking">ハイキング</string>
<string name="routing_engine_vehicle_type_walking">徒歩</string>
<string name="routing_engine_vehicle_type_cycling_electric">電動自転車</string>
<string name="routing_engine_vehicle_type_cycling_mountain">山岳(MTB)サイクリング</string>
<string name="routing_engine_vehicle_type_cycling_road">ロードサイクリング</string>
<string name="routing_engine_vehicle_type_cycling_regular">一般的なサイクリング</string>
<string name="routing_engine_vehicle_type_hgv">重量物運搬車</string>
<string name="routing_engine_vehicle_type_small_truck">小型トラック</string>
<string name="routing_engine_vehicle_type_truck">トラック</string>
<string name="routing_engine_vehicle_type_scooter">スクーター</string>
<string name="routing_engine_vehicle_type_racingbike">レーシングバイク</string>
<string name="routing_engine_vehicle_type_mtb">マウンテンバイク</string>
<string name="message_server_error">サーバーエラー: %1$s</string>
<string name="message_name_is_already_exists">この名前はすでに存在します</string>
<string name="delete_online_routing_engine">このオンラインルーティングエンジンを削除しますか?</string>
<string name="context_menu_read_full">全文を読む</string>
<string name="context_menu_edit_descr">説明の編集</string>
<string name="delete_waypoints">経由地点を削除</string>
<string name="copy_to_map_markers">マップマーカーにコピー</string>
<string name="copy_to_map_favorites">お気に入りにコピー</string>
<string name="upload_photo">アップロード中</string>
<string name="upload_photo_completed">アップロードが完了しました</string>
<string name="uploading_count">%2$d個中%1$d個をアップロード中</string>
<string name="select_segments">セグメントの選択</string>
<string name="select_segments_description">%1$sには複数のセグメントが含まれているため、ナビゲーションに必要な部分を選択する必要があります。</string>
<string name="segments_count">%1$dセグメント</string>
<string name="uploaded_count">%2$d個中%1$d個をアップロードしました</string>
<string name="toast_select_edits_for_upload">アップロードする編集を選択</string>
<string name="hillshade_slope_contour_lines">陰影起伏図 / 勾配 / 等高線</string>
<string name="open_place_reviews_plugin_description">OpenPlaceReviewsは、レストラン、ホテル、美術館、中途経由地点などの公共の場所に関するコミュニティが運営するプロジェクトです。写真、レビュー、他のシステムへのリンク、OpenStreetMap、Wikipediaへのリンクなど、それらに関するすべての公開情報を収集しています。
\n
\nOpenPlaceReviewデータは全て公開されており、誰でもアクセス可能です。http://openplacereviews.org/data
\n
\n詳細については下記サイトをご覧ください。http://openplacereviews.org</string>
<string name="open_place_reviews">OpenPlaceReviews</string>
<string name="opr_use_dev_url">test.openplacereviews.orgを使用</string>
<string name="login_open_place_reviews">OpenPlaceReviewsにログイン</string>
<string name="activity_type_water_name"></string>
<string name="activity_type_winter_name"></string>
<string name="activity_type_snowmobile_name">スノーモービル</string>
<string name="activity_type_riding_name">乗馬</string>
<string name="activity_type_racing_name">レーシング</string>
<string name="activity_type_mountainbike_name">マウンテンバイク</string>
<string name="activity_type_cycling_name">自転車</string>
<string name="activity_type_hiking_name">ハイキング</string>
<string name="activity_type_running_name">ランニング</string>
<string name="activity_type_walking_name">徒歩</string>
<string name="activity_type_offroad_name">未舗装道路</string>
<string name="activity_type_motorbike_name">オートバイ</string>
<string name="routing_attr_short_way_description">最適化されたなるべく短いルート (省エネ)</string>
<string name="activity_type_car_name"></string>
<string name="temporary_conditional_routing_descr">マップ上で現在有効になっている道路の制限を使用します</string>
<string name="routing_attr_driving_style_description">運転の目的を選択することで、より短くより速くより安全なルートを取得します</string>
<string name="snap_to_road_descr">現在地アイコンが現在のナビゲーションルートに保持されます</string>
<string name="map_orientation_threshold_descr">速度がしきい値未満の場合は、マップビューを回転させないでください</string>
<string name="restart">再起動</string>
<string name="shared_strings_all_regions">すべての地域</string>
<string name="delete_number_files_question">%1$d個のファイルを削除しますか</string>
<string name="track_recording_stop_without_saving">保存せずに終了</string>
<string name="track_recording_description">記録を停止してもよろしいですか?
\n保存しない場合データはすべて失われます。</string>
<string name="track_recording_save_and_stop">記録を保存して終了</string>
<string name="track_recording_title">記録を停止しました</string>
<string name="on_pause">一時停止中</string>
<string name="app_restart_required">一部の設定を適用するには、アプリケーションの再起動が必要です。</string>
<string name="routing_attr_height_obstacles_description">ルート検索時になるべく急な上り坂を回避するようにします。</string>
<string name="quick_action_coordinates_widget_descr">マップ上で座標ウィジェットの表示/非表示を切り替えます。</string>
<string name="map_widget_distance_by_tap">タップで距離</string>
<string name="latest_openstreetmap_update">利用可能な最新OpenStreetMapの更新:</string>
<string name="updated">更新: %s</string>
<string name="last_time_checked">最後にチェック時間: %s</string>
<string name="update_frequency">更新間隔</string>
<string name="live_update_frequency_week_variant">マップの更新は毎週チェックされます。次回は%2$sの%1$sです。</string>
<string name="live_update_frequency_day_variant">マップの更新は毎日チェックされます。次回は%2$sの%1$sです。</string>
<string name="live_update_frequency_hour_variant">マップの更新は1時間ごとにチェックされます。次回は%2$sの%1$sです。</string>
<string name="delete_updates">更新の削除</string>
<string name="live_update_delete_updates_msg">%sのライブアップデートをすべて削除してもよろしいですか</string>
<string name="purchases">購入</string>
<string name="select_category_descr">カテゴリを選択するか、新しいカテゴリを追加します</string>
<string name="track_recording_will_be_continued">記録を継続します。</string>
<string name="copy_poi_name">POI名をコピー</string>
<string name="quick_action_show_hide_title">表示/非表示</string>
<string name="shared_string_interval">間隔</string>
<string name="rendering_attr_noNatureReserveBoundaries_description">自然保護区、保護地域、国立公園の境界を非表示にします</string>
<string name="rendering_attr_noNatureReserveBoundaries_name">自然保護区の境界</string>
<string name="track_has_no_altitude">経路には標高データは含まれていません。</string>
<string name="track_has_no_speed">経路には速度データは含まれていません。</string>
<string name="select_another_colorization">別タイプのカラーを選択してください。</string>
<string name="trip_recording_logging_interval_info">ログ記録間隔は、OsmAndが現在の位置データを要求する期間を設定します。</string>
<string name="trip_recording_save_and_continue">保存して続行</string>
<string name="lost_data_warning">保存されていないデータはすべて失われます。</string>
</resources>

View file

@ -1626,7 +1626,7 @@
<string name="poi_historic_civilization_ancient_egyptian">Sivilisasjon: Det gamle Egypt (inntil 332 f.Kr.)</string>
<string name="poi_historic_civilization_imperial_chinese">Sivilisasjon: Det kinesiske keiserriket (221 f.Kr. 1911 e.Kr.)</string>
<string name="poi_historic_stone">Historisk stein</string>
<string name="poi_historic_era_neolithic">Historisk periode: neolittisk tid</string>
<string name="poi_historic_era_neolithic">Historisk periode: neolittisk tid (yngre steinalder)</string>
<string name="poi_historic_era_mesolithic">Historisk periode: mesolittisk tid</string>
<string name="poi_historic_era_paleolithic">Historisk periode: paleolittisk tid (2,6 millioner 10000 år før nåtid)</string>
<string name="poi_historic_period_ptolemaic_egypt">Historisk periode: Det ptolemeiske Egypt (305 f.Kr. 30 f.Kr.)</string>
@ -1647,4 +1647,42 @@
<string name="poi_historic_civilization_prehistoric">Sivilisasjon: forhistorisk tid</string>
<string name="poi_historic_manor">Historisk herregård</string>
<string name="poi_historic_yes">Historisk objekt</string>
<string name="poi_material_limestone">Materiale: kalkstein</string>
<string name="poi_material_granite_stone">Materiale: granittstein</string>
<string name="poi_material_sandstone">Materiale: sandstein</string>
<string name="poi_material_stone">Materiale: stein</string>
<string name="poi_social_facility_shelter">Husly</string>
<string name="poi_route_subway_ref">T-bane</string>
<string name="poi_route_ferry_ref">Ferge</string>
<string name="poi_route_bus_ref">Buss</string>
<string name="poi_surface_snow">Overflate: snø</string>
<string name="poi_surface_salt">Overflate: salt</string>
<string name="poi_surface_ice">Overflate: is</string>
<string name="poi_surface_mud">Overflate: gjørme</string>
<string name="poi_surface_dirt">Overflate: jord</string>
<string name="poi_surface_ground">Overflate: jord</string>
<string name="poi_surface_grass">Overflate: gress</string>
<string name="poi_surface_sand">Overflate: sand</string>
<string name="poi_surface_compacted">Overflate: komprimert</string>
<string name="poi_surface_fine_gravel">Overflate: fin grus</string>
<string name="poi_surface_gravel">Overflate: grus</string>
<string name="poi_surface_wood">Overflate: tre</string>
<string name="poi_surface_metal">Overflate: metall</string>
<string name="poi_surface_stone">Overflate: stein</string>
<string name="poi_surface_pebblestone">Overflate: rullestein (liten)</string>
<string name="poi_surface_paving_stones">Overflate: belegningsstein</string>
<string name="poi_surface_cobblestone">Overflate: kuppelstein</string>
<string name="poi_surface_sett">Overflate: brostein</string>
<string name="poi_surface_concrete">Overflate: betong</string>
<string name="poi_surface_asphalt">Overflate: asfalt</string>
<string name="poi_surface_paved">Overflate: fast dekke</string>
<string name="poi_surface_unpaved">Overflate: uten fast dekke</string>
<string name="poi_shelter_type_lean_to">Gapahuk</string>
<string name="poi_resource_stone">Stein</string>
<string name="poi_resource_sandstone">Sandstein</string>
<string name="poi_resource_limestone">Kalkstein</string>
<string name="poi_memorial_stone">Stein</string>
<string name="poi_barrier_entrance">Passasje i en mur eller et gjerde</string>
<string name="poi_shelter">Ly</string>
<string name="poi_boundary_stone">Grensestein</string>
</resources>

View file

@ -167,7 +167,7 @@
<string name="use_fluorescent_overlays">Fluorescerende overlegg</string>
<string name="use_fluorescent_overlays_descr">Bruk fluorescerende farger til å vise spor og ruter.</string>
<string name="offline_edition">Frakoblet redigering</string>
<string name="offline_edition_descr">Bruk alltid frakoblet redigering.</string>
<string name="offline_edition_descr">Hvis redigering uten nett er aktivert, lagres endringer lokalt først og lastes opp på forespørsel, ellers vil endringer bli lastet opp umiddelbart.</string>
<string name="free_version_message">Du kan laste ned eller oppdatere %1$s kart.</string>
<string name="free_version_title">Gratisversjon</string>
<string name="poi_context_menu_showdescription">Vis interessepunkt-beskrivelse.</string>
@ -401,7 +401,7 @@
<string name="search_offline_address">Offline-søk</string>
<string name="search_online_address">Nettbasert søk</string>
<string name="max_level_download_tile">Maks. nettbasert zoom</string>
<string name="max_level_download_tile_descr">Ikke bla gjennom nettbaserte kartfliser for zoomnivåer utover dette.</string>
<string name="max_level_download_tile_descr">Ikke bla gjennom nettbaserte kart for zoomnivåer utover dette.</string>
<string name="route_general_information">Total distanse %1$s, reisetid %2$d t %3$d min.</string>
<string name="router_service_descr">Nettbasert eller frakoblet navigeringstjeneste.</string>
<string name="router_service">Navigeringstjeneste</string>
@ -1492,7 +1492,7 @@
<string name="wait_current_task_finished">Vent til gjeldende oppgave er ferdig</string>
<string name="recording_delete_confirm">Slett dette elementet\?</string>
<string name="osmand_parking_delete">Slett parkeringsplassmarkør</string>
<string name="local_openstreetmap_delete">Slett endring</string>
<string name="local_openstreetmap_delete">Slett redigering</string>
<string name="poi_dialog_reopen">Gjenåpne</string>
<string name="do_you_like_osmand">Liker du OsmAnd\?</string>
<string name="building_number">Bygningsnummer</string>
@ -1520,7 +1520,7 @@
<string name="lang_kn">Kannada</string>
<string name="app_mode_bus">Buss</string>
<string name="app_mode_train">Tog</string>
<string name="voice_data_unavailable">Valgte taledata er ikke tilgjengelig</string>
<string name="voice_data_unavailable">Valgte talemeldingspakke er ikke tilgjengelig</string>
<string name="voice_data_corrupted">Spesifisert taledata er ødelagt</string>
<string name="voice_data_not_supported">Taledataversjon som ikke støttes</string>
<string name="background_router_service_descr">Sporer posisjonen din mens skjermen er slått av.</string>
@ -2173,7 +2173,7 @@
<string name="validate_gpx_upload_name_pwd">Angi ditt OSM-brukernavn og passord for å laste opp GPX-filer.</string>
<string name="support_new_features_descr">Doner for å se nye funksjoner implementert i programmet.</string>
<string name="local_openstreetmap_uploadall">Last opp alle</string>
<string name="local_openstreetmap_upload">Last opp endring til OSM</string>
<string name="local_openstreetmap_upload">Last opp redigering til OSM</string>
<string name="local_openstreetmap_descr_title">Asynkron OSM-redigering:</string>
<string name="live_monitoring_interval_descr">Oppgi det nettbaserte sporingsintervallet.</string>
<string name="live_monitoring_interval">Nettbasert sporingsintervall</string>
@ -2239,7 +2239,7 @@
<string name="quick_action_add_parking">Legg til parkeringsplass</string>
<string name="quick_action_edit_action">Rediger handling</string>
<string name="quick_actions_delete">Slett handling</string>
<string name="quick_favorites_name_preset">Navneforvalg</string>
<string name="quick_favorites_name_preset">Forhåndsinnstilt navn</string>
<string name="quick_action_add_marker_descr">En knapp for å legge til en kartmarkør i skjermsenteret.</string>
<string name="quick_action_add_gpx_descr">En knapp for å legge til et GPX-rutepunkt i midten av skjermen.</string>
<string name="quick_action_take_audio_note_descr">En knapp for å legge til et lydnotat i midten av skjermen.</string>
@ -2829,7 +2829,7 @@
<string name="routeInfo_roadClass_name">Veitype</string>
<string name="routeInfo_surface_name">Overflate</string>
<string name="routeInfo_smoothness_name">Jevnhet</string>
<string name="routeInfo_steepness_name">Stigning</string>
<string name="routeInfo_steepness_name">Bratthet</string>
<string name="add_home">Legg til bosted</string>
<string name="add_work">Legg til arbeidssted</string>
<string name="work_button">Arbeid</string>
@ -2865,9 +2865,9 @@
<string name="rendering_attr_surface_paved_name">Fast dekke</string>
<string name="rendering_attr_surface_concrete_name">Betong</string>
<string name="rendering_attr_surface_sett_name">Brostein</string>
<string name="rendering_attr_surface_cobblestone_name">Naturlig brostein</string>
<string name="rendering_attr_surface_paving_stones_name">Steinbelagt</string>
<string name="rendering_attr_surface_pebblestone_name">Rullestein</string>
<string name="rendering_attr_surface_cobblestone_name">Kuppelstein</string>
<string name="rendering_attr_surface_paving_stones_name">Belegningsstein</string>
<string name="rendering_attr_surface_pebblestone_name">Rullestein (liten)</string>
<string name="rendering_attr_surface_stone_name">Stein</string>
<string name="rendering_attr_surface_metal_name">Metall</string>
<string name="rendering_attr_surface_wood_name">Tre</string>
@ -2907,8 +2907,8 @@
<string name="shared_string_milliradians">Milliradianer</string>
<string name="angular_measeurement">Vinkel-måleenheter</string>
<string name="angular_measeurement_descr">Endre hva asimut måles i.</string>
<string name="routing_attr_avoid_sett_name">Ingen rustikk brostein eller brostein</string>
<string name="routing_attr_avoid_sett_description">Unngår rustikk brostein og brostein</string>
<string name="routing_attr_avoid_sett_name">Ingen kuppelstein eller brostein</string>
<string name="routing_attr_avoid_sett_description">Unngår kuppelstein og brostein</string>
<string name="routing_attr_avoid_tram_name">Ingen trikk</string>
<string name="routing_attr_avoid_tram_description">Unngår trikk</string>
<string name="routing_attr_avoid_bus_name">Ingen buss</string>
@ -3145,7 +3145,8 @@
<string name="shared_string_other">Annet</string>
<string name="shared_preference">Delt</string>
<string name="layer_osm_edits">OSM-redigeringer</string>
<string name="new_route_calculated_dist_dbg">Rute: Distanse %1$s, rutingstid %2$s \nUtregning: %3$.1f sec, %4$d veier, %5$d flis)</string>
<string name="new_route_calculated_dist_dbg">Rute: Distanse %1$s, rutetid %2$s
\nBeregning: %3$.1f sek., %4$d veier, %5$d fliser)</string>
<string name="contour_lines_and_hillshade">Koter og relieffskygge</string>
<string name="update_all_maps">Oppdater alle kart</string>
<string name="update_all_maps_q">Er du sikker på at du vil oppdatere alle (%1$d) kart\?</string>
@ -3938,4 +3939,6 @@
<string name="routing_attr_short_way_description">Optimalisert kortere rute (energisparende)</string>
<string name="snap_to_road_descr">Aktuelle posisjonsikon vil bli festet til gjeldende navigeringsrute</string>
<string name="routing_attr_height_obstacles_description">Ruting kan unngå kraftige oppoverbakker.</string>
<string name="trip_recording_save_and_continue">Lagre og fortsett</string>
<string name="lost_data_warning">All ulagret data vil gå tapt.</string>
</resources>

View file

@ -3748,7 +3748,7 @@
\n
\n</string>
<string name="what_is_new">Wat is er nieuw</string>
<string name="snowmobile_render_descr">Voor sneeuwscooter, rijden met speciale wegen en tracks.</string>
<string name="snowmobile_render_descr">Voor sneeuwscooter, rijden op speciale wegen en tracks.</string>
<string name="set_working_days_to_continue">Stel werkdagen in om door te gaan</string>
<string name="gpx_split_interval_descr">Selecteer het interval waarmee markeringen met afstand of tijd op de track worden weergegeven.</string>
<string name="gpx_split_interval_none_descr">Selecteer de gewenste splitsingsoptie: op tijd of op afstand.</string>

View file

@ -4040,4 +4040,6 @@
<string name="select_another_colorization">Selecione outro tipo de colorização.</string>
<string name="rendering_attr_noNatureReserveBoundaries_name">Limites naturais</string>
<string name="segments_count">Segmento %1$d</string>
<string name="trip_recording_save_and_continue">Salvar e continuar</string>
<string name="lost_data_warning">Todos os dados não salvos serão perdidos.</string>
</resources>

View file

@ -4037,9 +4037,9 @@
<string name="copy_poi_name">Копировать имя POI</string>
<string name="shared_string_interval">Интервал</string>
<string name="rendering_attr_noNatureReserveBoundaries_description">Скрыть природный заповедник, особо охраняемые природные территории и границы национального парка</string>
<string name="gpx_upload_trackable_visibility_descr">«Отслеживаемый» означает, что трек не будет виден в любых общедоступных списках, но обработанные точки из него будут доступны через public GPS API c временными отметками. Другие пользователи смогут лишь загружать обработанные точки из вашего трека. При этом трек не будет ассоциирован с вами.</string>
<string name="gpx_upload_identifiable_visibility_descr">«Идентифицируемый» означает, что трек будет виден всем в разделе треки пользователя, загрузившего трек и в общем списке треков, доступным на закладке GPS-треки. Другие пользователи смогут загрузить данные трека и в свойствах трека будет указано имя пользователя, загрузившего трек. Отметки времени точек трека доступны через public GPS API.</string>
<string name="gpx_upload_public_visibility_descr">«Общедоступный» означает, что трек будет виден всем в разделе треки пользователя, загрузившего трек и в общем списке треков, доступным на закладке GPS-треки. Отметки времени точек трека не доступны через public GPS API. Однако, другие пользователи по-прежнему могут загрузить файл трека из общего списка треков и данные трека будут иметь все отметки времени.</string>
<string name="gpx_upload_trackable_visibility_descr">«Отслеживаемый» означает, что трек не будет виден в любых общедоступных списках, но обработанные точки c отметками времени из него будут доступны через public GPS API (при этом трек не будет ассоциирован с вами). Другие пользователи смогут лишь загружать обработанные точки из вашего трека.</string>
<string name="gpx_upload_identifiable_visibility_descr">«Идентифицируемый» означает, что трек будет виден всем в разделе треки пользователя, загрузившего трек и в общем списке треков, доступном на странице GPS-треки. Другие пользователи смогут загрузить данные трека и в свойствах трека будет указано имя пользователя, загрузившего трек. Отметки времени точек трека доступны через public GPS API будут ссылаться на страницу с вашим оригинальным треком.</string>
<string name="gpx_upload_public_visibility_descr">«Общедоступный» означает, что трек будет виден всем в разделе треки пользователя, загрузившего трек и в общем списке треков, доступном на странице GPS-треки. Отметки времени точек трека не доступны через public GPS API. Однако, другие пользователи по-прежнему могут загрузить файл трека из общего списка треков и данные трека будут иметь все отметки времени.</string>
<string name="gpx_upload_private_visibility_descr">«Частный» означает, что трек не будет виден в любых общедоступных списках, но точки из него будут доступны через public GPS API без отметок времени.</string>
<string name="routing_attr_driving_style_description">Выберите цель, чтобы проложить к ней короткий, быстрый или безопасный маршрут</string>
<string name="delete_number_files_question">Удалить %1$d файлов\?</string>

View file

@ -3253,4 +3253,80 @@
<string name="poi_climbing_crag_filter">Klättring</string>
<string name="poi_rtsa_scale_filter">Svårighetskategori</string>
<string name="poi_park_ride">Parkera och åk</string>
<string name="poi_socket_tesla_roadster_output">Uttag: Tesla Roadster: utgående</string>
<string name="poi_socket_tesla_roadster_current">Uttag: Tesla Roadster: ström</string>
<string name="poi_socket_tesla_roadster">Uttag: Tesla Roadster</string>
<string name="poi_socket_tesla_supercharger">Uttag: Tesla Supercharger</string>
<string name="poi_socket_tesla_supercharger_output">Uttag: Tesla Supercharger: utgående</string>
<string name="poi_socket_tesla_supercharger_current">Uttag: Tesla Supercharger: ström</string>
<string name="poi_socket_tesla_standard_output">Uttag: Tesla standard: utgående</string>
<string name="poi_socket_tesla_standard_current">Uttag: Tesla standard: ström</string>
<string name="poi_socket_tesla_standard">Uttag: Tesla standard</string>
<string name="poi_socket_chademo_output">Uttag: CHAdeMO: utgående</string>
<string name="poi_socket_chademo_current">Uttag: CHAdeMO: ström</string>
<string name="poi_socket_chademo">Uttag: CHAdeMO</string>
<string name="poi_socket_type3_output">Uttag: Typ 3: utgeånde</string>
<string name="poi_socket_type3_current">Uttag: Typ 3: ström</string>
<string name="poi_socket_type3">Uttag: Typ 3</string>
<string name="poi_socket_type2_combo_output">Uttag: Typ 2: utgeånde</string>
<string name="poi_socket_type2_combo_current">Uttag: Typ 2 kombo: ström</string>
<string name="poi_socket_type2_combo">Uttag: Typ 2 kombo</string>
<string name="poi_socket_type2_output">Uttag: Typ 2: utgående</string>
<string name="poi_socket_type2_current">Uttag: Typ 2: ström</string>
<string name="poi_socket_type2">Uttag: Typ 2</string>
<string name="poi_socket_type1_combo_current">Uttag: Typ 1 kombo: ström</string>
<string name="poi_socket_type1_combo">Uttag: Typ 1 kombo</string>
<string name="poi_socket_type1_output">Uttag: Typ 1: utgående</string>
<string name="poi_socket_type1_current">Uttag: Typ 1: ström</string>
<string name="poi_socket_type1">Uttag: Typ 1</string>
<string name="poi_socket_type1_combo_output">Uttag: Typ 1 kombo: utgående</string>
<string name="poi_socket_cee_red_125a_output">Uttag: CEE röd 125A: utgående</string>
<string name="poi_socket_cee_red_125a_current">Uttag: CEE röd 125A: ström</string>
<string name="poi_socket_cee_red_125a">Uttag: CEE röd 125A</string>
<string name="poi_socket_cee_red_64a_output">Uttag: CEE röd 64A: utgående</string>
<string name="poi_socket_cee_red_64a_current">Uttag: CEE röd 64A: ström</string>
<string name="poi_socket_cee_red_64a">Uttag: CEE röd 64A</string>
<string name="poi_socket_cee_red_32a_output">Uttag: CEE röd 32A: utgående</string>
<string name="poi_socket_cee_red_32a_current">Uttag: CEE röd 32A: ström</string>
<string name="poi_socket_cee_red_32a">Uttag: CEE röd 32A</string>
<string name="poi_socket_cee_red_16a_output">Uttag: CEE röd 16A: utgående</string>
<string name="poi_socket_cee_red_16a_current">Uttag: CEE röd 16A: ström</string>
<string name="poi_socket_cee_red_16a">Uttag: CEE röd 16A</string>
<string name="poi_socket_cee_blue_output">Uttag: CEE blå: utgående</string>
<string name="poi_socket_cee_blue_current">Uttag: CEE blå: ström</string>
<string name="poi_socket_cee_blue">Uttag: CEE blå</string>
<string name="poi_water_place_access_multifamilies">Multi familj</string>
<string name="poi_water_place_access_family">Familj</string>
<string name="poi_water_place_access_community">Gemenskap</string>
<string name="poi_water_supply_bottled_water">Flaskvatten</string>
<string name="poi_water_supply_water_tank">Vattentank</string>
<string name="poi_water_supply_water_trucking">Vattentransporter</string>
<string name="poi_water_supply_borehole">Borrhål</string>
<string name="poi_water_supply_pump">Pump</string>
<string name="poi_water_supply_running_water">Rinnande vatten</string>
<string name="poi_water_supply_pipeline">Rörledning</string>
<string name="poi_water_supply_water_well">Vattenbrunn</string>
<string name="poi_water_purification_aquatabs">Aquatabs</string>
<string name="poi_water_purification_reverse_osmosis">Omvänd osmos</string>
<string name="poi_water_purification_chlorine">Klor</string>
<string name="poi_water_purification_none">Ingen</string>
<string name="poi_water_place_durability_emergency">Hållbarhet på vattenplats: kritiskt</string>
<string name="poi_water_place_durability_durable">Hållbarhet på vattenplats: hållbar</string>
<string name="poi_operational_status_needs_maintenance">Behöver underhåll</string>
<string name="poi_operational_status_broken">Trasig</string>
<string name="poi_operational_status_restricted">Begränsad</string>
<string name="poi_operational_status_closed">Stängd</string>
<string name="poi_operational_status_open">Öppen</string>
<string name="poi_visibility_area">Plats: area</string>
<string name="poi_visibility_street">Plats: väg</string>
<string name="poi_visibility_house">Plats: hus</string>
<string name="poi_location_entrance">Plats: entre</string>
<string name="poi_location_wall">Plats: vägg</string>
<string name="poi_location_bridge">Plats: bro</string>
<string name="poi_location_kiosk">Plats: kiosk</string>
<string name="poi_location_platform">Plats: plattform</string>
<string name="poi_location_indoor">Plats: inne</string>
<string name="poi_location_outdoor">Plats: ute</string>
<string name="poi_location_rooftop">Plats: tak</string>
<string name="poi_location_roof">Plats: tak</string>
</resources>

View file

@ -84,7 +84,8 @@
<string name="select_animate_speedup">Välj animerad ruttacceleration</string>
<string name="global_app_allocated_memory_descr">Allokerat minne %1$s MB (Android-gräns %2$s MB, Dalvik %3$s MB).</string>
<string name="global_app_allocated_memory">Allokerat minne</string>
<string name="native_app_allocated_memory_descr">Totalt inbyggt minne allokerat av appen %1$s MB (Dalvik %2$s MB, övrigt %3$s MB). Proportionellt minne %4$s MB (Android-gräns %5$s MB, Dalvik %6$s MB).</string>
<string name="native_app_allocated_memory_descr">Totalt inbyggt minne allokerat av appen %1$s MB (Dalvik %2$s MB, övrigt %3$s MB).
\nProportionellt minne %4$s MB (Android-gräns %5$s MB, Dalvik %6$s MB).</string>
<string name="native_app_allocated_memory">Totalt inbyggt minne</string>
<string name="starting_point_too_far">Startpunkten ligger för långt från närmaste väg.</string>
<string name="shared_location">Delad plats</string>
@ -165,9 +166,8 @@
<string name="osmand_parking_pm">em</string>
<string name="osmand_parking_am">fm</string>
<string name="osmand_parking_position_name">Parkeringsplats</string>
<string name="osmand_parking_plugin_description">Modulen Parkeringsplats hjälper dig att hålla reda på var din bil är parkerad och vid behov hur mycket parkeringstid det är kvar.
Du hittar din parkeringsplats och -tid på instrumentbrädan och i widgeten på kartskärmen. Du kan lägga till ett larm i kalendern som en påminnelse.</string>
<string name="osmand_parking_plugin_description">Låter dig spara var din bil är parkerad, inklusive hur mycket parkeringstid som finns kvar.
\nBåde plats och tid är synliga både på instrumentpanelen och i en kartwidget. En larmpåminnelse kan läggas till i Android-kalendern.</string>
<string name="osmand_parking_plugin_name">Parkeringsplats</string>
<string name="context_menu_item_add_parking_point">Markera som parkeringsplats</string>
<string name="context_menu_item_delete_parking_point">Ta bort P-markering</string>
@ -192,11 +192,11 @@ Du hittar din parkeringsplats och -tid på instrumentbrädan och i widgeten på
<string name="map_online_data">Online-kartor och kartrutor</string>
<string name="map_online_data_descr">Använd online-kartor (hämta och cacha kartbitar på SD-kortet).</string>
<string name="online_map_settings_descr">Konfigurera online- eller cachade källor för kartbitar.</string>
<string name="osmand_rastermaps_plugin_description">"Med denna modul får man tillgång till många typer av online-kartor, från fördefinierade Openstreetmap-rutor (som Mapnik) till satellitbilder och speciella lager såsom väderkartor, klimatkartor, geologiska kartor, reliefkartor o.s.v.
<string name="osmand_rastermaps_plugin_description">Med denna modul får man tillgång till många typer av online-kartor, från fördefinierade Openstreetmap-rutor (som Mapnik) till satellitbilder och speciella lager såsom väderkartor, klimatkartor, geologiska kartor, reliefkartor o.s.v.
\n
\nDessa kartor kan användas antingen som huvudkarta (baskarta) och visas på kartskärmen i OsmAnd eller som ett över- eller underlägg till en annan baskarta (som OsmAnds vanliga offline-kartor). För att göra en underliggande karta tydligare kan vissa element i OsmAnds vektorkartor lätt döljas via menyn \'Konfigurera karta\'.
\nDessa kartor kan användas antingen som huvudkarta (baskarta) och visas på kartskärmen i OsmAnd eller som ett över- eller underlägg till en annan baskarta (som OsmAnds vanliga offline-kartor). För att göra en underliggande karta tydligare kan vissa element i OsmAnds vektorkartor lätt döljas via menyn \'Konfigurera karta\'.
\n
\nKartbitar (tile maps) kan hämtas direkt på nätet eller förberedas för användning frånkopplad (och kopieras manuellt till OsmAnds datamapp) som en SQLite-databas som kan skapas med olika tredjepartsverktyg. "</string>
\nKartbitar (tile maps) kan hämtas direkt på nätet eller förberedas för användning frånkopplad (och kopieras manuellt till OsmAnds datamapp) som en SQLite-databas som kan skapas med olika tredjepartsverktyg.</string>
<string name="osmand_background_plugin_description">Visa inställningarna för att aktivera spårning och navigering i bakgrundsläge (skärm av) genom att periodvis väcka GPS-enheten.</string>
<string name="osmand_development_plugin_description">Denna modul visar inställningarna för utvecklings- och felsökningsfunktioner som rutt-testning och -simulering eller visning av renderingsprestanda eller röststyrning. Dessa inställningar är avsedda för utvecklare och behövs inte för den vanliga användaren.</string>
<string name="plugins_screen">Hantera insticksmoduler</string>
@ -208,19 +208,33 @@ Du hittar din parkeringsplats och -tid på instrumentbrädan och i widgeten på
<string name="osmand_parking_position_description">Din parkerade bils plats. %1$s</string>
<string name="prefs_plugins_descr">Insticksmoduler aktiverar avancerade inställningar samt ger ytterligare funktionalitet.</string>
<string name="prefs_plugins">Insticksmoduler</string>
<string name="osm_editing_plugin_description">"Med denna modul kan OsmAnd användas för att göra bidrag till OSM såsom skapa eller modifiera OSM POI-objekt, öppna eller kommentera OSM-anteckningar, och bidra med inspelade GPX-filer. OSM är ett globalt kartprojekt inom public domain, För mer info, se https://openstreetmap.org. Aktivt deltagande uppskattas och bidrag kan göras direkt från OsmAnd om du anger dina autentiseringsuppgifter till OSM i appen."</string>
<string name="osm_editing_plugin_description">Ge OSM-bidrag som att skapa eller modifiera OSM POI-objekt, öppna eller kommentera OSM-anteckningar och bidra med inspelade GPX-filer i OsmAnd genom att ange ditt användarnamn och lösenord. OpenStreetMap.org är ett community-driven, globalt kartläggningsprojekt för allmän domän.</string>
<string name="vector_maps_may_display_faster_on_some_devices">Vektorkartor ritas sannolikt upp snabbare. Fungerar kanske inte så bra på vissa enheter.</string>
<string name="play_commands_of_currently_selected_voice">Spela upp kommandon med vald röst</string>
<string name="test_voice_prompts">Test av röstmeddelanden</string>
<string name="switch_to_raster_map_to_see">Det finns ingen offline vektorkarta för den här platsen. Du kan hämta en i Inställningar (Hantera kartfiler) eller byta till online-kartor (aktivera modulen för online-kartor för detta).</string>
<string name="osmand_long_description_1000_chars">"OsmAnd (Open Street Maps Automated Navigation Directions)
\n
\nOsmAnd är ett öppen källkodsprogram med tillgång till ett brett utbud av global OpenStreetMap-data. Alla kartdata (vektor- eller rasterkartor) kan lagras i telefonens minneskort för offlineanvändning. OsmAnd erbjuder även navigering offline och online, inklusive röstguidning. Några av de viktigaste funktionerna: - Komplett offline-funktionalitet (lagra nedladdade vektorkartor eller kartbitar på enheten) - Kompakta offline-vektorkartor för hela världen finns tillgängliga - Nedladdning av land- eller regionkartor direkt från appen - Överlägg av flera kartlager möjligt, som GPX- eller navigationsspår, sevärdheter, favoriter, höjddata, offentliga hållplatser, extra kartor med anpassningsbara transparens - Sökning offline efter adresser och platser (POIs) - Offline-dirigering för medellånga sträckor (experimentell) - Bil-, cykel- och fotgängarlägen med: - Tillval automatisk växling mellan dag- och nattvisning - Tillval hastighetsberoende zoomning - Valfri inställningen enligt kompass eller färdriktningen - Frivillig körfältsvägledning, visning av hastighetsgräns, inspelade röster samt TTS-röster
\n
\nBegränsningar i denna gratisversion av OsmAnd: - Antalet hämtningar av kartor är begränsat - Ingen tillgång till Wikipedia offline POIs
\n
\nOsmAnd utvecklas aktivt och vårt projekt och dess fortsatta framsteg bygger på ekonomiska bidrag för att finansiera utveckling och testning av ny funktionalitet. Vänligen överväg att köpa OsmAnd+, finansiera specifika nya funktioner eller göra en allmän donation på osmand.net.
\n "</string>
<string name="osmand_long_description_1000_chars">OsmAnd (OSM Automated Navigation Directions)
\n
\nOsmAnd är en programvara för öppen källkodsnavigering med tillgång till ett stort antal globala OSM-data. Alla kartdata (vektor- eller brickor) kan lagras på telefonens minneskort för offline-användning. Offline- och online-dirigeringsfunktioner erbjuds också, inklusive röstvägledning för sväng.
\n
\nNågra av kärnfunktionerna:
\n- Komplett offline-funktionalitet (lagra nedladdad vektor eller kakelkartor i enhetens lagring)
\n- Kompakta offlinevektorkartor för hela världen
\n- Ladda ner land- eller regionkartor direkt från appen
\n- Överlagring av flera kartlager möjliga, som GPX eller navigationsspår, intressanta platser, favoriter, konturlinjer, kollektivtrafikstopp, ytterligare kartor med anpassningsbar transparens
\n- Offline sökning efter adresser och platser (POI)
\n- Offline-dirigering för medelstora avstånd
\n- Lägen för bil, cykel och fotgängare med tillval:
\n- Automatisk växling mellan dag och natt
\n- Hastighetsberoende kartzoomning
\n- Kartinriktning enligt kompass eller rörelseriktning
\n- Fältvägledning, hastighetsgränsvisning, inspelade och text-till-tal-röster
\n
\nBegränsningar av denna gratisversion av OsmAnd:
\n- Antalet nedladdningar av kartor begränsat
\n- Ingen offlineåtkomst till Wikipedia-intressepunkter
\n
\nOsmAnd utvecklas aktivt och vårt projekt och dess fortsatta framsteg är beroende av ekonomiska bidrag för utveckling och testning av ny funktionalitet. Överväg att köpa OsmAnd +, eller finansiera specifika nya funktioner eller göra en allmän donation på https://osmand.net.</string>
<string name="native_rendering">Inbyggd rendering</string>
<string name="default_buttons_support">Support</string>
<string name="support_new_features">Ge stöd till nya funktioner</string>
@ -297,9 +311,8 @@ Du hittar din parkeringsplats och -tid på instrumentbrädan och i widgeten på
<string name="osmand_service">Bakgrundsläge</string>
<string name="osmand_service_descr">OsmAnd körs i bakgrunden medan skärmen är avstängd.</string>
<string name="download_files_not_enough_space">Det finns inte tillräckligt med ledigt utrymme för att hämta %1$s MB (ledigt: %2$s).</string>
<string name="download_files_question_space">Hämta {0} fil(er)?
Nyttjat utrymme är {1} MB.
(Tillgängligt utrymme är {2} MB.)</string>
<string name="download_files_question_space">Hämta {0} fil(er)\?
\n{1} MB (av {2} MB) kommer att användas.</string>
<string name="use_transparent_map_theme">Genomskinligt tema</string>
<string name="native_library_not_supported">Inbyggt bibliotek stöds inte på den här enheten.</string>
<string name="init_native_library">Initierar inbyggt bibliotek …</string>
@ -382,7 +395,7 @@ Nyttjat utrymme är {1} MB.
<string name="installing_new_resources">Packar upp nya data …</string>
<string name="internet_connection_required_for_online_route">En online-navigeringstjänst är vald men ingen internetanslutning är tillgänglig.</string>
<string name="tts_language_not_supported_title">Språket stöds inte</string>
<string name="tts_language_not_supported">Det valda språket stöds inte av den installerade Android TTS (text-till-tal)-motorn. Vill du söka efter en annan TTS-motor på Market? Annars kommer det förinställda TTS-språket att användas.</string>
<string name="tts_language_not_supported">Det valda språket stöds inte av Android TTS (text-till-tal) -motorn installerad, dess förinställda TTS-språk används istället. Leta efter en annan TTS-motor i butiken\?</string>
<string name="tts_missing_language_data_title">Data saknas</string>
<string name="tts_missing_language_data">Inga data för det valda språket är installerade. Vill du besöka Google Play för att installera?</string>
<string name="gpx_option_reverse_route">Omvänd GPX-riktning</string>
@ -701,7 +714,7 @@ Nyttjat utrymme är {1} MB.
<string name="search_villages_and_postcodes">Sök efter fler byar/postnummer</string>
<string name="rendering_attr_showRoadMaps_description">Välj när du vill visa kartor som endast har vägar:</string>
<string name="rendering_attr_showRoadMaps_name">Kartor med enbart vägar</string>
<string name="download_roads_only_item">"Vägar "</string>
<string name="download_roads_only_item">Bara vägar</string>
<string name="download_regular_maps">Standardkartor</string>
<string name="download_roads_only_maps">Karta med enbart vägar</string>
<string name="safe_mode_description">Kör appen i felsäkert läge (för långsammare Android istället för intern kod).</string>
@ -783,9 +796,9 @@ Nyttjat utrymme är {1} MB.
<string name="av_settings">Inställningar för ljud och video </string>
<string name="recording_error">Ett fel uppstod under inspelningen </string>
<string name="recording_camera_not_available">Ingen kamera tillgänglig</string>
<string name="srtm_plugin_description">"Denna modul erbjuder överlägg med höjdkurvor som kan visas i kombination med OsmAnds standardkartor. Denna funktion kommer att uppskattas av idrottsmän, vandrare och alla som är intresserade av höjdskillnader i landskapet.
\n
\nDessa globala data (mellan 70 grader norr och 70 grader syd) baseras på mätningar av SRTM (Shuttle Radar Topography Mission) och ASTER (Advanced Spaceborne Thermal Emission and Reflection Radiometer), ett bildinstrument ombord Terra, flaggskeppet i NASA:s Earth Observing System. ASTER är ett samprojekt mellan NASA, Japans Ministry of Economy, Trade and Industry (METI), and Japan Space Systems (J-spacesystems). "</string>
<string name="srtm_plugin_description">Denna modul erbjuder överlägg med höjdkurvor som kan visas i kombination med OsmAnds standardkartor. Denna funktion kommer att uppskattas av idrottsmän, vandrare och alla som är intresserade av höjdskillnader i landskapet.
\n
\nDessa globala data (mellan 70 grader norr och 70 grader syd) baseras på mätningar av SRTM (Shuttle Radar Topography Mission) och ASTER (Advanced Spaceborne Thermal Emission and Reflection Radiometer), ett bildinstrument ombord Terra, flaggskeppet i NASA:s Earth Observing System. ASTER är ett samprojekt mellan NASA, Japans Ministry of Economy, Trade and Industry (METI), and Japan Space Systems (J-spacesystems).</string>
<string name="delete_target_point">Ta bort destination</string>
<string name="intermediate_point">Mellanliggande destination %1$s</string>
<string name="poi_filter_nominatim">Online Nominatim</string>
@ -874,11 +887,11 @@ Nyttjat utrymme är {1} MB.
<string name="prefer_in_routing_descr">Föredra motorvägar.</string>
<string name="item_checked">markerad</string>
<string name="item_unchecked">ej markerad</string>
<string name="av_def_action_choose">Välj vid användning</string>
<string name="av_def_action_choose">På förfrågan\?</string>
<string name="enable_plugin_monitoring_services">Aktivera Trippinspelningspluginen för att använda positionsloggningstjänster (GPX-loggning, online-spårning)</string>
<string name="osmand_srtm_long_description_1000_chars">"Denna modul erbjuder både ett överlägg med konturlinjer och ett höjdkurvslager som kan visas ovanpå OsmAnds offline-kartor. Denna funktion kommer att uppskattas av idrottsmän, vandrare och alla som är intresserade av höjdskillnader i landskapet.
<string name="osmand_srtm_long_description_1000_chars">Denna modul erbjuder både ett överlägg med konturlinjer och ett höjdkurvslager som kan visas ovanpå OsmAnds offline-kartor. Denna funktion kommer att uppskattas av idrottsmän, vandrare och alla som är intresserade av höjdskillnader i landskapet.
\n
\nDessa globala data (mellan 70 grader norr och 70 grader syd) är baserade på SRTM (Shuttle Radar Topography Mission) och ASTER (Advanced Spaceborne Thermal Emission and Reflection Radiometer), ett bildinstrument på Terra, NASA:s Earth Observing Systems satellit. ASTER är ett samarbete mellan NASA, Japans finansdepartement, Trade and Industry (METI) och Japan Space Systems (J-spacesystems). "</string>
\nDessa globala data (mellan 70 grader norr och 70 grader syd) är baserade på SRTM (Shuttle Radar Topography Mission) och ASTER (Advanced Spaceborne Thermal Emission and Reflection Radiometer), ett bildinstrument på Terra, NASA:s Earth Observing Systems satellit. ASTER är ett samarbete mellan NASA, Japans finansdepartement, Trade and Industry (METI) och Japan Space Systems (J-spacesystems).</string>
<string name="access_arrival_time">Ankomsttid</string>
<string name="index_name_openmaps">OpenMaps EU</string>
<string name="layer_hillshade">Skuggad relief-lager</string>
@ -892,7 +905,7 @@ Nyttjat utrymme är {1} MB.
<string name="files_limit">%1$d filer kvar</string>
<string name="available_downloads_left">Du har %1$d filer kvar att hämta</string>
<string name="install_paid">Fullversion</string>
<string name="cancel_route">Avbryt rutten</string>
<string name="cancel_route">Avbryt rutten\?</string>
<string name="cancel_navigation">Avbryt navigeringen</string>
<string name="clear_destination">Ta bort destinationen</string>
<string name="download_using_mobile_internet">Wi-Fi är för tillfället inte anslutet. Vill du hämta med din nuvarande anslutning till Internet?</string>
@ -1218,9 +1231,9 @@ Nyttjat utrymme är {1} MB.
<string name="speak_poi">Närbelägna intresssepunkter</string>
<string name="index_tours">Rundturer</string>
<string name="shared_string_all">Alla</string>
<string name="record_plugin_description">"Denna modul aktiverar funktionen att antingen spela in och spara dina spår genom att du trycker på widgeten GPX-loggning på kartskärmen eller att alla dina rutter sparas automatiskt i en GPX-fil.
<string name="record_plugin_description">Denna modul aktiverar funktionen att antingen spela in och spara dina spår genom att du trycker på widgeten GPX-loggning på kartskärmen eller att alla dina rutter sparas automatiskt i en GPX-fil.
\n
\nInspelade spår kan delas ut till vänner eller användas som bidrag till OSM. Idrottsmän kan använda inspelade spår för att följa sin träning. Viss grundläggande spåranalys kan göras direkt i OsmAnd, såsom varvtider, genomsnittshastighet o.s.v. och spår kan givetvis också analyseras i efterhand i speciella analysverktyg från tredje part. "</string>
\nInspelade spår kan delas ut till vänner eller användas som bidrag till OSM. Idrottsmän kan använda inspelade spår för att följa sin träning. Viss grundläggande spåranalys kan göras direkt i OsmAnd, såsom varvtider, genomsnittshastighet o.s.v. och spår kan givetvis också analyseras i efterhand i speciella analysverktyg från tredje part.</string>
<string name="record_plugin_name">Inspelning av resa</string>
<string name="int_hour">h</string>
<string name="duration">Längd</string>
@ -1279,7 +1292,7 @@ Nyttjat utrymme är {1} MB.
<string name="everything_up_to_date">Alla filer är uppdaterade</string>
<string name="use_opengl_render">Använd OpenGL-rendering</string>
<string name="use_opengl_render_descr">Använd hårdvaruaccelererad OpenGL-rendering (fungerar kanske inte på vissa enheter).</string>
<string name="no_internet_connection">Kan inte hämta; kontrollera din internetsanslutning.</string>
<string name="no_internet_connection">Kan inte hämta, kontrollera din internetsanslutning.</string>
<string name="rendering_attr_roadStyle_name">Vägtyp</string>
<string name="rendering_value_default_name">Standard</string>
<string name="rendering_value_orange_name">Brandgul</string>
@ -1349,13 +1362,20 @@ Nyttjat utrymme är {1} MB.
\nEn kartfil som innehåller alla nautiska symboler globalt finns tillgänglig som en enda nedladdning med namnet \'World seamarks\'.
\n
\nDenna vy kan ändras genom att antingen inaktivera den här igen eller genom att ändra kartstilen under Konfigurera kartor.</string>
<string name="plugin_ski_descr">"Om du aktiverar denna vy ändras kartstilen till Vinter och skidor, och visar landskapet i vinterskrud.
\n\nEn global karta med alla pister och längdskidspår i denna vy finns tillgänglig under Alla kartor som \'World ski map\'.
\n\nDenna vy kan ändras genom att antingen inaktivera den här igen eller genom att ändra kartstilen under Konfigurera kartor. "</string>
<string name="plugin_touringview_descr">"Om du aktiverar denna vy ändras kartan till \'Vägkartsvy\', som är en speciell vy med mycket detaljer för resenärer och yrkesförare.
\n\nDenna vy ger, vid varje zoomnivå, maximalt antal detaljer som är tillgängliga i kartdatat (speciellt vägar, stigar och orienteringsmärken).\n\nDen visar också alla vägtyper på ett mycket tydligt sätt via färgkoder något som är användbart t.ex vid framförande av stora fordon.
\n\nOch den erbjuder också speciella alternativ såsom visning av cykelrutter eller rutter i Alperna.\n\nIngen speciell hämtning av någon karta krävs; denna vy skapas med våra standardkartor.
\n\nDenna vy kan ändras genom att antingen inaktivera den här igen eller genom att ändra kartstilen under Konfigurera kartor. "</string>
<string name="plugin_ski_descr">Detta plugin för OsmAnd ger dig detaljer om globala utförsåkning, längdskidspår, alpina skidvägar, linbanor och skidliftar. Rutter och pister visas färgkodade av svårigheter och avbildas i en speciell \"vinter\" -stil som liknar ett snöfärgat vinterlandskap.
\n
\nOm du aktiverar den här vyn ändras kartstilen till \"Vinter och skidor\" och visar alla landskapsfunktioner under vinterförhållanden. Denna vy kan återställas genom att antingen avaktivera den igen här, eller genom att ändra \'Kartstil\' under \'Konfigurera karta\' efter önskemål.</string>
<string name="plugin_touringview_descr">Om du aktiverar denna vy ändras kartan till \'Vägkartsvy\', som är en speciell vy med mycket detaljer för resenärer och yrkesförare.
\n
\nDenna vy ger, vid varje zoomnivå, maximalt antal detaljer som är tillgängliga i kartdatat (speciellt vägar, stigar och orienteringsmärken).
\n
\nDen visar också alla vägtyper på ett mycket tydligt sätt via färgkoder något som är användbart t.ex vid framförande av stora fordon.
\n
\nOch den erbjuder också speciella alternativ såsom visning av cykelrutter eller rutter i Alperna.
\n
\nIngen speciell hämtning av någon karta krävs; denna vy skapas med våra standardkartor.
\n
\nDenna vy kan ändras genom att antingen inaktivera den här igen eller genom att ändra kartstilen under Konfigurera kartor.</string>
<string name="location_on_map">Plats:\n Lat %1$s\n Lon %2$s</string>
<string name="plugin_touringview_name">Vägkartsvy</string>
<string name="days_behind">dagar efter</string>
@ -1423,7 +1443,7 @@ Nyttjat utrymme är {1} MB.
<string name="simulate_your_location">Simulera din plats</string>
<string name="drawer">Platt lista</string>
<string name="short_location_on_map">Lat %1$s
Long %2$s</string>
\nLong %2$s</string>
<string name="tips_and_tricks_descr">Frågor och svar, nyliga förändringar och annat.</string>
<string name="routing_settings_2">Navigeringsinställningar</string>
<string name="general_settings_2">Allmänna inställningar</string>
@ -1495,7 +1515,7 @@ Long %2$s</string>
<string name="local_recordings_delete_all_confirm">Du håller på att ta bort %1$d anteckningar. Är du säker?</string>
<string name="download_wikipedia_maps">Wikipedia</string>
<string name="shared_string_import2osmand">Importera till OsmAnd</string>
<string name="gps_network_not_enabled">Platstjänsten är inte aktiverad. Vill du slå på den?</string>
<string name="gps_network_not_enabled">Platstjänsten är av. Vill du slå på den\?</string>
<string name="archive_wikipedia_data">Du har gamla och inkompatibla data från Wikipedia. Vill du arkivera dem?</string>
<string name="download_wikipedia_files">Hämta ytterligare data från Wikipedia (%1$s MB)?</string>
<string name="lang_vo">Volapük</string>
@ -1611,7 +1631,7 @@ Long %2$s</string>
<string name="si_m_s">Meter per sekund</string>
<string name="si_min_km">Minuter per kilometer</string>
<string name="si_min_m">Minuter per mile</string>
<string name="si_nm_h">Sjömil i timmen (knop)</string>
<string name="si_nm_h">Sjömil per timme (knop)</string>
<string name="shared_string_trip_recording">Inspelning av resa</string>
<string name="shared_string_navigation">Navigering</string>
<string name="osmand_running_in_background">Körs i bakgrunden</string>
@ -1619,7 +1639,7 @@ Long %2$s</string>
<string name="favorite_category_select">Välj kategori</string>
<string name="count_of_lines">Antal rader</string>
<string name="nm">di</string>
<string name="nm_h">nmi/h</string>
<string name="nm_h">M</string>
<string name="min_mile">min/mi</string>
<string name="min_km">min/km</string>
<string name="m_s">m/s</string>
@ -1746,7 +1766,7 @@ Long %2$s</string>
<string name="route_distance">Avstånd:</string>
<string name="route_duration">Tid:</string>
<string name="missing_write_external_storage_permission">Appen har inte tillåtelse att använda SD-kortet</string>
<string name="no_location_permission">Appen har inte tillräckliga behörigheter för att komma åt platsdata.</string>
<string name="no_location_permission">Appen saknar behörigheter för att komma åt platsdata.</string>
<string name="no_camera_permission">Appen har inte tillräckliga behörigheter för att komma åt kameran.</string>
<string name="no_microphone_permission">Appen har inte tillräckliga behörigheter för att komma åt mikrofonen.</string>
<string name="select_voice_provider">Välj röstvägledning</string>
@ -1807,9 +1827,10 @@ Long %2$s</string>
<string name="shared_string_toolbar">Verktygsfält</string>
<string name="shared_string_widgets">Widgetar</string>
<string name="download_files_error_not_enough_space">Inte tillräckligt med utrymme!
Detta skulle kräva {3} MB temporärt och {1} MB permanent.
Tillgängligt utrymme är blott {2} MB.</string>
<string name="download_files_question_space_with_temp">Hämta {0} fil(er)? Nyttjat utrymme är {3} MB temporärt och {1} MB permanent. (Tillgängligt utrymme är {2} MB.)</string>
\n{3} MB temporärt och {1} MB permanent.
\n(Bara {2} MB tillgängligt.)</string>
<string name="download_files_question_space_with_temp">Hämta {0} fil(er)\?
\n{3} MB används temporärt och {1} MB permanent. (Av{2} MB.)</string>
<string name="upload_osm_note">Ladda upp OSM-anteckning</string>
<string name="upload_anonymously">Ladda upp anonymt</string>
<string name="select_map_marker">Välj kartmarkör</string>
@ -1879,8 +1900,8 @@ Tillgängligt utrymme är blott {2} MB.</string>
<string name="storage_permission_restart_is_required">Nu har appen tillåtelse att skriva till extern lagringsplats. En manuell omstart av appen krävs.</string>
<string name="osm_live_support_region">Stödregion</string>
<string name="osm_live_header">Denna prenumeration aktiverar uppdateringar varje timme av kartor runt omkring i världen.
En del av inkomsterna går tillbaka till OSM-gemenskapen och betalas ut för varje OSM-bidrag.
Om du tycker om OsmAnd och OSM och vill stödja dem så är detta ett utmärkt sätt att göra det på.</string>
\nEn del av inkomsterna går tillbaka till OSM-gemenskapen och betalas ut för varje OSM-bidrag.
\nOm du tycker om OsmAnd och OSM och vill stödja och stödjas av dem så är detta ett utmärkt sätt att göra det på.</string>
<string name="access_no_destination">Destinationen är inte fastställd</string>
<string name="map_widget_magnetic_bearing">Magnetisk bäring</string>
<string name="rec_split_clip_length">Klipplängd</string>
@ -1936,7 +1957,7 @@ Om du tycker om OsmAnd och OSM och vill stödja dem så är detta ett utmärkt s
<string name="delete_filter">Ta bort filter</string>
<string name="new_filter">Nytt filter</string>
<string name="new_filter_desc">Ange ett namn på det nya filtret. Det kommer att läggas till på fliken Kategorier.</string>
<string name="translit_name_if_miss">"Transkribera om %1$s namn saknas"</string>
<string name="translit_name_if_miss">Transkribera om %1$s namn saknas</string>
<string name="skip_map_downloading">Hoppa över nerladdning av kartor</string>
<string name="search_another_country">Välj en annan region</string>
<string name="osmand_plus_banner_desc">Obegränsade nedladdningar av kartor, uppdateringar och Wikipedia-plugin.</string>
@ -1960,7 +1981,7 @@ Om du tycker om OsmAnd och OSM och vill stödja dem så är detta ett utmärkt s
<string name="donation_to_osm">Donation till OpenStreetMap-gemenskapen</string>
<string name="get_it">Skaffa det</string>
<string name="get_for">Skaffa för %1$s</string>
<string name="skip_map_downloading_desc">"Du har inte några offline-kartor installerade. Du kan välja en karta från listan eller hämta kartor senare via \'Meny - %1$s\'."</string>
<string name="skip_map_downloading_desc">Du har inte några offline-kartor installerade. Du kan välja en karta från listan eller hämta kartor senare via \'Meny - %1$s\'.</string>
<string name="search_map">Söker efter kartor …</string>
<string name="first_usage_greeting">Erhåll vägbeskrivningar och upptäck nya platser utan Internetuppkoppling</string>
<string name="search_my_location">Sök efter min plats</string>
@ -2047,7 +2068,7 @@ Om du tycker om OsmAnd och OSM och vill stödja dem så är detta ett utmärkt s
<string name="navigate_point_olc_info_invalid">Ogiltig OLC
\n</string>
<string name="navigate_point_olc_info_short">Kort OLC
Vänligen tillhandahåll fullständig kod</string>
\nVänligen tillhandahåll fullständig kod</string>
<string name="file_can_not_be_moved">Filen kan inte flyttas.</string>
<string name="shared_string_move">Flytta</string>
<string name="shared_string_gpx_tracks">Spår</string>
@ -2090,7 +2111,7 @@ Vänligen tillhandahåll fullständig kod</string>
<string name="shared_string_action_name">Åtgärdsnamn</string>
<string name="quick_action_map_overlay_title">Kartöverlägg</string>
<string name="quick_action_map_overlay_action">Lägg till överlägg</string>
<string name="quick_action_map_overlay_switch">"Kartöverlägget har ändrats till \"%s\"."</string>
<string name="quick_action_map_overlay_switch">Kartöverlägget har ändrats till \"%s\".</string>
<string name="quick_action_btn_tutorial_descr">Tryck länge och dra knappen för att ändra dess position på skärmen.</string>
<string name="routing_attr_height_obstacles_name">Använd höjddata</string>
<string name="rendering_attr_depthContours_description">Visa djupkonturer och punkter.</string>
@ -2420,7 +2441,9 @@ Vänligen tillhandahåll fullständig kod</string>
<string name="max_min">Max/Min</string>
<string name="min_max">Min/Max</string>
<string name="route_is_too_long_v2">Denna väg kan vara för lång tid att beräkna. Lägg till mellanliggande destinationer om inget resultat finns inom 10 minuter.</string>
<string name="osmand_extended_description_part1">"OsmAnd (OSM Automated Navigation Directions) är en kartnavigationsapp med tillgång till gratis, världsomfattande OpenStreetMap (OSM)-data av hög kvalitet. Njut av röstnavigation eller visuell navigation, visning av POI (points of interest - nyttoplatser), att skapa och hantera GPX-spår, visa höjdkurvor och höjdinfo (via plugin), val mellan bil-, cykel-, fotgängar-lägen, OSM-redigering och mycket mer."</string>
<string name="osmand_extended_description_part1">OsmAnd (OSM Automated Navigation Directions) är en kartnavigationsapp med tillgång till gratis, världsomfattande OpenStreetMap (OSM)-data av hög kvalitet.
\n
\nNjut av röstnavigation eller visuell navigation, visning av POI (points of interest - nyttoplatser), att skapa och hantera GPX-spår, visa höjdkurvor och höjdinfo (via plugin), val mellan bil-, cykel-, fotgängar-lägen, OSM-redigering och mycket mer.</string>
<string name="osmand_extended_description_part2">GPS-navigering
\n• Välj mellan offline- (inga roaming-avgifter när du är utomlands) eller online-läge a(snabbare)
\n• Steg-för-steg röstguidning leder dig längs vägen (inspelade och genererade röster)
@ -2442,8 +2465,14 @@ Vänligen tillhandahåll fullständig kod</string>
\n • Låter dig välja hur du vill visa namn på kartan: på svenska, lokala, eller fonetisk stavning
\n • Visar specialiserade online-rutor, satellitvy (från Bing), olika överlägg som tour/navigering GPX-spår och ytterligare lager med anpassningsbar transparens
\n</string>
<string name="osmand_extended_description_part4">Skidåkning OsmAnd skidkartor plugin gör att du kan se skidspår svårighetsgrad och en del kompletterande information, som plats för liftar och andra faciliteter.</string>
<string name="osmand_extended_description_part5">Cykling • Du kan hitta cykelstigar på kartan • GPS-navigering i cykelläge skapar din rutt med hjälp av cykelvägar • Du kan se din hastighet och höjd • Med GPX-inspelningsalternativet kan du spela in din resa och dela den • Via ytterligare plugin kan du aktivera visning av höjdkurvor och höjdrelief</string>
<string name="osmand_extended_description_part4">Skidåkning
\nOsmAnd skidkartor plugin gör att du kan se skidspår svårighetsgrad och en del kompletterande information, som plats för liftar och andra faciliteter.</string>
<string name="osmand_extended_description_part5">Cykling
\n• Hitta cykelvägar på kartan
\n• GPS-navigering i cykelläge bygger din rutt med cykelvägar
\n• Se din hastighet och höjd
\n• Med GPX-inspelningsalternativ kan du spela in din resa och dela den
\n• Via ett extra plugin kan du aktivera konturlinjer och backskuggning</string>
<string name="osmand_extended_description_part6">Promenader, vandring, stadsrundtur
\n • Kartan visar promenad- och vandringsleder
\n • Wikipedia på ditt föredragna språk kan berätta en hel del under en stadsrundtur
@ -2458,23 +2487,58 @@ Vänligen tillhandahåll fullständig kod</string>
\n</string>
<string name="clear_all_intermediates">Rensa alla mellanliggande punkter</string>
<string name="rendering_attr_whiteWaterSports_name">Strömsporter</string>
<string name="osmand_extended_description_part8">OsmAnd är open-source och är utvecklas aktivt. Alla kan bidra till appen genom att rapportera buggar, förbättra översättningar eller programmera nya funktioner. Projektet är i ett dynamiskt tillstånd av kontinuerlig förbättring av alla dessa former genom utvecklare och interaktion med användare. Projektet är också beroende av ekonomiska bidrag för att finansiera kodning och testning av nya funktioner. Ungefärlig karttäckning och kvalitet: • Västeuropa: **** • Östeuropa: *** • Ryssland: *** • Nordamerika: *** • Sydamerika: ** • Asien: ** • Japan &amp; Korea: *** • Mellanöstern: ** • Afrika: ** • Antarktis: * De flesta länder runt om i världen finns tillgängliga för hämtning! Få en tillförlitlig navigator i ditt land - det kan vara Tyskland, Frankrike, Mexiko, Storbritannien, Spanien, Nederländerna, USA, Ryssland, Brasilien eller något annat.</string>
<string name="osmand_plus_long_description_1000_chars">OsmAnd+ (OSM Automated Navigation Directions)
<string name="osmand_extended_description_part8">OsmAnd är aktivt utvecklad programvara med öppen källkod. Alla kan bidra till appen genom att rapportera fel, förbättra översättningar eller koda nya funktioner. Dessutom bygger projektet på ekonomiska bidrag för att finansiera kodning och testning av nya funktioner.
\nUngefärlig karttäckning och kvalitet:
\n• Västeuropa: ****
\n• Östeuropa: ***
\n• Ryssland: ***
\n• Nordamerika: ***
\n• Sydamerika: **
\n• Asien: **
\n• Japan och Korea: ***
\n• Mellanöstern: **
\n• Afrika: **
\n• Antarktis: *
\nDe flesta länder runt om i världen är tillgängliga för nedladdning!
\nFå en pålitlig navigatör i ditt land - vare sig det är Frankrike, Tyskland, Mexiko, Storbritannien, Spanien, Nederländerna, USA, Ryssland, Brasilien eller något annat.</string>
<string name="osmand_plus_long_description_1000_chars">OsmAnd + (OSM Automated Navigation Directions)
\n
\nOsmAnd+ är ett open source-navigationsapp med tillgång till ett brett utbud av global OpenStreetMap(OSM)-data. Alla kartdata (vektor- eller rasterkartor) kan sparas på telefonens minneskort för användning offline. OsmAnd erbjuder även offline och online-ruttunktioner, inklusive turn-by-turn röstguidning.
\nOsmAnd + är en programvara för programvara med öppen källkod för navigering med tillgång till ett stort antal globala OSM-data. Alla kartdata (vektor- eller brickor) kan lagras på telefonens minneskort för offline-användning. Offline- och online-dirigeringsfunktioner erbjuds också, inklusive röstvägledning för sväng.
\n
\nOsmAnd+ är den betalversionenen av appeb, genom att köpa det stödjer du projektet, finansierar utveckling av nya funktioner, och får de senaste uppdateringarna.
\nOsmAnd + är den betalda appversionen, genom att köpa den stöder du projektet, finansierar utvecklingen av nya funktioner och får de senaste uppdateringarna.
\n
\nNågra av de centrala funktionerna: - Komplett offline-funktionalitet (spara vektor- eller rasterkartor i enhetens lagring) - Kompakta offline vektorkartor för hela världen finns tillgängliga - Obegränsad hämtning av land- eller regionkartor direkt från appen - Offline Wikipedia-artiklar (hämta Wikipedia-POI), utmärkt för sightseeing
\nNågra av kärnfunktionerna:
\n- Komplett offline-funktionalitet (lagra nedladdad vektor eller kakelkartor i enhetens lagring)
\n- Kompakta offlinevektorkartor för hela världen
\n- Obegränsad nedladdning av land- eller regionkartor direkt från appen
\n- Offline Wikipedia-funktion (ladda ner Wikipedia POI), perfekt för sightseeing
\n- Överlagring av flera kartlager möjliga, som GPX eller navigationsspår, intressanta platser, favoriter, konturlinjer, kollektivtrafikstopp, ytterligare kartor med anpassningsbar transparens
\n
\n - Överlagring av flera kartskikt är möjligt, som GPX eller navigeringsspår, Punkter av Intresse, favoriter, höjdkurvor, hållplatser för kollektivtrafiken, fler kartor med anpassningsbar genomskinlighet- Offlinesökning efter adresser och intressepunkter (POI) - Offline routing för mediumdistansavstånd - Bil-, cykel- och fotgängarelägen med: - tillval automatiskt byte av dag/nattläge -
\n
\n - Valfri hastighetsbunden kartzoom - valfri kartjustering enligt kompass eller riktning - som tillval körfältsguide, hastighetsgräns visas, inspelade- och TTS-röster</string>
\n- Offline sökning efter adresser och platser (POI)
\n- Offline-dirigering för medelstora avstånd
\n- Lägen för bil, cykel och fotgängare med tillval:
\n- Automatisk växling mellan dag och natt
\n- Hastighetsberoende kartzoomning
\n- Kartinriktning enligt kompass eller rörelseriktning
\n- Fältvägledning, hastighetsgränsvisning, inspelade och text-till-tal-röster
\n</string>
<string name="nothing_found_in_radius">Kunde inte hitta något inom:</string>
<string name="select_waypoints_category_description">Lägg till alla spårens vägpunkter, eller välj separata kategorier.</string>
<string name="shared_string_total">Totalt</string>
<string name="osmand_plus_extended_description_part1">OsmAnd+ (OSM Automated Navigation Directions) är en kartnavigationsapp med tillgång till gratis världsomfattande och högkvalitativa OpenStreetMap (OSM)-data. Njut av röst- och visuell navigation, visning av POI (points of interest - intressepunkter), att skapa och hantera GPX-spår, se höjdkurvor och höjdinfo, välja mellan bil-cykel- och fotgängarlägen, OSM-redigering och mycket mer. OsmAnd+ är en betalversion av appen. Genom att köpa den, stödjer du projektet, finansierar utveckling av nya funktioner, och får de senaste uppdateringarna. Några av de viktigaste funktionerna:</string>
<string name="osmand_plus_extended_description_part2">Navigering • Fungerar på nätet (snabb) eller offline (inga roaming-avgifter när du är utomlands) • Sväng-för-sväng-röstguidning (inspelade och syntetiska röster) • Valfri körfältsguide, gatunamn visas, och beräknad ankomsttid • Stödjer mellanliggande punkter på din resplan • Automatisk omdirigering när du avviker från rutten • Sök platser efter adress eller typ (t ex: restaurang, hotell, bensinstation, museum), eller med geografiska koordinater</string>
<string name="osmand_plus_extended_description_part1">OsmAnd+ (OSM Automated Navigation Directions) är en kartnavigationsapp med tillgång till gratis världsomfattande och högkvalitativa OSM-data.
\nNjut av röst- och visuell navigation, visning av POI (points of interest - intressepunkter), att skapa och hantera GPX-spår, se höjdkurvor och höjdinfo, välja mellan bil-cykel- och fotgängarlägen, OSM-redigering och mycket mer.
\n
\nOsmAnd+ är en betalversion av appen. Genom att köpa den, stödjer du projektet, finansierar utveckling av nya funktioner, och får de senaste uppdateringarna.
\n
\nNågra av de viktigaste funktionerna:</string>
<string name="osmand_plus_extended_description_part2">Navigering
\n• Fungerar online (snabbt) eller offline (inga roamingavgifter när du är utomlands)
\n• Röstvägledning för sväng (inspelade och syntetiserade röster)
\n• Valfri körvägledning, visning av gatunamn och beräknad ankomsttid
\n• Stöder mellanliggande poäng på din resplan
\n• Automatisk omdirigering när du avviker från rutten
\n• Sök efter platser efter adress, efter typ (t.ex. restaurang, hotell, bensinstation, museum) eller efter geografiska koordinater
\n</string>
<string name="osmand_plus_extended_description_part3">Kartvisning
\n • Visa din position och orientering
\n • Eventuellt justera bilden i förhållande till kompass eller din riktning
@ -2490,8 +2554,7 @@ Vänligen tillhandahåll fullständig kod</string>
<string name="save_poi_too_many_uppercase">Namnet innehåller för många versaler. Vill du fortsätta?</string>
<string name="quick_action_add_gpx_descr">Knackning på åtgärdsknappen kommer att lägga till en GPX-punkt vid skärmens mitt.</string>
<string name="quick_action_take_audio_note_descr">Knackning på åtgärdsknappen kommer att lägga en ljudanteckning vid skärmens mitt.</string>
<string name="quick_action_take_video_note_descr">Att trycka på denna åtgärdsknapp lägger
\ntill en videoanteckning mitt på skärmen.</string>
<string name="quick_action_take_video_note_descr">Att trycka på denna åtgärdsknapp lägger till en videoanteckning mitt på skärmen.</string>
<string name="quick_action_take_photo_note_descr">Knackning på åtgärdsknappen kommer att lägga till en fotoanteckning vid skärmens mitt.</string>
<string name="quick_action_add_osm_bug_descr">Knackning på åtgärdsknappen kommer att lägga till en OSM-anteckning vid skärmens mitt.</string>
<string name="quick_action_add_poi_descr">Knackning på åtgärdsknappen kommer att lägga till en Intressepunkt vid skärmens mitt.</string>
@ -2600,7 +2663,13 @@ Vänligen tillhandahåll fullständig kod</string>
\n• Valfri hastighetsbaserad zoomning
\n• Dela din position så att dina vänner kan hitta dig
\n</string>
<string name="osmand_plus_extended_description_part6">Funktioner för cykel och gående • Se vägar för gående och cyklande samt vandringsstigar, utmärkta för utomhusaktiviteter • Speciella ruttval och visningsläge för cykel och gående • Valfria kollektivtrafiksplatser (buss, spårvagn, tåg) inklusive linjenamn • Valfri reseinspelning till lokal GPX-fil eller onlinetjänst • Valfri visning av hastighet och höjd • Visa konturlinjer och höjdreliefer (via separat plugin)</string>
<string name="osmand_plus_extended_description_part6">Funktioner för cykel och gående
\n• Se vägar för gående och cyklande samt vandringsstigar, utmärkta för utomhusaktiviteter
\n• Speciella ruttval och visningsläge för cykel och gående
\n• Valfria kollektivtrafiksplatser (buss, spårvagn, tåg) inklusive linjenamn
\n• Valfri reseinspelning till lokal GPX-fil eller onlinetjänst
\n• Valfri visning av hastighet och höjd
\n• Visa konturlinjer och höjdreliefer (via separat plugin)</string>
<string name="osmand_plus_extended_description_part7">Bidra direkt till OSM
\n• Rapportera databuggar
\n• Ladda upp GPX-spår till OSM direkt från appen
@ -3267,4 +3336,9 @@ Vänligen tillhandahåll fullständig kod</string>
<string name="track_has_no_altitude">Spåret innehåller inte höjddata.</string>
<string name="track_has_no_speed">Spåret innehåller inte hastighetsdata.</string>
<string name="select_another_colorization">Välj en annan typ av färgning.</string>
<string name="save_heading_descr">Spara riktning till varje spårningspunkt under inspelning.</string>
<string name="app_mode_go_cart">Go-cart</string>
<string name="trip_recording_logging_interval_info">Loggningsintervall ställde in den tidsperiod under vilken OsmAnd kommer att be om aktuell positionspositionsdata.</string>
<string name="trip_recording_save_and_continue">Spara och fortsätt</string>
<string name="lost_data_warning">All osparad data kommer att försvinna.</string>
</resources>

View file

@ -4044,4 +4044,7 @@
<string name="select_another_colorization">Виберіть інший тип забарвлення.</string>
<string name="rendering_attr_noNatureReserveBoundaries_description">Сховати природні заповідники, заповідні території та межі національних парків</string>
<string name="rendering_attr_noNatureReserveBoundaries_name">Межі природи</string>
<string name="trip_recording_logging_interval_info">Інтервал журналювання встановлює проміжок часу, впродовж якого OsmAnd запитуватиме дані про поточне розташування.</string>
<string name="trip_recording_save_and_continue">Зберегти й продовжити</string>
<string name="lost_data_warning">Усі незбережені дані буде втрачено.</string>
</resources>

View file

@ -769,4 +769,6 @@
<string name="poi_charging_station">充电站</string>
<string name="poi_takeaway_no">无外卖</string>
<string name="poi_takeaway_only">仅限外卖</string>
<string name="poi_pharmacy_dispensing">配药</string>
<string name="poi_automated">自动化</string>
</resources>

View file

@ -4038,4 +4038,7 @@
<string name="select_another_colorization">請選擇另一種顏色。</string>
<string name="rendering_attr_noNatureReserveBoundaries_description">隱藏自然保留區、保護區與國家公園界線</string>
<string name="rendering_attr_noNatureReserveBoundaries_name">自然界線</string>
<string name="trip_recording_logging_interval_info">紀錄間隔設定的時段OsmAnd 將會要求目前位置的位置資料。</string>
<string name="trip_recording_save_and_continue">儲存並繼續</string>
<string name="lost_data_warning">所有未儲存的資料都將會遺失。</string>
</resources>

View file

@ -29,6 +29,15 @@
<string name="contact_support_description">If you have any questions, please contact us at %1$s.</string>
<string name="new_device_account">New device / new account</string>
<string name="no_purchases">You don\'t have any purchases</string>
<string name="specify_color_for_map_mode">Specify color for map mode: %1$s.</string>
<string name="route_line_use_map_style_appearance">Route line would be use %1$s specified on selected map style: %2$s.</string>
<string name="shared_string_route_line">Route line</string>
<string name="customize_route_line">Customize route line</string>
<string name="trip_recording_show_start_dialog_setting">If disabled, recording will start right after tap on the widget or menu item, skipping the confirmation dialog.</string>
<string name="show_start_dialog">Show start dialog</string>
<string name="lost_data_warning">All unsaved data will be lost.</string>
<string name="trip_recording_save_and_continue">Save and continue</string>
<string name="trip_recording_logging_interval_info">Logging interval set time period in which OsmAnd will ask for the current location position data.</string>
<string name="select_another_colorization">Please select another type of colorization.</string>
<string name="track_has_no_speed">The track does not contain speed data.</string>
<string name="track_has_no_altitude">The track does not contain altitude data.</string>
@ -1192,7 +1201,7 @@
<string name="search_no_results_feedback">No search results?\nProvide feedback</string>
<!-- string name="release_3_2_pre">
• Fixed crash on startup that occurred on some devices\n\n
• New Markers feature: Display already traversed markers\n\n
• New Markers feature: Display already traversed markers\n\n
• Search history now shows previously searched categories\n\n
• Fixed crash on startup that occurred with non-latin maps\n\n
• Improved rendering speed issues on Android 8.0 devices\n\n

View file

@ -4,6 +4,14 @@
xmlns:tools="http://schemas.android.com/tools"
android:title="@string/monitoring_settings">
<net.osmand.plus.settings.preferences.SwitchPreferenceEx
android:key="show_trip_recording_start_dialog"
android:layout="@layout/preference_with_descr_dialog_and_switch"
android:summaryOff="@string/shared_string_disabled"
android:summaryOn="@string/shared_string_enabled"
android:title="@string/show_start_dialog"
tools:icon="@drawable/ic_action_dialog" />
<PreferenceCategory
android:key="navigation"
android:layout="@layout/preference_category_with_descr"
@ -36,8 +44,8 @@
<net.osmand.plus.settings.preferences.ListPreferenceEx
android:key="save_global_track_interval"
android:layout="@layout/preference_with_descr"
android:title="@string/save_global_track_interval"
android:persistent="false"
android:title="@string/save_global_track_interval"
tools:icon="@drawable/ic_action_time_span"
tools:summary="3 seconds" />

View file

@ -76,4 +76,11 @@
android:title="@string/select_navigation_icon"
android:selectable="false"/>
<Preference
android:key="customize_route_line"
android:layout="@layout/preference_button"
android:persistent="false"
android:title="@string/customize_route_line"
android:icon="@drawable/ic_action_route_distance" />
</PreferenceScreen>

View file

@ -93,7 +93,6 @@ import net.osmand.plus.importfiles.ImportHelper;
import net.osmand.plus.mapcontextmenu.AdditionalActionsBottomSheetDialogFragment;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.builders.cards.dialogs.ContextMenuCardDialogFragment;
import net.osmand.plus.mapcontextmenu.editors.SelectFavoriteCategoryBottomSheet;
import net.osmand.plus.mapcontextmenu.other.DestinationReachedMenu;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
import net.osmand.plus.mapmarkers.MapMarker;
@ -105,7 +104,7 @@ import net.osmand.plus.measurementtool.LoginBottomSheetFragment;
import net.osmand.plus.measurementtool.MeasurementEditingContext;
import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.measurementtool.SnapTrackWarningFragment;
import net.osmand.plus.monitoring.TripRecordingBottomSheet;
import net.osmand.plus.monitoring.TripRecordingStartingBottomSheet;
import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.routepreparationmenu.ChooseRouteFragment;
@ -126,6 +125,7 @@ import net.osmand.plus.settings.datastorage.DataStorageFragment;
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType;
import net.osmand.plus.settings.fragments.ConfigureProfileFragment;
import net.osmand.plus.settings.fragments.RouteLineAppearanceFragment;
import net.osmand.plus.track.TrackAppearanceFragment;
import net.osmand.plus.track.TrackMenuFragment;
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
@ -2242,8 +2242,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
return getFragment(MeasurementToolFragment.TAG);
}
public TripRecordingBottomSheet getTripRecordingBottomSheet() {
return getFragment(TripRecordingBottomSheet.TAG);
public TripRecordingStartingBottomSheet getTripRecordingBottomSheet() {
return getFragment(TripRecordingStartingBottomSheet.TAG);
}
public ChooseRouteFragment getChooseRouteFragment() {
@ -2266,6 +2266,10 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
return getFragment(TrackMenuFragment.TAG);
}
public RouteLineAppearanceFragment getRouteLineAppearanceFragment() {
return getFragment(RouteLineAppearanceFragment.TAG);
}
public void backToConfigureProfileFragment() {
FragmentManager fragmentManager = getSupportFragmentManager();
int backStackEntryCount = fragmentManager.getBackStackEntryCount();

View file

@ -62,8 +62,8 @@ import net.osmand.plus.mapmarkers.MarkersPlanRouteContext;
import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.measurementtool.StartPlanRouteBottomSheet;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet;
import net.osmand.plus.monitoring.TripRecordingBottomSheet;
import net.osmand.plus.monitoring.TripRecordingStartingBottomSheet;
import net.osmand.plus.osmedit.dialogs.DismissRouteBottomSheetFragment;
import net.osmand.plus.profiles.ProfileDataObject;
import net.osmand.plus.profiles.ProfileDataUtils;
@ -854,9 +854,9 @@ public class MapActivityActions implements DialogProvider {
app.logEvent("trip_recording_open");
MapActivity.clearPrevActivityIntent();
if (monitoringPlugin.hasDataToSave() || monitoringPlugin.wasTrackMonitored()) {
TripRecordingActiveBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), monitoringPlugin.getCurrentTrack());
} else {
TripRecordingBottomSheet.showInstance(mapActivity.getSupportFragmentManager());
} else {
TripRecordingStartingBottomSheet.showTripRecordingDialog(mapActivity.getSupportFragmentManager(), app);
}
return true;
}

View file

@ -139,7 +139,7 @@ public class PluginInfoFragment extends BaseOsmAndFragment implements PluginStat
if (settingsScreenType != null) {
Bundle args = new Bundle();
args.putBoolean(PLUGIN_INFO, true);
BaseSettingsFragment.showInstance(activity, settingsScreenType, null, args);
BaseSettingsFragment.showInstance(activity, settingsScreenType, null, args, null);
}
}
}

View file

@ -317,7 +317,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
}
}
private String formatDateTime(Context ctx, long dateTime) {
public static String formatDateTime(Context ctx, long dateTime) {
DateFormat dateFormat = android.text.format.DateFormat.getMediumDateFormat(ctx);
DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(ctx);
return dateFormat.format(dateTime) + " " + timeFormat.format(dateTime);

View file

@ -49,7 +49,7 @@ public class SimpleBottomSheetItem extends BaseBottomSheetItem {
}
public void setTitle(String title) {
public void setTitle(CharSequence title) {
this.title = title;
titleTv.setText(title);
}

View file

@ -193,10 +193,7 @@ public class SelectMapStyleBottomSheetDialogFragment extends MenuBottomSheetDial
List<String> names = new ArrayList<>(renderers.keySet());
for (String name : names) {
String translation = RendererRegistry.getTranslatedRendererName(context, name);
if (translation == null) {
translation = name.replace('_', ' ').replace('-', ' ');
}
String translation = RendererRegistry.getRendererName(context, name);
res.put(translation, name);
}

View file

@ -85,9 +85,9 @@ import static net.osmand.plus.liveupdates.LiveUpdatesHelper.preferenceUpdateFreq
import static net.osmand.plus.liveupdates.LiveUpdatesHelper.runLiveUpdate;
import static net.osmand.plus.liveupdates.LiveUpdatesHelper.setAlarmForPendingIntent;
import static net.osmand.plus.liveupdates.LiveUpdatesSettingsDialogFragmentNew.getTertiaryTextColorId;
import static net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.getActiveTextColorId;
import static net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.getOsmandIconColorId;
import static net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.getSecondaryIconColorId;
import static net.osmand.plus.monitoring.TripRecordingBottomSheet.getActiveTextColorId;
import static net.osmand.plus.monitoring.TripRecordingBottomSheet.getOsmandIconColorId;
import static net.osmand.plus.monitoring.TripRecordingBottomSheet.getSecondaryIconColorId;
public class LiveUpdatesFragmentNew extends BaseOsmAndDialogFragment implements OnLiveUpdatesForLocalChange {

View file

@ -20,15 +20,16 @@ import net.osmand.data.FavouritePoint.BackgroundType;
import net.osmand.data.LatLon;
import net.osmand.data.WptLocationPoint;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.base.PointImageDrawable;
import net.osmand.plus.itinerary.ItineraryGroup;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.editors.WptPtEditor.OnDismissListener;
import net.osmand.plus.itinerary.ItineraryGroup;
import net.osmand.plus.track.SaveGpxAsyncTask;
import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener;
import net.osmand.util.Algorithms;
@ -213,6 +214,7 @@ public class WptPtEditorFragmentNew extends PointEditorFragmentNew {
String description = Algorithms.isEmpty(getDescriptionTextValue()) ? null : getDescriptionTextValue();
if (editor.isNew()) {
doAddWpt(name, category, description);
wpt = getWpt();
} else {
doUpdateWpt(name, category, description);
}
@ -222,7 +224,7 @@ public class WptPtEditorFragmentNew extends PointEditorFragmentNew {
}
MapContextMenu menu = mapActivity.getContextMenu();
if (menu.getLatLon() != null && menu.isActive()) {
if (menu.getLatLon() != null && menu.isActive() && wpt != null) {
LatLon latLon = new LatLon(wpt.getLatitude(), wpt.getLongitude());
if (menu.getLatLon().equals(latLon)) {
menu.update(latLon, new WptLocationPoint(wpt).getPointDescription(mapActivity), wpt);
@ -402,7 +404,9 @@ public class WptPtEditorFragmentNew extends PointEditorFragmentNew {
}
@Override
public String getAddressInitValue() { return ""; }
public String getAddressInitValue() {
return "";
}
@Override
public Drawable getNameIcon() {
@ -480,6 +484,25 @@ public class WptPtEditorFragmentNew extends PointEditorFragmentNew {
return 0;
}
@Override
protected boolean isCategoryVisible(String name) {
WptPtEditor editor = getWptPtEditor();
if (selectedGpxHelper == null || editor == null || editor.getGpxFile() == null) {
return true;
}
SelectedGpxFile selectedGpxFile;
if (editor.getGpxFile().showCurrentTrack) {
selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack();
} else {
selectedGpxFile = selectedGpxHelper.getSelectedFileByPath(editor.getGpxFile().path);
}
if (selectedGpxFile != null) {
Set<String> hiddenGroups = selectedGpxFile.getHiddenGroups();
return !hiddenGroups.contains(name);
}
return true;
}
private void saveGpx(final OsmandApplication app, final GPXFile gpxFile, final boolean gpxSelected) {
new SaveGpxAsyncTask(new File(gpxFile.path), gpxFile, new SaveGpxListener() {
@Override

View file

@ -8,6 +8,7 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
@ -175,6 +176,18 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
calculateGpxApproximation(true);
final ScrollView profileView = (ScrollView) getBottomScrollView();
profileView.postDelayed(new Runnable() {
@Override
public void run() {
View view = profileView.findViewWithTag(snapToRoadAppMode.getStringKey());
if (view != null) {
int headerHeight = getResources().getDimensionPixelSize(R.dimen.measurement_tool_button_height);
profileView.scrollTo(0, view.getTop() + headerHeight);
}
}
}, 100);
return mainView;
}

View file

@ -106,6 +106,7 @@ import static net.osmand.plus.measurementtool.command.ClearPointsCommand.ClearCo
import static net.osmand.plus.measurementtool.command.ClearPointsCommand.ClearCommandMode.AFTER;
import static net.osmand.plus.measurementtool.command.ClearPointsCommand.ClearCommandMode.ALL;
import static net.osmand.plus.measurementtool.command.ClearPointsCommand.ClearCommandMode.BEFORE;
import static net.osmand.plus.routing.TransportRoutingHelper.PUBLIC_TRANSPORT_KEY;
public class MeasurementToolFragment extends BaseOsmAndFragment implements RouteBetweenPointsFragmentListener,
OptionsFragmentListener, GpxApproximationFragmentListener, SelectedPointFragmentListener,
@ -135,6 +136,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
private ImageView mainIcon;
private String fileName;
private OnBackPressedCallback onBackPressedCallback;
private boolean showSnapWarning;
private InfoType currentInfoType;
@ -238,6 +240,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
if (mapActivity == null) {
return null;
}
final MeasurementToolLayer measurementLayer = mapActivity.getMapLayers().getMeasurementToolLayer();
final OsmandApplication app = mapActivity.getMyApplication();
@ -362,7 +365,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
}
});
View applyPointBeforeAfterButton = mainView.findViewById(R.id.apply_point_before_after_point_button);
UiUtilities.setupDialogButton(nightMode, applyPointBeforeAfterButton,
UiUtilities.DialogButtonType.PRIMARY, R.string.shared_string_apply);
@ -567,11 +569,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
});
initMeasurementMode(gpxData, savedInstanceState == null);
if (savedInstanceState == null) {
if (fileName != null) {
addNewGpxData(getGpxFile(fileName));
} else if (editingCtx.isApproximationNeeded() && isFollowTrackMode()) {
} else if (editingCtx.isApproximationNeeded() && isFollowTrackMode() && isShowSnapWarning()) {
enterApproximationMode(mapActivity);
}
} else {
@ -716,6 +717,15 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
this.fileName = fileName;
}
public boolean isShowSnapWarning() {
return this.showSnapWarning;
}
public void setShowSnapWarning(boolean showSnapWarning) {
this.showSnapWarning = showSnapWarning;
}
public MeasurementEditingContext getEditingCtx() {
return editingCtx;
}
@ -897,7 +907,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
case SnapTrackWarningFragment.CONTINUE_RESULT_CODE:
if (mapActivity != null) {
ApplicationMode mode = editingCtx.getAppMode();
if (mode == ApplicationMode.DEFAULT || "public_transport".equals(mode.getRoutingProfile())) {
if (mode == ApplicationMode.DEFAULT || PUBLIC_TRANSPORT_KEY.equals(mode.getRoutingProfile())) {
mode = null;
}
List<List<WptPt>> pointsSegments = editingCtx.getPointsSegments(true, false);
@ -2008,10 +2018,11 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
}
public static boolean showInstance(FragmentManager fragmentManager, MeasurementEditingContext editingCtx,
boolean followTrackMode) {
boolean followTrackMode, boolean showSnapWarning) {
MeasurementToolFragment fragment = new MeasurementToolFragment();
fragment.setEditingCtx(editingCtx);
fragment.setMode(FOLLOW_TRACK_MODE, followTrackMode);
fragment.setShowSnapWarning(showSnapWarning);
return showFragment(fragment, fragmentManager);
}
@ -2179,4 +2190,5 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
public interface OnUpdateInfoListener {
void onUpdateInfo();
}
}

View file

@ -20,6 +20,8 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static net.osmand.plus.routing.TransportRoutingHelper.PUBLIC_TRANSPORT_KEY;
public class ProfileCard extends BaseCard {
private ApplicationMode selectedMode;
@ -42,7 +44,7 @@ public class ProfileCard extends BaseCard {
Iterator<ApplicationMode> iterator = modes.iterator();
while (iterator.hasNext()) {
ApplicationMode mode = iterator.next();
if ("public_transport".equals(mode.getRoutingProfile())) {
if (PUBLIC_TRANSPORT_KEY.equals(mode.getRoutingProfile())) {
iterator.remove();
}
}

View file

@ -35,6 +35,7 @@ import static net.osmand.plus.UiUtilities.CustomRadioButtonType.END;
import static net.osmand.plus.UiUtilities.CustomRadioButtonType.START;
import static net.osmand.plus.measurementtool.MeasurementEditingContext.DEFAULT_APP_MODE;
import static net.osmand.plus.measurementtool.SelectFileBottomSheet.BOTTOM_SHEET_HEIGHT_DP;
import static net.osmand.plus.routing.TransportRoutingHelper.PUBLIC_TRANSPORT_KEY;
public class RouteBetweenPointsBottomSheetDialogFragment extends BottomSheetBehaviourDialogFragment {
@ -116,7 +117,7 @@ public class RouteBetweenPointsBottomSheetDialogFragment extends BottomSheetBeha
for (int i = 0; i < modes.size(); i++) {
ApplicationMode mode = modes.get(i);
if (!"public_transport".equals(mode.getRoutingProfile())) {
if (!PUBLIC_TRANSPORT_KEY.equals(mode.getRoutingProfile())) {
icon = app.getUIUtilities().getPaintedIcon(mode.getIconRes(), mode.getProfileColor(nightMode));
addProfileView(navigationType, onClickListener, i, icon, mode.toHumanString(), mode.equals(appMode));
}

View file

@ -9,25 +9,27 @@ import android.text.SpannableStringBuilder;
import android.view.LayoutInflater;
import android.view.View;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.OsmAndAppCustomization;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.settings.backend.CommonPreference;
import net.osmand.plus.settings.backend.OsmandPreference;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.myplaces.FavoritesActivity;
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet;
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener;
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.CommonPreference;
import net.osmand.plus.settings.backend.OsmAndAppCustomization;
import net.osmand.plus.settings.backend.OsmandPreference;
import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet;
import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet.ResetAppModePrefsListener;
import net.osmand.plus.settings.bottomsheets.SingleSelectPreferenceBottomSheet;
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import net.osmand.plus.settings.preferences.ListPreferenceEx;
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
import net.osmand.plus.widgets.style.CustomTypefaceSpan;
@ -36,11 +38,11 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import static net.osmand.plus.activities.PluginInfoFragment.PLUGIN_INFO;
import static net.osmand.plus.settings.backend.OsmandSettings.MONTHLY_DIRECTORY;
import static net.osmand.plus.settings.backend.OsmandSettings.REC_DIRECTORY;
import static net.osmand.plus.monitoring.OsmandMonitoringPlugin.MINUTES;
import static net.osmand.plus.monitoring.OsmandMonitoringPlugin.SECONDS;
import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID;
import static net.osmand.plus.settings.backend.OsmandSettings.MONTHLY_DIRECTORY;
import static net.osmand.plus.settings.backend.OsmandSettings.REC_DIRECTORY;
public class MonitoringSettingsFragment extends BaseSettingsFragment
implements CopyAppModePrefsListener, ResetAppModePrefsListener {
@ -81,6 +83,8 @@ public class MonitoringSettingsFragment extends BaseSettingsFragment
@Override
protected void setupPreferences() {
setupShowStartDialog();
setupSaveTrackToGpxPref();
setupSaveTrackIntervalPref();
@ -103,6 +107,12 @@ public class MonitoringSettingsFragment extends BaseSettingsFragment
setupResetToDefaultPref();
}
private void setupShowStartDialog() {
SwitchPreferenceEx showStartDialog = (SwitchPreferenceEx) findPreference(settings.SHOW_TRIP_REC_START_DIALOG.getId());
showStartDialog.setDescription(getString(R.string.trip_recording_show_start_dialog_setting));
showStartDialog.setIcon(getPersistentPrefIcon(R.drawable.ic_action_dialog));
}
private void setupSaveTrackToGpxPref() {
SwitchPreferenceEx saveTrackToGpx = (SwitchPreferenceEx) findPreference(settings.SAVE_TRACK_TO_GPX.getId());
saveTrackToGpx.setDescription(getString(R.string.save_track_to_gpx_descrp));
@ -110,7 +120,7 @@ public class MonitoringSettingsFragment extends BaseSettingsFragment
}
private void setupSaveTrackIntervalPref() {
HashMap<Object, String> entry = getTimeValues(false);
HashMap<Object, String> entry = getTimeValues();
ListPreferenceEx saveTrackInterval = (ListPreferenceEx) findPreference(settings.SAVE_TRACK_INTERVAL.getId());
saveTrackInterval.setEntries(entry.values().toArray(new String[0]));
saveTrackInterval.setEntryValues(entry.keySet().toArray());
@ -119,25 +129,18 @@ public class MonitoringSettingsFragment extends BaseSettingsFragment
}
private void setupSaveGlobalTrackIntervalPref() {
HashMap<Object, String> entry = getTimeValues(true);
HashMap<Object, String> entry = getTimeValues();
ListPreferenceEx saveTrackInterval = (ListPreferenceEx) findPreference(settings.SAVE_GLOBAL_TRACK_INTERVAL.getId());
saveTrackInterval.setEntries(entry.values().toArray(new String[0]));
saveTrackInterval.setEntryValues(entry.keySet().toArray());
ApplicationMode selectedAppMode = getSelectedAppMode();
if (!settings.SAVE_GLOBAL_TRACK_REMEMBER.getModeValue(selectedAppMode)) {
saveTrackInterval.setValue(settings.SAVE_GLOBAL_TRACK_REMEMBER.getModeValue(selectedAppMode));
} else {
saveTrackInterval.setValue(settings.SAVE_GLOBAL_TRACK_INTERVAL.getModeValue(selectedAppMode));
}
saveTrackInterval.setValue(settings.SAVE_GLOBAL_TRACK_INTERVAL.getModeValue(selectedAppMode));
saveTrackInterval.setIcon(getActiveIcon(R.drawable.ic_action_time_span));
saveTrackInterval.setDescription(R.string.save_global_track_interval_descr);
}
private HashMap<Object, String> getTimeValues(boolean alwaysAskEntry) {
private HashMap<Object, String> getTimeValues() {
HashMap<Object, String> entry = new LinkedHashMap<>();
if (alwaysAskEntry) {
entry.put(settings.SAVE_GLOBAL_TRACK_REMEMBER.getModeValue(getSelectedAppMode()), getString(R.string.confirm_every_run));
}
for (int second : SECONDS) {
entry.put(second * 1000, second + " " + getString(R.string.int_seconds));
}
@ -292,6 +295,18 @@ public class MonitoringSettingsFragment extends BaseSettingsFragment
resetToDefault.setIcon(getActiveIcon(R.drawable.ic_action_reset_to_default_dark));
}
@Override
public void onDestroy() {
FragmentActivity activity = getActivity();
if (activity != null && !activity.isChangingConfigurations()) {
Fragment target = getTargetFragment();
if (target instanceof TripRecordingStartingBottomSheet) {
((TripRecordingStartingBottomSheet) target).show();
}
}
super.onDestroy();
}
@Override
public boolean onPreferenceClick(Preference preference) {
String prefId = preference.getKey();

View file

@ -25,6 +25,7 @@ import com.google.android.material.slider.Slider;
import net.osmand.AndroidUtils;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.ValueHolder;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.NavigationService;
@ -41,19 +42,25 @@ import net.osmand.plus.dashboard.tools.DashFragmentData;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType;
import net.osmand.plus.track.TrackMenuFragment;
import net.osmand.plus.views.OsmandMapLayer.DrawSettings;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.layers.MapInfoLayer;
import net.osmand.plus.views.mapwidgets.widgets.TextInfoWidget;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.List;
import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT;
public class OsmandMonitoringPlugin extends OsmandPlugin {
private static final Log LOG = PlatformUtil.getLog(OsmandMonitoringPlugin.class);
public static final String ID = "osmand.monitoring";
public final static String OSMAND_SAVE_SERVICE_ACTION = "OSMAND_SAVE_SERVICE_ACTION";
public static final int REQUEST_LOCATION_PERMISSION_FOR_GPX_RECORDING = 208;
@ -79,6 +86,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
pluginPreferences.add(settings.DISABLE_RECORDING_ONCE_APP_KILLED);
pluginPreferences.add(settings.SAVE_HEADING_TO_GPX);
pluginPreferences.add(settings.SHOW_TRIP_REC_NOTIFICATION);
pluginPreferences.add(settings.SHOW_TRIP_REC_START_DIALOG);
pluginPreferences.add(settings.TRACK_STORAGE_DIRECTORY);
pluginPreferences.add(settings.LIVE_MONITORING);
pluginPreferences.add(settings.LIVE_MONITORING_URL);
@ -329,9 +337,9 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
public void controlDialog(final Activity activity, final boolean showTrackSelection) {
FragmentManager fragmentManager = ((FragmentActivity) activity).getSupportFragmentManager();
if (hasDataToSave() || wasTrackMonitored()) {
TripRecordingActiveBottomSheet.showInstance(fragmentManager, getCurrentTrack());
} else {
TripRecordingBottomSheet.showInstance(fragmentManager);
} else {
TripRecordingStartingBottomSheet.showTripRecordingDialog(fragmentManager, app);
}
/*final boolean wasTrackMonitored = settings.SAVE_GLOBAL_TRACK_TO_GPX.get();
@ -436,16 +444,22 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
}
public void saveCurrentTrack() {
saveCurrentTrack(null, null);
saveCurrentTrack(null, null, true, false);
}
public void saveCurrentTrack(@Nullable final Runnable onComplete) {
saveCurrentTrack(onComplete, null);
saveCurrentTrack(onComplete, null, true, false);
}
public void saveCurrentTrack(@Nullable final Runnable onComplete, @Nullable Activity activity) {
stopRecording();
saveCurrentTrack(onComplete, activity, true, false);
}
public void saveCurrentTrack(@Nullable final Runnable onComplete, @Nullable Activity activity,
final boolean stopRecording, final boolean openTrack) {
if (stopRecording) {
stopRecording();
}
final WeakReference<Activity> activityRef = activity != null ? new WeakReference<>(activity) : null;
app.getTaskManager().runInBackground(new OsmAndTaskRunnable<Void, Void, SaveGpxResult>() {
@ -464,7 +478,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
helper.close();
return result;
} catch (Exception e) {
e.printStackTrace();
LOG.error(e.getMessage(), e);
}
return null;
}
@ -474,10 +488,31 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
isSaving = false;
app.getNotificationHelper().refreshNotifications();
updateControl();
if (activityRef != null && !Algorithms.isEmpty(result.getFilenames())) {
final Activity a = activityRef.get();
if (a instanceof FragmentActivity && !a.isFinishing()) {
SaveGPXBottomSheetFragment.showInstance(((FragmentActivity) a).getSupportFragmentManager(), result.getFilenames());
File file = null;
File dir = app.getAppCustomization().getTracksDir();
File[] children = dir.listFiles();
if (children != null && !Algorithms.isEmpty(result.getFilenames())) {
SavingTrackHelper helper = app.getSavingTrackHelper();
for (File child : children) {
if (child.getName().startsWith(result.getFilenames().get(0))
&& child.lastModified() == helper.getLastTimeFileSaved()) {
file = child;
}
}
}
if (file != null && file.exists()) {
if (!openTrack) {
if (activityRef != null) {
final Activity a = activityRef.get();
if (a instanceof FragmentActivity && !a.isFinishing()) {
List<String> singleName = Collections.singletonList(Algorithms.getFileNameWithoutExtension(file));
SaveGPXBottomSheet.showInstance(((FragmentActivity) a)
.getSupportFragmentManager(), singleName);
}
}
} else {
TrackMenuFragment.openTrack(mapActivity, file, null);
}
}
@ -523,7 +558,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
runnable.run();
} else if (map instanceof FragmentActivity) {
FragmentActivity activity = (FragmentActivity) map;
TripRecordingBottomSheet.showInstance(activity.getSupportFragmentManager());
TripRecordingStartingBottomSheet.showTripRecordingDialog(activity.getSupportFragmentManager(), app);
}
}

View file

@ -42,10 +42,10 @@ import java.util.List;
import static net.osmand.FileUtils.ILLEGAL_FILE_NAME_CHARACTERS;
public class SaveGPXBottomSheetFragment extends MenuBottomSheetDialogFragment {
public class SaveGPXBottomSheet extends MenuBottomSheetDialogFragment {
public static final String TAG = "SaveGPXBottomSheetFragment";
public static final String SAVED_TRACKS_KEY = "saved_track_filename";
private static final Log LOG = PlatformUtil.getLog(SaveGPXBottomSheetFragment.class);
private static final Log LOG = PlatformUtil.getLog(SaveGPXBottomSheet.class);
private boolean openTrack = false;
private File file;
@ -227,7 +227,7 @@ public class SaveGPXBottomSheetFragment extends MenuBottomSheetDialogFragment {
if (fragmentManager.isStateSaved()) {
return;
}
SaveGPXBottomSheetFragment f = new SaveGPXBottomSheetFragment();
SaveGPXBottomSheet f = new SaveGPXBottomSheet();
Bundle b = new Bundle();
b.putStringArrayList(SAVED_TRACKS_KEY, new ArrayList<>(filenames));
f.setArguments(b);

View file

@ -1,660 +0,0 @@
package net.osmand.plus.monitoring;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.TypedValue;
import android.text.format.DateUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.SwitchCompat;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.snackbar.Snackbar;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.activities.SavingTrackHelper.SaveGpxResult;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.myplaces.SaveCurrentTrackTask;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.track.GpxBlockStatisticsBuilder;
import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener;
import net.osmand.plus.track.TrackAppearanceFragment;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static net.osmand.AndroidUtils.getSecondaryTextColorId;
import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT;
public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragment {
public static final String TAG = TripRecordingActiveBottomSheet.class.getSimpleName();
private static final Log log = PlatformUtil.getLog(TripRecordingActiveBottomSheet.class);
private static final String UPDATE_CURRENT_GPX_FILE = "update_current_gpx_file";
public static final String UPDATE_TRACK_ICON = "update_track_icon";
private static final int GENERAL_UPDATE_GPS_INTERVAL = 1000;
private static final int GENERAL_UPDATE_SAVE_INTERVAL = 1000;
private OsmandApplication app;
private OsmandSettings settings;
private SavingTrackHelper helper;
private SelectedGpxFile selectedGpxFile;
private View statusContainer;
private LinearLayout buttonAppearance;
private View buttonSave;
private GpxBlockStatisticsBuilder blockStatisticsBuilder;
private final Handler handler = new Handler();
private Runnable updatingGPS;
private Runnable updatingTimeTrackSaved;
private GPXFile getGPXFile() {
return selectedGpxFile.getGpxFile();
}
public void setSelectedGpxFile(SelectedGpxFile selectedGpxFile) {
this.selectedGpxFile = selectedGpxFile;
}
public boolean hasDataToSave() {
return app.getSavingTrackHelper().hasDataToSave();
}
public boolean searchingGPS() {
return app.getLocationProvider().getLastKnownLocation() == null;
}
public boolean wasTrackMonitored() {
return settings.SAVE_GLOBAL_TRACK_TO_GPX.get();
}
public static void showInstance(@NonNull FragmentManager fragmentManager, SelectedGpxFile selectedGpxFile) {
if (!fragmentManager.isStateSaved()) {
TripRecordingActiveBottomSheet fragment = new TripRecordingActiveBottomSheet();
fragment.setSelectedGpxFile(selectedGpxFile);
fragment.show(fragmentManager, TAG);
}
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
app = requiredMyApplication();
settings = app.getSettings();
helper = app.getSavingTrackHelper();
LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode);
final FragmentManager fragmentManager = getFragmentManager();
View itemView = inflater.inflate(R.layout.trip_recording_active_fragment, null, false);
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(itemView)
.create());
View buttonClear = itemView.findViewById(R.id.button_clear);
final View buttonOnline = itemView.findViewById(R.id.button_online);
final View buttonSegment = itemView.findViewById(R.id.button_segment);
buttonSave = itemView.findViewById(R.id.button_save);
final View buttonPause = itemView.findViewById(R.id.button_pause);
View buttonStop = itemView.findViewById(R.id.button_stop);
createItem(buttonClear, ItemType.CLEAR_DATA, hasDataToSave());
createItem(buttonOnline, ItemType.STOP_ONLINE, hasDataToSave());
createItem(buttonSegment, ItemType.START_SEGMENT, wasTrackMonitored());
createItem(buttonPause, wasTrackMonitored() ? ItemType.PAUSE : ItemType.RESUME, true);
createItem(buttonStop, ItemType.STOP, true);
AndroidUiHelper.updateVisibility(buttonOnline, app.getLiveMonitoringHelper().isLiveMonitoringEnabled());
statusContainer = itemView.findViewById(R.id.status_container);
updateStatus();
RecyclerView statBlocks = itemView.findViewById(R.id.block_statistics);
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(UPDATE_CURRENT_GPX_FILE)
&& savedInstanceState.getBoolean(UPDATE_CURRENT_GPX_FILE)) {
selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack();
}
}
blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile);
blockStatisticsBuilder.setBlocksView(statBlocks);
blockStatisticsBuilder.setBlocksClickable(false);
blockStatisticsBuilder.initStatBlocks(null, ContextCompat.getColor(app, getActiveTextColorId(nightMode)), nightMode);
LinearLayout showTrackContainer = itemView.findViewById(R.id.show_track_on_map);
showTrackContainer.setMinimumHeight(app.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_list_item_height));
final LinearLayout buttonShow = showTrackContainer.findViewById(R.id.basic_item_body);
TextView showTrackTitle = buttonShow.findViewById(R.id.title);
Integer showTitle = ItemType.SHOW_TRACK.getTitleId();
if (showTitle != null) {
showTrackTitle.setText(showTitle);
}
AndroidUtils.setPadding(buttonShow, AndroidUtils.dpToPx(app, 12f), 0, buttonShow.getPaddingRight(), 0);
showTrackTitle.setTextColor(ContextCompat.getColor(app, getActiveIconColorId(nightMode)));
showTrackTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.default_desc_text_size));
Typeface typeface = FontCache.getFont(app, app.getResources().getString(R.string.font_roboto_medium));
showTrackTitle.setTypeface(typeface);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float letterSpacing = AndroidUtils.getFloatValueFromRes(app, R.dimen.text_button_letter_spacing);
showTrackTitle.setLetterSpacing(letterSpacing);
}
final SwitchCompat showTrackOnMapButton = buttonShow.findViewById(R.id.switch_button);
showTrackOnMapButton.setChecked(app.getSelectedGpxHelper().getSelectedCurrentRecordingTrack() != null);
UiUtilities.setupCompoundButton(showTrackOnMapButton, nightMode, PROFILE_DEPENDENT);
buttonAppearance = showTrackContainer.findViewById(R.id.additional_button);
View divider = buttonAppearance.getChildAt(0);
AndroidUiHelper.setVisibility(View.GONE, divider);
int marginS = app.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_small);
UiUtilities.setMargins(buttonAppearance, marginS, 0, 0, 0);
updateTrackIcon(buttonAppearance);
buttonAppearance.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (showTrackOnMapButton.isChecked()) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
hide();
SelectedGpxFile selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack();
TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, TripRecordingActiveBottomSheet.this);
}
}
}
});
createItem(buttonAppearance, ItemType.APPEARANCE, showTrackOnMapButton.isChecked());
setShowOnMapBackground(buttonShow, app, showTrackOnMapButton.isChecked(), nightMode);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
buttonShow.setBackgroundTintList(null);
}
buttonShow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = !showTrackOnMapButton.isChecked();
showTrackOnMapButton.setChecked(checked);
app.getSelectedGpxHelper().selectGpxFile(app.getSavingTrackHelper().getCurrentGpx(), checked, false);
createItem(buttonAppearance, ItemType.APPEARANCE, checked);
setShowOnMapBackground(buttonShow, app, checked, nightMode);
}
});
buttonClear.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (fragmentManager != null && hasDataToSave()) {
ClearRecordedDataBottomSheetFragment.showInstance(fragmentManager, TripRecordingActiveBottomSheet.this);
}
}
});
buttonOnline.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
settings.LIVE_MONITORING.set(false);
AndroidUiHelper.updateVisibility(buttonOnline, false);
}
});
buttonSegment.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (wasTrackMonitored()) {
blockStatisticsBuilder.stopUpdatingStatBlocks();
helper.startNewSegment();
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
}
}
});
buttonSave.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (hasDataToSave()) {
final GPXFile gpxFile = getGPXFile();
new SaveCurrentTrackTask(app, gpxFile, createSaveListener(new Runnable() {
@Override
public void run() {
blockStatisticsBuilder.stopUpdatingStatBlocks();
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
stopUpdatingTimeTrackSaved();
runUpdatingTimeTrackSaved();
}
})).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
});
buttonPause.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean wasTrackMonitored = !wasTrackMonitored();
if (!wasTrackMonitored) {
blockStatisticsBuilder.stopUpdatingStatBlocks();
} else {
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
}
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored);
updateStatus();
createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true);
createItem(buttonSegment, ItemType.START_SEGMENT, wasTrackMonitored);
}
});
buttonStop.findViewById(R.id.button_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (fragmentManager != null) {
StopTrackRecordingBottomFragment.showInstance(getMapActivity(), fragmentManager, TripRecordingActiveBottomSheet.this);
}
}
});
}
private void updateStatus() {
TextView statusTitle = statusContainer.findViewById(R.id.text_status);
AppCompatImageView statusIcon = statusContainer.findViewById(R.id.icon_status);
ItemType status = searchingGPS() ? ItemType.SEARCHING_GPS : !wasTrackMonitored() ? ItemType.ON_PAUSE : ItemType.RECORDING;
Integer titleId = status.getTitleId();
if (titleId != null) {
statusTitle.setText(titleId);
}
int colorText = status.equals(ItemType.SEARCHING_GPS) ? getSecondaryTextColorId(nightMode) : getOsmandIconColorId(nightMode);
statusTitle.setTextColor(ContextCompat.getColor(app, colorText));
Integer iconId = status.getIconId();
if (iconId != null) {
int colorDrawable = ContextCompat.getColor(app,
status.equals(ItemType.SEARCHING_GPS) ? getSecondaryIconColorId(nightMode) : getOsmandIconColorId(nightMode));
Drawable statusDrawable = UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, iconId), colorDrawable);
statusIcon.setImageDrawable(statusDrawable);
}
}
private void updateTrackIcon(View buttonAppearance) {
String width = settings.CURRENT_TRACK_WIDTH.get();
boolean showArrows = settings.CURRENT_TRACK_SHOW_ARROWS.get();
int color = settings.CURRENT_TRACK_COLOR.get();
Drawable appearanceDrawable = TrackAppearanceFragment.getTrackIcon(app, width, showArrows, color);
AppCompatImageView appearanceIcon = buttonAppearance.findViewById(R.id.icon_after_divider);
int marginTrackIconH = app.getResources().getDimensionPixelSize(R.dimen.content_padding_small);
UiUtilities.setMargins(appearanceIcon, marginTrackIconH, 0, marginTrackIconH, 0);
appearanceIcon.setImageDrawable(appearanceDrawable);
}
private void createItem(View view, ItemType type, boolean enabled) {
createItem(app, nightMode, view, type, enabled, null);
}
private void createItem(View view, ItemType type, boolean enabled, @Nullable String description) {
createItem(app, nightMode, view, type, enabled, description);
}
public static View createItem(Context context, boolean nightMode, LayoutInflater inflater, ItemType type) {
View button = inflater.inflate(R.layout.bottom_sheet_button_with_icon, null);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
int horizontal = context.getResources().getDimensionPixelSize(R.dimen.content_padding);
params.setMargins(horizontal, 0, horizontal, 0);
button.setLayoutParams(params);
LinearLayout container = button.findViewById(R.id.button_container);
container.setClickable(false);
container.setFocusable(false);
createItem(context, nightMode, button, type, true, null);
return button;
}
public static void createItem(Context context, boolean nightMode, View view, ItemType type, boolean enabled, @Nullable String description) {
view.setTag(type);
LinearLayout button = view.findViewById(R.id.button_container);
AppCompatImageView icon = view.findViewById(R.id.icon);
if (icon != null) {
setTintedIcon(context, icon, enabled, nightMode, type);
}
TextView title = view.findViewById(R.id.button_text);
Integer titleId = type.getTitleId();
if (title != null && titleId != null) {
title.setText(titleId);
setTextColor(context, title, enabled, nightMode, type);
}
TextViewEx desc = view.findViewById(R.id.desc);
if (desc != null) {
boolean isShowDesc = !Algorithms.isBlank(description);
int marginDesc = isShowDesc ? 0 : context.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium);
AndroidUiHelper.updateVisibility(desc, isShowDesc);
if (title != null) {
UiUtilities.setMargins(title, 0, marginDesc, 0, marginDesc);
}
desc.setText(description);
setTextColor(context, desc, false, nightMode, type);
}
setItemBackground(context, nightMode, button != null ? button : (LinearLayout) view, enabled);
}
private String getTimeTrackSaved() {
long timeTrackSaved = helper.getLastTimeFileSaved();
if (timeTrackSaved != 0) {
long now = System.currentTimeMillis();
CharSequence time = DateUtils.getRelativeTimeSpanString(timeTrackSaved, now, DateUtils.MINUTE_IN_MILLIS);
return String.valueOf(time);
} else {
return null;
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(UPDATE_CURRENT_GPX_FILE, true);
}
@Override
public void onResume() {
super.onResume();
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
runUpdatingGPS();
runUpdatingTimeTrackSaved();
}
@Override
public void onPause() {
super.onPause();
blockStatisticsBuilder.stopUpdatingStatBlocks();
stopUpdatingGPS();
stopUpdatingTimeTrackSaved();
}
public void stopUpdatingGPS() {
handler.removeCallbacks(updatingGPS);
}
public void runUpdatingGPS() {
updatingGPS = new Runnable() {
@Override
public void run() {
int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
updateStatus();
handler.postDelayed(this, Math.max(GENERAL_UPDATE_GPS_INTERVAL, interval));
}
};
handler.post(updatingGPS);
}
public void stopUpdatingTimeTrackSaved() {
handler.removeCallbacks(updatingTimeTrackSaved);
}
public void runUpdatingTimeTrackSaved() {
updatingTimeTrackSaved = new Runnable() {
@Override
public void run() {
String time = getTimeTrackSaved();
createItem(buttonSave, ItemType.SAVE, hasDataToSave(), !Algorithms.isEmpty(time) ? time : null);
handler.postDelayed(this, GENERAL_UPDATE_SAVE_INTERVAL);
}
};
handler.post(updatingTimeTrackSaved);
}
private SaveGpxListener createSaveListener(@Nullable final Runnable callback) {
return new SaveGpxListener() {
@Override
public void gpxSavingStarted() {
}
@Override
public void gpxSavingFinished(Exception errorMessage) {
final MapActivity mapActivity = getMapActivity();
final Context context = getContext();
final SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir());
ArrayList<String> filenames = new ArrayList<>(result.getFilenames());
String fileName = "";
if (filenames.size() > 0) {
fileName = filenames.get(filenames.size() - 1) + IndexConstants.GPX_FILE_EXT;
}
String message = fileName + " " + app.getResources().getString(R.string.shared_string_is_saved) + ". "
+ app.getResources().getString(R.string.track_recording_will_be_continued);
if (mapActivity != null && context != null) {
final WeakReference<MapActivity> mapActivityRef = new WeakReference<>(mapActivity);
final FragmentManager fragmentManager = mapActivityRef.get().getSupportFragmentManager();
Snackbar snackbar = Snackbar.make(getView(),
message,
Snackbar.LENGTH_LONG)
.setAction(R.string.shared_string_rename, new View.OnClickListener() {
@Override
public void onClick(View view) {
fragmentManager.beginTransaction().remove(TripRecordingActiveBottomSheet.this).commitAllowingStateLoss();
SaveGPXBottomSheetFragment.showInstance(fragmentManager, result.getFilenames());
}
});
View view = snackbar.getView();
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
params.gravity = Gravity.TOP;
AndroidUtils.setMargins(params, 0, AndroidUtils.getStatusBarHeight(context), 0, 0);
view.setLayoutParams(params);
UiUtilities.setupSnackbar(snackbar, nightMode);
snackbar.show();
if (callback != null) {
callback.run();
}
}
}
};
}
@Nullable
public MapActivity getMapActivity() {
Activity activity = getActivity();
if (activity instanceof MapActivity) {
return (MapActivity) activity;
}
return null;
}
public void show() {
Dialog dialog = getDialog();
if (dialog != null) {
dialog.show();
}
}
public void show(String... keys) {
show();
for (String key : keys) {
if (key.equals(UPDATE_TRACK_ICON)) {
updateTrackIcon(buttonAppearance);
}
}
}
public void hide() {
Dialog dialog = getDialog();
if (dialog != null) {
dialog.hide();
}
}
public enum ItemType {
SHOW_TRACK(R.string.shared_string_show_on_map, null),
APPEARANCE(null, null),
SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info),
RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable),
ON_PAUSE(R.string.on_pause, R.drawable.ic_pause),
CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark),
START_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment),
SAVE(R.string.shared_string_save, R.drawable.ic_action_save_to_file),
PAUSE(R.string.shared_string_pause, R.drawable.ic_pause),
RESUME(R.string.shared_string_resume, R.drawable.ic_play_dark),
STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop),
STOP_AND_DISCARD(R.string.track_recording_stop_without_saving, R.drawable.ic_action_rec_stop),
STOP_AND_SAVE(R.string.track_recording_save_and_stop, R.drawable.ic_action_save_to_file),
STOP_ONLINE(R.string.live_monitoring_stop, R.drawable.ic_world_globe_dark),
CANCEL(R.string.shared_string_cancel, R.drawable.ic_action_close);
@StringRes
private final Integer titleId;
@DrawableRes
private final Integer iconId;
private static final List<ItemType> negative = Arrays.asList(CLEAR_DATA, STOP_AND_DISCARD);
ItemType(@Nullable @StringRes Integer titleId, @Nullable @DrawableRes Integer iconId) {
this.titleId = titleId;
this.iconId = iconId;
}
@Nullable
public Integer getTitleId() {
return titleId;
}
@Nullable
public Integer getIconId() {
return iconId;
}
public boolean isNegative() {
return negative.contains(this);
}
}
public static void setItemBackground(Context context, boolean nightMode, LinearLayout view, boolean enabled) {
Drawable background = AppCompatResources.getDrawable(context, R.drawable.btn_background_inactive_light);
if (background != null && enabled) {
ColorStateList iconColorStateList = AndroidUtils.createPressedColorStateList(
context, getInactiveButtonColorId(nightMode), getActiveButtonColorId(nightMode)
);
DrawableCompat.setTintList(background, iconColorStateList);
} else {
UiUtilities.tintDrawable(background, ContextCompat.getColor(context, getInactiveButtonColorId(nightMode)));
}
view.setBackgroundDrawable(background);
}
public static void setShowOnMapBackground(LinearLayout view, Context context, boolean checked, boolean nightMode) {
Drawable background = AppCompatResources.getDrawable(context,
nightMode ? checked ? R.drawable.btn_background_inactive_dark : R.drawable.btn_background_stroked_inactive_dark
: checked ? R.drawable.btn_background_inactive_light : R.drawable.btn_background_stroked_inactive_light);
view.setBackgroundDrawable(background);
}
public static void setTextColor(Context context, TextView tv, boolean enabled, boolean nightMode, ItemType type) {
if (tv != null) {
int activeColorId = type.isNegative() ? R.color.color_osm_edit_delete : getActiveTextColorId(nightMode);
int normalColorId = enabled ? activeColorId : getSecondaryTextColorId(nightMode);
ColorStateList textColorStateList = AndroidUtils.createPressedColorStateList(context, normalColorId, getPressedColorId(nightMode));
tv.setTextColor(textColorStateList);
}
}
public static void setTintedIcon(Context context, AppCompatImageView iv, boolean enabled, boolean nightMode, ItemType type) {
Integer iconId = type.getIconId();
if (iv != null && iconId != null) {
Drawable icon = AppCompatResources.getDrawable(context, iconId);
int activeColorId = type.isNegative() ? R.color.color_osm_edit_delete : getActiveIconColorId(nightMode);
int normalColorId = enabled ? activeColorId : getSecondaryIconColorId(nightMode);
ColorStateList iconColorStateList = AndroidUtils.createPressedColorStateList(context, normalColorId, getPressedColorId(nightMode));
if (icon != null) {
DrawableCompat.setTintList(icon, iconColorStateList);
}
iv.setImageDrawable(icon);
if (type.iconId == R.drawable.ic_action_rec_stop) {
int stopSize = iv.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin_large);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(stopSize, stopSize);
iv.setLayoutParams(params);
}
}
}
@ColorRes
public static int getActiveTextColorId(boolean nightMode) {
return nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light;
}
@ColorRes
public static int getActiveIconColorId(boolean nightMode) {
return nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
}
@ColorRes
public static int getSecondaryIconColorId(boolean nightMode) {
return nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
}
@ColorRes
public static int getActiveButtonColorId(boolean nightMode) {
return nightMode ? R.color.active_buttons_and_links_bg_pressed_dark : R.color.active_buttons_and_links_bg_pressed_light;
}
@ColorRes
public static int getInactiveButtonColorId(boolean nightMode) {
return nightMode ? R.color.inactive_buttons_and_links_bg_dark : R.color.inactive_buttons_and_links_bg_light;
}
@ColorRes
public static int getOsmandIconColorId(boolean nightMode) {
return nightMode ? R.color.icon_color_osmand_dark : R.color.icon_color_osmand_light;
}
@ColorRes
public static int getPressedColorId(boolean nightMode) {
return nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light;
}
@Override
protected int getDismissButtonHeight() {
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_close;
}
@Override
protected boolean useVerticalButtons() {
return true;
}
}

View file

@ -3,197 +3,238 @@ package net.osmand.plus.monitoring;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Typeface;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.SpannableString;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.annotation.StringRes;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.slider.RangeSlider;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.PlatformUtil;
import net.osmand.data.LatLon;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.NavigationService;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.UiUtilities.DialogButtonType;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.mapcontextmenu.other.TrackChartPoints;
import net.osmand.plus.myplaces.GPXItemPagerAdapter;
import net.osmand.plus.myplaces.SegmentActionsListener;
import net.osmand.plus.myplaces.SegmentGPXAdapter;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.track.GpxBlockStatisticsBuilder;
import net.osmand.plus.track.TrackAppearanceFragment;
import net.osmand.plus.track.TrackDisplayHelper;
import net.osmand.plus.views.controls.PagerSlidingTabStrip;
import net.osmand.plus.views.controls.WrapContentHeightViewPager;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.util.Algorithms;
import static net.osmand.plus.UiUtilities.CompoundButtonType.PROFILE_DEPENDENT;
import static net.osmand.plus.monitoring.OsmandMonitoringPlugin.MINUTES;
import static net.osmand.plus.monitoring.OsmandMonitoringPlugin.SECONDS;
import org.apache.commons.logging.Log;
public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment {
import java.io.File;
import java.util.Arrays;
import java.util.List;
import static net.osmand.AndroidUtils.getSecondaryTextColorId;
import static net.osmand.AndroidUtils.setPadding;
import static net.osmand.plus.UiUtilities.CompoundButtonType.GLOBAL;
import static net.osmand.plus.track.GpxBlockStatisticsBuilder.INIT_BLOCKS_ALTITUDE;
import static net.osmand.plus.track.GpxBlockStatisticsBuilder.INIT_BLOCKS_GENERAL;
import static net.osmand.plus.track.GpxBlockStatisticsBuilder.INIT_BLOCKS_SPEED;
public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment implements SegmentActionsListener {
public static final String TAG = TripRecordingBottomSheet.class.getSimpleName();
private static final Log LOG = PlatformUtil.getLog(TripRecordingBottomSheet.class);
public static final String UPDATE_TRACK_ICON = "update_track_icon";
private static final int GPS_UPDATE_INTERVAL = 1000;
private static final String[] INIT_BLOCKS_KEYS =
new String[]{INIT_BLOCKS_GENERAL, INIT_BLOCKS_ALTITUDE, INIT_BLOCKS_SPEED};
private OsmandApplication app;
private OsmandSettings settings;
private SavingTrackHelper helper;
private OsmandMonitoringPlugin plugin;
private ImageView upDownBtn;
private SwitchCompat confirmEveryRun;
private TextView intervalValueView;
private LinearLayout container;
private View divider;
private boolean infoExpanded;
private View statusContainer;
private AppCompatImageView trackAppearanceIcon;
private LinearLayout segmentsContainer;
private TrackDisplayHelper displayHelper;
private TrackChartPoints trackChartPoints;
private GPXItemPagerAdapter graphsAdapter;
private GpxBlockStatisticsBuilder blockStatisticsBuilder;
private SelectedGpxFile selectedGpxFile;
private final Handler handler = new Handler();
private Runnable updatingGPS;
private GPXFile getGPXFile() {
return selectedGpxFile.getGpxFile();
}
private boolean hasDataToSave() {
return helper.hasDataToSave();
}
private boolean searchingGPS() {
return app.getLocationProvider().getLastKnownLocation() == null;
}
private boolean wasTrackMonitored() {
return settings.SAVE_GLOBAL_TRACK_TO_GPX.get();
}
public static void showInstance(@NonNull FragmentManager fragmentManager) {
if (!fragmentManager.isStateSaved()) {
TripRecordingBottomSheet fragment = new TripRecordingBottomSheet();
fragment.show(fragmentManager, TAG);
}
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
app = requiredMyApplication();
settings = app.getSettings();
Context context = requireContext();
helper = app.getSavingTrackHelper();
plugin = OsmandPlugin.getPlugin(OsmandMonitoringPlugin.class);
selectedGpxFile = helper.getCurrentTrack();
LayoutInflater inflater = UiUtilities.getInflater(getContext(), nightMode);
final FragmentManager fragmentManager = getFragmentManager();
LayoutInflater inflater = UiUtilities.getInflater(context, nightMode);
View itemView = inflater.inflate(R.layout.trip_recording_fragment, null, false);
items.add(new BottomSheetItemWithDescription.Builder()
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(itemView)
.create());
final int paddingSmall = getResources().getDimensionPixelSize(R.dimen.content_padding_small);
statusContainer = itemView.findViewById(R.id.status_container);
updateStatus();
LinearLayout showTrackOnMapView = itemView.findViewById(R.id.show_track_on_map);
TextView showTrackOnMapTitle = showTrackOnMapView.findViewById(R.id.title);
showTrackOnMapTitle.setText(R.string.show_track_on_map);
LinearLayout showTrackContainer = itemView.findViewById(R.id.show_track_on_map);
trackAppearanceIcon = showTrackContainer.findViewById(R.id.additional_button_icon);
createShowTrackItem(showTrackContainer, trackAppearanceIcon, ItemType.SHOW_TRACK.getTitleId(),
TripRecordingBottomSheet.this, nightMode, new Runnable() {
@Override
public void run() {
hide();
}
});
ImageView trackAppearanceIcon = showTrackOnMapView.findViewById(R.id.icon_after_divider);
segmentsContainer = itemView.findViewById(R.id.segments_container);
createSegmentsTabs(segmentsContainer);
int color = settings.CURRENT_TRACK_COLOR.get();
String width = settings.CURRENT_TRACK_WIDTH.get();
boolean showArrows = settings.CURRENT_TRACK_SHOW_ARROWS.get();
Drawable drawable = TrackAppearanceFragment.getTrackIcon(app, width, showArrows, color);
RecyclerView statBlocks = itemView.findViewById(R.id.block_statistics);
blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile, nightMode);
blockStatisticsBuilder.setBlocksView(statBlocks);
blockStatisticsBuilder.setBlocksClickable(false);
blockStatisticsBuilder.setInitBlocksKey(INIT_BLOCKS_GENERAL);
blockStatisticsBuilder.initStatBlocks(null,
ContextCompat.getColor(app, getActiveTextColorId(nightMode)));
trackAppearanceIcon.setImageDrawable(drawable);
trackAppearanceIcon.setOnClickListener(new View.OnClickListener() {
CardView cardLeft = itemView.findViewById(R.id.button_left);
createItem(cardLeft, ItemType.CANCEL);
cardLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
final CardView cardCenterLeft = itemView.findViewById(R.id.button_center_left);
createItem(cardCenterLeft, wasTrackMonitored() ? ItemType.PAUSE : ItemType.RESUME);
cardCenterLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean wasTrackMonitored = !wasTrackMonitored();
if (!wasTrackMonitored) {
blockStatisticsBuilder.stopUpdatingStatBlocks();
} else {
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
}
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored);
updateStatus();
createItem(cardCenterLeft, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME);
}
});
CardView cardCenterRight = itemView.findViewById(R.id.button_center_right);
createItem(cardCenterRight, ItemType.FINISH);
cardCenterRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
hide();
SelectedGpxFile selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack();
TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, TripRecordingBottomSheet.this);
if (mapActivity != null && plugin != null && hasDataToSave()) {
plugin.saveCurrentTrack(null, mapActivity);
app.getNotificationHelper().refreshNotifications();
dismiss();
}
}
});
divider = itemView.findViewById(R.id.second_divider);
LinearLayout expandHideIntervalContainer = itemView.findViewById(R.id.interval_view_container);
upDownBtn = itemView.findViewById(R.id.up_down_button);
expandHideIntervalContainer.setOnClickListener(new View.OnClickListener() {
CardView cardRight = itemView.findViewById(R.id.button_right);
createItem(cardRight, ItemType.OPTIONS);
cardRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleInfoView();
}
});
final int secondsLength = SECONDS.length;
final int minutesLength = MINUTES.length;
intervalValueView = itemView.findViewById(R.id.interval_value);
updateIntervalLegend();
container = itemView.findViewById(R.id.always_ask_and_range_slider_container);
RangeSlider intervalSlider = itemView.findViewById(R.id.interval_slider);
intervalSlider.setValueTo(secondsLength + minutesLength - 1);
int currentModeColor = app.getSettings().getApplicationMode().getProfileColor(nightMode);
UiUtilities.setupSlider(intervalSlider, nightMode, currentModeColor, true);
container.setVisibility(View.GONE);
intervalSlider.addOnChangeListener(new RangeSlider.OnChangeListener() {
@Override
public void onValueChange(@NonNull RangeSlider slider, float value, boolean fromUser) {
int progress = (int) value;
if (progress == 0) {
settings.SAVE_GLOBAL_TRACK_INTERVAL.set(0);
} else if (progress < secondsLength) {
settings.SAVE_GLOBAL_TRACK_INTERVAL.set(SECONDS[progress] * 1000);
} else {
settings.SAVE_GLOBAL_TRACK_INTERVAL.set(MINUTES[progress - secondsLength] * 60 * 1000);
}
updateIntervalLegend();
}
});
for (int i = 0; i < secondsLength + minutesLength; i++) {
if (i < secondsLength) {
if (settings.SAVE_GLOBAL_TRACK_INTERVAL.get() <= SECONDS[i] * 1000) {
intervalSlider.setValues((float) i);
break;
}
} else {
if (settings.SAVE_GLOBAL_TRACK_INTERVAL.get() <= MINUTES[i - secondsLength] * 1000 * 60) {
intervalSlider.setValues((float) i);
break;
if (fragmentManager != null) {
TripRecordingOptionsBottomSheet.showInstance(fragmentManager, TripRecordingBottomSheet.this);
}
}
}
boolean checked = !settings.SAVE_GLOBAL_TRACK_REMEMBER.get();
confirmEveryRun = itemView.findViewById(R.id.confirm_every_run);
confirmEveryRun.setChecked(checked);
setBackgroundAndPadding(checked, paddingSmall);
confirmEveryRun.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setBackgroundAndPadding(isChecked, paddingSmall);
settings.SAVE_GLOBAL_TRACK_REMEMBER.set(!isChecked);
}
});
final SwitchCompat showTrackOnMapButton = showTrackOnMapView.findViewById(R.id.switch_button);
showTrackOnMapButton.setChecked(app.getSelectedGpxHelper().getSelectedCurrentRecordingTrack() != null);
View basicItem = itemView.findViewById(R.id.basic_item_body);
basicItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = !showTrackOnMapButton.isChecked();
showTrackOnMapButton.setChecked(checked);
app.getSelectedGpxHelper().selectGpxFile(app.getSavingTrackHelper().getCurrentGpx(), checked, false);
}
});
UiUtilities.setupCompoundButton(showTrackOnMapButton, nightMode, PROFILE_DEPENDENT);
updateUpDownBtn();
}
private void updateIntervalLegend() {
String text = getString(R.string.save_track_interval_globally);
String textValue;
int interval = settings.SAVE_GLOBAL_TRACK_INTERVAL.get();
if (interval == 0) {
textValue = getString(R.string.int_continuosly);
} else {
int seconds = interval / 1000;
if (seconds <= SECONDS[SECONDS.length - 1]) {
textValue = seconds + " " + getString(R.string.int_seconds);
} else {
textValue = (seconds / 60) + " " + getString(R.string.int_min);
}
@Override
public void onResume() {
super.onResume();
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
runUpdatingGPS();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMapLayers().getGpxLayer().setTrackChartPoints(trackChartPoints);
}
}
@Override
public void onPause() {
super.onPause();
blockStatisticsBuilder.stopUpdatingStatBlocks();
stopUpdatingGPS();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMapLayers().getGpxLayer().setTrackChartPoints(null);
}
String textAll = getString(R.string.ltr_or_rtl_combine_via_colon, text, textValue);
Typeface typeface = FontCache.getRobotoMedium(app);
SpannableString spannableString = UiUtilities.createCustomFontSpannable(typeface, textAll, textValue);
intervalValueView.setText(spannableString);
}
public void show() {
@ -203,6 +244,15 @@ public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment {
}
}
public void show(String... keys) {
show();
for (String key : keys) {
if (key.equals(UPDATE_TRACK_ICON)) {
updateTrackIcon(app, trackAppearanceIcon);
}
}
}
public void hide() {
Dialog dialog = getDialog();
if (dialog != null) {
@ -210,82 +260,398 @@ public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment {
}
}
private void setBackgroundAndPadding(boolean isChecked, int paddingSmall) {
if (nightMode) {
confirmEveryRun.setBackgroundResource(
isChecked ? R.drawable.layout_bg_dark_solid : R.drawable.layout_bg_dark);
} else {
confirmEveryRun.setBackgroundResource(
isChecked ? R.drawable.layout_bg_solid : R.drawable.layout_bg);
public void stopUpdatingGPS() {
handler.removeCallbacks(updatingGPS);
}
public void runUpdatingGPS() {
updatingGPS = new Runnable() {
@Override
public void run() {
int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
updateStatus();
handler.postDelayed(this, Math.max(GPS_UPDATE_INTERVAL, interval));
}
};
handler.post(updatingGPS);
}
private void recreateStatBlocks(String initBlocksKey) {
blockStatisticsBuilder.stopUpdatingStatBlocks();
blockStatisticsBuilder.setInitBlocksKey(initBlocksKey);
blockStatisticsBuilder.runUpdatingStatBlocksIfNeeded();
}
private void setupDisplayHelper() {
displayHelper = new TrackDisplayHelper(app);
if (!selectedGpxFile.isShowCurrentTrack()) {
File file = new File(getGPXFile().path);
displayHelper.setFile(file);
displayHelper.setGpxDataItem(app.getGpxDbHelper().getItem(file));
}
confirmEveryRun.setPadding(paddingSmall, 0, paddingSmall, 0);
displayHelper.setGpx(getGPXFile());
}
private void updateUpDownBtn() {
int iconId = infoExpanded ? R.drawable.ic_action_arrow_down : R.drawable.ic_action_arrow_up;
upDownBtn.setImageDrawable(getContentIcon(iconId));
private void createSegmentsTabs(ViewGroup viewGroup) {
viewGroup.removeAllViews();
setupDisplayHelper();
View segmentView = SegmentGPXAdapter.createGpxTabsView(displayHelper, viewGroup, this, nightMode);
AndroidUiHelper.setVisibility(View.GONE, segmentView.findViewById(R.id.list_item_divider));
WrapContentHeightViewPager pager = segmentView.findViewById(R.id.pager);
PagerSlidingTabStrip tabLayout = segmentView.findViewById(R.id.sliding_tabs);
tabLayout.setOnTabReselectedListener(new PagerSlidingTabStrip.OnTabReselectedListener() {
@Override
public void onTabSelected(int position) {
recreateStatBlocks(INIT_BLOCKS_KEYS[position]);
}
@Override
public void onTabReselected(int position) {
recreateStatBlocks(INIT_BLOCKS_KEYS[position]);
}
});
graphsAdapter = new GPXItemPagerAdapter(app, GpxUiHelper.makeGpxDisplayItem(app,
displayHelper.getGpx()), displayHelper, nightMode, this, true);
pager.setAdapter(graphsAdapter);
tabLayout.setViewPager(pager);
viewGroup.addView(segmentView);
}
private void toggleInfoView() {
infoExpanded = !infoExpanded;
ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) divider.getLayoutParams();
final int dp8 = AndroidUtils.dpToPx(app, 8f);
final int dp16 = AndroidUtils.dpToPx(app, 16f);
if (infoExpanded) {
AndroidUtils.setMargins(marginParams, 0, dp16, 0, dp8);
} else {
AndroidUtils.setMargins(marginParams, 0, 0, 0, dp8);
private void updateStatus() {
TextView statusTitle = statusContainer.findViewById(R.id.text_status);
AppCompatImageView statusIcon = statusContainer.findViewById(R.id.icon_status);
ItemType status = searchingGPS() ? ItemType.SEARCHING_GPS : !wasTrackMonitored() ? ItemType.ON_PAUSE : ItemType.RECORDING;
Integer titleId = status.getTitleId();
if (titleId != null) {
statusTitle.setText(titleId);
}
int colorText = status.equals(ItemType.SEARCHING_GPS) ? getSecondaryTextColorId(nightMode) : getOsmandIconColorId(nightMode);
statusTitle.setTextColor(ContextCompat.getColor(app, colorText));
Integer iconId = status.getIconId();
if (iconId != null) {
int colorDrawable = ContextCompat.getColor(app,
status.equals(ItemType.SEARCHING_GPS) ? getSecondaryIconColorId(nightMode) : getOsmandIconColorId(nightMode));
Drawable statusDrawable = UiUtilities.tintDrawable(AppCompatResources.getDrawable(app, iconId), colorDrawable);
statusIcon.setImageDrawable(statusDrawable);
}
}
public static void updateTrackIcon(OsmandApplication app, AppCompatImageView appearanceIcon) {
if (appearanceIcon != null) {
OsmandSettings settings = app.getSettings();
String width = settings.CURRENT_TRACK_WIDTH.get();
boolean showArrows = settings.CURRENT_TRACK_SHOW_ARROWS.get();
int color = settings.CURRENT_TRACK_COLOR.get();
Drawable appearanceDrawable = TrackAppearanceFragment.getTrackIcon(app, width, showArrows, color);
int marginTrackIconH = app.getResources().getDimensionPixelSize(R.dimen.content_padding_small);
UiUtilities.setMargins(appearanceIcon, marginTrackIconH, 0, marginTrackIconH, 0);
appearanceIcon.setImageDrawable(appearanceDrawable);
}
}
public static void createShowTrackItem(LinearLayout showTrackContainer, AppCompatImageView trackAppearanceIcon,
Integer showTrackId, final Fragment target,
final boolean nightMode, final Runnable hideOnClickButtonAppearance) {
FragmentActivity activity = target.getActivity();
if (!(activity instanceof MapActivity)) {
return;
}
final MapActivity mapActivity = (MapActivity) activity;
final OsmandApplication app = mapActivity.getMyApplication();
final CardView buttonShowTrack = showTrackContainer.findViewById(R.id.compound_container);
final CardView buttonAppearance = showTrackContainer.findViewById(R.id.additional_button_container);
TextView showTrackTextView = buttonShowTrack.findViewById(R.id.title);
if (showTrackId != null) {
showTrackTextView.setText(showTrackId);
}
final CompoundButton showTrackCompound = buttonShowTrack.findViewById(R.id.compound_button);
showTrackCompound.setChecked(app.getSelectedGpxHelper().getSelectedCurrentRecordingTrack() != null);
UiUtilities.setupCompoundButton(showTrackCompound, nightMode, GLOBAL);
setShowTrackItemBackground(buttonShowTrack, showTrackCompound.isChecked(), nightMode);
buttonShowTrack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = !showTrackCompound.isChecked();
showTrackCompound.setChecked(checked);
app.getSelectedGpxHelper().selectGpxFile(app.getSavingTrackHelper().getCurrentGpx(), checked, false);
setShowTrackItemBackground(buttonShowTrack, checked, nightMode);
createItem(app, nightMode, buttonAppearance, ItemType.APPEARANCE, checked, null);
}
});
updateTrackIcon(app, trackAppearanceIcon);
createItem(app, nightMode, buttonAppearance, ItemType.APPEARANCE, showTrackCompound.isChecked(), null);
buttonAppearance.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (showTrackCompound.isChecked()) {
hideOnClickButtonAppearance.run();
SelectedGpxFile selectedGpxFile = app.getSavingTrackHelper().getCurrentTrack();
TrackAppearanceFragment.showInstance(mapActivity, selectedGpxFile, target);
}
}
});
}
public static void setShowTrackItemBackground(View view, boolean checked, boolean nightMode) {
Drawable background = AppCompatResources.getDrawable(view.getContext(),
checked ? getActiveTransparentBackgroundId(nightMode) : getInactiveStrokedBackgroundId(nightMode));
view.setBackgroundDrawable(background);
}
private void createItem(View view, ItemType type) {
createItem(app, nightMode, view, type, true, null);
}
public static View createItem(Context context, boolean nightMode, LayoutInflater inflater, ItemType type) {
return createItem(context, nightMode, inflater, type, true, null);
}
public static View createItem(Context context, boolean nightMode, LayoutInflater inflater, ItemType type, boolean enabled, String description) {
View button = inflater.inflate(R.layout.bottom_sheet_button_with_icon, null);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
int horizontal = context.getResources().getDimensionPixelSize(R.dimen.content_padding);
params.setMargins(horizontal, 0, horizontal, 0);
button.setLayoutParams(params);
createItem(context, nightMode, button, type, enabled, description);
return button;
}
public static void createItem(Context context, boolean nightMode, View view, ItemType type, boolean enabled, @Nullable String description) {
view.setTag(type);
AppCompatImageView icon = view.findViewById(R.id.icon);
if (icon != null) {
setTintedIcon(context, icon, enabled, nightMode, type);
}
TextView title = view.findViewById(R.id.button_text);
Integer titleId = type.getTitleId();
if (title != null && titleId != null) {
title.setText(titleId);
setTextColor(context, title, enabled, nightMode, type);
}
TextViewEx desc = view.findViewById(R.id.desc);
if (desc != null) {
boolean isShowDesc = !Algorithms.isBlank(description);
int marginDesc = isShowDesc ? 0 : context.getResources().getDimensionPixelSize(R.dimen.context_menu_padding_margin_medium);
AndroidUiHelper.updateVisibility(desc, isShowDesc);
if (title != null) {
UiUtilities.setMargins(title, 0, marginDesc, 0, marginDesc);
}
desc.setText(description);
setTextColor(context, desc, false, nightMode, type);
}
setItemBackground(context, nightMode, view, enabled);
}
public static void setItemBackground(Context context, boolean nightMode, View view, boolean enabled) {
if (view instanceof CardView) {
int colorId = enabled ? getActiveTransparentColorId(nightMode) : getInactiveButtonColorId(nightMode);
((CardView) view).setCardBackgroundColor(AndroidUtils.createPressedColorStateList(
context, colorId, getActiveTextColorId(nightMode)
));
return;
}
Drawable background = AppCompatResources.getDrawable(context, getInactiveButtonBackgroundId(nightMode));
if (background != null && enabled) {
DrawableCompat.setTintList(background, AndroidUtils.createPressedColorStateList(
context, getInactiveButtonColorId(nightMode), getActiveTextColorId(nightMode)
));
} else {
UiUtilities.tintDrawable(background, ContextCompat.getColor(context, getInactiveButtonColorId(nightMode)));
}
view.setBackgroundDrawable(background);
}
public enum ItemType {
SHOW_TRACK(R.string.shared_string_show_on_map, null),
APPEARANCE(null, null),
SEARCHING_GPS(R.string.searching_gps, R.drawable.ic_action_gps_info),
RECORDING(R.string.recording_default_name, R.drawable.ic_action_track_recordable),
ON_PAUSE(R.string.on_pause, R.drawable.ic_pause),
CLEAR_DATA(R.string.clear_recorded_data, R.drawable.ic_action_delete_dark),
START_NEW_SEGMENT(R.string.gpx_start_new_segment, R.drawable.ic_action_new_segment),
SAVE(R.string.trip_recording_save_and_continue, R.drawable.ic_action_save_to_file),
PAUSE(R.string.shared_string_pause, R.drawable.ic_pause),
RESUME(R.string.shared_string_resume, R.drawable.ic_play_dark),
STOP(R.string.shared_string_control_stop, R.drawable.ic_action_rec_stop),
STOP_AND_DISCARD(R.string.track_recording_stop_without_saving, R.drawable.ic_action_rec_stop),
STOP_AND_SAVE(R.string.track_recording_save_and_stop, R.drawable.ic_action_save_to_file),
STOP_ONLINE(R.string.live_monitoring_stop, R.drawable.ic_world_globe_dark),
CANCEL(R.string.shared_string_cancel, R.drawable.ic_action_close),
START_RECORDING(R.string.shared_string_control_start, R.drawable.ic_action_direction_movement),
SETTINGS(R.string.shared_string_settings, R.drawable.ic_action_settings),
FINISH(R.string.shared_string_finish, R.drawable.ic_action_point_destination),
OPTIONS(R.string.shared_string_options, R.drawable.ic_overflow_menu_with_background);
@StringRes
private final Integer titleId;
@DrawableRes
private final Integer iconId;
private static final List<ItemType> negative = Arrays.asList(CLEAR_DATA, STOP_AND_DISCARD);
ItemType(@Nullable @StringRes Integer titleId, @Nullable @DrawableRes Integer iconId) {
this.titleId = titleId;
this.iconId = iconId;
}
@Nullable
public Integer getTitleId() {
return titleId;
}
@Nullable
public Integer getIconId() {
return iconId;
}
public boolean isNegative() {
return negative.contains(this);
}
}
protected static void setTextColor(Context context, TextView tv, boolean enabled, boolean nightMode, ItemType type) {
if (tv != null) {
int activeColorId = type.isNegative() ? R.color.color_osm_edit_delete : getActiveTextColorId(nightMode);
int normalColorId = enabled ? activeColorId : getSecondaryTextColorId(nightMode);
ColorStateList textColorStateList = AndroidUtils.createPressedColorStateList(context, normalColorId, getPressedColorId(nightMode));
tv.setTextColor(textColorStateList);
}
}
protected static void setTintedIcon(Context context, AppCompatImageView iv, boolean enabled, boolean nightMode, ItemType type) {
Integer iconId = type.getIconId();
if (iv != null && iconId != null) {
Drawable icon = AppCompatResources.getDrawable(context, iconId);
int activeColorId = type.isNegative() ? R.color.color_osm_edit_delete : getActiveIconColorId(nightMode);
int normalColorId = enabled ? activeColorId : getSecondaryIconColorId(nightMode);
ColorStateList iconColorStateList = AndroidUtils.createPressedColorStateList(context, normalColorId, getPressedColorId(nightMode));
if (icon != null) {
DrawableCompat.setTintList(icon, iconColorStateList);
}
iv.setImageDrawable(icon);
if (type.iconId == R.drawable.ic_action_rec_stop) {
int stopSize = iv.getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin_large);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(stopSize, stopSize);
iv.setLayoutParams(params);
View container = (View) iv.getParent();
setPadding(container, container.getPaddingLeft(), container.getTop(),
context.getResources().getDimensionPixelSize(R.dimen.content_padding_half), container.getBottom());
}
}
AndroidUiHelper.updateVisibility(container, infoExpanded);
updateUpDownBtn();
}
@Override
protected boolean useVerticalButtons() {
return true;
}
@Override
protected int getRightButtonHeight() {
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
}
@Override
protected int getDismissButtonHeight() {
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.start_recording;
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_cancel;
}
@Override
protected DialogButtonType getRightBottomButtonType() {
return DialogButtonType.PRIMARY;
}
@Override
public int getSecondDividerHeight() {
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin);
}
@Override
protected void onRightBottomButtonClick() {
SavingTrackHelper helper = app.getSavingTrackHelper();
helper.startNewSegment();
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(true);
app.startNavigationService(NavigationService.USED_BY_GPX);
public void onPointSelected(TrkSegment segment, double lat, double lon) {
if (trackChartPoints == null) {
trackChartPoints = new TrackChartPoints();
trackChartPoints.setGpx(displayHelper.getGpx());
}
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
TripRecordingActiveBottomSheet.showInstance(mapActivity.getSupportFragmentManager(), helper.getCurrentTrack());
int segmentColor = segment != null ? segment.getColor(0) : 0;
trackChartPoints.setSegmentColor(segmentColor);
trackChartPoints.setHighlightedPoint(new LatLon(lat, lon));
mapActivity.getMapLayers().getGpxLayer().setTrackChartPoints(trackChartPoints);
mapActivity.refreshMap();
}
dismiss();
}
@Override
public void updateContent() {
}
@Override
public void onChartTouch() {
}
@Override
public void scrollBy(int px) {
}
@Override
public void openSplitInterval(GpxDisplayItem gpxItem, TrkSegment trkSegment) {
}
@Override
public void showOptionsPopupMenu(View view, TrkSegment segment, boolean confirmDeletion, GpxDisplayItem gpxItem) {
}
@Override
public void openAnalyzeOnMap(GpxDisplayItem gpxItem) {
}
public interface DismissTargetFragment {
void dismissTarget();
}
@ColorRes
public static int getActiveTextColorId(boolean nightMode) {
return nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light;
}
@ColorRes
public static int getActiveIconColorId(boolean nightMode) {
return nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
}
@ColorRes
public static int getSecondaryIconColorId(boolean nightMode) {
return nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
}
@ColorRes
public static int getActiveButtonColorId(boolean nightMode) {
return nightMode ? R.color.active_buttons_and_links_bg_pressed_dark : R.color.active_buttons_and_links_bg_pressed_light;
}
@ColorRes
public static int getInactiveButtonColorId(boolean nightMode) {
return nightMode ? R.color.inactive_buttons_and_links_bg_dark : R.color.inactive_buttons_and_links_bg_light;
}
@ColorRes
public static int getOsmandIconColorId(boolean nightMode) {
return nightMode ? R.color.icon_color_osmand_dark : R.color.icon_color_osmand_light;
}
@ColorRes
public static int getActiveTransparentColorId(boolean nightMode) {
return nightMode ? R.color.switch_button_active_dark : R.color.switch_button_active_light;
}
@ColorRes
public static int getPressedColorId(boolean nightMode) {
return nightMode ? R.color.active_buttons_and_links_text_dark : R.color.active_buttons_and_links_text_light;
}
@DrawableRes
public static int getActiveTransparentBackgroundId(boolean nightMode) {
return nightMode ? R.drawable.btn_background_active_transparent_dark : R.drawable.btn_background_active_transparent_light;
}
@DrawableRes
public static int getInactiveStrokedBackgroundId(boolean nightMode) {
return nightMode ? R.drawable.btn_background_stroked_inactive_dark : R.drawable.btn_background_stroked_inactive_light;
}
@DrawableRes
public static int getInactiveButtonBackgroundId(boolean nightMode) {
return nightMode ? R.drawable.btn_background_inactive_dark : R.drawable.btn_background_inactive_light;
}
@Override
protected boolean hideButtonsContainer() {
return true;
}
@Nullable
@ -296,11 +662,4 @@ public class TripRecordingBottomSheet extends MenuBottomSheetDialogFragment {
}
return null;
}
public static void showInstance(@NonNull FragmentManager fragmentManager) {
if (!fragmentManager.isStateSaved()) {
TripRecordingBottomSheet fragment = new TripRecordingBottomSheet();
fragment.show(fragmentManager, TAG);
}
}
}
}

View file

@ -11,21 +11,23 @@ import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.ItemType;
import net.osmand.plus.monitoring.TripRecordingBottomSheet.ItemType;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogFragment {
import static net.osmand.AndroidUtils.getPrimaryTextColorId;
public static final String TAG = ClearRecordedDataBottomSheetFragment.class.getSimpleName();
public class TripRecordingClearDataBottomSheet extends MenuBottomSheetDialogFragment implements TripRecordingBottomSheet.DismissTargetFragment {
public static final String TAG = TripRecordingClearDataBottomSheet.class.getSimpleName();
private OsmandApplication app;
public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull Fragment target) {
if (!fragmentManager.isStateSaved()) {
ClearRecordedDataBottomSheetFragment fragment = new ClearRecordedDataBottomSheetFragment();
TripRecordingClearDataBottomSheet fragment = new TripRecordingClearDataBottomSheet();
fragment.setTargetFragment(target, 0);
fragment.show(fragmentManager, TAG);
}
@ -37,14 +39,14 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
int verticalBig = getResources().getDimensionPixelSize(R.dimen.dialog_content_margin);
int verticalNormal = getResources().getDimensionPixelSize(R.dimen.content_padding);
String description = getString(R.string.clear_recorded_data_warning)
.concat("\n").concat(getString(R.string.lost_data_warning));
final View buttonClear = createItem(inflater, ItemType.CLEAR_DATA);
final View buttonCancel = createItem(inflater, ItemType.CANCEL);
items.add(new BottomSheetItemWithDescription.Builder()
.setDescription(app.getString(R.string.clear_recorded_data_warning))
.setDescriptionColorId(!nightMode ? R.color.text_color_primary_light : R.color.text_color_primary_dark)
.setDescriptionMaxLines(2)
.setDescription(description)
.setDescriptionColorId(getPrimaryTextColorId(nightMode))
.setTitle(app.getString(R.string.clear_recorded_data))
.setLayoutId(R.layout.bottom_sheet_item_title_with_description)
.create());
@ -58,6 +60,7 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF
public void onClick(View v) {
app.getSavingTrackHelper().clearRecordedData(true);
dismiss();
dismissTarget();
}
})
.create());
@ -78,15 +81,15 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF
}
private View createItem(LayoutInflater inflater, ItemType type) {
return TripRecordingActiveBottomSheet.createItem(app, nightMode, inflater, type);
return TripRecordingBottomSheet.createItem(app, nightMode, inflater, type);
}
@Override
public void onResume() {
super.onResume();
Fragment target = getTargetFragment();
if (target instanceof TripRecordingActiveBottomSheet) {
((TripRecordingActiveBottomSheet) target).hide();
if (target instanceof TripRecordingOptionsBottomSheet) {
((TripRecordingOptionsBottomSheet) target).hide();
}
}
@ -94,8 +97,8 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF
public void onPause() {
super.onPause();
Fragment target = getTargetFragment();
if (target instanceof TripRecordingActiveBottomSheet) {
((TripRecordingActiveBottomSheet) target).show();
if (target instanceof TripRecordingOptionsBottomSheet) {
((TripRecordingOptionsBottomSheet) target).show();
}
}
@ -103,4 +106,12 @@ public class ClearRecordedDataBottomSheetFragment extends MenuBottomSheetDialogF
protected boolean hideButtonsContainer() {
return true;
}
}
@Override
public void dismissTarget() {
Fragment target = getTargetFragment();
if (target instanceof TripRecordingOptionsBottomSheet) {
((TripRecordingOptionsBottomSheet) target).dismiss();
}
}
}

View file

@ -8,36 +8,28 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.ItemType;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.monitoring.TripRecordingBottomSheet.ItemType;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragment {
import static net.osmand.AndroidUtils.getPrimaryTextColorId;
import static net.osmand.plus.monitoring.TripRecordingOptionsBottomSheet.ACTION_STOP_AND_DISMISS;
public static final String TAG = StopTrackRecordingBottomFragment.class.getSimpleName();
public class TripRecordingDiscardBottomSheet extends MenuBottomSheetDialogFragment implements TripRecordingBottomSheet.DismissTargetFragment {
public static final String TAG = TripRecordingDiscardBottomSheet.class.getSimpleName();
private OsmandApplication app;
private MapActivity mapActivity;
private OsmandSettings settings;
private OsmandMonitoringPlugin plugin;
private ItemType tag = ItemType.CANCEL;
public void setMapActivity(MapActivity mapActivity) {
this.mapActivity = mapActivity;
}
public static void showInstance(MapActivity mapActivity, @NonNull FragmentManager fragmentManager, @NonNull Fragment target) {
public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull Fragment target) {
if (!fragmentManager.isStateSaved()) {
StopTrackRecordingBottomFragment fragment = new StopTrackRecordingBottomFragment();
fragment.setMapActivity(mapActivity);
TripRecordingDiscardBottomSheet fragment = new TripRecordingDiscardBottomSheet();
fragment.setTargetFragment(target, 0);
fragment.show(fragmentManager, TAG);
}
@ -46,67 +38,52 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm
@Override
public void createMenuItems(Bundle savedInstanceState) {
app = requiredMyApplication();
settings = app.getSettings();
plugin = OsmandPlugin.getPlugin(OsmandMonitoringPlugin.class);
final OsmandMonitoringPlugin plugin = OsmandPlugin.getPlugin(OsmandMonitoringPlugin.class);
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
int verticalBig = getResources().getDimensionPixelSize(R.dimen.dialog_content_margin);
int verticalNormal = getResources().getDimensionPixelSize(R.dimen.content_padding);
// final View buttonDiscard = createItem(inflater, ItemType.STOP_AND_DISCARD);
final View buttonSave = createItem(inflater, ItemType.STOP_AND_SAVE);
final View buttonDiscard = createItem(inflater, ItemType.STOP_AND_DISCARD);
final View buttonCancel = createItem(inflater, ItemType.CANCEL);
items.add(new BottomSheetItemWithDescription.Builder()
.setDescription(app.getString(R.string.track_recording_description))
.setDescriptionColorId(!nightMode ? R.color.text_color_primary_light : R.color.text_color_primary_dark)
.setDescriptionMaxLines(4)
.setDescription(getString(R.string.track_recording_description))
.setDescriptionColorId(getPrimaryTextColorId(nightMode))
.setTitle(app.getString(R.string.track_recording_title))
.setLayoutId(R.layout.bottom_sheet_item_title_with_description)
.create());
items.add(new DividerSpaceItem(app, verticalBig));
/*items.add(new BaseBottomSheetItem.Builder()
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(buttonDiscard)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tag = (ItemType) buttonDiscard.getTag();
if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) {
if (plugin != null && app.getSettings().SAVE_GLOBAL_TRACK_TO_GPX.get()) {
plugin.stopRecording();
app.getNotificationHelper().refreshNotifications();
}
app.getSavingTrackHelper().clearRecordedData(true);
dismiss();
}
})
.create());
items.add(new DividerSpaceItem(app, verticalBig));*/
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(buttonSave)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tag = (ItemType) buttonSave.getTag();
if (plugin != null && app.getSavingTrackHelper().hasDataToSave()) {
plugin.saveCurrentTrack(null, mapActivity);
app.getNotificationHelper().refreshNotifications();
dismiss();
Fragment target = getTargetFragment();
if (target != null) {
Bundle args = new Bundle();
args.putBoolean(ACTION_STOP_AND_DISMISS, true);
target.setArguments(args);
}
dismissTarget();
}
})
.create());
items.add(new DividerSpaceItem(app, verticalNormal));
items.add(new DividerSpaceItem(app, verticalBig));
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(buttonCancel)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tag = (ItemType) buttonCancel.getTag();
dismiss();
}
})
@ -116,15 +93,15 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm
}
private View createItem(LayoutInflater inflater, ItemType type) {
return TripRecordingActiveBottomSheet.createItem(app, nightMode, inflater, type);
return TripRecordingBottomSheet.createItem(app, nightMode, inflater, type);
}
@Override
public void onResume() {
super.onResume();
Fragment target = getTargetFragment();
if (target instanceof TripRecordingActiveBottomSheet) {
((TripRecordingActiveBottomSheet) target).hide();
if (target instanceof TripRecordingOptionsBottomSheet) {
((TripRecordingOptionsBottomSheet) target).hide();
}
}
@ -132,13 +109,16 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm
public void onPause() {
super.onPause();
Fragment target = getTargetFragment();
if (target instanceof TripRecordingActiveBottomSheet) {
TripRecordingActiveBottomSheet tripRec = (TripRecordingActiveBottomSheet) target;
if (tag == ItemType.CANCEL) {
tripRec.show();
} else {
tripRec.dismiss();
}
if (target instanceof TripRecordingOptionsBottomSheet) {
((TripRecordingOptionsBottomSheet) target).show();
}
}
@Override
public void dismissTarget() {
Fragment target = getTargetFragment();
if (target instanceof TripRecordingOptionsBottomSheet) {
((TripRecordingOptionsBottomSheet) target).dismiss();
}
}

View file

@ -0,0 +1,321 @@
package net.osmand.plus.monitoring;
import android.app.Activity;
import android.app.Dialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.monitoring.TripRecordingBottomSheet.ItemType;
import net.osmand.plus.myplaces.SaveCurrentTrackTask;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener;
import net.osmand.util.Algorithms;
import static net.osmand.AndroidUtils.getPrimaryTextColorId;
public class TripRecordingOptionsBottomSheet extends MenuBottomSheetDialogFragment implements TripRecordingBottomSheet.DismissTargetFragment {
public static final String TAG = TripRecordingOptionsBottomSheet.class.getSimpleName();
public static final String ACTION_STOP_AND_DISMISS = "action_stop_and_discard";
private static final int SAVE_UPDATE_INTERVAL = 1000;
private OsmandApplication app;
private OsmandSettings settings;
private SavingTrackHelper helper;
private View buttonClear;
private View buttonSave;
private SelectedGpxFile selectedGpxFile;
private final Handler handler = new Handler();
private Runnable updatingTimeTrackSaved;
private int indexButtonOnline = -1;
private int indexButtonOnlineDivider = -1;
private GPXFile getGPXFile() {
return selectedGpxFile.getGpxFile();
}
public void setSelectedGpxFile(SelectedGpxFile selectedGpxFile) {
this.selectedGpxFile = selectedGpxFile;
}
public boolean hasDataToSave() {
return app.getSavingTrackHelper().hasDataToSave();
}
public boolean wasTrackMonitored() {
return settings.SAVE_GLOBAL_TRACK_TO_GPX.get();
}
public static void showInstance(@NonNull FragmentManager fragmentManager, @NonNull Fragment target) {
if (!fragmentManager.isStateSaved()) {
TripRecordingOptionsBottomSheet fragment = new TripRecordingOptionsBottomSheet();
fragment.setTargetFragment(target, 0);
fragment.show(fragmentManager, TAG);
}
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
app = requiredMyApplication();
settings = app.getSettings();
helper = app.getSavingTrackHelper();
selectedGpxFile = helper.getCurrentTrack();
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
final FragmentManager fragmentManager = getFragmentManager();
int dp16 = getResources().getDimensionPixelSize(R.dimen.content_padding);
int dp36 = getResources().getDimensionPixelSize(R.dimen.context_menu_controller_height);
buttonClear = createItem(inflater, ItemType.CLEAR_DATA, hasDataToSave());
final View buttonDiscard = createItem(inflater, ItemType.STOP_AND_DISCARD);
final View buttonOnline = createItem(inflater, ItemType.STOP_ONLINE, hasDataToSave());
buttonSave = createItem(inflater, ItemType.SAVE, hasDataToSave());
final View buttonSegment = createItem(inflater, ItemType.START_NEW_SEGMENT, wasTrackMonitored());
items.add(new SimpleBottomSheetItem.Builder()
.setTitle(getString(R.string.shared_string_options))
.setTitleColorId(getPrimaryTextColorId(nightMode))
.setLayoutId(R.layout.bottom_sheet_item_title)
.create());
items.add(new DividerSpaceItem(app, getResources().getDimensionPixelSize(R.dimen.content_padding_small)));
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(buttonClear)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (fragmentManager != null && hasDataToSave()) {
TripRecordingClearDataBottomSheet.showInstance(fragmentManager, TripRecordingOptionsBottomSheet.this);
}
}
})
.create());
items.add(new DividerSpaceItem(app, dp16));
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(buttonDiscard)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (fragmentManager != null) {
TripRecordingDiscardBottomSheet.showInstance(fragmentManager, TripRecordingOptionsBottomSheet.this);
}
}
})
.create());
items.add(new DividerSpaceItem(app, dp36));
if (app.getLiveMonitoringHelper().isLiveMonitoringEnabled()) {
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(buttonOnline)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
settings.LIVE_MONITORING.set(false);
if (indexButtonOnline != -1) {
AndroidUiHelper.updateVisibility(items.get(indexButtonOnline).getView(), false);
}
if (indexButtonOnlineDivider != -1) {
AndroidUiHelper.updateVisibility(items.get(indexButtonOnlineDivider).getView(), false);
}
}
})
.create());
indexButtonOnline = items.size() - 1;
items.add(new DividerSpaceItem(app, dp36));
indexButtonOnlineDivider = items.size() - 1;
}
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(buttonSave)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (hasDataToSave()) {
final GPXFile gpxFile = getGPXFile();
new SaveCurrentTrackTask(app, gpxFile, createSaveListener()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
})
.create());
items.add(new DividerSpaceItem(app, dp16));
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(buttonSegment)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (wasTrackMonitored()) {
helper.startNewSegment();
}
}
})
.create());
items.add(new DividerSpaceItem(app, getResources().getDimensionPixelSize(R.dimen.content_padding_small)));
}
@Override
public void onResume() {
super.onResume();
runUpdatingTimeTrackSaved();
Fragment target = getTargetFragment();
if (target instanceof TripRecordingBottomSheet) {
((TripRecordingBottomSheet) target).hide();
}
}
@Override
public void onPause() {
super.onPause();
stopUpdatingTimeTrackSaved();
dismissTarget();
}
public void show() {
Dialog dialog = getDialog();
if (dialog != null) {
dialog.show();
}
}
public void hide() {
Dialog dialog = getDialog();
if (dialog != null) {
dialog.hide();
}
}
public void stopUpdatingTimeTrackSaved() {
handler.removeCallbacks(updatingTimeTrackSaved);
}
public void runUpdatingTimeTrackSaved() {
updatingTimeTrackSaved = new Runnable() {
@Override
public void run() {
String time = getTimeTrackSaved();
TripRecordingBottomSheet.createItem(app, nightMode, buttonSave, ItemType.SAVE, hasDataToSave(), !Algorithms.isEmpty(time) ? time : null);
TripRecordingBottomSheet.createItem(app, nightMode, buttonClear, ItemType.CLEAR_DATA, hasDataToSave(), null);
handler.postDelayed(this, SAVE_UPDATE_INTERVAL);
}
};
handler.post(updatingTimeTrackSaved);
}
private String getTimeTrackSaved() {
long timeTrackSaved = helper.getLastTimeFileSaved();
if (timeTrackSaved != 0) {
long now = System.currentTimeMillis();
CharSequence time = DateUtils.getRelativeTimeSpanString(timeTrackSaved, now, DateUtils.MINUTE_IN_MILLIS);
return String.valueOf(time);
} else {
return null;
}
}
private View createItem(LayoutInflater inflater, ItemType type, boolean enabled) {
return TripRecordingBottomSheet.createItem(app, nightMode, inflater, type, enabled, null);
}
private View createItem(LayoutInflater inflater, ItemType type) {
return TripRecordingBottomSheet.createItem(app, nightMode, inflater, type);
}
private SaveGpxListener createSaveListener() {
return new SaveGpxListener() {
@Override
public void gpxSavingStarted() {
}
@Override
public void gpxSavingFinished(Exception errorMessage) {
MapActivity mapActivity = getMapActivity();
OsmandMonitoringPlugin plugin = OsmandPlugin.getPlugin(OsmandMonitoringPlugin.class);
if (mapActivity != null && plugin != null) {
stopUpdatingTimeTrackSaved();
plugin.saveCurrentTrack(null, mapActivity, false, true);
Bundle args = new Bundle();
args.putBoolean(ACTION_STOP_AND_DISMISS, true);
setArguments(args);
dismiss();
dismissTarget();
}
}
};
}
private boolean isDiscard() {
Bundle args = getArguments();
if (args != null) {
return args.getBoolean(ACTION_STOP_AND_DISMISS);
}
return false;
}
@Override
public void dismissTarget() {
Fragment target = getTargetFragment();
if (target instanceof TripRecordingBottomSheet) {
if (isDiscard()) {
((TripRecordingBottomSheet) target).dismiss();
} else {
((TripRecordingBottomSheet) target).show();
}
}
}
@Nullable
public MapActivity getMapActivity() {
Activity activity = getActivity();
if (activity instanceof MapActivity) {
return (MapActivity) activity;
}
return null;
}
@Override
protected int getDismissButtonHeight() {
return getResources().getDimensionPixelSize(R.dimen.bottom_sheet_cancel_button_height);
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_back;
}
@Override
protected boolean useVerticalButtons() {
return true;
}
}

View file

@ -0,0 +1,266 @@
package net.osmand.plus.monitoring;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.SpannableString;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.cardview.widget.CardView;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.slider.RangeSlider;
import net.osmand.plus.NavigationService;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.monitoring.TripRecordingBottomSheet.ItemType;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType;
import static net.osmand.plus.monitoring.OsmandMonitoringPlugin.MINUTES;
import static net.osmand.plus.monitoring.OsmandMonitoringPlugin.SECONDS;
import static net.osmand.plus.monitoring.TripRecordingBottomSheet.createItem;
import static net.osmand.plus.monitoring.TripRecordingBottomSheet.createShowTrackItem;
import static net.osmand.plus.monitoring.TripRecordingBottomSheet.updateTrackIcon;
public class TripRecordingStartingBottomSheet extends MenuBottomSheetDialogFragment {
public static final String TAG = TripRecordingStartingBottomSheet.class.getSimpleName();
public static final String UPDATE_LOGGING_INTERVAL = "update_logging_interval";
private OsmandApplication app;
private OsmandSettings settings;
private AppCompatImageView upDownBtn;
private AppCompatImageView trackAppearanceIcon;
private TextView intervalValueView;
private LinearLayout intervalContainer;
private RangeSlider intervalSlider;
private boolean infoExpanded;
public static void showInstance(@NonNull FragmentManager fragmentManager) {
if (!fragmentManager.isStateSaved()) {
TripRecordingStartingBottomSheet fragment = new TripRecordingStartingBottomSheet();
fragment.show(fragmentManager, TAG);
}
}
public static void showTripRecordingDialog(@NonNull FragmentManager fragmentManager, OsmandApplication app) {
if (!fragmentManager.isStateSaved()) {
OsmandSettings settings = app.getSettings();
boolean showStartDialog = settings.SHOW_TRIP_REC_START_DIALOG.get();
if (showStartDialog) {
showInstance(fragmentManager);
} else {
startRecording(app);
TripRecordingBottomSheet.showInstance(fragmentManager);
}
}
}
@Override
public void createMenuItems(Bundle savedInstanceState) {
app = requiredMyApplication();
settings = app.getSettings();
Context context = requireContext();
LayoutInflater inflater = UiUtilities.getInflater(context, nightMode);
View itemView = inflater.inflate(R.layout.trip_recording_starting_fragment, null, false);
items.add(new BaseBottomSheetItem.Builder()
.setCustomView(itemView)
.create());
LinearLayout expandHideIntervalContainer = itemView.findViewById(R.id.interval_view_container);
upDownBtn = itemView.findViewById(R.id.up_down_button);
expandHideIntervalContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateIntervalContainer();
}
});
intervalValueView = itemView.findViewById(R.id.interval_value);
intervalContainer = itemView.findViewById(R.id.always_ask_and_range_slider_container);
intervalSlider = itemView.findViewById(R.id.interval_slider);
updateIntervalValue();
LinearLayout showTrackContainer = itemView.findViewById(R.id.show_track_on_map);
trackAppearanceIcon = showTrackContainer.findViewById(R.id.additional_button_icon);
createShowTrackItem(showTrackContainer, trackAppearanceIcon, R.string.shared_string_show_on_map,
TripRecordingStartingBottomSheet.this, nightMode, new Runnable() {
@Override
public void run() {
hide();
}
});
updateUpDownBtn();
CardView cardLeft = itemView.findViewById(R.id.button_left);
createItem(app, nightMode, cardLeft, ItemType.CANCEL, true, null);
cardLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
CardView cardCenter = itemView.findViewById(R.id.button_center);
createItem(app, nightMode, cardCenter, ItemType.START_RECORDING, true, null);
cardCenter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startRecording();
}
});
CardView cardRight = itemView.findViewById(R.id.button_right);
createItem(app, nightMode, cardRight, ItemType.SETTINGS, true, null);
cardRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
hide();
BaseSettingsFragment.showInstance(mapActivity, SettingsScreenType.MONITORING_SETTINGS,
null, new Bundle(), TripRecordingStartingBottomSheet.this);
}
}
});
}
private void updateIntervalLegend() {
String text = getString(R.string.save_track_interval_globally);
String textValue;
int interval = settings.SAVE_GLOBAL_TRACK_INTERVAL.get();
if (interval == 0) {
textValue = getString(R.string.int_continuosly);
} else {
int seconds = interval / 1000;
if (seconds <= SECONDS[SECONDS.length - 1]) {
textValue = seconds + " " + getString(R.string.int_seconds);
} else {
textValue = (seconds / 60) + " " + getString(R.string.int_min);
}
}
String textAll = getString(R.string.ltr_or_rtl_combine_via_colon, text, textValue);
Typeface typeface = FontCache.getRobotoMedium(app);
SpannableString spannableString = UiUtilities.createCustomFontSpannable(typeface, textAll, textValue);
intervalValueView.setText(spannableString);
}
private void updateIntervalValue() {
if (intervalSlider != null && intervalContainer != null) {
updateIntervalLegend();
final int secondsLength = SECONDS.length;
final int minutesLength = MINUTES.length;
intervalSlider.setValueTo(secondsLength + minutesLength - 1);
int currentModeColor = app.getSettings().getApplicationMode().getProfileColor(nightMode);
UiUtilities.setupSlider(intervalSlider, nightMode, currentModeColor, true);
intervalContainer.setVisibility(View.GONE);
intervalSlider.addOnChangeListener(new RangeSlider.OnChangeListener() {
@Override
public void onValueChange(@NonNull RangeSlider slider, float value, boolean fromUser) {
int progress = (int) value;
if (progress == 0) {
settings.SAVE_GLOBAL_TRACK_INTERVAL.set(0);
} else if (progress < secondsLength) {
settings.SAVE_GLOBAL_TRACK_INTERVAL.set(SECONDS[progress] * 1000);
} else {
settings.SAVE_GLOBAL_TRACK_INTERVAL.set(MINUTES[progress - secondsLength] * 60 * 1000);
}
updateIntervalLegend();
}
});
for (int i = 0; i < secondsLength + minutesLength; i++) {
if (i < secondsLength) {
if (settings.SAVE_GLOBAL_TRACK_INTERVAL.get() <= SECONDS[i] * 1000) {
intervalSlider.setValues((float) i);
break;
}
} else {
if (settings.SAVE_GLOBAL_TRACK_INTERVAL.get() <= MINUTES[i - secondsLength] * 1000 * 60) {
intervalSlider.setValues((float) i);
break;
}
}
}
}
}
private void updateIntervalContainer() {
infoExpanded = !infoExpanded;
AndroidUiHelper.updateVisibility(intervalContainer, infoExpanded);
updateUpDownBtn();
}
private void updateUpDownBtn() {
int iconId = infoExpanded ? R.drawable.ic_action_arrow_down : R.drawable.ic_action_arrow_up;
upDownBtn.setImageDrawable(getContentIcon(iconId));
}
private static void startRecording(OsmandApplication app) {
app.getSavingTrackHelper().startNewSegment();
app.getSettings().SAVE_GLOBAL_TRACK_TO_GPX.set(true);
app.startNavigationService(NavigationService.USED_BY_GPX);
}
private void startRecording() {
startRecording(app);
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
TripRecordingBottomSheet.showInstance(mapActivity.getSupportFragmentManager());
}
dismiss();
}
public void show() {
Dialog dialog = getDialog();
if (dialog != null) {
dialog.show();
updateTrackIcon(app, trackAppearanceIcon);
updateIntervalValue();
AndroidUiHelper.updateVisibility(intervalContainer, infoExpanded);
}
}
public void hide() {
Dialog dialog = getDialog();
if (dialog != null) {
dialog.hide();
}
}
@Nullable
public MapActivity getMapActivity() {
Activity activity = getActivity();
if (activity instanceof MapActivity) {
return (MapActivity) activity;
}
return null;
}
@Override
protected boolean hideButtonsContainer() {
return true;
}
}

View file

@ -61,6 +61,8 @@ import java.util.Map;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.ALTITUDE;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SLOPE;
import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SPEED;
import static net.osmand.plus.myplaces.GPXTabItemType.GPX_TAB_ITEM_ALTITUDE;
import static net.osmand.plus.myplaces.GPXTabItemType.GPX_TAB_ITEM_SPEED;
public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvider, ViewAtPositionInterface {
@ -79,18 +81,21 @@ public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvid
private boolean chartClicked;
private boolean nightMode;
private boolean onlyGraphs;
public GPXItemPagerAdapter(@NonNull OsmandApplication app,
@NonNull GpxDisplayItem gpxItem,
@NonNull TrackDisplayHelper displayHelper,
boolean nightMode, @NonNull SegmentActionsListener actionsListener) {
boolean nightMode,
@NonNull SegmentActionsListener actionsListener,
boolean onlyGraphs) {
super();
this.app = app;
this.gpxItem = gpxItem;
this.nightMode = nightMode;
this.displayHelper = displayHelper;
this.actionsListener = actionsListener;
this.onlyGraphs = onlyGraphs;
iconsCache = app.getUIUtilities();
fetchTabTypes();
}
@ -100,10 +105,10 @@ public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvid
tabTypeList.add(GPXTabItemType.GPX_TAB_ITEM_GENERAL);
if (gpxItem != null && gpxItem.analysis != null) {
if (gpxItem.analysis.hasElevationData) {
tabTypeList.add(GPXTabItemType.GPX_TAB_ITEM_ALTITUDE);
tabTypeList.add(GPX_TAB_ITEM_ALTITUDE);
}
if (gpxItem.analysis.isSpeedSpecified()) {
tabTypeList.add(GPXTabItemType.GPX_TAB_ITEM_SPEED);
tabTypeList.add(GPX_TAB_ITEM_SPEED);
}
}
tabTypes = tabTypeList.toArray(new GPXTabItemType[0]);
@ -217,72 +222,87 @@ public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvid
private View getViewForTab(@NonNull ViewGroup container, @NonNull GPXTabItemType tabType) {
LayoutInflater inflater = LayoutInflater.from(container.getContext());
switch (tabType) {
case GPX_TAB_ITEM_ALTITUDE:
return inflater.inflate(R.layout.gpx_item_altitude, container, false);
case GPX_TAB_ITEM_SPEED:
return inflater.inflate(R.layout.gpx_item_speed, container, false);
case GPX_TAB_ITEM_GENERAL:
default:
return inflater.inflate(R.layout.gpx_item_general, container, false);
int layoutResId;
if (tabType == GPX_TAB_ITEM_ALTITUDE) {
layoutResId = R.layout.gpx_item_altitude;
} else if (tabType == GPX_TAB_ITEM_SPEED) {
layoutResId = R.layout.gpx_item_speed;
} else {
layoutResId = R.layout.gpx_item_general;
}
View view = inflater.inflate(layoutResId, container, false);
if (onlyGraphs) {
AndroidUiHelper.setVisibility(View.GONE,
view.findViewById(R.id.gpx_join_gaps_container),
view.findViewById(R.id.top_line_blocks),
view.findViewById(R.id.list_divider),
view.findViewById(R.id.bottom_line_blocks),
view.findViewById(R.id.details_divider),
view.findViewById(R.id.details_view)
);
}
return view;
}
private void setupSpeedTab(View view, LineChart chart, GPXTrackAnalysis analysis, GPXFile gpxFile, int position) {
if (analysis != null && analysis.isSpeedSpecified()) {
if (analysis.hasSpeedData) {
GpxUiHelper.setupGPXChart(app, chart, 4);
chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_SPEED, SPEED, null)));
chart.setData(new LineData(getDataSets(chart, GPX_TAB_ITEM_SPEED, SPEED, null)));
updateChart(chart);
chart.setVisibility(View.VISIBLE);
} else {
chart.setVisibility(View.GONE);
}
((ImageView) view.findViewById(R.id.average_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_speed));
((ImageView) view.findViewById(R.id.max_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_max_speed));
((ImageView) view.findViewById(R.id.time_moving_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_span));
((ImageView) view.findViewById(R.id.distance_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_polygom_dark));
if (!onlyGraphs) {
((ImageView) view.findViewById(R.id.average_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_speed));
((ImageView) view.findViewById(R.id.max_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_max_speed));
((ImageView) view.findViewById(R.id.time_moving_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_span));
((ImageView) view.findViewById(R.id.distance_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_polygom_dark));
String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app);
String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app);
String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app);
String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app);
((TextView) view.findViewById(R.id.average_text)).setText(avg);
((TextView) view.findViewById(R.id.max_text)).setText(max);
((TextView) view.findViewById(R.id.average_text)).setText(avg);
((TextView) view.findViewById(R.id.max_text)).setText(max);
view.findViewById(R.id.gpx_join_gaps_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (displayHelper.setJoinSegments(!displayHelper.isJoinSegments())) {
actionsListener.updateContent();
for (int i = 0; i < getCount(); i++) {
View view = getViewAtPosition(i);
updateJoinGapsInfo(view, i);
view.findViewById(R.id.gpx_join_gaps_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (displayHelper.setJoinSegments(!displayHelper.isJoinSegments())) {
actionsListener.updateContent();
for (int i = 0; i < getCount(); i++) {
View view = getViewAtPosition(i);
updateJoinGapsInfo(view, i);
}
}
}
}
});
});
}
} else {
chart.setVisibility(View.GONE);
view.findViewById(R.id.average_max).setVisibility(View.GONE);
view.findViewById(R.id.top_line_blocks).setVisibility(View.GONE);
view.findViewById(R.id.list_divider).setVisibility(View.GONE);
view.findViewById(R.id.time_distance).setVisibility(View.GONE);
view.findViewById(R.id.bottom_line_blocks).setVisibility(View.GONE);
}
updateJoinGapsInfo(view, position);
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openAnalyzeOnMap(GPXTabItemType.GPX_TAB_ITEM_SPEED);
if (!onlyGraphs) {
updateJoinGapsInfo(view, position);
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openAnalyzeOnMap(GPX_TAB_ITEM_SPEED);
}
});
TextView overflowMenu = view.findViewById(R.id.overflow_menu);
if (!gpxItem.group.getTrack().generalTrack) {
setupOptionsPopupMenu(overflowMenu, false);
} else {
overflowMenu.setVisibility(View.GONE);
}
});
TextView overflowMenu = view.findViewById(R.id.overflow_menu);
if (!gpxItem.group.getTrack().generalTrack) {
setupOptionsPopupMenu(overflowMenu, false);
} else {
overflowMenu.setVisibility(View.GONE);
}
}
@ -300,62 +320,66 @@ public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvid
if (analysis != null) {
if (analysis.hasElevationData) {
GpxUiHelper.setupGPXChart(app, chart, 4);
chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_ALTITUDE, ALTITUDE, SLOPE)));
chart.setData(new LineData(getDataSets(chart, GPX_TAB_ITEM_ALTITUDE, ALTITUDE, SLOPE)));
updateChart(chart);
chart.setVisibility(View.VISIBLE);
} else {
chart.setVisibility(View.GONE);
}
((ImageView) view.findViewById(R.id.average_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_altitude_average));
((ImageView) view.findViewById(R.id.range_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_altitude_average));
((ImageView) view.findViewById(R.id.ascent_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_altitude_ascent));
((ImageView) view.findViewById(R.id.descent_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_altitude_descent));
if (!onlyGraphs) {
((ImageView) view.findViewById(R.id.average_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_altitude_average));
((ImageView) view.findViewById(R.id.range_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_altitude_average));
((ImageView) view.findViewById(R.id.ascent_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_altitude_ascent));
((ImageView) view.findViewById(R.id.descent_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_altitude_descent));
String min = OsmAndFormatter.getFormattedAlt(analysis.minElevation, app);
String max = OsmAndFormatter.getFormattedAlt(analysis.maxElevation, app);
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
String min = OsmAndFormatter.getFormattedAlt(analysis.minElevation, app);
String max = OsmAndFormatter.getFormattedAlt(analysis.maxElevation, app);
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
((TextView) view.findViewById(R.id.average_text))
.setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
((TextView) view.findViewById(R.id.range_text)).setText(String.format("%s - %s", min, max));
((TextView) view.findViewById(R.id.ascent_text)).setText(asc);
((TextView) view.findViewById(R.id.descent_text)).setText(desc);
((TextView) view.findViewById(R.id.average_text))
.setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
((TextView) view.findViewById(R.id.range_text)).setText(String.format("%s - %s", min, max));
((TextView) view.findViewById(R.id.ascent_text)).setText(asc);
((TextView) view.findViewById(R.id.descent_text)).setText(desc);
view.findViewById(R.id.gpx_join_gaps_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (displayHelper.setJoinSegments(!displayHelper.isJoinSegments())) {
actionsListener.updateContent();
for (int i = 0; i < getCount(); i++) {
View view = getViewAtPosition(i);
updateJoinGapsInfo(view, i);
view.findViewById(R.id.gpx_join_gaps_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (displayHelper.setJoinSegments(!displayHelper.isJoinSegments())) {
actionsListener.updateContent();
for (int i = 0; i < getCount(); i++) {
View view = getViewAtPosition(i);
updateJoinGapsInfo(view, i);
}
}
}
}
});
});
}
} else {
chart.setVisibility(View.GONE);
view.findViewById(R.id.average_range).setVisibility(View.GONE);
view.findViewById(R.id.top_line_blocks).setVisibility(View.GONE);
view.findViewById(R.id.list_divider).setVisibility(View.GONE);
view.findViewById(R.id.ascent_descent).setVisibility(View.GONE);
view.findViewById(R.id.bottom_line_blocks).setVisibility(View.GONE);
}
updateJoinGapsInfo(view, position);
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openAnalyzeOnMap(GPXTabItemType.GPX_TAB_ITEM_ALTITUDE);
if (!onlyGraphs) {
updateJoinGapsInfo(view, position);
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openAnalyzeOnMap(GPX_TAB_ITEM_ALTITUDE);
}
});
TextView overflowMenu = view.findViewById(R.id.overflow_menu);
if (!gpxItem.group.getTrack().generalTrack) {
setupOptionsPopupMenu(overflowMenu, false);
} else {
overflowMenu.setVisibility(View.GONE);
}
});
TextView overflowMenu = view.findViewById(R.id.overflow_menu);
if (!gpxItem.group.getTrack().generalTrack) {
setupOptionsPopupMenu(overflowMenu, false);
} else {
overflowMenu.setVisibility(View.GONE);
}
}
@ -369,60 +393,63 @@ public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvid
} else {
chart.setVisibility(View.GONE);
}
if (!onlyGraphs) {
((ImageView) view.findViewById(R.id.distance_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_polygom_dark));
((ImageView) view.findViewById(R.id.duration_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_span));
((ImageView) view.findViewById(R.id.start_time_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_start));
((ImageView) view.findViewById(R.id.end_time_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_end));
((ImageView) view.findViewById(R.id.distance_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_polygom_dark));
((ImageView) view.findViewById(R.id.duration_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_span));
((ImageView) view.findViewById(R.id.start_time_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_start));
((ImageView) view.findViewById(R.id.end_time_icon))
.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_time_end));
view.findViewById(R.id.gpx_join_gaps_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (displayHelper.setJoinSegments(!displayHelper.isJoinSegments())) {
actionsListener.updateContent();
for (int i = 0; i < getCount(); i++) {
View view = getViewAtPosition(i);
updateJoinGapsInfo(view, i);
view.findViewById(R.id.gpx_join_gaps_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (displayHelper.setJoinSegments(!displayHelper.isJoinSegments())) {
actionsListener.updateContent();
for (int i = 0; i < getCount(); i++) {
View view = getViewAtPosition(i);
updateJoinGapsInfo(view, i);
}
}
}
}
});
if (analysis.timeSpan > 0) {
DateFormat tf = SimpleDateFormat.getTimeInstance(DateFormat.SHORT);
DateFormat df = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM);
});
if (analysis.timeSpan > 0) {
DateFormat tf = SimpleDateFormat.getTimeInstance(DateFormat.SHORT);
DateFormat df = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM);
Date start = new Date(analysis.startTime);
((TextView) view.findViewById(R.id.start_time_text)).setText(tf.format(start));
((TextView) view.findViewById(R.id.start_date_text)).setText(df.format(start));
Date end = new Date(analysis.endTime);
((TextView) view.findViewById(R.id.end_time_text)).setText(tf.format(end));
((TextView) view.findViewById(R.id.end_date_text)).setText(df.format(end));
} else {
view.findViewById(R.id.list_divider).setVisibility(View.GONE);
view.findViewById(R.id.start_end_time).setVisibility(View.GONE);
Date start = new Date(analysis.startTime);
((TextView) view.findViewById(R.id.start_time_text)).setText(tf.format(start));
((TextView) view.findViewById(R.id.start_date_text)).setText(df.format(start));
Date end = new Date(analysis.endTime);
((TextView) view.findViewById(R.id.end_time_text)).setText(tf.format(end));
((TextView) view.findViewById(R.id.end_date_text)).setText(df.format(end));
} else {
view.findViewById(R.id.list_divider).setVisibility(View.GONE);
view.findViewById(R.id.bottom_line_blocks).setVisibility(View.GONE);
}
}
} else {
chart.setVisibility(View.GONE);
view.findViewById(R.id.distance_time_span).setVisibility(View.GONE);
view.findViewById(R.id.top_line_blocks).setVisibility(View.GONE);
view.findViewById(R.id.list_divider).setVisibility(View.GONE);
view.findViewById(R.id.start_end_time).setVisibility(View.GONE);
view.findViewById(R.id.bottom_line_blocks).setVisibility(View.GONE);
}
updateJoinGapsInfo(view, position);
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openAnalyzeOnMap(GPXTabItemType.GPX_TAB_ITEM_GENERAL);
if (!onlyGraphs) {
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openAnalyzeOnMap(GPXTabItemType.GPX_TAB_ITEM_GENERAL);
}
});
TextView overflowMenu = view.findViewById(R.id.overflow_menu);
if (!gpxItem.group.getTrack().generalTrack) {
setupOptionsPopupMenu(overflowMenu, true);
} else {
overflowMenu.setVisibility(View.GONE);
}
});
TextView overflowMenu = view.findViewById(R.id.overflow_menu);
if (!gpxItem.group.getTrack().generalTrack) {
setupOptionsPopupMenu(overflowMenu, true);
} else {
overflowMenu.setVisibility(View.GONE);
}
}
@ -598,7 +625,7 @@ public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvid
@Override
public void tabStylesUpdated(View tabsContainer, int currentPosition) {
ViewGroup.MarginLayoutParams params = (MarginLayoutParams) tabsContainer.getLayoutParams();
params.height = app.getResources().getDimensionPixelSize(R.dimen.dialog_button_height);
params.height = app.getResources().getDimensionPixelSize(!onlyGraphs ? R.dimen.dialog_button_height : R.dimen.context_menu_buttons_bottom_height);
tabsContainer.setLayoutParams(params);
UiUtilities.updateCustomRadioButtons(app, tabsContainer, nightMode, getCustomRadioButtonType(currentPosition));
}
@ -645,7 +672,7 @@ public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvid
((TextView) view.findViewById(R.id.distance_text)).setText(OsmAndFormatter.getFormattedDistance(totalDistance, app));
((TextView) view.findViewById(R.id.duration_text)).setText(Algorithms.formatDuration((int) (timeSpan / 1000), app.accessibilityEnabled()));
} else if (tabType.equals(GPXTabItemType.GPX_TAB_ITEM_SPEED)) {
} else if (tabType.equals(GPX_TAB_ITEM_SPEED)) {
long timeMoving = !joinSegments && gpxItem.isGeneralTrack() ? analysis.timeMovingWithoutGaps : analysis.timeMoving;
float totalDistanceMoving = !joinSegments && gpxItem.isGeneralTrack() ? analysis.totalDistanceMovingWithoutGaps : analysis.totalDistanceMoving;

View file

@ -55,7 +55,7 @@ public class SegmentGPXAdapter extends ArrayAdapter<GpxDisplayItem> {
WrapContentHeightViewPager pager = row.findViewById(R.id.pager);
PagerSlidingTabStrip tabLayout = row.findViewById(R.id.sliding_tabs);
pager.setAdapter(new GPXItemPagerAdapter(app, item, displayHelper, nightMode, listener));
pager.setAdapter(new GPXItemPagerAdapter(app, item, displayHelper, nightMode, listener, false));
if (create) {
tabLayout.setViewPager(pager);
} else {

View file

@ -102,9 +102,7 @@ public class MapStyleAction extends SwitchableAction<String> {
@Override
public String getTranslatedItemName(Context context, String item) {
String translation = RendererRegistry.getTranslatedRendererName(context, item);
return translation != null ? translation
: item.replace('_', ' ').replace('-', ' ');
return RendererRegistry.getRendererName(context, item);
}
public List<String> getFilteredStyles() {
@ -175,9 +173,8 @@ public class MapStyleAction extends SwitchableAction<String> {
List<String> visibleNamesList = new ArrayList<>();
final List<String> items = new ArrayList<>(renderers.keySet());
for (String item : items) {
String translation = RendererRegistry.getTranslatedRendererName(activity, item);
visibleNamesList.add(translation != null ? translation
: item.replace('_', ' ').replace('-', ' '));
String name = RendererRegistry.getRendererName(activity, item);
visibleNamesList.add(name);
}
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(themedContext, R.layout.dialog_text_item);

View file

@ -289,6 +289,20 @@ public class RendererRegistry {
return renderers;
}
public String getSelectedRendererName() {
RenderingRulesStorage storage = getCurrentSelectedRenderer();
if (storage == null) {
return "";
}
return RendererRegistry.getRendererName(app, storage.getName());
}
public static String getRendererName(@NonNull Context ctx, @NonNull String name) {
String translation = getTranslatedRendererName(ctx, name);
return translation != null ? translation :
name.replace('_', ' ').replace('-', ' ');
}
@Nullable
public static String getTranslatedRendererName(@NonNull Context ctx, @NonNull String key) {
switch (key) {

View file

@ -57,8 +57,8 @@ import net.osmand.plus.routepreparationmenu.cards.ReverseTrackCard;
import net.osmand.plus.routepreparationmenu.cards.SelectTrackCard;
import net.osmand.plus.routepreparationmenu.cards.TrackEditCard;
import net.osmand.plus.routepreparationmenu.cards.TracksToFollowCard;
import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.routing.GPXRouteParams.GPXRouteParamsBuilder;
import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.routing.RouteService;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.settings.backend.ApplicationMode;
@ -446,8 +446,11 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
if (mapActivity != null) {
if (card instanceof ImportTrackCard) {
importTrack();
} else if (card instanceof TrackEditCard || card instanceof AttachTrackToRoadsCard) {
openPlanRoute();
} else if (card instanceof AttachTrackToRoadsCard) {
openPlanRoute(true);
close();
} else if (card instanceof TrackEditCard) {
openPlanRoute(false);
close();
} else if (card instanceof SelectTrackCard) {
updateSelectionMode(true);
@ -574,7 +577,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
}
}
public void openPlanRoute() {
public void openPlanRoute(boolean showSnapWarning) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null && gpxFile != null) {
editingTrack = true;
@ -583,7 +586,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
editingContext.setGpxData(gpxData);
editingContext.setAppMode(app.getRoutingHelper().getAppMode());
editingContext.setSelectedSegment(app.getSettings().GPX_ROUTE_SEGMENT.get());
MeasurementToolFragment.showInstance(mapActivity.getSupportFragmentManager(), editingContext, true);
MeasurementToolFragment.showInstance(mapActivity.getSupportFragmentManager(), editingContext, true, showSnapWarning);
}
}

View file

@ -12,9 +12,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@ -107,7 +105,7 @@ public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment {
private final Class<? extends LocalRoutingParameter>[] excludeParameters;
@SafeVarargs
DialogMode(Class<? extends LocalRoutingParameter> ... excludeParameters) {
DialogMode(Class<? extends LocalRoutingParameter>... excludeParameters) {
this.excludeParameters = excludeParameters;
}
@ -556,7 +554,7 @@ public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment {
Bundle args = new Bundle();
args.putString(DIALOG_MODE_KEY, dialogMode.name());
BaseSettingsFragment.showInstance(mapActivity,
SettingsScreenType.NAVIGATION, applicationMode, args);
SettingsScreenType.NAVIGATION, applicationMode, args, null);
}
})
.create();
@ -695,9 +693,9 @@ public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment {
}
public static void showInstance(MapActivity mapActivity,
Fragment targetFragment,
DialogMode dialogMode,
String appModeKey) {
Fragment targetFragment,
DialogMode dialogMode,
String appModeKey) {
try {
FragmentManager fm = mapActivity.getSupportFragmentManager();
if (!fm.isStateSaved()) {

View file

@ -0,0 +1,156 @@
package net.osmand.plus.routing;
import android.os.Bundle;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.util.Algorithms;
public class RouteLineDrawInfo {
private static final String LINE_COLOR = "line_color";
private static final String LINE_WIDTH = "line_width";
private static final String NAVIGATION_ICON_ID = "navigation_icon_id";
private static final String NAVIGATION_ICON_COLOR = "navigation_icon_color";
private static final String CENTER_X = "center_x";
private static final String CENTER_Y = "center_y";
private static final String SCREEN_HEIGHT = "screen_height";
// parameters to save
@ColorInt
private Integer color;
private String width;
// temporally parameters to show in preview
@ColorInt
private int iconColor;
private int iconId;
private int centerX;
private int centerY;
private int screenHeight;
public RouteLineDrawInfo(@Nullable @ColorInt Integer color,
@Nullable String width) {
this.color = color;
this.width = width;
}
public RouteLineDrawInfo(@NonNull Bundle bundle) {
readBundle(bundle);
}
public RouteLineDrawInfo(@NonNull RouteLineDrawInfo existed) {
this.color = existed.color;
this.width = existed.width;
this.iconId = existed.iconId;
this.iconColor = existed.iconColor;
this.centerX = existed.centerX;
this.centerY = existed.centerY;
this.screenHeight = existed.screenHeight;
}
public void setColor(@Nullable Integer color) {
this.color = color;
}
public void setWidth(@Nullable String width) {
this.width = width;
}
public void setIconId(int iconId) {
this.iconId = iconId;
}
public void setIconColor(int iconColor) {
this.iconColor = iconColor;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setScreenHeight(int screenHeight) {
this.screenHeight = screenHeight;
}
@Nullable
public Integer getColor() {
return color;
}
@Nullable
public String getWidth() {
return width;
}
public int getIconId() {
return iconId;
}
@ColorInt
public int getIconColor() {
return iconColor;
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public int getScreenHeight() {
return screenHeight;
}
private void readBundle(@NonNull Bundle bundle) {
if (bundle.containsKey(LINE_COLOR)) {
color = bundle.getInt(LINE_COLOR);
}
width = bundle.getString(LINE_WIDTH);
iconId = bundle.getInt(NAVIGATION_ICON_ID);
iconColor = bundle.getInt(NAVIGATION_ICON_COLOR);
centerX = bundle.getInt(CENTER_X);
centerY = bundle.getInt(CENTER_Y);
screenHeight = bundle.getInt(SCREEN_HEIGHT);
}
public void saveToBundle(@NonNull Bundle bundle) {
if (color != null) {
bundle.putInt(LINE_COLOR, color);
}
if (width != null) {
bundle.putString(LINE_WIDTH, width);
}
bundle.putInt(NAVIGATION_ICON_ID, iconId);
bundle.putInt(NAVIGATION_ICON_COLOR, iconColor);
bundle.putInt(CENTER_X, centerX);
bundle.putInt(CENTER_Y, centerY);
bundle.putInt(SCREEN_HEIGHT, screenHeight);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RouteLineDrawInfo)) return false;
RouteLineDrawInfo that = (RouteLineDrawInfo) o;
if (!Algorithms.objectEquals(getColor(), that.getColor())) return false;
return Algorithms.objectEquals(getWidth(), that.getWidth());
}
@Override
public int hashCode() {
int result = color != null ? color.hashCode() : 0;
result = 31 * result + (width != null ? width.hashCode() : 0);
return result;
}
}

View file

@ -55,6 +55,8 @@ public class TransportRoutingHelper {
private static final org.apache.commons.logging.Log log = PlatformUtil.getLog(TransportRoutingHelper.class);
public static final String PUBLIC_TRANSPORT_KEY = "public_transport";
private List<WeakReference<IRouteInformationListener>> listeners = new LinkedList<>();
private final OsmandApplication app;

View file

@ -0,0 +1,332 @@
package net.osmand.plus.routing.cards;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.ColorDialogs;
import net.osmand.plus.helpers.enums.DayNightMode;
import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
import net.osmand.plus.routing.RouteLineDrawInfo;
import net.osmand.plus.settings.backend.ListStringPreference;
import net.osmand.plus.track.AppearanceViewHolder;
import net.osmand.plus.track.ColorsCard;
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
import net.osmand.plus.widgets.MultiStateToggleButton;
import net.osmand.plus.widgets.MultiStateToggleButton.OnRadioItemClickListener;
import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class RouteLineColorCard extends BaseCard implements CardListener, ColorPickerListener {
private static final int DAY_TITLE_ID = R.string.day;
private static final int NIGHT_TITLE_ID = R.string.night;
private final Fragment targetFragment;
private ColorsCard colorsCard;
private ColorTypeAdapter colorAdapter;
private RecyclerView groupRecyclerView;
private TextView tvColorName;
private TextView tvDescription;
private View themeToggleContainer;
private ViewGroup cardsContainer;
private ColorMode selectedMode;
private RouteLineDrawInfo routeLineDrawInfo;
private DayNightMode initMapTheme;
private DayNightMode selectedMapTheme;
private enum ColorMode {
DEFAULT(R.string.map_widget_renderer, R.drawable.ic_action_map_style),
CUSTOM(R.string.shared_string_custom, R.drawable.ic_action_settings);
ColorMode(int titleId, int iconId) {
this.titleId = titleId;
this.iconId = iconId;
}
int titleId;
int iconId;
}
public RouteLineColorCard(@NonNull MapActivity mapActivity,
@NonNull Fragment targetFragment,
@NonNull RouteLineDrawInfo routeLineDrawInfo,
@NonNull DayNightMode initMapTheme,
@NonNull DayNightMode selectedMapTheme) {
super(mapActivity);
this.targetFragment = targetFragment;
this.routeLineDrawInfo = routeLineDrawInfo;
this.initMapTheme = initMapTheme;
this.selectedMapTheme = selectedMapTheme;
}
@Override
public int getCardLayoutId() {
return R.layout.route_line_color_card;
}
@Override
protected void updateContent() {
tvColorName = view.findViewById(R.id.color_name);
tvDescription = view.findViewById(R.id.description);
colorAdapter = new ColorTypeAdapter();
groupRecyclerView = view.findViewById(R.id.recycler_view);
groupRecyclerView.setAdapter(colorAdapter);
groupRecyclerView.setLayoutManager(new LinearLayoutManager(app, RecyclerView.HORIZONTAL, false));
themeToggleContainer = view.findViewById(R.id.theme_toggle_container);
LinearLayout radioGroup = (LinearLayout) view.findViewById(R.id.custom_radio_buttons);
setupRadioGroup(radioGroup);
cardsContainer = (ViewGroup) view.findViewById(R.id.colors_card_container);
createColorSelector(cardsContainer);
initSelectedMode();
}
private void initSelectedMode() {
selectedMode = routeLineDrawInfo.getColor() == null ? ColorMode.DEFAULT : ColorMode.CUSTOM;
modeChanged();
}
private void modeChanged() {
if (selectedMode == ColorMode.DEFAULT) {
themeToggleContainer.setVisibility(View.GONE);
cardsContainer.setVisibility(View.GONE);
changeMapTheme(initMapTheme);
} else {
themeToggleContainer.setVisibility(View.VISIBLE);
cardsContainer.setVisibility(View.VISIBLE);
changeMapTheme(isNightMap() ? DayNightMode.NIGHT : DayNightMode.DAY);
}
updateSelectedColor();
updateDescription();
}
private void setupRadioGroup(LinearLayout buttonsContainer) {
RadioItem day = createMapThemeButton(false);
RadioItem night = createMapThemeButton(true);
MultiStateToggleButton radioGroup = new MultiStateToggleButton(app, buttonsContainer, nightMode);
radioGroup.setItems(day, night);
radioGroup.setSelectedItem(!isNightMap() ? day : night);
}
private RadioItem createMapThemeButton(final boolean isNight) {
RadioItem item = new RadioItem(app.getString(!isNight ? DAY_TITLE_ID : NIGHT_TITLE_ID));
item.setOnClickListener(new OnRadioItemClickListener() {
@Override
public boolean onRadioItemClick(RadioItem radioItem, View view) {
selectedMapTheme = isNight ? DayNightMode.NIGHT : DayNightMode.DAY;
changeMapTheme(selectedMapTheme);
updateDescription();
return true;
}
});
return item;
}
private void changeMapTheme(DayNightMode mapTheme) {
if (targetFragment instanceof OnMapThemeUpdateListener) {
((OnMapThemeUpdateListener) targetFragment).onMapThemeUpdated(mapTheme);
}
}
private void createColorSelector(ViewGroup container) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
List<Integer> colors = new ArrayList<>();
for (int color : ColorDialogs.pallette) {
colors.add(color);
}
Integer selectedColor = routeLineDrawInfo.getColor();
if (selectedColor != null) {
if (!ColorDialogs.isPaletteColor(selectedColor)) {
colors.add(selectedColor);
}
} else {
selectedColor = colors.get(0);
}
ListStringPreference preference = app.getSettings().CUSTOM_ROUTE_LINE_COLORS;
colorsCard = new ColorsCard(mapActivity, selectedColor, targetFragment, colors, preference, null);
colorsCard.setListener(this);
container.addView(colorsCard.build(mapActivity));
}
}
@Override
public void onColorSelected(Integer prevColor, int newColor) {
colorsCard.onColorSelected(prevColor, newColor);
updateSelectedColor();
}
private void updateSelectedColor() {
Integer color = selectedMode == ColorMode.CUSTOM ? colorsCard.getSelectedColor() : null;
routeLineDrawInfo.setColor(color);
updateColorName();
if (targetFragment instanceof OnSelectedColorChangeListener) {
((OnSelectedColorChangeListener) targetFragment).onSelectedColorChanged();
}
}
private void updateColorName() {
if (selectedMode == ColorMode.DEFAULT) {
tvColorName.setText(app.getString(R.string.map_widget_renderer));
} else if (routeLineDrawInfo.getColor() != null) {
int colorNameId = ColorDialogs.getColorName(routeLineDrawInfo.getColor());
tvColorName.setText(app.getString(colorNameId));
}
}
private void updateDescription() {
String description;
if (selectedMode == ColorMode.DEFAULT) {
String pattern = app.getString(R.string.route_line_use_map_style_appearance);
String color = app.getString(R.string.shared_string_color).toLowerCase();
description = String.format(pattern, color, app.getRendererRegistry().getSelectedRendererName());
} else {
String pattern = app.getString(R.string.specify_color_for_map_mode);
String mapModeTitle = app.getString(isNightMap() ? NIGHT_TITLE_ID : DAY_TITLE_ID);
description = String.format(pattern, mapModeTitle.toLowerCase());
}
tvDescription.setText(description);
}
private boolean isNightMap() {
return selectedMapTheme.isNight();
}
@Override
public void onCardLayoutNeeded(@NonNull BaseCard card) {
}
@Override
public void onCardPressed(@NonNull BaseCard card) {
if (card instanceof ColorsCard) {
updateSelectedColor();
}
}
@Override
public void onCardButtonPressed(@NonNull BaseCard card, int buttonIndex) {
}
private class ColorTypeAdapter extends RecyclerView.Adapter<AppearanceViewHolder> {
private List<ColorMode> items = Arrays.asList(ColorMode.values());
@NonNull
@Override
public AppearanceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater themedInflater = UiUtilities.getInflater(parent.getContext(), nightMode);
View view = themedInflater.inflate(R.layout.point_editor_group_select_item, parent, false);
view.getLayoutParams().width = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_width);
view.getLayoutParams().height = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_height);
AppearanceViewHolder holder = new AppearanceViewHolder(view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, holder.button, nightMode, R.drawable.ripple_solid_light_6dp,
R.drawable.ripple_solid_dark_6dp);
}
return holder;
}
@Override
public void onBindViewHolder(@NonNull final AppearanceViewHolder holder, int position) {
ColorMode item = items.get(position);
holder.title.setText(app.getString(item.titleId));
updateButtonBg(holder, item);
updateTextAndIconColor(holder, item);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
selectedMode = items.get(holder.getAdapterPosition());
notifyItemRangeChanged(0, getItemCount());
modeChanged();
CardListener listener = getListener();
if (listener != null) {
listener.onCardPressed(RouteLineColorCard.this);
}
}
});
}
private void updateButtonBg(AppearanceViewHolder holder, ColorMode item) {
GradientDrawable rectContourDrawable = (GradientDrawable) AppCompatResources.getDrawable(app, R.drawable.bg_select_group_button_outline);
if (rectContourDrawable != null) {
if (selectedMode == item) {
int strokeColor = ContextCompat.getColor(app, nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light);
rectContourDrawable.setStroke(AndroidUtils.dpToPx(app, 2), strokeColor);
} else {
int strokeColor = ContextCompat.getColor(app, nightMode ?
R.color.stroked_buttons_and_links_outline_dark :
R.color.stroked_buttons_and_links_outline_light);
rectContourDrawable.setStroke(AndroidUtils.dpToPx(app, 1), strokeColor);
}
holder.button.setImageDrawable(rectContourDrawable);
}
}
private void updateTextAndIconColor(AppearanceViewHolder holder, ColorMode item) {
Context ctx = holder.itemView.getContext();
int iconColorId;
int textColorId;
if (selectedMode == item) {
iconColorId = AndroidUtils.getColorFromAttr(ctx, R.attr.default_icon_color);
textColorId = AndroidUtils.getColorFromAttr(ctx, android.R.attr.textColor);
} else {
iconColorId = AndroidUtils.getColorFromAttr(ctx, R.attr.colorPrimary);
textColorId = iconColorId;
}
holder.icon.setImageDrawable(app.getUIUtilities().getPaintedIcon(item.iconId, iconColorId));
holder.title.setTextColor(textColorId);
}
@Override
public int getItemCount() {
return items.size();
}
}
public interface OnSelectedColorChangeListener {
void onSelectedColorChanged();
}
public interface OnMapThemeUpdateListener {
void onMapThemeUpdated(@NonNull DayNightMode mapTheme);
}
}

View file

@ -0,0 +1,305 @@
package net.osmand.plus.routing.cards;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.github.ksoichiro.android.observablescrollview.ScrollUtils;
import com.google.android.material.slider.Slider;
import net.osmand.AndroidUtils;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routing.RouteLineDrawInfo;
import net.osmand.plus.track.AppearanceViewHolder;
import net.osmand.plus.track.TrackAppearanceFragment.OnNeedScrollListener;
import net.osmand.util.Algorithms;
import java.util.Arrays;
import java.util.List;
public class RouteLineWidthCard extends BaseCard {
private final static int CUSTOM_WIDTH_MIN = 1;
private final static int CUSTOM_WIDTH_MAX = 24;
private RouteLineDrawInfo routeLineDrawInfo;
private OnNeedScrollListener onNeedScrollListener;
private WidthMode selectedMode;
private WidthAdapter widthAdapter;
private View sliderContainer;
private RecyclerView groupRecyclerView;
private TextView tvModeType;
private TextView tvDescription;
private enum WidthMode {
DEFAULT(R.string.map_widget_renderer, R.drawable.ic_action_map_style, null),
THIN(R.string.rendering_value_thin_name, R.drawable.ic_action_track_line_thin_color, "thin"),
MEDIUM(R.string.rendering_value_medium_name, R.drawable.ic_action_track_line_medium_color, "medium"),
THICK(R.string.rendering_value_bold_name, R.drawable.ic_action_track_line_bold_color, "bold"),
CUSTOM(R.string.shared_string_custom, R.drawable.ic_action_settings, null);
WidthMode(int titleId, int iconId, String widthKey) {
this.titleId = titleId;
this.iconId = iconId;
this.widthKey = widthKey;
}
int titleId;
int iconId;
String widthKey;
}
public RouteLineWidthCard(@NonNull MapActivity mapActivity,
@NonNull RouteLineDrawInfo routeLineDrawInfo,
@NonNull OnNeedScrollListener onNeedScrollListener) {
super(mapActivity);
this.routeLineDrawInfo = routeLineDrawInfo;
this.onNeedScrollListener = onNeedScrollListener;
}
@Override
public int getCardLayoutId() {
return R.layout.route_line_width_card;
}
@Override
protected void updateContent() {
widthAdapter = new WidthAdapter();
groupRecyclerView = view.findViewById(R.id.recycler_view);
groupRecyclerView.setAdapter(widthAdapter);
groupRecyclerView.setLayoutManager(new LinearLayoutManager(app, RecyclerView.HORIZONTAL, false));
tvModeType = view.findViewById(R.id.width_type);
tvDescription = view.findViewById(R.id.description);
sliderContainer = view.findViewById(R.id.slider_container);
AndroidUiHelper.updateVisibility(view.findViewById(R.id.top_divider), isShowDivider());
initSelectedMode();
}
private void initSelectedMode() {
selectedMode = findAppropriateMode(getRouteLineWidth());
modeChanged();
}
private void modeChanged() {
updateHeader();
updateDescription();
updateCustomWidthSlider();
scrollMenuToSelectedItem();
}
public void updateItems() {
if (widthAdapter != null) {
widthAdapter.notifyDataSetChanged();
}
}
private void setRouteLineWidth(String widthKey) {
routeLineDrawInfo.setWidth(widthKey);
mapActivity.refreshMap();
}
private String getRouteLineWidth() {
return routeLineDrawInfo.getWidth();
}
private void updateHeader() {
tvModeType.setText(app.getString(selectedMode.titleId));
}
private void updateDescription() {
if (selectedMode == WidthMode.DEFAULT) {
String pattern = app.getString(R.string.route_line_use_map_style_appearance);
String width = app.getString(R.string.shared_string_color).toLowerCase();
String description = String.format(pattern, width, app.getRendererRegistry().getSelectedRendererName());
tvDescription.setText(description);
tvDescription.setVisibility(View.VISIBLE);
} else {
tvDescription.setVisibility(View.GONE);
}
}
private void updateCustomWidthSlider() {
if (selectedMode == WidthMode.CUSTOM) {
Slider slider = view.findViewById(R.id.width_slider);
final TextView tvCustomWidth = view.findViewById(R.id.width_value_tv);
slider.setValueTo(CUSTOM_WIDTH_MAX);
slider.setValueFrom(CUSTOM_WIDTH_MIN);
((TextView) view.findViewById(R.id.width_value_min)).setText(String.valueOf(CUSTOM_WIDTH_MIN));
((TextView) view.findViewById(R.id.width_value_max)).setText(String.valueOf(CUSTOM_WIDTH_MAX));
String widthKey = getRouteLineWidth();
int width = Algorithms.parseIntSilently(widthKey, 1);
widthKey = String.valueOf(width);
setRouteLineWidth(widthKey);
tvCustomWidth.setText(widthKey);
slider.setValue(width);
slider.addOnChangeListener(new Slider.OnChangeListener() {
@Override
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
if (fromUser) {
String newWidth = String.valueOf((int) value);
setRouteLineWidth(newWidth);
tvCustomWidth.setText(newWidth);
}
}
});
UiUtilities.setupSlider(slider, nightMode, null, true);
ScrollUtils.addOnGlobalLayoutListener(sliderContainer, new Runnable() {
@Override
public void run() {
if (sliderContainer.getVisibility() == View.VISIBLE) {
onNeedScrollListener.onVerticalScrollNeeded(sliderContainer.getBottom());
}
}
});
AndroidUiHelper.updateVisibility(sliderContainer, true);
} else {
AndroidUiHelper.updateVisibility(sliderContainer, false);
}
}
private void scrollMenuToSelectedItem() {
int position = widthAdapter.getItemPosition(selectedMode);
if (position != -1) {
groupRecyclerView.scrollToPosition(position);
}
}
private static WidthMode findAppropriateMode(@Nullable String widthKey) {
if (widthKey != null) {
for (WidthMode mode : WidthMode.values()) {
if (mode.widthKey != null && mode.widthKey.equals(widthKey)) {
return mode;
}
}
return WidthMode.CUSTOM;
}
return WidthMode.DEFAULT;
}
private class WidthAdapter extends RecyclerView.Adapter<AppearanceViewHolder> {
private final List<WidthMode> items = Arrays.asList(WidthMode.values());
@NonNull
@Override
public AppearanceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater themedInflater = UiUtilities.getInflater(parent.getContext(), nightMode);
View view = themedInflater.inflate(R.layout.point_editor_group_select_item, parent, false);
view.getLayoutParams().width = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_width);
view.getLayoutParams().height = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_height);
AppearanceViewHolder holder = new AppearanceViewHolder(view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, holder.button, nightMode, R.drawable.ripple_solid_light_6dp,
R.drawable.ripple_solid_dark_6dp);
}
return holder;
}
@Override
public void onBindViewHolder(@NonNull final AppearanceViewHolder holder, int position) {
WidthMode item = items.get(position);
holder.title.setText(app.getString(item.titleId));
updateButtonBg(holder, item);
updateTextAndIconColor(holder, item);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int prevSelectedPosition = getItemPosition(selectedMode);
selectedMode = items.get(holder.getAdapterPosition());
notifyItemChanged(holder.getAdapterPosition());
notifyItemChanged(prevSelectedPosition);
if (selectedMode != WidthMode.CUSTOM) {
setRouteLineWidth(selectedMode.widthKey);
}
modeChanged();
CardListener listener = getListener();
if (listener != null) {
listener.onCardPressed(RouteLineWidthCard.this);
}
}
});
}
private void updateTextAndIconColor(AppearanceViewHolder holder, WidthMode item) {
Context ctx = holder.itemView.getContext();
int iconColor;
int textColorId;
if (selectedMode == item) {
iconColor = getIconColor(item, AndroidUtils.getColorFromAttr(ctx, R.attr.default_icon_color));
textColorId = AndroidUtils.getColorFromAttr(ctx, android.R.attr.textColor);
} else {
iconColor = getIconColor(item, AndroidUtils.getColorFromAttr(ctx, R.attr.colorPrimary));
textColorId = AndroidUtils.getColorFromAttr(ctx, R.attr.colorPrimary);
}
holder.icon.setImageDrawable(app.getUIUtilities().getPaintedIcon(item.iconId, iconColor));
holder.title.setTextColor(textColorId);
}
private int getIconColor(@NonNull WidthMode mode, @ColorInt int defaultColor) {
return mode.widthKey != null ? getRouteLineColor() : defaultColor;
}
private int getRouteLineColor() {
Integer color = routeLineDrawInfo.getColor();
return color != null ? color :
mapActivity.getMapLayers().getRouteLayer().getRouteLineColor(nightMode);
}
private void updateButtonBg(AppearanceViewHolder holder, WidthMode item) {
GradientDrawable rectContourDrawable = (GradientDrawable) AppCompatResources.getDrawable(app, R.drawable.bg_select_group_button_outline);
if (rectContourDrawable != null) {
if (selectedMode == item) {
int strokeColor = ContextCompat.getColor(app, nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light);
rectContourDrawable.setStroke(AndroidUtils.dpToPx(app, 2), strokeColor);
} else {
int strokeColor = ContextCompat.getColor(app, nightMode ?
R.color.stroked_buttons_and_links_outline_dark
: R.color.stroked_buttons_and_links_outline_light);
rectContourDrawable.setStroke(AndroidUtils.dpToPx(app, 1), strokeColor);
}
holder.button.setImageDrawable(rectContourDrawable);
}
}
@Override
public int getItemCount() {
return items.size();
}
int getItemPosition(WidthMode widthMode) {
return items.indexOf(widthMode);
}
}
}

View file

@ -30,7 +30,7 @@ public class EnumStringPreference<E extends Enum<E>> extends CommonPreference<E>
@Override
protected String toString(E o) {
return o.name();
return o == null ? null : o.name();
}
@Override

View file

@ -84,6 +84,7 @@ import java.util.StringTokenizer;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.CONFIGURE_MAP_ITEM_ID_SCHEME;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_ITEM_ID_SCHEME;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_ACTIONS;
import static net.osmand.plus.routing.TransportRoutingHelper.PUBLIC_TRANSPORT_KEY;
public class OsmandSettings {
@ -998,7 +999,7 @@ public class OsmandSettings {
ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.CAR, "car");
ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.BICYCLE, "bicycle");
ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.PEDESTRIAN, "pedestrian");
ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.PUBLIC_TRANSPORT, "public_transport");
ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.PUBLIC_TRANSPORT, PUBLIC_TRANSPORT_KEY);
ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.BOAT, "boat");
ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.AIRCRAFT, "STRAIGHT_LINE_MODE");
ROUTING_PROFILE.setModeDefaultValue(ApplicationMode.SKI, "ski");
@ -1276,6 +1277,7 @@ public class OsmandSettings {
public final CommonPreference<Integer> SAVE_GLOBAL_TRACK_INTERVAL = new IntPreference(this, "save_global_track_interval", 5000).makeProfile().cache();
public final CommonPreference<Boolean> SAVE_GLOBAL_TRACK_REMEMBER = new BooleanPreference(this, "save_global_track_remember", false).makeProfile().cache();
public final CommonPreference<Boolean> SHOW_SAVED_TRACK_REMEMBER = new BooleanPreference(this, "show_saved_track_remember", true).makeGlobal().makeShared();
public final CommonPreference<Boolean> SHOW_TRIP_REC_START_DIALOG = new BooleanPreference(this, "show_trip_recording_start_dialog", true).makeGlobal().makeShared();
// this value string is synchronized with settings_pref.xml preference name
public final CommonPreference<Boolean> SAVE_TRACK_TO_GPX = new BooleanPreference(this, "save_track_to_gpx", false).makeProfile().cache();
@ -2689,6 +2691,9 @@ public class OsmandSettings {
public final CommonPreference<Float> ROUTE_RECALCULATION_DISTANCE = new FloatPreference(this, "routing_recalc_distance", 0.f).makeProfile();
public final CommonPreference<Float> ROUTE_STRAIGHT_ANGLE = new FloatPreference(this, "routing_straight_angle", 30.f).makeProfile();
public final ListStringPreference CUSTOM_ROUTE_LINE_COLORS = (ListStringPreference) new ListStringPreference(this, "custom_route_line_colors", null, ",").makeShared().makeGlobal();
public final CommonPreference<Integer> ROUTE_LINE_COLOR = new IntPreference(this, "route_line_color", 0).makeProfile();
public final CommonPreference<String> ROUTE_LINE_WIDTH = new StringPreference(this, "route_line_width", null).makeProfile();
public final OsmandPreference<Boolean> USE_OSM_LIVE_FOR_ROUTING = new BooleanPreference(this, "enable_osmc_routing", true).makeProfile();

View file

@ -900,11 +900,11 @@ public class SettingsHelper {
List<ITileSource> tileSourceTemplates = new ArrayList<>();
List<File> routingFilesList = new ArrayList<>();
List<File> renderFilesList = new ArrayList<>();
List<File> multimediaFilesList = new ArrayList<>();
List<File> ttsVoiceFilesList = new ArrayList<>();
List<File> voiceFilesList = new ArrayList<>();
List<FileSettingsItem> mapFilesList = new ArrayList<>();
List<FileSettingsItem> tracksFilesList = new ArrayList<>();
List<FileSettingsItem> multimediaFilesList = new ArrayList<>();
List<AvoidRoadInfo> avoidRoads = new ArrayList<>();
List<GlobalSettingsItem> globalSettingsItems = new ArrayList<>();
List<OsmNotesPoint> notesPointList = new ArrayList<>();
@ -927,7 +927,7 @@ public class SettingsHelper {
} else if (fileItem.getSubtype() == FileSubtype.ROUTING_CONFIG) {
routingFilesList.add(fileItem.getFile());
} else if (fileItem.getSubtype() == FileSubtype.MULTIMEDIA_NOTES) {
multimediaFilesList.add(fileItem.getFile());
multimediaFilesList.add(fileItem);
} else if (fileItem.getSubtype() == FileSubtype.GPX) {
tracksFilesList.add(fileItem);
} else if (fileItem.getSubtype().isMap()) {

View file

@ -6,7 +6,6 @@ import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
@ -34,9 +33,8 @@ import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
import org.apache.commons.logging.Log;
import static net.osmand.plus.UiUtilities.CompoundButtonType.TOOLBAR;
import static net.osmand.plus.liveupdates.LiveUpdatesSettingsDialogFragmentNew.getActivePrimaryColorId;
import static net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.getSecondaryIconColorId;
import static net.osmand.plus.monitoring.TripRecordingBottomSheet.getSecondaryIconColorId;
public class BooleanPreferenceBottomSheet extends BasePreferenceBottomSheet {

View file

@ -685,6 +685,11 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl
ContextCompat.getColor(app, nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light);
}
@ColorRes
protected int getActiveColorRes() {
return isNightMode() ? R.color.active_color_primary_dark : R.color.active_color_primary_light;
}
@ColorRes
protected int getBackgroundColorRes() {
return isNightMode() ? R.color.list_background_color_dark : R.color.list_background_color_light;
@ -888,17 +893,18 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl
}
public static boolean showInstance(FragmentActivity activity, SettingsScreenType screenType, @Nullable ApplicationMode appMode) {
return showInstance(activity, screenType, appMode, new Bundle());
return showInstance(activity, screenType, appMode, new Bundle(), null);
}
public static boolean showInstance(FragmentActivity activity, SettingsScreenType screenType,
@Nullable ApplicationMode appMode, @NonNull Bundle args) {
@Nullable ApplicationMode appMode, @NonNull Bundle args, @Nullable Fragment target) {
try {
Fragment fragment = Fragment.instantiate(activity, screenType.fragmentName);
if (appMode != null) {
args.putString(APP_MODE_KEY, appMode.getStringKey());
}
fragment.setArguments(args);
fragment.setTargetFragment(target, 0);
activity.getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, fragment, screenType.fragmentName)
.addToBackStack(DRAWER_SETTINGS_ID + ".new")

View file

@ -6,8 +6,10 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ExpandableListView;
import android.widget.LinearLayout;
import android.widget.ListView;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
@ -18,6 +20,8 @@ import androidx.core.view.ViewCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.github.ksoichiro.android.observablescrollview.ScrollUtils;
import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
@ -129,6 +133,7 @@ public abstract class BaseSettingsListFragment extends BaseOsmAndFragment implem
adapter = new ExportSettingsAdapter(app, exportMode, this, nightMode);
adapter.updateSettingsItems(dataList, selectedItemsMap);
expandableList.setAdapter(adapter);
setupListView(expandableList);
updateAvailableSpace();
return root;
@ -195,6 +200,22 @@ public abstract class BaseSettingsListFragment extends BaseOsmAndFragment implem
});
}
private void setupListView(@NonNull final ListView listView) {
if (listView.getFooterViewsCount() == 0) {
int padding = getResources().getDimensionPixelSize(R.dimen.toolbar_height_expanded);
View emptyView = new View(listView.getContext());
emptyView.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, padding));
listView.addFooterView(emptyView);
ScrollUtils.addOnGlobalLayoutListener(listView, new Runnable() {
@Override
public void run() {
listView.requestLayout();
}
});
}
}
protected void updateAvailableSpace() {
long calculatedSize = ExportSettingsAdapter.calculateItemsSize(adapter.getData());
if (calculatedSize != 0) {

View file

@ -6,6 +6,10 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
@ -15,6 +19,7 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.audionotes.AudioVideoNotesPlugin;
import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording;
import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.helpers.GpxUiHelper;
@ -36,10 +41,6 @@ import org.apache.commons.logging.Log;
import java.io.File;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import static net.osmand.plus.settings.backend.backup.FileSettingsItem.FileSubtype;
public class DuplicatesSettingsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@ -154,6 +155,7 @@ public class DuplicatesSettingsAdapter extends RecyclerView.Adapter<RecyclerView
if (iconId == -1) {
iconId = R.drawable.ic_action_photo_dark;
}
itemHolder.title.setText(new Recording(file).getName(app, true));
itemHolder.icon.setImageDrawable(uiUtilities.getIcon(iconId, activeColorRes));
} else if (fileSubtype.isMap()
|| fileSubtype == FileSubtype.TTS_VOICE

View file

@ -6,6 +6,13 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.IndexConstants;
@ -21,6 +28,7 @@ import net.osmand.plus.R;
import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.audionotes.AudioVideoNotesPlugin;
import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton;
@ -61,13 +69,9 @@ import java.io.File;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.widget.CompoundButtonCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import static net.osmand.plus.audionotes.AudioVideoNotesPlugin.IMG_EXTENSION;
import static net.osmand.plus.audionotes.AudioVideoNotesPlugin.MPEG4_EXTENSION;
import static net.osmand.plus.audionotes.AudioVideoNotesPlugin.THREEGP_EXTENSION;
import static net.osmand.view.ThreeStateCheckbox.State.CHECKED;
import static net.osmand.view.ThreeStateCheckbox.State.MISC;
import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED;
@ -142,15 +146,21 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
selectedItems.remove(item[0].getTag());
}
updateTitleView();
setupBottomSheetItem(item[0], item[0].getTag());
}
})
.setTag(object);
setupBottomSheetItem(builder, object);
item[0] = builder.create();
items.add(item[0]);
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
updateItems();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@ -177,7 +187,7 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
selectedItems.clear();
}
updateTitleView();
updateItems(checked);
updateItems();
}
});
setupDescription(view);
@ -221,10 +231,12 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
return itemsSize;
}
private void updateItems(boolean checked) {
private void updateItems() {
for (BaseBottomSheetItem item : items) {
if (item instanceof BottomSheetItemWithCompoundButton) {
((BottomSheetItemWithCompoundButton) item).setChecked(checked);
if (item instanceof BottomSheetItemWithCompoundButton && item.getTag() != null) {
BottomSheetItemWithCompoundButton bottomSheetItem = (BottomSheetItemWithCompoundButton) item;
setupBottomSheetItem(bottomSheetItem, item.getTag());
bottomSheetItem.setChecked(selectedItems.contains(item.getTag()));
}
}
}
@ -274,7 +286,7 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
return null;
}
private void setupBottomSheetItem(Builder builder, Object object) {
private void setupBottomSheetItem(BottomSheetItemWithCompoundButton item, Object object) {
if (object instanceof ApplicationModeBean) {
ApplicationModeBean modeBean = (ApplicationModeBean) object;
String profileName = modeBean.userProfileName;
@ -286,7 +298,7 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
profileName = StringUtils.capitalize(modeBean.stringKey);
}
}
builder.setTitle(profileName);
item.setTitle(profileName);
String routingProfile = "";
String routingProfileValue = modeBean.routingProfile;
@ -300,122 +312,153 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
}
}
if (!Algorithms.isEmpty(routingProfile)) {
builder.setDescription(getString(R.string.ltr_or_rtl_combine_via_colon, getString(R.string.nav_type_hint), routingProfile));
item.setDescription(getString(R.string.ltr_or_rtl_combine_via_colon, getString(R.string.nav_type_hint), routingProfile));
} else {
builder.setDescription(getString(R.string.profile_type_osmand_string));
item.setDescription(getString(R.string.profile_type_osmand_string));
}
int profileIconRes = AndroidUtils.getDrawableId(app, modeBean.iconName);
ProfileIconColors iconColor = modeBean.iconColor;
Integer customIconColor = modeBean.customIconColor;
int actualIconColor = customIconColor != null ?
customIconColor : ContextCompat.getColor(app, iconColor.getColor(nightMode));
builder.setIcon(uiUtilities.getPaintedIcon(profileIconRes, actualIconColor));
int actualIconColor;
if (selectedItems.contains(object)) {
actualIconColor = customIconColor != null ? customIconColor : ContextCompat.getColor(app, iconColor.getColor(nightMode));
} else {
actualIconColor = ContextCompat.getColor(app, secondaryColorRes);
}
item.setIcon(uiUtilities.getPaintedIcon(profileIconRes, actualIconColor));
} else if (object instanceof QuickAction) {
QuickAction quickAction = (QuickAction) object;
builder.setTitle(quickAction.getName(app));
builder.setIcon(uiUtilities.getIcon(quickAction.getIconRes(), activeColorRes));
item.setTitle(quickAction.getName(app));
item.setIcon(uiUtilities.getIcon(quickAction.getIconRes(), getItemIconColor(object)));
} else if (object instanceof PoiUIFilter) {
PoiUIFilter poiUIFilter = (PoiUIFilter) object;
builder.setTitle(poiUIFilter.getName());
item.setTitle(poiUIFilter.getName());
int iconRes = RenderingIcons.getBigIconResourceId(poiUIFilter.getIconId());
builder.setIcon(uiUtilities.getIcon(iconRes != 0 ? iconRes : R.drawable.ic_action_user, activeColorRes));
item.setIcon(uiUtilities.getIcon(iconRes != 0 ? iconRes : R.drawable.ic_action_user, activeColorRes));
} else if (object instanceof TileSourceTemplate || object instanceof SQLiteTileSource) {
ITileSource tileSource = (ITileSource) object;
builder.setTitle(tileSource.getName());
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_map, activeColorRes));
item.setTitle(tileSource.getName());
item.setIcon(uiUtilities.getIcon(R.drawable.ic_map, getItemIconColor(object)));
} else if (object instanceof File) {
setupBottomSheetItemForFile(builder, (File) object);
setupBottomSheetItemForFile(item, (File) object);
} else if (object instanceof GpxSettingsItem) {
GpxSettingsItem item = (GpxSettingsItem) object;
setupBottomSheetItemForGpx(builder, item.getFile(), item.getAppearanceInfo());
GpxSettingsItem settingsItem = (GpxSettingsItem) object;
setupBottomSheetItemForGpx(item, settingsItem.getFile(), settingsItem.getAppearanceInfo());
} else if (object instanceof FileSettingsItem) {
FileSettingsItem item = (FileSettingsItem) object;
setupBottomSheetItemForFile(builder, item.getFile());
FileSettingsItem settingsItem = (FileSettingsItem) object;
setupBottomSheetItemForFile(item, settingsItem.getFile());
} else if (object instanceof AvoidRoadInfo) {
AvoidRoadInfo avoidRoadInfo = (AvoidRoadInfo) object;
builder.setTitle(avoidRoadInfo.name);
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_alert, activeColorRes));
item.setTitle(avoidRoadInfo.name);
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_alert, getItemIconColor(object)));
} else if (object instanceof OsmNotesPoint) {
OsmNotesPoint osmNotesPoint = (OsmNotesPoint) object;
builder.setTitle(osmNotesPoint.getText());
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_osm_note_add, activeColorRes));
item.setTitle(osmNotesPoint.getText());
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_osm_note_add, getItemIconColor(object)));
} else if (object instanceof OpenstreetmapPoint) {
OpenstreetmapPoint openstreetmapPoint = (OpenstreetmapPoint) object;
builder.setTitle(OsmEditingPlugin.getTitle(openstreetmapPoint, app));
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_info_dark, activeColorRes));
item.setTitle(OsmEditingPlugin.getTitle(openstreetmapPoint, app));
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_info_dark, getItemIconColor(object)));
} else if (object instanceof FavoriteGroup) {
FavoriteGroup group = (FavoriteGroup) object;
builder.setTitle(group.getDisplayName(app));
int color = group.getColor() == 0 ? ContextCompat.getColor(app, R.color.color_favorite) : group.getColor();
builder.setIcon(uiUtilities.getPaintedIcon(R.drawable.ic_action_folder, color));
item.setTitle(group.getDisplayName(app));
int color;
if (selectedItems.contains(object)) {
color = group.getColor() == 0 ? ContextCompat.getColor(app, R.color.color_favorite) : group.getColor();
} else {
color = ContextCompat.getColor(app, secondaryColorRes);
}
item.setIcon(uiUtilities.getPaintedIcon(R.drawable.ic_action_folder, color));
int points = group.getPoints().size();
String itemsDescr = getString(R.string.shared_string_gpx_points);
builder.setDescription(getString(R.string.ltr_or_rtl_combine_via_colon, itemsDescr, points));
item.setDescription(getString(R.string.ltr_or_rtl_combine_via_colon, itemsDescr, points));
} else if (object instanceof GlobalSettingsItem) {
GlobalSettingsItem globalSettingsItem = (GlobalSettingsItem) object;
builder.setTitle(globalSettingsItem.getPublicName(app));
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_settings, activeColorRes));
item.setTitle(globalSettingsItem.getPublicName(app));
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_settings, getItemIconColor(object)));
} else if (object instanceof ItineraryGroup) {
ItineraryGroup markersGroup = (ItineraryGroup) object;
if (ExportSettingsType.ACTIVE_MARKERS.name().equals(markersGroup.getId())) {
builder.setTitle(getString(R.string.map_markers));
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_flag, activeColorRes));
item.setTitle(getString(R.string.map_markers));
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_flag, getItemIconColor(object)));
} else if (ExportSettingsType.HISTORY_MARKERS.name().equals(markersGroup.getId())) {
builder.setTitle(getString(R.string.markers_history));
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_history, activeColorRes));
item.setTitle(getString(R.string.markers_history));
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_history, getItemIconColor(object)));
}
int selectedMarkers = markersGroup.getMarkers().size();
String itemsDescr = getString(R.string.shared_string_items);
builder.setDescription(getString(R.string.ltr_or_rtl_combine_via_colon, itemsDescr, selectedMarkers));
item.setDescription(getString(R.string.ltr_or_rtl_combine_via_colon, itemsDescr, selectedMarkers));
} else if (object instanceof HistoryEntry) {
HistoryEntry historyEntry = (HistoryEntry) object;
builder.setTitle(historyEntry.getName().getName());
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_history, activeColorRes));
item.setTitle(historyEntry.getName().getName());
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_history, getItemIconColor(object)));
} else if (object instanceof OnlineRoutingEngine) {
OnlineRoutingEngine onlineRoutingEngine = (OnlineRoutingEngine) object;
builder.setTitle(onlineRoutingEngine.getName(app));
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_world_globe_dark, activeColorRes));
item.setTitle(onlineRoutingEngine.getName(app));
item.setIcon(uiUtilities.getIcon(R.drawable.ic_world_globe_dark, getItemIconColor(object)));
}
}
private void setupBottomSheetItemForFile(Builder builder, File file) {
private void setupBottomSheetItemForFile(BottomSheetItemWithCompoundButton item, File file) {
FileSubtype fileSubtype = FileSubtype.getSubtypeByPath(app, file.getPath());
builder.setTitle(file.getName());
item.setTitle(file.getName());
if (file.getAbsolutePath().contains(IndexConstants.RENDERERS_DIR)) {
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_map_style, activeColorRes));
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_map_style, getItemIconColor(item.getTag())));
} else if (file.getAbsolutePath().contains(IndexConstants.ROUTING_PROFILES_DIR)) {
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_route_distance, activeColorRes));
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_route_distance, getItemIconColor(item.getTag())));
} else if (file.getAbsolutePath().contains(IndexConstants.GPX_INDEX_DIR)) {
setupBottomSheetItemForGpx(builder, file, null);
setupBottomSheetItemForGpx(item, file, null);
} else if (file.getAbsolutePath().contains(IndexConstants.AV_INDEX_DIR)) {
int iconId = AudioVideoNotesPlugin.getIconIdForRecordingFile(file);
if (iconId == -1) {
iconId = R.drawable.ic_action_photo_dark;
}
builder.setIcon(uiUtilities.getIcon(iconId, activeColorRes));
builder.setDescription(AndroidUtils.formatSize(app, file.length()));
if (item.getTag() instanceof FileSettingsItem) {
FileSettingsItem settingsItem = (FileSettingsItem) item.getTag();
item.setTitle(getNameForMultimediaFile(settingsItem.getFile(), settingsItem.getLastModified()));
} else {
item.setTitle(new Recording(file).getName(app, true));
}
item.setIcon(uiUtilities.getIcon(iconId, getItemIconColor(item.getTag())));
item.setDescription(AndroidUtils.formatSize(app, file.length()));
} else if (fileSubtype.isMap()
|| fileSubtype == FileSettingsItem.FileSubtype.TTS_VOICE
|| fileSubtype == FileSettingsItem.FileSubtype.VOICE) {
builder.setTitle(FileNameTranslationHelper.getFileNameWithRegion(app, file.getName()));
builder.setIcon(uiUtilities.getIcon(fileSubtype.getIconId(), activeColorRes));
item.setTitle(FileNameTranslationHelper.getFileNameWithRegion(app, file.getName()));
item.setIcon(uiUtilities.getIcon(fileSubtype.getIconId(), getItemIconColor(item.getTag())));
if (fileSubtype.isMap()) {
String mapDescription = getMapDescription(file);
String formattedSize = AndroidUtils.formatSize(app, file.length());
if (mapDescription != null) {
builder.setDescription(getString(R.string.ltr_or_rtl_combine_via_bold_point, mapDescription, formattedSize));
item.setDescription(getString(R.string.ltr_or_rtl_combine_via_bold_point, mapDescription, formattedSize));
} else {
builder.setDescription(formattedSize);
item.setDescription(formattedSize);
}
}
}
}
private void setupBottomSheetItemForGpx(Builder builder, File file, @Nullable GpxAppearanceInfo appearanceInfo) {
builder.setTitle(GpxUiHelper.getGpxTitle(file.getName()));
builder.setDescription(getTrackDescr(file, file.lastModified(), file.length(), appearanceInfo));
builder.setIcon(uiUtilities.getIcon(R.drawable.ic_action_route_distance, activeColorRes));
private void setupBottomSheetItemForGpx(BottomSheetItemWithCompoundButton item, File file, @Nullable GpxAppearanceInfo appearanceInfo) {
item.setTitle(GpxUiHelper.getGpxTitle(file.getName()));
item.setDescription(getTrackDescr(file, file.lastModified(), file.length(), appearanceInfo));
item.setIcon(uiUtilities.getIcon(R.drawable.ic_action_route_distance, getItemIconColor(item.getTag())));
}
private String getNameForMultimediaFile(@NonNull File file, long lastModified) {
String fileName = file.getName();
if (fileName.endsWith(IMG_EXTENSION)) {
return getString(R.string.shared_string_photo) + " " + Recording.formatDateTime(app, lastModified);
} else if (fileName.endsWith(MPEG4_EXTENSION)) {
return getString(R.string.shared_string_video) + " " + Recording.formatDateTime(app, lastModified);
} else if (fileName.endsWith(THREEGP_EXTENSION)) {
return getString(R.string.shared_string_audio) + " " + Recording.formatDateTime(app, lastModified);
}
return "";
}
private int getItemIconColor(Object object) {
return selectedItems.contains(object) ? activeColorRes : secondaryColorRes;
}
private final GpxDataItemCallback gpxDataItemCallback = new GpxDataItemCallback() {

View file

@ -58,7 +58,6 @@ public class ExportSettingsAdapter extends OsmandBaseExpandableListAdapter {
private final int secondaryColorRes;
private final int groupViewHeight;
private final int childViewHeight;
private final int listBottomPadding;
ExportSettingsAdapter(OsmandApplication app, boolean exportMode, OnItemSelectedListener listener, boolean nightMode) {
this.app = app;
@ -71,7 +70,6 @@ public class ExportSettingsAdapter extends OsmandBaseExpandableListAdapter {
secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light;
groupViewHeight = app.getResources().getDimensionPixelSize(R.dimen.setting_list_item_group_height);
childViewHeight = app.getResources().getDimensionPixelSize(R.dimen.setting_list_item_large_height);
listBottomPadding = app.getResources().getDimensionPixelSize(R.dimen.fab_recycler_view_padding_bottom);
}
@Override
@ -118,9 +116,6 @@ public class ExportSettingsAdapter extends OsmandBaseExpandableListAdapter {
}
});
boolean addPadding = !isExpanded && groupPosition == getGroupCount() - 1;
group.setPadding(0, 0, 0, addPadding ? listBottomPadding : 0);
adjustIndicator(app, groupPosition, isExpanded, group, nightMode);
AndroidUiHelper.updateVisibility(group.findViewById(R.id.divider), isExpanded);
AndroidUiHelper.updateVisibility(group.findViewById(R.id.card_top_divider), true);
@ -188,8 +183,6 @@ public class ExportSettingsAdapter extends OsmandBaseExpandableListAdapter {
notifyDataSetChanged();
}
});
boolean addPadding = isLastChild && groupPosition == getGroupCount() - 1;
child.setPadding(0, 0, 0, addPadding ? listBottomPadding : 0);
AndroidUiHelper.updateVisibility(child.findViewById(R.id.card_bottom_divider), isLastChild);
return child;

View file

@ -54,10 +54,13 @@ import net.osmand.plus.profiles.SelectProfileBottomSheet.DialogMode;
import net.osmand.plus.profiles.SelectProfileBottomSheet.OnSelectProfileCallback;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
import net.osmand.plus.routing.RouteLineDrawInfo;
import net.osmand.plus.routing.RouteService;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.CommonPreference;
import net.osmand.plus.settings.backend.backup.ProfileSettingsItem;
import net.osmand.plus.settings.backend.backup.SettingsHelper;
import net.osmand.plus.settings.fragments.RouteLineAppearanceFragment.OnApplyRouteLineListener;
import net.osmand.plus.track.ColorsCard;
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
import net.osmand.plus.widgets.FlowLayout;
@ -74,8 +77,9 @@ import java.util.List;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_SETTINGS_ID;
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILES_LIST_UPDATED_ARG;
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG;
import static net.osmand.plus.routing.TransportRoutingHelper.PUBLIC_TRANSPORT_KEY;
public class ProfileAppearanceFragment extends BaseSettingsFragment implements OnSelectProfileCallback, CardListener, ColorPickerListener {
public class ProfileAppearanceFragment extends BaseSettingsFragment implements OnSelectProfileCallback, CardListener, ColorPickerListener, OnApplyRouteLineListener {
private static final Log LOG = PlatformUtil.getLog(ProfileAppearanceFragment.class);
@ -91,6 +95,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
private static final String LOCATION_ICON_ITEMS = "location_icon_items";
private static final String SELECT_NAV_ICON = "select_nav_icon";
private static final String NAV_ICON_ITEMS = "nav_icon_items";
private static final String CUSTOMIZE_ROUTE_LINE = "customize_route_line";
private static final String PROFILE_NAME_KEY = "profile_name_key";
private static final String PROFILE_STRINGKEY_KEY = "profile_stringkey_key";
@ -159,6 +164,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
changedProfile.routeService = profile.routeService;
changedProfile.locationIcon = profile.locationIcon;
changedProfile.navigationIcon = profile.navigationIcon;
changedProfile.routeLineDrawInfo = profile.routeLineDrawInfo;
isNewProfile = ApplicationMode.valueOfStringKey(changedProfile.stringKey, null) == null;
}
requireMyActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@ -179,6 +185,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
profile.routeService = baseModeForNewProfile.getRouteService();
profile.locationIcon = baseModeForNewProfile.getLocationIcon();
profile.navigationIcon = baseModeForNewProfile.getNavigationIcon();
profile.routeLineDrawInfo = createRouteLineDrawInfo(baseModeForNewProfile);
}
@Override
@ -239,6 +246,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
findPreference(SELECT_ICON).setVisible(false);
findPreference(ICON_ITEMS).setVisible(false);
}
updateRouteLinePreference();
}
@SuppressLint("InlinedApi")
@ -318,6 +326,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
outState.putBoolean(IS_BASE_PROFILE_IMPORTED, isBaseProfileImported);
outState.putSerializable(PROFILE_LOCATION_ICON_KEY, changedProfile.locationIcon);
outState.putSerializable(PROFILE_NAVIGATION_ICON_KEY, changedProfile.navigationIcon);
changedProfile.routeLineDrawInfo.saveToBundle(outState);
}
private void restoreState(Bundle savedInstanceState) {
@ -331,6 +340,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
isBaseProfileImported = savedInstanceState.getBoolean(IS_BASE_PROFILE_IMPORTED);
changedProfile.locationIcon = (LocationIcon) savedInstanceState.getSerializable(PROFILE_LOCATION_ICON_KEY);
changedProfile.navigationIcon = (NavigationIcon) savedInstanceState.getSerializable(PROFILE_NAVIGATION_ICON_KEY);
changedProfile.routeLineDrawInfo = new RouteLineDrawInfo(savedInstanceState);
isNewProfile = savedInstanceState.getBoolean(IS_NEW_PROFILE_KEY);
}
@ -709,6 +719,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
changedProfile.routingProfile = changedProfile.parent.getRoutingProfile();
changedProfile.routeService = changedProfile.parent.getRouteService();
this.isBaseProfileImported = isBaseProfileImported;
updateRouteLinePreference();
}
private void setupBaseProfileView(String stringKey) {
@ -716,6 +727,14 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
baseProfileName.setText(Algorithms.capitalizeFirstLetter(mode.toHumanString()));
}
private void updateRouteLinePreference() {
Preference preference = findPreference(CUSTOMIZE_ROUTE_LINE);
boolean isDefaultProfile = getSelectedAppMode().equals(ApplicationMode.DEFAULT) && !isNewProfile;
boolean isPublicTransport = PUBLIC_TRANSPORT_KEY.equals(changedProfile.routingProfile);
preference.setVisible(!isDefaultProfile && !isPublicTransport);
preference.setIcon(getIcon(R.drawable.ic_action_route_distance, getActiveColorRes()));
}
private boolean checkProfileName() {
if (Algorithms.isBlank(changedProfile.name)) {
Activity activity = getActivity();
@ -756,6 +775,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
mode.setCustomIconColor(changedProfile.customColor);
mode.setLocationIcon(changedProfile.locationIcon);
mode.setNavigationIcon(changedProfile.navigationIcon);
saveRouteLineAppearance(mode, changedProfile.routeLineDrawInfo);
FragmentActivity activity = getActivity();
if (activity != null) {
@ -783,6 +803,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
if (!ApplicationMode.values(app).contains(mode)) {
ApplicationMode.changeProfileAvailability(mode, true, app);
}
saveRouteLineAppearance(mode, changedProfile.routeLineDrawInfo);
return mode;
}
@ -967,6 +988,21 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
}
}
@Override
public boolean onPreferenceClick(Preference preference) {
String prefId = preference.getKey();
if (CUSTOMIZE_ROUTE_LINE.equals(prefId)) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
RouteLineDrawInfo drawInfo = changedProfile.routeLineDrawInfo;
drawInfo.setIconId(changedProfile.navigationIcon.getIconId());
drawInfo.setIconColor(changedProfile.getActualColor());
RouteLineAppearanceFragment.showInstance(mapActivity, drawInfo, this);
}
}
return super.onPreferenceClick(preference);
}
@Override
public void onCardButtonPressed(@NonNull BaseCard card, int buttonIndex) {
}
@ -977,6 +1013,29 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
this.onCardPressed(colorsCard);
}
@Override
public void applyRouteLineAppearance(@NonNull RouteLineDrawInfo routeLineDrawInfo) {
changedProfile.routeLineDrawInfo = routeLineDrawInfo;
}
private RouteLineDrawInfo createRouteLineDrawInfo(@NonNull ApplicationMode appMode) {
int storedValue = settings.ROUTE_LINE_COLOR.getModeValue(appMode);
Integer color = storedValue != 0 ? storedValue : null;
String widthKey = settings.ROUTE_LINE_WIDTH.getModeValue(appMode);
return new RouteLineDrawInfo(color, widthKey);
}
private void saveRouteLineAppearance(@NonNull ApplicationMode appMode,
@NonNull RouteLineDrawInfo drawInfo) {
Integer color = drawInfo.getColor();
if (color != null) {
settings.ROUTE_LINE_COLOR.setModeValue(appMode, color);
} else {
settings.ROUTE_LINE_COLOR.resetModeToDefault(appMode);
}
settings.ROUTE_LINE_WIDTH.setModeValue(appMode, drawInfo.getWidth());
}
public static boolean showInstance(FragmentActivity activity, SettingsScreenType screenType, @Nullable String appMode, boolean imported) {
try {
Fragment fragment = Fragment.instantiate(activity, screenType.fragmentName);
@ -1008,6 +1067,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
RouteService routeService;
NavigationIcon navigationIcon;
LocationIcon locationIcon;
RouteLineDrawInfo routeLineDrawInfo;
@ColorInt
public int getActualColor() {
@ -1044,6 +1104,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
return false;
if (routeService != that.routeService) return false;
if (navigationIcon != that.navigationIcon) return false;
if (routeLineDrawInfo != null ? !routeLineDrawInfo.equals(that.routeLineDrawInfo) : that.routeLineDrawInfo != null) return false;
return locationIcon == that.locationIcon;
}
@ -1059,6 +1120,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
result = 31 * result + (routeService != null ? routeService.hashCode() : 0);
result = 31 * result + (navigationIcon != null ? navigationIcon.hashCode() : 0);
result = 31 * result + (locationIcon != null ? locationIcon.hashCode() : 0);
result = 31 * result + (routeLineDrawInfo != null ? routeLineDrawInfo.hashCode() : 0);
return result;
}
}

View file

@ -0,0 +1,431 @@
package net.osmand.plus.settings.fragments;
import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.UiUtilities.DialogButtonType;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.ContextMenuScrollFragment;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.enums.DayNightMode;
import net.osmand.plus.routing.RouteLineDrawInfo;
import net.osmand.plus.routing.cards.RouteLineColorCard;
import net.osmand.plus.routing.cards.RouteLineColorCard.OnMapThemeUpdateListener;
import net.osmand.plus.routing.cards.RouteLineColorCard.OnSelectedColorChangeListener;
import net.osmand.plus.routing.cards.RouteLineWidthCard;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
import net.osmand.plus.track.TrackAppearanceFragment.OnNeedScrollListener;
public class RouteLineAppearanceFragment extends ContextMenuScrollFragment implements ColorPickerListener, OnSelectedColorChangeListener, OnMapThemeUpdateListener {
public static final String TAG = RouteLineAppearanceFragment.class.getName();
private static final String INIT_MAP_THEME = "init_map_theme";
private static final String SELECTED_MAP_THEME = "selected_map_theme";
private RouteLineDrawInfo routeLineDrawInfo;
private int toolbarHeightPx;
private DayNightMode initMapTheme;
private DayNightMode selectedMapTheme;
private View buttonsShadow;
private View controlButtons;
private View toolbarContainer;
private RouteLineColorCard colorCard;
private RouteLineWidthCard widthCard;
@Override
public int getMainLayoutId() {
return R.layout.route_line_appearance;
}
@Override
public int getHeaderViewHeight() {
return 0;
}
@Override
public boolean isHeaderViewDetached() {
return false;
}
@Override
public int getToolbarHeight() {
return isPortrait() ? toolbarHeightPx : 0;
}
@Override
public float getMiddleStateKoef() {
return 0.5f;
}
@Override
public int getInitialMenuState() {
return MenuState.HALF_SCREEN;
}
@Override
public int getSupportedMenuStatesPortrait() {
return MenuState.HALF_SCREEN | MenuState.FULL_SCREEN;
}
@Override
public boolean shouldShowMapControls(int menuState) {
return menuState == MenuState.HALF_SCREEN;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
toolbarHeightPx = getResources().getDimensionPixelSize(R.dimen.dashboard_map_toolbar);
if (savedInstanceState != null) {
routeLineDrawInfo = new RouteLineDrawInfo(savedInstanceState);
initMapTheme = DayNightMode.valueOf(savedInstanceState.getString(INIT_MAP_THEME));
selectedMapTheme = DayNightMode.valueOf(savedInstanceState.getString(SELECTED_MAP_THEME));
} else {
initMapTheme = getMyApplication().getSettings().DAYNIGHT_MODE.get();
selectedMapTheme = initMapTheme;
}
requireMapActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
public void handleOnBackPressed() {
dismiss();
}
});
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
if (view != null) {
toolbarContainer = view.findViewById(R.id.context_menu_toolbar_container);
buttonsShadow = view.findViewById(R.id.buttons_shadow);
controlButtons = view.findViewById(R.id.control_buttons);
if (isPortrait()) {
updateCardsLayout();
} else {
int widthNoShadow = getLandscapeNoShadowWidth();
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(widthNoShadow, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.BOTTOM | Gravity.START;
controlButtons.setLayoutParams(params);
}
initContent(view);
}
return view;
}
private void initContent(@NonNull View view) {
setupCards();
setupToolbar();
setupButtons(view);
setupScrollShadow();
enterAppearanceMode();
openMenuHalfScreen();
calculateLayout();
}
private void calculateLayout() {
runLayoutListener(new Runnable() {
@Override
public void run() {
updateMapControlsPos(RouteLineAppearanceFragment.this, getViewY(), true);
initVisibleRect();
}
});
}
private void setupCards() {
MapActivity mapActivity = requireMapActivity();
ViewGroup cardsContainer = getCardsContainer();
cardsContainer.removeAllViews();
colorCard = new RouteLineColorCard(mapActivity, this, routeLineDrawInfo, initMapTheme, selectedMapTheme);
cardsContainer.addView(colorCard.build(mapActivity));
widthCard = new RouteLineWidthCard(mapActivity, routeLineDrawInfo, createScrollListener());
cardsContainer.addView(widthCard.build(mapActivity));
}
private OnNeedScrollListener createScrollListener() {
return new OnNeedScrollListener() {
@Override
public void onVerticalScrollNeeded(int y) {
View view = widthCard.getView();
if (view != null) {
int resultYPosition = view.getTop() + y;
int dialogHeight = getInnerScrollableHeight();
ScrollView scrollView = (ScrollView) getBottomScrollView();
if (resultYPosition > (scrollView.getScrollY() + dialogHeight)) {
scrollView.smoothScrollTo(0, resultYPosition - dialogHeight);
}
}
}
private int getInnerScrollableHeight() {
int totalScreenHeight = getViewHeight() - getMenuStatePosY(getCurrentMenuState());
int frameTotalHeight = controlButtons.getHeight() + buttonsShadow.getHeight();
return totalScreenHeight - frameTotalHeight;
}
};
}
private void setupToolbar() {
ImageView closeButton = toolbarContainer.findViewById(R.id.close_button);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
closeButton.setImageResource(AndroidUtils.getNavigationIconResId(toolbarContainer.getContext()));
updateToolbarVisibility(toolbarContainer);
}
@Override
public int getStatusBarColorId() {
View view = getView();
if (Build.VERSION.SDK_INT >= 23 && !isNightMode() && view != null) {
view.setSystemUiVisibility(view.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
return isNightMode() ? R.color.divider_color_dark : R.color.divider_color_light;
}
@Override
public float getToolbarAlpha(int y) {
return isPortrait() ? 1f : 0f;
}
private void setupButtons(View view) {
View buttonsContainer = view.findViewById(R.id.buttons_container);
buttonsContainer.setBackgroundColor(AndroidUtils.getColorFromAttr(view.getContext(), R.attr.bg_color));
View saveButton = view.findViewById(R.id.right_bottom_button);
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getTargetFragment() instanceof OnApplyRouteLineListener) {
((OnApplyRouteLineListener) getTargetFragment()).applyRouteLineAppearance(routeLineDrawInfo);
}
dismiss();
}
});
View cancelButton = view.findViewById(R.id.dismiss_button);
cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentActivity activity = getActivity();
if (activity != null) {
activity.onBackPressed();
}
}
});
UiUtilities.setupDialogButton(isNightMode(), cancelButton, DialogButtonType.SECONDARY, R.string.shared_string_cancel);
UiUtilities.setupDialogButton(isNightMode(), saveButton, DialogButtonType.PRIMARY, R.string.shared_string_apply);
AndroidUiHelper.updateVisibility(saveButton, true);
AndroidUiHelper.updateVisibility(view.findViewById(R.id.buttons_divider), true);
}
private void setupScrollShadow() {
final View scrollView = getBottomScrollView();
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
boolean scrollToBottomAvailable = scrollView.canScrollVertically(1);
if (scrollToBottomAvailable) {
showShadowButton();
} else {
hideShadowButton();
}
}
});
}
private void showShadowButton() {
buttonsShadow.setVisibility(View.VISIBLE);
buttonsShadow.animate()
.alpha(0.8f)
.setDuration(200)
.setListener(null);
}
private void hideShadowButton() {
buttonsShadow.animate()
.alpha(0f)
.setDuration(200);
}
private void initVisibleRect() {
MapActivity ctx = getMapActivity();
int screenHeight = AndroidUtils.getScreenHeight(ctx);
int screenWidth = AndroidUtils.getScreenWidth(ctx);
int statusBarHeight = AndroidUtils.getStatusBarHeight(ctx);
int centerX;
int centerY;
if (isPortrait()) {
centerX = screenWidth / 2;
centerY = (getViewY() + toolbarContainer.getHeight() + statusBarHeight) / 2;
} else {
boolean isRtl = AndroidUtils.isLayoutRtl(ctx);
int dialogWidth = getLandscapeNoShadowWidth();
int left = isRtl ? 0 : dialogWidth;
int right = isRtl ? screenWidth - dialogWidth : screenWidth;
centerX = (left + right) / 2;
centerY = (screenHeight + statusBarHeight) / 2 ;
}
routeLineDrawInfo.setCenterX(centerX);
routeLineDrawInfo.setCenterY(centerY);
routeLineDrawInfo.setScreenHeight(screenHeight);
}
@Override
public void onResume() {
super.onResume();
setDrawInfoOnRouteLayer(routeLineDrawInfo);
}
@Override
public void onPause() {
super.onPause();
setDrawInfoOnRouteLayer(null);
}
private void setDrawInfoOnRouteLayer(@Nullable RouteLineDrawInfo drawInfo) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMapLayers().getRouteLayer().setRouteLineDrawInfo(drawInfo);
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(INIT_MAP_THEME, initMapTheme.name());
outState.putString(SELECTED_MAP_THEME, selectedMapTheme.name());
routeLineDrawInfo.saveToBundle(outState);
}
@Override
public void onDestroyView() {
super.onDestroyView();
exitAppearanceMode();
}
private void enterAppearanceMode() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
boolean portrait = AndroidUiHelper.isOrientationPortrait(mapActivity);
AndroidUiHelper.setVisibility(mapActivity, portrait ? View.INVISIBLE : View.GONE,
R.id.map_left_widgets_panel,
R.id.map_right_widgets_panel,
R.id.map_center_info);
}
}
private void exitAppearanceMode() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
AndroidUiHelper.setVisibility(mapActivity, View.VISIBLE,
R.id.map_left_widgets_panel,
R.id.map_right_widgets_panel,
R.id.map_center_info,
R.id.map_search_button);
changeMapTheme(initMapTheme);
}
}
private void updateCardsLayout() {
View mainView = getMainView();
if (mainView != null) {
LinearLayout cardsContainer = getCardsContainer();
View topShadow = getTopShadow();
FrameLayout bottomContainer = getBottomContainer();
if (getCurrentMenuState() == MenuState.HEADER_ONLY) {
topShadow.setVisibility(View.INVISIBLE);
bottomContainer.setBackgroundDrawable(null);
AndroidUtils.setBackground(mainView.getContext(), cardsContainer, isNightMode(), R.drawable.travel_card_bg_light, R.drawable.travel_card_bg_dark);
} else {
topShadow.setVisibility(View.VISIBLE);
AndroidUtils.setBackground(mainView.getContext(), bottomContainer, isNightMode(), R.color.list_background_color_light, R.color.list_background_color_dark);
AndroidUtils.setBackground(mainView.getContext(), cardsContainer, isNightMode(), R.color.list_background_color_light, R.color.list_background_color_dark);
}
}
}
@Override
public void onColorSelected(Integer prevColor, int newColor) {
colorCard.onColorSelected(prevColor, newColor);
}
@Override
public void onSelectedColorChanged() {
if (widthCard != null) {
widthCard.updateItems();
}
if (getMapActivity() != null) {
getMapActivity().refreshMap();
}
}
public static boolean showInstance(@NonNull MapActivity mapActivity,
@NonNull RouteLineDrawInfo drawInfo,
@NonNull Fragment target) {
try {
RouteLineAppearanceFragment fragment = new RouteLineAppearanceFragment();
fragment.setTargetFragment(target, 0);
fragment.routeLineDrawInfo = new RouteLineDrawInfo(drawInfo);
mapActivity.getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragmentContainer, fragment, TAG)
.addToBackStack(TAG)
.commitAllowingStateLoss();
return true;
} catch (RuntimeException e) {
return false;
}
}
@Override
public void onMapThemeUpdated(@NonNull DayNightMode mapTheme) {
changeMapTheme(mapTheme);
}
private void changeMapTheme(@NonNull DayNightMode mapTheme) {
OsmandApplication app = getMyApplication();
if (app != null) {
app.getSettings().DAYNIGHT_MODE.set(mapTheme);
selectedMapTheme = mapTheme;
}
}
public interface OnApplyRouteLineListener {
void applyRouteLineAppearance(@NonNull RouteLineDrawInfo routeLineDrawInfo);
}
}

View file

@ -8,13 +8,13 @@ import androidx.recyclerview.widget.RecyclerView;
import net.osmand.plus.R;
public class TrackAppearanceViewHolder extends RecyclerView.ViewHolder {
public class AppearanceViewHolder extends RecyclerView.ViewHolder {
final TextView title;
final ImageView icon;
final ImageView button;
public final TextView title;
public final ImageView icon;
public final ImageView button;
TrackAppearanceViewHolder(View itemView) {
public AppearanceViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.groupName);
icon = itemView.findViewById(R.id.groupIcon);

View file

@ -6,7 +6,6 @@ import android.view.View;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import androidx.fragment.app.Fragment;
@ -28,12 +27,6 @@ import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import androidx.fragment.app.Fragment;
public class ColorsCard extends BaseCard implements ColorPickerListener {
public static final int MAX_CUSTOM_COLORS = 6;
@ -58,7 +51,12 @@ public class ColorsCard extends BaseCard implements ColorPickerListener {
return R.layout.colors_card;
}
public ColorsCard(MapActivity mapActivity, int selectedColor, Fragment targetFragment, List<Integer> colors, ListStringPreference colorsListPreference, ApplicationMode appMode) {
public ColorsCard(MapActivity mapActivity,
int selectedColor,
Fragment targetFragment,
List<Integer> colors,
ListStringPreference colorsListPreference,
ApplicationMode appMode) {
super(mapActivity);
this.targetFragment = targetFragment;
this.selectedColor = selectedColor;

View file

@ -8,6 +8,16 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
@ -26,39 +36,44 @@ import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import static net.osmand.plus.liveupdates.LiveUpdatesFragmentNew.getDefaultIconColorId;
public class GpxBlockStatisticsBuilder {
private static final Log log = PlatformUtil.getLog(GpxBlockStatisticsBuilder.class);
private static final int GENERAL_UPDATE_INTERVAL = 1000;
private static final Log LOG = PlatformUtil.getLog(GpxBlockStatisticsBuilder.class);
private static final int BLOCKS_UPDATE_INTERVAL = 1000;
public static final String INIT_BLOCKS_BASE = "init_blocks_base";
public static final String INIT_BLOCKS_GENERAL = "init_blocks_general";
public static final String INIT_BLOCKS_ALTITUDE = "init_blocks_altitude";
public static final String INIT_BLOCKS_SPEED = "init_blocks_speed";
private final OsmandApplication app;
private final boolean nightMode;
private RecyclerView blocksView;
private final SelectedGpxFile selectedGpxFile;
private GPXTrackAnalysis analysis;
private BlockStatisticsAdapter adapter;
private final List<StatBlock> items = new ArrayList<>();
private boolean blocksClickable = true;
private String initBlocksKey = INIT_BLOCKS_BASE;
private final Handler handler = new Handler();
private Runnable updatingItems;
private boolean updateRunning = false;
public GpxBlockStatisticsBuilder(OsmandApplication app, SelectedGpxFile selectedGpxFile) {
public GpxBlockStatisticsBuilder(OsmandApplication app, SelectedGpxFile selectedGpxFile, boolean nightMode) {
this.app = app;
this.selectedGpxFile = selectedGpxFile;
this.nightMode = nightMode;
}
public boolean isUpdateRunning() {
@ -73,6 +88,10 @@ public class GpxBlockStatisticsBuilder {
this.blocksView = blocksView;
}
public void setInitBlocksKey(String initBlocksKey) {
this.initBlocksKey = initBlocksKey;
}
@Nullable
public GpxDisplayItem getDisplayItem(GPXFile gpxFile) {
return gpxFile.tracks.size() > 0 ? GpxUiHelper.makeGpxDisplayItem(app, gpxFile) : null;
@ -82,9 +101,9 @@ public class GpxBlockStatisticsBuilder {
return selectedGpxFile.getGpxFile();
}
public void initStatBlocks(@Nullable SegmentActionsListener actionsListener, @ColorInt int activeColor, boolean nightMode) {
public void initStatBlocks(@Nullable SegmentActionsListener actionsListener, @ColorInt int activeColor) {
initItems();
adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor, nightMode);
adapter = new BlockStatisticsAdapter(getDisplayItem(getGPXFile()), actionsListener, activeColor);
adapter.setItems(items);
blocksView.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false));
blocksView.setAdapter(adapter);
@ -107,7 +126,7 @@ public class GpxBlockStatisticsBuilder {
}
AndroidUiHelper.updateVisibility(blocksView, !Algorithms.isEmpty(items));
int interval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
updateRunning = handler.postDelayed(this, Math.max(GENERAL_UPDATE_INTERVAL, interval));
updateRunning = handler.postDelayed(this, Math.max(BLOCKS_UPDATE_INTERVAL, interval));
}
};
updateRunning = handler.post(updatingItems);
@ -119,7 +138,7 @@ public class GpxBlockStatisticsBuilder {
if (app == null || gpxFile == null) {
return;
}
GPXTrackAnalysis analysis = null;
analysis = null;
boolean withoutGaps = true;
if (gpxFile.equals(app.getSavingTrackHelper().getCurrentGpx())) {
GPXFile currentGpx = app.getSavingTrackHelper().getCurrentTrack().getGpxFile();
@ -133,34 +152,140 @@ public class GpxBlockStatisticsBuilder {
withoutGaps = !selectedGpxFile.isJoinSegments() && gpxDisplayItem.isGeneralTrack();
}
}
items.clear();
if (analysis != null) {
float totalDistance = withoutGaps ? analysis.totalDistanceWithoutGaps : analysis.totalDistance;
float timeSpan = withoutGaps ? analysis.timeSpanWithoutGaps : analysis.timeSpan;
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app);
String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app);
items.clear();
prepareData(analysis, app.getString(R.string.distance), OsmAndFormatter.getFormattedDistance(totalDistance, app),
R.drawable.ic_action_track_16, R.color.icon_color_default_light, GPXDataSetType.ALTITUDE, GPXDataSetType.SPEED, ItemType.ITEM_DISTANCE);
prepareData(analysis, app.getString(R.string.altitude_ascent), asc,
R.drawable.ic_action_arrow_up_16, R.color.gpx_chart_red, GPXDataSetType.SLOPE, null, ItemType.ITEM_ALTITUDE);
prepareData(analysis, app.getString(R.string.altitude_descent), desc,
R.drawable.ic_action_arrow_down_16, R.color.gpx_pale_green, GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE, ItemType.ITEM_ALTITUDE);
prepareData(analysis, app.getString(R.string.average_speed), avg,
R.drawable.ic_action_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED);
prepareData(analysis, app.getString(R.string.max_speed), max,
R.drawable.ic_action_max_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED);
prepareData(analysis, app.getString(R.string.shared_string_time_span),
Algorithms.formatDuration((int) (timeSpan / 1000), app.accessibilityEnabled()),
R.drawable.ic_action_time_span_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ItemType.ITEM_TIME);
switch (initBlocksKey) {
case INIT_BLOCKS_GENERAL: {
float totalDistance = withoutGaps ? analysis.totalDistanceWithoutGaps : analysis.totalDistance;
float timeSpan = withoutGaps ? analysis.timeSpanWithoutGaps : analysis.timeSpan;
Date start = new Date(analysis.startTime);
Date end = new Date(analysis.endTime);
prepareDataDistance(totalDistance);
prepareDataTimeSpan(timeSpan);
prepareDataStartTime(start);
prepareDataEndTime(end);
break;
}
case INIT_BLOCKS_ALTITUDE: {
String min = OsmAndFormatter.getFormattedAlt(analysis.minElevation, app);
String max = OsmAndFormatter.getFormattedAlt(analysis.maxElevation, app);
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
prepareDataAverageAltitude();
prepareDataAltitudeRange(min, max);
prepareDataAscent(asc);
prepareDataDescent(desc);
break;
}
case INIT_BLOCKS_SPEED: {
String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app);
String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app);
long timeMoving = withoutGaps ? analysis.timeMovingWithoutGaps : analysis.timeMoving;
float totalDistanceMoving = withoutGaps ? analysis.totalDistanceMovingWithoutGaps : analysis.totalDistanceMoving;
prepareDataAverageSpeed(avg);
prepareDataMaximumSpeed(max);
prepareDataTimeMoving(timeMoving);
prepareDataDistanceCorrected(totalDistanceMoving);
break;
}
default:
case INIT_BLOCKS_BASE: {
float totalDistance = withoutGaps ? analysis.totalDistanceWithoutGaps : analysis.totalDistance;
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app);
String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app);
float timeSpan = withoutGaps ? analysis.timeSpanWithoutGaps : analysis.timeSpan;
prepareDataDistance(totalDistance);
prepareDataAscent(asc);
prepareDataDescent(desc);
prepareDataAverageSpeed(avg);
prepareDataMaximumSpeed(max);
prepareDataTimeSpan(timeSpan);
break;
}
}
}
}
public void prepareData(GPXTrackAnalysis analysis, String title, String value,
@DrawableRes int imageResId, @ColorRes int imageColorId,
public void prepareDataDistance(float totalDistance) {
prepareData(app.getString(R.string.distance), OsmAndFormatter.getFormattedDistance(totalDistance, app),
R.drawable.ic_action_track_16, GPXDataSetType.ALTITUDE, GPXDataSetType.SPEED, ItemType.ITEM_DISTANCE);
}
public void prepareDataAverageAltitude() {
prepareData(app.getString(R.string.average_altitude), OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app),
R.drawable.ic_action_altitude_average_16, GPXDataSetType.ALTITUDE, null, ItemType.ITEM_ALTITUDE);
}
public void prepareDataAltitudeRange(String min, String max) {
String pattern = app.getString(R.string.ltr_or_rtl_combine_via_dash);
prepareData(app.getString(R.string.altitude_range), String.format(pattern, min, max),
R.drawable.ic_action_altitude_range_16, GPXDataSetType.ALTITUDE, null, ItemType.ITEM_ALTITUDE);
}
public void prepareDataAscent(String asc) {
prepareData(app.getString(R.string.altitude_ascent), asc,
R.drawable.ic_action_arrow_up_16, R.color.gpx_chart_red,
GPXDataSetType.SLOPE, null, ItemType.ITEM_ALTITUDE);
}
public void prepareDataDescent(String desc) {
prepareData(app.getString(R.string.altitude_descent), desc,
R.drawable.ic_action_arrow_down_16, R.color.gpx_pale_green,
GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE, ItemType.ITEM_ALTITUDE);
}
public void prepareDataAverageSpeed(String avg) {
prepareData(app.getString(R.string.average_speed), avg,
R.drawable.ic_action_speed_16, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED);
}
public void prepareDataMaximumSpeed(String max) {
prepareData(app.getString(R.string.max_speed), max,
R.drawable.ic_action_max_speed_16, GPXDataSetType.SPEED, null, ItemType.ITEM_SPEED);
}
public void prepareDataTimeMoving(long timeMoving) {
prepareData(app.getString(R.string.shared_string_time_moving),
Algorithms.formatDuration((int) (timeMoving / 1000), app.accessibilityEnabled()),
R.drawable.ic_action_time_span_16, GPXDataSetType.SPEED, null, ItemType.ITEM_TIME_MOVING);
}
public void prepareDataDistanceCorrected(float totalDistanceMoving) {
prepareData(app.getString(R.string.distance_moving),
OsmAndFormatter.getFormattedDistance(totalDistanceMoving, app),
R.drawable.ic_action_polygom_dark, GPXDataSetType.SPEED, null, ItemType.ITEM_DISTANCE_MOVING);
}
public void prepareDataTimeSpan(float timeSpan) {
prepareData(app.getString(R.string.shared_string_time_span),
Algorithms.formatDuration((int) (timeSpan / 1000), app.accessibilityEnabled()),
R.drawable.ic_action_time_span_16, GPXDataSetType.SPEED, null, ItemType.ITEM_TIME_SPAN);
}
public void prepareDataStartTime(Date start) {
DateFormat dtf = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
prepareData(app.getString(R.string.shared_string_start_time), dtf.format(start),
R.drawable.ic_action_time_start_16, GPXDataSetType.SPEED, null, ItemType.ITEM_TIME);
}
public void prepareDataEndTime(Date end) {
DateFormat dtf = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
prepareData(app.getString(R.string.shared_string_end_time), dtf.format(end),
R.drawable.ic_action_time_end_16, GPXDataSetType.SPEED, null, ItemType.ITEM_TIME);
}
public void prepareData(String title, String value, @DrawableRes int imageResId,
GPXDataSetType firstType, GPXDataSetType secondType, ItemType itemType) {
prepareData(title, value, imageResId, getDefaultIconColorId(nightMode), firstType, secondType, itemType);
}
public void prepareData(String title, String value, @DrawableRes int imageResId, @ColorRes int imageColorId,
GPXDataSetType firstType, GPXDataSetType secondType, ItemType itemType) {
if (analysis == null) {
return;
}
StatBlock statBlock = new StatBlock(title, value, imageResId, imageColorId, firstType, secondType, itemType);
switch (statBlock.itemType) {
case ITEM_DISTANCE: {
@ -169,6 +294,12 @@ public class GpxBlockStatisticsBuilder {
}
break;
}
case ITEM_DISTANCE_MOVING: {
if (analysis.totalDistanceMoving != 0f) {
items.add(statBlock);
}
break;
}
case ITEM_ALTITUDE: {
if (analysis.hasElevationData) {
items.add(statBlock);
@ -182,11 +313,23 @@ public class GpxBlockStatisticsBuilder {
break;
}
case ITEM_TIME: {
if (analysis.timeSpan > 0) {
items.add(statBlock);
}
break;
}
case ITEM_TIME_SPAN: {
if (analysis.hasSpeedData) {
items.add(statBlock);
}
break;
}
case ITEM_TIME_MOVING: {
if (analysis.isTimeMoving()) {
items.add(statBlock);
}
break;
}
}
}
@ -213,9 +356,12 @@ public class GpxBlockStatisticsBuilder {
public enum ItemType {
ITEM_DISTANCE,
ITEM_DISTANCE_MOVING,
ITEM_ALTITUDE,
ITEM_SPEED,
ITEM_TIME;
ITEM_TIME,
ITEM_TIME_SPAN,
ITEM_TIME_MOVING;
}
private class BlockStatisticsAdapter extends RecyclerView.Adapter<BlockStatisticsViewHolder> {
@ -225,17 +371,15 @@ public class GpxBlockStatisticsBuilder {
private final SegmentActionsListener actionsListener;
@ColorInt
private final int activeColor;
private final boolean nightMode;
private final int minWidthPx;
private final int maxWidthPx;
private final int textSize;
public BlockStatisticsAdapter(GpxDisplayItem displayItem, SegmentActionsListener actionsListener,
@ColorInt int activeColor, boolean nightMode) {
@ColorInt int activeColor) {
this.displayItem = displayItem;
this.actionsListener = actionsListener;
this.activeColor = activeColor;
this.nightMode = nightMode;
minWidthPx = AndroidUtils.dpToPx(app, 60f);
maxWidthPx = AndroidUtils.dpToPx(app, 120f);
textSize = app.getResources().getDimensionPixelSize(R.dimen.default_desc_text_size);
@ -260,7 +404,7 @@ public class GpxBlockStatisticsBuilder {
holder.valueText.setText(item.value);
holder.valueText.setTextColor(activeColor);
holder.titleText.setText(item.title);
holder.titleText.setTextColor(app.getResources().getColor(R.color.text_color_secondary_light));
holder.titleText.setTextColor(ContextCompat.getColor(app, R.color.text_color_secondary_light));
float letterSpacing = 0.00f;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
letterSpacing = Math.max(holder.valueText.getLetterSpacing(), holder.titleText.getLetterSpacing());

View file

@ -51,7 +51,7 @@ public class OverviewCard extends BaseCard {
super(mapActivity);
this.actionsListener = actionsListener;
this.selectedGpxFile = selectedGpxFile;
blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile);
blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile, nightMode);
}
@Override
@ -80,7 +80,7 @@ public class OverviewCard extends BaseCard {
initEditButton(iconColorDef, iconColorPres);
initDirectionsButton(iconColorDef, iconColorPres);
}
blockStatisticsBuilder.initStatBlocks(actionsListener, getActiveColor(), nightMode);
blockStatisticsBuilder.initStatBlocks(actionsListener, getActiveColor());
}
private GPXFile getGPXFile() {

View file

@ -47,7 +47,7 @@ public class SegmentsCard extends BaseCard {
WrapContentHeightViewPager pager = segmentView.findViewById(R.id.pager);
PagerSlidingTabStrip tabLayout = segmentView.findViewById(R.id.sliding_tabs);
pager.setAdapter(new GPXItemPagerAdapter(app, displayItem, displayHelper, nightMode, listener));
pager.setAdapter(new GPXItemPagerAdapter(app, displayItem, displayHelper, nightMode, listener, false));
tabLayout.setViewPager(pager);
container.addView(segmentView);

View file

@ -36,8 +36,8 @@ import net.osmand.plus.dialogs.GpxAppearanceAdapter;
import net.osmand.plus.dialogs.GpxAppearanceAdapter.AppearanceListItem;
import net.osmand.plus.dialogs.GpxAppearanceAdapter.GpxAppearanceAdapterType;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.monitoring.TripRecordingActiveBottomSheet;
import net.osmand.plus.monitoring.TripRecordingBottomSheet;
import net.osmand.plus.monitoring.TripRecordingStartingBottomSheet;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
import net.osmand.plus.settings.backend.CommonPreference;
@ -64,7 +64,7 @@ import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_COLOR_ATTR;
import static net.osmand.plus.dialogs.GpxAppearanceAdapter.TRACK_WIDTH_BOLD;
import static net.osmand.plus.dialogs.GpxAppearanceAdapter.TRACK_WIDTH_MEDIUM;
import static net.osmand.plus.dialogs.GpxAppearanceAdapter.getAppearanceItems;
import static net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.UPDATE_TRACK_ICON;
import static net.osmand.plus.monitoring.TripRecordingBottomSheet.UPDATE_TRACK_ICON;
public class TrackAppearanceFragment extends ContextMenuScrollFragment implements CardListener, ColorPickerListener {
@ -398,10 +398,10 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
@Override
public void onContextMenuDismiss(@NonNull ContextMenuFragment fragment) {
Fragment target = getTargetFragment();
if (target instanceof TripRecordingBottomSheet) {
((TripRecordingBottomSheet) target).show();
} else if (target instanceof TripRecordingActiveBottomSheet) {
((TripRecordingActiveBottomSheet) target).show(UPDATE_TRACK_ICON);
if (target instanceof TripRecordingStartingBottomSheet) {
((TripRecordingStartingBottomSheet) target).show();
} else if (target instanceof TripRecordingBottomSheet) {
((TripRecordingBottomSheet) target).show(UPDATE_TRACK_ICON);
}
}

View file

@ -135,7 +135,7 @@ public class TrackColoringCard extends BaseCard {
updateHeader();
}
private class TrackColoringAdapter extends RecyclerView.Adapter<TrackAppearanceViewHolder> {
private class TrackColoringAdapter extends RecyclerView.Adapter<AppearanceViewHolder> {
private List<TrackAppearanceItem> items;
@ -145,16 +145,16 @@ public class TrackColoringCard extends BaseCard {
@NonNull
@Override
public TrackAppearanceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
public AppearanceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater themedInflater = UiUtilities.getInflater(parent.getContext(), nightMode);
View view = themedInflater.inflate(R.layout.point_editor_group_select_item, parent, false);
view.getLayoutParams().width = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_width);
view.getLayoutParams().height = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_height);
return new TrackAppearanceViewHolder(view);
return new AppearanceViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final TrackAppearanceViewHolder holder, int position) {
public void onBindViewHolder(@NonNull final AppearanceViewHolder holder, int position) {
final TrackAppearanceItem item = items.get(position);
if (item.isActive() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@ -186,7 +186,7 @@ public class TrackColoringCard extends BaseCard {
});
}
private void updateButtonBg(TrackAppearanceViewHolder holder, TrackAppearanceItem item) {
private void updateButtonBg(AppearanceViewHolder holder, TrackAppearanceItem item) {
GradientDrawable rectContourDrawable = (GradientDrawable) AppCompatResources.getDrawable(app, R.drawable.bg_select_group_button_outline);
if (rectContourDrawable != null) {
Context ctx = holder.itemView.getContext();
@ -217,7 +217,7 @@ public class TrackColoringCard extends BaseCard {
}
}
private void updateTextAndIconColor(TrackAppearanceViewHolder holder, TrackAppearanceItem item) {
private void updateTextAndIconColor(AppearanceViewHolder holder, TrackAppearanceItem item) {
Context ctx = holder.itemView.getContext();
boolean isSelected = item.getAttrName().equals(getSelectedAppearanceItem().getAttrName());
int iconColorId;

View file

@ -114,6 +114,12 @@ public class TrackPointsCard extends BaseCard implements OnChildClickListener, O
this.selectedGroup = selectedGroup;
}
public void updateGroups() {
selectedItems.clear();
selectedGroups.clear();
adapter.synchronizeGroups(getDisplayGroups());
}
public List<GpxDisplayGroup> getGroups() {
return adapter.groups;
}
@ -263,9 +269,7 @@ public class TrackPointsCard extends BaseCard implements OnChildClickListener, O
@Override
public void onPointsDeleted() {
selectedItems.clear();
selectedGroups.clear();
adapter.synchronizeGroups(getDisplayGroups());
updateGroups();
}
public void filter(String text) {

View file

@ -184,7 +184,7 @@ public class TrackWidthCard extends BaseCard {
}
}
private class GpxWidthAdapter extends RecyclerView.Adapter<TrackAppearanceViewHolder> {
private class GpxWidthAdapter extends RecyclerView.Adapter<AppearanceViewHolder> {
private List<AppearanceListItem> items;
@ -194,13 +194,13 @@ public class TrackWidthCard extends BaseCard {
@NonNull
@Override
public TrackAppearanceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
public AppearanceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater themedInflater = UiUtilities.getInflater(parent.getContext(), nightMode);
View view = themedInflater.inflate(R.layout.point_editor_group_select_item, parent, false);
view.getLayoutParams().width = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_width);
view.getLayoutParams().height = app.getResources().getDimensionPixelSize(R.dimen.gpx_group_button_height);
TrackAppearanceViewHolder holder = new TrackAppearanceViewHolder(view);
AppearanceViewHolder holder = new AppearanceViewHolder(view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, holder.button, nightMode, R.drawable.ripple_solid_light_6dp,
R.drawable.ripple_solid_dark_6dp);
@ -209,7 +209,7 @@ public class TrackWidthCard extends BaseCard {
}
@Override
public void onBindViewHolder(@NonNull final TrackAppearanceViewHolder holder, int position) {
public void onBindViewHolder(@NonNull final AppearanceViewHolder holder, int position) {
AppearanceListItem item = items.get(position);
holder.title.setText(item.getLocalizedValue());
@ -238,7 +238,7 @@ public class TrackWidthCard extends BaseCard {
});
}
private void updateWidthIcon(TrackAppearanceViewHolder holder, AppearanceListItem item) {
private void updateWidthIcon(AppearanceViewHolder holder, AppearanceListItem item) {
int color = trackDrawInfo.getColor();
int iconId;
@ -251,7 +251,7 @@ public class TrackWidthCard extends BaseCard {
holder.icon.setImageDrawable(app.getUIUtilities().getPaintedIcon(iconId, color));
}
private void updateButtonBg(TrackAppearanceViewHolder holder, AppearanceListItem item) {
private void updateButtonBg(AppearanceViewHolder holder, AppearanceListItem item) {
GradientDrawable rectContourDrawable = (GradientDrawable) AppCompatResources.getDrawable(app, R.drawable.bg_select_group_button_outline);
if (rectContourDrawable != null) {
if (getSelectedItem() != null && getSelectedItem().equals(item)) {

View file

@ -147,6 +147,7 @@ public class AddGpxPointBottomSheetHelper implements OnDismissListener {
private void onClose() {
TrackMenuFragment fragment = mapActivity.getTrackMenuFragment();
if (fragment != null) {
fragment.updateContent();
fragment.show();
} else {
TrackMenuFragment.openTrack(mapActivity, new File(newGpxPoint.getGpx().path), null);

View file

@ -377,6 +377,7 @@ public abstract class OsmandMapLayer {
public Paint paint;
public Paint customColorPaint;
public int customColor = 0;
public float customWidth = 0;
public int defaultWidth = 0;
public int defaultColor = 0;
public boolean isPaint2;
@ -481,8 +482,13 @@ public abstract class OsmandMapLayer {
if (isShadowPaint) {
canvas.drawPath(path, shadowPaint);
}
if (customColor != 0) {
customColorPaint.setColor(customColor);
if (customColor != 0 || customWidth != 0) {
if (customColor != 0) {
customColorPaint.setColor(customColor);
}
if (customWidth != 0) {
customColorPaint.setStrokeWidth(customWidth);
}
canvas.drawPath(path, customColorPaint);
} else {
canvas.drawPath(path, paint);

Some files were not shown because too many files have changed in this diff Show more