Merge branch 'master' into Fix_7752

This commit is contained in:
Dima-1 2020-01-30 17:48:21 +02:00
commit 04592db0fa
1862 changed files with 46691 additions and 21440 deletions

View file

@ -76,7 +76,6 @@
* 3rd party libraries present in the libs folder (https://github.com/osmandapp/Osmand/tree/master/OsmAnd-java/libs):
- bzip2-20090327.jar Bzip2 - Apache License
- bsh-core-2.0b4.jar Bean Shell - SPL and LGPL (http://www.beanshell.org/license.html)
- commons-logging-1.1.1.jar - Apache License
- gnu-trove-osmand.jar GNU trove - LGPL
- icu4j-49_1.jar - ICU license (http://source.icu-project.org/repos/icu/icu/trunk/license.html)

View file

@ -73,6 +73,7 @@ import net.osmand.aidlapi.customization.SetWidgetsParams;
import net.osmand.aidlapi.customization.OsmandSettingsParams;
import net.osmand.aidlapi.customization.OsmandSettingsInfoParams;
import net.osmand.aidlapi.customization.CustomizationInfoParams;
import net.osmand.aidlapi.customization.ProfileSettingsParams;
import net.osmand.aidlapi.gpx.AGpxFile;
import net.osmand.aidlapi.gpx.AGpxFileDetails;
@ -831,4 +832,6 @@ interface IOsmAndAidlInterface {
* Empty class of params
*/
boolean removeAllActiveMapMarkers(in RemoveMapMarkersParams params);
boolean importProfile(in ProfileSettingsParams params);
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidlapi.customization;
parcelable ProfileSettingsParams;

View file

@ -0,0 +1,62 @@
package net.osmand.aidlapi.customization;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import net.osmand.aidlapi.AidlParams;
public class ProfileSettingsParams extends AidlParams {
private Uri profileSettingsUri;
private String latestChanges;
private int version;
public ProfileSettingsParams(Uri profileSettingsUri, String latestChanges, int version) {
this.profileSettingsUri = profileSettingsUri;
this.latestChanges = latestChanges;
this.version = version;
}
public ProfileSettingsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<ProfileSettingsParams> CREATOR = new Creator<ProfileSettingsParams>() {
@Override
public ProfileSettingsParams createFromParcel(Parcel in) {
return new ProfileSettingsParams(in);
}
@Override
public ProfileSettingsParams[] newArray(int size) {
return new ProfileSettingsParams[size];
}
};
public int getVersion() {
return version;
}
public String getLatestChanges() {
return latestChanges;
}
public Uri getProfileSettingsUri() {
return profileSettingsUri;
}
@Override
public void writeToBundle(Bundle bundle) {
bundle.putInt("version", version);
bundle.putString("latestChanges", latestChanges);
bundle.putParcelable("profileSettingsUri", profileSettingsUri);
}
@Override
protected void readFromBundle(Bundle bundle) {
version = bundle.getInt("version");
latestChanges = bundle.getString("latestChanges");
profileSettingsUri = bundle.getParcelable("profileSettingsUri");
}
}

View file

@ -99,7 +99,6 @@ dependencies {
implementation group: 'commons-logging', name: 'commons-logging', version: '1.2'
implementation group: 'org.json', name: 'json', version: '20171018'
implementation 'it.unibo.alice.tuprolog:tuprolog:3.2.1'
implementation 'org.beanshell:bsh-core:2.0b4'
implementation 'org.apache.commons:commons-compress:1.17'
implementation 'com.moparisthebest:junidecode:0.1.1'
implementation 'com.vividsolutions:jts-core:1.14.0'

View file

@ -42,6 +42,8 @@ import java.util.TimeZone;
public class GPXUtilities {
public final static Log log = PlatformUtil.getLog(GPXUtilities.class);
private static final String ICON_NAME_EXTENSION = "icon";
private static final String DEFAULT_ICON_NAME = "special_star";
private final static String GPX_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; //$NON-NLS-1$
private final static String GPX_TIME_FORMAT_MILLIS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; //$NON-NLS-1$
@ -187,6 +189,7 @@ public class GPXUtilities {
public double ele = Double.NaN;
public double speed = 0;
public double hdop = Double.NaN;
public float heading = Float.NaN;
public boolean deleted = false;
public int colourARGB = 0; // point colour (used for altitude/speed colouring)
public double distance = 0.0; // cumulative distance, if in a track
@ -208,6 +211,7 @@ public class GPXUtilities {
this.ele = wptPt.ele;
this.speed = wptPt.speed;
this.hdop = wptPt.hdop;
this.heading = wptPt.heading;
this.deleted = wptPt.deleted;
this.colourARGB = wptPt.colourARGB;
this.distance = wptPt.distance;
@ -233,20 +237,40 @@ public class GPXUtilities {
return lon;
}
public float getHeading() {
return heading;
}
public WptPt(double lat, double lon, long time, double ele, double speed, double hdop) {
this(lat, lon, time, ele, speed, hdop, Float.NaN);
}
public WptPt(double lat, double lon, long time, double ele, double speed, double hdop, float heading) {
this.lat = lat;
this.lon = lon;
this.time = time;
this.ele = ele;
this.speed = speed;
this.hdop = hdop;
this.heading = heading;
}
public boolean isVisible() {
return true;
}
public String getIconName() {
String iconName = getExtensionsToRead().get(ICON_NAME_EXTENSION);
if (iconName == null) {
iconName = DEFAULT_ICON_NAME;
}
return iconName;
}
public void setIconName(String iconName) {
getExtensionsToWrite().put(ICON_NAME_EXTENSION, iconName);
}
@Override
public int hashCode() {
final int prime = 31;
@ -287,17 +311,17 @@ public class GPXUtilities {
public Object renderer;
public List<GPXTrackAnalysis> splitByDistance(double meters) {
return split(getDistanceMetric(), getTimeSplit(), meters);
public List<GPXTrackAnalysis> splitByDistance(double meters, boolean joinSegments) {
return split(getDistanceMetric(), getTimeSplit(), meters, joinSegments);
}
public List<GPXTrackAnalysis> splitByTime(int seconds) {
return split(getTimeSplit(), getDistanceMetric(), seconds);
public List<GPXTrackAnalysis> splitByTime(int seconds, boolean joinSegments) {
return split(getTimeSplit(), getDistanceMetric(), seconds, joinSegments);
}
private List<GPXTrackAnalysis> split(SplitMetric metric, SplitMetric secondaryMetric, double metricLimit) {
private List<GPXTrackAnalysis> split(SplitMetric metric, SplitMetric secondaryMetric, double metricLimit, boolean joinSegments) {
List<SplitSegment> splitSegments = new ArrayList<>();
splitSegment(metric, secondaryMetric, metricLimit, splitSegments, this);
splitSegment(metric, secondaryMetric, metricLimit, splitSegments, this, joinSegments);
return convert(splitSegments);
}
@ -853,7 +877,7 @@ public class GPXUtilities {
private static void splitSegment(SplitMetric metric, SplitMetric secondaryMetric,
double metricLimit, List<SplitSegment> splitSegments,
TrkSegment segment) {
TrkSegment segment, boolean joinSegments) {
double currentMetricEnd = metricLimit;
double secondaryMetricEnd = 0;
SplitSegment sp = new SplitSegment(segment, 0, 0);
@ -862,8 +886,11 @@ public class GPXUtilities {
for (int k = 0; k < segment.points.size(); k++) {
WptPt point = segment.points.get(k);
if (k > 0) {
double currentSegment = metric.metric(prev, point);
secondaryMetricEnd += secondaryMetric.metric(prev, point);
double currentSegment = 0;
if (!(segment.generalSegment && !joinSegments && point.firstPoint)) {
currentSegment = metric.metric(prev, point);
secondaryMetricEnd += secondaryMetric.metric(prev, point);
}
while (total + currentSegment > currentMetricEnd) {
double p = currentMetricEnd - total;
double cf = (p / currentSegment);
@ -1603,6 +1630,9 @@ public class GPXUtilities {
if (p.speed > 0) {
p.getExtensionsToWrite().put("speed", decimalFormat.format(p.speed));
}
if (!Float.isNaN(p.heading)) {
p.getExtensionsToWrite().put("heading", String.valueOf(Math.round(p.heading)));
}
writeExtensions(serializer, p);
}

View file

@ -41,6 +41,8 @@ public class IndexConstants {
public static final String FONT_INDEX_EXT_ZIP = ".otf.zip"; //$NON-NLS-1$
public static final String OSMAND_SETTINGS_FILE_EXT = ".osf";
public static final String ROUTING_FILE_EXT = ".xml";
public static final String RENDERER_INDEX_EXT = ".render.xml"; //$NON-NLS-1$

View file

@ -5,7 +5,6 @@ import net.osmand.ResultMatcher;
import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.data.Building;
import net.osmand.data.Building.BuildingInterpolation;
import net.osmand.data.City;
import net.osmand.data.LatLon;
import net.osmand.data.MapObject;
@ -22,14 +21,12 @@ import org.apache.commons.logging.Log;
import java.io.IOException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import gnu.trove.set.hash.TLongHashSet;

File diff suppressed because it is too large Load diff

View file

@ -632,18 +632,18 @@ public class RouteDataObject {
return def;
}
public boolean loop(){
return pointsX[0] == pointsX[pointsX.length - 1] && pointsY[0] == pointsY[pointsY.length - 1] ;
public boolean loop() {
return pointsX[0] == pointsX[pointsX.length - 1] && pointsY[0] == pointsY[pointsY.length - 1];
}
public boolean platform(){
public boolean platform() {
int sz = types.length;
for(int i=0; i<sz; i++) {
for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if(r.getTag().equals("railway") && r.getValue().equals("platform")) {
if (r.getTag().equals("railway") && r.getValue().equals("platform")) {
return true;
}
if(r.getTag().equals("public_transport") && r.getValue().equals("platform")) {
if (r.getTag().equals("public_transport") && r.getValue().equals("platform")) {
return true;
}
}
@ -676,7 +676,72 @@ public class RouteDataObject {
}
return false;
}
public boolean isExitPoint() {
if (pointTypes != null) {
int ptSz = pointTypes.length;
for (int i = 0; i < ptSz; i++) {
int[] point = pointTypes[i];
if (point != null) {
int pSz = point.length;
for (int j = 0; j < pSz; j++) {
if (region.routeEncodingRules.get(point[j]).getValue().equals("motorway_junction")) {
return true;
}
}
}
}
}
return false;
}
// public boolean isMotorWayLink() {
// int sz = types.length;
// for (int i = 0; i < sz; i++) {
// RouteTypeRule r = region.quickGetEncodingRule(types[i]);
// if (r.getTag().equals("highway") && r.getValue().equals("motorway_link")) {
// return true;
// }
// }
// return false;
// }
public String getExitName() {
if (pointNames != null && pointNameTypes != null) {
int pnSz = pointNames.length;
for (int i = 0; i < pnSz; i++) {
String[] point = pointNames[i];
if (point != null) {
int pSz = point.length;
for (int j = 0; j < pSz; j++) {
if (pointNameTypes[i][j] == region.nameTypeRule) {
return point[j];
}
}
}
}
}
return null;
}
public String getExitRef() {
if (pointNames != null && pointNameTypes != null) {
int pnSz = pointNames.length;
for (int i = 0; i < pnSz; i++) {
String[] point = pointNames[i];
if (point != null) {
int pSz = point.length;
for (int j = 0; j < pSz; j++) {
if (pointNameTypes[i][j] == region.refTypeRule) {
return point[j];
}
}
}
}
}
return null;
}
public int getOneway() {
int sz = types.length;
for (int i = 0; i < sz; i++) {

View file

@ -629,6 +629,7 @@ public class OsmandRegions {
return;
}
WorldRegion world = new WorldRegion(WorldRegion.WORLD);
initWorldRegion(world, WorldRegion.ANTARCTICA_REGION_ID);
initWorldRegion(world, WorldRegion.AFRICA_REGION_ID);
initWorldRegion(world, WorldRegion.ASIA_REGION_ID);
initWorldRegion(world, WorldRegion.CENTRAL_AMERICA_REGION_ID);
@ -690,31 +691,21 @@ public class OsmandRegions {
}
}
public List<WorldRegion> getWoldRegionsAt(LatLon latLon) throws IOException {
List<WorldRegion> result = new ArrayList<>();
List<BinaryMapDataObject> mapDataObjects = getBinaryMapDataObjectsAt(latLon);
for (BinaryMapDataObject obj : mapDataObjects) {
String fullName = getFullName(obj);
if (fullName != null) {
WorldRegion reg = getRegionData(fullName);
if (reg != null) {
result.add(reg);
}
}
}
return result;
public List<WorldRegion> getWorldRegionsAt(LatLon latLon) throws IOException {
Map<WorldRegion, BinaryMapDataObject> mapDataObjects = getBinaryMapDataObjectsWithRegionsAt(latLon);
return new ArrayList<>(mapDataObjects.keySet());
}
public BinaryMapDataObject getSmallestBinaryMapDataObjectAt(LatLon latLon) throws IOException {
List<BinaryMapDataObject> mapDataObjects = getBinaryMapDataObjectsAt(latLon);
return getSmallestBinaryMapDataObjectAt(mapDataObjects);
public Map.Entry<WorldRegion, BinaryMapDataObject> getSmallestBinaryMapDataObjectAt(LatLon latLon) throws IOException {
Map<WorldRegion, BinaryMapDataObject> mapDataObjectsWithRegions = getBinaryMapDataObjectsWithRegionsAt(latLon);
return getSmallestBinaryMapDataObjectAt(mapDataObjectsWithRegions);
}
public BinaryMapDataObject getSmallestBinaryMapDataObjectAt(List<BinaryMapDataObject> mapDataObjects) {
BinaryMapDataObject res = null;
public Map.Entry<WorldRegion, BinaryMapDataObject> getSmallestBinaryMapDataObjectAt(Map<WorldRegion, BinaryMapDataObject> mapDataObjectsWithRegions) {
Map.Entry<WorldRegion, BinaryMapDataObject> res = null;
double smallestArea = -1;
for (BinaryMapDataObject o : mapDataObjects) {
double area = OsmandRegions.getArea(o);
for (Map.Entry<WorldRegion, BinaryMapDataObject> o : mapDataObjectsWithRegions.entrySet()) {
double area = OsmandRegions.getArea(o.getValue());
if (smallestArea == -1) {
smallestArea = area;
res = o;
@ -726,10 +717,10 @@ public class OsmandRegions {
return res;
}
private List<BinaryMapDataObject> getBinaryMapDataObjectsAt(LatLon latLon) throws IOException {
private Map<WorldRegion, BinaryMapDataObject> getBinaryMapDataObjectsWithRegionsAt(LatLon latLon) throws IOException {
int point31x = MapUtils.get31TileNumberX(latLon.getLongitude());
int point31y = MapUtils.get31TileNumberY(latLon.getLatitude());
Map<WorldRegion, BinaryMapDataObject> foundObjects = new LinkedHashMap<>();
List<BinaryMapDataObject> mapDataObjects;
try {
mapDataObjects = queryBboxNoInit(point31x, point31x, point31y, point31y, true);
@ -742,25 +733,18 @@ public class OsmandRegions {
while (it.hasNext()) {
BinaryMapDataObject o = it.next();
if (o.getTypes() != null) {
boolean isRegion = true;
for (int i = 0; i < o.getTypes().length; i++) {
TagValuePair tp = o.getMapIndex().decodeType(o.getTypes()[i]);
if ("boundary".equals(tp.value)) {
isRegion = false;
break;
}
}
WorldRegion downloadRegion = getRegionData(getFullName(o));
if (!isRegion
|| downloadRegion == null
if ( downloadRegion == null
|| !downloadRegion.isRegionMapDownload()
|| !contain(o, point31x, point31y)) {
it.remove();
} else {
foundObjects.put(downloadRegion, o);
}
}
}
}
return mapDataObjects;
return foundObjects;
}

View file

@ -15,10 +15,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.ArrayList;
@ -26,23 +24,22 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import bsh.Interpreter;
public class TileSourceManager {
private static final Log log = PlatformUtil.getLog(TileSourceManager.class);
public static final String RULE_BEANSHELL = "beanshell";
public static final String RULE_YANDEX_TRAFFIC = "yandex_traffic";
private static final String RULE_WMS = "wms_tile";
private static final String RULE_TEMPLATE_1 = "template:1";
private static final String RND_ALG_WIKIMAPIA = "wikimapia";
private static final TileSourceTemplate MAPNIK_SOURCE =
new TileSourceTemplate("OsmAnd (online tiles)", "https://tile.osmand.net/hd/{0}/{1}/{2}.png", ".png", 19, 1, 512, 8, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
private static final TileSourceTemplate CYCLE_MAP_SOURCE =
new TileSourceTemplate("CycleMap", "https://b.tile.thunderforest.com/cycle/{0}/{1}/{2}.png?apikey=a778ae1a212641d38f46dc11f20ac116", ".png", 16, 1, 256, 32, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
private static final TileSourceTemplate MAPILLARY_RASTER_SOURCE =
new TileSourceTemplate("Mapillary (raster tiles)", "https://d6a1v2w10ny40.cloudfront.net/v0.1/{0}/{1}/{2}.png", ".png", 13, 0, 256, 16, 32000);
new TileSourceTemplate("Mapillary (raster tiles)", "https://d6a1v2w10ny40.cloudfront.net/v0.1/{0}/{1}/{2}.png", ".png", 16, 0, 256, 16, 32000);
private static final TileSourceTemplate MAPILLARY_VECTOR_SOURCE =
new TileSourceTemplate("Mapillary (vector tiles)", "https://d25uarhxywzl1j.cloudfront.net/v0.1/{0}/{1}/{2}.mvt", ".mvt", 21, 14, 256, 16, 3200);
new TileSourceTemplate("Mapillary (vector tiles)", "https://d25uarhxywzl1j.cloudfront.net/v0.1/{0}/{1}/{2}.mvt", ".mvt", 21, 17, 256, 16, 3200);
static {
MAPILLARY_RASTER_SOURCE.setExpirationTimeMinutes(60 * 24);
@ -51,6 +48,9 @@ public class TileSourceManager {
MAPILLARY_VECTOR_SOURCE.setHidden(true);
}
private static final String PARAM_BING_QUAD_KEY = "{q}";
private static final String PARAM_RND = "{rnd}";
public static class TileSourceTemplate implements ITileSource, Cloneable {
private int maxZoom;
private int minZoom;
@ -63,6 +63,9 @@ public class TileSourceManager {
// -1 never expires,
private long expirationTimeMillis = -1;
private boolean ellipticYTile;
private boolean invertedYTile;
private String randoms;
private String[] randomsArray;
private String rule;
private boolean hidden; // if hidden in configure map settings, for example mapillary sources
@ -79,15 +82,65 @@ public class TileSourceManager {
this.avgSize = avgSize;
this.bitDensity = bitDensity;
}
public static String normalizeUrl(String url){
if(url != null){
url = url.replaceAll("\\{\\$z\\}", "{0}"); //$NON-NLS-1$ //$NON-NLS-2$
url = url.replaceAll("\\{\\$x\\}", "{1}"); //$NON-NLS-1$//$NON-NLS-2$
url = url.replaceAll("\\{\\$y\\}", "{2}"); //$NON-NLS-1$ //$NON-NLS-2$
public static String normalizeUrl(String url) {
if (url != null) {
url = url.replaceAll("\\{\\$z\\}", "{0}");
url = url.replaceAll("\\{\\$x\\}", "{1}");
url = url.replaceAll("\\{\\$y\\}", "{2}");
url = url.replaceAll("\\{z\\}", "{0}");
url = url.replaceAll("\\{x\\}", "{1}");
url = url.replaceAll("\\{y\\}", "{2}");
}
return url;
}
public static String[] buildRandomsArray(String randomsStr) {
List<String> randoms = new ArrayList<>();
if (!Algorithms.isEmpty(randomsStr)) {
if (randomsStr.equals(RND_ALG_WIKIMAPIA)) {
return new String[]{RND_ALG_WIKIMAPIA};
}
String[] valuesArray = randomsStr.split(",");
for (String s : valuesArray) {
String[] rangeArray = s.split("-");
if (rangeArray.length == 2) {
String s1 = rangeArray[0];
String s2 = rangeArray[1];
boolean rangeValid = false;
try {
int a = Integer.parseInt(s1);
int b = Integer.parseInt(s2);
if (b > a) {
for (int i = a; i <= b; i++) {
randoms.add(String.valueOf(i));
}
rangeValid = true;
}
} catch (NumberFormatException e) {
if (s1.length() == 1 && s2.length() == 1) {
char a = s1.charAt(0);
char b = s2.charAt(0);
if (b > a) {
for (char i = a; i <= b; i++) {
randoms.add(String.valueOf(i));
}
rangeValid = true;
}
}
}
if (!rangeValid) {
randoms.add(s1);
randoms.add(s2);
}
} else {
randoms.add(s);
}
}
}
return randoms.toArray(new String[randoms.size()]);
}
public void setMinZoom(int minZoom) {
this.minZoom = minZoom;
}
@ -117,6 +170,31 @@ public class TileSourceManager {
return ellipticYTile;
}
public boolean isInvertedYTile() {
return invertedYTile;
}
public void setInvertedYTile(boolean invertedYTile) {
this.invertedYTile = invertedYTile;
}
public String getRandoms() {
return randoms;
}
public void setRandoms(String randoms) {
this.randoms = randoms;
this.randomsArray = buildRandomsArray(randoms);
}
public String[] getRandomsArray() {
return randomsArray;
}
public void setRandomsArray(String[] randomsArray) {
this.randomsArray = randomsArray;
}
@Override
public int getBitDensity() {
return bitDensity;
@ -208,9 +286,53 @@ public class TileSourceManager {
if (urlToLoad == null) {
return null;
}
return MessageFormat.format(urlToLoad, zoom + "", x + "", y + ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (isInvertedYTile()) {
y = (1 << zoom) - 1 - y;
}
return buildUrlToLoad(urlToLoad, randomsArray, x, y, zoom);
}
private static String eqtBingQuadKey(int z, int x, int y) {
char[] NUM_CHAR = {'0', '1', '2', '3'};
char[] tn = new char[z];
for (int i = z - 1; i >= 0; i--) {
int num = (x % 2) | ((y % 2) << 1);
tn[i] = NUM_CHAR[num];
x >>= 1;
y >>= 1;
}
return new String(tn);
}
public static String buildUrlToLoad(String urlTemplate, String[] randomsArray, int x, int y, int zoom) {
try {
if (randomsArray != null && randomsArray.length > 0) {
String rand;
if (RND_ALG_WIKIMAPIA.equals(randomsArray[0])) {
rand = String.valueOf(x % 4 + (y % 4) * 4);
} else {
rand = randomsArray[(x + y) % randomsArray.length];
}
urlTemplate = urlTemplate.replace(PARAM_RND, rand);
} else if (urlTemplate.contains(PARAM_RND)) {
log.error("Cannot resolve randoms for template: " + urlTemplate);
return null;
}
int bingQuadKeyParamIndex = urlTemplate.indexOf(PARAM_BING_QUAD_KEY);
if (bingQuadKeyParamIndex != -1) {
return urlTemplate.replace(PARAM_BING_QUAD_KEY, eqtBingQuadKey(zoom, x, y));
}
return MessageFormat.format(urlTemplate, zoom + "", x + "", y + "");
} catch (IllegalArgumentException e) {
log.error("Cannot build url for template: " + urlTemplate, e);
return null;
}
}
public String getUrlTemplate() {
return urlToLoad;
}
@ -349,6 +471,12 @@ public class TileSourceManager {
if (tm.isEllipticYTile()) {
properties.put("ellipsoid", tm.isEllipticYTile() + "");
}
if (tm.isInvertedYTile()) {
properties.put("inverted_y", tm.isInvertedYTile() + "");
}
if (tm.getRandoms() != null) {
properties.put("randoms", tm.getRandoms());
}
if (tm.getExpirationTimeMinutes() != -1) {
properties.put("expiration_time_minutes", tm.getExpirationTimeMinutes() + "");
}
@ -390,12 +518,8 @@ public class TileSourceManager {
try {
if (readUrl.exists()) {
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(readUrl), "UTF-8")); //$NON-NLS-1$
new FileInputStream(readUrl), "UTF-8"));
url = reader.readLine();
//
//url = url.replaceAll("\\{\\$z\\}", "{0}"); //$NON-NLS-1$ //$NON-NLS-2$
//url = url.replaceAll("\\{\\$x\\}", "{1}"); //$NON-NLS-1$//$NON-NLS-2$
//url = url.replaceAll("\\{\\$y\\}", "{2}"); //$NON-NLS-1$ //$NON-NLS-2$
url = TileSourceTemplate.normalizeUrl(url);
reader.close();
}
@ -457,7 +581,7 @@ public class TileSourceManager {
final List<TileSourceTemplate> templates = new ArrayList<TileSourceTemplate>();
try {
URLConnection connection = NetworkUtils.getHttpURLConnection((https ? "https" : "http")
+ "://osmand.net/tile_sources?" + versionAsUrl);
+ "://test.osmand.net/tile_sources?" + versionAsUrl);
XmlPullParser parser = PlatformUtil.newXMLPullParser();
parser.setInput(connection.getInputStream(), "UTF-8");
int tok;
@ -487,12 +611,12 @@ public class TileSourceManager {
}
public static TileSourceTemplate createTileSourceTemplate(Map<String, String> attrs) {
TileSourceTemplate template = null;
TileSourceTemplate template;
String rule = attrs.get("rule");
if(rule == null){
if (rule == null){
template = createSimpleTileSourceTemplate(attrs, false);
} else if (RULE_TEMPLATE_1.equalsIgnoreCase(rule)) {
template = createSimpleTileSourceTemplate(attrs, false);
} else if(RULE_BEANSHELL.equalsIgnoreCase(rule)){
template = createBeanshellTileSourceTemplate(attrs);
} else if (RULE_WMS.equalsIgnoreCase(rule)) {
template = createWmsTileSourceTemplate(attrs);
} else if (RULE_YANDEX_TRAFFIC.equalsIgnoreCase(rule)) {
@ -521,8 +645,10 @@ public class TileSourceManager {
String ext = attributes.get("ext") == null ? ".jpg" : attributes.get("ext");
int bitDensity = parseInt(attributes, "img_density", 16);
int avgTileSize = parseInt(attributes, "avg_img_size", 18000);
String randoms = attributes.get("randoms");
urlTemplate = "http://whoots.mapwarper.net/tms/{0}/{1}/{2}/"+layer+"/"+urlTemplate;
TileSourceTemplate templ = new TileSourceTemplate(name, urlTemplate, ext, maxZoom, minZoom, tileSize, bitDensity, avgTileSize);
templ.setRandoms(randoms);
return templ;
}
@ -534,10 +660,7 @@ public class TileSourceManager {
if (name == null || (urlTemplate == null && !ignoreTemplate)) {
return null;
}
//As I see, here is no changes to urlTemplate
//if(urlTemplate != null){
//urlTemplate.replace("${x}", "{1}").replace("${y}", "{2}").replace("${z}", "{0}");
//}
urlTemplate = TileSourceTemplate.normalizeUrl(urlTemplate);
int maxZoom = parseInt(attributes, "max_zoom", 18);
@ -551,82 +674,18 @@ public class TileSourceManager {
if (Boolean.parseBoolean(attributes.get("ellipsoid"))) {
ellipsoid = true;
}
boolean invertedY = false;
if (Boolean.parseBoolean(attributes.get("inverted_y"))) {
invertedY = true;
}
String randoms = attributes.get("randoms");
TileSourceTemplate templ = new TileSourceTemplate(name, urlTemplate, ext, maxZoom, minZoom, tileSize, bitDensity, avgTileSize);
if(expirationTime >= 0) {
templ.setExpirationTimeMinutes(expirationTime);
}
templ.setEllipticYTile(ellipsoid);
templ.setInvertedYTile(invertedY);
templ.setRandoms(randoms);
return templ;
}
private static TileSourceTemplate createBeanshellTileSourceTemplate(Map<String, String> attributes) {
String name = attributes.get("name");
String urlTemplate = attributes.get("url_template");
if (name == null || urlTemplate == null) {
return null;
}
int maxZoom = parseInt(attributes, "max_zoom", 18);
int minZoom = parseInt(attributes, "min_zoom", 5);
int tileSize = parseInt(attributes, "tile_size", 256);
String ext = attributes.get("ext") == null ? ".jpg" : attributes.get("ext");
int bitDensity = parseInt(attributes, "img_density", 16);
int avgTileSize = parseInt(attributes, "avg_img_size", 18000);
int expirationTime = parseInt(attributes, "expiration_time_minutes", -1);
boolean ellipsoid = false;
if (Boolean.parseBoolean(attributes.get("ellipsoid"))) {
ellipsoid = true;
}
TileSourceTemplate templ;
templ = new BeanShellTileSourceTemplate(name, urlTemplate, ext, maxZoom, minZoom, tileSize, bitDensity, avgTileSize);
templ.setEllipticYTile(ellipsoid);
if(expirationTime > 0) {
templ.setExpirationTimeMinutes(expirationTime);
}
return templ;
}
public static class BeanShellTileSourceTemplate extends TileSourceTemplate {
Interpreter bshInterpreter;
public BeanShellTileSourceTemplate(String name, String urlToLoad, String ext,
int maxZoom, int minZoom, int tileSize, int bitDensity, int avgSize) {
super(name, urlToLoad, ext, maxZoom, minZoom, tileSize, bitDensity, avgSize);
bshInterpreter = new Interpreter();
try {
bshInterpreter.eval(urlToLoad);
bshInterpreter.getClassManager().setClassLoader(new ClassLoader() {
@Override
public URL getResource(String resName) {
return null;
}
@Override
public InputStream getResourceAsStream(String resName) {
return null;
}
@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
throw new ClassNotFoundException("Error requesting " + className);
}
});
} catch (bsh.EvalError e) {
log.error("Error executing the map init script " + urlToLoad, e);
}
}
@Override
public String getUrlToLoad(int x, int y, int zoom) {
try {
return (String) bshInterpreter.eval("getTileUrl("+zoom+","+x+","+y+");");
} catch (bsh.EvalError e) {
log.error(e.getMessage(), e);
return null;
}
}
}
}

View file

@ -10,6 +10,7 @@ import java.util.List;
public class WorldRegion implements Serializable {
public static final String WORLD_BASEMAP = "world_basemap";
public static final String ANTARCTICA_REGION_ID = "antarctica";
public static final String AFRICA_REGION_ID = "africa";
public static final String ASIA_REGION_ID = "asia";
public static final String AUSTRALIA_AND_OCEANIA_REGION_ID = "australia-oceania";

View file

@ -369,9 +369,10 @@ public class BinaryRoutePlanner {
public void printDebugMemoryInformation(RoutingContext ctx, PriorityQueue<RouteSegment> graphDirectSegments, PriorityQueue<RouteSegment> graphReverseSegments,
TLongObjectHashMap<RouteSegment> visitedDirectSegments,TLongObjectHashMap<RouteSegment> visitedOppositeSegments) {
printInfo("Time to calculate : " + (System.nanoTime() - ctx.timeToCalculate) / 1e6 +
", time to load : " + ctx.timeToLoad / 1e6 + ", time to load headers : " + ctx.timeToLoadHeaders / 1e6 +
", time to calc dev : " + ctx.timeNanoToCalcDeviation / 1e6);
printInfo(String.format("Time. Total: %.2f, to load: %.2f, to load headers: %.2f, to calc dev: %.2f, to calc rules: %.2f ",
(System.nanoTime() - ctx.timeToCalculate) / 1e6, ctx.timeToLoad / 1e6,
ctx.timeToLoadHeaders / 1e6, ctx.timeNanoToCalcDeviation / 1e6, GeneralRouter.TIMER / 1e6));
GeneralRouter.TIMER = 0;
int maxLoadedTiles = Math.max(ctx.maxLoadedTiles, ctx.getCurrentlyLoadedTiles());
printInfo("Current loaded tiles : " + ctx.getCurrentlyLoadedTiles() + ", maximum loaded tiles " + maxLoadedTiles);
printInfo("Loaded tiles " + ctx.loadedTiles + " (distinct " + ctx.distinctLoadedTiles + "), unloaded tiles " + ctx.unloadedTiles +

View file

@ -0,0 +1,25 @@
package net.osmand.router;
public class ExitInfo {
private String ref;
private String exitStreetName;
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
public String getExitStreetName() {
return exitStreetName;
}
public void setExitStreetName(String exitStreetName) {
this.exitStreetName = exitStreetName;
}
}

View file

@ -9,6 +9,7 @@ import net.osmand.util.MapUtils;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
@ -39,6 +40,9 @@ public class GeneralRouter implements VehicleRouter {
public static final String VEHICLE_HEIGHT = "height";
public static final String VEHICLE_WEIGHT = "weight";
public static final String VEHICLE_WIDTH = "width";
private static boolean USE_CACHE = true;
public static long TIMER = 0;
private final RouteAttributeContext[] objectAttributes;
public final Map<String, String> attributes;
@ -70,6 +74,7 @@ public class GeneralRouter implements VehicleRouter {
private TLongHashSet impassableRoads;
private GeneralRouterProfile profile;
Map<RouteRegion, Map<IntHolder, Float>>[] evalCache;
public enum RouteDataObjectAttribute {
ROAD_SPEED("speed"),
@ -111,41 +116,6 @@ public class GeneralRouter implements VehicleRouter {
SYMBOLIC
}
public GeneralRouter(GeneralRouterProfile profile, Map<String, String> attributes) {
this.profile = profile;
this.attributes = new LinkedHashMap<String, String>();
Iterator<Entry<String, String>> e = attributes.entrySet().iterator();
while(e.hasNext()){
Entry<String, String> next = e.next();
addAttribute(next.getKey(), next.getValue());
}
objectAttributes = new RouteAttributeContext[RouteDataObjectAttribute.values().length];
for (int i = 0; i < objectAttributes.length; i++) {
objectAttributes[i] = new RouteAttributeContext();
}
universalRules = new LinkedHashMap<String, Integer>();
universalRulesById = new ArrayList<String>();
tagRuleMask = new LinkedHashMap<String, BitSet>();
ruleToValue = new ArrayList<Object>();
parameters = new LinkedHashMap<String, GeneralRouter.RoutingParameter>();
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getProfileName() {
return profileName;
}
public void setProfileName(String profileName) {
this.profileName = profileName;
}
public GeneralRouter(GeneralRouter parent, Map<String, String> params) {
this.profile = parent.profile;
this.attributes = new LinkedHashMap<String, String>();
@ -180,8 +150,58 @@ public class GeneralRouter implements VehicleRouter {
if (params.containsKey(MAX_SPEED)) {
maxSpeed = parseSilentFloat(params.get(MAX_SPEED), maxSpeed);
}
initCaches();
}
public GeneralRouter(GeneralRouterProfile profile, Map<String, String> attributes) {
this.profile = profile;
this.attributes = new LinkedHashMap<String, String>();
Iterator<Entry<String, String>> e = attributes.entrySet().iterator();
while(e.hasNext()){
Entry<String, String> next = e.next();
addAttribute(next.getKey(), next.getValue());
}
objectAttributes = new RouteAttributeContext[RouteDataObjectAttribute.values().length];
for (int i = 0; i < objectAttributes.length; i++) {
objectAttributes[i] = new RouteAttributeContext();
}
universalRules = new LinkedHashMap<String, Integer>();
universalRulesById = new ArrayList<String>();
tagRuleMask = new LinkedHashMap<String, BitSet>();
ruleToValue = new ArrayList<Object>();
parameters = new LinkedHashMap<String, GeneralRouter.RoutingParameter>();
initCaches();
}
@SuppressWarnings("unchecked")
private void initCaches() {
int l = RouteDataObjectAttribute.values().length;
evalCache = new Map[l];
for (int i = 0; i < l; i++) {
evalCache[i] = new HashMap<>();
}
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getProfileName() {
return profileName;
}
public void setProfileName(String profileName) {
this.profileName = profileName;
}
public GeneralRouterProfile getProfile() {
return profile;
}
@ -243,7 +263,11 @@ public class GeneralRouter implements VehicleRouter {
@Override
public boolean acceptLine(RouteDataObject way) {
int res = getObjContext(RouteDataObjectAttribute.ACCESS).evaluateInt(way, 0);
Float res = getCache(RouteDataObjectAttribute.ACCESS, way);
if(res == null) {
res = (float) getObjContext(RouteDataObjectAttribute.ACCESS).evaluateInt(way, 0);
putCache(RouteDataObjectAttribute.ACCESS, way, res);
}
if(impassableRoads != null && impassableRoads.contains(way.id)) {
return false;
}
@ -333,7 +357,12 @@ public class GeneralRouter implements VehicleRouter {
public float defineObstacle(RouteDataObject road, int point) {
int[] pointTypes = road.getPointTypes(point);
if(pointTypes != null) {
return getObjContext(RouteDataObjectAttribute.OBSTACLES).evaluateFloat(road.region, pointTypes, 0);
Float obst = getCache(RouteDataObjectAttribute.OBSTACLES, road.region, pointTypes);
if(obst == null) {
obst = getObjContext(RouteDataObjectAttribute.OBSTACLES).evaluateFloat(road.region, pointTypes, 0);
putCache(RouteDataObjectAttribute.OBSTACLES, road.region, pointTypes, obst);
}
return obst;
}
return 0;
}
@ -342,7 +371,12 @@ public class GeneralRouter implements VehicleRouter {
public float defineRoutingObstacle(RouteDataObject road, int point) {
int[] pointTypes = road.getPointTypes(point);
if(pointTypes != null){
return getObjContext(RouteDataObjectAttribute.ROUTING_OBSTACLES).evaluateFloat(road.region, pointTypes, 0);
Float obst = getCache(RouteDataObjectAttribute.ROUTING_OBSTACLES, road.region, pointTypes);
if(obst == null) {
obst = getObjContext(RouteDataObjectAttribute.ROUTING_OBSTACLES).evaluateFloat(road.region, pointTypes, 0);
putCache(RouteDataObjectAttribute.ROUTING_OBSTACLES, road.region, pointTypes, obst);
}
return obst;
}
return 0;
}
@ -380,7 +414,12 @@ public class GeneralRouter implements VehicleRouter {
@Override
public int isOneWay(RouteDataObject road) {
return getObjContext(RouteDataObjectAttribute.ONEWAY).evaluateInt(road, 0);
Float res = getCache(RouteDataObjectAttribute.ONEWAY, road);
if(res == null) {
res = (float) getObjContext(RouteDataObjectAttribute.ONEWAY).evaluateInt(road, 0);
putCache(RouteDataObjectAttribute.ONEWAY, road, res);
}
return res.intValue();
}
@Override
@ -390,25 +429,96 @@ public class GeneralRouter implements VehicleRouter {
@Override
public float getPenaltyTransition(RouteDataObject road) {
return getObjContext(RouteDataObjectAttribute.PENALTY_TRANSITION).evaluateInt(road, 0);
Float vl = getCache(RouteDataObjectAttribute.PENALTY_TRANSITION, road);
if (vl == null) {
vl = (float) getObjContext(RouteDataObjectAttribute.PENALTY_TRANSITION).evaluateInt(road, 0);
putCache(RouteDataObjectAttribute.PENALTY_TRANSITION, road, vl);
}
return vl;
}
@Override
public float defineRoutingSpeed(RouteDataObject road) {
float spd = getObjContext(RouteDataObjectAttribute.ROAD_SPEED).evaluateFloat(road, defaultSpeed);
return Math.max(Math.min(spd, maxSpeed), minSpeed);
Float definedSpd = getCache(RouteDataObjectAttribute.ROAD_SPEED, road);
if (definedSpd == null) {
float spd = getObjContext(RouteDataObjectAttribute.ROAD_SPEED).evaluateFloat(road, defaultSpeed);
definedSpd = Math.max(Math.min(spd, maxSpeed), minSpeed);
putCache(RouteDataObjectAttribute.ROAD_SPEED, road, definedSpd);
}
return definedSpd;
}
@Override
public float defineVehicleSpeed(RouteDataObject road) {
float spd = getObjContext(RouteDataObjectAttribute.ROAD_SPEED).evaluateFloat(road, defaultSpeed);
return Math.max(Math.min(spd, maxSpeed), minSpeed);
Float sp = getCache(RouteDataObjectAttribute.ROAD_SPEED, road);
if (sp == null) {
float spd = getObjContext(RouteDataObjectAttribute.ROAD_SPEED).evaluateFloat(road, defaultSpeed);
sp = Math.max(Math.min(spd, maxSpeed), minSpeed);
putCache(RouteDataObjectAttribute.ROAD_SPEED, road, sp);
}
return sp;
}
@Override
public float defineSpeedPriority(RouteDataObject road) {
return getObjContext(RouteDataObjectAttribute.ROAD_PRIORITIES).evaluateFloat(road, 1f);
Float sp = getCache(RouteDataObjectAttribute.ROAD_PRIORITIES, road);
if(sp == null) {
sp = getObjContext(RouteDataObjectAttribute.ROAD_PRIORITIES).evaluateFloat(road, 1f);
putCache(RouteDataObjectAttribute.ROAD_PRIORITIES, road, sp);
}
return sp;
}
private void putCache(RouteDataObjectAttribute attr, RouteDataObject road, Float val) {
putCache(attr, road.region, road.types, val);
}
private void putCache(RouteDataObjectAttribute attr, RouteRegion reg, int[] types, Float val) {
Map<RouteRegion, Map<IntHolder, Float>> ch = evalCache[attr.ordinal()];
if (USE_CACHE) {
Map<IntHolder, Float> rM = ch.get(reg);
if (rM == null) {
rM = new HashMap<IntHolder, Float>();
ch.put(reg, rM);
}
rM.put(new IntHolder(types), val);
}
TIMER += System.nanoTime();
}
class IntHolder {
private final int[] array;
IntHolder(int[] ts) { array = ts; }
@Override public int hashCode() { return Arrays.hashCode(array); }
@Override public boolean equals(Object other) {
if (array == other) { return true; }
if (! (other instanceof IntHolder) ) {
return false;
}
//noinspection unchecked
return Arrays.equals(array, ((IntHolder) other).array);
}
}
private Float getCache(RouteDataObjectAttribute attr, RouteDataObject road) {
return getCache(attr, road.region, road.types);
}
private Float getCache(RouteDataObjectAttribute attr, RouteRegion reg, int[] types) {
Map<RouteRegion, Map<IntHolder, Float>> ch = evalCache[attr.ordinal()];
TIMER -= System.nanoTime();
if (USE_CACHE) {
Map<IntHolder, Float> rM = ch.get(reg);
if (rM == null) {
return null;
}
Float vl = rM.get(new IntHolder(types));
if(vl != null) {
TIMER += System.nanoTime();
return vl;
}
}
return null;
}
@Override
@ -669,7 +779,7 @@ public class GeneralRouter implements VehicleRouter {
}
public float evaluateFloat(RouteDataObject ro, float defValue) {
Object o = evaluate(ro);
Object o = evaluate(ro);
if(!(o instanceof Number)) {
return defValue;
}

View file

@ -1087,14 +1087,15 @@ public class RouteResultPreparation {
t = attachKeepLeftInfoAndLanes(leftSide, prev, rr);
}
if (t != null) {
t.setTurnAngle((float) -mpi);
t.setTurnAngle((float) - mpi);
}
}
return t;
}
private int[] getTurnLanesInfo(RouteSegmentResult prevSegm, int mainTurnType) { String turnLanes = getTurnLanesString(prevSegm);
int[] lanesArray ;
private int[] getTurnLanesInfo(RouteSegmentResult prevSegm, int mainTurnType) {
String turnLanes = getTurnLanesString(prevSegm);
int[] lanesArray;
if (turnLanes == null) {
if(prevSegm.getTurnType() != null && prevSegm.getTurnType().getLanes() != null
&& prevSegm.getDistance() < 100) {
@ -1739,8 +1740,10 @@ public class RouteResultPreparation {
}
};
} else {
RouteSegment rt = ctx.loadRouteSegment(road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd), ctx.config.memoryLimitation);
it = rt == null ? null : rt.getIterator();
// Here we assume that all segments should be attached by native
it = null;
// RouteSegment rt = ctx.loadRouteSegment(road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd), ctx.config.memoryLimitation);
// it = rt == null ? null : rt.getIterator();
}
// try to attach all segments except with current id
while (it != null && it.hasNext()) {

View file

@ -133,6 +133,17 @@ public class RoutingConfiguration {
}
public String getRoutingProfileKeyByFileName(String fileName) {
if (fileName != null && routers != null) {
for (Map.Entry<String, GeneralRouter> router : routers.entrySet()) {
if (fileName.equals(router.getValue().getFilename())) {
return router.getKey();
}
}
}
return null;
}
public Map<String, GeneralRouter> getAllRouters() {
return routers;
}

View file

@ -299,7 +299,7 @@ public class MapAlgorithms {
* count the intersections when going from lat, lon to outside the ring
* @param polyNodes2
*/
private static int countIntersections(Collection<Node> polyNodes, double latitude, double longitude) {
public static int countIntersections(Collection<Node> polyNodes, double latitude, double longitude) {
int intersections = 0;
if (polyNodes.size() == 0)
return 0;

View file

@ -80,8 +80,6 @@ public class MapUtils {
// not very accurate computation on sphere but for distances < 1000m it is ok
double mDist = (fromLat - toLat) * (fromLat - toLat) + (fromLon - toLon) * (fromLon - toLon);
double projection = scalarMultiplication(fromLat, fromLon, toLat, toLon, lat, lon);
double prlat;
double prlon;
if (projection < 0) {
return 0;
} else if (projection >= mDist) {
@ -413,6 +411,16 @@ public class MapUtils {
}
return rotate;
}
public static float normalizeDegrees360(float degrees) {
while (degrees < 0.0f) {
degrees += 360.0f;
}
while (degrees >= 360.0f) {
degrees -= 360.0f;
}
return degrees;
}
/**
* @param diff align difference between 2 angles ]-PI, PI]
@ -619,6 +627,12 @@ public class MapUtils {
r.bottom = Math.min(r.bottom, latitude);
}
}
public static boolean areLatLonEqual(Location l1, Location l2) {
return l1 == null && l2 == null
|| (l1 != null && l2 != null && Math.abs(l1.getLatitude() - l2.getLatitude()) < 0.00001
&& Math.abs(l1.getLongitude() - l2.getLongitude()) < 0.00001);
}
}

View file

@ -17,6 +17,7 @@
"Parking fee: no (Charging station / Transportation)",
"Parking fee: yes (Charging station / Transportation)",
"Parking lot (Fire hydrant / Emergency infrastructure)",
"Parking space (Personal transport)",
"Parking tickets (Vending machine / Store)",
"Parking tickets (Vending machine / Store)",
"Parking time limit (Parking / Personal transport)",

View file

@ -15,7 +15,7 @@
android:name="net.osmand.telegram.TelegramApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:label="@string/app_name_short"
android:launchMode="singleTask"
android:screenOrientation="unspecified"
android:supportsRtl="true"

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

View file

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

View file

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -75,6 +75,35 @@
<include layout="@layout/list_item_divider"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="@dimen/list_header_height"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/units_and_formats"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium"/>
<LinearLayout
android:id="@+id/units_and_formats_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
<include layout="@layout/list_item_divider"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View file

@ -50,7 +50,7 @@
android:id="@+id/text_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/content_padding_standard"
android:layout_marginBottom="@dimen/content_padding_half"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:paddingLeft="@dimen/my_location_text_sides_margin"
@ -58,7 +58,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height">
android:layout_height="wrap_content">
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/title"
@ -66,6 +66,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:paddingTop="@dimen/app_bar_title_padding_small"
android:paddingBottom="@dimen/app_bar_title_padding_small"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
@ -295,6 +297,30 @@
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/bg_list_item_dark">
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/back_to_osmand"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:drawableStart="@drawable/ic_action_undo"
android:drawableLeft="@drawable/ic_action_undo"
android:drawablePadding="@dimen/my_location_text_sides_margin"
android:gravity="center_vertical"
android:minHeight="@dimen/list_item_height_min"
android:paddingStart="@dimen/content_padding_standard"
android:paddingLeft="@dimen/content_padding_standard"
android:text="@string/back_to_osmand"
android:textColor="?attr/colorPrimaryDark"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_regular" />
</FrameLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout

View file

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="?attr/card_bg_color">
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="@dimen/list_item_height"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="@dimen/list_item_icon_size_big"
android:layout_height="@dimen/list_item_icon_size_big"
android:layout_marginStart="@dimen/list_item_icon_margin_left"
android:layout_marginLeft="@dimen/list_item_icon_margin_left"
android:layout_marginEnd="@dimen/list_item_icon_margin_right"
android:layout_marginRight="@dimen/list_item_icon_margin_right"
tools:src="@drawable/img_user_picture" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:layout_weight="1"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_regular"
tools:text="Share to Share Location" />
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/list_item_description_text_size"
app:typeface="@string/font_roboto_regular"
tools:text="for 1 hour" />
</LinearLayout>
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="@dimen/dialog_button_height"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/image_button_padding"
android:layout_marginRight="@dimen/image_button_padding"
android:background="?attr/secondary_btn_bg"
android:gravity="center"
android:paddingLeft="@dimen/image_button_padding"
android:paddingRight="@dimen/image_button_padding"
android:text="@string/shared_string_start"
android:textColor="?attr/ctrl_active_color"
android:textSize="@dimen/text_button_text_size"
app:typeface="@string/font_roboto_medium"
tools:text="Start" />
</LinearLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:background="?attr/card_divider_color"
android:visibility="gone"
tools:visibility="visible" />
</FrameLayout>
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:id="@+id/divider_top"
android:layout_width="match_parent"
android:layout_height="26dp" />
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/shared_chat_card_bg"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="54dp"
android:gravity="start|center_vertical"
android:paddingStart="@dimen/content_padding_standard"
android:paddingLeft="@dimen/content_padding_half"
android:paddingRight="@dimen/content_padding_half"
android:text="@string/shared_string_suggested"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/hint_text_size"
app:typeface="@string/font_roboto_mono_bold"
tools:text="Suggested" />
<LinearLayout
android:id="@+id/last_items_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
<View
android:id="@+id/divider_bottom"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/card_divider_color"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>

View file

@ -1,2 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="time_zone">المنطقة الزمنية</string>
</resources>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="km_h">كم/س</string>
<string name="shared_string_ok">حسناً</string>
<string name="shared_string_ok">موافق</string>
<string name="timeline_available_for_free_now">الجدول الزمني ميزة متوفرة الآن مجانا.</string>
<string name="disable_monitoring">تعطيل العرض</string>
<string name="location_recording_enabled">تسجيل الموقع ممكن</string>
@ -10,8 +10,63 @@
<string name="shared_string_telegram">تيليجرام</string>
<string name="privacy_policy_use_telegram">يستخدم تيليجرام (تطبيق المراسلة) للاتصال والتواصل مع الأشخاص.</string>
<string name="shared_string_later">لاحقا</string>
<string name="osmand_service">وضع الخلفية</string>
<string name="nm_h">م.بح/س</string>
<string name="osmand_service">حالة وضع السكون</string>
<string name="nm_h">ميل بحري</string>
<string name="si_nm_h">ميل بحري في الساعة (عقدة)</string>
<string name="si_km_m">كم/م</string>
<string name="si_km_m">كم ، متر</string>
<string name="shared_string_end">نهاية</string>
<string name="saved_messages">الرسائل المحفوظة</string>
<string name="shared_string_update">تحديث</string>
<string name="average_altitude">متوسط الارتفاع</string>
<string name="average_speed">متوسط السرعة</string>
<string name="shared_string_map">إدارة الخرائط</string>
<string name="shared_string_add">إضافة</string>
<string name="shared_string_hide">إخفاء</string>
<string name="shared_string_status">الحالة</string>
<string name="shared_string_disable">تعطيل</string>
<string name="shared_string_save">حفظ</string>
<string name="shared_string_name">الاسم</string>
<string name="by_name">بالاسم</string>
<string name="shared_string_sort">فرز</string>
<string name="shared_string_exit">مخرج</string>
<string name="shared_string_close">إغلاق</string>
<string name="shared_string_all">الكل</string>
<string name="shared_string_off">إيقاف</string>
<string name="shared_string_install">تثبيت</string>
<string name="shared_string_share">مشاركة</string>
<string name="shared_string_back">عودة</string>
<string name="shared_string_password">كلمة المرور</string>
<string name="shared_string_continue">استمرار</string>
<string name="shared_string_cancel">إلغاء</string>
<string name="shared_string_settings">الإعدادات</string>
<string name="shared_string_distance">المسافة</string>
<string name="yard">ياردة</string>
<string name="foot">قدم</string>
<string name="mile">ميل</string>
<string name="km">كلم</string>
<string name="m">م</string>
<string name="nm">ميل بحري</string>
<string name="min_mile">د/م</string>
<string name="min_km">د/كم</string>
<string name="m_s">م/ث</string>
<string name="mile_per_hour">ميل ساعة</string>
<string name="si_kmh">كم/س</string>
<string name="si_mph">ميل ساعة</string>
<string name="si_m_s">م/ث</string>
<string name="si_min_km">دقيقة/كم</string>
<string name="si_min_m">دقيقة/ميل</string>
<string name="si_mi_feet">ميل ، قدم</string>
<string name="si_mi_yard">ميل ، ياردة</string>
<string name="si_nm">ميل بحري</string>
<string name="si_mi_meters">ميل ، متر</string>
<string name="shared_string_search">بحث</string>
<string name="altitude">الارتفاع</string>
<string name="shared_string_enable">تفعيل</string>
<string name="shared_string_select">تحديد</string>
<string name="shared_string_start">بدء</string>
<string name="shared_string_apply">تطبيق</string>
<string name="shared_string_enabled">مفعل</string>
<string name="units_and_formats">الوحدات والأشكال</string>
<string name="unit_of_length_descr">اختيار الوحدات: كم، ميل، ميل بحري.. إلخ.</string>
<string name="unit_of_length">وحدات الطول</string>
</resources>

View file

@ -32,7 +32,7 @@
<string name="last_available_location">Апошняе даступнае месца</string>
<string name="sharing_status">"Статус абмену "</string>
<string name="location_sharing_status">Абмен: %1$s</string>
<string name="shared_string_enabled">Уключаны</string>
<string name="shared_string_enabled">Уключана</string>
<string name="shared_string_status">Статус</string>
<string name="no_gps_connection">Злучэнне з GPS адсутнічае</string>
<string name="no_internet_connection">Злучэнне з Інтэрнэтам адсутнічае</string>
@ -250,4 +250,17 @@
<string name="shared_string_apply">Ужыць</string>
<string name="set_time_timeline_descr">Абраць час для паказу</string>
<string name="start_end_date">Пачатак - дата завяршэння</string>
<string name="saved_messages">Захаваныя паведамленні</string>
<string name="time_zone_descr">Абярыце часавы пояс, каб паказваць ваш час у паведамленнях.</string>
<string name="time_zone">Часавы пояс</string>
<string name="units_and_formats">Адзінкі вымярэння і фарматы</string>
<string name="unit_of_length_descr">Змяніць адзінкі вымярэння адлегласці.</string>
<string name="unit_of_length">Адзінкі даўжыні</string>
<string name="unit_of_speed_system_descr">Вызначце адзінку вымярэння хуткасці.</string>
<string name="unit_of_speed_system">Адзінка вымярэння хуткасці</string>
<string name="buffer_time_descr">Максімальны час захоўвання пунктаў у буферы</string>
<string name="buffer_time">Час дзеяння буферу</string>
<string name="shared_string_suggested">Прапанавана</string>
<string name="status_widget_title">Статус OsmAnd Tracker</string>
<string name="back_to_osmand">Вярнуцца ў OsmAnd</string>
</resources>

View file

@ -46,7 +46,7 @@
<string name="closing">S\'està tancant</string>
<string name="app_name_short">Rastrejador OsmAnd</string>
<string name="privacy_policy_telegram_client">El rastrejador d\'OsmAnd és un dels clients que usen la plataforma oberta de Telegram. Els vostres contactes poden usar qualsevol altra client de Telegram.</string>
<string name="privacy_policy_agree">En fer clic a continuar, accepteu les condicions de la Política de Privadesa de Telegram i de la Política de Privadesa d\'OsmAnd.</string>
<string name="privacy_policy_agree">En clicar \"Continua\" accepteu les condicions de les polítiques de privadesa de Telegram i d\'OsmAnd.</string>
<string name="shared_string_accept">D\'acord</string>
<string name="telegram_privacy_policy">Política de Privadesa de Telegram</string>
<string name="osmand_privacy_policy">Política de Privadesa d\'OsmAnd</string>
@ -250,4 +250,17 @@
<string name="shared_string_apply">Aplica</string>
<string name="set_time_timeline_descr">Seleccioneu la durada a mostrar</string>
<string name="start_end_date">Data d\' Inici — Fi</string>
<string name="saved_messages">Missatges desats</string>
<string name="time_zone_descr">Seleccioneu fus horari per mostrar en els vostres missatges d\'ubicació.</string>
<string name="time_zone">Fus horari</string>
<string name="units_and_formats">Unitats i formats</string>
<string name="unit_of_length_descr">Canvieu en què es mesuren les distàncies.</string>
<string name="unit_of_length">Unitats de longitud</string>
<string name="unit_of_speed_system_descr">Establiu la unitat de velocitat.</string>
<string name="unit_of_speed_system">Unitat de velocitat</string>
<string name="buffer_time_descr">Temps màxim per mantenir punts a la memòria intermèdia</string>
<string name="buffer_time">Temps de caducitat de la memòria intermèdia</string>
<string name="shared_string_suggested">Suggeriment</string>
<string name="status_widget_title">Estat de l\'enregistrador d\'OsmAnd</string>
<string name="back_to_osmand">Torna a OsmAnd</string>
</resources>

View file

@ -204,7 +204,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (besked app) bruges til at forbinde og kommunikere med mennesker.</string>
<string name="privacy_policy_telegram_client">OsmAnd Tracker er en af de klienter, der bruger den åbne Telegram platform. Kontaktpersoner kan bruge enhver anden Telegram klient.</string>
<string name="privacy_policy_agree">Ved at klikke på fortsæt accepteres betingelserne i Telegram Privacy Policy og OsmAnd Privacy Policy.</string>
<string name="privacy_policy_agree">Ved at klikke på \"Fortsæt\" accepteres betingelserne i Telegram- og OsmAnd privatlivspolitik.</string>
<string name="shared_string_accept">Accepter</string>
<string name="telegram_privacy_policy">Telegram privatlivspolitik</string>
<string name="osmand_privacy_policy">OsmAnd privatlivspolitik</string>
@ -250,4 +250,17 @@
<string name="shared_string_apply">Anvend</string>
<string name="set_time_timeline_descr">Vælg tid at vise</string>
<string name="start_end_date">Start — slutdato</string>
<string name="saved_messages">Gemte beskeder</string>
<string name="time_zone_descr">Vælg tidszone, der skal vises i placeringsbeskeder.</string>
<string name="time_zone">Tidszone</string>
<string name="units_and_formats">Enheder &amp; formater</string>
<string name="unit_of_length">Længdeenheder</string>
<string name="unit_of_speed_system_descr">Vælg enhed for hastighed.</string>
<string name="unit_of_speed_system">Hastighed</string>
<string name="buffer_time_descr">Maksimal tid til lagring af punkter i bufferen</string>
<string name="buffer_time">Buffer udløbstid</string>
<string name="unit_of_length_descr">Ændr enhed for afstand.</string>
<string name="shared_string_suggested">Foreslået</string>
<string name="status_widget_title">OsmAnd Tracker-status</string>
<string name="back_to_osmand">Tilbage til OsmAnd</string>
</resources>

View file

@ -35,7 +35,7 @@
<string name="shared_string_close">Schließen</string>
<string name="connected_account">Verbundenes Konto</string>
<string name="shared_string_account">Konto</string>
<string name="in_time">"in %1$s "</string>
<string name="in_time">in %1$s</string>
<string name="osmand_connect_desc">Wählen Sie die OsmAnd-Version, die OsmAnd Tracker verwendet, um Positionen anzuzeigen.</string>
<string name="osmand_connect">OsmAnd verbinden</string>
<string name="location_history_desc">Blendet Kontakte aus, die sich eine bestimmte Zeit lang nicht bewegt haben.</string>
@ -199,18 +199,18 @@
<string name="privacy_policy_use_telegram">Telegram (die Messaging-App) wird verwendet, um sich mit Menschen zu verbinden und mit ihnen zu kommunizieren.</string>
<string name="shared_string_ok">OK</string>
<string name="location_recording_enabled">Standortaufzeichnung aktiviert</string>
<string name="app_name_short">OsmAnd-Tracker</string>
<string name="app_name_short">OsmAnd Tracker</string>
<string name="shared_string_accept">Akzeptieren</string>
<string name="telegram_privacy_policy">Telegram-Datenschutzerklärung</string>
<string name="osmand_privacy_policy">OsmAnd Datenschutzerklärung</string>
<string name="how_it_works">Wie es funktioniert</string>
<string name="received_gps_points">GPX-Punkte erhalten: %1$s</string>
<string name="received_gps_points">Empfangene GPS-Punkte: %1$s</string>
<string name="shared_string_appearance">Aussehen</string>
<string name="show_gps_points">GPS-Punkte anzeigen</string>
<string name="disable_monitoring">Aufzeichnung deaktivieren</string>
<string name="timeline_description">Aufzeichnung aktivieren, um den Standortverlauf zu speichern.</string>
<string name="show_gps_points_descr">Anzahl gesammelter und gesendeter GPS-Punkte anzeigen.</string>
<string name="privacy_policy_agree">Wenn Sie fortfahren, willigen Sie in die Bedingungen der Datenschutzerklärungen von Telegram und OsmAnd ein.</string>
<string name="privacy_policy_agree">Wenn Sie auf \"Fortfahren\" klicken, willigen Sie in die Bedingungen der Datenschutzerklärungen von Telegram und OsmAnd ein.</string>
<string name="privacy_policy_telegram_client">Osmand Tracker ist eine der Apps die Telegrams offene Plattform nutzt. Ihre Kontake können beliebige andere Telegram-Apps nutzen.</string>
<string name="timeline_available_for_free_now">Die Timeline ist eine Funktion, die jetzt kostenlos zur Verfügung steht.</string>
<string name="search_contacts">Kontakte suchen</string>
@ -250,4 +250,17 @@
<string name="start_end_date">Start — Ende Datum</string>
<string name="shared_string_apply">Anwenden</string>
<string name="set_time_timeline_descr">Dauer der Anzeige auswählen</string>
<string name="saved_messages">Gespeicherte Nachrichten</string>
<string name="time_zone">Zeitzone</string>
<string name="units_and_formats">Einheiten und Formate</string>
<string name="unit_of_length">Längeneinheiten</string>
<string name="unit_of_speed_system_descr">Geschwindigkeitseinheit festlegen.</string>
<string name="unit_of_speed_system">Geschwindigkeitseinheit</string>
<string name="time_zone_descr">Wählen Sie die Zeitzone aus, die in Ihren Standortmeldungen angezeigt werden soll.</string>
<string name="unit_of_length_descr">Maß für Entfernungen ändern.</string>
<string name="buffer_time_descr">Maximale Zeit zum Speichern von Punkten im Puffer</string>
<string name="buffer_time">Verfallszeit des Puffers</string>
<string name="shared_string_suggested">Empfohlen</string>
<string name="status_widget_title">OsmAnd Tracker-Status</string>
<string name="back_to_osmand">Zurück zu OsmAnd</string>
</resources>

View file

@ -1,2 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="shared_string_ok">Εντάξει</string>
<string name="shared_string_update">Ενημέρωση</string>
<string name="shared_string_map">Χάρτης</string>
<string name="shared_string_add">Προσθήκη</string>
<string name="shared_string_hide">Απόκρυψη</string>
<string name="shared_string_save">Αποθήκευση</string>
<string name="shared_string_sort">Ταξινόμηση</string>
<string name="km">χλμ</string>
<string name="m">μ</string>
<string name="nm">ναυτικό μίλι</string>
<string name="min_mile">λεπτά/μίλι</string>
<string name="min_km">λεπτά/χιλιόμετρο</string>
<string name="m_s">μέτρα/δευτερόλεπτο</string>
<string name="km_h">χλμ/ω</string>
<string name="si_kmh">Χιλιόμετρα ανά ώρα</string>
<string name="si_mph">Μίλια ανά ώρα</string>
<string name="si_m_s">Μέτρα ανά δευτερόλεπτο</string>
<string name="si_min_km">Λεπτά ανά χιλιόμετρο</string>
<string name="si_min_m">Λεπτά ανά μίλι</string>
<string name="si_nm">Ναυτικά μίλια</string>
<string name="si_mi_meters">Μίλια/μέτρα</string>
<string name="shared_string_all">Όλα</string>
<string name="altitude">Υψόμετρο</string>
<string name="shared_string_name">Όνομα</string>
<string name="osmand_service">Κατάσταση παρασκηνίου</string>
<string name="shared_string_apply">Εφαρμογή</string>
<string name="shared_string_select">Επιλέξτε</string>
<string name="shared_string_enable">Ενεργοποίηση</string>
<string name="shared_string_search">Αναζήτηση</string>
<string name="average_altitude">Μέσο υψόμετρο</string>
<string name="average_speed">Μέση ταχύτητα</string>
<string name="shared_string_status">Κατάσταση</string>
<string name="shared_string_disable">Απενεργοποίηση</string>
<string name="shared_string_close">Κλείσιμο</string>
<string name="shared_string_off">Ανενεργό</string>
<string name="shared_string_install">Εγκατάσταση</string>
<string name="shared_string_share">Διαμοιρασμός</string>
<string name="shared_string_back">Προηγούμενο</string>
<string name="shared_string_continue">Συνέχεια</string>
<string name="shared_string_cancel">Ακύρωση</string>
<string name="shared_string_settings">Επιλογές</string>
<string name="shared_string_enabled">Ενεργοποιημένο</string>
<string name="units_and_formats">Μονάδες μέτρησης &amp; φορμά</string>
</resources>

View file

@ -197,7 +197,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (la aplicación de mensajería) se utiliza para conectar y comunicar a las personas.</string>
<string name="privacy_policy_telegram_client">El rastreador de OsmAnd (en inglés como «OsmAnd Tracker»), es uno de los clientes que utiliza la plataforma abierta de Telegram. Sus contactos pueden utilizar cualquier otro cliente de Telegram.</string>
<string name="privacy_policy_agree">Al pulsar en continuar, acepta las Políticas de Privacidad de Telegram y de OsmAnd.</string>
<string name="privacy_policy_agree">Al pulsar en «Continuar», acepta las Políticas de Privacidad de Telegram y de OsmAnd.</string>
<string name="shared_string_accept">Aceptar</string>
<string name="telegram_privacy_policy">Política de privacidad de Telegram</string>
<string name="osmand_privacy_policy">Política de privacidad de OsmAnd</string>
@ -249,4 +249,17 @@
<string name="shared_string_apply">Aplicar</string>
<string name="set_time_timeline_descr">Elige la hora de visualización</string>
<string name="start_end_date">Fecha de inicio — fin</string>
<string name="saved_messages">Mensajes guardados</string>
<string name="time_zone_descr">Marca la zona horaria que deseas que aparezca en los mensajes de ubicación.</string>
<string name="time_zone">Zona horaria</string>
<string name="units_and_formats">Unidades y formatos</string>
<string name="unit_of_length_descr">Cambia las unidades de longitud.</string>
<string name="unit_of_length">Unidades de longitud</string>
<string name="unit_of_speed_system_descr">Define la unidad de velocidad.</string>
<string name="unit_of_speed_system">Unidad de velocidad</string>
<string name="buffer_time_descr">Tiempo máximo para almacenar puntos en el búfer</string>
<string name="buffer_time">Tiempo de expiración del búfer</string>
<string name="shared_string_suggested">Sugerido</string>
<string name="status_widget_title">Estado de OsmAnd Tracker</string>
<string name="back_to_osmand">Volver a OsmAnd</string>
</resources>

View file

@ -12,7 +12,7 @@
<string name="last_available_location">Última ubicación disponible</string>
<string name="sharing_status">Estado de compartición</string>
<string name="location_sharing_status">Compartir: %1$s</string>
<string name="shared_string_enabled">Habilitado</string>
<string name="shared_string_enabled">Activado</string>
<string name="shared_string_status">Estado</string>
<string name="no_gps_connection">Sin conexión GPS</string>
<string name="no_internet_connection">Sin conexión a Internet</string>
@ -194,7 +194,7 @@
<string name="shared_string_sent">Enviado</string>
<string name="please_update_osmand">Actualice OsmAnd para ver datos en el mapa</string>
<string name="shared_string_update">Actualizar</string>
<string name="shared_string_ok">Aplicar</string>
<string name="shared_string_ok">Aceptar</string>
<string name="timeline_available_for_free_now">La línea de tiempo es una función disponible ahora de forma gratuita.</string>
<string name="disable_monitoring">Desactivar la monitorización</string>
<string name="location_recording_enabled">Grabación de ubicación activada</string>
@ -203,7 +203,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (la aplicación de mensajería) se utiliza para conectar y comunicar a las personas.</string>
<string name="privacy_policy_telegram_client">El rastreador de OsmAnd (en inglés como «OsmAnd Tracker»), es uno de los clientes que utiliza la plataforma abierta de Telegram. Sus contactos pueden utilizar cualquier otro cliente de Telegram.</string>
<string name="privacy_policy_agree">Al pulsar en continuar, acepta las Políticas de Privacidad de Telegram y de OsmAnd.</string>
<string name="privacy_policy_agree">Al hacer clic en \"Continuar\", aceptas las condiciones de la política de privacidad de Telegram- y OsmAnd.</string>
<string name="shared_string_accept">Aceptar</string>
<string name="telegram_privacy_policy">Política de privacidad de Telegram</string>
<string name="osmand_privacy_policy">Política de privacidad de OsmAnd</string>
@ -249,4 +249,22 @@
<string name="shared_string_start">Inicio</string>
<string name="set_time_timeline_descr">Elige la hora de visualización</string>
<string name="start_end_date">Fecha de Inicio — Fin</string>
<string name="saved_messages">Mensajes guardados</string>
<string name="time_zone_descr">Seleccione la zona horaria que desea mostrar en los mensajes de ubicación.</string>
<string name="time_zone">Zona horaria</string>
<string name="units_and_formats">Unidades y formatos</string>
<string name="unit_of_length_descr">Cambia las unidades de longitud.</string>
<string name="unit_of_length">Unidades de longitud</string>
<string name="unit_of_speed_system_descr">Definir la unidad de velocidad.</string>
<string name="unit_of_speed_system">Unidad de velocidad</string>
<string name="buffer_time_descr">Tiempo después del cual se eliminarán los mensajes de ubicación almacenados en búfer</string>
<string name="buffer_time">Tiempo de expiración del búfer</string>
<string name="shared_string_suggested">Sugerido</string>
<string name="status_widget_title">Estado de OsmAnd Tracker</string>
<string name="back_to_osmand">Volver a OsmAnd</string>
<string name="last_update_from_telegram_date">Última actualización desde Telegram: %1$s</string>
<string name="last_response_date">Última respuesta: %1$s</string>
<string name="last_update_from_telegram_duration">Última actualización desde Telegram: hace %1$s</string>
<string name="last_response_duration">Última respuesta: hace %1$s</string>
<string name="duration_ago">hace %1$s</string>
</resources>

View file

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="buffer_time_descr">Maksimaalne punktide puhvris säilitamise aeg</string>
<string name="buffer_time">Puhvri aegumisaeg</string>
<string name="time_zone_descr">Vali oma asukohateadetes kuvatav ajavöönd.</string>
<string name="time_zone">Ajavöönd</string>
<string name="units_and_formats">Ühikud ja formaadid</string>
<string name="unit_of_length_descr">Muuda kauguse mõõtmise ühikuid.</string>
<string name="unit_of_length">Pikkusühikud</string>
<string name="unit_of_speed_system_descr">Määra kiiruse ühik.</string>
<string name="unit_of_speed_system">Kiiruse ühik</string>
<string name="saved_messages">Salvestatud sõnumid</string>
<string name="shared_string_end">Lõpp</string>
<string name="shared_string_start">Algus</string>
<string name="shared_string_apply">Rakenda</string>
<string name="set_time_timeline_descr">Vali kuvatav aeg</string>
<string name="start_end_date">Alguse — Lõpu kuupäev</string>
<string name="timeline_no_data_descr">Meil pole valitud päeva kohta andmeid kogutud</string>
<string name="timeline_no_data">Andmed puuduvad</string>
<string name="shared_string_select">Vali</string>
<string name="min_logging_distance">Vähim logimise vahemaa</string>
<string name="min_logging_distance_descr">Filter: vähim vahemaa, mille järel uus punkt logida</string>
<string name="min_logging_accuracy">Vähim logimise täpsus</string>
<string name="min_logging_accuracy_descr">Filter: mitte logida kuni täpsus pole saavutatud</string>
<string name="min_logging_speed">Vähim logimise kiirus</string>
<string name="min_logging_speed_descr">Filter: mitte logida alla valitud kiiruse</string>
<string name="gpx_settings">GPX seaded</string>
<string name="proxy_key">Võti</string>
<string name="proxy_password">Salasõna</string>
<string name="proxy_username">Kasutajanimi</string>
<string name="proxy_credentials">Rekvisiidid</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Server</string>
<string name="shared_string_connection">Ühendus</string>
<string name="shared_string_enable">Luba</string>
<string name="proxy_type">Puhverserveri liik</string>
<string name="proxy_connected">Ühendatud</string>
<string name="proxy_disconnected">Ühendus puudub</string>
<string name="proxy_settings">Puhverserveri seaded</string>
<string name="proxy">Puhverserver</string>
<string name="altitude">Kõrgus</string>
<string name="shared_string_search">Otsi</string>
<string name="shared_string_ok">OK</string>
<string name="shared_string_update">Uuenda</string>
<string name="average_altitude">Keskmine kõrgus</string>
<string name="average_speed">Keskmine kiirus</string>
<string name="shared_string_map">Kaart</string>
<string name="shared_string_add">Lisa</string>
<string name="shared_string_hide">Peida</string>
<string name="shared_string_enabled">Lubatud</string>
<string name="shared_string_status">Olek</string>
<string name="shared_string_disable">Keela</string>
<string name="shared_string_save">Salvesta</string>
<string name="shared_string_name">Nimi</string>
<string name="shared_string_sort">Sorteeri</string>
<string name="shared_string_exit">Välju</string>
<string name="shared_string_close">Sulge</string>
<string name="shared_string_all">Kõik</string>
<string name="shared_string_off">Väljas</string>
<string name="shared_string_install">Paigalda</string>
<string name="shared_string_share">Jaga</string>
<string name="shared_string_back">Tagasi</string>
<string name="shared_string_continue">Jätka</string>
<string name="shared_string_cancel">Tühista</string>
<string name="shared_string_settings">Seaded</string>
<string name="osmand_service">Taustarežiim</string>
<string name="yard">yd</string>
<string name="foot">ft</string>
<string name="mile">mi</string>
<string name="km">km</string>
<string name="m">m</string>
<string name="nm">nmi</string>
<string name="min_mile">min/m</string>
<string name="min_km">min/km</string>
<string name="m_s">m/s</string>
<string name="km_h">km/h</string>
<string name="mile_per_hour">mph</string>
<string name="si_kmh">Kilomeetrit tunnis</string>
<string name="si_mph">Miili tunnis</string>
<string name="si_m_s">Meetrit sekundis</string>
<string name="si_min_km">Minutit kilomeetri kohta</string>
<string name="si_min_m">Minutit miili kohta</string>
<string name="si_mi_feet">Miilid/jalad</string>
<string name="si_mi_yard">Miilid/jardid</string>
<string name="si_km_m">Kilomeetrid/meetrid</string>
<string name="si_nm">Meremiilid</string>
<string name="si_mi_meters">Miilid/meetrid</string>
<string name="privacy">Privaatsus</string>
<string name="direction">Suund</string>
<string name="precision">Täpsus</string>
<string name="bearing">Kurss</string>
<string name="search_contacts">Otsi kontaktide hulgast</string>
<string name="search_contacts_descr">Otsi kõigist oma gruppidest ja kontaktidest.</string>
<string name="type_contact_or_group_name">Kirjuta kontakti või grupi nimi</string>
<string name="timeline_available_for_free_now">Ajaskaala on nüüd tasuta saadaval olev funktsioon.</string>
<string name="disable_monitoring">Keela jälgimine</string>
<string name="location_recording_enabled">Asukoha salvestamine lubatud</string>
<string name="timeline_description">Luba jälgimine kõigi asukohtade ajaloos salvestamiseks.</string>
<string name="app_name_short">OsmAnd Tracker</string>
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (sõnumirakendus) on kasutusel inimestega kontakteerumiseks ja suhtlemiseks.</string>
<string name="privacy_policy_telegram_client">OsmAnd Tracker on üks Telegrami avatud platvormi kasutavaid kliente. Teie kontaktid saavad kasutada mis tahes muud Telegrami klienti.</string>
<string name="privacy_policy_agree">Vajutades \"Jätka\" nõustud Telegram ja OsmAnd rakenduste privaatsuspoliitika tingimustega.</string>
<string name="shared_string_accept">Nõustu</string>
<string name="telegram_privacy_policy">Telegram privaatsuspoliitika</string>
<string name="osmand_privacy_policy">OsmAnd privaatsuspoliitika</string>
<string name="how_it_works">Kuidas see töötab</string>
<string name="received_gps_points">Saadud GPX punktid: %1$s</string>
<string name="shared_string_appearance">Välimus</string>
<string name="show_gps_points">Kuva GPS punktid</string>
<string name="show_gps_points_descr">Kuva kogutud ja saadetud GPS punktide arv.</string>
<string name="please_update_osmand">Palun uuenda OsmAnd andmete vaatamiseks kaardil</string>
<string name="gps_points_in_buffer">saadetud (%1$d puhvris)</string>
<string name="points_size">%1$d punkti</string>
<string name="shared_string_date">Kuupäev</string>
<string name="shared_string_collected">Kogutud</string>
<string name="gps_points">GPS punktid</string>
<string name="shared_string_sent">Saadetud</string>
<string name="monitoring_is_enabled">Jälgimine on lubatud</string>
<string name="monitoring_is_disabled">Jälgimine on keelatud</string>
<string name="time_on_the_move">Liikumisaeg</string>
<string name="open_in_osmand">Kuva OsmAndis</string>
<string name="end_date">Lõppkuupäev</string>
<string name="start_date">Alguskuupäev</string>
<string name="send_location_as">Saada asukoht kui</string>
<string name="send_location_as_descr">Vali oma asukoha sõnumite välimus.</string>
<string name="shared_string_text">Tekst</string>
<string name="map_and_text">Kaart ja tekst</string>
<string name="last_update_from_telegram">Viimane Telegram poolne uuendus</string>
<string name="enter_another_device_name">Vali nimi, mida Sa pole veel kasutanud</string>
<string name="device_added_successfully">%1$s lisatud.</string>
<string name="error_adding_new_device">Uut seadet ei saanud lisada</string>
<string name="enter_device_name_description">Nimeta oma uus seade maksimaalselt 200 tähemärgiga.</string>
<string name="device_name_is_too_long">Seadme nimi liiga pikk</string>
<string name="device_name_cannot_be_empty">Seadme nimi ei tohi olla tühi</string>
<string name="device_name">Seadme nimi</string>
<string name="share_location_as_description_second_line">Seadme ID saate luua ja vaadata %1$s vestlusboti abil Telegrami kliendis. %2$s</string>
<string name="share_location_as_description">Soovides siduda ühe Telegrami kontoga mitut seadet, peate oma asukoha jagamiseks kasutama erinevat seadet.</string>
<string name="last_updated_location">Viimati värskendatud asukoht:</string>
<string name="successfully_sent_and_updated">Edukalt saadetud ja värskendatud</string>
<string name="not_possible_to_send_to_telegram_chats">Telegrami vestlusi pole võimalik saata:</string>
<string name="waiting_for_response_from_telegram">Telegram vastuse ootel</string>
<string name="sending_location_messages">Asukoha saatmine</string>
<string name="initializing">Alustamine</string>
<string name="searching_for_gps">Positsioneerimine…</string>
<string name="connecting_to_the_internet">Interneti-ühenduse loomine</string>
<string name="background_work_description">Asukoha jagamise stabiliseerimiseks muuda aku optimeerimise sätteid.</string>
<string name="background_work">Tausttöö</string>
<string name="battery_optimization_description">Lülita aku optimeerimine OsmAnd Trackeris välja, nii et see taustal olles ootamatult välja ei lülitu.</string>
<string name="sharing_in_background">Taustal jagamine</string>
<string name="go_to_settings">Mine seadete juurde</string>
<string name="shared_string_later">Hiljem</string>
<string name="not_sent_yet">Ei ole veel saadetud</string>
<string name="not_found_yet">Ei ole veel leitud</string>
<string name="re_send_location">Saada asukoht uuesti</string>
<string name="last_available_location">Viimane saadaolev asukoht</string>
<string name="sharing_status">Jagamise olek</string>
<string name="location_sharing_status">Jagamine: %1$s</string>
<string name="no_gps_connection">GPS ühendus puudub</string>
<string name="no_internet_connection">Interneti-ühendus puudub</string>
<string name="add_device">Lisa seade</string>
<string name="share_location_as">Jaga asukohta kui</string>
<string name="live_now_description">Sinuga asukohta jagavad kontaktid ja grupid.</string>
<string name="logout_from_osmand_telegram_descr">Kas soovid kindlasti OsmAnd Trackerist välja logida, et ei saaks asukohta jagada ega teiste asukohta näha\?</string>
<string name="logout_from_osmand_telegram">Logida OsmAnd Trackerist välja\?</string>
<string name="by_distance">Kauguse järgi</string>
<string name="by_name">Nime järgi</string>
<string name="by_group">Grupi järgi</string>
<string name="shared_string_sort_by">Sorteerimisalus</string>
<string name="choose_osmand_desc">Vali OsmAnd versioon, kus kontaktid kuvatakse kaardil.</string>
<string name="choose_osmand">Vali kasutatav OsmAnd versioon</string>
<string name="disable_all_sharing_desc">Lülitab asukoha jagamise välja kõikides valitud vestlustes (%1$d).</string>
<string name="disable_all_sharing">Keela igasugune jagamine</string>
<string name="turn_off_all">Lülita kõik välja</string>
<string name="time_ago">tagasi</string>
<string name="last_response">Viimane vastus</string>
<string name="shared_string_group">Grupp</string>
<string name="logout_no_internet_msg">Telegramist korrektseks väljalogimiseks loo interneti-ühendus.</string>
<string name="disconnect_from_telegram_desc">Asukoha jagamise juurdepääsu tühistamine. Ava Telegram, mine menüüsse Seaded → Privaatsus ja turvalisus → Seansid ja lõpeta OsmAnd Trackeri seanss.</string>
<string name="disconnect_from_telegram">Kuidas OsmAnd Tracker Telegramist välja lülitada</string>
<string name="logout_help_desc">Kuidas OsmAnd Tracker Telegramist välja lülitada</string>
<string name="connected_account">Ühendatud konto</string>
<string name="shared_string_account">Konto</string>
<string name="in_time">%1$s jooksul</string>
<string name="osmand_connect_desc">Vali OsmAnd Trackeri poolt asukohtade kuvamiseks kasutatav OsmAnd versioon.</string>
<string name="osmand_connect">OsmAnd ühendamine</string>
<string name="location_history_desc">Peida kontaktid, kes pole antud aja jooksul liikunud.</string>
<string name="location_history">Asukoha ajalugu</string>
<string name="stale_location_desc">Kontakti viimase liikumise aeg.</string>
<string name="stale_location">Ei liigu</string>
<string name="send_my_location_desc">Seadista asukoha jagamise minimaalne ajavahemik.</string>
<string name="send_my_location">Saada minu asukoht</string>
<string name="gps_and_location">Asukoht</string>
<string name="sharing_time">Jagamise aeg</string>
<string name="expire_at">Aegub</string>
<string name="stop_sharing_all">Jagamine on sisse lülitatud (lülita välja)</string>
<string name="turn_off_location_sharing">Lülita asukoha jagamine välja</string>
<string name="open_osmand">Ava OsmAnd</string>
<string name="shared_string_live">Reaalajas</string>
<string name="shared_string_bot">Bot</string>
<string name="get_telegram_title">Telegramis registreerumine</string>
<string name="get_telegram_account_first">Asukoha jagamiseks vajad Telegram kontot.</string>
<string name="get_telegram_description_continue">Palun paigalda Telegram ja seadista konto.</string>
<string name="get_telegram_after_creating_account">Seejärel saad seda rakendust kasutada.</string>
<string name="already_registered_in_telegram">Vajad registreeritud Telegrami kontot ja telefoninumbrit</string>
<string name="do_not_have_telegram">Mul ei ole Telegrami kontot</string>
<string name="enter_phone_number">Sisesta telefoninumber</string>
<string name="enter_authentication_code">Sisesta autentimiskood</string>
<string name="set_visible_time_for_all">Määra kõigile nähtav oleku aeg</string>
<string name="hours_and_minutes_format">%1$d h %2$d m</string>
<string name="minutes_format">%1$d m</string>
<string name="hours_format">%1$d h</string>
<string name="visible_time_for_all">Kõigile nähtav oleku aeg</string>
<string name="set_time_description">Vali aeg, mille jooksul valitud kontaktid ja rühmad näevad sinu asukohta reaalajas.</string>
<string name="set_time">Määra aeg</string>
<string name="location_sharing_description">Vali kontaktid ja rühmad, kellega soovid oma asukohta jagada.</string>
<string name="my_location_search_hint">Otsi: grupp või kontakt</string>
<string name="start_location_sharing">Jaga asukohta</string>
<string name="show_on_map">Kuva kaardil</string>
<string name="app_name">OsmAnd võrguühendusega GPS jälgija</string>
<string name="phone_number_title">Telefoninumber</string>
<string name="phone_number_descr">Telefoninumber rahvusvahelises formaadis</string>
<string name="shared_string_password">Salasõna</string>
<string name="enter_code">Sisesta kood</string>
<string name="authentication_code">Autentimiskood</string>
<string name="authentication_code_descr">Telegram saatis sulle koodi OsmAnd-i abil oma kontole sisse logimiseks.</string>
<string name="enter_password">Sisesta salasõna</string>
<string name="password_descr">Telegram salasõna</string>
<string name="shared_string_login">Logi sisse</string>
<string name="shared_string_logout">Logi välja</string>
<string name="initialization">Alustamine</string>
<string name="logging_out">Välja logimine</string>
<string name="closing">Sulgemine</string>
<string name="gps_network_not_enabled">Lülitada sisse \"Asukoht\"\?</string>
<string name="not_logged_in">Sa ei ole sisse logitud</string>
<string name="no_location_permission">Rakendusel puudub juurdepääs asukohaandmetele.</string>
<string name="gps_not_available">Palun lülita süsteemi seadetes sisse \"Asukoht\"</string>
<string name="location_service_no_gps_available">Vali oma asukoha jagamiseks üks asukoha pakkujatest.</string>
<string name="osmand_service_descr">OsmAnd Tracker töötab taustal välja lülitatud ekraaniga.</string>
<string name="shared_string_distance">Kaugus</string>
<string name="share_location">Jaga asukohta</string>
<string name="sharing_location">Asukoha jagamine</string>
<string name="process_service">OsmAnd Tracker teenus</string>
<string name="osmand_logo">OsmAnd logo</string>
<string name="install_osmand_dialog_message">Esmalt pead paigaldama OsmAnd tasuta või tasulise versiooni</string>
<string name="install_osmand">Paigalda OsmAnd</string>
<string name="show_users_on_map">Kuva kasutajad kaardil</string>
<string name="active_chats">Aktiivsed vestlused</string>
<string name="shared_string_authorization">Autoriseerimine</string>
<string name="shared_string_authorization_descr">Palun sisesta oma Telegrami telefoninumber rahvusvahelises formaadis</string>
<string name="shared_string_welcome">Tere tulemast</string>
<string name="nm_h">nmi/h</string>
<string name="si_nm_h">Meremiili tunnis (sõlm)</string>
<string name="shared_string_hour_short">h</string>
<string name="shared_string_minute_short">min</string>
<string name="shared_string_second_short">sek</string>
<string name="welcome_descr"><b>OsmAnd Tracker</b> võimaldab sul jagada oma asukohta ja näha teiste asukohta OsmAndis. <br/> <br/>Rakendus kasutab Telegrami API-t, seega vajad Telegrami kontot.</string>
<string name="my_location">Minu asukoht</string>
<string name="live_now">Nüüd reaalajas nähtav</string>
<string name="timeline">Ajajoon</string>
<string name="shared_string_suggested">Soovitatud</string>
<string name="status_widget_title">OsmAnd Tracker olek</string>
<string name="back_to_osmand">Tagasi OsmAnd-i</string>
<string name="last_update_from_telegram_date">Viimane Telegram uuendus: %1$s</string>
<string name="last_response_date">Viimane vastus: %1$s</string>
<string name="last_update_from_telegram_duration">Viimane Telegram uuendus: %1$s tagasi</string>
<string name="last_response_duration">Viimane vastus: %1$s tagasi</string>
<string name="duration_ago">%1$s tagasi</string>
</resources>

View file

@ -186,4 +186,5 @@
<string name="shared_string_apply">Aplikatu</string>
<string name="set_time_timeline_descr">Hautatu bistaratzeko denbora</string>
<string name="start_end_date">Hasiera — Amaiera data</string>
<string name="shared_string_enabled">Gaituta</string>
</resources>

View file

@ -19,7 +19,7 @@
<string name="not_found_yet">هنوز پیدا نشده</string>
<string name="re_send_location">بازفرستی موقعیت</string>
<string name="shared_string_status">وضعیت</string>
<string name="shared_string_close">بستن</string>
<string name="shared_string_close">ببند</string>
<string name="shared_string_hide">نشان نده</string>
<string name="shared_string_disable">غیرفعال</string>
<string name="shared_string_save">ذخیره</string>
@ -68,4 +68,8 @@
<string name="shared_string_apply">به‌کارگیری</string>
<string name="nm_h">nmi/h</string>
<string name="si_nm_h">مایل دریایی بر ساعت (نات)</string>
<string name="shared_string_enabled">فعال</string>
<string name="units_and_formats">یکاها و قالب‌ها</string>
<string name="unit_of_length_descr">یکاهای طول را تغییر دهید.</string>
<string name="unit_of_length">یکاهای طول</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -139,7 +139,7 @@
<string name="no_location_permission">A aplicación non ten permiso para acceder ós datos da ubicación.</string>
<string name="gps_not_available">Activar «Ubicación» nos axustes do sistema</string>
<string name="location_service_no_gps_available">Escolle un dos fornecedores da ubicación para compartilla-la túa ubicación.</string>
<string name="osmand_service">Modo no segundo plano</string>
<string name="osmand_service">Modo en segundo plano</string>
<string name="osmand_service_descr">O OsmAnd Tracker execútase no modo en segundo plano ca pantalla apagada.</string>
<string name="shared_string_distance">Distancia</string>
<string name="share_location">Compartillar ubicación</string>

View file

@ -195,7 +195,7 @@
<string name="shared_string_telegram">טלגרם</string>
<string name="privacy_policy_use_telegram">טלגרם (יישומון ההתכתבות) משמש תשתית להתחברות ולתקשורת עם אנשים.</string>
<string name="privacy_policy_telegram_client">העוקב של OsmAnd הוא אחד הלקוחות שמשתמש בפלטפורמה הפתוחה של טלגרם. אנשי הקשר שלך יכולים להשתמש בכל לקוח טלגרם שיבחרו.</string>
<string name="privacy_policy_agree">לחיצה על המשך מהווה את הסכמתך לתנאי מדיניות הפרטיות של טלגרם ולתנאי מדיניות הפרטיות של OsmAnd.</string>
<string name="privacy_policy_agree">לחיצה על המשך מהווה את הסכמתך לתנאי מדיניות הפרטיות של טלגרם ושל OsmAnd.</string>
<string name="shared_string_accept">קבלה</string>
<string name="telegram_privacy_policy">מדיניות הפרטיות של טלגרם</string>
<string name="osmand_privacy_policy">מדיניות הפרטיות של OsmAnd</string>
@ -249,4 +249,22 @@
<string name="start_end_date">תאריך התחלה - סיום</string>
<string name="location_sharing_status">משותף: %1$s</string>
<string name="shared_string_enabled">מופעל</string>
<string name="saved_messages">הודעות שמורות</string>
<string name="time_zone_descr">נא לבחור את אזור הזמן בהודעות המיקום שלך.</string>
<string name="time_zone">אזור זמן</string>
<string name="units_and_formats">יחידות ותבניות</string>
<string name="unit_of_length_descr">שינוי היחידות שבהן מודדים מרחק.</string>
<string name="unit_of_length">יחידות אורך</string>
<string name="unit_of_speed_system_descr">הגדרת יחידת מהירות.</string>
<string name="unit_of_speed_system">יחידת מהירות</string>
<string name="buffer_time_descr">הזמן המרבי לשמירת נקודות בזיכרון</string>
<string name="buffer_time">זמן פקיעת הזיכרון</string>
<string name="shared_string_suggested">מוצע</string>
<string name="status_widget_title">מצב עוקב OsmAnd</string>
<string name="back_to_osmand">חזרה ל־OsmAnd</string>
<string name="last_update_from_telegram_date">עדכון אחרון מטלגרם: %1$s</string>
<string name="last_response_date">תגובה אחרונה: %1$s</string>
<string name="last_update_from_telegram_duration">עדכון אחרון מטלגרם: %1$s ago</string>
<string name="last_response_duration">תגובה אחרונה: לפני %1$s</string>
<string name="duration_ago">לפני %1$s</string>
</resources>

View file

@ -2,8 +2,8 @@
<resources>
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">A Telegram (üzenetküldő alkalmazás) a másokkal való összekapcsolódásra és kommunikációra használható.</string>
<string name="privacy_policy_telegram_client">A Telegram nyílt platformot használó kliensprogramok egyike az OsmAnd tracker. Partnerei bármelyik másik Telegram kliensprogramot is használhatják.</string>
<string name="privacy_policy_agree">A továbbra kattintva elfogadja a Telegram és az OsmAnd adatvédelmi irányelveinek feltételeit.</string>
<string name="privacy_policy_telegram_client">A Telegram nyílt platformot használó kliensprogramok egyike az OsmAnd Tracker. Partnerei bármelyik másik Telegram kliensprogramot is használhatják.</string>
<string name="privacy_policy_agree">A „Tovább”-ra kattintva elfogadja a Telegram és az OsmAnd adatvédelmi irányelveinek feltételeit.</string>
<string name="shared_string_accept">Elfogadás</string>
<string name="telegram_privacy_policy">Telegram adatvédelmi irányelvei</string>
<string name="osmand_privacy_policy">OsmAnd adatvédelmi irányelvei</string>
@ -62,7 +62,7 @@
<string name="last_available_location">Utolsó elérhető tartózkodási hely</string>
<string name="sharing_status">Megosztás állapota</string>
<string name="location_sharing_status">Megosztás: %1$s</string>
<string name="shared_string_enabled">engedélyezve</string>
<string name="shared_string_enabled">Engedélyezve</string>
<string name="shared_string_status">Állapot</string>
<string name="no_gps_connection">Nincs GPS-kapcsolat</string>
<string name="no_internet_connection">Nincs internetkapcsolat</string>
@ -249,4 +249,22 @@
<string name="shared_string_apply">Alkalmazás</string>
<string name="set_time_timeline_descr">Megjelenítendő időszak kijelölése</string>
<string name="start_end_date">Kezdő és záró dátum</string>
<string name="saved_messages">Mentett üzenetek</string>
<string name="time_zone_descr">Időzóna kijelölése a helyzetjelentésekben való megjelenítéshez.</string>
<string name="time_zone">Időzóna</string>
<string name="units_and_formats">Mértékegységek &amp; formátumok</string>
<string name="unit_of_length_descr">Távolság mértékegységének módosítása</string>
<string name="unit_of_length">Hosszmértékegységek</string>
<string name="unit_of_speed_system_descr">Sebesség mértékegységének meghatározása</string>
<string name="unit_of_speed_system">Sebesség mértékegysége</string>
<string name="buffer_time_descr">Az a leghosszabb idő, ameddig a pontok a pufferben tárolódnak</string>
<string name="buffer_time">Puffer lejárati ideje</string>
<string name="shared_string_suggested">Javasolt</string>
<string name="status_widget_title">Az OsmAnd Tracker állapota</string>
<string name="back_to_osmand">Vissza az OsmAndba</string>
<string name="last_update_from_telegram_date">Utolsó frissítés a Telegramtól: %1$s</string>
<string name="last_response_date">Utolsó válasz: %1$s</string>
<string name="last_update_from_telegram_duration">Utolsó frissítés a Telegramtól: %1$s</string>
<string name="last_response_duration">Utolsó válasz: %1$s</string>
<string name="duration_ago">Ennyivel ezelőtt: %1$s</string>
</resources>

View file

@ -32,7 +32,7 @@
<string name="last_available_location">Ultima posizione disponibile</string>
<string name="sharing_status">Condivisione dello stato</string>
<string name="location_sharing_status">Condivisione: %1$s</string>
<string name="shared_string_enabled">Attivata</string>
<string name="shared_string_enabled">Abilitato</string>
<string name="shared_string_status">Stato</string>
<string name="no_gps_connection">Nessuna connessione GPS</string>
<string name="no_internet_connection">Nessuna connessione ad Internet</string>
@ -187,9 +187,9 @@
<string name="shared_string_text">Testo</string>
<string name="map_and_text">Mappa e testo</string>
<string name="timeline">Cronologia</string>
<string name="shared_string_ok">OK</string>
<string name="shared_string_ok">Ok</string>
<string name="timeline_available_for_free_now">La funzionalità Timeline è adesso disponibile gratuitamente.</string>
<string name="disable_monitoring">Disattivare il monitoraggio</string>
<string name="disable_monitoring">Disattiva il monitoraggio</string>
<string name="location_recording_enabled">Registrazione della posizione abilitata</string>
<string name="timeline_description">Attivare il monitoraggio per salvare lo storico delle locazioni.</string>
<string name="app_name_short">Tracker OsmAnd</string>
@ -228,11 +228,11 @@
<string name="proxy_port">Porta</string>
<string name="proxy_server">Server</string>
<string name="shared_string_connection">Connessione</string>
<string name="shared_string_enable">Abilitato</string>
<string name="proxy_type">Tipo di Proxy</string>
<string name="shared_string_enable">Attiva</string>
<string name="proxy_type">Tipo di proxy</string>
<string name="proxy_connected">Connesso</string>
<string name="proxy_disconnected">Disconnesso</string>
<string name="proxy_settings">Impostazioni Proxy</string>
<string name="proxy_settings">Impostazioni proxy</string>
<string name="proxy">Proxy</string>
<string name="privacy">Privacy</string>
<string name="shared_string_select">Seleziona</string>
@ -249,5 +249,12 @@
<string name="shared_string_end">Fine</string>
<string name="shared_string_start">Avvia</string>
<string name="set_time_timeline_descr">Seleziona l\'ora da visualizzare</string>
<string name="start_end_date">Inizio - Data di fine</string>
<string name="start_end_date">Data di inizio - fine</string>
<string name="saved_messages">Messaggi salvati</string>
<string name="units_and_formats">Unità e formati</string>
<string name="unit_of_length_descr">Cambia l\'unità di misura della distanza.</string>
<string name="unit_of_length">Unità di misura di lunghezza</string>
<string name="time_zone">Fuso orario</string>
<string name="unit_of_speed_system">Unità di misura della velocità</string>
<string name="back_to_osmand">Torna a OsmAnd</string>
</resources>

View file

@ -0,0 +1,263 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="shared_string_end">終了</string>
<string name="shared_string_start">開始</string>
<string name="shared_string_apply">決定</string>
<string name="set_time_timeline_descr">表示時間を選択</string>
<string name="start_end_date">開始—終了日</string>
<string name="timeline_no_data_descr">選択した日のデータは未収集です</string>
<string name="timeline_no_data">データなし</string>
<string name="shared_string_select">選択</string>
<string name="min_logging_distance">最小記録距離</string>
<string name="min_logging_distance_descr">フィルター:新しい地点記録の最小距離</string>
<string name="min_logging_accuracy">最小記録精度</string>
<string name="min_logging_accuracy_descr">フィルター:指定精度に届いたログはありません</string>
<string name="min_logging_speed">最小記録速度</string>
<string name="min_logging_speed_descr">フィルター:指定記録速度に届いたログはありません</string>
<string name="gpx_settings">GPX設定</string>
<string name="proxy_key">キー</string>
<string name="proxy_password">パスワード</string>
<string name="proxy_username">ユーザー名</string>
<string name="proxy_credentials">資格情報</string>
<string name="proxy_port">ポート</string>
<string name="proxy_server">サーバー</string>
<string name="shared_string_connection">接続</string>
<string name="shared_string_enable">有効</string>
<string name="proxy_type">プロキシタイプ</string>
<string name="proxy_connected">接続しました</string>
<string name="proxy_disconnected">切断しました</string>
<string name="proxy_settings">プロキシ設定</string>
<string name="proxy">プロキシ</string>
<string name="privacy">プライバシー</string>
<string name="direction">方向</string>
<string name="precision">精度</string>
<string name="altitude">標高</string>
<string name="bearing">ベアリング</string>
<string name="search_contacts">連絡先を検索</string>
<string name="search_contacts_descr">すべてのグループと連絡先を検索します。</string>
<string name="type_contact_or_group_name">連絡先またはグループ名を入力</string>
<string name="shared_string_search">検索</string>
<string name="shared_string_ok">OK</string>
<string name="timeline_available_for_free_now">タイムライン機能は現在無料で利用できます。</string>
<string name="disable_monitoring">モニタリングを無効化</string>
<string name="location_recording_enabled">ロケーション記録が有効になりました</string>
<string name="timeline_description">モニタリング機能を有効にして、すべての場所を履歴に保存します。</string>
<string name="app_name_short">OsmAndトラッカー</string>
<string name="shared_string_telegram">テレグラム</string>
<string name="privacy_policy_use_telegram">テレグラム(メッセージングアプリ)は、他の人々と通信するために使用されます。</string>
<string name="privacy_policy_telegram_client">OsmAndトラッカーは、Telegramオープンプラットフォームを利用するクライアントの1つです。連絡先は他のTelegramクライアントのものを利用できます。</string>
<string name="privacy_policy_agree">続行をクリックすると、TelegramおよびOsmAndプライバシーポリシーの条件に同意したとみなされます。</string>
<string name="shared_string_accept">決定</string>
<string name="telegram_privacy_policy">Telegramプライバシーポリシー</string>
<string name="osmand_privacy_policy">OsmAndプライバシーポリシー</string>
<string name="how_it_works">使い方</string>
<string name="received_gps_points">GPXポイントを受信しました:%1$s</string>
<string name="shared_string_appearance">外観</string>
<string name="show_gps_points">GPSポイントの表示</string>
<string name="show_gps_points_descr">収集および送信されたGPSポイントの数量を表示します。</string>
<string name="please_update_osmand">マップ上でデータを表示するにはOsmAndを更新してください</string>
<string name="shared_string_update">更新</string>
<string name="gps_points_in_buffer">送信済み(バッファ内 %1$d)</string>
<string name="points_size">%1$d地点</string>
<string name="shared_string_date">日付</string>
<string name="shared_string_collected">収集済み</string>
<string name="gps_points">GPSポイント</string>
<string name="shared_string_sent">送信済み</string>
<string name="monitoring_is_enabled">モニタリングを有効化しました</string>
<string name="monitoring_is_disabled">モニタリングを無効化しました</string>
<string name="time_on_the_move">移動時間</string>
<string name="average_altitude">平均標高</string>
<string name="average_speed">平均速度</string>
<string name="open_in_osmand">OsmAndで表示</string>
<string name="end_date">終了日</string>
<string name="start_date">開始日</string>
<string name="send_location_as">場所を送信</string>
<string name="send_location_as_descr">メッセージと現在地の表示方法を選択します。</string>
<string name="shared_string_map">マップ</string>
<string name="shared_string_text">テキスト</string>
<string name="map_and_text">マップ&テキスト</string>
<string name="last_update_from_telegram">Telegramの最終更新</string>
<string name="enter_another_device_name">使用されていない名前を選択してください</string>
<string name="device_added_successfully">%1$sが追加されました。</string>
<string name="shared_string_add">追加</string>
<string name="error_adding_new_device">新しいデバイスを追加できませんでした</string>
<string name="enter_device_name_description">新しいデバイスに名前をつけます。 最大200文字(半角英文字の場合)。</string>
<string name="device_name_is_too_long">デバイス名が長すぎます</string>
<string name="device_name_cannot_be_empty">デバイス名を無しにすることはできません</string>
<string name="device_name">デバイス名</string>
<string name="shared_string_hide">非表示</string>
<string name="share_location_as_description_second_line">チャットボット%1$sを利用して、TelegramクライアントのデバイスID作成および表示ができます。%2$s</string>
<string name="share_location_as_description">複数のデバイスを1つのTelegramアカウントに接続する場合は、異なるデバイス間にて現在地を共有する必要があります。</string>
<string name="last_updated_location">最終更新場所:</string>
<string name="successfully_sent_and_updated">送信および更新に成功しました</string>
<string name="not_possible_to_send_to_telegram_chats">Telegramチャットに送信できません:</string>
<string name="waiting_for_response_from_telegram">Telegramからの応答を待っています</string>
<string name="sending_location_messages">送信場所</string>
<string name="initializing">起動中</string>
<string name="searching_for_gps">位置取得中…</string>
<string name="connecting_to_the_internet">インターネットに接続</string>
<string name="background_work_description">バッテリー最適化設定を変更し(消費電力を上げて)、位置情報の共有を安定化させます。</string>
<string name="background_work">バックグラウンド動作</string>
<string name="battery_optimization_description">OsmAnd Trackerのバッテリー最適化をオフにして、バックグラウンド動作時に動作が中断しないようにします。</string>
<string name="sharing_in_background">バックグラウンドで共有</string>
<string name="go_to_settings">設定に移動</string>
<string name="shared_string_later">後で</string>
<string name="not_sent_yet">まだ送信されていません</string>
<string name="not_found_yet">まだ見つかりません</string>
<string name="re_send_location">場所を再送信</string>
<string name="last_available_location">最後に有効化されていた場所</string>
<string name="sharing_status">共有ステータス</string>
<string name="location_sharing_status">共有:%1$s</string>
<string name="shared_string_enabled">有効</string>
<string name="shared_string_status">ステータス</string>
<string name="no_gps_connection">GPS未接続</string>
<string name="no_internet_connection">インターネット未接続</string>
<string name="shared_string_disable">無効化</string>
<string name="shared_string_save">保存</string>
<string name="add_device">デバイスの追加</string>
<string name="share_location_as">現在地を共有</string>
<string name="live_now_description">位置情報を共有する連絡先とグループです。</string>
<string name="logout_from_osmand_telegram_descr">自身の居場所や他のユーザーの場所を共有および表示しないよう、OsmAnd Trackerからログアウトしますか</string>
<string name="logout_from_osmand_telegram">OsmAnd Trackerからログアウトしますか</string>
<string name="shared_string_name">名前</string>
<string name="by_distance">距離で</string>
<string name="by_name">名前で</string>
<string name="by_group">グループで</string>
<string name="shared_string_sort">並び替え</string>
<string name="shared_string_sort_by">並び替え:</string>
<string name="choose_osmand_desc">OsmAndのバージョンを選択すると、マップ上に連絡先が表示されます。</string>
<string name="choose_osmand">使用するOsmAndバージョンを選択</string>
<string name="disable_all_sharing_desc">選択したチャット (%1$d)で、現在地の共有をOFFにします。</string>
<string name="disable_all_sharing">すべての共有を無効化</string>
<string name="turn_off_all">すべてOFF</string>
<string name="shared_string_exit">終了</string>
<string name="time_ago"></string>
<string name="last_response">最後の返信</string>
<string name="shared_string_group">グループ</string>
<string name="logout_no_internet_msg">インターネットに接続すると、Telegramから正しい手順でログアウトします。</string>
<string name="shared_string_close">閉じる</string>
<string name="disconnect_from_telegram_desc">位置共有アクセスを取り消すためには Telegramを開き、\'設定\'→\'プライバシーとセキュリティ\'→\'セッション\'に移動して、OsmAnd Trackerセッションを終了します。</string>
<string name="disconnect_from_telegram">TelegramからOsmAnd TrackerをOFFにする方法</string>
<string name="logout_help_desc">TelegramからOsmAnd TrackerをOFFにする方法</string>
<string name="connected_account">接続済みアカウント</string>
<string name="shared_string_account">アカウント</string>
<string name="in_time">%1$s内</string>
<string name="osmand_connect_desc">OsmAndのバージョンを選択すると、OsmAnd Trackerにて位置の表示が使用できます。</string>
<string name="osmand_connect">OsmAndの接続</string>
<string name="location_history_desc">特定の時間内で移動していない場合は、連絡先を非表示にします。</string>
<string name="location_history">位置履歴</string>
<string name="stale_location_desc">連絡相手が移動した最後の時刻をしめしています。</string>
<string name="stale_location">移動していません</string>
<string name="send_my_location_desc">位置共有の最小間隔を設定します。</string>
<string name="send_my_location">現在地の送信</string>
<string name="gps_and_location">GPSでの位置</string>
<string name="sharing_time">共有時刻</string>
<string name="expire_at">超過時間:</string>
<string name="stop_sharing_all">共有はON</string>
<string name="turn_off_location_sharing">現在地共有をOFFにする</string>
<string name="open_osmand">OsmAndを開く</string>
<string name="shared_string_live">Live</string>
<string name="shared_string_bot">BOT</string>
<string name="get_telegram_title">Telegramへの登録</string>
<string name="get_telegram_account_first">現在地の共有をおこなうには、Telegramアカウントが必要です。</string>
<string name="get_telegram_description_continue">Telegramをインストールしてアカウントを設定してください。</string>
<string name="get_telegram_after_creating_account">その後、このアプリを使用できます。</string>
<string name="shared_string_all">全て</string>
<string name="shared_string_off">OFF</string>
<string name="already_registered_in_telegram">登録済みのTelegramアカウントと電話番号が必要です。</string>
<string name="do_not_have_telegram">私はTelegramアカウントを持っていません</string>
<string name="enter_phone_number">電話番号を入力</string>
<string name="enter_authentication_code">認証コードを入力</string>
<string name="set_visible_time_for_all">時間表示を全ユーザーに設定</string>
<string name="hours_and_minutes_format">%1$d時間%2$d分</string>
<string name="minutes_format">%1$d分</string>
<string name="hours_format">%1$d時間</string>
<string name="shared_string_install">インストール</string>
<string name="shared_string_share">共有</string>
<string name="shared_string_back">戻る</string>
<string name="visible_time_for_all">時間が全てのユーザーから閲覧されます</string>
<string name="set_time_description">選択した連絡先とグループに現在地をリアルタイムで表示する時間を設定します。</string>
<string name="set_time">時間の設定</string>
<string name="location_sharing_description">現在地を共有する連絡先とグループを選択します。</string>
<string name="my_location_search_hint">検索:グループまたは連絡先</string>
<string name="start_location_sharing">現在地の共有</string>
<string name="show_on_map">マップ上に表示</string>
<string name="app_name">OsmAnd Online GPS Tracker</string>
<string name="phone_number_title">電話番号</string>
<string name="phone_number_descr">国際形式に則った電話番号</string>
<string name="shared_string_password">パスワード</string>
<string name="enter_code">コードを入力</string>
<string name="authentication_code">認証コード</string>
<string name="authentication_code_descr">TelegramからOsmAndにコードが送信され、アカウントにログインできるようになります。</string>
<string name="enter_password">パスワードを入力</string>
<string name="password_descr">Telegramのパスワード</string>
<string name="shared_string_login">ログイン</string>
<string name="shared_string_logout">ログアウト</string>
<string name="initialization">起動</string>
<string name="logging_out">ログアウト</string>
<string name="closing">クローズ</string>
<string name="gps_network_not_enabled">\"位置情報\"をONにしますか</string>
<string name="not_logged_in">ログインしていません</string>
<string name="shared_string_continue">続行</string>
<string name="shared_string_cancel">キャンセル</string>
<string name="shared_string_settings">設定</string>
<string name="no_location_permission">アプリに位置データを取得する権限がありません。</string>
<string name="gps_not_available">システム設定で\"現在地\"(あるいは位置情報やGPSなど)をONにしてください</string>
<string name="location_service_no_gps_available">位置情報を共有するために位置情報提供機能のいずれかを選択してください。</string>
<string name="osmand_service">バックグラウンドモード</string>
<string name="osmand_service_descr">OsmAnd Trackerは、画面をOFFにしてもバックグラウンドで動作します。</string>
<string name="shared_string_distance">距離</string>
<string name="share_location">位置情報の共有</string>
<string name="sharing_location">位置情報は共有中</string>
<string name="process_service">OsmAnd Trackerサービス</string>
<string name="osmand_logo">OsmAndロゴ</string>
<string name="install_osmand_dialog_message">無料版OsmAnd、または有料版OsmAnd+を先にインストールする必要があります</string>
<string name="install_osmand">OsmAndのインストール</string>
<string name="show_users_on_map">マップにユーザーを表示</string>
<string name="active_chats">アクティブチャット</string>
<string name="shared_string_authorization">認証</string>
<string name="shared_string_authorization_descr">国際形式でTelegramを利用する端末の電話番号を入力してください(日本の場合+81を先頭につけて電話番号最初の0を除いた番号を入力)</string>
<string name="shared_string_welcome">ようこそ</string>
<string name="yard">ヤード</string>
<string name="foot">フィート</string>
<string name="mile">マイル</string>
<string name="km">キロメートル</string>
<string name="m">メートル</string>
<string name="nm">海里</string>
<string name="min_mile">min/m</string>
<string name="min_km">min/km</string>
<string name="nm_h">ノット</string>
<string name="m_s">m/s</string>
<string name="km_h">km/h</string>
<string name="mile_per_hour">mph</string>
<string name="si_kmh">キロメートル毎時</string>
<string name="si_mph">マイル毎時</string>
<string name="si_m_s">メートル毎秒</string>
<string name="si_nm_h">海里毎時(ノット)</string>
<string name="si_mi_feet">マイル/フィート</string>
<string name="si_mi_yard">マイル/ヤード</string>
<string name="si_km_m">キロメートル/メートル</string>
<string name="si_nm">海里</string>
<string name="si_mi_meters">マイル/メートル</string>
<string name="shared_string_hour_short">時間</string>
<string name="shared_string_minute_short"></string>
<string name="shared_string_second_short"></string>
<string name="welcome_descr">
<b>OsmAnd Tracker</b>OsmAndで現在地を共有して他の人たちの現在地も確認できます。<br/>
<br/>アプリはTelegram APIを使用するため、Telegramアカウントが必要です。</string>
<string name="my_location">現在地</string>
<string name="live_now">今現在</string>
<string name="timeline">タイムライン</string>
<string name="si_min_km">分/キロメートル</string>
<string name="si_min_m">分/マイル</string>
<string name="units_and_formats">単位と形式</string>
<string name="unit_of_length">長さの単位</string>
<string name="saved_messages">保存したメッセージ</string>
<string name="time_zone_descr">ロケーションメッセージに表示するタイムゾーンを選択します。</string>
<string name="time_zone">タイムゾーン</string>
<string name="unit_of_length_descr">測定する距離を変更します。</string>
<string name="unit_of_speed_system_descr">速度の単位を指定します。</string>
<string name="unit_of_speed_system">速度の単位</string>
<string name="buffer_time_descr">バッファー内に保存する時間を指定します</string>
<string name="buffer_time">バッファー有効時間</string>
</resources>

View file

@ -2,7 +2,7 @@
<resources>
<string name="background_work_description">Endre batterioptimiseringsinnstillinger for mer stabil posisjonsdeling.</string>
<string name="background_work">Bakgrunnsarbeid</string>
<string name="battery_optimization_description">Skru av batterioptimisering for OsmAnd Tracker slik at det ikke plutselig skrur seg av når det er i bakgrunnen.</string>
<string name="battery_optimization_description">Skru av batterioptimisering for OsmAnd-sporeren slik at det ikke plutselig skrur seg av når det er i bakgrunnen.</string>
<string name="sharing_in_background">Deling i bakgrunnen</string>
<string name="go_to_settings">Gå til innstillinger</string>
<string name="shared_string_later">Senere</string>
@ -20,8 +20,8 @@
<string name="add_device">Legg til enhet</string>
<string name="share_location_as">Del posisjon som</string>
<string name="live_now_description">Kontakter og grupper som deler sin posisjon med deg.</string>
<string name="logout_from_osmand_telegram_descr">Er du sikker på at du vil logge ut av OsmAnd Tracker slik at du ikke kan sende din posisjon, eller se andres\?</string>
<string name="logout_from_osmand_telegram">Logg ut av OsmAnd Tracker\?</string>
<string name="logout_from_osmand_telegram_descr">Er du sikker på at du vil logge ut av OsmAnd-sporeren slik at du ikke kan sende din posisjon, eller se andres\?</string>
<string name="logout_from_osmand_telegram">Logg ut av OsmAnd-sporeren\?</string>
<string name="shared_string_name">Navn</string>
<string name="by_distance">Etter distanse</string>
<string name="by_name">Etter navn</string>
@ -39,13 +39,13 @@
<string name="shared_string_group">Gruppe</string>
<string name="logout_no_internet_msg">Koble til Internett for å logge ut av Telegram ordentlig.</string>
<string name="shared_string_close">Lukk</string>
<string name="disconnect_from_telegram_desc">For å tilbakekalle posisjonsdelingstilgang. Åpne Telegram, gå til Innstillinger - Personvern og sikkerhet - Økter, og sluttfør OsmAnd Tracker-økta.</string>
<string name="disconnect_from_telegram_desc">For å tilbakekalle posisjonsdelingstilgang. Åpne Telegram, gå til Innstillinger - Personvern og sikkerhet - Økter, og sluttfør OsmAnd-sporerøkta.</string>
<string name="disconnect_from_telegram">Hvordan koble fra OsmAnd-sporeren fra Telegram</string>
<string name="logout_help_desc">Hvordan koble fra OsmAnd-sporeren fra Telegram</string>
<string name="connected_account">Tilkoblet konto</string>
<string name="shared_string_account">Konto</string>
<string name="in_time">i %1$s</string>
<string name="osmand_connect_desc">Velg OsmAnd-versjonen OsmAnd Tracker bruker for å vise posisjoner på kartet.</string>
<string name="osmand_connect_desc">Velg OsmAnd-versjonen OsmAnd-sporeren bruker for å vise posisjoner på kartet.</string>
<string name="osmand_connect">OsmAnd connect</string>
<string name="location_history_desc">Skjul kontaktene som ikke har oppdatert sin plassering etter et gitt tidsintervall.</string>
<string name="location_history">Posisjonshistorikk</string>
@ -84,7 +84,7 @@
<string name="my_location_search_hint">Søk: Gruppe eller kontakt</string>
<string name="start_location_sharing">Del posisjon</string>
<string name="show_on_map">Vis på kartet</string>
<string name="app_name">OsmAnd Online GPS Tracker</string>
<string name="app_name">OsmAnd nettbasert GPS-sporer</string>
<string name="phone_number_title">Telefonnummer</string>
<string name="phone_number_descr">Telefonnummer i internasjonalt format</string>
<string name="shared_string_password">Passord</string>
@ -103,11 +103,11 @@
<string name="gps_not_available">Skru på «Posisjon» i systeminnstillingene</string>
<string name="location_service_no_gps_available">Velg en av posisjonstilbyderne for å dele din posisjon.</string>
<string name="osmand_service">Bakgrunnsmodus</string>
<string name="osmand_service_descr">OsmAnd Tracker kjører som nisse med skjermen av.</string>
<string name="osmand_service_descr">OsmAnd-sporeren kjører som nisse med skjermen av.</string>
<string name="shared_string_distance">Distanse</string>
<string name="share_location">Del posisjon</string>
<string name="sharing_location">Deler posisjon</string>
<string name="process_service">OsmAnd Tracker-tjeneste</string>
<string name="process_service">OsmAnd-sporertjeneste</string>
<string name="osmand_logo">OsmAnd-logo</string>
<string name="install_osmand_dialog_message">Du må installere gratis- eller betalt versjon av OsmAnd først</string>
<string name="install_osmand">Installer OsmAnd</string>
@ -125,7 +125,9 @@
<string name="shared_string_hour_short">t</string>
<string name="shared_string_minute_short">min</string>
<string name="shared_string_second_short">sek</string>
<string name="welcome_descr"><b>OsmAnd-sporer</b> lar deg dele din posisjon og se andres i OsmAnd.<br/> <br/>Programmet belager seg på Telegram-API-et, så du må ha en Telegram-konto.</string>
<string name="welcome_descr">
<b>OsmAnd-sporeren</b> lar deg dele din posisjon og se andres i OsmAnd.<br/>
<br/>Programmet belager seg på Telegram-API-et, så du må ha en Telegram-konto.</string>
<string name="my_location">Min posisjon</string>
<string name="last_updated_location">Sist oppdaterte posisjon:</string>
<string name="successfully_sent_and_updated">Sendt og oppdatert</string>
@ -235,7 +237,7 @@
<string name="privacy">Personvern</string>
<string name="shared_string_select">Velg</string>
<string name="min_logging_distance">Minste loggingsavstand</string>
<string name="min_logging_distance_descr">Filter: Minimumsdistanse til neste loggingspunkt</string>
<string name="min_logging_distance_descr">Filter: Minimumsavstand for logging av nytt punkt</string>
<string name="min_logging_accuracy">Minimumsnøyaktighet for logging</string>
<string name="min_logging_accuracy_descr">Filter: Ingen logging med mindre nøyaktigheten nås</string>
<string name="min_logging_speed">Minimumshastighet ved logging</string>
@ -248,4 +250,22 @@
<string name="shared_string_apply">Bruk</string>
<string name="set_time_timeline_descr">Velg tid å vise</string>
<string name="start_end_date">Startsluttdato</string>
<string name="saved_messages">Lagrede meldinger</string>
<string name="time_zone_descr">Velg tidssone å vise i dine plasseringsmeldinger.</string>
<string name="time_zone">Tidssone</string>
<string name="units_and_formats">Enheter og formater</string>
<string name="unit_of_length_descr">Endre hva lengde måles i.</string>
<string name="unit_of_length">Lengdeenhet</string>
<string name="unit_of_speed_system_descr">Definer en fartsenhet</string>
<string name="unit_of_speed_system">Fartsenhet</string>
<string name="buffer_time_descr">Maksimal tid å lagre punkter i mellomlageret</string>
<string name="buffer_time">Utløpstid for mellomlager</string>
<string name="shared_string_suggested">Foreslått</string>
<string name="status_widget_title">OsmAnd-sporerstatus</string>
<string name="back_to_osmand">Tilbake til OsmAnd</string>
<string name="last_update_from_telegram_date">Siste oppdatering fra Telegram: %1$s</string>
<string name="last_response_date">Siste respons: %1$s</string>
<string name="last_update_from_telegram_duration">Siste oppdatering fra Telegram: %1$s siden</string>
<string name="last_response_duration">Siste respons: %1$s siden</string>
<string name="duration_ago">%1$s siden</string>
</resources>

View file

@ -9,7 +9,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (de berichten-app) wordt gebruikt om mensen te verbinden en te communiceren met mensen.</string>
<string name="privacy_policy_telegram_client">OsmAnd-tracker is een van de app clients die het open platform van Telegram gebruiken. Uw contactpersonen kunnen elke andere Telegram-client gebruiken.</string>
<string name="privacy_policy_agree">Door op Doorgaan te klikken gaat u accoord met het privacy beleid van Telegram en van OsmAnd.</string>
<string name="privacy_policy_agree">Door op Doorgaan te klikken gaat u akkoord met het privacy beleid van zowel Telegram als OsmAnd.</string>
<string name="shared_string_accept">Aanvaard</string>
<string name="telegram_privacy_policy">Telegram privacy beleid</string>
<string name="osmand_privacy_policy">OsmAnd privacy beleid</string>
@ -169,7 +169,7 @@
<string name="initialization">Initialiseer</string>
<string name="location_service_no_gps_available">Selecteer de locatie provider waarmee u uw locatie deelt.</string>
<string name="osmand_service">Achtergrond modus</string>
<string name="osmand_service_descr">OsmAnd loopt in de achtergrond met uitgeschakeld scherm.</string>
<string name="osmand_service_descr">OsmAnd tracker loopt in de achtergrond met uitgeschakeld scherm.</string>
<string name="shared_string_distance">Afstand</string>
<string name="share_location">Deel locatie</string>
<string name="sharing_location">Locatie wordt gedeeld</string>
@ -194,17 +194,17 @@
<string name="m_s">m/s</string>
<string name="km_h">km/u</string>
<string name="mile_per_hour">mpu</string>
<string name="si_kmh">Kilometers per uur</string>
<string name="si_kmh">Kilometer per uur</string>
<string name="si_mph">Mijlen per uur</string>
<string name="si_m_s">Meters per seconde</string>
<string name="si_m_s">Meter per seconde</string>
<string name="si_min_km">Minuten per kilometer</string>
<string name="si_min_m">Minuten per mijl</string>
<string name="si_nm_h">Nautische mijlen per uur (knopen)</string>
<string name="si_mi_feet">Mijlen/voeten</string>
<string name="si_mi_yard">Mijlen/yards</string>
<string name="si_km_m">Kilometers/meters</string>
<string name="si_km_m">Kilometer/meter</string>
<string name="si_nm">Nautische mijlen</string>
<string name="si_mi_meters">Mijlen/meters</string>
<string name="si_mi_meters">Mijl/meter</string>
<string name="shared_string_hour_short">u</string>
<string name="shared_string_minute_short">min</string>
<string name="shared_string_second_short">sec</string>
@ -213,4 +213,48 @@
<string name="my_location">Mijn locatie</string>
<string name="live_now">Nu live</string>
<string name="timeline">Tijdlijn</string>
<string name="sharing_time">Tijd van delen</string>
<string name="set_visible_time_for_all">Zet zichtbare tijd voor iedereen</string>
<string name="visible_time_for_all">Zichtbare tijd voor iedereen</string>
<string name="direction">Richting</string>
<string name="precision">Nauwkeurigheid</string>
<string name="altitude">Hoogte</string>
<string name="bearing">Richting</string>
<string name="proxy_key">Sleutel</string>
<string name="proxy_password">Wachtwoord</string>
<string name="proxy_username">Gebruikersnaam</string>
<string name="proxy_credentials">(Gebruiker)gegevens</string>
<string name="proxy_port">Poort</string>
<string name="proxy_server">Server</string>
<string name="shared_string_connection">Verbinding</string>
<string name="shared_string_enable">Activeer</string>
<string name="proxy_type">Proxy soort</string>
<string name="proxy_connected">Verbonden</string>
<string name="proxy_disconnected">Niet verbonden</string>
<string name="proxy_settings">Proxy instellingen</string>
<string name="proxy">Proxy</string>
<string name="privacy">Privacy</string>
<string name="shared_string_select">Kies</string>
<string name="min_logging_distance">Minimale logging-afstand</string>
<string name="min_logging_distance_descr">Filter: minimale afstand voordat een nieuw punt gelogd wordt</string>
<string name="min_logging_accuracy">Minimale logging-nauwkeurigheid</string>
<string name="min_logging_accuracy_descr">Filter: geen logging tenzij de nauwkeurigheid bereikt is</string>
<string name="min_logging_speed">Minimale logging-snelheid</string>
<string name="min_logging_speed_descr">Filter: geen logging beneden geselecteerde snelheid</string>
<string name="gpx_settings">GPX instellingen</string>
<string name="timeline_no_data_descr">We hebben geen data verzameld op de geselecteerde dag</string>
<string name="timeline_no_data">Geen data</string>
<string name="shared_string_end">Eind</string>
<string name="shared_string_start">Start</string>
<string name="shared_string_apply">Pas toe</string>
<string name="set_time_timeline_descr">Kies te tonen tijd</string>
<string name="start_end_date">Start — Eind datum</string>
<string name="saved_messages">Bewaarde gesprekken</string>
<string name="time_zone_descr">Selecteer de te tonen tijdzone in uw locatie berichten.</string>
<string name="time_zone">Tijdzone</string>
<string name="units_and_formats">Eenheden &amp; formaten</string>
<string name="unit_of_length_descr">Wijzig de eenheid van afstand voor metingen.</string>
<string name="unit_of_length">Afstand eenheden</string>
<string name="unit_of_speed_system_descr">Definieer de eenheid voor snelheid.</string>
<string name="unit_of_speed_system">Eenheid van snelheid</string>
</resources>

View file

@ -25,7 +25,7 @@
<string name="logout_from_osmand_telegram">Wylogować się z OsmAnd Tracker\?</string>
<string name="shared_string_name">Nazwa</string>
<string name="by_distance">Według odległości</string>
<string name="by_name">Według nazwy</string>
<string name="by_name">Alfabetycznie</string>
<string name="by_group">Według grupy</string>
<string name="shared_string_sort">Sortuj</string>
<string name="shared_string_sort_by">Sortuj według</string>
@ -203,7 +203,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (aplikacji do wysyłania wiadomości) jest używana do łączenia i komunikowania się z ludźmi.</string>
<string name="privacy_policy_telegram_client">OsmAnd Tracker to jeden z klientów używających otwartej platformy Telegramu. Twoje kontrakty mogą używać innych klientów Telegramu.</string>
<string name="privacy_policy_agree">Klikając \"Kontynuuj\" zgadzam się z warunkami Polityki Prywatności Telegramu i Polityki Prywatności OsmAnd.</string>
<string name="privacy_policy_agree">Klikając \"Kontynuuj\" zgadzasz się na warunki polityki prywatności Telegramu i OsmAnd.</string>
<string name="shared_string_accept">Akceptuj</string>
<string name="telegram_privacy_policy">Polityka prywatności Telegramu</string>
<string name="osmand_privacy_policy">Polityka prywatności OsmAnd</string>
@ -250,4 +250,17 @@
<string name="shared_string_start">Start</string>
<string name="set_time_timeline_descr">Wybierz czas wyświetlania</string>
<string name="start_end_date">Daty rozpoczęcia i zakończenia</string>
<string name="saved_messages">Zapisane wiadomości</string>
<string name="time_zone">Strefa czasowa</string>
<string name="units_and_formats">Jednostki i formaty</string>
<string name="unit_of_length_descr">Zmienia jednostki długości.</string>
<string name="unit_of_length">Jednostki długości</string>
<string name="unit_of_speed_system_descr">Określ jednostkę prędkości.</string>
<string name="unit_of_speed_system">Jednostka prędkości</string>
<string name="buffer_time_descr">Maksymalny czas przechowywania punktów w buforze</string>
<string name="buffer_time">Czas ważności bufora</string>
<string name="time_zone_descr">Wybierz strefę czasową, która ma być wyświetlana w Twoich wiadomościach o lokalizacji.</string>
<string name="shared_string_suggested">Sugerowane</string>
<string name="status_widget_title">Stan nadajnika OsmAnd</string>
<string name="back_to_osmand">Wróć do OsmAnd</string>
</resources>

View file

@ -102,7 +102,7 @@
<string name="minutes_format">%1$d m</string>
<string name="hours_format">%1$d h</string>
<string name="shared_string_install">Instalar</string>
<string name="shared_string_share">Compartilhar</string>
<string name="shared_string_share">Enviar</string>
<string name="shared_string_back">Voltar</string>
<string name="visible_time_for_all">Hora visível para todos</string>
<string name="set_time_description">Defina a hora em que seus contatos e grupos selecionados verão sua localização em tempo real.</string>
@ -198,7 +198,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegrama (o aplicativo de mensagens) é usado para conectar e se comunicar com as pessoas.</string>
<string name="privacy_policy_telegram_client">OsmAnd tracker é um dos clientes que usam a Plataforma aberta do Telegram . Seus contatos podem usar qualquer outro cliente Telegram.</string>
<string name="privacy_policy_agree">Ao clicar em continuar, você concorda com as condições da política de privacidade do Telegram e da política de privacidade da OsmAnd.</string>
<string name="privacy_policy_agree">Ao clicar em \"Continuar\", você concorda com as condições da política de privacidade do Telegram- e OsmAnd.</string>
<string name="shared_string_accept">Aceitar</string>
<string name="telegram_privacy_policy">Política de privacidade do Telegram</string>
<string name="osmand_privacy_policy">"Política de privacidade do OsmAnd "</string>
@ -250,4 +250,22 @@
<string name="shared_string_apply">Aplicar</string>
<string name="set_time_timeline_descr">Selecionar a hora para exibir</string>
<string name="start_end_date">Data de início - fim</string>
<string name="saved_messages">Mensagens salvas</string>
<string name="units_and_formats">Unidades e formatos</string>
<string name="unit_of_length_descr">Altere as unidades de medida.</string>
<string name="unit_of_length">Unidades de medida</string>
<string name="time_zone_descr">Selecione o fuso horário para mostrar nas mensagens de localização.</string>
<string name="time_zone">Fuso horário</string>
<string name="unit_of_speed_system_descr">Defina a unidade de velocidade.</string>
<string name="unit_of_speed_system">Unidade de velocidade</string>
<string name="buffer_time_descr">Tempo máximo para armazenar pontos no buffer</string>
<string name="buffer_time">Tempo de expiração do buffer</string>
<string name="shared_string_suggested">Sugerido</string>
<string name="status_widget_title">Status do OsmAnd Tracker</string>
<string name="back_to_osmand">Voltar para OsmAnd</string>
<string name="last_update_from_telegram_date">Última atualização do Telegram: %1$s</string>
<string name="last_response_date">Última resposta: %1$s</string>
<string name="last_update_from_telegram_duration">Última atualização do Telegram: %1$s atrás</string>
<string name="last_response_duration">Última resposta: %1$s atrás</string>
<string name="duration_ago">%1$s atrás</string>
</resources>

View file

@ -96,9 +96,7 @@
<string name="not_possible_to_send_to_telegram_chats">Não é possível enviar para bate-papo do Telegram:</string>
<string name="not_sent_yet">Ainda não enviado</string>
<string name="points_size">%1$d pontos</string>
<string name="welcome_descr">
<b>OsmAnd Tracker</b> permite que partilhe a sua localização e veja a dos outros no OsmAnd.<br/>
<br/>O app usa a API Telegram e você precisa de uma conta Telegram.</string>
<string name="welcome_descr"><b>OsmAnd Tracker</b> permite que partilhe a sua localização e veja a dos outros no OsmAnd.<br/> <br/>O app usa a API Telegram e você precisa de uma conta do Telegram.</string>
<string name="min_logging_distance_descr">Filtro: distância mínima para registrar um novo ponto</string>
<string name="device_name_cannot_be_empty">O nome do aparelho não pode estar vazio</string>
<string name="yard">yd</string>
@ -201,7 +199,7 @@
<string name="shared_string_authorization_descr">Por favor, insira o número de telefone do seu Telegram em formato internacional</string>
<string name="set_visible_time_for_all">Definir tempo visível para todos</string>
<string name="phone_number_title">Número de telefone</string>
<string name="privacy_policy_agree">Ao clicar em continuar, você concorda com as condições da política de privacidade do Telegram e da política de privacidade da OsmAnd.</string>
<string name="privacy_policy_agree">Ao clicar em \"Continuar\" você concorda com as condições da política de privacidade do Telegram e OsmAnd.</string>
<string name="si_mi_feet">Milhas/pés</string>
<string name="monitoring_is_enabled">Monitoramento está ativado</string>
<string name="osmand_connect_desc">Escolha a versão OsmAnd que OsmAnd Tracker usa para exibir posições.</string>
@ -250,4 +248,17 @@
<string name="choose_osmand_desc">Selecione a versão OsmAnd, onde os contatos serão exibidos no mapa.</string>
<string name="si_mi_yard">Milhas/jardas</string>
<string name="initializing">Iniciando</string>
<string name="saved_messages">Mensagens gravadas</string>
<string name="time_zone_descr">Selecione o fuso horário a mostrar nas suas mensagens de localização.</string>
<string name="time_zone">Fuso horário</string>
<string name="units_and_formats">Unidades e formatos</string>
<string name="unit_of_length_descr">Alterar unidade de distância.</string>
<string name="unit_of_length">Unidades de comprimento</string>
<string name="unit_of_speed_system_descr">Definir unidade de velocidade.</string>
<string name="unit_of_speed_system">Unidade de velocidade</string>
<string name="buffer_time_descr">Tempo máximo para armazenar pontos no buffer</string>
<string name="buffer_time">Tempo de expiração do buffer</string>
<string name="shared_string_suggested">Sugerido</string>
<string name="status_widget_title">Estado do Rastreador de OsmAnd</string>
<string name="back_to_osmand">Voltar para OsmAnd</string>
</resources>

View file

@ -16,7 +16,7 @@
<string name="altitude">Altitude</string>
<string name="shared_string_search">Pesquisar</string>
<string name="shared_string_ok">Ok</string>
<string name="app_name_short">OsmAnd Tracker</string>
<string name="app_name_short">Rastreador OsmAnd</string>
<string name="shared_string_telegram">Telegram</string>
<string name="shared_string_appearance">Aparência</string>
<string name="shared_string_update">Atualizar</string>
@ -60,7 +60,7 @@
<string name="timeline_description">Ative o monitoramento para salvar todos os locais no histórico.</string>
<string name="privacy_policy_use_telegram">Telegrama (o aplicativo de mensagens) é usado para conectar e se comunicar com as pessoas.</string>
<string name="privacy_policy_telegram_client">OsmAnd tracker é um dos clientes que usam a Plataforma aberta do Telegram . Seus contatos podem usar qualquer outro cliente Telegram.</string>
<string name="privacy_policy_agree">Ao clicar em continuar, você concorda com as condições da política de privacidade do Telegram e da política de privacidade da OsmAnd.</string>
<string name="privacy_policy_agree">Ao clicar em \"Continuar\" você concorda com as condições da política de privacidade do Telegram e OsmAnd.</string>
<string name="shared_string_accept">Aceitar</string>
<string name="telegram_privacy_policy">Política de privacidade do Telegram</string>
<string name="osmand_privacy_policy">Política de privacidade do OsmAnd</string>
@ -249,4 +249,17 @@
<string name="my_location">Minha localização</string>
<string name="live_now">Ao vivo agora</string>
<string name="timeline">Cronologia</string>
<string name="saved_messages">Mensagens gravadas</string>
<string name="time_zone_descr">Selecione o fuso horário para mostrar nas suas mensagens de localização.</string>
<string name="time_zone">Fuso horário</string>
<string name="units_and_formats">Unidades e formatos</string>
<string name="unit_of_length_descr">Alterar unidade de medida de distância.</string>
<string name="unit_of_length">Unidades de comprimento</string>
<string name="unit_of_speed_system_descr">Definir unidade de velocidade.</string>
<string name="unit_of_speed_system">Unidade de velocidade</string>
<string name="buffer_time_descr">Tempo máximo para armazenar pontos no buffer</string>
<string name="buffer_time">Tempo de expiração do buffer</string>
<string name="shared_string_suggested">Sugerido</string>
<string name="status_widget_title">Estado do Rastreador de OsmAnd</string>
<string name="back_to_osmand">Voltar para OsmAnd</string>
</resources>

View file

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="timeline_available_for_free_now">"Попробуйте функцию Хронология бесплатно.</string>
<string name="timeline_available_for_free_now">Хронология теперь доступна бесплатно.</string>
<string name="location_recording_enabled">Запись местоположений включена</string>
<string name="privacy_policy_use_telegram">Telegram (менеджер сообщений) используется для связи и общения с людьми.</string>
<string name="privacy_policy_telegram_client">OsmAnd Tracker является одним из клиентов, использующих открытую платформу Telegram. Ваши контакты могут использовать любой другой клиент Telegram.</string>
<string name="privacy_policy_agree">Нажимая продолжить, вы соглашаетесь с условиями политики конфиденциальности Telegram и OsmAnd.</string>
<string name="privacy_policy_agree">Нажимая \"Продолжить\", вы соглашаетесь с условиями политики конфиденциальности Telegram и OsmAnd.</string>
<string name="timeline_description">Включите мониторинг, чтобы сохранять все местоположения в истории.</string>
<string name="last_update_from_telegram">Последнее обновление в Telegram</string>
<string name="device_name">Имя устройства</string>
<string name="shared_string_hide">Спрятать</string>
<string name="shared_string_hide">Скрыть</string>
<string name="share_location_as_description_second_line">Вы можете создать и просмотреть идентификатор устройства в клиенте telegram, используя %1$s чат бота. %2$s</string>
<string name="logout_no_internet_msg">Подключитесь к Интернету, чтобы правильно выйти из Telegram.</string>
<string name="set_visible_time_for_all">Установить видимое время для всех</string>
@ -25,7 +25,7 @@
<string name="no_location_permission">Приложение не имеет разрешения на доступ к данным о местоположении.</string>
<string name="gps_not_available">Пожалуйста, включите «Местоположение» в системных настройках</string>
<string name="location_service_no_gps_available">Выберите один из провайдеров определения местоположения, чтобы поделиться своим местоположением.</string>
<string name="background_work">Работа в фоне</string>
<string name="background_work">Фоновый режим</string>
<string name="battery_optimization_description">Отключите оптимизацию батареи для OsmAnd Tracker, чтобы не было внезапного отключения в фоновом режиме.</string>
<string name="osmand_service">Фоновый режим</string>
<string name="osmand_service_descr">OsmAnd Tracker работает в фоновом режиме с выключенным экраном.</string>
@ -95,7 +95,7 @@
<string name="show_on_map">Показать на карте</string>
<string name="open_osmand">Открыть OsmAnd</string>
<string name="shared_string_all">Все</string>
<string name="shared_string_off">Отключить</string>
<string name="shared_string_off">Выкл.</string>
<string name="shared_string_settings">Настройки</string>
<string name="sharing_time">Время трансляции</string>
<string name="turn_off_location_sharing">Отключить трансляцию</string>
@ -109,7 +109,7 @@
<string name="successfully_sent_and_updated">Успешно отправлено и обновлено</string>
<string name="not_possible_to_send_to_telegram_chats">Невозможно отправить Telegram чаты:</string>
<string name="waiting_for_response_from_telegram">Ожидание ответа от Telegram</string>
<string name="searching_for_gps">Поиск GPS</string>
<string name="searching_for_gps">Поиск GPS</string>
<string name="connecting_to_the_internet">Подключение к Интернету</string>
<string name="background_work_description">Измените настройки оптимизации батареи, чтобы обеспечить стабильную отправку местоположения.</string>
<string name="location_history">История местоположений</string>
@ -121,7 +121,7 @@
<string name="location_history_desc">Скройте контакты, которые не обновили свое местоположение за определенный промежуток времени.</string>
<string name="share_location_as">Поделиться местоположением как</string>
<string name="share_location_as_description">Если вы хотите подключить несколько устройств к одной учетной записи Telegram, вам необходимо использовать другое устройство для трансляции местоположения.</string>
<string name="osmand_connect_desc">Выберите версию OsmAnd которую OsmAnd Tracker использует для отображения позиций на карте.</string>
<string name="osmand_connect_desc">Выберите версию OsmAnd которую OsmAnd Tracker использует для отображения положений на карте.</string>
<string name="osmand_connect">OsmAnd подключение</string>
<string name="connected_account">Связанная учетная запись</string>
<string name="shared_string_account">Учетная запись</string>
@ -129,21 +129,21 @@
<string name="install_osmand_dialog_message">Вам необходимо сначала установить бесплатную или платную версию OsmAnd</string>
<string name="disconnect_from_telegram">Как отключить OsmAnd Tracker от Telegram</string>
<string name="logout_help_desc">Как отключить OsmAnd Tracker от Telegram</string>
<string name="disconnect_from_telegram_desc">Отмена доступа к отправке локаций. Откройте Telegram, перейдите в Настройки - Конфиденциальность и безопасность - Сессии и завершите сеанс OsmAnd Tracker.</string>
<string name="disconnect_from_telegram_desc">Для отзыва доступа к трансляции местоположения. Откройте Telegram, перейдите в Настройки → Конфиденциальность и безопасность → Активные сессии, и завершите сессию OsmAnd Tracker.</string>
<string name="logout_from_osmand_telegram">Выйти из OsmAnd Tracker?</string>
<string name="shared_string_login">Войти</string>
<string name="shared_string_logout">Выйти</string>
<string name="logout_from_osmand_telegram_descr">Вы уверены, что хотите выйти из OsmAnd Tracker, так вы не сможете делиться местоположением или не видеть местоположения других?</string>
<string name="logout_from_osmand_telegram_descr">Вы уверены, что хотите выйти из OsmAnd Tracker\? Выйдя из приложения, вы не сможете делиться местоположением или не видеть местоположения других.</string>
<string name="not_found_yet">Не найдено</string>
<string name="re_send_location">Отправить местоположение</string>
<string name="last_available_location">Последнее местоположение</string>
<string name="sharing_status">Статус отправки</string>
<string name="location_sharing_status">Трансляция: %1$s</string>
<string name="shared_string_enabled">включена</string>
<string name="shared_string_enabled">Включен</string>
<string name="shared_string_status">Статус</string>
<string name="no_gps_connection">Отсутствует GPS</string>
<string name="no_internet_connection">Отсутствует интернет</string>
<string name="shared_string_disable">Выкл.</string>
<string name="shared_string_disable">Выключить</string>
<string name="shared_string_save">Сохранить</string>
<string name="add_device">Добавить устройство</string>
<string name="go_to_settings">Перейти в настройки</string>
@ -181,7 +181,7 @@
<string name="shared_string_map">Карта</string>
<string name="shared_string_text">Текст</string>
<string name="map_and_text">Карта и текст</string>
<string name="stop_sharing_all">Совместное использование включено (выключено)</string>
<string name="stop_sharing_all">Совместное использование включено (выключить)</string>
<string name="my_location_search_hint">Поиск: группа или контакт</string>
<string name="app_name">OsmAnd Online GPS Tracker</string>
<string name="logging_out">Выход</string>
@ -193,7 +193,7 @@
<string name="foot">фут</string>
<string name="km">км</string>
<string name="m">м</string>
<string name="nm">мор. мл</string>
<string name="nm">мор. миля</string>
<string name="min_mile">мин/м</string>
<string name="min_km">мин/км</string>
<string name="nm_h">nmi/ч</string>
@ -222,14 +222,45 @@
<string name="proxy_server">Сервер</string>
<string name="shared_string_connection">Соединение</string>
<string name="proxy_type">Тип прокси</string>
<string name="proxy_connected">Подключено</string>
<string name="proxy_disconnected">Отключено</string>
<string name="proxy_connected">Соединено</string>
<string name="proxy_disconnected">Разъединено</string>
<string name="proxy_settings">Настройки прокси</string>
<string name="proxy">Прокси</string>
<string name="gpx_settings">настройки GPX</string>
<string name="gpx_settings">Настройки GPX</string>
<string name="timeline_no_data_descr">Нет собранных данных за выбранный день</string>
<string name="timeline_no_data">Нет данных</string>
<string name="shared_string_apply">Применить</string>
<string name="start_end_date">Дата начала - окончания</string>
<string name="shared_string_enable">Вкл.</string>
<string name="start_end_date">Дата начала — окончания</string>
<string name="shared_string_enable">Включить</string>
<string name="mile">миля</string>
<string name="mile_per_hour">миль/ч</string>
<string name="altitude">Высота</string>
<string name="bearing">Ориентация</string>
<string name="proxy_key">Ключ</string>
<string name="proxy_password">Пароль</string>
<string name="proxy_username">Имя пользователя</string>
<string name="privacy">Приватность</string>
<string name="shared_string_select">Выбрать</string>
<string name="min_logging_distance">Минимальное расстояние регистрации</string>
<string name="min_logging_distance_descr">Фильтр: минимальное расстояние, необходимое для регистрации новой точки</string>
<string name="min_logging_accuracy">Минимальная точность регистрации</string>
<string name="min_logging_accuracy_descr">Фильтр: не регистрировать, пока не достигнута необходимая точность</string>
<string name="min_logging_speed">Минимальная скорость регистрации</string>
<string name="min_logging_speed_descr">Фильтр: не регистрировать, пока не достигнута необходимая скорость</string>
<string name="shared_string_end">Конец</string>
<string name="shared_string_start">Начало</string>
<string name="set_time_timeline_descr">Выберите время для отображения</string>
<string name="saved_messages">Сохраненные сообщения</string>
<string name="time_zone_descr">Выберите часовой пояс, чтобы показывать время вашего местоположения в сообщениях.</string>
<string name="time_zone">Часовой пояс</string>
<string name="units_and_formats">Единицы измерения и форматы</string>
<string name="unit_of_length_descr">Изменить единицу измерения расстояния.</string>
<string name="unit_of_length">Единицы измерения расстояния</string>
<string name="unit_of_speed_system_descr">Выберите единицу измерения скорости.</string>
<string name="unit_of_speed_system">Единица измерения скорости</string>
<string name="buffer_time_descr">Максимальное время хранения точек в буфере</string>
<string name="buffer_time">Срок действия буфера</string>
<string name="shared_string_suggested">Предложено</string>
<string name="status_widget_title">Статус OsmAnd Tracker</string>
<string name="back_to_osmand">Вернуться к OsmAnd</string>
</resources>

View file

@ -197,7 +197,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (s\'aplicatzione pro sos messàgios) benit impreadu pro cunnètere e fàghere comunicare sa gente.</string>
<string name="privacy_policy_telegram_client">OsmAnd Tracker est una de sas aplicatziones clientes chi impreant sa prataforma aberta de Telegram. Sos cuntatos tuos podent impreare cale si siat àtera aplicatzione cliente de Telegram.</string>
<string name="privacy_policy_agree">Incarchende \"sighi\" atzetas sas cunditziones de sa Polìtica de Riservadesa de Telegram e de cussa de OsmAnd.</string>
<string name="privacy_policy_agree">Incarchende \"Sighi\" atzetas sas cunditziones de sa Polìtica de Riservadesa de Telegram e de OsmAnd.</string>
<string name="shared_string_accept">Atzeta</string>
<string name="telegram_privacy_policy">Polìtica de riservadesa de Telegram</string>
<string name="osmand_privacy_policy">Polìtica de riservadesa de OsmAnd</string>
@ -233,7 +233,7 @@
<string name="proxy_settings">Impostatziones de su servidore intermediàriu</string>
<string name="proxy">Servidore intermediàriu (proxy)</string>
<string name="privacy">Privadesa</string>
<string name="bearing">Andamentu</string>
<string name="bearing">Orientamentu</string>
<string name="shared_string_select">Seletziona</string>
<string name="min_logging_distance">Distàntzia mìnima de registratzione</string>
<string name="min_logging_distance_descr">FIltru: distàntzia mìnima pro registrare unu puntu nou</string>
@ -245,8 +245,26 @@
<string name="timeline_no_data_descr">Non tenimus datos collidos pro sa die ischertada</string>
<string name="timeline_no_data">Perunu datu</string>
<string name="shared_string_end">Acaba</string>
<string name="shared_string_start">Incumintza</string>
<string name="shared_string_start">Allughe</string>
<string name="shared_string_apply">Àplica</string>
<string name="set_time_timeline_descr">Ischerta su tempus de ammustrare</string>
<string name="start_end_date">Data de incumintzu — de acabu</string>
<string name="saved_messages">Messàgios sarvados</string>
<string name="time_zone_descr">Issèbera su fusu oràriu de ammustrare in sos messàgios de positzione tuos.</string>
<string name="time_zone">Fusu oràriu</string>
<string name="units_and_formats">Unidades e formados</string>
<string name="unit_of_length_descr">Muda s\'unidade de mèdida pro sa distàntzia.</string>
<string name="unit_of_length">Unidades de longària</string>
<string name="unit_of_speed_system_descr">Issèbera s\'unidade de letresa.</string>
<string name="unit_of_speed_system">Unidade de lestresa</string>
<string name="buffer_time_descr">Tempus màssimu de archiviatzione de sos puntos in sa memòria tampone (buffer)</string>
<string name="buffer_time">Tempus de iscadidura de sa memòria tampone</string>
<string name="shared_string_suggested">Cunsigiadu</string>
<string name="status_widget_title">Istadu de s\'arrastadore de OsmAnd</string>
<string name="back_to_osmand">Torra a OsmAnd</string>
<string name="last_update_from_telegram_date">Ùrtimu agiornamentu dae Telegram: %1$s</string>
<string name="last_response_date">Ùrtima risposta: %1$s</string>
<string name="last_update_from_telegram_duration">Ùrtimu agiornamentu dae Telegram: %1$s a como</string>
<string name="last_response_duration">Ùrtima risposta: %1$s a como</string>
<string name="duration_ago">%1$s a como</string>
</resources>

View file

@ -206,4 +206,6 @@
<string name="gps_points_in_buffer">poslano (%1$d v medpomnilniku)</string>
<string name="timeline_available_for_free_now">Časovnica je od sedaj na voljo brezplačno.</string>
<string name="location_recording_enabled">Beleženje trenutnega mesta je omogočeno</string>
<string name="units_and_formats">Enote in zapisi</string>
<string name="unit_of_length_descr">Izbor enote za prikaz razdalje.</string>
</resources>

View file

@ -49,4 +49,8 @@
<string name="si_nm">Наутичке миље</string>
<string name="si_mi_meters">Миље/метри</string>
<string name="shared_string_apply">Примени</string>
<string name="shared_string_enabled">Укључен</string>
<string name="units_and_formats">Мерне јединице &amp; форматирања</string>
<string name="unit_of_length_descr">Промени јединице за дужину.</string>
<string name="unit_of_length">Јединице дужине</string>
</resources>

View file

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="shared_string_apply">Uygula</string>
<string name="shared_string_select">Seç</string>
<string name="shared_string_enable">Etkinleştir</string>
<string name="altitude">Rakım</string>
<string name="shared_string_search">Arama</string>
<string name="shared_string_ok">Tamam</string>
<string name="shared_string_update">Güncelle</string>
<string name="average_altitude">Ortalama yükseklik</string>
<string name="average_speed">Ortalama hız</string>
<string name="shared_string_map">Harita</string>
<string name="shared_string_add">Ekle</string>
<string name="shared_string_hide">Gizle</string>
<string name="shared_string_later">Daha sonra</string>
<string name="shared_string_enabled">Etkin</string>
<string name="shared_string_status">Durum</string>
<string name="shared_string_disable">Devre dışı bırak</string>
<string name="shared_string_save">Kaydet</string>
<string name="shared_string_name">İsim</string>
<string name="shared_string_sort">Sırala</string>
<string name="shared_string_exit">Çıkış</string>
<string name="shared_string_close">Kapat</string>
<string name="shared_string_all">Tümü</string>
<string name="shared_string_off">Kapalı</string>
<string name="shared_string_install">Yükle</string>
<string name="shared_string_share">Paylaş</string>
<string name="shared_string_back">Geri</string>
<string name="shared_string_continue">Devam et</string>
<string name="shared_string_cancel">İptal</string>
<string name="shared_string_settings">Ayarlar</string>
<string name="osmand_service">Arka plan modu</string>
<string name="shared_string_distance">Mesafe</string>
<string name="yard">yd</string>
<string name="foot">ft</string>
<string name="mile">mi</string>
<string name="km">km</string>
<string name="m">m</string>
<string name="nm">nmi</string>
<string name="min_mile">min/m</string>
<string name="min_km">min/km</string>
<string name="nm_h">nmi/h</string>
<string name="m_s">m/s</string>
<string name="km_h">km/h</string>
<string name="mile_per_hour">mph</string>
<string name="si_kmh">Kilometre/saat</string>
<string name="si_mph">Mil/saat</string>
<string name="si_m_s">Metre/saniye</string>
<string name="si_min_km">Dakika/kilometre</string>
<string name="si_min_m">Dakika/mil</string>
<string name="si_nm_h">Deniz mili/saat (knot)</string>
<string name="si_mi_feet">Mil/feet</string>
<string name="si_mi_yard">Mil/yard</string>
<string name="si_km_m">Kilometre/metre</string>
<string name="si_nm">Deniz mili</string>
<string name="si_mi_meters">Mil/metre</string>
<string name="shared_string_end">Bitiş</string>
<string name="shared_string_start">Başlangıç</string>
<string name="set_time_timeline_descr">Görüntülemek için zaman seçin</string>
<string name="start_end_date">Başlangıç — Bitiş tarihi</string>
<string name="timeline_no_data_descr">Seçilen gün için toplanan veri yok</string>
<string name="timeline_no_data">Veri yok</string>
<string name="min_logging_distance">Minimum kayıt mesafesi</string>
<string name="min_logging_distance_descr">Filtre: yeni bir nokta kaydetmek için minimum mesafe</string>
<string name="min_logging_accuracy">Minimum kayıt hassasiyeti</string>
<string name="min_logging_accuracy_descr">Filtre: hassasiyete ulaşılmadığı sürece kaydetme yok</string>
<string name="min_logging_speed">Minimum kayıt hızı</string>
<string name="min_logging_speed_descr">Filtre: seçili hızın altında kaydetme yok</string>
<string name="gpx_settings">GPX ayarları</string>
<string name="proxy_key">Anahtar</string>
<string name="proxy_password">Parola</string>
<string name="proxy_username">Kullanıcı adı</string>
<string name="proxy_credentials">Kimlik bilgileri</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Sunucu</string>
<string name="shared_string_connection">Bağlantı</string>
<string name="proxy_type">Proxy türü</string>
<string name="proxy_connected">Bağlandı</string>
<string name="proxy_disconnected">Bağlantı kesildi</string>
<string name="proxy_settings">Proxy Ayarları</string>
<string name="proxy">Proxy</string>
<string name="privacy">Gizlilik</string>
<string name="direction">Yön</string>
<string name="precision">Hassaslık</string>
<string name="search_contacts">Kişileri ara</string>
<string name="search_contacts_descr">Tüm gruplarınızda ve kişilerinizde arayın.</string>
<string name="type_contact_or_group_name">Kişi veya grup adı yazın</string>
<string name="timeline_available_for_free_now">Zaman çizelgesi artık ücretsiz olarak kullanılabilen bir özelliktir.</string>
<string name="disable_monitoring">İzlemeyi devre dışı bırak</string>
<string name="location_recording_enabled">Konum kaydı etkin</string>
<string name="timeline_description">Tüm konumları geçmişe kaydetmek için izlemeyi etkinleştirin.</string>
<string name="app_name_short">OsmAnd Tracker</string>
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (mesajlaşma uygulaması) insanlarla bağlantı ve iletişim kurmak için kullanılmaktadır.</string>
<string name="privacy_policy_telegram_client">OsmAnd Tracker, Telegram açık platformunu kullanan istemcilerden biridir. Kişileriniz başka herhangi bir Telegram istemcisini kullanabilir.</string>
<string name="privacy_policy_agree">\"Devam et\" butonuna tıklayarak, Telegram ve OsmAnd Gizlilik Politikası koşullarını kabul etmiş olursunuz.</string>
<string name="shared_string_accept">Kabul et</string>
<string name="telegram_privacy_policy">Telegram Gizlilik Politikası</string>
<string name="osmand_privacy_policy">OsmAnd Gizlilik Politikası</string>
<string name="how_it_works">Nasıl çalışır</string>
<string name="received_gps_points">Alınan GPX noktaları: %1$s</string>
<string name="shared_string_appearance">Görünüm</string>
<string name="show_gps_points">GPS noktalarını göster</string>
<string name="show_gps_points_descr">Toplanan ve gönderilen GPS noktalarının miktarını göster.</string>
<string name="please_update_osmand">Verileri haritada görüntülemek için lütfen OsmAnd\'ı güncelleyin</string>
<string name="bearing">Konum açısı</string>
<string name="gps_points_in_buffer">gönderilen (%1$d arabellekte)</string>
<string name="points_size">%1$d nokta</string>
<string name="shared_string_date">Tarih</string>
<string name="shared_string_collected">Toplanmış</string>
<string name="gps_points">GPS noktaları</string>
<string name="shared_string_sent">Gönderilen</string>
<string name="monitoring_is_enabled">İzleme etkin</string>
<string name="monitoring_is_disabled">İzleme devre dışı</string>
<string name="time_on_the_move">Hareket zamanı</string>
<string name="open_in_osmand">OsmAnd\'da göster</string>
<string name="end_date">Bitiş tarihi</string>
<string name="start_date">Başlangıç tarihi</string>
<string name="send_location_as">Konum gönderme biçimi</string>
<string name="send_location_as_descr">Konumunuzdaki mesajların nasıl görüneceğini seçin.</string>
<string name="shared_string_text">Metin</string>
<string name="map_and_text">Harita ve metin</string>
<string name="last_update_from_telegram">Telegram\'dan son güncelleme</string>
<string name="enter_another_device_name">Daha önce kullanmadığınız bir isim seçin</string>
<string name="device_added_successfully">%1$s eklendi.</string>
<string name="error_adding_new_device">Yeni cihaz eklenemedi</string>
<string name="enter_device_name_description">Yeni cihazınıza en fazla 200 sembolden oluşan bir isim verin.</string>
<string name="device_name_is_too_long">Cihaz adı çok uzun</string>
<string name="device_name_cannot_be_empty">Cihaz adı boş olamaz</string>
<string name="device_name">Cihaz adı</string>
<string name="share_location_as_description_second_line">%1$s sohbet botunu kullanarak Cihaz kimliğini Telegram istemcisinde oluşturabilir ve görüntüleyebilirsiniz. %2$s</string>
<string name="share_location_as_description">Bir Telegram hesabına birden fazla cihaz bağlamak istiyorsanız, konumunuzu paylaşmak için farklı Cihaz kullanmanız gerekmektedir.</string>
<string name="last_updated_location">Son güncellenen konum:</string>
<string name="successfully_sent_and_updated">Başarıyla gönderildi ve güncellendi</string>
<string name="not_possible_to_send_to_telegram_chats">Telegram sohbetlerine göndermek mümkün değil:</string>
<string name="waiting_for_response_from_telegram">Telegram\'dan cevap bekleniyor</string>
<string name="sending_location_messages">Konum gönderiliyor</string>
<string name="initializing">Başlatılıyor</string>
<string name="searching_for_gps">Konumlandırılıyor…</string>
<string name="connecting_to_the_internet">İnternete bağlanılıyor</string>
<string name="background_work_description">Konum paylaşımını stabilize etmek için pil optimizasyon ayarlarını değiştirin.</string>
<string name="background_work">Arka plan çalışması</string>
<string name="battery_optimization_description">Arka planda iken aniden kapanmaması için OsmAnd Tracker için pil optimizasyonunu kapatın.</string>
<string name="sharing_in_background">Arka planda paylaşma</string>
<string name="go_to_settings">Ayarlara git</string>
<string name="not_sent_yet">Henüz gönderilmedi</string>
<string name="not_found_yet">Henüz bulunamadı</string>
<string name="re_send_location">Konumu tekrar gönder</string>
<string name="last_available_location">Son kullanılabilir konum</string>
<string name="sharing_status">Paylaşım durumu</string>
<string name="location_sharing_status">Paylaşım: %1$s</string>
<string name="no_gps_connection">GPS bağlantısı yok</string>
<string name="no_internet_connection">İnternet bağlantısı yok</string>
<string name="add_device">Cihaz ekle</string>
<string name="share_location_as">Konum paylaşma biçimi</string>
<string name="live_now_description">Sizinle konum paylaşımı yapan kişi ve gruplar.</string>
<string name="logout_from_osmand_telegram_descr">OsmAnd Tracker\'dan çıkış yapmak istediğinizden emin misiniz, bu durumda konum paylaşamaz veya başkalarının yerlerini göremezsiniz\?</string>
<string name="logout_from_osmand_telegram">OsmAnd Tracker oturumu kapatılsın mı\?</string>
<string name="by_distance">Mesafeye göre</string>
<string name="by_name">Ada göre</string>
<string name="by_group">Gruba göre</string>
<string name="shared_string_sort_by">Sıralama kriteri</string>
<string name="choose_osmand_desc">Kişilerin haritada görüntüleneceği OsmAnd versiyonunu seçin.</string>
<string name="choose_osmand">Kullanılacak OsmAnd versiyonunu seçin</string>
<string name="disable_all_sharing_desc">Konum paylaşımını tüm seçili sohbetlere kapatır (%1$d).</string>
<string name="disable_all_sharing">Tüm paylaşımı devre dışı bırak</string>
<string name="turn_off_all">Hepsini kapat</string>
<string name="time_ago">önce</string>
<string name="last_response">Son cevap</string>
<string name="shared_string_group">Grup</string>
<string name="logout_no_internet_msg">Telegram\'dan düzgün bir şekilde çıkış yapmak için Internet\'e bağlanın.</string>
<string name="disconnect_from_telegram_desc">Konum paylaşma erişimini iptal etmek için. Telegram\'ıın, Ayarlar → Gizlilik ve Güvenlik → Oturumlar\'a gidin ve OsmAnd Tracker oturumunu sonlandırın.</string>
<string name="saved_messages">Kaydedilen mesajlar</string>
<string name="disconnect_from_telegram">Telegram\'dan OsmAnd Tracker nasıl kapatılır</string>
<string name="logout_help_desc">Telegram\'dan OsmAnd Tracker nasıl kapatılır</string>
<string name="connected_account">Bağlı hesap</string>
<string name="shared_string_account">Hesap</string>
<string name="in_time">%1$s içinde</string>
<string name="osmand_connect_desc">Konumları görüntülemek için OsmAnd Tracker\'ın kullandığı OsmAnd versiyonunu seçin.</string>
<string name="osmand_connect">OsmAnd bağlan</string>
<string name="location_history_desc">Belirli bir süre içinde hareket etmemiş kişileri gizle.</string>
<string name="location_history">Konum geçmişi</string>
<string name="stale_location_desc">Bir kişinin en son hareket ettiği zaman.</string>
<string name="stale_location">Hareket etmiyor</string>
<string name="send_my_location_desc">Konum paylaşımı için minimum aralığı ayarlayın.</string>
<string name="send_my_location">Konumumu gönder</string>
<string name="gps_and_location">Konum</string>
<string name="sharing_time">Paylaşım zamanı</string>
<string name="expire_at">Süre sonu</string>
<string name="stop_sharing_all">Paylaşım açık (kapat)</string>
<string name="turn_off_location_sharing">Konum paylaşımını kapat</string>
<string name="open_osmand">OsmAnd\'ı</string>
<string name="shared_string_live">Canlı</string>
<string name="shared_string_bot">Bot</string>
<string name="get_telegram_title">Telegram kaydı</string>
<string name="get_telegram_account_first">Konum paylaşımını kullanmak için bir Telegram hesabına ihtiyacınız var.</string>
<string name="get_telegram_description_continue">Lütfen Telegram\'ı yükleyin ve bir hesap oluşturun.</string>
<string name="get_telegram_after_creating_account">Daha sonra bu uygulamayı kullanabilirsiniz.</string>
<string name="already_registered_in_telegram">Kayıtlı bir Telegram hesabına ve telefon numarasına ihtiyacınız var</string>
<string name="do_not_have_telegram">Telegram hesabım yok</string>
<string name="enter_phone_number">Telefon numarasını girin</string>
<string name="enter_authentication_code">Kimlik doğrulama kodunu girin</string>
<string name="set_visible_time_for_all">Herkes için görünür zamanı ayarla</string>
<string name="hours_and_minutes_format">%1$d sa %2$d dk</string>
<string name="minutes_format">%1$d dk</string>
<string name="hours_format">%1$d sa</string>
<string name="visible_time_for_all">Herkes için görünür zaman</string>
<string name="set_time_description">Seçtiğiniz kişilerin ve grupların konumunuzu gerçek zamanlı olarak göreceği zamanı ayarlayın.</string>
<string name="set_time">Zamanı ayarla</string>
<string name="location_sharing_description">Konumunuzu paylaşmak istediğiniz kişileri ve grupları seçin.</string>
<string name="my_location_search_hint">Ara: Grup veya kişi</string>
<string name="start_location_sharing">Konumu paylaş</string>
<string name="show_on_map">Haritada göster</string>
<string name="app_name">OsmAnd Çevrim İçi GPS İzleyici</string>
<string name="phone_number_title">Telefon numarası</string>
<string name="phone_number_descr">Uluslararası formatta telefon numarası</string>
<string name="shared_string_password">Parola</string>
<string name="enter_code">Kodu girin</string>
<string name="authentication_code">Kimlik doğrulama kodu</string>
<string name="authentication_code_descr">Telegram, OsmAnd için hesabınıza bir giriş yapma kodu gönderdi.</string>
<string name="enter_password">Parola girin</string>
<string name="password_descr">Telegram parolası</string>
<string name="shared_string_login">Oturum aç</string>
<string name="shared_string_logout">Oturumu kapat</string>
<string name="initialization">Başlatılıyor</string>
<string name="logging_out">Çıkış yapılıyor</string>
<string name="closing">Kapatılıyor</string>
<string name="gps_network_not_enabled">\"Konum\" açılsın mı\?</string>
<string name="not_logged_in">Oturum açmadınız</string>
<string name="no_location_permission">Uygulamanın konum verilerine erişim izni yok.</string>
<string name="gps_not_available">Lütfen sistem ayarlarından \"Konum\"u açın</string>
<string name="location_service_no_gps_available">Konumunuzu paylaşmak için konum sağlayıcılardan birini seçin.</string>
<string name="osmand_service_descr">OsmAnd Tracker, ekran kapalıyken arka planda çalışır.</string>
<string name="share_location">Konumu paylaş</string>
<string name="sharing_location">Konum paylaşılıyor</string>
<string name="process_service">OsmAnd Tracker servisi</string>
<string name="osmand_logo">OsmAnd logosu</string>
<string name="install_osmand_dialog_message">Önce OsmAnd\'ın ücretsiz veya ücretli sürümünü yüklemeniz gerekmektedir</string>
<string name="install_osmand">OsmAnd\'ı yükle</string>
<string name="show_users_on_map">Kullanıcıları haritada göster</string>
<string name="active_chats">Aktif sohbetler</string>
<string name="shared_string_authorization">Yetkilendirme</string>
<string name="shared_string_authorization_descr">Lütfen Telegram telefon numaranızı uluslararası formatta girin</string>
<string name="shared_string_welcome">Hoşgeldiniz</string>
<string name="shared_string_hour_short">sa</string>
<string name="shared_string_minute_short">dk</string>
<string name="shared_string_second_short">sn</string>
<string name="welcome_descr"><b>OsmAnd Tracker</b> konumunuzu paylaşmanıza ve OsmAnd\'daki diğer kişileri görmenize olanak sağlar.<br/><br/>Uygulama Telegram API\'sini kullanmaktadır, bu nedenle bir Telegram hesabına ihtiyacınız vardır.</string>
<string name="my_location">Konumum</string>
<string name="live_now">Şimdi canlı</string>
<string name="timeline">Zaman çizelgesi</string>
<string name="time_zone_descr">Konum mesajlarınızda gösterilecek saat dilimini seçin.</string>
<string name="time_zone">Saat dilimi</string>
<string name="units_and_formats">Birimler ve formatlar</string>
<string name="unit_of_length_descr">Mesafe ölçüm birimini değiştir.</string>
<string name="unit_of_length">Uzunluk birimleri</string>
<string name="unit_of_speed_system_descr">Hız birimini tanımlayın.</string>
<string name="unit_of_speed_system">Hız birimi</string>
<string name="buffer_time_descr">Noktaların arabellekte saklanacağı maksimum süre</string>
<string name="buffer_time">Arabellek zaman aşım süresi</string>
<string name="shared_string_suggested">Önerilen</string>
<string name="status_widget_title">OsmAnd Tracker durumu</string>
<string name="back_to_osmand">OsmAnd\'a geri dön</string>
<string name="last_update_from_telegram_date">Telegram\'dan son güncelleme: %1$s</string>
<string name="last_response_date">Son cevap: %1$s</string>
<string name="last_update_from_telegram_duration">Telegram\'dan son güncelleme: %1$s önce</string>
<string name="last_response_duration">Son cevap: %1$s önce</string>
<string name="duration_ago">%1$s önce</string>
</resources>

View file

@ -31,7 +31,7 @@
<string name="last_available_location">Крайнє доступне позиціювання</string>
<string name="sharing_status">Стан трансляції</string>
<string name="location_sharing_status">Трансляція: %1$s</string>
<string name="shared_string_enabled">Увімкнута</string>
<string name="shared_string_enabled">Увімкнено</string>
<string name="shared_string_status">Статус</string>
<string name="no_gps_connection">Немає зʼєднання із GPS</string>
<string name="no_internet_connection">Немає зʼєднання із інтернетом</string>
@ -81,7 +81,7 @@
<string name="get_telegram_description_continue">Будь ласка, встановіть Telegram та налаштуйте обліковий запис.</string>
<string name="get_telegram_after_creating_account">Тоді Ви зможете використовувати цей додаток.</string>
<string name="shared_string_all">Всі</string>
<string name="shared_string_off">Вимкнути</string>
<string name="shared_string_off">Вимк.</string>
<string name="already_registered_in_telegram">Вам необхідно мати зареєстрований обліковий запис Telegram та номер телефону</string>
<string name="do_not_have_telegram">Я не маю облікового запису Telegram</string>
<string name="enter_phone_number">Введіть номер телефону</string>
@ -249,5 +249,23 @@
<string name="min_logging_accuracy">Мінімальна точність реєстрації</string>
<string name="min_logging_accuracy_descr">Фільтр: реєстрація не проводиться, якщо не досягнуто точності</string>
<string name="min_logging_speed">Мінімальна швидкість реєстрації</string>
<string name="min_logging_speed_descr">Фільтр: не реєструвати, якщо швидкість меньша за обрану</string>
<string name="min_logging_speed_descr">Фільтр: не реєструвати, якщо швидкість менша за обрану</string>
<string name="saved_messages">Збережені повідомлення</string>
<string name="time_zone_descr">Оберіть часовий пояс щоб відобразити повідомлення у вашому розташуванні.</string>
<string name="time_zone">Часовий пояс</string>
<string name="units_and_formats">Одиниця вимірювання та формати</string>
<string name="unit_of_length">Одиниці вимірювання довжини</string>
<string name="unit_of_length_descr">Змінити одиницю вимірювання відстані.</string>
<string name="unit_of_speed_system_descr">Визначити одиницю швидкості.</string>
<string name="unit_of_speed_system">Одиниця вимірювання швидкості</string>
<string name="buffer_time_descr">Найбільший час зберігання точок у буфері</string>
<string name="buffer_time">Термін дії буфера</string>
<string name="shared_string_suggested">Запропоновано</string>
<string name="status_widget_title">Статус відстежувача OsmAnd</string>
<string name="back_to_osmand">Повернутися до OsmAnd</string>
<string name="last_update_from_telegram_date">Останнє оновлення від Telegram: %1$s</string>
<string name="last_response_date">Остання відповідь: %1$s</string>
<string name="last_update_from_telegram_duration">Останнє оновлення від Telegram: %1$s тому</string>
<string name="last_response_duration">Остання відповідь: %1$s тому</string>
<string name="duration_ago">%1$s тому</string>
</resources>

View file

@ -189,7 +189,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram即時通訊應用程式用以與人們連線與溝通。</string>
<string name="privacy_policy_telegram_client">OsmAnd 追蹤器是其中一個使用 Telegram 開放平臺的客戶。您的聯絡人可以使用其他任何 Telegram 客戶端。</string>
<string name="privacy_policy_agree">點選繼續就代表您同意 Telegram 隱私權政策與 OsmAnd 隱私權政策。</string>
<string name="privacy_policy_agree">點選繼續就代表您同意 Telegram 與 OsmAnd 隱私權政策。</string>
<string name="shared_string_accept">接受</string>
<string name="telegram_privacy_policy">Telegram 隱私權政策</string>
<string name="osmand_privacy_policy">OsmAnd 隱私權政策</string>
@ -249,4 +249,24 @@
<string name="shared_string_apply">套用</string>
<string name="set_time_timeline_descr">選取要顯示的時間</string>
<string name="start_end_date">開始到結束日期</string>
<string name="location_sharing_status">正在分享:%1$s</string>
<string name="shared_string_enabled">已啟用</string>
<string name="saved_messages">已儲存的訊息</string>
<string name="time_zone_descr">選取要在您位置訊息中顯示的時區。</string>
<string name="time_zone">時區</string>
<string name="units_and_formats">單位與格式</string>
<string name="unit_of_length_descr">變更距離的測量方式。</string>
<string name="unit_of_length">長度單位</string>
<string name="unit_of_speed_system_descr">定義速度單位。</string>
<string name="unit_of_speed_system">速度單位</string>
<string name="buffer_time_descr">在緩衝中儲存點的最長時間</string>
<string name="buffer_time">緩衝過期時間</string>
<string name="shared_string_suggested">建議</string>
<string name="status_widget_title">OsmAnd Tracker 狀態</string>
<string name="back_to_osmand">回到 OsmAnd</string>
<string name="last_update_from_telegram_date">從 Telegram 而來的最後更新:%1$s</string>
<string name="last_response_date">最後回應:%1$s</string>
<string name="last_update_from_telegram_duration">從 Telegram 而來的最後更新:%1$s 前</string>
<string name="last_response_duration">最後回應:%1$s 前</string>
<string name="duration_ago">%1$s 前</string>
</resources>

View file

@ -12,6 +12,7 @@
<attr name="primary_btn_text_color" format="reference" />
<attr name="secondary_btn_bg" format="reference" />
<attr name="shared_chat_card_bg" format="reference" />
<attr name="bg_list_item_dark" format="reference" />
</declare-styleable>
<declare-styleable name="TextViewEx">

View file

@ -45,4 +45,6 @@
<color name="live_track_active_icon">#F54522</color>
<color name="bg_list_item_dark">#727272</color>
</resources>

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="app_bar_title_padding_small">8dp</dimen>
<dimen name="app_bar_title_padding_big">14dp</dimen>
<dimen name="content_padding_tiny">2dp</dimen>
<dimen name="content_padding_small">4dp</dimen>
<dimen name="content_padding_half">8dp</dimen>
@ -51,7 +53,7 @@
<dimen name="image_button_padding">12dp</dimen>
<dimen name="my_location_image_height">168dp</dimen>
<dimen name="my_location_image_height">148dp</dimen>
<dimen name="my_location_text_sides_margin">32dp</dimen>
<dimen name="my_location_user_icon_size">60dp</dimen>

View file

@ -1,5 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="last_update_from_telegram_date">Last update from Telegram: %1$s</string>
<string name="last_response_date">Last response: %1$s</string>
<string name="last_update_from_telegram_duration">Last update from Telegram: %1$s ago</string>
<string name="last_response_duration">Last response: %1$s ago</string>
<string name="duration_ago">%1$s ago</string>
<string name="back_to_osmand">Back to OsmAnd</string>
<string name="shared_string_suggested">Suggested</string>
<string name="status_widget_title">OsmAnd Tracker status</string>
<string name="buffer_time_descr">Maximum time to store points in the buffer</string>
<string name="buffer_time">Buffer expiration time</string>
<string name="time_zone_descr">Select time zone to show in your location messages.</string>
<string name="time_zone">Time zone</string>
<string name="units_and_formats">Units &amp; formats</string>
<string name="unit_of_length_descr">Change what distance is measured in.</string>
<string name="unit_of_length">Units of length</string>
<string name="unit_of_speed_system_descr">Define unit of speed.</string>
<string name="unit_of_speed_system">Unit of speed</string>
<string name="saved_messages">Saved messages</string>
<string name="shared_string_end">End</string>
<string name="shared_string_start">Start</string>
<string name="shared_string_apply">Apply</string>
@ -46,7 +64,7 @@
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (the messaging app) is used to connect and communicate with people.</string>
<string name="privacy_policy_telegram_client">OsmAnd tracker is one of the clients that use the Telegram open platform. Your contacts can use any other Telegram client.</string>
<string name="privacy_policy_agree">By clicking continue you agree to the conditions of Telegram Privacy Policy and OsmAnd Privacy Policy.</string>
<string name="privacy_policy_agree">By clicking \"Continue\" you agree to the conditions of the Telegram- and OsmAnd privacy policy.</string>
<string name="shared_string_accept">Accept</string>
<string name="telegram_privacy_policy">Telegram Privacy Policy</string>
<string name="osmand_privacy_policy">OsmAnd Privacy Policy</string>

View file

@ -29,6 +29,7 @@
<item name="windowNoTitle">true</item>
<item name="bottom_nav_shadow">@drawable/bg_bottom_bar_shadow_with_line_day</item>
<item name="shared_chat_card_bg">@drawable/chat_card_bg_light</item>
<item name="bg_list_item_dark">@color/bg_list_item_dark</item>
</style>
<style name="AppTheme.NoActionbar">

View file

@ -7,6 +7,11 @@ import android.content.Intent
class InitAppBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// do nothing, TelegramApplication already initialized
// check if aidl connection was lost
val app = context.applicationContext as TelegramApplication
val aidlHelper = app.osmandAidlHelper
if (aidlHelper.isOsmandBound() && !aidlHelper.isOsmandConnected()) {
aidlHelper.connectOsmand()
}
}
}
}

View file

@ -14,7 +14,7 @@ import net.osmand.telegram.notifications.NotificationHelper
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.UiUtils
class TelegramApplication : Application(), OsmandHelperListener {
class TelegramApplication : Application() {
val telegramHelper = TelegramHelper.instance
lateinit var settings: TelegramSettings private set
@ -42,7 +42,7 @@ class TelegramApplication : Application(), OsmandHelperListener {
telegramHelper.messageActiveTimeSec = settings.locHistoryTime
uiUtils = UiUtils(this)
osmandAidlHelper = OsmandAidlHelper(this)
osmandAidlHelper.listener = object : OsmandHelperListener {
osmandAidlHelper.addConnectionListener(object : OsmandHelperListener {
override fun onOsmandConnectionStateChanged(connected: Boolean) {
if (connected) {
osmandAidlHelper.clearNavDrawerItems("net.osmand.telegram")
@ -54,11 +54,13 @@ class TelegramApplication : Application(), OsmandHelperListener {
listOf("ic_action_location_sharing_app"),
listOf(-1)
)
showLocationHelper.setupMapLayer()
showLocationHelper.addDirectionContextMenuButton()
showLocationHelper.startShowingLocation()
showLocationHelper.addOrUpdateStatusWidget(-1, false)
}
}
}
})
osmandAidlHelper.setUpdatesListener(object : UpdatesListener {
override fun update() {
if (settings.hasAnyChatToShowOnMap()) {
@ -140,13 +142,6 @@ class TelegramApplication : Application(), OsmandHelperListener {
return internetConnectionAvailable
}
override fun onOsmandConnectionStateChanged(connected: Boolean) {
if (connected) {
showLocationHelper.setupMapLayer()
showLocationHelper.addDirectionContextMenuButton()
}
}
private fun startTelegramService(intent: Int, serviceOffInterval: Long = 0) {
var i = intent
var interval = serviceOffInterval

View file

@ -13,19 +13,24 @@ import android.os.*
import android.util.Log
import android.widget.Toast
import net.osmand.PlatformUtil
import net.osmand.telegram.helpers.TelegramHelper.TelegramIncomingMessagesListener
import net.osmand.telegram.helpers.TelegramHelper.TelegramOutgoingMessagesListener
import net.osmand.telegram.TelegramSettings.ShareChatInfo
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.*
import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandLocationUtils
import org.drinkless.td.libcore.telegram.TdApi
import java.util.*
private const val UPDATE_WIDGET_INTERVAL_MS = 1000L // 1 sec
private const val UPDATE_LIVE_MESSAGES_INTERVAL_MS = 10000L // 10 sec
private const val UPDATE_LIVE_TRACKS_INTERVAL_MS = 30000L // 30 sec
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener,
TelegramOutgoingMessagesListener {
private val log = PlatformUtil.getLog(TelegramService::class.java)
private fun app() = application as TelegramApplication
private val binder = LocationServiceBinder()
private var shouldCleanupResources: Boolean = false
@ -36,6 +41,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
private var updateTracksHandler: Handler? = null
private var tracksHandlerThread = HandlerThread("TracksUpdateServiceThread")
private var updateWidgetHandler: Handler? = null
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
var handler: Handler? = null
private set
var usedBy = 0
@ -58,8 +66,10 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
super.onCreate()
mHandlerThread.start()
tracksHandlerThread.start()
updateWidgetThread.start()
updateShareInfoHandler = Handler(mHandlerThread.looper)
updateTracksHandler = Handler(tracksHandlerThread.looper)
updateWidgetHandler = Handler(updateWidgetThread.looper)
}
override fun onBind(intent: Intent): IBinder? {
@ -99,18 +109,21 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
sendLocationInterval = intent.getLongExtra(SEND_LOCATION_INTERVAL, 0)
setupServiceErrorInterval()
app.telegramService = this
app.telegramHelper.addIncomingMessagesListener(this)
app.telegramHelper.addOutgoingMessagesListener(this)
app.telegramService = this
if (isUsedByMyLocation(usedBy)) {
initLocationUpdates()
startShareInfoUpdates()
startWidgetUpdates()
}
if (isUsedByUsersLocations(usedBy)) {
app.telegramHelper.startLiveMessagesUpdates(app.settings.sendMyLocInterval)
startTracksUpdates()
}
app.shareLocationHelper.checkAndSendBufferMessages()
val locationNotification = app.notificationHelper.locationNotification
val notification = app.notificationHelper.buildNotification(locationNotification)
@ -139,6 +152,8 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
app.telegramService = null
tracksHandlerThread.quit()
mHandlerThread.quit()
updateWidgetThread.quit()
app().showLocationHelper.addOrUpdateStatusWidget(-1, false)
usedBy = 0
@ -209,6 +224,37 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}
}, UPDATE_LIVE_TRACKS_INTERVAL_MS)
}
private fun startWidgetUpdates() {
updateWidgetHandler?.postDelayed({
if (isUsedByMyLocation(usedBy)) {
val sharingStatus = app().settings.sharingStatusChanges.last()
var isSending = sharingStatus.statusType == TelegramSettings.SharingStatusType.SENDING
val sharingChats = app().settings.getShareLocationChats()
var oldestTime = 0L
if (sharingChats.isNotEmpty() && app().shareLocationHelper.sharingLocation) {
sharingChats.forEach { id ->
val bufferMessages = app().locationMessages.getBufferedMessagesForChat(id)
if (bufferMessages.isNotEmpty()) {
val newTime = bufferMessages[0].time
if (oldestTime == 0L || newTime < oldestTime) {
oldestTime = newTime
}
} else {
oldestTime = 0L
}
}
} else {
isSending = false
oldestTime = -1
}
app().showLocationHelper.addOrUpdateStatusWidget(oldestTime, isSending)
} else {
app().showLocationHelper.addOrUpdateStatusWidget(-1, false)
}
startWidgetUpdates()
}, UPDATE_WIDGET_INTERVAL_MS)
}
@SuppressLint("MissingPermission")
private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? {
@ -327,8 +373,12 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
app().settings.onDeleteLiveMessages(chatId, messages)
}
override fun onSendLiveLocationError(code: Int, message: String) {
override fun onSendLiveLocationError(code: Int, message: String, shareInfo: ShareChatInfo, messageType: Int) {
Log.d(PlatformUtil.TAG, "Send live location error: $code - $message")
when (messageType) {
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText--
TelegramHelper.MESSAGE_TYPE_MAP -> shareInfo.pendingTdLibMap--
}
}
companion object {

View file

@ -9,20 +9,21 @@ import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import net.osmand.PlatformUtil
import net.osmand.telegram.helpers.OsmandAidlHelper
import net.osmand.telegram.helpers.ShareLocationHelper.Companion.MAX_MESSAGES_IN_TDLIB_PER_CHAT
import net.osmand.telegram.helpers.ShowLocationHelper
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandApiUtils
import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.telegram.utils.*
import net.osmand.telegram.utils.OsmandFormatter.MetricsConstants
import net.osmand.telegram.utils.OsmandFormatter.SpeedConstants
import net.osmand.telegram.utils.OsmandLocationUtils
import org.drinkless.td.libcore.telegram.TdApi
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.collections.ArrayList
import kotlin.math.max
val ADDITIONAL_ACTIVE_TIME_VALUES_SEC = listOf(15 * 60L, 30 * 60L, 60 * 60L, 180 * 60L)
@ -63,6 +64,12 @@ private const val MIN_LOCATION_DISTANCE_INDEX = 0
private const val MIN_LOCATION_ACCURACY_INDEX = 0
private const val MIN_LOCATION_SPEED_INDEX = 0
private val BUFFER_TIME = listOf(60 * 60L, 2 * 60 * 60L, 4 * 60 * 60L, 8 * 60 * 60L,
12 * 60 * 60L, 24 * 60 * 60L)
private const val BUFFER_TIME_INDEX = 0
private const val BUFFER_TIME_KEY = "buffer_time"
private const val FREE_TIMELINE_INFO_SHOWN_TIME_KEY = "free_timeline_info_shown_time"
private const val SETTINGS_NAME = "osmand_telegram_settings"
private const val SHARE_LOCATION_CHATS_KEY = "share_location_chats"
@ -72,6 +79,7 @@ private const val SHARING_MODE_KEY = "current_sharing_mode"
private const val METRICS_CONSTANTS_KEY = "metrics_constants"
private const val SPEED_CONSTANTS_KEY = "speed_constants"
private const val UTC_OFFSET_CONSTANTS_KEY = "utc_offset_constants"
private const val SEND_MY_LOC_INTERVAL_KEY = "send_my_loc_interval"
private const val STALE_LOC_TIME_KEY = "stale_loc_time"
@ -102,10 +110,12 @@ private const val PROXY_ENABLED = "proxy_enabled"
private const val PROXY_PREFERENCES_KEY = "proxy_preferences"
private const val SHARING_INITIALIZATION_TIME = 60 * 2L // 2 minutes
private const val WAITING_TDLIB_TIME = 30 // 2 seconds
private const val WAITING_TDLIB_TIME = 3 // 3 seconds
private const val GPS_UPDATE_EXPIRED_TIME = 60 * 3L // 3 minutes
private const val LAST_CHATS_INFO_KEY = "last_chats_info"
class TelegramSettings(private val app: TelegramApplication) {
private val log = PlatformUtil.getLog(TelegramSettings::class.java)
@ -114,6 +124,7 @@ class TelegramSettings(private val app: TelegramApplication) {
private var hiddenOnMapChats: Set<Long> = emptySet()
private var shareDevices: Set<DeviceBot> = emptySet()
private var liveTracksInfo = emptyList<LiveTrackInfo>()
var lastChatsInfo = LinkedList<LastChatInfo>()
var sharingStatusChanges = ConcurrentLinkedQueue<SharingStatus>()
@ -125,6 +136,7 @@ class TelegramSettings(private val app: TelegramApplication) {
var metricsConstants = MetricsConstants.KILOMETERS_AND_METERS
var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR
var utcOffset = DataConstants.UTC_FORMAT
var sendMyLocInterval = SEND_MY_LOC_VALUES_SEC[SEND_MY_LOC_DEFAULT_INDEX]
var staleLocTime = STALE_LOC_VALUES_SEC[STALE_LOC_DEFAULT_INDEX]
@ -140,8 +152,10 @@ class TelegramSettings(private val app: TelegramApplication) {
var liveNowSortType = LiveNowSortType.SORT_BY_DISTANCE
val gpsAndLocPrefs = listOf(SendMyLocPref(), StaleLocPref(), LocHistoryPref(), ShareTypePref())
val gpsAndLocPrefs = listOf(SendMyLocPref(), StaleLocPref(), LocHistoryPref(), ShareTypePref(),
BufferTimePref())
val gpxLoggingPrefs = listOf(MinLocationDistance(), MinLocationAccuracy(), MinLocationSpeed())
val unitsAndFormatsPrefs = listOf(UnitsOfSpeed(), UnitsOfLength(), UtcOffset())
var batteryOptimisationAsked = false
@ -151,6 +165,10 @@ class TelegramSettings(private val app: TelegramApplication) {
var proxyEnabled = false
var bufferTime = BUFFER_TIME[BUFFER_TIME_INDEX]
var freeTimelineInfoShownTime = 0L
init {
updatePrefs()
read()
@ -380,6 +398,9 @@ class TelegramSettings(private val app: TelegramApplication) {
} else if (state.constructor == TdApi.MessageSendingStateFailed.CONSTRUCTOR) {
shareInfo.hasSharingError = true
shareInfo.pendingMapMessage = false
if (!isOsmAndBot) {
shareInfo.pendingTdLibMap--
}
log.debug("updateShareInfo MAP ${message.id} MessageSendingStateFailed")
}
} else {
@ -411,6 +432,9 @@ class TelegramSettings(private val app: TelegramApplication) {
log.debug("updateShareInfo TEXT ${message.id} MessageSendingStateFailed")
shareInfo.hasSharingError = true
shareInfo.pendingTextMessage = false
if (!isOsmAndBot) {
shareInfo.pendingTdLibText--
}
}
} else {
shareInfo.currentTextMessageId = message.id
@ -487,13 +511,15 @@ class TelegramSettings(private val app: TelegramApplication) {
private fun getNewSharingStatusHistoryItem(): SharingStatus {
return SharingStatus().apply {
statusChangeTime = System.currentTimeMillis()
val currentTimeMillis = System.currentTimeMillis()
val currentTime = currentTimeMillis / 1000
statusChangeTime = currentTimeMillis
val lm = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val gpsEnabled = try {
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
val loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER)
val gpsActive = loc != null && ((statusChangeTime - loc.time) / 1000) < GPS_UPDATE_EXPIRED_TIME
val lastSentLocationExpired = ((statusChangeTime - app.shareLocationHelper.lastLocationUpdateTime) / 1000) > GPS_UPDATE_EXPIRED_TIME
val gpsActive = loc != null && ((currentTimeMillis - loc.time) / 1000) < GPS_UPDATE_EXPIRED_TIME
val lastSentLocationExpired = ((currentTimeMillis - app.shareLocationHelper.lastLocationUpdateTime) / 1000) > GPS_UPDATE_EXPIRED_TIME
(gpsActive || !lastSentLocationExpired)
} else {
false
@ -505,20 +531,25 @@ class TelegramSettings(private val app: TelegramApplication) {
var initializing = false
var sendChatsErrors = false
val chatsCount = shareChatsInfo.size
shareChatsInfo.forEach { (_, shareInfo) ->
if (shareInfo.lastTextSuccessfulSendTime == -1L && shareInfo.lastMapSuccessfulSendTime == -1L
&& ((statusChangeTime / 1000 - shareInfo.start) < SHARING_INITIALIZATION_TIME)) {
val initTime = (currentTime - shareInfo.start) < SHARING_INITIALIZATION_TIME
var initSending = false
initSending = initSending || (shareInfo.lastTextSuccessfulSendTime == -1L && shareTypeValue != SHARE_TYPE_MAP)
initSending = initSending || (shareInfo.lastMapSuccessfulSendTime == -1L && shareTypeValue != SHARE_TYPE_TEXT)
if (initTime && initSending) {
initializing = true
} else {
val textSharingError = shareInfo.lastSendTextMessageTime - shareInfo.lastTextSuccessfulSendTime > WAITING_TDLIB_TIME
val mapSharingError = shareInfo.lastSendMapMessageTime - shareInfo.lastMapSuccessfulSendTime > WAITING_TDLIB_TIME
val maxWaitingTime = WAITING_TDLIB_TIME * MAX_MESSAGES_IN_TDLIB_PER_CHAT * max(1, chatsCount)
val textSharingError = !shareInfo.lastTextMessageHandled && currentTime - shareInfo.lastSendTextMessageTime > maxWaitingTime
val mapSharingError = !shareInfo.lastMapMessageHandled && currentTime - shareInfo.lastSendMapMessageTime > maxWaitingTime
if (shareInfo.hasSharingError
|| (shareTypeValue == SHARE_TYPE_MAP_AND_TEXT && (textSharingError || mapSharingError))
|| textSharingError && (shareTypeValue == SHARE_TYPE_TEXT)
|| mapSharingError && (shareTypeValue == SHARE_TYPE_MAP)
) {
sendChatsErrors = true
locationTime = Math.max(shareInfo.lastTextSuccessfulSendTime, shareInfo.lastMapSuccessfulSendTime)
locationTime = max(shareInfo.lastTextSuccessfulSendTime, shareInfo.lastMapSuccessfulSendTime)
chatsIds.add(shareInfo.chatId)
}
}
@ -606,6 +637,7 @@ class TelegramSettings(private val app: TelegramApplication) {
edit.putString(METRICS_CONSTANTS_KEY, metricsConstants.name)
edit.putString(SPEED_CONSTANTS_KEY, speedConstants.name)
edit.putString(UTC_OFFSET_CONSTANTS_KEY, utcOffset)
edit.putLong(SEND_MY_LOC_INTERVAL_KEY, sendMyLocInterval)
edit.putLong(STALE_LOC_TIME_KEY, staleLocTime)
@ -629,6 +661,10 @@ class TelegramSettings(private val app: TelegramApplication) {
edit.putBoolean(PROXY_ENABLED, proxyEnabled)
edit.putLong(BUFFER_TIME_KEY, bufferTime)
edit.putLong(FREE_TIMELINE_INFO_SHOWN_TIME_KEY, freeTimelineInfoShownTime)
val jArray = convertShareChatsInfoToJson()
if (jArray != null) {
edit.putString(SHARE_CHATS_INFO_KEY, jArray.toString())
@ -649,6 +685,11 @@ class TelegramSettings(private val app: TelegramApplication) {
edit.putString(LIVE_TRACKS_KEY, jsonArrayLiveTracks.toString())
}
val jArrayLastInfo = convertLastChatsInfoToJson()
if (jArrayLastInfo != null) {
edit.putString(LAST_CHATS_INFO_KEY, jArrayLastInfo.toString())
}
edit.apply()
}
@ -668,6 +709,7 @@ class TelegramSettings(private val app: TelegramApplication) {
speedConstants = SpeedConstants.valueOf(
prefs.getString(SPEED_CONSTANTS_KEY, SpeedConstants.KILOMETERS_PER_HOUR.name)
)
utcOffset = prefs.getString(UTC_OFFSET_CONSTANTS_KEY, DataConstants.UTC_FORMAT)
try {
parseShareChatsInfo(JSONArray(prefs.getString(SHARE_CHATS_INFO_KEY, "")))
@ -675,6 +717,12 @@ class TelegramSettings(private val app: TelegramApplication) {
e.printStackTrace()
}
try {
parseLastChatsInfo(JSONArray(prefs.getString(LAST_CHATS_INFO_KEY, "")))
} catch (e: JSONException) {
log.error(e)
}
parseShareDevices(prefs.getString(SHARE_DEVICES_KEY, ""))
val sendMyLocDef = SEND_MY_LOC_VALUES_SEC[SEND_MY_LOC_DEFAULT_INDEX]
@ -710,6 +758,11 @@ class TelegramSettings(private val app: TelegramApplication) {
showGpsPoints = prefs.getBoolean(SHOW_GPS_POINTS, false)
proxyEnabled = prefs.getBoolean(PROXY_ENABLED, false)
bufferTime = prefs.getLong(BUFFER_TIME_KEY, BUFFER_TIME[BUFFER_TIME_INDEX])
freeTimelineInfoShownTime = prefs.getLong(FREE_TIMELINE_INFO_SHOWN_TIME_KEY, 0L)
try {
parseProxyPreferences(JSONObject(prefs.getString(PROXY_PREFERENCES_KEY, "")))
} catch (e: JSONException) {
@ -814,6 +867,22 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
private fun convertLastChatsInfoToJson(): JSONArray? {
return try {
val jArray = JSONArray()
lastChatsInfo.forEach { lastInfo ->
val obj = JSONObject()
obj.put(LastChatInfo.CHAT_ID_KEY, lastInfo.chatId)
obj.put(LastChatInfo.PERIOD_KEY, lastInfo.period)
jArray.put(obj)
}
jArray
} catch (e: JSONException) {
log.error(e)
null
}
}
private fun parseShareChatsInfo(json: JSONArray) {
for (i in 0 until json.length()) {
val obj = json.getJSONObject(i)
@ -880,6 +949,40 @@ class TelegramSettings(private val app: TelegramApplication) {
shareDevices = OsmandApiUtils.parseJsonContents(json).toHashSet()
}
private fun parseLastChatsInfo(json: JSONArray) {
for (i in 0 until json.length()) {
val obj = json.getJSONObject(i)
val lastInfo = LastChatInfo().apply {
chatId = obj.optLong(LastChatInfo.CHAT_ID_KEY)
period = obj.optLong(LastChatInfo.PERIOD_KEY)
}
lastChatsInfo.addLast(lastInfo)
}
}
fun addTimePeriodToLastItem(id: Long, time: Long) {
val lastInfo = lastChatsInfo.find { it.chatId == id }
if (lastInfo == null) {
addItemToSuggested(id, time)
} else {
val index = lastChatsInfo.indexOf(lastInfo)
lastChatsInfo[index].period = time
}
}
private fun addItemToSuggested(id: Long, time: Long) {
val newLastInfo = LastChatInfo().apply {
chatId = id
period = time
}
if (lastChatsInfo.size < 5) {
lastChatsInfo.addFirst(newLastInfo)
} else {
lastChatsInfo.removeLast()
lastChatsInfo.addFirst(newLastInfo)
}
}
private fun getLiveNowChats() = app.telegramHelper.getMessagesByChatIds(locHistoryTime).keys
private fun updatePrefs() {
@ -895,68 +998,64 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
inner class SendMyLocPref : NumericPref(
inner class SendMyLocPref : ListPreference(
R.drawable.ic_action_share_location,
R.string.send_my_location,
R.string.send_my_location_desc,
SEND_MY_LOC_VALUES_SEC
R.string.send_my_location_desc
) {
override fun getCurrentValue() =
OsmandFormatter.getFormattedDuration(app, sendMyLocInterval)
override fun setCurrentValue(index: Int) {
sendMyLocInterval = values[index].toLong()
sendMyLocInterval = SEND_MY_LOC_VALUES_SEC[index]
app.updateSendLocationInterval()
}
override fun getMenuItems() =
values.map { OsmandFormatter.getFormattedDuration(app, it.toLong()) }
SEND_MY_LOC_VALUES_SEC.map { OsmandFormatter.getFormattedDuration(app, it) }
}
inner class StaleLocPref : NumericPref(
inner class StaleLocPref : ListPreference(
R.drawable.ic_action_time_span,
R.string.stale_location,
R.string.stale_location_desc,
STALE_LOC_VALUES_SEC
R.string.stale_location_desc
) {
override fun getCurrentValue() =
OsmandFormatter.getFormattedDuration(app, staleLocTime)
override fun setCurrentValue(index: Int) {
staleLocTime = values[index].toLong()
staleLocTime = STALE_LOC_VALUES_SEC[index]
}
override fun getMenuItems() =
values.map { OsmandFormatter.getFormattedDuration(app, it.toLong()) }
STALE_LOC_VALUES_SEC.map { OsmandFormatter.getFormattedDuration(app, it) }
}
inner class LocHistoryPref : NumericPref(
inner class LocHistoryPref : ListPreference(
R.drawable.ic_action_location_history,
R.string.location_history,
R.string.location_history_desc,
LOC_HISTORY_VALUES_SEC
R.string.location_history_desc
) {
override fun getCurrentValue() =
OsmandFormatter.getFormattedDuration(app, locHistoryTime)
override fun setCurrentValue(index: Int) {
val value = values[index]
locHistoryTime = value.toLong()
app.telegramHelper.messageActiveTimeSec = value.toLong()
val value = LOC_HISTORY_VALUES_SEC[index]
locHistoryTime = value
app.telegramHelper.messageActiveTimeSec = value
}
override fun getMenuItems() =
values.map { OsmandFormatter.getFormattedDuration(app, it.toLong()) }
LOC_HISTORY_VALUES_SEC.map { OsmandFormatter.getFormattedDuration(app, it) }
}
inner class ShareTypePref : NumericPref(
inner class ShareTypePref : ListPreference(
R.drawable.ic_action_location_history,
R.string.send_location_as,
R.string.send_location_as_descr,
emptyList()
R.string.send_location_as_descr
) {
override fun getCurrentValue(): String {
@ -988,20 +1087,16 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
inner class MinLocationDistance : NumericPref(
0, R.string.min_logging_distance,
R.string.min_logging_distance_descr,
MIN_LOCATION_DISTANCE
) {
inner class MinLocationDistance :
ListPreference(0, R.string.min_logging_distance, R.string.min_logging_distance_descr) {
override fun getCurrentValue() = getFormattedValue(minLocationDistance)
override fun setCurrentValue(index: Int) {
val value = values[index]
minLocationDistance = value.toFloat()
minLocationDistance = MIN_LOCATION_DISTANCE[index]
}
override fun getMenuItems() = values.map { getFormattedValue(it.toFloat()) }
override fun getMenuItems() = MIN_LOCATION_DISTANCE.map { getFormattedValue(it) }
private fun getFormattedValue(value: Float): String {
return if (value == 0f) app.getString(R.string.shared_string_select)
@ -1009,20 +1104,16 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
inner class MinLocationAccuracy : NumericPref(
0, R.string.min_logging_accuracy,
R.string.min_logging_accuracy_descr,
MIN_LOCATION_ACCURACY
) {
inner class MinLocationAccuracy :
ListPreference(0, R.string.min_logging_accuracy, R.string.min_logging_accuracy_descr) {
override fun getCurrentValue() = getFormattedValue(minLocationAccuracy)
override fun setCurrentValue(index: Int) {
val value = values[index]
minLocationAccuracy = value.toFloat()
minLocationAccuracy = MIN_LOCATION_ACCURACY[index]
}
override fun getMenuItems() = values.map { getFormattedValue(it.toFloat()) }
override fun getMenuItems() = MIN_LOCATION_ACCURACY.map { getFormattedValue(it) }
private fun getFormattedValue(value: Float): String {
return if (value == 0f) app.getString(R.string.shared_string_select)
@ -1030,20 +1121,16 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
inner class MinLocationSpeed : NumericPref(
0, R.string.min_logging_speed,
R.string.min_logging_speed_descr,
MIN_LOCATION_SPEED
) {
inner class MinLocationSpeed :
ListPreference(0, R.string.min_logging_speed, R.string.min_logging_speed_descr) {
override fun getCurrentValue() = getFormattedValue(minLocationSpeed)
override fun setCurrentValue(index: Int) {
val value = values[index]
minLocationSpeed = value.toFloat()
minLocationSpeed = MIN_LOCATION_SPEED[index]
}
override fun getMenuItems() = values.map { getFormattedValue(it.toFloat()) }
override fun getMenuItems() = MIN_LOCATION_SPEED.map { getFormattedValue(it) }
private fun getFormattedValue(value: Float): String {
return when (value) {
@ -1054,11 +1141,67 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
abstract inner class NumericPref(
inner class UnitsOfSpeed : ListPreference(
R.drawable.ic_action_speed,
R.string.unit_of_speed_system,
R.string.unit_of_speed_system_descr
) {
override fun getCurrentValue() = speedConstants.toShortString(app)
override fun setCurrentValue(index: Int) {
speedConstants = SpeedConstants.values()[index]
}
override fun getMenuItems() = SpeedConstants.values().map { it.toShortString(app) }
}
inner class UnitsOfLength : ListPreference(
R.drawable.ic_action_ruler_unit, R.string.unit_of_length,
R.string.unit_of_length_descr
) {
override fun getCurrentValue() = metricsConstants.toHumanString(app)
override fun setCurrentValue(index: Int) {
metricsConstants = MetricsConstants.values()[index]
}
override fun getMenuItems() = MetricsConstants.values().map { it.toHumanString(app) }
}
inner class UtcOffset : ListPreference(
R.drawable.ic_world_globe_dark, R.string.time_zone,
R.string.time_zone_descr
) {
private val formattedUtcOffsets = DataConstants.utcOffsets.keys.toList()
override fun getCurrentValue() = utcOffset
override fun setCurrentValue(index: Int) {
utcOffset = formattedUtcOffsets[index]
}
override fun getMenuItems() = formattedUtcOffsets
}
inner class BufferTimePref : ListPreference(R.drawable.ic_action_time_span, R.string.buffer_time,
R.string.buffer_time_descr) {
override fun getCurrentValue() = OsmandFormatter.getFormattedDuration(app, bufferTime)
override fun setCurrentValue(index: Int) {
bufferTime = BUFFER_TIME[index]
}
override fun getMenuItems(): List<String> {
return BUFFER_TIME.map { OsmandFormatter.getFormattedDuration(app, it) }
}
}
abstract inner class ListPreference(
@DrawableRes val iconId: Int,
@StringRes val titleId: Int,
@StringRes val descriptionId: Int,
val values: List<Number>
@StringRes val descriptionId: Int
) {
abstract fun getCurrentValue(): String
@ -1296,16 +1439,33 @@ class TelegramSettings(private val app: TelegramApplication) {
var lastTextSuccessfulSendTime = -1L
var lastMapSuccessfulSendTime = -1L
var lastSendTextMessageTime = -1
set(value) {
field = value
lastTextMessageHandled = false
}
var lastSendMapMessageTime = -1
set(value) {
field = value
lastMapMessageHandled = false
}
var sentMessages = 0
var pendingTdLibText = 0
set(value) {
field = max(0, value)
}
var pendingTdLibMap = 0
set(value) {
field = max(0, value)
}
var pendingTextMessage = false
var pendingMapMessage = false
var shouldSendViaBotTextMessage = false
var shouldSendViaBotMapMessage = false
var hasSharingError = false
var additionalActiveTime = ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0]
var lastMapMessageHandled = false
var lastTextMessageHandled = false
var lastBufferCheckTime = -1L
fun getNextAdditionalActiveTime(): Long {
var index = ADDITIONAL_ACTIVE_TIME_VALUES_SEC.indexOf(additionalActiveTime)
@ -1320,6 +1480,13 @@ class TelegramSettings(private val app: TelegramApplication) {
return userSetLivePeriod - ((System.currentTimeMillis() / 1000) - start)
}
fun isPendingMessagesLimitReached() =
pendingTdLibText >= MAX_MESSAGES_IN_TDLIB_PER_CHAT || pendingTdLibMap >= MAX_MESSAGES_IN_TDLIB_PER_CHAT
fun isPendingTextMessagesLimitReached() = pendingTdLibText >= MAX_MESSAGES_IN_TDLIB_PER_CHAT
fun isPendingMapMessagesLimitReached() = pendingTdLibMap >= MAX_MESSAGES_IN_TDLIB_PER_CHAT
companion object {
internal const val CHAT_ID_KEY = "chatId"
@ -1341,4 +1508,15 @@ class TelegramSettings(private val app: TelegramApplication) {
internal const val SENT_MESSAGES_KEY = "sentMessages"
}
}
}
class LastChatInfo {
var chatId = -1L
var period = -1L
companion object {
internal const val CHAT_ID_KEY = "chatId"
internal const val PERIOD_KEY = "period"
}
}
}

View file

@ -23,6 +23,8 @@ class LocationMessages(val app: TelegramApplication) {
private val dbHelper: SQLiteHelper
private var lastRemoveTime: Long? = null
init {
dbHelper = SQLiteHelper(app)
readBufferedMessages()
@ -30,30 +32,37 @@ class LocationMessages(val app: TelegramApplication) {
}
fun getBufferedMessages(): List<BufferMessage> {
removeOldBufferedMessages()
return bufferedMessages.sortedBy { it.time }
}
fun getBufferedMessagesCount(): Int {
removeOldBufferedMessages()
return bufferedMessages.size
}
fun getBufferedMessagesCountForChat(chatId: Long, type: Int): Int {
removeOldBufferedMessages()
return bufferedMessages.count { it.chatId == chatId && it.type == type }
}
fun getBufferedMessagesCountForChat(chatId: Long): Int {
removeOldBufferedMessages()
return bufferedMessages.count { it.chatId == chatId}
}
fun getBufferedMessagesForChat(chatId: Long): List<BufferMessage> {
removeOldBufferedMessages()
return bufferedMessages.filter { it.chatId == chatId }.sortedBy { it.time }
}
fun getBufferedTextMessagesForChat(chatId: Long): List<BufferMessage> {
removeOldBufferedMessages()
return bufferedMessages.filter { it.chatId == chatId && it.type == TYPE_TEXT }.sortedBy { it.time }
}
fun getBufferedMapMessagesForChat(chatId: Long): List<BufferMessage> {
removeOldBufferedMessages()
return bufferedMessages.filter { it.chatId == chatId && it.type == TYPE_MAP }.sortedBy { it.time }
}
@ -84,7 +93,7 @@ class LocationMessages(val app: TelegramApplication) {
fun addBufferedMessage(message: BufferMessage) {
log.debug("addBufferedMessage $message")
val messages = mutableListOf(*this.bufferedMessages.toTypedArray())
val messages = this.bufferedMessages.toMutableList()
messages.add(message)
this.bufferedMessages = messages
dbHelper.addBufferedMessage(message)
@ -134,14 +143,38 @@ class LocationMessages(val app: TelegramApplication) {
fun removeBufferedMessage(message: BufferMessage) {
log.debug("removeBufferedMessage $message")
val messages = mutableListOf(*this.bufferedMessages.toTypedArray())
val messages = this.bufferedMessages.toMutableList()
messages.remove(message)
this.bufferedMessages = messages
dbHelper.removeBufferedMessage(message)
}
private fun removeOldBufferedMessages() {
val currentTime = System.currentTimeMillis()
if (this.bufferedMessages.isNotEmpty() && isTimeToDelete(currentTime)) {
val bufferExpirationTime = app.settings.bufferTime * 1000
val messages = this.bufferedMessages.toMutableList()
val expiredList = messages.filter {
currentTime - it.time > bufferExpirationTime
}
expiredList.forEach { message ->
dbHelper.removeBufferedMessage(message)
}
messages.removeAll(expiredList)
this.bufferedMessages = messages.toList()
lastRemoveTime = currentTime
}
}
private fun isTimeToDelete(currentTime: Long) = if (lastRemoveTime != null) {
currentTime - lastRemoveTime!! > 60000L
} else {
true
}
private fun readBufferedMessages() {
this.bufferedMessages = dbHelper.getBufferedMessages()
removeOldBufferedMessages()
}
private fun readLastMessages() {

View file

@ -58,6 +58,8 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
const val OSMAND_NIGHTLY_PACKAGE_NAME = "net.osmand.dev"
const val UPDATE_TIME_MS = 5000L
private const val CALLBACK_INVALID_ID = -1L
}
private var mIOsmAndAidlInterface: IOsmAndAidlInterface? = null
@ -68,7 +70,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
private var osmandUpdatesCallbackId: Long = -1
private var osmandContextMenuCallbackId: Long = -1
var listener: OsmandHelperListener? = null
private val connectionListeners = HashSet<OsmandHelperListener>()
interface OsmandHelperListener {
fun onOsmandConnectionStateChanged(connected: Boolean)
@ -133,6 +135,14 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
}
}
fun addConnectionListener(listener: OsmandHelperListener) {
connectionListeners.add(listener)
}
fun removeConnectionListener(listener: OsmandHelperListener) {
connectionListeners.remove(listener)
}
fun setSearchCompleteListener(mSearchCompleteListener: SearchCompleteListener) {
this.mSearchCompleteListener = mSearchCompleteListener
}
@ -155,7 +165,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
this.mUpdatesListener = mUpdatesListener
}
fun updatesCallbackRegistered() = osmandUpdatesCallbackId > 0
fun updatesCallbackRegistered() = osmandUpdatesCallbackId > CALLBACK_INVALID_ID
/**
* Class for interacting with the main interface of the service.
*/
@ -169,16 +179,18 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
// representation of that from the raw service object.
mIOsmAndAidlInterface = IOsmAndAidlInterface.Stub.asInterface(service)
initialized = true
//Toast.makeText(app, "OsmAnd connected", Toast.LENGTH_SHORT).show()
listener?.onOsmandConnectionStateChanged(true)
connectionListeners.forEach {
it.onOsmandConnectionStateChanged(true)
}
}
override fun onServiceDisconnected(className: ComponentName) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mIOsmAndAidlInterface = null
//Toast.makeText(app, "OsmAnd disconnected", Toast.LENGTH_SHORT).show()
listener?.onOsmandConnectionStateChanged(false)
connectionListeners.forEach {
it.onOsmandConnectionStateChanged(false)
}
}
}
@ -193,7 +205,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
fun isOsmandConnected(): Boolean {
return mIOsmAndAidlInterface != null
}
/**
* Get list of active GPX files.
*
@ -1162,20 +1174,20 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
if (mIOsmAndAidlInterface != null) {
try {
osmandUpdatesCallbackId = mIOsmAndAidlInterface!!.registerForUpdates(UPDATE_TIME_MS, mIOsmAndAidlCallback)
return osmandUpdatesCallbackId > 0
return osmandUpdatesCallbackId > CALLBACK_INVALID_ID
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
fun unregisterFromUpdates(): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val unregistered = mIOsmAndAidlInterface!!.unregisterFromUpdates(osmandUpdatesCallbackId)
if (unregistered) {
osmandUpdatesCallbackId = 0
osmandUpdatesCallbackId = CALLBACK_INVALID_ID
}
return unregistered
} catch (e: RemoteException) {
@ -1222,7 +1234,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
val params = RemoveContextMenuButtonsParams(paramsId, osmandContextMenuCallbackId)
val removed = mIOsmAndAidlInterface!!.removeContextMenuButtons(params)
if (removed) {
osmandContextMenuCallbackId = -1
osmandContextMenuCallbackId = CALLBACK_INVALID_ID
}
return removed
} catch (e: RemoteException) {

View file

@ -1,5 +1,7 @@
package net.osmand.telegram.helpers
import android.os.Handler
import android.os.Message
import net.osmand.Location
import net.osmand.PlatformUtil
import net.osmand.telegram.*
@ -7,6 +9,7 @@ import net.osmand.telegram.helpers.LocationMessages.BufferMessage
import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import net.osmand.telegram.utils.AndroidNetworkUtils
import net.osmand.telegram.utils.BASE_URL
import net.osmand.telegram.utils.OsmandLocationUtils
import net.osmand.util.MapUtils
import org.drinkless.td.libcore.telegram.TdApi
import org.json.JSONException
@ -14,26 +17,27 @@ import org.json.JSONObject
private const val USER_SET_LIVE_PERIOD_DELAY_MS = 5000 // 5 sec
private const val UPDATE_LOCATION_ACCURACY = 150 // 150 meters
private const val MIN_MESSAGE_SENDING_INTERVAL_MS = 1000 // 1 sec
private const val MIN_MESSAGES_BUFFER_CHECK_INTERVAL_MS = 300 // 0.3 sec
private const val SENT_LOCATIONS_INTERVAL_TIME_MS = 4000 // 4 sec
private const val SEND_MESSAGES_BUFFER_MS_MSG_ID = 5000
class ShareLocationHelper(private val app: TelegramApplication) {
private val log = PlatformUtil.getLog(ShareLocationHelper::class.java)
var sharingLocation: Boolean = false
var sharingLocation = false
private set
var duration: Long = 0
var duration = 0L
private set
var distance: Int = 0
var distance = 0
private set
var lastLocationUpdateTime: Long = 0
var lastLocationUpdateTime = 0L
var lastLocationSentTime: Long = 0
private var lastShareLocationMessageTime = 0L
var lastLocation: Location? = null
set(value) {
@ -52,6 +56,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
private var lastTimeInMillis: Long = 0L
private var sendBufferMessagesHandler = Handler()
private var sendBufferMessagesRunnable = Runnable { app.shareLocationHelper.checkAndSendBufferMessages(false) }
fun updateLocation(location: Location?) {
val lastPoint = lastLocation
var record = true
@ -90,7 +97,10 @@ class ShareLocationHelper(private val app: TelegramApplication) {
app.settings.getChatsShareInfo().forEach { (chatId, shareInfo) ->
val currentTime = System.currentTimeMillis() / 1000
when {
shareInfo.getChatLiveMessageExpireTime() <= 0 -> app.settings.shareLocationToChat(chatId, false)
shareInfo.getChatLiveMessageExpireTime() <= 0 -> {
app.settings.shareLocationToChat(chatId, false)
app.settings.addTimePeriodToLastItem(shareInfo.chatId, shareInfo.livePeriod)
}
currentTime > shareInfo.currentMessageLimit -> {
shareInfo.apply {
val newLivePeriod =
@ -117,32 +127,48 @@ class ShareLocationHelper(private val app: TelegramApplication) {
}
}
fun checkAndSendBufferMessages() {
fun checkAndSendBufferMessages(checkNetworkTypeAllowed: Boolean = true) {
log.debug("checkAndSendBufferMessages")
var bufferedMessagesFull = false
var pendingMessagesLimitReached = false
app.settings.getChatsShareInfo().forEach { (chatId, shareInfo) ->
checkAndSendBufferMessagesToChat(chatId)
if (shareInfo.pendingTdLibText >= MAX_MESSAGES_IN_TDLIB_PER_CHAT || shareInfo.pendingTdLibMap >= MAX_MESSAGES_IN_TDLIB_PER_CHAT) {
bufferedMessagesFull = true
checkAndSendBufferMessagesToChat(chatId, true)
if (shareInfo.isPendingMessagesLimitReached()) {
pendingMessagesLimitReached = true
}
}
if (bufferedMessagesFull) {
if (pendingMessagesLimitReached && checkNetworkTypeAllowed) {
checkNetworkType()
}
}
fun checkAndSendBufferMessagesToChat(chatId: Long) {
fun checkAndSendBufferMessagesDelayed() {
if (!sendBufferMessagesHandler.hasMessages(SEND_MESSAGES_BUFFER_MS_MSG_ID)) {
val msg = Message.obtain(sendBufferMessagesHandler, sendBufferMessagesRunnable)
msg.what = SEND_MESSAGES_BUFFER_MS_MSG_ID
sendBufferMessagesHandler.sendMessageDelayed(msg, MIN_MESSAGES_BUFFER_CHECK_INTERVAL_MS.toLong() + 1L)
}
}
fun checkAndSendBufferMessagesToChat(chatId: Long, forced: Boolean = false): Int {
val shareChatsInfo = app.settings.getChatsShareInfo()
val shareInfo = shareChatsInfo[chatId]
val chatsCounts = shareChatsInfo.size
val currentTime = System.currentTimeMillis()
if (shareInfo != null && currentTime - lastLocationSentTime > chatsCounts * SENT_LOCATIONS_INTERVAL_TIME_MS) {
if (shareInfo != null) {
val bufferedMessagesCount = app.locationMessages.getBufferedMessagesCountForChat(chatId)
if (bufferedMessagesCount > 0) {
checkAndSendBufferMessagesDelayed()
}
val currentTime = System.currentTimeMillis()
if (currentTime - shareInfo.lastBufferCheckTime < MIN_MESSAGES_BUFFER_CHECK_INTERVAL_MS && !forced) {
return bufferedMessagesCount
}
shareInfo.lastBufferCheckTime = currentTime
app.locationMessages.getBufferedTextMessagesForChat(chatId).take(MAX_MESSAGES_IN_TDLIB_PER_CHAT).forEach {
if (shareInfo.pendingTdLibText < MAX_MESSAGES_IN_TDLIB_PER_CHAT) {
if (!shareInfo.isPendingTextMessagesLimitReached()) {
if (it.deviceName.isEmpty()) {
if (!shareInfo.pendingTextMessage && shareInfo.currentTextMessageId != -1L) {
lastLocationSentTime = System.currentTimeMillis()
app.telegramHelper.editTextLocation(shareInfo, it)
val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, it, app)
app.telegramHelper.editTextLocation(shareInfo, content)
app.locationMessages.removeBufferedMessage(it)
}
} else {
@ -151,10 +177,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
}
}
app.locationMessages.getBufferedMapMessagesForChat(chatId).take(MAX_MESSAGES_IN_TDLIB_PER_CHAT).forEach {
if (shareInfo.pendingTdLibMap < MAX_MESSAGES_IN_TDLIB_PER_CHAT) {
if (!shareInfo.isPendingMapMessagesLimitReached()) {
if (it.deviceName.isEmpty()) {
if (!shareInfo.pendingMapMessage && shareInfo.currentMapMessageId != -1L) {
lastLocationSentTime = System.currentTimeMillis()
app.telegramHelper.editMapLocation(shareInfo, it)
app.locationMessages.removeBufferedMessage(it)
}
@ -163,7 +188,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
}
}
}
return app.locationMessages.getBufferedMessagesCountForChat(chatId)
}
return 0
}
fun startSharingLocation() {
@ -174,7 +201,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
refreshNotification()
checkAndSendBufferMessages()
if (app.telegramService != null) {
checkAndSendBufferMessages()
}
} else {
app.forceUpdateMyLocation()
}
@ -216,44 +245,44 @@ class ShareLocationHelper(private val app: TelegramApplication) {
val time = location.time
val isBot = app.settings.currentSharingMode != userId.toString()
val deviceName = if (isBot) app.settings.currentSharingMode else ""
var bufferedMessagesFull = false
val chatsCounts = chatsShareInfo.size
var pendingMessagesLimitReached = false
val currentTime = System.currentTimeMillis()
app.locationMessages.addMyLocationMessage(location)
if (currentTime - lastLocationSentTime <= chatsCounts * SENT_LOCATIONS_INTERVAL_TIME_MS) {
if (currentTime - lastShareLocationMessageTime < MIN_MESSAGE_SENDING_INTERVAL_MS) {
return
}
lastShareLocationMessageTime = currentTime
chatsShareInfo.values.forEach { shareInfo ->
if (shareInfo.pendingTdLibText >= MAX_MESSAGES_IN_TDLIB_PER_CHAT || shareInfo.pendingTdLibMap >= MAX_MESSAGES_IN_TDLIB_PER_CHAT) {
bufferedMessagesFull = true
val hasBufferedMessages = checkAndSendBufferMessagesToChat(shareInfo.chatId) > 0
if (shareInfo.isPendingMessagesLimitReached()) {
pendingMessagesLimitReached = true
}
checkAndSendBufferMessagesToChat(shareInfo.chatId)
when (app.settings.shareTypeValue) {
SHARE_TYPE_MAP -> {
val message = BufferMessage(shareInfo.chatId, latitude, longitude, altitude, speed, accuracy, bearing, time, LocationMessages.TYPE_MAP, deviceName)
prepareMapMessage(shareInfo, message, isBot)
prepareMapMessage(shareInfo, message, isBot, hasBufferedMessages)
}
SHARE_TYPE_TEXT -> {
val message = BufferMessage(shareInfo.chatId, latitude, longitude, altitude, speed, accuracy, bearing, time, LocationMessages.TYPE_TEXT, deviceName)
prepareTextMessage(shareInfo, message, isBot)
prepareTextMessage(shareInfo, message, isBot, hasBufferedMessages)
}
SHARE_TYPE_MAP_AND_TEXT -> {
val messageMap = BufferMessage(shareInfo.chatId, latitude, longitude, altitude, speed, accuracy, bearing, time, LocationMessages.TYPE_MAP, deviceName)
val messageText = BufferMessage(shareInfo.chatId, latitude, longitude, altitude, speed, accuracy, bearing, time, LocationMessages.TYPE_TEXT, deviceName)
prepareMapMessage(shareInfo, messageMap, isBot)
prepareTextMessage(shareInfo, messageText, isBot)
prepareMapMessage(shareInfo, messageMap, isBot, hasBufferedMessages)
prepareTextMessage(shareInfo, messageText, isBot, hasBufferedMessages)
}
}
}
if (bufferedMessagesFull) {
if (pendingMessagesLimitReached) {
checkNetworkType()
}
}
private fun prepareTextMessage(shareInfo: TelegramSettings.ShareChatInfo, message: BufferMessage, isBot: Boolean) {
private fun prepareTextMessage(shareInfo: TelegramSettings.ShareChatInfo, message: BufferMessage, isBot: Boolean, hasBufferedMessages: Boolean) {
log.debug("prepareTextMessage $message")
if (shareInfo.currentTextMessageId == -1L) {
if (shareInfo.pendingTextMessage) {
@ -262,8 +291,8 @@ class ShareLocationHelper(private val app: TelegramApplication) {
if (isBot) {
sendLocationToBot(message, shareInfo, SHARE_TYPE_TEXT)
} else {
lastLocationSentTime = System.currentTimeMillis()
app.telegramHelper.sendNewTextLocation(shareInfo, message)
val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, message, app)
app.telegramHelper.sendNewTextLocation(shareInfo, content)
}
}
} else {
@ -274,9 +303,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
app.locationMessages.addBufferedMessage(message)
}
} else {
if (shareInfo.pendingTdLibText < MAX_MESSAGES_IN_TDLIB_PER_CHAT) {
lastLocationSentTime = System.currentTimeMillis()
app.telegramHelper.editTextLocation(shareInfo, message)
if (!shareInfo.isPendingTextMessagesLimitReached() && !hasBufferedMessages) {
val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, message, app)
app.telegramHelper.editTextLocation(shareInfo, content)
} else {
app.locationMessages.addBufferedMessage(message)
}
@ -284,7 +313,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
}
}
private fun prepareMapMessage(shareInfo: TelegramSettings.ShareChatInfo, message: BufferMessage, isBot: Boolean) {
private fun prepareMapMessage(shareInfo: TelegramSettings.ShareChatInfo, message: BufferMessage, isBot: Boolean, hasBufferedMessages: Boolean) {
log.debug("prepareMapMessage $message")
if (shareInfo.currentMapMessageId == -1L) {
if (shareInfo.pendingMapMessage) {
@ -297,7 +326,6 @@ class ShareLocationHelper(private val app: TelegramApplication) {
app.locationMessages.addBufferedMessage(message)
}
} else {
lastLocationSentTime = System.currentTimeMillis()
app.telegramHelper.sendNewMapLocation(shareInfo, message)
}
}
@ -309,8 +337,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
app.locationMessages.addBufferedMessage(message)
}
} else {
if (shareInfo.pendingTdLibMap < MAX_MESSAGES_IN_TDLIB_PER_CHAT) {
lastLocationSentTime = System.currentTimeMillis()
if (!shareInfo.isPendingMapMessagesLimitReached() && !hasBufferedMessages) {
app.telegramHelper.editMapLocation(shareInfo, message)
} else {
app.locationMessages.addBufferedMessage(message)
@ -339,7 +366,6 @@ class ShareLocationHelper(private val app: TelegramApplication) {
} else if (shareType == SHARE_TYPE_MAP) {
shareInfo.lastSendMapMessageTime = (System.currentTimeMillis() / 1000).toInt()
}
lastLocationSentTime = System.currentTimeMillis()
AndroidNetworkUtils.sendRequestAsync(app, url, null, "Send Location", false, false,
object : AndroidNetworkUtils.OnRequestResultListener {
override fun onResult(result: String?) {
@ -403,7 +429,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
companion object {
const val MAX_MESSAGES_IN_TDLIB_PER_CHAT = 10
const val MAX_MESSAGES_IN_TDLIB_PER_CHAT = 5
// min and max values for the UI
const val MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC = TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC - 1

View file

@ -14,6 +14,7 @@ import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.OsmandAidlHelper.ContextMenuButtonsListener
import net.osmand.telegram.helpers.TelegramUiHelper.ListItem
import net.osmand.telegram.ui.OPEN_MY_LOCATION_TAB_KEY
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.telegram.utils.OsmandLocationUtils
@ -34,6 +35,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
const val MIN_OSMAND_CALLBACK_VERSION_CODE = 320
const val MIN_OSMAND_CREATE_IMPORT_DIRS_VERSION_CODE = 340
const val MIN_OSMAND_SHARE_WIDGET_ICON_VERSION_CODE = 356
const val MAP_CONTEXT_MENU_BUTTON_ID = 1
const val MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID = "DIRECTION"
@ -43,6 +45,17 @@ class ShowLocationHelper(private val app: TelegramApplication) {
const val GPX_COLORS_COUNT = 10
private const val STATUS_WIDGET_ID = "status_widget"
private const val STATUS_WIDGET_MENU_ICON = "widget_location_sharing_night"
private const val STATUS_WIDGET_MENU_ICON_OLD = "ic_action_relative_bearing"
private const val STATUS_WIDGET_ICON_OLD = "widget_relative_bearing_day"
private const val STATUS_WIDGET_ANIM_ICON_DAY = "anim_widget_location_sharing_day"
private const val STATUS_WIDGET_ANIM_ICON_NIGHT = "anim_widget_location_sharing_night"
private const val STATUS_WIDGET_ON_ANIM_ICON_DAY = "anim_widget_location_sharing_on_day"
private const val STATUS_WIDGET_ON_ANIM_ICON_NIGHT = "anim_widget_location_sharing_on_night"
private const val STATUS_WIDGET_OFF_ICON_DAY = "widget_location_sharing_off_day"
private const val STATUS_WIDGET_OFF_ICON_NIGHT = "widget_location_sharing_off_night"
val GPX_COLORS = arrayOf(
"red", "orange", "lightblue", "blue", "purple",
"translucent_red", "translucent_orange", "translucent_lightblue",
@ -64,6 +77,15 @@ class ShowLocationHelper(private val app: TelegramApplication) {
private var forcedStop: Boolean = false
init {
app.osmandAidlHelper.addConnectionListener(object : OsmandAidlHelper.OsmandHelperListener {
override fun onOsmandConnectionStateChanged(connected: Boolean) {
if (!connected && showingLocation && !app.settings.monitoringEnabled) {
if (isUseOsmandCallback() && app.osmandAidlHelper.updatesCallbackRegistered()) {
showingLocation = false
}
}
}
})
app.osmandAidlHelper.setContextMenuButtonsListener(object : ContextMenuButtonsListener {
override fun onContextMenuButtonClicked(buttonId: Int, pointId: String, layerId: String) {
@ -124,7 +146,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
osmandAidlHelper.showMapPoint(MAP_LAYER_ID, pointId, name, name, item.chatTitle, Color.WHITE, aLatLon, details, params)
}
}
fun updateLocationsOnMap() {
osmandAidlHelper.execOsmandApi {
val messages = telegramHelper.getMessages()
@ -174,7 +196,10 @@ class ShowLocationHelper(private val app: TelegramApplication) {
bearing = content.bearing.toFloat()
}
val params = generatePointParams(photoPath, stale, speed, bearing)
val typeName = if (isGroup) chatTitle else OsmandFormatter.getListItemLiveTimeDescr(app, date, app.getString(R.string.last_response) + ": ")
val typeName = if (isGroup) chatTitle else OsmandFormatter.getListItemLiveTimeDescr(
app, date, R.string.last_response_date,
R.string.last_response_duration
)
if (update) {
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, pointId, name, name, typeName, Color.WHITE, aLatLon, details, params)
} else {
@ -198,6 +223,67 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
}
fun addOrUpdateStatusWidget(time: Long, isSending: Boolean) {
var iconDay: String
var iconNight: String
val menuIcon = if (isOsmandHasStatusWidgetIcon()) {
STATUS_WIDGET_MENU_ICON
} else {
STATUS_WIDGET_MENU_ICON_OLD
}
val text = when {
time > 0L -> {
iconDay = STATUS_WIDGET_ANIM_ICON_DAY
iconNight = STATUS_WIDGET_ANIM_ICON_NIGHT
val diffTime = (System.currentTimeMillis() - time) / 1000
OsmandFormatter.getFormattedDurationForWidget(diffTime)
}
time == 0L && isSending -> {
iconDay = STATUS_WIDGET_ON_ANIM_ICON_DAY
iconNight = STATUS_WIDGET_ON_ANIM_ICON_NIGHT
app.getString(R.string.shared_string_ok)
}
time == 0L && !isSending -> {
iconDay = STATUS_WIDGET_ANIM_ICON_DAY
iconNight = STATUS_WIDGET_ANIM_ICON_NIGHT
app.getString(R.string.shared_string_ok)
}
else -> {
iconDay = STATUS_WIDGET_OFF_ICON_DAY
iconNight = STATUS_WIDGET_OFF_ICON_NIGHT
app.getString(R.string.shared_string_start)
}
}
if (!isOsmandHasStatusWidgetIcon()) {
iconDay = STATUS_WIDGET_ICON_OLD
iconNight = STATUS_WIDGET_ICON_OLD
}
val subText = when {
time > 0 -> {
if (text.length > 2) {
app.getString(R.string.shared_string_hour_short)
} else {
app.getString(R.string.shared_string_minute_short)
}
}
else -> ""
}
osmandAidlHelper.addMapWidget(
STATUS_WIDGET_ID,
menuIcon,
app.getString(R.string.status_widget_title),
iconDay,
iconNight,
text, subText, 50, getStatusWidgetIntent())
}
private fun getStatusWidgetIntent(): Intent {
val startIntent = app.packageManager.getLaunchIntentForPackage(app.packageName)
startIntent.addCategory(Intent.CATEGORY_LAUNCHER)
startIntent.putExtra(OPEN_MY_LOCATION_TAB_KEY,true)
return startIntent
}
private fun getALatLonFromMessage(content: TdApi.MessageContent): ALatLon? {
return when (content) {
is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude)
@ -350,7 +436,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
forcedStop = force
if (showingLocation) {
showingLocation = false
if (isUseOsmandCallback() && app.osmandAidlHelper.updatesCallbackRegistered()) {
if (isUseOsmandCallback() && osmandAidlHelper.updatesCallbackRegistered()) {
osmandAidlHelper.unregisterFromUpdates()
} else if (!app.settings.monitoringEnabled) {
app.stopUserLocationService()
@ -394,6 +480,11 @@ class ShowLocationHelper(private val app: TelegramApplication) {
return version >= MIN_OSMAND_CREATE_IMPORT_DIRS_VERSION_CODE
}
fun isOsmandHasStatusWidgetIcon(): Boolean {
val version = AndroidUtils.getAppVersionCode(app, app.settings.appToConnectPackage)
return version >= MIN_OSMAND_SHARE_WIDGET_ICON_VERSION_CODE
}
fun startShowMessagesTask(chatId: Long, vararg messages: TdApi.Message) {
if (app.settings.isShowingChatOnMap(chatId)) {
ShowMessagesTask(app).executeOnExecutor(executor, *messages)
@ -502,4 +593,4 @@ class ShowLocationHelper(private val app: TelegramApplication) {
osmandAidlHelper.removeMapPoint(MAP_LAYER_ID, "${chatId}_${content.deviceName}")
}
}
}
}

View file

@ -6,6 +6,7 @@ import net.osmand.telegram.SHARE_TYPE_MAP
import net.osmand.telegram.SHARE_TYPE_MAP_AND_TEXT
import net.osmand.telegram.SHARE_TYPE_TEXT
import net.osmand.telegram.TelegramSettings
import net.osmand.telegram.TelegramSettings.ShareChatInfo
import net.osmand.telegram.helpers.TelegramHelper.TelegramAuthenticationParameterType.*
import net.osmand.telegram.utils.GRAYSCALE_PHOTOS_DIR
import net.osmand.telegram.utils.GRAYSCALE_PHOTOS_EXT
@ -43,6 +44,10 @@ class TelegramHelper private constructor() {
const val MAX_LOCATION_MESSAGE_HISTORY_SCAN_SEC = 60 * 60 * 24 // one day
const val MESSAGE_TYPE_MAP = 1
const val MESSAGE_TYPE_TEXT = 2
const val MESSAGE_TYPE_BOT = 3
private var helper: TelegramHelper? = null
val instance: TelegramHelper
@ -247,7 +252,7 @@ class TelegramHelper private constructor() {
interface TelegramOutgoingMessagesListener {
fun onUpdateMessages(messages: List<TdApi.Message>)
fun onDeleteMessages(chatId: Long, messages: List<Long>)
fun onSendLiveLocationError(code: Int, message: String)
fun onSendLiveLocationError(code: Int, message: String, shareInfo: ShareChatInfo, messageType: Int)
}
interface FullInfoUpdatesListener {
@ -487,7 +492,7 @@ class TelegramHelper private constructor() {
}
}
fun sendViaBotLocationMessage(userId: Int, shareInfo: TelegramSettings.ShareChatInfo, location: TdApi.Location, device: TelegramSettings.DeviceBot, shareType:String) {
fun sendViaBotLocationMessage(userId: Int, shareInfo: ShareChatInfo, location: TdApi.Location, device: TelegramSettings.DeviceBot, shareType:String) {
log.debug("sendViaBotLocationMessage - ${shareInfo.chatId}")
client?.send(TdApi.GetInlineQueryResults(userId, shareInfo.chatId, location, device.deviceName, "")) { obj ->
when (obj.constructor) {
@ -495,7 +500,6 @@ class TelegramHelper private constructor() {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
} else {
shareInfo.shouldSendViaBotTextMessage = true
shareInfo.shouldSendViaBotMapMessage = true
}
@ -508,7 +512,7 @@ class TelegramHelper private constructor() {
}
private fun sendViaBotMessageFromQueryResults(
shareInfo: TelegramSettings.ShareChatInfo,
shareInfo: ShareChatInfo,
inlineQueryResults: TdApi.InlineQueryResults,
deviceId: String,
shareType: String
@ -528,9 +532,10 @@ class TelegramHelper private constructor() {
}
}
resultArticles.forEach {
shareInfo.lastTextMessageHandled = false
client?.send(TdApi.SendInlineQueryResultMessage(shareInfo.chatId, 0, true,
true, inlineQueryResults.inlineQueryId, it.id, false)) { obj ->
handleTextLocationMessageUpdate(obj, shareInfo)
handleTextLocationMessageUpdate(obj, shareInfo, true)
}
}
}
@ -764,8 +769,8 @@ class TelegramHelper private constructor() {
fun createPrivateChatWithUser(
userId: Int,
shareInfo: TelegramSettings.ShareChatInfo,
shareChatsInfo: ConcurrentHashMap<Long, TelegramSettings.ShareChatInfo>
shareInfo: ShareChatInfo,
shareChatsInfo: ConcurrentHashMap<Long, ShareChatInfo>
) {
client?.send(TdApi.CreatePrivateChat(userId, false)) { obj ->
when (obj.constructor) {
@ -832,127 +837,48 @@ class TelegramHelper private constructor() {
}
}
fun stopSendingLiveLocationToChat(shareInfo: TelegramSettings.ShareChatInfo) {
fun stopSendingLiveLocationToChat(shareInfo: ShareChatInfo) {
if (shareInfo.currentMapMessageId != -1L && shareInfo.chatId != -1L) {
shareInfo.lastSendMapMessageTime = (System.currentTimeMillis() / 1000).toInt()
client?.send(
TdApi.EditMessageLiveLocation(shareInfo.chatId, shareInfo.currentMapMessageId, null, null)) { obj ->
handleMapLocationMessageUpdate(obj, shareInfo)
handleMapLocationMessageUpdate(obj, shareInfo, false)
}
}
needRefreshActiveLiveLocationMessages = true
}
fun stopSendingLiveLocationMessages(chatsShareInfo: Map<Long, TelegramSettings.ShareChatInfo>) {
fun stopSendingLiveLocationMessages(chatsShareInfo: Map<Long, ShareChatInfo>) {
chatsShareInfo.forEach { (_, chatInfo) ->
stopSendingLiveLocationToChat(chatInfo)
}
}
fun getActiveLiveLocationMessages(onComplete: (() -> Unit)?) {
requestingActiveLiveLocationMessages = true
client?.send(TdApi.GetActiveLiveLocationMessages()) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
needRefreshActiveLiveLocationMessages = true
outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(error.code, error.message)
}
}
}
TdApi.Messages.CONSTRUCTOR -> {
val messages = (obj as TdApi.Messages).messages
if (messages.isNotEmpty()) {
log.debug("getActiveLiveLocationMessages: $messages")
outgoingMessagesListeners.forEach {
it.onUpdateMessages(messages.asList())
}
}
onComplete?.invoke()
}
else -> outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(-1, "Receive wrong response from TDLib: $obj")
}
}
requestingActiveLiveLocationMessages = false
}
}
private fun recreateLiveLocationMessage(shareInfo: TelegramSettings.ShareChatInfo, content: TdApi.InputMessageContent) {
if (shareInfo.chatId != -1L) {
val array = LongArray(1)
if (content is TdApi.InputMessageLocation) {
array[0] = shareInfo.currentMapMessageId
} else if (content is TdApi.InputMessageText) {
array[0] = shareInfo.currentTextMessageId
}
if (array[0] != 0L) {
log.debug("recreateLiveLocationMessage - ${array[0]}")
client?.send(TdApi.DeleteMessages(shareInfo.chatId, array, true)) { obj ->
when (obj.constructor) {
TdApi.Ok.CONSTRUCTOR -> sendNewLiveLocationMessage(shareInfo, content)
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
needRefreshActiveLiveLocationMessages = true
outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(error.code, error.message)
}
}
}
}
}
}
}
needRefreshActiveLiveLocationMessages = true
}
private fun sendNewLiveLocationMessage(shareInfo: TelegramSettings.ShareChatInfo, content: TdApi.InputMessageContent) {
needRefreshActiveLiveLocationMessages = true
log.debug("sendNewLiveLocationMessage")
if (content is TdApi.InputMessageText) {
shareInfo.lastSendTextMessageTime = (System.currentTimeMillis() / 1000).toInt()
} else if (content is TdApi.InputMessageLocation) {
shareInfo.lastSendMapMessageTime = (System.currentTimeMillis() / 1000).toInt()
}
client?.send(TdApi.SendMessage(shareInfo.chatId, 0, false, true, null, content)) { obj ->
if (content is TdApi.InputMessageText) {
handleTextLocationMessageUpdate(obj, shareInfo)
} else if (content is TdApi.InputMessageLocation) {
handleMapLocationMessageUpdate(obj, shareInfo)
}
}
}
fun sendNewTextLocation(shareInfo: TelegramSettings.ShareChatInfo, location: LocationMessages.BufferMessage) {
fun sendNewTextLocation(shareInfo: ShareChatInfo, content: TdApi.InputMessageText) {
shareInfo.updateTextMessageId = 1
val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, location)
if (!shareInfo.pendingTextMessage) {
shareInfo.pendingTextMessage = true
shareInfo.pendingTdLibText++
shareInfo.lastSendTextMessageTime = (System.currentTimeMillis() / 1000).toInt()
log.error("sendNewTextLocation ${shareInfo.pendingTdLibText}")
client?.send(TdApi.SendMessage(shareInfo.chatId, 0, false, true, null, content)) { obj ->
handleTextLocationMessageUpdate(obj, shareInfo)
handleTextLocationMessageUpdate(obj, shareInfo, false)
}
}
}
fun editTextLocation(shareInfo: TelegramSettings.ShareChatInfo, location: LocationMessages.BufferMessage) {
val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, location)
if (shareInfo.currentTextMessageId!=-1L) {
fun editTextLocation(shareInfo: ShareChatInfo, content: TdApi.InputMessageText) {
if (shareInfo.currentTextMessageId != -1L) {
shareInfo.pendingTdLibText++
shareInfo.lastSendTextMessageTime = (System.currentTimeMillis() / 1000).toInt()
log.info("editTextLocation ${shareInfo.currentTextMessageId} pendingTdLibText: ${shareInfo.pendingTdLibText}")
client?.send(TdApi.EditMessageText(shareInfo.chatId, shareInfo.currentTextMessageId, null, content)) { obj ->
handleTextLocationMessageUpdate(obj, shareInfo)
handleTextLocationMessageUpdate(obj, shareInfo, false)
}
}
}
fun sendNewMapLocation(shareInfo: TelegramSettings.ShareChatInfo, locationMessage: LocationMessages.BufferMessage) {
fun sendNewMapLocation(shareInfo: ShareChatInfo, locationMessage: LocationMessages.BufferMessage) {
needRefreshActiveLiveLocationMessages = true
val location = TdApi.Location(locationMessage.lat, locationMessage.lon)
val livePeriod =
@ -968,12 +894,12 @@ class TelegramHelper private constructor() {
shareInfo.lastSendMapMessageTime = (System.currentTimeMillis() / 1000).toInt()
log.error("sendNewMapLocation ${shareInfo.pendingTdLibMap}")
client?.send(TdApi.SendMessage(shareInfo.chatId, 0, false, true, null, content)) { obj ->
handleMapLocationMessageUpdate(obj, shareInfo)
handleMapLocationMessageUpdate(obj, shareInfo, false)
}
}
}
fun editMapLocation(shareInfo: TelegramSettings.ShareChatInfo, locationMessage: LocationMessages.BufferMessage) {
fun editMapLocation(shareInfo: ShareChatInfo, locationMessage: LocationMessages.BufferMessage) {
needRefreshActiveLiveLocationMessages = true
val location = TdApi.Location(locationMessage.lat, locationMessage.lon)
if (shareInfo.currentMapMessageId!=-1L) {
@ -981,22 +907,24 @@ class TelegramHelper private constructor() {
shareInfo.lastSendMapMessageTime = (System.currentTimeMillis() / 1000).toInt()
log.info("editMapLocation ${shareInfo.currentMapMessageId} pendingTdLibMap: ${shareInfo.pendingTdLibMap}")
client?.send(TdApi.EditMessageLiveLocation(shareInfo.chatId, shareInfo.currentMapMessageId, null, location)) { obj ->
handleMapLocationMessageUpdate(obj, shareInfo)
handleMapLocationMessageUpdate(obj, shareInfo, false)
}
}
}
private fun handleMapLocationMessageUpdate(obj: TdApi.Object, shareInfo: TelegramSettings.ShareChatInfo) {
private fun handleMapLocationMessageUpdate(obj: TdApi.Object, shareInfo: ShareChatInfo, isBot: Boolean) {
shareInfo.lastMapMessageHandled = true
val messageType = if (isBot) MESSAGE_TYPE_BOT else MESSAGE_TYPE_MAP
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
log.debug("handleMapLocationMessageUpdate - ERROR $obj")
val error = obj as TdApi.Error
needRefreshActiveLiveLocationMessages = true
shareInfo.pendingMapMessage = false
if (error.code != IGNORED_ERROR_CODE) {
shareInfo.hasSharingError = true
needRefreshActiveLiveLocationMessages = true
shareInfo.pendingMapMessage = false
outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(error.code, error.message)
it.onSendLiveLocationError(error.code, error.message, shareInfo, messageType)
}
}
}
@ -1009,7 +937,7 @@ class TelegramHelper private constructor() {
shareInfo.pendingMapMessage = false
log.debug("handleTextLocationMessageUpdate - MessageSendingStateFailed")
outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(-1, "Map location message ${obj.id} failed to send")
it.onSendLiveLocationError(-1, "Map location message ${obj.id} failed to send", shareInfo, messageType)
}
}
obj.sendingState?.constructor == TdApi.MessageSendingStatePending.CONSTRUCTOR -> {
@ -1033,16 +961,18 @@ class TelegramHelper private constructor() {
}
}
private fun handleTextLocationMessageUpdate(obj: TdApi.Object, shareInfo: TelegramSettings.ShareChatInfo) {
private fun handleTextLocationMessageUpdate(obj: TdApi.Object, shareInfo: ShareChatInfo, isBot: Boolean) {
shareInfo.lastTextMessageHandled = true
val messageType = if (isBot) MESSAGE_TYPE_BOT else MESSAGE_TYPE_TEXT
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
log.debug("handleTextLocationMessageUpdate - ERROR")
val error = obj as TdApi.Error
shareInfo.pendingMapMessage = false
if (error.code != IGNORED_ERROR_CODE) {
shareInfo.hasSharingError = true
shareInfo.pendingTextMessage = false
outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(error.code, error.message)
it.onSendLiveLocationError(error.code, error.message, shareInfo, messageType)
}
}
}
@ -1055,7 +985,7 @@ class TelegramHelper private constructor() {
needRefreshActiveLiveLocationMessages = true
log.debug("handleTextLocationMessageUpdate - MessageSendingStateFailed")
outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(-1, "Text location message ${obj.id} failed to send")
it.onSendLiveLocationError(-1, "Text location message ${obj.id} failed to send", shareInfo, messageType)
}
}
obj.sendingState?.constructor == TdApi.MessageSendingStatePending.CONSTRUCTOR -> {

View file

@ -60,8 +60,6 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
private var heading: Float? = null
private var locationUiUpdateAllowed: Boolean = true
private var lastTelegramUpdateStr = ""
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -71,7 +69,6 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
val appBarLayout = mainView.findViewById<View>(R.id.app_bar_layout)
lastTelegramUpdateTime = mainView.findViewById<TextView>(R.id.last_telegram_update_time)
lastTelegramUpdateStr = getString(R.string.last_update_from_telegram) + ": "
AndroidUtils.addStatusBarPadding19v(context!!, appBarLayout)
adapter = LiveNowListAdapter()
@ -302,7 +299,12 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
if (res.isEmpty()) {
lastTelegramUpdateTime.visibility = View.VISIBLE
lastTelegramUpdateTime.text = OsmandFormatter.getListItemLiveTimeDescr(app, telegramHelper.lastTelegramUpdateTime, lastTelegramUpdateStr)
lastTelegramUpdateTime.text = OsmandFormatter.getListItemLiveTimeDescr(
app,
telegramHelper.lastTelegramUpdateTime,
R.string.last_update_from_telegram_date,
R.string.last_update_from_telegram_duration
)
} else {
lastTelegramUpdateTime.visibility = View.GONE
}
@ -398,8 +400,6 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
inner class LiveNowListAdapter : RecyclerView.Adapter<BaseViewHolder>() {
private var lastResponseStr = getString(R.string.last_response) + ": "
private val menuList =
listOf(getString(R.string.shared_string_off), getString(R.string.shared_string_all))
@ -478,7 +478,12 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
if (lastItem) {
holder.lastTelegramUpdateTime?.visibility = View.VISIBLE
holder.lastTelegramUpdateTime?.text = OsmandFormatter.getListItemLiveTimeDescr(app, telegramHelper.lastTelegramUpdateTime, lastTelegramUpdateStr)
holder.lastTelegramUpdateTime?.text = OsmandFormatter.getListItemLiveTimeDescr(
app,
telegramHelper.lastTelegramUpdateTime,
R.string.last_update_from_telegram_date,
R.string.last_update_from_telegram_duration
)
} else {
holder.lastTelegramUpdateTime?.visibility = View.GONE
}
@ -509,7 +514,10 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
holder.bottomDivider?.visibility = if (nextIsLocation) View.VISIBLE else View.GONE
holder.topDivider?.visibility = if (!sortByGroup && position != 0) View.GONE else View.VISIBLE
} else if (item is LocationItem && holder is ContactViewHolder) {
holder.description?.text = OsmandFormatter.getListItemLiveTimeDescr(app, item.lastUpdated, lastResponseStr)
holder.description?.text = OsmandFormatter.getListItemLiveTimeDescr(
app, item.lastUpdated, R.string.last_response_date,
R.string.last_response_duration
)
holder.topShadowDivider?.visibility = View.GONE
}
}
@ -517,15 +525,17 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
override fun getItemCount() = items.size
private fun getChatItemDescription(item: ChatItem): String {
val dateRes = R.string.last_response_date
val durationRes = R.string.last_response_duration
return when {
item.chatWithBot -> {
if (settings.liveNowSortType.isSortByGroup()) {
getString(R.string.shared_string_bot)
} else {
OsmandFormatter.getListItemLiveTimeDescr(app, item.lastUpdated, lastResponseStr)
OsmandFormatter.getListItemLiveTimeDescr(app, item.lastUpdated, dateRes, durationRes)
}
}
item.privateChat -> OsmandFormatter.getListItemLiveTimeDescr(app, item.lastUpdated, lastResponseStr)
item.privateChat -> OsmandFormatter.getListItemLiveTimeDescr(app, item.lastUpdated, dateRes, durationRes)
else -> {
if (settings.liveNowSortType.isSortByGroup()) {
val live = getString(R.string.shared_string_live)
@ -533,7 +543,7 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
val liveStr = "$live ${item.liveMembersCount}"
if (item.membersCount > 0) "$liveStr$all ${item.membersCount}" else liveStr
} else {
OsmandFormatter.getListItemLiveTimeDescr(app, item.lastUpdated, lastResponseStr)
OsmandFormatter.getListItemLiveTimeDescr(app, item.lastUpdated, dateRes, durationRes)
}
}
}

View file

@ -12,6 +12,8 @@ import android.support.v4.app.DialogFragment
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter
import android.support.v4.view.PagerAdapter
import android.support.v4.view.ViewPager
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.ListPopupWindow
@ -22,7 +24,6 @@ import net.osmand.PlatformUtil
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.OsmandAidlHelper
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.*
import net.osmand.telegram.ui.LoginDialogFragment.LoginDialogType
import net.osmand.telegram.ui.MyLocationTabFragment.ActionButtonsListener
@ -34,6 +35,9 @@ import net.osmand.telegram.utils.OsmandApiUtils
import org.drinkless.td.libcore.telegram.TdApi
import java.io.File
import java.lang.ref.WeakReference
import java.time.MonthDay
import java.util.*
import kotlin.collections.ArrayList
const val OPEN_MY_LOCATION_TAB_KEY = "open_my_location_tab"
@ -66,8 +70,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
private lateinit var buttonsBar: LinearLayout
private lateinit var bottomNav: BottomNavigationView
private lateinit var coordinatorLayout: CoordinatorLayout
private var snackbarShown = false
private lateinit var viewPager: ViewPager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -81,7 +84,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
paused = false
val viewPager = findViewById<LockableViewPager>(R.id.view_pager).apply {
viewPager = findViewById<LockableViewPager>(R.id.view_pager).apply {
swipeLocked = true
offscreenPageLimit = 3
adapter = ViewPagerAdapter(supportFragmentManager)
@ -108,7 +111,9 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
TIMELINE_TAB_POS -> {
liveNowTabFragment?.tabClosed()
timelineTabFragment?.tabOpened()
showSnackBar()
if (shouldShowFreeTimelineInfo()) {
showFreeTimelineInfo()
}
}
}
viewPager.currentItem = pos
@ -327,7 +332,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
settings.removeNonexistingChats(presentChatTitles)
}
fun stopShowingChatsOnMap(forceStop: Boolean) {
private fun stopShowingChatsOnMap(forceStop: Boolean) {
settings.getShowOnMapChats().forEach { app.showLocationHelper.hideChatMessages(it) }
app.showLocationHelper.stopShowingLocation(forceStop)
}
@ -380,13 +385,22 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
imageView.setOnClickListener { showOptionsPopupMenu(imageView) }
}
fun showSnackBar() {
if (!snackbarShown) {
val snackbar = Snackbar.make(coordinatorLayout, R.string.timeline_available_for_free_now, Snackbar.LENGTH_LONG).setAction(R.string.shared_string_ok) {}
AndroidUtils.setSnackbarTextColor(snackbar, R.color.ctrl_active_dark)
snackbar.show()
snackbarShown = true
private fun shouldShowFreeTimelineInfo(): Boolean {
val freeTimelineInfoShownTime = settings.freeTimelineInfoShownTime
if (freeTimelineInfoShownTime != 0L) {
val cal = Calendar.getInstance()
val day = cal.get(Calendar.DAY_OF_MONTH)
cal.timeInMillis = freeTimelineInfoShownTime
return day != cal.get(Calendar.DAY_OF_MONTH)
}
return true
}
private fun showFreeTimelineInfo() {
val snackbar = Snackbar.make(coordinatorLayout, R.string.timeline_available_for_free_now, Snackbar.LENGTH_LONG).setAction(R.string.shared_string_ok) {}
AndroidUtils.setSnackbarTextColor(snackbar, R.color.ctrl_active_dark)
snackbar.show()
settings.freeTimelineInfoShownTime = System.currentTimeMillis()
}
private fun showOptionsPopupMenu(anchor: View) {
@ -484,6 +498,10 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
}
}
fun refreshPages() {
viewPager.adapter?.notifyDataSetChanged()
}
private fun showOsmandMissingDialog() {
OsmandMissingDialogFragment().show(supportFragmentManager, null)
}
@ -510,5 +528,9 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
override fun getItem(position: Int) = fragments[position]
override fun getCount() = fragments.size
override fun getItemPosition(`object`: Any): Int {
return PagerAdapter.POSITION_NONE
}
}
}

View file

@ -3,6 +3,8 @@ package net.osmand.telegram.ui
import android.animation.*
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Typeface
import android.graphics.drawable.GradientDrawable
import android.os.Build
@ -17,13 +19,12 @@ import android.text.SpannableString
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan
import android.util.TypedValue
import android.view.*
import android.view.animation.LinearInterpolator
import android.widget.*
import net.osmand.telegram.ADDITIONAL_ACTIVE_TIME_VALUES_SEC
import net.osmand.telegram.R
import net.osmand.telegram.SHARE_TYPE_MAP
import net.osmand.telegram.TelegramApplication
import net.osmand.PlatformUtil
import net.osmand.telegram.*
import net.osmand.telegram.helpers.LocationMessages
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.TelegramListener
@ -31,9 +32,13 @@ import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandFormatter
import org.drinkless.td.libcore.telegram.TdApi
import java.util.*
import kotlin.Comparator
import kotlin.collections.HashSet
private const val SELECTED_CHATS_KEY = "selected_chats"
private const val SELECTED_CHATS_USERS = "selected_users"
private const val SUGGESTED = 2
private const val SHARE_LOCATION_CHAT = 1
private const val DEFAULT_CHAT = 0
@ -41,10 +46,14 @@ private const val ADAPTER_UPDATE_INTERVAL_MIL = 5 * 1000L // 5 sec
class MyLocationTabFragment : Fragment(), TelegramListener {
private val log = PlatformUtil.getLog(MyLocationTabFragment::class.java)
private var textMarginSmall: Int = 0
private var textMarginBig: Int = 0
private var searchBoxHeight: Int = 0
private var searchBoxSidesMargin: Int = 0
private var titlePaddingSmall: Int = 0
private var titlePaddingBig: Int = 0
private var appBarScrollRange: Int = -1
@ -68,6 +77,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
private lateinit var sharingStatusTitle: TextView
private lateinit var sharingStatusIcon: ImageView
private lateinit var startSharingBtn: View
private lateinit var backToOsmAndBtn: TextView
private lateinit var searchBoxBg: GradientDrawable
@ -85,6 +95,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
private var updateEnable: Boolean = false
private lateinit var lastChatsInfo: LinkedList<TelegramSettings.LastChatInfo>
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -99,6 +111,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
textMarginBig = resources.getDimensionPixelSize(R.dimen.my_location_text_sides_margin)
searchBoxHeight = resources.getDimensionPixelSize(R.dimen.search_box_height)
searchBoxSidesMargin = resources.getDimensionPixelSize(R.dimen.content_padding_half)
titlePaddingSmall = resources.getDimensionPixelSize(R.dimen.app_bar_title_padding_small)
titlePaddingBig = resources.getDimensionPixelSize(R.dimen.app_bar_title_padding_big)
sharingMode = settings.hasAnyChatToShareLocation()
@ -166,7 +180,6 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
if (Build.VERSION.SDK_INT >= 16) {
layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
}
AndroidUtils.addStatusBarPadding19v(app, this)
title = findViewById(R.id.title)
description = findViewById(R.id.description)
}
@ -234,6 +247,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
}
}
backToOsmAndBtn = mainView.findViewById<TextView>(R.id.back_to_osmand)
lastChatsInfo = settings.lastChatsInfo
return mainView
}
@ -268,6 +284,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
}
}
DisableSharingBottomSheet.SHARING_DISABLED_REQUEST_CODE -> {
saveChatsToLastChatsInfo()
sharingMode = false
app.stopSharingLocation()
updateContent()
@ -388,10 +405,19 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
private fun adjustText() {
val gravity = if (appBarCollapsed) Gravity.START else Gravity.CENTER
val padding = if (appBarCollapsed) textMarginSmall else textMarginBig
val titlePadding = if (appBarCollapsed) titlePaddingBig else titlePaddingSmall
textContainer.apply {
setPadding(padding, paddingTop, padding, paddingBottom)
if (appBarCollapsed) {
AndroidUtils.addStatusBarPadding19v(app, this)
} else {
AndroidUtils.removeStatusBarPadding19v(app, this)
}
}
title.apply {
this.gravity = gravity
setPadding(paddingLeft, titlePadding, paddingRight, titlePadding)
}
title.gravity = gravity
description.gravity = gravity
}
@ -470,6 +496,25 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
if (sharingMode) 0 else AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
stopSharingSwitcher.isChecked = true
appBarScrollRange = -1
updateBackToOsmAndBtn()
}
private fun updateBackToOsmAndBtn() {
val pckg = app.settings.appToConnectPackage
backToOsmAndBtn.apply {
visibility = if (pckg.isNotEmpty() && sharingMode && AndroidUtils.isAppInstalled(app, pckg)) {
setOnClickListener {
val startIntent = app.packageManager.getLaunchIntentForPackage(pckg)
if (startIntent != null) {
startIntent.addCategory(Intent.CATEGORY_LAUNCHER)
startActivity(startIntent)
}
}
View.VISIBLE
} else {
View.GONE
}
}
}
private fun updateSharingStatus() {
@ -487,9 +532,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
}
private fun updateList() {
val items: MutableList<TdApi.Object> = mutableListOf()
val lastItems = getLastShareItems()
val items: MutableList<Any> = mutableListOf()
val chats: MutableList<TdApi.Chat> = mutableListOf()
val currentUser = telegramHelper.getCurrentUser()
val contacts = telegramHelper.getContacts()
val chatList = if (sharingMode) {
settings.getShareLocationChats()
@ -501,10 +546,6 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
if (chat != null) {
if (!sharingMode && settings.isSharingLocationToChat(chatId)) {
continue
} else if (telegramHelper.isPrivateChat(chat)) {
if ((chat.type as TdApi.ChatTypePrivate).userId == currentUser?.id) {
continue
}
}
chats.add(chat)
}
@ -512,22 +553,50 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
items.addAll(chats)
if (!sharingMode) {
for (user in contacts.values) {
val containsInChats =
chats.any { telegramHelper.getUserIdFromChatType(it.type) == user.id }
if ((!sharingMode && settings.isSharingLocationToUser(user.id)) || user.id == currentUser?.id || containsInChats) {
val containsInChats = chats.any { telegramHelper.getUserIdFromChatType(it.type) == user.id }
if ((!sharingMode && settings.isSharingLocationToUser(user.id)) || containsInChats) {
continue
}
items.add(user)
}
}
if (sharingMode && settings.hasAnyChatToShareLocation()) {
adapter.items = sortAdapterItems(items)
val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList()
val sortedItems = sortAdapterItems(items as MutableList<TdApi.Object>)
sortedItems.add(SuggestedChats(filteredLastItems))
adapter.items = sortedItems
} else {
val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList()
items.add(0, SuggestedChats(filteredLastItems))
adapter.items = items
}
}
private fun sortAdapterItems(list: MutableList<TdApi.Object>): MutableList<TdApi.Object> {
private fun getLastShareItems(): MutableList<LastChat> {
val lastItems: MutableList<LastChat> = mutableListOf()
val chatListIds = telegramHelper.getChatListIds()
chatListIds.forEach { chatId ->
val chat = telegramHelper.getChat(chatId)
val lastInfo = lastChatsInfo.find { it.chatId == chatId }
if (chat != null && lastInfo != null) {
val index = lastChatsInfo.indexOf(lastInfo)
lastItems.add(LastChat(chat, lastChatsInfo[index].period))
}
}
return lastItems
}
private fun saveChatsToLastChatsInfo() {
val chatListIds = settings.getShareLocationChats()
chatListIds.forEach { id ->
val shareInfo = settings.getChatsShareInfo()[id]
if (shareInfo != null) {
settings.addTimePeriodToLastItem(shareInfo.chatId, shareInfo.livePeriod)
}
}
}
private fun sortAdapterItems(list: MutableList<TdApi.Object>): MutableList<Any> {
list.sortWith(Comparator<TdApi.Object> { o1, o2 ->
val title1 = when (o1) {
is TdApi.Chat -> o1.title
@ -541,12 +610,12 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
}
title1.compareTo(title2)
})
return list
return list.toMutableList()
}
inner class MyLocationListAdapter :
RecyclerView.Adapter<MyLocationListAdapter.BaseViewHolder>() {
var items = mutableListOf<TdApi.Object>()
var items = mutableListOf<Any>()
set(value) {
field = value
notifyDataSetChanged()
@ -559,7 +628,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
is TdApi.User -> item.id.toLong()
else -> -1
}
return if (settings.isSharingLocationToChat(id) && sharingMode) {
return if (item is SuggestedChats) {
SUGGESTED
} else if (settings.isSharingLocationToChat(id) && sharingMode) {
SHARE_LOCATION_CHAT
} else {
DEFAULT_CHAT
@ -578,6 +649,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
.inflate(R.layout.user_list_item, parent, false)
ChatViewHolder(view)
}
SUGGESTED -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.suggested_list_item, parent, false)
SuggestedViewHolder(view)
}
else -> throw RuntimeException("Unsupported view type: $viewType")
}
}
@ -588,31 +664,18 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
val isChat = item is TdApi.Chat
val itemId = if (isChat) {
(item as TdApi.Chat).id
} else if (item is TdApi.User) {
item.id.toLong()
} else {
(item as TdApi.User).id.toLong()
-1
}
val lastItem = position == itemCount - 1
val placeholderId =
if (isChat && telegramHelper.isGroup(item as TdApi.Chat)) R.drawable.img_group_picture else R.drawable.img_user_picture
val live = (isChat && settings.isSharingLocationToChat(itemId))
val shareInfo = if (isChat) settings.getChatsShareInfo()[itemId] else null
val photoPath = when (item) {
is TdApi.Chat -> item.photo?.small?.local?.path
is TdApi.User -> item.profilePhoto?.small?.local?.path
else -> null
}
TelegramUiHelper.setupPhoto(app, holder.icon, photoPath, placeholderId, false)
val title = when (item) {
is TdApi.Chat -> item.title
is TdApi.User -> TelegramUiHelper.getUserName(item)
else -> null
}
holder.title?.text = title
setupPhoto(item, holder.icon, isChat)
holder.title?.text = getTitleText(item)
if (holder is ChatViewHolder) {
holder.description?.visibility = View.GONE
@ -666,8 +729,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
settings.shareLocationToChat(itemId, false)
if (shareInfo != null) {
telegramHelper.stopSendingLiveLocationToChat(shareInfo)
settings.addTimePeriodToLastItem(shareInfo.chatId,shareInfo.livePeriod)
}
removeItem(item)
removeItem(item as TdApi.Object)
}
}
}
@ -740,12 +804,113 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
text = description
}
}
} else if (holder is SuggestedViewHolder) {
holder.list.removeAllViews()
if ((item as SuggestedChats).list.isEmpty()) {
holder.container?.visibility = View.GONE
} else {
holder.container?.visibility = View.VISIBLE
val iterator = item.list.iterator()
iterator.forEach {
holder.list.addView(createLastChatView(it, iterator.hasNext()))
}
}
val tv = TypedValue()
if (!sharingMode) {
holder.dividerTop?.visibility = View.GONE
holder.dividerBottom?.visibility = View.VISIBLE
holder.header?.visibility = View.GONE
if (context?.theme?.resolveAttribute(R.attr.card_bg_color, tv, true) != null) {
holder.container?.setBackgroundColor(tv.data)
}
} else {
holder.dividerTop?.visibility = View.VISIBLE
holder.dividerBottom?.visibility = View.GONE
holder.header?.visibility = View.VISIBLE
if (context?.theme?.resolveAttribute(R.attr.shared_chat_card_bg, tv, true) != null) {
holder.container?.setBackgroundResource(tv.resourceId)
}
}
}
}
private fun getTitleText(item: Any): String? {
val currentUserId = telegramHelper.getCurrentUserId()
return when (item) {
is LastChat -> {
if (telegramHelper.isPrivateChat(item.chat) && (item.chat.type as TdApi.ChatTypePrivate).userId == currentUserId) {
getString(R.string.saved_messages)
} else {
item.chat.title
}
}
is TdApi.Chat -> {
if (telegramHelper.isPrivateChat(item) && (item.type as TdApi.ChatTypePrivate).userId == currentUserId) {
getString(R.string.saved_messages)
} else {
item.title
}
}
is TdApi.User -> {
if (item.id == currentUserId) getString(R.string.saved_messages) else TelegramUiHelper.getUserName(item)
}
else -> null
}
}
private fun setupPhoto(item: Any, icon: ImageView?, isChat: Boolean) {
val photoPath = when (item) {
is LastChat -> item.chat.photo?.small?.local?.path
is TdApi.Chat -> item.photo?.small?.local?.path
is TdApi.User -> item.profilePhoto?.small?.local?.path
else -> null
}
val placeholderId =
if (isChat && telegramHelper.isGroup(item as TdApi.Chat)) R.drawable.img_group_picture else R.drawable.img_user_picture
TelegramUiHelper.setupPhoto(app, icon, photoPath, placeholderId, false)
}
private fun createLastChatView(lastChat: LastChat, hasNext: Boolean): View {
val view = layoutInflater.inflate(R.layout.last_share_list_item, null)
val time: TextView = view.findViewById(R.id.time)
val container: LinearLayout = view.findViewById(R.id.container)
val icon: ImageView = view.findViewById(R.id.icon)
val title: TextView = view.findViewById(R.id.title)
val divider: View = view.findViewById(R.id.divider)
if (sharingMode && hasNext) {
divider.visibility = View.VISIBLE
}
container.setOnClickListener {
if (!AndroidUtils.isLocationPermissionAvailable(view!!.context)) {
AndroidUtils.requestLocationPermission(activity!!)
} else {
settings.shareLocationToChat(lastChat.chat.id, true, lastChat.time)
app.shareLocationHelper.startSharingLocation()
(activity as MainActivity).refreshPages()
}
}
title.text = getTitleText(lastChat.chat)
setupPhoto(lastChat.chat, icon, true)
icon.colorFilter = ColorMatrixColorFilter(ColorMatrix().apply { setSaturation(0F) })
val sharingTime = SpannableStringBuilder("${getString(R.string.sharing_time)}: ")
val formattedTime = OsmandFormatter.getFormattedDuration(app, lastChat.time, false)
val start = sharingTime.length
sharingTime.append(formattedTime)
sharingTime.setSpan(StyleSpan(Typeface.BOLD), start, sharingTime.length, 0)
sharingTime.setSpan(ForegroundColorSpan(ContextCompat.getColor(app, R.color.ctrl_active_light)), start, sharingTime.length, 0)
time.text = sharingTime
return view
}
private fun removeItem(chat: TdApi.Object) {
items.remove(chat)
if (items.isEmpty()) {
val filtered = items.filterIsInstance<TdApi.Object>()
if (filtered.isEmpty()) {
sharingMode = false
updateContent()
shareLocationHelper.stopSharingLocation()
@ -775,9 +940,21 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
val sharingExpiresLine: TextView? = view.findViewById(R.id.expires_line)
val gpsPointsLine: TextView? = view.findViewById(R.id.gps_points_line)
}
inner class SuggestedViewHolder(val view: View) : BaseViewHolder(view) {
val list: LinearLayout = view.findViewById(R.id.last_items_list)
val container: LinearLayout? = view.findViewById(R.id.container)
val dividerBottom: View? = view.findViewById(R.id.divider_bottom)
val dividerTop: View? = view.findViewById(R.id.divider_top)
val header: TextView? = view.findViewById(R.id.header)
}
}
interface ActionButtonsListener {
fun switchButtonsVisibility(visible: Boolean)
}
}
}
class LastChat internal constructor(val chat: TdApi.Chat, val time: Long)
class SuggestedChats internal constructor(val list: MutableList<LastChat>)

View file

@ -155,14 +155,22 @@ class SearchDialogFragment : BaseDialogFragment(), TelegramHelper.TelegramSearch
}
private fun runSearch(text: String) {
if (getSavedMessagesChatTitle().startsWith(text, true)) {
val savedMessages = telegramHelper.getChat(telegramHelper.getCurrentUserId().toLong())
if (savedMessages != null) {
telegramHelper.searchChats(savedMessages.title)
}
}
telegramHelper.searchChats(text)
telegramHelper.searchChatsOnServer(text)
telegramHelper.searchContacts(text)
if (text.length > 4) {
if (text.length > 4 && !getSavedMessagesChatTitle().startsWith(text, true)) {
telegramHelper.searchPublicChats(text)
}
}
private fun getSavedMessagesChatTitle() = getString(R.string.saved_messages)
override fun onResume() {
super.onResume()
telegramHelper.addSearchListener(this)
@ -231,7 +239,7 @@ class SearchDialogFragment : BaseDialogFragment(), TelegramHelper.TelegramSearch
selectedChats.forEach {
val chat = telegramHelper.getChat(it)
if (chat != null) {
if (!telegramHelper.isChannel(chat) && telegramHelper.getUserIdFromChatType(chat.type) != currentUserId) {
if (!telegramHelper.isChannel(chat)) {
items.add(chat)
}
} else {
@ -250,7 +258,7 @@ class SearchDialogFragment : BaseDialogFragment(), TelegramHelper.TelegramSearch
searchedChatsIds.forEach {
val chat = telegramHelper.getChat(it)
if (chat != null && !selectedChats.contains(it)) {
if (!telegramHelper.isChannel(chat) && telegramHelper.getUserIdFromChatType(chat.type) != currentUserId) {
if (!telegramHelper.isChannel(chat)) {
chats.add(chat)
}
} else {
@ -382,9 +390,18 @@ class SearchDialogFragment : BaseDialogFragment(), TelegramHelper.TelegramSearch
TelegramUiHelper.setupPhoto(app, holder.icon, photoPath, placeholderId, false)
val currentUserId = telegramHelper.getCurrentUserId()
val title = when (item) {
is TdApi.Chat -> item.title
is TdApi.User -> TelegramUiHelper.getUserName(item)
is TdApi.Chat -> {
if (telegramHelper.isPrivateChat(item) && (item.type as TdApi.ChatTypePrivate).userId == currentUserId) {
getSavedMessagesChatTitle()
} else {
item.title
}
}
is TdApi.User -> {
if (item.id == currentUserId) getSavedMessagesChatTitle() else TelegramUiHelper.getUserName(item)
}
else -> null
}
@ -485,7 +502,7 @@ class SearchDialogFragment : BaseDialogFragment(), TelegramHelper.TelegramSearch
private fun getItemDescription(item: TdApi.Object, lastUpdateTime: Int?): String? {
if (lastUpdateTime != null) {
return OsmandFormatter.getListItemLiveTimeDescr(app, lastUpdateTime)
return OsmandFormatter.getListItemShortLiveTimeDescr(app, lastUpdateTime, R.string.duration_ago)
}
if (item is TdApi.Chat && telegramHelper.isGroup(item)) {
return getString(R.string.shared_string_group)

View file

@ -322,9 +322,18 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
TelegramUiHelper.setupPhoto(app, holder.icon, photoPath, placeholderId, false)
val currentUserId = telegramHelper.getCurrentUserId()
val title = when (item) {
is TdApi.Chat -> item.title
is TdApi.User -> TelegramUiHelper.getUserName(item)
is TdApi.Chat -> {
if (telegramHelper.isPrivateChat(item) && (item.type as TdApi.ChatTypePrivate).userId == currentUserId) {
getString(R.string.saved_messages)
} else {
item.title
}
}
is TdApi.User -> {
if (item.id == currentUserId) getString(R.string.saved_messages) else TelegramUiHelper.getUserName(item)
}
else -> null
}
@ -340,7 +349,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
if (message != null && content is TdApi.MessageLocation && (location != null && content.location != null)) {
val lastUpdated = OsmandLocationUtils.getLastUpdatedTime(message)
holder.description?.visibility = View.VISIBLE
holder.description?.text = OsmandFormatter.getListItemLiveTimeDescr(app, lastUpdated)
holder.description?.text = OsmandFormatter.getListItemShortLiveTimeDescr(app, lastUpdated,R.string.duration_ago)
holder.locationViewContainer?.visibility = if (lastUpdated > 0) View.VISIBLE else View.GONE
locationViewCache.outdatedLocation = System.currentTimeMillis() / 1000 -

View file

@ -17,7 +17,7 @@ import android.view.ViewGroup
import android.widget.*
import net.osmand.telegram.R
import net.osmand.telegram.TelegramSettings
import net.osmand.telegram.TelegramSettings.NumericPref
import net.osmand.telegram.TelegramSettings.ListPreference
import net.osmand.telegram.helpers.TelegramHelper.Companion.OSMAND_BOT_USERNAME
import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.utils.AndroidUtils
@ -50,7 +50,7 @@ class SettingsDialogFragment : BaseDialogFragment() {
}
var container = mainView.findViewById<ViewGroup>(R.id.gps_and_loc_container)
settings.gpsAndLocPrefs.forEach {
createNumericPref(inflater, container, it)
createListPref(inflater, container, it)
}
if (Build.VERSION.SDK_INT >= 26) {
@ -66,6 +66,11 @@ class SettingsDialogFragment : BaseDialogFragment() {
}
}
container = mainView.findViewById<ViewGroup>(R.id.units_and_formats_container)
settings.unitsAndFormatsPrefs.forEach {
createListPref(inflater, container, it)
}
container = mainView.findViewById<ViewGroup>(R.id.gps_points_container)
inflater.inflate(R.layout.item_with_descr_and_right_switch, container, false).apply {
findViewById<ImageView>(R.id.icon).setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_connect))
@ -139,7 +144,7 @@ class SettingsDialogFragment : BaseDialogFragment() {
container = mainView.findViewById<ViewGroup>(R.id.gpx_settings_container)
settings.gpxLoggingPrefs.forEach {
createNumericPref(inflater, container, it)
createListPref(inflater, container, it)
}
container = mainView.findViewById(R.id.osmand_connect_container)
@ -243,7 +248,7 @@ class SettingsDialogFragment : BaseDialogFragment() {
}
}
private fun createNumericPref(inflater: LayoutInflater, container: ViewGroup, pref: NumericPref) {
private fun createListPref(inflater: LayoutInflater, container: ViewGroup, pref: ListPreference) {
inflater.inflate(R.layout.item_with_desc_and_right_value, container, false).apply {
findViewById<ImageView>(R.id.icon).apply {
if (pref.iconId != 0) {
@ -284,14 +289,14 @@ class SettingsDialogFragment : BaseDialogFragment() {
}
}
private fun showPopupMenu(pref: NumericPref, valueView: TextView) {
private fun showPopupMenu(pref: ListPreference, valueView: TextView) {
val menuList = pref.getMenuItems()
val ctx = valueView.context
ListPopupWindow(ctx).apply {
isModal = true
anchorView = valueView
setContentWidth(AndroidUtils.getPopupMenuWidth(ctx, menuList))
height = if (menuList.size < 6) {
height = if (menuList.size <= 6) {
ListPopupWindow.WRAP_CONTENT
} else {
AndroidUtils.getPopupMenuHeight(ctx)

View file

@ -106,6 +106,14 @@ object AndroidUtils {
}
}
fun removeStatusBarPadding19v(ctx: Context, view: View) {
if (Build.VERSION.SDK_INT >= 19) {
view.apply {
setPadding(paddingLeft, paddingTop - getStatusBarHeight(ctx), paddingRight, paddingBottom)
}
}
}
fun getNavBarHeight(ctx: Context): Int {
if (!hasNavBar(ctx)) {
return 0

View file

@ -2,6 +2,8 @@ package net.osmand.telegram.utils
object DataConstants {
const val UTC_FORMAT = "UTC"
val countryPhoneCodes = mapOf("AB" to "+7840,+7940,+99544", "AF" to "+93", "AX" to "+35818",
"AL" to "+355","DZ" to "+213", "AS" to "+1684", "AD" to "+376", "AO" to "+244","AI" to "+1264",
"AG" to "+1268", "AR" to "+54", "AM" to "+374","AW" to "+297", "SH" to "+247", "AU" to "+61",
@ -44,4 +46,46 @@ object DataConstants {
"TM" to "+993", "TC" to "+1649", "TV" to "+688", "UG" to "+256","UA" to "+380", "AE" to "+971",
"UK" to "+44", "US" to "+1","UY" to "+598", "VI" to "+1340", "UZ" to "+998", "VU" to "+678", "VE" to "+58",
"VA" to "+3906698,+379", "VN" to "+84", "WF" to "+681","YE" to "+967", "ZM" to "+260", "ZW" to "+263")
val utcOffsets = mapOf(
"$UTC_FORMAT-12" to -12f,
"$UTC_FORMAT-11" to -11f,
"$UTC_FORMAT-10" to -10f,
"$UTC_FORMAT-09:30" to -9.5f,
"$UTC_FORMAT-9" to -9f,
"$UTC_FORMAT-8" to -8f,
"$UTC_FORMAT-7" to -7f,
"$UTC_FORMAT-6" to -6f,
"$UTC_FORMAT-5" to -5f,
"$UTC_FORMAT-4" to -4f,
"$UTC_FORMAT-03:30" to -3.5f,
"$UTC_FORMAT-3" to -3f,
"$UTC_FORMAT-2" to -2f,
"$UTC_FORMAT-1" to -1f,
UTC_FORMAT to 0f,
"$UTC_FORMAT+1" to 1f,
"$UTC_FORMAT+2" to 2f,
"$UTC_FORMAT+3" to 3f,
"$UTC_FORMAT+03:30" to 3.5f,
"$UTC_FORMAT+4" to 4f,
"$UTC_FORMAT+04:30" to 4.5f,
"$UTC_FORMAT+5" to 5f,
"$UTC_FORMAT+05:30" to 5.5f,
"$UTC_FORMAT+05:45" to 5.75f,
"$UTC_FORMAT+6" to 6f,
"$UTC_FORMAT+06:30" to 6.5f,
"$UTC_FORMAT+7" to 7f,
"$UTC_FORMAT+8" to 8f,
"$UTC_FORMAT+08:45" to 8.75f,
"$UTC_FORMAT+9" to 9f,
"$UTC_FORMAT+09:30" to 9.5f,
"$UTC_FORMAT+10" to 10f,
"$UTC_FORMAT+10:30" to 10.5f,
"$UTC_FORMAT+11" to 11f,
"$UTC_FORMAT+12" to 12f,
"$UTC_FORMAT+12:45" to 12.75f,
"$UTC_FORMAT+13" to 13f,
"$UTC_FORMAT+13:45" to 13.75f,
"$UTC_FORMAT+14" to 14f
)
}

View file

@ -1,6 +1,7 @@
package net.osmand.telegram.utils
import android.content.Context
import androidx.annotation.StringRes
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import java.text.DateFormatSymbols
@ -17,6 +18,14 @@ object OsmandFormatter {
val YARDS_IN_ONE_METER = 1.0936f
val FEET_IN_ONE_METER = YARDS_IN_ONE_METER * 3f
val FORMAT_METERS_KEY = "m"
val FORMAT_FEET_KEY = "ft"
val FORMAT_YARDS_KEY = "yd"
val FORMAT_KILOMETERS_KEY = "km"
val FORMAT_NAUTICALMILES_KEY = "nmi"
val FORMAT_MILES_KEY = "mi"
private val fixed2 = DecimalFormat("0.00")
private val fixed1 = DecimalFormat("0.0")
@ -37,6 +46,18 @@ object OsmandFormatter {
fixed2.minimumIntegerDigits = 1
}
fun getFormattedDurationForWidget(seconds: Long): String {
val hours = seconds / (60 * 60)
val minutes = seconds / 60 % 60
return when {
hours > 9 -> String.format("%10d:%01d", hours, minutes)
hours > 0 -> String.format("%1d:%01d", hours, minutes)
minutes > 9 -> String.format("%11d", minutes)
minutes > 0 -> String.format("%1d", minutes)
else -> "1"
}.trim()
}
fun getFormattedDuration(ctx: Context, seconds: Long, short: Boolean = false): String {
val hours = seconds / (60 * 60)
val minutes = seconds / 60 % 60
@ -86,17 +107,32 @@ object OsmandFormatter {
}
}
fun getListItemLiveTimeDescr(ctx: TelegramApplication, lastUpdated: Int, prefix: String = ""): String {
fun getListItemLiveTimeDescr(
ctx: TelegramApplication,
lastUpdated: Int, @StringRes dateRes: Int, @StringRes durationRes: Int
): String {
return if (lastUpdated > 0) {
val duration = System.currentTimeMillis() / 1000 - lastUpdated
when {
duration > MIN_DURATION_FOR_DATE_FORMAT -> prefix + getFormattedDate(lastUpdated.toLong())
duration > 0 -> prefix + getFormattedDuration(ctx, duration) + " " + ctx.getString(R.string.time_ago)
duration > MIN_DURATION_FOR_DATE_FORMAT -> ctx.getString(dateRes, getFormattedDate(lastUpdated.toLong()))
duration > 0 -> ctx.getString(durationRes, getFormattedDuration(ctx, duration))
else -> ""
}
} else {
""
}
} else ""
}
fun getListItemShortLiveTimeDescr(
ctx: TelegramApplication,
lastUpdated: Int, @StringRes durationRes: Int
): String {
return if (lastUpdated > 0) {
val duration = System.currentTimeMillis() / 1000 - lastUpdated
when {
duration > MIN_DURATION_FOR_DATE_FORMAT -> getFormattedDate(lastUpdated.toLong())
duration > 0 -> ctx.getString(durationRes, getFormattedDuration(ctx, duration))
else -> ""
}
} else ""
}
fun calculateRoundedDist(distInMeters: Double, ctx: TelegramApplication): Double {
@ -166,118 +202,94 @@ object OsmandFormatter {
}
@JvmOverloads
fun getFormattedDistance(meters: Float, ctx: TelegramApplication, forceTrailingZeros: Boolean = true): String {
fun getFormattedDistance(meters: Float, ctx: TelegramApplication, forceTrailingZeros: Boolean = true, useLocalizedString: Boolean = true): String {
val format1 = if (forceTrailingZeros) "{0,number,0.0} " else "{0,number,0.#} "
val format2 = if (forceTrailingZeros) "{0,number,0.00} " else "{0,number,0.##} "
val mc = ctx.settings.metricsConstants
val mainUnitStr: Int
val mainUnitStr: String
val mainUnitInMeters: Float
if (mc == MetricsConstants.KILOMETERS_AND_METERS) {
mainUnitStr = R.string.km
mainUnitInMeters = METERS_IN_KILOMETER
} else if (mc == MetricsConstants.NAUTICAL_MILES) {
mainUnitStr = R.string.nm
mainUnitInMeters = METERS_IN_ONE_NAUTICALMILE
} else {
mainUnitStr = R.string.mile
mainUnitInMeters = METERS_IN_ONE_MILE
when (mc) {
MetricsConstants.KILOMETERS_AND_METERS -> {
mainUnitStr = if (useLocalizedString) ctx.getString(R.string.km) else FORMAT_KILOMETERS_KEY
mainUnitInMeters = METERS_IN_KILOMETER
}
MetricsConstants.NAUTICAL_MILES -> {
mainUnitStr = if (useLocalizedString) ctx.getString(R.string.nm) else FORMAT_NAUTICALMILES_KEY
mainUnitInMeters = METERS_IN_ONE_NAUTICALMILE
}
else -> {
mainUnitStr = if (useLocalizedString) ctx.getString(R.string.mile) else FORMAT_MILES_KEY
mainUnitInMeters = METERS_IN_ONE_MILE
}
}
if (meters >= 100 * mainUnitInMeters) {
return (meters / mainUnitInMeters + 0.5).toInt().toString() + " " + ctx.getString(mainUnitStr) //$NON-NLS-1$
return (meters / mainUnitInMeters + 0.5).toInt().toString() + " " + mainUnitStr //$NON-NLS-1$
} else if (meters > 9.99f * mainUnitInMeters) {
return MessageFormat.format(format1 + ctx.getString(mainUnitStr), meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
return MessageFormat.format(format1 + mainUnitStr, meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
} else if (meters > 0.999f * mainUnitInMeters) {
return MessageFormat.format(format2 + ctx.getString(mainUnitStr), meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
return MessageFormat.format(format2 + mainUnitStr, meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
} else if (mc == MetricsConstants.MILES_AND_FEET && meters > 0.249f * mainUnitInMeters) {
return MessageFormat.format(format2 + ctx.getString(mainUnitStr), meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
return MessageFormat.format(format2 + mainUnitStr, meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
} else if (mc == MetricsConstants.MILES_AND_METERS && meters > 0.249f * mainUnitInMeters) {
return MessageFormat.format(format2 + ctx.getString(mainUnitStr), meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
return MessageFormat.format(format2 + mainUnitStr, meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
} else if (mc == MetricsConstants.MILES_AND_YARDS && meters > 0.249f * mainUnitInMeters) {
return MessageFormat.format(format2 + ctx.getString(mainUnitStr), meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
return MessageFormat.format(format2 + mainUnitStr, meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
} else if (mc == MetricsConstants.NAUTICAL_MILES && meters > 0.99f * mainUnitInMeters) {
return MessageFormat.format(format2 + ctx.getString(mainUnitStr), meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
return MessageFormat.format(format2 + mainUnitStr, meters / mainUnitInMeters).replace('\n', ' ') //$NON-NLS-1$
} else {
if (mc == MetricsConstants.KILOMETERS_AND_METERS || mc == MetricsConstants.MILES_AND_METERS) {
return (meters + 0.5).toInt().toString() + " " + ctx.getString(R.string.m) //$NON-NLS-1$
return (meters + 0.5).toInt().toString() + if (useLocalizedString) " " + ctx.getString(R.string.m) else " $FORMAT_METERS_KEY" //$NON-NLS-1$
} else if (mc == MetricsConstants.MILES_AND_FEET) {
val feet = (meters * FEET_IN_ONE_METER + 0.5).toInt()
return feet.toString() + " " + ctx.getString(R.string.foot) //$NON-NLS-1$
return feet.toString() + if (useLocalizedString) " " + ctx.getString(R.string.foot) else " $FORMAT_FEET_KEY" //$NON-NLS-1$
} else if (mc == MetricsConstants.MILES_AND_YARDS) {
val yards = (meters * YARDS_IN_ONE_METER + 0.5).toInt()
return yards.toString() + " " + ctx.getString(R.string.yard) //$NON-NLS-1$
return yards.toString() + if (useLocalizedString) " " + ctx.getString(R.string.yard) else " $FORMAT_YARDS_KEY" //$NON-NLS-1$
}
return (meters + 0.5).toInt().toString() + " " + ctx.getString(R.string.m) //$NON-NLS-1$
return (meters + 0.5).toInt().toString() + if (useLocalizedString) " " + ctx.getString(R.string.m) else " $FORMAT_METERS_KEY" //$NON-NLS-1$
}
}
fun getFormattedAlt(alt: Double, ctx: TelegramApplication): String {
fun getFormattedAlt(alt: Double, ctx: TelegramApplication, useLocalizedString: Boolean = true): String {
val mc = ctx.settings.metricsConstants
return if (mc == MetricsConstants.KILOMETERS_AND_METERS) {
(alt + 0.5).toInt().toString() + " " + ctx.getString(R.string.m)
val useFeet = mc == MetricsConstants.MILES_AND_FEET || mc == MetricsConstants.MILES_AND_YARDS
return if (!useFeet) {
(alt + 0.5).toInt().toString() + if (useLocalizedString) " " + ctx.getString(R.string.m) else " $FORMAT_METERS_KEY"
} else {
(alt * FEET_IN_ONE_METER + 0.5).toInt().toString() + " " + ctx.getString(R.string.foot)
(alt * FEET_IN_ONE_METER + 0.5).toInt().toString() + if (useLocalizedString) " " + ctx.getString(R.string.foot) else " $FORMAT_FEET_KEY"
}
}
fun getFormattedSpeed(metersperseconds: Float, ctx: TelegramApplication): String {
fun getFormattedSpeed(metersPerSeconds: Float, ctx: TelegramApplication, useLocalizedString: Boolean = true): String {
val mc = ctx.settings.speedConstants
val kmh = metersperseconds * 3.6f
if (mc == SpeedConstants.KILOMETERS_PER_HOUR) {
val kmh = metersPerSeconds * 3.6f
val convertedSpeed: Float = when (mc) {
SpeedConstants.KILOMETERS_PER_HOUR -> kmh
SpeedConstants.MILES_PER_HOUR -> kmh * METERS_IN_KILOMETER / METERS_IN_ONE_MILE
SpeedConstants.NAUTICALMILES_PER_HOUR -> kmh * METERS_IN_KILOMETER / METERS_IN_ONE_NAUTICALMILE
SpeedConstants.MINUTES_PER_KILOMETER -> {
if (metersPerSeconds < 0.111111111) {
return "-" + if (useLocalizedString) mc.toShortString(ctx) else mc.getDefaultString()
}
METERS_IN_KILOMETER / (metersPerSeconds * 60)
}
SpeedConstants.MINUTES_PER_MILE -> {
if (metersPerSeconds < 0.111111111) {
return "-" + if (useLocalizedString) mc.toShortString(ctx) else mc.getDefaultString()
}
METERS_IN_ONE_MILE / (metersPerSeconds * 60)
}
else -> metersPerSeconds /*if (mc == SpeedConstants.METERS_PER_SECOND) */
}
return if (convertedSpeed >= mc.speedThreshold) {
// e.g. car case and for high-speeds: Display rounded to 1 km/h (5% precision at 20 km/h)
if (kmh >= 20) {
return Math.round(kmh).toString() + " " + mc.toShortString(ctx)
}
"${Math.round(convertedSpeed)} " + if (useLocalizedString) mc.toShortString(ctx) else mc.getDefaultString()
} else {
// for smaller values display 1 decimal digit x.y km/h, (0.5% precision at 20 km/h)
val kmh10 = Math.round(kmh * 10f)
return (kmh10 / 10f).toString() + " " + mc.toShortString(ctx)
} else if (mc == SpeedConstants.MILES_PER_HOUR) {
val mph = kmh * METERS_IN_KILOMETER / METERS_IN_ONE_MILE
if (mph >= 20) {
return Math.round(mph).toString() + " " + mc.toShortString(ctx)
} else {
val mph10 = Math.round(mph * 10f)
return (mph10 / 10f).toString() + " " + mc.toShortString(ctx)
}
} else if (mc == SpeedConstants.NAUTICALMILES_PER_HOUR) {
val mph = kmh * METERS_IN_KILOMETER / METERS_IN_ONE_NAUTICALMILE
if (mph >= 20) {
return Math.round(mph).toString() + " " + mc.toShortString(ctx)
} else {
val mph10 = Math.round(mph * 10f)
return (mph10 / 10f).toString() + " " + mc.toShortString(ctx)
}
} else if (mc == SpeedConstants.MINUTES_PER_KILOMETER) {
if (metersperseconds < 0.111111111) {
return "-" + mc.toShortString(ctx)
}
val minperkm = METERS_IN_KILOMETER / (metersperseconds * 60)
if (minperkm >= 10) {
return Math.round(minperkm).toString() + " " + mc.toShortString(ctx)
} else {
val mph10 = Math.round(minperkm * 10f)
return (mph10 / 10f).toString() + " " + mc.toShortString(ctx)
}
} else if (mc == SpeedConstants.MINUTES_PER_MILE) {
if (metersperseconds < 0.111111111) {
return "-" + mc.toShortString(ctx)
}
val minperm = METERS_IN_ONE_MILE / (metersperseconds * 60)
if (minperm >= 10) {
return Math.round(minperm).toString() + " " + mc.toShortString(ctx)
} else {
val mph10 = Math.round(minperm * 10f)
return (mph10 / 10f).toString() + " " + mc.toShortString(ctx)
}
} else
/*if (mc == SpeedConstants.METERS_PER_SECOND) */ {
if (metersperseconds >= 10) {
return Math.round(metersperseconds).toString() + " " + SpeedConstants.METERS_PER_SECOND.toShortString(ctx)
}
// for smaller values display 1 decimal digit x.y km/h, (0.5% precision at 20 km/h)
val kmh10 = Math.round(metersperseconds * 10f)
return (kmh10 / 10f).toString() + " " + SpeedConstants.METERS_PER_SECOND.toShortString(ctx)
"${Math.round(convertedSpeed * 10f) / 10f} " + if (useLocalizedString) mc.toShortString(ctx) else mc.getDefaultString()
}
}
@ -311,20 +323,27 @@ object OsmandFormatter {
}
}
enum class SpeedConstants private constructor(private val key: Int, private val descr: Int) {
KILOMETERS_PER_HOUR(R.string.km_h, R.string.si_kmh),
MILES_PER_HOUR(R.string.mile_per_hour, R.string.si_mph),
METERS_PER_SECOND(R.string.m_s, R.string.si_m_s),
MINUTES_PER_MILE(R.string.min_mile, R.string.si_min_m),
MINUTES_PER_KILOMETER(R.string.min_km, R.string.si_min_km),
NAUTICALMILES_PER_HOUR(R.string.nm_h, R.string.si_nm_h);
enum class SpeedConstants private constructor(
private val key: String,
private val title: Int,
private val descr: Int,
val speedThreshold: Int
) {
KILOMETERS_PER_HOUR("km/h", R.string.km_h, R.string.si_kmh, 20),
MILES_PER_HOUR("mph", R.string.mile_per_hour, R.string.si_mph, 20),
METERS_PER_SECOND("m/s", R.string.m_s, R.string.si_m_s, 10),
MINUTES_PER_MILE("min/m", R.string.min_mile, R.string.si_min_m, 10),
MINUTES_PER_KILOMETER("min/km", R.string.min_km, R.string.si_min_km, 10),
NAUTICALMILES_PER_HOUR("nmi/h", R.string.nm_h, R.string.si_nm_h, 20);
fun toHumanString(ctx: Context): String {
return ctx.getString(descr)
}
fun toShortString(ctx: Context): String {
return ctx.getString(key)
return ctx.getString(title)
}
fun getDefaultString() = key
}
}

View file

@ -42,7 +42,9 @@ object OsmandLocationUtils {
const val SECONDS_AGO_SUFFIX = " seconds ago"
const val MINUTES_AGO_SUFFIX = " minutes ago"
const val HOURS_AGO_SUFFIX = " hours ago"
const val UTC_FORMAT_SUFFIX = " UTC"
const val UTC_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss"
const val ONE_HOUR_TIME_MS = 60 * 60 * 1000 // 1 hour
val UTC_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.US).apply {
timeZone = TimeZone.getTimeZone("UTC")
@ -163,9 +165,17 @@ object OsmandLocationUtils {
return String.format(Locale.US, "%.5f, %.5f", sig.lat, sig.lon)
}
fun formatFullTime(ti: Long): String {
fun formatFullTime(ti: Long, app: TelegramApplication): String {
val dt = Date(ti)
return UTC_DATE_FORMAT.format(dt) + " " + UTC_TIME_FORMAT.format(dt) + " UTC"
val offsetKey = app.settings.utcOffset
val utcOffset = DataConstants.utcOffsets[offsetKey] ?: 0f
val simpleDateFormat = SimpleDateFormat(UTC_FORMAT_PATTERN, Locale.US)
simpleDateFormat.timeZone = TimeZone.getTimeZone(DataConstants.UTC_FORMAT).apply {
rawOffset = (utcOffset * ONE_HOUR_TIME_MS).toInt()
}
return "${simpleDateFormat.format(dt)} $offsetKey"
}
fun parseOsmAndBotLocationContent(oldContent: MessageOsmAndBotLocation, content: TdApi.MessageContent): MessageOsmAndBotLocation {
@ -242,21 +252,11 @@ object OsmandLocationUtils {
}
s.startsWith(ALTITUDE_PREFIX) -> {
val altStr = s.removePrefix(ALTITUDE_PREFIX)
try {
val alt = altStr.split(" ").first()
res.altitude = alt.toDouble()
} catch (e: Exception) {
e.printStackTrace()
}
res.altitude = parseDistance(altStr)
}
s.startsWith(SPEED_PREFIX) -> {
val speedStr = s.removePrefix(SPEED_PREFIX)
try {
val speed = speedStr.split(" ").first()
res.speed = speed.toDouble()
} catch (e: Exception) {
e.printStackTrace()
}
res.speed = parseSpeed(speedStr)
}
s.startsWith(BEARING_PREFIX) -> {
val bearingStr = s.removePrefix(BEARING_PREFIX)
@ -269,12 +269,7 @@ object OsmandLocationUtils {
}
s.startsWith(HDOP_PREFIX) -> {
val hdopStr = s.removePrefix(HDOP_PREFIX)
try {
val hdop = hdopStr.split(" ").first()
res.hdop = hdop.toDouble()
} catch (e: Exception) {
e.printStackTrace()
}
res.hdop = parseDistance(hdopStr)
}
s.startsWith(UPDATED_PREFIX) -> {
if (res.lastUpdated == 0) {
@ -314,13 +309,19 @@ object OsmandLocationUtils {
val hours = locStr.toLong()
return (System.currentTimeMillis() - hours * 60 * 60 * 1000)
}
timeS.endsWith(UTC_FORMAT_SUFFIX) -> {
val locStr = timeS.removeSuffix(UTC_FORMAT_SUFFIX)
val (latS, lonS) = locStr.split(" ")
val date = UTC_DATE_FORMAT.parse(latS)
val time = UTC_TIME_FORMAT.parse(lonS)
val res = date.time + time.time
return res
timeS.contains(DataConstants.UTC_FORMAT) -> {
val utcIndex = timeS.indexOf(DataConstants.UTC_FORMAT)
if (utcIndex != -1) {
val locStr = timeS.substring(0, utcIndex)
val utcOffset = timeS.substring(utcIndex)
val utcTimeOffset = DataConstants.utcOffsets[utcOffset] ?: 0f
val simpleDateFormat = SimpleDateFormat(UTC_FORMAT_PATTERN, Locale.US)
simpleDateFormat.timeZone = TimeZone.getTimeZone(DataConstants.UTC_FORMAT).apply {
rawOffset = (utcTimeOffset * ONE_HOUR_TIME_MS).toInt()
}
val res = simpleDateFormat.parse(locStr)
return res.time
}
}
}
} catch (e: Exception) {
@ -329,50 +330,48 @@ object OsmandLocationUtils {
return 0
}
fun getTextMessageContent(updateId: Int, location: LocationMessage): TdApi.InputMessageText {
val entities = mutableListOf<TdApi.TextEntity>()
val builder = StringBuilder()
val locationMessage = formatLocation(location)
val firstSpace = USER_TEXT_LOCATION_TITLE.indexOf(' ')
val secondSpace = USER_TEXT_LOCATION_TITLE.indexOf(' ', firstSpace + 1)
entities.add(TdApi.TextEntity(builder.length + firstSpace + 1, secondSpace - firstSpace, TdApi.TextEntityTypeTextUrl(SHARING_LINK)))
builder.append("$USER_TEXT_LOCATION_TITLE\n")
entities.add(TdApi.TextEntity(builder.lastIndex, LOCATION_PREFIX.length, TdApi.TextEntityTypeBold()))
builder.append(LOCATION_PREFIX)
entities.add(TdApi.TextEntity(builder.length, locationMessage.length,
TdApi.TextEntityTypeTextUrl("$BASE_SHARING_URL?lat=${location.lat}&lon=${location.lon}")))
builder.append("$locationMessage\n")
if (location.altitude != 0.0) {
entities.add(TdApi.TextEntity(builder.lastIndex, ALTITUDE_PREFIX.length, TdApi.TextEntityTypeBold()))
builder.append(String.format(Locale.US, "$ALTITUDE_PREFIX%.1f m\n", location.altitude))
fun parseSpeed(speedS: String): Double {
try {
if (!speedS.contains(" ")) {
return 0.0
}
val speedSplit = speedS.split(" ")
val speedVal = speedSplit.first().toDouble()
val speedFormat = OsmandFormatter.SpeedConstants.values().firstOrNull { it.getDefaultString() == speedSplit.last() }
return when (speedFormat) {
OsmandFormatter.SpeedConstants.KILOMETERS_PER_HOUR -> speedVal / 3.6f
OsmandFormatter.SpeedConstants.MILES_PER_HOUR -> (speedVal / 3.6f) / (OsmandFormatter.METERS_IN_KILOMETER / OsmandFormatter.METERS_IN_ONE_MILE)
OsmandFormatter.SpeedConstants.NAUTICALMILES_PER_HOUR -> (speedVal / 3.6f) / (OsmandFormatter.METERS_IN_KILOMETER / OsmandFormatter.METERS_IN_ONE_NAUTICALMILE)
OsmandFormatter.SpeedConstants.MINUTES_PER_KILOMETER -> (OsmandFormatter.METERS_IN_KILOMETER / speedVal) / 60
OsmandFormatter.SpeedConstants.MINUTES_PER_MILE -> (OsmandFormatter.METERS_IN_ONE_MILE / speedVal) / 60
else -> speedVal
}
} catch (e: Exception) {
e.printStackTrace()
}
if (location.speed > 0) {
entities.add(TdApi.TextEntity(builder.lastIndex, SPEED_PREFIX.length, TdApi.TextEntityTypeBold()))
builder.append(String.format(Locale.US, "$SPEED_PREFIX%.1f m/s\n", location.speed))
}
if (location.bearing > 0) {
entities.add(TdApi.TextEntity(builder.lastIndex, BEARING_PREFIX.length, TdApi.TextEntityTypeBold()))
builder.append(String.format(Locale.US, "$BEARING_PREFIX%.1f$BEARING_SUFFIX\n", location.bearing))
}
if (location.hdop != 0.0 && location.speed == 0.0) {
entities.add(TdApi.TextEntity(builder.lastIndex, HDOP_PREFIX.length, TdApi.TextEntityTypeBold()))
builder.append(String.format(Locale.US, "$HDOP_PREFIX%d m\n", location.hdop.toInt()))
}
if (updateId == 0) {
builder.append(String.format("$UPDATED_PREFIX%s\n", formatFullTime(location.time)))
} else {
builder.append(String.format("$UPDATED_PREFIX%s (%d)\n", formatFullTime(location.time), updateId))
}
val textMessage = builder.toString().trim()
return TdApi.InputMessageText(TdApi.FormattedText(textMessage, entities.toTypedArray()), true, true)
return 0.0
}
fun getTextMessageContent(updateId: Int, location: BufferMessage): TdApi.InputMessageText {
fun parseDistance(distanceS: String): Double {
try {
val distanceSplit = distanceS.split(" ")
val distanceVal = distanceSplit.first().toDouble()
return when (distanceSplit.last()) {
OsmandFormatter.FORMAT_METERS_KEY -> return distanceVal
OsmandFormatter.FORMAT_FEET_KEY -> return distanceVal / OsmandFormatter.FEET_IN_ONE_METER
OsmandFormatter.FORMAT_YARDS_KEY -> return distanceVal / OsmandFormatter.YARDS_IN_ONE_METER
OsmandFormatter.FORMAT_KILOMETERS_KEY -> return distanceVal * OsmandFormatter.METERS_IN_KILOMETER
OsmandFormatter.FORMAT_NAUTICALMILES_KEY -> return distanceVal * OsmandFormatter.METERS_IN_ONE_NAUTICALMILE
OsmandFormatter.FORMAT_MILES_KEY -> return distanceVal * OsmandFormatter.METERS_IN_ONE_MILE
else -> distanceVal
}
} catch (e: Exception) {
e.printStackTrace()
}
return 0.0
}
fun getTextMessageContent(updateId: Int, location: BufferMessage, app: TelegramApplication): TdApi.InputMessageText {
val entities = mutableListOf<TdApi.TextEntity>()
val builder = StringBuilder()
val locationMessage = formatLocation(location)
@ -391,11 +390,13 @@ object OsmandLocationUtils {
if (location.altitude != 0.0) {
entities.add(TdApi.TextEntity(builder.lastIndex, ALTITUDE_PREFIX.length, TdApi.TextEntityTypeBold()))
builder.append(String.format(Locale.US, "$ALTITUDE_PREFIX%.1f m\n", location.altitude))
val formattedAltitude = OsmandFormatter.getFormattedAlt(location.altitude, app, false)
builder.append(String.format(Locale.US, "$ALTITUDE_PREFIX%s\n", formattedAltitude))
}
if (location.speed > 0) {
entities.add(TdApi.TextEntity(builder.lastIndex, SPEED_PREFIX.length, TdApi.TextEntityTypeBold()))
builder.append(String.format(Locale.US, "$SPEED_PREFIX%.1f m/s\n", location.speed))
val formattedSpeed = OsmandFormatter.getFormattedSpeed(location.speed.toFloat(), app, false)
builder.append(String.format(Locale.US, "$SPEED_PREFIX%s\n", formattedSpeed))
}
if (location.bearing > 0) {
entities.add(TdApi.TextEntity(builder.lastIndex, BEARING_PREFIX.length, TdApi.TextEntityTypeBold()))
@ -403,12 +404,13 @@ object OsmandLocationUtils {
}
if (location.hdop != 0.0 && location.speed == 0.0) {
entities.add(TdApi.TextEntity(builder.lastIndex, HDOP_PREFIX.length, TdApi.TextEntityTypeBold()))
builder.append(String.format(Locale.US, "$HDOP_PREFIX%d m\n", location.hdop.toInt()))
val formattedHdop = OsmandFormatter.getFormattedDistance(location.hdop.toFloat(), app, false, false)
builder.append(String.format(Locale.US, "$HDOP_PREFIX%s\n", formattedHdop))
}
if (updateId == 0) {
builder.append(String.format("$UPDATED_PREFIX%s\n", formatFullTime(location.time)))
builder.append(String.format("$UPDATED_PREFIX%s\n", formatFullTime(location.time, app)))
} else {
builder.append(String.format("$UPDATED_PREFIX%s (%d)\n", formatFullTime(location.time), updateId))
builder.append(String.format("$UPDATED_PREFIX%s (%d)\n", formatFullTime(location.time, app), updateId))
}
val textMessage = builder.toString().trim()

11
OsmAnd/.gitignore vendored
View file

@ -18,6 +18,15 @@ huaweidrmlib/
HwDRM_SDK_*
drm_strings.xml
# copy_widget_icons.sh
res/drawable-large/map_*
res/drawable-large-hdpi/map_*
res/drawable-large-xhdpi/map_*
# copy_widget_icons.sh
res/drawable-large/widget_*
res/drawable-large-hdpi/widget_*
res/drawable-large-xhdpi/widget_*
valgrind/
bin/
dist/
@ -67,4 +76,4 @@ assets/OsmAndCore_ResourcesBundle/
/resourcesSrc
.project
.classpath
.classpath

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