Merge branch 'r3.3' into app_profiles

# Conflicts:
#	OsmAnd/res/values/sizes.xml
#	OsmAnd/res/values/strings.xml
This commit is contained in:
madwasp79 2019-04-10 09:32:20 +03:00
commit 7cbd9bd8c8
108 changed files with 5904 additions and 5028 deletions

View file

@ -1,47 +1,98 @@
// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.openlocationcode;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
* Representation of open location code. https://github.com/google/open-location-code The
* OpenLocationCode class is a wrapper around String value {@code code}, which guarantees that the
* value is a valid Open Location Code.
* Convert locations to and from convenient short codes.
*
* Open Location Codes are short, ~10 character codes that can be used instead of street
* addresses. The codes can be generated and decoded offline, and use a reduced character set that
* minimises the chance of codes including words.
*
* This provides both object and static methods.
*
* Create an object with:
* OpenLocationCode code = new OpenLocationCode("7JVW52GR+2V");
* OpenLocationCode code = new OpenLocationCode("52GR+2V");
* OpenLocationCode code = new OpenLocationCode(27.175063, 78.042188);
* OpenLocationCode code = new OpenLocationCode(27.175063, 78.042188, 11);
*
* Once you have a code object, you can apply the other methods to it, such as to shorten:
* code.shorten(27.176, 78.05)
*
* Recover the nearest match (if the code was a short code):
* code.recover(27.176, 78.05)
*
* Or decode a code into its coordinates, returning a CodeArea object.
* code.decode()
*
* @author Jiri Semecky
* @author Doug Rinckes
*/
public final class OpenLocationCode {
private static final BigDecimal BD_0 = new BigDecimal(0);
private static final BigDecimal BD_5 = new BigDecimal(5);
private static final BigDecimal BD_4 = new BigDecimal(4);
private static final BigDecimal BD_20 = new BigDecimal(20);
private static final BigDecimal BD_90 = new BigDecimal(90);
private static final BigDecimal BD_180 = new BigDecimal(180);
private static final double LATITUDE_PRECISION_8_DIGITS = computeLatitudePrecision(8) / 4;
private static final double LATITUDE_PRECISION_6_DIGITS = computeLatitudePrecision(6) / 4;
private static final double LATITUDE_PRECISION_4_DIGITS = computeLatitudePrecision(4) / 4;
// Provides a normal precision code, approximately 14x14 meters.
public static final int CODE_PRECISION_NORMAL = 10;
private static final char[] ALPHABET = "23456789CFGHJMPQRVWX".toCharArray();
private static final Map<Character, Integer> CHARACTER_TO_INDEX = new HashMap<>();
// The character set used to encode the values.
public static final String CODE_ALPHABET = "23456789CFGHJMPQRVWX";
static {
int index = 0;
for (char character : ALPHABET) {
char lowerCaseCharacter = Character.toLowerCase(character);
CHARACTER_TO_INDEX.put(character, index);
CHARACTER_TO_INDEX.put(lowerCaseCharacter, index);
index++;
}
}
// A separator used to break the code into two parts to aid memorability.
public static final char SEPARATOR = '+';
private static final char SEPARATOR = '+';
private static final char SEPARATOR_POSITION = 8;
private static final char SUFFIX_PADDING = '0';
// The character used to pad codes.
public static final char PADDING_CHARACTER = '0';
/** Class providing information about area covered by Open Location Code. */
public class CodeArea {
// The number of characters to place before the separator.
private static final int SEPARATOR_POSITION = 8;
// The max number of digits to process in a plus code.
public static final int MAX_DIGIT_COUNT = 15;
// Note: The double type can't be used because of the rounding arithmetic due to floating point
// implementation. Eg. "8.95 - 8" can give result 0.9499999999999 instead of 0.95 which
// incorrectly classify the points on the border of a cell. Therefore all the calculation is done
// using BigDecimal.
// The base to use to convert numbers to/from.
private static final BigDecimal ENCODING_BASE = new BigDecimal(CODE_ALPHABET.length());
// The maximum value for latitude in degrees.
private static final BigDecimal LATITUDE_MAX = new BigDecimal(90);
// The maximum value for longitude in degrees.
private static final BigDecimal LONGITUDE_MAX = new BigDecimal(180);
// Maximum code length using just lat/lng pair encoding.
private static final int PAIR_CODE_LENGTH = 10;
// Number of columns in the grid refinement method.
private static final BigDecimal GRID_COLUMNS = new BigDecimal(4);
// Number of rows in the grid refinement method.
private static final BigDecimal GRID_ROWS = new BigDecimal(5);
/**
* Coordinates of a decoded Open Location Code.
*
* <p>The coordinates include the latitude and longitude of the lower left and upper right corners
* and the center of the bounding box for the area the code represents.
*/
public static class CodeArea {
private final BigDecimal southLatitude;
private final BigDecimal westLongitude;
@ -49,10 +100,10 @@ public final class OpenLocationCode {
private final BigDecimal eastLongitude;
public CodeArea(
BigDecimal southLatitude,
BigDecimal westLongitude,
BigDecimal northLatitude,
BigDecimal eastLongitude) {
BigDecimal southLatitude,
BigDecimal westLongitude,
BigDecimal northLatitude,
BigDecimal eastLongitude) {
this.southLatitude = southLatitude;
this.westLongitude = westLongitude;
this.northLatitude = northLatitude;
@ -92,91 +143,111 @@ public final class OpenLocationCode {
}
}
/** The state of the OpenLocationCode. */
/** The current code for objects. */
private final String code;
/** Creates Open Location Code for the provided code. */
/**
* Creates Open Location Code object for the provided code.
* @param code A valid OLC code. Can be a full code or a shortened code.
* @throws IllegalArgumentException when the passed code is not valid.
*/
public OpenLocationCode(String code) {
if (!isValidCode(code)) {
if (!isValidCode(code.toUpperCase())) {
throw new IllegalArgumentException(
"The provided code '" + code + "' is not a valid Open Location Code.");
"The provided code '" + code + "' is not a valid Open Location Code.");
}
this.code = code.toUpperCase();
}
/** Creates Open Location Code from the provided latitude, longitude and desired code length. */
public OpenLocationCode(double latitude, double longitude, int codeLength)
throws IllegalArgumentException {
if (codeLength < 4 || (codeLength < 10 & codeLength % 2 == 1)) {
/**
* Creates Open Location Code.
* @param latitude The latitude in decimal degrees.
* @param longitude The longitude in decimal degrees.
* @param codeLength The desired number of digits in the code.
* @throws IllegalArgumentException if the code length is not valid.
*/
public OpenLocationCode(double latitude, double longitude, int codeLength) {
// Limit the maximum number of digits in the code.
codeLength = Math.min(codeLength, MAX_DIGIT_COUNT);
// Check that the code length requested is valid.
if (codeLength < 4 || (codeLength < PAIR_CODE_LENGTH && codeLength % 2 == 1)) {
throw new IllegalArgumentException("Illegal code length " + codeLength);
}
// Ensure that latitude and longitude are valid.
latitude = clipLatitude(latitude);
longitude = normalizeLongitude(longitude);
// Latitude 90 needs to be adjusted to be just less, so the returned code can also be decoded.
if (latitude == 90) {
if (latitude == LATITUDE_MAX.doubleValue()) {
latitude = latitude - 0.9 * computeLatitudePrecision(codeLength);
}
StringBuilder codeBuilder = new StringBuilder();
// Adjust latitude and longitude to be in positive number ranges.
// We add the max values when creating the BigDecimal (as opposed to creating a BigDecimal and
// then adding the value) to be consistent with the other implementations.
BigDecimal remainingLatitude = new BigDecimal(latitude + LATITUDE_MAX.doubleValue());
BigDecimal remainingLongitude = new BigDecimal(longitude + LONGITUDE_MAX.doubleValue());
// Ensure the latitude and longitude are within [0, 180] and [0, 360) respectively.
/* Note: double type can't be used because of the rounding arithmetic due to floating point
* implementation. Eg. "8.95 - 8" can give result 0.9499999999999 instead of 0.95 which
* incorrectly classify the points on the border of a cell.
*/
BigDecimal remainingLongitude = new BigDecimal(longitude + 180);
BigDecimal remainingLatitude = new BigDecimal(latitude + 90);
// Create up to 10 significant digits from pairs alternating latitude and longitude.
// Count how many digits have been created.
int generatedDigits = 0;
// Store the code.
StringBuilder codeBuilder = new StringBuilder();
// The precisions are initially set to ENCODING_BASE^2 because they will be immediately
// divided.
BigDecimal latPrecision = ENCODING_BASE.multiply(ENCODING_BASE);
BigDecimal lngPrecision = ENCODING_BASE.multiply(ENCODING_BASE);
while (generatedDigits < codeLength) {
// Always the integer part of the remaining latitude/longitude will be used for the following
// digit.
if (generatedDigits == 0) {
// First step World division: Map <0..400) to <0..20) for both latitude and longitude.
remainingLatitude = remainingLatitude.divide(BD_20);
remainingLongitude = remainingLongitude.divide(BD_20);
} else if (generatedDigits < 10) {
remainingLatitude = remainingLatitude.multiply(BD_20);
remainingLongitude = remainingLongitude.multiply(BD_20);
} else {
remainingLatitude = remainingLatitude.multiply(BD_5);
remainingLongitude = remainingLongitude.multiply(BD_4);
}
int latitudeDigit = remainingLatitude.intValue();
int longitudeDigit = remainingLongitude.intValue();
if (generatedDigits < 10) {
codeBuilder.append(ALPHABET[latitudeDigit]);
codeBuilder.append(ALPHABET[longitudeDigit]);
if (generatedDigits < PAIR_CODE_LENGTH) {
// Use the normal algorithm for the first set of digits.
latPrecision = latPrecision.divide(ENCODING_BASE);
lngPrecision = lngPrecision.divide(ENCODING_BASE);
BigDecimal latDigit = remainingLatitude.divide(latPrecision, 0, BigDecimal.ROUND_FLOOR);
BigDecimal lngDigit = remainingLongitude.divide(lngPrecision, 0, BigDecimal.ROUND_FLOOR);
remainingLatitude = remainingLatitude.subtract(latPrecision.multiply(latDigit));
remainingLongitude = remainingLongitude.subtract(lngPrecision.multiply(lngDigit));
codeBuilder.append(CODE_ALPHABET.charAt(latDigit.intValue()));
codeBuilder.append(CODE_ALPHABET.charAt(lngDigit.intValue()));
generatedDigits += 2;
} else {
codeBuilder.append(ALPHABET[4 * latitudeDigit + longitudeDigit]);
// Use the 4x5 grid for remaining digits.
latPrecision = latPrecision.divide(GRID_ROWS);
lngPrecision = lngPrecision.divide(GRID_COLUMNS);
BigDecimal row = remainingLatitude.divide(latPrecision, 0, BigDecimal.ROUND_FLOOR);
BigDecimal col = remainingLongitude.divide(lngPrecision, 0, BigDecimal.ROUND_FLOOR);
remainingLatitude = remainingLatitude.subtract(latPrecision.multiply(row));
remainingLongitude = remainingLongitude.subtract(lngPrecision.multiply(col));
codeBuilder.append(
CODE_ALPHABET.charAt(row.intValue() * GRID_COLUMNS.intValue() + col.intValue()));
generatedDigits += 1;
}
remainingLatitude = remainingLatitude.subtract(new BigDecimal(latitudeDigit));
remainingLongitude = remainingLongitude.subtract(new BigDecimal(longitudeDigit));
// If we are at the separator position, add the separator.
if (generatedDigits == SEPARATOR_POSITION) {
codeBuilder.append(SEPARATOR);
}
}
// If the generated code is shorter than the separator position, pad the code and add the
// separator.
if (generatedDigits < SEPARATOR_POSITION) {
for (; generatedDigits < SEPARATOR_POSITION; generatedDigits++) {
codeBuilder.append(SUFFIX_PADDING);
codeBuilder.append(PADDING_CHARACTER);
}
codeBuilder.append(SEPARATOR);
}
this.code = codeBuilder.toString();
}
/** Creates Open Location Code with code length 10 from the provided latitude, longitude. */
/**
* Creates Open Location Code with the default precision length.
* @param latitude The latitude in decimal degrees.
* @param longitude The longitude in decimal degrees.
*/
public OpenLocationCode(double latitude, double longitude) {
this(latitude, longitude, 10);
this(latitude, longitude, CODE_PRECISION_NORMAL);
}
/**
* Returns the string representation of the code.
*/
public String getCode() {
return code;
}
@ -184,6 +255,8 @@ public final class OpenLocationCode {
/**
* Encodes latitude/longitude into 10 digit Open Location Code. This method is equivalent to
* creating the OpenLocationCode object and getting the code from it.
* @param latitude The latitude in decimal degrees.
* @param longitude The longitude in decimal degrees.
*/
public static String encode(double latitude, double longitude) {
return new OpenLocationCode(latitude, longitude).getCode();
@ -192,6 +265,8 @@ public final class OpenLocationCode {
/**
* Encodes latitude/longitude into Open Location Code of the provided length. This method is
* equivalent to creating the OpenLocationCode object and getting the code from it.
* @param latitude The latitude in decimal degrees.
* @param longitude The longitude in decimal degrees.
*/
public static String encode(double latitude, double longitude, int codeLength) {
return new OpenLocationCode(latitude, longitude, codeLength).getCode();
@ -204,48 +279,49 @@ public final class OpenLocationCode {
public CodeArea decode() {
if (!isFullCode(code)) {
throw new IllegalStateException(
"Method decode() could only be called on valid full codes, code was " + code + ".");
"Method decode() could only be called on valid full codes, code was " + code + ".");
}
String decoded = code.replaceAll("[0+]", "");
// Decode the lat/lng pair component.
BigDecimal southLatitude = BD_0;
BigDecimal westLongitude = BD_0;
// Strip padding and separator characters out of the code.
String decoded = code.replace(String.valueOf(SEPARATOR), "")
.replace(String.valueOf(PADDING_CHARACTER), "");
int digit = 0;
double latitudeResolution = 400, longitudeResolution = 400;
// The precisions are initially set to ENCODING_BASE^2 because they will be immediately
// divided.
BigDecimal latPrecision = ENCODING_BASE.multiply(ENCODING_BASE);
BigDecimal lngPrecision = ENCODING_BASE.multiply(ENCODING_BASE);
// Save the coordinates.
BigDecimal southLatitude = BigDecimal.ZERO;
BigDecimal westLongitude = BigDecimal.ZERO;
// Decode pair.
while (digit < decoded.length()) {
if (digit < 10) {
latitudeResolution /= 20;
longitudeResolution /= 20;
southLatitude =
southLatitude.add(
new BigDecimal(latitudeResolution * CHARACTER_TO_INDEX.get(decoded.charAt(digit))));
westLongitude =
westLongitude.add(
new BigDecimal(
longitudeResolution * CHARACTER_TO_INDEX.get(decoded.charAt(digit + 1))));
// Decode the digits.
while (digit < Math.min(decoded.length(), MAX_DIGIT_COUNT)) {
if (digit < PAIR_CODE_LENGTH) {
// Decode a pair of digits, the first being latitude and the second being longitude.
latPrecision = latPrecision.divide(ENCODING_BASE);
lngPrecision = lngPrecision.divide(ENCODING_BASE);
int digitVal = CODE_ALPHABET.indexOf(decoded.charAt(digit));
southLatitude = southLatitude.add(latPrecision.multiply(new BigDecimal(digitVal)));
digitVal = CODE_ALPHABET.indexOf(decoded.charAt(digit + 1));
westLongitude = westLongitude.add(lngPrecision.multiply(new BigDecimal(digitVal)));
digit += 2;
} else {
latitudeResolution /= 5;
longitudeResolution /= 4;
southLatitude =
southLatitude.add(
new BigDecimal(
latitudeResolution * (CHARACTER_TO_INDEX.get(decoded.charAt(digit)) / 4)));
westLongitude =
westLongitude.add(
new BigDecimal(
longitudeResolution * (CHARACTER_TO_INDEX.get(decoded.charAt(digit)) % 4)));
// Use the 4x5 grid for digits after 10.
int digitVal = CODE_ALPHABET.indexOf(decoded.charAt(digit));
int row = (int) (digitVal / GRID_COLUMNS.intValue());
int col = digitVal % GRID_COLUMNS.intValue();
latPrecision = latPrecision.divide(GRID_ROWS);
lngPrecision = lngPrecision.divide(GRID_COLUMNS);
southLatitude = southLatitude.add(latPrecision.multiply(new BigDecimal(row)));
westLongitude = westLongitude.add(lngPrecision.multiply(new BigDecimal(col)));
digit += 1;
}
}
return new CodeArea(
southLatitude.subtract(BD_90),
westLongitude.subtract(BD_180),
southLatitude.subtract(BD_90).add(new BigDecimal(latitudeResolution)),
westLongitude.subtract(BD_180).add(new BigDecimal(longitudeResolution)));
southLatitude.subtract(LATITUDE_MAX),
westLongitude.subtract(LONGITUDE_MAX),
southLatitude.subtract(LATITUDE_MAX).add(latPrecision),
westLongitude.subtract(LONGITUDE_MAX).add(lngPrecision));
}
/**
@ -284,7 +360,7 @@ public final class OpenLocationCode {
* contains less than 8 valid digits.
*/
private boolean isPadded() {
return code.indexOf(SUFFIX_PADDING) >= 0;
return code.indexOf(PADDING_CHARACTER) >= 0;
}
/**
@ -297,7 +373,7 @@ public final class OpenLocationCode {
/**
* Returns short {@link OpenLocationCode} from the full Open Location Code created by removing
* four or six digits, depending on the provided reference point. It removes as many digits as
* four or six digits, depending on the provided reference point. It removes as many digits as
* possible.
*/
public OpenLocationCode shorten(double referenceLatitude, double referenceLongitude) {
@ -309,20 +385,22 @@ public final class OpenLocationCode {
}
CodeArea codeArea = decode();
double latitudeDiff = Math.abs(referenceLatitude - codeArea.getCenterLatitude());
double longitudeDiff = Math.abs(referenceLongitude - codeArea.getCenterLongitude());
if (latitudeDiff < LATITUDE_PRECISION_8_DIGITS && longitudeDiff < LATITUDE_PRECISION_8_DIGITS) {
return new OpenLocationCode(code.substring(8));
}
if (latitudeDiff < LATITUDE_PRECISION_6_DIGITS && longitudeDiff < LATITUDE_PRECISION_6_DIGITS) {
return new OpenLocationCode(code.substring(6));
}
if (latitudeDiff < LATITUDE_PRECISION_4_DIGITS && longitudeDiff < LATITUDE_PRECISION_4_DIGITS) {
return new OpenLocationCode(code.substring(4));
double range = Math.max(
Math.abs(referenceLatitude - codeArea.getCenterLatitude()),
Math.abs(referenceLongitude - codeArea.getCenterLongitude()));
// We are going to check to see if we can remove three pairs, two pairs or just one pair of
// digits from the code.
for (int i = 4; i >= 1; i--) {
// Check if we're close enough to shorten. The range must be less than 1/2
// the precision to shorten at all, and we want to allow some safety, so
// use 0.3 instead of 0.5 as a multiplier.
if (range < (computeLatitudePrecision(i * 2) * 0.3)) {
// We're done.
return new OpenLocationCode(code.substring(i * 2));
}
}
throw new IllegalArgumentException(
"Reference location is too far from the Open Location Code center.");
"Reference location is too far from the Open Location Code center.");
}
/**
@ -337,39 +415,45 @@ public final class OpenLocationCode {
referenceLatitude = clipLatitude(referenceLatitude);
referenceLongitude = normalizeLongitude(referenceLongitude);
int digitsToRecover = 8 - code.indexOf(SEPARATOR);
// The resolution (height and width) of the padded area in degrees.
double paddedAreaSize = Math.pow(20, 2 - (digitsToRecover / 2));
int digitsToRecover = SEPARATOR_POSITION - code.indexOf(SEPARATOR);
// The precision (height and width) of the missing prefix in degrees.
double prefixPrecision = Math.pow(ENCODING_BASE.intValue(), 2 - (digitsToRecover / 2));
// Use the reference location to pad the supplied short code and decode it.
// Use the reference location to generate the prefix.
String recoveredPrefix =
new OpenLocationCode(referenceLatitude, referenceLongitude)
.getCode()
.substring(0, digitsToRecover);
new OpenLocationCode(referenceLatitude, referenceLongitude)
.getCode()
.substring(0, digitsToRecover);
// Combine the prefix with the short code and decode it.
OpenLocationCode recovered = new OpenLocationCode(recoveredPrefix + code);
CodeArea recoveredCodeArea = recovered.decode();
// Work out whether the new code area is too far from the reference location. If it is, we
// move it. It can only be out by a single precision step.
double recoveredLatitude = recoveredCodeArea.getCenterLatitude();
double recoveredLongitude = recoveredCodeArea.getCenterLongitude();
// Move the recovered latitude by one resolution up or down if it is too far from the reference.
// Move the recovered latitude by one precision up or down if it is too far from the reference,
// unless doing so would lead to an invalid latitude.
double latitudeDiff = recoveredLatitude - referenceLatitude;
if (latitudeDiff > paddedAreaSize / 2) {
recoveredLatitude -= paddedAreaSize;
} else if (latitudeDiff < -paddedAreaSize / 2) {
recoveredLatitude += paddedAreaSize;
if (latitudeDiff > prefixPrecision / 2
&& recoveredLatitude - prefixPrecision > -LATITUDE_MAX.intValue()) {
recoveredLatitude -= prefixPrecision;
} else if (latitudeDiff < -prefixPrecision / 2
&& recoveredLatitude + prefixPrecision < LATITUDE_MAX.intValue()) {
recoveredLatitude += prefixPrecision;
}
// Move the recovered longitude by one resolution up or down if it is too far from the
// Move the recovered longitude by one precision up or down if it is too far from the
// reference.
double longitudeDiff = recoveredCodeArea.getCenterLongitude() - referenceLongitude;
if (longitudeDiff > paddedAreaSize / 2) {
recoveredLongitude -= paddedAreaSize;
} else if (longitudeDiff < -paddedAreaSize / 2) {
recoveredLongitude += paddedAreaSize;
if (longitudeDiff > prefixPrecision / 2) {
recoveredLongitude -= prefixPrecision;
} else if (longitudeDiff < -prefixPrecision / 2) {
recoveredLongitude += prefixPrecision;
}
return new OpenLocationCode(
recoveredLatitude, recoveredLongitude, recovered.getCode().length() - 1);
recoveredLatitude, recoveredLongitude, recovered.getCode().length() - 1);
}
/**
@ -378,9 +462,9 @@ public final class OpenLocationCode {
public boolean contains(double latitude, double longitude) {
CodeArea codeArea = decode();
return codeArea.getSouthLatitude() <= latitude
&& latitude < codeArea.getNorthLatitude()
&& codeArea.getWestLongitude() <= longitude
&& longitude < codeArea.getEastLongitude();
&& latitude < codeArea.getNorthLatitude()
&& codeArea.getWestLongitude() <= longitude
&& longitude < codeArea.getEastLongitude();
}
@Override
@ -392,7 +476,7 @@ public final class OpenLocationCode {
return false;
}
OpenLocationCode that = (OpenLocationCode) o;
return hashCode() == that.hashCode();
return code == that.code || code != null && code.equals(that.code);
}
@Override
@ -412,6 +496,7 @@ public final class OpenLocationCode {
if (code == null || code.length() < 2) {
return false;
}
code = code.toUpperCase();
// There must be exactly one separator.
int separatorPosition = code.indexOf(SEPARATOR);
@ -429,13 +514,13 @@ public final class OpenLocationCode {
// Check first two characters: only some values from the alphabet are permitted.
if (separatorPosition == 8) {
// First latitude character can only have first 9 values.
Integer index0 = CHARACTER_TO_INDEX.get(code.charAt(0));
Integer index0 = CODE_ALPHABET.indexOf(code.charAt(0));
if (index0 == null || index0 > 8) {
return false;
}
// First longitude character can only have first 18 values.
Integer index1 = CHARACTER_TO_INDEX.get(code.charAt(1));
Integer index1 = CODE_ALPHABET.indexOf(code.charAt(1));
if (index1 == null || index1 > 17) {
return false;
}
@ -446,15 +531,15 @@ public final class OpenLocationCode {
for (int i = 0; i < separatorPosition; i++) {
if (paddingStarted) {
// Once padding starts, there must not be anything but padding.
if (code.charAt(i) != SUFFIX_PADDING) {
if (code.charAt(i) != PADDING_CHARACTER) {
return false;
}
continue;
}
if (CHARACTER_TO_INDEX.keySet().contains(code.charAt(i))) {
if (CODE_ALPHABET.indexOf(code.charAt(i)) != -1) {
continue;
}
if (SUFFIX_PADDING == code.charAt(i)) {
if (PADDING_CHARACTER == code.charAt(i)) {
paddingStarted = true;
// Padding can start on even character: 2, 4 or 6.
if (i != 2 && i != 4 && i != 6) {
@ -462,7 +547,7 @@ public final class OpenLocationCode {
}
continue;
}
return false; // Illegal character.
return false; // Illegal character.
}
// Check the characters after the separator.
@ -475,7 +560,7 @@ public final class OpenLocationCode {
return false;
}
for (int i = separatorPosition + 1; i < code.length(); i++) {
if (!CHARACTER_TO_INDEX.keySet().contains(code.charAt(i))) {
if (CODE_ALPHABET.indexOf(code.charAt(i)) == -1) {
return false;
}
}
@ -505,15 +590,15 @@ public final class OpenLocationCode {
// Private static methods.
private static double clipLatitude(double latitude) {
return Math.min(Math.max(latitude, -90), 90);
return Math.min(Math.max(latitude, -LATITUDE_MAX.intValue()), LATITUDE_MAX.intValue());
}
private static double normalizeLongitude(double longitude) {
if (longitude < -180) {
longitude = (longitude % 360) + 360;
while (longitude < -LONGITUDE_MAX.intValue()) {
longitude = longitude + LONGITUDE_MAX.intValue() * 2;
}
if (longitude >= 180) {
longitude = (longitude % 360) - 360;
while (longitude >= LONGITUDE_MAX.intValue()) {
longitude = longitude - LONGITUDE_MAX.intValue() * 2;
}
return longitude;
}
@ -524,9 +609,10 @@ public final class OpenLocationCode {
* grid method having fewer columns than rows. Copied from the JS implementation.
*/
private static double computeLatitudePrecision(int codeLength) {
if (codeLength <= 10) {
return Math.pow(20, Math.floor(codeLength / -2 + 2));
if (codeLength <= CODE_PRECISION_NORMAL) {
return Math.pow(ENCODING_BASE.intValue(), Math.floor(codeLength / -2 + 2));
}
return Math.pow(20, -3) / Math.pow(5, codeLength - 10);
return Math.pow(ENCODING_BASE.intValue(), -3)
/ Math.pow(GRID_ROWS.intValue(), codeLength - PAIR_CODE_LENGTH);
}
}
}

View file

@ -1,12 +1,7 @@
package net.osmand;
import com.google.openlocationcode.OpenLocationCode;
import net.osmand.data.LatLon;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.IllegalFormatException;
import java.util.Locale;
import java.util.StringTokenizer;

View file

@ -157,6 +157,9 @@ public class RouteResultPreparation {
}
List<RouteSegmentResult> prepareResult(RoutingContext ctx, List<RouteSegmentResult> result) throws IOException {
for(int i = 0; i < result.size(); i++) {
checkAndInitRouteRegion(ctx, result.get(i).getObject());
}
combineWayPointsForAreaRouting(ctx, result);
validateAllPointsConnected(result);
splitRoadsAndAttachRoadSegments(ctx, result);
@ -290,8 +293,6 @@ public class RouteResultPreparation {
ctx.unloadUnusedTiles(ctx.config.memoryLimitation);
}
RouteSegmentResult rr = result.get(i);
RouteDataObject road = rr.getObject();
checkAndInitRouteRegion(ctx, road);
boolean plus = rr.getStartPointIndex() < rr.getEndPointIndex();
int next;
for (int j = rr.getStartPointIndex(); j != rr.getEndPointIndex(); j = next) {

View file

@ -28,6 +28,8 @@ import net.osmand.util.MapUtils;
public class TransportRoutePlanner {
private static final boolean MEASURE_TIME = false;
public static final long GEOMETRY_WAY_ID = -1;
public static final long STOPS_WAY_ID = -2;
public List<TransportRouteResult> buildRoute(TransportRoutingContext ctx, LatLon start, LatLon end) throws IOException, InterruptedException {
ctx.startCalcTime = System.currentTimeMillis();
@ -371,11 +373,11 @@ public class TransportRoutePlanner {
}
public List<Way> getGeometry() {
List<Way> list = new ArrayList<Way>();
List<Way> list = new ArrayList<>();
route.mergeForwardWays();
if(DISPLAY_FULL_SEGMENT_ROUTE) {
if (DISPLAY_FULL_SEGMENT_ROUTE) {
System.out.println("TOTAL SEGMENTS: " + route.getForwardWays().size());
if(route.getForwardWays().size() > DISPLAY_SEGMENT_IND) {
if (route.getForwardWays().size() > DISPLAY_SEGMENT_IND) {
return Collections.singletonList(route.getForwardWays().get(DISPLAY_SEGMENT_IND));
}
return route.getForwardWays();
@ -386,38 +388,38 @@ public class TransportRoutePlanner {
LatLon str = getStart().getLocation();
LatLon en = getEnd().getLocation();
int endInd = -1;
List<Node> res = new ArrayList<Node>();
for(int i = 0; i < fw.size() ; i++) {
List<Node> res = new ArrayList<>();
for (int i = 0; i < fw.size() ; i++) {
List<Node> nodes = fw.get(i).getNodes();
for(int j = 0; j < nodes.size(); j++) {
for (int j = 0; j < nodes.size(); j++) {
Node n = nodes.get(j);
if(MapUtils.getDistance(str, n.getLatitude(), n.getLongitude()) < minStart) {
if (MapUtils.getDistance(str, n.getLatitude(), n.getLongitude()) < minStart) {
minStart = MapUtils.getDistance(str, n.getLatitude(), n.getLongitude());
res.clear();
}
res.add(n);
if(MapUtils.getDistance(en, n.getLatitude(), n.getLongitude()) < minEnd) {
if (MapUtils.getDistance(en, n.getLatitude(), n.getLongitude()) < minEnd) {
endInd = res.size();
minEnd = MapUtils.getDistance(en, n.getLatitude(), n.getLongitude());
}
}
}
Way way = new Way(-1);
if (res.isEmpty()) {
Way way;
if (res.isEmpty() || endInd == -1) {
way = new Way(STOPS_WAY_ID);
for (int i = start; i <= end; i++) {
LatLon l = getStop(i).getLocation();
Node n = new Node(l.getLatitude(), l.getLongitude(), -1);
way.addNode(n);
}
list.add(way);
} else {
for(int k = 0; k < res.size() && k < endInd; k++) {
way = new Way(GEOMETRY_WAY_ID);
for(int k = 0; k < res.size() && k < endInd; k++) {
way.addNode(res.get(k));
}
}
list.add(way);
return list;
}
public double getTravelDist() {

View file

@ -702,6 +702,14 @@ public class SearchUICore {
break;
}
}
if (Algorithms.isEmpty(object.alternateName) && object.object instanceof Amenity) {
for (String value : ((Amenity) object.object).getAdditionalInfo().values()) {
if (phrase.getNameStringMatcher().matches(value)) {
object.alternateName = value;
break;
}
}
}
}
if (Algorithms.isEmpty(object.localeName) && object.alternateName != null) {
object.localeName = object.alternateName;

View file

@ -31,10 +31,12 @@ import net.osmand.util.Algorithms;
import net.osmand.util.GeoPointParserUtil;
import net.osmand.util.GeoPointParserUtil.GeoParsedPoint;
import net.osmand.util.LocationParser;
import net.osmand.util.LocationParser.ParsedOpenLocationCode;
import net.osmand.util.MapUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@ -54,6 +56,7 @@ import gnu.trove.list.array.TIntArrayList;
public class SearchCoreFactory {
public static final int MAX_DEFAULT_SEARCH_RADIUS = 7;
public static final int SEARCH_MAX_PRIORITY = Integer.MAX_VALUE;
//////////////// CONSTANTS //////////
public static final int SEARCH_REGION_API_PRIORITY = 300;
@ -1220,6 +1223,10 @@ public class SearchCoreFactory {
public static class SearchLocationAndUrlAPI extends SearchBaseAPI {
private int olcPhraseHash;
private ParsedOpenLocationCode cachedParsedCode;
private final List<String> citySubTypes = Arrays.asList("city", "town", "village");
public SearchLocationAndUrlAPI() {
super(ObjectType.LOCATION, ObjectType.PARTIAL_LOCATION);
}
@ -1286,34 +1293,71 @@ public class SearchCoreFactory {
return new LatLon(lat, 0);
}
private void parseLocation(SearchPhrase phrase, SearchResultMatcher resultMatcher) {
private void parseLocation(SearchPhrase phrase, SearchResultMatcher resultMatcher) throws IOException {
String lw = phrase.getUnknownSearchPhrase();
LatLon searchLocation = phrase.getLastTokenLocation();
LatLon l = LocationParser.parseLocation(lw, searchLocation);
if (l != null) {
if (phrase.isSearchTypeAllowed(ObjectType.LOCATION)) {
SearchResult sp = new SearchResult(phrase);
sp.priority = SEARCH_LOCATION_PRIORITY;
sp.object = sp.location = l;
sp.localeName = ((float) sp.location.getLatitude()) + ", " + ((float) sp.location.getLongitude());
sp.objectType = ObjectType.LOCATION;
sp.wordsSpan = lw;
resultMatcher.publish(sp);
// Detect OLC
ParsedOpenLocationCode parsedCode = cachedParsedCode;
if (parsedCode != null) {
LatLon latLon = parsedCode.getLatLon();
// do we have local code with locality
if (latLon == null && !parsedCode.isFull() && !Algorithms.isEmpty(parsedCode.getPlaceName())) {
List<SearchResult> requestResults = resultMatcher.getRequestResults();
if (requestResults.size() > 0) {
LatLon searchLocation = null;
for (SearchResult sr : requestResults) {
switch (sr.objectType) {
case POI:
Amenity a = (Amenity) sr.object;
if (citySubTypes.contains(a.getSubType())) {
searchLocation = sr.location;
}
break;
case CITY:
case VILLAGE:
searchLocation = sr.location;
break;
}
if (searchLocation != null) {
break;
}
}
if (searchLocation != null) {
latLon = parsedCode.recover(searchLocation);
}
}
}
} else if (phrase.isNoSelectedType()) {
LatLon ll = parsePartialLocation(lw);
if (ll != null && phrase.isSearchTypeAllowed(ObjectType.PARTIAL_LOCATION)) {
SearchResult sp = new SearchResult(phrase);
sp.priority = SEARCH_LOCATION_PRIORITY;
if (latLon != null) {
publishLocation(phrase, resultMatcher, lw, latLon);
}
} else {
LatLon l = LocationParser.parseLocation(lw);
if (l != null && phrase.isSearchTypeAllowed(ObjectType.LOCATION)) {
publishLocation(phrase, resultMatcher, lw, l);
} else if (l == null && phrase.isNoSelectedType() && phrase.isSearchTypeAllowed(ObjectType.PARTIAL_LOCATION)) {
LatLon ll = parsePartialLocation(lw);
if (ll != null) {
SearchResult sp = new SearchResult(phrase);
sp.priority = SEARCH_LOCATION_PRIORITY;
sp.object = sp.location = ll;
sp.localeName = ((float) sp.location.getLatitude()) + ", <input> ";
sp.objectType = ObjectType.PARTIAL_LOCATION;
resultMatcher.publish(sp);
sp.object = sp.location = ll;
sp.localeName = ((float) sp.location.getLatitude()) + ", <input> ";
sp.objectType = ObjectType.PARTIAL_LOCATION;
resultMatcher.publish(sp);
}
}
}
}
private void publishLocation(SearchPhrase phrase, SearchResultMatcher resultMatcher, String lw, LatLon l) {
SearchResult sp = new SearchResult(phrase);
sp.priority = SEARCH_LOCATION_PRIORITY;
sp.object = sp.location = l;
sp.localeName = ((float) sp.location.getLatitude()) + ", " + ((float) sp.location.getLongitude());
sp.objectType = ObjectType.LOCATION;
sp.wordsSpan = lw;
resultMatcher.publish(sp);
}
private boolean parseUrl(SearchPhrase phrase, SearchResultMatcher resultMatcher) {
String text = phrase.getUnknownSearchPhrase();
GeoParsedPoint pnt = GeoPointParserUtil.parse(text);
@ -1339,7 +1383,12 @@ public class SearchCoreFactory {
if (!p.isNoSelectedType() || !p.isUnknownSearchWordPresent()) {
return -1;
}
return SEARCH_LOCATION_PRIORITY;
int olcPhraseHash = p.getUnknownSearchPhrase().hashCode();
if (this.olcPhraseHash != olcPhraseHash) {
this.olcPhraseHash = olcPhraseHash;
cachedParsedCode = LocationParser.parseOpenLocationCode(p.getUnknownSearchPhrase());
}
return cachedParsedCode == null ? SEARCH_LOCATION_PRIORITY : SEARCH_MAX_PRIORITY;
}
}
}

View file

@ -11,6 +11,7 @@ import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.osm.AbstractPoiType;
import net.osmand.util.Algorithms;
import net.osmand.util.LocationParser;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
@ -782,7 +783,7 @@ public class SearchPhrase {
searchWords.add(0, getUnknownSearchWord());
Collections.sort(searchWords, commonWordsComparator);
for (String s : searchWords) {
if (s.length() > 0 && !Character.isDigit(s.charAt(0))) {
if (s.length() > 0 && !Character.isDigit(s.charAt(0)) && !LocationParser.isValidOLC(s)) {
return s;
}
}

View file

@ -1,6 +1,7 @@
package net.osmand.util;
import com.google.openlocationcode.OpenLocationCode;
import com.google.openlocationcode.OpenLocationCode.CodeArea;
import com.jwetherell.openmap.common.LatLonPoint;
import com.jwetherell.openmap.common.UTMPoint;
@ -10,20 +11,87 @@ import java.util.ArrayList;
import java.util.List;
public class LocationParser {
public static LatLon parseLocation(String locPhrase, LatLon searchLocation) {
locPhrase = locPhrase.trim();
// detect OLC first
// avoid throwing exceptions by carefully checking exceptions
if (locPhrase.length() > 0 && OpenLocationCode.isValidCode(locPhrase)) {
OpenLocationCode olc = new OpenLocationCode(locPhrase);
if (olc.isFull()) {
OpenLocationCode.CodeArea codeArea = olc.decode();
return new LatLon(codeArea.getCenterLatitude(), codeArea.getCenterLongitude());
} else if (olc.isShort() && searchLocation != null) {
OpenLocationCode.CodeArea codeArea = olc.recover(searchLocation.getLatitude(), searchLocation.getLongitude()).decode();
return new LatLon(codeArea.getCenterLatitude(), codeArea.getCenterLongitude());
public static class ParsedOpenLocationCode {
private String text;
private String code;
private boolean full;
private String placeName;
private OpenLocationCode olc;
private LatLon latLon;
private ParsedOpenLocationCode(String text) {
this.text = text;
parse();
}
private void parse() {
if (!Algorithms.isEmpty(text)) {
String[] split = text.split(" ");
if (split.length > 0) {
code = split[0];
try {
olc = new OpenLocationCode(code);
full = olc.isFull();
if (full) {
CodeArea codeArea = olc.decode();
latLon = new LatLon(codeArea.getCenterLatitude(), codeArea.getCenterLongitude());
} else {
if (split.length > 1) {
placeName = text.substring(code.length() + 1);
}
}
} catch (IllegalArgumentException e) {
code = null;
}
}
}
}
public LatLon recover(LatLon searchLocation) {
if (olc != null) {
CodeArea codeArea = olc.recover(searchLocation.getLatitude(), searchLocation.getLongitude()).decode();
latLon = new LatLon(codeArea.getCenterLatitude(), codeArea.getCenterLongitude());
}
return latLon;
}
boolean isValidCode() {
return !Algorithms.isEmpty(code);
}
public String getText() {
return text;
}
public String getCode() {
return code;
}
public boolean isFull() {
return full;
}
public String getPlaceName() {
return placeName;
}
public LatLon getLatLon() {
return latLon;
}
}
public static boolean isValidOLC(String code) {
return OpenLocationCode.isValidCode(code);
}
public static ParsedOpenLocationCode parseOpenLocationCode(String locPhrase) {
ParsedOpenLocationCode parsedCode = new ParsedOpenLocationCode(locPhrase.trim());
return !parsedCode.isValidCode() ? null : parsedCode;
}
public static LatLon parseLocation(String locPhrase) {
locPhrase = locPhrase.trim();
boolean valid = isValidLocPhrase(locPhrase);
if (!valid) {
String[] split = locPhrase.split(" ");

View file

@ -222,7 +222,7 @@ public class SearchCoreUITest {
});
if (files != null) {
for (File f : files) {
//testSearchImpl(f);
testSearchImpl(f);
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -2,20 +2,20 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
<stroke android:width="1dp" android:color="@color/active_buttons_and_links_dark" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="rectangle">
<solid android:color="@color/activity_background_dark" />
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@null" />
<corners android:radius="18dp" />
<solid android:color="@color/card_and_list_background_dark" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
<stroke android:width="1dp" android:color="@color/divider_dark" />
</shape>
</item>

View file

@ -2,20 +2,20 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
<stroke android:width="1dp" android:color="@color/active_buttons_and_links_light" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="rectangle">
<solid android:color="@color/activity_background_light" />
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@null" />
<corners android:radius="18dp" />
<solid android:color="@color/card_and_list_background_light" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
<stroke android:width="1dp" android:color="@color/divider_light" />
</shape>
</item>

View file

@ -2,7 +2,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
<solid android:color="@color/active_buttons_and_links_trans_dark" />
<stroke android:width="1dp" android:color="@color/active_buttons_and_links_dark" />
</shape>
@ -10,13 +10,13 @@
<item android:state_enabled="false">
<shape android:shape="rectangle">
<solid android:color="@color/activity_background_dark" />
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@null" />
<corners android:radius="18dp" />
<solid android:color="@color/card_and_list_background_dark" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
<stroke android:width="1dp" android:color="@color/divider_dark" />
</shape>
</item>

View file

@ -2,7 +2,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
<solid android:color="@color/active_buttons_and_links_trans_light" />
<stroke android:width="1dp" android:color="@color/active_buttons_and_links_light" />
</shape>
@ -10,13 +10,13 @@
<item android:state_enabled="false">
<shape android:shape="rectangle">
<solid android:color="@color/activity_background_light" />
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@null" />
<corners android:radius="18dp" />
<solid android:color="@color/card_and_list_background_light" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
<stroke android:width="1dp" android:color="@color/divider_light" />
</shape>
</item>

View file

@ -0,0 +1,13 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp">
<shape android:shape="oval">
<stroke
android:width="1dp"
android:color="@color/divider_dark" />
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,13 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp">
<shape android:shape="oval">
<stroke
android:width="1dp"
android:color="@color/divider_light" />
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/active_buttons_and_links_dark"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/active_buttons_and_links_light"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<nine-patch android:src="@drawable/bg_route_indicator"/>
</item>
<item>
<shape>
<solid android:color="@color/card_and_list_background_dark"/>
<corners android:radius="6dp"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<nine-patch android:src="@drawable/bg_route_indicator"/>
</item>
<item>
<shape>
<solid android:color="@color/card_and_list_background_light"/>
<corners android:radius="6dp"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/inactive_buttons_and_links_dark"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/inactive_buttons_and_links_light"/>
</shape>
</item>
</layer-list>

View file

@ -3,7 +3,7 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@color/active_buttons_and_links_dark" />
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
</shape>
</item>
</ripple>

View file

@ -3,7 +3,7 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@color/active_buttons_and_links_light" />
<corners android:radius="18dp" />
<corners android:radius="@dimen/route_info_button_bg_line_radius" />
</shape>
</item>
</ripple>

View file

@ -78,9 +78,9 @@
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginLeft="@dimen/bottom_sheet_content_margin_small"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
android:layout_marginStart="@dimen/bottom_sheet_content_margin_small"
android:layout_marginStart="@dimen/content_padding"
tools:src="@drawable/ic_action_info_dark" />
<TextView

View file

@ -0,0 +1,19 @@
<?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:gravity="center_vertical"
android:minHeight="@dimen/bottom_sheet_selected_item_title_height">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="horizontal"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
tools:listitem="@layout/bottom_sheet_item_with_descr_56dp" />
</LinearLayout>

View file

@ -11,8 +11,8 @@
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"

View file

@ -12,8 +12,8 @@
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"

View file

@ -12,8 +12,8 @@
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"

View file

@ -14,8 +14,8 @@
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
tools:src="@drawable/ic_action_coordinates_latitude"/>

View file

@ -12,8 +12,8 @@
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
tools:src="@drawable/ic_action_coordinates_latitude"/>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/context_menu_top_shadow"
android:layout_width="match_parent"
android:layout_height="@dimen/contex_menu_top_shadow_height"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:scaleType="fitXY"
android:src="@drawable/bg_shadow_onmap" />
</FrameLayout>

View file

@ -35,11 +35,11 @@
android:id="@+id/back_button_flow"
android:layout_width="@dimen/route_info_toolbar_button_size"
android:layout_height="@dimen/route_info_toolbar_button_size"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:background="@drawable/btn_circle_transparent_full"
android:contentDescription="@string/shared_string_back"
android:src="@drawable/ic_arrow_back"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:tint="?attr/primary_icon_color" />
<LinearLayout
@ -210,6 +210,31 @@
</LinearLayout>
<LinearLayout
android:id="@+id/pages_control"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="?attr/pages_bg"
android:gravity="center">
<View
android:layout_width="@dimen/pages_item_size"
android:layout_height="@dimen/pages_item_size"
android:layout_marginLeft="@dimen/pages_item_margin"
android:layout_marginRight="@dimen/pages_item_padding"
android:background="@drawable/pages_active_dark" />
<View
android:layout_width="@dimen/pages_item_size"
android:layout_height="@dimen/pages_item_size"
android:layout_marginRight="@dimen/pages_item_margin"
android:background="@drawable/pages_inactive_dark" />
</LinearLayout>
<LinearLayout
android:id="@+id/map_hud_controls"
android:layout_width="wrap_content"

View file

@ -12,24 +12,13 @@
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/top_shadow"
android:layout_width="match_parent"
android:layout_height="16dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:scaleType="fitXY"
android:src="@drawable/bg_shadow_onmap" />
</FrameLayout>
<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/card_and_list_background_basic"
android:orientation="vertical">
<FrameLayout
@ -41,6 +30,7 @@
android:id="@+id/modes_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/card_and_list_background_basic"
tools:ignore="UselessParent">
<LinearLayout
@ -60,6 +50,7 @@
android:id="@+id/app_modes_fold_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/color_transparent"
android:layout_gravity="start"
android:orientation="horizontal">
@ -71,7 +62,7 @@
android:paddingLeft="@dimen/route_info_icon_padding_right"
android:paddingRight="@dimen/route_info_icon_padding_right"
android:src="@drawable/ic_action_arrow_down"
android:tint="?attr/primary_icon_color" />
android:tint="@color/description_font_and_bottom_sheet_icons" />
</LinearLayout>
@ -79,6 +70,7 @@
android:id="@+id/app_modes_options_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/color_transparent"
android:layout_gravity="end">
<ImageView
@ -156,12 +148,12 @@
<FrameLayout
android:id="@+id/from_button"
android:layout_width="wrap_content"
android:layout_height="@dimen/route_info_buttons_height"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/context_menu_padding_margin_medium"
android:layout_marginTop="@dimen/route_info_icon_vertical_padding"
android:layout_marginRight="@dimen/context_menu_padding_margin_medium"
android:layout_marginBottom="@dimen/route_info_icon_vertical_padding"
tools:background="@drawable/btn_border_rounded_dark">
tools:background="@drawable/btn_rounded_dark">
<LinearLayout
android:id="@+id/from_button_container"
@ -186,12 +178,13 @@
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/text_button_text_size"
osmand:typeface="@string/font_roboto_medium"
android:visibility="gone"
tools:ignore="UnusedAttribute" />
<ImageView
android:id="@+id/from_button_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginLeft="@dimen/route_info_icon_vertical_padding"
android:layout_marginTop="@dimen/route_info_icon_vertical_padding"
android:layout_marginRight="@dimen/route_info_icon_vertical_padding"
@ -265,7 +258,7 @@
android:singleLine="true"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/default_list_text_size"
tools:text="Intermediate point"/>
tools:text="Intermediate point" />
</LinearLayout>
@ -277,7 +270,7 @@
android:layout_marginTop="@dimen/route_info_icon_vertical_padding"
android:layout_marginRight="@dimen/context_menu_padding_margin_medium"
android:layout_marginBottom="@dimen/route_info_icon_vertical_padding"
tools:background="@drawable/btn_border_rounded_dark">
tools:background="@drawable/btn_rounded_dark">
<LinearLayout
android:id="@+id/via_button_container"
@ -306,8 +299,8 @@
<ImageView
android:id="@+id/via_button_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginLeft="@dimen/route_info_icon_vertical_padding"
android:layout_marginTop="@dimen/route_info_icon_vertical_padding"
android:layout_marginRight="@dimen/route_info_icon_vertical_padding"
@ -378,7 +371,7 @@
android:singleLine="true"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/default_list_text_size"
tools:text="Destination"/>
tools:text="Destination" />
</LinearLayout>
@ -390,7 +383,7 @@
android:layout_marginTop="@dimen/route_info_icon_vertical_padding"
android:layout_marginRight="@dimen/context_menu_padding_margin_medium"
android:layout_marginBottom="@dimen/route_info_icon_vertical_padding"
tools:background="@drawable/btn_border_rounded_dark">
tools:background="@drawable/btn_rounded_dark">
<LinearLayout
android:id="@+id/to_button_container"
@ -419,8 +412,8 @@
<ImageView
android:id="@+id/to_button_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_marginLeft="@dimen/route_info_icon_vertical_padding"
android:layout_marginTop="@dimen/route_info_icon_vertical_padding"
android:layout_marginRight="@dimen/route_info_icon_vertical_padding"
@ -527,22 +520,22 @@
android:id="@+id/bottom_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundGravity="top|fill_horizontal"
android:foreground="@drawable/bg_contextmenu_shadow">
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"
tools:background="?attr/ctx_menu_info_view_bg">
android:background="?attr/activity_background_basic">
<LinearLayout
android:id="@+id/route_menu_cards_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/activity_background_basic"
android:orientation="vertical"
android:paddingBottom="60dp"
tools:background="?attr/ctx_menu_info_view_bg">
android:paddingBottom="30dp">
</LinearLayout>
@ -582,6 +575,7 @@
android:orientation="vertical">
<ImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_gravity="bottom"
@ -590,7 +584,7 @@
<include
layout="@layout/route_info_menu_control_buttons"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_height="@dimen/route_info_control_buttons_height"
android:layout_gravity="bottom" />
</LinearLayout>

View file

@ -0,0 +1,36 @@
<?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:id="@+id/route_details_legend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/route_info_legend_item_size"
android:orientation="horizontal"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<ImageView
android:id="@+id/legend_icon_color"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
tools:background="@drawable/circle_contour_bg_light"
tools:src="@drawable/ic_action_circle"
tools:tint="?attr/active_color_basic" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/legend_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:maxLines="2"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="Unpaved 13.4 km" />
</LinearLayout>

View file

@ -0,0 +1,27 @@
<?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"
android:id="@+id/route_directions_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_and_list_background_basic"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/directions_card_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="@dimen/content_padding"
android:text="@string/step_by_step"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/text_button_text_size"
osmand:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>

View file

@ -10,12 +10,14 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/content_padding">
android:paddingTop="@dimen/route_info_card_details_margin"
android:paddingBottom="@dimen/route_info_card_details_margin">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/info_type_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:gravity="center"
android:letterSpacing="@dimen/text_button_letter_spacing"
@ -23,26 +25,49 @@
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/text_button_text_size"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:ignore="UnusedAttribute"
tools:text="@string/route_class_stat_container" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/info_type_details"
<LinearLayout
android:id="@+id/info_type_details_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:gravity="center"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:text="@string/rendering_category_details"
android:textSize="@dimen/text_button_text_size"
android:textColor="?attr/active_color_basic"
osmand:typeface="@string/font_roboto_medium"
tools:ignore="UnusedAttribute" />
android:background="?attr/selectableItemBackground"
android:orientation="horizontal"
android:paddingStart="@dimen/bottom_sheet_content_margin_small"
android:paddingLeft="@dimen/bottom_sheet_content_margin_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/info_type_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="1"
android:paddingLeft="@dimen/bottom_sheet_content_margin_small"
android:paddingTop="@dimen/bottom_sheet_image_text_margin_start"
android:paddingRight="@dimen/bottom_sheet_content_margin_small"
android:paddingBottom="@dimen/bottom_sheet_image_text_margin_start"
android:text="@string/rendering_category_details"
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:ignore="UnusedAttribute" />
<ImageView
android:id="@+id/up_down_icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center"
tools:src="@drawable/ic_action_arrow_down"
tools:tint="@color/description_font_and_bottom_sheet_icons" />
</LinearLayout>
</FrameLayout>

View file

@ -9,7 +9,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingTop="8dp"
@ -20,6 +20,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingLeft="16dp">
<ImageView
@ -32,6 +33,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginLeft="18dp"
android:orientation="vertical">
@ -63,6 +65,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingLeft="16dp">
<ImageView
@ -75,6 +78,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginLeft="18dp"
android:orientation="vertical">
@ -105,7 +109,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.github.mikephil.charting.charts.LineChart
@ -117,8 +121,9 @@
</LinearLayout>
<LinearLayout
android:id="@+id/altitude_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingBottom="4dp">
@ -128,6 +133,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingLeft="16dp">
<ImageView
@ -140,6 +146,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginLeft="18dp"
android:orientation="vertical">
@ -171,6 +178,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingLeft="16dp">
<ImageView
@ -183,6 +191,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginLeft="18dp"
android:orientation="vertical">
@ -212,8 +221,9 @@
</LinearLayout>
<LinearLayout
android:id="@+id/slope_info_divider"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingTop="4dp"
@ -224,7 +234,9 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingEnd="8dp"
android:paddingRight="8dp">
<View
@ -239,7 +251,9 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingEnd="16dp"
android:paddingRight="16dp">
<View
@ -252,8 +266,9 @@
</LinearLayout>
<LinearLayout
android:id="@+id/slope_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingTop="4dp"
@ -264,6 +279,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingLeft="16dp">
<ImageView
@ -276,6 +292,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginLeft="18dp"
android:orientation="vertical">
@ -307,6 +324,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingLeft="16dp">
<ImageView
@ -319,6 +337,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginLeft="18dp"
android:orientation="vertical">
@ -347,4 +366,40 @@
</LinearLayout>
<LinearLayout
android:id="@+id/buttons_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/route_info_buttons_padding_top_bottom"
android:layout_marginTop="@dimen/route_info_details_padding"
android:layout_marginRight="@dimen/route_info_buttons_padding_top_bottom"
android:layout_marginBottom="@dimen/route_info_details_padding"
android:visibility="visible">
<FrameLayout
android:id="@+id/analyse_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/analyse_button_descr"
android:layout_width="match_parent"
android:layout_height="@dimen/route_info_buttons_height"
android:layout_gravity="center"
android:ellipsize="end"
android:gravity="center"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="1"
android:text="@string/analyze_on_map"
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/text_button_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:ignore="UnusedAttribute" />
</FrameLayout>
</LinearLayout>
</LinearLayout>

View file

@ -10,23 +10,28 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/context_menu_top_shadow" />
<FrameLayout
android:id="@+id/bottom_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/route_info_bg"
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: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="60dp">
android:paddingBottom="24dp">
</LinearLayout>

View file

@ -3,7 +3,7 @@
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_height="@dimen/route_info_control_buttons_height"
android:orientation="horizontal">
<FrameLayout
@ -36,7 +36,7 @@
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="?attr/divider_color_basic"
android:visibility="gone"/>
android:visibility="visible"/>
<FrameLayout
android:id="@+id/start_button"

View file

@ -5,7 +5,6 @@
android:id="@+id/route_info_details_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_and_list_background_basic"
android:orientation="vertical">
<View
@ -19,6 +18,7 @@
android:id="@+id/RouteInfoControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_and_list_background_basic"
android:orientation="vertical">
<LinearLayout
@ -33,13 +33,14 @@
android:layout_height="wrap_content"
android:minHeight="@dimen/route_info_list_item_height"
android:orientation="horizontal"
android:paddingBottom="@dimen/route_info_details_padding"
android:paddingTop="@dimen/route_info_details_padding">
android:paddingTop="@dimen/route_info_details_padding"
android:paddingBottom="@dimen/route_info_details_padding">
<LinearLayout
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="36dp"
android:orientation="horizontal"
android:paddingEnd="@dimen/route_info_buttons_padding_top_bottom"
android:paddingRight="@dimen/route_info_buttons_padding_top_bottom">
@ -66,14 +67,15 @@
android:gravity="left"
android:singleLine="true"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/default_list_text_size" />
android:textSize="@dimen/default_list_text_size"
tools:text="10 km" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/DistanceTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:text="@string/route_distance"
android:text="@string/distance"
android:textColor="@color/description_font_and_bottom_sheet_icons"
android:textSize="@dimen/default_sub_text_size" />
@ -90,8 +92,9 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="36dp"
android:orientation="horizontal"
android:paddingEnd="@dimen/route_info_buttons_padding_top_bottom"
android:paddingRight="@dimen/route_info_buttons_padding_top_bottom">
@ -118,16 +121,17 @@
android:gravity="left"
android:singleLine="true"
android:textColor="?attr/main_font_color_basic"
android:textSize="@dimen/default_list_text_size" />
android:textSize="@dimen/default_list_text_size"
tools:text="5 min" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/DurationTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:text="@string/arrive_at_time"
android:textColor="@color/description_font_and_bottom_sheet_icons"
android:textSize="@dimen/default_sub_text_size" />
android:textSize="@dimen/default_sub_text_size"
tools:text="@string/arrive_at_time" />
</LinearLayout>
@ -146,18 +150,18 @@
<FrameLayout
android:id="@+id/details_button"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_height="@dimen/route_info_buttons_height"
android:layout_gravity="center_vertical"
android:layout_marginBottom="@dimen/route_info_details_padding"
android:layout_marginLeft="@dimen/route_info_buttons_padding_top_bottom"
android:layout_marginRight="@dimen/route_info_buttons_padding_top_bottom"
android:layout_marginTop="@dimen/route_info_details_padding"
android:layout_marginRight="@dimen/route_info_buttons_padding_top_bottom"
android:layout_marginBottom="@dimen/route_info_details_padding"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/details_button_descr"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:ellipsize="end"
android:gravity="center"

View file

@ -118,6 +118,7 @@
android:focusable="false"/>
<LinearLayout
android:id="@+id/chart_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"

View file

@ -77,7 +77,7 @@
<FrameLayout
android:id="@+id/details_button"
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_height="@dimen/route_info_buttons_height"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
@ -85,7 +85,7 @@
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/details_button_descr"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:ellipsize="end"
android:gravity="center"
@ -102,7 +102,7 @@
<FrameLayout
android:id="@+id/show_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_height="@dimen/route_info_buttons_height"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
@ -112,7 +112,7 @@
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/show_button_descr"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:ellipsize="end"
android:gravity="center"

View file

@ -1,7 +1,7 @@
<?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:id="@+id/home_work_card"
android:id="@+id/warning_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

View file

@ -46,6 +46,7 @@
<dimen name="map_widget_icon_margin">3dp</dimen>
<dimen name="standard_icon_size">36dp</dimen>
<!-- ContextMenu -->
<dimen name="context_menu_top_shadow_h">30dp</dimen>
@ -190,7 +191,11 @@
<dimen name="route_info_list_text_padding">78dp</dimen>
<dimen name="route_info_legend_padding">12dp</dimen>
<dimen name="route_info_warning_padding">27dp</dimen>
<dimen name="route_info_chart_height">78dp</dimen>
<dimen name="route_info_chart_height">106dp</dimen>
<dimen name="route_info_control_buttons_height">72dp</dimen>
<dimen name="route_info_button_bg_line_radius">27dp</dimen>
<dimen name="route_info_card_details_margin">13dp</dimen>
<dimen name="route_info_legend_item_size">60dp</dimen>
<dimen name="multi_selection_header_height">78dp</dimen>

View file

@ -3455,4 +3455,6 @@
<string name="poi_wiki_link">Википедия</string>
<string name="poi_rtsa_scale_filter">Категория сложности</string>
<string name="poi_flare">Газовый факел</string>
</resources>

View file

@ -112,6 +112,8 @@
<attr name="main_font_color_basic" format="reference" />
<attr name="active_color_basic" format="reference" />
<attr name="card_and_list_background_basic" format="reference" />
<attr name="activity_background_basic" format="reference" />
<attr name="pages_bg" format="reference"/>
</declare-styleable>
<declare-styleable name="PagerSlidingTabStrip">

View file

@ -476,6 +476,8 @@
<color name="additional_description_light">#b3b3b3</color>
<color name="active_buttons_and_links_light">#237bff</color>
<color name="active_buttons_and_links_dark">#d28521</color>
<color name="inactive_buttons_and_links_light">#cccccc</color>
<color name="inactive_buttons_and_links_dark">#505050</color>
<color name="active_buttons_and_links_trans_light">#66237bff</color>
<color name="active_buttons_and_links_trans_dark">#66d28521</color>

View file

@ -3932,4 +3932,7 @@
<string name="poi_rtsa_scale_3b"></string>
<string name="poi_rtsa_scale_3b_asterisk">3Б*</string>
<string name="poi_flare">Gas flare;Flare stack</string>
<string name="poi_change_delete">Deleted object</string>
</resources>

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="contex_menu_top_shadow_height">16dp</dimen>
<dimen name="dialog_button_ex_height">60dp</dimen>
<dimen name="dialog_button_ex_min_width">72dp</dimen>
<dimen name="dialog_button_ex_max_width">120dp</dimen>
@ -35,6 +36,7 @@
<dimen name="dashboard_land_width">360dp</dimen>
<dimen name="dashboard_map_toolbar">56dp</dimen>
<dimen name="dash_parking_height">78dp</dimen>
<dimen name="dashboard_land_shadow_width">15dp</dimen>
<dimen name="subHeaderPadding">2dp</dimen>
<dimen name="subHeaderMarginLeft">15dp</dimen>
@ -283,8 +285,12 @@
<dimen name="route_info_list_text_padding">54dp</dimen>
<dimen name="route_info_legend_padding">8dp</dimen>
<dimen name="route_info_warning_padding">18dp</dimen>
<dimen name="route_info_chart_height">52dp</dimen>
<dimen name="route_info_chart_height">71dp</dimen>
<dimen name="route_info_toolbar_button_size">40dp</dimen>
<dimen name="route_info_control_buttons_height">48dp</dimen>
<dimen name="route_info_button_bg_line_radius">18dp</dimen>
<dimen name="route_info_card_details_margin">9dp</dimen>
<dimen name="route_info_legend_item_size">40dp</dimen>
<dimen name="multi_selection_header_height">52dp</dimen>
@ -329,6 +335,11 @@
<dimen name="text_button_letter_spacing" format="float">0.01</dimen>
<dimen name="text_button_line_spacing_multiplier" format="float">1.2</dimen>
<dimen name="pages_item_size">4dp</dimen>
<dimen name="pages_item_padding">3dp</dimen>
<dimen name="pages_item_margin">4dp</dimen>
<dimen name="setting_profile_item_height">64dp</dimen>
<dimen name="setting_profile_image_margin">20dp</dimen>
<dimen name="setting_profile_item_switch_margin">18dp</dimen>

File diff suppressed because it is too large Load diff

View file

@ -244,6 +244,8 @@
<item name="main_font_color_basic">@color/main_font_light</item>
<item name="active_color_basic">@color/active_buttons_and_links_light</item>
<item name="card_and_list_background_basic">@color/card_and_list_background_light</item>
<item name="activity_background_basic">@color/activity_background_light</item>
<item name="pages_bg">@drawable/pages_bg_light</item>
</style>
<style name="OverflowMenuButton" parent="@style/Widget.AppCompat.ActionButton.Overflow">
@ -474,6 +476,8 @@
<item name="main_font_color_basic">@color/main_font_dark</item>
<item name="active_color_basic">@color/active_buttons_and_links_dark</item>
<item name="card_and_list_background_basic">@color/card_and_list_background_dark</item>
<item name="activity_background_basic">@color/activity_background_dark</item>
<item name="pages_bg">@drawable/pages_bg_dark</item>
</style>
<style name="FreeVersionBanner" parent="OsmandDarkTheme">

View file

@ -80,7 +80,7 @@ public class UiUtilities {
}
public Drawable getThemedIcon(@DrawableRes int id) {
return getDrawable(id, app.getSettings().isLightContent() ? R.color.icon_color : 0);
return getDrawable(id, R.color.description_font_and_bottom_sheet_icons);
}
public Drawable getIcon(@DrawableRes int id) {

View file

@ -165,6 +165,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
private MapViewTrackingUtilities mapViewTrackingUtilities;
private static MapContextMenu mapContextMenu = new MapContextMenu();
private static MapRouteInfoMenu mapRouteInfoMenu = new MapRouteInfoMenu();
private static TrackDetailsMenu trackDetailsMenu = new TrackDetailsMenu();
private static Intent prevActivityIntent = null;
private List<ActivityResultListener> activityResultListeners = new ArrayList<>();
@ -228,6 +229,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
mapViewTrackingUtilities = app.getMapViewTrackingUtilities();
mapContextMenu.setMapActivity(this);
mapRouteInfoMenu.setMapActivity(this);
trackDetailsMenu.setMapActivity(this);
super.onCreate(savedInstanceState);
// Full screen is not used here
@ -345,8 +347,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
if (removeFragment(PlanRouteFragment.TAG)) {
app.getMapMarkersHelper().getPlanRouteContext().setFragmentVisible(true);
}
if (TrackDetailsMenu.isVisible()) {
mapLayers.getMapControlsLayer().getTrackDetailsMenu().hide();
if (trackDetailsMenu.isVisible()) {
trackDetailsMenu.dismiss();
}
removeFragment(ImportGpxBottomSheetDialogFragment.TAG);
removeFragment(AdditionalActionsBottomSheetDialogFragment.TAG);
@ -587,8 +589,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
showQuickSearch(ShowQuickSearchMode.CURRENT, false);
return;
}
if (TrackDetailsMenu.isVisible()) {
getMapLayers().getMapControlsLayer().getTrackDetailsMenu().hide();
if (trackDetailsMenu.isVisible()) {
trackDetailsMenu.hide();
if (prevActivityIntent == null) {
return;
}
@ -1094,6 +1096,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
dashboardOnMap.hideDashboard();
}
}
if (trackDetailsMenu.isVisible()) {
trackDetailsMenu.show();
}
if (searchRequestToShow != null) {
showQuickSearch(searchRequestToShow);
}
@ -1124,7 +1129,6 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
//mapContextMenu.setMapZoom(settings.getMapZoomToShow());
mapContextMenu.setMapZoom(tb.getZoom());
if (toShow instanceof GpxDisplayItem) {
TrackDetailsMenu trackDetailsMenu = mapLayers.getMapControlsLayer().getTrackDetailsMenu();
trackDetailsMenu.setGpxItem((GpxDisplayItem) toShow);
trackDetailsMenu.show();
} else if (mapRouteInfoMenu.isVisible()) {
@ -1269,6 +1273,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
super.onDestroy();
mapContextMenu.setMapActivity(null);
mapRouteInfoMenu.setMapActivity(null);
trackDetailsMenu.setMapActivity(null);
unregisterReceiver(screenOffReceiver);
app.getAidlApi().onDestroyMapActivity(this);
FailSafeFuntions.quitRouteRestoreDialog();
@ -1596,6 +1601,16 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
return mapRouteInfoMenu;
}
@NonNull
public TrackDetailsMenu getTrackDetailsMenu() {
return trackDetailsMenu;
}
public void hideContextAndRouteInfoMenues() {
mapContextMenu.hideMenues();
mapRouteInfoMenu.hide();
}
public void openDrawer() {
mapActions.updateDrawerMenu();
boolean animate = !settings.DO_NOT_USE_ANIMATIONS.get();
@ -1818,7 +1833,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
WeakReference<MapRouteInfoMenuFragment> fragmentRef = mapRouteInfoMenu.findMenuFragment();
if (fragmentRef != null) {
MapRouteInfoMenuFragment f = fragmentRef.get();
if (landscapeLayout) {
if (!f.isPortrait()) {
tileBoxWidthPx = tb.getPixWidth() - f.getWidth();
} else {
tileBoxHeightPx = tb.getPixHeight() - f.getHeight();

View file

@ -889,7 +889,8 @@ public class MapActivityActions implements DialogProvider {
}
public void openIntermediatePointsDialog() {
WaypointsFragment.showInstance(mapActivity);
mapActivity.hideContextAndRouteInfoMenues();
WaypointsFragment.showInstance(mapActivity.getSupportFragmentManager());
}
public void openRoutePreferencesDialog() {

View file

@ -29,6 +29,7 @@ import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.OverScroller;
import android.widget.Toast;
@ -46,7 +47,6 @@ import net.osmand.plus.mapcontextmenu.InterceptorLinearLayout;
import net.osmand.plus.views.controls.HorizontalSwipeConfirm;
import static net.osmand.plus.mapcontextmenu.MapContextMenuFragment.CURRENT_Y_UNDEFINED;
import static net.osmand.plus.mapcontextmenu.MenuBuilder.SHADOW_HEIGHT_TOP_DP;
public abstract class ContextMenuFragment extends BaseOsmAndFragment {
@ -57,11 +57,16 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
}
public static final int ANIMATION_DURATION = 200;
public static final float MIDDLE_STATE_KOEF = .75f;
public static final String MENU_STATE_KEY = "menu_state_key";
private InterceptorLinearLayout mainView;
private View view;
private OnLayoutChangeListener containerLayoutListener;
private View topShadow;
private LinearLayout cardsContainer;
private FrameLayout bottomContainer;
private LockableScrollView bottomScrollView;
private boolean portrait;
private boolean nightMode;
@ -75,13 +80,11 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
private int topScreenPosY;
private int topToolbarPosY;
private int bottomToolbarPosY;
private int topPadding;
private int menuFullHeightMax;
private int menuBottomViewHeight;
private int menuFullHeight;
private int screenHeight;
private int viewHeight;
private int topShadowMargin;
private int currentMenuState;
private int shadowHeight;
private int statusBarHeight;
@ -92,7 +95,7 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
private ContextMenuFragmentListener listener;
public interface ContextMenuFragmentListener {
void onContextMenuYPosChanged(@NonNull ContextMenuFragment fragment, int y, boolean animated);
void onContextMenuYPosChanged(@NonNull ContextMenuFragment fragment, int y, boolean needMapAdjust, boolean animated);
void onContextMenuStateChanged(@NonNull ContextMenuFragment fragment, int menuState);
void onContextMenuDismiss(@NonNull ContextMenuFragment fragment);
}
@ -101,13 +104,47 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
public abstract int getMainLayoutId();
@IdRes
public abstract int getMainViewId();
public int getMainViewId() {
return R.id.main_view;
}
@IdRes
public abstract int getBottomScrollViewId();
public int getTopShadowViewId() {
return R.id.context_menu_top_shadow;
}
@IdRes
public int getBottomContainerViewId() {
return R.id.bottom_container;
}
@IdRes
public int getCardsContainerViewId() {
return R.id.route_menu_cards_container;
}
@IdRes
public int getBottomScrollViewId() {
return R.id.route_menu_bottom_scroll;
}
@IdRes
public int getTopViewId() {
return 0;
}
public abstract int getHeaderViewHeight();
public abstract boolean isHeaderViewDetached();
public int getLandscapeWidth() {
return getResources().getDimensionPixelSize(R.dimen.dashboard_land_width);
}
public int getLandscapeNoShadowWidth() {
return getLandscapeWidth() - getResources().getDimensionPixelSize(R.dimen.dashboard_land_shadow_width);
}
public abstract int getToolbarHeight();
public boolean isSingleFragment() {
@ -170,12 +207,29 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
return portrait;
}
public View getTopShadow() {
return topShadow;
}
public LinearLayout getCardsContainer() {
return cardsContainer;
}
public FrameLayout getBottomContainer() {
return bottomContainer;
}
public LockableScrollView getBottomScrollView() {
return bottomScrollView;
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
MapActivity mapActivity = requireMapActivity();
OsmandApplication app = mapActivity.getMyApplication();
nightMode = app.getDaynightHelper().isNightModeForMapControls();
preferredMapLang = app.getSettings().MAP_PREFERRED_LOCALE.get();
transliterateNames = app.getSettings().MAP_TRANSLITERATE_NAMES.get();
@ -193,39 +247,37 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
}
portrait = AndroidUiHelper.isOrientationPortrait(mapActivity);
topShadowMargin = AndroidUtils.dpToPx(mapActivity, 9f);
statusBarHeight = AndroidUtils.getStatusBarHeight(mapActivity);
shadowHeight = portrait ? AndroidUtils.dpToPx(mapActivity, SHADOW_HEIGHT_TOP_DP) : 0;
topScreenPosY = addStatusBarHeightIfNeeded(-shadowHeight);
shadowHeight = getResources().getDimensionPixelSize(R.dimen.contex_menu_top_shadow_height);
topScreenPosY = addStatusBarHeightIfNeeded(-shadowHeight) + getToolbarHeight();
topToolbarPosY = getMenuStatePosY(MenuState.FULL_SCREEN);
bottomToolbarPosY = topToolbarPosY + getToolbarHeight();
mainView = view.findViewById(getMainViewId());
nightMode = app.getDaynightHelper().isNightModeForMapControls();
topShadow = view.findViewById(getTopShadowViewId());
cardsContainer = (LinearLayout) view.findViewById(getCardsContainerViewId());
bottomContainer = (FrameLayout) view.findViewById(getBottomContainerViewId());
bottomScrollView = (LockableScrollView) view.findViewById(getBottomScrollViewId());
LockableScrollView bottomScrollView = (LockableScrollView) view.findViewById(getBottomScrollViewId());
bottomScrollView.setScrollingEnabled(false);
AndroidUtils.setBackground(app, bottomScrollView, nightMode, R.color.route_info_bg_light, R.color.route_info_bg_dark);
AndroidUtils.setBackground(app, mainView, nightMode, R.drawable.bg_map_context_menu_light, R.drawable.bg_map_context_menu_dark);
if (getTopViewId() != 0) {
View topView = view.findViewById(getTopViewId());
AndroidUtils.setBackground(app, topView, nightMode, R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
}
if (!portrait) {
currentMenuState = MenuState.FULL_SCREEN;
if (isSingleFragment()) {
topPadding = getToolbarHeight() - topScreenPosY;
final TypedValue typedValueAttr = new TypedValue();
mapActivity.getTheme().resolveAttribute(R.attr.left_menu_view_bg, typedValueAttr, true);
mainView.setBackgroundResource(typedValueAttr.resourceId);
mainView.setLayoutParams(new FrameLayout.LayoutParams(getResources().getDimensionPixelSize(R.dimen.dashboard_land_width), ViewGroup.LayoutParams.MATCH_PARENT));
mainView.setLayoutParams(new FrameLayout.LayoutParams(getLandscapeWidth(), ViewGroup.LayoutParams.MATCH_PARENT));
} else {
topPadding = getToolbarHeight() + topShadowMargin;
mainView.setLayoutParams(new FrameLayout.LayoutParams(AndroidUtils.dpToPx(mapActivity, 345f), ViewGroup.LayoutParams.MATCH_PARENT));
mainView.setLayoutParams(new FrameLayout.LayoutParams(getLandscapeNoShadowWidth(), ViewGroup.LayoutParams.MATCH_PARENT));
}
bottomScrollView.setPadding(0, topPadding, 0, 0);
}
processScreenHeight(container);
minHalfY = viewHeight - (int) (viewHeight * .75f);
minHalfY = viewHeight - (int) (viewHeight * MIDDLE_STATE_KOEF);
final GestureDetector swipeDetector = new GestureDetector(app, new HorizontalSwipeConfirm(true));
@ -426,15 +478,7 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
private int addStatusBarHeightIfNeeded(int res) {
MapActivity mapActivity = getMapActivity();
if (Build.VERSION.SDK_INT >= 21 && mapActivity != null) {
return res + (isSingleFragment() ? statusBarHeight : -statusBarHeight);
}
return res;
}
public int getTopShadowMargin() {
int res = topShadowMargin;
if (Build.VERSION.SDK_INT >= 21 && !isSingleFragment()) {
res -= statusBarHeight;
return res + (isSingleFragment() ? statusBarHeight : 0);
}
return res;
}
@ -525,7 +569,7 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
mainView.setY(y);
ContextMenuFragmentListener listener = this.listener;
if (listener != null) {
listener.onContextMenuYPosChanged(this, y, false);
listener.onContextMenuYPosChanged(this, y, adjustMapPos, false);
}
}
@ -534,27 +578,50 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
screenHeight = container.getHeight() + statusBarHeight;
viewHeight = screenHeight - statusBarHeight - topPadding;
minHalfY = viewHeight - (int) (viewHeight * .75f);
viewHeight = screenHeight - statusBarHeight;
minHalfY = viewHeight - (int) (viewHeight * MIDDLE_STATE_KOEF);
}
}
private int getFullScreenTopPosY() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
int res = topShadowMargin + getToolbarHeight();
if (Build.VERSION.SDK_INT >= 21 && !isSingleFragment()) {
res -= statusBarHeight;
}
return res;
public boolean isMoving() {
return moving;
}
public int getWidth() {
InterceptorLinearLayout mainView = getMainView();
if (mainView != null) {
return mainView.getWidth();
} else {
return 0;
}
}
private int getHeaderOnlyTopY() {
public int getHeight() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
int height = getMenuStatePosY(getCurrentMenuState());
return viewHeight - height - statusBarHeight;
} else {
return 0;
}
}
public int getViewHeight() {
return viewHeight;
}
public int getShadowHeight() {
return shadowHeight;
}
public int getFullScreenTopPosY() {
return topScreenPosY;
}
public int getHeaderOnlyTopY() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
int shadowHeight = getShadowHeight();
if (getHeaderViewHeight() > 0) {
return viewHeight - getHeaderViewHeight() - shadowHeight;
} else {
@ -566,9 +633,6 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
}
public int getMenuStatePosY(int menuState) {
if (!portrait) {
return topScreenPosY;
}
switch (menuState) {
case MenuState.HEADER_ONLY:
return getHeaderOnlyTopY();
@ -712,7 +776,7 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
return posY;
}
private void updateMainViewLayout(int posY) {
protected void updateMainViewLayout(int posY) {
MapActivity mapActivity = getMapActivity();
if (view != null && mapActivity != null) {
ViewGroup.LayoutParams lp = mainView.getLayoutParams();
@ -722,7 +786,7 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
}
}
protected void applyPosY(final int currentY, final boolean needCloseMenu, boolean needMapAdjust,
protected int applyPosY(final int currentY, final boolean needCloseMenu, boolean needMapAdjust,
final int previousMenuState, final int newMenuState, int dZoom, final boolean animated) {
final int posY = getPosY(currentY, needCloseMenu, previousMenuState);
if (getViewY() != posY || dZoom != 0) {
@ -769,9 +833,10 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
}
ContextMenuFragmentListener listener = this.listener;
if (listener != null) {
listener.onContextMenuYPosChanged(this, posY, true);
listener.onContextMenuYPosChanged(this, posY, needMapAdjust, true);
}
}
return posY;
}
public void animateView(@NonNull View view, int y) {
@ -803,10 +868,7 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
if (getActivity() == null) {
return;
}
menuFullHeight = mainView.getHeight();
menuBottomViewHeight = menuFullHeight;
menuFullHeightMax = view.findViewById(R.id.route_menu_cards_container).getHeight();
calculateLayout(view);
if (!moving) {
doLayoutMenu();
@ -823,6 +885,13 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
}
}
protected void calculateLayout(View view) {
menuFullHeight = mainView.getHeight();
menuBottomViewHeight = menuFullHeight;
menuFullHeightMax = view.findViewById(R.id.route_menu_cards_container).getHeight() +
(isHeaderViewDetached() ? getHeaderViewHeight() : 0);
}
private void doLayoutMenu() {
final int posY = getPosY(initLayout ? CURRENT_Y_UNDEFINED : getViewY(), false, getCurrentMenuState());
setViewY(posY, true, !initLayout);
@ -888,7 +957,7 @@ public abstract class ContextMenuFragment extends BaseOsmAndFragment {
if (!portrait) {
tileBoxWidthPx = tb.getPixWidth() - view.getWidth();
} else {
tileBoxHeightPx = getHeaderOnlyTopY();
tileBoxHeightPx = getHeaderOnlyTopY() - getShadowHeight();
}
if (tileBoxHeightPx > 0 || tileBoxWidthPx > 0) {
int topMarginPx = getToolbarHeight();

View file

@ -179,7 +179,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
}
final int screenHeight = AndroidUtils.getScreenHeight(activity);
final int statusBarHeight = AndroidUtils.getStatusBarHeight(activity);
final int contentHeight = getContentHeight(screenHeight - statusBarHeight - AndroidUtils.getNavBarHeight(activity));
final int contentHeight = getContentHeight(screenHeight - statusBarHeight);
mainView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override

View file

@ -0,0 +1,65 @@
package net.osmand.plus.base.bottomsheetmenu;
import android.support.annotation.LayoutRes;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
public class HorizontalRecyclerBottomSheetItem extends BaseBottomSheetItem {
protected RecyclerView.Adapter adapter;
private RecyclerView recyclerView;
public HorizontalRecyclerBottomSheetItem(View customView,
@LayoutRes int layoutId,
Object tag,
boolean disabled,
View.OnClickListener onClickListener,
int position,
RecyclerView.Adapter adapter) {
super(customView, layoutId, tag, disabled, onClickListener, position);
this.adapter = adapter;
}
protected HorizontalRecyclerBottomSheetItem() {
}
public void setAdapter(RecyclerView.Adapter adapter) {
this.adapter = adapter;
recyclerView.setAdapter(adapter);
}
@Override
public void inflate(OsmandApplication app, ViewGroup container, boolean nightMode) {
super.inflate(app, container, nightMode);
recyclerView = ((RecyclerView) view.findViewById(R.id.recycler_view));
if (recyclerView != null && adapter != null) {
recyclerView.setAdapter(adapter);
}
}
public static class Builder extends BaseBottomSheetItem.Builder {
protected RecyclerView.Adapter adapter;
public HorizontalRecyclerBottomSheetItem.Builder setAdapter(RecyclerView.Adapter adapter) {
this.adapter = adapter;
return this;
}
public HorizontalRecyclerBottomSheetItem create() {
return new HorizontalRecyclerBottomSheetItem(customView,
layoutId,
tag,
disabled,
onClickListener,
position,
adapter);
}
}
}

View file

@ -28,7 +28,7 @@ public class WhatsNewDialogFragment extends DialogFragment {
final OsmandApplication osmandApplication = (OsmandApplication) getActivity().getApplication();
final String appVersion = Version.getAppVersion(osmandApplication);
builder.setTitle(getString(R.string.whats_new) + " " + appVersion)
.setMessage(getString(R.string.release_3_3))
.setMessage(getString(R.string.release_3_3_7))
.setNegativeButton(R.string.shared_string_close, null);
if (AppInitializer.LATEST_CHANGES_URL != null) {
builder.setPositiveButton(R.string.read_more, new DialogInterface.OnClickListener() {

View file

@ -60,18 +60,18 @@ import com.github.mikephil.charting.utils.MPPointF;
import net.osmand.AndroidUtils;
import net.osmand.CallbackWithObject;
import net.osmand.IndexConstants;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.Elevation;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.GPXUtilities.Speed;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.IndexConstants;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
@ -96,6 +96,8 @@ import net.osmand.router.RouteStatistics;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import java.io.File;
import java.text.DateFormat;
import java.text.MessageFormat;
@ -106,7 +108,6 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import static com.github.mikephil.charting.components.XAxis.XAxisPosition.BOTTOM;
import static net.osmand.binary.RouteDataObject.HEIGHT_UNDEFINED;
@ -123,7 +124,7 @@ import static net.osmand.plus.download.DownloadActivity.formatMb;
public class GpxUiHelper {
private static final int OPEN_GPX_DOCUMENT_REQUEST = 1005;
private static final int DEFAULT_DISTANCE_FOR_SLOPE_DATA = 2000000;
private static final int MAX_CHART_DATA_ITEMS = 10000;
private static final Log LOG = PlatformUtil.getLog(GpxUiHelper.class);
public static String getDescription(OsmandApplication app, GPXFile result, File f, boolean html) {
@ -1257,10 +1258,12 @@ public class GpxUiHelper {
chart.setExtraRightOffset(16);
chart.setExtraLeftOffset(16);
yl.setTextColor(ContextCompat.getColor(app, nightMode ? R.color.primary_text_dark : R.color.primary_text_light));
yr.setTextColor(ContextCompat.getColor(app, nightMode ? R.color.primary_text_dark : R.color.primary_text_light));
int mainFontColor = ContextCompat.getColor(app, nightMode ? R.color.main_font_dark : R.color.main_font_light);
yl.setTextColor(mainFontColor);
yr.setTextColor(mainFontColor);
chart.setFitBars(true);
chart.setBorderColor(ContextCompat.getColor(app, nightMode ? R.color.divider_dark : R.color.divider_light));
Legend l = chart.getLegend();
l.setEnabled(false);
@ -1297,7 +1300,6 @@ public class GpxUiHelper {
entries.add(new BarEntry(0, stacks));
BarDataSet barDataSet = new BarDataSet(entries, "");
barDataSet.setColors(colors);
barDataSet.setBarBorderColor(ContextCompat.getColor(app, nightMode ? R.color.divider_dark : R.color.divider_light));
BarData dataSet = new BarData(barDataSet);
dataSet.setDrawValues(false);
dataSet.setBarWidth(1);
@ -1618,8 +1620,9 @@ public class GpxUiHelper {
int lastIndex = values.size() - 1;
double STEP = 5;
if (totalDistance > DEFAULT_DISTANCE_FOR_SLOPE_DATA) {
STEP = STEP * (totalDistance / DEFAULT_DISTANCE_FOR_SLOPE_DATA);
int l = 10;
while (l > 0 && totalDistance / STEP > MAX_CHART_DATA_ITEMS) {
STEP = Math.max(STEP, totalDistance / (values.size() * l--));
}
double[] calculatedDist = new double[(int) (totalDistance / STEP) + 1];
@ -1629,15 +1632,15 @@ public class GpxUiHelper {
if (k > 0) {
calculatedDist[k] = calculatedDist[k - 1] + STEP;
}
while(nextW < lastIndex && calculatedDist[k] > values.get(nextW).getX()) {
nextW ++;
while (nextW < lastIndex && calculatedDist[k] > values.get(nextW).getX()) {
nextW++;
}
double pd = nextW == 0 ? 0 : values.get(nextW - 1).getX();
double ph = nextW == 0 ? values.get(0).getY() : values.get(nextW - 1).getY();
calculatedH[k] = ph + (values.get(nextW).getY() - ph) / (values.get(nextW).getX() - pd) * (calculatedDist[k] - pd);
}
double SLOPE_PROXIMITY = 100;
double SLOPE_PROXIMITY = Math.max(100, STEP * 2);
if (totalDistance - SLOPE_PROXIMITY < 0) {
if (useRightAxis) {

View file

@ -937,10 +937,17 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
public void doZoomIn() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
if (map.isZooming() && map.hasCustomMapRatio()) {
RotatedTileBox tb = map.getCurrentRotatedTileBox().copy();
boolean containsLatLon = tb.containsLatLon(menu.getLatLon());
if (!containsLatLon) {
restoreCustomMapRatio();
}
if (map.isZooming() && (map.hasCustomMapRatio() || !containsLatLon)) {
mapActivity.changeZoom(2, System.currentTimeMillis());
} else {
setCustomMapRatio();
if (containsLatLon) {
setCustomMapRatio();
}
mapActivity.changeZoom(1, System.currentTimeMillis());
}
}
@ -949,7 +956,13 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
public void doZoomOut() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
setCustomMapRatio();
RotatedTileBox tb = map.getCurrentRotatedTileBox().copy();
boolean containsLatLon = tb.containsLatLon(menu.getLatLon());
if (containsLatLon) {
setCustomMapRatio();
} else {
restoreCustomMapRatio();
}
mapActivity.changeZoom(-1, System.currentTimeMillis());
}
}
@ -1250,7 +1263,7 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
super.onResume();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
if (!menu.isActive() || (mapActivity.getMapRouteInfoMenu().isVisible()) || MapRouteInfoMenu.chooseRoutesVisible) {
if (!menu.isActive() || (mapActivity.getMapRouteInfoMenu().isVisible()) || MapRouteInfoMenu.chooseRoutesVisible || MapRouteInfoMenu.waypointsVisible) {
dismissMenu();
return;
}

View file

@ -3,7 +3,7 @@ package net.osmand.plus.mapcontextmenu.other;
import android.content.Context;
import android.graphics.Matrix;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.annotation.Nullable;
import android.support.v7.widget.PopupMenu;
import android.view.MenuItem;
import android.view.MotionEvent;
@ -21,14 +21,14 @@ import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import net.osmand.AndroidUtils;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
@ -43,7 +43,6 @@ import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -51,42 +50,114 @@ import java.util.List;
public class TrackDetailsMenu {
@Nullable
private MapActivity mapActivity;
@Nullable
private GpxDisplayItem gpxItem;
@Nullable
private TrackDetailsBarController toolbarController;
@Nullable
private TrkSegment segment;
@Nullable
private TrackChartPoints trackChartPoints;
@Nullable
private List<WptPt> xAxisPoints;
private int topMarginPx;
private boolean visible;
private boolean hidding;
private static boolean VISIBLE;
public TrackDetailsMenu(@NonNull MapActivity mapActivity) {
this.mapActivity = mapActivity;
topMarginPx = AndroidUtils.dpToPx(mapActivity, 48f);
public TrackDetailsMenu() {
}
@Nullable
public MapActivity getMapActivity() {
return mapActivity;
}
public void setMapActivity(@Nullable MapActivity mapActivity) {
this.mapActivity = mapActivity;
if (mapActivity != null) {
if (topMarginPx == 0) {
topMarginPx = AndroidUtils.dpToPx(mapActivity, 48f);
}
}
}
@Nullable
public GpxDisplayItem getGpxItem() {
return gpxItem;
}
public void setGpxItem(GpxDisplayItem gpxItem) {
public void setGpxItem(@NonNull GpxDisplayItem gpxItem) {
this.gpxItem = gpxItem;
}
public static boolean isVisible() {
return VISIBLE;
public boolean isVisible() {
return visible;
}
public void show() {
if (!VISIBLE) {
VISIBLE = true;
MapActivity mapActivity = getMapActivity();
if (mapActivity != null && getGpxItem() != null) {
visible = true;
TrackDetailsMenuFragment.showInstance(mapActivity);
}
}
public void dismiss() {
TrackDetailsMenuFragment fragment = getMenuFragment();
if (fragment != null) {
fragment.dismiss();
}
}
public void hide() {
TrackDetailsMenuFragment fragment = getMenuFragment();
if (fragment != null) {
hidding = true;
fragment.dismiss();
} else {
segment = null;
trackChartPoints = null;
}
}
public void update() {
TrackDetailsMenuFragment fragment = getMenuFragment();
if (fragment != null) {
fragment.updateInfo();
}
}
private TrackDetailsMenuFragment getMenuFragment() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
TrackDetailsMenuFragment fragment = (TrackDetailsMenuFragment) mapActivity.getSupportFragmentManager()
.findFragmentByTag(TrackDetailsMenuFragment.TAG);
if (fragment != null && !fragment.isDetached()) {
return fragment;
}
}
return null;
}
public void onShow() {
MapActivity mapActivity = getMapActivity();
GpxDisplayItem gpxItem = getGpxItem();
if (mapActivity != null && gpxItem != null) {
OsmandApplication app = mapActivity.getMyApplication();
GPXFile groupGpx = gpxItem.group.getGpx();
if (groupGpx != null) {
gpxItem.wasHidden = app.getSelectedGpxHelper().getSelectedFileByPath(groupGpx.path) == null;
app.getSelectedGpxHelper().setGpxFileToDisplay(groupGpx);
}
boolean portrait = AndroidUiHelper.isOrientationPortrait(mapActivity);
if (!portrait) {
mapActivity.getMapView().setMapPositionX(1);
} else {
toolbarController = new TrackDetailsBarController();
if (gpxItem != null && gpxItem.group != null) {
TrackDetailsBarController toolbarController = new TrackDetailsBarController();
this.toolbarController = toolbarController;
if (gpxItem.group != null) {
toolbarController.setTitle(gpxItem.group.getGpxName());
} else {
toolbarController.setTitle(mapActivity.getString(R.string.rendering_category_details));
@ -94,7 +165,10 @@ public class TrackDetailsMenu {
toolbarController.setOnBackButtonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mapActivity.onBackPressed();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.onBackPressed();
}
}
});
toolbarController.setOnCloseButtonClickListener(new View.OnClickListener() {
@ -105,55 +179,34 @@ public class TrackDetailsMenu {
});
mapActivity.showTopToolbar(toolbarController);
}
mapActivity.refreshMap();
TrackDetailsMenuFragment.showInstance(mapActivity);
mapActivity.getMapLayers().getContextMenuLayer().enterGpxDetailsMode();
}
}
public void hide() {
WeakReference<TrackDetailsMenuFragment> fragmentRef = findMenuFragment();
if (fragmentRef != null) {
fragmentRef.get().dismiss();
} else {
segment = null;
VISIBLE = false;
}
}
public void update() {
WeakReference<TrackDetailsMenuFragment> fragmentRef = findMenuFragment();
if (fragmentRef != null) {
fragmentRef.get().updateInfo();
}
}
private WeakReference<TrackDetailsMenuFragment> findMenuFragment() {
Fragment fragment = mapActivity.getSupportFragmentManager().findFragmentByTag(TrackDetailsMenuFragment.TAG);
if (fragment != null && !fragment.isDetached()) {
return new WeakReference<>((TrackDetailsMenuFragment) fragment);
} else {
return null;
}
}
public void onDismiss() {
VISIBLE = false;
if (gpxItem != null && !gpxItem.route && gpxItem.wasHidden && gpxItem.group != null && gpxItem.group.getGpx() != null) {
mapActivity.getMyApplication().getSelectedGpxHelper().selectGpxFile(gpxItem.group.getGpx(), false, false);
GpxDisplayItem gpxItem = getGpxItem();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
if (gpxItem != null && !gpxItem.route && gpxItem.wasHidden && gpxItem.group != null && gpxItem.group.getGpx() != null) {
mapActivity.getMyApplication().getSelectedGpxHelper().selectGpxFile(gpxItem.group.getGpx(), false, false);
}
TrackDetailsBarController toolbarController = this.toolbarController;
if (toolbarController != null) {
mapActivity.hideTopToolbar(toolbarController);
}
mapActivity.getMapLayers().getContextMenuLayer().exitGpxDetailsMode();
mapActivity.getMapLayers().getGpxLayer().setTrackChartPoints(null);
mapActivity.getMapLayers().getMapInfoLayer().setTrackChartPoints(null);
mapActivity.getMapView().setMapPositionX(0);
mapActivity.getMapView().refreshMap();
}
if (toolbarController != null) {
mapActivity.hideTopToolbar(toolbarController);
if (hidding) {
hidding = false;
visible = false;
segment = null;
trackChartPoints = null;
}
mapActivity.getMapLayers().getContextMenuLayer().exitGpxDetailsMode();
mapActivity.getMapLayers().getGpxLayer().setTrackChartPoints(null);
mapActivity.getMapLayers().getMapInfoLayer().setTrackChartPoints(null);
mapActivity.getMapView().setMapPositionX(0);
mapActivity.getMapView().refreshMap();
segment = null;
trackChartPoints = null;
}
public void updateInfo(final View main) {
@ -161,9 +214,11 @@ public class TrackDetailsMenu {
}
private TrkSegment getTrackSegment(LineChart chart) {
TrkSegment segment = this.segment;
if (segment == null) {
List<ILineDataSet> ds = chart.getLineData().getDataSets();
if (ds != null && ds.size() > 0) {
GpxDisplayItem gpxItem = getGpxItem();
if (ds != null && ds.size() > 0 && gpxItem != null) {
for (GPXUtilities.Track t : gpxItem.group.getGpx().tracks) {
for (TrkSegment s : t.segments) {
if (s.points.size() > 0 && s.points.get(0).equals(gpxItem.analysis.locationStart)) {
@ -175,6 +230,7 @@ public class TrackDetailsMenu {
break;
}
}
this.segment = segment;
}
}
return segment;
@ -183,11 +239,12 @@ public class TrackDetailsMenu {
private WptPt getPoint(LineChart chart, float pos) {
WptPt wpt = null;
List<ILineDataSet> ds = chart.getLineData().getDataSets();
if (ds != null && ds.size() > 0) {
GpxDisplayItem gpxItem = getGpxItem();
if (ds != null && ds.size() > 0 && gpxItem != null) {
TrkSegment segment = getTrackSegment(chart);
OrderedLineDataSet dataSet = (OrderedLineDataSet) ds.get(0);
if (gpxItem.chartAxisType == GPXDataSetAxisType.TIME ||
gpxItem.chartAxisType == GPXDataSetAxisType.TIMEOFDAY) {
gpxItem.chartAxisType == GPXDataSetAxisType.TIMEOFDAY) {
float time = pos * 1000;
for (WptPt p : segment.points) {
if (p.time - gpxItem.analysis.startTime >= time) {
@ -220,7 +277,8 @@ public class TrackDetailsMenu {
double left = 0, right = 0;
double top = 0, bottom = 0;
List<ILineDataSet> ds = chart.getLineData().getDataSets();
if (ds != null && ds.size() > 0) {
GpxDisplayItem gpxItem = getGpxItem();
if (ds != null && ds.size() > 0 && gpxItem != null) {
TrkSegment segment = getTrackSegment(chart);
OrderedLineDataSet dataSet = (OrderedLineDataSet) ds.get(0);
if (gpxItem.chartAxisType == GPXDataSetAxisType.TIME || gpxItem.chartAxisType == GPXDataSetAxisType.TIMEOFDAY) {
@ -274,45 +332,55 @@ public class TrackDetailsMenu {
private void fitTrackOnMap(LineChart chart, LatLon location, boolean forceFit) {
QuadRect rect = getRect(chart, chart.getLowestVisibleX(), chart.getHighestVisibleX());
RotatedTileBox tb = mapActivity.getMapView().getCurrentRotatedTileBox().copy();
int tileBoxWidthPx = 0;
int tileBoxHeightPx = 0;
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
RotatedTileBox tb = mapActivity.getMapView().getCurrentRotatedTileBox().copy();
int tileBoxWidthPx = 0;
int tileBoxHeightPx = 0;
WeakReference<TrackDetailsMenuFragment> fragmentRef = findMenuFragment();
if (fragmentRef != null) {
TrackDetailsMenuFragment f = fragmentRef.get();
boolean portrait = AndroidUiHelper.isOrientationPortrait(mapActivity);
if (!portrait) {
tileBoxWidthPx = tb.getPixWidth() - f.getWidth();
} else {
tileBoxHeightPx = tb.getPixHeight() - f.getHeight();
TrackDetailsMenuFragment fragment = getMenuFragment();
if (fragment != null) {
boolean portrait = AndroidUiHelper.isOrientationPortrait(mapActivity);
if (!portrait) {
tileBoxWidthPx = tb.getPixWidth() - fragment.getWidth();
} else {
tileBoxHeightPx = tb.getPixHeight() - fragment.getHeight();
}
}
}
if (tileBoxHeightPx > 0) {
if (forceFit) {
mapActivity.getMapView().fitRectToMap(rect.left, rect.right, rect.top, rect.bottom,
tileBoxWidthPx, tileBoxHeightPx, topMarginPx);
} else if (location != null &&
!mapActivity.getMapView().getTileBox(tileBoxWidthPx, tileBoxHeightPx, topMarginPx).containsLatLon(location)) {
boolean animating = mapActivity.getMapView().getAnimatedDraggingThread().isAnimating();
mapActivity.getMapView().fitLocationToMap(location.getLatitude(), location.getLongitude(),
mapActivity.getMapView().getZoom(), tileBoxWidthPx, tileBoxHeightPx, topMarginPx, !animating);
} else {
mapActivity.refreshMap();
if (tileBoxHeightPx > 0 || tileBoxWidthPx > 0) {
if (forceFit) {
mapActivity.getMapView().fitRectToMap(rect.left, rect.right, rect.top, rect.bottom,
tileBoxWidthPx, tileBoxHeightPx, topMarginPx);
} else if (location != null &&
!mapActivity.getMapView().getTileBox(tileBoxWidthPx, tileBoxHeightPx, topMarginPx).containsLatLon(location)) {
boolean animating = mapActivity.getMapView().getAnimatedDraggingThread().isAnimating();
mapActivity.getMapView().fitLocationToMap(location.getLatitude(), location.getLongitude(),
mapActivity.getMapView().getZoom(), tileBoxWidthPx, tileBoxHeightPx, topMarginPx, !animating);
} else {
mapActivity.refreshMap();
}
}
}
}
private void refreshChart(LineChart chart, boolean forceFit) {
MapActivity mapActivity = getMapActivity();
GpxDisplayItem gpxItem = getGpxItem();
if (mapActivity == null || gpxItem == null) {
return;
}
Highlight[] highlights = chart.getHighlighted();
LatLon location = null;
TrackChartPoints trackChartPoints = this.trackChartPoints;
if (trackChartPoints == null) {
trackChartPoints = new TrackChartPoints();
TrkSegment segment = getTrackSegment(chart);
int segmentColor = segment != null ? segment.getColor(0) : 0;
trackChartPoints.setSegmentColor(segmentColor);
trackChartPoints.setGpx(getGpxItem().group.getGpx());
trackChartPoints.setGpx(gpxItem.group.getGpx());
this.trackChartPoints = trackChartPoints;
}
float minimumVisibleXValue = chart.getLowestVisibleX();
@ -370,6 +438,11 @@ public class TrackDetailsMenu {
}
private void updateView(final View parentView) {
MapActivity mapActivity = getMapActivity();
GpxDisplayItem gpxItem = getGpxItem();
if (mapActivity == null || gpxItem == null) {
return;
}
GPXTrackAnalysis analysis = gpxItem.analysis;
if (analysis == null || gpxItem.chartTypes == null) {
parentView.setVisibility(View.GONE);
@ -408,15 +481,18 @@ public class TrackDetailsMenu {
@Override
public void onChartGestureEnd(MotionEvent me, ChartGesture lastPerformedGesture) {
if ((lastPerformedGesture == ChartGesture.DRAG && hasTranslated) ||
lastPerformedGesture == ChartGesture.X_ZOOM ||
lastPerformedGesture == ChartGesture.Y_ZOOM ||
lastPerformedGesture == ChartGesture.PINCH_ZOOM ||
lastPerformedGesture == ChartGesture.DOUBLE_TAP ||
lastPerformedGesture == ChartGesture.ROTATE) {
GpxDisplayItem gpxItem = getGpxItem();
if (gpxItem != null) {
if ((lastPerformedGesture == ChartGesture.DRAG && hasTranslated) ||
lastPerformedGesture == ChartGesture.X_ZOOM ||
lastPerformedGesture == ChartGesture.Y_ZOOM ||
lastPerformedGesture == ChartGesture.PINCH_ZOOM ||
lastPerformedGesture == ChartGesture.DOUBLE_TAP ||
lastPerformedGesture == ChartGesture.ROTATE) {
gpxItem.chartMatrix = new Matrix(chart.getViewPortHandler().getMatrixTouch());
refreshChart(chart, true);
gpxItem.chartMatrix = new Matrix(chart.getViewPortHandler().getMatrixTouch());
refreshChart(chart, true);
}
}
}
@ -500,21 +576,21 @@ public class TrackDetailsMenu {
final List<GPXDataSetType[]> availableTypes = new ArrayList<>();
boolean hasSlopeChart = false;
if (analysis.hasElevationData) {
availableTypes.add(new GPXDataSetType[] { GPXDataSetType.ALTITUDE });
availableTypes.add(new GPXDataSetType[]{GPXDataSetType.ALTITUDE});
if (gpxItem.chartAxisType != GPXDataSetAxisType.TIME
&& gpxItem.chartAxisType != GPXDataSetAxisType.TIMEOFDAY) {
&& gpxItem.chartAxisType != GPXDataSetAxisType.TIMEOFDAY) {
availableTypes.add(new GPXDataSetType[]{GPXDataSetType.SLOPE});
}
}
if (analysis.hasSpeedData) {
availableTypes.add(new GPXDataSetType[] { GPXDataSetType.SPEED });
availableTypes.add(new GPXDataSetType[]{GPXDataSetType.SPEED});
}
if (analysis.hasElevationData && gpxItem.chartAxisType != GPXDataSetAxisType.TIME
&& gpxItem.chartAxisType != GPXDataSetAxisType.TIMEOFDAY) {
availableTypes.add(new GPXDataSetType[] { GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE });
&& gpxItem.chartAxisType != GPXDataSetAxisType.TIMEOFDAY) {
availableTypes.add(new GPXDataSetType[]{GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE});
}
if (analysis.hasElevationData && analysis.hasSpeedData) {
availableTypes.add(new GPXDataSetType[] { GPXDataSetType.ALTITUDE, GPXDataSetType.SPEED });
availableTypes.add(new GPXDataSetType[]{GPXDataSetType.ALTITUDE, GPXDataSetType.SPEED});
}
for (GPXDataSetType t : gpxItem.chartTypes) {
@ -529,7 +605,7 @@ public class TrackDetailsMenu {
yAxis.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final PopupMenu optionsMenu = new PopupMenu(mapActivity, v);
PopupMenu optionsMenu = new PopupMenu(v.getContext(), v);
DirectionsDialogs.setupPopUpMenuIcon(optionsMenu);
for (final GPXDataSetType[] types : availableTypes) {
MenuItem menuItem = optionsMenu.getMenu()
@ -538,6 +614,7 @@ public class TrackDetailsMenu {
menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem mItem) {
GpxDisplayItem gpxItem = getGpxItem();
gpxItem.chartTypes = types;
update();
return true;
@ -572,20 +649,24 @@ public class TrackDetailsMenu {
xAxis.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final PopupMenu optionsMenu = new PopupMenu(mapActivity, v);
final PopupMenu optionsMenu = new PopupMenu(v.getContext(), v);
DirectionsDialogs.setupPopUpMenuIcon(optionsMenu);
for (final GPXDataSetAxisType type : GPXDataSetAxisType.values()) {
MenuItem menuItem = optionsMenu.getMenu()
.add(type.getStringId()).setIcon(type.getImageDrawable(app));
.add(type.getStringId()).setIcon(type.getImageDrawable(app));
menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem mItem) {
gpxItem.chartAxisType = type;
gpxItem.chartHighlightPos = -1;
gpxItem.chartMatrix = null;
update();
return true;
GpxDisplayItem gpxItem = getGpxItem();
if (gpxItem != null) {
gpxItem.chartAxisType = type;
gpxItem.chartHighlightPos = -1;
gpxItem.chartMatrix = null;
update();
return true;
} else {
return false;
}
}
});
}
@ -603,15 +684,18 @@ public class TrackDetailsMenu {
}
private void updateChart(LineChart chart) {
GpxDisplayItem gpxItem = getGpxItem();
chart.notifyDataSetChanged();
chart.invalidate();
if (gpxItem.chartMatrix != null) {
chart.getViewPortHandler().refresh(new Matrix(gpxItem.chartMatrix), chart, true);
}
if (gpxItem.chartHighlightPos != -1) {
chart.highlightValue(gpxItem.chartHighlightPos, 0);
} else {
chart.highlightValue(null);
if (gpxItem != null) {
if (gpxItem.chartMatrix != null) {
chart.getViewPortHandler().refresh(new Matrix(gpxItem.chartMatrix), chart, true);
}
if (gpxItem.chartHighlightPos != -1) {
chart.highlightValue(gpxItem.chartHighlightPos, 0);
} else {
chart.highlightValue(null);
}
}
}

View file

@ -3,8 +3,10 @@ package net.osmand.plus.mapcontextmenu.other;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -24,20 +26,29 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
private TrackDetailsMenu menu;
private View mainView;
private boolean paused = true;
@Nullable
private MapActivity getMapActivity() {
return (MapActivity) getActivity();
}
@NonNull
private MapActivity requireMapActivity() {
return (MapActivity) requireMyActivity();
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
MapActivity mapActivity = getMapActivity();
menu = mapActivity.getMapLayers().getMapControlsLayer().getTrackDetailsMenu();
View view = inflater.inflate(R.layout.track_details, container, false);
if (!AndroidUiHelper.isOrientationPortrait(getActivity())) {
AndroidUtils.addStatusBarPadding21v(getActivity(), view);
MapActivity mapActivity = requireMapActivity();
menu = mapActivity.getTrackDetailsMenu();
boolean nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls();
ContextThemeWrapper context =
new ContextThemeWrapper(mapActivity, !nightMode ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
View view = LayoutInflater.from(context).inflate(R.layout.track_details, container, false);
if (!AndroidUiHelper.isOrientationPortrait(mapActivity)) {
AndroidUtils.addStatusBarPadding21v(mapActivity, view);
}
if (menu == null || menu.getGpxItem() == null) {
return view;
@ -50,7 +61,7 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
if (menu.getGpxItem().group != null) {
topBarTitle.setText(menu.getGpxItem().group.getGpxName());
} else {
topBarTitle.setText(mapActivity.getString(R.string.rendering_category_details));
topBarTitle.setText(R.string.rendering_category_details);
}
}
@ -60,7 +71,10 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().onBackPressed();
FragmentActivity activity = getActivity();
if (activity != null) {
activity.onBackPressed();
}
}
});
}
@ -68,7 +82,7 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
menu.hide();
}
});
}
@ -101,7 +115,16 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
super.onResume();
if (menu == null || menu.getGpxItem() == null) {
dismiss();
} else {
menu.onShow();
}
paused = false;
}
@Override
public void onPause() {
super.onPause();
paused = true;
}
@Override
@ -117,6 +140,10 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
return R.color.status_bar_transparent_gradient;
}
public boolean isPaused() {
return paused;
}
public int getHeight() {
if (mainView != null) {
return mainView.getHeight();
@ -158,28 +185,29 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
public void applyDayNightMode() {
MapActivity ctx = getMapActivity();
boolean portraitMode = AndroidUiHelper.isOrientationPortrait(ctx);
boolean landscapeLayout = !portraitMode;
boolean nightMode = ctx.getMyApplication().getDaynightHelper().isNightModeForMapControls();
if (!landscapeLayout) {
AndroidUtils.setBackground(ctx, mainView, nightMode, R.drawable.bg_bottom_menu_light, R.drawable.bg_bottom_menu_dark);
} else {
AndroidUtils.setBackground(ctx, mainView, nightMode, R.drawable.bg_left_menu_light, R.drawable.bg_left_menu_dark);
if (ctx != null) {
boolean portraitMode = AndroidUiHelper.isOrientationPortrait(ctx);
boolean landscapeLayout = !portraitMode;
boolean nightMode = ctx.getMyApplication().getDaynightHelper().isNightModeForMapControls();
if (!landscapeLayout) {
AndroidUtils.setBackground(ctx, mainView, nightMode, R.drawable.bg_bottom_menu_light, R.drawable.bg_bottom_menu_dark);
} else {
AndroidUtils.setBackground(ctx, mainView, nightMode, R.drawable.bg_left_menu_light, R.drawable.bg_left_menu_dark);
}
AndroidUtils.setTextPrimaryColor(ctx, (TextView) mainView.findViewById(R.id.y_axis_title), nightMode);
AndroidUtils.setTextPrimaryColor(ctx, (TextView) mainView.findViewById(R.id.x_axis_title), nightMode);
ImageView yAxisArrow = (ImageView) mainView.findViewById(R.id.y_axis_arrow);
ImageView xAxisArrow = (ImageView) mainView.findViewById(R.id.x_axis_arrow);
yAxisArrow.setImageDrawable(getContentIcon(R.drawable.ic_action_arrow_drop_down));
xAxisArrow.setImageDrawable(getContentIcon(R.drawable.ic_action_arrow_drop_down));
ImageButton backButton = (ImageButton) mainView.findViewById(R.id.top_bar_back_button);
if (backButton != null) {
backButton.setImageDrawable(getIcon(R.drawable.ic_arrow_back, R.color.color_white));
}
}
AndroidUtils.setTextPrimaryColor(ctx, (TextView) mainView.findViewById(R.id.y_axis_title), nightMode);
AndroidUtils.setTextPrimaryColor(ctx, (TextView) mainView.findViewById(R.id.x_axis_title), nightMode);
ImageView yAxisArrow = (ImageView) mainView.findViewById(R.id.y_axis_arrow);
ImageView xAxisArrow = (ImageView) mainView.findViewById(R.id.x_axis_arrow);
yAxisArrow.setImageDrawable(getContentIcon(R.drawable.ic_action_arrow_drop_down));
xAxisArrow.setImageDrawable(getContentIcon(R.drawable.ic_action_arrow_drop_down));
ImageButton backButton = (ImageButton) mainView.findViewById(R.id.top_bar_back_button);
if (backButton != null) {
backButton.setImageDrawable(getIcon(R.drawable.ic_arrow_back, R.color.color_white));
}
}
public static boolean showInstance(final MapActivity mapActivity) {

View file

@ -316,14 +316,17 @@ public class MeasurementEditingContext {
public void onRouteCalculated(RouteCalculationResult route) {
List<Location> locations = route.getRouteLocations();
ArrayList<WptPt> pts = new ArrayList<>(locations.size());
double prevAltitude = Double.NaN;
for (Location loc : locations) {
if(!loc.hasAltitude()){
continue;
}
WptPt pt = new WptPt();
pt.lat = loc.getLatitude();
pt.lon = loc.getLongitude();
pt.ele = loc.getAltitude();
if (loc.hasAltitude()) {
prevAltitude = loc.getAltitude();
pt.ele = prevAltitude;
} else if (!Double.isNaN(prevAltitude)) {
pt.ele = prevAltitude;
}
pts.add(pt);
}
calculatedPairs++;

View file

@ -1358,10 +1358,6 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment {
if (list.size() > 0) {
gpxItem.chartTypes = list.toArray(new GPXDataSetType[list.size()]);
}
if (gpxItem.group.getGpx() != null) {
gpxItem.wasHidden = app.getSelectedGpxHelper().getSelectedFileByPath(gpxInfo.file.getAbsolutePath()) == null;
app.getSelectedGpxHelper().setGpxFileToDisplay(gpxItem.group.getGpx());
}
final OsmandSettings settings = app.getSettings();
settings.setMapLocationToShow(gpxItem.locationStart.lat, gpxItem.locationStart.lon,
settings.getLastKnownMapZoom(),

View file

@ -157,6 +157,9 @@ public class TrackPointFragment extends OsmandExpandableListFragment implements
public void onPause() {
super.onPause();
setUpdateEnable(false);
if (actionMode != null) {
actionMode.finish();
}
if (optionsMenu != null) {
optionsMenu.close();
}
@ -1004,7 +1007,7 @@ public class TrackPointFragment extends OsmandExpandableListFragment implements
public void onClick(View v) {
List<GpxDisplayItem> items = itemGroups.get(group);
if (ch.isChecked()) {
if (groupPosition == 0) {
if (groupPosition == 0 && groups.size() > 1) {
setTrackPointsSelection(true);
} else {
setGroupSelection(items, groupPosition, true);
@ -1027,7 +1030,7 @@ public class TrackPointFragment extends OsmandExpandableListFragment implements
}
private void setTrackPointsSelection(boolean select) {
if (groups.size() > 1) {
if (!groups.isEmpty()) {
setGroupSelection(null, 0, select);
for (int i = 1; i < groups.size(); i++) {
GpxDisplayGroup g = groups.get(i);

View file

@ -1168,12 +1168,6 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
gpxItem.locationOnMap = gpxItem.locationStart;
}
GPXFile gpx = getGpx();
GPXFile groupGpx = gpxItem.group.getGpx();
if (gpx != null && groupGpx != null) {
gpxItem.wasHidden = app.getSelectedGpxHelper().getSelectedFileByPath(gpx.path) == null;
app.getSelectedGpxHelper().setGpxFileToDisplay(groupGpx);
}
final OsmandSettings settings = app.getSettings();
settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(),
settings.getLastKnownMapZoom(),

View file

@ -1,30 +1,41 @@
package net.osmand.plus.routepreparationmenu;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.text.SpannableString;
import android.util.Pair;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.AndroidUtils;
import net.osmand.Location;
import net.osmand.data.FavouritePoint;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.MapMarkersHelper;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.TargetPointsHelper;
import net.osmand.plus.TargetPointsHelper.TargetPoint;
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.HorizontalRecyclerBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerHalfItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.helpers.MapMarkerDialogHelper;
import net.osmand.plus.helpers.WaypointDialogHelper;
@ -33,10 +44,9 @@ import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu.PointType;
import net.osmand.plus.search.QuickSearchDialogFragment;
import net.osmand.plus.widgets.style.CustomTypefaceSpan;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.data.PointDescription.POINT_TYPE_MY_LOCATION;
public class AddPointBottomSheetDialog extends MenuBottomSheetDialogFragment {
public static final String TAG = "AddPointBottomSheetDialog";
@ -44,6 +54,8 @@ public class AddPointBottomSheetDialog extends MenuBottomSheetDialogFragment {
public static final int ADD_FAVOURITE_TO_ROUTE_REQUEST_CODE = 1;
public static final String FAVOURITES = "favourites";
private PointType pointType = PointType.START;
@Override
@ -81,27 +93,27 @@ public class AddPointBottomSheetDialog extends MenuBottomSheetDialogFragment {
case START:
createMyLocItem();
createSelectOnTheMapItem();
createFavouritesItem();
createFavouritesScrollItem();
createMarkersItem();
items.add(new DividerHalfItem(getContext()));
createSwitchStartAndEndItem();
break;
case TARGET:
createSelectOnTheMapItem();
createFavouritesItem();
createFavouritesScrollItem();
createMarkersItem();
items.add(new DividerHalfItem(getContext()));
createSwitchStartAndEndItem();
break;
case INTERMEDIATE:
createSelectOnTheMapItem();
createFavouritesItem();
createFavouritesScrollItem();
createMarkersItem();
break;
case HOME:
case WORK:
createSelectOnTheMapItem();
createFavouritesItem();
createFavouritesScrollItem();
createMarkersItem();
break;
default:
@ -245,30 +257,6 @@ public class AddPointBottomSheetDialog extends MenuBottomSheetDialogFragment {
items.add(selectOnTheMapItem);
}
private void createFavouritesItem() {
BaseBottomSheetItem favouritesItem = new SimpleBottomSheetItem.Builder()
.setIcon(getContentIcon(R.drawable.ic_action_fav_dark))
.setTitle(getString(R.string.shared_string_favorites))
.setLayoutId(R.layout.bottom_sheet_item_simple_56dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = (MapActivity) getActivity();
if (mapActivity != null) {
FragmentManager fragmentManager = mapActivity.getSupportFragmentManager();
FavouritesBottomSheetMenuFragment fragment = new FavouritesBottomSheetMenuFragment();
Bundle args = new Bundle();
args.putString(FavouritesBottomSheetMenuFragment.POINT_TYPE_KEY, pointType.name());
fragment.setTargetFragment(AddPointBottomSheetDialog.this, ADD_FAVOURITE_TO_ROUTE_REQUEST_CODE);
fragment.setArguments(args);
fragment.show(fragmentManager, FavouritesBottomSheetMenuFragment.TAG);
}
}
})
.create();
items.add(favouritesItem);
}
private void createMarkersItem() {
final OsmandApplication app = getMyApplication();
if (app == null) {
@ -352,4 +340,249 @@ public class AddPointBottomSheetDialog extends MenuBottomSheetDialogFragment {
}).create();
items.add(switchStartAndEndItem);
}
private void loadFavoritesItems(List<Object> items, FavouritesDbHelper helper) {
items.clear();
addMainScrollItems(items);
items.addAll(helper.getVisibleFavouritePoints());
if (items.isEmpty()) {
items.addAll(helper.getFavouritePoints());
}
}
private void addMainScrollItems(List<Object> items) {
items.add(FAVOURITES);
items.add(PointType.HOME);
items.add(PointType.WORK);
}
private void createFavouritesScrollItem() {
final OsmandApplication app = getMyApplication();
if (app != null) {
List<Object> items = new ArrayList<>();
final FavouritesItemsAdapter adapter = new FavouritesItemsAdapter(app, items);
adapter.setItemClickListener(getAdapterOnClickListener(items));
final FavouritesDbHelper helper = app.getFavorites();
if (helper.isFavoritesLoaded()) {
loadFavoritesItems(items, helper);
} else {
addMainScrollItems(items);
helper.addListener(new FavouritesDbHelper.FavoritesListener() {
@Override
public void onFavoritesLoaded() {
MapActivity mapActivity = (MapActivity) getActivity();
if (mapActivity != null) {
loadFavoritesItems(adapter.items, helper);
adapter.notifyDataSetChanged();
}
}
});
}
BaseBottomSheetItem scrollItem = new HorizontalRecyclerBottomSheetItem.Builder()
.setAdapter(adapter)
.setLayoutId(R.layout.bottom_sheet_item_recyclerview)
.create();
this.items.add(scrollItem);
}
}
private View.OnClickListener getAdapterOnClickListener(final List<Object> items) {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = (MapActivity) getActivity();
RecyclerView.ViewHolder viewHolder = (RecyclerView.ViewHolder) v.getTag();
int position = viewHolder != null ? viewHolder.getAdapterPosition() : RecyclerView.NO_POSITION;
if (mapActivity == null || position == RecyclerView.NO_POSITION) {
return;
}
Object item = items.get(position);
if (item.equals(FAVOURITES)) {
openFavouritesDialog();
} else {
TargetPointsHelper helper = mapActivity.getMyApplication().getTargetPointsHelper();
Pair<LatLon, PointDescription> pair = getLocationAndDescrFromItem(item, helper);
LatLon ll = pair.first;
PointDescription name = pair.second;
if (ll == null) {
if (item instanceof PointType) {
AddPointBottomSheetDialog.showInstance(mapActivity, (PointType) item);
} else {
dismiss();
}
} else {
switch (pointType) {
case START:
helper.setStartPoint(ll, true, name);
break;
case TARGET:
helper.navigateToPoint(ll, true, -1, name);
break;
case INTERMEDIATE:
helper.navigateToPoint(ll, true, helper.getIntermediatePoints().size(), name);
break;
}
dismiss();
}
}
}
};
}
private Pair<LatLon, PointDescription> getLocationAndDescrFromItem(Object item, TargetPointsHelper helper) {
PointDescription name = null;
LatLon ll = null;
if (item instanceof FavouritePoint) {
FavouritePoint point = (FavouritePoint) item;
ll = new LatLon(point.getLatitude(), point.getLongitude());
name = point.getPointDescription();
} else if (item instanceof PointType) {
TargetPointsHelper.TargetPoint point = null;
if (item == PointType.HOME) {
point = helper.getHomePoint();
} else if (item == PointType.WORK) {
point = helper.getWorkPoint();
}
if (point != null) {
ll = new LatLon(point.getLatitude(), point.getLongitude());
name = point.getOriginalPointDescription();
}
}
return new Pair<>(ll, name);
}
private void openFavouritesDialog() {
MapActivity mapActivity = (MapActivity) getActivity();
if (mapActivity != null) {
FragmentManager fragmentManager = mapActivity.getSupportFragmentManager();
FavouritesBottomSheetMenuFragment fragment = new FavouritesBottomSheetMenuFragment();
Bundle args = new Bundle();
args.putString(FavouritesBottomSheetMenuFragment.POINT_TYPE_KEY, pointType.name());
fragment.setTargetFragment(AddPointBottomSheetDialog.this, ADD_FAVOURITE_TO_ROUTE_REQUEST_CODE);
fragment.setArguments(args);
fragment.show(fragmentManager, FavouritesBottomSheetMenuFragment.TAG);
}
}
public static boolean showInstance(@NonNull MapActivity mapActivity, PointType pointType) {
return showInstance(mapActivity, pointType, true);
}
public static boolean showInstance(@NonNull MapActivity mapActivity, PointType pointType, boolean usedOnMap) {
try {
if (mapActivity.isActivityDestroyed()) {
return false;
}
Bundle args = new Bundle();
args.putString(AddPointBottomSheetDialog.POINT_TYPE_KEY, pointType.name());
AddPointBottomSheetDialog fragment = new AddPointBottomSheetDialog();
fragment.setArguments(args);
fragment.setUsedOnMap(usedOnMap);
fragment.show(mapActivity.getSupportFragmentManager(), TAG);
return true;
} catch (RuntimeException e) {
return false;
}
}
public class FavouritesItemsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<Object> items;
private OsmandApplication app;
private View.OnClickListener listener;
public FavouritesItemsAdapter(OsmandApplication app, List<Object> items) {
this.app = app;
this.items = items;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.bottom_sheet_item_with_descr_56dp, viewGroup, false);
view.setOnClickListener(listener);
Activity activity = getActivity();
if (activity != null) {
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
if (AndroidUiHelper.isOrientationPortrait(getActivity())) {
layoutParams.width = AndroidUtils.getScreenWidth(activity) / 2;
} else {
// 11.5dp is the shadow width
layoutParams.width = (getResources().getDimensionPixelSize(R.dimen.landscape_bottom_sheet_dialog_fragment_width) / 2) - AndroidUtils.dpToPx(activity, 11.5f);
}
view.setLayoutParams(layoutParams);
}
FavouritesViewHolder viewHolder = new FavouritesViewHolder(view);
view.setTag(viewHolder);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof FavouritesViewHolder) {
Object item = getItem(position);
FavouritesViewHolder favouritesViewHolder = (FavouritesViewHolder) holder;
if (item.equals(FAVOURITES)) {
favouritesViewHolder.title.setText(R.string.shared_string_favorites);
favouritesViewHolder.icon.setImageDrawable(getContentIcon(R.drawable.ic_action_fav_dark));
favouritesViewHolder.description.setVisibility(View.GONE);
} else {
if (item instanceof PointType) {
final TargetPointsHelper helper = app.getTargetPointsHelper();
TargetPointsHelper.TargetPoint point = null;
if (item == PointType.HOME) {
point = helper.getHomePoint();
favouritesViewHolder.title.setText(getString(R.string.home_button));
favouritesViewHolder.icon.setImageDrawable(getContentIcon(R.drawable.ic_action_home_dark));
} else if (item == PointType.WORK) {
point = helper.getWorkPoint();
favouritesViewHolder.title.setText(getString(R.string.work_button));
favouritesViewHolder.icon.setImageDrawable(getContentIcon(R.drawable.ic_action_work));
}
favouritesViewHolder.description.setText(point != null ? point.getPointDescription(app).getSimpleName(app, false) : getString(R.string.shared_string_add));
} else if (item instanceof FavouritePoint) {
FavouritePoint point = (FavouritePoint) getItem(position);
favouritesViewHolder.title.setText(point.getName());
if (point.getCategory().equals("")) {
favouritesViewHolder.description.setText(R.string.shared_string_favorites);
} else {
favouritesViewHolder.description.setText(point.getCategory());
}
int pointColor = point.getColor();
int color = pointColor == 0 || pointColor == Color.BLACK ? ContextCompat.getColor(app, R.color.color_favorite) : pointColor;
favouritesViewHolder.icon.setImageDrawable(app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_fav_dark, color));
}
favouritesViewHolder.description.setVisibility(View.VISIBLE);
}
}
}
@Override
public int getItemCount() {
return items.size();
}
private Object getItem(int position) {
return items.get(position);
}
public void setItemClickListener(View.OnClickListener listener) {
this.listener = listener;
}
class FavouritesViewHolder extends RecyclerView.ViewHolder {
final TextView title;
final TextView description;
final ImageView icon;
public FavouritesViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
icon = (ImageView) itemView.findViewById(R.id.icon);
}
}
}
}

View file

@ -302,11 +302,7 @@ public class AvoidRoadsBottomSheetDialogFragment extends MenuBottomSheetDialogFr
avoidSpecificRoads.removeImpassableRoad(routeLocation);
}
RoutingHelper routingHelper = app.getRoutingHelper();
if (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated()) {
routingHelper.recalculateRouteDueToSettingsChange();
}
app.getRoutingHelper().recalculateRouteDueToSettingsChange();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
final MapRouteInfoMenu mapRouteInfoMenu = mapActivity.getMapRouteInfoMenu();

View file

@ -3,6 +3,7 @@ package net.osmand.plus.routepreparationmenu;
import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@ -27,14 +28,19 @@ import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
import net.osmand.Location;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.LockableViewPager;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmAndLocationProvider;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.MapActivityActions;
@ -82,13 +88,18 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
private View zoomButtonsView;
@Nullable
private ImageButton myLocButtonView;
@Nullable
private ViewGroup pagesView;
private boolean portrait;
private boolean nightMode;
private boolean wasDrawerDisabled;
private int currentMenuState;
private int routesCount;
private boolean publicTransportMode;
private int routeInfoMenuState = -1;
private boolean openingAnalyseOnMap = false;
@Nullable
@Override
@ -107,8 +118,10 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
routeInfoMenuState = args.getInt(ROUTE_INFO_STATE_KEY, -1);
initialMenuState = args.getInt(INITIAL_MENU_STATE_KEY, initialMenuState);
}
routesCount = 1;
if (routes != null && !routes.isEmpty()) {
publicTransportMode = true;
routesCount = routes.size();
}
ContextThemeWrapper context =
new ContextThemeWrapper(mapActivity, !nightMode ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
@ -121,7 +134,8 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
this.viewPager = viewPager;
if (!portrait) {
initialMenuState = MenuState.FULL_SCREEN;
solidToolbarView.setLayoutParams(new FrameLayout.LayoutParams(AndroidUtils.dpToPx(mapActivity, 345f), ViewGroup.LayoutParams.WRAP_CONTENT));
int width = getResources().getDimensionPixelSize(R.dimen.dashboard_land_width) - getResources().getDimensionPixelSize(R.dimen.dashboard_land_shadow_width);
solidToolbarView.setLayoutParams(new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
solidToolbarView.setVisibility(View.VISIBLE);
final TypedValue typedValueAttr = new TypedValue();
mapActivity.getTheme().resolveAttribute(R.attr.left_menu_view_bg, typedValueAttr, true);
@ -129,9 +143,11 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
view.setLayoutParams(new FrameLayout.LayoutParams(getResources().getDimensionPixelSize(R.dimen.dashboard_land_width), ViewGroup.LayoutParams.MATCH_PARENT));
}
viewPager.setClipToPadding(false);
final RoutesPagerAdapter pagerAdapter = new RoutesPagerAdapter(getChildFragmentManager(), publicTransportMode ? routes.size() : 1, initialMenuState);
currentMenuState = initialMenuState;
final RoutesPagerAdapter pagerAdapter = new RoutesPagerAdapter(getChildFragmentManager(), routesCount);
viewPager.setAdapter(pagerAdapter);
viewPager.setCurrentItem(routeIndex);
viewPager.setOffscreenPageLimit(routesCount);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {
}
@ -141,22 +157,30 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
public void onPageSelected(int position) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
View view = getView();
if (mapActivity != null && view != null) {
mapActivity.getMyApplication().getTransportRoutingHelper().setCurrentRoute(position);
mapActivity.refreshMap();
buildPagesControl(view);
List<WeakReference<RouteDetailsFragment>> routeDetailsFragments = ChooseRouteFragment.this.routeDetailsFragments;
for (WeakReference<RouteDetailsFragment> ref : routeDetailsFragments) {
RouteDetailsFragment f = ref.get();
if (f != null) {
PublicTransportCard card = f.getTransportCard();
if (card != null) {
card.update();
card.updateButtons();
}
if (f == getCurrentFragment()) {
updateZoomButtonsPos(f, f.getViewY(), true);
updatePagesViewPos(f, f.getViewY(), true);
}
}
}
}
}
});
this.pagesView = (ViewGroup) view.findViewById(R.id.pages_control);
buildPagesControl(view);
buildZoomButtons(view);
buildMenuButtons(view);
return view;
@ -227,13 +251,27 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
return getIcon(id, nightMode ? R.color.ctx_menu_info_text_dark : R.color.icon_color);
}
public void analyseOnMap(LatLon location, GpxDisplayItem gpxItem) {
openingAnalyseOnMap = true;
OsmandApplication app = requireMyApplication();
final OsmandSettings settings = app.getSettings();
settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(),
settings.getLastKnownMapZoom(),
new PointDescription(PointDescription.POINT_TYPE_WPT, gpxItem.name),
false,
gpxItem);
dismiss();
MapActivity.launchMapActivityMoveToTop(getMapActivity());
}
public void dismiss() {
try {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getSupportFragmentManager().beginTransaction().remove(this).commitAllowingStateLoss();
if (routeInfoMenuState != -1) {
mapActivity.getMapLayers().getMapControlsLayer().showRouteInfoMenu(routeInfoMenuState);
if (routeInfoMenuState != -1 && !openingAnalyseOnMap) {
mapActivity.getMapLayers().getMapControlsLayer().showRouteInfoControlDialog(routeInfoMenuState);
}
}
} catch (Exception e) {
@ -241,6 +279,41 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
}
}
private void buildPagesControl(@NonNull View view) {
ViewGroup pagesView = this.pagesView;
if (pagesView != null) {
pagesView.removeAllViews();
LockableViewPager viewPager = this.viewPager;
if (portrait && routesCount > 1 && viewPager != null) {
int itemSize = getResources().getDimensionPixelSize(R.dimen.pages_item_size);
int itemMargin = getResources().getDimensionPixelSize(R.dimen.pages_item_margin);
int itemPadding = getResources().getDimensionPixelSize(R.dimen.pages_item_padding);
for (int i = 0; i < routesCount; i++) {
boolean active = i == viewPager.getCurrentItem();
Context ctx = view.getContext();
View itemView = new View(ctx);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(itemSize, itemSize);
AndroidUtils.setBackground(ctx, itemView, nightMode,
active ? R.drawable.pages_active_light : R.drawable.pages_inactive_light,
active ? R.drawable.pages_active_dark : R.drawable.pages_inactive_dark);
if (i == 0) {
layoutParams.setMargins(itemMargin, 0, itemPadding, 0);
} else if (i == routesCount - 1) {
layoutParams.setMargins(0, 0, itemMargin, 0);
} else {
layoutParams.setMargins(0, 0, itemPadding, 0);
}
itemView.setLayoutParams(layoutParams);
pagesView.addView(itemView);
}
pagesView.requestLayout();
pagesView.setVisibility(View.VISIBLE);
} else {
pagesView.setVisibility(View.GONE);
}
}
}
private void buildZoomButtons(@NonNull View view) {
OsmandApplication app = requireMyApplication();
// Zoom buttons
@ -351,6 +424,26 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
}
}
private void updatePagesViewVisibility(int menuState) {
View pagesView = this.pagesView;
if (portrait && routesCount > 1 && pagesView != null) {
if (menuState != MenuState.FULL_SCREEN) {
if (pagesView.getVisibility() != View.VISIBLE) {
pagesView.setVisibility(View.VISIBLE);
}
} else {
if (pagesView.getVisibility() == View.VISIBLE) {
pagesView.setVisibility(View.INVISIBLE);
}
}
}
}
private int getPagesViewHeight() {
ViewGroup pagesView = this.pagesView;
return pagesView != null ? pagesView.getHeight() : 0;
}
private int getZoomButtonsHeight() {
View zoomButtonsView = this.zoomButtonsView;
return zoomButtonsView != null ? zoomButtonsView.getHeight() : 0;
@ -644,10 +737,24 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
}
}
public void updatePagesViewPos(@NonNull ContextMenuFragment fragment, int y, boolean animated) {
ViewGroup pagesView = this.pagesView;
if (pagesView != null) {
int pagesY = y - getPagesViewHeight() + fragment.getShadowHeight() +
(Build.VERSION.SDK_INT >= 21 ? AndroidUtils.getStatusBarHeight(pagesView.getContext()) : 0);
if (animated) {
fragment.animateView(pagesView, pagesY);
} else {
pagesView.setY(pagesY);
}
}
}
public void updateZoomButtonsPos(@NonNull ContextMenuFragment fragment, int y, boolean animated) {
View zoomButtonsView = this.zoomButtonsView;
if (zoomButtonsView != null) {
int zoomY = y - getZoomButtonsHeight() - fragment.getTopShadowMargin();
int zoomY = y - getZoomButtonsHeight() +
(Build.VERSION.SDK_INT >= 21 ? AndroidUtils.getStatusBarHeight(zoomButtonsView.getContext()) : 0);
if (animated) {
fragment.animateView(zoomButtonsView, zoomY);
} else {
@ -668,15 +775,15 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
mapActivity.getMapView().setMapPositionX(visible ? 0 : 1);
}
}
mapActivity.findViewById(R.id.bottom_controls_container).setVisibility(visibility);
mapActivity.refreshMap();
}
}
@Override
public void onContextMenuYPosChanged(@NonNull ContextMenuFragment fragment, int y, boolean animated) {
public void onContextMenuYPosChanged(@NonNull ContextMenuFragment fragment, int y, boolean needMapAdjust, boolean animated) {
if (fragment == getCurrentFragment()) {
updateToolbars(fragment, y, animated);
updatePagesViewPos(fragment, y, animated);
updateZoomButtonsPos(fragment, y, animated);
updateViewPager(fragment.getViewY());
}
@ -685,17 +792,18 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
@Override
public void onContextMenuStateChanged(@NonNull ContextMenuFragment fragment, int menuState) {
LockableViewPager viewPager = this.viewPager;
if (viewPager != null) {
int currentItem = viewPager.getCurrentItem();
RouteDetailsFragment current = getCurrentFragment();
if (viewPager != null && current != null && fragment == current) {
currentMenuState = menuState;
List<WeakReference<RouteDetailsFragment>> routeDetailsFragments = this.routeDetailsFragments;
for (WeakReference<RouteDetailsFragment> ref : routeDetailsFragments) {
RouteDetailsFragment f = ref.get();
if (f != null) {
boolean current = f.getRouteId() == currentItem;
if (!current && f.getCurrentMenuState() != menuState) {
if (f != current && f.getCurrentMenuState() != menuState) {
f.openMenuScreen(menuState, false);
}
if (current) {
if (f == current) {
updatePagesViewVisibility(menuState);
updateZoomButtonsVisibility(menuState);
updateViewPager(fragment.getViewY());
}
@ -748,12 +856,10 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
public class RoutesPagerAdapter extends FragmentPagerAdapter {
private int routesCount;
private int initialMenuState;
RoutesPagerAdapter(FragmentManager fm, int routesCount, int initialMenuState) {
RoutesPagerAdapter(FragmentManager fm, int routesCount) {
super(fm);
this.routesCount = routesCount;
this.initialMenuState = initialMenuState;
}
@Override
@ -764,7 +870,7 @@ public class ChooseRouteFragment extends BaseOsmAndFragment implements ContextMe
@Override
public Fragment getItem(int position) {
Bundle args = new Bundle();
args.putInt(ContextMenuFragment.MENU_STATE_KEY, initialMenuState);
args.putInt(ContextMenuFragment.MENU_STATE_KEY, currentMenuState);
args.putInt(RouteDetailsFragment.ROUTE_ID_KEY, position);
return Fragment.instantiate(ChooseRouteFragment.this.getContext(), RouteDetailsFragment.class.getName(), args);
}

View file

@ -1,11 +1,11 @@
package net.osmand.plus.routepreparationmenu;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
@ -60,9 +60,12 @@ import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.mapmarkers.MapMarkerSelectionFragment;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.AvoidPTTypesRoutingParameter;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.AvoidRoadsRoutingParameter;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.LocalRoutingParameter;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.LocalRoutingParameterGroup;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.MuteSoundRoutingParameter;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.RouteMenuAppModes;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.ShowAlongTheRouteItem;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
@ -78,6 +81,7 @@ import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.routing.TransportRoutingHelper;
import net.osmand.plus.search.QuickSearchHelper;
import net.osmand.plus.widgets.TextViewExProgress;
import net.osmand.router.GeneralRouter;
import net.osmand.router.GeneralRouter.RoutingParameter;
import net.osmand.router.TransportRoutePlanner.TransportRouteResult;
@ -105,6 +109,8 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
public static int directionInfo = -1;
public static boolean chooseRoutesVisible = false;
public static boolean waypointsVisible = false;
private boolean routeCalculationInProgress;
private boolean selectFromMapTouch;
@ -135,7 +141,6 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
@Nullable
private View mainView;
private int currentMenuState;
private boolean portraitMode;
private boolean swapButtonCollapsing;
@ -162,7 +167,6 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
}
public MapRouteInfoMenu() {
currentMenuState = getInitialMenuState();
onMarkerSelectListener = new OnMarkerSelectListener() {
@Override
public void onSelect(int index, PointType pointType) {
@ -209,7 +213,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
return animationsHandler;
}
private int getInitialMenuState() {
public int getInitialMenuState() {
return MenuState.FULL_SCREEN;
}
@ -321,7 +325,11 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
}
public int getCurrentMenuState() {
return currentMenuState;
WeakReference<MapRouteInfoMenuFragment> fragmentRef = findMenuFragment();
if (fragmentRef != null) {
return fragmentRef.get().getCurrentMenuState();
}
return 0;
}
public int getSupportedMenuStates() {
@ -340,30 +348,6 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
return MenuState.HEADER_ONLY | MenuState.HALF_SCREEN | MenuState.FULL_SCREEN;
}
public boolean slideUp() {
int v = currentMenuState;
for (int i = 0; i < 2; i++) {
v = v << 1;
if ((v & getSupportedMenuStates()) != 0) {
currentMenuState = v;
return true;
}
}
return false;
}
public boolean slideDown() {
int v = currentMenuState;
for (int i = 0; i < 2; i++) {
v = v >> 1;
if ((v & getSupportedMenuStates()) != 0) {
currentMenuState = v;
return true;
}
}
return false;
}
public void showHideMenu(int menuState) {
intermediateRequestsLatLon.clear();
if (isVisible()) {
@ -672,7 +656,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
View mainView = getMainView();
if (mainView != null) {
AppCompatImageView foldButtonView = (AppCompatImageView) mainView.findViewById(R.id.fold_button);
foldButtonView.setImageResource(currentMenuState == MenuState.HEADER_ONLY ?
foldButtonView.setImageResource(getCurrentMenuState() == MenuState.HEADER_ONLY ?
R.drawable.ic_action_arrow_up : R.drawable.ic_action_arrow_down);
foldButtonView.setOnClickListener(new OnClickListener() {
@Override
@ -691,7 +675,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
}
private void expandCollapse() {
if (currentMenuState == MenuState.HEADER_ONLY) {
if (getCurrentMenuState() == MenuState.HEADER_ONLY) {
openMenuFullScreen();
} else {
openMenuHeaderOnly();
@ -825,60 +809,10 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
}
final OsmandApplication app = mapActivity.getMyApplication();
RoutingHelper routingHelper = app.getRoutingHelper();
final boolean nightMode = app.getDaynightHelper().isNightModeForMapControls();
final OsmandSettings settings = app.getSettings();
final int colorActive = ContextCompat.getColor(app, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
final int colorDisabled = ContextCompat.getColor(app, R.color.description_font_and_bottom_sheet_icons);
final ApplicationMode applicationMode = routingHelper.getAppMode();
final RoutingOptionsHelper.RouteMenuAppModes mode = app.getRoutingOptionsHelper().modes.get(applicationMode);
int margin = AndroidUtils.dpToPx(app, 3);
View startButton = mainView.findViewById(R.id.start_button);
TextView startButtonText = (TextView) mainView.findViewById(R.id.start_button_descr);
boolean publicTransportMode = routingHelper.getAppMode() == ApplicationMode.PUBLIC_TRANSPORT;
int iconId = publicTransportMode ? R.drawable.ic_map : R.drawable.ic_action_start_navigation;
if (isRouteCalculated()) {
AndroidUtils.setBackground(app, startButton, nightMode, R.color.active_buttons_and_links_light, R.color.active_buttons_and_links_dark);
int color = nightMode ? R.color.main_font_dark : R.color.card_and_list_background_light;
startButtonText.setTextColor(ContextCompat.getColor(app, color));
Drawable icon = app.getUIUtilities().getIcon(iconId, color);
startButtonText.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
} else {
AndroidUtils.setBackground(app, startButton, nightMode, R.color.activity_background_light, R.color.activity_background_dark);
int color = R.color.description_font_and_bottom_sheet_icons;
startButtonText.setTextColor(ContextCompat.getColor(app, color));
Drawable icon = app.getUIUtilities().getIcon(iconId, color);
startButtonText.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
}
if (publicTransportMode) {
startButtonText.setText(R.string.shared_string_show_on_map);
} else if (routingHelper.isFollowingMode() || routingHelper.isPauseNavigation()) {
startButtonText.setText(R.string.shared_string_continue);
} else {
startButtonText.setText(R.string.shared_string_control_start);
}
startButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
clickRouteGo();
}
});
View cancelButton = mainView.findViewById(R.id.cancel_button);
TextView cancelButtonText = (TextView) mainView.findViewById(R.id.cancel_button_descr);
if (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated() || isTransportRouteCalculated()) {
cancelButtonText.setText(R.string.shared_string_dismiss);
} else {
cancelButtonText.setText(R.string.shared_string_cancel);
}
AndroidUtils.setBackground(app, cancelButton, nightMode, R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
cancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
clickRouteCancel();
}
});
final RouteMenuAppModes mode = app.getRoutingOptionsHelper().modes.get(applicationMode);
updateControlButtons(mapActivity, mainView);
LinearLayout optionsButton = (LinearLayout) mainView.findViewById(R.id.map_options_route_button);
TextView optionsTitle = (TextView) mainView.findViewById(R.id.map_options_route_button_title);
ImageView optionsIcon = (ImageView) mainView.findViewById(R.id.map_options_route_button_icon);
@ -905,271 +839,373 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
if (mode == null) {
return;
}
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
LinearLayout.LayoutParams newLp = new LinearLayout.LayoutParams(AndroidUtils.dpToPx(app, 100), ViewGroup.LayoutParams.MATCH_PARENT);
lp.setMargins(margin, 0, margin, 0);
createRoutingParametersButtons(mapActivity, mode, optionsContainer);
int rightPadding = AndroidUtils.dpToPx(app, 70);
if (mode.parameters.size() > 2) {
optionsTitle.setVisibility(View.GONE);
} else {
optionsTitle.setVisibility(View.VISIBLE);
}
for (final RoutingOptionsHelper.LocalRoutingParameter parameter : mode.parameters) {
if (parameter instanceof MuteSoundRoutingParameter) {
String text = null;
final boolean active = !app.getRoutingHelper().getVoiceRouter().isMute();
if (mode.parameters.size() <= 2) {
text = app.getString(active ? R.string.shared_string_on : R.string.shared_string_off);
}
View item = createToolbarOptionView(active, text, parameter.getActiveIconId(), parameter.getDisabledIconId(), new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = getApp();
if (app != null) {
app.getRoutingOptionsHelper().switchSound();
boolean active = !app.getRoutingHelper().getVoiceRouter().isMute();
String text = app.getString(active ? R.string.shared_string_on : R.string.shared_string_off);
Drawable itemDrawable = app.getUIUtilities().getIcon(active ? parameter.getActiveIconId() : parameter.getDisabledIconId(), nightMode ? R.color.route_info_control_icon_color_dark : R.color.route_info_control_icon_color_light);
Drawable activeItemDrawable = app.getUIUtilities().getIcon(active ? parameter.getActiveIconId() : parameter.getDisabledIconId(), nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
if (Build.VERSION.SDK_INT >= 21) {
itemDrawable = AndroidUtils.createPressedStateListDrawable(itemDrawable, activeItemDrawable);
}
((ImageView) v.findViewById(R.id.route_option_image_view)).setImageDrawable(active ? activeItemDrawable : itemDrawable);
((TextView) v.findViewById(R.id.route_option_title)).setText(text);
((TextView) v.findViewById(R.id.route_option_title)).setTextColor(active ? colorActive : colorDisabled);
}
}
});
if (item != null) {
optionsContainer.addView(item, lp);
}
} else if (parameter instanceof ShowAlongTheRouteItem) {
final Set<PoiUIFilter> poiFilters = app.getPoiFilters().getSelectedPoiFilters();
final boolean traffic = app.getSettings().SHOW_TRAFFIC_WARNINGS.getModeValue(applicationMode);
final boolean fav = app.getSettings().SHOW_NEARBY_FAVORITES.getModeValue(applicationMode);
if (!poiFilters.isEmpty()) {
LinearLayout item = createToolbarOptionView(false, null, -1, -1, null);
if (item != null) {
item.findViewById(R.id.route_option_container).setVisibility(View.GONE);
Iterator<PoiUIFilter> it = poiFilters.iterator();
while (it.hasNext()) {
final PoiUIFilter poiUIFilter = it.next();
final View container = createToolbarSubOptionView(true, poiUIFilter.getName(), R.drawable.ic_action_remove_dark, !it.hasNext(), new OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMyApplication().getPoiFilters().removeSelectedPoiFilter(poiUIFilter);
mapActivity.getMapView().refreshMap();
updateOptionsButtons();
}
}
});
if (container != null) {
item.addView(container, newLp);
}
}
optionsContainer.addView(item, lp);
}
}
if (traffic) {
LinearLayout item = createToolbarOptionView(false, null, -1, -1, null);
if (item != null) {
item.findViewById(R.id.route_option_container).setVisibility(View.GONE);
final View container = createToolbarSubOptionView(true, app.getString(R.string.way_alarms), R.drawable.ic_action_remove_dark, true, new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = getApp();
if (app != null) {
app.getWaypointHelper().enableWaypointType(WaypointHelper.ALARMS, false);
updateOptionsButtons();
}
}
});
if (container != null) {
AndroidUtils.setBackground(app, container, nightMode, R.drawable.btn_border_light, R.drawable.btn_border_dark);
item.addView(container, newLp);
optionsContainer.addView(item, lp);
}
}
}
if (fav) {
LinearLayout item = createToolbarOptionView(false, null, -1, -1, null);
if (item != null) {
item.findViewById(R.id.route_option_container).setVisibility(View.GONE);
final View container = createToolbarSubOptionView(true, app.getString(R.string.favourites), R.drawable.ic_action_remove_dark, true, new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = getApp();
if (app != null) {
app.getWaypointHelper().enableWaypointType(WaypointHelper.FAVORITES, false);
updateOptionsButtons();
}
}
});
if (container != null) {
AndroidUtils.setBackground(app, container, nightMode, R.drawable.btn_border_light, R.drawable.btn_border_dark);
item.addView(container, newLp);
optionsContainer.addView(item, lp);
}
}
}
} else if (parameter instanceof AvoidRoadsRoutingParameter || parameter instanceof RoutingOptionsHelper.AvoidPTTypesRoutingParameter) {
final LinearLayout item = createToolbarOptionView(false, null, -1, -1, null);
if (item != null) {
item.findViewById(R.id.route_option_container).setVisibility(View.GONE);
Map<LatLon, RouteDataObject> impassableRoads = new TreeMap<>();
if (parameter instanceof AvoidRoadsRoutingParameter) {
impassableRoads = app.getAvoidSpecificRoads().getImpassableRoads();
}
Iterator<RouteDataObject> it = impassableRoads.values().iterator();
while (it.hasNext()) {
final RouteDataObject routeDataObject = it.next();
final View container = createToolbarSubOptionView(false, app.getAvoidSpecificRoads().getText(routeDataObject), R.drawable.ic_action_remove_dark, !it.hasNext(), new OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
OsmandApplication app = mapActivity.getMyApplication();
RoutingHelper routingHelper = app.getRoutingHelper();
if (routeDataObject != null) {
app.getAvoidSpecificRoads().removeImpassableRoad(routeDataObject);
}
if (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated()) {
routingHelper.recalculateRouteDueToSettingsChange();
}
if (app.getAvoidSpecificRoads().getImpassableRoads().isEmpty()) {
mode.parameters.remove(parameter);
}
mapActivity.getMapView().refreshMap();
if (mode.parameters.size() > 2) {
item.removeView(v);
} else {
updateOptionsButtons();
}
}
}
});
if (container != null) {
item.addView(container, newLp);
}
}
List<RoutingParameter> avoidParameters = app.getRoutingOptionsHelper().getAvoidRoutingPrefsForAppMode(applicationMode);
final List<RoutingParameter> avoidedParameters = new ArrayList<>();
for (int i = 0; i < avoidParameters.size(); i++) {
RoutingParameter p = avoidParameters.get(i);
CommonPreference<Boolean> preference = settings.getCustomRoutingBooleanProperty(p.getId(), p.getDefaultBoolean());
if (preference != null && preference.getModeValue(app.getRoutingHelper().getAppMode())) {
avoidedParameters.add(p);
}
}
for (int i = 0; i < avoidedParameters.size(); i++) {
final RoutingParameter routingParameter = avoidedParameters.get(i);
final View container = createToolbarSubOptionView(false, SettingsBaseActivity.getRoutingStringPropertyName(app, routingParameter.getId(), routingParameter.getName()), R.drawable.ic_action_remove_dark, i == avoidedParameters.size() - 1, new OnClickListener() {
@Override
public void onClick(View v) {
CommonPreference<Boolean> preference = settings.getCustomRoutingBooleanProperty(routingParameter.getId(), routingParameter.getDefaultBoolean());
preference.setModeValue(app.getRoutingHelper().getAppMode(), false);
avoidedParameters.remove(routingParameter);
if (avoidedParameters.isEmpty()) {
mode.parameters.remove(parameter);
}
if (mode.parameters.size() > 2) {
item.removeView(v);
} else {
updateOptionsButtons();
}
}
});
if (container != null) {
item.addView(container, newLp);
}
}
if(avoidedParameters.size() > 0 || impassableRoads.size() > 0) {
optionsContainer.addView(item, lp);
}
}
} else if (parameter instanceof LocalRoutingParameterGroup) {
final LocalRoutingParameterGroup group = (LocalRoutingParameterGroup) parameter;
String text = null;
RoutingOptionsHelper.LocalRoutingParameter selected = group.getSelected(settings);
if (selected != null) {
text = group.getText(mapActivity);
}
View item = createToolbarOptionView(false, text, parameter.getActiveIconId(), parameter.getDisabledIconId(), new OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMyApplication().getRoutingOptionsHelper().showLocalRoutingParameterGroupDialog(group, mapActivity, new RoutingOptionsHelper.OnClickListener() {
@Override
public void onClick() {
updateOptionsButtons();
}
});
}
}
});
if (item != null) {
optionsContainer.addView(item, lp);
}
} else {
String text;
boolean active;
if (parameter.routingParameter != null) {
if (parameter.routingParameter.getId().equals(GeneralRouter.USE_SHORTEST_WAY)) {
// if short route settings - it should be inverse of fast_route_mode
active = !settings.FAST_ROUTE_MODE.getModeValue(routingHelper.getAppMode());
} else {
active = parameter.isSelected(settings);
}
text = parameter.getText(mapActivity);
View item = createToolbarOptionView(active, text, parameter.getActiveIconId(), parameter.getDisabledIconId(), new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = getApp();
if (parameter.routingParameter != null && app != null) {
boolean selected = !parameter.isSelected(settings);
app.getRoutingOptionsHelper().applyRoutingParameter(parameter, selected);
Drawable itemDrawable = app.getUIUtilities().getIcon(selected ? parameter.getActiveIconId() : parameter.getDisabledIconId(), nightMode ? R.color.route_info_control_icon_color_dark : R.color.route_info_control_icon_color_light);
Drawable activeItemDrawable = app.getUIUtilities().getIcon(selected ? parameter.getActiveIconId() : parameter.getDisabledIconId(), nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
if (Build.VERSION.SDK_INT >= 21) {
itemDrawable = AndroidUtils.createPressedStateListDrawable(itemDrawable, activeItemDrawable);
}
((ImageView) v.findViewById(R.id.route_option_image_view)).setImageDrawable(selected ? activeItemDrawable : itemDrawable);
((TextView) v.findViewById(R.id.route_option_title)).setTextColor(selected ? colorActive : colorDisabled);
}
}
});
if (item != null) {
LinearLayout.LayoutParams newLp2 = new LinearLayout.LayoutParams(AndroidUtils.dpToPx(app, 100), ViewGroup.LayoutParams.MATCH_PARENT);
newLp2.setMargins(margin, 0, margin, 0);
optionsContainer.addView(item, newLp2);
}
}
}
}
int rightPadding = AndroidUtils.dpToPx(app, 70);
if (optionsTitle.getVisibility() == View.VISIBLE) {
rightPadding += AndroidUtils.getTextWidth(app.getResources().getDimensionPixelSize(R.dimen.text_button_text_size), app.getString(R.string.shared_string_options));
}
optionsContainer.setPadding(optionsContainer.getPaddingLeft(), optionsContainer.getPaddingTop(), rightPadding, optionsContainer.getPaddingBottom());
}
private void updateControlButtons(MapActivity mapActivity, View mainView) {
if (mapActivity == null || mainView == null) {
return;
}
final OsmandApplication app = mapActivity.getMyApplication();
final RoutingHelper helper = app.getRoutingHelper();
View startButton = mainView.findViewById(R.id.start_button);
TextViewExProgress startButtonText = (TextViewExProgress) mainView.findViewById(R.id.start_button_descr);
boolean publicTransportMode = helper.getAppMode() == ApplicationMode.PUBLIC_TRANSPORT;
int iconId = publicTransportMode ? R.drawable.ic_map : R.drawable.ic_action_start_navigation;
int color;
if (isRouteCalculated()) {
AndroidUtils.setBackground(app, startButton, nightMode, R.color.active_buttons_and_links_light, R.color.active_buttons_and_links_dark);
color = nightMode ? R.color.main_font_dark : R.color.card_and_list_background_light;
} else {
AndroidUtils.setBackground(app, startButton, nightMode, R.color.activity_background_light, R.color.activity_background_dark);
color = R.color.description_font_and_bottom_sheet_icons;
}
startButtonText.color2 = ContextCompat.getColor(app, color);
startButtonText.setCompoundDrawablesWithIntrinsicBounds(app.getUIUtilities().getIcon(iconId, color), null, null, null);
if (publicTransportMode) {
startButtonText.setText(R.string.shared_string_show_on_map);
} else if (helper.isFollowingMode() || helper.isPauseNavigation()) {
startButtonText.setText(R.string.shared_string_continue);
} else {
startButtonText.setText(R.string.shared_string_control_start);
}
startButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
clickRouteGo();
}
});
View cancelButton = mainView.findViewById(R.id.cancel_button);
TextView cancelButtonText = (TextView) mainView.findViewById(R.id.cancel_button_descr);
if (helper.isRouteCalculated() || helper.isRouteBeingCalculated() || isTransportRouteCalculated()) {
cancelButtonText.setText(R.string.shared_string_dismiss);
} else {
cancelButtonText.setText(R.string.shared_string_cancel);
}
AndroidUtils.setBackground(app, cancelButton, nightMode, R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
cancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
clickRouteCancel();
}
});
}
private void createRoutingParametersButtons(MapActivity mapActivity, final RouteMenuAppModes mode, LinearLayout optionsContainer) {
if (mapActivity == null || optionsContainer == null) {
return;
}
for (final LocalRoutingParameter parameter : mode.parameters) {
if (parameter instanceof MuteSoundRoutingParameter) {
createMuteSoundRoutingParameterButton(mapActivity, (MuteSoundRoutingParameter) parameter, mode, optionsContainer);
} else if (parameter instanceof ShowAlongTheRouteItem) {
createShowAlongTheRouteItems(mapActivity, optionsContainer);
} else if (parameter instanceof AvoidRoadsRoutingParameter || parameter instanceof AvoidPTTypesRoutingParameter) {
createAvoidRoadsRoutingParameterButton(mapActivity, parameter, mode, optionsContainer);
} else if (parameter instanceof LocalRoutingParameterGroup) {
createLocalRoutingParameterGroupButton(mapActivity, parameter, optionsContainer);
} else {
createSimpleRoutingParameterButton(mapActivity, parameter, optionsContainer);
}
}
}
private void createMuteSoundRoutingParameterButton(MapActivity mapActivity, final MuteSoundRoutingParameter parameter, final RouteMenuAppModes mode, LinearLayout optionsContainer) {
final int colorActive = ContextCompat.getColor(mapActivity, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
final int colorDisabled = ContextCompat.getColor(mapActivity, R.color.description_font_and_bottom_sheet_icons);
String text = null;
final boolean active = !mapActivity.getRoutingHelper().getVoiceRouter().isMute();
if (mode.parameters.size() <= 2) {
text = mapActivity.getString(active ? R.string.shared_string_on : R.string.shared_string_off);
}
View item = createToolbarOptionView(active, text, parameter.getActiveIconId(), parameter.getDisabledIconId(), new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = getApp();
if (app != null) {
app.getRoutingOptionsHelper().switchSound();
boolean active = !app.getRoutingHelper().getVoiceRouter().isMute();
String text = app.getString(active ? R.string.shared_string_on : R.string.shared_string_off);
Drawable itemDrawable = app.getUIUtilities().getIcon(active ? parameter.getActiveIconId() : parameter.getDisabledIconId(), nightMode ? R.color.route_info_control_icon_color_dark : R.color.route_info_control_icon_color_light);
Drawable activeItemDrawable = app.getUIUtilities().getIcon(active ? parameter.getActiveIconId() : parameter.getDisabledIconId(), nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
if (Build.VERSION.SDK_INT >= 21) {
itemDrawable = AndroidUtils.createPressedStateListDrawable(itemDrawable, activeItemDrawable);
}
((ImageView) v.findViewById(R.id.route_option_image_view)).setImageDrawable(active ? activeItemDrawable : itemDrawable);
((TextView) v.findViewById(R.id.route_option_title)).setText(text);
((TextView) v.findViewById(R.id.route_option_title)).setTextColor(active ? colorActive : colorDisabled);
}
}
});
if (item != null) {
optionsContainer.addView(item, getContainerButtonLayoutParams(mapActivity, true));
}
}
private void createShowAlongTheRouteItems(MapActivity mapActivity, LinearLayout optionsContainer) {
OsmandApplication app = mapActivity.getMyApplication();
final ApplicationMode applicationMode = app.getRoutingHelper().getAppMode();
final Set<PoiUIFilter> poiFilters = app.getPoiFilters().getSelectedPoiFilters();
final boolean traffic = app.getSettings().SHOW_TRAFFIC_WARNINGS.getModeValue(applicationMode);
final boolean fav = app.getSettings().SHOW_NEARBY_FAVORITES.getModeValue(applicationMode);
if (!poiFilters.isEmpty()) {
createPoiFiltersItems(mapActivity, poiFilters, optionsContainer);
}
if (traffic) {
createWaypointItem(mapActivity, optionsContainer, WaypointHelper.ALARMS);
}
if (fav) {
createWaypointItem(mapActivity, optionsContainer, WaypointHelper.FAVORITES);
}
}
private void createPoiFiltersItems(MapActivity mapActivity, Set<PoiUIFilter> poiFilters, LinearLayout optionsContainer) {
LinearLayout item = createToolbarOptionView(false, null, -1, -1, null);
if (item != null) {
item.findViewById(R.id.route_option_container).setVisibility(View.GONE);
Iterator<PoiUIFilter> it = poiFilters.iterator();
while (it.hasNext()) {
final PoiUIFilter poiUIFilter = it.next();
final View container = createToolbarSubOptionView(true, poiUIFilter.getName(), R.drawable.ic_action_remove_dark, !it.hasNext(), new OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMyApplication().getPoiFilters().removeSelectedPoiFilter(poiUIFilter);
mapActivity.getMapView().refreshMap();
updateOptionsButtons();
}
}
});
if (container != null) {
item.addView(container, getContainerButtonLayoutParams(mapActivity, false));
}
}
optionsContainer.addView(item, getContainerButtonLayoutParams(mapActivity, true));
}
}
private void createWaypointItem(MapActivity mapActivity, LinearLayout optionsContainer, final int waypointType) {
LinearLayout item = createToolbarOptionView(false, null, -1, -1, null);
if (item != null) {
item.findViewById(R.id.route_option_container).setVisibility(View.GONE);
String title = "";
if (waypointType == WaypointHelper.ALARMS) {
title = mapActivity.getString(R.string.way_alarms);
} else if (waypointType == WaypointHelper.FAVORITES) {
title = mapActivity.getString(R.string.favourites);
}
final View container = createToolbarSubOptionView(true, title, R.drawable.ic_action_remove_dark, true, new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = getApp();
if (app != null) {
app.getWaypointHelper().enableWaypointType(waypointType, false);
updateOptionsButtons();
}
}
});
if (container != null) {
AndroidUtils.setBackground(app, container, nightMode, R.drawable.btn_border_light, R.drawable.btn_border_dark);
item.addView(container, getContainerButtonLayoutParams(mapActivity, false));
optionsContainer.addView(item, getContainerButtonLayoutParams(mapActivity, true));
}
}
}
private void createAvoidRoadsRoutingParameterButton(MapActivity mapActivity, final LocalRoutingParameter parameter, final RouteMenuAppModes mode, LinearLayout optionsContainer) {
OsmandApplication app = mapActivity.getMyApplication();
final LinearLayout item = createToolbarOptionView(false, null, -1, -1, null);
if (item != null) {
item.findViewById(R.id.route_option_container).setVisibility(View.GONE);
Map<LatLon, RouteDataObject> impassableRoads = new TreeMap<>();
if (parameter instanceof AvoidRoadsRoutingParameter) {
impassableRoads = app.getAvoidSpecificRoads().getImpassableRoads();
}
final List<RoutingParameter> avoidedParameters = getAvoidedParameters(app);
createImpassableRoadsItems(mapActivity, impassableRoads, parameter, mode, item);
createAvoidParametersItems(mapActivity, avoidedParameters, parameter, mode, item);
if (avoidedParameters.size() > 0 || impassableRoads.size() > 0) {
optionsContainer.addView(item, getContainerButtonLayoutParams(mapActivity, true));
}
}
}
private List<RoutingParameter> getAvoidedParameters(OsmandApplication app) {
final ApplicationMode applicationMode = app.getRoutingHelper().getAppMode();
List<RoutingParameter> avoidParameters = app.getRoutingOptionsHelper().getAvoidRoutingPrefsForAppMode(applicationMode);
final List<RoutingParameter> avoidedParameters = new ArrayList<>();
for (int i = 0; i < avoidParameters.size(); i++) {
RoutingParameter p = avoidParameters.get(i);
CommonPreference<Boolean> preference = app.getSettings().getCustomRoutingBooleanProperty(p.getId(), p.getDefaultBoolean());
if (preference != null && preference.getModeValue(app.getRoutingHelper().getAppMode())) {
avoidedParameters.add(p);
}
}
return avoidedParameters;
}
private void createImpassableRoadsItems(MapActivity mapActivity, Map<LatLon, RouteDataObject> impassableRoads, final LocalRoutingParameter parameter, final RouteMenuAppModes mode, final LinearLayout item) {
OsmandApplication app = mapActivity.getMyApplication();
Iterator<RouteDataObject> it = impassableRoads.values().iterator();
while (it.hasNext()) {
final RouteDataObject routeDataObject = it.next();
final View container = createToolbarSubOptionView(false, app.getAvoidSpecificRoads().getText(routeDataObject), R.drawable.ic_action_remove_dark, !it.hasNext(), new OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
OsmandApplication app = mapActivity.getMyApplication();
RoutingHelper routingHelper = app.getRoutingHelper();
if (routeDataObject != null) {
app.getAvoidSpecificRoads().removeImpassableRoad(routeDataObject);
}
routingHelper.recalculateRouteDueToSettingsChange();
if (app.getAvoidSpecificRoads().getImpassableRoads().isEmpty() && getAvoidedParameters(app).isEmpty()) {
mode.parameters.remove(parameter);
}
mapActivity.getMapView().refreshMap();
if (mode.parameters.size() > 2) {
item.removeView(v);
} else {
updateOptionsButtons();
}
}
}
});
if (container != null) {
item.addView(container, getContainerButtonLayoutParams(mapActivity, false));
}
}
}
private void createAvoidParametersItems(MapActivity mapActivity, final List<RoutingParameter> avoidedParameters, final LocalRoutingParameter parameter, final RouteMenuAppModes mode, final LinearLayout item) {
final OsmandSettings settings = mapActivity.getMyApplication().getSettings();
for (int i = 0; i < avoidedParameters.size(); i++) {
final RoutingParameter routingParameter = avoidedParameters.get(i);
final View container = createToolbarSubOptionView(false, SettingsBaseActivity.getRoutingStringPropertyName(app, routingParameter.getId(), routingParameter.getName()), R.drawable.ic_action_remove_dark, i == avoidedParameters.size() - 1, new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = getApp();
if (app == null) {
return;
}
CommonPreference<Boolean> preference = settings.getCustomRoutingBooleanProperty(routingParameter.getId(), routingParameter.getDefaultBoolean());
preference.setModeValue(app.getRoutingHelper().getAppMode(), false);
avoidedParameters.remove(routingParameter);
app.getRoutingHelper().recalculateRouteDueToSettingsChange();
if (app.getAvoidSpecificRoads().getImpassableRoads().isEmpty() && avoidedParameters.isEmpty()) {
mode.parameters.remove(parameter);
}
if (mode.parameters.size() > 2) {
item.removeView(v);
} else {
updateOptionsButtons();
}
}
});
if (container != null) {
item.addView(container, getContainerButtonLayoutParams(mapActivity, false));
}
}
}
private void createLocalRoutingParameterGroupButton(MapActivity mapActivity, final LocalRoutingParameter parameter, LinearLayout optionsContainer) {
final OsmandSettings settings = mapActivity.getMyApplication().getSettings();
final LocalRoutingParameterGroup group = (LocalRoutingParameterGroup) parameter;
String text = null;
LocalRoutingParameter selected = group.getSelected(settings);
if (selected != null) {
text = group.getText(mapActivity);
}
View item = createToolbarOptionView(false, text, parameter.getActiveIconId(), parameter.getDisabledIconId(), new OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMyApplication().getRoutingOptionsHelper().showLocalRoutingParameterGroupDialog(group, mapActivity, new RoutingOptionsHelper.OnClickListener() {
@Override
public void onClick() {
updateOptionsButtons();
}
});
}
}
});
if (item != null) {
optionsContainer.addView(item, getContainerButtonLayoutParams(mapActivity, true));
}
}
private void createSimpleRoutingParameterButton(MapActivity mapActivity, final LocalRoutingParameter parameter, LinearLayout optionsContainer) {
OsmandApplication app = mapActivity.getMyApplication();
RoutingHelper routingHelper = app.getRoutingHelper();
final int colorActive = ContextCompat.getColor(app, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
final int colorDisabled = ContextCompat.getColor(app, R.color.description_font_and_bottom_sheet_icons);
int margin = AndroidUtils.dpToPx(app, 3);
final OsmandSettings settings = app.getSettings();
String text;
boolean active;
if (parameter.routingParameter != null) {
if (parameter.routingParameter.getId().equals(GeneralRouter.USE_SHORTEST_WAY)) {
// if short route settings - it should be inverse of fast_route_mode
active = !settings.FAST_ROUTE_MODE.getModeValue(routingHelper.getAppMode());
} else {
active = parameter.isSelected(settings);
}
text = parameter.getText(mapActivity);
View item = createToolbarOptionView(active, text, parameter.getActiveIconId(), parameter.getDisabledIconId(), new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = getApp();
if (parameter.routingParameter != null && app != null) {
boolean selected = !parameter.isSelected(settings);
app.getRoutingOptionsHelper().applyRoutingParameter(parameter, selected);
Drawable itemDrawable = app.getUIUtilities().getIcon(selected ? parameter.getActiveIconId() : parameter.getDisabledIconId(), nightMode ? R.color.route_info_control_icon_color_dark : R.color.route_info_control_icon_color_light);
Drawable activeItemDrawable = app.getUIUtilities().getIcon(selected ? parameter.getActiveIconId() : parameter.getDisabledIconId(), nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
if (Build.VERSION.SDK_INT >= 21) {
itemDrawable = AndroidUtils.createPressedStateListDrawable(itemDrawable, activeItemDrawable);
}
((ImageView) v.findViewById(R.id.route_option_image_view)).setImageDrawable(selected ? activeItemDrawable : itemDrawable);
((TextView) v.findViewById(R.id.route_option_title)).setTextColor(selected ? colorActive : colorDisabled);
}
}
});
if (item != null) {
LinearLayout.LayoutParams layoutParams = getContainerButtonLayoutParams(mapActivity, false);
layoutParams.setMargins(margin, 0, margin, 0);
optionsContainer.addView(item, layoutParams);
}
}
}
private LinearLayout.LayoutParams getContainerButtonLayoutParams(Context context, boolean containerParams) {
if (containerParams) {
int margin = AndroidUtils.dpToPx(context, 3);
LinearLayout.LayoutParams containerBtnLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
containerBtnLp.setMargins(margin, 0, margin, 0);
return containerBtnLp;
} else {
return new LinearLayout.LayoutParams(AndroidUtils.dpToPx(context, 100), ViewGroup.LayoutParams.MATCH_PARENT);
}
}
@Nullable
private LinearLayout createToolbarOptionView(boolean active, String title, @DrawableRes int activeIconId,
@DrawableRes int disabledIconId, OnClickListener listener) {
@DrawableRes int disabledIconId, OnClickListener listener) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return null;
@ -1221,7 +1257,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
@Nullable
private View createToolbarSubOptionView(boolean hideTextLine, String title, @DrawableRes int iconId,
boolean lastItem, OnClickListener listener) {
boolean lastItem, OnClickListener listener) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return null;
@ -1248,6 +1284,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
container.findViewById(R.id.title_divider).setVisibility(View.GONE);
}
routeOptionTV.setText(title);
routeOptionTV.setTextColor(ContextCompat.getColor(app, R.color.description_font_and_bottom_sheet_icons));
routeOptionImageView.setImageDrawable(app.getUIUtilities().getIcon(iconId, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light));
container.setOnClickListener(listener);
@ -1315,7 +1352,8 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
public void onClick(View v) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null && mapActivity.getMyApplication().getTargetPointsHelper().checkPointToNavigateShort()) {
WaypointsFragment.showInstance(mapActivity);
hide();
WaypointsFragment.showInstance(mapActivity.getSupportFragmentManager(), getCurrentMenuState());
}
}
});
@ -1325,10 +1363,10 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
LinearLayout viaButtonContainer = (LinearLayout) mainView.findViewById(R.id.via_button_container);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, viaButton, nightMode, R.drawable.btn_border_rounded_light, R.drawable.btn_border_rounded_dark);
AndroidUtils.setBackground(app, viaButton, nightMode, R.drawable.btn_rounded_light, R.drawable.btn_rounded_dark);
AndroidUtils.setBackground(app, viaButtonContainer, nightMode, R.drawable.ripple_rounded_light, R.drawable.ripple_rounded_dark);
} else {
AndroidUtils.setBackground(app, viaButtonContainer, nightMode, R.drawable.btn_border_trans_rounded_light, R.drawable.btn_border_trans_rounded_dark);
AndroidUtils.setBackground(app, viaButtonContainer, nightMode, R.drawable.btn_trans_rounded_light, R.drawable.btn_trans_rounded_dark);
}
ImageView viaButtonImageView = (ImageView) mainView.findViewById(R.id.via_button_image_view);
@ -1369,7 +1407,10 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
toLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
openAddPointDialog(PointType.TARGET);
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
AddPointBottomSheetDialog.showInstance(mapActivity, PointType.TARGET);
}
}
});
@ -1382,10 +1423,10 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
final LinearLayout toButtonContainer = (LinearLayout) mainView.findViewById(R.id.to_button_container);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, toButton, nightMode, R.drawable.btn_border_rounded_light, R.drawable.btn_border_rounded_dark);
AndroidUtils.setBackground(app, toButton, nightMode, R.drawable.btn_rounded_light, R.drawable.btn_rounded_dark);
AndroidUtils.setBackground(app, toButtonContainer, nightMode, R.drawable.ripple_rounded_light, R.drawable.ripple_rounded_dark);
} else {
AndroidUtils.setBackground(app, toButtonContainer, nightMode, R.drawable.btn_border_trans_rounded_light, R.drawable.btn_border_trans_rounded_dark);
AndroidUtils.setBackground(app, toButtonContainer, nightMode, R.drawable.btn_trans_rounded_light, R.drawable.btn_trans_rounded_dark);
}
ImageView toButtonImageView = (ImageView) mainView.findViewById(R.id.to_button_image_view);
@ -1400,9 +1441,9 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
toButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
OsmandApplication app = getApp();
if (app != null) {
openAddPointDialog(app.getTargetPointsHelper().getPointToNavigate() == null ? PointType.TARGET : PointType.INTERMEDIATE);
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
AddPointBottomSheetDialog.showInstance(mapActivity, mapActivity.getMyApplication().getTargetPointsHelper().getPointToNavigate() == null ? PointType.TARGET : PointType.INTERMEDIATE);
}
}
});
@ -1443,7 +1484,10 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
fromLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
openAddPointDialog(PointType.START);
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
AddPointBottomSheetDialog.showInstance(mapActivity, PointType.START);
}
}
});
@ -1451,10 +1495,10 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
final LinearLayout fromButtonContainer = (LinearLayout) mainView.findViewById(R.id.from_button_container);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, fromButton, nightMode, R.drawable.btn_border_rounded_light, R.drawable.btn_border_rounded_dark);
AndroidUtils.setBackground(app, fromButton, nightMode, R.drawable.btn_rounded_light, R.drawable.btn_rounded_dark);
AndroidUtils.setBackground(app, fromButtonContainer, nightMode, R.drawable.ripple_rounded_light, R.drawable.ripple_rounded_dark);
} else {
AndroidUtils.setBackground(app, fromButtonContainer, nightMode, R.drawable.btn_border_trans_rounded_light, R.drawable.btn_border_trans_rounded_dark);
AndroidUtils.setBackground(app, fromButtonContainer, nightMode, R.drawable.btn_trans_rounded_light, R.drawable.btn_trans_rounded_dark);
}
ImageView swapDirectionView = (ImageView) mainView.findViewById(R.id.from_button_image_view);
@ -1576,7 +1620,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
public void selectOnScreen(PointType pointType) {
selectFromMapTouch = true;
selectFromMapPointType = pointType;
selectFromMapMenuState = currentMenuState;
selectFromMapMenuState = getCurrentMenuState();
hide();
}
@ -1659,17 +1703,6 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
}
}
private void openAddPointDialog(PointType pointType) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
Bundle args = new Bundle();
args.putString(AddPointBottomSheetDialog.POINT_TYPE_KEY, pointType.name());
AddPointBottomSheetDialog fragment = new AddPointBottomSheetDialog();
fragment.setArguments(args);
fragment.show(mapActivity.getSupportFragmentManager(), AddPointBottomSheetDialog.TAG);
}
}
private boolean isLight() {
return !nightMode;
}
@ -1713,10 +1746,12 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
WeakReference<MapRouteInfoMenuFragment> fragmentRef = routeInfoMenu.findMenuFragment();
if (fragmentRef != null) {
MapRouteInfoMenuFragment f = fragmentRef.get();
if (mapActivity.isLandscapeLayout()) {
tileBoxWidthPx = tb.getPixWidth() - f.getWidth();
} else {
tileBoxHeightPx = tb.getPixHeight() - f.getHeight();
if (f != null) {
if (!f.isPortrait()) {
tileBoxWidthPx = tb.getPixWidth() - f.getWidth();
} else {
tileBoxHeightPx = tb.getPixHeight() - f.getHeight();
}
}
}
mapActivity.getMapView().fitLocationToMap(latitude, longitude, mapActivity.getMapView().getZoom(),
@ -1880,6 +1915,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
if (mapActivity.getPointToNavigate() == null && !selectFromMapTouch) {
mapActivity.getMapActions().stopNavigationWithoutConfirm();
}
mapActivity.updateStatusBarColor();
}
if (onDismissListener != null) {
onDismissListener.onDismiss(null);
@ -1897,12 +1933,12 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
}
MapActivity mapActivity = getMapActivity();
if (!isVisible() && mapActivity != null) {
currentMenuState = menuState;
int initialMenuState = menuState;
switched = mapActivity.getMapLayers().getMapControlsLayer().switchToRoutePlanningLayout();
boolean refreshMap = !switched;
boolean portrait = AndroidUiHelper.isOrientationPortrait(mapActivity);
if (!portrait) {
currentMenuState = MenuState.FULL_SCREEN;
initialMenuState = MenuState.FULL_SCREEN;
mapActivity.getMapView().setMapPositionX(1);
refreshMap = true;
}
@ -1911,7 +1947,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
mapActivity.refreshMap();
}
MapRouteInfoMenuFragment.showInstance(mapActivity);
MapRouteInfoMenuFragment.showInstance(mapActivity, initialMenuState);
if (!AndroidUiHelper.isXLargeDevice(mapActivity)) {
AndroidUiHelper.updateVisibility(mapActivity.findViewById(R.id.map_right_widgets_panel), false);

View file

@ -1,10 +1,6 @@
package net.osmand.plus.routepreparationmenu;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
@ -13,7 +9,6 @@ import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.view.ContextThemeWrapper;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
@ -26,8 +21,6 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@ -69,6 +62,7 @@ import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener;
import net.osmand.plus.routepreparationmenu.cards.PublicTransportCard;
import net.osmand.plus.routepreparationmenu.cards.PublicTransportCard.PublicTransportCardListener;
import net.osmand.plus.routepreparationmenu.cards.RouteDirectionsCard;
import net.osmand.plus.routepreparationmenu.cards.RouteInfoCard;
import net.osmand.plus.routepreparationmenu.cards.RouteStatisticCard;
import net.osmand.plus.routing.RouteCalculationResult;
@ -76,7 +70,6 @@ import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.routing.TransportRoutingHelper;
import net.osmand.plus.transport.TransportStopRoute;
import net.osmand.plus.views.TurnPathHelper;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.plus.widgets.style.CustomTypefaceSpan;
import net.osmand.render.RenderingRuleSearchRequest;
@ -104,7 +97,9 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
private int toolbarHeightPx;
private GPXFile gpx;
@Nullable
private OrderedLineDataSet slopeDataSet;
@Nullable
private OrderedLineDataSet elevationDataSet;
private GpxDisplayItem gpxItem;
private List<BaseCard> menuCards = new ArrayList<>();
@ -116,21 +111,16 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
return R.layout.route_info_layout;
}
@Override
public int getMainViewId() {
return R.id.main_view;
}
@Override
public int getBottomScrollViewId() {
return R.id.route_menu_bottom_scroll;
}
@Override
public int getHeaderViewHeight() {
return !menuCards.isEmpty() ? menuCards.get(0).getViewHeight() : 0;
}
@Override
public boolean isHeaderViewDetached() {
return false;
}
@Override
public int getToolbarHeight() {
return toolbarHeightPx;
@ -159,13 +149,26 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
if (view != null) {
if (isPortrait()) {
view.findViewById(getBottomScrollViewId()).setBackgroundDrawable(null);
LinearLayout cardsContainer = getCardsContainer();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) cardsContainer.getLayoutParams();
layoutParams.setMargins(pageMarginPx, 0, pageMarginPx, 0);
cardsContainer.setLayoutParams(layoutParams);
}
updateCards(view);
updateCards();
runLayoutListener();
}
return view;
}
@Override
public int getShadowHeight() {
int res = super.getShadowHeight();
if (getCurrentMenuState() == MenuState.HEADER_ONLY) {
res += pageMarginPx;
}
return res;
}
@Nullable
public PublicTransportCard getTransportCard() {
return transportCard;
@ -176,59 +179,25 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
super.changeMenuState(currentY, slidingUp, slidingDown, animated);
View mainView = getMainView();
if (mainView != null && isPortrait()) {
final LinearLayout cardsContainer = (LinearLayout) mainView.findViewById(R.id.route_menu_cards_container);
final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) cardsContainer.getLayoutParams();
final int currentMenuState = getCurrentMenuState();
if (animated) {
final int marginStart = layoutParams.leftMargin;
final int marginEnd = currentMenuState == MenuState.HEADER_ONLY ? pageMarginPx : 0;
if (marginStart != marginEnd) {
Animation a = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int margin = marginStart + (int) ((marginEnd - marginStart) * interpolatedTime);
layoutParams.setMargins(margin, 0, margin, 0);
cardsContainer.setLayoutParams(layoutParams);
}
};
a.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
updateCardsLayout();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
a.setDuration(ANIMATION_DURATION);
cardsContainer.startAnimation(a);
}
} else {
updateCardsLayout();
}
updateCardsLayout();
}
}
private void updateCardsLayout() {
View mainView = getMainView();
if (mainView != null) {
LinearLayout cardsContainer = (LinearLayout) mainView.findViewById(R.id.route_menu_cards_container);
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) cardsContainer.getLayoutParams();
LinearLayout cardsContainer = getCardsContainer();
View topShadow = getTopShadow();
FrameLayout bottomContainer = getBottomContainer();
if (getCurrentMenuState() == MenuState.HEADER_ONLY) {
layoutParams.setMargins(pageMarginPx, 0, pageMarginPx, 0);
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);
mainView.setBackgroundDrawable(null);
} else {
layoutParams.setMargins(0, 0, 0, 0);
cardsContainer.setBackgroundDrawable(null);
AndroidUtils.setBackground(mainView.getContext(), mainView, isNightMode(), R.drawable.bg_map_route_menu_light, R.drawable.bg_map_route_menu_dark);
topShadow.setVisibility(View.VISIBLE);
AndroidUtils.setBackground(mainView.getContext(), bottomContainer, isNightMode(), R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
AndroidUtils.setBackground(mainView.getContext(), cardsContainer, isNightMode(), R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
}
cardsContainer.setLayoutParams(layoutParams);
}
}
@ -237,36 +206,28 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
super.setViewY(y, animated, adjustMapPos);
View mainView = getMainView();
if (mainView != null && isPortrait()) {
int headerOnlyY = getMenuStatePosY(MenuState.HEADER_ONLY);
LinearLayout cardsContainer = getCardsContainer();
View topShadow = getTopShadow();
FrameLayout bottomContainer = getBottomContainer();
int halfScreenY = getMenuStatePosY(MenuState.HALF_SCREEN);
float margin = 0;
if (y > headerOnlyY) {
margin = PAGE_MARGIN;
} else if (y > halfScreenY) {
margin = PAGE_MARGIN * (1f - (float)(headerOnlyY - y) / (headerOnlyY - halfScreenY));
}
int marginPx = dpToPx(margin);
LinearLayout cardsContainer = (LinearLayout) mainView.findViewById(R.id.route_menu_cards_container);
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) cardsContainer.getLayoutParams();
if (layoutParams.leftMargin != marginPx) {
layoutParams.setMargins(marginPx, 0, marginPx, 0);
}
if (y > halfScreenY) {
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);
mainView.setBackgroundDrawable(null);
} else {
cardsContainer.setBackgroundDrawable(null);
AndroidUtils.setBackground(mainView.getContext(),mainView, isNightMode(), R.drawable.bg_map_route_menu_light, R.drawable.bg_map_route_menu_dark);
topShadow.setVisibility(View.VISIBLE);
AndroidUtils.setBackground(mainView.getContext(), bottomContainer, isNightMode(), R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
AndroidUtils.setBackground(mainView.getContext(), cardsContainer, isNightMode(), R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
}
}
}
private void updateCards(@NonNull View view) {
private void updateCards() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
OsmandApplication app = mapActivity.getMyApplication();
RoutingHelper routingHelper = app.getRoutingHelper();
LinearLayout cardsContainer = (LinearLayout) view.findViewById(R.id.route_menu_cards_container);
LinearLayout cardsContainer = getCardsContainer();
cardsContainer.removeAllViews();
if (routeId != -1) {
List<TransportRouteResult> routes = routingHelper.getTransportRoutingHelper().getRoutes();
@ -291,75 +252,40 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
transportCard = null;
makeGpx();
createRouteStatisticCards(cardsContainer);
createRouteDirections(cardsContainer);
createRouteDirectionsCard(cardsContainer);
}
}
}
}
private void createRouteDirections(LinearLayout cardsContainer) {
OsmandApplication app = requireMyApplication();
TextViewEx routeDirectionsTitle = new TextViewEx(app);
routeDirectionsTitle.setTextColor(getMainFontColor());
routeDirectionsTitle.setTextSize(15);
routeDirectionsTitle.setGravity(Gravity.CENTER_VERTICAL);
routeDirectionsTitle.setPadding(dpToPx(16), dpToPx(16), dpToPx(16), dpToPx(16));
routeDirectionsTitle.setText(R.string.step_by_step);
routeDirectionsTitle.setTypeface(FontCache.getRobotoMedium(app));
cardsContainer.addView(routeDirectionsTitle);
List<RouteDirectionInfo> routeDirections = app.getRoutingHelper().getRouteDirections();
for (int i = 0; i < routeDirections.size(); i++) {
RouteDirectionInfo routeDirectionInfo = routeDirections.get(i);
OnClickListener onClickListener = createRouteDirectionInfoViewClickListener(i, routeDirectionInfo);
View view = getRouteDirectionView(i, routeDirectionInfo, routeDirections, onClickListener);
cardsContainer.addView(view);
}
}
private OnClickListener createRouteDirectionInfoViewClickListener(final int directionInfoIndex, final RouteDirectionInfo routeDirectionInfo) {
return new OnClickListener() {
@Override
public void onClick(View view) {
OsmandApplication app = requireMyApplication();
Location loc = app.getRoutingHelper().getLocationFromRouteDirection(routeDirectionInfo);
if (loc != null) {
MapRouteInfoMenu.directionInfo = directionInfoIndex;
OsmandSettings settings = app.getSettings();
settings.setMapLocationToShow(loc.getLatitude(), loc.getLongitude(),
Math.max(13, settings.getLastKnownMapZoom()),
new PointDescription(PointDescription.POINT_TYPE_MARKER,
routeDirectionInfo.getDescriptionRoutePart() + " " + getTimeDescription(app, routeDirectionInfo)),
false, null);
MapActivity.launchMapActivityMoveToTop(getActivity());
dismiss();
}
}
};
}
private void createRouteStatisticCards(LinearLayout cardsContainer) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return;
}
OsmandApplication app = mapActivity.getMyApplication();
if (gpx.hasAltitude) {
RouteStatisticCard statisticCard = new RouteStatisticCard(mapActivity, gpx, new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
InterceptorLinearLayout mainView = getMainView();
if (mainView != null) {
mainView.requestDisallowInterceptTouchEvent(true);
}
return false;
RouteStatisticCard statisticCard = new RouteStatisticCard(mapActivity, gpx, new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
InterceptorLinearLayout mainView = getMainView();
if (mainView != null) {
mainView.requestDisallowInterceptTouchEvent(true);
}
});
menuCards.add(statisticCard);
cardsContainer.addView(statisticCard.build(mapActivity));
buildRowDivider(cardsContainer, false);
slopeDataSet = statisticCard.getSlopeDataSet();
elevationDataSet = statisticCard.getElevationDataSet();
return false;
}
}, new OnClickListener() {
@Override
public void onClick(View v) {
openDetails();
}
});
statisticCard.setTransparentBackground(true);
menuCards.add(statisticCard);
cardsContainer.addView(statisticCard.build(mapActivity));
buildRowDivider(cardsContainer, false);
slopeDataSet = statisticCard.getSlopeDataSet();
elevationDataSet = statisticCard.getElevationDataSet();
if (gpx.hasAltitude) {
List<RouteSegmentResult> route = app.getRoutingHelper().getRoute().getOriginalRoute();
if (route != null) {
RenderingRulesStorage currentRenderer = app.getRendererRegistry().getCurrentSelectedRenderer();
@ -390,9 +316,23 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
}
}
private void createRouteDirectionsCard(LinearLayout cardsContainer) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return;
}
RouteDirectionsCard directionsCard = new RouteDirectionsCard(mapActivity);
directionsCard.setTransparentBackground(true);
directionsCard.setListener(this);
menuCards.add(directionsCard);
cardsContainer.addView(directionsCard.build(mapActivity));
buildRowDivider(cardsContainer, false);
}
private void createRouteCard(LinearLayout cardsContainer, RouteInfoCard routeInfoCard) {
OsmandApplication app = requireMyApplication();
menuCards.add(routeInfoCard);
routeInfoCard.setListener(this);
cardsContainer.addView(routeInfoCard.build(app));
buildRowDivider(cardsContainer, false);
}
@ -403,7 +343,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
}
private void buildSegmentItem(View view, final TransportRouteResultSegment segment,
final TransportRouteResultSegment nextSegment, int[] startTime, double walkSpeed, double boardingTime) {
final TransportRouteResultSegment nextSegment, int[] startTime, double walkSpeed, double boardingTime) {
OsmandApplication app = requireMyApplication();
TransportRoute transportRoute = segment.route;
List<TransportStop> stops = segment.getTravelStops();
@ -883,8 +823,8 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageViewLayoutParams.setMargins(dpToPx(14), dpToPx(8), dpToPx(22), 0);
iconView.setPadding(dpToPx(2), dpToPx(2), dpToPx(2), dpToPx(2));
iconView.setBackgroundResource(R.drawable.border_round_solid_light);
iconView.setPadding(dpToPx(2), dpToPx(2), dpToPx(2), dpToPx(2));
baseItemView.addView(iconView);
}
@ -1003,8 +943,8 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageViewLayoutParams.setMargins(dpToPx(14), dpToPx(8), dpToPx(22), 0);
iconView.setPadding(dpToPx(2), dpToPx(2), dpToPx(2), dpToPx(2));
iconView.setBackgroundResource(R.drawable.border_round_solid_light);
iconView.setPadding(dpToPx(2), dpToPx(2), dpToPx(2), dpToPx(2));
baseItemView.addView(iconView);
}
@ -1046,10 +986,10 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
@Override
public void geocodingDone(String address) {
RouteDetailsFragment fragment = fragmentRef.get();
View view = getView();
if (!TextUtils.isEmpty(address) && fragment != null && !fragment.isPaused() && view != null) {
if (!TextUtils.isEmpty(address) && fragment != null && !fragment.isPaused()) {
fragment.destinationStreetStr = address;
fragment.updateCards(view);
fragment.updateCards();
doAfterMenuStateChange(0, 0);
}
}
}, null);
@ -1273,8 +1213,8 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageViewLayoutParams.setMargins(dpToPx(17), 0, dpToPx(25), 0);
iconView.setPadding(dpToPx(2), dpToPx(2), dpToPx(2), dpToPx(2));
iconView.setBackgroundResource(R.drawable.border_round_solid_light_small);
iconView.setPadding(dpToPx(2), dpToPx(2), dpToPx(2), dpToPx(2));
baseItemView.addView(iconView);
}
@ -1357,9 +1297,9 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
ll.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams llParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ll.setMinimumHeight(dpToPx(minHeight));
ll.setPadding(dpToPx(64), 0, dpToPx(16), 0);
ll.setLayoutParams(llParams);
ll.setBackgroundResource(AndroidUtils.resolveAttribute(context, android.R.attr.selectableItemBackground));
ll.setPadding(dpToPx(64f), 0, dpToPx(16f), 0);
ll.setOnLongClickListener(onLongClickListener);
return ll;
}
@ -1449,10 +1389,12 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
float distance = i * 5;
inclines.add(i, new Incline(0f, distance));
}
float lastDistance = slopeDataSet.getEntryForIndex(size - 1).getX();
for (int i = 1; i <= 10; i++) {
float distance = lastDistance * 1000f + i * 5f;
inclines.add(new Incline(0f, distance));
if (slopeDataSet != null) {
float lastDistance = slopeDataSet.getEntryForIndex(size - 1).getX();
for (int i = 1; i <= 10; i++) {
float distance = lastDistance * 1000f + i * 5f;
inclines.add(new Incline(0f, distance));
}
}
for (Incline incline : inclines) {
incline.computeBoundaries(minIncline, maxIncline);
@ -1474,8 +1416,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
}
void openDetails() {
if (gpxItem != null) {
OsmandApplication app = requireMyApplication();
if (gpxItem != null && elevationDataSet != null) {
LatLon location = null;
WptPt wpt = null;
gpxItem.chartTypes = new GPXDataSetType[]{GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE};
@ -1504,33 +1445,33 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
gpxItem.locationOnMap = gpxItem.locationStart;
}
final MapActivity activity = (MapActivity) getActivity();
if (activity != null) {
ChooseRouteFragment parent = (ChooseRouteFragment) getParentFragment();
if (parent != null) {
parent.analyseOnMap(location, gpxItem);
}
}
}
private void showDirectionsInfo(int directionInfoIndex) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return;
}
RoutingHelper helper = mapActivity.getRoutingHelper();
List<RouteDirectionInfo> routeDirections = helper.getRouteDirections();
if (routeDirections.size() > directionInfoIndex) {
RouteDirectionInfo routeDirectionInfo = routeDirections.get(directionInfoIndex);
Location loc = helper.getLocationFromRouteDirection(routeDirectionInfo);
if (loc != null) {
MapRouteInfoMenu.directionInfo = directionInfoIndex;
OsmandSettings settings = mapActivity.getMyApplication().getSettings();
settings.setMapLocationToShow(loc.getLatitude(), loc.getLongitude(),
Math.max(13, settings.getLastKnownMapZoom()),
new PointDescription(PointDescription.POINT_TYPE_MARKER,
routeDirectionInfo.getDescriptionRoutePart() + " " + getTimeDescription(mapActivity.getMyApplication(), routeDirectionInfo)),
false, null);
MapActivity.launchMapActivityMoveToTop(mapActivity);
dismiss();
final OsmandSettings settings = app.getSettings();
settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(),
settings.getLastKnownMapZoom(),
new PointDescription(PointDescription.POINT_TYPE_WPT, gpxItem.name),
false,
gpxItem);
final MapRouteInfoMenu mapRouteInfoMenu = activity.getMapRouteInfoMenu();
if (mapRouteInfoMenu.isVisible()) {
// We arrived here by the route info menu.
// First, we close it and then show the details.
mapRouteInfoMenu.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
mapRouteInfoMenu.setOnDismissListener(null);
MapActivity.launchMapActivityMoveToTop(activity);
}
});
mapRouteInfoMenu.hide();
} else {
// We arrived here by the dashboard.
MapActivity.launchMapActivityMoveToTop(activity);
}
}
}
}
@ -1552,6 +1493,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
@Override
public void onCardLayoutNeeded(@NonNull BaseCard card) {
runLayoutListener();
}
@Override
@ -1563,6 +1505,8 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
public void onCardButtonPressed(@NonNull BaseCard card, int buttonIndex) {
if (card instanceof PublicTransportCard && buttonIndex == 0) {
openMenuFullScreen();
} else if (card instanceof RouteDirectionsCard && buttonIndex >= 0) {
showDirectionsInfo(buttonIndex);
}
}
@ -1576,48 +1520,6 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT
}
}
public View getRouteDirectionView(int position, RouteDirectionInfo model, List<RouteDirectionInfo> directionsInfo, OnClickListener onClickListener) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return null;
}
OsmandApplication app = mapActivity.getMyApplication();
ContextThemeWrapper context = new ContextThemeWrapper(mapActivity, isNightMode() ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme);
View row = LayoutInflater.from(context).inflate(R.layout.route_info_list_item, null);
TextView label = (TextView) row.findViewById(R.id.description);
TextView distanceLabel = (TextView) row.findViewById(R.id.distance);
TextView timeLabel = (TextView) row.findViewById(R.id.time);
TextView cumulativeDistanceLabel = (TextView) row.findViewById(R.id.cumulative_distance);
TextView cumulativeTimeLabel = (TextView) row.findViewById(R.id.cumulative_time);
ImageView icon = (ImageView) row.findViewById(R.id.direction);
row.findViewById(R.id.divider).setVisibility(position == directionsInfo.size() - 1 ? View.INVISIBLE : View.VISIBLE);
TurnPathHelper.RouteDrawable drawable = new TurnPathHelper.RouteDrawable(getResources(), true);
drawable.setColorFilter(new PorterDuffColorFilter(getActiveColor(), PorterDuff.Mode.SRC_ATOP));
drawable.setRouteType(model.getTurnType());
icon.setImageDrawable(drawable);
label.setText(model.getDescriptionRoutePart());
if (model.distance > 0) {
distanceLabel.setText(OsmAndFormatter.getFormattedDistance(model.distance, app));
timeLabel.setText(getTimeDescription(app, model));
row.setContentDescription(label.getText() + " " + timeLabel.getText());
} else {
if (Algorithms.isEmpty(label.getText().toString())) {
label.setText(getString((position != directionsInfo.size() - 1) ? R.string.arrived_at_intermediate_point : R.string.arrived_at_destination));
}
distanceLabel.setText("");
timeLabel.setText("");
row.setContentDescription("");
}
CumulativeInfo cumulativeInfo = getRouteDirectionCumulativeInfo(position, directionsInfo);
cumulativeDistanceLabel.setText(OsmAndFormatter.getFormattedDistance(cumulativeInfo.distance, app));
cumulativeTimeLabel.setText(Algorithms.formatDuration(cumulativeInfo.time, app.accessibilityEnabled()));
row.setOnClickListener(onClickListener);
return row;
}
public static CumulativeInfo getRouteDirectionCumulativeInfo(int position, List<RouteDirectionInfo> routeDirections) {
CumulativeInfo cumulativeInfo = new CumulativeInfo();
if (position >= routeDirections.size()) {

View file

@ -284,16 +284,15 @@ public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment {
if (parameter != null) {
final BottomSheetItemWithCompoundButton[] item = new BottomSheetItemWithCompoundButton[1];
BottomSheetItemWithCompoundButton.Builder builder = new BottomSheetItemWithCompoundButton.Builder();
int iconId = -1;
if (parameter.routingParameter != null || parameter instanceof RoutingOptionsHelper.OtherLocalRoutingParameter) {
builder.setTitle(parameter.getText(mapActivity));
int iconId = parameter.isSelected(settings) ? parameter.getActiveIconId() : parameter.getDisabledIconId();
if (iconId != -1) {
builder.setIcon(getContentIcon(iconId));
}
iconId = parameter.isSelected(settings) ? parameter.getActiveIconId() : parameter.getDisabledIconId();
}
if (parameter instanceof LocalRoutingParameterGroup) {
final LocalRoutingParameterGroup group = (LocalRoutingParameterGroup) parameter;
LocalRoutingParameter selected = group.getSelected(settings);
iconId = selected != null ? parameter.getActiveIconId() : parameter.getDisabledIconId();
if (selected != null) {
builder.setTitle(group.getText(mapActivity));
builder.setDescription(selected.getText(mapActivity));
@ -338,6 +337,9 @@ public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment {
}
});
}
if (iconId != -1) {
builder.setIcon(getContentIcon(iconId));
}
item[0] = builder.create();
items.add(item[0]);
}

View file

@ -474,6 +474,13 @@ public class RoutingOptionsHelper {
}
private static void updateRoutingParameterIcons(LocalRoutingParameter rp) {
if (rp instanceof LocalRoutingParameterGroup) {
LocalRoutingParameterGroup group = (LocalRoutingParameterGroup) rp;
if (group.groupName.equals(DRIVING_STYLE)) {
rp.activeIconId = R.drawable.ic_action_bicycle_dark;
rp.disabledIconId = R.drawable.ic_action_bicycle_dark;
}
}
if (rp.routingParameter == null) {
return;
}

View file

@ -460,6 +460,17 @@ public class ShowAlongTheRouteBottomSheet extends MenuBottomSheetDialogFragment
}
}
private MapActivity getMapActivity() {
return (MapActivity) getActivity();
}
private void updateMenu() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMapRouteInfoMenu().updateMenu();
}
}
protected void selectDifferentRadius(final int type) {
int length = WaypointHelper.SEARCH_RADIUS_VALUES.length;
String[] names = new String[length];
@ -548,6 +559,7 @@ public class ShowAlongTheRouteBottomSheet extends MenuBottomSheetDialogFragment
ShowAlongTheRouteBottomSheet fragment = fragmentRef.get();
if (fragment != null && fragment.isAdded()) {
fragment.updateAdapter();
fragment.updateMenu();
}
}
}

View file

@ -1,6 +1,5 @@
package net.osmand.plus.routepreparationmenu;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
@ -59,17 +58,13 @@ import java.util.ArrayList;
import java.util.List;
import static net.osmand.plus.helpers.WaypointDialogHelper.showOnMap;
import static net.osmand.plus.routepreparationmenu.ChooseRouteFragment.ROUTE_INFO_STATE_KEY;
public class WaypointsFragment extends BaseOsmAndFragment implements ObservableScrollViewCallbacks,
DynamicListViewCallbacks, WaypointDialogHelper.WaypointDialogHelperCallback {
public static final String TAG = "WaypointsFragment";
private OsmandApplication app;
private MapActivity mapActivity;
private WaypointDialogHelper waypointDialogHelper;
private View view;
private View mainView;
private DynamicListView listView;
@ -88,26 +83,24 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
private boolean nightMode;
private boolean wasDrawerDisabled;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = getMyApplication();
mapActivity = (MapActivity) getActivity();
}
private int routeInfoMenuState = -1;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
MapActivity mapActivity = (MapActivity) requireActivity();
portrait = AndroidUiHelper.isOrientationPortrait(mapActivity);
nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls();
waypointDialogHelper = mapActivity.getDashboard().getWaypointDialogHelper();
view = inflater.inflate(R.layout.route_waypoints_fragment, parent, false);
if (view == null) {
return null;
}
AndroidUtils.addStatusBarPadding21v(app, view);
AndroidUtils.addStatusBarPadding21v(mapActivity, view);
Bundle args = getArguments();
if (args != null) {
routeInfoMenuState = args.getInt(ROUTE_INFO_STATE_KEY, -1);
}
mainView = view.findViewById(R.id.main_view);
listView = (DynamicListView) view.findViewById(R.id.dash_list_view);
@ -147,9 +140,12 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
if (hasActivePoints) {
TargetOptionsBottomSheetDialogFragment fragment = new TargetOptionsBottomSheetDialogFragment();
fragment.setUsedOnMap(true);
fragment.show(mapActivity.getSupportFragmentManager(), TargetOptionsBottomSheetDialogFragment.TAG);
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
TargetOptionsBottomSheetDialogFragment fragment = new TargetOptionsBottomSheetDialogFragment();
fragment.setUsedOnMap(true);
fragment.show(mapActivity.getSupportFragmentManager(), TargetOptionsBottomSheetDialogFragment.TAG);
}
}
}
});
@ -159,8 +155,8 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
mapActivity.getTheme().resolveAttribute(R.attr.left_menu_view_bg, typedValueAttr, true);
mainView.setBackgroundResource(typedValueAttr.resourceId);
mainView.setLayoutParams(new FrameLayout.LayoutParams(getResources().getDimensionPixelSize(R.dimen.dashboard_land_width), ViewGroup.LayoutParams.MATCH_PARENT));
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(AndroidUtils.dpToPx(app, 345f), ViewGroup.LayoutParams.WRAP_CONTENT);
int width = getResources().getDimensionPixelSize(R.dimen.dashboard_land_width) - getResources().getDimensionPixelSize(R.dimen.dashboard_land_shadow_width);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.BOTTOM;
view.findViewById(R.id.control_buttons).setLayoutParams(params);
@ -225,29 +221,34 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
@Override
public String getTitle() {
List<Object> activeObjects;
if ((mapActivity.getRoutingHelper().isRoutePlanningMode() || mapActivity.getRoutingHelper().isFollowingMode())
&& item != null
&& ((activeObjects = stableAdapter.getActiveObjects()).isEmpty() || isContainsOnlyStart(activeObjects))) {
return mapActivity.getResources().getString(R.string.cancel_navigation);
} else {
return null;
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
List<Object> activeObjects;
if ((mapActivity.getRoutingHelper().isRoutePlanningMode() || mapActivity.getRoutingHelper().isFollowingMode())
&& item != null
&& ((activeObjects = stableAdapter.getActiveObjects()).isEmpty() || isContainsOnlyStart(activeObjects))) {
return mapActivity.getResources().getString(R.string.cancel_navigation);
}
}
return null;
}
};
}
@Override
public void onHidePopup() {
StableArrayAdapter stableAdapter = (StableArrayAdapter) listAdapter;
stableAdapter.refreshData();
applyPointsChanges();
updateTitle();
List<Object> activeObjects = stableAdapter.getActiveObjects();
if (activeObjects.isEmpty() || isContainsOnlyStart(activeObjects)) {
mapActivity.getMapActions().stopNavigationWithoutConfirm();
mapActivity.getMyApplication().getTargetPointsHelper().removeAllWayPoints(false, true);
mapActivity.getMapRouteInfoMenu().hide();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
StableArrayAdapter stableAdapter = (StableArrayAdapter) listAdapter;
stableAdapter.refreshData();
applyPointsChanges();
updateTitle();
List<Object> activeObjects = stableAdapter.getActiveObjects();
if (activeObjects.isEmpty() || isContainsOnlyStart(activeObjects)) {
mapActivity.getMapActions().stopNavigationWithoutConfirm();
mapActivity.getMyApplication().getTargetPointsHelper().removeAllWayPoints(false, true);
mapActivity.getMapRouteInfoMenu().hide();
}
}
}
@ -269,12 +270,15 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
addButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle args = new Bundle();
args.putString(AddPointBottomSheetDialog.POINT_TYPE_KEY, MapRouteInfoMenu.PointType.INTERMEDIATE.name());
AddPointBottomSheetDialog fragment = new AddPointBottomSheetDialog();
fragment.setArguments(args);
fragment.setUsedOnMap(true);
fragment.show(mapActivity.getSupportFragmentManager(), AddPointBottomSheetDialog.TAG);
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
Bundle args = new Bundle();
args.putString(AddPointBottomSheetDialog.POINT_TYPE_KEY, MapRouteInfoMenu.PointType.INTERMEDIATE.name());
AddPointBottomSheetDialog fragment = new AddPointBottomSheetDialog();
fragment.setArguments(args);
fragment.setUsedOnMap(true);
fragment.show(mapActivity.getSupportFragmentManager(), AddPointBottomSheetDialog.TAG);
}
}
});
@ -284,9 +288,12 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
app.getTargetPointsHelper().clearAllPoints(true);
updateTitle();
reloadAdapter();
OsmandApplication app = getMyApplication();
if (app != null) {
app.getTargetPointsHelper().clearAllPoints(true);
updateTitle();
reloadAdapter();
}
}
});
@ -331,23 +338,33 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
@Override
public void onResume() {
super.onResume();
wasDrawerDisabled = mapActivity.isDrawerDisabled();
waypointDialogHelper.addHelperCallback(this);
app.getTargetPointsHelper().addListener(onStateChangedListener);
if (!wasDrawerDisabled) {
mapActivity.disableDrawer();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
MapRouteInfoMenu.waypointsVisible = true;
wasDrawerDisabled = mapActivity.isDrawerDisabled();
mapActivity.getDashboard().getWaypointDialogHelper().addHelperCallback(this);
mapActivity.getMyApplication().getTargetPointsHelper().addListener(onStateChangedListener);
if (!wasDrawerDisabled) {
mapActivity.disableDrawer();
}
updateRouteCalculationProgress(0);
updateControlsVisibility(false, false);
}
updateRouteCalculationProgress(0);
}
@Override
public void onPause() {
super.onPause();
cancelTimer();
waypointDialogHelper.removeHelperCallback(this);
app.getTargetPointsHelper().removeListener(onStateChangedListener);
if (!wasDrawerDisabled) {
mapActivity.enableDrawer();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
MapRouteInfoMenu.waypointsVisible = false;
mapActivity.getDashboard().getWaypointDialogHelper().removeHelperCallback(this);
mapActivity.getMyApplication().getTargetPointsHelper().removeListener(onStateChangedListener);
if (!wasDrawerDisabled) {
mapActivity.enableDrawer();
}
updateControlsVisibility(true, routeInfoMenuState != -1);
}
}
@ -395,20 +412,29 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
startTimer();
}
@Nullable
private MapActivity getMapActivity() {
return (MapActivity) getActivity();
}
public void applyDayNightMode() {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return;
}
boolean landscapeLayout = !portrait;
boolean nightMode = app.getDaynightHelper().isNightModeForMapControls();
boolean nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls();
int colorActive = ContextCompat.getColor(mapActivity, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
if (!landscapeLayout) {
AndroidUtils.setBackground(app, mainView, nightMode, R.drawable.route_info_menu_bg_light, R.drawable.route_info_menu_bg_dark);
AndroidUtils.setBackground(mapActivity, mainView, nightMode, R.drawable.route_info_menu_bg_light, R.drawable.route_info_menu_bg_dark);
} else {
AndroidUtils.setBackground(app, mainView, nightMode, R.drawable.route_info_menu_bg_left_light, R.drawable.route_info_menu_bg_left_dark);
AndroidUtils.setBackground(mapActivity, mainView, nightMode, R.drawable.route_info_menu_bg_left_light, R.drawable.route_info_menu_bg_left_dark);
}
((TextView) view.findViewById(R.id.sort_button)).setTextColor(colorActive);
((TextView) view.findViewById(R.id.add_button_descr)).setTextColor(colorActive);
((TextView) view.findViewById(R.id.clear_all_button_descr)).setTextColor(colorActive);
((TextView) view.findViewById(R.id.title)).setTextColor(ContextCompat.getColor(app, nightMode ? R.color.main_font_dark : R.color.main_font_light));
((TextView) view.findViewById(R.id.title)).setTextColor(ContextCompat.getColor(mapActivity, nightMode ? R.color.main_font_dark : R.color.main_font_light));
FrameLayout addButton = view.findViewById(R.id.add_button);
TextView addButtonDescr = (TextView) view.findViewById(R.id.add_button_descr);
@ -416,10 +442,10 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
addButtonDescr.setText(R.string.shared_string_add);
addButtonDescr.setCompoundDrawablesWithIntrinsicBounds(getPaintedContentIcon(R.drawable.ic_action_plus, colorActive), null, null, null);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, addButton, nightMode, R.drawable.btn_border_light, R.drawable.btn_border_dark);
AndroidUtils.setBackground(app, addButtonDescr, nightMode, R.drawable.ripple_light, R.drawable.ripple_dark);
AndroidUtils.setBackground(mapActivity, addButton, nightMode, R.drawable.btn_border_light, R.drawable.btn_border_dark);
AndroidUtils.setBackground(mapActivity, addButtonDescr, nightMode, R.drawable.ripple_light, R.drawable.ripple_dark);
} else {
AndroidUtils.setBackground(app, addButton, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark);
AndroidUtils.setBackground(mapActivity, addButton, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark);
}
FrameLayout clearButton = view.findViewById(R.id.clear_all_button);
@ -428,12 +454,13 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
clearButtonDescr.setCompoundDrawablesWithIntrinsicBounds(getPaintedContentIcon(R.drawable.ic_action_clear_all, colorActive), null, null, null);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, clearButton, nightMode, R.drawable.btn_border_light, R.drawable.btn_border_dark);
AndroidUtils.setBackground(app, clearButtonDescr, nightMode, R.drawable.ripple_light, R.drawable.ripple_dark);
AndroidUtils.setBackground(mapActivity, clearButton, nightMode, R.drawable.btn_border_light, R.drawable.btn_border_dark);
AndroidUtils.setBackground(mapActivity, clearButtonDescr, nightMode, R.drawable.ripple_light, R.drawable.ripple_dark);
} else {
AndroidUtils.setBackground(app, clearButtonDescr, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark);
AndroidUtils.setBackground(mapActivity, clearButtonDescr, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark);
}
AndroidUtils.setBackground(app, view.findViewById(R.id.cancel_button), nightMode, R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
AndroidUtils.setBackground(mapActivity, view.findViewById(R.id.cancel_button), nightMode, R.color.card_and_list_background_light, R.color.card_and_list_background_dark);
AndroidUtils.setBackground(mapActivity, view.findViewById(R.id.controls_divider), nightMode, R.color.divider_light, R.color.divider_dark);
((TextView) view.findViewById(R.id.cancel_button_descr)).setTextColor(colorActive);
((TextView) view.findViewById(R.id.start_button_descr)).setText(getText(R.string.shared_string_apply));
@ -442,6 +469,11 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
public void reloadListAdapter(ArrayAdapter<Object> listAdapter) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return;
}
WaypointDialogHelper waypointDialogHelper = mapActivity.getDashboard().getWaypointDialogHelper();
mapActivity.getMyApplication().getWaypointHelper().removeVisibleLocationPoint(new ArrayList<LocationPointWrapper>());
listAdapter.setNotifyOnChange(false);
@ -461,7 +493,8 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
return new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int item, long l) {
if (listAdapter.getItem(item) instanceof LocationPointWrapper) {
OsmandApplication app = getMyApplication();
if (app != null && listAdapter.getItem(item) instanceof LocationPointWrapper) {
LocationPointWrapper ps = (LocationPointWrapper) listAdapter.getItem(item);
if (ps != null) {
showOnMap(app, ctx, ps.getPoint(), false);
@ -476,6 +509,8 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
final boolean edit, final List<LocationPointWrapper> deletedPoints,
final MapActivity ctx, final int[] running, final boolean flat, final boolean nightMode) {
final WaypointDialogHelper waypointDialogHelper = ctx.getDashboard().getWaypointDialogHelper();
List<Object> points = waypointDialogHelper.getTargetPoints();
List<Object> activePoints = waypointDialogHelper.getActivePoints(points);
@ -489,7 +524,7 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
Object obj = getItem(position);
if (obj instanceof LocationPointWrapper) {
LocationPointWrapper point = (LocationPointWrapper) obj;
v = updateWaypointItemView(edit, deletedPoints, app, ctx, waypointDialogHelper, v, point, this, nightMode, flat, position);
v = updateWaypointItemView(edit, deletedPoints, ctx, v, point, this, nightMode, flat, position);
}
return v;
}
@ -501,7 +536,7 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
if (w.type == WaypointHelper.TARGETS) {
final TargetPoint t = (TargetPoint) w.point;
if (t.getOriginalPointDescription() != null
&& t.getOriginalPointDescription().isSearchingAddress(mapActivity)) {
&& t.getOriginalPointDescription().isSearchingAddress(ctx)) {
GeocodingLookupService.AddressLookupRequest lookupRequest
= new GeocodingLookupService.AddressLookupRequest(t.point, new GeocodingLookupService.OnAddressLookupResult() {
@Override
@ -510,9 +545,8 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
//updateRouteInfoMenu(ctx);
}
}, null);
app.getGeocodingLookupService().lookupAddress(lookupRequest);
ctx.getMyApplication().getGeocodingLookupService().lookupAddress(lookupRequest);
}
}
}
}
@ -520,12 +554,32 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
return listAdapter;
}
public void updateControlsVisibility(boolean visible, boolean openingRouteInfo) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
int visibility = visible ? View.VISIBLE : View.GONE;
mapActivity.findViewById(R.id.map_center_info).setVisibility(visibility);
mapActivity.findViewById(R.id.map_left_widgets_panel).setVisibility(visibility);
if (!openingRouteInfo) {
mapActivity.findViewById(R.id.map_right_widgets_panel).setVisibility(visibility);
if (!portrait) {
mapActivity.getMapView().setMapPositionX(visible ? 0 : 1);
}
}
mapActivity.refreshMap();
}
}
public void newRouteIsCalculated(boolean newRoute, ValueHolder<Boolean> showToast) {
reloadAdapter();
showToast.value = false;
}
public void updateRouteCalculationProgress(int progress) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return;
}
ProgressBar progressBarButton = (ProgressBar) view.findViewById(R.id.progress_bar_button);
if (progressBarButton != null) {
if (progressBarButton.getVisibility() != View.VISIBLE) {
@ -542,10 +596,13 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
public void setupRouteCalculationButtonProgressBar(@NonNull ProgressBar pb) {
int bgColor = ContextCompat.getColor(app, nightMode ? R.color.activity_background_dark : R.color.activity_background_light);
int progressColor = ContextCompat.getColor(app, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
OsmandApplication app = getMyApplication();
if (app != null) {
int bgColor = ContextCompat.getColor(app, nightMode ? R.color.activity_background_dark : R.color.activity_background_light);
int progressColor = ContextCompat.getColor(app, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light);
pb.setProgressDrawable(AndroidUtils.createProgressDrawable(bgColor, progressColor));
pb.setProgressDrawable(AndroidUtils.createProgressDrawable(bgColor, progressColor));
}
}
private void setDynamicListItems(DynamicListView listView, StableArrayAdapter listAdapter) {
@ -554,6 +611,10 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
private void updateListAdapter() {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return;
}
List<LocationPointWrapper> deletedPoints = new ArrayList<>();
listView.setEmptyView(null);
StableArrayAdapter listAdapter = getWaypointsDrawerAdapter(true, deletedPoints, mapActivity, running, false, nightMode);
@ -588,7 +649,8 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
private void updateTitle() {
if (isAdded()) {
OsmandApplication app = getMyApplication();
if (app != null && isAdded()) {
final TextViewEx title = (TextViewEx) view.findViewById(R.id.title);
int pointsSize = app.getTargetPointsHelper().getAllPoints().size();
String text = getString(R.string.shared_string_target_points) + " (" + (pointsSize != 0 ? pointsSize : 1) + ")";
@ -597,6 +659,10 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
private void applyPointsChanges() {
OsmandApplication app = getMyApplication();
if (app == null) {
return;
}
app.runInUIThread(new Runnable() {
@Override
public void run() {
@ -672,16 +738,17 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
private static View updateWaypointItemView(final boolean edit, final List<LocationPointWrapper> deletedPoints,
final OsmandApplication app, final Activity ctx,
final WaypointDialogHelper helper, View v,
final MapActivity mapActivity, View v,
final LocationPointWrapper point,
final ArrayAdapter adapter, final boolean nightMode,
final boolean flat, final int position) {
final OsmandApplication app = mapActivity.getMyApplication();
final WaypointDialogHelper helper = mapActivity.getDashboard().getWaypointDialogHelper();
if (v == null || v.findViewById(R.id.info_close) == null) {
v = ctx.getLayoutInflater().inflate(R.layout.route_waypoint_item, null);
v = mapActivity.getLayoutInflater().inflate(R.layout.route_waypoint_item, null);
}
v.setBackgroundColor(ContextCompat.getColor(app, nightMode ? R.color.card_and_list_background_dark : R.color.card_and_list_background_light));
updatePointInfoView(app, ctx, v, point, true, nightMode, edit, false);
v.setBackgroundColor(ContextCompat.getColor(mapActivity, nightMode ? R.color.card_and_list_background_dark : R.color.card_and_list_background_light));
updatePointInfoView(mapActivity, v, point, true, nightMode, edit, false);
final ImageView move = (ImageView) v.findViewById(R.id.info_move);
final ImageButton remove = (ImageButton) v.findViewById(R.id.info_close);
@ -708,11 +775,11 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
public void onClick(View v) {
if (targetPointsHelper.getPointToStart() == null) {
if (!targetPointsHelper.getIntermediatePoints().isEmpty()) {
WaypointDialogHelper.replaceStartWithFirstIntermediate(targetPointsHelper, ctx, helper);
WaypointDialogHelper.replaceStartWithFirstIntermediate(targetPointsHelper, mapActivity, helper);
}
} else {
targetPointsHelper.setStartPoint(null, true, null);
WaypointDialogHelper.updateControls(ctx, helper);
WaypointDialogHelper.updateControls(mapActivity, helper);
}
}
});
@ -720,13 +787,13 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
remove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
WaypointDialogHelper.deletePoint(app, ctx, adapter, helper, point, deletedPoints, true);
WaypointDialogHelper.deletePoint(app, mapActivity, adapter, helper, point, deletedPoints, true);
}
});
}
}
AndroidUtils.setBackground(ctx, topDivider, nightMode, R.color.divider_light, R.color.divider_dark);
AndroidUtils.setBackground(mapActivity, topDivider, nightMode, R.color.divider_light, R.color.divider_dark);
topDivider.setVisibility(position != 0 ? View.VISIBLE : View.GONE);
move.setVisibility(notFlatTargets ? View.VISIBLE : View.GONE);
@ -744,36 +811,35 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
return v;
}
private static void updatePointInfoView(final OsmandApplication app, final Activity activity,
private static void updatePointInfoView(final MapActivity mapActivity,
View localView, final LocationPointWrapper ps,
final boolean mapCenter, final boolean nightMode,
final boolean edit, final boolean topBar) {
WaypointHelper wh = app.getWaypointHelper();
final OsmandApplication app = mapActivity.getMyApplication();
WaypointHelper wh = mapActivity.getMyApplication().getWaypointHelper();
final LocationPoint point = ps.getPoint();
TextView text = (TextView) localView.findViewById(R.id.waypoint_text);
if (!topBar) {
text.setTextColor(ContextCompat.getColor(app, nightMode ? R.color.main_font_dark : R.color.main_font_light));
text.setTextColor(ContextCompat.getColor(mapActivity, nightMode ? R.color.main_font_dark : R.color.main_font_light));
}
TextView textShadow = (TextView) localView.findViewById(R.id.waypoint_text_shadow);
if (!edit) {
localView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showOnMap(app, activity, point, mapCenter);
showOnMap(app, mapActivity, point, mapCenter);
}
});
}
TextView textDist = (TextView) localView.findViewById(R.id.waypoint_dist);
textDist.setTextColor(ContextCompat.getColor(app, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light));
((ImageView) localView.findViewById(R.id.waypoint_icon)).setImageDrawable(ps.getDrawable(activity, app, nightMode));
((ImageView) localView.findViewById(R.id.waypoint_icon)).setImageDrawable(ps.getDrawable(mapActivity, app, nightMode));
int dist = -1;
boolean startPoint = ps.type == WaypointHelper.TARGETS && ((TargetPoint) ps.point).start;
if (!startPoint) {
if (!wh.isRouteCalculated()) {
if (activity instanceof MapActivity) {
dist = (int) MapUtils.getDistance(((MapActivity) activity).getMapView().getLatitude(), ((MapActivity) activity)
.getMapView().getLongitude(), point.getLatitude(), point.getLongitude());
}
dist = (int) MapUtils.getDistance(mapActivity.getMapView().getLatitude(), mapActivity.getMapView().getLongitude(),
point.getLatitude(), point.getLongitude());
} else {
dist = wh.getRouteDistance(ps);
}
@ -831,15 +897,15 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
case WaypointHelper.TARGETS:
TargetPoint targetPoint = (TargetPoint) ps.point;
if (targetPoint.start) {
pointDescription = activity.getResources().getString(R.string.starting_point);
pointDescription = mapActivity.getResources().getString(R.string.starting_point);
} else {
pointDescription = getPointDescription(activity, targetPoint).getTypeName();
pointDescription = getPointDescription(mapActivity, targetPoint).getTypeName();
}
break;
case WaypointHelper.FAVORITES:
FavouritePoint favPoint = (FavouritePoint) ps.point;
pointDescription = Algorithms.isEmpty(favPoint.getCategory()) ? activity.getResources().getString(R.string.shared_string_favorites) : favPoint.getCategory();
pointDescription = Algorithms.isEmpty(favPoint.getCategory()) ? mapActivity.getResources().getString(R.string.shared_string_favorites) : favPoint.getCategory();
break;
}
}
@ -864,15 +930,20 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
}
public static boolean showInstance(final MapActivity mapActivity) {
try {
mapActivity.getContextMenu().hideMenues();
public static boolean showInstance(FragmentManager fragmentManager) {
return WaypointsFragment.showInstance(fragmentManager, -1);
}
public static boolean showInstance(FragmentManager fragmentManager, int routeInfoState) {
try {
WaypointsFragment fragment = new WaypointsFragment();
mapActivity.getSupportFragmentManager()
.beginTransaction()
Bundle args = new Bundle();
args.putInt(ROUTE_INFO_STATE_KEY, routeInfoState);
fragment.setArguments(args);
fragmentManager.beginTransaction()
.add(R.id.routeMenuContainer, fragment, TAG)
.addToBackStack(TAG)
.commitAllowingStateLoss();
return true;
@ -883,14 +954,16 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS
}
private void dismiss() {
FragmentActivity activity = getActivity();
if (activity != null) {
try {
activity.getSupportFragmentManager().popBackStack(TAG,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
} catch (Exception e) {
//
try {
MapActivity mapActivity = (MapActivity) getActivity();
if (mapActivity != null) {
mapActivity.getSupportFragmentManager().beginTransaction().remove(this).commitAllowingStateLoss();
if (routeInfoMenuState != -1) {
mapActivity.getMapLayers().getMapControlsLayer().showRouteInfoControlDialog(routeInfoMenuState);
}
}
} catch (Exception e) {
//
}
}
}

View file

@ -1,6 +1,5 @@
package net.osmand.plus.routepreparationmenu.cards;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
@ -40,7 +39,7 @@ public class HomeWorkCard extends BaseCard {
@Override
public void onClick(View v) {
if (homePoint == null) {
openAddPointDialog(mapActivity, true);
AddPointBottomSheetDialog.showInstance(mapActivity, PointType.HOME);
} else {
targetPointsHelper.navigateToPoint(homePoint.point, true, -1, homePoint.getOriginalPointDescription());
}
@ -49,7 +48,7 @@ public class HomeWorkCard extends BaseCard {
homeButton.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
openAddPointDialog(mapActivity, true);
AddPointBottomSheetDialog.showInstance(mapActivity, PointType.HOME);
return true;
}
});
@ -59,7 +58,7 @@ public class HomeWorkCard extends BaseCard {
@Override
public void onClick(View v) {
if (workPoint == null) {
openAddPointDialog(mapActivity, false);
AddPointBottomSheetDialog.showInstance(mapActivity, PointType.WORK);
} else {
targetPointsHelper.navigateToPoint(workPoint.point, true, -1, workPoint.getOriginalPointDescription());
}
@ -68,18 +67,9 @@ public class HomeWorkCard extends BaseCard {
workButton.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
openAddPointDialog(mapActivity, false);
AddPointBottomSheetDialog.showInstance(mapActivity, PointType.WORK);
return true;
}
});
}
private void openAddPointDialog(MapActivity mapActivity, boolean home) {
Bundle args = new Bundle();
args.putString(AddPointBottomSheetDialog.POINT_TYPE_KEY, home ? PointType.HOME.name() : PointType.WORK.name());
AddPointBottomSheetDialog fragment = new AddPointBottomSheetDialog();
fragment.setArguments(args);
fragment.setUsedOnMap(true);
fragment.show(mapActivity.getSupportFragmentManager(), AddPointBottomSheetDialog.TAG);
}
}

View file

@ -86,6 +86,18 @@ public class PublicTransportCard extends BaseCard {
fromLine.setText(getFirstLineDescrSpan());
wayLine.setText(getSecondLineDescrSpan(segments));
updateButtons();
view.findViewById(R.id.bottom_shadow).setVisibility(showBottomShadow ? View.VISIBLE : View.GONE);
view.findViewById(R.id.card_divider).setVisibility(showTopShadow ? View.VISIBLE : View.GONE);
view.findViewById(R.id.top_divider).setVisibility(!showTopShadow && showDivider ? View.VISIBLE : View.GONE);
if (transparentBackground) {
view.findViewById(R.id.routes_info_container).setBackgroundDrawable(null);
}
}
public void updateButtons() {
int color = getActiveColor();
FrameLayout detailsButton = (FrameLayout) view.findViewById(R.id.details_button);
TextView detailsButtonDescr = (TextView) view.findViewById(R.id.details_button_descr);
@ -95,7 +107,6 @@ public class PublicTransportCard extends BaseCard {
} else {
AndroidUtils.setBackground(app, detailsButton, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark);
}
int color = getActiveColor();
detailsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -107,7 +118,6 @@ public class PublicTransportCard extends BaseCard {
}
}
});
FrameLayout showButton = (FrameLayout) view.findViewById(R.id.show_button);
TextView showButtonDescr = (TextView) view.findViewById(R.id.show_button_descr);
if (isCurrentRoute()) {
@ -136,13 +146,6 @@ public class PublicTransportCard extends BaseCard {
});
}
showButtonDescr.setTextColor(color);
view.findViewById(R.id.bottom_shadow).setVisibility(showBottomShadow ? View.VISIBLE : View.GONE);
view.findViewById(R.id.card_divider).setVisibility(showTopShadow ? View.VISIBLE : View.GONE);
view.findViewById(R.id.top_divider).setVisibility(!showTopShadow && showDivider ? View.VISIBLE : View.GONE);
if (transparentBackground) {
view.findViewById(R.id.routes_info_container).setBackgroundDrawable(null);
}
}
public int getRouteId() {

View file

@ -0,0 +1,105 @@
package net.osmand.plus.routepreparationmenu.cards;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.support.annotation.NonNull;
import android.support.v7.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.routepreparationmenu.RouteDetailsFragment;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.views.TurnPathHelper;
import net.osmand.util.Algorithms;
import java.util.List;
public class RouteDirectionsCard extends BaseCard {
public RouteDirectionsCard(@NonNull MapActivity mapActivity) {
super(mapActivity);
}
@Override
public int getCardLayoutId() {
return R.layout.route_directions_card;
}
@Override
protected void updateContent() {
LinearLayout root = (LinearLayout) view.findViewById(R.id.items);
root.removeAllViews();
createRouteDirections(root);
}
private void createRouteDirections(LinearLayout cardsContainer) {
List<RouteDirectionInfo> routeDirections = app.getRoutingHelper().getRouteDirections();
for (int i = 0; i < routeDirections.size(); i++) {
RouteDirectionInfo routeDirectionInfo = routeDirections.get(i);
View view = getRouteDirectionView(i, routeDirectionInfo, routeDirections);
cardsContainer.addView(view);
}
}
private static String getTimeDescription(OsmandApplication app, RouteDirectionInfo model) {
final int timeInSeconds = model.getExpectedTime();
return Algorithms.formatDuration(timeInSeconds, app.accessibilityEnabled());
}
private View getRouteDirectionView(final int directionInfoIndex, RouteDirectionInfo model, List<RouteDirectionInfo> directionsInfo) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return null;
}
OsmandApplication app = mapActivity.getMyApplication();
ContextThemeWrapper context = new ContextThemeWrapper(mapActivity, nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme);
View row = LayoutInflater.from(context).inflate(R.layout.route_info_list_item, null);
TextView label = (TextView) row.findViewById(R.id.description);
TextView distanceLabel = (TextView) row.findViewById(R.id.distance);
TextView timeLabel = (TextView) row.findViewById(R.id.time);
TextView cumulativeDistanceLabel = (TextView) row.findViewById(R.id.cumulative_distance);
TextView cumulativeTimeLabel = (TextView) row.findViewById(R.id.cumulative_time);
ImageView icon = (ImageView) row.findViewById(R.id.direction);
row.findViewById(R.id.divider).setVisibility(directionInfoIndex == directionsInfo.size() - 1 ? View.INVISIBLE : View.VISIBLE);
TurnPathHelper.RouteDrawable drawable = new TurnPathHelper.RouteDrawable(mapActivity.getResources(), true);
drawable.setColorFilter(new PorterDuffColorFilter(getActiveColor(), PorterDuff.Mode.SRC_ATOP));
drawable.setRouteType(model.getTurnType());
icon.setImageDrawable(drawable);
label.setText(model.getDescriptionRoutePart());
if (model.distance > 0) {
distanceLabel.setText(OsmAndFormatter.getFormattedDistance(model.distance, app));
timeLabel.setText(getTimeDescription(app, model));
row.setContentDescription(label.getText() + " " + timeLabel.getText());
} else {
if (Algorithms.isEmpty(label.getText().toString())) {
label.setText(mapActivity.getString((directionInfoIndex != directionsInfo.size() - 1) ? R.string.arrived_at_intermediate_point : R.string.arrived_at_destination));
}
distanceLabel.setText("");
timeLabel.setText("");
row.setContentDescription("");
}
RouteDetailsFragment.CumulativeInfo cumulativeInfo = RouteDetailsFragment.getRouteDirectionCumulativeInfo(directionInfoIndex, directionsInfo);
cumulativeDistanceLabel.setText(OsmAndFormatter.getFormattedDistance(cumulativeInfo.distance, app));
cumulativeTimeLabel.setText(Algorithms.formatDuration(cumulativeInfo.time, app.accessibilityEnabled()));
row.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CardListener listener = getListener();
if (listener != null) {
listener.onCardButtonPressed(RouteDirectionsCard.this, directionInfoIndex);
}
}
});
return row;
}
}

View file

@ -2,18 +2,21 @@ package net.osmand.plus.routepreparationmenu.cards;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.ColorUtils;
import android.support.v7.view.ContextThemeWrapper;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.StyleSpan;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.data.BarData;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.R;
@ -36,9 +39,13 @@ import static net.osmand.router.RouteStatistics.UNDEFINED_ATTR;
public class RouteInfoCard extends BaseCard {
private static final int MINIMUM_CONTRAST_RATIO = 3;
private Statistics routeStatistics;
private GPXUtilities.GPXTrackAnalysis analysis;
private boolean showLegend;
public RouteInfoCard(MapActivity mapActivity, Statistics routeStatistics, GPXUtilities.GPXTrackAnalysis analysis) {
super(mapActivity);
this.routeStatistics = routeStatistics;
@ -54,11 +61,28 @@ public class RouteInfoCard extends BaseCard {
protected void updateContent() {
updateHeader();
final HorizontalBarChart chart = (HorizontalBarChart) view.findViewById(R.id.chart);
GpxUiHelper.setupHorizontalGPXChart(app, chart, 5, 10, 10, true, nightMode);
GpxUiHelper.setupHorizontalGPXChart(app, chart, 5, 9, 24, true, nightMode);
BarData barData = GpxUiHelper.buildStatisticChart(app, chart, routeStatistics, analysis, true, nightMode);
chart.setData(barData);
LinearLayout container = view.findViewById(R.id.route_items);
attachLegend(container, routeStatistics);
final LinearLayout container = (LinearLayout) view.findViewById(R.id.route_items);
container.removeAllViews();
if (showLegend) {
attachLegend(container, routeStatistics);
}
final ImageView iconViewCollapse = (ImageView) view.findViewById(R.id.up_down_icon);
iconViewCollapse.setImageDrawable(getCollapseIcon(!showLegend));
view.findViewById(R.id.info_type_details_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showLegend = !showLegend;
updateContent();
setLayoutNeeded();
}
});
}
private Drawable getCollapseIcon(boolean collapsed) {
return collapsed ? getContentIcon(R.drawable.ic_action_arrow_down) : getActiveIcon(R.drawable.ic_action_arrow_up);
}
private void updateHeader() {
@ -83,46 +107,49 @@ public class RouteInfoCard extends BaseCard {
private <E> void attachLegend(ViewGroup container, Statistics<E> routeStatistics) {
Map<E, RouteSegmentAttribute<E>> partition = routeStatistics.getPartition();
List<E> list = new ArrayList<E>(partition.keySet());
List<Map.Entry<E, RouteSegmentAttribute<E>>> list = new ArrayList<>(partition.entrySet());
sortRouteSegmentAttributes(list);
for (E key : list) {
RouteSegmentAttribute<E> segment = partition.get(key);
int color = segment.getColor();
Drawable circle = app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, color);
ContextThemeWrapper ctx = new ContextThemeWrapper(mapActivity, !nightMode ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
LayoutInflater inflater = LayoutInflater.from(ctx);
for (Map.Entry<E, RouteSegmentAttribute<E>> entry : list) {
RouteSegmentAttribute<E> segment = entry.getValue();
View view = inflater.inflate(R.layout.route_details_legend, container, false);
int segmentColor = segment.getColor();
Drawable circle = app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, segmentColor);
ImageView legendIcon = (ImageView) view.findViewById(R.id.legend_icon_color);
legendIcon.setImageDrawable(circle);
double contrastRatio = ColorUtils.calculateContrast(segmentColor, ContextCompat.getColor(app, nightMode ? R.color.card_and_list_background_dark : R.color.card_and_list_background_light));
if (contrastRatio < MINIMUM_CONTRAST_RATIO) {
legendIcon.setBackgroundResource(nightMode ? R.drawable.circle_contour_bg_dark : R.drawable.circle_contour_bg_light);
}
String propertyName = segment.getPropertyName();
String name = SettingsNavigationActivity.getStringPropertyName(app, propertyName, propertyName.replaceAll("_", " "));
Spannable text = getSpanLegend(name, segment);
TextView legend = new TextView(app);
legend.setTextColor(getMainFontColor());
legend.setTextSize(15);
legend.setGravity(Gravity.CENTER_VERTICAL);
legend.setCompoundDrawablePadding(AndroidUtils.dpToPx(app, 16));
legend.setPadding(AndroidUtils.dpToPx(app, 16), AndroidUtils.dpToPx(app, 4), AndroidUtils.dpToPx(app, 16), AndroidUtils.dpToPx(app, 4));
legend.setCompoundDrawablesWithIntrinsicBounds(circle, null, null, null);
TextView legend = (TextView) view.findViewById(R.id.legend_text);
legend.setText(text);
container.addView(legend);
container.addView(view);
}
}
private <E> void sortRouteSegmentAttributes(List<E> list) {
Collections.sort(list, new Comparator<E>() {
private <E> void sortRouteSegmentAttributes(List<Map.Entry<E, RouteSegmentAttribute<E>>> list) {
Collections.sort(list, new Comparator<Map.Entry<E, RouteSegmentAttribute<E>>>() {
@Override
public int compare(E o1, E o2) {
if (o1 instanceof String && o2 instanceof String) {
String name1 = (String) o1;
String name2 = (String) o2;
public int compare(Map.Entry<E, RouteSegmentAttribute<E>> o1, Map.Entry<E, RouteSegmentAttribute<E>> o2) {
Object key1 = o1.getKey();
Object key2 = o2.getKey();
if (key1 instanceof String && key2 instanceof String) {
float distance1 = o1.getValue().getDistance();
float distance2 = o2.getValue().getDistance();
if (name1.equalsIgnoreCase(UNDEFINED_ATTR)) {
if (((String) key1).equalsIgnoreCase(UNDEFINED_ATTR) || distance1 < distance2) {
return 1;
}
if (name2.equalsIgnoreCase(UNDEFINED_ATTR)) {
if (((String) key2).equalsIgnoreCase(UNDEFINED_ATTR) || distance1 > distance2) {
return -1;
}
return name1.compareTo(name2);
} else if (o1 instanceof Boundaries && o2 instanceof Boundaries) {
return ((Boundaries) o1).compareTo((Boundaries) o2);
} else if (key1 instanceof Boundaries && key2 instanceof Boundaries) {
return ((Boundaries) key1).compareTo((Boundaries) key2);
}
return 0;
}

View file

@ -1,11 +1,15 @@
package net.osmand.plus.routepreparationmenu.cards;
import android.graphics.Matrix;
import android.support.v4.content.ContextCompat;
import android.os.Build;
import android.support.annotation.Nullable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@ -13,17 +17,21 @@ import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.ChartTouchListener;
import com.github.mikephil.charting.listener.ChartTouchListener.ChartGesture;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import net.osmand.GPXUtilities;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.routing.RoutingHelper;
import java.util.ArrayList;
@ -32,15 +40,20 @@ import java.util.List;
public class RouteStatisticCard extends BaseCard {
private GPXFile gpx;
private GpxSelectionHelper.GpxDisplayItem gpxItem;
private GpxUiHelper.OrderedLineDataSet slopeDataSet;
private GpxUiHelper.OrderedLineDataSet elevationDataSet;
private View.OnTouchListener onTouchListener;
private GpxDisplayItem gpxItem;
@Nullable
private OrderedLineDataSet slopeDataSet;
@Nullable
private OrderedLineDataSet elevationDataSet;
private OnTouchListener onTouchListener;
private OnClickListener onAnalyseClickListener;
public RouteStatisticCard(MapActivity mapActivity, GPXFile gpx, View.OnTouchListener onTouchListener) {
public RouteStatisticCard(MapActivity mapActivity, GPXFile gpx, OnTouchListener onTouchListener,
OnClickListener onAnalyseClickListener) {
super(mapActivity);
this.gpx = gpx;
this.onTouchListener = onTouchListener;
this.onAnalyseClickListener = onAnalyseClickListener;
makeGpxDisplayItem();
}
@ -66,7 +79,7 @@ public class RouteStatisticCard extends BaseCard {
SpannableStringBuilder distanceStr = new SpannableStringBuilder(text);
int spaceIndex = text.indexOf(" ");
if (spaceIndex != -1) {
distanceStr.setSpan(new ForegroundColorSpan(ContextCompat.getColor(app, nightMode ? R.color.primary_text_dark : R.color.primary_text_light)), 0, spaceIndex, 0);
distanceStr.setSpan(new ForegroundColorSpan(getMainFontColor()), 0, spaceIndex, 0);
}
distanceTv.setText(distanceStr);
SpannableStringBuilder timeStr = new SpannableStringBuilder();
@ -78,7 +91,7 @@ public class RouteStatisticCard extends BaseCard {
}
spaceIndex = timeStr.toString().lastIndexOf(" ");
if (spaceIndex != -1) {
timeStr.setSpan(new ForegroundColorSpan(ContextCompat.getColor(app, nightMode ? R.color.primary_text_dark : R.color.primary_text_light)), 0, spaceIndex, 0);
timeStr.setSpan(new ForegroundColorSpan(getMainFontColor()), 0, spaceIndex, 0);
}
TextView timeTv = (TextView) view.findViewById(R.id.time);
timeTv.setText(timeStr);
@ -87,32 +100,58 @@ public class RouteStatisticCard extends BaseCard {
String arriveStr = app.getString(R.string.arrive_at_time, OsmAndFormatter.getFormattedTime(time, true));
arriveTimeTv.setText(arriveStr);
GPXUtilities.GPXTrackAnalysis analysis = gpx.getAnalysis(0);
buildSlopeInfo();
buildHeader(analysis);
((TextView) view.findViewById(R.id.average_text)).setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
String min = OsmAndFormatter.getFormattedAlt(analysis.minElevation, app);
String max = OsmAndFormatter.getFormattedAlt(analysis.maxElevation, app);
((TextView) view.findViewById(R.id.range_text)).setText(min + " - " + max);
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
((TextView) view.findViewById(R.id.descent_text)).setText(desc);
((TextView) view.findViewById(R.id.ascent_text)).setText(asc);
((ImageView) view.findViewById(R.id.average_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_altitude_average));
((ImageView) view.findViewById(R.id.range_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_altitude_average));
((ImageView) view.findViewById(R.id.descent_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_altitude_descent));
((ImageView) view.findViewById(R.id.ascent_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_altitude_ascent));
if (isTransparentBackground()) {
view.setBackgroundDrawable(null);
}
}
public GpxUiHelper.OrderedLineDataSet getSlopeDataSet() {
private void buildSlopeInfo() {
GPXTrackAnalysis analysis = gpx.getAnalysis(0);
buildHeader(analysis);
if (analysis.hasElevationData) {
((TextView) view.findViewById(R.id.average_text)).setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
String min = OsmAndFormatter.getFormattedAlt(analysis.minElevation, app);
String max = OsmAndFormatter.getFormattedAlt(analysis.maxElevation, app);
((TextView) view.findViewById(R.id.range_text)).setText(min + " - " + max);
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
((TextView) view.findViewById(R.id.descent_text)).setText(desc);
((TextView) view.findViewById(R.id.ascent_text)).setText(asc);
((ImageView) view.findViewById(R.id.average_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_altitude_average));
((ImageView) view.findViewById(R.id.range_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_altitude_average));
((ImageView) view.findViewById(R.id.descent_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_altitude_descent));
((ImageView) view.findViewById(R.id.ascent_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_altitude_ascent));
TextView analyseButtonDescr = (TextView) view.findViewById(R.id.analyse_button_descr);
FrameLayout analyseButton = (FrameLayout) view.findViewById(R.id.analyse_button);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
AndroidUtils.setBackground(app, analyseButton, nightMode, R.drawable.btn_border_light, R.drawable.btn_border_dark);
AndroidUtils.setBackground(app, analyseButtonDescr, nightMode, R.drawable.ripple_light, R.drawable.ripple_dark);
} else {
AndroidUtils.setBackground(app, analyseButton, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark);
}
analyseButton.setOnClickListener(onAnalyseClickListener);
}
view.findViewById(R.id.altitude_container).setVisibility(analysis.hasElevationData ? View.VISIBLE : View.GONE);
view.findViewById(R.id.slope_info_divider).setVisibility(analysis.hasElevationData ? View.VISIBLE : View.GONE);
view.findViewById(R.id.slope_container).setVisibility(analysis.hasElevationData ? View.VISIBLE : View.GONE);
view.findViewById(R.id.buttons_container).setVisibility(analysis.hasElevationData ? View.VISIBLE : View.GONE);
}
@Nullable
public OrderedLineDataSet getSlopeDataSet() {
return slopeDataSet;
}
public GpxUiHelper.OrderedLineDataSet getElevationDataSet() {
@Nullable
public OrderedLineDataSet getElevationDataSet() {
return elevationDataSet;
}
@ -127,23 +166,27 @@ public class RouteStatisticCard extends BaseCard {
}
}
private void buildHeader(GPXUtilities.GPXTrackAnalysis analysis) {
private void buildHeader(GPXTrackAnalysis analysis) {
final LineChart mChart = (LineChart) view.findViewById(R.id.chart);
GpxUiHelper.setupGPXChart(mChart, 4, 24f, 16f, !nightMode, true);
mChart.setOnTouchListener(onTouchListener);
if (analysis.hasElevationData) {
List<ILineDataSet> dataSets = new ArrayList<>();
elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis,
GpxUiHelper.GPXDataSetAxisType.DISTANCE, false, true);
OrderedLineDataSet slopeDataSet = null;
OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis,
GPXDataSetAxisType.DISTANCE, false, true);
if (elevationDataSet != null) {
dataSets.add(elevationDataSet);
slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis,
GPXDataSetAxisType.DISTANCE, elevationDataSet.getValues(), true, true);
}
slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis,
GpxUiHelper.GPXDataSetAxisType.DISTANCE, elevationDataSet.getValues(), true, true);
if (slopeDataSet != null) {
dataSets.add(slopeDataSet);
}
this.elevationDataSet = elevationDataSet;
this.slopeDataSet = slopeDataSet;
LineData data = new LineData(dataSets);
mChart.setData(data);
@ -152,7 +195,7 @@ public class RouteStatisticCard extends BaseCard {
float highlightDrawX = -1;
@Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
public void onChartGestureStart(MotionEvent me, ChartGesture lastPerformedGesture) {
if (mChart.getHighlighted() != null && mChart.getHighlighted().length > 0) {
highlightDrawX = mChart.getHighlighted()[0].getDrawX();
} else {
@ -161,7 +204,7 @@ public class RouteStatisticCard extends BaseCard {
}
@Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
public void onChartGestureEnd(MotionEvent me, ChartGesture lastPerformedGesture) {
gpxItem.chartMatrix = new Matrix(mChart.getViewPortHandler().getMatrixTouch());
Highlight[] highlights = mChart.getHighlighted();
if (highlights != null && highlights.length > 0) {

View file

@ -17,6 +17,7 @@ import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.routing.RoutingHelper;
import java.util.ArrayList;
@ -26,6 +27,7 @@ public class SimpleRouteCard extends BaseCard {
private MapActivity mapActivity;
private GPXFile gpx;
private LineData data;
public SimpleRouteCard(MapActivity mapActivity, GPXFile gpx) {
super(mapActivity);
@ -112,21 +114,25 @@ public class SimpleRouteCard extends BaseCard {
final GPXUtilities.GPXTrackAnalysis analysis = gpx.getAnalysis(0);
GpxUiHelper.setupGPXChart(mChart, 4, 4f, 4f, !nightMode, false);
GpxUiHelper.OrderedLineDataSet elevationDataSet;
GpxUiHelper.OrderedLineDataSet slopeDataSet;
if (analysis.hasElevationData) {
List<ILineDataSet> dataSets = new ArrayList<>();
elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis,
GpxUiHelper.GPXDataSetAxisType.DISTANCE, false, true);
if (elevationDataSet != null) {
dataSets.add(elevationDataSet);
LineData data = this.data;
if (data == null) {
List<ILineDataSet> dataSets = new ArrayList<>();
OrderedLineDataSet slopeDataSet = null;
OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis,
GpxUiHelper.GPXDataSetAxisType.DISTANCE, false, true);
if (elevationDataSet != null) {
dataSets.add(elevationDataSet);
slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis,
GpxUiHelper.GPXDataSetAxisType.DISTANCE, elevationDataSet.getValues(), true, true);
}
if (slopeDataSet != null) {
dataSets.add(slopeDataSet);
}
data = new LineData(dataSets);
this.data = data;
}
slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis,
GpxUiHelper.GPXDataSetAxisType.DISTANCE, elevationDataSet.getValues(), true, true);
if (slopeDataSet != null) {
dataSets.add(slopeDataSet);
}
mChart.setData(new LineData(dataSets));
mChart.setData(data);
mChart.setVisibility(View.VISIBLE);
} else {
mChart.setVisibility(View.GONE);

View file

@ -2,9 +2,7 @@ package net.osmand.plus.routepreparationmenu.cards;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
@ -55,7 +53,7 @@ public class WarningCard extends BaseCard {
@Override
public void onClick(@NonNull View widget) {
WikipediaDialogFragment.showFullArticle(app, Uri.parse(OSMAND_BLOG_LINK), nightMode);
WikipediaDialogFragment.showFullArticle(mapActivity, Uri.parse(OSMAND_BLOG_LINK), nightMode);
}
};
int startIndex = text.lastIndexOf(" ");
@ -78,7 +76,7 @@ public class WarningCard extends BaseCard {
@Override
public void onClick(@NonNull View widget) {
openAddPointDialog();
AddPointBottomSheetDialog.showInstance(mapActivity, PointType.INTERMEDIATE);
}
};
text.setSpan(clickableSpan, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@ -88,16 +86,4 @@ public class WarningCard extends BaseCard {
warningDescr.setText(text);
}
}
private void openAddPointDialog() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
Bundle args = new Bundle();
args.putString(AddPointBottomSheetDialog.POINT_TYPE_KEY, PointType.INTERMEDIATE.name());
AddPointBottomSheetDialog fragment = new AddPointBottomSheetDialog();
fragment.setArguments(args);
fragment.setUsedOnMap(true);
fragment.show(mapActivity.getSupportFragmentManager(), AddPointBottomSheetDialog.TAG);
}
}
}

View file

@ -645,7 +645,7 @@ public class QuickSearchCoordinatesFragment extends DialogFragment implements Os
private OsmandApplication app;
private WeakReference<QuickSearchCoordinatesFragment> weakFragment;
private final List<String> citySubTypes = Arrays.asList("city", "town");
private final List<String> citySubTypes = Arrays.asList("city", "town", "village");
private final LatLon searchLocation;
private final String region;

View file

@ -916,6 +916,11 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
@Override
public boolean searchFinished(SearchPhrase phrase) {
SearchWord lastSelectedWord = phrase.getLastSelectedWord();
if (mainSearchFragment != null && mainSearchFragment.isShowResult() &&
isResultEmpty() && lastSelectedWord != null) {
mainSearchFragment.showResult(lastSelectedWord.getResult());
}
return true;
}
};

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