Merge branch 'master' into travel_obf_gpx
# Conflicts: # OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java
This commit is contained in:
commit
fd76a4054f
73 changed files with 2094 additions and 984 deletions
|
@ -1790,6 +1790,7 @@ public class GPXUtilities {
|
|||
serializer.attribute(null, "creator", file.author); //$NON-NLS-1$
|
||||
}
|
||||
serializer.attribute(null, "xmlns", "http://www.topografix.com/GPX/1/1"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
serializer.attribute(null, "xmlns:osmand", "https://osmand.net");
|
||||
serializer.attribute(null, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
|
||||
serializer.attribute(null, "xsi:schemaLocation",
|
||||
"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd");
|
||||
|
@ -1938,7 +1939,7 @@ public class GPXUtilities {
|
|||
serializer.startTag(null, "extensions");
|
||||
if (!extensions.isEmpty()) {
|
||||
for (Entry<String, String> s : extensions.entrySet()) {
|
||||
writeNotNullText(serializer, s.getKey(), s.getValue());
|
||||
writeNotNullText(serializer,"osmand:" + s.getKey(), s.getValue());
|
||||
}
|
||||
}
|
||||
if (extensionsWriter != null) {
|
||||
|
|
|
@ -719,9 +719,10 @@ public class SearchCoreFactory {
|
|||
results.put(res.pt.getKeyName(), res);
|
||||
}
|
||||
}
|
||||
if (nmAdditional != null) {
|
||||
addAditonals(nmAdditional, results, types.getOtherMapCategory());
|
||||
}
|
||||
// don't spam results with unsearchable additionals like 'description', 'email', ...
|
||||
// if (nmAdditional != null) {
|
||||
// addAditonals(nmAdditional, results, types.getOtherMapCategory());
|
||||
// }
|
||||
for (PoiCategory c : categories) {
|
||||
PoiTypeResult res = checkPoiType(nm, c);
|
||||
if(res != null) {
|
||||
|
|
|
@ -553,11 +553,20 @@ public class GeoPointParserUtil {
|
|||
}
|
||||
|
||||
if (searchRequest != null) {
|
||||
String searchPattern = Pattern.compile("(?:\\.|,|\\s+|\\+|[+-]?\\d+(?:\\.\\d+)?)").pattern();
|
||||
String[] search = searchRequest.split(searchPattern);
|
||||
if (search.length > 0) {
|
||||
return new GeoParsedPoint(searchRequest);
|
||||
}
|
||||
final Matcher positionInSearchRequestMatcher =
|
||||
positionPattern.matcher(searchRequest);
|
||||
if (lat == 0.0 && lon == 0.0 && positionInSearchRequestMatcher.find()) {
|
||||
lat = Double.valueOf(positionInSearchRequestMatcher.group(1));
|
||||
lon = Double.valueOf(positionInSearchRequestMatcher.group(2));
|
||||
double tempLat = Double.valueOf(positionInSearchRequestMatcher.group(1));
|
||||
double tempLon = Double.valueOf(positionInSearchRequestMatcher.group(2));
|
||||
if (tempLat >= -90 && tempLat <= 90 && tempLon >= -180 && tempLon <= 180) {
|
||||
lat = tempLat;
|
||||
lon = tempLon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application
|
||||
android:name="net.osmand.telegram.TelegramApplication"
|
||||
|
@ -19,7 +17,10 @@
|
|||
android:launchMode="singleTask"
|
||||
android:screenOrientation="unspecified"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
android:theme="@style/AppTheme"
|
||||
android:hasFragileUserData="true"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
|
||||
<activity android:name=".ui.TrackerLogcatActivity" />
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
|
@ -45,17 +46,6 @@
|
|||
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".TelegramService"
|
||||
android:label="@string/process_service"
|
||||
android:stopWithTask="false">
|
||||
<intent-filter>
|
||||
<action android:name="net.osmand.telegram.TelegramService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<receiver android:name=".OnTelegramServiceAlarmReceiver" />
|
||||
|
||||
<receiver
|
||||
android:name=".InitAppBroadcastReceiver"
|
||||
android:enabled="true"
|
||||
|
|
|
@ -4,8 +4,8 @@ apply plugin: 'kotlin-android'
|
|||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.3"
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.3"
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
|
@ -23,7 +23,7 @@ android {
|
|||
defaultConfig {
|
||||
applicationId "net.osmand.telegram"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 29
|
||||
multiDexEnabled true
|
||||
versionCode 1
|
||||
versionCode System.getenv("APK_NUMBER_VERSION") ? System.getenv("APK_NUMBER_VERSION").toInteger() : versionCode
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="background_work_description">Endre batterioptimiseringsinnstillinger for mer stabil posisjonsdeling.</string>
|
||||
<string name="background_work_description">Endre batterioptimaliseringsinnstillinger for mer stabil posisjonsdeling.</string>
|
||||
<string name="background_work">Bakgrunnsarbeid</string>
|
||||
<string name="battery_optimization_description">Skru av batterioptimisering for OsmAnd-sporeren slik at det ikke plutselig skrur seg av når det er i bakgrunnen.</string>
|
||||
<string name="battery_optimization_description">Skru av batterioptimalisering for OsmAnd-sporeren slik at det ikke plutselig skrur seg av når det er i bakgrunnen.</string>
|
||||
<string name="sharing_in_background">Deling i bakgrunnen</string>
|
||||
<string name="go_to_settings">Gå til innstillinger</string>
|
||||
<string name="shared_string_later">Senere</string>
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
package net.osmand.telegram
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.location.LocationManager
|
||||
import net.osmand.telegram.utils.AndroidUtils
|
||||
|
||||
class OnTelegramServiceAlarmReceiver : BroadcastReceiver() {
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val lock = TelegramService.getLock(context)
|
||||
val app = context.applicationContext as TelegramApplication
|
||||
val service = app.telegramService
|
||||
// do not do nothing
|
||||
if (lock.isHeld || service == null) {
|
||||
return
|
||||
}
|
||||
lock.acquire(15 * 60 * 1000L)
|
||||
|
||||
// request location updates
|
||||
val locationManager = service.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
try {
|
||||
if (AndroidUtils.isLocationPermissionAvailable(app)) {
|
||||
locationManager.requestLocationUpdates(service.serviceOffProvider, 0, 0f, service)
|
||||
}
|
||||
val handler = service.handler
|
||||
if (service.serviceOffInterval > service.serviceErrorInterval && handler != null) {
|
||||
handler.postDelayed({
|
||||
// if lock is not anymore held
|
||||
if (lock.isHeld) {
|
||||
lock.release()
|
||||
locationManager.removeUpdates(service)
|
||||
}
|
||||
}, service.serviceErrorInterval)
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,12 +8,13 @@ import android.net.ConnectivityManager
|
|||
import android.net.NetworkInfo
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import androidx.core.content.ContextCompat
|
||||
import net.osmand.PlatformUtil
|
||||
import net.osmand.telegram.ui.TrackerLogcatActivity
|
||||
import net.osmand.telegram.helpers.*
|
||||
import net.osmand.telegram.helpers.OsmandAidlHelper.OsmandHelperListener
|
||||
import net.osmand.telegram.helpers.OsmandAidlHelper.UpdatesListener
|
||||
import net.osmand.telegram.notifications.NotificationHelper
|
||||
import net.osmand.telegram.ui.TrackerLogcatActivity
|
||||
import net.osmand.telegram.utils.AndroidUtils
|
||||
import net.osmand.telegram.utils.UiUtils
|
||||
import java.io.File
|
||||
|
@ -146,35 +147,23 @@ class TelegramApplication : Application() {
|
|||
return internetConnectionAvailable
|
||||
}
|
||||
|
||||
private fun startTelegramService(intent: Int, serviceOffInterval: Long = 0) {
|
||||
private fun startTelegramService(intent: Int) {
|
||||
/*
|
||||
var i = intent
|
||||
var interval = serviceOffInterval
|
||||
val serviceIntent = Intent(this, TelegramService::class.java)
|
||||
|
||||
val telegramService = telegramService
|
||||
if (telegramService != null) {
|
||||
i = intent or telegramService.usedBy
|
||||
interval = if (TelegramService.isOffIntervalDepended(intent)) {
|
||||
Math.min(telegramService.serviceOffInterval, interval)
|
||||
} else {
|
||||
telegramService.serviceOffInterval
|
||||
}
|
||||
telegramService.stopSelf()
|
||||
}
|
||||
|
||||
serviceIntent.putExtra(TelegramService.USAGE_INTENT, i)
|
||||
serviceIntent.putExtra(TelegramService.USAGE_OFF_INTERVAL, interval)
|
||||
serviceIntent.putExtra(TelegramService.SEND_LOCATION_INTERVAL, settings.sendMyLocInterval)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(serviceIntent)
|
||||
} else {
|
||||
startService(serviceIntent)
|
||||
}
|
||||
ContextCompat.startForegroundService(this, serviceIntent)
|
||||
*/
|
||||
}
|
||||
|
||||
fun startMyLocationService() {
|
||||
val interval = settings.sendMyLocInterval
|
||||
startTelegramService(TelegramService.USED_BY_MY_LOCATION, TelegramService.normalizeOffInterval(interval))
|
||||
startTelegramService(TelegramService.USED_BY_MY_LOCATION)
|
||||
}
|
||||
|
||||
fun stopMyLocationService() {
|
||||
|
|
|
@ -54,34 +54,6 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
private var agpsDataLastTimeDownloaded: Long = 0
|
||||
private val useMagneticFieldSensorCompass = false
|
||||
|
||||
// note, passive provider is from API_LEVEL 8 but it is a constant, we can check for it.
|
||||
// constant should not be changed in future
|
||||
// LocationManager.PASSIVE_PROVIDER
|
||||
// put passive provider to first place
|
||||
// find location
|
||||
val firstTimeRunDefaultLocation: net.osmand.Location?
|
||||
@SuppressLint("MissingPermission")
|
||||
get() {
|
||||
if (!AndroidUtils.isLocationPermissionAvailable(app)) {
|
||||
return null
|
||||
}
|
||||
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
val ps = service.getProviders(true) ?: return null
|
||||
val providers = ArrayList(ps)
|
||||
val passiveFirst = providers.indexOf("passive")
|
||||
if (passiveFirst > -1) {
|
||||
providers.add(0, providers.removeAt(passiveFirst))
|
||||
}
|
||||
for (provider in providers) {
|
||||
val location = convertLocation(service.getLastKnownLocation(provider))
|
||||
if (location != null) {
|
||||
return location
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
private val gpsListener = object : LocationListener {
|
||||
override fun onLocationChanged(location: Location?) {
|
||||
if (location != null) {
|
||||
|
@ -115,6 +87,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun resumeAllUpdates() {
|
||||
/*
|
||||
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
if (app.isInternetConnectionAvailable) {
|
||||
if (System.currentTimeMillis() - agpsDataLastTimeDownloaded > AGPS_TO_REDOWNLOAD) {
|
||||
|
@ -162,11 +135,12 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
registerOrUnregisterCompassListener(true)
|
||||
}
|
||||
|
||||
fun redownloadAGPS() {
|
||||
private fun redownloadAGPS() {
|
||||
/*
|
||||
try {
|
||||
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
service.sendExtraCommand(LocationManager.GPS_PROVIDER, "delete_aiding_data", null)
|
||||
|
@ -178,7 +152,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
agpsDataLastTimeDownloaded = 0L
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
private fun getGpsStatusListener(service: LocationManager): GpsStatus.Listener {
|
||||
|
@ -245,6 +219,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
|
||||
@Synchronized
|
||||
fun registerOrUnregisterCompassListener(register: Boolean) {
|
||||
/*
|
||||
if (sensorRegistered && !register) {
|
||||
Log.d(PlatformUtil.TAG, "Disable sensor") //$NON-NLS-1$
|
||||
(app.getSystemService(Context.SENSOR_SERVICE) as SensorManager).unregisterListener(this)
|
||||
|
@ -285,6 +260,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
}
|
||||
sensorRegistered = true
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
|
||||
|
@ -418,12 +394,14 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
}
|
||||
|
||||
private fun stopLocationRequests() {
|
||||
/*
|
||||
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
service.removeGpsStatusListener(gpsStatusListener)
|
||||
service.removeUpdates(gpsListener)
|
||||
while (!networkListeners.isEmpty()) {
|
||||
service.removeUpdates(networkListeners.poll())
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
fun pauseAllUpdates() {
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
package net.osmand.telegram
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.location.Location
|
||||
import android.location.LocationListener
|
||||
import android.location.LocationManager
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import net.osmand.PlatformUtil
|
||||
import net.osmand.telegram.TelegramSettings.ShareChatInfo
|
||||
|
@ -43,21 +41,14 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
private var updateWidgetHandler: Handler? = null
|
||||
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
|
||||
|
||||
var handler: Handler? = null
|
||||
private set
|
||||
var usedBy = 0
|
||||
private set
|
||||
var serviceOffProvider: String = LocationManager.GPS_PROVIDER
|
||||
private set
|
||||
var serviceOffInterval = 0L
|
||||
private set
|
||||
var serviceErrorInterval = 0L
|
||||
private set
|
||||
var sendLocationInterval = 0L
|
||||
private set
|
||||
|
||||
private var lastLocationSentTime = 0L
|
||||
private var pendingIntent: PendingIntent? = null
|
||||
|
||||
class LocationServiceBinder : Binder()
|
||||
|
||||
|
@ -71,7 +62,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
updateWidgetHandler = Handler(updateWidgetThread.looper)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
override fun onBind(intent: Intent): IBinder {
|
||||
return binder
|
||||
}
|
||||
|
||||
|
@ -86,13 +77,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
ctx.stopService(serviceIntent)
|
||||
}
|
||||
isUsedByMyLocation(usedBy) -> {
|
||||
val app = app()
|
||||
if (app.settings.sendMyLocInterval >= OFF_INTERVAL_THRESHOLD && serviceOffInterval == 0L) {
|
||||
serviceOffInterval = app.settings.sendMyLocInterval
|
||||
setupServiceErrorInterval()
|
||||
setupAlarm()
|
||||
}
|
||||
app.notificationHelper.refreshNotification(NotificationType.LOCATION)
|
||||
app().notificationHelper.refreshNotification(NotificationType.LOCATION)
|
||||
}
|
||||
isUsedByUsersLocations(usedBy) -> removeLocationUpdates()
|
||||
}
|
||||
|
@ -100,19 +85,21 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
val app = app()
|
||||
handler = Handler()
|
||||
val usageIntent = intent.getIntExtra(USAGE_INTENT, 0)
|
||||
usedBy = usageIntent or usedBy
|
||||
|
||||
serviceOffInterval = intent.getLongExtra(USAGE_OFF_INTERVAL, 0)
|
||||
sendLocationInterval = intent.getLongExtra(SEND_LOCATION_INTERVAL, 0)
|
||||
setupServiceErrorInterval()
|
||||
|
||||
app.telegramHelper.addIncomingMessagesListener(this)
|
||||
app.telegramHelper.addOutgoingMessagesListener(this)
|
||||
|
||||
app.telegramService = this
|
||||
|
||||
val locationNotification = app.notificationHelper.locationNotification
|
||||
val notification = app.notificationHelper.buildNotification(locationNotification)
|
||||
startForeground(locationNotification.telegramNotificationId, notification)
|
||||
app.notificationHelper.refreshNotification(locationNotification.type)
|
||||
|
||||
if (isUsedByMyLocation(usedBy)) {
|
||||
initLocationUpdates()
|
||||
startShareInfoUpdates()
|
||||
|
@ -124,21 +111,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
}
|
||||
app.shareLocationHelper.checkAndSendBufferMessages()
|
||||
|
||||
val locationNotification = app.notificationHelper.locationNotification
|
||||
val notification = app.notificationHelper.buildNotification(locationNotification)
|
||||
startForeground(locationNotification.telegramNotificationId, notification)
|
||||
app.notificationHelper.refreshNotification(locationNotification.type)
|
||||
return Service.START_REDELIVER_INTENT
|
||||
}
|
||||
|
||||
private fun setupServiceErrorInterval() {
|
||||
serviceErrorInterval = serviceOffInterval / 5
|
||||
// 1. not more than 12 mins
|
||||
serviceErrorInterval = Math.min(serviceErrorInterval, 12 * 60 * 1000)
|
||||
// 2. not less than 30 seconds
|
||||
serviceErrorInterval = Math.max(serviceErrorInterval, 30 * 1000)
|
||||
// 3. not more than serviceOffInterval
|
||||
serviceErrorInterval = Math.min(serviceErrorInterval, serviceOffInterval)
|
||||
return START_REDELIVER_INTENT
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -158,13 +131,6 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
|
||||
removeLocationUpdates()
|
||||
|
||||
if (!isContinuous()) {
|
||||
val lock = getLock(this)
|
||||
if (lock.isHeld) {
|
||||
lock.release()
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldCleanupResources) {
|
||||
app.cleanupResources()
|
||||
}
|
||||
|
@ -186,22 +152,19 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
val firstLocation = getFirstTimeRunDefaultLocation()
|
||||
app().shareLocationHelper.updateLocation(firstLocation)
|
||||
|
||||
// requesting
|
||||
if (isContinuous()) {
|
||||
// request location updates
|
||||
/*
|
||||
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
try {
|
||||
locationManager.requestLocationUpdates(serviceOffProvider, 0, 0f, this@TelegramService)
|
||||
} catch (e: SecurityException) {
|
||||
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
|
||||
Log.d(PlatformUtil.TAG, "Location service permission not granted") //$NON-NLS-1$
|
||||
log.debug("Location service permission not granted")
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
|
||||
Log.d(PlatformUtil.TAG, "GPS location provider not available") //$NON-NLS-1$
|
||||
}
|
||||
} else {
|
||||
setupAlarm()
|
||||
log.debug("GPS location provider not available")
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private fun startShareInfoUpdates() {
|
||||
|
@ -261,6 +224,8 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
if (!AndroidUtils.isLocationPermissionAvailable(app)) {
|
||||
return null
|
||||
}
|
||||
var location: net.osmand.Location? = null
|
||||
/*
|
||||
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
val ps = service.getProviders(true) ?: return null
|
||||
val providers = ArrayList(ps)
|
||||
|
@ -272,53 +237,31 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
providers.add(0, providers.removeAt(passiveFirst))
|
||||
}
|
||||
// find location
|
||||
var location: net.osmand.Location? = null
|
||||
for (provider in providers) {
|
||||
val loc = convertLocation(service.getLastKnownLocation(provider))
|
||||
if (loc != null && (location == null || loc.hasAccuracy() && loc.accuracy < location.accuracy)) {
|
||||
location = loc
|
||||
}
|
||||
}
|
||||
*/
|
||||
return location
|
||||
}
|
||||
|
||||
private fun setupAlarm() {
|
||||
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
pendingIntent = PendingIntent.getBroadcast(this, 0, Intent(this, OnTelegramServiceAlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 500, serviceOffInterval, pendingIntent)
|
||||
}
|
||||
|
||||
private fun removeLocationUpdates() {
|
||||
// remove updates
|
||||
/*
|
||||
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
try {
|
||||
locationManager.removeUpdates(this)
|
||||
} catch (e: SecurityException) {
|
||||
Log.d(PlatformUtil.TAG, "Location service permission not granted")
|
||||
log.debug("Location service permission not granted")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isContinuous(): Boolean {
|
||||
return serviceOffInterval == 0L
|
||||
*/
|
||||
}
|
||||
|
||||
override fun onLocationChanged(l: Location?) {
|
||||
val location = convertLocation(l)
|
||||
if (!isContinuous()) {
|
||||
// unregister listener and wait next time
|
||||
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
try {
|
||||
locationManager.removeUpdates(this)
|
||||
} catch (e: Throwable) {
|
||||
Log.d(PlatformUtil.TAG, "Location service permission not granted") //$NON-NLS-1$
|
||||
}
|
||||
|
||||
val lock = getLock(this)
|
||||
if (lock.isHeld) {
|
||||
lock.release()
|
||||
}
|
||||
app().shareLocationHelper.updateLocation(location)
|
||||
} else if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
|
||||
if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
|
||||
lastLocationSentTime = System.currentTimeMillis()
|
||||
app().shareLocationHelper.updateLocation(location)
|
||||
}
|
||||
|
@ -373,7 +316,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
}
|
||||
|
||||
override fun onSendLiveLocationError(code: Int, message: String, shareInfo: ShareChatInfo, messageType: Int) {
|
||||
Log.d(PlatformUtil.TAG, "Send live location error: $code - $message")
|
||||
log.debug("Send live location error: $code - $message")
|
||||
when (messageType) {
|
||||
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText--
|
||||
TelegramHelper.MESSAGE_TYPE_MAP -> {
|
||||
|
@ -388,26 +331,8 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
const val USED_BY_MY_LOCATION: Int = 1
|
||||
const val USED_BY_USERS_LOCATIONS: Int = 2
|
||||
const val USAGE_INTENT = "SERVICE_USED_BY"
|
||||
const val USAGE_OFF_INTERVAL = "SERVICE_OFF_INTERVAL"
|
||||
const val SEND_LOCATION_INTERVAL = "SEND_LOCATION_INTERVAL"
|
||||
|
||||
const val OFF_INTERVAL_THRESHOLD: Long = 30000L
|
||||
|
||||
private var lockStatic: PowerManager.WakeLock? = null
|
||||
|
||||
@Synchronized
|
||||
fun getLock(context: Context): PowerManager.WakeLock {
|
||||
var lockStatic = lockStatic
|
||||
return if (lockStatic == null) {
|
||||
val mgr = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "OsmandServiceLock")
|
||||
this.lockStatic = lockStatic
|
||||
lockStatic
|
||||
} else {
|
||||
lockStatic
|
||||
}
|
||||
}
|
||||
|
||||
fun isUsedByMyLocation(usedBy: Int): Boolean {
|
||||
return (usedBy and USED_BY_MY_LOCATION) > 0
|
||||
}
|
||||
|
@ -416,14 +341,6 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
return (usedBy and USED_BY_USERS_LOCATIONS) > 0
|
||||
}
|
||||
|
||||
fun isOffIntervalDepended(usedBy: Int): Boolean {
|
||||
return isUsedByMyLocation(usedBy)
|
||||
}
|
||||
|
||||
fun normalizeOffInterval(interval: Long): Long {
|
||||
return if (interval < OFF_INTERVAL_THRESHOLD) 0 else interval
|
||||
}
|
||||
|
||||
fun convertLocation(l: Location?): net.osmand.Location? {
|
||||
if (l == null) {
|
||||
return null
|
||||
|
|
|
@ -505,6 +505,8 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
val currentTimeMillis = System.currentTimeMillis()
|
||||
val currentTime = currentTimeMillis / 1000
|
||||
statusChangeTime = currentTimeMillis
|
||||
val gpsEnabled = false
|
||||
/*
|
||||
val lm = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
val gpsEnabled = try {
|
||||
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
|
@ -518,6 +520,7 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
} catch (ex: Exception) {
|
||||
false
|
||||
}
|
||||
*/
|
||||
|
||||
var initializing = false
|
||||
var sendChatsErrors = false
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.widget.*
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import net.osmand.PlatformUtil
|
||||
import net.osmand.telegram.*
|
||||
|
@ -42,7 +41,7 @@ private const val SUGGESTED = 2
|
|||
private const val SHARE_LOCATION_CHAT = 1
|
||||
private const val DEFAULT_CHAT = 0
|
||||
|
||||
private const val ADAPTER_UPDATE_INTERVAL_MIL = 5 * 1000L // 5 sec
|
||||
private const val ADAPTER_UPDATE_INTERVAL_MS = 5 * 1000L // 5 sec
|
||||
|
||||
class MyLocationTabFragment : Fragment(), TelegramListener {
|
||||
|
||||
|
@ -380,7 +379,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
updateContent()
|
||||
startHandler()
|
||||
}
|
||||
}, ADAPTER_UPDATE_INTERVAL_MIL)
|
||||
}, ADAPTER_UPDATE_INTERVAL_MS)
|
||||
}
|
||||
|
||||
private fun animateStartSharingBtn(show: Boolean) {
|
||||
|
|
|
@ -287,7 +287,6 @@ task collectHelpContentsAssets(type: Copy) {
|
|||
include "about.html"
|
||||
include "changes.html"
|
||||
include "faq.html"
|
||||
include "technical-articles.html"
|
||||
include "map-legend.html"
|
||||
}
|
||||
from("../../help/website/feature_articles") {
|
||||
|
|
|
@ -174,7 +174,6 @@ task collectHelpContentsAssets(type: Copy) {
|
|||
include "about.html"
|
||||
include "changes.html"
|
||||
include "faq.html"
|
||||
include "technical-articles.html"
|
||||
include "map-legend.html"
|
||||
}
|
||||
from("../../help/website/feature_articles") {
|
||||
|
|
14
OsmAnd/res/drawable/ic_action_name_field.xml
Normal file
14
OsmAnd/res/drawable/ic_action_name_field.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M2,5C2,3.3431 3.3431,2 5,2H19C20.6569,2 22,3.3431 22,5V19C22,20.6569 20.6569,22 19,22H5C3.3431,22 2,20.6569 2,19V5Z"
|
||||
android:strokeAlpha="0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.5"/>
|
||||
<path
|
||||
android:pathData="M7,17V7H9L13,13.6667V7H15V17H13L9,10.3333V17H7Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
15
OsmAnd/res/drawable/ic_overflow_menu_with_background.xml
Normal file
15
OsmAnd/res/drawable/ic_overflow_menu_with_background.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
|
||||
android:strokeAlpha="0.1"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.1"/>
|
||||
<path
|
||||
android:pathData="M12,8C13.1,8 14,7.1 14,6C14,4.9 13.1,4 12,4C10.9,4 10,4.9 10,6C10,7.1 10.9,8 12,8ZM12,10C10.9,10 10,10.9 10,12C10,13.1 10.9,14 12,14C13.1,14 14,13.1 14,12C14,10.9 13.1,10 12,10ZM12,16C10.9,16 10,16.9 10,18C10,19.1 10.9,20 12,20C13.1,20 14,19.1 14,18C14,16.9 13.1,16 12,16Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
91
OsmAnd/res/drawable/img_help_announcement_time_day.xml
Normal file
91
OsmAnd/res/drawable/img_help_announcement_time_day.xml
Normal file
|
@ -0,0 +1,91 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="328dp"
|
||||
android:height="90dp"
|
||||
android:viewportWidth="328"
|
||||
android:viewportHeight="90">
|
||||
<group>
|
||||
<clip-path android:pathData="M0,0h328v90h-328z M 0,0"/>
|
||||
<path
|
||||
android:pathData="M2.0,0.0L326.0,0.0A2.0,2.0,0,0,1,328.0,2.0L328.0,88.0A2.0,2.0,0,0,1,326.0,90.0L2.0,90.0A2.0,2.0,0,0,1,0.0,88.0L0.0,2.0A2.0,2.0,0,0,1,2.0,0.0z"
|
||||
android:fillColor="#F5F5F5"/>
|
||||
<path
|
||||
android:pathData="M306 0H278V31H0V59H278V90H306V59H328V31H306V0Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M304 0H280V33H0V57H280V90H304V57H328V33H304V0Z"
|
||||
android:fillColor="#EAEAEC"/>
|
||||
<path
|
||||
android:pathData="M8 45C8 44.4477 8.44772 44 9 44H19C19.5523 44 20 44.4477 20 45C20 45.5523 19.5523 46 19 46H9C8.44772 46 8 45.5523 8 45Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M32 45C32 44.4477 32.4477 44 33 44H43C43.5523 44 44 44.4477 44 45C44 45.5523 43.5523 46 43 46H33C32.4477 46 32 45.5523 32 45Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M80 45C80 44.4477 80.4477 44 81 44H91C91.5523 44 92 44.4477 92 45C92 45.5523 91.5523 46 91 46H81C80.4477 46 80 45.5523 80 45Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M128 45C128 44.4477 128.448 44 129 44H139C139.552 44 140 44.4477 140 45C140 45.5523 139.552 46 139 46H129C128.448 46 128 45.5523 128 45Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M177 44C176.448 44 176 44.4477 176 45C176 45.5523 176.448 46 177 46H187C187.552 46 188 45.5523 188 45C188 44.4477 187.552 44 187 44H177Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M321 44C320.448 44 320 44.4477 320 45C320 45.5523 320.448 46 321 46H331C331.552 46 332 45.5523 332 45C332 44.4477 331.552 44 331 44H321Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M273 44C272.448 44 272 44.4477 272 45C272 45.5523 272.448 46 273 46H283C283.552 46 284 45.5523 284 45C284 44.4477 283.552 44 283 44H273Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M225 44C224.448 44 224 44.4477 224 45C224 45.5523 224.448 46 225 46H235C235.552 46 236 45.5523 236 45C236 44.4477 235.552 44 235 44H225Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M152 45C152 44.4477 152.448 44 153 44H163C163.552 44 164 44.4477 164 45C164 45.5523 163.552 46 163 46H153C152.448 46 152 45.5523 152 45Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M104 45C104 44.4477 104.448 44 105 44H115C115.552 44 116 44.4477 116 45C116 45.5523 115.552 46 115 46H105C104.448 46 104 45.5523 104 45Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M297 44C296.448 44 296 44.4477 296 45C296 45.5523 296.448 46 297 46H307C307.552 46 308 45.5523 308 45C308 44.4477 307.552 44 307 44H297Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M56 45C56 44.4477 56.4477 44 57 44H67C67.5523 44 68 44.4477 68 45C68 45.5523 67.5523 46 67 46H57C56.4477 46 56 45.5523 56 45Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M249 44C248.448 44 248 44.4477 248 45C248 45.5523 248.448 46 249 46H259C259.552 46 260 45.5523 260 45C260 44.4477 259.552 44 259 44H249Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M201 44C200.448 44 200 44.4477 200 45C200 45.5523 200.448 46 201 46H211C211.552 46 212 45.5523 212 45C212 44.4477 211.552 44 211 44H201Z"
|
||||
android:fillColor="#D7D8DB"/>
|
||||
<path
|
||||
android:pathData="M23.8187 58.233C23.2003 57.6146 23.047 56.6698 23.4381 55.8876L28.8819 45L23.4381 34.1124C23.047 33.3302 23.2003 32.3854 23.8187 31.767C24.3865 31.1993 25.2354 31.0191 25.9848 31.3074L57.3923 43.3872C58.0596 43.6438 58.5 44.285 58.5 45C58.5 45.715 58.0596 46.3562 57.3923 46.6128L25.9848 58.6926C25.2354 58.9809 24.3865 58.8007 23.8187 58.233Z"
|
||||
android:strokeAlpha="0.6"
|
||||
android:fillColor="#3252F1"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.6"/>
|
||||
<path
|
||||
android:pathData="M57.0333 44.3205C57.3145 44.4286 57.5 44.6987 57.5 45C57.5 45.3012 57.3145 45.5713 57.0333 45.6795L25.6259 57.7593C25.2453 57.9056 24.8142 57.8142 24.5259 57.5258C24.2118 57.2118 24.134 56.732 24.3326 56.3348L30 45L24.3326 33.6651C24.134 33.2679 24.2118 32.7881 24.5259 32.4741C24.8142 32.1858 25.2453 32.0943 25.6259 32.2407L57.0333 44.3205Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M32 45L27 55L53.2287 44.9999L27 35L32 45Z"
|
||||
android:fillColor="#3252F1"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M36 45L27 55L32 45L27 35L36 45Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillAlpha="0.2"/>
|
||||
<path
|
||||
android:pathData="M53.5 45L27 55L36 45H53.5Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.1"/>
|
||||
<path
|
||||
android:pathData="M65 38H67V52H65V38Z"
|
||||
android:fillColor="#EE5622"/>
|
||||
<path
|
||||
android:pathData="M278 38H280V52H278V38Z"
|
||||
android:fillColor="#EE5622"/>
|
||||
<path
|
||||
android:pathData="M77.1783 50.2652L72.5577 46H272.442L267.822 50.2652L269.178 51.7348L276.474 45L269.178 38.2652L267.822 39.7348L272.442 44H72.5577L77.1783 39.7348L75.8217 38.2652L68.5257 45L75.8217 51.7348L77.1783 50.2652Z"
|
||||
android:fillColor="#EE5622"/>
|
||||
</group>
|
||||
</vector>
|
91
OsmAnd/res/drawable/img_help_announcement_time_night.xml
Normal file
91
OsmAnd/res/drawable/img_help_announcement_time_night.xml
Normal file
|
@ -0,0 +1,91 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="328dp"
|
||||
android:height="90dp"
|
||||
android:viewportWidth="328"
|
||||
android:viewportHeight="90">
|
||||
<group>
|
||||
<clip-path android:pathData="M0,0h328v90h-328z M 0,0"/>
|
||||
<path
|
||||
android:pathData="M2.0,0.0L326.0,0.0A2.0,2.0,0,0,1,328.0,2.0L328.0,88.0A2.0,2.0,0,0,1,326.0,90.0L2.0,90.0A2.0,2.0,0,0,1,0.0,88.0L0.0,2.0A2.0,2.0,0,0,1,2.0,0.0z"
|
||||
android:fillColor="#28292A"/>
|
||||
<path
|
||||
android:pathData="M306 0H278V31H0V59H278V90H306V59H328V31H306V0Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M304 0H280V33H0V57H280V90H304V57H328V33H304V0Z"
|
||||
android:fillColor="#58595B"/>
|
||||
<path
|
||||
android:pathData="M8 45C8 44.4477 8.44772 44 9 44H19C19.5523 44 20 44.4477 20 45C20 45.5523 19.5523 46 19 46H9C8.44772 46 8 45.5523 8 45Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M32 45C32 44.4477 32.4477 44 33 44H43C43.5523 44 44 44.4477 44 45C44 45.5523 43.5523 46 43 46H33C32.4477 46 32 45.5523 32 45Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M80 45C80 44.4477 80.4477 44 81 44H91C91.5523 44 92 44.4477 92 45C92 45.5523 91.5523 46 91 46H81C80.4477 46 80 45.5523 80 45Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M128 45C128 44.4477 128.448 44 129 44H139C139.552 44 140 44.4477 140 45C140 45.5523 139.552 46 139 46H129C128.448 46 128 45.5523 128 45Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M177 44C176.448 44 176 44.4477 176 45C176 45.5523 176.448 46 177 46H187C187.552 46 188 45.5523 188 45C188 44.4477 187.552 44 187 44H177Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M321 44C320.448 44 320 44.4477 320 45C320 45.5523 320.448 46 321 46H331C331.552 46 332 45.5523 332 45C332 44.4477 331.552 44 331 44H321Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M273 44C272.448 44 272 44.4477 272 45C272 45.5523 272.448 46 273 46H283C283.552 46 284 45.5523 284 45C284 44.4477 283.552 44 283 44H273Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M225 44C224.448 44 224 44.4477 224 45C224 45.5523 224.448 46 225 46H235C235.552 46 236 45.5523 236 45C236 44.4477 235.552 44 235 44H225Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M152 45C152 44.4477 152.448 44 153 44H163C163.552 44 164 44.4477 164 45C164 45.5523 163.552 46 163 46H153C152.448 46 152 45.5523 152 45Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M104 45C104 44.4477 104.448 44 105 44H115C115.552 44 116 44.4477 116 45C116 45.5523 115.552 46 115 46H105C104.448 46 104 45.5523 104 45Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M297 44C296.448 44 296 44.4477 296 45C296 45.5523 296.448 46 297 46H307C307.552 46 308 45.5523 308 45C308 44.4477 307.552 44 307 44H297Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M56 45C56 44.4477 56.4477 44 57 44H67C67.5523 44 68 44.4477 68 45C68 45.5523 67.5523 46 67 46H57C56.4477 46 56 45.5523 56 45Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M249 44C248.448 44 248 44.4477 248 45C248 45.5523 248.448 46 249 46H259C259.552 46 260 45.5523 260 45C260 44.4477 259.552 44 259 44H249Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M201 44C200.448 44 200 44.4477 200 45C200 45.5523 200.448 46 201 46H211C211.552 46 212 45.5523 212 45C212 44.4477 211.552 44 211 44H201Z"
|
||||
android:fillColor="#4B4C4E"/>
|
||||
<path
|
||||
android:pathData="M23.8187 58.233C23.2003 57.6146 23.047 56.6698 23.4381 55.8876L28.8819 45L23.4381 34.1124C23.047 33.3302 23.2003 32.3854 23.8187 31.767C24.3865 31.1993 25.2354 31.0191 25.9848 31.3074L57.3923 43.3872C58.0596 43.6438 58.5 44.285 58.5 45C58.5 45.715 58.0596 46.3562 57.3923 46.6128L25.9848 58.6926C25.2354 58.9809 24.3865 58.8007 23.8187 58.233Z"
|
||||
android:strokeAlpha="0.6"
|
||||
android:fillColor="#3252F1"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.6"/>
|
||||
<path
|
||||
android:pathData="M57.0333 44.3205C57.3145 44.4286 57.5 44.6987 57.5 45C57.5 45.3012 57.3145 45.5713 57.0333 45.6795L25.6259 57.7593C25.2453 57.9056 24.8142 57.8142 24.5259 57.5258C24.2118 57.2118 24.134 56.732 24.3326 56.3348L30 45L24.3326 33.6651C24.134 33.2679 24.2118 32.7881 24.5259 32.4741C24.8142 32.1858 25.2453 32.0943 25.6259 32.2407L57.0333 44.3205Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M32 45L27 55L53.2287 44.9999L27 35L32 45Z"
|
||||
android:fillColor="#3252F1"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M36 45L27 55L32 45L27 35L36 45Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillAlpha="0.2"/>
|
||||
<path
|
||||
android:pathData="M53.5 45L27 55L36 45H53.5Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.1"/>
|
||||
<path
|
||||
android:pathData="M65 38H67V52H65V38Z"
|
||||
android:fillColor="#EE5622"/>
|
||||
<path
|
||||
android:pathData="M278 38H280V52H278V38Z"
|
||||
android:fillColor="#EE5622"/>
|
||||
<path
|
||||
android:pathData="M77.1783 50.2652L72.5577 46H272.442L267.822 50.2652L269.178 51.7348L276.474 45L269.178 38.2652L267.822 39.7348L272.442 44H72.5577L77.1783 39.7348L75.8217 38.2652L68.5257 45L75.8217 51.7348L77.1783 50.2652Z"
|
||||
android:fillColor="#EE5622"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:osmand="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:minHeight="@dimen/bottom_sheet_selected_item_title_height"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/content_padding"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingTop="@dimen/wikilink_bottom_sheet_padding"
|
||||
android:paddingEnd="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/subHeaderPadding"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:minHeight="@dimen/default_title_line_height"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:lineHeight="@dimen/default_title_line_height"
|
||||
osmand:typeface="@string/font_roboto_medium"
|
||||
tools:text="Some title" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:minHeight="@dimen/default_desc_line_height"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
osmand:lineHeight="@dimen/default_desc_line_height"
|
||||
osmand:typeface="@string/font_roboto_regular"
|
||||
tools:text="Some description" />
|
||||
|
||||
</LinearLayout>
|
|
@ -14,10 +14,11 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/main_item_part"
|
||||
android:id="@+id/basic_item_body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingStart="@dimen/content_padding"
|
||||
android:paddingRight="0dp"
|
||||
|
@ -79,22 +80,24 @@
|
|||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_padding"
|
||||
android:layout_marginBottom="@dimen/content_padding"
|
||||
android:background="?attr/divider_color_basic"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/eng_button"
|
||||
android:id="@+id/end_button"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/end_button_icon"
|
||||
android:layout_width="@dimen/standard_icon_size"
|
||||
android:layout_height="@dimen/standard_icon_size"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:srcCompat="@drawable/ic_action_settings"
|
||||
android:tint="?attr/default_icon_color" />
|
||||
app:srcCompat="@drawable/ic_action_settings" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
44
OsmAnd/res/layout/select_folder_row.xml
Normal file
44
OsmAnd/res/layout/select_folder_row.xml
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:osmand="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/card_row_min_height"
|
||||
android:background="?attr/list_background_color"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/bottom_sheet_cancel_button_height_small"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:layout_weight="1"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:text="@string/select_folder"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/select_folder_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawableRight="@drawable/ic_action_markers_list"
|
||||
android:drawablePadding="@dimen/content_padding_small_half"
|
||||
android:drawableTint="?attr/active_color_basic"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="@dimen/content_padding_half"
|
||||
android:paddingLeft="@dimen/content_padding_half"
|
||||
android:paddingEnd="@dimen/content_padding_half"
|
||||
android:paddingRight="@dimen/content_padding_half"
|
||||
android:text="@string/shared_string_list"
|
||||
android:textColor="?attr/color_dialog_buttons"
|
||||
osmand:typeface="@string/font_roboto_medium" />
|
||||
|
||||
</LinearLayout>
|
|
@ -275,7 +275,7 @@
|
|||
<string name="modify_transparency">Nastavte průhlednost (0 - průhledný, 255 - neprůhledný)</string>
|
||||
<string name="layer_underlay">Podkladová mapa…</string>
|
||||
<string name="map_underlay">Podkresová mapa</string>
|
||||
<string name="map_underlay_descr">Vyberte podkladovou mapu.</string>
|
||||
<string name="map_underlay_descr">Vyberte podkladovou mapu</string>
|
||||
<string name="layer_overlay">Překryvná mapa…</string>
|
||||
<string name="shared_string_none">Žádná</string>
|
||||
<string name="map_overlay">Překryvná mapa</string>
|
||||
|
@ -309,7 +309,9 @@
|
|||
<string name="context_menu_item_share_location">Sdílet polohu</string>
|
||||
<string name="add_waypoint_dialog_added">GPX bod na trase \'\'{0}\'\' byl přidán</string>
|
||||
<string name="add_waypoint_dialog_title">Přidat bod na zaznamenávanou GPX trasu</string>
|
||||
<string name="osmand_routing_experimental">Off-line navigace je experimentální a funguje jen pro větší vzdálenosti než 20 km. Navigace je dočasně přepnuta na on-line CloudMade.</string>
|
||||
<string name="osmand_routing_experimental">Off-line navigace je experimentální a funguje jen pro větší vzdálenosti než 20 km.
|
||||
\n
|
||||
\nNavigace je dočasně přepnuta na online službu CloudMade.</string>
|
||||
<string name="specified_dir_doesnt_exist">Nepodařilo se najít zadaný adresář.</string>
|
||||
<string name="application_dir">Adresář pro data</string>
|
||||
<string name="gps_status_app_not_found">Aplikace pro zobrazení stavu GPS není nainstalovaná. Hledat v obchodě?</string>
|
||||
|
@ -440,7 +442,7 @@
|
|||
<string name="map_orientation_landscape">Na šířku</string>
|
||||
<string name="map_screen_orientation">Orientace obrazovky</string>
|
||||
<string name="map_screen_orientation_descr">Orientace obrazovky: na výšku, na šířku, podle zařízení.</string>
|
||||
<string name="opening_hours_not_supported">Formát otevírací doby nemůže být změněn</string>
|
||||
<string name="opening_hours_not_supported">Formát otevírací doby nemůže být změněn.</string>
|
||||
<string name="add_new_rule">Přidat nové pravidlo</string>
|
||||
<string name="transport_Routes">Cesty</string>
|
||||
<string name="transport_Stop">Zastávka</string>
|
||||
|
@ -459,8 +461,8 @@
|
|||
<string name="show_transport_over_map">Zobrazit zastávky</string>
|
||||
<string name="hello">Navigační aplikace OsmAnd</string>
|
||||
<string name="update_poi_success">Data POI byla aktualizována ({0} načteno)</string>
|
||||
<string name="update_poi_error_local">Nelze aktualizovat lokální seznam POI</string>
|
||||
<string name="update_poi_error_loading">Nelze načíst data ze serveru</string>
|
||||
<string name="update_poi_error_local">Nepodařilo se aktualizovat lokální seznam POI.</string>
|
||||
<string name="update_poi_error_loading">Nepodařilo se načíst data ze serveru.</string>
|
||||
<string name="update_poi_no_offline_poi_index">Pro tuto oblast nejsou dostupné žádné off-line POI</string>
|
||||
<string name="update_poi_is_not_available_for_zoom">Větší přiblížení vám umožní aktualizovat POI</string>
|
||||
<string name="context_menu_item_update_poi">Aktualizovat POI</string>
|
||||
|
@ -482,11 +484,11 @@
|
|||
<string name="search_offline_address">Hledání off-line</string>
|
||||
<string name="search_online_address">Hledat on-line</string>
|
||||
<string name="max_level_download_tile">Maximální zvětšení</string>
|
||||
<string name="max_level_download_tile_descr">Nelze procházet dlaždice online map pro přiblížení nad tuto úroveň.</string>
|
||||
<string name="max_level_download_tile_descr">Nepoužívat online mapy pro přiblížení nad tuto úroveň.</string>
|
||||
<string name="route_general_information">Celková vzdálenost %1$s, doba cesty %2$d h %3$d min.</string>
|
||||
<string name="router_service_descr">Vyberte online nebo offline navigační službu.</string>
|
||||
<string name="router_service_descr">Online nebo offline navigační služba.</string>
|
||||
<string name="router_service">Navigace</string>
|
||||
<string name="sd_dir_not_accessible">Úložný datový adresář na paměťové kartě není dostupný!</string>
|
||||
<string name="sd_dir_not_accessible">Úložný adresář na paměťové kartě není dostupný!</string>
|
||||
<string name="download_question">Stáhnout {0} - {1} ?</string>
|
||||
<string name="download_question_exist">Offline data pro {0} již existují ({1}). Aktualizovat je ({2})\?</string>
|
||||
<string name="address">Adresa</string>
|
||||
|
@ -500,7 +502,7 @@
|
|||
<string name="only_show">Pouze zobrazit</string>
|
||||
<string name="follow">Spustit navádění</string>
|
||||
<string name="recalculate_route_to_your_location">Způsob dopravy:</string>
|
||||
<string name="mark_final_location_first">Prosím zadejte nejprve cíl</string>
|
||||
<string name="mark_final_location_first">Prosím nejprve zadejte cíl</string>
|
||||
<string name="get_directions">Navigace</string>
|
||||
<string name="opening_hours">Otevírací doba</string>
|
||||
<string name="opening_changeset">Otevírání sady změn…</string>
|
||||
|
@ -515,14 +517,14 @@
|
|||
<string name="loading_streets">Načítání ulic…</string>
|
||||
<string name="loading_cities">Načítání měst…</string>
|
||||
<string name="poi">POI</string>
|
||||
<string name="error_occurred_saving_gpx">Nelze uložit soubor GPX</string>
|
||||
<string name="error_calculating_route">Nelze vypočítat trasu</string>
|
||||
<string name="error_calculating_route_occured">Nelze vypočítat trasu</string>
|
||||
<string name="empty_route_calculated">Vypočtená trasa je prázdná</string>
|
||||
<string name="error_occurred_saving_gpx">Nepodařilo se uložit soubor GPX.</string>
|
||||
<string name="error_calculating_route">Nepodařilo se vypočítat trasu.</string>
|
||||
<string name="error_calculating_route_occured">Nepodařilo se vypočítat trasu.</string>
|
||||
<string name="empty_route_calculated">Vypočítaná trasa je prázdná.</string>
|
||||
<string name="new_route_calculated_dist">Vypočtena nová trasa, vzdálenost</string>
|
||||
<string name="arrived_at_destination">Dorazili jste do cíle</string>
|
||||
<string name="arrived_at_destination">Dorazili jste do cíle.</string>
|
||||
<string name="invalid_locations">Neplatné souřadnice</string>
|
||||
<string name="go_back_to_osmand">Vrátit se k mapě OsmAnd</string>
|
||||
<string name="go_back_to_osmand">Vrátit se k mapě</string>
|
||||
<string name="shared_string_close">Zavřít</string>
|
||||
<string name="loading_data">Načítání dat…</string>
|
||||
<string name="reading_indexes">Načítání místních dat…</string>
|
||||
|
@ -559,15 +561,15 @@
|
|||
<string name="show_view_angle">Zorné pole</string>
|
||||
<string name="map_view_3d_descr">Zapnout 3D pohled na mapu.</string>
|
||||
<string name="map_view_3d">3D Mapa</string>
|
||||
<string name="show_poi_over_map_description">Zobrazit naposledy vybrané POI jako vrstvu na mapě.</string>
|
||||
<string name="show_poi_over_map_description">Zobrazit naposledy použité POI jako vrstvu.</string>
|
||||
<string name="show_poi_over_map">Zobrazit vrstvu POI</string>
|
||||
<string name="map_tile_source_descr">Zvolte zdroj on-line dlaždic nebo dlaždic v mezipaměti.</string>
|
||||
<string name="map_tile_source_descr">Zvolte zdroj online mapových dlaždic nebo dlaždic v mezipaměti.</string>
|
||||
<string name="map_tile_source">Zdroj rastrových map</string>
|
||||
<string name="map_source">Zdroj map</string>
|
||||
<string name="use_internet">Používat Internet</string>
|
||||
<string name="show_location">Zobrazit mou polohu</string>
|
||||
<string name="show_gps_coordinates_text">Zobrazit GPS souřadnice na mapě</string>
|
||||
<string name="use_internet_to_download_tile">Stahovat chybějící části mapy z internetu</string>
|
||||
<string name="use_internet_to_download_tile">Stáhnout chybějící mapové dlaždice</string>
|
||||
<string name="app_description">Navigační aplikace</string>
|
||||
<string name="shared_string_exit">Konec</string>
|
||||
<string name="search_button">Hledat</string>
|
||||
|
@ -586,11 +588,11 @@
|
|||
<string name="app_mode_pedestrian">Chůze</string>
|
||||
<string name="position_on_map_center">Uprostřed</string>
|
||||
<string name="position_on_map_bottom">Dole</string>
|
||||
<string name="navigate_point_top_text">Zadejte zem. šířku a délku ve vybraném formátu (D - stupně, M - minuty, S - vteřiny)</string>
|
||||
<string name="navigate_point_top_text">Zadejte zeměpisnou šířku a délku ve vybraném formátu (D - stupně, M - minuty, S - vteřiny)</string>
|
||||
<string name="navigate_point_latitude">Šířka</string>
|
||||
<string name="navigate_point_longitude">Délka</string>
|
||||
<string name="shared_string_show_on_map">Zobrazit na mapě</string>
|
||||
<string name="search_address_top_text">Zvolit adresu</string>
|
||||
<string name="search_address_top_text">Adresa</string>
|
||||
<string name="search_address_region">Oblast</string>
|
||||
<string name="search_address_city">Město</string>
|
||||
<string name="search_address_street">Ulice</string>
|
||||
|
@ -621,7 +623,7 @@
|
|||
<string name="poi_remove_confirm_template">Vymazat {0} (komentář) \?</string>
|
||||
<string name="poi_remove_title">Vymazat POI</string>
|
||||
<string name="shared_string_delete">Vymazat</string>
|
||||
<string name="poi_remove_success">POI byl vymazán</string>
|
||||
<string name="poi_remove_success">Smazáno</string>
|
||||
<string name="poi_action_add">Přidání</string>
|
||||
<string name="poi_action_change">Změna</string>
|
||||
<string name="poi_action_succeded_template">Akce {0} provedena.</string>
|
||||
|
@ -636,9 +638,9 @@
|
|||
<string name="shared_string_clear">Vyčistit</string>
|
||||
<string name="filter_current_poiButton">Filtr</string>
|
||||
<string name="edit_filter_save_as_menu_item">Uložit jako</string>
|
||||
<string name="edit_filter_delete_dialog_title">Smazat vybraný filtr?</string>
|
||||
<string name="edit_filter_delete_message">Filtr %1$s byl smazán</string>
|
||||
<string name="edit_filter_create_message">Filtr %1$s byl vytvořen</string>
|
||||
<string name="edit_filter_delete_dialog_title">Smazat tento filtr\?</string>
|
||||
<string name="edit_filter_delete_message">Filtr \'%1$s\' byl smazán</string>
|
||||
<string name="edit_filter_create_message">Filtr \'%1$s\' byl vytvořen</string>
|
||||
<string name="offline_navigation_not_available">Off-line navigace OsmAnd je dočasně nedostupná.</string>
|
||||
<string name="left_side_navigation">Levostranný provoz</string>
|
||||
<string name="left_side_navigation_descr">Pro země, kde se jezdí po levé straně cesty.</string>
|
||||
|
@ -672,8 +674,8 @@
|
|||
<string name="favourites_edit_dialog_category">Kategorie</string>
|
||||
<string name="local_index_descr_title">Správce mapových souborů.</string>
|
||||
<string name="navigate_point_format_D">DDD.DDDDD</string>
|
||||
<string name="navigate_point_format_DM">DDD MM.MMMMM</string>
|
||||
<string name="navigate_point_format_DMS">DDD MM SS.SSSSS</string>
|
||||
<string name="navigate_point_format_DM">DDD MM.MMM</string>
|
||||
<string name="navigate_point_format_DMS">DDD MM SS.S</string>
|
||||
<string name="local_index_routing_data">Navigační data</string>
|
||||
<string name="navigate_point_format">Formát</string>
|
||||
<string name="poi_search_desc">Hledat body zájmu (POI)</string>
|
||||
|
@ -1022,15 +1024,15 @@
|
|||
<string name="speak_traffic_warnings">Dopravní varování</string>
|
||||
<string name="osb_author_dialog_password">Heslo OSM (volitelné)</string>
|
||||
<string name="av_camera_focus">Typ ostření fotoaparátu</string>
|
||||
<string name="av_camera_focus_descr">Zvolte způsob ostření vestavěného fotoaparátu.</string>
|
||||
<string name="av_camera_focus_descr">Režim zaostřování fotoaparátu:</string>
|
||||
<string name="av_camera_focus_auto">Automatické ostření</string>
|
||||
<string name="av_camera_focus_hiperfocal">Fix-focus</string>
|
||||
<string name="av_camera_focus_edof">Fix-focus</string>
|
||||
<string name="av_camera_focus_infinity">Ostření na nekonečno</string>
|
||||
<string name="av_camera_focus_infinity">Ostření je nastaveno na nekonečno</string>
|
||||
<string name="av_camera_focus_macro">Makro</string>
|
||||
<string name="av_camera_focus_continuous">Kamera ostří souvisle</string>
|
||||
<string name="av_photo_play_sound">Přehrát zvuk závěrky</string>
|
||||
<string name="av_photo_play_sound_descr">Zvolte zda při vyfotografování snímku má být přehrán zvuk závěrky.</string>
|
||||
<string name="av_photo_play_sound_descr">Nastavit zvuk či ticho při pořízení snímku.</string>
|
||||
<string name="new_directions_point_dialog">Mezicíle jsou již nastaveny.</string>
|
||||
<string name="context_menu_item_directions_to">Navigovat sem</string>
|
||||
<string name="context_menu_item_directions_from">Navigovat odsud</string>
|
||||
|
@ -1229,8 +1231,7 @@
|
|||
<string name="save_as_favorites_points">Uložit jako skupinu Oblíbených</string>
|
||||
<string name="select_destination_and_intermediate_points">Určete cíle</string>
|
||||
<string name="layer_amenity_label">Překryvné popisky bodů</string>
|
||||
<string name="create_poi_link_to_osm_doc">
|
||||
<u>On-line OSM</u> klasifikace map s obrázky.</string>
|
||||
<string name="create_poi_link_to_osm_doc"><u>On-line OSM</u> klasifikace map s obrázky.</string>
|
||||
<string name="show_zoom_buttons_navigation_descr">Zobrazit tlačítka lupy během navigace.</string>
|
||||
<string name="show_zoom_buttons_navigation">Zobrazit tlačítka lupy</string>
|
||||
<string name="sort_by_distance">Třídit podle vzdálenosti</string>
|
||||
|
@ -1287,7 +1288,7 @@
|
|||
<string name="arrival_distance_factor_late">Později</string>
|
||||
<string name="arrival_distance_factor_at_last">V posledních metrech</string>
|
||||
<string name="av_camera_pic_size">Velikost fotografie</string>
|
||||
<string name="av_camera_pic_size_descr">Vyberte velikost obrázku interního fotoaparátu.</string>
|
||||
<string name="av_camera_pic_size_descr">Nastavte velikost obrázku fotoaparátu</string>
|
||||
<string name="shared_string_more">Více…</string>
|
||||
<string name="rendering_value_browse_map_name">Standardní</string>
|
||||
<string name="rendering_value_car_name">Automobil</string>
|
||||
|
@ -1442,12 +1443,12 @@
|
|||
<string name="shared_string_export">Exportovat</string>
|
||||
<string name="shared_string_enable">Povolit</string>
|
||||
<string name="shared_string_disable">Zakázat</string>
|
||||
<string name="plugin_install_needs_network">Pro instalaci tohoto modulu je potřeba internetové připojení.</string>
|
||||
<string name="plugin_install_needs_network">Pro instalaci tohoto modulu musíte být online.</string>
|
||||
<string name="get_plugin">Získat</string>
|
||||
<string name="route_points">Body cesty</string>
|
||||
<string name="simulate_your_location">Simulovat polohu</string>
|
||||
<string name="short_location_on_map">Šířka %1$s
|
||||
Délka %2$s</string>
|
||||
\nDélka %2$s</string>
|
||||
<string name="routing_settings_2">Nastavení navigace</string>
|
||||
<string name="general_settings_2">Všeobecná nastavení</string>
|
||||
<string name="shared_string_ellipsis">…</string>
|
||||
|
@ -1589,11 +1590,11 @@ Délka %2$s</string>
|
|||
<string name="add_opening_hours">Přidat otevírací dobu</string>
|
||||
<string name="contact_info">Kontaktní informace</string>
|
||||
<string name="do_you_like_osmand">Máte rádi OsmAnd?</string>
|
||||
<string name="we_really_care_about_your_opinion">Záleží nám na vašem názoru, zpětná vazba je pro nás důležitá.</string>
|
||||
<string name="we_really_care_about_your_opinion">Oceníme váš názor a zpětnou vazbu.</string>
|
||||
<string name="rate_this_app">Ohodnoťte tuto aplikaci</string>
|
||||
<string name="rate_this_app_long">Ohodnoťte prosím aplikaci OsmAnd na Google Play</string>
|
||||
<string name="user_hates_app_get_feedback">Řekněte nám proč.</string>
|
||||
<string name="user_hates_app_get_feedback_long">Sdělte nám prosím, co byste chtěli v této aplikaci změnit.</string>
|
||||
<string name="user_hates_app_get_feedback_long">Sdělte nám prosím své návrhy.</string>
|
||||
<string name="shared_string_skip">Přeskočit</string>
|
||||
<string name="app_name_osmand">OsmAnd</string>
|
||||
<string name="plugin_settings">Moduly</string>
|
||||
|
@ -1612,7 +1613,7 @@ Délka %2$s</string>
|
|||
<string name="shared_string_card_was_hidden">Karta byla skryta</string>
|
||||
<string name="shared_string_undo">Zpět</string>
|
||||
<string name="offline_maps_and_navigation">Off-line mapy
|
||||
& navigace</string>
|
||||
\n& navigace</string>
|
||||
<string name="commit_poi">Odeslat POI</string>
|
||||
<string name="tab_title_basic">Základní</string>
|
||||
<string name="tab_title_advanced">Rozšířené</string>
|
||||
|
@ -1836,7 +1837,7 @@ Délka %2$s</string>
|
|||
<string name="weekly">Jednou týdně</string>
|
||||
<string name="morning">Ráno</string>
|
||||
<string name="night">V noci</string>
|
||||
<string name="select_month_and_country">Vyberte měsíc a krajinu</string>
|
||||
<string name="select_month_and_country">Měsíc a země:</string>
|
||||
<string name="shared_string_remove">Odstranit</string>
|
||||
<string name="rendering_attr_hideIcons_name">Ikony POI</string>
|
||||
<string name="shared_string_select">Vybrat</string>
|
||||
|
@ -1918,7 +1919,7 @@ Délka %2$s</string>
|
|||
<string name="consider_turning_polygons_off">Doporučujeme vypnout vykreslování polygonů.</string>
|
||||
<string name="rendering_attr_showMtbRoutes_name">Zobrazit trasy pro horská kola</string>
|
||||
<string name="storage_permission_restart_is_required">Aplikace nyní smí zapisovat na externí úložiště, ale je potřeba její restart.</string>
|
||||
<string name="file_name_containes_illegal_char">Název souboru obsahuje nepovolené znaky</string>
|
||||
<string name="file_name_containes_illegal_char">Nepovolený znak v názvu souboru</string>
|
||||
<string name="access_no_destination">Modul usnadnění: Cíl není nastaven</string>
|
||||
<string name="map_widget_magnetic_bearing">Magnetické směrování</string>
|
||||
<string name="map_widget_bearing">Relativní směrování</string>
|
||||
|
@ -2112,20 +2113,20 @@ Délka %2$s</string>
|
|||
<string name="quick_actions_delete_text">Opravdu chcete odstranit akci \"%s\"?</string>
|
||||
<string name="quick_favorites_show_favorites_dialog">Zobrazit dialog Oblíbených</string>
|
||||
<string name="quick_favorites_name_preset">Přednastavení názvu</string>
|
||||
<string name="quick_action_add_marker_descr">Klepnutím na tlačítko akce se přidá mapová značka do středu obrazovky.</string>
|
||||
<string name="quick_action_add_gpx_descr">Klepnutím na tlačítko akce se přidá GPX bod trasy na místo ve středu obrazovky.</string>
|
||||
<string name="quick_action_take_audio_note_descr">Klepnutím na tlačítko akce se přidá audio záznam na místo ve středu obrazovky.</string>
|
||||
<string name="quick_action_take_video_note_descr">Klepnutím na tlačítko akce se přidá video záznam na místo ve středu obrazovky.</string>
|
||||
<string name="quick_action_take_photo_note_descr">Klepnutím na tlačítko akce se přidá foto záznam na místo ve středu obrazovky.</string>
|
||||
<string name="quick_action_add_osm_bug_descr">Klepnutím na tlačítko akce se přidá OSM poznámka na místo ve středu obrazovky.</string>
|
||||
<string name="quick_action_add_poi_descr">Klepnutím na tlačítko akce se přidá POI na místo ve středu obrazovky.</string>
|
||||
<string name="quick_action_navigation_voice_descr">Klepnutím na tlačítko akce se vypnou nebo zapnou hlasové pokyny během navigace.</string>
|
||||
<string name="quick_action_add_parking_descr">Klepnutím na tlačítko akce se přidá parkovací místo do středu obrazovky.</string>
|
||||
<string name="quick_action_add_marker_descr">Tlačítko pro přidání mapové značky do středu obrazovky.</string>
|
||||
<string name="quick_action_add_gpx_descr">Tlačítko pro přidání bodu GPX trasy do středu obrazovky.</string>
|
||||
<string name="quick_action_take_audio_note_descr">Tlačítko pro přidání zvukové poznámky do středu obrazovky.</string>
|
||||
<string name="quick_action_take_video_note_descr">Tlačítko pro přidání video poznámky do středu obrazovky.</string>
|
||||
<string name="quick_action_take_photo_note_descr">Tlačítko pro přidání foto poznámky do středu obrazovky.</string>
|
||||
<string name="quick_action_add_osm_bug_descr">Tlačítko pro přidání OSM poznámky do středu obrazovky.</string>
|
||||
<string name="quick_action_add_poi_descr">Tlačítko pro přidání bodu zájmu do středu obrazovky.</string>
|
||||
<string name="quick_action_navigation_voice_descr">Tlačítko pro vypnutí nebo zapnutí hlasových pokynů během navigace.</string>
|
||||
<string name="quick_action_add_parking_descr">Tlačítko pro přidání místa zaparkování do středu obrazovky.</string>
|
||||
<string name="favorite_empty_place_name">Místo</string>
|
||||
<string name="quick_action_duplicates">Zadaný název rychlé akce je již použit a byl změněn na %1$s z důvodu duplicity.</string>
|
||||
<string name="quick_action_duplicates">Rychlá akce byla přejmenována na %1$s z důvodu duplicity.</string>
|
||||
<string name="quick_action_duplicate">Duplicitní název rychlé akce</string>
|
||||
<string name="quick_action_showhide_favorites_descr">Klepnutím na tlačítko akce se zobrazí nebo skryjí Oblíbená místa na mapě.</string>
|
||||
<string name="quick_action_showhide_poi_descr">Klepnutím na tlačítko akce se zobrazí nebo skryjí POI na mapě.</string>
|
||||
<string name="quick_action_showhide_favorites_descr">Tlačítko pro zobrazení nebo skrytí Oblíbených míst na mapě.</string>
|
||||
<string name="quick_action_showhide_poi_descr">Tlačítko pro zobrazení nebo skrytí bodů zájmu na mapě.</string>
|
||||
<string name="quick_action_showhide_favorites_title">Zobrazit/skrýt Oblíbená místa</string>
|
||||
<string name="quick_action_favorites_show">Zobrazit oblíbená místa</string>
|
||||
<string name="quick_action_favorites_hide">Skrýt Oblíbená místa</string>
|
||||
|
@ -2139,7 +2140,7 @@ Délka %2$s</string>
|
|||
<string name="quick_action_fav_name_descr">Ponecháte-li prázdné, bude použita adresa nebo název místa.</string>
|
||||
<string name="quick_action_bug_descr">Tato zpráva je zahrnuta v poli komentáře.</string>
|
||||
<string name="quick_action_bug_message">Zpráva</string>
|
||||
<string name="quick_action_category_descr">Vyberte kategorii pro uložení Oblíbeného místa.</string>
|
||||
<string name="quick_action_category_descr">Kategorie pro uložení Oblíbeného místa:</string>
|
||||
<string name="quick_action_gpx_category_descr">Vyberte volitelnou kategorii.</string>
|
||||
<string name="quick_action_poi_list">Seznam POI</string>
|
||||
<string name="quick_action_sh_poi_descr">Přidat jednu nebo více kategorií POI pro zobrazení na mapě.</string>
|
||||
|
@ -2155,23 +2156,23 @@ Délka %2$s</string>
|
|||
<string name="quick_action_map_source">Změnit zdroj mapy</string>
|
||||
<string name="quick_action_map_source_title">Mapové zdroje</string>
|
||||
<string name="quick_action_map_source_action">Přidat zdroj mapy</string>
|
||||
<string name="quick_action_map_source_switch">Zdroj mapy se změnil na \"%s\".</string>
|
||||
<string name="quick_action_map_source_switch">Zdroj mapy změněn na \"%s\".</string>
|
||||
<string name="quick_action_btn_tutorial_title">Změnit polohu tlačítka</string>
|
||||
<string name="quick_action_btn_tutorial_descr">Podržení a potáhnutí tlačítka změní jeho umístění na obrazovce.</string>
|
||||
<string name="shared_string_action_name">Název akce</string>
|
||||
<string name="navigate_point_olc_info_invalid">Neplatný OLC
|
||||
</string>
|
||||
\n</string>
|
||||
<string name="navigate_point_olc_info_short">Krátké OLC
|
||||
Prosím uveďte úplný kód</string>
|
||||
\nProsím zadejte úplný kód</string>
|
||||
<string name="navigate_point_olc_info_area">Platné plné OLC
|
||||
Zobrazená oblast: %1$s x %2$s</string>
|
||||
<string name="favorite_autofill_toast_text">" je uložen do "</string>
|
||||
<string name="quick_action_map_overlay_switch">Překryvná mapa se změnila na \"%s\".</string>
|
||||
<string name="quick_action_map_underlay_switch">Mapa podkladu se změnila na \"%s\".</string>
|
||||
\nOdpovídá oblasti: %1$s x %2$s</string>
|
||||
<string name="favorite_autofill_toast_text">" uložený do "</string>
|
||||
<string name="quick_action_map_overlay_switch">Překryvná mapa změněna na \"%s\".</string>
|
||||
<string name="quick_action_map_underlay_switch">Podkladová mapa změněna na \"%s\".</string>
|
||||
<string name="auto_split_recording_title">Při pauze automaticky rozdělovat nahrávky</string>
|
||||
<string name="auto_split_recording_descr">Začít nový úsek po 6minutové pauze, novou trasu po 2hodinové pauze nebo nový soubor po delší pauze, pokud se změnilo datum.</string>
|
||||
<string name="quick_action_interim_dialog">Zobrazit dočasné okno</string>
|
||||
<string name="quick_action_page_list_descr">Aktivace tlačítka akce posune seznam na další stranu.</string>
|
||||
<string name="quick_action_page_list_descr">Tlačítko pro posunutí seznamu na další stranu.</string>
|
||||
<string name="rendering_attr_depthContours_description">Zobrazit hloubkové vrstevnice a body.</string>
|
||||
<string name="rendering_attr_depthContours_name">Námořní hloubkové vrstevnice</string>
|
||||
<string name="navigate_point_olc">Open Location Code (OLC)</string>
|
||||
|
@ -2337,10 +2338,10 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
<string name="measurement_tool">Měřit vzdálenost</string>
|
||||
<string name="live_monitoring_max_interval_to_send">Časový zásobník pro online sledování</string>
|
||||
<string name="live_monitoring_max_interval_to_send_desrc">Zadejte čas pro podržení pozic k odeslání, pokud není připojení</string>
|
||||
<string name="mappilary_no_internet_desc">Pro zobrazení fotografií z Mapillary potřebujete internetové připojení.</string>
|
||||
<string name="mappilary_no_internet_desc">Fotografie z Mapillary jsou dostupné pouze online.</string>
|
||||
<string name="retry">Zkusit znovu</string>
|
||||
<string name="add_waypoint">Přidat trasový bod</string>
|
||||
<string name="save_gpx_waypoint">Uložit trasový bod GPX</string>
|
||||
<string name="save_gpx_waypoint">Uložit bod GPX trasy</string>
|
||||
<string name="save_route_point">Uložit bod trasy</string>
|
||||
<string name="waypoint_one">Trasový bod 1</string>
|
||||
<string name="route_point_one">Bod trasy 1</string>
|
||||
|
@ -2564,7 +2565,8 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
\n• Svoji polohu můžete sdílet se svými přáteli
|
||||
\n• Důležitá místa si můžete uložit do složky \'Moje místa\'
|
||||
\n• Můžete si vybrat, jak se na mapě budou zobrazovat názvy: V angličtině, v místním jazyce nebo ve fonetickém přepisu
|
||||
\n• Zobrazuje specializované online dlaždice, satelitní mapy (z Bingu), různé překryvné informace jako navigační GPX trasy a další vrstvy s volitelnou průhledností</string>
|
||||
\n• Zobrazuje specializované online dlaždice, satelitní mapy (z Bingu), různé překryvné informace jako navigační GPX trasy a další vrstvy s volitelnou průhledností
|
||||
\n</string>
|
||||
<string name="osmand_extended_description_part4">Lyžování
|
||||
\nOsmAnd plugin Lyžařský mapový pohled zobrazuje lyžařské trasy podle stupně obtížnosti a také další informace jako polohy vleků a dalších zařízení.</string>
|
||||
<string name="osmand_extended_description_part5">Cyklistika
|
||||
|
@ -2578,11 +2580,13 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
\n• Wikipedie ve vašem zvoleném jazyce vám poskytne mnoho informací při procházce městem
|
||||
\n• Při pohybu v neznámém městě vám pomůže zobrazování názvů zastávek a tras veřejné dopravy (autobusy, tramvaje, vlaky)
|
||||
\n• GPS navigace v režimu Pěší vytvoří trasu cest vhodných pro chodce
|
||||
\n• Můžete otevřít GPX trasu a následovat ji nebo zaznamenat a sdílet svou vlastní</string>
|
||||
\n• Můžete otevřít GPX trasu a následovat ji nebo zaznamenat a sdílet svou vlastní
|
||||
\n</string>
|
||||
<string name="osmand_extended_description_part7">Přispějte do OSM
|
||||
\n• Hlaste chyby v datech
|
||||
\n•Nahrávejte GPX trasy do OSM přímo z aplikace
|
||||
\n• Přidávejte body zájmu a rovnou je nahrávejte do OSM (nebo později, pokud jste zrovna offline)</string>
|
||||
\n• Přidávejte body zájmu a rovnou je nahrávejte do OSM (nebo později, pokud jste zrovna offline)
|
||||
\n</string>
|
||||
<string name="osmand_extended_description_part8">OsmAnd je aktivně vyvíjený open source software. Do aplikace může každý přispět hlášením chyb, vylepšováním překladů nebo programováním nových funkcí. Projekt je také závislý na finančních příspěvcích pro vývoj a testování nových funkcí.
|
||||
\n Přibližné pokrytí a kvalita map:
|
||||
\n • Západní Evropa: ****
|
||||
|
@ -2609,7 +2613,8 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
\n• Volitelné navádění do jízdních pruhů, zobrazení názvů ulic a předpokládaného čas příjezdu
|
||||
\n• Podporuje mezicíle v itineráři
|
||||
\n• Automatické přepočítání trasy při odchýlení
|
||||
\n• Hledání míst podle adresy, typu (např. restaurace, hotel, čerpací stanice, muzeum) či podle geografických souřadnic</string>
|
||||
\n• Hledání míst podle adresy, typu (např. restaurace, hotel, čerpací stanice, muzeum) či podle geografických souřadnic
|
||||
\n</string>
|
||||
<string name="osmand_plus_extended_description_part3">Prohlížení mapy
|
||||
\n • Zobrazení vaší pozice a orientace
|
||||
\n • Volitelné otáčení podle směru vašeho pohybu (nebo podle kompasu)
|
||||
|
@ -2630,7 +2635,8 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
\n• Volitelné automatické přepínání denního a nočního režimu
|
||||
\n• Volitelné zobrazení rychlostních limitů s upozorněním při překročení
|
||||
\n• Volitelné přiblížení mapy v závislosti na rychlosti
|
||||
\n• Sdílení polohy s přáteli</string>
|
||||
\n• Sdílení polohy s přáteli
|
||||
\n</string>
|
||||
<string name="osmand_plus_extended_description_part6">Funkce pro cyklisty a pěší
|
||||
\n• Zobrazení pěších, turistických a cyklistických tras, skvělé pro venkovní aktivity
|
||||
\n• Speciální navigační režim a zobrazení pro cyklisty a chodce
|
||||
|
@ -2784,7 +2790,7 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
<string name="wikivoyage_travel_guide_descr">Průvodce Wikivoyage Vám ukáže nejzajímavější místa planety, přímo v aplikaci OsmAnd a bez nutnosti připojení k internetu.</string>
|
||||
<string name="access_intermediate_arrival_time">Čas příjezdu do mezicíle</string>
|
||||
<string name="map_widget_intermediate_time">Do průjezdního bodu</string>
|
||||
<string name="test_voice_desrc">Klepněte na tlačítko pro vyslechnutí odpovídajícího hlasového pokynu, aby jste zjistili chybné nebo chybějící pokyny.</string>
|
||||
<string name="test_voice_desrc">Klepněte na tlačítko pro vyslechnutí odpovídajícího hlasového pokynu, abyste zjistili, zda chybí nebo je chybný</string>
|
||||
<string name="nautical_render_descr">Pro námořní navigaci. Obsahuje bóje, majáky, plavební cesty, mořské cesty a značky, přístavy, námořní služby a hloubkové vrstevnice.</string>
|
||||
<string name="ski_map_render_descr">Pro lyžování. Obsahuje sjezdovky, lyžařské vleky, běžkařské trasy atd. Nedůležité objekty jsou na mapě méně výrazné.</string>
|
||||
<string name="welcome_to_open_beta">Vítejte v otevřené beta verzi</string>
|
||||
|
@ -2843,7 +2849,7 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
<string name="run_full_osmand_msg">Používáte mapu {0}, která běží na aplikaci OsmAnd. Chcete spustit plnou verzi OsmAnd\?</string>
|
||||
<string name="run_full_osmand_header">Spustit OsmAnd\?</string>
|
||||
<string name="lang_gn_py">Guaranština</string>
|
||||
<string name="quick_action_switch_day_night_descr">Klepnutím na tlačítko akce se přepíná mezi denním a nočním režimem OsmAnd</string>
|
||||
<string name="quick_action_switch_day_night_descr">Tlačítko pro přepínání mezi denním a nočním režimem v OsmAnd.</string>
|
||||
<string name="quick_action_switch_day_mode">Denní režim</string>
|
||||
<string name="quick_action_switch_night_mode">Noční režim</string>
|
||||
<string name="quick_action_day_night_switch_mode">Přepnout denní/noční režim</string>
|
||||
|
@ -2886,7 +2892,7 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
<string name="exit_at">Výjezd na</string>
|
||||
<string name="shared_string_swap">Vyměnit</string>
|
||||
<string name="quick_action_show_hide_gpx_tracks">Zobrazit/skrýt stopy</string>
|
||||
<string name="quick_action_show_hide_gpx_tracks_descr">Tlačítko pro zobrazení nebo skrytí vybraných stop na mapě</string>
|
||||
<string name="quick_action_show_hide_gpx_tracks_descr">Tlačítko pro zobrazení nebo skrytí vybraných stop na mapě.</string>
|
||||
<string name="quick_action_gpx_tracks_hide">Skrýt stopy</string>
|
||||
<string name="quick_action_gpx_tracks_show">Zobrazit stopy</string>
|
||||
<string name="transfers_size">%1$d přenosů</string>
|
||||
|
@ -2965,8 +2971,8 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
\n
|
||||
\n • Odstraněné analytické moduly Facebook a Firebase z verze zdarma (OsmAnd+ je neobsahoval)
|
||||
\n "</string>
|
||||
<string name="routing_attr_avoid_sett_name">Vyhnout se kostkám</string>
|
||||
<string name="routing_attr_avoid_sett_description">Vyhnout se kočičím hlavám a dlažebním kostkám</string>
|
||||
<string name="routing_attr_avoid_sett_name">Žádné dlažební kostky</string>
|
||||
<string name="routing_attr_avoid_sett_description">Vyhne se dlažebním kostkám</string>
|
||||
<string name="shared_string_degrees">Stupně</string>
|
||||
<string name="shared_string_milliradians">Miliradiány</string>
|
||||
<string name="angular_measeurement">Úhlová jednotka</string>
|
||||
|
@ -3068,10 +3074,10 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
<string name="application_profiles_descr">Zvolte profily, které mají být viditelné v aplikaci.</string>
|
||||
<string name="application_profiles">Profily aplikace</string>
|
||||
<string name="zoom_by_wunderlinq">Použít WunderLINQ pro ovládání</string>
|
||||
<string name="quick_action_need_to_add_item_to_list">Musíte přidat alespoň jednu položku v nastavení Rychlé akce</string>
|
||||
<string name="routing_attr_piste_type_downhill_name">Alpské/sjezdové lyžování</string>
|
||||
<string name="quick_action_need_to_add_item_to_list">Přidejte alespoň jednu položku do seznamu \'Rychlá akce\'</string>
|
||||
<string name="routing_attr_piste_type_downhill_name">Alpské a sjezdové lyžování</string>
|
||||
<string name="routing_attr_piste_type_downhill_description">Svahy pro alpské nebo sjezdové lyžování a přístup k lyžařským vlekům.</string>
|
||||
<string name="routing_attr_piste_type_nordic_name">Běžecké a severské lyžování</string>
|
||||
<string name="routing_attr_piste_type_nordic_name">Běžecké a klasické lyžování</string>
|
||||
<string name="routing_attr_piste_type_nordic_description">Trasy pro severské nebo běžecké lyžování.</string>
|
||||
<string name="routing_attr_piste_type_skitour_name">Lyžařské okruhy</string>
|
||||
<string name="routing_attr_piste_type_skitour_description">Trasy pro lyžařské okruhy.</string>
|
||||
|
@ -3556,7 +3562,7 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
<string name="shared_string_gpx_files">Stopy</string>
|
||||
<string name="layer_gpx_layer">Stopy</string>
|
||||
<string name="show_gpx">Stopy</string>
|
||||
<string name="save_track_to_gpx_globally">"Ukládat trasu do GPX souboru"</string>
|
||||
<string name="save_track_to_gpx_globally">Ukládat trasu do GPX souboru</string>
|
||||
<string name="shared_string_gpx_route">Trasa ze stopy</string>
|
||||
<string name="empty_state_my_tracks">Přidat soubory stop</string>
|
||||
<string name="simplified_track">Zjednodušená trasa</string>
|
||||
|
@ -4014,4 +4020,27 @@ Zobrazená oblast: %1$s x %2$s</string>
|
|||
<string name="routing_attr_allow_streams_name">Povolit říčky a stoky</string>
|
||||
<string name="routing_attr_allow_intermittent_description">Povolit občasné vodní cesty</string>
|
||||
<string name="routing_attr_allow_intermittent_name">Povolit občasné vodní cesty</string>
|
||||
<string name="voice_prompts_timetable">Časy hlasových pokynů</string>
|
||||
<string name="add_online_routing_engine">Přidat online navigační službu</string>
|
||||
<string name="edit_online_routing_engine">Upravit online navigační službu</string>
|
||||
<string name="shared_string_subtype">Podtyp</string>
|
||||
<string name="shared_string_vehicle">Vozidlo</string>
|
||||
<string name="shared_string_api_key">API klíč</string>
|
||||
<string name="shared_string_server_url">URL serveru</string>
|
||||
<string name="shared_string_enter_param">Zadejte parametr</string>
|
||||
<string name="keep_it_empty_if_not">Pokud ne, nechte prázdné</string>
|
||||
<string name="online_routing_example_hint">Adresa se všemi parametry bude vypadat takto:</string>
|
||||
<string name="test_route_calculation">Vyzkoušet výpočet trasy</string>
|
||||
<string name="routing_engine_vehicle_type_driving">Řízení vozidla</string>
|
||||
<string name="routing_engine_vehicle_type_foot">Chůze</string>
|
||||
<string name="routing_engine_vehicle_type_bike">Kolo</string>
|
||||
<string name="routing_engine_vehicle_type_car">Auto</string>
|
||||
<string name="message_error_recheck_parameters">Chyba, zkontrolujte parametry</string>
|
||||
<string name="copy_address">Kopírovat adresu</string>
|
||||
<string name="online_routing_engine">Online navigační služba</string>
|
||||
<string name="online_routing_engines">Online navigační služby</string>
|
||||
<string name="shared_string_folders">Složky</string>
|
||||
<string name="select_folder">Zvolte složku</string>
|
||||
<string name="select_folder_descr">Zvolte složku nebo vytvořte novou</string>
|
||||
<string name="shared_string_empty">Prázdné</string>
|
||||
</resources>
|
|
@ -108,7 +108,7 @@
|
|||
<string name="poi_cave_entrance">Höhleneingang</string>
|
||||
<string name="poi_cemetery">Friedhof</string>
|
||||
<string name="poi_chalet">Ferienhaus</string>
|
||||
<string name="poi_electricity_combined_charging">Ladestation</string>
|
||||
<string name="poi_electricity_combined_charging">Ladestation;Ladestation für elektische Fahrzeuge;Aufladestation</string>
|
||||
<string name="poi_chemist">Drogerie</string>
|
||||
<string name="poi_chess">Schach</string>
|
||||
<string name="poi_clothes_children">Kinderbekleidungsgeschäft</string>
|
||||
|
|
|
@ -738,7 +738,7 @@
|
|||
<string name="osm_settings">OpenStreetMap-Bearbeitung</string>
|
||||
<string name="additional_settings">Weitere Einstellungen</string>
|
||||
<string name="shared_string_settings">Einstellungen</string>
|
||||
<string name="update_tile">Karte aktualisieren</string>
|
||||
<string name="update_tile">Aktualisieren</string>
|
||||
<string name="reload_tile">Kartenteile aktualisieren</string>
|
||||
<string name="mark_point">Ziel</string>
|
||||
<string name="shared_string_add_to_favorites">Zu \'Favoriten\' hinzufügen</string>
|
||||
|
@ -4047,4 +4047,11 @@
|
|||
<string name="shared_string_subtype">Subtyp</string>
|
||||
<string name="keep_it_empty_if_not">Leer lassen, wenn kein API-Schlüssel vorhanden</string>
|
||||
<string name="copy_address">Adresse kopieren</string>
|
||||
<string name="routing_engine_vehicle_type_driving">Fahren</string>
|
||||
<string name="online_routing_engine">Online Navigationssystem</string>
|
||||
<string name="online_routing_engines">Online Navigationssysteme</string>
|
||||
<string name="shared_string_folders">Ordner</string>
|
||||
<string name="select_folder">Ordner auswählen</string>
|
||||
<string name="select_folder_descr">Ordner auswählen oder neuen hinzufügen</string>
|
||||
<string name="shared_string_empty">Leer</string>
|
||||
</resources>
|
|
@ -4044,4 +4044,10 @@
|
|||
<string name="routing_engine_vehicle_type_car">Aŭtomobilo</string>
|
||||
<string name="message_error_recheck_parameters">Eraro, rekontrolu parametrojn</string>
|
||||
<string name="copy_address">Kopii adreson</string>
|
||||
<string name="online_routing_engine">Enreta navigilo</string>
|
||||
<string name="online_routing_engines">Enretaj navigiloj</string>
|
||||
<string name="shared_string_folders">Dosierujoj</string>
|
||||
<string name="select_folder">Elekti dosierujon</string>
|
||||
<string name="select_folder_descr">Elekti dosierujon aŭ krei novan</string>
|
||||
<string name="shared_string_empty">Malplena</string>
|
||||
</resources>
|
|
@ -4049,4 +4049,6 @@
|
|||
<string name="routing_engine_vehicle_type_car">Automóvil</string>
|
||||
<string name="message_error_recheck_parameters">Error, vuelve a comprobar los parámetros</string>
|
||||
<string name="copy_address">Copiar dirección</string>
|
||||
<string name="online_routing_engine">Motor de navegación en línea</string>
|
||||
<string name="online_routing_engines">Motores de navegación en línea</string>
|
||||
</resources>
|
|
@ -512,7 +512,7 @@
|
|||
<string name="poi_canadian_football">Football canadien</string>
|
||||
<string name="poi_cycling">Cyclisme</string>
|
||||
<string name="poi_shooting">Tir</string>
|
||||
<string name="poi_physiotherapist">Psychothérapeute</string>
|
||||
<string name="poi_physiotherapist">Kinésithérapeute</string>
|
||||
<string name="poi_occupational_therapist">Ergothérapeute</string>
|
||||
<string name="poi_place_farm">Ferme</string>
|
||||
<string name="poi_place_allotments">Jardins familiaux</string>
|
||||
|
|
|
@ -4023,4 +4023,10 @@
|
|||
<string name="edit_online_routing_engine">Modifier le moteur de routage en ligne</string>
|
||||
<string name="online_routing_example_hint">L\'URL avec tous les paramètres sera de la forme :</string>
|
||||
<string name="copy_address">Copier l\'adresse</string>
|
||||
<string name="online_routing_engine">Moteur de routage en ligne</string>
|
||||
<string name="online_routing_engines">Moteurs de routage en ligne</string>
|
||||
<string name="shared_string_folders">Dossiers</string>
|
||||
<string name="select_folder">Sélectionnez le dossier</string>
|
||||
<string name="select_folder_descr">Sélectionnez un dossier ou créez-en un nouveau</string>
|
||||
<string name="shared_string_empty">Vide</string>
|
||||
</resources>
|
|
@ -3958,7 +3958,7 @@ Lon %2$s</string>
|
|||
<string name="navigate_point_mgrs">MGRS</string>
|
||||
<string name="navigate_point_format_mgrs">MGRS</string>
|
||||
<string name="mgrs_format_descr">O OsmAnd emprega MGRS, que é semellante ó formato UTM NATO.</string>
|
||||
<string name="message_need_calculate_route_before_show_graph">%1$s datos dispoñíbeis só nas estrada, necesitas calcular unha ruta empregando \"Ruta entre puntos\" para obtela.</string>
|
||||
<string name="message_need_calculate_route_before_show_graph">Os datos de %1$s só dispoñíbeis nas estradas, calcula unha ruta empregando \"Ruta entre puntos\" para ver gráficas.</string>
|
||||
<string name="message_graph_will_be_available_after_recalculation">O gráfico estará dispoñíbel após o recálculo da ruta.</string>
|
||||
<string name="shared_string_local_maps">Mapas locais</string>
|
||||
<string name="app_mode_gap">Salto</string>
|
||||
|
@ -4050,4 +4050,27 @@ Lon %2$s</string>
|
|||
<string name="routing_attr_allow_streams_name">Permitir regatos e cunetas</string>
|
||||
<string name="routing_attr_allow_intermittent_description">Permitir canles de auga intermitentes</string>
|
||||
<string name="routing_attr_allow_intermittent_name">Permitir canles de auga intermitentes</string>
|
||||
<string name="add_online_routing_engine">Engadir motor de navegación en liña</string>
|
||||
<string name="edit_online_routing_engine">Editar motor de navegación en liña</string>
|
||||
<string name="shared_string_subtype">Subtipo</string>
|
||||
<string name="shared_string_vehicle">Vehículo</string>
|
||||
<string name="shared_string_api_key">Chave da API</string>
|
||||
<string name="shared_string_server_url">URL do servidor</string>
|
||||
<string name="shared_string_enter_param">Insire parámetro</string>
|
||||
<string name="keep_it_empty_if_not">Mantenlo baleiro se non</string>
|
||||
<string name="online_routing_example_hint">A URL con todos os parámetros será así:</string>
|
||||
<string name="test_route_calculation">Cálculo da ruta de proba</string>
|
||||
<string name="routing_engine_vehicle_type_driving">Conducindo</string>
|
||||
<string name="routing_engine_vehicle_type_foot">Pé</string>
|
||||
<string name="routing_engine_vehicle_type_bike">Bicicleta</string>
|
||||
<string name="routing_engine_vehicle_type_car">Coche</string>
|
||||
<string name="message_error_recheck_parameters">Erro, verifica novamente os parámetros</string>
|
||||
<string name="copy_address">Copiar enderezo</string>
|
||||
<string name="voice_prompts_timetable">Horarios dos avisos por voz</string>
|
||||
<string name="online_routing_engine">Motor de navegación en liña</string>
|
||||
<string name="online_routing_engines">Motores de navegación en liña</string>
|
||||
<string name="shared_string_folders">Cartafoles</string>
|
||||
<string name="select_folder_descr">Selecionar cartafol ou engadir un novo</string>
|
||||
<string name="select_folder">Seleccionar cartafol</string>
|
||||
<string name="shared_string_empty">Baleiro</string>
|
||||
</resources>
|
|
@ -4036,4 +4036,10 @@
|
|||
<string name="test_route_calculation">Útvonaltervezés kipróbálása</string>
|
||||
<string name="message_error_recheck_parameters">Hiba, ellenőrizze újra a paramétereket</string>
|
||||
<string name="copy_address">Cím másolása</string>
|
||||
<string name="online_routing_engine">Online útvonaltervező</string>
|
||||
<string name="online_routing_engines">Online útvonaltervezők</string>
|
||||
<string name="shared_string_folders">Mappák</string>
|
||||
<string name="select_folder">Mappa kijelölése</string>
|
||||
<string name="select_folder_descr">Mappa kijelölése vagy új hozzáadása</string>
|
||||
<string name="shared_string_empty">Üres</string>
|
||||
</resources>
|
|
@ -286,7 +286,7 @@
|
|||
<string name="poi_fuel_biogas">Lífgas</string>
|
||||
<string name="poi_fuel_lh2">Fljótandi vetni</string>
|
||||
<string name="poi_fuel_electricity">Rafmagn</string>
|
||||
<string name="poi_electricity_combined_charging">Hleðslustöð</string>
|
||||
<string name="poi_electricity_combined_charging">Hleðslustöð;Hleðslustöð fyrir rafknúin farartæki;EV-hleðslustöð;Hleðslustæði;Rafhleðslustæði;Þjónustustöð fyrir rafknúin farartæki</string>
|
||||
<string name="poi_compressed_air">Loftdæla</string>
|
||||
<string name="poi_motorcycle_parking">Mótorhjólastæði</string>
|
||||
<string name="poi_parking_entrance">Aðgangur að bílastæði</string>
|
||||
|
@ -3883,4 +3883,8 @@
|
|||
<string name="poi_lavoir">Þvottaþró (þvottaaðstaða)</string>
|
||||
<string name="poi_water_source_river">Á</string>
|
||||
<string name="poi_lifeguard_base">Bækistöð öryggisvarða</string>
|
||||
<string name="poi_wildlife_crossing_bat_tunnel">Göng fyrir leðurblökur</string>
|
||||
<string name="poi_wildlife_crossing_bat_bridge">Brú fyrir leðurblökur</string>
|
||||
<string name="poi_wildlife_crossing">Þverun villtra dýra</string>
|
||||
<string name="poi_swimming_area">Sundsvæði</string>
|
||||
</resources>
|
|
@ -4029,4 +4029,29 @@
|
|||
<string name="profile_type_user_string">Notandasnið</string>
|
||||
<string name="reverse_all_points">Snúa við öllum punktum</string>
|
||||
<string name="profile_type_osmand_string">OsmAnd-snið</string>
|
||||
<string name="voice_prompts_timetable">Tímasetning raddskipana</string>
|
||||
<string name="profile_by_default_description">Veldu sniðið sem verður notað þegar forritið er ræst.</string>
|
||||
<string name="shared_string_last_used">Síðast notað</string>
|
||||
<string name="routing_attr_prefer_hiking_routes_description">Velja frekar gönguleiðir</string>
|
||||
<string name="routing_attr_prefer_hiking_routes_name">Velja frekar gönguleiðir</string>
|
||||
<string name="routing_attr_allow_streams_description">Leyfa læki og afföll</string>
|
||||
<string name="routing_attr_allow_streams_name">Leyfa læki og afföll</string>
|
||||
<string name="routing_attr_allow_intermittent_description">Leyfa tímabundnar vatnaleiðir</string>
|
||||
<string name="routing_attr_allow_intermittent_name">Leyfa tímabundnar vatnaleiðir</string>
|
||||
<string name="add_online_routing_engine">Bæta við leiðagerð af netinu</string>
|
||||
<string name="edit_online_routing_engine">Breyta nettengdri leiðagerð</string>
|
||||
<string name="shared_string_subtype">Undirtegund</string>
|
||||
<string name="shared_string_vehicle">Farartæki</string>
|
||||
<string name="shared_string_api_key">API-lykill</string>
|
||||
<string name="shared_string_server_url">Vefslóð netþjóns</string>
|
||||
<string name="shared_string_enter_param">Setja inn breytu</string>
|
||||
<string name="keep_it_empty_if_not">Halda þessu auðu ef ekki</string>
|
||||
<string name="online_routing_example_hint">Vefslóð með öllum breytum mun líta svona út:</string>
|
||||
<string name="test_route_calculation">Útreikningur prufuleiðar</string>
|
||||
<string name="routing_engine_vehicle_type_driving">Akstur</string>
|
||||
<string name="routing_engine_vehicle_type_foot">Gangandi</string>
|
||||
<string name="routing_engine_vehicle_type_bike">Hjólandi</string>
|
||||
<string name="routing_engine_vehicle_type_car">Bíll</string>
|
||||
<string name="message_error_recheck_parameters">Villa, yfirfarðu breytur</string>
|
||||
<string name="copy_address">Afrita heimilisfang</string>
|
||||
</resources>
|
|
@ -4048,4 +4048,10 @@
|
|||
<string name="routing_engine_vehicle_type_car">מכונית</string>
|
||||
<string name="message_error_recheck_parameters">שגיאה, נא לבדוק את המשתנים מחדש</string>
|
||||
<string name="copy_address">העתקת כתובת</string>
|
||||
<string name="online_routing_engine">מנוע ניווט מקוון</string>
|
||||
<string name="online_routing_engines">מנועי ניווט מקוונים</string>
|
||||
<string name="shared_string_folders">תיקיות</string>
|
||||
<string name="select_folder">בחירת תקינה</string>
|
||||
<string name="select_folder_descr">נא לבחור תיקייה או להוסיף אחת חדשה</string>
|
||||
<string name="shared_string_empty">ריק</string>
|
||||
</resources>
|
|
@ -3940,4 +3940,30 @@
|
|||
<string name="routing_attr_allow_streams_description">Beken en sloten gebruiken</string>
|
||||
<string name="routing_attr_allow_streams_name">Beken en sloten gebruiken</string>
|
||||
<string name="routing_attr_allow_intermittent_description">Waterwegen die periodiek water voeren gebruiken</string>
|
||||
<string name="select_folder">Selecteer een map</string>
|
||||
<string name="select_folder_descr">Selecteer een map of maak een nieuwe</string>
|
||||
<string name="shared_string_empty">Leeg</string>
|
||||
<string name="select_groups_for_import">Selecteer de groepen om deze te importeren.</string>
|
||||
<string name="select_items_for_import">Selecteer de items om deze te importeren.</string>
|
||||
<string name="add_to_mapillary">Voeg toe aan Mapillary</string>
|
||||
<string name="add_to_opr">Voeg toe aan OpenPlaceReviews</string>
|
||||
<string name="use_dev_url">Gebruik dev.openstreetmap.org</string>
|
||||
<string name="profile_by_default_description">Selecteer het profiel dat zal worden gebruikt bij het starten van de applicatie.</string>
|
||||
<string name="add_online_routing_engine">Online routeplanner toevoegen</string>
|
||||
<string name="edit_online_routing_engine">Bewerk online routeplanner</string>
|
||||
<string name="shared_string_subtype">Subtype</string>
|
||||
<string name="shared_string_vehicle">Voertuig</string>
|
||||
<string name="shared_string_api_key">API-sleutel</string>
|
||||
<string name="shared_string_server_url">Server-URL</string>
|
||||
<string name="online_routing_example_hint">De URL met alle parameters ziet er als volgt uit:</string>
|
||||
<string name="test_route_calculation">Test routeberekening</string>
|
||||
<string name="routing_engine_vehicle_type_driving">Rijden</string>
|
||||
<string name="routing_engine_vehicle_type_foot">Te voet</string>
|
||||
<string name="routing_engine_vehicle_type_bike">Fiets</string>
|
||||
<string name="routing_engine_vehicle_type_car">Auto</string>
|
||||
<string name="message_error_recheck_parameters">Fout, controleer parameters opnieuw</string>
|
||||
<string name="copy_address">Kopieer adres</string>
|
||||
<string name="online_routing_engine">Online routeplanningssysteem</string>
|
||||
<string name="online_routing_engines">Online routeplanningssystemen</string>
|
||||
<string name="shared_string_folders">Mappen</string>
|
||||
</resources>
|
|
@ -4038,4 +4038,11 @@
|
|||
<string name="routing_engine_vehicle_type_bike">Bicicleta</string>
|
||||
<string name="routing_engine_vehicle_type_car">Carro</string>
|
||||
<string name="message_error_recheck_parameters">Erro, verifique novamente os parâmetros</string>
|
||||
<string name="copy_address">Copiar endereço</string>
|
||||
<string name="online_routing_engine">Motor de encaminhamento online</string>
|
||||
<string name="online_routing_engines">Mecanismos de roteamento online</string>
|
||||
<string name="shared_string_folders">Pastas</string>
|
||||
<string name="select_folder">Selecione a pasta</string>
|
||||
<string name="select_folder_descr">Selecione a pasta ou adicione uma nova</string>
|
||||
<string name="shared_string_empty">Vazio</string>
|
||||
</resources>
|
|
@ -3879,4 +3879,7 @@
|
|||
<string name="poi_water_source_tap">Torneira</string>
|
||||
<string name="poi_water_source_water_works">Estação de tratamento de água</string>
|
||||
<string name="poi_ranger_station">Posto de guarda florestal</string>
|
||||
<string name="poi_wildlife_crossing_bat_tunnel">Túnel de morcegos</string>
|
||||
<string name="poi_wildlife_crossing_bat_bridge">Ponte de morcegos</string>
|
||||
<string name="poi_swimming_area">Área de natação</string>
|
||||
</resources>
|
|
@ -4005,4 +4005,14 @@
|
|||
<string name="shared_string_last_used">Последний раз использовалось</string>
|
||||
<string name="routing_attr_allow_intermittent_description">Разрешить прерывистые водные пути</string>
|
||||
<string name="routing_attr_allow_intermittent_name">Разрешить прерывистые водные пути</string>
|
||||
<string name="release_3_9">• Добавлена возможность экспорта и импорта всех данных, включая настройки, ресурсы, мои места.
|
||||
\n
|
||||
\n• Планирование маршрута: графики для сегментов трека с маршрутом, добавлена возможность создавать и редактировать несколько сегментов трека.
|
||||
\n
|
||||
\n• Добавлен OAuth метод аутентификации для OpenStreetMap, улучшен интерфейс диалоговых OSM.
|
||||
\n
|
||||
\n • Поддержка пользовательских цветов для избранного и путевых точек трека.
|
||||
\n
|
||||
\n</string>
|
||||
<string name="copy_address">Скопировать адрес</string>
|
||||
</resources>
|
|
@ -4025,4 +4025,26 @@
|
|||
<string name="routing_attr_allow_intermittent_description">Permite caminos de abba intermitentes</string>
|
||||
<string name="routing_attr_allow_intermittent_name">Permite caminos de abba intermitentes</string>
|
||||
<string name="voice_prompts_timetable">Nùmeru de annùntzios vocales</string>
|
||||
<string name="add_online_routing_engine">Annanghe unu motore de càrculu de s\'àndala in lìnia</string>
|
||||
<string name="edit_online_routing_engine">Modìfica su motore de càrculu de s\'àndala in lìnia</string>
|
||||
<string name="shared_string_subtype">Suta-casta</string>
|
||||
<string name="shared_string_vehicle">Veìculu</string>
|
||||
<string name="shared_string_api_key">Crae de s\'API</string>
|
||||
<string name="shared_string_server_url">URL de su serbidore</string>
|
||||
<string name="shared_string_enter_param">Inserta su paràmetru</string>
|
||||
<string name="keep_it_empty_if_not">Si nono, mantene·lu bòidu</string>
|
||||
<string name="online_routing_example_hint">S\'URL cun totu sos paràmetros at a apàrrere gasi:</string>
|
||||
<string name="test_route_calculation">Proa a carculare un\'àndala</string>
|
||||
<string name="routing_engine_vehicle_type_driving">In vetura</string>
|
||||
<string name="routing_engine_vehicle_type_foot">A pee</string>
|
||||
<string name="routing_engine_vehicle_type_bike">Bitzicleta</string>
|
||||
<string name="routing_engine_vehicle_type_car">Màchina</string>
|
||||
<string name="message_error_recheck_parameters">Errore, torra a verificare sos paràmetros</string>
|
||||
<string name="copy_address">Còpia s\'indiritzu</string>
|
||||
<string name="online_routing_engine">Motore de càrculu in lìnia</string>
|
||||
<string name="online_routing_engines">Motores de càrculu in lìnia</string>
|
||||
<string name="shared_string_folders">Cartellas</string>
|
||||
<string name="select_folder">Ischerta sa cartella</string>
|
||||
<string name="select_folder_descr">Ischerta una cartella o crea·nde una noa</string>
|
||||
<string name="shared_string_empty">Bòidu</string>
|
||||
</resources>
|
|
@ -4043,4 +4043,7 @@
|
|||
<string name="routing_engine_vehicle_type_bike">Bicykel</string>
|
||||
<string name="routing_engine_vehicle_type_car">Auto</string>
|
||||
<string name="message_error_recheck_parameters">Chyba, skontrolujte parametre</string>
|
||||
<string name="copy_address">Kopírovať adresu</string>
|
||||
<string name="online_routing_engine">Online navigačná služba</string>
|
||||
<string name="online_routing_engines">Online navigačné služby</string>
|
||||
</resources>
|
|
@ -3999,4 +3999,10 @@
|
|||
<string name="routing_engine_vehicle_type_car">Araba</string>
|
||||
<string name="message_error_recheck_parameters">Hata, parametreleri tekrar gözden geçirin</string>
|
||||
<string name="copy_address">Adresi kopyala</string>
|
||||
<string name="online_routing_engine">Çevrim içi yönlendirme motoru</string>
|
||||
<string name="online_routing_engines">Çevrim içi yönlendirme motorları</string>
|
||||
<string name="shared_string_folders">Klasörler</string>
|
||||
<string name="select_folder">Klasör seç</string>
|
||||
<string name="select_folder_descr">Klasör seçin veya yeni bir tane ekleyin</string>
|
||||
<string name="shared_string_empty">Boş</string>
|
||||
</resources>
|
|
@ -4039,4 +4039,11 @@
|
|||
<string name="routing_engine_vehicle_type_bike">Велосипед</string>
|
||||
<string name="routing_engine_vehicle_type_car">Автомобіль</string>
|
||||
<string name="message_error_recheck_parameters">Помилка, повторно перевірте параметри</string>
|
||||
<string name="copy_address">Копіювати адресу</string>
|
||||
<string name="online_routing_engine">Мережний рушій маршрутизації</string>
|
||||
<string name="online_routing_engines">Мережні рушії маршрутизації</string>
|
||||
<string name="shared_string_folders">Теки</string>
|
||||
<string name="select_folder">Вибрати теку</string>
|
||||
<string name="select_folder_descr">Виберіть теку або додайте нову</string>
|
||||
<string name="shared_string_empty">Порожньо</string>
|
||||
</resources>
|
|
@ -4039,4 +4039,10 @@
|
|||
<string name="routing_engine_vehicle_type_car">汽車</string>
|
||||
<string name="message_error_recheck_parameters">錯誤,重新檢查參數</string>
|
||||
<string name="copy_address">複製地址</string>
|
||||
<string name="online_routing_engine">線上路線計算引擎</string>
|
||||
<string name="online_routing_engines">線上路線計算引擎</string>
|
||||
<string name="shared_string_folders">資料夾</string>
|
||||
<string name="select_folder">選取資料夾</string>
|
||||
<string name="select_folder_descr">選取資料夾或新增</string>
|
||||
<string name="shared_string_empty">空</string>
|
||||
</resources>
|
|
@ -7,11 +7,15 @@
|
|||
1. To not produce duplicate strings (check by name if a string already exists)
|
||||
2. Every apostrophe (quote) is preceded by a backslash.
|
||||
3. If you modify the English strings file, please add new strings at the top of the file, this makes periodic reviews before releases easier.
|
||||
- For wording and consistency, please note https://osmand.net/help-online?id=technical-articles#Creating_a_Consistent_User_Experience
|
||||
- For wording and consistency, please note https://docs.osmand.net/en/main@latest/development/contributing-to-osmand/translating-osmand
|
||||
Thx - Hardy
|
||||
|
||||
-->
|
||||
|
||||
<string name="shared_string_empty">Empty</string>
|
||||
<string name="select_folder_descr">Select folder or add new one</string>
|
||||
<string name="select_folder">Select folder</string>
|
||||
<string name="shared_string_folders">Folders</string>
|
||||
<string name="online_routing_engines">Online routing engines</string>
|
||||
<string name="online_routing_engine">Online routing engine</string>
|
||||
<string name="copy_address">Copy address</string>
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
package net.osmand;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.GPXUtilities.Metadata;
|
||||
import net.osmand.plus.GpxSelectionHelper;
|
||||
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.SQLiteTileSource;
|
||||
import net.osmand.plus.dialogs.RenameFileBottomSheet;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class FileUtils {
|
||||
|
@ -29,70 +26,11 @@ public class FileUtils {
|
|||
public static final Pattern ILLEGAL_FILE_NAME_CHARACTERS = Pattern.compile("[?:\"*|/<>]");
|
||||
public static final Pattern ILLEGAL_PATH_NAME_CHARACTERS = Pattern.compile("[?:\"*|<>]");
|
||||
|
||||
public static void renameFile(Activity a, final File f, final RenameCallback callback) {
|
||||
final WeakReference<Activity> weakActivity = new WeakReference<>(a);
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(a);
|
||||
if (f.exists()) {
|
||||
int xt = f.getName().lastIndexOf('.');
|
||||
final String ext = xt == -1 ? "" : f.getName().substring(xt);
|
||||
final String originalName = xt == -1 ? f.getName() : f.getName().substring(0, xt);
|
||||
final EditText editText = new EditText(a);
|
||||
editText.setText(originalName);
|
||||
editText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
Editable text = editText.getText();
|
||||
if (text.length() >= 1) {
|
||||
Activity activity = weakActivity.get();
|
||||
if (ILLEGAL_FILE_NAME_CHARACTERS.matcher(text).find() && activity != null) {
|
||||
editText.setError(activity.getString(R.string.file_name_containes_illegal_char));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
b.setTitle(R.string.shared_string_rename);
|
||||
int leftPadding = AndroidUtils.dpToPx(a, 24f);
|
||||
int topPadding = AndroidUtils.dpToPx(a, 4f);
|
||||
b.setView(editText, leftPadding, topPadding, leftPadding, topPadding);
|
||||
// Behaviour will be overwritten later;
|
||||
b.setPositiveButton(R.string.shared_string_save, null);
|
||||
b.setNegativeButton(R.string.shared_string_cancel, null);
|
||||
final AlertDialog alertDialog = b.create();
|
||||
alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialog) {
|
||||
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Activity activity = weakActivity.get();
|
||||
if (activity != null) {
|
||||
OsmandApplication app = (OsmandApplication) activity.getApplication();
|
||||
if (ext.equals(SQLiteTileSource.EXT)) {
|
||||
if (renameSQLiteFile(app, f, editText.getText().toString() + ext,
|
||||
callback) != null) {
|
||||
alertDialog.dismiss();
|
||||
}
|
||||
} else {
|
||||
if (renameGpxFile(app, f, editText.getText().toString() + ext,
|
||||
false, callback) != null) {
|
||||
alertDialog.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
alertDialog.show();
|
||||
public static void renameFile(@NonNull FragmentActivity activity, @NonNull File file,
|
||||
@Nullable Fragment target, boolean usedOnMap) {
|
||||
if (file.exists()) {
|
||||
FragmentManager fragmentManager = activity.getSupportFragmentManager();
|
||||
RenameFileBottomSheet.showInstance(fragmentManager, target, file, usedOnMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,6 +78,26 @@ public class FileUtils {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static File renameFile(@NonNull OsmandApplication app, @NonNull File source,
|
||||
@NonNull String newName, boolean dirAllowed, RenameCallback callback) {
|
||||
File dest = checkRenamePossibility(app, source, newName, dirAllowed);
|
||||
if (dest == null) {
|
||||
return null;
|
||||
}
|
||||
if (!dest.getParentFile().exists()) {
|
||||
dest.getParentFile().mkdirs();
|
||||
}
|
||||
File res = source.renameTo(dest) ? dest : null;
|
||||
if (res != null) {
|
||||
if (callback != null) {
|
||||
callback.renamedTo(res);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(app, R.string.file_can_not_be_renamed, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static File renameGpxFile(@NonNull OsmandApplication app, @NonNull File src, @NonNull File dest) {
|
||||
if (!dest.getParentFile().exists()) {
|
||||
dest.getParentFile().mkdirs();
|
||||
|
|
|
@ -168,8 +168,6 @@ public class HelpActivity extends OsmandActionBarActivity implements AdapterView
|
|||
contextMenuAdapter.addItem(createCategory(R.string.other_menu_group));
|
||||
contextMenuAdapter.addItem(createItem(R.string.instalation_troubleshooting_item, NULL_ID,
|
||||
"feature_articles/installation-and-troubleshooting.html"));
|
||||
contextMenuAdapter.addItem(createItem(R.string.techical_articles_item, NULL_ID,
|
||||
"feature_articles/technical-articles.html"));
|
||||
contextMenuAdapter.addItem(createItem(R.string.versions_item, NULL_ID,
|
||||
"feature_articles/changes.html"));
|
||||
contextMenuAdapter.addItem(createItem(R.string.what_is_new, NULL_ID,
|
||||
|
|
|
@ -63,8 +63,8 @@ import net.osmand.plus.measurementtool.MeasurementToolFragment;
|
|||
import net.osmand.plus.measurementtool.StartPlanRouteBottomSheet;
|
||||
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
||||
import net.osmand.plus.osmedit.dialogs.DismissRouteBottomSheetFragment;
|
||||
import net.osmand.plus.profiles.ProfileDataObject;
|
||||
import net.osmand.plus.profiles.ProfileDataUtils;
|
||||
import net.osmand.plus.profiles.RoutingProfileDataObject;
|
||||
import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu;
|
||||
import net.osmand.plus.routepreparationmenu.WaypointsFragment;
|
||||
import net.osmand.plus.routing.RouteProvider.GPXRouteParamsBuilder;
|
||||
|
@ -737,7 +737,7 @@ public class MapActivityActions implements DialogProvider {
|
|||
|
||||
String modeDescription;
|
||||
|
||||
Map<String, RoutingProfileDataObject> profilesObjects = ProfileDataUtils.getRoutingProfiles(app);
|
||||
Map<String, ProfileDataObject> profilesObjects = ProfileDataUtils.getRoutingProfiles(app);
|
||||
for (final ApplicationMode appMode : activeModes) {
|
||||
if (appMode.isCustomProfile()) {
|
||||
modeDescription = getProfileDescription(app, appMode, profilesObjects, getString(R.string.profile_type_user_string));
|
||||
|
@ -1046,7 +1046,7 @@ public class MapActivityActions implements DialogProvider {
|
|||
//switch profile button
|
||||
ApplicationMode currentMode = app.getSettings().APPLICATION_MODE.get();
|
||||
String modeDescription;
|
||||
Map<String, RoutingProfileDataObject> profilesObjects = ProfileDataUtils.getRoutingProfiles(app);
|
||||
Map<String, ProfileDataObject> profilesObjects = ProfileDataUtils.getRoutingProfiles(app);
|
||||
if (currentMode.isCustomProfile()) {
|
||||
modeDescription = getProfileDescription(app, currentMode, profilesObjects, getString(R.string.profile_type_user_string));
|
||||
} else {
|
||||
|
@ -1087,12 +1087,12 @@ public class MapActivityActions implements DialogProvider {
|
|||
}
|
||||
|
||||
private String getProfileDescription(OsmandApplication app, ApplicationMode mode,
|
||||
Map<String, RoutingProfileDataObject> profilesObjects, String defaultDescription) {
|
||||
Map<String, ProfileDataObject> profilesObjects, String defaultDescription) {
|
||||
String description = defaultDescription;
|
||||
|
||||
String routingProfileKey = mode.getRoutingProfile();
|
||||
if (!Algorithms.isEmpty(routingProfileKey)) {
|
||||
RoutingProfileDataObject profileDataObject = profilesObjects.get(routingProfileKey);
|
||||
ProfileDataObject profileDataObject = profilesObjects.get(routingProfileKey);
|
||||
if (profileDataObject != null) {
|
||||
description = String.format(app.getString(R.string.profile_type_descr_string),
|
||||
Algorithms.capitalizeFirstLetterAndLowercase(profileDataObject.getName()));
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.Intent;
|
|||
import android.content.res.ColorStateList;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.PersistableBundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
|
@ -45,6 +46,7 @@ import net.osmand.plus.settings.backend.OsmAndAppCustomization;
|
|||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.track.TrackDisplayHelper;
|
||||
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
@ -83,10 +85,35 @@ public class TrackActivity extends TabActivity {
|
|||
return;
|
||||
}
|
||||
displayHelper = new TrackDisplayHelper(app);
|
||||
if (intent.hasExtra(TRACK_FILE_NAME)) {
|
||||
if (savedInstanceState != null) {
|
||||
String path = savedInstanceState.getString(TRACK_FILE_NAME);
|
||||
if (!Algorithms.isEmpty(path)) {
|
||||
displayHelper.setFile(new File(path));
|
||||
}
|
||||
} else if (intent.hasExtra(TRACK_FILE_NAME)) {
|
||||
displayHelper.setFile(new File(intent.getStringExtra(TRACK_FILE_NAME)));
|
||||
}
|
||||
|
||||
setupActionBar();
|
||||
if (intent.hasExtra(OPEN_POINTS_TAB)
|
||||
|| (savedInstanceState != null && savedInstanceState.getBoolean(OPEN_POINTS_TAB, false))) {
|
||||
openPointsTab = true;
|
||||
}
|
||||
if (intent.hasExtra(OPEN_TRACKS_LIST)) {
|
||||
openTracksList = true;
|
||||
}
|
||||
setContentView(R.layout.track_content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
|
||||
File file = getFile();
|
||||
outState.putString(TRACK_FILE_NAME, file != null ? file.getAbsolutePath() : null);
|
||||
outState.putBoolean(CURRENT_RECORDING, file == null);
|
||||
super.onSaveInstanceState(outState, outPersistentState);
|
||||
}
|
||||
|
||||
public void setupActionBar() {
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
if (getFile() != null) {
|
||||
|
@ -97,14 +124,6 @@ public class TrackActivity extends TabActivity {
|
|||
}
|
||||
actionBar.setElevation(AndroidUtils.dpToPx(app, 4f));
|
||||
}
|
||||
if (intent.hasExtra(OPEN_POINTS_TAB)
|
||||
|| (savedInstanceState != null && savedInstanceState.getBoolean(OPEN_POINTS_TAB, false))) {
|
||||
openPointsTab = true;
|
||||
}
|
||||
if (intent.hasExtra(OPEN_TRACKS_LIST)) {
|
||||
openTracksList = true;
|
||||
}
|
||||
setContentView(R.layout.track_content);
|
||||
}
|
||||
|
||||
public TrackDisplayHelper getDisplayHelper() {
|
||||
|
|
168
OsmAnd/src/net/osmand/plus/dialogs/RenameFileBottomSheet.java
Normal file
168
OsmAnd/src/net/osmand/plus/dialogs/RenameFileBottomSheet.java
Normal file
|
@ -0,0 +1,168 @@
|
|||
package net.osmand.plus.dialogs;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.FileUtils.RenameCallback;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.SQLiteTileSource;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static net.osmand.FileUtils.ILLEGAL_FILE_NAME_CHARACTERS;
|
||||
import static net.osmand.FileUtils.renameFile;
|
||||
import static net.osmand.FileUtils.renameGpxFile;
|
||||
import static net.osmand.FileUtils.renameSQLiteFile;
|
||||
|
||||
public class RenameFileBottomSheet extends MenuBottomSheetDialogFragment {
|
||||
|
||||
private static final Log LOG = PlatformUtil.getLog(RenameFileBottomSheet.class);
|
||||
private static final String TAG = RenameFileBottomSheet.class.getName();
|
||||
private static final String SOURCE_FILE_NAME_KEY = "source_file_name_key";
|
||||
private static final String SELECTED_FILE_NAME_KEY = "selected_file_name_key";
|
||||
|
||||
private OsmandApplication app;
|
||||
|
||||
private TextInputEditText editText;
|
||||
private TextInputLayout nameTextBox;
|
||||
|
||||
private File file;
|
||||
private String selectedFileName;
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
app = requiredMyApplication();
|
||||
if (savedInstanceState != null) {
|
||||
String path = savedInstanceState.getString(SOURCE_FILE_NAME_KEY);
|
||||
if (!Algorithms.isEmpty(path)) {
|
||||
file = new File(path);
|
||||
}
|
||||
selectedFileName = savedInstanceState.getString(SELECTED_FILE_NAME_KEY);
|
||||
}
|
||||
items.add(new TitleItem(getString(R.string.shared_string_rename)));
|
||||
|
||||
View view = UiUtilities.getInflater(app, nightMode).inflate(R.layout.track_name_edit_text, null);
|
||||
nameTextBox = view.findViewById(R.id.name_text_box);
|
||||
nameTextBox.setBoxBackgroundColorResource(nightMode ? R.color.list_background_color_dark : R.color.activity_background_color_light);
|
||||
nameTextBox.setHint(AndroidUtils.addColon(app, R.string.shared_string_name));
|
||||
ColorStateList colorStateList = ColorStateList.valueOf(ContextCompat
|
||||
.getColor(app, nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light));
|
||||
nameTextBox.setDefaultHintTextColor(colorStateList);
|
||||
|
||||
editText = view.findViewById(R.id.name_edit_text);
|
||||
editText.setText(selectedFileName != null ? selectedFileName : Algorithms.getFileNameWithoutExtension(file));
|
||||
editText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
updateFileName(s.toString());
|
||||
}
|
||||
});
|
||||
|
||||
BaseBottomSheetItem editFolderName = new BaseBottomSheetItem.Builder()
|
||||
.setCustomView(view)
|
||||
.create();
|
||||
items.add(editFolderName);
|
||||
}
|
||||
|
||||
private void updateFileName(String name) {
|
||||
if (!Algorithms.isEmpty(name) && ILLEGAL_FILE_NAME_CHARACTERS.matcher(name).find()) {
|
||||
nameTextBox.setError(getString(R.string.file_name_containes_illegal_char));
|
||||
} else {
|
||||
selectedFileName = name;
|
||||
nameTextBox.setError(null);
|
||||
}
|
||||
updateBottomButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRightBottomButtonEnabled() {
|
||||
return nameTextBox.getError() == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putString(SOURCE_FILE_NAME_KEY, file.getAbsolutePath());
|
||||
outState.putString(SELECTED_FILE_NAME_KEY, selectedFileName);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRightBottomButtonClick() {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
AndroidUtils.hideSoftKeyboard(activity, editText);
|
||||
}
|
||||
File dest;
|
||||
int index = file.getName().lastIndexOf('.');
|
||||
String ext = index == -1 ? "" : file.getName().substring(index);
|
||||
if (SQLiteTileSource.EXT.equals(ext)) {
|
||||
dest = renameSQLiteFile(app, file, selectedFileName + ext, null);
|
||||
} else if (IndexConstants.GPX_FILE_EXT.equals(ext)) {
|
||||
dest = renameGpxFile(app, file, selectedFileName + ext, false, null);
|
||||
} else {
|
||||
dest = renameFile(app, file, selectedFileName + ext, false, null);
|
||||
}
|
||||
if (dest != null) {
|
||||
Fragment fragment = getTargetFragment();
|
||||
if (fragment instanceof RenameCallback) {
|
||||
RenameCallback listener = (RenameCallback) fragment;
|
||||
listener.renamedTo(dest);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDismissButtonTextId() {
|
||||
return R.string.shared_string_cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getRightBottomButtonTextId() {
|
||||
return R.string.shared_string_save;
|
||||
}
|
||||
|
||||
public static void showInstance(@NonNull FragmentManager fragmentManager, @Nullable Fragment target,
|
||||
@NonNull File file, boolean usedOnMap) {
|
||||
if (file.exists() && !fragmentManager.isStateSaved()
|
||||
&& fragmentManager.findFragmentByTag(RenameFileBottomSheet.TAG) == null) {
|
||||
RenameFileBottomSheet fragment = new RenameFileBottomSheet();
|
||||
fragment.file = file;
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setTargetFragment(target, 0);
|
||||
fragment.show(fragmentManager, RenameFileBottomSheet.TAG);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import androidx.appcompat.view.ActionMode;
|
|||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.Collator;
|
||||
|
@ -74,7 +75,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
public class LocalIndexesFragment extends OsmandExpandableListFragment implements DownloadEvents,
|
||||
OnMapSourceUpdateListener {
|
||||
OnMapSourceUpdateListener, RenameCallback {
|
||||
private LoadLocalIndexTask asyncLoader;
|
||||
private Map<String, IndexItem> filesToUpdate = new HashMap<>();
|
||||
private LocalIndexesAdapter listAdapter;
|
||||
|
@ -141,13 +142,11 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
|
|||
|
||||
private boolean performBasicOperation(int resId, final LocalIndexInfo info) {
|
||||
if (resId == R.string.shared_string_rename) {
|
||||
FileUtils.renameFile(getActivity(), new File(info.getPathToData()), new RenameCallback() {
|
||||
|
||||
@Override
|
||||
public void renamedTo(File file) {
|
||||
getDownloadActivity().reloadLocalIndexes();
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
File file = new File(info.getPathToData());
|
||||
FileUtils.renameFile(activity, file, this, false);
|
||||
}
|
||||
});
|
||||
} else if (resId == R.string.clear_tile_data) {
|
||||
AlertDialog.Builder confirm = new AlertDialog.Builder(getActivity());
|
||||
confirm.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
|
||||
|
@ -188,7 +187,19 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
|
|||
|
||||
@Override
|
||||
public void onMapSourceUpdated() {
|
||||
getDownloadActivity().reloadLocalIndexes();
|
||||
reloadLocalIndexes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renamedTo(File file) {
|
||||
reloadLocalIndexes();
|
||||
}
|
||||
|
||||
private void reloadLocalIndexes() {
|
||||
DownloadActivity activity = getDownloadActivity();
|
||||
if (activity != null) {
|
||||
activity.reloadLocalIndexes();
|
||||
}
|
||||
}
|
||||
|
||||
public class LoadLocalIndexTask extends AsyncTask<Void, LocalIndexInfo, List<LocalIndexInfo>>
|
||||
|
@ -666,7 +677,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
|
|||
|
||||
public void localOptionsMenu(final int itemId) {
|
||||
if (itemId == R.string.shared_string_refresh) {
|
||||
getDownloadActivity().reloadLocalIndexes();
|
||||
reloadLocalIndexes();
|
||||
} else if (itemId == R.string.shared_string_delete) {
|
||||
openSelectionMode(itemId, R.drawable.ic_action_delete_dark,
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
|
|
@ -93,18 +93,20 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
protected void buildNearestPoiRow(View view) {
|
||||
}
|
||||
|
||||
private void buildRow(View view, int iconId, String text, String textPrefix,
|
||||
private void buildRow(View view, int iconId, String text, String textPrefix, String socialMediaUrl,
|
||||
boolean collapsable, final CollapsableView collapsableView,
|
||||
int textColor, boolean isWiki, boolean isText, boolean needLinks,
|
||||
boolean isPhoneNumber, boolean isUrl, boolean matchWidthDivider, int textLinesLimit) {
|
||||
buildRow(view, iconId == 0 ? null : getRowIcon(iconId), text, textPrefix, collapsable, collapsableView, textColor,
|
||||
buildRow(view, iconId == 0 ? null : getRowIcon(iconId), text, textPrefix, socialMediaUrl,
|
||||
collapsable, collapsableView, textColor,
|
||||
isWiki, isText, needLinks, isPhoneNumber, isUrl, matchWidthDivider, textLinesLimit);
|
||||
}
|
||||
|
||||
protected void buildRow(final View view, Drawable icon, final String text, final String textPrefix,
|
||||
boolean collapsable, final CollapsableView collapsableView,
|
||||
int textColor, boolean isWiki, boolean isText, boolean needLinks,
|
||||
boolean isPhoneNumber, boolean isUrl, boolean matchWidthDivider, int textLinesLimit) {
|
||||
final String socialMediaUrl, boolean collapsable,
|
||||
final CollapsableView collapsableView, int textColor, boolean isWiki,
|
||||
boolean isText, boolean needLinks, boolean isPhoneNumber, boolean isUrl,
|
||||
boolean matchWidthDivider, int textLinesLimit) {
|
||||
|
||||
if (!isFirstRow()) {
|
||||
buildRowDivider(view);
|
||||
|
@ -312,8 +314,9 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
WikipediaArticleWikiLinkFragment.showInstance(mapActivity.getSupportFragmentManager(), text);
|
||||
}
|
||||
} else {
|
||||
String uri = socialMediaUrl == null ? text : socialMediaUrl;
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(text));
|
||||
intent.setData(Uri.parse(uri));
|
||||
v.getContext().startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
@ -366,6 +369,7 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
continue;
|
||||
}
|
||||
|
||||
String socialMediaUrl = null;
|
||||
String textPrefix = "";
|
||||
CollapsableView collapsableView = null;
|
||||
boolean collapsable = false;
|
||||
|
@ -397,6 +401,11 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
|
||||
if (vl.startsWith("http://") || vl.startsWith("https://") || vl.startsWith("HTTP://") || vl.startsWith("HTTPS://")) {
|
||||
isUrl = true;
|
||||
} else {
|
||||
socialMediaUrl = getSocialMediaUrl(key, vl);
|
||||
if (socialMediaUrl != null) {
|
||||
isUrl = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pType != null && !pType.isText()) {
|
||||
|
@ -557,16 +566,16 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
AmenityInfoRow row;
|
||||
if (isDescription) {
|
||||
row = new AmenityInfoRow(key, R.drawable.ic_action_note_dark, textPrefix,
|
||||
vl, collapsable, collapsableView, 0, false, true,
|
||||
true, 0, "", false, false, matchWidthDivider, 0);
|
||||
vl, null, collapsable, collapsableView, 0, false,
|
||||
true, true, 0, "", false, false, matchWidthDivider, 0);
|
||||
} else if (icon != null) {
|
||||
row = new AmenityInfoRow(key, icon, textPrefix, vl, collapsable, collapsableView,
|
||||
textColor, isWiki, isText, needLinks, poiTypeOrder, poiTypeKeyName,
|
||||
isPhoneNumber, isUrl, matchWidthDivider, 0);
|
||||
row = new AmenityInfoRow(key, icon, textPrefix, vl, socialMediaUrl, collapsable,
|
||||
collapsableView, textColor, isWiki, isText, needLinks, poiTypeOrder,
|
||||
poiTypeKeyName, isPhoneNumber, isUrl, matchWidthDivider, 0);
|
||||
} else {
|
||||
row = new AmenityInfoRow(key, iconId, textPrefix, vl, collapsable, collapsableView,
|
||||
textColor, isWiki, isText, needLinks, poiTypeOrder, poiTypeKeyName,
|
||||
isPhoneNumber, isUrl, matchWidthDivider, 0);
|
||||
row = new AmenityInfoRow(key, iconId, textPrefix, vl, socialMediaUrl, collapsable,
|
||||
collapsableView, textColor, isWiki, isText, needLinks, poiTypeOrder,
|
||||
poiTypeKeyName, isPhoneNumber, isUrl, matchWidthDivider, 0);
|
||||
}
|
||||
if (isDescription) {
|
||||
descriptions.add(row);
|
||||
|
@ -613,8 +622,11 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
}
|
||||
boolean cuisineOrDish = categoryName.equals(Amenity.CUISINE) || categoryName.equals(Amenity.DISH);
|
||||
CollapsableView collapsableView = getPoiTypeCollapsableView(view.getContext(), true, categoryTypes, true, cuisineOrDish ? cuisineRow : null);
|
||||
infoRows.add(new AmenityInfoRow(poiAdditionalCategoryName, icon, pType.getPoiAdditionalCategoryTranslation(), sb.toString(), true, collapsableView,
|
||||
0, false, false, false, pType.getOrder(), pType.getKeyName(), false, false, false, 1));
|
||||
infoRows.add(new AmenityInfoRow(poiAdditionalCategoryName, icon,
|
||||
pType.getPoiAdditionalCategoryTranslation(), sb.toString(), null,
|
||||
true, collapsableView, 0, false, false,
|
||||
false, pType.getOrder(), pType.getKeyName(), false,
|
||||
false, false, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -629,8 +641,10 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
}
|
||||
sb.append(pt.getTranslation());
|
||||
}
|
||||
infoRows.add(new AmenityInfoRow(poiCategory.getKeyName(), icon, poiCategory.getTranslation(), sb.toString(), true, collapsableView,
|
||||
0, false, false, false, 40, poiCategory.getKeyName(), false, false, false, 1));
|
||||
infoRows.add(new AmenityInfoRow(poiCategory.getKeyName(), icon,
|
||||
poiCategory.getTranslation(), sb.toString(), null, true,
|
||||
collapsableView, 0, false, false, false, 40,
|
||||
poiCategory.getKeyName(), false, false, false, 1));
|
||||
}
|
||||
|
||||
Collections.sort(infoRows, new Comparator<AmenityInfoRow>() {
|
||||
|
@ -670,7 +684,8 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
|
||||
if (processNearestWiki() && nearestWiki.size() > 0) {
|
||||
AmenityInfoRow wikiInfo = new AmenityInfoRow(
|
||||
"nearest_wiki", R.drawable.ic_plugin_wikipedia, null, app.getString(R.string.wiki_around) + " (" + nearestWiki.size() + ")", true,
|
||||
"nearest_wiki", R.drawable.ic_plugin_wikipedia, null, app.getString(R.string.wiki_around) + " (" + nearestWiki.size() + ")",
|
||||
null, true,
|
||||
getCollapsableView(view.getContext(), true, nearestWiki),
|
||||
0, false, false, false, 1000, null, false, false, false, 0);
|
||||
buildAmenityRow(view, wikiInfo);
|
||||
|
@ -678,7 +693,8 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
|
||||
if (processNearestPoi() && nearestPoi.size() > 0) {
|
||||
AmenityInfoRow poiInfo = new AmenityInfoRow(
|
||||
"nearest_poi", AmenityMenuController.getRightIconId(amenity), null, app.getString(R.string.speak_poi) + " (" + nearestPoi.size() + ")", true,
|
||||
"nearest_poi", AmenityMenuController.getRightIconId(amenity), null, app.getString(R.string.speak_poi) + " (" + nearestPoi.size() + ")",
|
||||
null, true,
|
||||
getCollapsableView(view.getContext(), true, nearestPoi),
|
||||
0, false, false, false, 1000, null, false, false, false, 0);
|
||||
buildAmenityRow(view, poiInfo);
|
||||
|
@ -783,12 +799,14 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
|
||||
public void buildAmenityRow(View view, AmenityInfoRow info) {
|
||||
if (info.icon != null) {
|
||||
buildRow(view, info.icon, info.text, info.textPrefix, info.collapsable, info.collapsableView,
|
||||
info.textColor, info.isWiki, info.isText, info.needLinks, info.isPhoneNumber,
|
||||
buildRow(view, info.icon, info.text, info.textPrefix, info.socialMediaUrl,
|
||||
info.collapsable, info.collapsableView, info.textColor, info.isWiki, info.isText,
|
||||
info.needLinks, info.isPhoneNumber,
|
||||
info.isUrl, info.matchWidthDivider, info.textLinesLimit);
|
||||
} else {
|
||||
buildRow(view, info.iconId, info.text, info.textPrefix, info.collapsable, info.collapsableView,
|
||||
info.textColor, info.isWiki, info.isText, info.needLinks, info.isPhoneNumber,
|
||||
buildRow(view, info.iconId, info.text, info.textPrefix, info.socialMediaUrl,
|
||||
info.collapsable, info.collapsableView, info.textColor, info.isWiki, info.isText,
|
||||
info.needLinks, info.isPhoneNumber,
|
||||
info.isUrl, info.matchWidthDivider, info.textLinesLimit);
|
||||
}
|
||||
}
|
||||
|
@ -892,12 +910,45 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
return new CollapsableView(view, this, collapsed);
|
||||
}
|
||||
|
||||
private String getSocialMediaUrl(String key, String value) {
|
||||
// Remove leading and closing slashes
|
||||
StringBuilder sb = new StringBuilder(value.trim());
|
||||
if (sb.charAt(0) == '/') {
|
||||
sb.deleteCharAt(0);
|
||||
}
|
||||
int lastIdx = sb.length() - 1;
|
||||
if (sb.charAt(lastIdx) == '/') {
|
||||
sb.deleteCharAt(lastIdx);
|
||||
}
|
||||
|
||||
// It cannot be username
|
||||
if (sb.indexOf("/") != -1) {
|
||||
return "https://" + value;
|
||||
}
|
||||
|
||||
Map<String, String> urls = new HashMap<>(7);
|
||||
urls.put("facebook", "https://facebook.com/%s");
|
||||
urls.put("vk", "https://vk.com/%s");
|
||||
urls.put("instagram", "https://instagram.com/%s");
|
||||
urls.put("twitter", "https://twitter.com/%s");
|
||||
urls.put("ok", "https://ok.ru/%s");
|
||||
urls.put("telegram", "https://t.me/%s");
|
||||
urls.put("flickr", "https://flickr.com/%s");
|
||||
|
||||
if (urls.containsKey(key)) {
|
||||
return String.format(urls.get(key), value);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AmenityInfoRow {
|
||||
private String key;
|
||||
private Drawable icon;
|
||||
private int iconId;
|
||||
private String textPrefix;
|
||||
private String text;
|
||||
private String socialMediaUrl;
|
||||
private CollapsableView collapsableView;
|
||||
private boolean collapsable;
|
||||
private int textColor;
|
||||
|
@ -912,14 +963,16 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
private int textLinesLimit;
|
||||
|
||||
public AmenityInfoRow(String key, Drawable icon, String textPrefix, String text,
|
||||
boolean collapsable, CollapsableView collapsableView,
|
||||
int textColor, boolean isWiki, boolean isText, boolean needLinks,
|
||||
int order, String name, boolean isPhoneNumber, boolean isUrl,
|
||||
String socialMediaUrl, boolean collapsable,
|
||||
CollapsableView collapsableView, int textColor, boolean isWiki,
|
||||
boolean isText, boolean needLinks, int order, String name,
|
||||
boolean isPhoneNumber, boolean isUrl,
|
||||
boolean matchWidthDivider, int textLinesLimit) {
|
||||
this.key = key;
|
||||
this.icon = icon;
|
||||
this.textPrefix = textPrefix;
|
||||
this.text = text;
|
||||
this.socialMediaUrl = socialMediaUrl;
|
||||
this.collapsable = collapsable;
|
||||
this.collapsableView = collapsableView;
|
||||
this.textColor = textColor;
|
||||
|
@ -935,14 +988,16 @@ public class AmenityMenuBuilder extends MenuBuilder {
|
|||
}
|
||||
|
||||
public AmenityInfoRow(String key, int iconId, String textPrefix, String text,
|
||||
boolean collapsable, CollapsableView collapsableView,
|
||||
int textColor, boolean isWiki, boolean isText, boolean needLinks,
|
||||
int order, String name, boolean isPhoneNumber, boolean isUrl,
|
||||
String socialMediaUrl, boolean collapsable,
|
||||
CollapsableView collapsableView, int textColor, boolean isWiki,
|
||||
boolean isText, boolean needLinks, int order, String name,
|
||||
boolean isPhoneNumber, boolean isUrl,
|
||||
boolean matchWidthDivider, int textLinesLimit) {
|
||||
this.key = key;
|
||||
this.iconId = iconId;
|
||||
this.textPrefix = textPrefix;
|
||||
this.text = text;
|
||||
this.socialMediaUrl = socialMediaUrl;
|
||||
this.collapsable = collapsable;
|
||||
this.collapsableView = collapsableView;
|
||||
this.textColor = textColor;
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.os.Bundle;
|
|||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -16,13 +17,16 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -35,12 +39,17 @@ import net.osmand.plus.base.bottomsheetmenu.HorizontalRecyclerBottomSheetItem;
|
|||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
|
||||
import net.osmand.plus.measurementtool.adapter.FolderListAdapter;
|
||||
import net.osmand.plus.myplaces.MoveGpxFileBottomSheet;
|
||||
import net.osmand.plus.myplaces.MoveGpxFileBottomSheet.OnTrackFileMoveListener;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDialogFragment {
|
||||
public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDialogFragment implements OnTrackFileMoveListener {
|
||||
|
||||
public static final String TAG = SaveAsNewTrackBottomSheetDialogFragment.class.getSimpleName();
|
||||
private static final Log LOG = PlatformUtil.getLog(SaveAsNewTrackBottomSheetDialogFragment.class);
|
||||
|
@ -52,19 +61,24 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
|
|||
public static final String SOURCE_FOLDER_NAME_KEY = "source_folder_name_key";
|
||||
public static final String SHOW_SIMPLIFIED_BUTTON_KEY = "show_simplified_button_key";
|
||||
|
||||
private boolean showOnMap;
|
||||
private boolean simplifiedTrack;
|
||||
private OsmandApplication app;
|
||||
|
||||
private FolderListAdapter adapter;
|
||||
private TextInputLayout nameTextBox;
|
||||
private RecyclerView recyclerView;
|
||||
|
||||
private String fileName;
|
||||
private String sourceFileName;
|
||||
private String sourceFolderName;
|
||||
private String folderName;
|
||||
private boolean showOnMap;
|
||||
private boolean simplifiedTrack;
|
||||
private boolean rightButtonEnabled = true;
|
||||
private boolean showSimplifiedButton = true;
|
||||
private TextInputLayout nameTextBox;
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
OsmandApplication app = getMyApplication();
|
||||
app = getMyApplication();
|
||||
if (app == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -118,12 +132,30 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
|
|||
|
||||
items.add(new DividerSpaceItem(app, contentPaddingSmall));
|
||||
|
||||
FolderListAdapter adapter = new FolderListAdapter(app, nightMode, folderName);
|
||||
View selectFolderView = View.inflate(UiUtilities.getThemedContext(app, nightMode), R.layout.select_folder_row, null);
|
||||
selectFolderView.findViewById(R.id.select_folder_button).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
File dest = getFile(app, folderName, fileName);
|
||||
MoveGpxFileBottomSheet.showInstance(activity.getSupportFragmentManager(),
|
||||
SaveAsNewTrackBottomSheetDialogFragment.this, dest.getAbsolutePath(), usedOnMap);
|
||||
}
|
||||
}
|
||||
});
|
||||
BaseBottomSheetItem selectFolderItem = new BaseBottomSheetItem.Builder()
|
||||
.setCustomView(selectFolderView)
|
||||
.create();
|
||||
items.add(selectFolderItem);
|
||||
|
||||
adapter = new FolderListAdapter(app, nightMode, folderName);
|
||||
adapter.setFolders(getFolders());
|
||||
if (adapter.getItemCount() > 0) {
|
||||
adapter.setListener(createFolderSelectListener());
|
||||
View view = View.inflate(UiUtilities.getThemedContext(app, nightMode), R.layout.bottom_sheet_item_recyclerview,
|
||||
null);
|
||||
View recyclerView = view.findViewById(R.id.recycler_view);
|
||||
recyclerView = view.findViewById(R.id.recycler_view);
|
||||
recyclerView.setPadding(contentPaddingHalf, 0, contentPaddingHalf, 0);
|
||||
BaseBottomSheetItem scrollItem = new HorizontalRecyclerBottomSheetItem.Builder()
|
||||
.setAdapter(adapter)
|
||||
|
@ -284,7 +316,7 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
|
|||
}
|
||||
}
|
||||
}
|
||||
GPXUtilities.GPXFile gpxFile = GPXUtilities.loadGPXFile(dest);
|
||||
GPXFile gpxFile = GPXUtilities.loadGPXFile(dest);
|
||||
if (gpxFile.error != null) {
|
||||
return;
|
||||
}
|
||||
|
@ -331,6 +363,38 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
|
|||
return false;
|
||||
}
|
||||
|
||||
private List<String> getFolders() {
|
||||
List<File> dirs = new ArrayList<>();
|
||||
File gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
|
||||
dirs.add(gpxDir);
|
||||
Algorithms.collectDirs(gpxDir, dirs);
|
||||
List<String> dirItems = new ArrayList<>();
|
||||
for (File dir : dirs) {
|
||||
dirItems.add(dir.getName());
|
||||
}
|
||||
return dirItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileMove(@NonNull File src, @NonNull File dest) {
|
||||
File destFolder = dest.getParentFile();
|
||||
if (destFolder != null) {
|
||||
folderName = destFolder.getName();
|
||||
boolean newFolder = destFolder.mkdirs();
|
||||
List<String> folders = getFolders();
|
||||
if (newFolder) {
|
||||
adapter.setFolders(folders);
|
||||
}
|
||||
adapter.setSelectedFolderName(folderName);
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
int position = folders.indexOf(folderName);
|
||||
if (position != -1) {
|
||||
recyclerView.scrollToPosition(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBgColorId() {
|
||||
return nightMode ? R.color.activity_background_color_dark : R.color.list_background_color_light;
|
||||
|
|
|
@ -15,14 +15,11 @@ import androidx.core.content.ContextCompat;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class FolderListAdapter extends RecyclerView.Adapter<FolderListAdapter.GroupsViewHolder> {
|
||||
|
@ -38,24 +35,15 @@ public class FolderListAdapter extends RecyclerView.Adapter<FolderListAdapter.Gr
|
|||
this.app = app;
|
||||
this.nightMode = nightMode;
|
||||
selectedItemName = folderName;
|
||||
fillGroups();
|
||||
}
|
||||
|
||||
private void fillGroups() {
|
||||
public void setSelectedFolderName(String folderName) {
|
||||
this.selectedItemName = folderName;
|
||||
}
|
||||
|
||||
public void setFolders(List<String> folders) {
|
||||
items.clear();
|
||||
items.addAll(getFolders());
|
||||
}
|
||||
|
||||
private Collection<? extends String> getFolders() {
|
||||
List<File> dirs = new ArrayList<>();
|
||||
File gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
|
||||
dirs.add(gpxDir);
|
||||
Algorithms.collectDirs(gpxDir, dirs);
|
||||
List<String> dirItems = new ArrayList<>();
|
||||
for (File dir : dirs) {
|
||||
dirItems.add(dir.getName());
|
||||
}
|
||||
return dirItems;
|
||||
items.addAll(folders);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
package net.osmand.plus.myplaces;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static net.osmand.FileUtils.ILLEGAL_PATH_NAME_CHARACTERS;
|
||||
|
||||
public class AddNewTrackFolderBottomSheet extends MenuBottomSheetDialogFragment {
|
||||
|
||||
public static final String TAG = AddNewTrackFolderBottomSheet.class.getName();
|
||||
private static final Log LOG = PlatformUtil.getLog(AddNewTrackFolderBottomSheet.class);
|
||||
private static final String FOLDER_NAME_KEY = "folder_name_key";
|
||||
|
||||
private OsmandApplication app;
|
||||
|
||||
private TextInputEditText editText;
|
||||
private TextInputLayout nameTextBox;
|
||||
|
||||
private String folderName;
|
||||
private boolean rightButtonEnabled = true;
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
app = requiredMyApplication();
|
||||
if (savedInstanceState != null) {
|
||||
folderName = savedInstanceState.getString(FOLDER_NAME_KEY);
|
||||
} else if (Algorithms.isEmpty(folderName)) {
|
||||
folderName = app.getAppPath(IndexConstants.GPX_INDEX_DIR).getName();
|
||||
}
|
||||
items.add(new TitleItem(getString(R.string.add_new_folder)));
|
||||
|
||||
View view = UiUtilities.getInflater(app, nightMode).inflate(R.layout.track_name_edit_text, null);
|
||||
nameTextBox = view.findViewById(R.id.name_text_box);
|
||||
nameTextBox.setBoxBackgroundColorResource(nightMode ? R.color.list_background_color_dark : R.color.activity_background_color_light);
|
||||
nameTextBox.setHint(AndroidUtils.addColon(app, R.string.shared_string_name));
|
||||
ColorStateList colorStateList = ColorStateList.valueOf(ContextCompat
|
||||
.getColor(app, nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light));
|
||||
nameTextBox.setDefaultHintTextColor(colorStateList);
|
||||
editText = view.findViewById(R.id.name_edit_text);
|
||||
editText.setText(folderName);
|
||||
editText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
updateFileNameFromEditText(s.toString());
|
||||
}
|
||||
});
|
||||
BaseBottomSheetItem editFolderName = new BaseBottomSheetItem.Builder()
|
||||
.setCustomView(view)
|
||||
.create();
|
||||
items.add(editFolderName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRightBottomButtonEnabled() {
|
||||
return rightButtonEnabled;
|
||||
}
|
||||
|
||||
private void updateFileNameFromEditText(String name) {
|
||||
rightButtonEnabled = false;
|
||||
if (ILLEGAL_PATH_NAME_CHARACTERS.matcher(name).find()) {
|
||||
nameTextBox.setError(getString(R.string.file_name_containes_illegal_char));
|
||||
} else if (Algorithms.isEmpty(name.trim())) {
|
||||
nameTextBox.setError(getString(R.string.empty_filename));
|
||||
} else {
|
||||
File destFolder = new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), name);
|
||||
if (destFolder.exists()) {
|
||||
nameTextBox.setError(getString(R.string.file_with_name_already_exist));
|
||||
} else {
|
||||
nameTextBox.setError(null);
|
||||
folderName = name;
|
||||
rightButtonEnabled = true;
|
||||
}
|
||||
}
|
||||
updateBottomButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putString(FOLDER_NAME_KEY, folderName);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRightBottomButtonClick() {
|
||||
AndroidUtils.hideSoftKeyboard(requireActivity(), editText);
|
||||
Fragment fragment = getTargetFragment();
|
||||
if (fragment instanceof OnTrackFolderAddListener) {
|
||||
OnTrackFolderAddListener listener = (OnTrackFolderAddListener) fragment;
|
||||
listener.onTrackFolderAdd(folderName);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDismissButtonTextId() {
|
||||
return R.string.shared_string_cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getRightBottomButtonTextId() {
|
||||
return R.string.shared_string_add;
|
||||
}
|
||||
|
||||
public interface OnTrackFolderAddListener {
|
||||
|
||||
void onTrackFolderAdd(String folderName);
|
||||
}
|
||||
|
||||
public static void showInstance(@NonNull FragmentManager fragmentManager, @Nullable Fragment target,
|
||||
@NonNull String folderName, boolean usedOnMap) {
|
||||
try {
|
||||
if (!fragmentManager.isStateSaved() && fragmentManager.findFragmentByTag(AddNewTrackFolderBottomSheet.TAG) == null) {
|
||||
AddNewTrackFolderBottomSheet fragment = new AddNewTrackFolderBottomSheet();
|
||||
fragment.folderName = folderName;
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setTargetFragment(target, 0);
|
||||
fragment.show(fragmentManager, AddNewTrackFolderBottomSheet.TAG);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error("showInstance", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.Collator;
|
||||
|
@ -81,11 +82,12 @@ import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
|
|||
import net.osmand.plus.helpers.enums.TracksSortByMode;
|
||||
import net.osmand.plus.mapmarkers.CoordinateInputDialogFragment;
|
||||
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
||||
import net.osmand.plus.myplaces.MoveGpxFileBottomSheet.OnTrackFileMoveListener;
|
||||
import net.osmand.plus.osmedit.OsmEditingPlugin;
|
||||
import net.osmand.plus.osmedit.oauth.OsmOAuthHelper.OsmAuthorizationListener;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.widgets.popup.PopUpMenuItem;
|
||||
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
|
||||
import net.osmand.plus.widgets.popup.PopUpMenuItem;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
|
@ -105,6 +107,7 @@ import java.util.regex.Pattern;
|
|||
|
||||
import static net.osmand.plus.GpxSelectionHelper.CURRENT_TRACK;
|
||||
import static net.osmand.plus.myplaces.FavoritesActivity.GPX_TAB;
|
||||
import static net.osmand.plus.myplaces.FavoritesActivity.OPEN_GPX_REQUEST;
|
||||
import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID;
|
||||
import static net.osmand.util.Algorithms.capitalizeFirstLetter;
|
||||
import static net.osmand.util.Algorithms.collectDirs;
|
||||
|
@ -113,9 +116,8 @@ import static net.osmand.util.Algorithms.objectEquals;
|
|||
import static net.osmand.util.Algorithms.removeAllFiles;
|
||||
|
||||
public class AvailableGPXFragment extends OsmandExpandableListFragment implements
|
||||
FavoritesFragmentStateHolder, OsmAuthorizationListener {
|
||||
FavoritesFragmentStateHolder, OsmAuthorizationListener, OnTrackFileMoveListener, RenameCallback {
|
||||
|
||||
public static final Pattern ILLEGAL_PATH_NAME_CHARACTERS = Pattern.compile("[?:\"*|<>]");
|
||||
public static final int SEARCH_ID = -1;
|
||||
// public static final int ACTION_ID = 0;
|
||||
// protected static final int DELETE_ACTION_ID = 1;
|
||||
|
@ -426,7 +428,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
|
|||
newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, f.getAbsolutePath());
|
||||
}
|
||||
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
a.startActivity(newIntent);
|
||||
a.startActivityForResult(newIntent, OPEN_GPX_REQUEST);
|
||||
}
|
||||
|
||||
public void reloadTracks() {
|
||||
|
@ -434,6 +436,10 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
|
|||
asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
|
||||
}
|
||||
|
||||
public void resetTracksLoader() {
|
||||
asyncLoader = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, @NonNull MenuInflater inflater) {
|
||||
menu.clear();
|
||||
|
@ -790,129 +796,10 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
|
|||
}
|
||||
|
||||
private void moveGpx(final GpxInfo info) {
|
||||
|
||||
final ContextMenuAdapter menuAdapter = new ContextMenuAdapter(app);
|
||||
ContextMenuItem.ItemBuilder itemBuilder = new ContextMenuItem.ItemBuilder();
|
||||
|
||||
final List<File> dirs = new ArrayList<>();
|
||||
collectDirs(app.getAppPath(IndexConstants.GPX_INDEX_DIR), dirs, info.file.getParentFile());
|
||||
if (!info.file.getParentFile().equals(app.getAppPath(IndexConstants.GPX_INDEX_DIR))) {
|
||||
dirs.add(0, app.getAppPath(IndexConstants.GPX_INDEX_DIR));
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
MoveGpxFileBottomSheet.showInstance(activity.getSupportFragmentManager(), this, info.file.getAbsolutePath(), false);
|
||||
}
|
||||
String gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR).getPath();
|
||||
int i = 0;
|
||||
for (File dir : dirs) {
|
||||
String dirName = dir.getPath();
|
||||
if (dirName.startsWith(gpxDir)) {
|
||||
if (dirName.length() == gpxDir.length()) {
|
||||
dirName = dir.getName();
|
||||
} else {
|
||||
dirName = dirName.substring(gpxDir.length() + 1);
|
||||
}
|
||||
}
|
||||
menuAdapter.addItem(itemBuilder.setTitle(capitalizeFirstLetter(dirName))
|
||||
.setIcon(R.drawable.ic_action_folder_stroke).setTag(i).createItem());
|
||||
i++;
|
||||
}
|
||||
menuAdapter.addItem(itemBuilder.setTitleId(R.string.add_new_folder, app)
|
||||
.setIcon(R.drawable.ic_zoom_in).setTag(-1).createItem());
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
final ArrayAdapter<ContextMenuItem> listAdapter =
|
||||
menuAdapter.createListAdapter(getActivity(), app.getSettings().isLightContent());
|
||||
builder.setTitle(R.string.select_gpx_folder);
|
||||
builder.setAdapter(listAdapter, new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
ContextMenuItem item = menuAdapter.getItem(which);
|
||||
int index = item.getTag();
|
||||
if (index == -1) {
|
||||
Activity a = getActivity();
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(a);
|
||||
b.setTitle(R.string.add_new_folder);
|
||||
final EditText editText = new EditText(a);
|
||||
editText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
Editable text = editText.getText();
|
||||
if (text.length() >= 1) {
|
||||
if (ILLEGAL_PATH_NAME_CHARACTERS.matcher(text).find()) {
|
||||
editText.setError(app.getString(R.string.file_name_containes_illegal_char));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
int leftPadding = AndroidUtils.dpToPx(a, 24f);
|
||||
int topPadding = AndroidUtils.dpToPx(a, 4f);
|
||||
b.setView(editText, leftPadding, topPadding, leftPadding, topPadding);
|
||||
// Behaviour will be overwritten later;
|
||||
b.setPositiveButton(R.string.shared_string_ok, null);
|
||||
b.setNegativeButton(R.string.shared_string_cancel, null);
|
||||
final AlertDialog alertDialog = b.create();
|
||||
alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialog) {
|
||||
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String newName = editText.getText().toString();
|
||||
if (ILLEGAL_PATH_NAME_CHARACTERS.matcher(newName).find()) {
|
||||
Toast.makeText(app, R.string.file_name_containes_illegal_char,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
File destFolder = new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), newName);
|
||||
if (destFolder.exists()) {
|
||||
Toast.makeText(app, R.string.file_with_name_already_exists,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
} else if (destFolder.mkdirs()) {
|
||||
File dest = new File(destFolder, info.fileName);
|
||||
if (info.file.renameTo(dest)) {
|
||||
app.getGpxDbHelper().rename(info.file, dest);
|
||||
asyncLoader = new LoadGpxTask();
|
||||
asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
|
||||
} else {
|
||||
Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
} else {
|
||||
Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
alertDialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
alertDialog.show();
|
||||
} else {
|
||||
File dir = dirs.get(index);
|
||||
File dest = new File(dir, info.file.getName());
|
||||
if (dest.exists()) {
|
||||
Toast.makeText(app, R.string.file_with_name_already_exists, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
if (info.file.renameTo(dest)) {
|
||||
app.getGpxDbHelper().rename(info.file, dest);
|
||||
asyncLoader = new LoadGpxTask();
|
||||
asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
|
||||
} else {
|
||||
Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.shared_string_cancel, null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -938,6 +825,26 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
|
|||
app.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileMove(@NonNull File src, @NonNull File dest) {
|
||||
File destFolder = dest.getParentFile();
|
||||
if (destFolder != null && !destFolder.exists() && !destFolder.mkdirs()) {
|
||||
app.showToastMessage(R.string.file_can_not_be_moved);
|
||||
} else if (dest.exists()) {
|
||||
app.showToastMessage(R.string.file_with_name_already_exists);
|
||||
} else if (src.renameTo(dest)) {
|
||||
app.getGpxDbHelper().rename(src, dest);
|
||||
asyncLoader = new LoadGpxTask();
|
||||
asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
|
||||
} else {
|
||||
app.showToastMessage(R.string.file_can_not_be_moved);
|
||||
}
|
||||
}
|
||||
|
||||
public void renamedTo(File file) {
|
||||
reloadTracks();
|
||||
}
|
||||
|
||||
public class LoadGpxTask extends AsyncTask<Activity, GpxInfo, List<GpxInfo>> {
|
||||
|
||||
private List<GpxInfo> result;
|
||||
|
@ -1543,13 +1450,10 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
|
|||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
FileUtils.renameFile(getActivity(), gpxInfo.file, new RenameCallback() {
|
||||
@Override
|
||||
public void renamedTo(File file) {
|
||||
asyncLoader = new LoadGpxTask();
|
||||
asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
FileUtils.renameFile(activity, gpxInfo.file, AvailableGPXFragment.this, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.create()
|
||||
|
@ -1711,20 +1615,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
|
|||
GpxInfo item = allGpxAdapter.getChild(groupPosition, childPosition);
|
||||
|
||||
if (!selectionMode) {
|
||||
Intent newIntent = new Intent(getActivity(), getMyApplication().getAppCustomization().getTrackActivity());
|
||||
// causes wrong position caching: newIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
if (item.currentlyRecordingTrack) {
|
||||
newIntent.putExtra(TrackActivity.CURRENT_RECORDING, true);
|
||||
} else {
|
||||
newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, item.file.getAbsolutePath());
|
||||
}
|
||||
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(newIntent);
|
||||
// item.setExpanded(!item.isExpanded());
|
||||
// if (item.isExpanded()) {
|
||||
// descriptionLoader = new LoadLocalIndexDescriptionTask();
|
||||
// descriptionLoader.execute(item);
|
||||
// }
|
||||
openTrack(getActivity(), item.file);
|
||||
} else {
|
||||
if (!selectedItems.contains(item)) {
|
||||
selectedItems.add(item);
|
||||
|
|
|
@ -42,6 +42,8 @@ import java.lang.ref.WeakReference;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.plus.myplaces.TrackSegmentFragment.TRACK_DELETED_KEY;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -50,6 +52,7 @@ public class FavoritesActivity extends TabActivity {
|
|||
|
||||
private static final int OPEN_GPX_DOCUMENT_REQUEST = 1006;
|
||||
private static final int IMPORT_FAVOURITES_REQUEST = 1007;
|
||||
protected static final int OPEN_GPX_REQUEST = 1008;
|
||||
|
||||
public static final String TAB_ID = "selected_tab_id";
|
||||
|
||||
|
@ -152,6 +155,13 @@ public class FavoritesActivity extends TabActivity {
|
|||
if (data != null && data.getData() != null) {
|
||||
importHelper.handleGpxOrFavouritesImport(data.getData());
|
||||
}
|
||||
} else if (requestCode == OPEN_GPX_REQUEST && resultCode == Activity.RESULT_OK) {
|
||||
if (data != null && data.getBooleanExtra(TRACK_DELETED_KEY, false)) {
|
||||
AvailableGPXFragment gpxFragment = getGpxFragment();
|
||||
if (gpxFragment != null) {
|
||||
gpxFragment.resetTracksLoader();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
|
183
OsmAnd/src/net/osmand/plus/myplaces/MoveGpxFileBottomSheet.java
Normal file
183
OsmAnd/src/net/osmand/plus/myplaces/MoveGpxFileBottomSheet.java
Normal file
|
@ -0,0 +1,183 @@
|
|||
package net.osmand.plus.myplaces;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
|
||||
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerItem;
|
||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.plus.myplaces.AddNewTrackFolderBottomSheet.OnTrackFolderAddListener;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.util.Algorithms.capitalizeFirstLetter;
|
||||
import static net.osmand.util.Algorithms.collectDirs;
|
||||
|
||||
public class MoveGpxFileBottomSheet extends MenuBottomSheetDialogFragment implements OnTrackFolderAddListener {
|
||||
|
||||
public static final String TAG = MoveGpxFileBottomSheet.class.getSimpleName();
|
||||
private static final Log LOG = PlatformUtil.getLog(MoveGpxFileBottomSheet.class);
|
||||
private static final String FILE_PATH_KEY = "file_path_key";
|
||||
|
||||
private OsmandApplication app;
|
||||
private String filePath;
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
app = requiredMyApplication();
|
||||
if (savedInstanceState != null) {
|
||||
filePath = savedInstanceState.getString(FILE_PATH_KEY);
|
||||
}
|
||||
if (filePath == null) {
|
||||
return;
|
||||
}
|
||||
final File file = new File(filePath);
|
||||
final File fileDir = file.getParentFile();
|
||||
|
||||
BaseBottomSheetItem titleItem = new BottomSheetItemWithDescription.Builder()
|
||||
.setDescription(getString(R.string.select_folder_descr))
|
||||
.setTitle(getString(R.string.shared_string_folders))
|
||||
.setLayoutId(R.layout.bottom_sheet_item_title_with_description)
|
||||
.create();
|
||||
items.add(titleItem);
|
||||
|
||||
View addNewFolderView = UiUtilities.getInflater(app, nightMode).inflate(R.layout.bottom_sheet_item_with_descr_64dp, null);
|
||||
addNewFolderView.setMinimumHeight(getResources().getDimensionPixelSize(R.dimen.bottom_sheet_list_item_height));
|
||||
AndroidUiHelper.updateVisibility(addNewFolderView.findViewById(R.id.description), false);
|
||||
BaseBottomSheetItem addNewFolderItem = new SimpleBottomSheetItem.Builder()
|
||||
.setTitle(getString(R.string.add_new_folder))
|
||||
.setIcon(getActiveIcon(R.drawable.ic_action_folder_add))
|
||||
.setLayoutId(R.layout.bottom_sheet_item_with_descr_64dp)
|
||||
.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
AddNewTrackFolderBottomSheet.showInstance(activity.getSupportFragmentManager(),
|
||||
MoveGpxFileBottomSheet.this, fileDir.getName(), usedOnMap);
|
||||
}
|
||||
}
|
||||
})
|
||||
.setCustomView(addNewFolderView)
|
||||
.create();
|
||||
items.add(addNewFolderItem);
|
||||
|
||||
DividerItem dividerItem = new DividerItem(app);
|
||||
dividerItem.setMargins(0, 0, 0, 0);
|
||||
items.add(dividerItem);
|
||||
|
||||
final List<File> dirs = new ArrayList<>();
|
||||
collectDirs(app.getAppPath(IndexConstants.GPX_INDEX_DIR), dirs, fileDir);
|
||||
if (!Algorithms.objectEquals(fileDir, app.getAppPath(IndexConstants.GPX_INDEX_DIR))) {
|
||||
dirs.add(0, app.getAppPath(IndexConstants.GPX_INDEX_DIR));
|
||||
}
|
||||
String gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR).getPath();
|
||||
for (final File dir : dirs) {
|
||||
String dirName = dir.getPath();
|
||||
if (dirName.startsWith(gpxDir)) {
|
||||
if (dirName.length() == gpxDir.length()) {
|
||||
dirName = dir.getName();
|
||||
} else {
|
||||
dirName = dirName.substring(gpxDir.length() + 1);
|
||||
}
|
||||
}
|
||||
String description;
|
||||
List<File> files = collectFiles(dir);
|
||||
if (Algorithms.isEmpty(files)) {
|
||||
description = getString(R.string.shared_string_empty);
|
||||
} else {
|
||||
description = String.valueOf(files.size());
|
||||
}
|
||||
final BaseBottomSheetItem[] folderItem = new BaseBottomSheetItem[1];
|
||||
folderItem[0] = new BottomSheetItemWithDescription.Builder()
|
||||
.setDescription(description)
|
||||
.setTitle(capitalizeFirstLetter(dirName))
|
||||
.setIcon(getActiveIcon(R.drawable.ic_action_folder))
|
||||
.setLayoutId(R.layout.bottom_sheet_item_with_descr_64dp)
|
||||
.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Fragment fragment = getTargetFragment();
|
||||
if (fragment instanceof OnTrackFileMoveListener) {
|
||||
OnTrackFileMoveListener listener = (OnTrackFileMoveListener) fragment;
|
||||
listener.onFileMove(file, new File(dir, file.getName()));
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
})
|
||||
.setTag(dir)
|
||||
.create();
|
||||
items.add(folderItem[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(FILE_PATH_KEY, filePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackFolderAdd(String folderName) {
|
||||
Fragment fragment = getTargetFragment();
|
||||
if (fragment instanceof OnTrackFileMoveListener) {
|
||||
File file = new File(filePath);
|
||||
File destFolder = new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), folderName);
|
||||
OnTrackFileMoveListener listener = (OnTrackFileMoveListener) fragment;
|
||||
listener.onFileMove(file, new File(destFolder, file.getName()));
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
public List<File> collectFiles(File parentDir) {
|
||||
List<File> files = new ArrayList<>();
|
||||
File[] listFiles = parentDir.listFiles();
|
||||
if (listFiles != null) {
|
||||
for (File file : listFiles) {
|
||||
if (!file.isDirectory()) {
|
||||
files.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
public static void showInstance(@NonNull FragmentManager fragmentManager, @Nullable Fragment target,
|
||||
@NonNull String filePath, boolean usedOnMap) {
|
||||
try {
|
||||
if (!fragmentManager.isStateSaved() && fragmentManager.findFragmentByTag(MoveGpxFileBottomSheet.TAG) == null) {
|
||||
MoveGpxFileBottomSheet fragment = new MoveGpxFileBottomSheet();
|
||||
fragment.filePath = filePath;
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setTargetFragment(target, 0);
|
||||
fragment.show(fragmentManager, MoveGpxFileBottomSheet.TAG);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error("showInstance", e);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnTrackFileMoveListener {
|
||||
void onFileMove(@NonNull File src, @NonNull File dest);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package net.osmand.plus.myplaces;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
|
@ -23,6 +25,8 @@ import androidx.fragment.app.FragmentManager;
|
|||
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.FileUtils;
|
||||
import net.osmand.FileUtils.RenameCallback;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.GPXUtilities.Track;
|
||||
import net.osmand.GPXUtilities.TrkSegment;
|
||||
|
@ -53,7 +57,10 @@ import java.io.File;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TrackSegmentFragment extends OsmAndListFragment implements TrackBitmapDrawerListener, SegmentActionsListener {
|
||||
public class TrackSegmentFragment extends OsmAndListFragment implements TrackBitmapDrawerListener,
|
||||
SegmentActionsListener, RenameCallback {
|
||||
|
||||
public static final String TRACK_DELETED_KEY = "track_deleted_key";
|
||||
|
||||
private OsmandApplication app;
|
||||
private TrackDisplayHelper displayHelper;
|
||||
|
@ -134,8 +141,40 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
}
|
||||
});
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
MenuItem renameItem = menu.add(R.string.shared_string_rename)
|
||||
.setIcon(app.getUIUtilities().getIcon((R.drawable.ic_action_edit_dark)))
|
||||
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
GPXFile gpx = displayHelper.getGpx();
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null && gpx != null) {
|
||||
FileUtils.renameFile(activity, new File(gpx.path), TrackSegmentFragment.this, false);
|
||||
}
|
||||
if (gpxFile.showCurrentTrack) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
renameItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
MenuItem deleteItem = menu.add(R.string.shared_string_delete)
|
||||
.setIcon(app.getUIUtilities().getIcon((R.drawable.ic_action_delete_dark)))
|
||||
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
GPXFile gpx = displayHelper.getGpx();
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null && gpx != null) {
|
||||
if (FileUtils.removeGpxFile(app, new File((gpx.path)))) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(TRACK_DELETED_KEY, true);
|
||||
activity.setResult(Activity.RESULT_OK, intent);
|
||||
activity.onBackPressed();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
deleteItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
} else if (gpxFile.showCurrentTrack) {
|
||||
MenuItem item = menu.add(R.string.shared_string_refresh).setIcon(R.drawable.ic_action_refresh_dark)
|
||||
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
|
@ -415,4 +454,14 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
}
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renamedTo(File file) {
|
||||
displayHelper.setFile(file);
|
||||
TrackActivity activity = getTrackActivity();
|
||||
if (activity != null) {
|
||||
activity.setupActionBar();
|
||||
activity.loadGpx();
|
||||
}
|
||||
}
|
||||
}
|
24
OsmAnd/src/net/osmand/plus/onlinerouting/EngineType.java
Normal file
24
OsmAnd/src/net/osmand/plus/onlinerouting/EngineType.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package net.osmand.plus.onlinerouting;
|
||||
|
||||
public enum EngineType {
|
||||
|
||||
GRAPHHOPPER("Graphhopper", "https://graphhopper.com/api/1/route"),
|
||||
OSRM("OSRM", "https://router.project-osrm.org/route/v1/"),
|
||||
ORS("Openroute Service", "https://api.openrouteservice.org/v2/directions/");
|
||||
|
||||
private String title;
|
||||
private String standardUrl;
|
||||
|
||||
EngineType(String title, String standardUrl) {
|
||||
this.title = title;
|
||||
this.standardUrl = standardUrl;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getStandardUrl() {
|
||||
return standardUrl;
|
||||
}
|
||||
}
|
|
@ -15,32 +15,32 @@ public class OnlineRoutingEngine {
|
|||
|
||||
public final static String ONLINE_ROUTING_ENGINE_PREFIX = "online_routing_engine_";
|
||||
|
||||
public enum EngineParameterType {
|
||||
CUSTOM_SERVER_URL,
|
||||
public enum EngineParameter {
|
||||
CUSTOM_NAME,
|
||||
CUSTOM_URL,
|
||||
API_KEY
|
||||
}
|
||||
|
||||
private String stringKey;
|
||||
private ServerType serverType;
|
||||
private EngineType type;
|
||||
private String vehicleKey;
|
||||
private Map<String, String> params = new HashMap<>();
|
||||
|
||||
public OnlineRoutingEngine(@NonNull String stringKey,
|
||||
@NonNull ServerType serverType,
|
||||
@NonNull EngineType type,
|
||||
@NonNull String vehicleKey,
|
||||
@Nullable Map<String, String> params) {
|
||||
this(stringKey, serverType, vehicleKey);
|
||||
this(stringKey, type, vehicleKey);
|
||||
if (!Algorithms.isEmpty(params)) {
|
||||
this.params.putAll(params);
|
||||
}
|
||||
}
|
||||
|
||||
public OnlineRoutingEngine(@NonNull String stringKey,
|
||||
@NonNull ServerType serverType,
|
||||
@NonNull EngineType type,
|
||||
@NonNull String vehicleKey) {
|
||||
this.stringKey = stringKey;
|
||||
this.serverType = serverType;
|
||||
this.type = type;
|
||||
this.vehicleKey = vehicleKey;
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,16 @@ public class OnlineRoutingEngine {
|
|||
return stringKey;
|
||||
}
|
||||
|
||||
public ServerType getServerType() {
|
||||
return serverType;
|
||||
public EngineType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
String customUrl = getParameter(EngineParameter.CUSTOM_URL);
|
||||
if (Algorithms.isEmpty(customUrl)) {
|
||||
return type.getStandardUrl();
|
||||
}
|
||||
return customUrl;
|
||||
}
|
||||
|
||||
public String getVehicleKey() {
|
||||
|
@ -60,25 +68,16 @@ public class OnlineRoutingEngine {
|
|||
return params;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
String customServerUrl = getParameter(EngineParameterType.CUSTOM_SERVER_URL);
|
||||
if (!Algorithms.isEmpty(customServerUrl)) {
|
||||
return customServerUrl;
|
||||
} else {
|
||||
return serverType.getBaseUrl();
|
||||
}
|
||||
public String getParameter(EngineParameter paramKey) {
|
||||
return params.get(paramKey.name());
|
||||
}
|
||||
|
||||
public String getParameter(EngineParameterType paramType) {
|
||||
return params.get(paramType.name());
|
||||
}
|
||||
|
||||
public void putParameter(EngineParameterType paramType, String paramValue) {
|
||||
params.put(paramType.name(), paramValue);
|
||||
public void putParameter(EngineParameter paramKey, String paramValue) {
|
||||
params.put(paramKey.name(), paramValue);
|
||||
}
|
||||
|
||||
public String getName(@NonNull Context ctx) {
|
||||
String customName = getParameter(EngineParameterType.CUSTOM_NAME);
|
||||
String customName = getParameter(EngineParameter.CUSTOM_NAME);
|
||||
if (customName != null) {
|
||||
return customName;
|
||||
} else {
|
||||
|
@ -87,21 +86,21 @@ public class OnlineRoutingEngine {
|
|||
}
|
||||
|
||||
private String getStandardName(@NonNull Context ctx) {
|
||||
return getStandardName(ctx, serverType, vehicleKey);
|
||||
return getStandardName(ctx, type, vehicleKey);
|
||||
}
|
||||
|
||||
public static String getStandardName(@NonNull Context ctx,
|
||||
@NonNull ServerType serverType,
|
||||
@NonNull EngineType type,
|
||||
@NonNull String vehicleKey) {
|
||||
String vehicleTitle = VehicleType.toHumanString(ctx, vehicleKey);
|
||||
String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_dash);
|
||||
return String.format(pattern, serverType.getTitle(), vehicleTitle);
|
||||
return String.format(pattern, type.getTitle(), vehicleTitle);
|
||||
}
|
||||
|
||||
public static OnlineRoutingEngine createNewEngine(@NonNull ServerType serverType,
|
||||
public static OnlineRoutingEngine createNewEngine(@NonNull EngineType type,
|
||||
@NonNull String vehicleKey,
|
||||
@Nullable Map<String, String> params) {
|
||||
return new OnlineRoutingEngine(generateKey(), serverType, vehicleKey, params);
|
||||
return new OnlineRoutingEngine(generateKey(), type, vehicleKey, params);
|
||||
}
|
||||
|
||||
private static String generateKey() {
|
||||
|
|
|
@ -30,7 +30,7 @@ import net.osmand.plus.activities.MapActivity;
|
|||
import net.osmand.plus.base.BaseOsmAndFragment;
|
||||
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingCard.OnTextChangedListener;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameterType;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter;
|
||||
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
@ -62,7 +62,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
private View view;
|
||||
private ViewGroup segmentsContainer;
|
||||
private OnlineRoutingCard nameCard;
|
||||
private OnlineRoutingCard serverCard;
|
||||
private OnlineRoutingCard typeCard;
|
||||
private OnlineRoutingCard vehicleCard;
|
||||
private OnlineRoutingCard apiKeyCard;
|
||||
private OnlineRoutingCard exampleCard;
|
||||
|
@ -143,7 +143,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
setupToolbar((Toolbar) view.findViewById(R.id.toolbar));
|
||||
|
||||
setupNameCard();
|
||||
setupServerCard();
|
||||
setupTypeCard();
|
||||
setupVehicleCard();
|
||||
setupApiKeyCard();
|
||||
setupExampleCard();
|
||||
|
@ -152,7 +152,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
|
||||
setupButtons();
|
||||
|
||||
updateCardViews(nameCard, serverCard, vehicleCard, exampleCard);
|
||||
updateCardViews(nameCard, typeCard, vehicleCard, exampleCard);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -174,38 +174,39 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
segmentsContainer.addView(nameCard.getView());
|
||||
}
|
||||
|
||||
private void setupServerCard() {
|
||||
serverCard = new OnlineRoutingCard(mapActivity, isNightMode());
|
||||
serverCard.build(mapActivity);
|
||||
serverCard.setHeaderTitle(getString(R.string.shared_string_type));
|
||||
private void setupTypeCard() {
|
||||
typeCard = new OnlineRoutingCard(mapActivity, isNightMode());
|
||||
typeCard.build(mapActivity);
|
||||
typeCard.setHeaderTitle(getString(R.string.shared_string_type));
|
||||
List<HorizontalSelectionItem> serverItems = new ArrayList<>();
|
||||
for (ServerType server : ServerType.values()) {
|
||||
for (EngineType server : EngineType.values()) {
|
||||
serverItems.add(new HorizontalSelectionItem(server.getTitle(), server));
|
||||
}
|
||||
serverCard.setSelectionMenu(serverItems, engine.serverType.getTitle(),
|
||||
typeCard.setSelectionMenu(serverItems, engine.type.getTitle(),
|
||||
new CallbackWithObject<HorizontalSelectionItem>() {
|
||||
@Override
|
||||
public boolean processResult(HorizontalSelectionItem result) {
|
||||
ServerType server = (ServerType) result.getObject();
|
||||
if (engine.serverType != server) {
|
||||
engine.serverType = server;
|
||||
updateCardViews(nameCard, serverCard, exampleCard);
|
||||
EngineType type = (EngineType) result.getObject();
|
||||
if (engine.type != type) {
|
||||
engine.type = type;
|
||||
updateCardViews(nameCard, typeCard, exampleCard);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
serverCard.setOnTextChangedListener(new OnTextChangedListener() {
|
||||
typeCard.setOnTextChangedListener(new OnTextChangedListener() {
|
||||
@Override
|
||||
public void onTextChanged(boolean editedByUser, String text) {
|
||||
if (editedByUser) {
|
||||
engine.customServerUrl = text;
|
||||
updateCardViews(exampleCard);
|
||||
}
|
||||
}
|
||||
});
|
||||
serverCard.setFieldBoxLabelText(getString(R.string.shared_string_server_url));
|
||||
serverCard.showDivider();
|
||||
segmentsContainer.addView(serverCard.getView());
|
||||
typeCard.setFieldBoxLabelText(getString(R.string.shared_string_server_url));
|
||||
typeCard.showDivider();
|
||||
segmentsContainer.addView(typeCard.getView());
|
||||
}
|
||||
|
||||
private void setupVehicleCard() {
|
||||
|
@ -342,22 +343,28 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
for (BaseCard card : cardsToUpdate) {
|
||||
if (nameCard.equals(card)) {
|
||||
if (Algorithms.isEmpty(engine.customName)) {
|
||||
String name = OnlineRoutingEngine.getStandardName(app, engine.serverType, engine.getVehicleKey());
|
||||
String name;
|
||||
if (Algorithms.isEmpty(engine.getVehicleKey())) {
|
||||
name = engine.type.getTitle();
|
||||
} else {
|
||||
name = OnlineRoutingEngine.getStandardName(app, engine.type, engine.getVehicleKey());
|
||||
}
|
||||
nameCard.setEditedText(name);
|
||||
}
|
||||
|
||||
} else if (serverCard.equals(card)) {
|
||||
serverCard.setHeaderSubtitle(engine.serverType.getTitle());
|
||||
serverCard.setEditedText(engine.getBaseUrl());
|
||||
if (engine.serverType == ServerType.GRAPHHOPER) {
|
||||
} else if (typeCard.equals(card)) {
|
||||
typeCard.setHeaderSubtitle(engine.type.getTitle());
|
||||
typeCard.setEditedText(engine.getBaseUrl());
|
||||
if (engine.type == EngineType.GRAPHHOPPER || engine.type == EngineType.ORS) {
|
||||
apiKeyCard.show();
|
||||
} else {
|
||||
apiKeyCard.hide();
|
||||
}
|
||||
|
||||
} else if (vehicleCard.equals(card)) {
|
||||
vehicleCard.setHeaderSubtitle(engine.vehicleType.getTitle(app));
|
||||
if (engine.vehicleType == VehicleType.CUSTOM) {
|
||||
VehicleType vt = VehicleType.getVehicleByKey(engine.getVehicleKey());
|
||||
vehicleCard.setHeaderSubtitle(vt.getTitle(app));
|
||||
if (vt == VehicleType.CUSTOM) {
|
||||
vehicleCard.showFieldBox();
|
||||
vehicleCard.setEditedText(engine.getVehicleKey());
|
||||
} else {
|
||||
|
@ -400,15 +407,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
private void saveChanges() {
|
||||
OnlineRoutingEngine engineToSave;
|
||||
if (isEditingMode()) {
|
||||
engineToSave = new OnlineRoutingEngine(editedEngineKey, engine.serverType, engine.getVehicleKey());
|
||||
engineToSave = new OnlineRoutingEngine(editedEngineKey, engine.type, engine.getVehicleKey());
|
||||
} else {
|
||||
engineToSave = OnlineRoutingEngine.createNewEngine(engine.serverType, engine.getVehicleKey(), null);
|
||||
engineToSave = OnlineRoutingEngine.createNewEngine(engine.type, engine.getVehicleKey(), null);
|
||||
}
|
||||
|
||||
engineToSave.putParameter(EngineParameterType.CUSTOM_SERVER_URL, engine.customServerUrl);
|
||||
engineToSave.putParameter(EngineParameterType.CUSTOM_NAME, engine.customName);
|
||||
if (engine.serverType == ServerType.GRAPHHOPER) {
|
||||
engineToSave.putParameter(EngineParameterType.API_KEY, engine.apiKey);
|
||||
engineToSave.putParameter(EngineParameter.CUSTOM_NAME, engine.customName);
|
||||
engineToSave.putParameter(EngineParameter.CUSTOM_URL, engine.customServerUrl);
|
||||
if (engine.type == EngineType.GRAPHHOPPER || engine.type == EngineType.ORS) {
|
||||
engineToSave.putParameter(EngineParameter.API_KEY, engine.apiKey);
|
||||
}
|
||||
|
||||
helper.saveEngine(engineToSave);
|
||||
|
@ -419,30 +426,18 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
}
|
||||
|
||||
private String getTestUrl() {
|
||||
String baseUrl = engine.serverType.getBaseUrl();
|
||||
String vehicle = engine.getVehicleKey();
|
||||
|
||||
LatLon startPoint = selectedLocation.getCityCenterLatLon();
|
||||
LatLon endPoint = selectedLocation.getCityAirportLatLon();
|
||||
|
||||
if (engine.serverType == ServerType.GRAPHHOPER) {
|
||||
return baseUrl + "?" + "point=" + startPoint.getLatitude()
|
||||
+ "," + startPoint.getLongitude()
|
||||
+ "&" + "point=" + endPoint.getLatitude()
|
||||
+ "," + endPoint.getLongitude()
|
||||
+ "&" + "vehicle=" + vehicle
|
||||
+ (!Algorithms.isEmpty(engine.apiKey) ? ("&" + "key=" + engine.apiKey) : "");
|
||||
} else {
|
||||
return baseUrl + vehicle + "/" + startPoint.getLatitude()
|
||||
+ "," + startPoint.getLongitude()
|
||||
+ ";" + endPoint.getLatitude()
|
||||
+ "," + endPoint.getLongitude()
|
||||
+ "?" + "geometries=geojson";
|
||||
}
|
||||
List<LatLon> path = new ArrayList<>();
|
||||
path.add(selectedLocation.getCityCenterLatLon());
|
||||
path.add(selectedLocation.getCityAirportLatLon());
|
||||
OnlineRoutingEngine tmpEngine =
|
||||
OnlineRoutingEngine.createNewEngine(engine.type, engine.getVehicleKey(), null);
|
||||
tmpEngine.putParameter(EngineParameter.CUSTOM_URL, engine.customServerUrl);
|
||||
tmpEngine.putParameter(EngineParameter.API_KEY, engine.apiKey);
|
||||
return helper.createFullUrl(tmpEngine, path);
|
||||
}
|
||||
|
||||
private void testEngineWork() {
|
||||
final ServerType server = engine.serverType;
|
||||
final EngineType type = engine.type;
|
||||
final ExampleLocation location = selectedLocation;
|
||||
AndroidNetworkUtils.sendRequestAsync(app, exampleCard.getEditedText(), null,
|
||||
null, false, false, new OnRequestResultListener() {
|
||||
|
@ -453,10 +448,12 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
try {
|
||||
JSONObject obj = new JSONObject(response);
|
||||
|
||||
if (server == ServerType.GRAPHHOPER) {
|
||||
if (type == EngineType.GRAPHHOPPER) {
|
||||
resultOk = obj.has("paths");
|
||||
} else if (server == ServerType.OSRM) {
|
||||
} else if (type == EngineType.OSRM) {
|
||||
resultOk = obj.has("routes");
|
||||
} else if (type == EngineType.ORS) {
|
||||
resultOk = obj.has("features");
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
|
||||
|
@ -494,7 +491,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
|
||||
private void saveState(Bundle outState) {
|
||||
outState.putString(ENGINE_NAME_KEY, engine.customName);
|
||||
outState.putString(ENGINE_SERVER_KEY, engine.serverType.name());
|
||||
outState.putString(ENGINE_SERVER_KEY, engine.type.name());
|
||||
outState.putString(ENGINE_SERVER_URL_KEY, engine.customServerUrl);
|
||||
outState.putString(ENGINE_VEHICLE_TYPE_KEY, engine.vehicleType.name());
|
||||
outState.putString(ENGINE_CUSTOM_VEHICLE_KEY, engine.customVehicleKey);
|
||||
|
@ -508,7 +505,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
|
||||
private void restoreState(Bundle savedState) {
|
||||
engine.customName = savedState.getString(ENGINE_NAME_KEY);
|
||||
engine.serverType = ServerType.valueOf(savedState.getString(ENGINE_SERVER_KEY));
|
||||
engine.type = EngineType.valueOf(savedState.getString(ENGINE_SERVER_KEY));
|
||||
engine.customServerUrl = savedState.getString(ENGINE_SERVER_URL_KEY);
|
||||
engine.vehicleType = VehicleType.valueOf(savedState.getString(ENGINE_VEHICLE_TYPE_KEY));
|
||||
engine.customVehicleKey = savedState.getString(ENGINE_CUSTOM_VEHICLE_KEY);
|
||||
|
@ -519,16 +516,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
}
|
||||
|
||||
private void initState() {
|
||||
engine.serverType = ServerType.values()[0];
|
||||
engine.type = EngineType.values()[0];
|
||||
engine.vehicleType = VehicleType.values()[0];
|
||||
selectedLocation = ExampleLocation.values()[0];
|
||||
|
||||
if (isEditingMode()) {
|
||||
OnlineRoutingEngine editedEngine = helper.getEngineByKey(editedEngineKey);
|
||||
if (editedEngine != null) {
|
||||
engine.customName = editedEngine.getParameter(EngineParameterType.CUSTOM_NAME);
|
||||
engine.serverType = editedEngine.getServerType();
|
||||
engine.customServerUrl = editedEngine.getParameter(EngineParameterType.CUSTOM_SERVER_URL);
|
||||
engine.customName = editedEngine.getParameter(EngineParameter.CUSTOM_NAME);
|
||||
engine.type = editedEngine.getType();
|
||||
String vehicleKey = editedEngine.getVehicleKey();
|
||||
if (vehicleKey != null) {
|
||||
VehicleType vehicleType = VehicleType.getVehicleByKey(vehicleKey);
|
||||
|
@ -537,7 +533,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
}
|
||||
engine.vehicleType = vehicleType;
|
||||
}
|
||||
engine.apiKey = editedEngine.getParameter(EngineParameterType.API_KEY);
|
||||
engine.apiKey = editedEngine.getParameter(EngineParameter.API_KEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -583,7 +579,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
|
||||
private static class OnlineRoutingEngineObject {
|
||||
private String customName;
|
||||
private ServerType serverType;
|
||||
private EngineType type;
|
||||
private String customServerUrl;
|
||||
private VehicleType vehicleType;
|
||||
private String customVehicleKey;
|
||||
|
@ -596,15 +592,18 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
return vehicleType.getKey();
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return customServerUrl != null ? customServerUrl : serverType.getBaseUrl();
|
||||
}
|
||||
|
||||
public String getName(Context ctx) {
|
||||
if (customName != null) {
|
||||
return customName;
|
||||
}
|
||||
return OnlineRoutingEngine.getStandardName(ctx, serverType, getVehicleKey());
|
||||
return OnlineRoutingEngine.getStandardName(ctx, type, getVehicleKey());
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
if (Algorithms.isEmpty(customServerUrl)) {
|
||||
return type.getStandardUrl();
|
||||
}
|
||||
return customServerUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,18 +6,28 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.Version;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.GeoPolylineParserUtil;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -27,8 +37,7 @@ public class OnlineRoutingHelper {
|
|||
|
||||
private OsmandApplication app;
|
||||
private OsmandSettings settings;
|
||||
private List<OnlineRoutingEngine> cachedEngines;
|
||||
private Map<String, OnlineRoutingEngine> cachedEnginesMap;
|
||||
private Map<String, OnlineRoutingEngine> cachedEngines;
|
||||
|
||||
public OnlineRoutingHelper(OsmandApplication app) {
|
||||
this.app = app;
|
||||
|
@ -38,23 +47,121 @@ public class OnlineRoutingHelper {
|
|||
|
||||
@NonNull
|
||||
public List<OnlineRoutingEngine> getEngines() {
|
||||
return cachedEngines;
|
||||
return new ArrayList<>(cachedEngines.values());
|
||||
}
|
||||
|
||||
public OnlineRoutingEngine getEngineByKey(String stringKey) {
|
||||
return cachedEnginesMap.get(stringKey);
|
||||
return cachedEngines.get(stringKey);
|
||||
}
|
||||
|
||||
public List<LatLon> calculateRouteOnline(@NonNull OnlineRoutingEngine engine,
|
||||
@NonNull List<LatLon> path) throws IOException, JSONException {
|
||||
String fullUrl = createFullUrl(engine, path);
|
||||
String content = makeRequest(fullUrl);
|
||||
return parseResponse(engine, content);
|
||||
}
|
||||
|
||||
public String createFullUrl(OnlineRoutingEngine engine, List<LatLon> path) {
|
||||
StringBuilder sb = new StringBuilder(engine.getBaseUrl());
|
||||
String vehicle = engine.getVehicleKey();
|
||||
String apiKey = engine.getParameter(EngineParameter.API_KEY);
|
||||
switch (engine.getType()) {
|
||||
|
||||
case GRAPHHOPPER:
|
||||
sb.append("?");
|
||||
for (LatLon point : path) {
|
||||
sb.append("point=")
|
||||
.append(point.getLatitude())
|
||||
.append(',')
|
||||
.append(point.getLongitude())
|
||||
.append('&');
|
||||
}
|
||||
sb.append("vehicle=").append(vehicle);
|
||||
|
||||
if (!Algorithms.isEmpty(apiKey)) {
|
||||
sb.append('&').append("key=").append(apiKey);
|
||||
}
|
||||
break;
|
||||
|
||||
case OSRM:
|
||||
sb.append(vehicle).append('/');
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
LatLon point = path.get(i);
|
||||
sb.append(point.getLongitude()).append(',').append(point.getLatitude());
|
||||
if (i < path.size() - 1) {
|
||||
sb.append(';');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ORS:
|
||||
if (path.size() > 1) {
|
||||
sb.append("driving-car").append('?'); // todo only for testing
|
||||
if (!Algorithms.isEmpty(apiKey)) {
|
||||
sb.append("api_key=").append(apiKey);
|
||||
}
|
||||
LatLon start = path.get(0);
|
||||
LatLon end = path.get(path.size() - 1);
|
||||
sb.append('&').append("start=")
|
||||
.append(start.getLatitude()).append(',').append(start.getLongitude());
|
||||
sb.append('&').append("end=")
|
||||
.append(end.getLatitude()).append(',').append(end.getLongitude());
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private List<LatLon> parseResponse(OnlineRoutingEngine engine, String content) throws JSONException {
|
||||
JSONObject obj = new JSONObject(content);
|
||||
|
||||
switch (engine.getType()) {
|
||||
|
||||
case GRAPHHOPPER:
|
||||
return GeoPolylineParserUtil.parse(
|
||||
obj.getJSONArray("paths").getJSONObject(0).getString("points"),
|
||||
GeoPolylineParserUtil.PRECISION_5);
|
||||
|
||||
case OSRM:
|
||||
return GeoPolylineParserUtil.parse(
|
||||
obj.getJSONArray("routes").getJSONObject(0).getString("geometry"),
|
||||
GeoPolylineParserUtil.PRECISION_5);
|
||||
|
||||
case ORS:
|
||||
JSONArray array = obj.getJSONArray("features").getJSONObject(0)
|
||||
.getJSONObject("geometry").getJSONArray("coordinates");
|
||||
List<LatLon> track = new ArrayList<>();
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONArray point = array.getJSONArray(i);
|
||||
double lat = Double.parseDouble(point.getString(0));
|
||||
double lon = Double.parseDouble(point.getString(1));
|
||||
track.add(new LatLon(lat, lon));
|
||||
}
|
||||
return track;
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private String makeRequest(String url) throws IOException {
|
||||
URLConnection connection = NetworkUtils.getHttpURLConnection(url);
|
||||
connection.setRequestProperty("User-Agent", Version.getFullVersion(app));
|
||||
StringBuilder content = new StringBuilder();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String s;
|
||||
while ((s = reader.readLine()) != null) {
|
||||
content.append(s);
|
||||
}
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
|
||||
public void saveEngine(@NonNull OnlineRoutingEngine engine) {
|
||||
String stringKey = engine.getStringKey();
|
||||
OnlineRoutingEngine existedEngine = cachedEnginesMap.get(stringKey);
|
||||
if (existedEngine != null) {
|
||||
int index = cachedEngines.indexOf(existedEngine);
|
||||
cachedEngines.set(index, engine);
|
||||
} else {
|
||||
cachedEngines.add(engine);
|
||||
}
|
||||
cachedEnginesMap.put(stringKey, engine);
|
||||
cachedEngines.put(stringKey, engine);
|
||||
saveToSettings();
|
||||
}
|
||||
|
||||
|
@ -67,19 +174,18 @@ public class OnlineRoutingHelper {
|
|||
|
||||
public void deleteEngine(@NonNull OnlineRoutingEngine engine) {
|
||||
String stringKey = engine.getStringKey();
|
||||
if (cachedEnginesMap.containsKey(stringKey)) {
|
||||
OnlineRoutingEngine existedEngine = cachedEnginesMap.remove(stringKey);
|
||||
cachedEngines.remove(existedEngine);
|
||||
if (cachedEngines.containsKey(stringKey)) {
|
||||
cachedEngines.remove(stringKey);
|
||||
saveToSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadFromSettings() {
|
||||
cachedEngines = readFromSettings();
|
||||
cachedEnginesMap = new HashMap<>();
|
||||
for (OnlineRoutingEngine engine : cachedEngines) {
|
||||
cachedEnginesMap.put(engine.getStringKey(), engine);
|
||||
Map<String, OnlineRoutingEngine> cachedEngines = new LinkedHashMap<>();
|
||||
for (OnlineRoutingEngine engine : readFromSettings()) {
|
||||
cachedEngines.put(engine.getStringKey(), engine);
|
||||
}
|
||||
this.cachedEngines = cachedEngines;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -101,7 +207,7 @@ public class OnlineRoutingHelper {
|
|||
if (!Algorithms.isEmpty(cachedEngines)) {
|
||||
try {
|
||||
JSONObject json = new JSONObject();
|
||||
writeToJson(json, cachedEngines);
|
||||
writeToJson(json, getEngines());
|
||||
settings.ONLINE_ROUTING_ENGINES.set(json.toString());
|
||||
} catch (JSONException e) {
|
||||
LOG.debug("Error when writing engines to JSON ", e);
|
||||
|
@ -123,10 +229,10 @@ public class OnlineRoutingHelper {
|
|||
JSONObject object = itemsJson.getJSONObject(i);
|
||||
String key = object.getString("key");
|
||||
String vehicleKey = object.getString("vehicle");
|
||||
ServerType serverType = ServerType.valueOf(object.getString("serverType"));
|
||||
EngineType engineType = EngineType.valueOf(object.getString("type"));
|
||||
String paramsString = object.getString("params");
|
||||
HashMap<String, String> params = gson.fromJson(paramsString, type);
|
||||
engines.add(new OnlineRoutingEngine(key, serverType, vehicleKey, params));
|
||||
engines.add(new OnlineRoutingEngine(key, engineType, vehicleKey, params));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +244,7 @@ public class OnlineRoutingHelper {
|
|||
for (OnlineRoutingEngine engine : engines) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("key", engine.getStringKey());
|
||||
jsonObject.put("serverType", engine.getServerType().name());
|
||||
jsonObject.put("type", engine.getType().name());
|
||||
jsonObject.put("vehicle", engine.getVehicleKey());
|
||||
jsonObject.put("params", gson.toJson(engine.getParams(), type));
|
||||
jsonArray.put(jsonObject);
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package net.osmand.plus.onlinerouting;
|
||||
|
||||
public enum ServerType {
|
||||
GRAPHHOPER("Graphhoper", "https://graphhopper.com/api/1/route"),
|
||||
OSRM("OSRM", "https://zlzk.biz/route/v1/");
|
||||
|
||||
ServerType(String title, String baseUrl) {
|
||||
this.title = title;
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
private String title;
|
||||
private String baseUrl;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
}
|
|
@ -352,11 +352,11 @@ public class PoiUIFilter implements SearchPoiTypeFilter, Comparable<PoiUIFilter>
|
|||
}
|
||||
};
|
||||
}
|
||||
StringBuilder nmFilter = new StringBuilder();
|
||||
String[] items = filter.split(" ");
|
||||
boolean allTime = false;
|
||||
boolean open = false;
|
||||
List<PoiType> poiAdditionalsFilter = null;
|
||||
List<String> unknownFilters = null;
|
||||
for (String s : items) {
|
||||
s = s.trim();
|
||||
if (!Algorithms.isEmpty(s)) {
|
||||
|
@ -373,110 +373,179 @@ public class PoiUIFilter implements SearchPoiTypeFilter, Comparable<PoiUIFilter>
|
|||
poiAdditionalsFilter.add(pt);
|
||||
}
|
||||
} else {
|
||||
nmFilter.append(s).append(" ");
|
||||
if (unknownFilters == null) {
|
||||
unknownFilters = new ArrayList<>();
|
||||
}
|
||||
unknownFilters.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return getNameFilterInternal(nmFilter, allTime, open, poiAdditionalsFilter);
|
||||
return getNameFilterInternal(unknownFilters, allTime, open, poiAdditionalsFilter);
|
||||
}
|
||||
|
||||
private AmenityNameFilter getNameFilterInternal(StringBuilder nmFilter,
|
||||
final boolean allTime, final boolean open, final List<PoiType> poiAdditionals) {
|
||||
final CollatorStringMatcher sm = nmFilter.length() > 0 ?
|
||||
new CollatorStringMatcher(nmFilter.toString().trim(), StringMatcherMode.CHECK_CONTAINS) : null;
|
||||
private AmenityNameFilter getNameFilterInternal(
|
||||
final List<String> unknownFilters, final boolean shouldBeAllTime,
|
||||
final boolean shouldBeOpened, final List<PoiType> selectedFilters
|
||||
) {
|
||||
return new AmenityNameFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(Amenity a) {
|
||||
if (sm != null) {
|
||||
List<String> names = OsmAndFormatter.getPoiStringsWithoutType(a,
|
||||
app.getSettings().MAP_PREFERRED_LOCALE.get(), app.getSettings().MAP_TRANSLITERATE_NAMES.get());
|
||||
boolean match = false;
|
||||
for (String name : names) {
|
||||
if (sm.matches(name)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
public boolean accept(Amenity amenity) {
|
||||
if (shouldBeAllTime) {
|
||||
if (!"24/7".equalsIgnoreCase(amenity.getOpeningHours()) &&
|
||||
!"Mo-Su 00:00-24:00".equalsIgnoreCase(amenity.getOpeningHours())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (poiAdditionals != null) {
|
||||
Map<PoiType, PoiType> textPoiAdditionalsMap = new HashMap<>();
|
||||
Map<String, List<PoiType>> poiAdditionalCategoriesMap = new HashMap<>();
|
||||
for (PoiType pt : poiAdditionals) {
|
||||
String category = pt.getPoiAdditionalCategory();
|
||||
List<PoiType> types = poiAdditionalCategoriesMap.get(category);
|
||||
if (types == null) {
|
||||
types = new ArrayList<>();
|
||||
poiAdditionalCategoriesMap.put(category, types);
|
||||
}
|
||||
types.add(pt);
|
||||
|
||||
String osmTag = pt.getOsmTag();
|
||||
if (osmTag.length() < pt.getKeyName().length()) {
|
||||
PoiType textPoiType = poiTypes.getTextPoiAdditionalByKey(osmTag);
|
||||
if (textPoiType != null) {
|
||||
textPoiAdditionalsMap.put(pt, textPoiType);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (List<PoiType> types : poiAdditionalCategoriesMap.values()) {
|
||||
boolean acceptedAnyInCategory = false;
|
||||
for (PoiType p : types) {
|
||||
String inf = a.getAdditionalInfo(p.getKeyName());
|
||||
if (inf != null) {
|
||||
acceptedAnyInCategory = true;
|
||||
break;
|
||||
} else {
|
||||
PoiType textPoiType = textPoiAdditionalsMap.get(p);
|
||||
if (textPoiType != null) {
|
||||
inf = a.getAdditionalInfo(textPoiType.getKeyName());
|
||||
if (!Algorithms.isEmpty(inf)) {
|
||||
String[] items = inf.split(";");
|
||||
String val = p.getOsmValue().trim().toLowerCase();
|
||||
for (String item : items) {
|
||||
if (item.trim().toLowerCase().equals(val)) {
|
||||
acceptedAnyInCategory = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (acceptedAnyInCategory) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!acceptedAnyInCategory) {
|
||||
if (shouldBeOpened && !isOpened(amenity)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (allTime) {
|
||||
if (!"24/7".equalsIgnoreCase(a.getOpeningHours()) && !"Mo-Su 00:00-24:00".equalsIgnoreCase(a.getOpeningHours())) {
|
||||
|
||||
String nameFilter = extractNameFilter(amenity, unknownFilters);
|
||||
if (!matchesAnyAmenityName(amenity, nameFilter)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (open) {
|
||||
OpeningHours rs = OpeningHoursParser.parseOpenedHours(a.getOpeningHours());
|
||||
if (rs != null) {
|
||||
Calendar inst = Calendar.getInstance();
|
||||
inst.setTimeInMillis(System.currentTimeMillis());
|
||||
boolean work = rs.isOpenedForTime(inst);
|
||||
if (!work) {
|
||||
|
||||
if (!acceptedAnyFilterOfEachCategory(amenity, selectedFilters)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isOpened(Amenity amenity) {
|
||||
OpeningHours openedHours = OpeningHoursParser.parseOpenedHours(amenity.getOpeningHours());
|
||||
if (openedHours == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(System.currentTimeMillis());
|
||||
|
||||
return openedHours.isOpenedForTime(calendar);
|
||||
}
|
||||
|
||||
private String extractNameFilter(Amenity amenity, List<String> unknownFilters) {
|
||||
if (unknownFilters == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder nameFilter = new StringBuilder();
|
||||
for (String filter : unknownFilters) {
|
||||
String formattedFilter = filter.replace(':', '_').toLowerCase();
|
||||
if (amenity.getAdditionalInfo(formattedFilter) == null) {
|
||||
nameFilter.append(filter).append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
return nameFilter.toString();
|
||||
}
|
||||
|
||||
private boolean matchesAnyAmenityName(Amenity amenity, String nameFilter) {
|
||||
if (nameFilter.length() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final CollatorStringMatcher sm =
|
||||
new CollatorStringMatcher(nameFilter.trim(), StringMatcherMode.CHECK_CONTAINS);
|
||||
|
||||
List<String> names = OsmAndFormatter.getPoiStringsWithoutType(
|
||||
amenity, app.getSettings().MAP_PREFERRED_LOCALE.get(),
|
||||
app.getSettings().MAP_TRANSLITERATE_NAMES.get());
|
||||
for (String name : names) {
|
||||
if (sm.matches(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean acceptedAnyFilterOfEachCategory(Amenity amenity, List<PoiType> selectedFilters) {
|
||||
if (selectedFilters == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Map<String, List<PoiType>> filterCategories = new HashMap<>();
|
||||
Map<PoiType, PoiType> textFilters = new HashMap<>();
|
||||
|
||||
fillFilterCategories(selectedFilters, filterCategories, textFilters);
|
||||
|
||||
for (List<PoiType> category : filterCategories.values()) {
|
||||
if (!acceptedAnyFilterOfCategory(amenity, category, textFilters)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void fillFilterCategories(
|
||||
List<PoiType> selectedFilters,
|
||||
Map<String, List<PoiType>> filterCategories, Map<PoiType, PoiType> textFilters
|
||||
) {
|
||||
for (PoiType filter : selectedFilters) {
|
||||
String category = filter.getPoiAdditionalCategory();
|
||||
List<PoiType> filtersOfCategory = filterCategories.get(category);
|
||||
if (filtersOfCategory == null) {
|
||||
filtersOfCategory = new ArrayList<>();
|
||||
filterCategories.put(category, filtersOfCategory);
|
||||
}
|
||||
filtersOfCategory.add(filter);
|
||||
|
||||
String osmTag = filter.getOsmTag();
|
||||
if (osmTag.length() < filter.getKeyName().length()) {
|
||||
PoiType textFilter = poiTypes.getTextPoiAdditionalByKey(osmTag);
|
||||
if (textFilter != null) {
|
||||
textFilters.put(filter, textFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean acceptedAnyFilterOfCategory(
|
||||
Amenity amenity, List<PoiType> category, Map<PoiType, PoiType> textFilters) {
|
||||
for (PoiType filter : category) {
|
||||
if (acceptedFilter(amenity, filter, textFilters)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean acceptedFilter(
|
||||
Amenity amenity, PoiType filter, Map<PoiType, PoiType> textFilterCategories
|
||||
) {
|
||||
String filterValue = amenity.getAdditionalInfo(filter.getKeyName());
|
||||
|
||||
if (filterValue != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PoiType textPoiType = textFilterCategories.get(filter);
|
||||
if (textPoiType == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
filterValue = amenity.getAdditionalInfo(textPoiType.getKeyName());
|
||||
if (Algorithms.isEmpty(filterValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] items = filterValue.split(";");
|
||||
String val = filter.getOsmValue().trim().toLowerCase();
|
||||
for (String item : items) {
|
||||
if (item.trim().toLowerCase().equals(val)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getNameToken24H() {
|
||||
return app.getString(R.string.shared_string_is_open_24_7).replace(' ', '_').toLowerCase();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Map;
|
|||
public class ProfileDataUtils {
|
||||
|
||||
public static final String OSMAND_NAVIGATION = "osmand_navigation";
|
||||
public static final String ONLINE_NAVIGATION = "online_navigation";
|
||||
|
||||
public static List<ProfileDataObject> getDataObjects(OsmandApplication app,
|
||||
List<ApplicationMode> appModes) {
|
||||
|
@ -48,9 +49,9 @@ public class ProfileDataUtils {
|
|||
return description;
|
||||
}
|
||||
|
||||
public static List<RoutingProfileDataObject> getSortedRoutingProfiles(OsmandApplication app) {
|
||||
List<RoutingProfileDataObject> result = new ArrayList<>();
|
||||
Map<String, List<RoutingProfileDataObject>> routingProfilesByFileNames = getRoutingProfilesByFileNames(app);
|
||||
public static List<ProfileDataObject> getSortedRoutingProfiles(OsmandApplication app) {
|
||||
List<ProfileDataObject> result = new ArrayList<>();
|
||||
Map<String, List<ProfileDataObject>> routingProfilesByFileNames = getRoutingProfilesByFileNames(app);
|
||||
List<String> fileNames = new ArrayList<>(routingProfilesByFileNames.keySet());
|
||||
Collections.sort(fileNames, new Comparator<String>() {
|
||||
@Override
|
||||
|
@ -59,7 +60,7 @@ public class ProfileDataUtils {
|
|||
}
|
||||
});
|
||||
for (String fileName : fileNames) {
|
||||
List<RoutingProfileDataObject> routingProfilesFromFile = routingProfilesByFileNames.get(fileName);
|
||||
List<ProfileDataObject> routingProfilesFromFile = routingProfilesByFileNames.get(fileName);
|
||||
if (routingProfilesFromFile != null) {
|
||||
Collections.sort(routingProfilesFromFile);
|
||||
result.addAll(routingProfilesFromFile);
|
||||
|
@ -77,14 +78,20 @@ public class ProfileDataUtils {
|
|||
return objects;
|
||||
}
|
||||
|
||||
public static Map<String, List<RoutingProfileDataObject>> getRoutingProfilesByFileNames(OsmandApplication app) {
|
||||
Map<String, List<RoutingProfileDataObject>> result = new HashMap<>();
|
||||
for (final RoutingProfileDataObject profile : getRoutingProfiles(app).values()) {
|
||||
String fileName = profile.getFileName() != null ? profile.getFileName() : OSMAND_NAVIGATION;
|
||||
public static Map<String, List<ProfileDataObject>> getRoutingProfilesByFileNames(OsmandApplication app) {
|
||||
Map<String, List<ProfileDataObject>> result = new HashMap<>();
|
||||
for (final ProfileDataObject profile : getRoutingProfiles(app).values()) {
|
||||
String fileName = null;
|
||||
if (profile instanceof RoutingProfileDataObject) {
|
||||
fileName = ((RoutingProfileDataObject) profile).getFileName();
|
||||
} else if (profile instanceof OnlineRoutingEngineDataObject) {
|
||||
fileName = ONLINE_NAVIGATION;
|
||||
}
|
||||
fileName = fileName != null ? fileName : OSMAND_NAVIGATION;
|
||||
if (result.containsKey(fileName)) {
|
||||
result.get(fileName).add(profile);
|
||||
} else {
|
||||
result.put(fileName, new ArrayList<RoutingProfileDataObject>() {
|
||||
result.put(fileName, new ArrayList<ProfileDataObject>() {
|
||||
{ add(profile); }
|
||||
});
|
||||
}
|
||||
|
@ -92,8 +99,8 @@ public class ProfileDataUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static Map<String, RoutingProfileDataObject> getRoutingProfiles(OsmandApplication context) {
|
||||
Map<String, RoutingProfileDataObject> profilesObjects = new HashMap<>();
|
||||
public static Map<String, ProfileDataObject> getRoutingProfiles(OsmandApplication context) {
|
||||
Map<String, ProfileDataObject> profilesObjects = new HashMap<>();
|
||||
profilesObjects.put(RoutingProfilesResources.STRAIGHT_LINE_MODE.name(), new RoutingProfileDataObject(
|
||||
RoutingProfilesResources.STRAIGHT_LINE_MODE.name(),
|
||||
context.getString(RoutingProfilesResources.STRAIGHT_LINE_MODE.getStringRes()),
|
||||
|
@ -119,11 +126,14 @@ public class ProfileDataUtils {
|
|||
for (RoutingConfiguration.Builder builder : context.getAllRoutingConfigs()) {
|
||||
collectRoutingProfilesFromConfig(context, builder, profilesObjects, disabledRouterNames);
|
||||
}
|
||||
for (OnlineRoutingEngineDataObject onlineEngine : getOnlineRoutingProfiles(context)) {
|
||||
profilesObjects.put(onlineEngine.getStringKey(), onlineEngine);
|
||||
}
|
||||
return profilesObjects;
|
||||
}
|
||||
|
||||
private static void collectRoutingProfilesFromConfig(OsmandApplication app, RoutingConfiguration.Builder builder,
|
||||
Map<String, RoutingProfileDataObject> profilesObjects, List<String> disabledRouterNames) {
|
||||
Map<String, ProfileDataObject> profilesObjects, List<String> disabledRouterNames) {
|
||||
for (Map.Entry<String, GeneralRouter> entry : builder.getAllRouters().entrySet()) {
|
||||
String routerKey = entry.getKey();
|
||||
GeneralRouter router = entry.getValue();
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.app.Activity;
|
|||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
|
@ -58,7 +59,7 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
|
|||
|
||||
public final static String PROFILE_KEY_ARG = "profile_key_arg";
|
||||
public final static String USE_LAST_PROFILE_ARG = "use_last_profile_arg";
|
||||
public final static String IS_PROFILE_IMPORTED_ARG = "is_profile_imported_arg";
|
||||
public final static String PROFILES_LIST_UPDATED_ARG = "is_profiles_list_updated";
|
||||
|
||||
private DialogMode dialogMode;
|
||||
private final List<ProfileDataObject> profiles = new ArrayList<>();
|
||||
|
@ -130,7 +131,7 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
|
|||
}
|
||||
Bundle args = new Bundle();
|
||||
args.putString(PROFILE_KEY_ARG, item.getName());
|
||||
args.putBoolean(IS_PROFILE_IMPORTED_ARG, true);
|
||||
args.putBoolean(PROFILES_LIST_UPDATED_ARG, true);
|
||||
listener.onSelectedType(args);
|
||||
dismiss();
|
||||
break;
|
||||
|
@ -234,9 +235,10 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
|
|||
|
||||
int activeColorResId = nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light;
|
||||
int iconDefaultColorResId = nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light;
|
||||
final boolean onlineRoutingProfile = profile instanceof OnlineRoutingEngineDataObject;
|
||||
|
||||
View itemView = UiUtilities.getInflater(getContext(), nightMode).inflate(
|
||||
profile instanceof OnlineRoutingEngineDataObject ?
|
||||
onlineRoutingProfile ?
|
||||
R.layout.bottom_sheet_item_with_descr_radio_and_icon_btn :
|
||||
R.layout.bottom_sheet_item_with_descr_and_radio_btn, null);
|
||||
TextView tvTitle = itemView.findViewById(R.id.title);
|
||||
|
@ -262,28 +264,52 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
|
|||
UiUtilities.setupCompoundButton(compoundButton, nightMode, UiUtilities.CompoundButtonType.GLOBAL);
|
||||
bottomDivider.setVisibility(showBottomDivider ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
items.add(new BaseBottomSheetItem.Builder()
|
||||
.setCustomView(itemView)
|
||||
.setOnClickListener(new OnClickListener() {
|
||||
BaseBottomSheetItem.Builder builder =
|
||||
new BaseBottomSheetItem.Builder().setCustomView(itemView);
|
||||
|
||||
OnClickListener listener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(PROFILE_KEY_ARG, profile.getStringKey());
|
||||
args.putBoolean(PROFILES_LIST_UPDATED_ARG, onlineRoutingProfile);
|
||||
Fragment target = getTargetFragment();
|
||||
if (target instanceof OnSelectProfileCallback) {
|
||||
if (profile instanceof OnlineRoutingEngineDataObject) {
|
||||
((OnSelectProfileCallback) target).onProfileSelected(args);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
};
|
||||
|
||||
if (onlineRoutingProfile) {
|
||||
View basePart = itemView.findViewById(R.id.basic_item_body);
|
||||
View endBtn = itemView.findViewById(R.id.end_button);
|
||||
ImageView ivEndBtnIcon = itemView.findViewById(R.id.end_button_icon);
|
||||
|
||||
Drawable drawable = getIcon(R.drawable.ic_action_settings,
|
||||
nightMode ?
|
||||
R.color.route_info_control_icon_color_dark :
|
||||
R.color.route_info_control_icon_color_light);
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
Drawable activeDrawable = getIcon(R.drawable.ic_action_settings, activeColorResId);
|
||||
drawable = AndroidUtils.createPressedStateListDrawable(drawable, activeDrawable);
|
||||
}
|
||||
ivEndBtnIcon.setImageDrawable(drawable);
|
||||
|
||||
basePart.setOnClickListener(listener);
|
||||
endBtn.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (getActivity() != null) {
|
||||
OnlineRoutingEngineFragment.showInstance(getActivity(), getAppMode(), profile.getStringKey());
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
((OnSelectProfileCallback) target).onProfileSelected(args);
|
||||
builder.setOnClickListener(listener);
|
||||
}
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
})
|
||||
.create());
|
||||
items.add(builder.create());
|
||||
}
|
||||
|
||||
private void addCheckableItem(int titleId,
|
||||
|
@ -363,7 +389,6 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
|
|||
|
||||
case NAVIGATION_PROFILE:
|
||||
profiles.addAll(ProfileDataUtils.getSortedRoutingProfiles(app));
|
||||
profiles.addAll(ProfileDataUtils.getOnlineRoutingProfiles(app));
|
||||
break;
|
||||
|
||||
case DEFAULT_PROFILE:
|
||||
|
|
|
@ -22,6 +22,8 @@ import net.osmand.data.LocationPoint;
|
|||
import net.osmand.data.WptLocationPoint;
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.settings.backend.CommonPreference;
|
||||
import net.osmand.plus.R;
|
||||
|
@ -91,7 +93,8 @@ public class RouteProvider {
|
|||
OSMAND("OsmAnd (offline)"),
|
||||
BROUTER("BRouter (offline)"),
|
||||
STRAIGHT("Straight line"),
|
||||
DIRECT_TO("Direct To");
|
||||
DIRECT_TO("Direct To"),
|
||||
ONLINE("Online engine");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
@ -363,10 +366,8 @@ public class RouteProvider {
|
|||
res = findVectorMapsRoute(params, calcGPXRoute);
|
||||
} else if (params.mode.getRouteService() == RouteService.BROUTER) {
|
||||
res = findBROUTERRoute(params);
|
||||
// } else if (params.type == RouteService.ORS) {
|
||||
// res = findORSRoute(params);
|
||||
// } else if (params.type == RouteService.OSRM) {
|
||||
// res = findOSRMRoute(params);
|
||||
} else if (params.mode.getRouteService() == RouteService.ONLINE) {
|
||||
res = findOnlineRoute(params);
|
||||
} else if (params.mode.getRouteService() == RouteService.STRAIGHT ||
|
||||
params.mode.getRouteService() == RouteService.DIRECT_TO) {
|
||||
res = findStraightRoute(params);
|
||||
|
@ -383,6 +384,8 @@ public class RouteProvider {
|
|||
log.error("Failed to find route ", e); //$NON-NLS-1$
|
||||
} catch (SAXException e) {
|
||||
log.error("Failed to find route ", e); //$NON-NLS-1$
|
||||
} catch (JSONException e) {
|
||||
log.error("Failed to find route ", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
return new RouteCalculationResult(null);
|
||||
|
@ -1204,56 +1207,12 @@ public class RouteProvider {
|
|||
return exporter.exportRoute();
|
||||
}
|
||||
|
||||
private void appendOSRMLoc(StringBuilder uri, LatLon il) {
|
||||
uri.append(";").append(il.getLongitude());
|
||||
uri.append(",").append(il.getLatitude());
|
||||
}
|
||||
|
||||
protected RouteCalculationResult findOSRMRoute(RouteCalculationParams params)
|
||||
throws MalformedURLException, IOException, JSONException {
|
||||
// http://router.project-osrm.org/route/v1/driving/4.83,52.28;4.95,52.28
|
||||
List<Location> res = new ArrayList<Location>();
|
||||
StringBuilder uri = new StringBuilder();
|
||||
// possibly hide that API key because it is privacy of osmand
|
||||
// A6421860EBB04234AB5EF2D049F2CD8F key is compromised
|
||||
String scheme = "";
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
|
||||
scheme = "https";
|
||||
} else {
|
||||
scheme = "http";
|
||||
}
|
||||
uri.append(scheme + "://router.project-osrm.org/route/v1/driving/"); //$NON-NLS-1$
|
||||
uri.append(String.valueOf(params.start.getLongitude()));
|
||||
uri.append(",").append(String.valueOf(params.start.getLatitude()));
|
||||
if(params.intermediates != null && params.intermediates.size() > 0) {
|
||||
for(LatLon il : params.intermediates) {
|
||||
appendOSRMLoc(uri, il);
|
||||
}
|
||||
}
|
||||
appendOSRMLoc(uri, params.end);
|
||||
// to get more waypoints, add overview=full option
|
||||
// uri.append("?overview=full")
|
||||
|
||||
log.info("URL route " + uri);
|
||||
|
||||
URLConnection connection = NetworkUtils.getHttpURLConnection(uri.toString());
|
||||
connection.setRequestProperty("User-Agent", Version.getFullVersion(params.ctx));
|
||||
StringBuilder content = new StringBuilder();
|
||||
BufferedReader rs = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String s;
|
||||
while((s = rs.readLine()) != null) {
|
||||
content.append(s);
|
||||
}
|
||||
JSONObject obj = new JSONObject(content.toString());
|
||||
try {
|
||||
rs.close();
|
||||
} catch(IOException e){
|
||||
}
|
||||
List<LatLon> route = GeoPolylineParserUtil.parse(obj.getJSONArray("routes").getJSONObject(0).getString("geometry"),
|
||||
GeoPolylineParserUtil.PRECISION_5);
|
||||
if (route.isEmpty()) {
|
||||
return new RouteCalculationResult("Route is empty");
|
||||
}
|
||||
private RouteCalculationResult findOnlineRoute(RouteCalculationParams params) throws IOException, JSONException {
|
||||
OnlineRoutingHelper helper = params.ctx.getOnlineRoutingHelper();
|
||||
String stringKey = params.mode.getRoutingProfile();
|
||||
List<LatLon> route = helper.calculateRouteOnline(helper.getEngineByKey(stringKey), getFullPathFromParams(params));
|
||||
if (!route.isEmpty()) {
|
||||
List<Location> res = new ArrayList<>();
|
||||
for (LatLon pt : route) {
|
||||
WptPt wpt = new WptPt();
|
||||
wpt.lat = pt.getLatitude();
|
||||
|
@ -1262,6 +1221,19 @@ public class RouteProvider {
|
|||
}
|
||||
params.intermediates = null;
|
||||
return new RouteCalculationResult(res, null, params, null, true);
|
||||
} else {
|
||||
return new RouteCalculationResult("Route is empty");
|
||||
}
|
||||
}
|
||||
|
||||
private static List<LatLon> getFullPathFromParams(RouteCalculationParams params) {
|
||||
List<LatLon> points = new ArrayList<>();
|
||||
points.add(new LatLon(params.start.getLatitude(), params.start.getLongitude()));
|
||||
if (Algorithms.isEmpty(params.intermediates)) {
|
||||
points.addAll(params.intermediates);
|
||||
}
|
||||
points.add(params.end);
|
||||
return points;
|
||||
}
|
||||
|
||||
protected RouteCalculationResult findBROUTERRoute(RouteCalculationParams params) throws MalformedURLException,
|
||||
|
|
|
@ -8,7 +8,7 @@ import androidx.annotation.Nullable;
|
|||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameterType;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
@ -93,8 +93,8 @@ public class OnlineRoutingSettingsItem extends CollectionSettingsItem<OnlineRout
|
|||
int number = 0;
|
||||
while (true) {
|
||||
number++;
|
||||
OnlineRoutingEngine renamedItem = OnlineRoutingEngine.createNewEngine(item.getServerType(), item.getVehicleKey(), item.getParams());
|
||||
renamedItem.putParameter(EngineParameterType.CUSTOM_NAME, renamedItem.getName(app) + "_" + number);
|
||||
OnlineRoutingEngine renamedItem = OnlineRoutingEngine.createNewEngine(item.getType(), item.getVehicleKey(), item.getParams());
|
||||
renamedItem.putParameter(EngineParameter.CUSTOM_NAME, renamedItem.getName(app) + "_" + number);
|
||||
if (!isDuplicate(renamedItem)) {
|
||||
return renamedItem;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package net.osmand.plus.settings.bottomsheets;
|
|||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
@ -255,7 +254,7 @@ public class ElevationDateBottomSheet extends MenuBottomSheetDialogFragment {
|
|||
fragment.appMode = appMode;
|
||||
fragment.setUsedOnMap(usedOnMap);
|
||||
fragment.setTargetFragment(target, 0);
|
||||
fragment.show(fm, ScreenTimeoutBottomSheet.TAG);
|
||||
fragment.show(fm, ElevationDateBottomSheet.TAG);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error("showInstance", e);
|
||||
|
|
|
@ -35,7 +35,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import static net.osmand.plus.importfiles.ImportHelper.ImportType.SETTINGS;
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.IS_PROFILE_IMPORTED_ARG;
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILES_LIST_UPDATED_ARG;
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG;
|
||||
|
||||
public class MainSettingsFragment extends BaseSettingsFragment implements OnSelectProfileCallback{
|
||||
|
@ -229,7 +229,7 @@ public class MainSettingsFragment extends BaseSettingsFragment implements OnSele
|
|||
FragmentManager fragmentManager = activity.getSupportFragmentManager();
|
||||
if (fragmentManager != null) {
|
||||
String profileKey = args.getString(PROFILE_KEY_ARG);
|
||||
boolean imported = args.getBoolean(IS_PROFILE_IMPORTED_ARG);
|
||||
boolean imported = args.getBoolean(PROFILES_LIST_UPDATED_ARG);
|
||||
ProfileAppearanceFragment.showInstance(activity, SettingsScreenType.PROFILE_APPEARANCE,
|
||||
profileKey, imported);
|
||||
}
|
||||
|
|
|
@ -10,13 +10,14 @@ import androidx.preference.Preference;
|
|||
import androidx.preference.SwitchPreferenceCompat;
|
||||
|
||||
import net.osmand.plus.measurementtool.MeasurementToolFragment;
|
||||
import net.osmand.plus.profiles.ProfileDataObject;
|
||||
import net.osmand.plus.profiles.ProfileDataUtils;
|
||||
import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet;
|
||||
import net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.DialogMode;
|
||||
import net.osmand.plus.routing.RouteProvider.RouteService;
|
||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.profiles.RoutingProfileDataObject;
|
||||
import net.osmand.plus.profiles.RoutingProfileDataObject.RoutingProfilesResources;
|
||||
import net.osmand.plus.profiles.SelectProfileBottomSheet;
|
||||
import net.osmand.plus.profiles.SelectProfileBottomSheet.OnSelectProfileCallback;
|
||||
|
@ -26,7 +27,8 @@ import net.osmand.util.Algorithms;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.IS_PROFILE_IMPORTED_ARG;
|
||||
import static net.osmand.plus.onlinerouting.OnlineRoutingEngine.ONLINE_ROUTING_ENGINE_PREFIX;
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILES_LIST_UPDATED_ARG;
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG;
|
||||
import static net.osmand.plus.routepreparationmenu.RouteOptionsBottomSheet.DIALOG_MODE_KEY;
|
||||
|
||||
|
@ -35,13 +37,13 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
|
|||
public static final String TAG = NavigationFragment.class.getSimpleName();
|
||||
public static final String NAVIGATION_TYPE = "navigation_type";
|
||||
|
||||
private Map<String, RoutingProfileDataObject> routingProfileDataObjects;
|
||||
private Map<String, ProfileDataObject> routingProfileDataObjects;
|
||||
private Preference navigationType;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
routingProfileDataObjects = ProfileDataUtils.getRoutingProfiles(app);
|
||||
updateRoutingProfilesDataObjects();
|
||||
setupOnBackPressedCallback();
|
||||
}
|
||||
|
||||
|
@ -90,7 +92,7 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
|
|||
private void setupNavigationTypePref() {
|
||||
String routingProfileKey = getSelectedAppMode().getRoutingProfile();
|
||||
if (!Algorithms.isEmpty(routingProfileKey)) {
|
||||
RoutingProfileDataObject routingProfileDataObject = routingProfileDataObjects.get(routingProfileKey);
|
||||
ProfileDataObject routingProfileDataObject = routingProfileDataObjects.get(routingProfileKey);
|
||||
if (routingProfileDataObject != null) {
|
||||
navigationType.setSummary(routingProfileDataObject.getName());
|
||||
navigationType.setIcon(getActiveIcon(routingProfileDataObject.getIconRes()));
|
||||
|
@ -132,12 +134,16 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
|
|||
return false;
|
||||
}
|
||||
|
||||
private void updateRoutingProfilesDataObjects() {
|
||||
routingProfileDataObjects = ProfileDataUtils.getRoutingProfiles(app);
|
||||
}
|
||||
|
||||
void updateRoutingProfile(String profileKey) {
|
||||
RoutingProfileDataObject selectedRoutingProfileDataObject = routingProfileDataObjects.get(profileKey);
|
||||
ProfileDataObject selectedRoutingProfileDataObject = routingProfileDataObjects.get(profileKey);
|
||||
if (profileKey == null || selectedRoutingProfileDataObject == null) {
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<String, RoutingProfileDataObject> rp : routingProfileDataObjects.entrySet()) {
|
||||
for (Map.Entry<String, ProfileDataObject> rp : routingProfileDataObjects.entrySet()) {
|
||||
boolean selected = profileKey.equals(rp.getKey());
|
||||
rp.getValue().setSelected(selected);
|
||||
}
|
||||
|
@ -152,6 +158,8 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
|
|||
routeService = RouteProvider.RouteService.DIRECT_TO;
|
||||
} else if (profileKey.equals(RoutingProfilesResources.BROUTER_MODE.name())) {
|
||||
routeService = RouteProvider.RouteService.BROUTER;
|
||||
} else if (profileKey.startsWith(ONLINE_ROUTING_ENGINE_PREFIX)) {
|
||||
routeService = RouteService.ONLINE;
|
||||
} else {
|
||||
routeService = RouteProvider.RouteService.OSMAND;
|
||||
}
|
||||
|
@ -174,8 +182,8 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
|
|||
|
||||
@Override
|
||||
public void onProfileSelected(Bundle args) {
|
||||
if (args.getBoolean(IS_PROFILE_IMPORTED_ARG)) {
|
||||
routingProfileDataObjects = ProfileDataUtils.getRoutingProfiles(app);
|
||||
if (args.getBoolean(PROFILES_LIST_UPDATED_ARG)) {
|
||||
updateRoutingProfilesDataObjects();
|
||||
}
|
||||
updateRoutingProfile(args.getString(PROFILE_KEY_ARG));
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
|
||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_SETTINGS_ID;
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.IS_PROFILE_IMPORTED_ARG;
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILES_LIST_UPDATED_ARG;
|
||||
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG;
|
||||
|
||||
public class ProfileAppearanceFragment extends BaseSettingsFragment implements OnSelectProfileCallback {
|
||||
|
@ -934,7 +934,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
|
|||
@Override
|
||||
public void onProfileSelected(Bundle args) {
|
||||
String profileKey = args.getString(PROFILE_KEY_ARG);
|
||||
boolean imported = args.getBoolean(IS_PROFILE_IMPORTED_ARG);
|
||||
boolean imported = args.getBoolean(PROFILES_LIST_UPDATED_ARG);
|
||||
updateParentProfile(profileKey, imported);
|
||||
}
|
||||
|
||||
|
|
|
@ -574,7 +574,7 @@ public class TravelObfHelper implements TravelHelper {
|
|||
@Nullable
|
||||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull LatLon latLon, @NonNull final String lang) {
|
||||
QuadRect rect = MapUtils.calculateLatLonBbox(latLon.getLatitude(), latLon.getLongitude(), ARTICLE_SEARCH_RADIUS);
|
||||
QuadRect rect = latLon != null ? MapUtils.calculateLatLonBbox(latLon.getLatitude(), latLon.getLongitude(), ARTICLE_SEARCH_RADIUS) : new QuadRect();
|
||||
return getArticleByTitle(title, rect, lang);
|
||||
}
|
||||
|
||||
|
@ -582,7 +582,7 @@ public class TravelObfHelper implements TravelHelper {
|
|||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull QuadRect rect, @NonNull final String lang) {
|
||||
TravelArticle article = null;
|
||||
List<Amenity> amenities = null;
|
||||
final List<Amenity> amenities = new ArrayList<>();
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int left = 0;
|
||||
|
@ -600,9 +600,25 @@ public class TravelObfHelper implements TravelHelper {
|
|||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
x, y, title, left, right, top, bottom, getSearchFilter(false), null, null);
|
||||
req.setLimit(1);
|
||||
amenities = reader.searchPoiByName(req);
|
||||
x, y, title, left, right, top, bottom, getSearchFilter(false),
|
||||
new ResultMatcher<Amenity>() {
|
||||
boolean done = false;
|
||||
|
||||
@Override
|
||||
public boolean publish(Amenity amenity) {
|
||||
if (Algorithms.stringsEqual(title, Algorithms.emptyIfNull(amenity.getName(lang)))) {
|
||||
amenities.add(amenity);
|
||||
done = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return done;
|
||||
}
|
||||
}, null);
|
||||
reader.searchPoiByName(req);
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.4.10'
|
||||
ext.kotlin_version = '1.4.21'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
|
|
Loading…
Reference in a new issue