Merge branch 'master' of ssh://github.com/osmandapp/Osmand into RoutePreparationMenu
This commit is contained in:
commit
c824c1ba79
46 changed files with 2944 additions and 1426 deletions
|
@ -124,6 +124,9 @@ public class CollatorStringMatcher implements StringMatcher {
|
|||
public static boolean cstartsWith(Collator collator, String searchInParam, String theStart,
|
||||
boolean checkBeginning, boolean checkSpaces, boolean equals, boolean trim) {
|
||||
String searchIn = searchInParam.toLowerCase(Locale.getDefault());
|
||||
if (trim && searchIn.length() > 0) {
|
||||
searchIn += " ";
|
||||
}
|
||||
int searchInLength = searchIn.length();
|
||||
if (trim && searchInLength > 0 && theStart.length() > searchInLength) {
|
||||
theStart = theStart.substring(0, searchInLength);
|
||||
|
|
|
@ -194,7 +194,6 @@ public class Way extends Entity {
|
|||
}
|
||||
if (nodeIds != null) {
|
||||
nodeIds.reverse();
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ public class SearchUICore {
|
|||
SearchAmenityTypesAPI searchAmenityTypesAPI = new SearchAmenityTypesAPI(poiTypes);
|
||||
apis.add(searchAmenityTypesAPI);
|
||||
apis.add(new SearchCoreFactory.SearchAmenityByTypeAPI(poiTypes, searchAmenityTypesAPI));
|
||||
apis.add(new SearchCoreFactory.SearchAmenityByNameAPI(searchAmenityTypesAPI));
|
||||
apis.add(new SearchCoreFactory.SearchAmenityByNameAPI());
|
||||
SearchBuildingAndIntersectionsByStreetAPI streetsApi =
|
||||
new SearchCoreFactory.SearchBuildingAndIntersectionsByStreetAPI();
|
||||
apis.add(streetsApi);
|
||||
|
@ -500,7 +500,7 @@ public class SearchUICore {
|
|||
}
|
||||
currentSearchResult = collection;
|
||||
if (phrase.getSettings().isExportObjects()) {
|
||||
rm.createTestJSON(collection);
|
||||
//rm.createTestJSON(collection);
|
||||
}
|
||||
rm.searchFinished(phrase);
|
||||
if (onResultsComplete != null) {
|
||||
|
@ -841,7 +841,9 @@ public class SearchUICore {
|
|||
|
||||
@Override
|
||||
public int compare(SearchResult o1, SearchResult o2) {
|
||||
if (!ObjectType.isTopVisible(o1.objectType) && !ObjectType.isTopVisible(o2.objectType)) {
|
||||
boolean topVisible1 = ObjectType.isTopVisible(o1.objectType);
|
||||
boolean topVisible2 = ObjectType.isTopVisible(o2.objectType);
|
||||
if ((!topVisible1 && !topVisible2) || (topVisible1 && topVisible2)) {
|
||||
if (o1.isUnknownPhraseMatches() != o2.isUnknownPhraseMatches()) {
|
||||
return o1.isUnknownPhraseMatches() ? -1 : 1;
|
||||
} else if (o1.getFoundWordCount() != o2.getFoundWordCount()) {
|
||||
|
|
|
@ -316,6 +316,7 @@ public class SearchCoreFactory {
|
|||
String word = phrase.getUnknownWordToSearch();
|
||||
NameStringMatcher nm = phrase.getNameStringMatcher(word, phrase.isUnknownSearchWordComplete());
|
||||
NameStringMatcher wordEqualsMatcher = phrase.getNameStringMatcher(word, true);
|
||||
boolean firstUnknownWordMatches = word.equals(phrase.getUnknownSearchWord());
|
||||
resArray.clear();
|
||||
resArray = townCitiesQR.queryInBox(bbox, resArray);
|
||||
int limit = 0;
|
||||
|
@ -337,8 +338,8 @@ public class SearchCoreFactory {
|
|||
if (phrase.isEmptyQueryAllowed() && phrase.isEmpty()) {
|
||||
resultMatcher.publish(res);
|
||||
} else if (nm.matches(res.localeName) || nm.matches(res.otherNames)) {
|
||||
res.firstUnknownWordMatches = word.equals(phrase.getUnknownSearchWord());
|
||||
res.unknownPhraseMatches = wordEqualsMatcher.matches(res.localeName) || wordEqualsMatcher.matches(res.otherNames);
|
||||
res.firstUnknownWordMatches = firstUnknownWordMatches;
|
||||
res.unknownPhraseMatches = wordEqualsMatcher.matches(res.localeName);
|
||||
subSearchApiOrPublish(phrase, resultMatcher, res, cityApi);
|
||||
}
|
||||
if (limit++ > LIMIT * phrase.getRadiusLevel()) {
|
||||
|
@ -465,6 +466,7 @@ public class SearchCoreFactory {
|
|||
|
||||
String wordToSearch = phrase.getUnknownWordToSearch();
|
||||
NameStringMatcher wordEqualsMatcher = phrase.getNameStringMatcher(wordToSearch, true);
|
||||
boolean firstUnknownWordMatches = wordToSearch.equals(phrase.getUnknownSearchWord());
|
||||
while (offlineIterator.hasNext() && wordToSearch.length() > 0) {
|
||||
BinaryMapIndexReader r = offlineIterator.next();
|
||||
currentFile[0] = r;
|
||||
|
@ -478,8 +480,8 @@ public class SearchCoreFactory {
|
|||
}
|
||||
r.searchAddressDataByName(req);
|
||||
for (SearchResult res : immediateResults) {
|
||||
res.firstUnknownWordMatches = wordToSearch.equals(phrase.getUnknownSearchWord());
|
||||
res.unknownPhraseMatches = wordEqualsMatcher.matches(res.localeName) || wordEqualsMatcher.matches(res.otherNames);
|
||||
res.firstUnknownWordMatches = firstUnknownWordMatches;
|
||||
res.unknownPhraseMatches = wordEqualsMatcher.matches(res.localeName);
|
||||
if (res.objectType == ObjectType.STREET) {
|
||||
City ct = ((Street) res.object).getCity();
|
||||
phrase.countUnknownWordsMatch(res,
|
||||
|
@ -501,11 +503,9 @@ public class SearchCoreFactory {
|
|||
private static final int BBOX_RADIUS = 500 * 1000;
|
||||
private static final int BBOX_RADIUS_INSIDE = 10000 * 1000; // to support city search for basemap
|
||||
private static final int FIRST_WORD_MIN_LENGTH = 3;
|
||||
private SearchAmenityTypesAPI searchAmenityTypesAPI;
|
||||
|
||||
public SearchAmenityByNameAPI(SearchAmenityTypesAPI searchAmenityTypesAPI) {
|
||||
public SearchAmenityByNameAPI() {
|
||||
super(ObjectType.POI);
|
||||
this.searchAmenityTypesAPI = searchAmenityTypesAPI;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -574,7 +574,7 @@ public class SearchCoreFactory {
|
|||
}
|
||||
sr.priority = SEARCH_AMENITY_BY_NAME_PRIORITY;
|
||||
if (phraseMatcher != null) {
|
||||
sr.unknownPhraseMatches = phraseMatcher.matches(sr.localeName) || phraseMatcher.matches(sr.otherNames);
|
||||
sr.unknownPhraseMatches = phraseMatcher.matches(sr.localeName);
|
||||
}
|
||||
phrase.countUnknownWordsMatch(sr);
|
||||
sr.objectType = ObjectType.POI;
|
||||
|
@ -662,17 +662,19 @@ public class SearchCoreFactory {
|
|||
categories = types.getCategories(false);
|
||||
}
|
||||
List<AbstractPoiType> results = new ArrayList<AbstractPoiType>();
|
||||
NameStringMatcher nm =
|
||||
new NameStringMatcher(phrase.getUnknownSearchPhrase(), StringMatcherMode.CHECK_ONLY_STARTS_WITH_TRIM);
|
||||
|
||||
Set<String> filters = new HashSet<>();
|
||||
NameStringMatcher nm;
|
||||
String unknownSearchPhrase = phrase.getUnknownSearchPhrase();
|
||||
if (phrase.getUnknownSearchWord().length() < unknownSearchPhrase.length()) {
|
||||
nm = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_ONLY_STARTS_WITH_TRIM);
|
||||
} else {
|
||||
nm = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
|
||||
}
|
||||
for (AbstractPoiType pf : topVisibleFilters) {
|
||||
if (!phrase.isUnknownSearchWordPresent()
|
||||
|| nm.matches(pf.getTranslation())
|
||||
|| nm.matches(pf.getEnTranslation())
|
||||
|| nm.matches(pf.getSynonyms())) {
|
||||
results.add(pf);
|
||||
filters.add(pf.getTranslation());
|
||||
}
|
||||
}
|
||||
if (phrase.isUnknownSearchWordPresent()) {
|
||||
|
@ -682,7 +684,6 @@ public class SearchCoreFactory {
|
|||
|| nm.matches(c.getEnTranslation())
|
||||
|| nm.matches(c.getSynonyms()))) {
|
||||
results.add(c);
|
||||
filters.add(c.getTranslation());
|
||||
}
|
||||
}
|
||||
Iterator<Entry<String, PoiType>> it = translatedNames.entrySet().iterator();
|
||||
|
@ -690,7 +691,7 @@ public class SearchCoreFactory {
|
|||
Entry<String, PoiType> e = it.next();
|
||||
PoiType pt = e.getValue();
|
||||
if (pt.getCategory() != types.getOtherMapCategory()) {
|
||||
if (!results.contains(pt) && !filters.contains(pt.getTranslation())
|
||||
if (!results.contains(pt)
|
||||
&& (nm.matches(pt.getEnTranslation())
|
||||
|| nm.matches(pt.getTranslation())
|
||||
|| nm.matches(pt.getSynonyms()))) {
|
||||
|
@ -714,6 +715,8 @@ public class SearchCoreFactory {
|
|||
phrase.setUnknownSearchWordPoiTypes(new ArrayList<>(results));
|
||||
|
||||
if (resultMatcher != null) {
|
||||
String word = phrase.getUnknownSearchWord();
|
||||
NameStringMatcher startMatch = new NameStringMatcher(word, StringMatcherMode.CHECK_ONLY_STARTS_WITH);
|
||||
for (AbstractPoiType pt : results) {
|
||||
SearchResult res = new SearchResult(phrase);
|
||||
res.localeName = pt.getTranslation();
|
||||
|
@ -721,6 +724,7 @@ public class SearchCoreFactory {
|
|||
res.priority = SEARCH_AMENITY_TYPE_PRIORITY;
|
||||
res.priorityDistance = 0;
|
||||
res.objectType = ObjectType.POI_TYPE;
|
||||
res.firstUnknownWordMatches = startMatch.matches(res.localeName);
|
||||
resultMatcher.publish(res);
|
||||
}
|
||||
for (int i = 0; i < customPoiFilters.size(); i++) {
|
||||
|
@ -913,7 +917,7 @@ public class SearchCoreFactory {
|
|||
res.priority = SEARCH_AMENITY_BY_TYPE_PRIORITY;
|
||||
res.priorityDistance = 1;
|
||||
if (phraseMatcher != null) {
|
||||
boolean unknownPhraseMatches = phraseMatcher.matches(res.localeName) || phraseMatcher.matches(res.otherNames);
|
||||
boolean unknownPhraseMatches = phraseMatcher.matches(res.localeName);
|
||||
AbstractPoiType unknownSearchWordPoiType = phrase.getUnknownSearchWordPoiType();
|
||||
if (unknownPhraseMatches && unknownSearchWordPoiType != null) {
|
||||
unknownPhraseMatches = !phraseMatcher.matches(unknownSearchWordPoiType.getTranslation())
|
||||
|
@ -1037,7 +1041,7 @@ public class SearchCoreFactory {
|
|||
phrase.getNameStringMatcher().matches(res.localeName) ||
|
||||
phrase.getNameStringMatcher().matches(res.otherNames);
|
||||
if (phraseMatcher != null) {
|
||||
res.unknownPhraseMatches = phraseMatcher.matches(res.localeName) || phraseMatcher.matches(res.otherNames);
|
||||
res.unknownPhraseMatches = phraseMatcher.matches(res.localeName);
|
||||
}
|
||||
res.localeRelatedObjectName = c.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
|
||||
res.object = object;
|
||||
|
|
|
@ -9,6 +9,11 @@ public class SearchExportSettings {
|
|||
exportBuildings = true;
|
||||
}
|
||||
|
||||
public SearchExportSettings(boolean exportEmptyCities, boolean exportBuildings) {
|
||||
this.exportEmptyCities = exportEmptyCities;
|
||||
this.exportBuildings = exportBuildings;
|
||||
}
|
||||
|
||||
public boolean isExportEmptyCities() {
|
||||
return exportEmptyCities;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ public class SearchSettings {
|
|||
private boolean emptyQueryAllowed;
|
||||
private boolean sortByName;
|
||||
private SearchExportSettings exportSettings;
|
||||
//private SearchExportSettings exportSettings = new SearchExportSettings(false, false);
|
||||
|
||||
public SearchSettings(SearchSettings s) {
|
||||
if(s != null) {
|
||||
|
|
|
@ -526,11 +526,20 @@ public class GeoPointParserUtil {
|
|||
if (params.containsKey("z")) {
|
||||
zmPart = params.get("z");
|
||||
}
|
||||
String[] vls = silentSplit(path, ",");
|
||||
String[] vls = null;
|
||||
if(path.contains("@")) {
|
||||
path = path.substring(path.indexOf("@") + 1);
|
||||
if(path.contains(",")) {
|
||||
vls = silentSplit(path, ",");
|
||||
}
|
||||
}
|
||||
if(vls == null) {
|
||||
vls = silentSplit(path, ",");
|
||||
}
|
||||
|
||||
if (vls.length >= 2) {
|
||||
double lat = parseSilentDouble(vls[0]);
|
||||
double lon = parseSilentDouble(vls[1]);
|
||||
double lat = parseSilentDouble(vls[0], Double.NaN);
|
||||
double lon = parseSilentDouble(vls[1], Double.NaN);
|
||||
int zoom = GeoParsedPoint.NO_ZOOM;
|
||||
if (vls.length >= 3 || zmPart.length() > 0) {
|
||||
if (zmPart.length() == 0) {
|
||||
|
@ -543,7 +552,9 @@ public class GeoPointParserUtil {
|
|||
}
|
||||
zoom = parseZoom(zmPart);
|
||||
}
|
||||
return new GeoParsedPoint(lat, lon, zoom);
|
||||
if(!Double.isNaN(lat) && !Double.isNaN(lon)) {
|
||||
return new GeoParsedPoint(lat, lon, zoom);
|
||||
}
|
||||
}
|
||||
return new GeoParsedPoint(URLDecoder.decode(opath));
|
||||
}
|
||||
|
@ -566,13 +577,17 @@ public class GeoPointParserUtil {
|
|||
}
|
||||
|
||||
private static double parseSilentDouble(String zoom) {
|
||||
return parseSilentDouble(zoom, 0);
|
||||
}
|
||||
|
||||
private static double parseSilentDouble(String zoom, double vl) {
|
||||
try {
|
||||
if (zoom != null) {
|
||||
return Double.valueOf(zoom);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
return 0;
|
||||
return vl;
|
||||
}
|
||||
|
||||
private static int parseSilentInt(String zoom) {
|
||||
|
@ -739,8 +754,9 @@ public class GeoPointParserUtil {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return isGeoPoint() ? "GeoParsedPoint [lat=" + lat + ", lon=" + lon + ", zoom=" + zoom
|
||||
+ ", label=" + label + "]" : "GeoParsedPoint [query=" + query;
|
||||
return isGeoPoint() ?
|
||||
String.format("GeoParsedPoint [lat=%.5f, lon=%.5f, zoom=%d, label=%s]", lat, lon, zoom, label) :
|
||||
String.format("GeoParsedPoint [query=%s]",query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,19 @@ public class GeoPointParserUtilTest {
|
|||
GeoParsedPoint test = GeoPointParserUtil.parse("geo:0,0?q=86HJV99P%2B29");
|
||||
Assert.assertEquals(test.getQuery(), "86HJV99P+29");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoogleMaps() {
|
||||
// https://www.google.com/maps?daddr=Bahnhofplatz+3,+7000+Chur@46.853582,9.529903
|
||||
GeoParsedPoint actual = GeoPointParserUtil.parse(
|
||||
"https://www.google.com/maps?daddr=Bahnhofplatz+3,+7000+Chur");
|
||||
assertGeoPoint(actual, new GeoParsedPoint("Bahnhofplatz 3, 7000 Chur"));
|
||||
|
||||
actual = GeoPointParserUtil.parse(
|
||||
"https://www.google.com/maps?daddr=Bahnhofplatz+3,+7000+Chur@46.853582,9.529903");
|
||||
System.out.println(actual);
|
||||
assertGeoPoint(actual, new GeoParsedPoint(46.853582, 9.529903));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeoPoint() {
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
},
|
||||
"phrase": "parking",
|
||||
"results": [
|
||||
"Park (Leisure)",
|
||||
"Parking (Filter)",
|
||||
"Parking (Personal transport)",
|
||||
"Parking entrance (Personal transport)",
|
||||
"Parking fee (Charging station / Transportation)",
|
||||
"Parking fee: no (Charging station / Transportation)",
|
||||
|
@ -21,8 +20,8 @@
|
|||
"Parking tickets (Vending machine / Store)",
|
||||
"Parking tickets (Vending machine / Store)",
|
||||
"Parking time limit (Parking / Personal transport)",
|
||||
"Parking",
|
||||
"Parking",
|
||||
"Bicycle parking (Bicycle transport)",
|
||||
"Motorcycle parking (Personal transport)",
|
||||
"Parking",
|
||||
"Parking",
|
||||
"Parking",
|
||||
|
|
662
OsmAnd-java/src/test/resources/search/poi_biergarten.json
Normal file
662
OsmAnd-java/src/test/resources/search/poi_biergarten.json
Normal file
|
@ -0,0 +1,662 @@
|
|||
{
|
||||
"settings": {
|
||||
"lat": "51.04933",
|
||||
"lon": "13.73815",
|
||||
"radiusLevel": 1,
|
||||
"totalLimit": -1,
|
||||
"lang": "",
|
||||
"transliterateIfMissing": false,
|
||||
"emptyQueryAllowed": false,
|
||||
"sortByName": false
|
||||
},
|
||||
"phrase": "Biergarten",
|
||||
"results": [
|
||||
"Biergarten (Food)",
|
||||
"Biergarten Italienisches Dörfchen",
|
||||
"Biergarten Narrenhäus'l",
|
||||
"Biergarten Elbsegler",
|
||||
"Biergarten Elbsegler",
|
||||
"Biergarten",
|
||||
"Biergarten",
|
||||
"Biergarten",
|
||||
"Biergarten",
|
||||
"Biergarten"
|
||||
],
|
||||
"amenities": [
|
||||
{
|
||||
"lat": "51.02489",
|
||||
"lon": "13.69860",
|
||||
"id": 244538865,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"surface_fine_gravel": "fine_gravel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.09478",
|
||||
"lon": "13.84153",
|
||||
"id": 865332598,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Einkehr"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.01123",
|
||||
"lon": "13.67918",
|
||||
"id": 9712288200,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"website": "http://www.zur-linde-freital.de/",
|
||||
"operator": "Zur Linde",
|
||||
"image": "http://commons.wikimedia.org/wiki/File:Hotel_und_Gasthaus_Zur_Linde_Freital-Birkigt.jpg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Altes Wettbüro",
|
||||
"lat": "51.06472",
|
||||
"lon": "13.74467",
|
||||
"id": 11451975032,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Tu-Sa 17:00-22:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited",
|
||||
"outdoor_seating_yes": "yes",
|
||||
"outdoor_seating_filter_yes": "yes",
|
||||
"opening_hours": "Tu-Sa 17:00-22:00",
|
||||
"website": "http://www.altes-wettbuero.de",
|
||||
"phone": "+49 351 6588983",
|
||||
"operator": "Falk Gruß"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Carolaschlösschen",
|
||||
"lat": "51.03341",
|
||||
"lon": "13.76392",
|
||||
"id": 3704353318,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Mo-Su 11:00-24:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited",
|
||||
"opening_hours": "Mo-Su 11:00-24:00",
|
||||
"facebook": "https://www.facebook.com/carolaschloesschen/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.01251",
|
||||
"lon": "13.69407",
|
||||
"id": 562115695,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"name": "Torwirtschaft",
|
||||
"lat": "51.04156",
|
||||
"lon": "13.75139",
|
||||
"id": 517007905,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"website": "http://www.torwirtschaft-dresden.de",
|
||||
"facebook": "https://www.facebook.com/Torwirtschaft-der-Biergarten-f%C3%BCr-alle-Dynamofans-168677023169963/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Biergarten Italienisches Dörfchen",
|
||||
"lat": "51.05429",
|
||||
"lon": "13.73759",
|
||||
"id": 486232011,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"lat": "51.04261",
|
||||
"lon": "13.75229",
|
||||
"id": 98518191,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Körnergarten",
|
||||
"names": {
|
||||
"prefix": "Biergarten"
|
||||
},
|
||||
"lat": "51.05316",
|
||||
"lon": "13.81192",
|
||||
"id": 3704353594,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Mo-Su 11:00-24:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited",
|
||||
"opening_hours": "Mo-Su 11:00-24:00",
|
||||
"website": "http://www.koernergarten.de/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.06397",
|
||||
"lon": "13.79748",
|
||||
"id": 670742479,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"name": "Weingut Seifert",
|
||||
"lat": "51.11134",
|
||||
"lon": "13.66701",
|
||||
"id": 789740008,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"note": "not really a 'biergarten' :)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "50.98710",
|
||||
"lon": "13.65086",
|
||||
"id": 9037536542,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Zum Gründl"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.10538",
|
||||
"lon": "13.62622",
|
||||
"id": 9289210778,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Zum Bürgergarten"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.09459",
|
||||
"lon": "13.84170",
|
||||
"id": 5598697742,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Einkehr"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Trobischhof",
|
||||
"lat": "51.08649",
|
||||
"lon": "13.71338",
|
||||
"id": 409847251,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Demnitz Elbegarten",
|
||||
"lat": "51.05328",
|
||||
"lon": "13.81175",
|
||||
"id": 771102016,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_no": "no",
|
||||
"cuisine_german": "german",
|
||||
"website": "http://www.elbegarten.de"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Augustus Garten am Narrenhäusl",
|
||||
"lat": "51.05697",
|
||||
"lon": "13.74166",
|
||||
"id": 465538291,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"lat": "51.01529",
|
||||
"lon": "13.65107",
|
||||
"id": 7482890514,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Burgwartschänke"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "el Horst",
|
||||
"lat": "51.04361",
|
||||
"lon": "13.78979",
|
||||
"id": 559979958,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Oct-Apr: Mo-Fr 17:00-18:00+, Oct-Apr: Sa,PH 11:30-18:00+, May-Sep: Mo-Fr 15:00-18:00+, May-Sep: Sa,PH 11:30-18:00+",
|
||||
"additionalInfo": {
|
||||
"opening_hours": "Oct-Apr: Mo-Fr 17:00-18:00+, Oct-Apr: Sa,PH 11:30-18:00+, May-Sep: Mo-Fr 15:00-18:00+, May-Sep: Sa,PH 11:30-18:00+"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.07376",
|
||||
"lon": "13.70135",
|
||||
"id": 553613482,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Wirtshaus Lindenschänke"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wachstube",
|
||||
"lat": "51.04254",
|
||||
"lon": "13.75222",
|
||||
"id": 46060263,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "11:00+",
|
||||
"additionalInfo": {
|
||||
"wheelchair_no": "no",
|
||||
"opening_hours": "11:00+",
|
||||
"website": "https://www.torwirtschaft-dresden.de/wachstube/restaurant.php",
|
||||
"phone": "+49 351 4466975",
|
||||
"image": "https://commons.wikimedia.org/wiki/File:Torhaus_N_Grosser_Garten_Dresden-2.jpg",
|
||||
"wheelchair_description:de": "Zugang ins Gebäude nur über Stufen",
|
||||
"height": "5.7",
|
||||
"facebook": "https://www.facebook.com/Wachstube-im-Gro%C3%9Fen-Garten-Dresden-144180698984577/",
|
||||
"email": "info@wachstube-dresden.de"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.09050",
|
||||
"lon": "13.70555",
|
||||
"id": 6300849046,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Bäckerei Werner"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Biergarten Elbsegler",
|
||||
"lat": "51.05731",
|
||||
"lon": "13.73973",
|
||||
"id": 465318113,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Straußenwirtschaft Weingut Pesterwitz",
|
||||
"lat": "51.02883",
|
||||
"lon": "13.64144",
|
||||
"id": 478369183,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"website": "https://www.gut-pesterwitz.de/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Schillergarten",
|
||||
"lat": "51.05228",
|
||||
"lon": "13.80908",
|
||||
"id": 493702544,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Mo-Su 11:00-01:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"opening_hours": "Mo-Su 11:00-01:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.04111",
|
||||
"lon": "13.80554",
|
||||
"id": 5837244174,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Astloch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Spitzwegerich",
|
||||
"lat": "51.07767",
|
||||
"lon": "13.70757",
|
||||
"id": 412610355,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"toilets_wheelchair_no": "no"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Biergarten Goldener Anker",
|
||||
"lat": "51.10399",
|
||||
"lon": "13.62850",
|
||||
"id": 143015201,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Tu-Su,PH 11:00-21:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"opening_hours": "Tu-Su,PH 11:00-21:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Bottoms Up",
|
||||
"lat": "51.06516",
|
||||
"lon": "13.75615",
|
||||
"id": 1394136626,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"name": "Biergarten Narrenhäus'l",
|
||||
"lat": "51.05666",
|
||||
"lon": "13.74130",
|
||||
"id": 466763007,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"name": "Zum Schießhaus",
|
||||
"lat": "51.05464",
|
||||
"lon": "13.72727",
|
||||
"id": 326416539,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Mo-Su,PH 11:00-23:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"toilets_wheelchair_no": "no",
|
||||
"opening_hours": "Mo-Su,PH 11:00-23:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Palais Bistro",
|
||||
"lat": "51.05182",
|
||||
"lon": "13.73682",
|
||||
"id": 501015667,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Apr-Oct: Mo-Su 11:00-24:00, Nov-Mar: Mo-Th 12:00-14:30,17:30-24:00, Nov-Mar: Fr-Su 12:00-24:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"opening_hours": "Apr-Oct: Mo-Su 11:00-24:00, Nov-Mar: Mo-Th 12:00-14:30,17:30-24:00, Nov-Mar: Fr-Su 12:00-24:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Brauhaus am Waldschlößchen",
|
||||
"lat": "51.06778",
|
||||
"lon": "13.77786",
|
||||
"id": 594989978,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Mo-Su 11:00-01:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited",
|
||||
"opening_hours": "Mo-Su 11:00-01:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.00222",
|
||||
"lon": "13.68504",
|
||||
"id": 2469999180,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"name": "Biergarten Elbsegler",
|
||||
"lat": "51.05738",
|
||||
"lon": "13.73913",
|
||||
"id": 466539133,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"lat": "51.01010",
|
||||
"lon": "13.66208",
|
||||
"id": 7987508388,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"operator": "Zum goldenen Löwen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "50.99476",
|
||||
"lon": "13.72701",
|
||||
"id": 6765029580,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Eutschützer Mühle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "50.99295",
|
||||
"lon": "13.64362",
|
||||
"id": 6065174964,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Alte Schmiede"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Louisengarten",
|
||||
"lat": "51.06681",
|
||||
"lon": "13.75278",
|
||||
"id": 68516655,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Apr-Sep Su-Th 16:00+; Apr-Sep Fr,Sa 15:00+ || off \"Bei unfreundlichem Wetter\"",
|
||||
"additionalInfo": {
|
||||
"wheelchair_no": "no",
|
||||
"opening_hours": "Apr-Sep Su-Th 16:00+; Apr-Sep Fr,Sa 15:00+ || off \"Bei unfreundlichem Wetter\"",
|
||||
"website": "http://www.biergarten-dresden.de",
|
||||
"note": "Neustädter Winter Hüttn von Oktober-Dezember",
|
||||
"alt_name": "Neustädter Winter Hüttn"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.00871",
|
||||
"lon": "13.65959",
|
||||
"id": 9237211698,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"operator": "Akropolis"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.03435",
|
||||
"lon": "13.76042",
|
||||
"id": 595971770,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Apr-Oct: Mo-Fr 11:00-19:00; Sa-Su 10:00-19:00; PH 10:00-19:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"opening_hours": "Apr-Oct: Mo-Fr 11:00-19:00; Sa-Su 10:00-19:00; PH 10:00-19:00",
|
||||
"website": "https://www.grosser-garten-dresden.de/de/gaesteservice/gastronomie-shop/",
|
||||
"phone": "+49 152 37 00 67 53"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Landgut Hofewiese",
|
||||
"lat": "51.10989",
|
||||
"lon": "13.83207",
|
||||
"id": 8455509378,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Café & Restaurant Saite",
|
||||
"lat": "51.07636",
|
||||
"lon": "13.74825",
|
||||
"id": 577481323,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Mo-Fr 18:00-24:00, Su 10:00-15:00",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited",
|
||||
"opening_hours": "Mo-Fr 18:00-24:00, Su 10:00-15:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Alt-Dresden",
|
||||
"lat": "51.04977",
|
||||
"lon": "13.69881",
|
||||
"id": 970594717,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited",
|
||||
"phone": "0351 4135133"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.08677",
|
||||
"lon": "13.70081",
|
||||
"id": 413620001,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"lat": "50.98618",
|
||||
"lon": "13.63208",
|
||||
"id": 10355747978,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "Hirschbergschenke"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Fährgarten Johannstadt",
|
||||
"lat": "51.06151",
|
||||
"lon": "13.76679",
|
||||
"id": 4415013507072,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_yes": "yes",
|
||||
"outdoor_seating_yes": "yes",
|
||||
"outdoor_seating_filter_yes": "yes",
|
||||
"website": "http://www.faehrgarten.de/",
|
||||
"phone": "+49 351 4596262",
|
||||
"brewery_additional": "Radeberger",
|
||||
"email": "info@faehrgarten.de"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.02343",
|
||||
"lon": "13.73347",
|
||||
"id": 4563637454,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"name": "Besenwirtschaft Steinrücken",
|
||||
"lat": "51.11590",
|
||||
"lon": "13.62457",
|
||||
"id": 7474665554,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"website": "http://www.besenwirtschaft-steinruecken.de/index.html"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.05181",
|
||||
"lon": "13.81396",
|
||||
"id": 9819148822,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"operator": "WSV \"Am Blauen Wunder\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Zacke",
|
||||
"lat": "51.01300",
|
||||
"lon": "13.63618",
|
||||
"id": 7498805230,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance"
|
||||
},
|
||||
{
|
||||
"name": "Klotzscher Sommerwirtschaft",
|
||||
"lat": "51.11072",
|
||||
"lon": "13.76879",
|
||||
"id": 717794449,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Mo-Fr 17:00-23:00; Sa-Su 11:00-23:00; Nov-Mar off",
|
||||
"additionalInfo": {
|
||||
"opening_hours": "Mo-Fr 17:00-23:00; Sa-Su 11:00-23:00; Nov-Mar off",
|
||||
"website": "http://klotzschersommerwirtschaft.de",
|
||||
"phone": "+49 351 8804570",
|
||||
"fax": "+49 351 8902050",
|
||||
"email": "Kontakt@klotzscher-sommerwirtschaft.de",
|
||||
"capacity": "20"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Brauhaus Watzke",
|
||||
"lat": "51.07744",
|
||||
"lon": "13.71540",
|
||||
"id": 397976739,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"additionalInfo": {
|
||||
"wheelchair_limited": "limited",
|
||||
"toilets_wheelchair_no": "no"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Trachauer Sommergarten",
|
||||
"lat": "51.09166",
|
||||
"lon": "13.70289",
|
||||
"id": 1822089672,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "Mo-Su 17:00-21:00",
|
||||
"additionalInfo": {
|
||||
"opening_hours": "Mo-Su 17:00-21:00",
|
||||
"note": "Auch im Winter geöffnet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": "51.06520",
|
||||
"lon": "13.82406",
|
||||
"id": 11565282314,
|
||||
"subType": "biergarten",
|
||||
"type": "sustenance",
|
||||
"openingHours": "seasonal",
|
||||
"additionalInfo": {
|
||||
"outdoor_seating_yes": "yes",
|
||||
"outdoor_seating_filter_yes": "yes",
|
||||
"opening_hours": "seasonal"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
175
OsmAnd-telegram/res/values-be/strings.xml
Normal file
175
OsmAnd-telegram/res/values-be/strings.xml
Normal file
|
@ -0,0 +1,175 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources><string name="last_update_from_telegram">Апошняе абнаўленне з Telegram</string>
|
||||
<string name="enter_another_device_name">Абярыце імя, якое вы яшчэ не выкарыстоўвалі</string>
|
||||
<string name="device_added_successfully">%1$s дададзена.</string>
|
||||
<string name="shared_string_add">Дадаць</string>
|
||||
<string name="error_adding_new_device">Не атрымалася дадаць новую прыладу</string>
|
||||
<string name="enter_device_name_description">Максімальная даўжыня назвы новай прылады - 200 сімвалаў.</string>
|
||||
<string name="device_name_is_too_long">Назва прылады занадта доўгая</string>
|
||||
<string name="device_name_cannot_be_empty">Назва прылады не можа быць пустой</string>
|
||||
<string name="device_name">Назва прылады</string>
|
||||
<string name="shared_string_hide">Схаваць</string>
|
||||
<string name="share_location_as_description_second_line">Вы можаце стварыць і праглядзець ідэнтыфікатар прылады ў кліенце Тэлеграма, выкарыстоўваючы %1$s бота. %2$s</string>
|
||||
<string name="share_location_as_description">Калі вы хочаце падлучыць некалькі прылад да аднаго рахунка тэлеграм, то вам неабходна выкарыстаць розныя прылады, каб падзяліцца месцазнаходжаннем.</string>
|
||||
<string name="last_updated_location">Апошняе абнаўленне месцазнаходжання:</string>
|
||||
<string name="successfully_sent_and_updated">Паспяхова адпраўлена і абноўлена</string>
|
||||
<string name="not_possible_to_send_to_telegram_chats">Немагчыма адправіць у размову Тэлеграм:</string>
|
||||
<string name="waiting_for_response_from_telegram">Чаканне адказу ад Тэлеграм</string>
|
||||
<string name="sending_location_messages">Адпраўленне месцазнаходжання</string>
|
||||
<string name="initializing">Запуск</string>
|
||||
<string name="searching_for_gps">Пазіцыянаванне…</string>
|
||||
<string name="connecting_to_the_internet">Злучэнне з Інтэрнэтам</string>
|
||||
<string name="background_work_description">Змена параметраў аптымізацыі батарэі для стабілізацыі абмену інфармацыяй аб месцазнаходжанні.</string>
|
||||
<string name="background_work">Праца ў фонавым рэжыме</string>
|
||||
<string name="battery_optimization_description">Выключыць аптымізацыю батарэі для OsmAnd Telegram, каб прадухіліць нечаканае выключэнне фонавага рэжыму.</string>
|
||||
<string name="sharing_in_background">Абмен у фонавым рэжыме</string>
|
||||
<string name="go_to_settings">Перайсці ў налады</string>
|
||||
<string name="shared_string_later">Пазней</string>
|
||||
<string name="not_sent_yet">Яшчэ не адпраўлена</string>
|
||||
<string name="not_found_yet">Яшчэ не знойдзена</string>
|
||||
<string name="re_send_location">Пераадправіць звесткі аб месцазнаходжанні</string>
|
||||
<string name="last_available_location">Апошняе даступнае месца</string>
|
||||
<string name="sharing_status">"Статус абмену "</string>
|
||||
<string name="sharing_enabled">Абмен: Уключаны</string>
|
||||
<string name="shared_string_status">Статус</string>
|
||||
<string name="no_gps_connection">Злучэнне з GPS адсутнічае</string>
|
||||
<string name="no_internet_connection">Злучэнне з Інтэрнэтам адсутнічае</string>
|
||||
<string name="shared_string_disable">Выключыць</string>
|
||||
<string name="shared_string_save">Захаваць</string>
|
||||
<string name="add_device">Дадаць прыладу</string>
|
||||
<string name="share_location_as">Падзяліцца месцазнаходжаннем як</string>
|
||||
<string name="live_now_description">Кантакты і групы для абмену месцазнаходжаннем.</string>
|
||||
<string name="logout_from_osmand_telegram_descr">"Вы не зможаце падзяліцца сваім месцазнаходжаннем і ўбачыць месцазнаходжанне іншых. Сапраўды выйсці з OsmAnd Telegram\? "</string>
|
||||
<string name="logout_from_osmand_telegram">Выйсці з OsmAnd Telegram\?</string>
|
||||
<string name="shared_string_name">Імя</string>
|
||||
<string name="by_distance">Па адлегласці</string>
|
||||
<string name="by_name">Па імёнах</string>
|
||||
<string name="by_group">Па групе</string>
|
||||
<string name="shared_string_sort">Упарадкаваць</string>
|
||||
<string name="shared_string_sort_by">Упарадкаваць па</string>
|
||||
<string name="choose_osmand_desc">Абярыце версію OsmAnd, у якой кантакты будуць адлюстроўвацца на мапе.</string>
|
||||
<string name="choose_osmand">Абярыце версію OsmAnd для выкарыстання</string>
|
||||
<string name="disable_all_sharing_desc">Выключыць абмен для ўсіх абраных размоў (%1$d).</string>
|
||||
<string name="disable_all_sharing">Выключыць усе абмены</string>
|
||||
<string name="turn_off_all">Выключыце ўсе</string>
|
||||
<string name="shared_string_exit">Выйсці</string>
|
||||
<string name="time_ago">таму</string>
|
||||
<string name="last_response">Апошні адказ</string>
|
||||
<string name="shared_string_group">Група</string>
|
||||
<string name="logout_no_internet_msg">Падлучыцеся да Інтэрнэту, каб карэктна выйсці з Тэлеграм.</string>
|
||||
<string name="shared_string_close">Закрыць</string>
|
||||
<string name="disconnect_from_telegram_desc">Для таго, каб скасаваць абмен месцазнаходжаннем, адкрыйце Тэлеграм, перайдзіце ў Налады → Прыватнасць і бяспека → Сеансы і спыніце сеанс OsmAnd Telegram.</string>
|
||||
<string name="disconnect_from_telegram">Як выключыць абмен месцазнаходжаннем у OsmAnd праз Тэлеграм</string>
|
||||
<string name="logout_help_desc">Як выключыць абмен месцазнаходжаннем у OsmAnd праз Тэлеграм</string>
|
||||
<string name="connected_account">Падлучаны рахунак</string>
|
||||
<string name="shared_string_account">Рахунак</string>
|
||||
<string name="in_time">у %1$s</string>
|
||||
<string name="osmand_connect_desc">Абраць версію OsmAnd, якую OsmAnd Telegram будзе выкарыстоўваць для адлюстравання пазіцыі.</string>
|
||||
<string name="osmand_connect">Злучэнне з OsmAnd</string>
|
||||
<string name="location_history_desc">Схаваць кантакты, якія не перамяшчаліся пэўны час.</string>
|
||||
<string name="location_history">Гісторыя месцазнаходжанняў</string>
|
||||
<string name="stale_location_desc">Апошні раз кантакт рухаўся.</string>
|
||||
<string name="stale_location">Не рухаецца</string>
|
||||
<string name="send_my_location_desc">Вызначыць мінімальны інтэрвал для абмену інфармацыяй аб месцазнаходжанні.</string>
|
||||
<string name="send_my_location">Адправіць маё месцазнаходжанне</string>
|
||||
<string name="gps_and_location">Пазіцыя</string>
|
||||
<string name="sharing_time">"Час абмену "</string>
|
||||
<string name="expire_at">Сыходзіць</string>
|
||||
<string name="stop_sharing_all">Абмен уключаны (выключыць)</string>
|
||||
<string name="turn_off_location_sharing">Выключыць абмен</string>
|
||||
<string name="open_osmand">Адкрыць OsmAnd</string>
|
||||
<string name="shared_string_live">Дзейных</string>
|
||||
<string name="shared_string_bot">Бот</string>
|
||||
<string name="get_telegram_title">Рэгістрацыя ў Telegram</string>
|
||||
<string name="get_telegram_account_first">Для абмену вам неабходны рахунак Тэлеграм.</string>
|
||||
<string name="get_telegram_description_continue">Калі ласка, ўсталюйце Тэлеграм і наладзьце рахунак.</string>
|
||||
<string name="get_telegram_after_creating_account">Пасля гэтага вы зможаце выкарыстоўваць дадатак.</string>
|
||||
<string name="shared_string_all">Усе</string>
|
||||
<string name="shared_string_off">Выкл</string>
|
||||
<string name="already_registered_in_telegram">Вам неабходна мець рахунак Тэлеграм і нумар тэлефона</string>
|
||||
<string name="do_not_have_telegram">У мяне няма рахунка Тэлеграм</string>
|
||||
<string name="enter_phone_number">Увядзіце нумар тэлефона</string>
|
||||
<string name="enter_authentication_code">Увядзіце код аўтарызацыі</string>
|
||||
<string name="set_visible_time_for_all">Вызначце бачны час для ўсіх</string>
|
||||
<string name="hours_and_minutes_format">%1$d г %2$d хв</string>
|
||||
<string name="minutes_format">%1$d хв</string>
|
||||
<string name="hours_format">%1$d г</string>
|
||||
<string name="shared_string_install">Усталяваць</string>
|
||||
<string name="shared_string_share">Падзяліцца</string>
|
||||
<string name="shared_string_back">Назад</string>
|
||||
<string name="visible_time_for_all">Бачны для ўсіх час</string>
|
||||
<string name="set_time_description">Задайце час, што будуць бачыць абраныя вамі кантакты і групы ў рэжыме рэальнага часу.</string>
|
||||
<string name="set_time">Задаць час</string>
|
||||
<string name="location_sharing_description">Абярыце кантакты і групы, з якімі хочаце абменьвацца вашым месцазнаходжаннем.</string>
|
||||
<string name="my_location_search_hint">Пошук: група альбо кантакт</string>
|
||||
<string name="start_location_sharing">Падзяліцца месцазнаходжаннем</string>
|
||||
<string name="show_on_map">Паказаць на мапе</string>
|
||||
<string name="app_name">ОsmAnd Telegram</string>
|
||||
<string name="phone_number_title">Нумар тэлефона</string>
|
||||
<string name="phone_number_descr">Нумар тэлефона ў міжнародным фармаце</string>
|
||||
<string name="shared_string_password">Пароль</string>
|
||||
<string name="enter_code">Увядзіце код</string>
|
||||
<string name="authentication_code">Код аўтэнтыфікацыі</string>
|
||||
<string name="authentication_code_descr">Тэлеграм адправіў вам код для OsmAnd для ўваходу ў рахунак.</string>
|
||||
<string name="enter_password">Увядзіце пароль</string>
|
||||
<string name="password_descr">Пароль Тэлеграм</string>
|
||||
<string name="shared_string_login">Увайсці</string>
|
||||
<string name="shared_string_logout">Выйсці</string>
|
||||
<string name="initialization">Запуск</string>
|
||||
<string name="logging_out">Выхад</string>
|
||||
<string name="closing">Закрыццё</string>
|
||||
<string name="gps_network_not_enabled">Уключыць \"Месцазнаходжанне\"\?</string>
|
||||
<string name="not_logged_in">Вы не ўвайшлі</string>
|
||||
<string name="shared_string_continue">Працягнуць</string>
|
||||
<string name="shared_string_cancel">Скасаваць</string>
|
||||
<string name="shared_string_settings">Налады</string>
|
||||
<string name="no_location_permission">Дадатак не мае дазволу на доступ да даных аб месцазнаходжанні.</string>
|
||||
<string name="gps_not_available">Калі ласка, ўключыце \"Месцазнаходжанне\" ў сістэмных наладах</string>
|
||||
<string name="location_service_no_gps_available">Абярыце аднаго пастаўшчыка месцазнаходжання, каб падзяліцца сваім месцазнаходжаннем.</string>
|
||||
<string name="osmand_service">Фонавы рэжым</string>
|
||||
<string name="osmand_service_descr">OsmAnd Telegram працуе ў фонавым рэжыме з выключаным экранам.</string>
|
||||
<string name="shared_string_distance">Адлегласць</string>
|
||||
<string name="share_location">Падзяліцца месцазнаходжаннем</string>
|
||||
<string name="sharing_location">Абмен данымі аб месцазнаходжанні</string>
|
||||
<string name="process_service">Сэрвіс OsmAnd Telegram</string>
|
||||
<string name="osmand_logo">Лагатып OsmAnd</string>
|
||||
<string name="install_osmand_dialog_message">Спачатку вам неабходна ўсталяваць бясплатную ці платную версію OsmAnd</string>
|
||||
<string name="install_osmand">Усталяваць OsmAnd</string>
|
||||
<string name="show_users_on_map">Паказаць карыстальнікаў на мапе</string>
|
||||
<string name="active_chats">Актыўныя размовы</string>
|
||||
<string name="shared_string_authorization">Аўтарызацыя</string>
|
||||
<string name="shared_string_authorization_descr">Калі ласка, увядзіце ваш нумар тэлефона, звязаны з Тэлеграм, ў міжнародным фармаце</string>
|
||||
<string name="shared_string_welcome">Вітаем</string>
|
||||
|
||||
<string name="yard">ярд</string>
|
||||
<string name="foot">фут</string>
|
||||
<string name="mile">міл</string>
|
||||
<string name="km">км</string>
|
||||
<string name="m">м</string>
|
||||
<string name="nm">м.мілі</string>
|
||||
<string name="min_mile">хв/м</string>
|
||||
<string name="min_km">хв/км</string>
|
||||
<string name="nm_h">м.міль/г</string>
|
||||
<string name="m_s">м/с</string>
|
||||
<string name="km_h">км/г</string>
|
||||
<string name="mile_per_hour">м/г</string>
|
||||
<string name="si_kmh">Кіламетраў за гадзіну</string>
|
||||
<string name="si_mph">Міляў за гадзіну</string>
|
||||
<string name="si_m_s">Метраў за секунду</string>
|
||||
<string name="si_min_km">Хвілін на кіламетар</string>
|
||||
<string name="si_min_m">Хвілін на мілю</string>
|
||||
<string name="si_nm_h">Марскіх міль за гадзіну (вузлоў)</string>
|
||||
<string name="si_mi_feet">Мілі/футы</string>
|
||||
<string name="si_mi_yard">Мілі/ярды</string>
|
||||
<string name="si_km_m">Кіламетры/метры</string>
|
||||
<string name="si_nm">Марскія мілі</string>
|
||||
<string name="si_mi_meters">Мілі/метры</string>
|
||||
<string name="shared_string_hour_short">г</string>
|
||||
<string name="shared_string_minute_short">хвіл</string>
|
||||
<string name="shared_string_second_short">сек</string>
|
||||
<string name="welcome_descr"><b>Абмен месцазнаходжаннем OsmAnd</b> Дае магчымасць дзяліцца сваім месцазнаходжаннем і бачыць месцазнаходжанне іншых у OsmAnd.<br/><br/> Дадатак выкарыстоўвае Telegram API, таму вам неабходны рахунак Тэлеграм.</string>
|
||||
<string name="my_location">Маё месцазнаходжанне</string>
|
||||
<string name="live_now">Зараз дзейнічае</string>
|
||||
|
||||
|
||||
</resources>
|
|
@ -19,4 +19,5 @@
|
|||
<string name="re_send_location">بازفرستی موقعیت</string>
|
||||
<string name="sharing_enabled">اشتراکگذاری: فعال</string>
|
||||
<string name="shared_string_status">وضعیت</string>
|
||||
<string name="shared_string_close">بستن</string>
|
||||
</resources>
|
||||
|
|
29
OsmAnd-telegram/res/values-he/strings.xml
Normal file
29
OsmAnd-telegram/res/values-he/strings.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources><string name="last_update_from_telegram">עדכון אחרון מטלגרם</string>
|
||||
<string name="enter_another_device_name">נא לבחור שם שלא השתמשת בו עדיין</string>
|
||||
<string name="device_added_successfully">%1$s נוסף.</string>
|
||||
<string name="shared_string_add">הוספה</string>
|
||||
<string name="error_adding_new_device">לא ניתן להוסיף מכשיר חדש</string>
|
||||
<string name="enter_device_name_description">נא לתת שם באורך של עד 200 תווים למכשיר החדש שלך.</string>
|
||||
<string name="device_name_is_too_long">שם המכשיר ארוך מדי</string>
|
||||
<string name="device_name_cannot_be_empty">שם המכשיר לא יכול להישאר ריק</string>
|
||||
<string name="device_name">שם המכשיר</string>
|
||||
<string name="shared_string_hide">הסתרה</string>
|
||||
<string name="share_location_as_description_second_line">ניתן ליצור ולצפות במזהה ההתקן בלקוח הטלגרם הזה באמצעות רובוט ההתכתבות %1$s. %2$s</string>
|
||||
<string name="share_location_as_description">אם ברצונך לחבר מגוון מכשירים לחשבון טלגרם אחד, עליך להשתמש במכשיר אחר כדי לשתף את המיקום שלך.</string>
|
||||
<string name="last_updated_location">המיקום האחרון שעודכן:</string>
|
||||
<string name="successfully_sent_and_updated">נשלח ועודכן בהצלחה</string>
|
||||
<string name="not_possible_to_send_to_telegram_chats">אין אפשרות לשלוח להתכתבויות בטלגרם:</string>
|
||||
<string name="send_location_as">שליחת מיקום בתור</string>
|
||||
<string name="send_location_as_descr">נא לבחור כיצד הודעות עם המיקום שלך תיראנה.</string>
|
||||
<string name="shared_string_map">מפה</string>
|
||||
<string name="shared_string_text">טקסט</string>
|
||||
<string name="map_and_text">מפה וטקסט</string>
|
||||
<string name="waiting_for_response_from_telegram">בהמתנה לתגובה מטלגרם</string>
|
||||
<string name="sending_location_messages">המיקום נשלח</string>
|
||||
<string name="initializing">מופעל</string>
|
||||
<string name="searching_for_gps">מתבצע איתור המיקום…</string>
|
||||
<string name="connecting_to_the_internet">מתבצעת התחברות לאינטרנט</string>
|
||||
<string name="background_work_description">ניתן לשנות הגדרות מיטוב סוללה כדי לייצב את שיתוף המיקום.</string>
|
||||
<string name="background_work">עבודת רקע</string>
|
||||
</resources>
|
|
@ -174,4 +174,9 @@
|
|||
|
||||
|
||||
<string name="last_update_from_telegram">Siste oppdatering fra Telegram</string>
|
||||
<string name="send_location_as">Send plassering som</string>
|
||||
<string name="send_location_as_descr">Velg hvordan meldinger med din plassering skal se ut.</string>
|
||||
<string name="shared_string_map">Kart</string>
|
||||
<string name="shared_string_text">Tekst</string>
|
||||
<string name="map_and_text">Kart og tekst</string>
|
||||
</resources>
|
||||
|
|
|
@ -159,4 +159,5 @@
|
|||
<string name="my_location">Моя позиція</string>
|
||||
<string name="send_my_location_desc">Встановіть мінімальний інтервал між надсиланням позиції.</string>
|
||||
<string name="expire_at">Діє до</string>
|
||||
<string name="last_update_from_telegram">Нещодавнє оновлення з Telegram</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<resources>
|
||||
<string name="send_location_as">Send location as</string>
|
||||
<string name="send_location_as_descr">Choose how messages with your location will look like.</string>
|
||||
<string name="shared_string_map">Map</string>
|
||||
<string name="shared_string_text">Text</string>
|
||||
<string name="map_and_text">Map and text</string>
|
||||
<string name="last_update_from_telegram">Last update from Telegram</string>
|
||||
<string name="enter_another_device_name">Pick a name you haven\'t already used</string>
|
||||
<string name="device_added_successfully">%1$s added.</string>
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.support.annotation.DrawableRes
|
|||
import android.support.annotation.StringRes
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import net.osmand.data.LatLon
|
||||
import net.osmand.telegram.helpers.OsmandAidlHelper
|
||||
import net.osmand.telegram.helpers.TelegramHelper
|
||||
import net.osmand.telegram.utils.AndroidUtils
|
||||
|
@ -43,9 +42,15 @@ private val LOC_HISTORY_VALUES_SEC = listOf(
|
|||
24 * 60 * 60L
|
||||
)
|
||||
|
||||
const val SHARE_TYPE_MAP = "Map"
|
||||
const val SHARE_TYPE_TEXT = "Text"
|
||||
const val SHARE_TYPE_MAP_AND_TEXT = "Map_and_text"
|
||||
private val SHARE_TYPE_VALUES = listOf(SHARE_TYPE_MAP, SHARE_TYPE_TEXT, SHARE_TYPE_MAP_AND_TEXT)
|
||||
|
||||
private const val SEND_MY_LOC_DEFAULT_INDEX = 6
|
||||
private const val STALE_LOC_DEFAULT_INDEX = 4
|
||||
private const val LOC_HISTORY_DEFAULT_INDEX = 2
|
||||
private const val STALE_LOC_DEFAULT_INDEX = 0
|
||||
private const val LOC_HISTORY_DEFAULT_INDEX = 7
|
||||
private const val SHARE_TYPE_DEFAULT_INDEX = 2
|
||||
|
||||
private const val SETTINGS_NAME = "osmand_telegram_settings"
|
||||
|
||||
|
@ -60,6 +65,7 @@ private const val SPEED_CONSTANTS_KEY = "speed_constants"
|
|||
private const val SEND_MY_LOC_INTERVAL_KEY = "send_my_loc_interval"
|
||||
private const val STALE_LOC_TIME_KEY = "stale_loc_time"
|
||||
private const val LOC_HISTORY_TIME_KEY = "loc_history_time"
|
||||
private const val SHARE_TYPE_KEY = "share_type"
|
||||
|
||||
private const val APP_TO_CONNECT_PACKAGE_KEY = "app_to_connect_package"
|
||||
|
||||
|
@ -94,13 +100,14 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
var sendMyLocInterval = SEND_MY_LOC_VALUES_SEC[SEND_MY_LOC_DEFAULT_INDEX]
|
||||
var staleLocTime = STALE_LOC_VALUES_SEC[STALE_LOC_DEFAULT_INDEX]
|
||||
var locHistoryTime = LOC_HISTORY_VALUES_SEC[LOC_HISTORY_DEFAULT_INDEX]
|
||||
var shareTypeValue = SHARE_TYPE_VALUES[SHARE_TYPE_DEFAULT_INDEX]
|
||||
|
||||
var appToConnectPackage = ""
|
||||
private set
|
||||
|
||||
var liveNowSortType = LiveNowSortType.SORT_BY_GROUP
|
||||
|
||||
val gpsAndLocPrefs = listOf(SendMyLocPref(), StaleLocPref(), LocHistoryPref())
|
||||
val gpsAndLocPrefs = listOf(SendMyLocPref(), StaleLocPref(), LocHistoryPref(), ShareTypePref())
|
||||
|
||||
var batteryOptimisationAsked = false
|
||||
|
||||
|
@ -113,6 +120,8 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
|
||||
fun isSharingLocationToChat(chatId: Long) = shareChatsInfo.containsKey(chatId)
|
||||
|
||||
fun isSharingLocationToUser(userId: Int) = shareChatsInfo.values.any { it.userId == userId }
|
||||
|
||||
fun hasAnyChatToShowOnMap() = !hiddenOnMapChats.containsAll(getLiveNowChats())
|
||||
|
||||
fun isShowingChatOnMap(chatId: Long) = !hiddenOnMapChats.contains(chatId)
|
||||
|
@ -132,35 +141,33 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
addActiveTime: Long = ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0]
|
||||
) {
|
||||
if (share) {
|
||||
val lp: Long = when {
|
||||
livePeriod < TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC -> TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC.toLong()
|
||||
else -> livePeriod
|
||||
}
|
||||
var shareChatInfo = shareChatsInfo[chatId]
|
||||
if (shareChatInfo == null) {
|
||||
shareChatInfo = ShareChatInfo()
|
||||
}
|
||||
val currentTime = System.currentTimeMillis() / 1000
|
||||
val user = app.telegramHelper.getCurrentUser()
|
||||
if (user != null && currentSharingMode != user.id.toString() && shareChatInfo.start == -1L) {
|
||||
shareChatInfo.shouldSendViaBotMessage = true
|
||||
val chat = app.telegramHelper.getChat(chatId)
|
||||
if (chat != null && (chat.type is TdApi.ChatTypePrivate || chat.type is TdApi.ChatTypeSecret)) {
|
||||
shareChatInfo.userId = app.telegramHelper.getUserIdFromChatType(chat.type)
|
||||
}
|
||||
|
||||
shareChatInfo.chatId = chatId
|
||||
shareChatInfo.start = currentTime
|
||||
if (shareChatInfo.livePeriod == -1L) {
|
||||
shareChatInfo.livePeriod = lp
|
||||
}
|
||||
shareChatInfo.userSetLivePeriod = lp
|
||||
shareChatInfo.userSetLivePeriodStart = currentTime
|
||||
shareChatInfo.currentMessageLimit = currentTime + Math.min(lp, TelegramHelper.MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC.toLong())
|
||||
shareChatInfo.additionalActiveTime = addActiveTime
|
||||
updateChatShareInfo(shareChatInfo, livePeriod, addActiveTime)
|
||||
shareChatsInfo[chatId] = shareChatInfo
|
||||
} else {
|
||||
shareChatsInfo.remove(chatId)
|
||||
}
|
||||
}
|
||||
|
||||
fun shareLocationToUser(
|
||||
userId: Int,
|
||||
livePeriod: Long = DEFAULT_VISIBLE_TIME_SECONDS,
|
||||
addActiveTime: Long = ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0]
|
||||
) {
|
||||
val shareChatInfo = ShareChatInfo()
|
||||
shareChatInfo.userId = userId
|
||||
updateChatShareInfo(shareChatInfo, livePeriod, addActiveTime)
|
||||
app.telegramHelper.createPrivateChatWithUser(userId, shareChatInfo, shareChatsInfo)
|
||||
}
|
||||
|
||||
fun updateShareDevices(list: List<DeviceBot>) {
|
||||
shareDevices = list.toHashSet()
|
||||
}
|
||||
|
@ -195,9 +202,7 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
return false
|
||||
}
|
||||
|
||||
fun getShareDeviceNameWithExternalId(externalId: String): String? {
|
||||
return shareDevices.singleOrNull { it.externalId == externalId }?.deviceName
|
||||
}
|
||||
fun getCurrentSharingDevice() = shareDevices.singleOrNull { it.externalId == currentSharingMode }
|
||||
|
||||
fun getLastSuccessfulSendTime() = shareChatsInfo.values.maxBy { it.lastSuccessfulSendTimeMs }?.lastSuccessfulSendTimeMs ?: -1
|
||||
|
||||
|
@ -235,9 +240,14 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
fun updateShareInfo(message: TdApi.Message) {
|
||||
val shareChatInfo = shareChatsInfo[message.chatId]
|
||||
val content = message.content
|
||||
if (shareChatInfo != null && content is TdApi.MessageLocation) {
|
||||
shareChatInfo.currentMessageId = message.id
|
||||
shareChatInfo.lastSuccessfulLocation = LatLon(content.location.latitude, content.location.longitude)
|
||||
if (shareChatInfo != null) {
|
||||
when (content) {
|
||||
is TdApi.MessageLocation -> shareChatInfo.currentMapMessageId = message.id
|
||||
is TdApi.MessageText -> {
|
||||
shareChatInfo.currentTextMessageId = message.id
|
||||
shareChatInfo.updateTextMessageId++
|
||||
}
|
||||
}
|
||||
shareChatInfo.lastSuccessfulSendTimeMs = Math.max(message.editDate, message.date) * 1000L
|
||||
}
|
||||
}
|
||||
|
@ -271,6 +281,31 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateChatShareInfo(
|
||||
shareChatInfo: ShareChatInfo,
|
||||
livePeriod: Long = DEFAULT_VISIBLE_TIME_SECONDS,
|
||||
addActiveTime: Long = ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0]
|
||||
) {
|
||||
val lp: Long = when {
|
||||
livePeriod < TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC -> TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC.toLong()
|
||||
else -> livePeriod
|
||||
}
|
||||
val currentTime = System.currentTimeMillis() / 1000
|
||||
val user = app.telegramHelper.getCurrentUser()
|
||||
if (user != null && currentSharingMode != user.id.toString() && shareChatInfo.start == -1L) {
|
||||
shareChatInfo.shouldSendViaBotMessage = true
|
||||
}
|
||||
|
||||
shareChatInfo.start = currentTime
|
||||
if (shareChatInfo.livePeriod == -1L) {
|
||||
shareChatInfo.livePeriod = lp
|
||||
}
|
||||
shareChatInfo.userSetLivePeriod = lp
|
||||
shareChatInfo.userSetLivePeriodStart = currentTime
|
||||
shareChatInfo.currentMessageLimit = currentTime + Math.min(lp, TelegramHelper.MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC.toLong())
|
||||
shareChatInfo.additionalActiveTime = addActiveTime
|
||||
}
|
||||
|
||||
private fun getNewSharingStatusHistoryItem(): SharingStatus {
|
||||
return SharingStatus().apply {
|
||||
statusChangeTime = System.currentTimeMillis()
|
||||
|
@ -357,9 +392,14 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
}
|
||||
|
||||
fun onDeleteLiveMessages(chatId: Long, messages: List<Long>) {
|
||||
val currentMessageId = shareChatsInfo[chatId]?.currentMessageId
|
||||
if (messages.contains(currentMessageId)) {
|
||||
shareChatsInfo[chatId]?.currentMessageId = -1
|
||||
val currentMapMessageId = shareChatsInfo[chatId]?.currentMapMessageId
|
||||
if (messages.contains(currentMapMessageId)) {
|
||||
shareChatsInfo[chatId]?.currentMapMessageId = -1
|
||||
}
|
||||
val currentTextMessageId = shareChatsInfo[chatId]?.currentTextMessageId
|
||||
if (messages.contains(currentTextMessageId)) {
|
||||
shareChatsInfo[chatId]?.currentTextMessageId = -1
|
||||
shareChatsInfo[chatId]?.updateTextMessageId = 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,6 +423,8 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
edit.putLong(STALE_LOC_TIME_KEY, staleLocTime)
|
||||
edit.putLong(LOC_HISTORY_TIME_KEY, locHistoryTime)
|
||||
|
||||
edit.putString(SHARE_TYPE_KEY, shareTypeValue)
|
||||
|
||||
edit.putString(APP_TO_CONNECT_PACKAGE_KEY, appToConnectPackage)
|
||||
|
||||
edit.putString(LIVE_NOW_SORT_TYPE_KEY, liveNowSortType.name)
|
||||
|
@ -433,6 +475,8 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
staleLocTime = prefs.getLong(STALE_LOC_TIME_KEY, staleLocDef)
|
||||
val locHistoryDef = LOC_HISTORY_VALUES_SEC[LOC_HISTORY_DEFAULT_INDEX]
|
||||
locHistoryTime = prefs.getLong(LOC_HISTORY_TIME_KEY, locHistoryDef)
|
||||
val shareTypeDef = SHARE_TYPE_VALUES[SHARE_TYPE_DEFAULT_INDEX]
|
||||
shareTypeValue = prefs.getString(SHARE_TYPE_KEY, shareTypeDef)
|
||||
|
||||
currentSharingMode = prefs.getString(SHARING_MODE_KEY, "")
|
||||
|
||||
|
@ -472,10 +516,13 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
shareChatsInfo.forEach { (chatId, chatInfo) ->
|
||||
val obj = JSONObject()
|
||||
obj.put(ShareChatInfo.CHAT_ID_KEY, chatId)
|
||||
obj.put(ShareChatInfo.USER_ID_KEY, chatInfo.userId)
|
||||
obj.put(ShareChatInfo.START_KEY, chatInfo.start)
|
||||
obj.put(ShareChatInfo.LIVE_PERIOD_KEY, chatInfo.livePeriod)
|
||||
obj.put(ShareChatInfo.LIMIT_KEY, chatInfo.currentMessageLimit)
|
||||
obj.put(ShareChatInfo.CURRENT_MESSAGE_ID_KEY, chatInfo.currentMessageId)
|
||||
obj.put(ShareChatInfo.UPDATE_TEXT_MESSAGE_ID_KEY, chatInfo.updateTextMessageId)
|
||||
obj.put(ShareChatInfo.CURRENT_MAP_MESSAGE_ID_KEY, chatInfo.currentMapMessageId)
|
||||
obj.put(ShareChatInfo.CURRENT_TEXT_MESSAGE_ID_KEY, chatInfo.currentTextMessageId)
|
||||
obj.put(ShareChatInfo.USER_SET_LIVE_PERIOD_KEY, chatInfo.userSetLivePeriod)
|
||||
obj.put(ShareChatInfo.USER_SET_LIVE_PERIOD_START_KEY, chatInfo.userSetLivePeriodStart)
|
||||
obj.put(ShareChatInfo.LAST_SUCCESSFUL_SEND_TIME_KEY, chatInfo.lastSuccessfulSendTimeMs)
|
||||
|
@ -493,10 +540,13 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
val obj = json.getJSONObject(i)
|
||||
val shareInfo = ShareChatInfo().apply {
|
||||
chatId = obj.optLong(ShareChatInfo.CHAT_ID_KEY)
|
||||
userId = obj.optInt(ShareChatInfo.USER_ID_KEY)
|
||||
start = obj.optLong(ShareChatInfo.START_KEY)
|
||||
livePeriod = obj.optLong(ShareChatInfo.LIVE_PERIOD_KEY)
|
||||
currentMessageLimit = obj.optLong(ShareChatInfo.LIMIT_KEY)
|
||||
currentMessageId = obj.optLong(ShareChatInfo.CURRENT_MESSAGE_ID_KEY)
|
||||
updateTextMessageId = obj.optInt(ShareChatInfo.UPDATE_TEXT_MESSAGE_ID_KEY)
|
||||
currentMapMessageId = obj.optLong(ShareChatInfo.CURRENT_MAP_MESSAGE_ID_KEY)
|
||||
currentTextMessageId = obj.optLong(ShareChatInfo.CURRENT_TEXT_MESSAGE_ID_KEY)
|
||||
userSetLivePeriod = obj.optLong(ShareChatInfo.USER_SET_LIVE_PERIOD_KEY)
|
||||
userSetLivePeriodStart = obj.optLong(ShareChatInfo.USER_SET_LIVE_PERIOD_START_KEY)
|
||||
lastSuccessfulSendTimeMs = obj.optLong(ShareChatInfo.LAST_SUCCESSFUL_SEND_TIME_KEY)
|
||||
|
@ -572,6 +622,41 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
}
|
||||
}
|
||||
|
||||
inner class ShareTypePref : DurationPref(
|
||||
R.drawable.ic_action_location_history,
|
||||
R.string.send_location_as,
|
||||
R.string.send_location_as_descr,
|
||||
emptyList()
|
||||
) {
|
||||
|
||||
override fun getCurrentValue(): String {
|
||||
return getTextValue(shareTypeValue)
|
||||
}
|
||||
|
||||
override fun setCurrentValue(index: Int) {
|
||||
val newSharingType = SHARE_TYPE_VALUES[index]
|
||||
if (shareTypeValue != newSharingType && app.telegramHelper.getCurrentUser()?.id.toString() != currentSharingMode) {
|
||||
shareChatsInfo.forEach { (_, shareInfo) ->
|
||||
shareInfo.shouldSendViaBotMessage = true
|
||||
}
|
||||
}
|
||||
shareTypeValue = newSharingType
|
||||
}
|
||||
|
||||
override fun getMenuItems(): List<String> {
|
||||
return SHARE_TYPE_VALUES.map { getTextValue(it) }
|
||||
}
|
||||
|
||||
private fun getTextValue(shareType: String): String {
|
||||
return when (shareType) {
|
||||
SHARE_TYPE_MAP -> app.getString(R.string.shared_string_map)
|
||||
SHARE_TYPE_TEXT -> app.getString(R.string.shared_string_text)
|
||||
SHARE_TYPE_MAP_AND_TEXT -> app.getString(R.string.map_and_text)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract inner class DurationPref(
|
||||
@DrawableRes val iconId: Int,
|
||||
@StringRes val titleId: Int,
|
||||
|
@ -583,7 +668,7 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
|
||||
abstract fun setCurrentValue(index: Int)
|
||||
|
||||
fun getMenuItems() = values.map { OsmandFormatter.getFormattedDuration(app, it) }
|
||||
open fun getMenuItems() = values.map { OsmandFormatter.getFormattedDuration(app, it) }
|
||||
}
|
||||
|
||||
enum class AppConnect(
|
||||
|
@ -738,13 +823,15 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
class ShareChatInfo {
|
||||
|
||||
var chatId = -1L
|
||||
var userId = -1
|
||||
var start = -1L
|
||||
var livePeriod = -1L
|
||||
var updateTextMessageId = 1
|
||||
var currentMessageLimit = -1L
|
||||
var currentMessageId = -1L
|
||||
var currentMapMessageId = -1L
|
||||
var currentTextMessageId = -1L
|
||||
var userSetLivePeriod = -1L
|
||||
var userSetLivePeriodStart = -1L
|
||||
var lastSuccessfulLocation: LatLon? = null
|
||||
var lastSuccessfulSendTimeMs = -1L
|
||||
var shouldDeletePreviousMessage = false
|
||||
var shouldSendViaBotMessage = false
|
||||
|
@ -767,10 +854,13 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
companion object {
|
||||
|
||||
internal const val CHAT_ID_KEY = "chatId"
|
||||
internal const val USER_ID_KEY = "userId"
|
||||
internal const val START_KEY = "start"
|
||||
internal const val LIVE_PERIOD_KEY = "livePeriod"
|
||||
internal const val LIMIT_KEY = "limit"
|
||||
internal const val CURRENT_MESSAGE_ID_KEY = "currentMessageId"
|
||||
internal const val UPDATE_TEXT_MESSAGE_ID_KEY = "updateTextMessageId"
|
||||
internal const val CURRENT_MAP_MESSAGE_ID_KEY = "currentMapMessageId"
|
||||
internal const val CURRENT_TEXT_MESSAGE_ID_KEY = "currentTextMessageId"
|
||||
internal const val USER_SET_LIVE_PERIOD_KEY = "userSetLivePeriod"
|
||||
internal const val USER_SET_LIVE_PERIOD_START_KEY = "userSetLivePeriodStart"
|
||||
internal const val LAST_SUCCESSFUL_SEND_TIME_KEY = "lastSuccessfulSendTime"
|
||||
|
|
|
@ -2,8 +2,7 @@ package net.osmand.telegram.helpers
|
|||
|
||||
import net.osmand.Location
|
||||
import net.osmand.PlatformUtil
|
||||
import net.osmand.telegram.TelegramApplication
|
||||
import net.osmand.telegram.TelegramSettings
|
||||
import net.osmand.telegram.*
|
||||
import net.osmand.telegram.notifications.TelegramNotification.NotificationType
|
||||
import net.osmand.telegram.utils.AndroidNetworkUtils
|
||||
import net.osmand.telegram.utils.BASE_URL
|
||||
|
@ -57,9 +56,16 @@ class ShareLocationHelper(private val app: TelegramApplication) {
|
|||
val sharingMode = app.settings.currentSharingMode
|
||||
|
||||
if (user != null && sharingMode == user.id.toString()) {
|
||||
app.telegramHelper.sendLiveLocationMessage(chatsShareInfo, latitude, longitude)
|
||||
when (app.settings.shareTypeValue) {
|
||||
SHARE_TYPE_MAP -> app.telegramHelper.sendLiveLocationMessage(chatsShareInfo, latitude, longitude)
|
||||
SHARE_TYPE_TEXT -> app.telegramHelper.sendLiveLocationText(chatsShareInfo, location)
|
||||
SHARE_TYPE_MAP_AND_TEXT -> {
|
||||
app.telegramHelper.sendLiveLocationMessage(chatsShareInfo, latitude, longitude)
|
||||
app.telegramHelper.sendLiveLocationText(chatsShareInfo, location)
|
||||
}
|
||||
}
|
||||
} else if (sharingMode.isNotEmpty()) {
|
||||
val url = "$BASE_URL/device/$sharingMode/send?lat=$latitude&lon=$longitude"
|
||||
val url = getDeviceSharingUrl(location,sharingMode)
|
||||
AndroidNetworkUtils.sendRequestAsync(app, url, null, "Send Location", false, false,
|
||||
object : AndroidNetworkUtils.OnRequestResultListener {
|
||||
override fun onResult(result: String?) {
|
||||
|
@ -150,6 +156,24 @@ class ShareLocationHelper(private val app: TelegramApplication) {
|
|||
refreshNotification()
|
||||
}
|
||||
|
||||
private fun getDeviceSharingUrl(loc: Location, sharingMode: String): String {
|
||||
val url = "$BASE_URL/device/$sharingMode/send?lat=${loc.latitude}&lon=${loc.longitude}"
|
||||
val builder = StringBuilder(url)
|
||||
if (loc.hasBearing() && loc.bearing != 0.0f) {
|
||||
builder.append("&azi=${loc.bearing}")
|
||||
}
|
||||
if (loc.hasSpeed() && loc.speed != 0.0f) {
|
||||
builder.append("&spd=${loc.speed}")
|
||||
}
|
||||
if (loc.hasAltitude() && loc.altitude != 0.0) {
|
||||
builder.append("&alt=${loc.altitude}")
|
||||
}
|
||||
if (loc.hasAccuracy() && loc.accuracy != 0.0f) {
|
||||
builder.append("&hdop=${loc.accuracy}")
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun updateShareInfoSuccessfulSendTime(result: String?, chatsShareInfo: Map<Long, TelegramSettings.ShareChatInfo>) {
|
||||
if (result != null) {
|
||||
try {
|
||||
|
@ -167,11 +191,11 @@ class ShareLocationHelper(private val app: TelegramApplication) {
|
|||
}
|
||||
|
||||
private fun checkAndSendViaBotMessages(chatsShareInfo: Map<Long, TelegramSettings.ShareChatInfo>, location: TdApi.Location, osmandBot: TdApi.User) {
|
||||
val deviceName = app.settings.getShareDeviceNameWithExternalId(app.settings.currentSharingMode)
|
||||
if (deviceName != null) {
|
||||
val device = app.settings.getCurrentSharingDevice()
|
||||
if (device != null) {
|
||||
chatsShareInfo.forEach { (_, shareInfo) ->
|
||||
if (shareInfo.shouldSendViaBotMessage) {
|
||||
app.telegramHelper.sendViaBotLocationMessage(osmandBot.id, shareInfo, location, deviceName)
|
||||
app.telegramHelper.sendViaBotLocationMessage(osmandBot.id, shareInfo, location, device,app.settings.shareTypeValue)
|
||||
shareInfo.shouldSendViaBotMessage = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import net.osmand.aidl.maplayer.point.AMapPoint
|
|||
import net.osmand.telegram.R
|
||||
import net.osmand.telegram.TelegramApplication
|
||||
import net.osmand.telegram.helpers.TelegramHelper.MessageOsmAndBotLocation
|
||||
import net.osmand.telegram.helpers.TelegramHelper.MessageUserTextLocation
|
||||
import net.osmand.telegram.helpers.TelegramUiHelper.ListItem
|
||||
import net.osmand.telegram.utils.AndroidUtils
|
||||
import org.drinkless.td.libcore.telegram.TdApi
|
||||
|
@ -79,7 +80,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
val content = message.content
|
||||
val date = telegramHelper.getLastUpdatedTime(message)
|
||||
val stale = System.currentTimeMillis() / 1000 - date > app.settings.staleLocTime
|
||||
if (chatTitle != null && content is TdApi.MessageLocation) {
|
||||
if (chatTitle != null && (content is TdApi.MessageLocation || (content is MessageUserTextLocation && content.isValid()))) {
|
||||
var userName = ""
|
||||
var photoPath: String? = null
|
||||
val user = telegramHelper.getUser(message.senderUserId)
|
||||
|
@ -102,12 +103,19 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
}
|
||||
setupMapLayer()
|
||||
val params = generatePointParams(photoPath, stale)
|
||||
if (update) {
|
||||
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, "${chatId}_${message.senderUserId}", userName, userName,
|
||||
chatTitle, Color.WHITE, ALatLon(content.location.latitude, content.location.longitude), null, params)
|
||||
} else {
|
||||
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, "${chatId}_${message.senderUserId}", userName, userName,
|
||||
chatTitle, Color.WHITE, ALatLon(content.location.latitude, content.location.longitude), null, params)
|
||||
val aLatLon = when (content) {
|
||||
is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude)
|
||||
is MessageUserTextLocation -> ALatLon(content.lat, content.lon)
|
||||
else -> null
|
||||
}
|
||||
if (aLatLon != null) {
|
||||
if (update) {
|
||||
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, "${chatId}_${message.senderUserId}", userName, userName,
|
||||
chatTitle, Color.WHITE, aLatLon, null, params)
|
||||
} else {
|
||||
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, "${chatId}_${message.senderUserId}", userName, userName,
|
||||
chatTitle, Color.WHITE, aLatLon, null, params)
|
||||
}
|
||||
}
|
||||
} else if (chatTitle != null && content is MessageOsmAndBotLocation && content.isValid()) {
|
||||
val name = content.name
|
||||
|
@ -242,7 +250,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
|
||||
private fun removeMapPoint(chatId: Long, message: TdApi.Message) {
|
||||
val content = message.content
|
||||
if (content is TdApi.MessageLocation) {
|
||||
if (content is TdApi.MessageLocation || content is MessageUserTextLocation) {
|
||||
osmandAidlHelper.removeMapPoint(MAP_LAYER_ID, "${chatId}_${message.senderUserId}")
|
||||
} else if (content is MessageOsmAndBotLocation) {
|
||||
osmandAidlHelper.removeMapPoint(MAP_LAYER_ID, "${chatId}_${content.name}")
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
package net.osmand.telegram.helpers
|
||||
|
||||
import android.text.TextUtils
|
||||
import net.osmand.Location
|
||||
import net.osmand.PlatformUtil
|
||||
import net.osmand.telegram.SHARE_TYPE_MAP
|
||||
import net.osmand.telegram.SHARE_TYPE_MAP_AND_TEXT
|
||||
import net.osmand.telegram.SHARE_TYPE_TEXT
|
||||
import net.osmand.telegram.TelegramSettings
|
||||
import net.osmand.telegram.helpers.TelegramHelper.TelegramAuthenticationParameterType.*
|
||||
import net.osmand.telegram.utils.BASE_SHARING_URL
|
||||
import net.osmand.telegram.utils.GRAYSCALE_PHOTOS_DIR
|
||||
import net.osmand.telegram.utils.GRAYSCALE_PHOTOS_EXT
|
||||
import net.osmand.util.GeoPointParserUtil
|
||||
import org.drinkless.td.libcore.telegram.Client
|
||||
import org.drinkless.td.libcore.telegram.Client.ResultHandler
|
||||
import org.drinkless.td.libcore.telegram.TdApi
|
||||
|
@ -34,7 +40,13 @@ class TelegramHelper private constructor() {
|
|||
private const val LOCATION_PREFIX = "Location: "
|
||||
private const val LAST_LOCATION_PREFIX = "Last location: "
|
||||
private const val UPDATED_PREFIX = "Updated: "
|
||||
private const val USER_TEXT_LOCATION_TITLE = "\uD83D\uDDFA OsmAnd sharing:"
|
||||
|
||||
private const val ALTITUDE_PREFIX = "Altitude: "
|
||||
private const val SPEED_PREFIX = "Speed: "
|
||||
private const val HDOP_PREFIX = "Horizontal precision: "
|
||||
|
||||
private const val NOW = "now"
|
||||
private const val FEW_SECONDS_AGO = "few seconds ago"
|
||||
private const val SECONDS_AGO_SUFFIX = " seconds ago"
|
||||
private const val MINUTES_AGO_SUFFIX = " minutes ago"
|
||||
|
@ -68,6 +80,7 @@ class TelegramHelper private constructor() {
|
|||
var lastTelegramUpdateTime: Int = 0
|
||||
|
||||
private val users = ConcurrentHashMap<Int, TdApi.User>()
|
||||
private val contacts = ConcurrentHashMap<Int, TdApi.User>()
|
||||
private val basicGroups = ConcurrentHashMap<Int, TdApi.BasicGroup>()
|
||||
private val supergroups = ConcurrentHashMap<Int, TdApi.Supergroup>()
|
||||
private val secretChats = ConcurrentHashMap<Int, TdApi.SecretChat>()
|
||||
|
@ -141,6 +154,8 @@ class TelegramHelper private constructor() {
|
|||
|
||||
fun getChatListIds() = getChatList().map { it.chatId }
|
||||
|
||||
fun getContacts() = contacts
|
||||
|
||||
fun getChatIds() = chats.keys().toList()
|
||||
|
||||
fun getChat(id: Long) = chats[id]
|
||||
|
@ -197,10 +212,10 @@ class TelegramHelper private constructor() {
|
|||
|
||||
fun getLastUpdatedTime(message: TdApi.Message): Int {
|
||||
val content = message.content
|
||||
return if (content is MessageOsmAndBotLocation) {
|
||||
content.lastUpdated
|
||||
} else {
|
||||
Math.max(message.editDate, message.date)
|
||||
return when (content) {
|
||||
is MessageOsmAndBotLocation -> content.lastUpdated
|
||||
is MessageUserTextLocation -> content.lastUpdated
|
||||
else -> Math.max(message.editDate, message.date)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,6 +252,7 @@ class TelegramHelper private constructor() {
|
|||
fun onTelegramChatsRead()
|
||||
fun onTelegramChatsChanged()
|
||||
fun onTelegramChatChanged(chat: TdApi.Chat)
|
||||
fun onTelegramChatCreated(chat: TdApi.Chat)
|
||||
fun onTelegramUserChanged(user: TdApi.User)
|
||||
fun onTelegramError(code: Int, message: String)
|
||||
}
|
||||
|
@ -387,7 +403,12 @@ class TelegramHelper private constructor() {
|
|||
fun hasGrayscaleUserPhoto(userId: Int): Boolean {
|
||||
return File("$appDir/$GRAYSCALE_PHOTOS_DIR$userId$GRAYSCALE_PHOTOS_EXT").exists()
|
||||
}
|
||||
|
||||
|
||||
private fun isUserLocationMessage(message: TdApi.Message): Boolean {
|
||||
val cont = message.content
|
||||
return (cont is MessageUserTextLocation || cont is TdApi.MessageLocation)
|
||||
}
|
||||
|
||||
private fun hasLocalUserPhoto(user: TdApi.User): Boolean {
|
||||
val localPhoto = user.profilePhoto?.small?.local
|
||||
return if (localPhoto != null) {
|
||||
|
@ -485,9 +506,9 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
fun sendViaBotLocationMessage(userId: Int, shareInfo: TelegramSettings.ShareChatInfo, location: TdApi.Location, query: String) {
|
||||
fun sendViaBotLocationMessage(userId: Int, shareInfo: TelegramSettings.ShareChatInfo, location: TdApi.Location, device: TelegramSettings.DeviceBot, shareType:String) {
|
||||
log.debug("sendViaBotLocationMessage - ${shareInfo.chatId}")
|
||||
client?.send(TdApi.GetInlineQueryResults(userId, shareInfo.chatId, location, query, "")) { obj ->
|
||||
client?.send(TdApi.GetInlineQueryResults(userId, shareInfo.chatId, location, device.deviceName, "")) { obj ->
|
||||
when (obj.constructor) {
|
||||
TdApi.Error.CONSTRUCTOR -> {
|
||||
val error = obj as TdApi.Error
|
||||
|
@ -498,7 +519,7 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
TdApi.InlineQueryResults.CONSTRUCTOR -> {
|
||||
sendViaBotMessageFromQueryResults(shareInfo, obj as TdApi.InlineQueryResults, query)
|
||||
sendViaBotMessageFromQueryResults(shareInfo, obj as TdApi.InlineQueryResults, device.externalId, shareType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -507,16 +528,26 @@ class TelegramHelper private constructor() {
|
|||
private fun sendViaBotMessageFromQueryResults(
|
||||
shareInfo: TelegramSettings.ShareChatInfo,
|
||||
inlineQueryResults: TdApi.InlineQueryResults,
|
||||
query: String
|
||||
deviceId: String,
|
||||
shareType: String
|
||||
) {
|
||||
val queryResults = inlineQueryResults.results.asList()
|
||||
if (queryResults.isNotEmpty()) {
|
||||
val resultArticle = queryResults.firstOrNull {
|
||||
(it is TdApi.InlineQueryResultArticle && it.id.startsWith("t") && it.title == query)
|
||||
val resultArticles = mutableListOf<TdApi.InlineQueryResultArticle>()
|
||||
queryResults.forEach {
|
||||
if (it is TdApi.InlineQueryResultArticle && it.id.substring(1) == deviceId) {
|
||||
val textLocationArticle = it.id.startsWith("t")
|
||||
val mapLocationArticle = it.id.startsWith("m")
|
||||
if (shareType == SHARE_TYPE_MAP && mapLocationArticle
|
||||
|| shareType == SHARE_TYPE_TEXT && textLocationArticle
|
||||
|| shareType == SHARE_TYPE_MAP_AND_TEXT && (textLocationArticle || mapLocationArticle)) {
|
||||
resultArticles.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resultArticle != null && resultArticle is TdApi.InlineQueryResultArticle) {
|
||||
resultArticles.forEach {
|
||||
client?.send(TdApi.SendInlineQueryResultMessage(shareInfo.chatId, 0, true,
|
||||
true, inlineQueryResults.inlineQueryId, resultArticle.id)) { obj ->
|
||||
true, inlineQueryResults.inlineQueryId, it.id)) { obj ->
|
||||
handleLiveLocationMessageUpdate(obj, shareInfo)
|
||||
}
|
||||
}
|
||||
|
@ -561,6 +592,73 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun requestContacts(){
|
||||
client?.send(TdApi.GetContacts()) { 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.Users.CONSTRUCTOR -> {
|
||||
val usersIds = obj as TdApi.Users
|
||||
usersIds.userIds.forEach {
|
||||
requestUser(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestUser(id: Int) {
|
||||
client?.send(TdApi.GetUser(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.User.CONSTRUCTOR -> {
|
||||
val user = obj as TdApi.User
|
||||
contacts[user.id] = user
|
||||
if (!hasLocalUserPhoto(user) && hasRemoteUserPhoto(user)) {
|
||||
requestUserPhoto(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createPrivateChatWithUser(
|
||||
userId: Int,
|
||||
shareInfo: TelegramSettings.ShareChatInfo,
|
||||
shareChatsInfo: ConcurrentHashMap<Long, TelegramSettings.ShareChatInfo>
|
||||
) {
|
||||
client?.send(TdApi.CreatePrivateChat(userId, false)) { obj ->
|
||||
when (obj.constructor) {
|
||||
TdApi.Error.CONSTRUCTOR -> {
|
||||
val error = obj as TdApi.Error
|
||||
needRefreshActiveLiveLocationMessages = true
|
||||
if (error.code == MESSAGE_CANNOT_BE_EDITED_ERROR_CODE) {
|
||||
shareInfo.shouldDeletePreviousMessage = true
|
||||
} else if (error.code != IGNORED_ERROR_CODE) {
|
||||
shareInfo.hasSharingError = true
|
||||
outgoingMessagesListeners.forEach {
|
||||
it.onSendLiveLocationError(error.code, error.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
TdApi.Chat.CONSTRUCTOR -> {
|
||||
shareInfo.chatId = (obj as TdApi.Chat).id
|
||||
shareChatsInfo[shareInfo.chatId] = shareInfo
|
||||
listener?.onTelegramChatCreated(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadMessage(chatId: Long, messageId: Long) {
|
||||
requestMessage(chatId, messageId, this@TelegramHelper::addNewMessage)
|
||||
}
|
||||
|
@ -580,7 +678,11 @@ class TelegramHelper private constructor() {
|
|||
val viaBot = isOsmAndBot(message.viaBotUserId)
|
||||
val oldContent = message.content
|
||||
if (oldContent is TdApi.MessageText) {
|
||||
message.content = parseOsmAndBotLocation(oldContent.text.text)
|
||||
if (oldContent.text.text.startsWith(DEVICE_PREFIX)) {
|
||||
message.content = parseTextLocation(oldContent.text)
|
||||
} else if (oldContent.text.text.startsWith(USER_TEXT_LOCATION_TITLE)) {
|
||||
message.content = parseTextLocation(oldContent.text, false)
|
||||
}
|
||||
} else if (oldContent is TdApi.MessageLocation && (fromBot || viaBot)) {
|
||||
message.content = parseOsmAndBotLocation(message)
|
||||
}
|
||||
|
@ -609,7 +711,7 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (sameSender) {
|
||||
} else if (sameSender && isUserLocationMessage(message) && isUserLocationMessage(newMessage)) {
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
|
@ -638,9 +740,9 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
|
||||
fun stopSendingLiveLocationToChat(shareInfo: TelegramSettings.ShareChatInfo) {
|
||||
if (shareInfo.currentMessageId != -1L && shareInfo.chatId != -1L) {
|
||||
if (shareInfo.currentMapMessageId != -1L && shareInfo.chatId != -1L) {
|
||||
client?.send(
|
||||
TdApi.EditMessageLiveLocation(shareInfo.chatId, shareInfo.currentMessageId, null, null)) { obj ->
|
||||
TdApi.EditMessageLiveLocation(shareInfo.chatId, shareInfo.currentMapMessageId, null, null)) { obj ->
|
||||
handleLiveLocationMessageUpdate(obj, shareInfo)
|
||||
}
|
||||
}
|
||||
|
@ -683,20 +785,28 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun recreateLiveLocationMessage(shareInfo: TelegramSettings.ShareChatInfo, content: TdApi.InputMessageLocation) {
|
||||
if (shareInfo.currentMessageId != -1L && shareInfo.chatId != -1L) {
|
||||
log.info("recreateLiveLocationMessage - $shareInfo.currentMessageId")
|
||||
private fun recreateLiveLocationMessage(
|
||||
shareInfo: TelegramSettings.ShareChatInfo,
|
||||
content: TdApi.InputMessageContent
|
||||
) {
|
||||
if (shareInfo.chatId != -1L) {
|
||||
val array = LongArray(1)
|
||||
array[0] = shareInfo.currentMessageId
|
||||
client?.send(TdApi.DeleteMessages(shareInfo.chatId, array, true)) { obj ->
|
||||
when (obj.constructor) {
|
||||
TdApi.Ok.CONSTRUCTOR -> sendNewLiveLocationMessage(shareInfo, content)
|
||||
TdApi.Error.CONSTRUCTOR -> {
|
||||
val error = obj as TdApi.Error
|
||||
if (error.code != IGNORED_ERROR_CODE) {
|
||||
needRefreshActiveLiveLocationMessages = true
|
||||
outgoingMessagesListeners.forEach {
|
||||
it.onSendLiveLocationError(error.code, error.message)
|
||||
if (content is TdApi.InputMessageLocation) {
|
||||
array[0] = shareInfo.currentMapMessageId
|
||||
} else if (content is TdApi.InputMessageLocation) {
|
||||
array[0] = shareInfo.currentTextMessageId
|
||||
}
|
||||
if (array[0] != 0L) {
|
||||
client?.send(TdApi.DeleteMessages(shareInfo.chatId, array, true)) { obj ->
|
||||
when (obj.constructor) {
|
||||
TdApi.Ok.CONSTRUCTOR -> sendNewLiveLocationMessage(shareInfo, content)
|
||||
TdApi.Error.CONSTRUCTOR -> {
|
||||
val error = obj as TdApi.Error
|
||||
if (error.code != IGNORED_ERROR_CODE) {
|
||||
needRefreshActiveLiveLocationMessages = true
|
||||
outgoingMessagesListeners.forEach {
|
||||
it.onSendLiveLocationError(error.code, error.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -706,7 +816,7 @@ class TelegramHelper private constructor() {
|
|||
needRefreshActiveLiveLocationMessages = true
|
||||
}
|
||||
|
||||
private fun sendNewLiveLocationMessage(shareInfo: TelegramSettings.ShareChatInfo, content: TdApi.InputMessageLocation) {
|
||||
private fun sendNewLiveLocationMessage(shareInfo: TelegramSettings.ShareChatInfo, content: TdApi.InputMessageContent) {
|
||||
needRefreshActiveLiveLocationMessages = true
|
||||
log.info("sendNewLiveLocationMessage")
|
||||
client?.send(
|
||||
|
@ -728,12 +838,12 @@ class TelegramHelper private constructor() {
|
|||
shareInfo.livePeriod.toInt()
|
||||
}
|
||||
val content = TdApi.InputMessageLocation(location, livePeriod)
|
||||
val msgId = shareInfo.currentMessageId
|
||||
val msgId = shareInfo.currentMapMessageId
|
||||
if (msgId != -1L) {
|
||||
if (shareInfo.shouldDeletePreviousMessage) {
|
||||
recreateLiveLocationMessage(shareInfo, content)
|
||||
shareInfo.shouldDeletePreviousMessage = false
|
||||
shareInfo.currentMessageId = -1
|
||||
shareInfo.currentMapMessageId = -1
|
||||
} else {
|
||||
log.info("EditMessageLiveLocation - $msgId")
|
||||
client?.send(
|
||||
|
@ -780,6 +890,94 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
fun sendLiveLocationText(chatsShareInfo: Map<Long, TelegramSettings.ShareChatInfo>, location: Location) {
|
||||
chatsShareInfo.forEach { (chatId, shareInfo) ->
|
||||
if (shareInfo.getChatLiveMessageExpireTime() <= 0) {
|
||||
return@forEach
|
||||
}
|
||||
val msgId = shareInfo.currentTextMessageId
|
||||
if (msgId == -1L) {
|
||||
shareInfo.updateTextMessageId = 1
|
||||
}
|
||||
val content = getTextMessageContent(shareInfo.updateTextMessageId, location)
|
||||
if (msgId != -1L) {
|
||||
if (shareInfo.shouldDeletePreviousMessage) {
|
||||
recreateLiveLocationMessage(shareInfo, content)
|
||||
shareInfo.shouldDeletePreviousMessage = false
|
||||
shareInfo.currentTextMessageId = -1
|
||||
shareInfo.updateTextMessageId = 1
|
||||
} else {
|
||||
client?.send(TdApi.EditMessageText(chatId, msgId, null, content)) { obj ->
|
||||
handleLiveLocationMessageUpdate(obj, shareInfo)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
client?.send(TdApi.SendMessage(chatId, 0, false, false, null, content)) { obj ->
|
||||
handleLiveLocationMessageUpdate(obj, shareInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatLocation(sig: Location): String {
|
||||
return String.format(Locale.US, "%.5f, %.5f", sig.latitude, sig.longitude)
|
||||
}
|
||||
|
||||
private fun formatTime(ti: Long, now: Boolean): String {
|
||||
val dt = Date(ti)
|
||||
val current = System.currentTimeMillis() / 1000
|
||||
val tm = ti / 1000
|
||||
return when {
|
||||
current - tm < 10 -> if (now) NOW else FEW_SECONDS_AGO
|
||||
current - tm < 50 -> (current - tm).toString() + SECONDS_AGO_SUFFIX
|
||||
current - tm < 60 * 60 * 2 -> ((current - tm) / 60).toString() + MINUTES_AGO_SUFFIX
|
||||
current - tm < 60 * 60 * 24 -> ((current - tm) / (60 * 60)).toString() + HOURS_AGO_SUFFIX
|
||||
else -> UTC_DATE_FORMAT.format(dt) + " " + UTC_TIME_FORMAT.format(dt) + UTC_FORMAT_SUFFIX
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatFullTime(ti: Long): String {
|
||||
val dt = Date(ti)
|
||||
return UTC_DATE_FORMAT.format(dt) + " " + UTC_TIME_FORMAT.format(dt) + " UTC"
|
||||
}
|
||||
|
||||
private fun getTextMessageContent(updateId: Int, location: Location): TdApi.InputMessageText {
|
||||
val entities = mutableListOf<TdApi.TextEntity>()
|
||||
val builder = StringBuilder()
|
||||
val locationMessage = formatLocation(location)
|
||||
val locationTime = formatTime(location.time, true)
|
||||
|
||||
builder.append("$USER_TEXT_LOCATION_TITLE\n")
|
||||
|
||||
entities.add(TdApi.TextEntity(builder.lastIndex, LOCATION_PREFIX.length, TdApi.TextEntityTypeBold()))
|
||||
builder.append(LOCATION_PREFIX)
|
||||
|
||||
entities.add(TdApi.TextEntity(builder.length, locationMessage.length,
|
||||
TdApi.TextEntityTypeTextUrl("$BASE_SHARING_URL?lat=${location.latitude}&lon=${location.longitude}")))
|
||||
builder.append("$locationMessage ($locationTime)\n")
|
||||
|
||||
if (location.hasAltitude() && location.altitude != 0.0) {
|
||||
entities.add(TdApi.TextEntity(builder.lastIndex, ALTITUDE_PREFIX.length, TdApi.TextEntityTypeBold()))
|
||||
builder.append(String.format(Locale.US, "$ALTITUDE_PREFIX%.1f m\n", location.altitude))
|
||||
}
|
||||
if (location.hasSpeed() && location.speed > 0) {
|
||||
entities.add(TdApi.TextEntity(builder.lastIndex, SPEED_PREFIX.length, TdApi.TextEntityTypeBold()))
|
||||
builder.append(String.format(Locale.US, "$SPEED_PREFIX%.1f m/s\n", location.speed))
|
||||
}
|
||||
if (location.hasAccuracy() && location.accuracy != 0.0f && location.speed == 0.0f) {
|
||||
entities.add(TdApi.TextEntity(builder.lastIndex, HDOP_PREFIX.length, TdApi.TextEntityTypeBold()))
|
||||
builder.append(String.format(Locale.US, "$HDOP_PREFIX%d m\n", location.accuracy.toInt()))
|
||||
}
|
||||
if (updateId == 0) {
|
||||
builder.append(String.format("$UPDATED_PREFIX%s\n", formatFullTime(location.time)))
|
||||
} else {
|
||||
builder.append(String.format("$UPDATED_PREFIX%s (%d)\n", formatFullTime(location.time), updateId))
|
||||
}
|
||||
val textMessage = builder.toString().trim()
|
||||
|
||||
return TdApi.InputMessageText(TdApi.FormattedText(textMessage, entities.toTypedArray()), false, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* @chatId Id of the chat
|
||||
* @message Text of the message
|
||||
|
@ -896,6 +1094,7 @@ class TelegramHelper private constructor() {
|
|||
if (haveAuthorization) {
|
||||
requestChats(true)
|
||||
requestCurrentUser()
|
||||
requestContacts()
|
||||
}
|
||||
}
|
||||
val newAuthState = getTelegramAuthorizationState()
|
||||
|
@ -915,9 +1114,10 @@ class TelegramHelper private constructor() {
|
|||
return false
|
||||
}
|
||||
val content = content
|
||||
val isUserTextLocation = (content is TdApi.MessageText) && content.text.text.startsWith(USER_TEXT_LOCATION_TITLE)
|
||||
return when (content) {
|
||||
is TdApi.MessageLocation -> true
|
||||
is TdApi.MessageText -> (isOsmAndBot) && content.text.text.startsWith(DEVICE_PREFIX)
|
||||
is TdApi.MessageText -> (isOsmAndBot) && content.text.text.startsWith(DEVICE_PREFIX) || (isUserTextLocation && senderUserId != currentUser?.id)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
@ -942,13 +1142,16 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun parseOsmAndBotLocation(text: String): MessageOsmAndBotLocation {
|
||||
val res = MessageOsmAndBotLocation()
|
||||
private fun parseTextLocation(text: TdApi.FormattedText, botLocation: Boolean = true): MessageLocation {
|
||||
val res = if (botLocation) MessageOsmAndBotLocation() else MessageUserTextLocation()
|
||||
|
||||
var locationNA = false
|
||||
for (s in text.lines()) {
|
||||
for (s in text.text.lines()) {
|
||||
when {
|
||||
s.startsWith(DEVICE_PREFIX) -> {
|
||||
res.name = s.removePrefix(DEVICE_PREFIX)
|
||||
if (res is MessageOsmAndBotLocation) {
|
||||
res.name = s.removePrefix(DEVICE_PREFIX)
|
||||
}
|
||||
}
|
||||
s.startsWith(LOCATION_PREFIX) || s.startsWith(LAST_LOCATION_PREFIX) -> {
|
||||
var locStr: String
|
||||
|
@ -965,7 +1168,15 @@ class TelegramHelper private constructor() {
|
|||
parse = false
|
||||
}
|
||||
}
|
||||
if (parse) {
|
||||
val urlTextEntity = text.entities.firstOrNull { it.type is TdApi.TextEntityTypeTextUrl }
|
||||
if (urlTextEntity != null && urlTextEntity.offset == text.text.indexOf(locStr)) {
|
||||
val url = (urlTextEntity.type as TdApi.TextEntityTypeTextUrl).url
|
||||
val point: GeoPointParserUtil.GeoParsedPoint? = GeoPointParserUtil.parse(url)
|
||||
if (point != null) {
|
||||
res.lat = point.latitude
|
||||
res.lon = point.longitude
|
||||
}
|
||||
} else if (parse) {
|
||||
try {
|
||||
val (latS, lonS) = locStr.split(" ")
|
||||
val updatedS = locStr.substring(locStr.indexOf("("), locStr.length)
|
||||
|
@ -1029,10 +1240,8 @@ class TelegramHelper private constructor() {
|
|||
return 0
|
||||
}
|
||||
|
||||
class MessageOsmAndBotLocation : TdApi.MessageContent() {
|
||||
abstract class MessageLocation : TdApi.MessageContent() {
|
||||
|
||||
var name: String = ""
|
||||
internal set
|
||||
var lat: Double = Double.NaN
|
||||
internal set
|
||||
var lon: Double = Double.NaN
|
||||
|
@ -1042,7 +1251,21 @@ class TelegramHelper private constructor() {
|
|||
|
||||
override fun getConstructor() = -1
|
||||
|
||||
fun isValid() = name != "" && lat != Double.NaN && lon != Double.NaN
|
||||
abstract fun isValid(): Boolean
|
||||
}
|
||||
|
||||
class MessageOsmAndBotLocation : MessageLocation() {
|
||||
|
||||
var name: String = ""
|
||||
internal set
|
||||
|
||||
override fun isValid() = name != "" && lat != Double.NaN && lon != Double.NaN
|
||||
}
|
||||
|
||||
class MessageUserTextLocation : MessageLocation() {
|
||||
|
||||
override fun isValid() = lat != Double.NaN && lon != Double.NaN
|
||||
|
||||
}
|
||||
|
||||
class OrderedChat internal constructor(internal val order: Long, internal val chatId: Long, internal val isChannel: Boolean) : Comparable<OrderedChat> {
|
||||
|
@ -1085,6 +1308,9 @@ class TelegramHelper private constructor() {
|
|||
val updateUser = obj as TdApi.UpdateUser
|
||||
val user = updateUser.user
|
||||
users[updateUser.user.id] = user
|
||||
if (user.outgoingLink is TdApi.LinkStateIsContact) {
|
||||
contacts[user.id] = user
|
||||
}
|
||||
if (isOsmAndBot(user.id)) {
|
||||
osmandBot = user
|
||||
}
|
||||
|
@ -1256,8 +1482,10 @@ class TelegramHelper private constructor() {
|
|||
synchronized(message) {
|
||||
lastTelegramUpdateTime = Math.max(message.date, message.editDate)
|
||||
val newContent = updateMessageContent.newContent
|
||||
val fromBot = isOsmAndBot(message.senderUserId)
|
||||
val viaBot = isOsmAndBot(message.viaBotUserId)
|
||||
message.content = if (newContent is TdApi.MessageText) {
|
||||
parseOsmAndBotLocation(newContent.text.text)
|
||||
parseTextLocation(newContent.text, (fromBot || viaBot))
|
||||
} else if (newContent is TdApi.MessageLocation &&
|
||||
(isOsmAndBot(message.senderUserId) || isOsmAndBot(message.viaBotUserId))) {
|
||||
parseOsmAndBotLocationContent(message.content as MessageOsmAndBotLocation, newContent)
|
||||
|
@ -1377,6 +1605,13 @@ class TelegramHelper private constructor() {
|
|||
fullInfoUpdatesListeners.forEach { it.onSupergroupFullInfoUpdated(id, info) }
|
||||
}
|
||||
}
|
||||
TdApi.UpdateMessageSendSucceeded.CONSTRUCTOR -> {
|
||||
val udateMessageSendSucceeded = obj as TdApi.UpdateMessageSendSucceeded
|
||||
val message = udateMessageSendSucceeded.message
|
||||
outgoingMessagesListeners.forEach {
|
||||
it.onUpdateMessages(listOf(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import net.osmand.data.LatLon
|
|||
import net.osmand.telegram.R
|
||||
import net.osmand.telegram.TelegramApplication
|
||||
import net.osmand.telegram.helpers.TelegramHelper.MessageOsmAndBotLocation
|
||||
import net.osmand.telegram.helpers.TelegramHelper.MessageUserTextLocation
|
||||
import org.drinkless.td.libcore.telegram.TdApi
|
||||
|
||||
object TelegramUiHelper {
|
||||
|
@ -67,6 +68,8 @@ object TelegramUiHelper {
|
|||
val content = message.content
|
||||
if (content is TdApi.MessageLocation) {
|
||||
res.latLon = LatLon(content.location.latitude, content.location.longitude)
|
||||
} else if (content is MessageUserTextLocation) {
|
||||
res.latLon = LatLon(content.lat, content.lon)
|
||||
}
|
||||
}
|
||||
if (user != null) {
|
||||
|
@ -106,6 +109,7 @@ object TelegramUiHelper {
|
|||
val content = message.content
|
||||
return when (content) {
|
||||
is MessageOsmAndBotLocation -> botMessageToLocationItem(chat, content)
|
||||
is MessageUserTextLocation -> locationMessageToLocationItem(helper, chat, message)
|
||||
is TdApi.MessageLocation -> locationMessageToLocationItem(helper, chat, message)
|
||||
else -> null
|
||||
}
|
||||
|
@ -120,6 +124,7 @@ object TelegramUiHelper {
|
|||
return when (content) {
|
||||
is MessageOsmAndBotLocation -> botMessageToChatItem(helper, chat, content)
|
||||
is TdApi.MessageLocation -> locationMessageToChatItem(helper, chat, message)
|
||||
is MessageUserTextLocation -> locationMessageToChatItem(helper, chat, message)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
@ -148,12 +153,16 @@ object TelegramUiHelper {
|
|||
message: TdApi.Message
|
||||
): LocationItem? {
|
||||
val user = helper.getUser(message.senderUserId) ?: return null
|
||||
val content = message.content as TdApi.MessageLocation
|
||||
val content = message.content
|
||||
return LocationItem().apply {
|
||||
chatId = chat.id
|
||||
chatTitle = chat.title
|
||||
name = TelegramUiHelper.getUserName(user)
|
||||
latLon = LatLon(content.location.latitude, content.location.longitude)
|
||||
latLon = when (content) {
|
||||
is TdApi.MessageLocation -> LatLon(content.location.latitude, content.location.longitude)
|
||||
is MessageUserTextLocation -> LatLon(content.lat, content.lon)
|
||||
else -> null
|
||||
}
|
||||
photoPath = helper.getUserPhotoPath(user)
|
||||
grayscalePhotoPath = helper.getUserGreyPhotoPath(user)
|
||||
placeholderId = R.drawable.img_user_picture
|
||||
|
@ -190,12 +199,16 @@ object TelegramUiHelper {
|
|||
message: TdApi.Message
|
||||
): ChatItem? {
|
||||
val user = helper.getUser(message.senderUserId) ?: return null
|
||||
val content = message.content as TdApi.MessageLocation
|
||||
val content = message.content
|
||||
return ChatItem().apply {
|
||||
chatId = chat.id
|
||||
chatTitle = chat.title
|
||||
name = TelegramUiHelper.getUserName(user)
|
||||
latLon = LatLon(content.location.latitude, content.location.longitude)
|
||||
latLon = when (content) {
|
||||
is TdApi.MessageLocation -> LatLon(content.location.latitude, content.location.longitude)
|
||||
is MessageUserTextLocation -> LatLon(content.lat, content.lon)
|
||||
else -> null
|
||||
}
|
||||
if (helper.isGroup(chat)) {
|
||||
photoPath = helper.getUserPhotoPath(user)
|
||||
groupPhotoPath = chat.photo?.small?.local?.path
|
||||
|
|
|
@ -171,6 +171,10 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
|
|||
updateList()
|
||||
}
|
||||
|
||||
override fun onTelegramChatCreated(chat: TdApi.Chat) {
|
||||
updateList()
|
||||
}
|
||||
|
||||
override fun onTelegramUserChanged(user: TdApi.User) {
|
||||
updateList()
|
||||
}
|
||||
|
|
|
@ -254,6 +254,12 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
|
|||
}
|
||||
}
|
||||
|
||||
override fun onTelegramChatCreated(chat: TdApi.Chat) {
|
||||
runOnUi {
|
||||
listeners.forEach { it.get()?.onTelegramChatCreated(chat) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTelegramUserChanged(user: TdApi.User) {
|
||||
val photoPath = telegramHelper.getUserPhotoPath(user)
|
||||
if (photoPath != null) {
|
||||
|
|
|
@ -28,6 +28,7 @@ import net.osmand.telegram.utils.OsmandFormatter
|
|||
import org.drinkless.td.libcore.telegram.TdApi
|
||||
|
||||
private const val SELECTED_CHATS_KEY = "selected_chats"
|
||||
private const val SELECTED_CHATS_USERS = "selected_users"
|
||||
private const val SHARE_LOCATION_CHAT = 1
|
||||
private const val DEFAULT_CHAT = 0
|
||||
|
||||
|
@ -71,6 +72,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
private lateinit var appBarOutlineProvider: ViewOutlineProvider
|
||||
|
||||
private val selectedChats = HashSet<Long>()
|
||||
private val selectedUsers = HashSet<Long>()
|
||||
|
||||
private var actionButtonsListener: ActionButtonsListener? = null
|
||||
|
||||
|
@ -96,10 +98,15 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
sharingMode = settings.hasAnyChatToShareLocation()
|
||||
|
||||
savedInstanceState?.apply {
|
||||
selectedChats.addAll(getLongArray(SELECTED_CHATS_KEY).toSet())
|
||||
if (selectedChats.isNotEmpty()) {
|
||||
actionButtonsListener?.switchButtonsVisibility(true)
|
||||
val chatsArray = getLongArray(SELECTED_CHATS_KEY)
|
||||
val usersArray = getLongArray(SELECTED_CHATS_KEY)
|
||||
if (chatsArray != null) {
|
||||
selectedChats.addAll(chatsArray.toSet())
|
||||
}
|
||||
if (usersArray != null) {
|
||||
selectedUsers.addAll(usersArray.toSet())
|
||||
}
|
||||
actionButtonsListener?.switchButtonsVisibility((selectedUsers.isNotEmpty() || selectedChats.isNotEmpty()))
|
||||
}
|
||||
|
||||
val mainView = inflater.inflate(R.layout.fragment_my_location_tab, container, false)
|
||||
|
@ -191,7 +198,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
|
||||
mainView.findViewById<View>(R.id.stop_all_sharing_row).setOnClickListener {
|
||||
fragmentManager?.also { fm ->
|
||||
DisableSharingBottomSheet.showInstance(fm, this, adapter.chats.size)
|
||||
DisableSharingBottomSheet.showInstance(fm, this, adapter.items.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,6 +243,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putLongArray(SELECTED_CHATS_KEY, selectedChats.toLongArray())
|
||||
outState.putLongArray(SELECTED_CHATS_USERS, selectedUsers.toLongArray())
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
|
@ -274,7 +282,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
TelegramHelper.TelegramAuthorizationState.LOGGING_OUT,
|
||||
TelegramHelper.TelegramAuthorizationState.CLOSED,
|
||||
TelegramHelper.TelegramAuthorizationState.UNKNOWN -> {
|
||||
adapter.chats = mutableListOf()
|
||||
adapter.items = mutableListOf()
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
@ -292,6 +300,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
updateContent()
|
||||
}
|
||||
|
||||
override fun onTelegramChatCreated(chat: TdApi.Chat) {
|
||||
sharingMode = settings.hasAnyChatToShareLocation()
|
||||
updateContent()
|
||||
}
|
||||
|
||||
override fun onTelegramUserChanged(user: TdApi.User) {
|
||||
if (user.id == telegramHelper.getCurrentUser()?.id) {
|
||||
updateCurrentUserPhoto()
|
||||
|
@ -303,9 +316,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
}
|
||||
|
||||
fun onPrimaryBtnClick() {
|
||||
if (selectedChats.isNotEmpty()) {
|
||||
if (selectedChats.isNotEmpty() || selectedUsers.isNotEmpty()) {
|
||||
val fm = fragmentManager ?: return
|
||||
SetTimeDialogFragment.showInstance(fm, selectedChats, this)
|
||||
SetTimeDialogFragment.showInstance(fm, selectedChats, selectedUsers, this)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,6 +364,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
|
||||
private fun clearSelection() {
|
||||
selectedChats.clear()
|
||||
selectedUsers.clear()
|
||||
adapter.notifyDataSetChanged()
|
||||
actionButtonsListener?.switchButtonsVisibility(false)
|
||||
}
|
||||
|
@ -453,8 +467,10 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
}
|
||||
|
||||
private fun updateList() {
|
||||
val items: MutableList<TdApi.Object> = mutableListOf()
|
||||
val chats: MutableList<TdApi.Chat> = mutableListOf()
|
||||
val currentUser = telegramHelper.getCurrentUser()
|
||||
val contacts = telegramHelper.getContacts()
|
||||
val chatList = if (sharingMode) {
|
||||
settings.getShareLocationChats()
|
||||
} else {
|
||||
|
@ -473,27 +489,55 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
chats.add(chat)
|
||||
}
|
||||
}
|
||||
items.addAll(chats)
|
||||
if (!sharingMode) {
|
||||
for (user in contacts.values) {
|
||||
val containsInChats = chats.any { telegramHelper.getUserIdFromChatType(it.type) == user.id }
|
||||
if ((!sharingMode && settings.isSharingLocationToUser(user.id)) || user.id == currentUser?.id || containsInChats) {
|
||||
continue
|
||||
}
|
||||
items.add(user)
|
||||
}
|
||||
}
|
||||
if (sharingMode && settings.hasAnyChatToShareLocation()) {
|
||||
adapter.chats = sortAdapterItems(chats)
|
||||
adapter.items = sortAdapterItems(items)
|
||||
} else {
|
||||
adapter.chats = chats
|
||||
adapter.items = items
|
||||
}
|
||||
}
|
||||
|
||||
private fun sortAdapterItems(list: MutableList<TdApi.Chat>): MutableList<TdApi.Chat> {
|
||||
list.sortWith(Comparator<TdApi.Chat> { o1, o2 -> o1.title.compareTo(o2.title) })
|
||||
private fun sortAdapterItems(list: MutableList<TdApi.Object>): MutableList<TdApi.Object> {
|
||||
list.sortWith(Comparator<TdApi.Object> { o1, o2 ->
|
||||
val title1 = when (o1) {
|
||||
is TdApi.Chat -> o1.title
|
||||
is TdApi.User -> TelegramUiHelper.getUserName(o1)
|
||||
else -> ""
|
||||
}
|
||||
val title2 = when (o2) {
|
||||
is TdApi.Chat -> o2.title
|
||||
is TdApi.User -> TelegramUiHelper.getUserName(o2)
|
||||
else -> ""
|
||||
}
|
||||
title1.compareTo(title2)
|
||||
})
|
||||
return list
|
||||
}
|
||||
|
||||
inner class MyLocationListAdapter : RecyclerView.Adapter<MyLocationListAdapter.BaseViewHolder>() {
|
||||
var chats = mutableListOf<TdApi.Chat>()
|
||||
var items = mutableListOf<TdApi.Object>()
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (settings.isSharingLocationToChat(chats[position].id) && sharingMode) {
|
||||
val item = items[position]
|
||||
val id = when (item) {
|
||||
is TdApi.Chat -> item.id
|
||||
is TdApi.User -> item.id.toLong()
|
||||
else -> -1
|
||||
}
|
||||
return if (settings.isSharingLocationToChat(id) && sharingMode) {
|
||||
SHARE_LOCATION_CHAT
|
||||
} else {
|
||||
DEFAULT_CHAT
|
||||
|
@ -518,14 +562,34 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
|
||||
val chat = chats[position]
|
||||
val lastItem = position == itemCount - 1
|
||||
val placeholderId = if (telegramHelper.isGroup(chat)) R.drawable.img_group_picture else R.drawable.img_user_picture
|
||||
val live = settings.isSharingLocationToChat(chat.id)
|
||||
val shareInfo = settings.getChatsShareInfo()[chat.id]
|
||||
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()
|
||||
}
|
||||
|
||||
TelegramUiHelper.setupPhoto(app, holder.icon, chat.photo?.small?.local?.path, placeholderId, false)
|
||||
holder.title?.text = chat.title
|
||||
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
|
||||
|
||||
if (holder is ChatViewHolder) {
|
||||
holder.description?.visibility = View.GONE
|
||||
|
@ -535,21 +599,33 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
holder.checkBox?.apply {
|
||||
visibility = View.VISIBLE
|
||||
setOnCheckedChangeListener(null)
|
||||
isChecked = selectedChats.contains(chat.id)
|
||||
isChecked = if (isChat) {
|
||||
selectedChats.contains(itemId)
|
||||
} else {
|
||||
selectedUsers.contains(itemId)
|
||||
}
|
||||
setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
selectedChats.add(chat.id)
|
||||
if (isChat) {
|
||||
selectedChats.add(itemId)
|
||||
} else {
|
||||
selectedUsers.add(itemId)
|
||||
}
|
||||
} else {
|
||||
selectedChats.remove(chat.id)
|
||||
if (isChat) {
|
||||
selectedChats.remove(itemId)
|
||||
} else {
|
||||
selectedUsers.remove(itemId)
|
||||
}
|
||||
}
|
||||
actionButtonsListener?.switchButtonsVisibility(selectedChats.isNotEmpty())
|
||||
actionButtonsListener?.switchButtonsVisibility(selectedChats.isNotEmpty() || selectedUsers.isNotEmpty())
|
||||
}
|
||||
}
|
||||
}
|
||||
holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE
|
||||
holder.itemView.setOnClickListener {
|
||||
if (live) {
|
||||
settings.shareLocationToChat(chat.id, false)
|
||||
settings.shareLocationToChat(itemId, false)
|
||||
shareLocationHelper.stopSharingLocation()
|
||||
notifyItemChanged(position)
|
||||
} else {
|
||||
|
@ -563,11 +639,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
isChecked = live
|
||||
setOnCheckedChangeListener { _, isChecked ->
|
||||
if (!isChecked) {
|
||||
settings.shareLocationToChat(chat.id, false)
|
||||
settings.shareLocationToChat(itemId, false)
|
||||
if (shareInfo != null) {
|
||||
telegramHelper.stopSendingLiveLocationToChat(shareInfo)
|
||||
}
|
||||
removeItem(chat)
|
||||
removeItem(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -591,7 +667,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
val expireTime = shareInfo?.getChatLiveMessageExpireTime() ?: 0
|
||||
val newLivePeriod = expireTime + (shareInfo?.additionalActiveTime ?: ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0])
|
||||
val nextAdditionalActiveTime = shareInfo?.getNextAdditionalActiveTime() ?: ADDITIONAL_ACTIVE_TIME_VALUES_SEC[1]
|
||||
settings.shareLocationToChat(chat.id, true, newLivePeriod, nextAdditionalActiveTime)
|
||||
if (isChat) {
|
||||
settings.shareLocationToChat(itemId, true, newLivePeriod, nextAdditionalActiveTime)
|
||||
} else {
|
||||
settings.shareLocationToUser(itemId.toInt(), newLivePeriod, nextAdditionalActiveTime)
|
||||
}
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
@ -616,9 +696,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
|
||||
private fun getStopSharingVisibility(expiresIn: Long) = if (expiresIn > 0) View.VISIBLE else View.INVISIBLE
|
||||
|
||||
private fun removeItem(chat: TdApi.Chat) {
|
||||
chats.remove(chat)
|
||||
if (chats.isEmpty()) {
|
||||
private fun removeItem(chat: TdApi.Object) {
|
||||
items.remove(chat)
|
||||
if (items.isEmpty()) {
|
||||
sharingMode = false
|
||||
updateContent()
|
||||
shareLocationHelper.stopSharingLocation()
|
||||
|
@ -627,7 +707,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() = chats.size
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
abstract inner class BaseViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val icon: ImageView? = view.findViewById(R.id.icon)
|
||||
|
|
|
@ -14,8 +14,8 @@ import android.widget.TextView
|
|||
import net.osmand.Location
|
||||
import net.osmand.data.LatLon
|
||||
import net.osmand.telegram.R
|
||||
import net.osmand.telegram.TelegramLocationProvider.TelegramLocationListener
|
||||
import net.osmand.telegram.TelegramLocationProvider.TelegramCompassListener
|
||||
import net.osmand.telegram.TelegramLocationProvider.TelegramLocationListener
|
||||
import net.osmand.telegram.helpers.ShareLocationHelper
|
||||
import net.osmand.telegram.helpers.TelegramUiHelper
|
||||
import net.osmand.telegram.ui.SetTimeDialogFragment.SetTimeListAdapter.ChatViewHolder
|
||||
|
@ -36,6 +36,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
private lateinit var timeForAllValue: TextView
|
||||
|
||||
private val chatLivePeriods = HashMap<Long, Long>()
|
||||
private val userLivePeriods = HashMap<Long, Long>()
|
||||
|
||||
private var location: Location? = null
|
||||
private var heading: Float? = null
|
||||
|
@ -90,6 +91,9 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
chatLivePeriods.forEach { (chatId, livePeriod) ->
|
||||
settings.shareLocationToChat(chatId, true, livePeriod)
|
||||
}
|
||||
userLivePeriods.forEach { (userId, livePeriod) ->
|
||||
settings.shareLocationToUser(userId.toInt(), livePeriod)
|
||||
}
|
||||
app.shareLocationHelper.startSharingLocation()
|
||||
targetFragment?.also {
|
||||
it.onActivityResult(targetRequestCode, LOCATION_SHARED_REQUEST_CODE, null)
|
||||
|
@ -121,7 +125,13 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
chats.add(id)
|
||||
chats.add(livePeriod)
|
||||
}
|
||||
val users = mutableListOf<Long>()
|
||||
for ((id, livePeriod) in userLivePeriods) {
|
||||
users.add(id)
|
||||
users.add(livePeriod)
|
||||
}
|
||||
outState.putLongArray(CHATS_KEY, chats.toLongArray())
|
||||
outState.putLongArray(USERS_KEY, users.toLongArray())
|
||||
}
|
||||
|
||||
override fun updateLocation(location: Location?) {
|
||||
|
@ -167,17 +177,27 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
|
||||
private fun readFromBundle(bundle: Bundle?) {
|
||||
chatLivePeriods.clear()
|
||||
userLivePeriods.clear()
|
||||
bundle?.getLongArray(CHATS_KEY)?.also {
|
||||
for (i in 0 until it.size step 2) {
|
||||
val livePeriod = settings.getChatLivePeriod(it[i])
|
||||
chatLivePeriods[it[i]] = livePeriod ?: it[i + 1]
|
||||
}
|
||||
}
|
||||
bundle?.getLongArray(USERS_KEY)?.also {
|
||||
for (j in 0 until it.size step 2) {
|
||||
val livePeriod = settings.getChatLivePeriod(it[j])
|
||||
userLivePeriods[it[j]] = livePeriod ?: it[j + 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTimeForAll(useDefValue: Boolean = false): Long {
|
||||
val returnVal = if (useDefValue) DEFAULT_VISIBLE_TIME_SECONDS else NO_VALUE
|
||||
val iterator = chatLivePeriods.values.iterator()
|
||||
val allTime = mutableListOf<Long>()
|
||||
allTime.addAll(chatLivePeriods.values)
|
||||
allTime.addAll(userLivePeriods.values)
|
||||
val iterator = allTime.iterator()
|
||||
if (!iterator.hasNext()) {
|
||||
return returnVal
|
||||
}
|
||||
|
@ -202,7 +222,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
}
|
||||
}
|
||||
|
||||
private fun selectDuration(id: Long? = null) {
|
||||
private fun selectDuration(id: Long? = null, isChat: Boolean = true) {
|
||||
val timeForAll = getTimeForAll(true)
|
||||
val defSeconds = if (id == null) timeForAll else chatLivePeriods[id] ?: timeForAll
|
||||
val (defHours, defMinutes) = secondsToHoursAndMinutes(defSeconds)
|
||||
|
@ -213,11 +233,18 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
TimeUnit.MINUTES.toSeconds(minutes.toLong())
|
||||
if (seconds >= ShareLocationHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC) {
|
||||
if (id != null) {
|
||||
chatLivePeriods[id] = seconds
|
||||
if (isChat) {
|
||||
chatLivePeriods[id] = seconds
|
||||
} else {
|
||||
userLivePeriods[id] = seconds
|
||||
}
|
||||
} else {
|
||||
chatLivePeriods.keys.forEach {
|
||||
chatLivePeriods[it] = seconds
|
||||
}
|
||||
userLivePeriods.keys.forEach {
|
||||
userLivePeriods[it] = seconds
|
||||
}
|
||||
}
|
||||
updateTimeForAllRow()
|
||||
adapter.notifyDataSetChanged()
|
||||
|
@ -242,17 +269,19 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
}
|
||||
|
||||
private fun updateList() {
|
||||
val chats: MutableList<TdApi.Chat> = mutableListOf()
|
||||
val items: MutableList<TdApi.Object> = mutableListOf()
|
||||
telegramHelper.getChatList().filter { chatLivePeriods.keys.contains(it.chatId) }
|
||||
.forEach { orderedChat ->
|
||||
telegramHelper.getChat(orderedChat.chatId)?.also { chats.add(it) }
|
||||
telegramHelper.getChat(orderedChat.chatId)?.also { items.add(it) }
|
||||
}
|
||||
adapter.chats = chats
|
||||
telegramHelper.getContacts().values.filter { userLivePeriods.keys.contains(it.id.toLong()) }
|
||||
.forEach { user -> items.add(user) }
|
||||
adapter.items = items
|
||||
}
|
||||
|
||||
inner class SetTimeListAdapter : RecyclerView.Adapter<ChatViewHolder>() {
|
||||
|
||||
var chats: List<TdApi.Chat> = emptyList()
|
||||
var items: List<TdApi.Object> = emptyList()
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
|
@ -265,18 +294,38 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ChatViewHolder, position: Int) {
|
||||
val chat = chats[position]
|
||||
val placeholderId = if (telegramHelper.isGroup(chat)) R.drawable.img_group_picture else R.drawable.img_user_picture
|
||||
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()
|
||||
}
|
||||
|
||||
TelegramUiHelper.setupPhoto(app, holder.icon, chat.photo?.small?.local?.path, placeholderId, false)
|
||||
holder.title?.text = chat.title
|
||||
val placeholderId = if (isChat && telegramHelper.isGroup((item as TdApi.Chat))) R.drawable.img_group_picture else R.drawable.img_user_picture
|
||||
|
||||
if (telegramHelper.isGroup(chat)) {
|
||||
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
|
||||
|
||||
if (isChat && telegramHelper.isGroup((item as TdApi.Chat))) {
|
||||
holder.locationViewContainer?.visibility = View.GONE
|
||||
holder.description?.visibility = View.VISIBLE
|
||||
holder.description?.text = getString(R.string.shared_string_group)
|
||||
} else {
|
||||
val message = telegramHelper.getChatMessages(chat.id).firstOrNull()
|
||||
val message = telegramHelper.getChatMessages(itemId).firstOrNull()
|
||||
val content = message?.content
|
||||
if (message != null && content is TdApi.MessageLocation && (location != null && content.location != null)) {
|
||||
val lastUpdated = telegramHelper.getLastUpdatedTime(message)
|
||||
|
@ -301,15 +350,19 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
|
||||
holder.textInArea?.apply {
|
||||
visibility = View.VISIBLE
|
||||
chatLivePeriods[chat.id]?.also { text = formatLivePeriod(it) }
|
||||
if (isChat) {
|
||||
chatLivePeriods[itemId]?.also { text = formatLivePeriod(it) }
|
||||
} else {
|
||||
userLivePeriods[itemId]?.also { text = formatLivePeriod(it) }
|
||||
}
|
||||
}
|
||||
holder.bottomShadow?.visibility = View.GONE
|
||||
holder.itemView.setOnClickListener {
|
||||
selectDuration(chat.id)
|
||||
selectDuration(itemId, isChat)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() = chats.size
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
inner class ChatViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
val icon: ImageView? = view.findViewById(R.id.icon)
|
||||
|
@ -329,18 +382,31 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
|
|||
|
||||
private const val TAG = "SetTimeDialogFragment"
|
||||
private const val CHATS_KEY = "chats_key"
|
||||
private const val USERS_KEY = "users_key"
|
||||
private const val DEFAULT_VISIBLE_TIME_SECONDS = 60 * 60L // 1 hour
|
||||
private const val NO_VALUE = -1L
|
||||
|
||||
fun showInstance(fm: FragmentManager, chatIds: Set<Long>, target: Fragment): Boolean {
|
||||
fun showInstance(fm: FragmentManager, chatIds: Set<Long>, usersIds: Set<Long>, target: Fragment): Boolean {
|
||||
return try {
|
||||
val chats = mutableListOf<Long>()
|
||||
for (id in chatIds) {
|
||||
chats.add(id)
|
||||
chats.add(DEFAULT_VISIBLE_TIME_SECONDS)
|
||||
}
|
||||
val users = mutableListOf<Long>()
|
||||
for (id in usersIds) {
|
||||
users.add(id)
|
||||
users.add(DEFAULT_VISIBLE_TIME_SECONDS)
|
||||
}
|
||||
SetTimeDialogFragment().apply {
|
||||
arguments = Bundle().apply { putLongArray(CHATS_KEY, chats.toLongArray()) }
|
||||
arguments = Bundle().apply {
|
||||
if (chats.isNotEmpty()) {
|
||||
putLongArray(CHATS_KEY, chats.toLongArray())
|
||||
}
|
||||
if (users.isNotEmpty()) {
|
||||
putLongArray(USERS_KEY, users.toLongArray())
|
||||
}
|
||||
}
|
||||
setTargetFragment(target, LOCATION_SHARED_REQUEST_CODE)
|
||||
show(fm, TAG)
|
||||
}
|
||||
|
|
|
@ -228,7 +228,11 @@ class SettingsDialogFragment : BaseDialogFragment() {
|
|||
isModal = true
|
||||
anchorView = valueView
|
||||
setContentWidth(AndroidUtils.getPopupMenuWidth(ctx, menuList))
|
||||
height = AndroidUtils.getPopupMenuHeight(ctx)
|
||||
height = if (menuList.size < 6) {
|
||||
ListPopupWindow.WRAP_CONTENT
|
||||
} else {
|
||||
AndroidUtils.getPopupMenuHeight(ctx)
|
||||
}
|
||||
setDropDownGravity(Gravity.END or Gravity.TOP)
|
||||
setAdapter(ArrayAdapter(ctx, R.layout.popup_list_text_item, menuList))
|
||||
setOnItemClickListener { _, _, position, _ ->
|
||||
|
|
|
@ -10,6 +10,8 @@ import org.json.JSONObject
|
|||
|
||||
const val BASE_URL = "https://live.osmand.net"
|
||||
|
||||
const val BASE_SHARING_URL = "http://osmand.net/go"
|
||||
|
||||
object OsmandApiUtils {
|
||||
|
||||
private val log = PlatformUtil.getLog(OsmandApiUtils::class.java)
|
||||
|
|
|
@ -52,10 +52,10 @@ android {
|
|||
minSdkVersion System.getenv("MIN_SDK_VERSION") ? System.getenv("MIN_SDK_VERSION").toInteger() :
|
||||
(analytics ? 15 : 14)
|
||||
targetSdkVersion 26
|
||||
versionCode 320
|
||||
versionCode 330
|
||||
versionCode System.getenv("APK_NUMBER_VERSION") ? System.getenv("APK_NUMBER_VERSION").toInteger() : versionCode
|
||||
multiDexEnabled true
|
||||
versionName "3.2.0"
|
||||
versionName "3.3.0"
|
||||
versionName System.getenv("APK_VERSION")? System.getenv("APK_VERSION").toString(): versionName
|
||||
versionName System.getenv("APK_VERSION_SUFFIX")? versionName + System.getenv("APK_VERSION_SUFFIX").toString(): versionName
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
<string name="download_srtm_maps">الخطوط المحيطية (الكنتورية)</string>
|
||||
<string name="download_regular_maps">الخرائط العادية</string>
|
||||
<string name="rendering_attr_noAdminboundaries_name">الحدود</string>
|
||||
<string name="map_widget_max_speed">حدّ السرعة</string>
|
||||
<string name="map_widget_max_speed">حد السرعة</string>
|
||||
|
||||
|
||||
|
||||
|
@ -91,7 +91,7 @@
|
|||
<string name="poi_filter_food_shop">متاجر المواد الغذائية</string>
|
||||
<string name="poi_filter_for_tourists">للسياح</string>
|
||||
<string name="poi_filter_fuel">وقود</string>
|
||||
<string name="show_warnings_title">إظهار تنبيهات…</string>
|
||||
<string name="show_warnings_title">إظهار التنبيهات…</string>
|
||||
<string name="use_compass_navigation">استخدم البوصلة</string>
|
||||
<string name="avoid_motorway">تجنب الطرق السريعة</string>
|
||||
|
||||
|
@ -208,7 +208,7 @@
|
|||
<string name="driving_region_europe_asia">أوروبا، آسيا، أمريكا اللاتينية، وغيرها</string>
|
||||
<string name="driving_region_uk">المملكة المتحدة، الهند وما شابه ذلك</string>
|
||||
|
||||
<string name="speak_title">أعلن…</string>
|
||||
<string name="speak_title">أعلان…</string>
|
||||
<string name="osb_author_or_password_not_specified">يرجى تحديد مستخدم OSM وكلمة سره في الإعدادات</string>
|
||||
<string name="clear_intermediate_points">محو الوجهات الوسيطة</string>
|
||||
<string name="keep_intermediate_points">الحفاظ على الوجهات الوسيطة</string>
|
||||
|
@ -326,17 +326,17 @@
|
|||
|
||||
|
||||
<string name="speak_descr">ضبط إعدادات نطق أسماء الشوارع، وتحذيرات المرور (توقيفات الإجبارية، ومطبات السرعة)، و تحذيرات كاميرات السرعة، و السرعة القصوى.</string>
|
||||
<string name="speak_street_names">نطق أسماء الشوارع ( نطق آلي TTS )</string>
|
||||
<string name="speak_speed_limit">السرعة القصوى</string>
|
||||
<string name="speak_street_names">أسماء الشوارع (TTS)</string>
|
||||
<string name="speak_speed_limit">حد السرعة</string>
|
||||
<string name="speak_cameras">كاميرات السرعة</string>
|
||||
<string name="speak_traffic_warnings">تحذيرات حركة المرور</string>
|
||||
<string name="route_descr_map_location">الخريطة: </string>
|
||||
<string name="destination_point">الوجهة %1$s</string>
|
||||
<string name="search_street_in_neighborhood_cities">البحث عن الشارع في المدن المجاورة</string>
|
||||
<string name="intermediate_items_sort_by_distance">فرز باب لـ باب </string>
|
||||
<string name="intermediate_items_sort_by_distance">فرز باب لـ باب</string>
|
||||
<string name="wait_current_task_finished">الرجاء الانتظار حتى انتهاء المهمة الحالية</string>
|
||||
<string name="available_downloads_left">توفر %1$d ملفات للتنزيل</string>
|
||||
<string name="cancel_route">ألغ المسار</string>
|
||||
<string name="cancel_route">صرف المسار</string>
|
||||
<string name="monitoring_settings">تسجيل الرحلة</string>
|
||||
<string name="monitoring_settings_descr">قم بضبط كيفية تسجيل الرحلات.</string>
|
||||
|
||||
|
@ -397,9 +397,9 @@
|
|||
<string name="add_as_last_destination_point">أضف كآخر وجهة وسيطة</string>
|
||||
<string name="add_as_first_destination_point">أضف كأول وجهة وسيطة</string>
|
||||
<string name="intermediate_point_too_far">الوجهة %1$s بعيدة جدا من أقرب طريق.</string>
|
||||
<string name="arrived_at_intermediate_point">إنك قد وصلت إلى وجهتك الوسيطة</string>
|
||||
<string name="arrived_at_intermediate_point">لقد وصلت إلى وجهتك الوسيطة</string>
|
||||
<string name="context_menu_item_intermediate_point">أضف كوجهة وسيطة</string>
|
||||
<string name="map_widget_intermediate_distance">وجهة متوسطة</string>
|
||||
<string name="map_widget_intermediate_distance">وجهة وسيطة</string>
|
||||
<string name="ending_point_too_far">نقطة الوصول بعيدة جدا عن أقرب طريق.</string>
|
||||
<string name="add_tag">أضف وسما</string>
|
||||
<string name="show_warnings_descr">ضبط تحذيرات المرور ( حدود السرعة، والتوقف القسري، والمطبات الصناعية ) ، وتحذيرات كاميرا السرعة ، ومعلومات الممرات.</string>
|
||||
|
@ -409,7 +409,7 @@
|
|||
<string name="edit_tilesource_successfully">حُفِظ المصدر التّجانبي %1$s بنجاح</string>
|
||||
<string name="use_compass_navigation_descr">استخدم البوصلة عندما لا تكون هناك أي وجهة محددة.</string>
|
||||
<string name="auto_zoom_map_descr">ملائمة تقريب الخريطة وفقا لسرعتك (هذا بينما تتزامن الخريطة مع الموقع الحالي).</string>
|
||||
<string name="auto_zoom_map">تقريب الخريطة تلقائيًا</string>
|
||||
<string name="auto_zoom_map">تكبير الخريطة تلقائيًا</string>
|
||||
<string name="snap_to_road_descr">ألصق الموقع إلى الشوارع أثناء الملاحة.</string>
|
||||
<string name="snap_to_road">الالتصاق بالطريق</string>
|
||||
<string name="osmand_play_title_30_chars">خرائط OsmAnd وملاحة</string>
|
||||
|
@ -625,16 +625,16 @@
|
|||
<string name="auto_announce_on">تفعيل الإخطار التلقائي</string>
|
||||
|
||||
<string name="audionotes_location_not_defined">لم يتم ربط الملاحظة بأي موقع. إضغط على \"استخدام المكان …\" لترفق ملاحظة بالمكان المحدد.</string>
|
||||
<string name="animate_routing_route_not_calculated">الرجاء، احتسب المسار أولا</string>
|
||||
<string name="animate_routing_route_not_calculated">الرجاء حساب الطريق أولا</string>
|
||||
<string name="animate_routing_route">حاكي باستخدام المسار المحتسب </string>
|
||||
<string name="animate_routing_gpx">حاكي باستخدام مسار GPX</string>
|
||||
<string name="shared_string_remember_my_choice">تذكر اختياري</string>
|
||||
|
||||
<string name="native_app_allocated_memory_descr">إجمالي الذاكرة الأصلية المخصصة من قبل التطبيق %1$s ميغابايت (Dalvik %2$s ميغابايت، الأخرى %3$s ميغابايت). الذاكرة النسبية %4$s ميغابايت (حد الجهاز %5$s ميغابايت Dalvik %6$s ميغابايت).</string>
|
||||
<string name="app_mode_hiking">مشي</string>
|
||||
<string name="app_mode_hiking">التنزه</string>
|
||||
<string name="app_mode_motorcycle">دراجة نارية</string>
|
||||
<string name="app_mode_boat">قارب</string>
|
||||
<string name="app_mode_aircraft">الطائرات</string>
|
||||
<string name="app_mode_aircraft">طائرة</string>
|
||||
<string name="app_modes_choose_descr">اختر أوضاع الاستخدام لتكون مرئية في التطبيق.</string>
|
||||
<string name="app_modes_choose">ملامح التطبيق</string>
|
||||
|
||||
|
@ -976,7 +976,7 @@
|
|||
<string name="hours_ago">ساعة</string>
|
||||
<string name="minutes_ago">دقيقة</string>
|
||||
<string name="seconds_ago">ثانية</string>
|
||||
<string name="always_center_position_on_map">اظهر الموضع في المنتصف دائماً</string>
|
||||
<string name="always_center_position_on_map">اظهر الموقع في الوسط دائما</string>
|
||||
<string name="localization_pref_title">التوطين</string>
|
||||
<string name="lang_hr">الكرواتية</string>
|
||||
<string name="lang_pt_br">البرتغالية (البرازيل)</string>
|
||||
|
@ -1005,11 +1005,11 @@
|
|||
<string name="route_info">معلومات الطريق</string>
|
||||
|
||||
<string name="routing_attr_avoid_toll_name">تجنب الطرق ذات الرسوم</string>
|
||||
<string name="routing_attr_avoid_toll_description">إجتناب الطرق التي يجب دفع رسوم للمرور فيها.</string>
|
||||
<string name="routing_attr_avoid_unpaved_name">تجنب الطرق غير المعبّدة</string>
|
||||
<string name="routing_attr_avoid_toll_description">تجنب الطرق ذات الرسوم</string>
|
||||
<string name="routing_attr_avoid_unpaved_name">تجنب الطرق غير المعبدة</string>
|
||||
<string name="routing_attr_avoid_unpaved_description">اجتناب الطرق الترابية والوعرة.</string>
|
||||
<string name="routing_attr_avoid_ferries_name">تجنب العبّارات</string>
|
||||
<string name="routing_attr_weight_name">حد الوزن المسموح</string>
|
||||
<string name="routing_attr_weight_name">الوزن الأقصى</string>
|
||||
<string name="android_19_location_disabled">منذ نسخة أندرويد كتكات 4.4، لا يمكنك تنزيل أو تحديث الخرائط في مكان التخزين السابق (%s). هل تريد تغيير المكان إلى مكان مسموح ونسخ كل الملفات إليه ؟
|
||||
|
||||
ملاحظة 1 : الملفات القديمة ستبقى كما هي دون لمس (ولكن يمكن حذفها يدويا).
|
||||
|
@ -1142,7 +1142,7 @@
|
|||
<string name="get_directions">الاتجاهات</string>
|
||||
<string name="show_point_options">إستخدام الموقع …</string>
|
||||
<string name="favorite">مفضلة</string>
|
||||
<string name="speak_favorites">نقاط مفضلة مجاورة</string>
|
||||
<string name="speak_favorites">النقاط المفضلة مجاورة</string>
|
||||
<string name="save_as_favorites_points">إحفظ كمجموعة مفضلة</string>
|
||||
<string name="add_favorite_dialog_top_text">أدخل اسم المفضلة</string>
|
||||
<string name="add_favorite_dialog_favourite_added_template">"تم إضافة النقطة المفضلة \'\'{0}\'\' بنجاح."</string>
|
||||
|
@ -1221,12 +1221,12 @@
|
|||
<string name="rendering_attr_tramRoutes_name">خطوط الترام</string>
|
||||
<string name="rendering_category_routes">طرق</string>
|
||||
<string name="rendering_category_transport">المواصلات</string>
|
||||
<string name="rendering_category_others">سمات أخرى للخريطة</string>
|
||||
<string name="rendering_category_others">ميزات آخرى للخريطة</string>
|
||||
<string name="map_widget_appearance_rem">العناصر المتبقية</string>
|
||||
<string name="map_widget_top">شريط المعلومات</string>
|
||||
<string name="map_widget_right">اللوحة اليمنى</string>
|
||||
<string name="map_widget_left">اللوحة اليسرى</string>
|
||||
<string name="search_radius_proximity">ضمن</string>
|
||||
<string name="search_radius_proximity">في غضون</string>
|
||||
|
||||
<string name="anonymous_user">مستخدم مجهول</string>
|
||||
<string name="logged_as">سجل الدخول بـ %1$s</string>
|
||||
|
@ -1285,7 +1285,7 @@
|
|||
<string name="rendering_attr_hideNonVehicleHighways_name">الطرق السريعة غير المخصصة للمركبات</string>
|
||||
<string name="rendering_attr_hideText_name">النص</string>
|
||||
<string name="rendering_attr_buildings15zoom_name">المباني في التقريب 15</string>
|
||||
<string name="rendering_attr_moreDetailed_name">مزيد من التفاصيل</string>
|
||||
<string name="rendering_attr_moreDetailed_name">التفاصيل اكثر</string>
|
||||
<string name="rendering_attr_lessDetailed_name">تفاصيل أقل</string>
|
||||
<string name="rendering_attr_showSurfaceGrade_name">إظهار جودة الطريق</string>
|
||||
|
||||
|
@ -1327,21 +1327,21 @@
|
|||
<string name="rendering_attr_busRoutes_name">طرق الحافلات</string>
|
||||
<string name="rendering_attr_subwayMode_name">سكك مترو الأنفاق</string>
|
||||
<string name="rendering_attr_shareTaxiRoutes_name">شارك طرق التاكسي</string>
|
||||
<string name="speed_limit_exceed_message">حدد حد السرعة المسموح به لتلقي تنبيه صوتي ما إذا تجاوزته.</string>
|
||||
<string name="speed_limit_exceed_message">حدد مجال السرعة المسموح به لتتلقى تنبيه صوتي ما إذا تجاوزته.</string>
|
||||
<string name="traffic_warning_border_control">مراقبة الحدود</string>
|
||||
<string name="traffic_warning_payment">كشك الرسوم</string>
|
||||
<string name="traffic_warning_calming">تخفيف الازدحام</string>
|
||||
<string name="traffic_warning_speed_camera">كاميرا مراقبة السرعة</string>
|
||||
<string name="traffic_warning">تنبيه مروري</string>
|
||||
<string name="speak_poi">POI مجاورة</string>
|
||||
<string name="traffic_warning_speed_camera">كاميرا السرعة</string>
|
||||
<string name="traffic_warning">تحذير حركة المرور</string>
|
||||
<string name="speak_poi">POI المجاورة</string>
|
||||
<string name="way_alarms">تنبيهات مرورية</string>
|
||||
<string name="save_track_to_gpx_globally_headline">تسجيل المسار حسب الطلب</string>
|
||||
<string name="download_additional_maps">حمّل الخرائط المفقودة %1$s (%2$d MB)؟</string>
|
||||
|
||||
<string name="rendering_attr_hideAccess_name">قيود الدخول</string>
|
||||
<string name="rendering_attr_showAccess_name">عرض قيود الدخول</string>
|
||||
<string name="rendering_attr_showSurfaces_name">عرض سطح الطريق</string>
|
||||
<string name="rendering_attr_showCycleRoutes_name">عرض الطرق الدائرية</string>
|
||||
<string name="rendering_attr_showSurfaces_name">إظهار سطح الطريق</string>
|
||||
<string name="rendering_attr_showCycleRoutes_name">عرض الطرق الخاصة بالدرجات</string>
|
||||
|
||||
|
||||
<string name="delay_navigation_start">ابدأ التوجيه دروان بدوران تلقائيا</string>
|
||||
|
@ -1410,14 +1410,14 @@
|
|||
<string name="calculate_osmand_route_without_internet">احسب قسم طريق OsmAnd بدون إنترنت</string>
|
||||
<string name="gpx_option_calculate_first_last_segment">احسب طريق OsmAnd لأول وآخر قسمين في الطريق</string>
|
||||
<string name="use_displayed_track_for_navigation">هل ترغب باستخدام المسار المعروض للملاحة؟</string>
|
||||
<string name="keep_and_add_destination_point">أضافة كنقطة وجهة لاحقة</string>
|
||||
<string name="keep_and_add_destination_point">اضافة كنقطة وجهة لاحقة</string>
|
||||
<string name="select_gpx">اختر GPX…</string>
|
||||
<string name="route_descr_select_destination">حدد الوجهة</string>
|
||||
<string name="routing_attr_prefer_motorway_name">تفضيل طرق الدراجات النارية</string>
|
||||
<string name="routing_attr_prefer_motorway_description">تفضيل طرق الدراجات النارية.</string>
|
||||
<string name="routing_attr_avoid_ferries_description">تجنب العبّارات المائية.</string>
|
||||
<string name="routing_attr_prefer_motorway_name">تفضل الطرق السريعة</string>
|
||||
<string name="routing_attr_prefer_motorway_description">تفضيل الطرق السريعة</string>
|
||||
<string name="routing_attr_avoid_ferries_description">تجنب العبّارات المائية</string>
|
||||
<string name="routing_attr_avoid_motorway_name">تجنب الطرق السريعة</string>
|
||||
<string name="routing_attr_avoid_motorway_description">تجنب طرق الدراجات النارية.</string>
|
||||
<string name="routing_attr_avoid_motorway_description">تجنب الطرق السريعة</string>
|
||||
<string name="routing_attr_weight_description">حدد وزن المركبة الأقصى المسموح به على الطرقات.</string>
|
||||
<string name="copying_osmand_files_descr">نسخ ملفات بيانات OsmAnd إلى المسار الجديد (%s)…</string>
|
||||
<string name="calculate_osmand_route_gpx">احسب طريق OsmAnd بدون اتصال</string>
|
||||
|
@ -1640,7 +1640,7 @@
|
|||
<string name="lang_es_ar">الإسبانية (الأرجنتين)</string>
|
||||
<string name="si_nm">ميل بحري</string>
|
||||
<string name="dark_theme">داكن</string>
|
||||
<string name="routing_attr_height_name">تحديد الإرتفاع</string>
|
||||
<string name="routing_attr_height_name">الإرتفاع الاقصى</string>
|
||||
<string name="default_speed_system_descr">تحديد وحدة السرعة.</string>
|
||||
<string name="default_speed_system">وحدة السرعة</string>
|
||||
<string name="plugin_settings">ملحقات</string>
|
||||
|
@ -1819,7 +1819,7 @@
|
|||
<string name="active_markers">العلامات المفعلة</string>
|
||||
<string name="map_markers">علامات خرائطية</string>
|
||||
|
||||
<string name="routing_attr_avoid_borders_name">منع تخطي الحدود</string>
|
||||
<string name="routing_attr_avoid_borders_name">تجنب عبور الحدود</string>
|
||||
<string name="impassable_road_desc">حدد الطرق التي تريد تجنبها أثناء التنقل.</string>
|
||||
<string name="search_categories">فئات</string>
|
||||
<string name="shared_string_near">قرب</string>
|
||||
|
@ -2075,7 +2075,7 @@
|
|||
<string name="region_maps">خرائط واسعة النطاق</string>
|
||||
<string name="hillshade_layer_disabled">طبقة التضاريس غير مفعلة</string>
|
||||
<string name="srtm_plugin_disabled">الخطوط الكفافية معطلة</string>
|
||||
<string name="nm">nmi</string>
|
||||
<string name="nm">ميل بحري</string>
|
||||
<string name="nm_h">ميل بحري/ساعة</string>
|
||||
<string name="simulate_your_location_descr">محاكاة موقعك باستخدام طريق مقاس أو مسار GPX مسجل.</string>
|
||||
<string name="routing_attr_avoid_shuttle_train_name">تجنب قطار المدينة</string>
|
||||
|
@ -2128,11 +2128,11 @@
|
|||
|
||||
<string name="lang_hu_formal">الهنغارية (الرسمية)</string>
|
||||
<string name="routing_attr_avoid_stairs_name">تجنب الأدراج</string>
|
||||
<string name="routing_attr_avoid_stairs_description">تجنب الأدراج.</string>
|
||||
<string name="routing_attr_avoid_stairs_description">تجنب الأدراج</string>
|
||||
<string name="routing_attr_avoid_borders_description">تجنب عبور الحدود إلى بلد آخر.</string>
|
||||
<string name="routing_attr_height_description">تحديد ارتفاع السيارة المسموح على الطرق.</string>
|
||||
<string name="disable_complex_routing_descr">تعطيل 2-مرحلة التوجيه للملاحة بالسيارة.</string>
|
||||
<string name="rendering_attr_alpineHiking_name">مقياس جبال الألب للتنزه (نادي جبال الألب السويسرية)</string>
|
||||
<string name="rendering_attr_alpineHiking_name">مقياس جبال الألب للتنزه (SAC)</string>
|
||||
<string name="rendering_attr_alpineHiking_description">تقديم مسارات وفقا لمقياس SAC.</string>
|
||||
<string name="rendering_attr_hikingRoutesOSMC_name">غطاء رمز التنزه</string>
|
||||
<string name="rendering_attr_hikingRoutesOSMC_description">تقديم مسارات وفقا لآثار OSMC.</string>
|
||||
|
@ -2810,7 +2810,7 @@
|
|||
<string name="south_abbreviation">ج</string>
|
||||
<string name="north_abbreviation">ش</string>
|
||||
<string name="optional_point_name">الإسم الإختياري للنقطة</string>
|
||||
<string name="transport_nearby_routes_within">المسارات القريبة مِن</string>
|
||||
<string name="transport_nearby_routes_within">المسارات القريبة في غضون</string>
|
||||
<string name="enter_the_file_name">أدخل إسم الملف.</string>
|
||||
<string name="map_import_error">خطأ أثناء استرجاع الخريطة</string>
|
||||
<string name="map_imported_successfully">تمت عملية استيراد الخريطة</string>
|
||||
|
@ -2911,4 +2911,33 @@
|
|||
<string name="search_street">البحث عن شارع</string>
|
||||
<string name="start_search_from_city">اختر المدينة أولا</string>
|
||||
<string name="shared_string_restore">استعادة</string>
|
||||
<string name="third_party_application">تطبيق من طرف-ثالث</string>
|
||||
<string name="keep_passed_markers_descr">العلامات المضافة كمجموعة مفضلة أو نقاط طريق GPX ستظل على الخريطة. اذا كانت المجموعة غير نشطة، العلامات سوف تختفي من الخريطة.</string>
|
||||
<string name="keep_passed_markers">إبقاء العلامات المتجاوزة على الخريطة</string>
|
||||
<string name="more_transport_on_stop_hint">هناك المزيد من النقل في هذا الموقف.</string>
|
||||
<string name="ask_for_location_permission">يرجى إعطاء إذن الموقع للتطبيق لكي يواصل.</string>
|
||||
<string name="thank_you_for_feedback">شكرا على ردود الفعل</string>
|
||||
<string name="poi_cannot_be_found">النقطة أو الطريق غير موجود.</string>
|
||||
<string name="search_no_results_feedback">لا نتائج بحث؟
|
||||
\nاخبرنا بانطباعك</string>
|
||||
<string name="increase_search_radius_to">توسيع دائرة البحث بقطر %1$s</string>
|
||||
<string name="send_search_query">ارسال استفسار البحث؟</string>
|
||||
<string name="shared_string_world">العالم</string>
|
||||
<string name="point_deleted">تم حذف %1$s نقطة</string>
|
||||
<string name="coord_input_edit_point">تحرير نقطة</string>
|
||||
<string name="coord_input_add_point">إضافة نقطة</string>
|
||||
<string name="coord_input_save_as_track">حفظ كمسار</string>
|
||||
<string name="coord_input_save_as_track_descr">لقد أضفت %1$s نقطة. اكتب اسم الملف و اضغط على \"حفظ\".</string>
|
||||
<string name="error_notification_desc">يرجى إرسال لقطة شاشة من هذا الإخطار الى support@osmand.net</string>
|
||||
<string name="quick_action_edit_actions">تعديل الإجراءات</string>
|
||||
<string name="get_osmand_live">احصل على OsmAnd Live لفتح جميع الميزات: تحديثات يومية للخريطة مع تنزيلات غير محدودة، جميع الإضافات المدفوعة والمجانية، Wikipedia ،wikivoyage وأكثر من ذلك بكثير.</string>
|
||||
<string name="osm_live_subscriptions">الاشتراكات</string>
|
||||
<string name="default_price_currency_format">%1$.2f %2$s</string>
|
||||
<string name="read_wikipedia_offline_description">احصل على اشتراك OsmAnd Live لقراءة مقالات Wikipedia و wikivoyage.</string>
|
||||
<string name="purchase_cancelled_dialog_descr">جدد الاشتراك لتستمر في استخدام كافة الميزات:</string>
|
||||
|
||||
<string name="maps_you_need_descr">استنادا إلى المقالات التي قمتم بحفظها، الخرائط التالية موصى بتحميلها:</string>
|
||||
<string name="paid_app">تطبيق مدفوع</string>
|
||||
<string name="paid_plugin">أداة مدفوعة</string>
|
||||
<string name="start_editing_card_image_text">دليل السفر العالمي المجانا الذي بامكان أي شخص التعديل عليه.</string>
|
||||
</resources>
|
||||
|
|
|
@ -3168,4 +3168,5 @@ Praparcyjnaj pamiacі %4$s MB (Abmiežavańnie Android %5$s MB, Dalvik %6$s MB).
|
|||
<string name="osm_live_payment_contribute_descr">Častka dachodu idzie ŭdzieĺnikam OpenStreetMap.</string>
|
||||
<string name="powered_by_osmand">Pracuje na OsmAnd</string>
|
||||
<string name="mapillary_menu_title_pano">Pakazać tolki 360° malunki</string>
|
||||
<string name="osm_live_subscriptions">Padpiski</string>
|
||||
</resources>
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -2251,7 +2251,7 @@ Proportional hukommelse %4$s MB (Android grænse %5$s MB, Dalvik %6$s MB).</stri
|
|||
\nFor at aktivere alle nye funktioner, er det nødvendigt at genstarte OsmAnd.</string>
|
||||
<string name="osm_live_region_desc">En del af donationen vil blive sendt til OSM-brugere, som indsender ændringer til kortet i det pågældende område.</string>
|
||||
<string name="osm_live_subscription_settings">Indstillinger for abonnement</string>
|
||||
<string name="osm_live_ask_for_purchase">Køb først OsnAnd Live-abonnement</string>
|
||||
<string name="osm_live_ask_for_purchase">Køb først OsmAnd Live-abonnement</string>
|
||||
|
||||
<string name="osm_live_header">"Abonnementet giver timebaserede opdateringer til alle kort i hele verden.
|
||||
\nEn del af indtægten går tilbage til OSM-fællesskabet og udbetales for hvert OSM-bidrag.
|
||||
|
@ -2795,7 +2795,7 @@ Repræsenterer område: %1$s x %2$s</string>
|
|||
<string name="mapillary_menu_edit_text_hint">Indtast brugernavn</string>
|
||||
<string name="mapillary_menu_descr_username">Se kun billeder tilføjet af</string>
|
||||
<string name="mapillary_menu_title_username">Brugernavn</string>
|
||||
<string name="mapillary_menu_filter_description">Filtrer billeder efter indsender eller dato. Kun aktiv for højere zoomniveauer.</string>
|
||||
<string name="mapillary_menu_filter_description">Filtrer billeder efter indsender, dato eller type. Kun aktiv for højere zoomniveauer.</string>
|
||||
<string name="mapillary_menu_descr_dates">Se kun de billeder, der er tilføjet</string>
|
||||
<string name="shared_string_reload">Genindlæs</string>
|
||||
<string name="mapillary_menu_descr_tile_cache">Genindlæs kortbrikker for at se opdaterede data.</string>
|
||||
|
@ -3222,17 +3222,19 @@ Repræsenterer område: %1$s x %2$s</string>
|
|||
<string name="keep_passed_markers">Behold passerede markører på kortet</string>
|
||||
<string name="osm_live_plan_pricing">Plan & Priser</string>
|
||||
<string name="osm_live_payment_monthly_title">Betal månedligt</string>
|
||||
<string name="osm_live_payment_3_months_title">Betal én gang i 3 måneder</string>
|
||||
<string name="osm_live_payment_3_months_title">Betal én gang hver 3. måned</string>
|
||||
<string name="osm_live_payment_annual_title">Betal en gang om året</string>
|
||||
<string name="osm_live_payment_month_cost_descr">%1$s / måned</string>
|
||||
<string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$s / måned</string>
|
||||
<string name="osm_live_payment_discount_descr">Spar %1$s!</string>
|
||||
<string name="osm_live_payment_current_subscription">Nuværende abonnement</string>
|
||||
<string name="osm_live_payment_renews_monthly">Forny månedlig</string>
|
||||
<string name="osm_live_payment_renews_quarterly">Forny kvartalsvis</string>
|
||||
<string name="osm_live_payment_renews_annually">Forny hvert år</string>
|
||||
<string name="osm_live_payment_renews_monthly">Fornyes månedligt</string>
|
||||
<string name="osm_live_payment_renews_quarterly">Fornyes kvartalsvis</string>
|
||||
<string name="osm_live_payment_renews_annually">Fornyes hvert år</string>
|
||||
<string name="default_price_currency_format">%1$.2f %2$s</string>
|
||||
<string name="osm_live_payment_header">Vælg en passende betalingsperiode:</string>
|
||||
<string name="osm_live_payment_contribute_descr">En del af indtægterne går til OpenStreetMap bidragydere.</string>
|
||||
<string name="osm_live_payment_contribute_descr">En del af indtægterne går til OpenStreetMap bidragsydere.</string>
|
||||
<string name="powered_by_osmand">Drevet af OsmAnd</string>
|
||||
<string name="osm_live_subscriptions">Abonnementer</string>
|
||||
<string name="mapillary_menu_title_pano">Vis kun 360° billeder</string>
|
||||
</resources>
|
||||
|
|
|
@ -1200,7 +1200,7 @@
|
|||
<string name="poi_elevator_no">Ohne Aufzug</string>
|
||||
|
||||
<string name="poi_fuel_91ul">Avgas UL 91</string>
|
||||
<string name="poi_fuel_100ll">Avgas 100 LL</string>
|
||||
<string name="poi_fuel_100ll">Avgas 100LL</string>
|
||||
<string name="poi_fuel_autogas">Autogas</string>
|
||||
<string name="poi_fuel_jeta1">Flugzeug A-1 Kraftstoff</string>
|
||||
<string name="poi_fuel_adblue">AdBlue</string>
|
||||
|
|
|
@ -3921,7 +3921,7 @@
|
|||
<string name="poi_payment_contactless_no">No acepta Pagos sin contacto</string>
|
||||
|
||||
<string name="poi_hazard_nuclear">Peligro nuclear</string>
|
||||
<string name="poi_hazard_erosion">Peligro de erosión</string>
|
||||
<string name="poi_hazard_erosion">Peligro de derrumbe por erosión</string>
|
||||
<string name="poi_hazard_avalanche">Peligro de avalancha</string>
|
||||
<string name="poi_hazard_slippery_road">Camino resbaladizo</string>
|
||||
<string name="poi_hazard_flood">Peligro de inundación</string>
|
||||
|
|
|
@ -3680,7 +3680,7 @@
|
|||
<string name="poi_payment_contactless_no">No acepta Pagos sin contacto</string>
|
||||
|
||||
<string name="poi_hazard_nuclear">Peligro nuclear</string>
|
||||
<string name="poi_hazard_erosion">Peligro de erosión</string>
|
||||
<string name="poi_hazard_erosion">Peligro de derrumbe por erosión</string>
|
||||
<string name="poi_hazard_avalanche">Peligro de avalancha</string>
|
||||
<string name="poi_hazard_slippery_road">Camino resbaladizo</string>
|
||||
<string name="poi_hazard_flood">Peligro de inundación</string>
|
||||
|
|
|
@ -3903,7 +3903,7 @@
|
|||
<string name="poi_payment_contactless_no">Sin contacto: no se acepta</string>
|
||||
|
||||
<string name="poi_hazard_nuclear">Peligro nuclear</string>
|
||||
<string name="poi_hazard_erosion">Peligro de erosión</string>
|
||||
<string name="poi_hazard_erosion">Peligro de derrumbe por erosión</string>
|
||||
<string name="poi_hazard_avalanche">Peligro de avalancha</string>
|
||||
<string name="poi_hazard_slippery_road">Carretera resbaladiza</string>
|
||||
<string name="poi_hazard_flood">Peligro de inundación</string>
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
<string name="poi_railway_platform">Tren andena</string>
|
||||
<string name="poi_halt">Tren geltokia</string>
|
||||
<string name="poi_subway_entrance">Metro sarrera</string>
|
||||
<string name="poi_subway_station">Metro geltokia</string>
|
||||
<string name="poi_subway_station">Bai</string>
|
||||
<string name="poi_taxi">Taxi geltokia</string>
|
||||
|
||||
<string name="poi_aerodrome">Aireportua</string>
|
||||
|
@ -444,7 +444,7 @@
|
|||
<string name="poi_prison">Kartzela</string>
|
||||
<string name="poi_migration">Migrazioa</string>
|
||||
<string name="poi_tax_inspection">Ogasun ikuskaritza</string>
|
||||
<string name="poi_capital">Hiriburua</string>
|
||||
<string name="poi_capital">Bai</string>
|
||||
<string name="poi_town">Herria</string>
|
||||
<string name="poi_neighbourhood">Auzoa</string>
|
||||
<string name="poi_place_allotments">Baratza komunitarioak</string>
|
||||
|
@ -1541,7 +1541,7 @@
|
|||
<string name="poi_diet_pescetarian_yes">Peszetarianoa</string>
|
||||
|
||||
<string name="poi_brewery_additional">Garagardotegiaren izena</string>
|
||||
<string name="poi_microbrewery_yes">Mikro-garagardotegia</string>
|
||||
<string name="poi_microbrewery_yes">Bai</string>
|
||||
<string name="poi_microbrewery_no">Ez da mikro-garagardotegia</string>
|
||||
|
||||
<string name="poi_piste_grooming_skating">Patinajea</string>
|
||||
|
@ -3878,8 +3878,8 @@
|
|||
<string name="poi_bulk_purchase">Handizkaria</string>
|
||||
<string name="poi_substation_type">Mota</string>
|
||||
|
||||
<string name="poi_bulk_purchase_yes">Handizkaria: bai</string>
|
||||
<string name="poi_bulk_purchase_only">Handizkaria: besterik ez</string>
|
||||
<string name="poi_bulk_purchase_yes">Bai</string>
|
||||
<string name="poi_bulk_purchase_only">Besterik ez</string>
|
||||
|
||||
<string name="poi_substation_transmission">Transmisioa</string>
|
||||
<string name="poi_substation_distribution">Banaketa</string>
|
||||
|
@ -3887,7 +3887,7 @@
|
|||
<string name="poi_substation_industrial">Industriala</string>
|
||||
<string name="poi_substation_transition">Trantsizioa</string>
|
||||
<string name="poi_substation_traction">Trakzioa</string>
|
||||
<string name="poi_substation_converter"></string>
|
||||
<string name="poi_substation_converter">Bihurtzailea</string>
|
||||
<string name="poi_substation_compensation">Konpentsazioa</string>
|
||||
|
||||
<string name="poi_substation_compression">Konpresioa</string>
|
||||
|
|
|
@ -1755,7 +1755,7 @@
|
|||
<string name="shared_string_dismiss">بیخیال</string>
|
||||
<string name="use_opengl_render">استفاده از رندرگیری OpenGL</string>
|
||||
<string name="use_opengl_render_descr">از رندرگیری سرعتیافتهٔ سختافزاری OpenGL استفاده کن (شاید مصرف باتری افزایش یابد یا روی دستگاههای خیلی قدیمی کار نکند).</string>
|
||||
<string name="lock_screen_request_explanation">%1$s به این مجوز نیاز دارد تا برای صرفهجویی در انرژی، بتواند نمایشگر را خاموش کند.</string>
|
||||
<string name="lock_screen_request_explanation">%1$s به این مجوز نیاز دارد تا برای صرفهجویی در انرژی بتواند نمایشگر را خاموش کند.</string>
|
||||
<string name="wake_on_voice_descr">هنگام نزدیکشدن به پیچ، نمایشگر روشن شود (اگر خاموش است).</string>
|
||||
<string name="shared_string_never">هرگز</string>
|
||||
<string name="rendering_attr_trolleybusRoutes_name">مسیرهای اتوبوس برقی</string>
|
||||
|
|
|
@ -3514,4 +3514,5 @@
|
|||
<string name="poi_nuclear_explosion_type_underground_shaft">Type d\'explosion : sous-terrain, tunnel</string>
|
||||
<string name="poi_nuclear_explosion_type_space">Type d\'explosion : espace (au delà de 80 km d\'altitude)</string>
|
||||
<string name="poi_nuclear_explosion_type_underwater">Type d\'explosion : sous-marine</string>
|
||||
<string name="poi_nuclear_explosion_type_underground_tunnel">Type d\'explosion : sous terre, tunnel</string>
|
||||
</resources>
|
||||
|
|
|
@ -2737,7 +2737,7 @@ représentant la zone : %1$s x %2$s</string>
|
|||
<string name="mapillary_menu_title_tile_cache">Cache des tuiles</string>
|
||||
<string name="mapillary_menu_descr_dates">Afficher uniquement les images ajoutées</string>
|
||||
<string name="mapillary_menu_descr_username">Afficher uniquement les images ajoutées par</string>
|
||||
<string name="mapillary_menu_filter_description">Filtrer les images par date ou nom d\'utilisateur. Le filtre n\'est appliqué qu\'après avoir zoomé.</string>
|
||||
<string name="mapillary_menu_filter_description">Filtrez les images par date, nom d\'utilisateur ou type. Le filtre n\'est appliqué qu\'après avoir zoomé.</string>
|
||||
<string name="shared_string_reset">Réinitialiser</string>
|
||||
<string name="average">Moyenne</string>
|
||||
<string name="ascent_descent">Croissant / Décroissant</string>
|
||||
|
@ -3207,8 +3207,10 @@ représentant la zone : %1$s x %2$s</string>
|
|||
<string name="osm_live_payment_header">Sélectionnez la fréquence de règlement qui vous convient :</string>
|
||||
<string name="osm_live_payment_contribute_descr">Une partie des revenus est reversée aux contributeurs OpenStreetMap.</string>
|
||||
<string name="osm_live_plan_pricing">Plans et Tarifs</string>
|
||||
<string name="osm_live_payment_renews_monthly">Abonnement mensuel</string>
|
||||
<string name="osm_live_payment_renews_quarterly">Abonnement trimestriel</string>
|
||||
<string name="osm_live_payment_renews_annually">Abonnement annuel</string>
|
||||
<string name="osm_live_payment_renews_monthly">Abonnements mensuels</string>
|
||||
<string name="osm_live_payment_renews_quarterly">Abonnements trimestriels</string>
|
||||
<string name="osm_live_payment_renews_annually">Abonnements annuels</string>
|
||||
<string name="powered_by_osmand">Propulsé par OsmAnd</string>
|
||||
<string name="osm_live_subscriptions">Abonnements</string>
|
||||
<string name="mapillary_menu_title_pano">N\'afficher que les images à 360°</string>
|
||||
</resources>
|
||||
|
|
|
@ -2272,4 +2272,11 @@
|
|||
|
||||
<string name="poi_dispensing_yes">כן</string>
|
||||
<string name="poi_observatory_type_espionage">שימוש: ריגול</string>
|
||||
<string name="poi_telescope_usage_espionage">שימוש: ריגול</string>
|
||||
<string name="poi_telescope_usage_education">שימוש: חינוך</string>
|
||||
<string name="poi_telescope_usage_research">שימוש: מחקר</string>
|
||||
|
||||
<string name="poi_observatory_type_meteorological">מטאורולוגי</string>
|
||||
<string name="poi_observatory_type_gravitational">כבידתי</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -967,8 +967,8 @@
|
|||
<string name="poi_collection_times">Tempi di raccolta</string>
|
||||
<string name="poi_email">Email</string>
|
||||
<string name="poi_fax">Fax</string>
|
||||
<string name="facebook">"Facebook "</string>
|
||||
<string name="twitter">"Twitter "</string>
|
||||
<string name="facebook">Facebook</string>
|
||||
<string name="twitter">Twitter</string>
|
||||
<string name="poi_skype">Skype</string>
|
||||
<string name="poi_youtube">YouTube</string>
|
||||
<string name="poi_instagram">Instagram</string>
|
||||
|
|
|
@ -1733,8 +1733,8 @@
|
|||
<string name="first_intermediate_dest_description">Додаје прво стајање</string>
|
||||
<string name="switch_osm_notes_visibility_desc">Прикажи/Сакриј ОСМ белешке на карти.</string>
|
||||
<string name="shared_string_gpx_file">GPX фајл</string>
|
||||
<string name="release_3_0">• Ново: Подршка за глобалне туристичке водиче без потребе за интернет конекцијом. Референтни положају су повезани на карти. Иницијални подаци са сајта Wikivoyage.
|
||||
\n
|
||||
<string name="release_3_0">• Ново: Подршка за глобалне туристичке водиче без потребе за интернет конекцијом. Референтни положаји су повезани на карти. Иницијални подаци са сајта Wikivoyage.
|
||||
\n
|
||||
\n • Википедија: нови изглед, активне везе, слике
|
||||
\n
|
||||
\n • Open Track UI: приказ група пролазних тачака
|
||||
|
|
|
@ -476,7 +476,7 @@ Nyttjat utrymme är {1} MB.
|
|||
<string name="search_offline_geo_error">Det gick inte att tolka geo-uppsåt \'%s\'.</string>
|
||||
<string name="search_osm_offline">Sök adress med hjälp av offline-kartor</string>
|
||||
<string name="system_locale">System</string>
|
||||
<string name="preferred_locale_descr">Välj visningsspråk (starta om OsmAnd efter språkbyte).</string>
|
||||
<string name="preferred_locale_descr">Välj visningsspråk (träder i kraft när OsmAnd startas om).</string>
|
||||
<string name="preferred_locale">Visningsspråk</string>
|
||||
|
||||
|
||||
|
@ -3041,7 +3041,24 @@ Vänligen tillhandahåll fullständig kod</string>
|
|||
<string name="send_search_query_description">Vi skickar din sökfråga: <b>\"%1$s\"</b>, såväl som din plats.<br/><br/> Vi samlar inte in personlig information, vi behöver bara sökdata för att förbättra sökalgoritmen.<br/></string>
|
||||
<string name="third_party_application">Tredjepartsprogram</string>
|
||||
<string name="search_street">Sök gata</string>
|
||||
<string name="start_search_from_city">Börja sökning från stad</string>
|
||||
<string name="start_search_from_city">Välj en stad först</string>
|
||||
<string name="shared_string_restore">Återställ</string>
|
||||
<string name="keep_passed_markers">Behåll passerade markörer på kartan</string>
|
||||
<string name="powered_by_osmand">Drivs av OsmAnd</string>
|
||||
<string name="osm_live_plan_pricing">Abonnemang & Priser</string>
|
||||
<string name="osm_live_payment_monthly_title">Betala månadsvis</string>
|
||||
<string name="osm_live_payment_3_months_title">Betala var 3:e månad</string>
|
||||
<string name="osm_live_payment_annual_title">Betala en gång om året</string>
|
||||
<string name="osm_live_payment_month_cost_descr">%1$s / månad</string>
|
||||
<string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$s / månad</string>
|
||||
<string name="osm_live_payment_discount_descr">Spara %1$s!</string>
|
||||
<string name="osm_live_payment_current_subscription">Ditt nuvarande abonnemang</string>
|
||||
<string name="osm_live_payment_renews_monthly">Förnyas varje månad</string>
|
||||
<string name="osm_live_payment_renews_quarterly">Förnyas kvartalsvis</string>
|
||||
<string name="osm_live_payment_renews_annually">Förnyas årligen</string>
|
||||
<string name="default_price_currency_format">%1$.2f %2$s</string>
|
||||
<string name="osm_live_payment_header">Välj en passande betalningsperiod:</string>
|
||||
<string name="osm_live_payment_contribute_descr">En del av intäkterna går till OpenStreetMap bidragsgivare.</string>
|
||||
<string name="markers_remove_dialog_msg">Ta bort kartmarkör \'%s\'\?</string>
|
||||
<string name="edit_map_marker">Redigera kartmarkör</string>
|
||||
</resources>
|
||||
|
|
|
@ -523,7 +523,7 @@
|
|||
<string name="rendering_attr_showRoadMaps_description">选择何时显示仅包含道路的地图:</string>
|
||||
<string name="rendering_attr_showRoadMaps_name">仅包含道路的地图</string>
|
||||
<string name="safe_mode_description">在安全模式运行应用(使用较慢的 Android 代码代替原生代码)。</string>
|
||||
<string name="native_library_not_running">应用正运行在安全模式下(可在设置中关闭)。</string>
|
||||
<string name="native_library_not_running">应用正运行在安全模式下(可在“设置”中关闭)。</string>
|
||||
<string name="background_service_is_enabled_question">OsmAnd 睡眠模式服务仍在运行。是否要关闭?</string>
|
||||
<string name="close_changeset">关闭修改集</string>
|
||||
<string name="zxing_barcode_scanner_not_found">ZXing 条形码扫描应用未安装,是否转到应用市场中搜索?</string>
|
||||
|
@ -680,13 +680,13 @@
|
|||
<string name="local_indexes_cat_poi">兴趣点数据</string>
|
||||
<string name="ttsvoice">TTS语音</string>
|
||||
<string name="search_offline_clear_search">新搜索</string>
|
||||
<string name="map_text_size_descr">选择地图上名称的字体大小</string>
|
||||
<string name="map_text_size_descr">选择地图上名称的字体大小。</string>
|
||||
<string name="map_text_size">地图字体大小</string>
|
||||
<string name="trace_rendering_descr">显示渲染性能</string>
|
||||
<string name="trace_rendering_descr">显示渲染性能。</string>
|
||||
|
||||
<string name="installing_new_resources">解包新数据…</string>
|
||||
<string name="internet_connection_required_for_online_route">已选择在线导航服务,但网络连接不可用。</string>
|
||||
<string name="tts_language_not_supported_title">语言不支持</string>
|
||||
<string name="tts_language_not_supported_title">不支持的语言</string>
|
||||
<string name="tts_missing_language_data_title">数据丢失</string>
|
||||
<string name="gpx_option_destination_point">使用当前终点</string>
|
||||
<string name="voice_stream_notification">提醒语音音频</string>
|
||||
|
@ -1424,7 +1424,7 @@
|
|||
<string name="dash_download_manage">管理</string>
|
||||
<string name="rendering_attr_trainLightrailRoutes_name">铁路线路</string>
|
||||
<string name="rendering_category_hide">隐藏</string>
|
||||
<string name="traffic_warning_pedestrian">人行橫道</string>
|
||||
<string name="traffic_warning_pedestrian">人行横道</string>
|
||||
<string name="rendering_category_routes">线路</string>
|
||||
<string name="show_railway_warnings">铁道交口</string>
|
||||
<string name="rendering_category_details">详细信息</string>
|
||||
|
@ -1844,7 +1844,7 @@
|
|||
<string name="traffic_warning_speed_limit">速度限制</string>
|
||||
<string name="traffic_warning_border_control">边境管制</string>
|
||||
<string name="traffic_warning_payment">收费站</string>
|
||||
<string name="traffic_warning_stop">停车标志</string>
|
||||
<string name="traffic_warning_stop">停止标志</string>
|
||||
<string name="traffic_warning_calming">交通稳静化</string>
|
||||
<string name="traffic_warning_speed_camera">测速摄像机</string>
|
||||
<string name="traffic_warning">交通警告</string>
|
||||
|
@ -2730,5 +2730,10 @@
|
|||
<string name="osm_live_payment_month_cost_descr_ex">%1$.2f %2$s / 月</string>
|
||||
<string name="osm_live_payment_discount_descr">节省 %1$s!</string>
|
||||
<string name="osm_live_payment_current_subscription">您的当前订阅</string>
|
||||
<string name="open_in_browser_wiki_description"></string>
|
||||
<string name="open_in_browser_wiki_description">在网页浏览器中查看文章。</string>
|
||||
<string name="osm_live_subscriptions">订阅</string>
|
||||
<string name="osm_live_payment_renews_monthly">每月续期</string>
|
||||
<string name="osm_live_payment_renews_quarterly">每季度续期</string>
|
||||
<string name="osm_live_payment_renews_annually">每年续期</string>
|
||||
<string name="third_party_application">第三方应用程序</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue