commit
29e49d6271
11 changed files with 493 additions and 67 deletions
19
OsmAnd/res/drawable/seekbar_progress_announcement_time.xml
Normal file
19
OsmAnd/res/drawable/seekbar_progress_announcement_time.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:id="@android:id/background">
|
||||
<shape android:shape="rectangle" >
|
||||
<solid
|
||||
android:color="#4d007eb3" />
|
||||
<corners android:radius="30dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape android:shape="rectangle" >
|
||||
<solid
|
||||
android:color="@color/profile_icon_color_blue_light" />
|
||||
<corners android:radius="30dp" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
12
OsmAnd/res/drawable/seekbar_thumb_announcement_time.xml
Normal file
12
OsmAnd/res/drawable/seekbar_thumb_announcement_time.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<size
|
||||
android:height="12dp"
|
||||
android:width="12dp" />
|
||||
<solid android:color="@color/profile_icon_color_blue_light" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<size
|
||||
android:width="2dp"
|
||||
android:height="2dp" />
|
||||
<solid android:color="#17181A" />
|
||||
</shape>
|
143
OsmAnd/res/layout/bottom_sheet_announcement_time.xml
Normal file
143
OsmAnd/res/layout/bottom_sheet_announcement_time.xml
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?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:paddingBottom="@dimen/bottom_sheet_exit_button_margin">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="wrap_content"
|
||||
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:gravity="center_vertical"
|
||||
android:text="@string/announcement_time_title"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:typeface="@string/font_roboto_medium" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
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:lineSpacingMultiplier="1.1"
|
||||
android:text="@string/announcement_time_descr"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_illustration"
|
||||
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:adjustViewBounds="true"
|
||||
osmand:srcCompat="?attr/image_help_announcement_time" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/tv_seek_bar_label"
|
||||
android:layout_width="wrap_content"
|
||||
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:textColor="?attr/active_color_basic"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:typeface="@string/font_roboto_medium"
|
||||
tools:text="Normal" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seek_bar_arrival"
|
||||
style="@style/Widget.AppCompat.SeekBar.Discrete"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/pages_item_margin"
|
||||
android:maxHeight="2dp"
|
||||
android:paddingTop="11dp"
|
||||
android:paddingBottom="11dp"
|
||||
android:progressDrawable="@drawable/seekbar_progress_announcement_time"
|
||||
android:thumb="@drawable/seekbar_thumb_announcement_time"
|
||||
osmand:tickMark="@drawable/seekbar_tickmark_announcement_time"
|
||||
tools:max="3"
|
||||
tools:progress="1" />
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="@dimen/content_padding_small"
|
||||
android:background="?attr/divider_color_basic" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/description_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
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">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/announcement_time_intervals"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tint="?attr/default_icon_color"
|
||||
app:srcCompat="@drawable/ic_action_arrow_down" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/tv_interval_descr"
|
||||
android:layout_width="wrap_content"
|
||||
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:lineSpacingMultiplier="@dimen/line_spacing_multiplier_description"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
android:visibility="gone"
|
||||
osmand:typeface="@string/font_roboto_regular"
|
||||
tools:text="Turn
|
||||
\n • Prepare: 315 - 320 m, 110 sec.
|
||||
\n • Approach: 60 - 65 m, 20 sec.
|
||||
\n • Passing: 5 - 10 m, 3 sec.
|
||||
\nArrive at destination: 5 - 10 m, 2 sec.
|
||||
\nOff-route: 25 - 30 m, 9 sec.
|
||||
\nTraffic warnings
|
||||
\n • Approach: 5 - 10 m, 3 sec.
|
||||
\n • Passing: 15 - 20 m, 4 sec.
|
||||
\nWaypoint / Favourite / POI
|
||||
\n • Approach: 80 - 85 m, 25 sec
|
||||
\n • Passing: 20 - 25 m, 7 sec. "
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
|
@ -140,6 +140,7 @@
|
|||
<attr name="btn_radio_button_center" format="reference"/>
|
||||
<attr name="bg_dash_line" format="reference"/>
|
||||
<attr name="text_input_background" format="reference"/>
|
||||
<attr name="image_help_announcement_time" format="reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="PagerSlidingTabStrip">
|
||||
|
|
|
@ -12,6 +12,17 @@
|
|||
|
||||
-->
|
||||
|
||||
<string name="announcement_time_title">Announcement time</string>
|
||||
<string name="announcement_time_descr">Announcement time of different voice prompts depends on prompt type, current navigation speed and default navigation speed.</string>
|
||||
<string name="announcement_time_intervals">Time and distance intervals</string>
|
||||
<string name="shared_string_turn">Turn</string>
|
||||
<string name="announcement_time_arrive">Arrive at destination</string>
|
||||
<string name="announcement_time_off_route">Off route</string>
|
||||
<string name="announcement_time_prepare">Prepare</string>
|
||||
<string name="announcement_time_prepare_long">Long prepare</string>
|
||||
<string name="announcement_time_approach">Approach</string>
|
||||
<string name="announcement_time_passing">Passing</string>
|
||||
<string name="shared_string_sec">sec</string>
|
||||
<string name="change_folder">Change folder</string>
|
||||
<string name="rename_track">Rename track</string>
|
||||
<string name="edit_track">Edit track</string>
|
||||
|
|
|
@ -247,6 +247,7 @@
|
|||
<item name="checkboxStyle">@style/CheckboxStyle</item>
|
||||
<item name="radioButtonStyle">@style/RadioButtonStyle</item>
|
||||
<item name="text_input_background">@color/text_input_background_light</item>
|
||||
<item name="image_help_announcement_time">@drawable/img_help_announcement_time_day</item>
|
||||
</style>
|
||||
|
||||
<style name="ToolbarStyle" parent="@style/Widget.AppCompat.Toolbar">
|
||||
|
@ -543,6 +544,7 @@
|
|||
<item name="checkboxStyle">@style/CheckboxStyle</item>
|
||||
<item name="radioButtonStyle">@style/RadioButtonStyle</item>
|
||||
<item name="text_input_background">@color/text_input_background_dark</item>
|
||||
<item name="image_help_announcement_time">@drawable/img_help_announcement_time_night</item>
|
||||
</style>
|
||||
|
||||
<style name="FreeVersionBanner" parent="OsmandDarkTheme">
|
||||
|
|
|
@ -91,12 +91,6 @@
|
|||
android:layout="@layout/preference_with_descr"
|
||||
android:title="@string/arrival_distance" />
|
||||
|
||||
<Preference
|
||||
android:key="voice_prompts_timetable"
|
||||
android:layout="@layout/preference_with_descr"
|
||||
android:persistent="false"
|
||||
android:title="@string/voice_prompts_timetable" />
|
||||
|
||||
<Preference
|
||||
android:layout="@layout/simple_divider_item"
|
||||
android:selectable="false" />
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
package net.osmand.plus.routing.data;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.StyleSpan;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
|
||||
|
@ -78,29 +84,7 @@ public class AnnounceTimeDistances {
|
|||
PREPARE_DISTANCE_END = PREPARE_DISTANCE * 2;
|
||||
}
|
||||
|
||||
float ARRIVAL_DISTANCE_FACTOR = Math.max(settings.ARRIVAL_DISTANCE_FACTOR.getModeValue(appMode), 0.1f);
|
||||
|
||||
// Turn now: 3.5 s normal speed, 7 s for half speed (default)
|
||||
// float TURN_NOW_TIME = 7;
|
||||
// ** #8749 to keep 1m / 1 sec precision (POSITIONING_TOLERANCE = 12 m)
|
||||
// car 50 km/h - 7 s, bicycle 10 km/h - 3 s, pedestrian 4 km/h - 2 s, 1 km/h - 1 s
|
||||
float TURN_NOW_TIME = (float) Math.min(Math.sqrt(DEFAULT_SPEED * 3.6), 8);
|
||||
|
||||
// 3.6 s: car 45 m, bicycle 10 m -> 12 m, pedestrian 4 m -> 12 m (capped by POSITIONING_TOLERANCE)
|
||||
TURN_NOW_DISTANCE = (int) (Math.max(POSITIONING_TOLERANCE, DEFAULT_SPEED * 3.6) * ARRIVAL_DISTANCE_FACTOR);
|
||||
TURN_NOW_SPEED = TURN_NOW_DISTANCE / TURN_NOW_TIME;
|
||||
|
||||
// 5 s: car 63 m, bicycle 14 m, pedestrian 6 m -> 12 m (capped by POSITIONING_TOLERANCE)
|
||||
ARRIVAL_DISTANCE = (int) (Math.max(POSITIONING_TOLERANCE, DEFAULT_SPEED * 5.) * ARRIVAL_DISTANCE_FACTOR);
|
||||
|
||||
// 20 s: car 250 m, bicycle 56 m, pedestrian 22 m
|
||||
OFF_ROUTE_DISTANCE = DEFAULT_SPEED * 20 * ARRIVAL_DISTANCE_FACTOR; // 20 seconds
|
||||
|
||||
// assume for backward compatibility speed - 10 m/s
|
||||
SHORT_ALARM_ANNOUNCE_RADIUS = (int) (7 * DEFAULT_SPEED * ARRIVAL_DISTANCE_FACTOR); // 70 m
|
||||
LONG_ALARM_ANNOUNCE_RADIUS = (int) (12 * DEFAULT_SPEED * ARRIVAL_DISTANCE_FACTOR); // 120 m
|
||||
SHORT_PNT_ANNOUNCE_RADIUS = (int) (15 * DEFAULT_SPEED * ARRIVAL_DISTANCE_FACTOR); // 150 m
|
||||
LONG_PNT_ANNOUNCE_RADIUS = (int) (60 * DEFAULT_SPEED * ARRIVAL_DISTANCE_FACTOR); // 600 m
|
||||
setArrivalDistances(settings.ARRIVAL_DISTANCE_FACTOR.getModeValue(appMode));
|
||||
|
||||
// Trigger close prompts earlier to allow BT SCO link being established, or when VOICE_PROMPT_DELAY is set >0 for the other stream types
|
||||
int ams = settings.AUDIO_MANAGER_STREAM.getModeValue(appMode);
|
||||
|
@ -111,6 +95,31 @@ public class AnnounceTimeDistances {
|
|||
}
|
||||
}
|
||||
|
||||
public void setArrivalDistances(float arrivalDistanceFactor) {
|
||||
arrivalDistanceFactor = Math.max(arrivalDistanceFactor, 0.1f);
|
||||
// Turn now: 3.5 s normal speed, 7 s for half speed (default)
|
||||
// float TURN_NOW_TIME = 7;
|
||||
// ** #8749 to keep 1m / 1 sec precision (POSITIONING_TOLERANCE = 12 m)
|
||||
// car 50 km/h - 7 s, bicycle 10 km/h - 3 s, pedestrian 4 km/h - 2 s, 1 km/h - 1 s
|
||||
float TURN_NOW_TIME = (float) Math.min(Math.sqrt(DEFAULT_SPEED * 3.6), 8);
|
||||
|
||||
// 3.6 s: car 45 m, bicycle 10 m -> 12 m, pedestrian 4 m -> 12 m (capped by POSITIONING_TOLERANCE)
|
||||
TURN_NOW_DISTANCE = (int) (Math.max(POSITIONING_TOLERANCE, DEFAULT_SPEED * 3.6) * arrivalDistanceFactor);
|
||||
TURN_NOW_SPEED = TURN_NOW_DISTANCE / TURN_NOW_TIME;
|
||||
|
||||
// 5 s: car 63 m, bicycle 14 m, pedestrian 6 m -> 12 m (capped by POSITIONING_TOLERANCE)
|
||||
ARRIVAL_DISTANCE = (int) (Math.max(POSITIONING_TOLERANCE, DEFAULT_SPEED * 5.) * arrivalDistanceFactor);
|
||||
|
||||
// 20 s: car 250 m, bicycle 56 m, pedestrian 22 m
|
||||
OFF_ROUTE_DISTANCE = DEFAULT_SPEED * 20 * arrivalDistanceFactor; // 20 seconds
|
||||
|
||||
// assume for backward compatibility speed - 10 m/s
|
||||
SHORT_ALARM_ANNOUNCE_RADIUS = (int) (7 * DEFAULT_SPEED * arrivalDistanceFactor); // 70 m
|
||||
LONG_ALARM_ANNOUNCE_RADIUS = (int) (12 * DEFAULT_SPEED * arrivalDistanceFactor); // 120 m
|
||||
SHORT_PNT_ANNOUNCE_RADIUS = (int) (15 * DEFAULT_SPEED * arrivalDistanceFactor); // 150 m
|
||||
LONG_PNT_ANNOUNCE_RADIUS = (int) (60 * DEFAULT_SPEED * arrivalDistanceFactor); // 600 m
|
||||
}
|
||||
|
||||
public int getImminentTurnStatus(float dist, Location loc) {
|
||||
float speed = getSpeed(loc);
|
||||
if (isTurnStateActive(speed, dist, STATE_TURN_NOW)) {
|
||||
|
@ -199,38 +208,87 @@ public class AnnounceTimeDistances {
|
|||
return (int) (dist - voicePromptDelayTimeSec * speed);
|
||||
}
|
||||
|
||||
private void appendTurnDesc(StringBuilder s, String name, int dist) {
|
||||
appendTurnDesc(s, name, dist, DEFAULT_SPEED);
|
||||
private void appendTurnDesc(SpannableStringBuilder builder, String name, int dist, String meter, String second) {
|
||||
appendTurnDesc(builder, name, dist, DEFAULT_SPEED, meter, second);
|
||||
}
|
||||
|
||||
private void appendTurnDesc(StringBuilder s, String name, int dist, float speed) {
|
||||
private void appendTurnDesc(SpannableStringBuilder builder, String name, int dist, float speed, String meter, String second) {
|
||||
int minDist = (dist / 5) * 5;
|
||||
int time = (int) (dist / speed);
|
||||
if (time > 15) {
|
||||
// round to 5
|
||||
time = (time / 5) * 5;
|
||||
}
|
||||
s.append(String.format("%s: %d - %d m, %d sec\n", name, minDist, minDist + 5, time));
|
||||
builder.append(String.format("\n%s: %d - %d %s, %d %s.", name, minDist, minDist + 5, meter, time, second));
|
||||
}
|
||||
|
||||
public String getTurnsDescription() {
|
||||
StringBuilder turnDescriptions = new StringBuilder();
|
||||
appendTurnDesc(turnDescriptions, "Turn (now)", TURN_NOW_DISTANCE, TURN_NOW_SPEED);
|
||||
appendTurnDesc(turnDescriptions, "Turn (approach)", TURN_IN_DISTANCE);
|
||||
public Spannable getIntervalsDescription(OsmandApplication app) {
|
||||
String meter = app.getString(R.string.m);
|
||||
String second = app.getString(R.string.shared_string_sec);
|
||||
String turn = app.getString(R.string.shared_string_turn);
|
||||
String arrive = app.getString(R.string.announcement_time_arrive);
|
||||
String offRoute = app.getString(R.string.announcement_time_off_route);
|
||||
String traffic = "\n" + app.getString(R.string.way_alarms);
|
||||
String point = "\n" + String.format(
|
||||
"%s / %s / %s", app.getString(R.string.shared_string_waypoint),
|
||||
app.getString(R.string.favorite), app.getString(R.string.poi)
|
||||
);
|
||||
|
||||
String prepare = " • " + app.getString(R.string.announcement_time_prepare);
|
||||
String longPrepare = " • " + app.getString(R.string.announcement_time_prepare_long);
|
||||
String approach = " • " + app.getString(R.string.announcement_time_approach);
|
||||
String passing = " • " + app.getString(R.string.announcement_time_passing);
|
||||
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||
|
||||
// Turn
|
||||
builder.append(turn);
|
||||
makeBold(builder, turn);
|
||||
if (PREPARE_DISTANCE_END <= PREPARE_DISTANCE) {
|
||||
appendTurnDesc(turnDescriptions, "Turn (prepare)", PREPARE_DISTANCE);
|
||||
appendTurnDesc(builder, prepare, PREPARE_DISTANCE, meter, second);
|
||||
}
|
||||
if (PREPARE_LONG_DISTANCE_END <= PREPARE_LONG_DISTANCE) {
|
||||
appendTurnDesc(turnDescriptions, "Turn (early prepare)", PREPARE_LONG_DISTANCE);
|
||||
appendTurnDesc(builder, longPrepare, PREPARE_LONG_DISTANCE, meter, second);
|
||||
}
|
||||
appendTurnDesc(turnDescriptions, "Arrival", (int) getArrivalDistance());
|
||||
appendTurnDesc(builder, approach, TURN_IN_DISTANCE, meter, second);
|
||||
appendTurnDesc(builder, passing, TURN_NOW_DISTANCE, TURN_NOW_SPEED, meter, second);
|
||||
|
||||
// Arrive at destination
|
||||
appendTurnDesc(builder, arrive, (int) (getArrivalDistance()), meter, second);
|
||||
makeBoldFormatted(builder, arrive);
|
||||
|
||||
// Off-route
|
||||
if (getOffRouteDistance() > 0) {
|
||||
appendTurnDesc(turnDescriptions, "Off-route", (int) getOffRouteDistance());
|
||||
appendTurnDesc(builder, offRoute, (int) getOffRouteDistance(), meter, second);
|
||||
makeBoldFormatted(builder, offRoute);
|
||||
}
|
||||
appendTurnDesc(turnDescriptions, "Alarm (close)", SHORT_ALARM_ANNOUNCE_RADIUS);
|
||||
appendTurnDesc(turnDescriptions, "Alarm (standard)", LONG_ALARM_ANNOUNCE_RADIUS);
|
||||
appendTurnDesc(turnDescriptions, "Waypoint / fav / POI (passing)", SHORT_PNT_ANNOUNCE_RADIUS);
|
||||
appendTurnDesc(turnDescriptions, "Waypoint / fav / POI (approaching)", LONG_PNT_ANNOUNCE_RADIUS);
|
||||
return turnDescriptions.toString();
|
||||
|
||||
// Traffic warnings
|
||||
builder.append(traffic);
|
||||
makeBold(builder, traffic);
|
||||
appendTurnDesc(builder, approach, LONG_ALARM_ANNOUNCE_RADIUS, meter, second);
|
||||
appendTurnDesc(builder, passing, SHORT_ALARM_ANNOUNCE_RADIUS, meter, second);
|
||||
|
||||
// Waypoint / Favorite / POI
|
||||
builder.append(point);
|
||||
makeBold(builder, point);
|
||||
appendTurnDesc(builder, approach, LONG_PNT_ANNOUNCE_RADIUS, meter, second);
|
||||
appendTurnDesc(builder, passing, SHORT_PNT_ANNOUNCE_RADIUS, meter, second);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void makeBold(SpannableStringBuilder b, String word) {
|
||||
int end = b.length();
|
||||
int start = end - word.length();
|
||||
b.setSpan(new StyleSpan(Typeface.BOLD), start, end,
|
||||
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
private void makeBoldFormatted(SpannableStringBuilder b, String word) {
|
||||
int start = b.toString().indexOf(word);
|
||||
int end = start + word.length() + 1;
|
||||
b.setSpan(new StyleSpan(Typeface.BOLD), start, end,
|
||||
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
package net.osmand.plus.settings.bottomsheets;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.plus.routing.data.AnnounceTimeDistances;
|
||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||
import net.osmand.plus.settings.fragments.OnPreferenceChanged;
|
||||
import net.osmand.plus.settings.preferences.ListPreferenceEx;
|
||||
import net.osmand.plus.widgets.TextViewEx;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import static net.osmand.plus.settings.bottomsheets.SingleSelectPreferenceBottomSheet.SELECTED_ENTRY_INDEX_KEY;
|
||||
|
||||
|
||||
public class AnnouncementTimeBottomSheet extends BasePreferenceBottomSheet
|
||||
implements SeekBar.OnSeekBarChangeListener {
|
||||
|
||||
public static final String TAG = AnnouncementTimeBottomSheet.class.getSimpleName();
|
||||
private static final Log LOG = PlatformUtil.getLog(AnnouncementTimeBottomSheet.class);
|
||||
|
||||
private OsmandApplication app;
|
||||
private AnnounceTimeDistances announceTimeDistances;
|
||||
|
||||
private ListPreferenceEx listPreference;
|
||||
private int selectedEntryIndex = -1;
|
||||
|
||||
private TextViewEx tvSeekBarLabel;
|
||||
private SeekBar seekBarArrival;
|
||||
private ImageView ivArrow;
|
||||
private TextViewEx tvIntervalsDescr;
|
||||
|
||||
private boolean collapsed = true;
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
app = requiredMyApplication();
|
||||
announceTimeDistances = new AnnounceTimeDistances(getAppMode(), app.getSettings());
|
||||
|
||||
listPreference = getListPreference();
|
||||
if (listPreference == null || listPreference.getEntries() == null ||
|
||||
listPreference.getEntryValues() == null) {
|
||||
return;
|
||||
}
|
||||
if (savedInstanceState != null) {
|
||||
selectedEntryIndex = savedInstanceState.getInt(SELECTED_ENTRY_INDEX_KEY);
|
||||
} else {
|
||||
selectedEntryIndex = listPreference.findIndexOfValue(listPreference.getValue());
|
||||
}
|
||||
|
||||
items.add(createBottomSheetItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(SELECTED_ENTRY_INDEX_KEY, selectedEntryIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDismissButtonTextId() {
|
||||
return R.string.shared_string_cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getRightBottomButtonTextId() {
|
||||
return R.string.shared_string_apply;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRightBottomButtonClick() {
|
||||
Object[] entryValues = listPreference.getEntryValues();
|
||||
if (entryValues != null && selectedEntryIndex >= 0) {
|
||||
Object value = entryValues[selectedEntryIndex];
|
||||
if (listPreference.callChangeListener(value)) {
|
||||
listPreference.setValue(value);
|
||||
}
|
||||
Fragment target = getTargetFragment();
|
||||
if (target instanceof OnPreferenceChanged) {
|
||||
((OnPreferenceChanged) target).onPreferenceChanged(listPreference.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (progress != selectedEntryIndex) {
|
||||
selectedEntryIndex = progress;
|
||||
updateViews();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
private ListPreferenceEx getListPreference() {
|
||||
return (ListPreferenceEx) getPreference();
|
||||
}
|
||||
|
||||
private BaseBottomSheetItem createBottomSheetItem() {
|
||||
View rootView = UiUtilities.getInflater(getContext(), nightMode)
|
||||
.inflate(R.layout.bottom_sheet_announcement_time, null);
|
||||
|
||||
tvSeekBarLabel = rootView.findViewById(R.id.tv_seek_bar_label);
|
||||
seekBarArrival = rootView.findViewById(R.id.seek_bar_arrival);
|
||||
ivArrow = rootView.findViewById(R.id.iv_arrow);
|
||||
tvIntervalsDescr = rootView.findViewById(R.id.tv_interval_descr);
|
||||
|
||||
seekBarArrival.setOnSeekBarChangeListener(this);
|
||||
seekBarArrival.setMax(listPreference.getEntries().length - 1);
|
||||
rootView.findViewById(R.id.description_container).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
toggleDescriptionVisibility();
|
||||
}
|
||||
});
|
||||
|
||||
return new BaseBottomSheetItem.Builder()
|
||||
.setCustomView(rootView)
|
||||
.create();
|
||||
}
|
||||
|
||||
private void updateViews() {
|
||||
seekBarArrival.setProgress(selectedEntryIndex);
|
||||
tvSeekBarLabel.setText(listPreference.getEntries()[selectedEntryIndex]);
|
||||
|
||||
float value = (float) listPreference.getEntryValues()[selectedEntryIndex];
|
||||
announceTimeDistances.setArrivalDistances(value);
|
||||
tvIntervalsDescr.setText(announceTimeDistances.getIntervalsDescription(app));
|
||||
}
|
||||
|
||||
private void toggleDescriptionVisibility() {
|
||||
collapsed = !collapsed;
|
||||
ivArrow.setImageResource(collapsed ? R.drawable.ic_action_arrow_down : R.drawable.ic_action_arrow_up);
|
||||
AndroidUiHelper.updateVisibility(tvIntervalsDescr, !collapsed);
|
||||
}
|
||||
|
||||
public static void showInstance(@NonNull FragmentManager fm, String prefKey, Fragment target,
|
||||
@Nullable ApplicationMode appMode, boolean usedOnMap) {
|
||||
try {
|
||||
if (!fm.isStateSaved()) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(PREFERENCE_ID, prefKey);
|
||||
AnnouncementTimeBottomSheet fragment = new AnnouncementTimeBottomSheet();
|
||||
fragment.setArguments(args);
|
||||
fragment.setAppMode(appMode);
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setTargetFragment(target, 0);
|
||||
fragment.show(fm, TAG);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error("showInstance", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,12 +12,12 @@ import android.widget.TextView;
|
|||
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.plus.OsmandPlugin;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.Version;
|
||||
|
@ -27,9 +27,9 @@ import net.osmand.plus.download.DownloadActivity;
|
|||
import net.osmand.plus.download.DownloadActivityType;
|
||||
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
||||
import net.osmand.plus.helpers.enums.MetricsConstants;
|
||||
import net.osmand.plus.routing.data.AnnounceTimeDistances;
|
||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.settings.bottomsheets.AnnouncementTimeBottomSheet;
|
||||
import net.osmand.plus.settings.preferences.ListPreferenceEx;
|
||||
|
||||
import java.util.Set;
|
||||
|
@ -42,7 +42,6 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
|||
public static final String TAG = VoiceAnnouncesFragment.class.getSimpleName();
|
||||
|
||||
private static final String MORE_VALUE = "MORE_VALUE";
|
||||
private static final String VOICE_PROMPTS_TIMETABLE = "voice_prompts_timetable";
|
||||
|
||||
@Override
|
||||
protected void createToolbar(LayoutInflater inflater, View view) {
|
||||
|
@ -96,7 +95,6 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
|||
|
||||
setupKeepInformingPref();
|
||||
setupArrivalAnnouncementPref();
|
||||
updateVoicePromptsTimes();
|
||||
setupVoiceProviderPref();
|
||||
|
||||
if (!Version.isBlackberry(app)) {
|
||||
|
@ -108,17 +106,6 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
|||
setupSpeedCamerasAlert();
|
||||
}
|
||||
|
||||
private void updateVoicePromptsTimes() {
|
||||
Preference pref = findPreference(VOICE_PROMPTS_TIMETABLE);
|
||||
if (OsmandPlugin.isDevelopment()) {
|
||||
AnnounceTimeDistances atd = new AnnounceTimeDistances(getSelectedAppMode(), settings);
|
||||
pref.setSummary(atd.getTurnsDescription().trim());
|
||||
pref.setVisible(true);
|
||||
} else {
|
||||
pref.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupSpeedLimitExceedPref() {
|
||||
//array size must be equal!
|
||||
Float[] valuesKmh = new Float[] {-10f, -7f, -5f, 0f, 5f, 7f, 10f, 15f, 20f};
|
||||
|
@ -274,9 +261,6 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
|||
settings.SPEAK_SPEED_CAMERA.getId(), false, ApplyQueryType.SNACK_BAR);
|
||||
}
|
||||
}
|
||||
if (prefId.equals(settings.ARRIVAL_DISTANCE_FACTOR.getId())) {
|
||||
updateVoicePromptsTimes();
|
||||
}
|
||||
if (prefId.equals(settings.AUDIO_MANAGER_STREAM.getId())) {
|
||||
return onConfirmPreferenceChange(
|
||||
settings.AUDIO_MANAGER_STREAM.getId(), newValue, ApplyQueryType.SNACK_BAR);
|
||||
|
@ -314,12 +298,24 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
|||
String prefId = preference.getKey();
|
||||
if (settings.SPEED_CAMERAS_UNINSTALLED.getId().equals(prefId)) {
|
||||
SpeedCamerasBottomSheet.showInstance(requireActivity().getSupportFragmentManager(), this);
|
||||
} else if (VOICE_PROMPTS_TIMETABLE.equals(prefId)) {
|
||||
app.showToastMessage(String.valueOf(preference.getSummary()));
|
||||
}
|
||||
return super.onPreferenceClick(preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayPreferenceDialog(Preference preference) {
|
||||
String prefId = preference.getKey();
|
||||
|
||||
if (settings.ARRIVAL_DISTANCE_FACTOR.getId().equals(prefId)) {
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
if (fragmentManager != null) {
|
||||
AnnouncementTimeBottomSheet.showInstance(fragmentManager, preference.getKey(), this, getSelectedAppMode(), false);
|
||||
}
|
||||
} else {
|
||||
super.onDisplayPreferenceDialog(preference);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreferenceChanged(String prefId) {
|
||||
if (prefId.equals(settings.SPEED_CAMERAS_UNINSTALLED.getId())) {
|
||||
|
|
Loading…
Reference in a new issue