Merge branch 'LibraryCompilationFixes' of https://github.com/brainbeanapps/Osmand into library_compilation_obligatory_changes

This commit is contained in:
Viacheslav Burchenko 2019-05-20 20:53:56 +03:00
commit 21e1463870
302 changed files with 21093 additions and 9637 deletions

View file

@ -1,14 +0,0 @@
language: android
# Work in progress. Repo should be used for initial checkout https://github.com/osmandapp/OsmAnd-manifest/blob/master/android_build.xml
android:
components:
- tools
- platform-tools
# The BuildTools version used by your project
- build-tools-27.0.3
- android-27
script: ./gradlew test

View file

@ -1,5 +1,5 @@
apply plugin: 'java'
apply plugin: 'maven-publish'
configurations {
android
@ -77,6 +77,14 @@ artifacts {
android androidJar
}
publishing {
publications {
maven(MavenPublication) {
artifactId "osmand-base"
from components.java
}
}
}
dependencies {
testImplementation 'junit:junit:4.12'

View file

@ -199,6 +199,10 @@ public class RotatedTileBox {
return tile;
}
public double getPixDensity() {
final double dist = getDistance(0, getPixHeight() / 2, getPixWidth(), getPixHeight() / 2);
return getPixWidth() / dist;
}
public int getPixWidth() {
return pixWidth;

View file

@ -1,5 +1,10 @@
package net.osmand.data;
import net.osmand.osm.edit.Node;
import net.osmand.osm.edit.Way;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -7,11 +12,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.osmand.osm.edit.Node;
import net.osmand.osm.edit.Way;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
public class TransportRoute extends MapObject {
private List<TransportStop> forwardStops = new ArrayList<TransportStop>();
private String ref;
@ -221,17 +221,19 @@ public class TransportRoute extends MapObject {
return d;
}
public String getAdjustedRouteRef() {
if (ref != null) {
int charPos = ref.lastIndexOf(':');
public String getAdjustedRouteRef(boolean small) {
String adjustedRef = getRef();
if (adjustedRef != null) {
int charPos = adjustedRef.lastIndexOf(':');
if (charPos != -1) {
ref = ref.substring(0, charPos);
adjustedRef = adjustedRef.substring(0, charPos);
}
if (ref.length() > 4) {
ref = ref.substring(0, 4);
int maxRefLength = small ? 5 : 8;
if (adjustedRef.length() > maxRefLength) {
adjustedRef = adjustedRef.substring(0, maxRefLength - 1) + "";
}
}
return ref;
return adjustedRef;
}
public boolean compareRoute(TransportRoute thatObj) {

View file

@ -665,6 +665,7 @@ public class SearchCoreFactory {
categories = types.getCategories(false);
}
List<AbstractPoiType> results = new ArrayList<AbstractPoiType>();
List<AbstractPoiType> searchWordTypes = new ArrayList<AbstractPoiType>();
NameStringMatcher nm;
String unknownSearchPhrase = phrase.getUnknownSearchPhrase();
if (phrase.getUnknownSearchWord().length() < unknownSearchPhrase.length()) {
@ -678,6 +679,7 @@ public class SearchCoreFactory {
|| nm.matches(pf.getEnTranslation())
|| nm.matches(pf.getSynonyms())) {
results.add(pf);
searchWordTypes.add(pf);
}
}
if (phrase.isUnknownSearchWordPresent()) {
@ -687,6 +689,7 @@ public class SearchCoreFactory {
|| nm.matches(c.getEnTranslation())
|| nm.matches(c.getSynonyms()))) {
results.add(c);
searchWordTypes.add(c);
}
}
Iterator<Entry<String, PoiType>> it = translatedNames.entrySet().iterator();
@ -699,6 +702,7 @@ public class SearchCoreFactory {
|| nm.matches(pt.getTranslation())
|| nm.matches(pt.getSynonyms()))) {
results.add(pt);
searchWordTypes.add(pt);
}
List<PoiType> additionals = pt.getPoiAdditionals();
if (additionals != null) {
@ -715,7 +719,7 @@ public class SearchCoreFactory {
}
}
}
phrase.setUnknownSearchWordPoiTypes(new ArrayList<>(results));
phrase.setUnknownSearchWordPoiTypes(searchWordTypes);
if (resultMatcher != null) {
String word = phrase.getUnknownSearchWord();

View file

@ -1,8 +1,6 @@
package net.osmand.util;
/* Can be commented out in order to run the main function separately */
import gnu.trove.list.array.TIntArrayList;
import java.io.Serializable;
import java.text.DateFormatSymbols;
import java.util.ArrayList;
@ -15,6 +13,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import gnu.trove.list.array.TIntArrayList;
/**
* Class used to parse opening hours
* <p/>

View file

@ -113,336 +113,345 @@ public class OpeningHoursParserTest {
// 0. not properly supported
// hours = parseOpenedHours("Mo-Su (sunrise-00:30)-(sunset+00:30)");
OpeningHours hours = parseOpenedHours("Apr 05-Oct 24: Fr 08:00-16:00");
System.out.println(hours);
testOpened("26.08.2018 15:00", hours, false);
testOpened("29.03.2019 15:00", hours, false);
testOpened("05.04.2019 11:00", hours, true);
Locale locale = Locale.getDefault();
try {
Locale.setDefault(Locale.forLanguageTag("en-US"));
OpeningHours hours = parseOpenedHours("Apr 05-Oct 24: Fr 08:00-16:00");
System.out.println(hours);
testOpened("26.08.2018 15:00", hours, false);
testOpened("29.03.2019 15:00", hours, false);
testOpened("05.04.2019 11:00", hours, true);
hours = parseOpenedHours("Oct 24-Apr 05: Fr 08:00-16:00");
System.out.println(hours);
testOpened("26.08.2018 15:00", hours, false);
testOpened("29.03.2019 15:00", hours, true);
testOpened("26.04.2019 11:00", hours, false);
hours = parseOpenedHours("Oct 24-Apr 05: Fr 08:00-16:00");
System.out.println(hours);
testOpened("26.08.2018 15:00", hours, false);
testOpened("29.03.2019 15:00", hours, true);
testOpened("26.04.2019 11:00", hours, false);
hours = parseOpenedHours("Oct 24-Apr 05, Jun 10-Jun 20, Jul 6-12: Fr 08:00-16:00");
System.out.println(hours);
testOpened("26.08.2018 15:00", hours, false);
testOpened("02.01.2019 15:00", hours, false);
testOpened("29.03.2019 15:00", hours, true);
testOpened("26.04.2019 11:00", hours, false);
hours = parseOpenedHours("Oct 24-Apr 05, Jun 10-Jun 20, Jul 6-12: Fr 08:00-16:00");
System.out.println(hours);
testOpened("26.08.2018 15:00", hours, false);
testOpened("02.01.2019 15:00", hours, false);
testOpened("29.03.2019 15:00", hours, true);
testOpened("26.04.2019 11:00", hours, false);
hours = parseOpenedHours("Apr 05-24: Fr 08:00-16:00");
System.out.println(hours);
testOpened("12.10.2018 11:00", hours, false);
testOpened("12.04.2019 15:00", hours, true);
testOpened("27.04.2019 15:00", hours, false);
hours = parseOpenedHours("Apr 05-24: Fr 08:00-16:00");
System.out.println(hours);
testOpened("12.10.2018 11:00", hours, false);
testOpened("12.04.2019 15:00", hours, true);
testOpened("27.04.2019 15:00", hours, false);
hours = parseOpenedHours("Apr 5: Fr 08:00-16:00");
System.out.println(hours);
testOpened("05.04.2019 15:00", hours, true);
testOpened("06.04.2019 15:00", hours, false);
hours = parseOpenedHours("Apr 5: Fr 08:00-16:00");
System.out.println(hours);
testOpened("05.04.2019 15:00", hours, true);
testOpened("06.04.2019 15:00", hours, false);
hours = parseOpenedHours("Apr 24-05: Fr 08:00-16:00");
System.out.println(hours);
testOpened("12.10.2018 11:00", hours, false);
testOpened("12.04.2018 15:00", hours, false);
hours = parseOpenedHours("Apr 24-05: Fr 08:00-16:00");
System.out.println(hours);
testOpened("12.10.2018 11:00", hours, false);
testOpened("12.04.2018 15:00", hours, false);
hours = parseOpenedHours("Apr: Fr 08:00-16:00");
System.out.println(hours);
testOpened("12.10.2018 11:00", hours, false);
testOpened("12.04.2019 15:00", hours, true);
hours = parseOpenedHours("Apr: Fr 08:00-16:00");
System.out.println(hours);
testOpened("12.10.2018 11:00", hours, false);
testOpened("12.04.2019 15:00", hours, true);
hours = parseOpenedHours("Apr-Oct: Fr 08:00-16:00");
System.out.println(hours);
testOpened("09.11.2018 11:00", hours, false);
testOpened("12.10.2018 11:00", hours, true);
testOpened("24.08.2018 15:00", hours, true);
testOpened("09.03.2018 15:00", hours, false);
hours = parseOpenedHours("Apr-Oct: Fr 08:00-16:00");
System.out.println(hours);
testOpened("09.11.2018 11:00", hours, false);
testOpened("12.10.2018 11:00", hours, true);
testOpened("24.08.2018 15:00", hours, true);
testOpened("09.03.2018 15:00", hours, false);
hours = parseOpenedHours("Apr, Oct: Fr 08:00-16:00");
System.out.println(hours);
testOpened("09.11.2018 11:00", hours, false);
testOpened("12.10.2018 11:00", hours, true);
testOpened("24.08.2018 15:00", hours, false);
testOpened("12.04.2019 15:00", hours, true);
hours = parseOpenedHours("Apr, Oct: Fr 08:00-16:00");
System.out.println(hours);
testOpened("09.11.2018 11:00", hours, false);
testOpened("12.10.2018 11:00", hours, true);
testOpened("24.08.2018 15:00", hours, false);
testOpened("12.04.2019 15:00", hours, true);
// test basic case
hours = parseOpenedHours("Mo-Fr 08:30-14:40"); //$NON-NLS-1$
System.out.println(hours);
testOpened("09.08.2012 11:00", hours, true);
testOpened("09.08.2012 16:00", hours, false);
hours = parseOpenedHours("mo-fr 07:00-19:00; sa 12:00-18:00");
// test basic case
hours = parseOpenedHours("Mo-Fr 08:30-14:40"); //$NON-NLS-1$
System.out.println(hours);
testOpened("09.08.2012 11:00", hours, true);
testOpened("09.08.2012 16:00", hours, false);
hours = parseOpenedHours("mo-fr 07:00-19:00; sa 12:00-18:00");
String string = "Mo-Fr 11:30-15:00, 17:30-23:00; Sa, Su, PH 11:30-23:00";
hours = parseOpenedHours(string);
testParsedAndAssembledCorrectly(string, hours);
System.out.println(hours);
testOpened("7.09.2015 14:54", hours, true); // monday
testOpened("7.09.2015 15:05", hours, false);
testOpened("6.09.2015 16:05", hours, true);
String string = "Mo-Fr 11:30-15:00, 17:30-23:00; Sa, Su, PH 11:30-23:00";
hours = parseOpenedHours(string);
testParsedAndAssembledCorrectly(string, hours);
System.out.println(hours);
testOpened("7.09.2015 14:54", hours, true); // monday
testOpened("7.09.2015 15:05", hours, false);
testOpened("6.09.2015 16:05", hours, true);
// two time and date ranges
hours = parseOpenedHours("Mo-We, Fr 08:30-14:40,15:00-19:00"); //$NON-NLS-1$
System.out.println(hours);
testOpened("08.08.2012 14:00", hours, true);
testOpened("08.08.2012 14:50", hours, false);
testOpened("10.08.2012 15:00", hours, true);
// two time and date ranges
hours = parseOpenedHours("Mo-We, Fr 08:30-14:40,15:00-19:00"); //$NON-NLS-1$
System.out.println(hours);
testOpened("08.08.2012 14:00", hours, true);
testOpened("08.08.2012 14:50", hours, false);
testOpened("10.08.2012 15:00", hours, true);
// test exception on general schema
hours = parseOpenedHours("Mo-Sa 08:30-14:40; Tu 08:00 - 14:00"); //$NON-NLS-1$
System.out.println(hours);
testOpened("07.08.2012 14:20", hours, false);
testOpened("07.08.2012 08:15", hours, true); // Tuesday
// test exception on general schema
hours = parseOpenedHours("Mo-Sa 08:30-14:40; Tu 08:00 - 14:00"); //$NON-NLS-1$
System.out.println(hours);
testOpened("07.08.2012 14:20", hours, false);
testOpened("07.08.2012 08:15", hours, true); // Tuesday
// test off value
hours = parseOpenedHours("Mo-Sa 09:00-18:25; Th off"); //$NON-NLS-1$
System.out.println(hours);
testOpened("08.08.2012 12:00", hours, true);
testOpened("09.08.2012 12:00", hours, false);
// test off value
hours = parseOpenedHours("Mo-Sa 09:00-18:25; Th off"); //$NON-NLS-1$
System.out.println(hours);
testOpened("08.08.2012 12:00", hours, true);
testOpened("09.08.2012 12:00", hours, false);
// test 24/7
hours = parseOpenedHours("24/7"); //$NON-NLS-1$
System.out.println(hours);
testOpened("08.08.2012 23:59", hours, true);
testOpened("08.08.2012 12:23", hours, true);
testOpened("08.08.2012 06:23", hours, true);
// test 24/7
hours = parseOpenedHours("24/7"); //$NON-NLS-1$
System.out.println(hours);
testOpened("08.08.2012 23:59", hours, true);
testOpened("08.08.2012 12:23", hours, true);
testOpened("08.08.2012 06:23", hours, true);
// some people seem to use the following syntax:
hours = parseOpenedHours("Sa-Su 24/7");
System.out.println(hours);
hours = parseOpenedHours("Mo-Fr 9-19");
System.out.println(hours);
hours = parseOpenedHours("09:00-17:00");
System.out.println(hours);
hours = parseOpenedHours("sunrise-sunset");
System.out.println(hours);
hours = parseOpenedHours("10:00+");
System.out.println(hours);
hours = parseOpenedHours("Su-Th sunset-24:00, 04:00-sunrise; Fr-Sa sunset-sunrise");
System.out.println(hours);
testOpened("12.08.2012 04:00", hours, true);
testOpened("12.08.2012 23:00", hours, true);
testOpened("08.08.2012 12:00", hours, false);
testOpened("08.08.2012 05:00", hours, true);
// some people seem to use the following syntax:
hours = parseOpenedHours("Sa-Su 24/7");
System.out.println(hours);
hours = parseOpenedHours("Mo-Fr 9-19");
System.out.println(hours);
hours = parseOpenedHours("09:00-17:00");
System.out.println(hours);
hours = parseOpenedHours("sunrise-sunset");
System.out.println(hours);
hours = parseOpenedHours("10:00+");
System.out.println(hours);
hours = parseOpenedHours("Su-Th sunset-24:00, 04:00-sunrise; Fr-Sa sunset-sunrise");
System.out.println(hours);
testOpened("12.08.2012 04:00", hours, true);
testOpened("12.08.2012 23:00", hours, true);
testOpened("08.08.2012 12:00", hours, false);
testOpened("08.08.2012 05:00", hours, true);
// test simple day wrap
hours = parseOpenedHours("Mo 20:00-02:00");
System.out.println(hours);
testOpened("05.05.2013 10:30", hours, false);
testOpened("05.05.2013 23:59", hours, false);
testOpened("06.05.2013 10:30", hours, false);
testOpened("06.05.2013 20:30", hours, true);
testOpened("06.05.2013 23:59", hours, true);
testOpened("07.05.2013 00:00", hours, true);
testOpened("07.05.2013 00:30", hours, true);
testOpened("07.05.2013 01:59", hours, true);
testOpened("07.05.2013 20:30", hours, false);
// test simple day wrap
hours = parseOpenedHours("Mo 20:00-02:00");
System.out.println(hours);
testOpened("05.05.2013 10:30", hours, false);
testOpened("05.05.2013 23:59", hours, false);
testOpened("06.05.2013 10:30", hours, false);
testOpened("06.05.2013 20:30", hours, true);
testOpened("06.05.2013 23:59", hours, true);
testOpened("07.05.2013 00:00", hours, true);
testOpened("07.05.2013 00:30", hours, true);
testOpened("07.05.2013 01:59", hours, true);
testOpened("07.05.2013 20:30", hours, false);
// test maximum day wrap
hours = parseOpenedHours("Su 10:00-10:00");
System.out.println(hours);
testOpened("05.05.2013 09:59", hours, false);
testOpened("05.05.2013 10:00", hours, true);
testOpened("05.05.2013 23:59", hours, true);
testOpened("06.05.2013 00:00", hours, true);
testOpened("06.05.2013 09:59", hours, true);
testOpened("06.05.2013 10:00", hours, false);
// test maximum day wrap
hours = parseOpenedHours("Su 10:00-10:00");
System.out.println(hours);
testOpened("05.05.2013 09:59", hours, false);
testOpened("05.05.2013 10:00", hours, true);
testOpened("05.05.2013 23:59", hours, true);
testOpened("06.05.2013 00:00", hours, true);
testOpened("06.05.2013 09:59", hours, true);
testOpened("06.05.2013 10:00", hours, false);
// test day wrap as seen on OSM
hours = parseOpenedHours("Tu-Th 07:00-2:00; Fr 17:00-4:00; Sa 18:00-05:00; Su,Mo off");
System.out.println(hours);
testOpened("05.05.2013 04:59", hours, true); // sunday 05.05.2013
testOpened("05.05.2013 05:00", hours, false);
testOpened("05.05.2013 12:30", hours, false);
testOpened("06.05.2013 10:30", hours, false);
testOpened("07.05.2013 01:00", hours, false);
testOpened("07.05.2013 20:25", hours, true);
testOpened("07.05.2013 23:59", hours, true);
testOpened("08.05.2013 00:00", hours, true);
testOpened("08.05.2013 02:00", hours, false);
// test day wrap as seen on OSM
hours = parseOpenedHours("Tu-Th 07:00-2:00; Fr 17:00-4:00; Sa 18:00-05:00; Su,Mo off");
System.out.println(hours);
testOpened("05.05.2013 04:59", hours, true); // sunday 05.05.2013
testOpened("05.05.2013 05:00", hours, false);
testOpened("05.05.2013 12:30", hours, false);
testOpened("06.05.2013 10:30", hours, false);
testOpened("07.05.2013 01:00", hours, false);
testOpened("07.05.2013 20:25", hours, true);
testOpened("07.05.2013 23:59", hours, true);
testOpened("08.05.2013 00:00", hours, true);
testOpened("08.05.2013 02:00", hours, false);
// test day wrap as seen on OSM
hours = parseOpenedHours("Mo-Th 09:00-03:00; Fr-Sa 09:00-04:00; Su off");
testOpened("11.05.2015 08:59", hours, false);
testOpened("11.05.2015 09:01", hours, true);
testOpened("12.05.2015 02:59", hours, true);
testOpened("12.05.2015 03:00", hours, false);
testOpened("16.05.2015 03:59", hours, true);
testOpened("16.05.2015 04:01", hours, false);
testOpened("17.05.2015 01:00", hours, true);
testOpened("17.05.2015 04:01", hours, false);
// test day wrap as seen on OSM
hours = parseOpenedHours("Mo-Th 09:00-03:00; Fr-Sa 09:00-04:00; Su off");
testOpened("11.05.2015 08:59", hours, false);
testOpened("11.05.2015 09:01", hours, true);
testOpened("12.05.2015 02:59", hours, true);
testOpened("12.05.2015 03:00", hours, false);
testOpened("16.05.2015 03:59", hours, true);
testOpened("16.05.2015 04:01", hours, false);
testOpened("17.05.2015 01:00", hours, true);
testOpened("17.05.2015 04:01", hours, false);
hours = parseOpenedHours("Tu-Th 07:00-2:00; Fr 17:00-4:00; Sa 18:00-05:00; Su,Mo off");
testOpened("11.05.2015 08:59", hours, false);
testOpened("11.05.2015 09:01", hours, false);
testOpened("12.05.2015 01:59", hours, false);
testOpened("12.05.2015 02:59", hours, false);
testOpened("12.05.2015 03:00", hours, false);
testOpened("13.05.2015 01:59", hours, true);
testOpened("13.05.2015 02:59", hours, false);
testOpened("16.05.2015 03:59", hours, true);
testOpened("16.05.2015 04:01", hours, false);
testOpened("17.05.2015 01:00", hours, true);
testOpened("17.05.2015 05:01", hours, false);
hours = parseOpenedHours("Tu-Th 07:00-2:00; Fr 17:00-4:00; Sa 18:00-05:00; Su,Mo off");
testOpened("11.05.2015 08:59", hours, false);
testOpened("11.05.2015 09:01", hours, false);
testOpened("12.05.2015 01:59", hours, false);
testOpened("12.05.2015 02:59", hours, false);
testOpened("12.05.2015 03:00", hours, false);
testOpened("13.05.2015 01:59", hours, true);
testOpened("13.05.2015 02:59", hours, false);
testOpened("16.05.2015 03:59", hours, true);
testOpened("16.05.2015 04:01", hours, false);
testOpened("17.05.2015 01:00", hours, true);
testOpened("17.05.2015 05:01", hours, false);
// tests single month value
hours = parseOpenedHours("May: 07:00-19:00");
System.out.println(hours);
testOpened("05.05.2013 12:00", hours, true);
testOpened("05.05.2013 05:00", hours, false);
testOpened("05.05.2013 21:00", hours, false);
testOpened("05.01.2013 12:00", hours, false);
testOpened("05.01.2013 05:00", hours, false);
// tests single month value
hours = parseOpenedHours("May: 07:00-19:00");
System.out.println(hours);
testOpened("05.05.2013 12:00", hours, true);
testOpened("05.05.2013 05:00", hours, false);
testOpened("05.05.2013 21:00", hours, false);
testOpened("05.01.2013 12:00", hours, false);
testOpened("05.01.2013 05:00", hours, false);
// tests multi month value
hours = parseOpenedHours("Apr-Sep 8:00-22:00; Oct-Mar 10:00-18:00");
System.out.println(hours);
testOpened("05.03.2013 15:00", hours, true);
testOpened("05.03.2013 20:00", hours, false);
// tests multi month value
hours = parseOpenedHours("Apr-Sep 8:00-22:00; Oct-Mar 10:00-18:00");
System.out.println(hours);
testOpened("05.03.2013 15:00", hours, true);
testOpened("05.03.2013 20:00", hours, false);
testOpened("05.05.2013 20:00", hours, true);
testOpened("05.05.2013 23:00", hours, false);
testOpened("05.05.2013 20:00", hours, true);
testOpened("05.05.2013 23:00", hours, false);
testOpened("05.10.2013 15:00", hours, true);
testOpened("05.10.2013 20:00", hours, false);
testOpened("05.10.2013 15:00", hours, true);
testOpened("05.10.2013 20:00", hours, false);
// Test time with breaks
hours = parseOpenedHours("Mo-Fr: 9:00-13:00, 14:00-18:00");
System.out.println(hours);
testOpened("02.12.2015 12:00", hours, true);
testOpened("02.12.2015 13:30", hours, false);
testOpened("02.12.2015 16:00", hours, true);
// Test time with breaks
hours = parseOpenedHours("Mo-Fr: 9:00-13:00, 14:00-18:00");
System.out.println(hours);
testOpened("02.12.2015 12:00", hours, true);
testOpened("02.12.2015 13:30", hours, false);
testOpened("02.12.2015 16:00", hours, true);
testOpened("05.12.2015 16:00", hours, false);
testOpened("05.12.2015 16:00", hours, false);
hours = parseOpenedHours("Mo-Su 07:00-23:00; Dec 25 08:00-20:00");
System.out.println(hours);
testOpened("25.12.2015 07:00", hours, false);
testOpened("24.12.2015 07:00", hours, true);
testOpened("24.12.2015 22:00", hours, true);
testOpened("25.12.2015 08:00", hours, true);
testOpened("25.12.2015 22:00", hours, false);
hours = parseOpenedHours("Mo-Su 07:00-23:00; Dec 25 off");
System.out.println(hours);
testOpened("25.12.2015 14:00", hours, false);
testOpened("24.12.2015 08:00", hours, true);
// easter itself as public holiday is not supported
hours = parseOpenedHours("Mo-Su 07:00-23:00; Easter off; Dec 25 off");
System.out.println(hours);
testOpened("25.12.2015 14:00", hours, false);
testOpened("24.12.2015 08:00", hours, true);
hours = parseOpenedHours("Mo-Su 07:00-23:00; Dec 25 08:00-20:00");
System.out.println(hours);
testOpened("25.12.2015 07:00", hours, false);
testOpened("24.12.2015 07:00", hours, true);
testOpened("24.12.2015 22:00", hours, true);
testOpened("25.12.2015 08:00", hours, true);
testOpened("25.12.2015 22:00", hours, false);
// test time off (not days
hours = parseOpenedHours("Mo-Fr 08:30-17:00; 12:00-12:40 off;");
System.out.println(hours);
testOpened("07.05.2017 14:00", hours, false); // Sunday
testOpened("06.05.2017 12:15", hours, false); // Saturday
testOpened("05.05.2017 14:00", hours, true); // Friday
testOpened("05.05.2017 12:15", hours, false);
testOpened("05.05.2017 12:00", hours, false);
testOpened("05.05.2017 11:45", hours, true);
// Test holidays
String hoursString = "mo-fr 11:00-21:00; PH off";
hours = OpeningHoursParser.parseOpenedHoursHandleErrors(hoursString);
testParsedAndAssembledCorrectly(hoursString, hours);
hours = parseOpenedHours("Mo-Su 07:00-23:00; Dec 25 off");
System.out.println(hours);
testOpened("25.12.2015 14:00", hours, false);
testOpened("24.12.2015 08:00", hours, true);
// test open from/till
hours = parseOpenedHours("Mo-Fr 08:30-17:00; 12:00-12:40 off;");
System.out.println(hours);
testInfo("15.01.2018 09:00", hours, "Open till 12:00");
testInfo("15.01.2018 11:00", hours, "Will close at 12:00");
testInfo("15.01.2018 12:00", hours, "Will open at 12:40");
// easter itself as public holiday is not supported
hours = parseOpenedHours("Mo-Su 07:00-23:00; Easter off; Dec 25 off");
System.out.println(hours);
testOpened("25.12.2015 14:00", hours, false);
testOpened("24.12.2015 08:00", hours, true);
hours = parseOpenedHours("Mo-Fr: 9:00-13:00, 14:00-18:00");
System.out.println(hours);
testInfo("15.01.2018 08:00", hours, "Will open at 09:00");
testInfo("15.01.2018 09:00", hours, "Open till 13:00");
testInfo("15.01.2018 12:00", hours, "Will close at 13:00");
testInfo("15.01.2018 13:10", hours, "Will open at 14:00");
testInfo("15.01.2018 14:00", hours, "Open till 18:00");
testInfo("15.01.2018 16:00", hours, "Will close at 18:00");
testInfo("15.01.2018 18:10", hours, "Will open tomorrow at 09:00");
hours = parseOpenedHours("Mo-Sa 02:00-10:00; Th off");
System.out.println(hours);
testInfo("15.01.2018 23:00", hours, "Will open tomorrow at 02:00");
// test time off (not days
hours = parseOpenedHours("Mo-Fr 08:30-17:00; 12:00-12:40 off;");
System.out.println(hours);
testOpened("07.05.2017 14:00", hours, false); // Sunday
testOpened("06.05.2017 12:15", hours, false); // Saturday
testOpened("05.05.2017 14:00", hours, true); // Friday
testOpened("05.05.2017 12:15", hours, false);
testOpened("05.05.2017 12:00", hours, false);
testOpened("05.05.2017 11:45", hours, true);
hours = parseOpenedHours("Mo-Sa 23:00-02:00; Th off");
System.out.println(hours);
testInfo("15.01.2018 22:00", hours, "Will open at 23:00");
testInfo("15.01.2018 23:00", hours, "Open till 02:00");
testInfo("16.01.2018 00:30", hours, "Will close at 02:00");
testInfo("16.01.2018 02:00", hours, "Open from 23:00");
// Test holidays
String hoursString = "mo-fr 11:00-21:00; PH off";
hours = OpeningHoursParser.parseOpenedHoursHandleErrors(hoursString);
testParsedAndAssembledCorrectly(hoursString, hours);
hours = parseOpenedHours("Mo-Sa 08:30-17:00; Th off");
System.out.println(hours);
testInfo("17.01.2018 20:00", hours, "Will open on 08:30 Fri.");
testInfo("18.01.2018 05:00", hours, "Will open tomorrow at 08:30");
testInfo("20.01.2018 05:00", hours, "Open from 08:30");
testInfo("21.01.2018 05:00", hours, "Will open tomorrow at 08:30");
testInfo("22.01.2018 02:00", hours, "Open from 08:30");
testInfo("22.01.2018 04:00", hours, "Open from 08:30");
testInfo("22.01.2018 07:00", hours, "Will open at 08:30");
testInfo("23.01.2018 10:00", hours, "Open till 17:00");
testInfo("23.01.2018 16:00", hours, "Will close at 17:00");
// test open from/till
hours = parseOpenedHours("Mo-Fr 08:30-17:00; 12:00-12:40 off;");
System.out.println(hours);
testInfo("15.01.2018 09:00", hours, "Open till 12:00");
testInfo("15.01.2018 11:00", hours, "Will close at 12:00");
testInfo("15.01.2018 12:00", hours, "Will open at 12:40");
hours = parseOpenedHours("24/7");
System.out.println(hours);
testInfo("24.01.2018 02:00", hours, "Open 24/7");
hours = parseOpenedHours("Mo-Su 07:00-23:00, Fr 08:00-20:00");
System.out.println(hours);
testOpened("15.01.2018 06:45", hours, false);
testOpened("15.01.2018 07:45", hours, true);
testOpened("15.01.2018 23:45", hours, false);
testOpened("19.01.2018 07:45", hours, false);
testOpened("19.01.2018 08:45", hours, true);
testOpened("19.01.2018 20:45", hours, false);
hours = parseOpenedHours("Mo-Fr: 9:00-13:00, 14:00-18:00");
System.out.println(hours);
testInfo("15.01.2018 08:00", hours, "Will open at 09:00");
testInfo("15.01.2018 09:00", hours, "Open till 13:00");
testInfo("15.01.2018 12:00", hours, "Will close at 13:00");
testInfo("15.01.2018 13:10", hours, "Will open at 14:00");
testInfo("15.01.2018 14:00", hours, "Open till 18:00");
testInfo("15.01.2018 16:00", hours, "Will close at 18:00");
testInfo("15.01.2018 18:10", hours, "Will open tomorrow at 09:00");
// test fallback case
hours = parseOpenedHours("07:00-01:00 open \"Restaurant\" || Mo 00:00-04:00,07:00-04:00; Tu-Th 07:00-04:00; Fr 07:00-24:00; Sa,Su 00:00-24:00 open \"McDrive\"");
System.out.println(hours);
testOpened("22.01.2018 00:30", hours, true);
testOpened("22.01.2018 08:00", hours, true);
testOpened("22.01.2018 03:30", hours, true);
testOpened("22.01.2018 05:00", hours, false);
testOpened("23.01.2018 05:00", hours, false);
testOpened("27.01.2018 05:00", hours, true);
testOpened("28.01.2018 05:00", hours, true);
hours = parseOpenedHours("Mo-Sa 02:00-10:00; Th off");
System.out.println(hours);
testInfo("15.01.2018 23:00", hours, "Will open tomorrow at 02:00");
testInfo("22.01.2018 05:00", hours, "Will open at 07:00 - Restaurant", 0);
testInfo("26.01.2018 00:00", hours, "Will close at 01:00 - Restaurant", 0);
testInfo("22.01.2018 05:00", hours, "Will open at 07:00 - McDrive", 1);
testInfo("22.01.2018 00:00", hours, "Open till 04:00 - McDrive", 1);
testInfo("22.01.2018 02:00", hours, "Will close at 04:00 - McDrive", 1);
testInfo("27.01.2018 02:00", hours, "Open till 24:00 - McDrive", 1);
hours = parseOpenedHours("07:00-03:00 open \"Restaurant\" || 24/7 open \"McDrive\"");
System.out.println(hours);
testOpened("22.01.2018 02:00", hours, true);
testOpened("22.01.2018 17:00", hours, true);
testInfo("22.01.2018 05:00", hours, "Will open at 07:00 - Restaurant", 0);
testInfo("22.01.2018 04:00", hours, "Open 24/7 - McDrive", 1);
hours = parseOpenedHours("Mo-Sa 23:00-02:00; Th off");
System.out.println(hours);
testInfo("15.01.2018 22:00", hours, "Will open at 23:00");
testInfo("15.01.2018 23:00", hours, "Open till 02:00");
testInfo("16.01.2018 00:30", hours, "Will close at 02:00");
testInfo("16.01.2018 02:00", hours, "Open from 23:00");
hours = parseOpenedHours("Mo-Sa 08:30-17:00; Th off");
System.out.println(hours);
testInfo("17.01.2018 20:00", hours, "Will open on 08:30 Fri.");
testInfo("18.01.2018 05:00", hours, "Will open tomorrow at 08:30");
testInfo("20.01.2018 05:00", hours, "Open from 08:30");
testInfo("21.01.2018 05:00", hours, "Will open tomorrow at 08:30");
testInfo("22.01.2018 02:00", hours, "Open from 08:30");
testInfo("22.01.2018 04:00", hours, "Open from 08:30");
testInfo("22.01.2018 07:00", hours, "Will open at 08:30");
testInfo("23.01.2018 10:00", hours, "Open till 17:00");
testInfo("23.01.2018 16:00", hours, "Will close at 17:00");
hours = parseOpenedHours("24/7");
System.out.println(hours);
testInfo("24.01.2018 02:00", hours, "Open 24/7");
hours = parseOpenedHours("Mo-Su 07:00-23:00, Fr 08:00-20:00");
System.out.println(hours);
testOpened("15.01.2018 06:45", hours, false);
testOpened("15.01.2018 07:45", hours, true);
testOpened("15.01.2018 23:45", hours, false);
testOpened("19.01.2018 07:45", hours, false);
testOpened("19.01.2018 08:45", hours, true);
testOpened("19.01.2018 20:45", hours, false);
// test fallback case
hours = parseOpenedHours(
"07:00-01:00 open \"Restaurant\" || Mo 00:00-04:00,07:00-04:00; Tu-Th 07:00-04:00; Fr 07:00-24:00; Sa,Su 00:00-24:00 open \"McDrive\"");
System.out.println(hours);
testOpened("22.01.2018 00:30", hours, true);
testOpened("22.01.2018 08:00", hours, true);
testOpened("22.01.2018 03:30", hours, true);
testOpened("22.01.2018 05:00", hours, false);
testOpened("23.01.2018 05:00", hours, false);
testOpened("27.01.2018 05:00", hours, true);
testOpened("28.01.2018 05:00", hours, true);
testInfo("22.01.2018 05:00", hours, "Will open at 07:00 - Restaurant", 0);
testInfo("26.01.2018 00:00", hours, "Will close at 01:00 - Restaurant", 0);
testInfo("22.01.2018 05:00", hours, "Will open at 07:00 - McDrive", 1);
testInfo("22.01.2018 00:00", hours, "Open till 04:00 - McDrive", 1);
testInfo("22.01.2018 02:00", hours, "Will close at 04:00 - McDrive", 1);
testInfo("27.01.2018 02:00", hours, "Open till 24:00 - McDrive", 1);
hours = parseOpenedHours("07:00-03:00 open \"Restaurant\" || 24/7 open \"McDrive\"");
System.out.println(hours);
testOpened("22.01.2018 02:00", hours, true);
testOpened("22.01.2018 17:00", hours, true);
testInfo("22.01.2018 05:00", hours, "Will open at 07:00 - Restaurant", 0);
testInfo("22.01.2018 04:00", hours, "Open 24/7 - McDrive", 1);
hours = parseOpenedHours("Mo-Fr 12:00-15:00, Tu-Fr 17:00-23:00, Sa 12:00-23:00, Su 14:00-23:00");
System.out.println(hours);
testOpened("16.02.2018 14:00", hours, true);
testOpened("16.02.2018 16:00", hours, false);
testOpened("16.02.2018 17:00", hours, true);
testInfo("16.02.2018 9:45", hours, "Open from 12:00");
testInfo("16.02.2018 12:00", hours, "Open till 15:00");
testInfo("16.02.2018 14:00", hours, "Will close at 15:00");
testInfo("16.02.2018 16:00", hours, "Will open at 17:00");
testInfo("16.02.2018 18:00", hours, "Open till 23:00");
hours = parseOpenedHours(
"Mo-Fr 10:00-21:00; Sa 12:00-23:00; PH \"Wird auf der Homepage bekannt gegeben.\"");
testParsedAndAssembledCorrectly(
"Mo-Fr 10:00-21:00; Sa 12:00-23:00; PH - Wird auf der Homepage bekannt gegeben.", hours);
System.out.println(hours);
} finally {
Locale.setDefault(locale);
}
hours = parseOpenedHours("Mo-Fr 12:00-15:00, Tu-Fr 17:00-23:00, Sa 12:00-23:00, Su 14:00-23:00");
System.out.println(hours);
testOpened("16.02.2018 14:00", hours, true);
testOpened("16.02.2018 16:00", hours, false);
testOpened("16.02.2018 17:00", hours, true);
testInfo("16.02.2018 9:45", hours, "Open from 12:00");
testInfo("16.02.2018 12:00", hours, "Open till 15:00");
testInfo("16.02.2018 14:00", hours, "Will close at 15:00");
testInfo("16.02.2018 16:00", hours, "Will open at 17:00");
testInfo("16.02.2018 18:00", hours, "Open till 23:00");
hours = parseOpenedHours("Mo-Fr 10:00-21:00; Sa 12:00-23:00; PH \"Wird auf der Homepage bekannt gegeben.\"");
testParsedAndAssembledCorrectly("Mo-Fr 10:00-21:00; Sa 12:00-23:00; PH - Wird auf der Homepage bekannt gegeben.", hours);
System.out.println(hours);
}
private static OpeningHours parseOpenedHours(String string) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

View file

@ -28,34 +28,10 @@
</android.support.design.widget.CoordinatorLayout>
<LinearLayout
android:id="@+id/buttons_bar"
<include
layout="@layout/bottom_buttons_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/buttons_bottom_bar_height"
android:background="?attr/card_bg_color"
android:gravity="center_vertical"
android:paddingLeft="@dimen/content_padding_half"
android:paddingRight="@dimen/content_padding_half"
android:visibility="gone"
tools:visibility="visible">
<include
layout="@layout/secondary_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<View
android:layout_width="@dimen/content_padding_half"
android:layout_height="match_parent"/>
<include
layout="@layout/primary_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
android:layout_height="@dimen/buttons_bottom_bar_height" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_navigation"

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/buttons_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/buttons_bottom_bar_height"
android:background="?attr/card_bg_color"
android:gravity="center_vertical"
android:paddingLeft="@dimen/content_padding_half"
android:paddingRight="@dimen/content_padding_half"
android:visibility="gone"
tools:visibility="visible">
<include
layout="@layout/secondary_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<View
android:layout_width="@dimen/content_padding_half"
android:layout_height="match_parent" />
<include
layout="@layout/primary_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/empty_state_background_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/content_padding_standard"
android:scaleType="center"
android:src="@drawable/img_empty_state_search" />
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/content_padding_half"
android:background="@null"
android:text="@string/search_contacts"
android:textColor="?android:attr/textColorSecondary"
android:textSize="20sp"
osmand:typeface="@string/font_roboto_medium" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/empty_state_descr_margin"
android:layout_marginRight="@dimen/empty_state_descr_margin"
android:background="@null"
android:gravity="center"
android:text="@string/search_contacts_descr"
android:textColor="?android:attr/textColorSecondary"
android:textSize="18sp" />
</LinearLayout>

View file

@ -5,6 +5,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
@ -103,6 +104,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/privacy"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium"/>
<LinearLayout
android:id="@+id/proxy_settings_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

@ -101,49 +101,6 @@
</LinearLayout>
<FrameLayout
android:id="@+id/search_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:visibility="gone"
tools:background="@drawable/btn_round">
<LinearLayout
android:id="@+id/search_button"
android:layout_width="match_parent"
android:layout_height="@dimen/search_box_height"
android:background="?attr/selectableItemBackgroundBorderless"
android:gravity="center_vertical">
<TextView
android:id="@+id/search_hint"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding_standard"
android:layout_marginRight="@dimen/content_padding_standard"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:text="@string/my_location_search_hint"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/descr_text_size"/>
<ImageView
android:id="@+id/search_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
tools:src="@drawable/ic_action_search_dark"
tools:tint="@color/icon_light"/>
</LinearLayout>
</FrameLayout>
<LinearLayout
android:id="@+id/title_container"
android:layout_width="match_parent"
@ -296,6 +253,48 @@
</LinearLayout>
<FrameLayout
android:id="@+id/search_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
tools:background="@drawable/btn_round">
<LinearLayout
android:id="@+id/search_button"
android:layout_width="match_parent"
android:layout_height="@dimen/search_box_height"
android:background="?attr/selectableItemBackgroundBorderless"
android:gravity="center_vertical">
<TextView
android:id="@+id/search_hint"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding_standard"
android:layout_marginRight="@dimen/content_padding_standard"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:text="@string/my_location_search_hint"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/descr_text_size"/>
<ImageView
android:id="@+id/search_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
tools:src="@drawable/ic_action_search_dark"
tools:tint="@color/icon_light"/>
</LinearLayout>
</FrameLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout

View file

@ -0,0 +1,350 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:text="@string/proxy_settings"
android:textColor="@color/app_bar_title_light"
android:textSize="@dimen/title_text_size"
app:typeface="@string/font_roboto_mono_bold" />
</android.support.v7.widget.Toolbar>
<View
android:layout_width="wrap_content"
android:layout_height="1dp"
android:layout_marginStart="@dimen/content_padding_standard"
android:layout_marginLeft="@dimen/content_padding_standard"
android:background="?attr/card_divider_color" />
<LinearLayout
android:id="@+id/enable_proxy_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:minHeight="50dp"
android:orientation="horizontal"
tools:background="@color/card_bg_light">
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/shared_string_enable"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_regular" />
<Switch
android:id="@+id/switcher"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@null"
android:clickable="false"
android:focusable="false"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard" />
</LinearLayout>
</android.support.design.widget.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/list_view_bottom_padding_big">
<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/proxy_type"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/proxy_type_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"
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/shared_string_connection"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/connection_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:paddingBottom="@dimen/content_padding_standard">
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginBottom="@dimen/content_padding_standard"
app:hasClearButton="true"
app:labelText="@string/proxy_server">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/server_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
app:hasClearButton="true"
app:labelText="@string/proxy_port">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/port_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/proxy_sosks5_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<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/proxy_credentials"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/credentials_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:paddingBottom="@dimen/content_padding_standard">
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginBottom="@dimen/content_padding_standard"
app:hasClearButton="true"
app:labelText="@string/proxy_username">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/username_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
app:hasClearButton="true"
app:labelText="@string/proxy_password">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/password_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/proxy_mtproto_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<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/proxy_credentials"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_medium" />
<LinearLayout
android:id="@+id/mtproto_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:paddingBottom="@dimen/content_padding_standard">
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginBottom="@dimen/content_padding_standard"
app:hasClearButton="true"
app:labelText="@string/proxy_key">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/key_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<include layout="@layout/card_bottom_divider" />
</LinearLayout>
</ScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/save_button_Container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<android.support.v7.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="?attr/bottom_nav_shadow" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/proxy_save_button_height"
android:layout_gravity="bottom"
android:background="?attr/card_bg_color"
android:orientation="vertical"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingTop="@dimen/image_button_padding"
android:paddingRight="@dimen/content_padding_standard"
android:paddingBottom="@dimen/image_button_padding">
<include layout="@layout/primary_btn" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height">
<LinearLayout
android:id="@+id/title_row"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical">
<EditText
android:id="@+id/searchEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_standard"
android:layout_marginRight="@dimen/content_padding_standard"
android:layout_weight="1"
android:background="@null"
android:ellipsize="end"
android:gravity="center_vertical"
android:hint="@string/type_contact_or_group_name"
android:maxLines="1"
android:textColor="@color/app_bar_title_light"
android:textSize="@dimen/title_text_size" />
<ImageView
android:id="@+id/search_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/shared_string_search"
android:padding="@dimen/content_padding_standard"
android:src="@drawable/ic_action_search_dark"
android:tint="@color/icon_light" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.osmand.telegram.ui.views.EmptyStateRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="@dimen/buttons_bottom_bar_height" />
<include
android:id="@+id/empty_view"
layout="@layout/empty_state_search" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<android.support.v7.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="?attr/bottom_nav_shadow" />
<include
layout="@layout/bottom_buttons_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/buttons_bottom_bar_height"
android:layout_gravity="bottom" />
</LinearLayout>
</FrameLayout>
</LinearLayout>

View file

@ -50,6 +50,18 @@
</LinearLayout>
<ImageView
android:id="@+id/icon_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:paddingLeft="@dimen/image_button_padding"
android:paddingRight="@dimen/image_button_padding"
android:visibility="gone"
tools:src="@drawable/ic_action_additional_option"
tools:tint="@color/icon_light"
tools:visibility="visible" />
<Switch
android:id="@+id/switcher"
android:layout_width="wrap_content"

View file

@ -7,6 +7,10 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/top_divider"
layout="@layout/list_item_divider"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View file

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

View file

@ -213,4 +213,26 @@
<string name="shared_string_appearance">Выгляд</string>
<string name="show_gps_points">Паказаць кропкі GPS</string>
<string name="show_gps_points_descr">Паказваць колькасць сабраных і адпраўленых кропак GPS.</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="direction">Накірунак</string>
<string name="precision">Дакладнасць</string>
<string name="altitude">Вышыня над узроўнем мора</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="bearing">Накірунак</string>
</resources>

View file

@ -1,2 +1,238 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="shared_string_ok">D\'acord</string>
<string name="timeline_available_for_free_now">La línia temporal és ara una opció gratuita.</string>
<string name="disable_monitoring">Desactiva el seguiment</string>
<string name="location_recording_enabled">L\'enregistrament de localització està activat</string>
<string name="timeline_description">Activeu el seguiment per desar totes les fites a l\'historial.</string>
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (l\'aplicació de missatgeria) s\'utilitza per connectar i comunicar amb la gent.</string>
<string name="please_update_osmand">Actualitzeu OsmAnd per veure les dades al mapa</string>
<string name="device_added_successfully">S\'ha afegit %1$s.</string>
<string name="battery_optimization_description">Desactiveu l\'optimització de bateria per OsmAnd Telegram perquè no s\'aturi sobtadament quan quedi en procés de fons.</string>
<string name="go_to_settings">Ves a la configuració</string>
<string name="choose_osmand_desc">Seleccioneu la versió d\'OsmAnd on els contactes es situaran al mapa.</string>
<string name="choose_osmand">Seleccioneu la versió d\'OsmAnd a utilitzar</string>
<string name="disable_all_sharing_desc">Desactiva compartir la ubicació a tots els xats seleccionats (%1$d).</string>
<string name="disable_all_sharing">Desactiva compartir res</string>
<string name="turn_off_all">Desactiva-ho tot</string>
<string name="time_ago">ja fa</string>
<string name="last_response">Darrera resposta</string>
<string name="logout_no_internet_msg">Connecteu a Internet per sortir correctament de Telegram.</string>
<string name="disconnect_from_telegram_desc">Per aturar l\'accés a compartir la posició. Obriu Telegram, aneu a Configuració → Seguretat i Privacitat→ Sessions, i tanqueu la sessió d\'OsmAnd Telegram.</string>
<string name="disconnect_from_telegram">Com aturar des de Telegram l\'enregistrador OsmAnd</string>
<string name="logout_help_desc">Com aturar des de Telegram l\'enregistrador OsmAnd</string>
<string name="in_time">dins %@</string>
<string name="osmand_connect_desc">Seleccioneu la versió d\'OsmAnd que OsmAnd Telegram utilitzarà per mostrar la posició.</string>
<string name="osmand_connect">Connecta a OsmAnd</string>
<string name="location_history_desc">Amaga els contactes quiets més d\'un temps determinat.</string>
<string name="stale_location">Aturat</string>
<string name="send_my_location_desc">Indiqueu la variació mínima per compartir la posició.</string>
<string name="stop_sharing_all">La compartició està activada (atureu-la)</string>
<string name="turn_off_location_sharing">Atura la compartició de posició</string>
<string name="get_telegram_title">Registre de Telegram</string>
<string name="get_telegram_account_first">Us cal un compte Telegram per compartir la posició.</string>
<string name="get_telegram_description_continue">Instal·leu Telegram i activeu-ne un compte.</string>
<string name="get_telegram_after_creating_account">Llavors podreu utilitzar aquesta aplicació.</string>
<string name="shared_string_off">Inactiva</string>
<string name="already_registered_in_telegram">Us cal un compte registrat de Telegram i un número de telèfon</string>
<string name="set_visible_time_for_all">Indiqueu l\'horari de visibilitat per tothom</string>
<string name="visible_time_for_all">Horari de visibilitat per tothom</string>
<string name="set_time_description">Indiqueu l\'horari on els grups i contactes seleccionats podran veure la vostra posició en directe.</string>
<string name="set_time">Estableix horari</string>
<string name="location_sharing_description">Seleccioneu els grups i contactes amb qui voleu compartir la vostra posició.</string>
<string name="my_location_search_hint">Cerca: Grup o contacte</string>
<string name="authentication_code_descr">Telegram us ha enviat un codi perquè OsmAnd pugui entrar en el vostre compte.</string>
<string name="closing">S\'està tancant</string>
<string name="app_name_short_online">Rastrejador en línia</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="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>
<string name="how_it_works">Com funciona</string>
<string name="received_gps_points">Punts GPX rebuts: %1$s</string>
<string name="shared_string_appearance">Aparença</string>
<string name="show_gps_points">Mostra punts GPS</string>
<string name="show_gps_points_descr">Mostra el nombre de punts GPS recollits i enviats.</string>
<string name="shared_string_update">Actualitza</string>
<string name="gps_points_in_buffer">enviat ((%1$d en la memòria intermèdia)</string>
<string name="points_size">%1$d punts</string>
<string name="shared_string_date">Data</string>
<string name="shared_string_collected">enviat (%1$d en la memòria intermèdia)</string>
<string name="gps_points">Punts GPS</string>
<string name="shared_string_sent">Enviat</string>
<string name="monitoring_is_enabled">El monitoratge és actiu</string>
<string name="monitoring_is_disabled">El monitoratge és inactiu</string>
<string name="time_on_the_move">Temps de moviment</string>
<string name="average_altitude">Altitud mitjana</string>
<string name="average_speed">Velocitat mitjana</string>
<string name="open_in_osmand">Mostra en l\'OsmAnd</string>
<string name="end_date">Data de finalització</string>
<string name="start_date">Data d\'inici</string>
<string name="send_location_as">Envia la ubicació com a</string>
<string name="send_location_as_descr">Trieu l\'aspecte dels missatges amb la vostra ubicació.</string>
<string name="shared_string_map">Mapa</string>
<string name="shared_string_text">Text</string>
<string name="map_and_text">Mapa i text</string>
<string name="last_update_from_telegram">Última actualització des de Telegram</string>
<string name="enter_another_device_name">Trieu un nom que no estigui en ús</string>
<string name="shared_string_add">Afegeix</string>
<string name="error_adding_new_device">No s\'ha pogut afegir un aparell nou</string>
<string name="enter_device_name_description">Doneu un nom a l\'aparell nou amb un màxim de 200 caràcters.</string>
<string name="device_name_is_too_long">El nom de l\'aparell és massa llarg</string>
<string name="device_name_cannot_be_empty">El nom de l\'aparell no pot ser buit</string>
<string name="device_name">Nom de l\'aparell</string>
<string name="shared_string_hide">Amaga</string>
<string name="share_location_as_description_second_line">Podeu crear i visualitzar l\'ID de l\'aparell en el client de Telegram usant el bot %1$s. %2$s</string>
<string name="share_location_as_description">Si voleu connectar més d\'un aparell a un compte de Telegram, cal que useu un aparell diferent per a compartir la vostra ubicació.</string>
<string name="last_updated_location">Última ubicació actualitzada:</string>
<string name="successfully_sent_and_updated">S\'ha enviat i actualitzat correctament</string>
<string name="not_possible_to_send_to_telegram_chats">No és possible d\'enviar als xats de Telegram:</string>
<string name="waiting_for_response_from_telegram">S\'està esperant la resposta de Telegram</string>
<string name="sending_location_messages">S\'està enviant la ubicació</string>
<string name="initializing">S\'està iniciant</string>
<string name="searching_for_gps">S\'està ubicant…</string>
<string name="connecting_to_the_internet">S\'està connectant a internet</string>
<string name="background_work_description">Canvieu la configuració de l\'optimització de la bateria per a estabilitzar la compartició de la ubicació.</string>
<string name="background_work">Funcionament en segon pla</string>
<string name="sharing_in_background">Compartició en segon pla</string>
<string name="shared_string_later">Més tard</string>
<string name="not_sent_yet">Encara no s\'ha enviat</string>
<string name="not_found_yet">Encara no s\'ha trobat</string>
<string name="re_send_location">Torna a enviar la ubicació</string>
<string name="last_available_location">Última ubicació disponible</string>
<string name="sharing_status">Estat de la compartició</string>
<string name="sharing_enabled">Compartició: activada</string>
<string name="shared_string_status">Estat</string>
<string name="no_gps_connection">No hi ha connexió GPS</string>
<string name="no_internet_connection">No hi ha connexió a internet</string>
<string name="shared_string_disable">Desactiva</string>
<string name="shared_string_save">Desa</string>
<string name="add_device">Afegeix un aparell</string>
<string name="share_location_as">Comparteix la ubicació com a</string>
<string name="live_now_description">Contactes i grups que compateixen la ubicació amb vós.</string>
<string name="logout_from_osmand_telegram_descr">Esteu segur de voler tancar la sessió a OsmAnd Telegram i deixar de poder compartir la ubicació o veure la ubicació d\'altres usuaris\?</string>
<string name="logout_from_osmand_telegram">Voleu tancar la sessió de l\'OsmAnd Telegram\?</string>
<string name="shared_string_name">Nom</string>
<string name="by_distance">Per distància</string>
<string name="by_name">Per nom</string>
<string name="by_group">Per grup</string>
<string name="shared_string_sort">Ordena</string>
<string name="shared_string_sort_by">Ordena per</string>
<string name="shared_string_exit">Surt</string>
<string name="shared_string_group">Grup</string>
<string name="shared_string_close">Tanca</string>
<string name="connected_account">Compte connectat</string>
<string name="shared_string_account">Compte</string>
<string name="location_history">Historial d\'ubicacions</string>
<string name="stale_location_desc">L\'última vegada que s\'ha mogut un contacte.</string>
<string name="send_my_location">Envia la meva ubicació</string>
<string name="gps_and_location">Ubicació</string>
<string name="sharing_time">Temps de compartició</string>
<string name="expire_at">"Expiració: "</string>
<string name="open_osmand">Obre l\'OsmAnd</string>
<string name="shared_string_live">En directe</string>
<string name="shared_string_bot">Bot</string>
<string name="shared_string_all">Tot</string>
<string name="do_not_have_telegram">No tinc compte de Telegram</string>
<string name="enter_phone_number">Introduïu un número de telèfon</string>
<string name="enter_authentication_code">Introduïu un codi d\'autenticació</string>
<string name="hours_and_minutes_format">%1$d h %2$d min</string>
<string name="minutes_format">%1$d min</string>
<string name="hours_format">%1$d h</string>
<string name="shared_string_install">Instal·la</string>
<string name="shared_string_share">Comparteix</string>
<string name="shared_string_back">Enrere</string>
<string name="start_location_sharing">Comparteix la ubicació</string>
<string name="show_on_map">Mostra-ho al mapa</string>
<string name="app_name">OsmAnd Telegram</string>
<string name="phone_number_title">Número de telèfon</string>
<string name="phone_number_descr">Número de telèfon en format internacional</string>
<string name="shared_string_password">Contrasenya</string>
<string name="enter_code">Introduïu el codi</string>
<string name="authentication_code">Codi d\'autenticació</string>
<string name="enter_password">Introduïu la contrasenya</string>
<string name="password_descr">Contrasenya de Telegram</string>
<string name="shared_string_login">Inicia sessió</string>
<string name="shared_string_logout">Tanca la sessió</string>
<string name="initialization">S\'està iniciant</string>
<string name="logging_out">S\'està tancant</string>
<string name="gps_network_not_enabled">Voleu activa la ubicació\?</string>
<string name="not_logged_in">No heu iniciat sessió</string>
<string name="shared_string_continue">Continua</string>
<string name="shared_string_cancel">Cancel·la</string>
<string name="shared_string_settings">Configuració</string>
<string name="no_location_permission">L\'aplicació no té permisos per a accedir a les dades d\'ubicació.</string>
<string name="gps_not_available">Activeu «Ubicació» en la configuració del sistema</string>
<string name="location_service_no_gps_available">Seleccioneu un dels proveïdors d\'ubicació per a compartir la vostra ubicació.</string>
<string name="osmand_service">Mode en segon pla</string>
<string name="shared_string_distance">Distància</string>
<string name="share_location">Comparteix la ubicació</string>
<string name="process_service">Servei d\'OsmAnd Telegram</string>
<string name="osmand_logo">Logo de l\'OsmAnd</string>
<string name="install_osmand_dialog_message">Cal que primer instal·leu la versió gratuïta o la de pagament de l\'OsmAnd</string>
<string name="install_osmand">Instal·la l\'OsmAnd</string>
<string name="show_users_on_map">Mostra els usuaris en el mapa</string>
<string name="active_chats">Xats actius</string>
<string name="shared_string_authorization">Autorització</string>
<string name="shared_string_authorization_descr">Introduïu el vostre número de telèfon de Telegram en format internacional</string>
<string name="shared_string_welcome">Benvingut</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">NM</string>
<string name="m_s">m/s</string>
<string name="km_h">km/h</string>
<string name="si_kmh">Kilòmetres per hora</string>
<string name="si_mph">Milles per hora</string>
<string name="si_m_s">Metres per segon</string>
<string name="si_min_km">Minuts per kilòmetre</string>
<string name="si_min_m">Minuts per milla</string>
<string name="si_nm_h">Milles nàutiques per hora (nusos)</string>
<string name="si_mi_feet">Milles/peu</string>
<string name="si_mi_yard">Milles/iardes</string>
<string name="si_km_m">Kilòmetres/metres</string>
<string name="si_nm">Milles nàutiques</string>
<string name="si_mi_meters">Milles/metres</string>
<string name="shared_string_hour_short">h</string>
<string name="shared_string_minute_short">min</string>
<string name="my_location">La meva ubicació</string>
<string name="live_now">En directe</string>
<string name="timeline">Cronologia</string>
<string name="search_contacts">Cerca contactes</string>
<string name="search_contacts_descr">Cerca per tots els grups i contactes.</string>
<string name="type_contact_or_group_name">Escriviu un nom de contacte o de grup</string>
<string name="shared_string_search">Cerca</string>
<string name="osmand_service_descr">OsmAnd Telegram s\'executa en procés de fons amb la pantalla tancada.</string>
<string name="sharing_location">S\'està compartint la ubicació</string>
<string name="min_mile">min/m</string>
<string name="min_km">min/km</string>
<string name="nm_h">nusos</string>
<string name="mile_per_hour">mph</string>
<string name="shared_string_second_short">seg</string>
<string name="welcome_descr">
<b>OsmAnd Tracker</b> us permet compartir la vostra posició i veure la dels altres a OsmAnd.<br/>
<br/>L\'aplicació utilitza l\'API de Telegram, per tant us cal un compte de Telegram.</string>
<string name="direction">Adreça</string>
<string name="precision">Precisió</string>
<string name="altitude">Altitud</string>
<string name="bearing">Trajectòria</string>
<string name="proxy_key">Clau</string>
<string name="proxy_password">Contrasenya</string>
<string name="proxy_username">Nom d\'usuari</string>
<string name="proxy_credentials">Credencials</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Servidor</string>
<string name="shared_string_connection">Connexió</string>
<string name="shared_string_enable">Activa</string>
<string name="proxy_type">Tipus de servidor intermediari</string>
<string name="proxy_connected">Connectat</string>
<string name="proxy_disconnected">Desconnectat</string>
<string name="proxy_settings">Configuració del servidor intermediari</string>
<string name="proxy">Servidor intermediari</string>
<string name="privacy">Privacitat</string>
</resources>

View file

@ -19,7 +19,7 @@
<string name="add_device">Tilføj enhed</string>
<string name="share_location_as">Del placering som</string>
<string name="live_now_description">Kontakter og grupper som der deles placering med.</string>
<string name="logout_from_osmand_telegram_descr">"Bekræft logge ud af OsmAnd Tracker, så kan der ikke deles placering eller se placeringen af andre\?"</string>
<string name="logout_from_osmand_telegram_descr">"Bekræft log af OsmAnd Tracker, der kan ikke deles placering eller se placering af andre\?"</string>
<string name="logout_from_osmand_telegram">Log ud af OsmAnd Telegram\?</string>
<string name="shared_string_name">Navn</string>
<string name="by_distance">Efter afstand</string>
@ -38,7 +38,7 @@
<string name="shared_string_group">Gruppe</string>
<string name="logout_no_internet_msg">Opret forbindelse til Internettet for at logge ud af Telegram.</string>
<string name="shared_string_close">Luk</string>
<string name="disconnect_from_telegram_desc">"Sådan tilbagekaldes adgang til placeringsdeling. Åbn Telegram, gå til Settings - Privacy and Security - Sessions og afslut OsmAnd Telegram session. "</string>
<string name="disconnect_from_telegram_desc">Sådan tilbagekaldes adgang til placeringsdeling. Åbn Telegram, gå til Settings - Privacy and Security - Sessions og afslut OsmAnd Telegram session.</string>
<string name="disconnect_from_telegram">Sådan afbrydes OsmAnd Tracker fra Telegram</string>
<string name="logout_help_desc">Sådan afbrydes OsmAnd Tracker fra Telegram</string>
<string name="connected_account">Tilsluttet konto</string>
@ -213,4 +213,26 @@
<string name="shared_string_appearance">Udseende</string>
<string name="show_gps_points">Vis GPX-punkter</string>
<string name="show_gps_points_descr">Vis antallet af indsamlede og sendte GPX-punkter.</string>
<string name="search_contacts">Søg efter kontaktpersoner</string>
<string name="search_contacts_descr">Søg på tværs af alle grupper og kontaktpersoner.</string>
<string name="type_contact_or_group_name">Skriv navnet på kontakt eller gruppe</string>
<string name="shared_string_search">Søg</string>
<string name="direction">Retning</string>
<string name="altitude">Højde</string>
<string name="bearing">Kurs</string>
<string name="proxy_key">Nøgle</string>
<string name="proxy_password">Adgangskode</string>
<string name="proxy_username">Brugernavn</string>
<string name="proxy_credentials">Legitimationsoplysninger</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Server</string>
<string name="shared_string_connection">Forbindelse</string>
<string name="shared_string_enable">Aktiver</string>
<string name="proxy_type">Proxytype</string>
<string name="proxy_connected">Forbundet</string>
<string name="proxy_disconnected">Afbrudt</string>
<string name="proxy_settings">Proxy-indstillinger</string>
<string name="proxy">Proxy</string>
<string name="privacy">Privatliv</string>
<string name="precision">Præcision</string>
</resources>

View file

@ -145,7 +145,7 @@
<string name="turn_off_location_sharing">Standortfreigabe ausschalten</string>
<string name="shared_string_bot">Bot</string>
<string name="set_visible_time_for_all">Für alle sichtbare Zeit einstellen</string>
<string name="set_time_description">Zeit einstellen, zu der Ihren Kontakten und Gruppen Ihr Standorts in Echtzeit angezeigt wird.</string>
<string name="set_time_description">Stellen Sie die Zeit ein, zu der Ihren ausgewählten Kontakten und Gruppen Ihr Standort in Echtzeit angezeigt wird.</string>
<string name="location_sharing_description">Kontakte und Gruppen wählen, denen Sie Ihren Standort freigeben möchten.</string>
<string name="start_location_sharing">Standort freigeben</string>
<string name="location_service_no_gps_available">Wählen Sie einen der Standortanbieter aus, um Ihren Standort freizugeben.</string>
@ -213,4 +213,26 @@
<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_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>
<string name="search_contacts_descr">Alle Gruppen und Kontakte durchsuchen.</string>
<string name="type_contact_or_group_name">Kontakt- oder Gruppenname eingeben</string>
<string name="shared_string_search">Suchen</string>
<string name="direction">Richtung</string>
<string name="precision">Genauigkeit</string>
<string name="altitude">Höhe</string>
<string name="bearing">Peilung</string>
<string name="proxy_key">Schlüssel</string>
<string name="proxy_password">Passwort</string>
<string name="proxy_username">Benutzername</string>
<string name="proxy_credentials">Anmeldeinformationen</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Server</string>
<string name="shared_string_connection">Verbindung</string>
<string name="shared_string_enable">Aktivieren</string>
<string name="proxy_type">Proxy-Typ</string>
<string name="proxy_connected">Verbunden</string>
<string name="proxy_disconnected">Getrennt</string>
<string name="proxy_settings">Proxy-Einstellungen</string>
<string name="proxy">Proxy</string>
<string name="privacy">Datenschutz</string>
</resources>

View file

@ -212,4 +212,26 @@
<string name="timeline_description">Activa la monitorización para guardar todas las ubicaciones en el historial.</string>
<string name="app_name_short_online">Rastreador en línea</string>
<string name="app_name_short">Rastreador de OsmAnd</string>
<string name="search_contacts">Buscar contactos</string>
<string name="search_contacts_descr">Busca en todos tus grupos y contactos.</string>
<string name="type_contact_or_group_name">Escribe el nombre del contacto o grupo</string>
<string name="shared_string_search">Buscar</string>
<string name="direction">Dirección</string>
<string name="precision">Precisión</string>
<string name="altitude">Altitud</string>
<string name="bearing">Rumbo</string>
<string name="proxy_key">Clave</string>
<string name="proxy_password">Contraseña</string>
<string name="proxy_username">Nombre de usuario</string>
<string name="proxy_credentials">Credenciales</string>
<string name="proxy_port">Puerto</string>
<string name="proxy_server">Servidor</string>
<string name="shared_string_connection">Conexión</string>
<string name="shared_string_enable">Activar</string>
<string name="proxy_type">Tipo de proxy</string>
<string name="proxy_connected">Conectado</string>
<string name="proxy_disconnected">Desconectado</string>
<string name="proxy_settings">Ajustes del proxy</string>
<string name="proxy">Proxy</string>
<string name="privacy">Privacidad</string>
</resources>

View file

@ -212,4 +212,12 @@
<string name="shared_string_appearance">Aspecto</string>
<string name="show_gps_points">Mostrar puntos GPS</string>
<string name="show_gps_points_descr">Muestra la cantidad de puntos GPS recibidos y enviados.</string>
<string name="search_contacts">Buscar contactos</string>
<string name="search_contacts_descr">Buscar en todos tus grupos y contactos.</string>
<string name="type_contact_or_group_name">Escriba el nombre del contacto o grupo</string>
<string name="shared_string_search">Buscar</string>
<string name="direction">Dirección</string>
<string name="precision">Precisión</string>
<string name="altitude">Altitud</string>
<string name="bearing">Rumbo</string>
</resources>

View file

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="direction">Norabidea</string>
<string name="precision">Zehaztasuna</string>
<string name="altitude">Altitudea</string>
<string name="bearing">Orientazioa</string>
<string name="search_contacts">Bilatu kontaktuak</string>
<string name="type_contact_or_group_name">Idatzi kontaktu edo talde izena</string>
<string name="shared_string_search">Bilatu</string>
<string name="shared_string_ok">ADOS</string>
<string name="disable_monitoring">Desgaitu kontrola</string>
<string name="location_recording_enabled">Kokapen grabaketa gaituta</string>
<string name="timeline_description">Gaitu kontrola zure kokapen guztiak historian gordetzeko.</string>
<string name="app_name_short_online">Online Aztarnaria</string>
<string name="app_name_short">OsmAnd Aztarnaria</string>
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_use_telegram">Telegram (mezularitza aplikazioa) jendearekin konektatzeko eta komunikatzeko erabiltzen da.</string>
<string name="shared_string_accept">Onartu</string>
<string name="telegram_privacy_policy">Telegram Pribatutasun Politika</string>
<string name="osmand_privacy_policy">OsmAnd Pribatutasun Politika</string>
<string name="how_it_works">Zelan dabil</string>
<string name="shared_string_appearance">Itxura</string>
<string name="show_gps_points">Erakutsi GPS puntuak</string>
<string name="shared_string_update">Eguneratu</string>
<string name="shared_string_date">Data</string>
<string name="gps_points">GPs puntuak</string>
<string name="shared_string_sent">Bidalita</string>
<string name="open_in_osmand">Erakutsi OsmAnd-en</string>
<string name="end_date">Bukaera data</string>
<string name="start_date">Hasiera data</string>
<string name="shared_string_map">Mapa</string>
<string name="shared_string_text">Testua</string>
<string name="map_and_text">Mapa eta testua</string>
<string name="last_update_from_telegram">Azken eguneraketa Telegram-etik</string>
<string name="shared_string_add">Gehitu</string>
<string name="error_adding_new_device">Ezin izan da gailu berri bat gehitu</string>
<string name="device_name_is_too_long">Gailuaren izena luzeegia</string>
<string name="device_name_cannot_be_empty">Gailuaren izena ezin da hutsik egon</string>
<string name="device_name">Gailuaren izena</string>
<string name="shared_string_hide">Ezkutatu</string>
<string name="sending_location_messages">Kokapena bidaltzen</string>
<string name="initializing">Abiarazten</string>
<string name="searching_for_gps">Kokalekua…</string>
<string name="connecting_to_the_internet">Internetera konektatzen</string>
<string name="go_to_settings">Ezarpenetara joan</string>
<string name="shared_string_later">Gero</string>
<string name="re_send_location">Birbidali kokapena</string>
<string name="shared_string_status">Egoera</string>
<string name="no_gps_connection">GPS konexiorik ez</string>
<string name="no_internet_connection">Internet konexiorik ez</string>
<string name="shared_string_disable">Desgaitu</string>
<string name="shared_string_save">Gorde</string>
<string name="add_device">Gehitu gailua</string>
<string name="share_location_as">Partekatu kokapena honela</string>
<string name="shared_string_name">Izena</string>
<string name="shared_string_sort">Ordenatu</string>
<string name="shared_string_sort_by">Ordenatu honen arabera</string>
<string name="choose_osmand">Aukeratu erabili nahi duzun OsmAnd bertsioa</string>
<string name="disable_all_sharing">Desgaitu partekatze guztiak</string>
<string name="turn_off_all">Desaktibatu guztia</string>
<string name="shared_string_exit">Irten</string>
<string name="time_ago">lehenago</string>
<string name="shared_string_group">Taldea</string>
<string name="shared_string_close">Itxi</string>
<string name="connected_account">Konektatutako kontua</string>
<string name="shared_string_account">Kontua</string>
<string name="location_history">Kokapen historia</string>
<string name="send_my_location">Bidali nire kokapena</string>
<string name="gps_and_location">Posizioa</string>
<string name="open_osmand">Ireki OsmAnd</string>
<string name="shared_string_live">Zuzenean</string>
<string name="shared_string_bot">Bot</string>
<string name="get_telegram_description_continue">Mesedez instalatu Telegram eta konfiguratu kontu bat.</string>
<string name="shared_string_all">Guztia</string>
<string name="enter_phone_number">Sartu telefono zenbakia</string>
<string name="shared_string_install">Instalatu</string>
<string name="shared_string_share">Partekatu</string>
<string name="shared_string_back">Atzera</string>
<string name="start_location_sharing">Partekatu kokapena</string>
<string name="show_on_map">Erakutsi mapan</string>
<string name="app_name">OsmAnd Telegram</string>
<string name="phone_number_title">Telefono zenbakia</string>
<string name="phone_number_descr">Telefono zenbakia formatu internazionalean</string>
<string name="shared_string_password">Pasahitza</string>
<string name="enter_code">Sartu kodea</string>
<string name="authentication_code">Authentication kodea</string>
<string name="enter_password">Sartu pasahitza</string>
<string name="password_descr">Telegram pasahitza</string>
<string name="shared_string_login">Saioa hasi</string>
<string name="shared_string_logout">Saioa itxi</string>
<string name="initialization">Abiarazten</string>
<string name="logging_out">Saioa ixten</string>
<string name="closing">Ixten</string>
<string name="gps_network_not_enabled">Aktibatu \"Kokapena\"\?</string>
<string name="not_logged_in">Ez duzu saioa hasi</string>
<string name="shared_string_continue">Jarraitu</string>
<string name="shared_string_cancel">Utzi</string>
<string name="shared_string_settings">Ezarpenak</string>
<string name="gps_not_available">Mesedez aktibatu \"Kokapena\" sistemaren ezarpenetan</string>
<string name="osmand_service">Atzeko plano modua</string>
<string name="shared_string_distance">Distantzia</string>
<string name="share_location">Partekatu kokapena</string>
<string name="sharing_location">Partekatzen kokapena</string>
<string name="process_service">OsmAnd Telegram zebitzua</string>
<string name="osmand_logo">OsmAnd logoa</string>
<string name="install_osmand_dialog_message">OsmAnd doako edo ordainpeko bertsioa instalatu behar duzu lehenik</string>
<string name="install_osmand">Instalatu OsmAnd</string>
<string name="show_users_on_map">Erakutsi erabiltzaileak mapan</string>
<string name="active_chats">Aktibatu txata</string>
<string name="shared_string_authorization">Baimena</string>
<string name="shared_string_welcome">Ongi etorri</string>
<string name="yard">yd</string>
<string name="foot">oin</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">Kilometro orduko</string>
<string name="si_mph">Milia orduko</string>
<string name="si_m_s">Metro segunduko</string>
<string name="si_min_km">Minutu kilometroko</string>
<string name="si_min_m">Minutu miliaro</string>
<string name="si_nm_h">Milia nautikoa orduro (knot)</string>
<string name="si_mi_feet">Miliak/Oin</string>
<string name="si_mi_yard">Miliak/yardak</string>
<string name="si_km_m">Kilometroak/metroak</string>
<string name="si_nm">Milia nautikoak</string>
<string name="si_mi_meters">Miliak/metroak</string>
<string name="shared_string_hour_short">o</string>
<string name="shared_string_minute_short">min</string>
<string name="shared_string_second_short">seg</string>
<string name="my_location">Nire kokapena</string>
<string name="live_now">Zuzenean orain</string>
<string name="timeline">Denbora-eskala</string>
</resources>

View file

@ -212,4 +212,8 @@
<string name="shared_string_collected">Recolleitos</string>
<string name="gps_points">Puntos GPS</string>
<string name="shared_string_sent">Enviado</string>
<string name="search_contacts">Procurar contactos</string>
<string name="search_contacts_descr">Procura en tódolos teus grupos e contactos.</string>
<string name="type_contact_or_group_name">Escribe o nome do contacto ou do grupo</string>
<string name="shared_string_search">Procurar</string>
</resources>

View file

@ -212,4 +212,26 @@
<string name="location_recording_enabled">הופעלה הקלטת מיקום</string>
<string name="app_name_short_online">עוקב בזמן אמת</string>
<string name="app_name_short">עוקב OsmAnd</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="direction">כיוון</string>
<string name="precision">דיוק</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="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>
</resources>

View file

@ -192,4 +192,32 @@
<string name="connected_account">Csatlakoztatott fiók</string>
<string name="shared_string_account">Fiók</string>
<string name="in_time">ennyi idő múlva: %1$s</string>
<string name="search_contacts">Kapcsolatok keresése</string>
<string name="search_contacts_descr">Keresés az összes csoportban és kapcsolatban.</string>
<string name="type_contact_or_group_name">Gépelje be a kapcsolat vagy a csoport nevét</string>
<string name="shared_string_search">Keresés</string>
<string name="osmand_connect_desc">Válassza ki, melyik OsmAnd verziót használja a az OsmAnd Telegram a pozíciók megjelenítéséhez.</string>
<string name="osmand_connect">Kapcsolódás az OsmAndhoz</string>
<string name="already_registered_in_telegram">Regisztrált Telegram fiók és telefonszám szükséges</string>
<string name="do_not_have_telegram">Nincs Telegram fiókom</string>
<string name="enter_phone_number">Telefonszám megadása</string>
<string name="enter_authentication_code">Ellenőrző kód megadása</string>
<string name="set_visible_time_for_all">Látható idő megadása mindenkinek</string>
<string name="hours_format">%1$d óra</string>
<string name="authentication_code_descr">A fiókjába való belépéshez Telegram elküldött egy kódot az OsmAndhoz.</string>
<string name="no_location_permission">Az alkalmazásnak nincs engedélye a tartózkodási hely adataihoz való hozzáféréshez.</string>
<string name="gps_not_available">A rendszerbeállításoknál kapcsolja be a „Tartózkodási helyet”</string>
<string name="location_service_no_gps_available">Tartózkodási helyének megosztásához jelölje ki az egyik tartózkodásihely-szolgáltatót.</string>
<string name="osmand_service">Háttérmód</string>
<string name="osmand_service_descr">Az OsmAnd Telegram a háttérben fut, kikapcsolt képernyővel.</string>
<string name="install_osmand_dialog_message">Először telepítenie kell az OsmAnd ingyenes vagy fizetős verzióját</string>
<string name="install_osmand">OsmAnd telepítése</string>
<string name="show_users_on_map">Felhasználók megjelenítése a térképen</string>
<string name="active_chats">Aktív csevegések</string>
<string name="shared_string_authorization">Engedélyezés</string>
<string name="shared_string_authorization_descr">Kérjük, nemzetközi formátumban adja meg a Telegramhoz használt telefonszámát</string>
<string name="direction">Irány</string>
<string name="precision">Pontosság</string>
<string name="altitude">Magasság</string>
<string name="bearing">Tájolás</string>
</resources>

View file

@ -39,8 +39,8 @@
<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 Telegram-økta.</string>
<string name="disconnect_from_telegram">Hvordan koble fra OsmAnd posisjonsdeling fra Telegram</string>
<string name="logout_help_desc">Hvordan koble fra OsmAnd posisjonsdeling fra Telegram</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>
@ -125,8 +125,8 @@
<string name="shared_string_minute_short">min</string>
<string name="shared_string_second_short">sek</string>
<string name="welcome_descr">
<b>OsmAnd posisjonsdeling</b> lar deg dele din posisjon og se andres posisjon i OsmAnd.<br/>
<br/>Programmet belager seg på Telegram-API-et. For å bruke dette programmet må du ha en Telegram-konto.</string>
<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="my_location">Min posisjon</string>
<string name="last_updated_location">Sist oppdaterte posisjon:</string>
<string name="successfully_sent_and_updated">Sendt og oppdatert</string>
@ -182,13 +182,13 @@
<string name="time_on_the_move">Tid i bevegelse</string>
<string name="average_altitude">Gjennomsnittlig høyde</string>
<string name="average_speed">Gjennomsnittsfart</string>
<string name="open_in_osmand">Åpne i OsmAnd</string>
<string name="open_in_osmand">Vis i OsmAnd</string>
<string name="end_date">Sluttdato</string>
<string name="start_date">Startdato</string>
<string name="timeline">Tidslinje</string>
<string name="shared_string_telegram">Telegram</string>
<string name="privacy_policy_telegram_client">Telegram åpen plattform, og OsmAnd-sporeren er én av kundene. Dine kontakter kan bruke enhver annen Telegram-klient.</string>
<string name="privacy_policy_agree">Ved å klikke \"Fortsett\" samtykker du til Telegram-personvernspraksisen, og OsmAnd-personvernspraksisen.</string>
<string name="privacy_policy_telegram_client">OsmAnd-sporeren er én av klientene som bruker Telegram. Dine kontakter kan bruke enhver annen Telegram-klient.</string>
<string name="privacy_policy_agree">Ved å klikke \"Fortsett\" samtykker du til vilkårene i Telegram-personvernspraksisen, og OsmAnd-personvernspraksisen.</string>
<string name="shared_string_accept">Godta</string>
<string name="telegram_privacy_policy">Telegram-personvernspraksis</string>
<string name="how_it_works">Hvordan det virker</string>
@ -209,8 +209,30 @@
<string name="location_recording_enabled">Plasseringsregistrering påskrudd</string>
<string name="app_name_short_online">Nettbasert sporer</string>
<string name="app_name_short">OsmAnd-sporer</string>
<string name="privacy_policy_use_telegram">Telegram (meldingsprogrammet) brukes til å snakke med folk.</string>
<string name="privacy_policy_use_telegram">Telegram (meldingsprogrammet) brukes til å komme i kontakt og snakke med folk.</string>
<string name="osmand_privacy_policy">OsmAnd-personvernspraksis</string>
<string name="please_update_osmand">Oppdater OsmAnd for å vise data på kartet</string>
<string name="timeline_description">Skru på oppsyn for å samle bevegelsesdata i historikk.</string>
<string name="search_contacts">Søk i kontaktliste</string>
<string name="search_contacts_descr">Søk gjennom alle dine grupper og kontakter.</string>
<string name="type_contact_or_group_name">Skriv kontakt- eller gruppenavn</string>
<string name="shared_string_search">Søk</string>
<string name="direction">Retning</string>
<string name="precision">Nøyaktighet</string>
<string name="altitude">Høyde</string>
<string name="bearing">Kurs</string>
<string name="proxy_key">Nøkkel</string>
<string name="proxy_password">Passord</string>
<string name="proxy_username">Brukernavn</string>
<string name="proxy_credentials">Identitetsdetaljer</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Tjener</string>
<string name="shared_string_connection">Forbindelse</string>
<string name="shared_string_enable">Skru på</string>
<string name="proxy_type">Mellomtjenertype</string>
<string name="proxy_connected">Tilkoblet</string>
<string name="proxy_disconnected">Frakoblet</string>
<string name="proxy_settings">Mellomtjener-innstillinger</string>
<string name="proxy">Mellomtjener</string>
<string name="privacy">Personvern</string>
</resources>

View file

@ -1,2 +1,216 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="shared_string_ok">OK</string>
<string name="timeline_available_for_free_now">Tijdlijn is nu een gratis functionaliteit.</string>
<string name="disable_monitoring">Schakel monitoring uit</string>
<string name="location_recording_enabled">Locatie opname ingeschakeld</string>
<string name="timeline_description">Schakel monitoring in om alle locaties in de geschiedenis op te slaan.</string>
<string name="app_name_short_online">Online Tracker</string>
<string name="app_name_short">OsmAnd Tracker</string>
<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="shared_string_accept">Aanvaard</string>
<string name="telegram_privacy_policy">Telegram privacy beleid</string>
<string name="osmand_privacy_policy">OsmAnd privacy beleid</string>
<string name="how_it_works">Hoe werkt het</string>
<string name="received_gps_points">Ontvangen GPX punten: %1$s</string>
<string name="show_gps_points">Toon GPS punten</string>
<string name="show_gps_points_descr">Toon totaal aan verzamelde en verstuurde GPS punten.</string>
<string name="please_update_osmand">Update OsmAnd aub om data op de kaart te zien</string>
<string name="shared_string_update">Update</string>
<string name="gps_points_in_buffer">verzonden (%1$d in buffer)</string>
<string name="points_size">%1$d punten</string>
<string name="shared_string_date">Datum</string>
<string name="shared_string_collected">Verzameld</string>
<string name="gps_points">GPS punten</string>
<string name="shared_string_sent">Verzonden</string>
<string name="monitoring_is_enabled">Monitoring is ingeschakeld</string>
<string name="monitoring_is_disabled">Monitoring is uitgeschakeld</string>
<string name="average_altitude">Gemiddelde hoogte</string>
<string name="average_speed">Gemiddelde snelheid</string>
<string name="open_in_osmand">Toon in OsmAnd</string>
<string name="end_date">Einddatum</string>
<string name="start_date">Begindatum</string>
<string name="send_location_as">Verstuur locatie als</string>
<string name="send_location_as_descr">Kies hoe berichten met uw locatie er uit zullen zien.</string>
<string name="shared_string_map">Kaart</string>
<string name="shared_string_text">Tekst</string>
<string name="map_and_text">Kaart en Tekst</string>
<string name="last_update_from_telegram">Laatste update van Telegram</string>
<string name="enter_another_device_name">Kies een naam die u nog niet gebruikt heeft</string>
<string name="device_added_successfully">%1$s toegevoegd.</string>
<string name="shared_string_add">Voeg toe</string>
<string name="error_adding_new_device">Kan nieuw apparaat niet toevoegen</string>
<string name="enter_device_name_description">Geef uw apparaat een naam van max. 200 tekens.</string>
<string name="device_name_is_too_long">Apparaatnaam te lang</string>
<string name="device_name_cannot_be_empty">Apparaatnaam mag net leeg zijn</string>
<string name="device_name">Apparaatnaam</string>
<string name="shared_string_hide">Verberg</string>
<string name="share_location_as_description_second_line">U kunt het apparaat ID in de Telegram client maken en bekijken door de %1$s chat bot te gebruiken. %2$s</string>
<string name="share_location_as_description">Als u meerdere apparaten aan één Telegram id wilt verbinden, moet u een ander apparaat gebruiken om uw locatie te delen.</string>
<string name="last_updated_location">Laatst ververste locatie:</string>
<string name="successfully_sent_and_updated">Succesvol verzonden en ververst</string>
<string name="not_possible_to_send_to_telegram_chats">Niet mogelijk om naar Telegram chats te versturen:</string>
<string name="waiting_for_response_from_telegram">Wacht op respons van Telegram</string>
<string name="sending_location_messages">Locatie versturen</string>
<string name="initializing">Beginnen</string>
<string name="searching_for_gps">Positie bepalen…</string>
<string name="connecting_to_the_internet">Verbinden met Internet</string>
<string name="background_work_description">Wijzig batterij optimalisatie om het delen van uw locatie te verbeteren.</string>
<string name="battery_optimization_description">Schakel batterij optimalisatie uit voor OsmAnd Telegram zodat het niet uitgeschakeld wordt in de achtergrond.</string>
<string name="sharing_in_background">Delen in de achtergrond</string>
<string name="go_to_settings">Open Instellingen</string>
<string name="shared_string_later">Later</string>
<string name="not_sent_yet">Nog niet verstuurd</string>
<string name="not_found_yet">Nog niet gevonden</string>
<string name="re_send_location">Herzend locatie</string>
<string name="last_available_location">Laatst beschikbare locatie</string>
<string name="sharing_status">Delen status</string>
<string name="sharing_enabled">Delen: Ingeschakeld</string>
<string name="shared_string_status">Status</string>
<string name="no_gps_connection">Geen GPS verbinding</string>
<string name="no_internet_connection">Geen internet verbinding</string>
<string name="shared_string_disable">Schakel uit</string>
<string name="shared_string_save">Opslaan</string>
<string name="add_device">Voeg apparaat toe</string>
<string name="share_location_as">Deel locatie als</string>
<string name="live_now_description">Contacten en groepen die hun locatie delen met jou.</string>
<string name="logout_from_osmand_telegram_descr">Weet u zeker dat u uit wilt loggen uit Osmand Telegram en daarmee uw locatie niet meer deelt en de locatie van anderen niet meer kunt zien\?</string>
<string name="logout_from_osmand_telegram">Uitloggen uit OsmAnd Telegram\?</string>
<string name="shared_string_name">Naam</string>
<string name="by_distance">Op afstand</string>
<string name="by_name">Op naam</string>
<string name="by_group">Op groep</string>
<string name="shared_string_sort">Sorteer</string>
<string name="shared_string_sort_by">Sorteer op</string>
<string name="choose_osmand_desc">Selecteer de OsmAnd versie die uw contacten op de kaart toont.</string>
<string name="choose_osmand">Selecteer te gebruiken Osmand versie</string>
<string name="disable_all_sharing_desc">Schakel locatie delen uit naar alle geselecteerde chats (%1$d).</string>
<string name="disable_all_sharing">Schakel delen helemaal uit</string>
<string name="turn_off_all">Schakel alles uit</string>
<string name="shared_string_exit">Verlaat</string>
<string name="last_response">Laatste respons</string>
<string name="shared_string_group">Groep</string>
<string name="logout_no_internet_msg">Verbind met Internet om correct uit te loggen uit Telegram.</string>
<string name="shared_string_close">Sluit</string>
<string name="disconnect_from_telegram_desc">Om locatie delen toegang uit te schakelen: Open Telegram, gaan naar Instellingen -&gt; Privacy en veiligheid -&gt; Active sessies, en beeindig the OsmAnd Telegram sessie.</string>
<string name="disconnect_from_telegram">Hoe zet je de OsmAnd Tracker uit in Telegram</string>
<string name="logout_help_desc">Hoe zet je de OsmAnd Tracker uit in Telegram</string>
<string name="connected_account">Verbonden account</string>
<string name="shared_string_account">Account</string>
<string name="in_time">in %1$s</string>
<string name="osmand_connect_desc">Kies de OsmAnd versie die door OsmAnd Telegram gebruikt wordt om posities te tonen.</string>
<string name="location_history_desc">Verberg contacten die zich een bepaalde tijd niet verplaatsten.</string>
<string name="location_history">Locatie geschiedenis</string>
<string name="stale_location_desc">De laatste keer dat een contact zich verplaatste.</string>
<string name="stale_location">Onbeweeglijk</string>
<string name="send_my_location_desc">Stel de minimum interval in voor locatie delen.</string>
<string name="send_my_location">Verstuur mijn locatie</string>
<string name="gps_and_location">Positie</string>
<string name="stop_sharing_all">Delen staat aan (schakel uit)</string>
<string name="turn_off_location_sharing">Schakel locatie delen uit</string>
<string name="open_osmand">Open OsmAnd</string>
<string name="shared_string_live">Live</string>
<string name="shared_string_bot">Bot</string>
<string name="get_telegram_title">Registratie in Telegram</string>
<string name="get_telegram_account_first">U hebt een een Telegram account nodig om uw locatie te delen.</string>
<string name="get_telegram_description_continue">Installeer Telegram aub en stel een account in.</string>
<string name="get_telegram_after_creating_account">Dan kunt u deze app gebruiken.</string>
<string name="already_registered_in_telegram">U hebt een geregistreerd Telegram account en telefoonnummer nodig</string>
<string name="do_not_have_telegram">Ik heb geen Telegram account</string>
<string name="enter_phone_number">Vul telefoonnummer in</string>
<string name="enter_authentication_code">Vul verificatiecode in</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="shared_string_install">Installeer</string>
<string name="shared_string_share">Deel</string>
<string name="shared_string_back">Terug</string>
<string name="location_sharing_description">Selecteer de contacten en groepen waarmee u uw locatie wilt delen.</string>
<string name="my_location_search_hint">Zoek: Groep of contact</string>
<string name="start_location_sharing">Deel locatie</string>
<string name="show_on_map">Toon op de kaart</string>
<string name="app_name">OsmAnd Telegram</string>
<string name="phone_number_title">Telefoonnummer</string>
<string name="phone_number_descr">Telefoonnummer in internationaal formaat</string>
<string name="shared_string_password">Wachtwoord</string>
<string name="enter_code">Vul code in</string>
<string name="authentication_code">Verificatiecode</string>
<string name="authentication_code_descr">Telegram heeft u een inlogcode voor OsmAnd gestuurd om op uw account in te loggen.</string>
<string name="enter_password">Vul wachtwoord in</string>
<string name="password_descr">Telegram wachtwoord</string>
<string name="shared_string_login">Log in</string>
<string name="shared_string_logout">Log uit</string>
<string name="logging_out">Uitloggen</string>
<string name="closing">Sluiten</string>
<string name="gps_network_not_enabled">\"Locatie\" inschakelen\?</string>
<string name="not_logged_in">U bent niet ingelogd</string>
<string name="shared_string_continue">Doorgaan</string>
<string name="shared_string_cancel">Annuleren</string>
<string name="shared_string_settings">Instellingen</string>
<string name="no_location_permission">App mist permissie voor toegang tot Locatie.</string>
<string name="gps_not_available">Schakel aub \"Locatie\" in in de systeem instellingen</string>
<string name="search_contacts">Doorzoek contacten</string>
<string name="search_contacts_descr">Zoek door al uw groepen en contacten.</string>
<string name="type_contact_or_group_name">Type contact- of groepnaam</string>
<string name="shared_string_search">Zoek</string>
<string name="shared_string_appearance">Toon als</string>
<string name="time_on_the_move">Tijd in beweging</string>
<string name="background_work">Achtergond uitvoeringen</string>
<string name="time_ago">sinds</string>
<string name="osmand_connect">Verbind met OsmAnd</string>
<string name="expire_at">Verloopt op</string>
<string name="shared_string_all">Alles</string>
<string name="shared_string_off">Uit</string>
<string name="set_time_description">Stel de tijd in waarop uw contacten en groepen uw locatie kunnen zien.</string>
<string name="set_time">Stel tijd in</string>
<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="shared_string_distance">Afstand</string>
<string name="share_location">Deel locatie</string>
<string name="sharing_location">Locatie wordt gedeeld</string>
<string name="process_service">OsmAnd Telegram service</string>
<string name="osmand_logo">OsmAnd logo</string>
<string name="install_osmand_dialog_message">U dient eerst de gratis of betaalde versie van OsmAnd te installeren</string>
<string name="install_osmand">Installeer OsmAnd</string>
<string name="show_users_on_map">Toon gebruikers op de kaart</string>
<string name="active_chats">Actieve chats</string>
<string name="shared_string_authorization">Autorisatie</string>
<string name="shared_string_authorization_descr">Vul a.u.b. uw Telegram telefoon nummer in in internationaal formaat</string>
<string name="shared_string_welcome">Welkom</string>
<string name="yard">yard</string>
<string name="foot">voet</string>
<string name="mile">mijl</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/u</string>
<string name="mile_per_hour">mpu</string>
<string name="si_kmh">Kilometers per uur</string>
<string name="si_mph">Mijlen per uur</string>
<string name="si_m_s">Meters 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_nm">Nautische mijlen</string>
<string name="si_mi_meters">Mijlen/meters</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>
<string name="welcome_descr">Met <b>OsmAnd Tracker</b> kunt u uw locatie delen en die van anderen bekijken.<br/>
<br/>The app gebruikt de Telegram API, daarom hebt u een Telegram account nodig.</string>
<string name="my_location">Mijn locatie</string>
<string name="live_now">Nu live</string>
<string name="timeline">Tijdlijn</string>
</resources>

View file

@ -215,4 +215,26 @@
<string name="show_gps_points">Pokaż punkty GPS</string>
<string name="show_gps_points_descr">Pokaż ilość zebranych i wysłanych punktów GPS.</string>
<string name="gps_points_in_buffer">przesłano (%1$d w buforze)</string>
<string name="search_contacts">Wyszukiwanie kontaktów</string>
<string name="search_contacts_descr">Przeszukaj wszystkie swoje grupy i kontakty.</string>
<string name="type_contact_or_group_name">Wpisz nazwę kontaktu lub grupy</string>
<string name="shared_string_search">Szukaj</string>
<string name="direction">Kierunek</string>
<string name="precision">Precyzja</string>
<string name="altitude">Wysokość</string>
<string name="proxy_key">Klucz</string>
<string name="proxy_password">Hasło</string>
<string name="proxy_username">Nazwa użytkownika</string>
<string name="proxy_credentials">Poświadczenia</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Serwer</string>
<string name="shared_string_connection">Połączenia</string>
<string name="shared_string_enable">Włącz</string>
<string name="proxy_type">Typ serwera proxy</string>
<string name="proxy_connected">Podłączony</string>
<string name="proxy_disconnected">Odłączony</string>
<string name="proxy_settings">Ustawienia proxy</string>
<string name="proxy">Serwer proxy</string>
<string name="privacy">Prywatność</string>
<string name="bearing">Kierunek</string>
</resources>

View file

@ -213,4 +213,26 @@
<string name="timeline_description">Ative o monitoramento para salvar todos os locais no histórico.</string>
<string name="app_name_short_online">Rastreador online</string>
<string name="app_name_short">Rastreador OsmAnd</string>
<string name="search_contacts">Pesquisar contatos</string>
<string name="search_contacts_descr">Pesquise em todos os seus grupos e contatos.</string>
<string name="type_contact_or_group_name">Digite o nome do contato ou do grupo</string>
<string name="shared_string_search">Pesquisar</string>
<string name="direction">Direção</string>
<string name="precision">Precisão</string>
<string name="altitude">Altitude</string>
<string name="bearing">Rolamento</string>
<string name="proxy_key">Chave</string>
<string name="proxy_password">Senha</string>
<string name="proxy_username">Nome de usuário</string>
<string name="proxy_credentials">Credenciais</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Servidor</string>
<string name="shared_string_connection">Conexão</string>
<string name="shared_string_enable">Ativar</string>
<string name="proxy_type">Tipo de proxy</string>
<string name="proxy_connected">Conectado</string>
<string name="proxy_disconnected">Desconectado</string>
<string name="proxy_settings">Configurações de proxy</string>
<string name="proxy">Proxy</string>
<string name="privacy">Privacidade</string>
</resources>

View file

@ -211,4 +211,8 @@
<string name="si_nm">Морские мили</string>
<string name="si_mi_meters">Мили/метры</string>
<string name="timeline">Хронология</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>
</resources>

View file

@ -212,4 +212,26 @@
<string name="timeline_description">Abìlita su monitoràgiu pro sarvare totu sas positziones in sa cronologia.</string>
<string name="app_name_short_online">Arrastadore in lìnia</string>
<string name="app_name_short">Arrastadore de OsmAnd</string>
<string name="search_contacts">Chirca cuntatos</string>
<string name="search_contacts_descr">Chirca intre totu sos grupos e sos cuntatos tuos.</string>
<string name="type_contact_or_group_name">Iscrie su nùmene de unu cuntatu o de unu grupu</string>
<string name="shared_string_search">Chirca</string>
<string name="precision">Pretzisione</string>
<string name="altitude">Artària</string>
<string name="direction">Diretzione</string>
<string name="proxy_key">Crae servidore</string>
<string name="proxy_password">Crae de intrada</string>
<string name="proxy_username">Nùmene impreadore</string>
<string name="proxy_credentials">Credentziales</string>
<string name="proxy_port">Ghenna</string>
<string name="proxy_server">Servidore</string>
<string name="shared_string_connection">Connessione</string>
<string name="shared_string_enable">Abìlita</string>
<string name="proxy_type">Casta de servidore intermediàriu</string>
<string name="proxy_connected">Connessu</string>
<string name="proxy_disconnected">Disconnessu</string>
<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>
</resources>

View file

@ -1,93 +1,97 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources><string name="enter_another_device_name">Izberite ime, ki ga še niste uporabili</string>
<string name="device_added_successfully">Naprava %1$s je uspešno dodana.</string>
<string name="shared_string_add">Dodaj</string>
<string name="error_adding_new_device">Ni mogoče dodati nove naprave</string>
<string name="enter_device_name_description">Ime nove naprave je omejeno z 200 znaki.</string>
<string name="device_name_is_too_long">Ime naprave je predolgo</string>
<string name="device_name_cannot_be_empty">Ime naprave mora biti dodeljeno</string>
<string name="device_name">Ime naprave</string>
<string name="shared_string_hide">Skrij</string>
<string name="share_location_as_description_second_line">ID naprave je mogoče ustvariti in pogledati v odjemalcu Telegram z uporabo klepetalnega robota %1$s. %2$s</string>
<string name="last_updated_location">Nazadnje zabeleženo mesto:</string>
<string name="successfully_sent_and_updated">Podatki so uspešno poslani in posodobljeni.</string>
<string name="not_possible_to_send_to_telegram_chats">Ni mogoče pošiljati klepetov Telegram:</string>
<string name="waiting_for_response_from_telegram">Poteka čakanje na odziv programa Telegram</string>
<string name="sending_location_messages">Pošiljanje podatkov o trenutnem mestu</string>
<string name="initializing">Začenjanje</string>
<string name="searching_for_gps">Poteka določevanje mesta …</string>
<string name="connecting_to_the_internet">Poteka vzpostavljanje povezave na internet</string>
<string name="go_to_settings">Skoči na nastavitve</string>
<string name="shared_string_later">Kasneje</string>
<string name="not_sent_yet">Ni še poslano</string>
<string name="not_found_yet">Ni še najdeno</string>
<string name="re_send_location">Ponovno pošiljanje trenutnega mesta</string>
<string name="last_available_location">Zadnje določeno mesto</string>
<string name="sharing_status">Objavljanje stanja</string>
<string name="sharing_enabled">Objavljanje: omogočeno</string>
<string name="shared_string_status">Stanje</string>
<string name="no_gps_connection">Ni povezave z GPS</string>
<string name="no_internet_connection">Ni vzpostavljene internetne povezave</string>
<string name="shared_string_disable">Onemogoči</string>
<string name="shared_string_save">Shrani</string>
<string name="add_device">Dodaj napravo</string>
<string name="share_location_as">Objavi trenutno mesto kot</string>
<string name="logout_from_osmand_telegram">Ali se želite odjaviti iz storitve OsmAnd Tracker\?</string>
<string name="shared_string_name">Ime</string>
<string name="by_distance">Po razdalji</string>
<string name="by_name">Po imenu</string>
<string name="by_group">Po skupini</string>
<string name="shared_string_sort">Razvrsti</string>
<string name="shared_string_sort_by">Razvrsti po</string>
<string name="choose_osmand">Izbor različice OsmAnd za uporabo</string>
<string name="disable_all_sharing">Onemogoči vse objavljanje</string>
<string name="turn_off_all">Izklopi vse</string>
<string name="shared_string_exit">Končaj</string>
<string name="last_response">Zadnji odziv</string>
<string name="shared_string_group">Skupina</string>
<string name="logout_no_internet_msg">Pred odjavo storitve Telegram je treba vzpostaviti internetno povezavo.</string>
<string name="shared_string_close">Zapri</string>
<string name="connected_account">Povezan račun</string>
<string name="shared_string_account">Račun</string>
<string name="in_time">v %1$s</string>
<string name="show_on_map">Pokaži na zemljevidu</string>
<string name="app_name">OsmAnd Online GPS Tracker</string>
<string name="phone_number_title">Telefonska številka</string>
<string name="phone_number_descr">Telefonska številka v mednarodnem zapisu</string>
<string name="shared_string_password">Geslo</string>
<string name="enter_code">Koda</string>
<string name="authentication_code">Overitvena koda</string>
<string name="install_osmand">Namesti program OsmAnd</string>
<string name="show_users_on_map">Pokaži uporabnike na zemljevidu</string>
<string name="active_chats">Dejavni klepeti</string>
<string name="shared_string_authorization">Overitev</string>
<string name="shared_string_authorization_descr">Telefonsko številko programa Telegram je treba vpisati v mednarodnem zapisu</string>
<string name="shared_string_welcome">Dobrodošli</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">Kilometri na uro</string>
<string name="si_mph">Milje na uro</string>
<string name="si_m_s">Metri na sekundo</string>
<string name="si_min_km">Minute na kilometer</string>
<string name="si_min_m">Minute na miljo</string>
<string name="si_nm_h">Navtične milje na uro (vozli)</string>
<string name="si_mi_feet">Milje/Čevlji</string>
<string name="si_mi_yard">Milje/Jardi</string>
<string name="si_km_m">Kilometri/Metri</string>
<string name="si_nm">Navtične milje</string>
<string name="si_mi_meters">Milje/Metri</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>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="enter_another_device_name">Izberite ime, ki ga še niste uporabili</string>
<string name="device_added_successfully">Naprava %1$s je uspešno dodana.</string>
<string name="shared_string_add">Dodaj</string>
<string name="error_adding_new_device">Ni mogoče dodati nove naprave</string>
<string name="enter_device_name_description">Ime nove naprave je omejeno z 200 znaki.</string>
<string name="device_name_is_too_long">Ime naprave je predolgo</string>
<string name="device_name_cannot_be_empty">Ime naprave mora biti dodeljeno</string>
<string name="device_name">Ime naprave</string>
<string name="shared_string_hide">Skrij</string>
<string name="share_location_as_description_second_line">ID naprave je mogoče ustvariti in pogledati v odjemalcu Telegram z uporabo klepetalnega robota %1$s. %2$s</string>
<string name="last_updated_location">Nazadnje zabeleženo mesto:</string>
<string name="successfully_sent_and_updated">Podatki so uspešno poslani in posodobljeni.</string>
<string name="not_possible_to_send_to_telegram_chats">Ni mogoče pošiljati klepetov Telegram:</string>
<string name="waiting_for_response_from_telegram">Poteka čakanje na odziv programa Telegram</string>
<string name="sending_location_messages">Pošiljanje podatkov o trenutnem mestu</string>
<string name="initializing">Začenjanje</string>
<string name="searching_for_gps">Poteka določevanje mesta …</string>
<string name="connecting_to_the_internet">Poteka vzpostavljanje povezave na internet</string>
<string name="go_to_settings">Skoči na nastavitve</string>
<string name="shared_string_later">Kasneje</string>
<string name="not_sent_yet">Ni še poslano</string>
<string name="not_found_yet">Ni še najdeno</string>
<string name="re_send_location">Ponovno pošiljanje trenutnega mesta</string>
<string name="last_available_location">Zadnje določeno mesto</string>
<string name="sharing_status">Objavljanje stanja</string>
<string name="sharing_enabled">Objavljanje: omogočeno</string>
<string name="shared_string_status">Stanje</string>
<string name="no_gps_connection">Ni povezave z GPS</string>
<string name="no_internet_connection">Ni vzpostavljene internetne povezave</string>
<string name="shared_string_disable">Onemogoči</string>
<string name="shared_string_save">Shrani</string>
<string name="add_device">Dodaj napravo</string>
<string name="share_location_as">Objavi trenutno mesto kot</string>
<string name="logout_from_osmand_telegram">Ali se želite odjaviti iz storitve OsmAnd Tracker\?</string>
<string name="shared_string_name">Ime</string>
<string name="by_distance">Po razdalji</string>
<string name="by_name">Po imenu</string>
<string name="by_group">Po skupini</string>
<string name="shared_string_sort">Razvrsti</string>
<string name="shared_string_sort_by">Razvrsti po</string>
<string name="choose_osmand">Izbor različice OsmAnd za uporabo</string>
<string name="disable_all_sharing">Onemogoči vse objavljanje</string>
<string name="turn_off_all">Izklopi vse</string>
<string name="shared_string_exit">Končaj</string>
<string name="last_response">Zadnji odziv</string>
<string name="shared_string_group">Skupina</string>
<string name="logout_no_internet_msg">Pred odjavo storitve Telegram je treba vzpostaviti internetno povezavo.</string>
<string name="shared_string_close">Zapri</string>
<string name="connected_account">Povezan račun</string>
<string name="shared_string_account">Račun</string>
<string name="in_time">v %1$s</string>
<string name="show_on_map">Pokaži na zemljevidu</string>
<string name="app_name">OsmAnd Online GPS Tracker</string>
<string name="phone_number_title">Telefonska številka</string>
<string name="phone_number_descr">Telefonska številka v mednarodnem zapisu</string>
<string name="shared_string_password">Geslo</string>
<string name="enter_code">Koda</string>
<string name="authentication_code">Overitvena koda</string>
<string name="install_osmand">Namesti program OsmAnd</string>
<string name="show_users_on_map">Pokaži uporabnike na zemljevidu</string>
<string name="active_chats">Dejavni klepeti</string>
<string name="shared_string_authorization">Overitev</string>
<string name="shared_string_authorization_descr">Telefonsko številko programa Telegram je treba vpisati v mednarodnem zapisu</string>
<string name="shared_string_welcome">Dobrodošli</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">Kilometri na uro</string>
<string name="si_mph">Milje na uro</string>
<string name="si_m_s">Metri na sekundo</string>
<string name="si_min_km">Minute na kilometer</string>
<string name="si_min_m">Minute na miljo</string>
<string name="si_nm_h">Navtične milje na uro (vozli)</string>
<string name="si_mi_feet">Milje/Čevlji</string>
<string name="si_mi_yard">Milje/Jardi</string>
<string name="si_km_m">Kilometri/Metri</string>
<string name="si_nm">Navtične milje</string>
<string name="si_mi_meters">Milje/Metri</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="search_contacts">Iskanje stikov</string>
<string name="search_contacts_descr">Iskanje med skupinami in stiki</string>
<string name="shared_string_search">Iskanje</string>
<string name="shared_string_ok">V redu</string>
</resources>

View file

@ -214,4 +214,26 @@
<string name="timeline_description">啟用監視以儲存所有歷史中的位置。</string>
<string name="app_name_short_online">線上追蹤器</string>
<string name="app_name_short">OsmAnd 追蹤器</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="direction">方向</string>
<string name="precision">精確</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="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>
</resources>

View file

@ -44,6 +44,7 @@
<dimen name="list_item_baseline_to_top_height_big">28dp</dimen>
<dimen name="list_view_bottom_padding">52dp</dimen>
<dimen name="list_view_bottom_padding_big">140dp</dimen>
<dimen name="card_divider_bottom_margin">6dp</dimen>
@ -60,6 +61,7 @@
<dimen name="disable_sharing_icon_top_margin">30dp</dimen>
<dimen name="search_box_height">48dp</dimen>
<dimen name="empty_state_descr_margin">68dp</dimen>
<dimen name="buttons_bottom_bar_height">56dp</dimen>
@ -72,6 +74,8 @@
<dimen name="list_popup_window_height">300dp</dimen>
<dimen name="proxy_save_button_height">60dp</dimen>
<!-- Text sizes -->
<dimen name="dialog_title_text_size">22sp</dimen>

View file

@ -1,5 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="proxy_key">Key</string>
<string name="proxy_password">Password</string>
<string name="proxy_username">Username</string>
<string name="proxy_credentials">Credentials</string>
<string name="proxy_port">Port</string>
<string name="proxy_server">Server</string>
<string name="shared_string_connection">Connection</string>
<string name="shared_string_enable">Enable</string>
<string name="proxy_type">Proxy type</string>
<string name="proxy_connected">Connected</string>
<string name="proxy_disconnected">Disconnected</string>
<string name="proxy_settings">Proxy Settings</string>
<string name="proxy">Proxy</string>
<string name="privacy">Privacy</string>
<string name="direction">Direction</string>
<string name="precision">Precision</string>
<string name="altitude">Altitude</string>
<string name="bearing">Bearing</string>
<string name="search_contacts">Search contacts</string>
<string name="search_contacts_descr">Search across all of your groups and contacts.</string>
<string name="type_contact_or_group_name">Type contact or group name</string>
<string name="shared_string_search">Search</string>
<string name="shared_string_ok">OK</string>
<string name="timeline_available_for_free_now">Timeline is a feature available now for free.</string>
<string name="disable_monitoring">Disable monitoring</string>

View file

@ -2,13 +2,40 @@ package net.osmand.aidl;
import net.osmand.aidl.search.SearchResult;
import net.osmand.aidl.gpx.AGpxBitmap;
import net.osmand.aidl.navigation.ADirectionInfo;
interface IOsmAndAidlCallback {
/**
* Callback for search requests.
*
* @return resultSet - set of SearchResult
*/
void onSearchComplete(in List<SearchResult> resultSet);
/**
* Callback for {@link IOsmAndAidlInterface} registerForUpdates() method.
*/
void onUpdate();
/**
* Callback for {@link IOsmAndAidlInterface} registerForOsmandInitListener() method.
*/
void onAppInitialized();
/**
* Callback for {@link IOsmAndAidlInterface} getBitmapForGpx() method.
*
* @return bitmap - snapshot image of gpx track on map
*/
void onGpxBitmapCreated(in AGpxBitmap bitmap);
/**
* Callback for {@link IOsmAndAidlInterface} registerForNavigationUpdates() method.
*
* @return directionInfo - update on distance to next turn and turns type.
*/
void updateNavigationInfo(in ADirectionInfo directionInfo);
void onContextMenuButtonClicked(in int buttonId, String pointId, String layerId);
}

View file

@ -54,7 +54,6 @@ import net.osmand.aidl.gpx.RemoveGpxParams;
import net.osmand.aidl.maplayer.point.ShowMapPointParams;
import net.osmand.aidl.navdrawer.SetNavDrawerItemsParams;
import net.osmand.aidl.navdrawer.NavDrawerFooterParams;
import net.osmand.aidl.navdrawer.NavDrawerHeaderParams;
@ -76,104 +75,628 @@ import net.osmand.aidl.customization.OsmandSettingsParams;
import net.osmand.aidl.gpx.AGpxFile;
import net.osmand.aidl.gpx.AGpxFileDetails;
import net.osmand.aidl.gpx.CreateGpxBitmapParams;
import net.osmand.aidl.tiles.ASqliteDbFile;
import net.osmand.aidl.plugins.PluginParams;
import net.osmand.aidl.copyfile.CopyFileParams;
import net.osmand.aidl.navigation.ANavigationUpdateParams;
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.UpdateContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.RemoveContextMenuButtonsParams;
// NOTE: Add new methods at the end of file!!!
interface IOsmAndAidlInterface {
/**
* Add map marker at given location.
*
* @param lat (double) - latitude.
* @param lon (double) - longitude.
* @param name (String)- name of marker.
*/
boolean addMapMarker(in AddMapMarkerParams params);
/**
* Add map marker at given location.
*
* @param lat (double) - latitude.
* @param lon (double) - longitude.
* @param name (String)- name of marker.
*/
boolean removeMapMarker(in RemoveMapMarkerParams params);
/**
* Update map marker at given location with name.
*
* @param latPrev (double) - latitude (current marker).
* @param lonPrev (double) - longitude (current marker).
* @param namePrev (String) - name (current marker).
* @param latNew (double) - latitude (new marker).
* @param lonNew (double) - longitude (new marker).
* @param nameNew (String) - name (new marker).
*/
boolean updateMapMarker(in UpdateMapMarkerParams params);
/**
* Add map widget to the right side of the main screen.
* Note: any specified icon should exist in OsmAnd app resources.
*
* @param id (String) - widget id.
* @param menuIconName (String) - icon name (configure map menu).
* @param menuTitle (String) - widget name (configure map menu).
* @param lightIconName (String) - icon name for the light theme (widget).
* @param darkIconName (String) - icon name for the dark theme (widget).
* @param text (String) - main widget text.
* @param description (String) - sub text, like "km/h".
* @param order (int) - order position in the widgets list.
* @param intentOnClick (String) - onClick intent. Called after click on widget as startActivity(Intent intent).
*/
boolean addMapWidget(in AddMapWidgetParams params);
/**
* Remove map widget.
*
* @param (String) id - widget id.
*/
boolean removeMapWidget(in RemoveMapWidgetParams params);
/**
* Update map widget.
* Note: any specified icon should exist in OsmAnd app resources.
*
* @param id (String) - widget id.
* @param menuIconName (String) - icon name (configure map menu).
* @param menuTitle (String) - widget name (configure map menu).
* @param lightIconName (String) - icon name for the light theme (widget).
* @param darkIconName (String) - icon name for the dark theme (widget).
* @param text (String) - main widget text.
* @param description (String) - sub text, like "km/h".
* @param order (int) - order position in the widgets list.
* @param intentOnClick (String) - onClick intent. Called after click on widget as startActivity(Intent intent).
*/
boolean updateMapWidget(in UpdateMapWidgetParams params);
/**
* Add point to user layer.
*
* @param layerId (String) - layer id. Note: layer should be added first.
* @param pointId (String) - point id.
* @param shortName (String) - short name (single char). Displayed on the map.
* @param fullName (String) - full name. Displayed in the context menu on first row.
* @param typeName (String) - type name. Displayed in context menu on second row.
* @param color (int) - color of circle's background.
* @param location (ALatLon) - location of the point.
* @param details (List<String>)- list of details. Displayed under context menu.
* @param params (Map<String, String>) - optional map of params for point.
*/
boolean addMapPoint(in AddMapPointParams params);
/**
* Remove point.
*
* @param layerId (String) - layer id.
* @param pointId (String) - point id.
*/
boolean removeMapPoint(in RemoveMapPointParams params);
/**
* Update point.
*
* @param layerId (String) - layer id.
* @param pointId (String) - point id.
* @param shortName (String) - short name (single char). Displayed on the map.
* @param fullName (String) - full name. Displayed in the context menu on first row.
* @param typeName (String) - type name. Displayed in context menu on second row.
* @param color (String) - color of circle's background.
* @param location (ALatLon)- location of the point.
* @param details (List<String>) - list of details. Displayed under context menu.
* @param params (Map<String, String>) - optional map of params for point.
*/
boolean updateMapPoint(in UpdateMapPointParams params);
/**
* Add user layer on the map.
*
* @param id (String) - layer id.
* @param name (String) - layer name.
* @param zOrder (float) - z-order position of layer. Default value is 5.5f
* @param points Map<Sting, AMapPoint> - initial list of points. Nullable.
* @param imagePoints (boolean) - use new style for points on map or not. Also default zoom bounds for new style can be edited.
*/
boolean addMapLayer(in AddMapLayerParams params);
/**
* Remove user layer.
*
* @param id (String) - layer id.
*/
boolean removeMapLayer(in RemoveMapLayerParams params);
/**
* Update user layer.
*
* @param id (String) - layer id.
* @param name (String) - layer name.
* @param zOrder (float) - z-order position of layer. Default value is 5.5f
* @param points Map<Sting, AMapPoint> - list of points. Nullable.
* @param imagePoints (boolean) - use new style for points on map or not. Also default zoom bounds for new style can be edited.
*/
boolean updateMapLayer(in UpdateMapLayerParams params);
boolean importGpx(in ImportGpxParams params);
boolean showGpx(in ShowGpxParams params);
boolean hideGpx(in HideGpxParams params);
boolean getActiveGpx(out List<ASelectedGpxFile> files);
/**
* Import GPX file to OsmAnd (from URI or file).
*
* @param gpxUri (Uri) - URI created by FileProvider (preferable method).
* @param file (File) - File which represents GPX track (not recomended, OsmAnd should have rights to access file location).
* @param fileName (String) - Destination file name. May contain dirs.
* @param color (String) - color of gpx. Can be one of: "red", "orange", "lightblue", "blue", "purple",
* "translucent_red", "translucent_orange", "translucent_lightblue",
* "translucent_blue", "translucent_purple"
* @param show (boolean) - show track on the map after import
*/
boolean importGpx(in ImportGpxParams params);
/**
* Show GPX file on map.
*
* @param fileName (String) - file name to show. Must be imported first.
*/
boolean showGpx(in ShowGpxParams params);
/**
* Hide GPX file.
*
* @param fileName (String) - file name to hide.
*/
boolean hideGpx(in HideGpxParams params);
/**
* Get list of active GPX files.
*
* @return list of active gpx files.
*/
boolean getActiveGpx(out List<ASelectedGpxFile> files);
/**
* Set map view to current location.
*
* @param latitude (double) - latitude of new map center.
* @param longitude (double) - longitude of new map center.
* @param zoom (float) - map zoom level. Set 0 to keep zoom unchanged.
* @param animated (boolean) - set true to animate changes.
*/
boolean setMapLocation(in SetMapLocationParams params);
boolean setMapLocation(in SetMapLocationParams params);
boolean calculateRoute(in CalculateRouteParams params);
/**
* Refresh the map (UI)
*/
boolean refreshMap();
/**
* Add favorite group with given params.
*
* @param name (String) - group name.
* @param color (String) - group color. Can be one of: "red", "orange", "yellow",
* "lightgreen", "green", "lightblue", "blue", "purple", "pink", "brown".
* @param visible (boolean) - group visibility.
*/
boolean addFavoriteGroup(in AddFavoriteGroupParams params);
/**
* Update favorite group with given params.
*
* @param namePrev (String) - group name (current).
* @param colorPrev (String) - group color (current).
* @param visiblePrev (boolean) - group visibility (current).
* @param nameNew (String) - group name (new).
* @param colorNew (String) - group color (new).
* @param visibleNew (boolean) - group visibility (new).
*/
boolean removeFavoriteGroup(in RemoveFavoriteGroupParams params);
/**
* Remove favorite group with given name.
*
* @param name (String) - name of favorite group.
*/
boolean updateFavoriteGroup(in UpdateFavoriteGroupParams params);
/**
* Add favorite at given location with given params.
*
* @param lat (double) - latitude.
* @param lon (double) - longitude.
* @param name (String) - name of favorite item.
* @param description (String) - description of favorite item.
* @param category (String) - category of favorite item.
* @param color (String) - color of favorite item. Can be one of: "red", "orange", "yellow",
* "lightgreen", "green", "lightblue", "blue", "purple", "pink", "brown".
* @param visible (boolean) - should favorite item be visible after creation.
*/
boolean addFavorite(in AddFavoriteParams params);
/**
* Update favorite at given location with given params.
*
* @param latPrev (double) - latitude (current favorite).
* @param lonPrev (double) - longitude (current favorite).
* @param namePrev (String) - name of favorite item (current favorite).
* @param categoryPrev (String) - category of favorite item (current favorite).
* @param latNew (double) - latitude (new favorite).
* @param lonNew (double) - longitude (new favorite).
* @param nameNew (String) - name of favorite item (new favorite).
* @param descriptionNew (String) - description of favorite item (new favorite).
* @param categoryNew (String) - category of favorite item (new favorite). Use only to create a new category,
* not to update an existing one. If you want to update an existing category,
* use the {@link #updateFavoriteGroup(String, String, boolean, String, String, boolean)} method.
* @param colorNew (String) - color of new category. Can be one of: "red", "orange", "yellow",
* "lightgreen", "green", "lightblue", "blue", "purple", "pink", "brown".
* @param visibleNew (boolean) - should new category be visible after creation.
*/
boolean removeFavorite(in RemoveFavoriteParams params);
/**
* Remove favorite at given location with given params.
*
* @param lat (double) - latitude.
* @param lon (double) - longitude.
* @param name (String) - name of favorite item.
* @param category (String) - category of favorite item.
*/
boolean updateFavorite(in UpdateFavoriteParams params);
/**
* Start gpx recording.
*/
boolean startGpxRecording(in StartGpxRecordingParams params);
/**
* Stop gpx recording.
*/
boolean stopGpxRecording(in StopGpxRecordingParams params);
/**
* Take photo note.
*
* @param lat (double) - latutude of photo note.
* @param lon (double) - longitude of photo note.
*/
boolean takePhotoNote(in TakePhotoNoteParams params);
/**
* Start video note recording.
*
* @param lat (double) - latutude of video note point.
* @param lon (double) - longitude of video note point.
*/
boolean startVideoRecording(in StartVideoRecordingParams params);
/**
* Start audio note recording.
*
* @param lat (double) - latutude of audio note point.
* @param lon (double) - longitude of audio note point.
*/
boolean startAudioRecording(in StartAudioRecordingParams params);
/**
* Stop Audio/Video recording.
*/
boolean stopRecording(in StopRecordingParams params);
/**
* Start navigation.
*
* @param startName (String) - name of the start point as it displays in OsmAnd's UI. Nullable.
* @param startLat (double) - latitude of the start point. If 0 - current location is used.
* @param startLon (double) - longitude of the start point. If 0 - current location is used.
* @param destName (String) - name of the start point as it displays in OsmAnd's UI.
* @param destLat (double) - latitude of a destination point.
* @param destLon (double) - longitude of a destination point.
* @param profile (String) - One of: "default", "car", "bicycle", "pedestrian", "aircraft", "boat", "hiking", "motorcycle", "truck". Nullable (default).
* @param force (boolean) - ask to stop current navigation if any. False - ask. True - don't ask.
*/
boolean navigate(in NavigateParams params);
/**
* Start navigation using gpx file. User need to grant Uri permission to OsmAnd.
*
* @param gpxUri (Uri) - URI created by FileProvider.
* @param force (boolean) - ask to stop current navigation if any. False - ask. True - don't ask.
*/
boolean navigateGpx(in NavigateGpxParams params);
/**
* Remove GPX file.
*
* @param fileName (String) - file name to remove;
*/
boolean removeGpx(in RemoveGpxParams params);
/**
* Show AMapPoint on map in OsmAnd.
*
* @param layerId (String) - layer id. Note: layer should be added first.
* @param pointId (String) - point id.
* @param shortName (String) - short name (single char). Displayed on the map.
* @param fullName (String) - full name. Displayed in the context menu on first row.
* @param typeName (String) - type name. Displayed in context menu on second row.
* @param color (int) - color of circle's background.
* @param location (ALatLon) - location of the point.
* @param details List<String> - list of details. Displayed under context menu.
* @param params Map<String, String> - optional map of params for point.
*/
boolean showMapPoint(in ShowMapPointParams params);
/**
* Method for adding up to 3 items to the OsmAnd navigation drawer.
*
* @param appPackage - current application package.
* @param names - list of names for items.
* @param uris - list of uris for intents.
* @param iconNames - list of icon names for items.
* @param flags - list of flags for intents. Use -1 if no flags needed.
*/
boolean setNavDrawerItems(in SetNavDrawerItemsParams params);
/**
* Put navigation on pause.
*/
boolean pauseNavigation(in PauseNavigationParams params);
/**
* Resume navigation if it was paused before.
*/
boolean resumeNavigation(in ResumeNavigationParams params);
/**
* Stop navigation. Removes target / intermediate points and route path from the map.
*/
boolean stopNavigation(in StopNavigationParams params);
/**
* Mute voice guidance. Stays muted until unmute manually or via the api.
*/
boolean muteNavigation(in MuteNavigationParams params);
/**
* Unmute voice guidance.
*/
boolean unmuteNavigation(in UnmuteNavigationParams params);
/**
* Run search for POI / Address.
*
* @param searchQuery (String) - search query string.
* @param searchType (int) - type of search. Values:
* SearchParams.SEARCH_TYPE_ALL - all kind of search
* SearchParams.SEARCH_TYPE_POI - POIs only
* SearchParams.SEARCH_TYPE_ADDRESS - addresses only
*
* @param latitude (double) - latitude of original search location.
* @param longitude (double) - longitude of original search location.
* @param radiusLevel (int) - value from 1 to 7. Default value = 1.
* @param totalLimit (int) - limit of returned search result rows. Default value = -1 (unlimited).
*/
boolean search(in SearchParams params, IOsmAndAidlCallback callback);
/**
* Do search and start navigation.
*
* @param startName (String) - name of the start point as it displays in OsmAnd's UI. Nullable.
* @param startLat (double) - latitude of the start point. If 0 - current location is used.
* @param startLon (double) - longitude of the start point. If 0 - current location is used.
* @param searchQuery (String) - Text of a query for searching a destination point. Sent as URI parameter.
* @param searchLat (double) - original location of search (latitude). Sent as URI parameter.
* @param searchLon (double) - original location of search (longitude). Sent as URI parameter.
* @param profile (String) - one of: "default", "car", "bicycle", "pedestrian", "aircraft", "boat", "hiking", "motorcycle", "truck". Nullable (default).
* @param force (boolean) - ask to stop current navigation if any. False - ask. True - don't ask.
*/
boolean navigateSearch(in NavigateSearchParams params);
/**
* Method to register for periodical callbacks from OsmAnd
*
* @param updateTimeMS (long)- period of time in millisecond after which callback is triggered
* @param callback (IOsmAndCallback)- create and provide instance of {@link IOsmAndAidlCallback} interface
* @return id (long) - id of callback in OsmAnd. Needed to unsubscribe from updates.
*/
long registerForUpdates(in long updateTimeMS, IOsmAndAidlCallback callback);
/**
* Method to unregister from periodical callbacks from OsmAnd
*
* @param callbackId (long)- id of registered callback (provided by OsmAnd
* in {@link OsmAndAidlHelper#registerForUpdates(long, IOsmAndAidlCallback)})
*/
boolean unregisterFromUpdates(in long callbackId);
/**
* Method for adding image to the top of Osmand's NavDrawer.
*
* @param imageUri (String)- image's URI.toString
*
* @deprecated
* Use the {@link #setNavDrawerLogoWithParams(NavDrawerHeaderParams params)} method.
*/
boolean setNavDrawerLogo(in String imageUri);
/**
* Method for selected UI elements (like QuickSearch button) to show.
*
* @param ids (List<String>)- list of menu items keys from {@link OsmAndCustomizationConstants}
*/
boolean setEnabledIds(in List<String> ids);
/**
* Method for selected UI elements (like QuickSearch button) to hide.
*
* @param ids (List<String>)- list of menu items keys from {@link OsmAndCustomizationConstants}
*/
boolean setDisabledIds(in List<String> ids);
/**
* Method to show selected NavDrawer's menu items.
*
* @param patterns (List<String>) - list of menu items names from {@link OsmAndCustomizationConstants}
*/
boolean setEnabledPatterns(in List<String> patterns);
/**
* Method to hide selected NavDrawer's menu items.
*
* @param patterns (List<String>)- list of menu items names from {@link OsmAndCustomizationConstants}
*/
boolean setDisabledPatterns(in List<String> patterns);
/**
* Register OsmAnd widgets for visibility.
*
* @param widgetKey ()- widget id.
* @param appModKeys - list of OsmAnd Application modes widget active with. Could be "null" for all modes.
*/
boolean regWidgetVisibility(in SetWidgetsParams params);
/**
* Register OsmAnd widgets for availability.
*
* @param widgetKey (String) - widget id.
* @param appModKeys (List<String>)- ist of OsmAnd Application modes widget active with. Could be "null" for all modes.
*/
boolean regWidgetAvailability(in SetWidgetsParams params);
/**
* Add custom parameters for OsmAnd settings to associate with client app.
*
* @param sharedPreferencesName (String)- string with name of clint's app for shared preferences key
* @param bundle (Bundle)- bundle with keys from Settings IDs {@link OsmAndCustomizationConstants} and Settings params
*/
boolean customizeOsmandSettings(in OsmandSettingsParams params);
/**
* Method to get list of gpx files currently registered (imported or created) in OsmAnd;
*
* @return list of gpx files
*/
boolean getImportedGpx(out List<AGpxFile> files);
/**
* Method to get list of sqlitedb files registered in OsmAnd;
*
* @return list of sqlitedb files
*/
boolean getSqliteDbFiles(out List<ASqliteDbFile> files);
/**
* Method to get list of currently active sqlitedb files
*
* @return list of sqlitedb files
*/
boolean getActiveSqliteDbFiles(out List<ASqliteDbFile> files);
/**
* Method to show selected sqlitedb file as map overlay.
*
* @param fileName (String) - name of sqlitedb file
*/
boolean showSqliteDbFile(String fileName);
/**
* Method to hide sqlitedb file from map overlay.
*
* @param fileName (String) - name of sqlitedb file
*/
boolean hideSqliteDbFile(String fileName);
/**
* Method for adding image to the top of OsmAnd's NavDrawer with additional params
*
* @param imageUri (String) - image's URI.toString
* @param packageName (String) - client's app package name
* @param intent (String) - intent for additional functionality on image click
*
*/
boolean setNavDrawerLogoWithParams(in NavDrawerHeaderParams params);
/**
* Method for adding functionality to "Powered by Osmand" logo in NavDrawer's footer
* (reset OsmAnd settings to pre-clinet app's state)
*
* @param packageName (String) - package name
* @param intent (String) - intent
* @param appName (String) - client's app name
*/
boolean setNavDrawerFooterWithParams(in NavDrawerFooterParams params);
/**
* Restore default (pre-client) OsmAnd settings and state:
* clears features, widgets and settings customization, NavDraw logo.
*/
boolean restoreOsmand();
/**
* Method to change state of plug-ins in OsmAnd.
*
* @param pluginId (String) - id (name) of plugin.
* @param newState (int) - new state (0 - off, 1 - on).
*/
boolean changePluginState(in PluginParams params);
/**
* Method to register for callback on OsmAnd initialization
* @param callback (IOsmAndAidlCallback) - create and provide instance of {@link IOsmAndAidlCallback} interface
*/
boolean registerForOsmandInitListener(in IOsmAndAidlCallback callback);
/**
* Requests bitmap snap-shot of map with GPX file from provided URI in its center.
* You can set bitmap size, density and GPX lines color, but you need
* to manually download appropriate map in OsmAnd or background will be empty.
* Bitmap will be returned through callback {@link IOsmAndAidlCallback#onGpxBitmapCreated(AGpxBitmap)}
*
* @param gpxUri (Uri/File) - Uri for gpx file
* @param density (float) - image density. Recommended to use default metrics for device's display.
* @param widthPixels (int) - width of bitmap
* @param heightPixels (int) - height of bitmap
* @param color (int) - color in ARGB format
* @param callback (IOsmAndAidlCallback) - instance of callback from OsmAnd.
*/
boolean getBitmapForGpx(in CreateGpxBitmapParams file, IOsmAndAidlCallback callback);
/**
* Method to copy files to OsmAnd part by part. For now supports only sqlitedb format.
* Part size (bytearray) should not exceed 256k.
*
* @param fileName (String) - name of file
* @param filePartData (byte[]) - parts of file, byte[] with size 256k or less.
* @param startTime (long) - timestamp of copying start.
* @param isDone (boolean) - boolean to mark end of copying.
* @return number of last successfully received file part or error(-1).
*/
int copyFile(in CopyFileParams filePart);
/**
* Method to register for updates during navgation. Notifies user about distance to the next turn and its type.
*
* @params subscribeToUpdates (boolean) - boolean flag to subscribe or unsubscribe from updates
* @params callbackId (long) - id of callback, needed to unsubscribe from updates
* @params callback (IOsmAndAidlCallback) - callback to notify user on navigation data change
*/
long registerForNavigationUpdates(in ANavigationUpdateParams params, IOsmAndAidlCallback callback);
long addContextMenuButtons(in ContextMenuButtonsParams params, IOsmAndAidlCallback callback);
boolean removeContextMenuButtons(in RemoveContextMenuButtonsParams params);
boolean updateContextMenuButtons(in UpdateContextMenuButtonsParams params);
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable AContextMenuButton;

View file

@ -0,0 +1,101 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
public class AContextMenuButton implements Parcelable {
private int buttonId;
private String leftTextCaption;
private String rightTextCaption;
private String leftIconName;
private String rightIconName;
private boolean needColorizeIcon;
private boolean enabled;
public AContextMenuButton(int buttonId, String leftTextCaption, String rightTextCaption, String leftIconName, String rightIconName, boolean needColorizeIcon, boolean enabled) {
this.buttonId = buttonId;
this.leftTextCaption = leftTextCaption;
this.rightTextCaption = rightTextCaption;
this.leftIconName = leftIconName;
this.rightIconName = rightIconName;
this.needColorizeIcon = needColorizeIcon;
this.enabled = enabled;
}
protected AContextMenuButton(Parcel in) {
readFromParcel(in);
}
public static final Creator<AContextMenuButton> CREATOR = new Creator<AContextMenuButton>() {
@Override
public AContextMenuButton createFromParcel(Parcel in) {
return new AContextMenuButton(in);
}
@Override
public AContextMenuButton[] newArray(int size) {
return new AContextMenuButton[size];
}
};
public int getButtonId() {
return buttonId;
}
public String getLeftTextCaption() {
return leftTextCaption;
}
public String getRightTextCaption() {
return rightTextCaption;
}
public String getLeftIconName() {
return leftIconName;
}
public String getRightIconName() {
return rightIconName;
}
public boolean isNeedColorizeIcon() {
return needColorizeIcon;
}
public boolean isEnabled() {
return enabled;
}
public static Creator<AContextMenuButton> getCREATOR() {
return CREATOR;
}
@Override
public void writeToParcel(Parcel dest, int f) {
dest.writeInt(buttonId);
dest.writeString(leftTextCaption);
dest.writeString(rightTextCaption);
dest.writeString(leftIconName);
dest.writeString(rightIconName);
dest.writeInt(needColorizeIcon ? 1 : 0);
dest.writeInt(enabled ? 1 : 0);
}
private void readFromParcel(Parcel in) {
buttonId = in.readInt();
leftTextCaption = in.readString();
rightTextCaption = in.readString();
leftIconName = in.readString();
rightIconName = in.readString();
needColorizeIcon = in.readInt() != 0;
enabled = in.readInt() != 0;
}
@Override
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable ContextMenuButtonsParams;

View file

@ -0,0 +1,105 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
public class ContextMenuButtonsParams implements Parcelable {
private AContextMenuButton leftButton;
private AContextMenuButton rightButton;
private String id;
private String appPackage;
private String layerId;
private long callbackId = -1L;
private List<String> pointsIds = new ArrayList<>();
public ContextMenuButtonsParams(AContextMenuButton leftButton, AContextMenuButton rightButton, String id, String appPackage, String layerId, boolean followOpenedPoint, long callbackId, List<String> pointsIds) {
this.leftButton = leftButton;
this.rightButton = rightButton;
this.id = id;
this.appPackage = appPackage;
this.layerId = layerId;
this.callbackId = callbackId;
this.pointsIds = pointsIds;
}
public ContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<ContextMenuButtonsParams> CREATOR = new Creator<ContextMenuButtonsParams>() {
@Override
public ContextMenuButtonsParams createFromParcel(Parcel in) {
return new ContextMenuButtonsParams(in);
}
@Override
public ContextMenuButtonsParams[] newArray(int size) {
return new ContextMenuButtonsParams[size];
}
};
public AContextMenuButton getLeftButton() {
return leftButton;
}
public AContextMenuButton getRightButton() {
return rightButton;
}
public String getId() {
return id;
}
public String getAppPackage() {
return appPackage;
}
public String getLayerId() {
return layerId;
}
public long getCallbackId() {
return callbackId;
}
public void setCallbackId(long callbackId) {
this.callbackId = callbackId;
}
public List<String> getPointsIds() {
return pointsIds;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(leftButton, flags);
dest.writeParcelable(rightButton, flags);
dest.writeString(id);
dest.writeString(appPackage);
dest.writeString(layerId);
dest.writeLong(callbackId);
dest.writeStringList(pointsIds);
}
private void readFromParcel(Parcel in) {
leftButton = in.readParcelable(AContextMenuButton.class.getClassLoader());
rightButton = in.readParcelable(AContextMenuButton.class.getClassLoader());
id = in.readString();
appPackage = in.readString();
layerId = in.readString();
callbackId = in.readLong();
in.readStringList(pointsIds);
}
@Override
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable RemoveContextMenuButtonsParams;

View file

@ -0,0 +1,53 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
public class RemoveContextMenuButtonsParams implements Parcelable {
private String paramsId;
private long callbackId = -1L;
public RemoveContextMenuButtonsParams(String paramsId, long callbackId) {
this.paramsId = paramsId;
this.callbackId = callbackId;
}
public RemoveContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<RemoveContextMenuButtonsParams> CREATOR = new
Creator<RemoveContextMenuButtonsParams>() {
public RemoveContextMenuButtonsParams createFromParcel(Parcel in) {
return new RemoveContextMenuButtonsParams(in);
}
public RemoveContextMenuButtonsParams[] newArray(int size) {
return new RemoveContextMenuButtonsParams[size];
}
};
public String getParamsId() {
return paramsId;
}
public long getCallbackId() {
return callbackId;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(paramsId);
dest.writeLong(callbackId);
}
private void readFromParcel(Parcel in) {
paramsId = in.readString();
callbackId = in.readLong();
}
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable UpdateContextMenuButtonsParams;

View file

@ -0,0 +1,43 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
public class UpdateContextMenuButtonsParams implements Parcelable {
private ContextMenuButtonsParams buttonsParams;
public UpdateContextMenuButtonsParams(ContextMenuButtonsParams widget) {
this.buttonsParams = widget;
}
public UpdateContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<UpdateContextMenuButtonsParams> CREATOR = new
Creator<UpdateContextMenuButtonsParams>() {
public UpdateContextMenuButtonsParams createFromParcel(Parcel in) {
return new UpdateContextMenuButtonsParams(in);
}
public UpdateContextMenuButtonsParams[] newArray(int size) {
return new UpdateContextMenuButtonsParams[size];
}
};
public ContextMenuButtonsParams getContextMenuButtonsParams() {
return buttonsParams;
}
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(buttonsParams, flags);
}
private void readFromParcel(Parcel in) {
buttonsParams = in.readParcelable(ContextMenuButtonsParams.class.getClassLoader());
}
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.copyfile;
parcelable CopyFileParams;

View file

@ -0,0 +1,78 @@
package net.osmand.aidl.copyfile;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
public class CopyFileParams implements Parcelable {
private String fileName;
private byte[] filePartData;
private long startTime;
private boolean done;
public CopyFileParams(@NonNull String fileName, @NonNull byte[] filePartData, long startTime, boolean done) {
this.fileName = fileName;
this.filePartData = filePartData;
this.startTime = startTime;
this.done = done;
}
public String getFileName() {
return fileName;
}
public byte[] getFilePartData() {
return filePartData;
}
public boolean isDone() {
return done;
}
public long getStartTime() {
return startTime;
}
protected CopyFileParams(Parcel in) {
fileName = in.readString();
filePartData = in.createByteArray();
startTime = in.readLong();
done = in.readByte() == 0;
}
public static final Creator<CopyFileParams> CREATOR = new Creator<CopyFileParams>() {
@Override
public CopyFileParams createFromParcel(Parcel in) {
return new CopyFileParams(in);
}
@Override
public CopyFileParams[] newArray(int size) {
return new CopyFileParams[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
return "CopyFileParams {" +
" fileName=" + fileName +
", filePartData size=" + filePartData.length +
", startTime=" + startTime +
", done=" + done +
" }";
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(fileName);
dest.writeByteArray(filePartData);
dest.writeLong(startTime);
dest.writeByte((byte) (done ? 0 : 1));
}
}

View file

@ -21,10 +21,6 @@ public class AGpxBitmap implements Parcelable {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public static final Creator<AGpxBitmap> CREATOR = new
Creator<AGpxBitmap>() {
public AGpxBitmap createFromParcel(Parcel in) {

View file

@ -2,15 +2,27 @@ package net.osmand.aidl.gpx;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
public class ASelectedGpxFile implements Parcelable {
private String fileName;
private long modifiedTime;
private long fileSize;
private AGpxFileDetails details;
public ASelectedGpxFile(String fileName) {
public ASelectedGpxFile(@NonNull String fileName) {
this.fileName = fileName;
}
public ASelectedGpxFile(@NonNull String fileName, long modifiedTime, long fileSize, @Nullable AGpxFileDetails details) {
this.fileName = fileName;
this.modifiedTime = modifiedTime;
this.fileSize = fileSize;
this.details = details;
}
public ASelectedGpxFile(Parcel in) {
readFromParcel(in);
}
@ -30,12 +42,40 @@ public class ASelectedGpxFile implements Parcelable {
return fileName;
}
public long getModifiedTime() {
return modifiedTime;
}
public long getFileSize() {
return fileSize;
}
public AGpxFileDetails getDetails() {
return details;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(fileName);
out.writeLong(modifiedTime);
out.writeLong(fileSize);
out.writeByte((byte) (details != null ? 1 : 0));
if (details != null) {
out.writeParcelable(details, flags);
}
}
private void readFromParcel(Parcel in) {
fileName = in.readString();
modifiedTime = in.readLong();
fileSize = in.readLong();
boolean hasDetails= in.readByte() != 0;
if (hasDetails) {
details = in.readParcelable(AGpxFileDetails.class.getClassLoader());
} else {
details = null;
}
}
public int describeContents() {

View file

@ -66,6 +66,10 @@ public class AMapLayer implements Parcelable {
return new ArrayList<>(points.values());
}
public AMapPoint getPoint(String pointId) {
return points.get(pointId);
}
public boolean hasPoint(String pointId) {
return points.containsKey(pointId);
}

View file

@ -11,25 +11,28 @@ import java.util.List;
import java.util.Map;
public class AMapPoint implements Parcelable {
public static final int POINT_IMAGE_SIZE_PX = 160;
public static final String POINT_IMAGE_URI_PARAM = "point_image_uri_param";
public static final String POINT_SPEED_PARAM = "point_speed_param";
public static final String POINT_TYPE_ICON_NAME_PARAM = "point_type_icon_name_param";
public static final String POINT_STALE_LOC_PARAM = "point_stale_loc_param";
private String id;
private String shortName;
private String fullName;
private String typeName;
private String layerId;
private int color;
private ALatLon location;
private List<String> details = new ArrayList<>();
private Map<String, String> params = new HashMap<>();
public AMapPoint(String id, String shortName, String fullName, String typeName, int color,
ALatLon location, List<String> details, Map<String, String> params) {
public AMapPoint(String id, String shortName, String fullName, String typeName, String layerId,
int color, ALatLon location, List<String> details, Map<String, String> params) {
this.id = id;
this.shortName = shortName;
this.fullName = fullName;
this.typeName = typeName;
this.layerId = layerId;
this.color = color;
this.location = location;
if (details != null) {
@ -71,6 +74,10 @@ public class AMapPoint implements Parcelable {
return typeName;
}
public String getLayerId() {
return layerId;
}
public int getColor() {
return color;
}
@ -92,6 +99,7 @@ public class AMapPoint implements Parcelable {
out.writeString(shortName);
out.writeString(fullName);
out.writeString(typeName);
out.writeString(layerId);
out.writeInt(color);
out.writeParcelable(location, flags);
out.writeStringList(details);
@ -103,6 +111,7 @@ public class AMapPoint implements Parcelable {
shortName = in.readString();
fullName = in.readString();
typeName = in.readString();
layerId = in.readString();
color = in.readInt();
location = in.readParcelable(ALatLon.class.getClassLoader());
in.readStringList(details);

View file

@ -6,10 +6,12 @@ import android.os.Parcelable;
public class UpdateMapPointParams implements Parcelable {
private String layerId;
private AMapPoint point;
private boolean updateOpenedMenuAndMap;
public UpdateMapPointParams(String layerId, AMapPoint point) {
public UpdateMapPointParams(String layerId, AMapPoint point, boolean updateOpenedMenuAndMap) {
this.layerId = layerId;
this.point = point;
this.updateOpenedMenuAndMap = updateOpenedMenuAndMap;
}
public UpdateMapPointParams(Parcel in) {
@ -35,14 +37,20 @@ public class UpdateMapPointParams implements Parcelable {
return point;
}
public boolean isUpdateOpenedMenuAndMap() {
return updateOpenedMenuAndMap;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(layerId);
out.writeParcelable(point, flags);
out.writeInt(updateOpenedMenuAndMap ? 1 : 0);
}
private void readFromParcel(Parcel in) {
layerId = in.readString();
point = in.readParcelable(AMapPoint.class.getClassLoader());
updateOpenedMenuAndMap = in.readInt() != 0;
}
public int describeContents() {

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.navigation;
parcelable ADirectionInfo;

View file

@ -0,0 +1,73 @@
package net.osmand.aidl.navigation;
import android.os.Parcel;
import android.os.Parcelable;
public class ADirectionInfo implements Parcelable {
private int distanceTo; //distance to next turn
private int turnType; //turn type
private boolean isLeftSide; //is movement left-sided
public ADirectionInfo(int distanceTo, int turnType, boolean isLeftSide) {
this.distanceTo = distanceTo;
this.turnType = turnType;
this.isLeftSide = isLeftSide;
}
protected ADirectionInfo(Parcel in) {
distanceTo = in.readInt();
turnType = in.readInt();
isLeftSide = in.readByte() != 0;
}
public static final Creator<ADirectionInfo> CREATOR = new Creator<ADirectionInfo>() {
@Override
public ADirectionInfo createFromParcel(Parcel in) {
return new ADirectionInfo(in);
}
@Override
public ADirectionInfo[] newArray(int size) {
return new ADirectionInfo[size];
}
};
public int getDistanceTo() {
return distanceTo;
}
public int getTurnType() {
return turnType;
}
public boolean isLeftSide() {
return isLeftSide;
}
public void setDistanceTo(int distanceTo) {
this.distanceTo = distanceTo;
}
public void setTurnType(int turnType) {
this.turnType = turnType;
}
public void setLeftSide(boolean leftSide) {
isLeftSide = leftSide;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(distanceTo);
dest.writeInt(turnType);
dest.writeByte((byte) (isLeftSide ? 1 : 0));
}
}

View file

@ -0,0 +1,4 @@
package net.osmand.aidl.navigation;
parcelable ANavigationUpdateParams;

View file

@ -0,0 +1,57 @@
package net.osmand.aidl.navigation;
import android.os.Parcel;
import android.os.Parcelable;
public class ANavigationUpdateParams implements Parcelable {
private boolean subscribeToUpdates = true;
private long callbackId = -1L;
public ANavigationUpdateParams() {
}
public long getCallbackId() {
return callbackId;
}
public void setCallbackId(long callbackId) {
this.callbackId = callbackId;
}
public void setSubscribeToUpdates(boolean subscribeToUpdates) {
this.subscribeToUpdates = subscribeToUpdates;
}
public boolean isSubscribeToUpdates() {
return subscribeToUpdates;
}
protected ANavigationUpdateParams(Parcel in) {
callbackId = in.readLong();
subscribeToUpdates = in.readByte() != 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(callbackId);
dest.writeByte((byte) (subscribeToUpdates ? 1 : 0));
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<ANavigationUpdateParams> CREATOR = new Creator<ANavigationUpdateParams>() {
@Override
public ANavigationUpdateParams createFromParcel(Parcel in) {
return new ANavigationUpdateParams(in);
}
@Override
public ANavigationUpdateParams[] newArray(int size) {
return new ANavigationUpdateParams[size];
}
};
}

View file

@ -9,14 +9,20 @@ public class NavigateSearchParams implements Parcelable {
private double startLat;
private double startLon;
private String searchQuery;
private double searchLat;
private double searchLon;
private String profile;
private boolean force;
public NavigateSearchParams(String startName, double startLat, double startLon, String searchQuery, String profile, boolean force) {
public NavigateSearchParams(String startName, double startLat, double startLon,
String searchQuery, double searchLat, double searchLon,
String profile, boolean force) {
this.startName = startName;
this.startLat = startLat;
this.startLon = startLon;
this.searchQuery = searchQuery;
this.searchLat = searchLat;
this.searchLon = searchLon;
this.profile = profile;
this.force = force;
}
@ -53,6 +59,14 @@ public class NavigateSearchParams implements Parcelable {
return searchQuery;
}
public double getSearchLat() {
return searchLat;
}
public double getSearchLon() {
return searchLon;
}
public String getProfile() {
return profile;
}
@ -69,6 +83,8 @@ public class NavigateSearchParams implements Parcelable {
out.writeString(searchQuery);
out.writeString(profile);
out.writeByte((byte) (force ? 1 : 0));
out.writeDouble(searchLat);
out.writeDouble(searchLon);
}
private void readFromParcel(Parcel in) {
@ -78,6 +94,8 @@ public class NavigateSearchParams implements Parcelable {
searchQuery = in.readString();
profile = in.readString();
force = in.readByte() != 0;
searchLat = in.readDouble();
searchLon = in.readDouble();
}
@Override

View file

@ -11,15 +11,15 @@ public class SearchParams implements Parcelable {
private String searchQuery;
private int searchType;
private double latutude;
private double latitude;
private double longitude;
private int radiusLevel = 1;
private int totalLimit = -1;
public SearchParams(String searchQuery, int searchType, double latutude, double longitude, int radiusLevel, int totalLimit) {
public SearchParams(String searchQuery, int searchType, double latitude, double longitude, int radiusLevel, int totalLimit) {
this.searchQuery = searchQuery;
this.searchType = searchType;
this.latutude = latutude;
this.latitude = latitude;
this.longitude = longitude;
this.radiusLevel = radiusLevel;
this.totalLimit = totalLimit;
@ -49,8 +49,8 @@ public class SearchParams implements Parcelable {
return searchType;
}
public double getLatutude() {
return latutude;
public double getLatitude() {
return latitude;
}
public double getLongitude() {
@ -69,7 +69,7 @@ public class SearchParams implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeString(searchQuery);
out.writeInt(searchType);
out.writeDouble(latutude);
out.writeDouble(latitude);
out.writeDouble(longitude);
out.writeInt(radiusLevel);
out.writeInt(totalLimit);
@ -78,7 +78,7 @@ public class SearchParams implements Parcelable {
private void readFromParcel(Parcel in) {
searchQuery = in.readString();
searchType = in.readInt();
latutude = in.readDouble();
latitude = in.readDouble();
longitude = in.readDouble();
radiusLevel = in.readInt();
totalLimit = in.readInt();

View file

@ -52,6 +52,7 @@ class TelegramApplication : Application(), OsmandHelperListener {
listOf("ic_action_location_sharing_app"),
listOf(-1)
)
showLocationHelper.addDirectionContextMenuButton()
if (settings.hasAnyChatToShowOnMap()) {
showLocationHelper.startShowingLocation()
}
@ -138,7 +139,10 @@ class TelegramApplication : Application(), OsmandHelperListener {
}
override fun onOsmandConnectionStateChanged(connected: Boolean) {
showLocationHelper.setupMapLayer()
if (connected) {
showLocationHelper.setupMapLayer()
showLocationHelper.addDirectionContextMenuButton()
}
}
private fun startTelegramService(intent: Int, serviceOffInterval: Long = 0) {

View file

@ -85,6 +85,9 @@ private const val MONITORING_ENABLED = "monitoring_enabled"
private const val SHOW_GPS_POINTS = "show_gps_points"
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
@ -103,6 +106,9 @@ class TelegramSettings(private val app: TelegramApplication) {
var currentSharingMode = ""
private set
var currentProxyPref: ProxyPref = ProxySOCKS5Pref(-1, "", -1, "", "")
private set
var metricsConstants = MetricsConstants.KILOMETERS_AND_METERS
var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR
@ -124,9 +130,12 @@ class TelegramSettings(private val app: TelegramApplication) {
var showGpsPoints = false
var proxyEnabled = false
init {
updatePrefs()
read()
applyProxyPref()
}
fun hasAnyChatToShareLocation() = shareChatsInfo.isNotEmpty()
@ -202,6 +211,30 @@ class TelegramSettings(private val app: TelegramApplication) {
currentSharingMode = sharingMode
}
fun updateCurrentProxyPref(proxyPref: ProxyPref, proxyEnabled: Boolean) {
this.proxyEnabled = proxyEnabled
currentProxyPref = proxyPref
applyProxyPref()
}
fun updateProxySetting(enable: Boolean) {
this.proxyEnabled = enable
if (enable) {
app.telegramHelper.enableProxy(currentProxyPref.id)
} else {
app.telegramHelper.disableProxy()
}
}
fun applyProxyPref() {
val proxyId = currentProxyPref.id
if (proxyId != -1) {
app.telegramHelper.editProxyPref(currentProxyPref, proxyEnabled)
} else {
app.telegramHelper.addProxyPref(currentProxyPref, proxyEnabled)
}
}
fun prepareForSharingNewMessages() {
shareChatsInfo.forEach { (_, shareInfo) ->
prepareForSharingNewMessages(shareInfo)
@ -536,6 +569,8 @@ class TelegramSettings(private val app: TelegramApplication) {
edit.putBoolean(SHOW_GPS_POINTS, showGpsPoints)
edit.putBoolean(PROXY_ENABLED, proxyEnabled)
val jArray = convertShareChatsInfoToJson()
if (jArray != null) {
edit.putString(SHARE_CHATS_INFO_KEY, jArray.toString())
@ -546,6 +581,11 @@ class TelegramSettings(private val app: TelegramApplication) {
edit.putString(SHARE_DEVICES_KEY, jsonObject.toString())
}
val jsonObjectProxy = convertProxyPrefToJson()
if (jsonObjectProxy != null) {
edit.putString(PROXY_PREFERENCES_KEY, jsonObjectProxy.toString())
}
edit.apply()
}
@ -597,7 +637,14 @@ class TelegramSettings(private val app: TelegramApplication) {
monitoringEnabled = prefs.getBoolean(MONITORING_ENABLED,false)
showGpsPoints = prefs.getBoolean(SHOW_GPS_POINTS,false)
showGpsPoints = prefs.getBoolean(SHOW_GPS_POINTS, false)
proxyEnabled = prefs.getBoolean(PROXY_ENABLED, false)
try {
parseProxyPreferences(JSONObject(prefs.getString(PROXY_PREFERENCES_KEY, "")))
} catch (e: JSONException) {
e.printStackTrace()
}
}
private fun convertShareDevicesToJson():JSONObject?{
@ -621,6 +668,27 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
private fun convertProxyPrefToJson(): JSONObject? {
return try {
val proxyPref = currentProxyPref
JSONObject().apply {
put(ProxyPref.PROXY_ID, proxyPref.id)
put(ProxyPref.TYPE_ID, proxyPref.type)
put(ProxyPref.SERVER_ID, proxyPref.server)
put(ProxyPref.PORT_ID, proxyPref.port)
if (proxyPref is ProxyMTProtoPref) {
put(ProxyMTProtoPref.KEY_ID, proxyPref.key)
} else if (proxyPref is ProxySOCKS5Pref) {
put(ProxySOCKS5Pref.LOGIN_ID, proxyPref.login)
put(ProxySOCKS5Pref.PASSWORD_ID, proxyPref.password)
}
}
} catch (e: JSONException) {
e.printStackTrace()
null
}
}
private fun convertShareChatsInfoToJson(): JSONArray? {
return try {
val jArray = JSONArray()
@ -678,6 +746,28 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
private fun parseProxyPreferences(jsonObject: JSONObject) {
val proxyId = jsonObject.optInt(ProxyPref.PROXY_ID)
val typeString = jsonObject.optString(ProxyPref.TYPE_ID)
val server = jsonObject.optString(ProxyPref.SERVER_ID)
val port = jsonObject.optInt(ProxyPref.PORT_ID)
val proxyPref = when {
ProxyType.valueOf(typeString) == ProxyType.MTPROTO -> {
val key = jsonObject.optString(ProxyMTProtoPref.KEY_ID)
ProxyMTProtoPref(proxyId, server, port, key)
}
ProxyType.valueOf(typeString) == ProxyType.SOCKS5 -> {
val login = jsonObject.optString(ProxySOCKS5Pref.LOGIN_ID)
val password = jsonObject.optString(ProxySOCKS5Pref.PASSWORD_ID)
ProxySOCKS5Pref(proxyId, server, port, login, password)
}
else -> null
}
if (proxyPref != null) {
currentProxyPref = proxyPref
}
}
private fun parseShareDevices(json: String) {
shareDevices = OsmandApiUtils.parseJsonContents(json).toHashSet()
}
@ -926,6 +1016,45 @@ class TelegramSettings(private val app: TelegramApplication) {
}
}
enum class ProxyType {
MTPROTO, SOCKS5
}
abstract class ProxyPref(
var id: Int,
var type: ProxyType,
open var server: String,
open var port: Int
) {
companion object {
internal const val PROXY_ID = "proxyId"
internal const val TYPE_ID = "type"
internal const val SERVER_ID = "serverId"
internal const val PORT_ID = "portId"
}
}
class ProxyMTProtoPref(id: Int, server: String, port: Int, var key: String) :
ProxyPref(id, ProxyType.MTPROTO, server, port) {
companion object {
internal const val KEY_ID = "key"
}
}
class ProxySOCKS5Pref(
id: Int,
server: String,
port: Int,
var login: String,
var password: String
) :
ProxyPref(id, ProxyType.SOCKS5, server, port) {
companion object {
internal const val LOGIN_ID = "login"
internal const val PASSWORD_ID = "password"
}
}
class SharingStatus {
var title: String = ""

View file

@ -9,6 +9,9 @@ import android.os.IBinder
import android.os.RemoteException
import net.osmand.aidl.IOsmAndAidlCallback
import net.osmand.aidl.IOsmAndAidlInterface
import net.osmand.aidl.contextmenu.AContextMenuButton
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams
import net.osmand.aidl.contextmenu.RemoveContextMenuButtonsParams
import net.osmand.aidl.favorite.AFavorite
import net.osmand.aidl.favorite.AddFavoriteParams
import net.osmand.aidl.favorite.RemoveFavoriteParams
@ -43,6 +46,7 @@ import net.osmand.aidl.note.TakePhotoNoteParams
import net.osmand.aidl.search.SearchParams
import net.osmand.aidl.search.SearchResult
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.ShowLocationHelper.Companion.MAP_LAYER_ID
import java.io.File
import java.util.*
@ -61,7 +65,8 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
private var initialized: Boolean = false
private var bound: Boolean = false
private var osmandCallbackId: Long = 0
private var osmandUpdatesCallbackId: Long = -1
private var osmandContextMenuCallbackId: Long = -1
var listener: OsmandHelperListener? = null
@ -81,6 +86,12 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
fun onGpxBitmapCreated(bitmap: AGpxBitmap)
}
private var contextMenuButtonsListener: ContextMenuButtonsListener? = null
interface ContextMenuButtonsListener {
fun onContextMenuButtonClicked(buttonId:Int, pointId: String, layerId: String)
}
private val mIOsmAndAidlCallback = object : IOsmAndAidlCallback.Stub() {
@Throws(RemoteException::class)
@ -106,6 +117,16 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
gpxBitmapCreatedListener!!.onGpxBitmapCreated(bitmap)
}
}
override fun updateNavigationInfo(directionInfo: ADirectionInfo?) {
}
override fun onContextMenuButtonClicked(buttonId:Int, pointId: String, layerId: String) {
if (contextMenuButtonsListener != null) {
contextMenuButtonsListener!!.onContextMenuButtonClicked(buttonId, pointId, layerId)
}
}
}
fun setSearchCompleteListener(mSearchCompleteListener: SearchCompleteListener) {
@ -116,6 +137,10 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
this.gpxBitmapCreatedListener = gpxBitmapCreatedListener
}
fun setContextMenuButtonsListener(contextMenuButtonsListener: ContextMenuButtonsListener) {
this.contextMenuButtonsListener = contextMenuButtonsListener
}
private var mUpdatesListener: UpdatesListener? = null
interface UpdatesListener {
@ -126,7 +151,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
this.mUpdatesListener = mUpdatesListener
}
fun updatesCallbackRegistered() = osmandCallbackId > 0
fun updatesCallbackRegistered() = osmandUpdatesCallbackId > 0
/**
* Class for interacting with the main interface of the service.
*/
@ -407,6 +432,22 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
/**
* Add map marker at given location.
*
* @param marker - AMapMarker.
*/
fun addMapMarker(marker: AMapMarker): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
return mIOsmAndAidlInterface!!.addMapMarker(AddMapMarkerParams(marker))
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
@ -432,6 +473,23 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
/**
* Update map marker at given location with name.
*
* @param markerPrev - AMapMarker (current marker).
* @param markerNew - AMapMarker (new marker).
*/
fun updateMapMarker(markerPrev: AMapMarker, markerNew: AMapMarker): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
return mIOsmAndAidlInterface!!.updateMapMarker(UpdateMapMarkerParams(markerPrev, markerNew))
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
@ -611,7 +669,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
typeName: String, color: Int, location: ALatLon, details: List<String>?, params: Map<String, String>?): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details, params)
val point = AMapPoint(pointId, shortName, fullName, typeName, layerId, color, location, details, params)
return mIOsmAndAidlInterface!!.showMapPoint(ShowMapPointParams(layerId, point))
} catch (e: RemoteException) {
e.printStackTrace()
@ -636,7 +694,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
typeName: String, color: Int, location: ALatLon, details: List<String>?, params: Map<String, String>?): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details, params)
val point = AMapPoint(pointId, shortName, fullName, typeName, layerId, color, location, details, params)
return mIOsmAndAidlInterface!!.addMapPoint(AddMapPointParams(layerId, point))
} catch (e: RemoteException) {
e.printStackTrace()
@ -662,8 +720,8 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
typeName: String, color: Int, location: ALatLon, details: List<String>?, params: Map<String, String>?): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details, params)
return mIOsmAndAidlInterface!!.updateMapPoint(UpdateMapPointParams(layerId, point))
val point = AMapPoint(pointId, shortName, fullName, typeName, layerId, color, location, details, params)
return mIOsmAndAidlInterface!!.updateMapPoint(UpdateMapPointParams(layerId, point, true))
} catch (e: RemoteException) {
e.printStackTrace()
}
@ -939,10 +997,10 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
return false
}
fun navigateSearch(startName: String, startLat: Double, startLon: Double, searchQuery: String, profile: String, force: Boolean): Boolean {
fun navigateSearch(startName: String, startLat: Double, startLon: Double, searchQuery: String, searchLat: Double, searchLon: Double, profile: String, force: Boolean): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
return mIOsmAndAidlInterface!!.navigateSearch(NavigateSearchParams(startName, startLat, startLon, searchQuery, profile, force))
return mIOsmAndAidlInterface!!.navigateSearch(NavigateSearchParams(startName, startLat, startLon, searchQuery, searchLat, searchLon, profile, force))
} catch (e: RemoteException) {
e.printStackTrace()
}
@ -1070,8 +1128,8 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
fun registerForUpdates(): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
osmandCallbackId = mIOsmAndAidlInterface!!.registerForUpdates(UPDATE_TIME_MS, mIOsmAndAidlCallback)
return osmandCallbackId > 0
osmandUpdatesCallbackId = mIOsmAndAidlInterface!!.registerForUpdates(UPDATE_TIME_MS, mIOsmAndAidlCallback)
return osmandUpdatesCallbackId > 0
} catch (e: RemoteException) {
e.printStackTrace()
}
@ -1082,9 +1140,9 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
fun unregisterFromUpdates(): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val unregistered = mIOsmAndAidlInterface!!.unregisterFromUpdates(osmandCallbackId)
val unregistered = mIOsmAndAidlInterface!!.unregisterFromUpdates(osmandUpdatesCallbackId)
if (unregistered) {
osmandCallbackId = 0
osmandUpdatesCallbackId = 0
}
return unregistered
} catch (e: RemoteException) {
@ -1105,4 +1163,39 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
}
return false
}
fun addContextMenuButtons(
appPackage: String,paramsId:String,
leftTextCaption: String, rightTextCaption: String,
leftIconName: String, rightIconName: String,
needColorizeIcon: Boolean, enabled: Boolean, buttonId: Int
): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val leftButton = AContextMenuButton(buttonId, leftTextCaption, rightTextCaption, leftIconName, rightIconName, needColorizeIcon, enabled)
val params = ContextMenuButtonsParams(leftButton, null, paramsId, appPackage, MAP_LAYER_ID, true, osmandContextMenuCallbackId, mutableListOf())
osmandContextMenuCallbackId = mIOsmAndAidlInterface!!.addContextMenuButtons(params, mIOsmAndAidlCallback)
return osmandContextMenuCallbackId >= 0
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
fun removeContextMenuButtons(paramsId: String): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val params = RemoveContextMenuButtonsParams(paramsId, osmandContextMenuCallbackId)
val removed = mIOsmAndAidlInterface!!.removeContextMenuButtons(params)
if (removed) {
osmandContextMenuCallbackId = -1
}
return removed
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
}

View file

@ -6,15 +6,19 @@ import android.os.AsyncTask
import android.text.TextUtils
import net.osmand.aidl.map.ALatLon
import net.osmand.aidl.maplayer.point.AMapPoint
import net.osmand.aidl.mapmarker.AMapMarker
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.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.telegram.utils.OsmandLocationUtils
import net.osmand.telegram.utils.OsmandLocationUtils.MessageOsmAndBotLocation
import net.osmand.telegram.utils.OsmandLocationUtils.MessageUserLocation
import org.drinkless.td.libcore.telegram.TdApi
import java.io.File
import java.util.*
import java.util.concurrent.Executors
class ShowLocationHelper(private val app: TelegramApplication) {
@ -23,23 +27,65 @@ class ShowLocationHelper(private val app: TelegramApplication) {
const val MAP_LAYER_ID = "telegram_layer"
const val MIN_OSMAND_CALLBACK_VERSION_CODE = 320
const val MAP_CONTEXT_MENU_BUTTON_ID = 1
const val MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID = "DIRECTION"
const val DIRECTION_ICON_ID = "ic_action_start_navigation"
}
private val telegramHelper = app.telegramHelper
private val osmandAidlHelper = app.osmandAidlHelper
private val executor = Executors.newSingleThreadExecutor()
private val points = mutableMapOf<String, TdApi.Message>()
private val markers = mutableMapOf<String, AMapMarker>()
var showingLocation: Boolean = false
private set
private var forcedStop: Boolean = false
init {
app.osmandAidlHelper.setContextMenuButtonsListener(object : ContextMenuButtonsListener {
override fun onContextMenuButtonClicked(buttonId: Int, pointId: String, layerId: String) {
updateDirectionMarker(pointId)
}
})
}
fun setupMapLayer() {
osmandAidlHelper.execOsmandApi {
osmandAidlHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
}
}
private fun updateDirectionMarker(pointId: String) {
val message = points[pointId]
if (message != null) {
val aLatLon = getALatLonFromMessage(message.content)
val name = getNameFromMessage(message)
if (aLatLon != null) {
val marker = AMapMarker(ALatLon(aLatLon.latitude, aLatLon.longitude), name)
val markerPrev = markers[pointId]
var markerUpdated: Boolean
if (markerPrev != null) {
markerUpdated = app.osmandAidlHelper.updateMapMarker(markerPrev, marker)
if (!markerUpdated) {
app.osmandAidlHelper.removeMapMarker(markerPrev.latLon.latitude, markerPrev.latLon.longitude, name)
markerUpdated = app.osmandAidlHelper.addMapMarker(marker)
}
} else {
markerUpdated = app.osmandAidlHelper.addMapMarker(marker)
}
if (markerUpdated) {
markers[pointId] = marker
}
}
}
}
fun showLocationOnMap(item: ListItem, stale: Boolean = false) {
if (item.latLon == null) {
return
@ -53,8 +99,8 @@ class ShowLocationHelper(private val app: TelegramApplication) {
item.chatTitle,
Color.WHITE,
ALatLon(item.latLon!!.latitude, item.latLon!!.longitude),
null,
generatePointParams(if (stale) item.grayscalePhotoPath else item.photoPath, stale)
generatePointDetails(item.bearing?.toFloat(), item.altitude?.toFloat(), item.precision?.toFloat()),
generatePointParams(if (stale) item.grayscalePhotoPath else item.photoPath, stale, item.speed?.toFloat())
)
}
}
@ -77,61 +123,89 @@ class ShowLocationHelper(private val app: TelegramApplication) {
fun addOrUpdateLocationOnMap(message: TdApi.Message, update: Boolean = false) {
osmandAidlHelper.execOsmandApi {
val chatId = message.chatId
val chatTitle = telegramHelper.getChat(message.chatId)?.title
val chat = telegramHelper.getChat(message.chatId)
val chatTitle = chat?.title
val isGroup = chat != null && telegramHelper.isGroup(chat)
val content = message.content
val date = OsmandLocationUtils.getLastUpdatedTime(message)
val stale = System.currentTimeMillis() / 1000 - date > app.settings.staleLocTime
if (chatTitle != null && (content is TdApi.MessageLocation || (content is MessageUserLocation && content.isValid()))) {
var userName = ""
var photoPath: String? = null
val user = telegramHelper.getUser(OsmandLocationUtils.getSenderMessageId(message))
if (user != null) {
userName = "${user.firstName} ${user.lastName}".trim()
if (userName.isEmpty()) {
userName = user.username
val aLatLon = getALatLonFromMessage(content)
val details = if (content is OsmandLocationUtils.MessageLocation) generatePointDetails(content.bearing.toFloat(), content.altitude.toFloat(), content.hdop.toFloat()) else null
val name = getNameFromMessage(message)
val senderId = OsmandLocationUtils.getSenderMessageId(message)
val pointId = if (content is MessageOsmAndBotLocation) "${chatId}_${content.deviceName}" else "${chatId}_$senderId"
if (aLatLon != null && chatTitle != null) {
if ((content is TdApi.MessageLocation || (content is MessageUserLocation && content.isValid()))) {
var photoPath: String? = null
val user = telegramHelper.getUser(senderId)
if (user != null) {
photoPath = if (stale) {
telegramHelper.getUserGreyPhotoPath(user)
} else {
telegramHelper.getUserPhotoPath(user)
}
}
if (userName.isEmpty()) {
userName = user.phoneNumber
}
photoPath = if (stale) {
telegramHelper.getUserGreyPhotoPath(user)
} else {
telegramHelper.getUserPhotoPath(user)
}
}
if (userName.isEmpty()) {
userName = OsmandLocationUtils.getSenderMessageId(message).toString()
}
setupMapLayer()
val params = generatePointParams(photoPath, stale)
val aLatLon = when (content) {
is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude)
is MessageUserLocation -> ALatLon(content.lat, content.lon)
else -> null
}
if (aLatLon != null) {
setupMapLayer()
val params = generatePointParams(photoPath, stale, if (content is MessageUserLocation) content.speed.toFloat() else null)
val typeName = if (isGroup) chatTitle else OsmandFormatter.getListItemLiveTimeDescr(app, date, app.getString(R.string.last_response) + ": ")
if (update) {
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, "${chatId}_${OsmandLocationUtils.getSenderMessageId(message)}", userName, userName,
chatTitle, Color.WHITE, aLatLon, null, params)
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, pointId, name, name, typeName, Color.WHITE, aLatLon, details, params)
} else {
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, "${chatId}_${OsmandLocationUtils.getSenderMessageId(message)}", userName, userName,
chatTitle, Color.WHITE, aLatLon, null, params)
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, pointId, name, name, typeName, Color.WHITE, aLatLon, details, params)
}
points[pointId] = message
} else if (content is MessageOsmAndBotLocation && content.isValid()) {
setupMapLayer()
val params = generatePointParams(null, stale, content.speed.toFloat())
if (update) {
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, pointId, name, name, chatTitle, Color.WHITE, aLatLon, details, params)
} else {
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, pointId, name, name, chatTitle, Color.WHITE, aLatLon, details, params)
}
points[pointId] = message
}
} else if (chatTitle != null && content is MessageOsmAndBotLocation && content.isValid()) {
val name = content.deviceName
setupMapLayer()
if (update) {
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, "${chatId}_$name", name, name,
chatTitle, Color.WHITE, ALatLon(content.lat, content.lon), null, generatePointParams(null, stale))
} else {
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, "${chatId}_$name", name, name,
chatTitle, Color.WHITE, ALatLon(content.lat, content.lon), null, generatePointParams(null, stale))
if (markers.containsKey(pointId)) {
updateDirectionMarker(pointId)
}
}
}
}
private fun getALatLonFromMessage(content: TdApi.MessageContent): ALatLon? {
return when (content) {
is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude)
is OsmandLocationUtils.MessageLocation -> ALatLon(content.lat, content.lon)
else -> null
}
}
private fun getNameFromMessage(message: TdApi.Message): String {
var name = ""
val content = message.content
val senderId = OsmandLocationUtils.getSenderMessageId(message)
if ((content is TdApi.MessageLocation || (content is MessageUserLocation && content.isValid()))) {
val user = telegramHelper.getUser(senderId)
if (user != null) {
name = "${user.firstName} ${user.lastName}".trim()
if (name.isEmpty()) {
name = user.username
}
if (name.isEmpty()) {
name = user.phoneNumber
}
}
if (name.isEmpty()) {
name = senderId.toString()
}
} else if (content is MessageOsmAndBotLocation && content.isValid()) {
name = content.deviceName
}
return name
}
fun showChatMessages(chatId: Long) {
osmandAidlHelper.execOsmandApi {
val messages = telegramHelper.getChatMessages(chatId)
@ -156,6 +230,14 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
}
fun addDirectionContextMenuButton() {
osmandAidlHelper.addContextMenuButtons(app.packageName, MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID, app.getString(R.string.direction), "", DIRECTION_ICON_ID, "", true, true, MAP_CONTEXT_MENU_BUTTON_ID)
}
fun removeDirectionContextMenuButton() {
osmandAidlHelper.removeContextMenuButtons(MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID)
}
fun startShowingLocation() {
if (!showingLocation && !forcedStop) {
showingLocation = if (isUseOsmandCallback() && !app.settings.monitoringEnabled) {
@ -164,6 +246,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
app.startUserLocationService()
true
}
addDirectionContextMenuButton()
}
}
@ -176,6 +259,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
} else if (!app.settings.monitoringEnabled) {
app.stopUserLocationService()
}
removeDirectionContextMenuButton()
}
}
@ -253,17 +337,37 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
}
private fun generatePointParams(photoPath: String?, stale: Boolean): Map<String, String> {
private fun generatePointDetails(bearing: Float?, altitude: Float?, precision: Float?): List<String> {
val details = mutableListOf<String>()
if (bearing != null && bearing != 0.0f) {
details.add(String.format(Locale.US, "${OsmandLocationUtils.BEARING_PREFIX}%.1f \n", bearing))
}
if (altitude != null && altitude != 0.0f) {
details.add(String.format(Locale.US, "${OsmandLocationUtils.ALTITUDE_PREFIX}%.1f m\n", altitude))
}
if (precision != null && precision != 0.0f) {
details.add(String.format(Locale.US, "${OsmandLocationUtils.HDOP_PREFIX}%d m\n", precision.toInt()))
}
return details
}
private fun generatePointParams(photoPath: String?, stale: Boolean, speed: Float?): Map<String, String> {
val photoUri = generatePhotoUri(photoPath, stale)
app.grantUriPermission(
app.settings.appToConnectPackage,
photoUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
return mapOf(
val params = mutableMapOf(
AMapPoint.POINT_IMAGE_URI_PARAM to photoUri.toString(),
AMapPoint.POINT_STALE_LOC_PARAM to stale.toString()
)
if (speed != 0.0f) {
params[AMapPoint.POINT_SPEED_PARAM] = speed.toString()
}
return params
}
private fun generatePhotoUri(photoPath: String?, stale: Boolean) =

View file

@ -35,6 +35,8 @@ class TelegramHelper private constructor() {
private const val IGNORED_ERROR_CODE = 406
private const val MESSAGE_CANNOT_BE_EDITED_ERROR_CODE = 5
private const val MAX_SEARCH_ITEMS = Int.MAX_VALUE
// min and max values for the Telegram API
const val MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC = 61
const val MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC = 60 * 60 * 24 - 1 // one day
@ -98,6 +100,7 @@ class TelegramHelper private constructor() {
private val incomingMessagesListeners = HashSet<TelegramIncomingMessagesListener>()
private val outgoingMessagesListeners = HashSet<TelegramOutgoingMessagesListener>()
private val fullInfoUpdatesListeners = HashSet<FullInfoUpdatesListener>()
private val searchListeners = HashSet<TelegramSearchListener>()
fun addIncomingMessagesListener(listener: TelegramIncomingMessagesListener) {
incomingMessagesListeners.add(listener)
@ -123,6 +126,14 @@ class TelegramHelper private constructor() {
fullInfoUpdatesListeners.remove(listener)
}
fun addSearchListener(listener: TelegramSearchListener) {
searchListeners.add(listener)
}
fun removeSearchListener(listener: TelegramSearchListener) {
searchListeners.remove(listener)
}
fun getChatList(): TreeSet<OrderedChat> {
synchronized(chatList) {
return TreeSet(chatList.filter { !it.isChannel })
@ -193,7 +204,7 @@ class TelegramHelper private constructor() {
fun isSecretChat(chat: TdApi.Chat): Boolean = chat.type is TdApi.ChatTypeSecret
private fun isChannel(chat: TdApi.Chat): Boolean {
fun isChannel(chat: TdApi.Chat): Boolean {
return chat.type is TdApi.ChatTypeSupergroup && (chat.type as TdApi.ChatTypeSupergroup).isChannel
}
@ -249,6 +260,12 @@ class TelegramHelper private constructor() {
fun onTelegramAuthorizationRequestError(code: Int, message: String)
}
interface TelegramSearchListener {
fun onSearchChatsFinished(obj: TdApi.Chats)
fun onSearchPublicChatsFinished(obj: TdApi.Chats)
fun onSearchContactsFinished(obj: TdApi.Users)
}
inner class TelegramAuthorizationRequestHandler(val telegramAuthorizationRequestListener: TelegramAuthorizationRequestListener) {
fun applyAuthenticationParameter(parameterType: TelegramAuthenticationParameterType, parameterValue: String) {
@ -628,7 +645,7 @@ class TelegramHelper private constructor() {
}
}
private fun requestUser(id: Int) {
fun requestUser(id: Int) {
client?.send(TdApi.GetUser(id)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
@ -648,6 +665,98 @@ class TelegramHelper private constructor() {
}
}
fun requestChat(id: Long) {
client?.send(TdApi.GetChat(id)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Chat.CONSTRUCTOR -> {
val chat = obj as TdApi.Chat
chats[chat.id] = chat
listener?.onTelegramChatChanged(chat)
}
}
}
}
fun disableProxy() {
client?.send(TdApi.DisableProxy()) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Ok.CONSTRUCTOR -> {
}
}
}
}
fun enableProxy(proxyId: Int) {
client?.send(TdApi.EnableProxy(proxyId)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Ok.CONSTRUCTOR -> {
}
}
}
}
fun addProxyPref(proxyPref: TelegramSettings.ProxyPref, enable: Boolean) {
val proxyType: TdApi.ProxyType? = when (proxyPref) {
is TelegramSettings.ProxyMTProtoPref -> TdApi.ProxyTypeMtproto(proxyPref.key)
is TelegramSettings.ProxySOCKS5Pref -> TdApi.ProxyTypeSocks5(proxyPref.login, proxyPref.password)
else -> null
}
client?.send(TdApi.AddProxy(proxyPref.server, proxyPref.port, enable, proxyType)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Proxy.CONSTRUCTOR -> {
val proxy = (obj as TdApi.Proxy)
proxyPref.id = proxy.id
}
}
}
}
fun editProxyPref(proxyPref: TelegramSettings.ProxyPref, enable: Boolean) {
val proxyType: TdApi.ProxyType? = when (proxyPref) {
is TelegramSettings.ProxyMTProtoPref -> TdApi.ProxyTypeMtproto(proxyPref.key)
is TelegramSettings.ProxySOCKS5Pref -> TdApi.ProxyTypeSocks5(proxyPref.login, proxyPref.password)
else -> null
}
client?.send(TdApi.EditProxy(proxyPref.id, proxyPref.server, proxyPref.port, enable, proxyType)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Proxy.CONSTRUCTOR -> {
val proxy = (obj as TdApi.Proxy)
proxyPref.id = proxy.id
}
}
}
}
fun createPrivateChatWithUser(
userId: Int,
shareInfo: TelegramSettings.ShareChatInfo,
@ -965,6 +1074,53 @@ class TelegramHelper private constructor() {
}
}
fun searchChats(searchTerm: String) {
client?.send(TdApi.SearchChats(searchTerm, MAX_SEARCH_ITEMS)) { obj ->
checkChatsAndUsersSearch(obj)
}
}
fun searchChatsOnServer(searchTerm: String) {
client?.send(TdApi.SearchChatsOnServer(searchTerm, MAX_SEARCH_ITEMS)) { obj ->
checkChatsAndUsersSearch(obj)
}
}
fun searchPublicChats(searchTerm: String) {
client?.send(TdApi.SearchPublicChats(searchTerm)) { obj ->
checkChatsAndUsersSearch(obj, true)
}
}
fun searchContacts(searchTerm: String) {
client?.send(TdApi.SearchContacts(searchTerm, MAX_SEARCH_ITEMS)) { obj ->
checkChatsAndUsersSearch(obj)
}
}
private fun checkChatsAndUsersSearch(obj: TdApi.Object, publicChats: Boolean = false) {
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
listener?.onTelegramError(error.code, error.message)
}
}
TdApi.Chats.CONSTRUCTOR -> {
val chats = obj as TdApi.Chats
if (publicChats) {
searchListeners.forEach { it.onSearchPublicChatsFinished(chats) }
} else {
searchListeners.forEach { it.onSearchChatsFinished(chats) }
}
}
TdApi.Users.CONSTRUCTOR -> {
val users = obj as TdApi.Users
searchListeners.forEach { it.onSearchContactsFinished(users) }
}
}
}
fun logout(): Boolean {
return if (libraryLoaded) {
haveAuthorization = false

View file

@ -71,6 +71,10 @@ object TelegramUiHelper {
res.latLon = LatLon(content.location.latitude, content.location.longitude)
} else if (content is MessageUserLocation) {
res.latLon = LatLon(content.lat, content.lon)
res.speed = content.speed
res.bearing = content.bearing
res.altitude = content.altitude
res.precision = content.hdop
}
}
if (user != null) {
@ -140,6 +144,10 @@ object TelegramUiHelper {
chatTitle = chat.title
name = content.deviceName
latLon = LatLon(content.lat, content.lon)
speed = content.speed
bearing = content.bearing
altitude = content.altitude
precision = content.hdop
placeholderId = R.drawable.img_user_picture
lastUpdated = content.lastUpdated
}
@ -158,11 +166,18 @@ object TelegramUiHelper {
return LocationItem().apply {
chatId = chat.id
chatTitle = chat.title
name = TelegramUiHelper.getUserName(user)
latLon = when (content) {
is TdApi.MessageLocation -> LatLon(content.location.latitude, content.location.longitude)
is MessageUserLocation -> LatLon(content.lat, content.lon)
else -> null
name = getUserName(user)
when (content) {
is TdApi.MessageLocation -> {
latLon = LatLon(content.location.latitude, content.location.longitude)
}
is MessageUserLocation -> {
latLon = LatLon(content.lat, content.lon)
speed = content.speed
bearing = content.bearing
altitude = content.altitude
precision = content.hdop
}
}
photoPath = helper.getUserPhotoPath(user)
grayscalePhotoPath = helper.getUserGreyPhotoPath(user)
@ -184,6 +199,10 @@ object TelegramUiHelper {
chatTitle = chat.title
name = content.deviceName
latLon = LatLon(content.lat, content.lon)
speed = content.speed
bearing = content.bearing
altitude = content.altitude
precision = content.hdop
photoPath = chat.photo?.small?.local?.path
placeholderId = R.drawable.img_user_picture
privateChat = helper.isPrivateChat(chat) || helper.isSecretChat(chat)
@ -205,11 +224,18 @@ object TelegramUiHelper {
return ChatItem().apply {
chatId = chat.id
chatTitle = chat.title
name = TelegramUiHelper.getUserName(user)
latLon = when (content) {
is TdApi.MessageLocation -> LatLon(content.location.latitude, content.location.longitude)
is MessageUserLocation -> LatLon(content.lat, content.lon)
else -> null
name = getUserName(user)
when (content) {
is TdApi.MessageLocation -> {
latLon = LatLon(content.location.latitude, content.location.longitude)
}
is MessageUserLocation -> {
latLon = LatLon(content.lat, content.lon)
speed = content.speed
bearing = content.bearing
altitude = content.altitude
precision = content.hdop
}
}
if (helper.isGroup(chat)) {
photoPath = helper.getUserPhotoPath(user)
@ -244,7 +270,7 @@ object TelegramUiHelper {
photoPath = user?.profilePhoto?.small?.local?.path
}
if (user != null) {
name = TelegramUiHelper.getUserName(user)
name = getUserName(user)
userId = user.id
}
userLocations = userLocation
@ -264,6 +290,14 @@ object TelegramUiHelper {
internal set
var latLon: LatLon? = null
internal set
var bearing: Double? = null
internal set
var speed: Double? = null
internal set
var altitude: Double? = null
internal set
var precision: Double? = null
internal set
var photoPath: String? = null
internal set
var grayscalePhotoPath: String? = null

View file

@ -510,6 +510,7 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
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.topShadowDivider?.visibility = View.GONE
}
}
@ -601,6 +602,7 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
val description: TextView? = view.findViewById(R.id.description)
val receivedGpxPointsContainer: View? = view.findViewById(R.id.received_gps_points_container)
val receivedGpxPointsDescr: TextView? = view.findViewById(R.id.received_gps_points_description)
val topShadowDivider: View? = view.findViewById(R.id.top_divider)
val bottomShadow: View? = view.findViewById(R.id.bottom_shadow)
val lastTelegramUpdateTime: TextView? = view.findViewById(R.id.last_telegram_update_time)

View file

@ -217,17 +217,23 @@ class LoginDialogFragment : BaseDialogFragment() {
welcomeImage?.visibility = View.GONE
}
val continueButton = view?.findViewById<Button>(R.id.welcome_continue_button)
continueButton?.setOnClickListener {
showWelcomeDialog = false
if (!privacyPolicyAgreed) {
loginDialogActiveType = LoginDialogType.PRIVACY_POLICY
showProgress = false
} else if (loginDialogActiveType == null) {
loginDialogActiveType = LoginDialogType.ENTER_PHONE_NUMBER
showProgress = true
view?.findViewById<Button>(R.id.welcome_continue_button)?.apply {
val params = layoutParams as ViewGroup.MarginLayoutParams
val bottomMargin = AndroidUtils.getNavBarHeight(context) + resources.getDimensionPixelSize(R.dimen.dialog_button_bottom_padding)
params.apply {
setMargins(leftMargin, topMargin, rightMargin, bottomMargin)
}
setOnClickListener {
showWelcomeDialog = false
if (!privacyPolicyAgreed) {
loginDialogActiveType = LoginDialogType.PRIVACY_POLICY
showProgress = false
} else if (loginDialogActiveType == null) {
loginDialogActiveType = LoginDialogType.ENTER_PHONE_NUMBER
showProgress = true
}
buildDialog(view)
}
buildDialog(view)
}
view?.findViewById<View>(R.id.login_layout)?.visibility = View.GONE
view?.findViewById<View>(R.id.welcome_layout)?.visibility = View.VISIBLE

View file

@ -130,6 +130,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
appBarCollapsed = collapsed
adjustText()
adjustAppbar()
adjustSearchBox()
optionsBtn.visibility = if (collapsed) View.VISIBLE else View.GONE
}
})
@ -183,7 +184,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
setBackgroundDrawable(searchBoxBg)
}
findViewById<View>(R.id.search_button).setOnClickListener {
Toast.makeText(context, "Search", Toast.LENGTH_SHORT).show()
activity.supportFragmentManager?.also { SearchDialogFragment.showInstance(it, this@MyLocationTabFragment) }
}
findViewById<ImageView>(R.id.search_icon)
.setImageDrawable(app.uiUtils.getThemedIcon(R.drawable.ic_action_search_dark))
@ -635,6 +636,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
}
}
}
holder.topShadowDivider?.visibility = View.GONE
holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE
holder.itemView.setOnClickListener {
if (live) {
@ -754,6 +756,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
inner class ChatViewHolder(val view: View) : BaseViewHolder(view) {
val checkBox: CheckBox? = view.findViewById(R.id.check_box)
val topShadowDivider: View? = view.findViewById(R.id.top_divider)
val bottomShadow: View? = view.findViewById(R.id.bottom_shadow)
}

View file

@ -0,0 +1,217 @@
package net.osmand.telegram.ui
import android.os.Build
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.content.ContextCompat
import android.support.v7.widget.Toolbar
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.*
import net.osmand.telegram.R
import net.osmand.telegram.TelegramSettings.ProxyType
import net.osmand.telegram.TelegramSettings.ProxyPref
import net.osmand.telegram.TelegramSettings.ProxyMTProtoPref
import net.osmand.telegram.TelegramSettings.ProxySOCKS5Pref
class ProxySettingsDialogFragment : BaseDialogFragment() {
private val uiUtils get() = app.uiUtils
private lateinit var mainView: View
private lateinit var proxyEnableSwitcher: Switch
private lateinit var saveButtonContainer: LinearLayout
private lateinit var selectedProxyType: ProxyType
private lateinit var serverEditText: EditText
private lateinit var portEditText: EditText
override fun onCreateView(
inflater: LayoutInflater,
parent: ViewGroup?,
savedInstanceState: Bundle?
): View {
mainView = inflater.inflate(R.layout.fragment_proxy_settings_dialog, parent)
val window = dialog.window
if (window != null) {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
if (Build.VERSION.SDK_INT >= 21) {
window.statusBarColor = ContextCompat.getColor(app, R.color.card_bg_light)
}
}
mainView.findViewById<Toolbar>(R.id.toolbar).apply {
navigationIcon = uiUtils.getThemedIcon(R.drawable.ic_arrow_back)
setNavigationOnClickListener { dismiss() }
}
selectedProxyType = settings.currentProxyPref.type
mainView.findViewById<ViewGroup>(R.id.enable_proxy_btn).apply {
val title = findViewById<TextView>(R.id.title).apply {
text = if (settings.proxyEnabled) getText(R.string.shared_string_disable) else getText(
R.string.shared_string_enable
)
}
proxyEnableSwitcher = findViewById<Switch>(R.id.switcher).apply {
isChecked = settings.proxyEnabled
}
setOnClickListener {
val checked = !proxyEnableSwitcher.isChecked
proxyEnableSwitcher.isChecked = checked
title.text = if (checked) getText(R.string.shared_string_disable) else getText(R.string.shared_string_enable)
updateSaveButtonVisibility(true)
}
}
val container = mainView.findViewById<ViewGroup>(R.id.proxy_type_container)
ProxyType.values().forEach {
addItemToContainer(inflater, container, it)
}
serverEditText = mainView.findViewById<EditText>(R.id.server_edit_text).apply {
val server = settings.currentProxyPref.server
setText(server)
setSelection(server.length)
addTextChangedListener(object :
TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable) {
updateSaveButtonVisibility(s.isNotEmpty() && portEditText.text.isNotEmpty())
}
})
}
portEditText = mainView.findViewById<EditText>(R.id.port_edit_text).apply {
val port = settings.currentProxyPref.port
setText(if (port != -1) port.toString() else "")
addTextChangedListener(object :
TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable) {
updateSaveButtonVisibility(s.isNotEmpty() && serverEditText.text.isNotEmpty())
}
})
}
saveButtonContainer = mainView.findViewById<LinearLayout>(R.id.save_button_Container).apply {
findViewById<TextView>(R.id.primary_btn).apply {
text = getString(R.string.shared_string_save)
setOnClickListener {
saveChanges()
targetFragment?.also { target ->
target.onActivityResult(targetRequestCode, PROXY_PREFERENCES_UPDATED_REQUEST_CODE, null)
}
dismiss()
}
}
}
updateSelectedProxyType()
updateEditingMode()
updateProxyPrefInfo()
updateSaveButtonVisibility(false)
return mainView
}
private fun updateSaveButtonVisibility(visible: Boolean) {
saveButtonContainer.visibility = if (visible) View.VISIBLE else View.GONE
}
private fun saveChanges() {
val proxyPref = getSelectedProxyPref()
settings.updateCurrentProxyPref(proxyPref, proxyEnableSwitcher.isChecked)
}
private fun updateProxyPrefInfo() {
val proxyPref = settings.currentProxyPref
if (proxyPref is ProxyMTProtoPref) {
mainView.findViewById<TextView>(R.id.key_text).text = proxyPref.key
} else if (proxyPref is ProxySOCKS5Pref) {
mainView.findViewById<TextView>(R.id.username_text).text = proxyPref.login
mainView.findViewById<TextView>(R.id.password_text).text = proxyPref.password
}
}
private fun getSelectedProxyPref(): ProxyPref {
val server = serverEditText.text.toString()
val port = portEditText.text.toString().toIntOrNull() ?: -1
return when (selectedProxyType) {
ProxyType.MTPROTO -> {
val key = mainView.findViewById<TextView>(R.id.key_text).text.toString()
ProxyMTProtoPref(settings.currentProxyPref.id, server, port, key)
}
ProxyType.SOCKS5 -> {
val username = mainView.findViewById<TextView>(R.id.username_text).text.toString()
val password = mainView.findViewById<TextView>(R.id.password_text).text.toString()
ProxySOCKS5Pref(settings.currentProxyPref.id, server, port, username, password)
}
}
}
private fun updateSelectedProxyType() {
view?.findViewById<ViewGroup>(R.id.proxy_type_container)?.apply {
for (i in 0 until childCount) {
getChildAt(i).apply {
findViewById<RadioButton>(R.id.radio_button).isChecked = tag == selectedProxyType
}
}
}
}
private fun updateEditingMode() {
mainView.findViewById<LinearLayout>(R.id.proxy_sosks5_container)?.visibility =
if (selectedProxyType == ProxyType.SOCKS5) View.VISIBLE else View.GONE
mainView.findViewById<LinearLayout>(R.id.proxy_mtproto_container)?.visibility =
if (selectedProxyType == ProxyType.MTPROTO) View.VISIBLE else View.GONE
}
private fun addItemToContainer(
inflater: LayoutInflater,
container: ViewGroup,
proxyTypeTag: ProxyType
) {
inflater.inflate(R.layout.item_with_rb_and_btn, container, false).apply {
findViewById<TextView>(R.id.title).text = proxyTypeTag.name
findViewById<View>(R.id.primary_btn).visibility = View.GONE
findViewById<View>(R.id.icon).visibility = View.GONE
findViewById<RadioButton>(R.id.radio_button).isChecked = selectedProxyType == proxyTypeTag
setOnClickListener {
selectedProxyType = proxyTypeTag
updateSelectedProxyType()
updateEditingMode()
updateSaveButtonVisibility(selectedProxyType != settings.currentProxyPref.type && portEditText.text.isNotEmpty() && serverEditText.text.isNotEmpty())
}
this.tag = proxyTypeTag
container.addView(this)
}
}
companion object {
private const val TAG = "ProxySettingsDialogFragment"
const val PROXY_PREFERENCES_UPDATED_REQUEST_CODE = 6
fun showInstance(fm: FragmentManager, target: Fragment): Boolean {
return try {
ProxySettingsDialogFragment().apply {
setTargetFragment(target, PROXY_PREFERENCES_UPDATED_REQUEST_CODE)
show(fm, TAG)
}
true
} catch (e: RuntimeException) {
false
}
}
}
}

View file

@ -0,0 +1,548 @@
package net.osmand.telegram.ui
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.content.ContextCompat
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import net.osmand.Location
import net.osmand.PlatformUtil
import net.osmand.data.LatLon
import net.osmand.telegram.R
import net.osmand.telegram.TelegramLocationProvider.TelegramCompassListener
import net.osmand.telegram.TelegramLocationProvider.TelegramLocationListener
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.ui.views.EmptyStateRecyclerView
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.telegram.utils.OsmandLocationUtils
import net.osmand.telegram.utils.UiUtils
import net.osmand.util.MapUtils
import org.drinkless.td.libcore.telegram.TdApi
class SearchDialogFragment : BaseDialogFragment(), TelegramHelper.TelegramSearchListener,
TelegramLocationListener, TelegramCompassListener {
private val log = PlatformUtil.getLog(SearchDialogFragment::class.java)
private val uiUtils get() = app.uiUtils
private val adapter = SearchAdapter()
private lateinit var locationViewCache: UiUtils.UpdateLocationViewCache
private lateinit var searchEditText: EditText
private lateinit var buttonsBar: LinearLayout
private var searchedChatsIds = mutableSetOf<Long>()
private var searchedPublicChatsIds = mutableSetOf<Long>()
private var searchedContactsIds = mutableSetOf<Int>()
private val selectedChats = HashSet<Long>()
private val selectedUsers = HashSet<Long>()
private var searchQuery: String = ""
private var location: Location? = null
private var heading: Float? = null
private var locationUiUpdateAllowed: Boolean = true
override fun onCreateView(
inflater: LayoutInflater,
parent: ViewGroup?,
savedInstanceState: Bundle?
): View {
val mainView = inflater.inflate(R.layout.fragment_search_dialog, parent)
mainView.findViewById<Toolbar>(R.id.toolbar).apply {
navigationIcon = uiUtils.getThemedIcon(R.drawable.ic_arrow_back)
setNavigationOnClickListener { dismiss() }
}
val window = dialog.window
if (window != null && Build.VERSION.SDK_INT >= 21) {
window.statusBarColor = ContextCompat.getColor(app, R.color.card_bg_light)
}
searchEditText = mainView.findViewById<EditText>(R.id.searchEditText).apply {
addTextChangedListener(object : TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable) {
val newQueryText = s.toString()
if (!searchQuery.equals(newQueryText, true)) {
searchQuery = newQueryText
clearSearchedItems()
if (searchQuery.isNotBlank()) {
runSearch()
} else {
updateList()
}
}
}
})
}
mainView.findViewById<ImageView>(R.id.search_icon).setOnClickListener {
runSearch()
}
val emptyView = mainView.findViewById<LinearLayout>(R.id.empty_view)
mainView.findViewById<EmptyStateRecyclerView>(R.id.recycler_view).apply {
layoutManager = LinearLayoutManager(context)
adapter = this@SearchDialogFragment.adapter
setEmptyView(emptyView)
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
val scrolling = newState != RecyclerView.SCROLL_STATE_IDLE
locationUiUpdateAllowed = !scrolling
if (scrolling) {
hideKeyboard()
}
}
})
}
buttonsBar = mainView.findViewById<LinearLayout>(R.id.buttons_bar).apply {
findViewById<TextView>(R.id.primary_btn).apply {
text = getString(R.string.shared_string_continue)
setOnClickListener {
onPrimaryBtnClick()
}
}
findViewById<TextView>(R.id.secondary_btn).apply {
text = getString(R.string.shared_string_cancel)
setOnClickListener {
onSecondaryBtnClick()
}
}
}
return mainView
}
private fun hideKeyboard() {
val mainActivity = activity
if (mainActivity != null && searchEditText.hasFocus()) {
AndroidUtils.hideSoftKeyboard(mainActivity, searchEditText)
}
}
private fun clearSearchedItems() {
searchedChatsIds.clear()
searchedPublicChatsIds.clear()
searchedContactsIds.clear()
}
private fun runSearch() {
if (searchQuery.isNotBlank()) {
runSearch(searchQuery)
}
}
private fun runSearch(text: String) {
telegramHelper.searchChats(text)
telegramHelper.searchChatsOnServer(text)
telegramHelper.searchContacts(text)
if (text.length > 4) {
telegramHelper.searchPublicChats(text)
}
}
override fun onResume() {
super.onResume()
telegramHelper.addSearchListener(this)
locationViewCache = app.uiUtils.getUpdateLocationViewCache()
startLocationUpdate()
searchEditText.requestFocus()
AndroidUtils.softKeyboardDelayed(searchEditText)
}
override fun onPause() {
super.onPause()
telegramHelper.removeSearchListener(this)
stopLocationUpdate()
}
override fun updateLocation(location: Location?) {
val loc = this.location
val newLocation = loc == null && location != null
val locationChanged = loc != null && location != null
&& loc.latitude != location.latitude
&& loc.longitude != location.longitude
if (newLocation || locationChanged) {
this.location = location
updateLocationUi()
}
}
override fun updateCompassValue(value: Float) {
// 99 in next line used to one-time initialize arrows (with reference vs. fixed-north direction)
// on non-compass devices
val lastHeading = heading ?: 99f
heading = value
if (Math.abs(MapUtils.degreesDiff(lastHeading.toDouble(), value.toDouble())) > 5) {
updateLocationUi()
} else {
heading = lastHeading
}
}
private fun startLocationUpdate() {
app.locationProvider.addLocationListener(this)
app.locationProvider.addCompassListener(this)
updateLocationUi()
}
private fun stopLocationUpdate() {
app.locationProvider.removeLocationListener(this)
app.locationProvider.removeCompassListener(this)
}
private fun updateLocationUi() {
if (locationUiUpdateAllowed) {
app.runInUIThread { adapter.notifyDataSetChanged() }
}
}
private fun updateList() {
val items: MutableList<TdApi.Object> = mutableListOf()
val chats: MutableList<TdApi.Chat> = mutableListOf()
val publicChats: MutableList<TdApi.Chat> = mutableListOf()
val users: MutableList<TdApi.User> = mutableListOf()
val currentUserId = telegramHelper.getCurrentUserId()
selectedChats.forEach {
val chat = telegramHelper.getChat(it)
if (chat != null) {
if (!telegramHelper.isChannel(chat) && telegramHelper.getUserIdFromChatType(chat.type) != currentUserId) {
items.add(chat)
}
} else {
telegramHelper.requestChat(it)
}
}
selectedUsers.forEach {
val user = telegramHelper.getUser(it.toInt())
if (user != null) {
if (user.id != currentUserId)
items.add(user)
} else {
telegramHelper.requestUser(it.toInt())
}
}
searchedChatsIds.forEach {
val chat = telegramHelper.getChat(it)
if (chat != null && !selectedChats.contains(it)) {
if (!telegramHelper.isChannel(chat) && telegramHelper.getUserIdFromChatType(chat.type) != currentUserId) {
chats.add(chat)
}
} else {
telegramHelper.requestChat(it)
}
}
items.addAll(chats)
searchedContactsIds.forEach { userId ->
val user = telegramHelper.getUser(userId)
if (user != null && !selectedUsers.contains(userId.toLong())) {
if (user.id != currentUserId && !chats.any { telegramHelper.getUserIdFromChatType(it.type) == user.id })
users.add(user)
} else {
telegramHelper.requestUser(userId)
}
}
items.addAll(sortUsers(users))
searchedPublicChatsIds.forEach {
val chat = telegramHelper.getChat(it)
if (chat != null && !selectedChats.contains(it) && !searchedChatsIds.contains(it)) {
if (!telegramHelper.isChannel(chat) && telegramHelper.getUserIdFromChatType(chat.type) != currentUserId) {
publicChats.add(chat)
}
} else {
telegramHelper.requestChat(it)
}
}
items.addAll(publicChats)
adapter.items = items
}
private fun sortUsers(list: MutableList<TdApi.User>): MutableList<TdApi.User> {
list.sortWith(Comparator { o1, o2 ->
val title1 = TelegramUiHelper.getUserName(o1)
val title2 = TelegramUiHelper.getUserName(o2)
title1.compareTo(title2)
})
return list
}
override fun onSearchContactsFinished(obj: TdApi.Users) {
log.debug("searchContactsFinished $obj")
val ids = obj.userIds
if (ids.isNotEmpty()) {
searchedContactsIds = ids.toMutableSet()
app.runInUIThread { updateList() }
}
}
override fun onSearchChatsFinished(obj: TdApi.Chats) {
log.debug("searchChatsFinished $obj")
val ids = obj.chatIds
if (ids.isNotEmpty()) {
searchedChatsIds = ids.toMutableSet()
app.runInUIThread { updateList() }
}
}
override fun onSearchPublicChatsFinished(obj: TdApi.Chats) {
log.debug("onSearchPublicChatsFinished $obj")
val ids = obj.chatIds
if (ids.isNotEmpty()) {
searchedPublicChatsIds = ids.toMutableSet()
app.runInUIThread { updateList() }
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
LogoutBottomSheet.LOGOUT_REQUEST_CODE -> {
dismiss()
}
SetTimeDialogFragment.LOCATION_SHARED_REQUEST_CODE -> {
if (resultCode == SetTimeDialogFragment.LOCATION_SHARED_REQUEST_CODE) {
targetFragment?.also {
it.onActivityResult(targetRequestCode, resultCode, null)
}
dismiss()
}
}
}
}
inner class SearchAdapter : RecyclerView.Adapter<SearchAdapter.ChatViewHolder>() {
var items = mutableListOf<TdApi.Object>()
set(value) {
field = value
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.user_list_item, parent, false)
return ChatViewHolder(view)
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ChatViewHolder, position: Int) {
val item = items[position]
val isChat = item is TdApi.Chat
val itemId = if (isChat) {
(item as TdApi.Chat).id
} else {
(item as TdApi.User).id.toLong()
}
val latLon = getItemLastLocation(item)
val lastUpdate = getLastUpdateTime(item)
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
holder.checkBox?.apply {
visibility = if (live) View.GONE else View.VISIBLE
setOnCheckedChangeListener(null)
isChecked = if (isChat) {
selectedChats.contains(itemId)
} else {
selectedUsers.contains(itemId)
}
setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
if (isChat) {
selectedChats.add(itemId)
} else {
selectedUsers.add(itemId)
}
} else {
if (isChat) {
selectedChats.remove(itemId)
} else {
selectedUsers.remove(itemId)
}
if (!(searchedChatsIds.contains(itemId) || searchedPublicChatsIds.contains(itemId) || searchedContactsIds.contains(itemId.toInt()))) {
updateList()
}
}
switchButtonsVisibility(selectedChats.isNotEmpty() || selectedUsers.isNotEmpty())
}
}
holder.topShadowDivider?.visibility = if (position == 0) View.VISIBLE else View.GONE
holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE
holder.itemView.setOnClickListener {
if (!live) {
holder.checkBox?.apply {
isChecked = !isChecked
}
}
}
if (location != null && latLon != null && lastUpdate != null) {
val staleLocation = System.currentTimeMillis() / 1000 - lastUpdate > settings.staleLocTime
holder.locationViewContainer?.visibility = if (lastUpdate > 0) View.VISIBLE else View.GONE
locationViewCache.outdatedLocation = staleLocation
app.uiUtils.updateLocationView(holder.directionIcon, holder.distanceText, latLon, locationViewCache)
} else {
holder.locationViewContainer?.visibility = View.GONE
}
val expiresIn = shareInfo?.getChatLiveMessageExpireTime() ?: 0
holder.textInArea?.apply {
visibility = if (live) View.VISIBLE else View.GONE
text = OsmandFormatter.getFormattedDuration(app, expiresIn)
}
holder.description?.apply {
val description = getItemDescription(item, lastUpdate)
text = description
visibility = if (description != null) View.VISIBLE else View.GONE
}
}
private fun getItemLastMessage(item: TdApi.Object): TdApi.Message? {
when (item) {
is TdApi.User -> {
return telegramHelper.getUserMessage(item)
}
is TdApi.Chat -> {
return telegramHelper.getChatMessages(item.id).firstOrNull() ?: item.lastMessage
}
}
return null
}
private fun getItemLastLocation(item: TdApi.Object): LatLon? {
val message = getItemLastMessage(item)
if (message != null && OsmandLocationUtils.getSenderMessageId(message) != telegramHelper.getCurrentUserId()) {
val messageLocation = OsmandLocationUtils.parseMessageContent(message, telegramHelper)
if (messageLocation != null) {
return LatLon(messageLocation.lat, messageLocation.lon)
}
}
return null
}
private fun getLastUpdateTime(item: TdApi.Object): Int? {
val message = getItemLastMessage(item)
if (message != null && OsmandLocationUtils.getSenderMessageId(message) != telegramHelper.getCurrentUserId()) {
return OsmandLocationUtils.getLastUpdatedTime(message)
}
return null
}
private fun getItemDescription(item: TdApi.Object, lastUpdateTime: Int?): String? {
if (lastUpdateTime != null) {
return OsmandFormatter.getListItemLiveTimeDescr(app, lastUpdateTime)
}
if (item is TdApi.Chat && telegramHelper.isGroup(item)) {
return getString(R.string.shared_string_group)
}
return null
}
override fun getItemCount() = items.size
inner class ChatViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val icon: ImageView? = view.findViewById(R.id.icon)
val title: TextView? = view.findViewById(R.id.title)
val locationViewContainer: View? = view.findViewById(R.id.location_view_container)
val directionIcon: ImageView? = view.findViewById(R.id.direction_icon)
val distanceText: TextView? = view.findViewById(R.id.distance_text)
val description: TextView? = view.findViewById(R.id.description)
val checkBox: CheckBox? = view.findViewById(R.id.check_box)
val textInArea: TextView? = view.findViewById(R.id.text_in_area)
val topShadowDivider: View? = view.findViewById(R.id.top_divider)
val bottomShadow: View? = view.findViewById(R.id.bottom_shadow)
}
}
private fun onPrimaryBtnClick() {
if (selectedChats.isNotEmpty() || selectedUsers.isNotEmpty()) {
fragmentManager?.also {
SetTimeDialogFragment.showInstance(it, selectedChats, selectedUsers, this)
}
}
}
private fun onSecondaryBtnClick() {
clearSelection()
adapter.notifyDataSetChanged()
adapter.notifyDataSetChanged()
switchButtonsVisibility(false)
}
private fun clearSelection() {
selectedChats.clear()
selectedUsers.clear()
}
private fun switchButtonsVisibility(visible: Boolean) {
val buttonsVisibility = if (visible) View.VISIBLE else View.GONE
if (buttonsBar.visibility != buttonsVisibility) {
buttonsBar.visibility = buttonsVisibility
}
}
companion object {
const val TAG = "SearchDialogFragment"
fun showInstance(fm: FragmentManager, target: Fragment?): Boolean {
return try {
SearchDialogFragment().apply {
if (target != null) {
setTargetFragment(target, SetTimeDialogFragment.LOCATION_SHARED_REQUEST_CODE)
}
show(fm, TAG)
}
true
} catch (e: RuntimeException) {
false
}
}
}
}

View file

@ -79,6 +79,9 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
view.findViewById<TextView>(R.id.secondary_btn).apply {
text = getString(R.string.shared_string_back)
setOnClickListener {
targetFragment?.also {
it.onActivityResult(targetRequestCode, LOCATION_SHARING_CANCELED_CODE, null)
}
dismiss()
}
}
@ -271,12 +274,18 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
private fun updateList() {
val items: MutableList<TdApi.Object> = mutableListOf()
telegramHelper.getChatList().filter { chatLivePeriods.keys.contains(it.chatId) }
.forEach { orderedChat ->
telegramHelper.getChat(orderedChat.chatId)?.also { items.add(it) }
chatLivePeriods.keys.forEach {
val chat = telegramHelper.getChat(it)
if (chat != null) {
items.add(chat)
}
telegramHelper.getContacts().values.filter { userLivePeriods.keys.contains(it.id.toLong()) }
.forEach { user -> items.add(user) }
}
userLivePeriods.keys.forEach {
val user = telegramHelper.getUser(it.toInt())
if (user != null) {
items.add(user)
}
}
adapter.items = items
}
@ -357,6 +366,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
userLivePeriods[itemId]?.also { text = formatLivePeriod(it) }
}
}
holder.topShadowDivider?.visibility = View.GONE
holder.bottomShadow?.visibility = View.GONE
holder.itemView.setOnClickListener {
selectDuration(itemId, isChat)
@ -373,6 +383,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
val locationViewContainer: View? = view.findViewById(R.id.location_view_container)
val description: TextView? = view.findViewById(R.id.description)
val textInArea: TextView? = view.findViewById(R.id.text_in_area)
val topShadowDivider: View? = view.findViewById(R.id.top_divider)
val bottomShadow: View? = view.findViewById(R.id.bottom_shadow)
}
}
@ -380,6 +391,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
companion object {
const val LOCATION_SHARED_REQUEST_CODE = 0
const val LOCATION_SHARING_CANCELED_CODE = 1
private const val TAG = "SetTimeDialogFragment"
private const val CHATS_KEY = "chats_key"

View file

@ -5,6 +5,7 @@ import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v4.content.ContextCompat
import android.support.v7.widget.ListPopupWindow
import android.support.v7.widget.Toolbar
import android.text.SpannableStringBuilder
@ -39,14 +40,14 @@ class SettingsDialogFragment : BaseDialogFragment() {
): View {
val mainView = inflater.inflate(R.layout.fragement_settings_dialog, parent)
val appBarLayout = mainView.findViewById<View>(R.id.app_bar_layout)
AndroidUtils.addStatusBarPadding19v(context!!, appBarLayout)
mainView.findViewById<Toolbar>(R.id.toolbar).apply {
navigationIcon = uiUtils.getThemedIcon(R.drawable.ic_arrow_back)
setNavigationOnClickListener { dismiss() }
}
val window = dialog.window
if (window != null && Build.VERSION.SDK_INT >= 21) {
window.statusBarColor = ContextCompat.getColor(app, R.color.card_bg_light)
}
var container = mainView.findViewById<ViewGroup>(R.id.gps_and_loc_container)
for (pref in settings.gpsAndLocPrefs) {
inflater.inflate(R.layout.item_with_desc_and_right_value, container, false).apply {
@ -91,6 +92,32 @@ class SettingsDialogFragment : BaseDialogFragment() {
container.addView(this)
}
container = mainView.findViewById<ViewGroup>(R.id.proxy_settings_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_proxy))
findViewById<ImageView>(R.id.icon_right).apply {
visibility = View.VISIBLE
setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_additional_option))
setOnClickListener {
activity?.supportFragmentManager?.also { ProxySettingsDialogFragment.showInstance(it, this@SettingsDialogFragment) }
}
}
findViewById<TextView>(R.id.title).text = getText(R.string.proxy)
val description = findViewById<TextView>(R.id.description).apply {
text = if (settings.proxyEnabled) getText(R.string.proxy_connected) else getText(R.string.proxy_disconnected)
}
val switcher = findViewById<Switch>(R.id.switcher).apply {
isChecked = app.settings.proxyEnabled
}
setOnClickListener {
val checked = !app.settings.proxyEnabled
switcher.isChecked = checked
settings.updateProxySetting(checked)
description.text = if (checked) getText(R.string.proxy_connected) else getText(R.string.proxy_disconnected)
}
container.addView(this)
}
shareAsDescription = mainView.findViewById<TextView>(R.id.share_as_description).apply {
text = getText(R.string.share_location_as_description)
setOnClickListener {
@ -213,6 +240,12 @@ class SettingsDialogFragment : BaseDialogFragment() {
}
}
}
ProxySettingsDialogFragment.PROXY_PREFERENCES_UPDATED_REQUEST_CODE -> {
view?.findViewById<ViewGroup>(R.id.proxy_settings_container)?.apply {
findViewById<TextView>(R.id.description)?.text = if (settings.proxyEnabled) getText(R.string.proxy_connected) else getText(R.string.proxy_disconnected)
findViewById<Switch>(R.id.switcher)?.isChecked = app.settings.proxyEnabled
}
}
}
}

View file

@ -0,0 +1,56 @@
package net.osmand.telegram.ui.views
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.util.AttributeSet
import android.view.View
class EmptyStateRecyclerView : RecyclerView {
private var emptyView: View? = null
private val emptyStateObserver = object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
checkIfEmpty()
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
checkIfEmpty()
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
checkIfEmpty()
}
}
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
context,
attrs,
defStyle
)
override fun setAdapter(adapter: RecyclerView.Adapter<*>?) {
val oldAdapter = getAdapter()
oldAdapter?.unregisterAdapterDataObserver(emptyStateObserver)
super.setAdapter(adapter)
adapter?.registerAdapterDataObserver(emptyStateObserver)
checkIfEmpty()
}
fun setEmptyView(emptyView: View) {
this.emptyView = emptyView
checkIfEmpty()
}
private fun checkIfEmpty() {
adapter?.apply {
val empty = itemCount == 0
visibility = if (empty) View.GONE else View.VISIBLE
emptyView?.visibility = if (empty) View.VISIBLE else View.GONE
}
}
}

View file

@ -106,6 +106,27 @@ object AndroidUtils {
}
}
fun getNavBarHeight(ctx: Context): Int {
if (!hasNavBar(ctx)) {
return 0
}
val landscape = ctx.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
val isSmartphone = ctx.resources.configuration.smallestScreenWidthDp < 600
if (isSmartphone && landscape) {
return 0
}
val name = if (landscape) "navigation_bar_height_landscape" else "navigation_bar_height"
val id = ctx.resources.getIdentifier(name, "dimen", "android")
return if (id > 0) {
ctx.resources.getDimensionPixelSize(id)
} else 0
}
fun hasNavBar(ctx: Context): Boolean {
val id = ctx.resources.getIdentifier("config_showNavigationBar", "bool", "android")
return id > 0 && ctx.resources.getBoolean(id)
}
fun enterToTransparentFullScreen(activity: Activity) {
if (Build.VERSION.SDK_INT >= 23) {
val window = activity.window

View file

@ -29,6 +29,7 @@ object OsmandLocationUtils {
const val SHARING_LINK = "https://play.google.com/store/apps/details?id=net.osmand.telegram"
const val ALTITUDE_PREFIX = "Altitude: "
const val BEARING_PREFIX = "Bearing: "
const val SPEED_PREFIX = "Speed: "
const val HDOP_PREFIX = "Horizontal precision: "
@ -169,7 +170,10 @@ object OsmandLocationUtils {
}
}
fun parseTextLocation(text: TdApi.FormattedText, botLocation: Boolean): MessageLocation {
fun parseTextLocation(text: TdApi.FormattedText, botLocation: Boolean): MessageLocation? {
if (botLocation && !text.text.startsWith(DEVICE_PREFIX) || !botLocation && !text.text.startsWith(USER_TEXT_LOCATION_TITLE)) {
return null
}
val res = if (botLocation) MessageOsmAndBotLocation() else MessageUserLocation()
res.type = LocationMessages.TYPE_TEXT
var locationNA = false

View file

@ -43,6 +43,7 @@
<asset source="voice/sl/sl_tts.js" destination="voice/sl-tts/sl_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/sv/sv_tts.js" destination="voice/sv-tts/sv_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/sw/sw_tts.js" destination="voice/sw-tts/sw_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/tr/tr_tts.js" destination="voice/tr-tts/tr_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/uk/uk_tts.js" destination="voice/uk-tts/uk_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/zh/zh_tts.js" destination="voice/zh-tts/zh_tts.js" mode="alwaysOverwriteOrCopy" />
<asset source="voice/zh-hk/zh-hk_tts.js" destination="voice/zh-hk-tts/zh-hk_tts.js" mode="overwriteOnlyIfExists" />

View file

@ -31,6 +31,7 @@ task printc {
android {
compileSdkVersion 27
buildToolsVersion "27.0.3"
// compileNdkVersion "android-ndk-r17b"
signingConfigs {
development {
@ -412,9 +413,9 @@ dependencies {
// turn off for now
//implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2'
// JS core
implementation group: 'org.mozilla', name: 'rhino', version: '1.7.9'
// size restrictions
// implementation 'com.ibm.icu:icu4j:50.1'
// implementation 'net.sf.trove4j:trove4j:3.0.3'

View file

@ -31,6 +31,7 @@
<string name="osm_live_annual_price">€7,99</string>
<string name="osm_live_annual_monthly_price">€2,66</string>
<string name="twitter_address">https://twitter.com/osmandapp</string>
<string name="reddit_address">https://www.reddit.com/r/OsmAnd</string>
<string name="facebook_address">https://www.facebook.com/osmandapp</string>
<string name="vk_address">https://vk.com/osmandapp</string>
<string name="default_changeset_add">Add</string>

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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