commit
14b70262f3
64 changed files with 1869 additions and 934 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,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"
|
||||
|
@ -48,14 +51,13 @@
|
|||
<service
|
||||
android:name=".TelegramService"
|
||||
android:label="@string/process_service"
|
||||
android:foregroundServiceType="location"
|
||||
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,21 @@ 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() {
|
||||
|
|
|
@ -166,7 +166,7 @@ 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)
|
||||
|
|
|
@ -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
|
||||
|
@ -26,7 +24,7 @@ private const val UPDATE_LIVE_MESSAGES_INTERVAL_MS = 10000L // 10 sec
|
|||
private const val UPDATE_LIVE_TRACKS_INTERVAL_MS = 30000L // 30 sec
|
||||
|
||||
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener,
|
||||
TelegramOutgoingMessagesListener {
|
||||
TelegramOutgoingMessagesListener {
|
||||
|
||||
private val log = PlatformUtil.getLog(TelegramService::class.java)
|
||||
|
||||
|
@ -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$
|
||||
} 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()
|
||||
// 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.debug("Location service permission not granted")
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
|
||||
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) {
|
||||
|
|
|
@ -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>
|
|
@ -12,6 +12,10 @@
|
|||
|
||||
-->
|
||||
|
||||
<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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,7 +44,7 @@ public class FileUtils {
|
|||
dest.getParentFile().mkdirs();
|
||||
}
|
||||
if (source.renameTo(dest)) {
|
||||
final String[] suffixes = new String[]{"-journal", "-wal", "-shm"};
|
||||
final String[] suffixes = new String[] {"-journal", "-wal", "-shm"};
|
||||
for (String s : suffixes) {
|
||||
File file = new File(ctx.getDatabasePath(source + s).toString());
|
||||
if (file.exists()) {
|
||||
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
@ -191,7 +223,7 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
|
|||
GradientDrawable background = (GradientDrawable) AppCompatResources.getDrawable(app,
|
||||
R.drawable.bg_select_group_button_outline);
|
||||
if (background != null) {
|
||||
int highlightColor = ContextCompat.getColor(app,nightMode ?
|
||||
int highlightColor = ContextCompat.getColor(app, nightMode ?
|
||||
R.color.list_background_color_dark : R.color.activity_background_color_light);
|
||||
int strokedColor = AndroidUtils.getColorFromAttr(UiUtilities.getThemedContext(app, nightMode),
|
||||
R.attr.stroked_buttons_and_links_outline);
|
||||
|
@ -234,7 +266,7 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
|
|||
}
|
||||
|
||||
public static void showInstance(@NonNull FragmentManager fm, @Nullable Fragment targetFragment, String folderName,
|
||||
String fileName, boolean showSimplifiedButton, boolean showOnMap) {
|
||||
String fileName, boolean showSimplifiedButton, boolean showOnMap) {
|
||||
try {
|
||||
if (!fm.isStateSaved()) {
|
||||
SaveAsNewTrackBottomSheetDialogFragment fragment = new SaveAsNewTrackBottomSheetDialogFragment();
|
||||
|
@ -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);
|
||||
}
|
||||
if (gpxFile.showCurrentTrack) {
|
||||
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);
|
||||
}
|
||||
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 String vehicleKey,
|
||||
@Nullable Map<String, String> params) {
|
||||
this(stringKey, serverType, vehicleKey);
|
||||
@NonNull EngineType type,
|
||||
@NonNull String vehicleKey,
|
||||
@Nullable Map<String, String> params) {
|
||||
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,
|
||||
@NonNull String vehicleKey,
|
||||
@Nullable Map<String, String> params) {
|
||||
return new OnlineRoutingEngine(generateKey(), serverType, vehicleKey, params);
|
||||
public static OnlineRoutingEngine createNewEngine(@NonNull EngineType type,
|
||||
@NonNull String vehicleKey,
|
||||
@Nullable Map<String, String> 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;
|
||||
|
@ -132,8 +132,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
view = getInflater().inflate(
|
||||
R.layout.online_routing_engine_fragment, container, false);
|
||||
segmentsContainer = (ViewGroup) view.findViewById(R.id.segments_container);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -568,8 +564,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
}
|
||||
|
||||
public static void showInstance(@NonNull FragmentActivity activity,
|
||||
@NonNull ApplicationMode appMode,
|
||||
String editedEngineKey) {
|
||||
@NonNull ApplicationMode appMode,
|
||||
String editedEngineKey) {
|
||||
FragmentManager fm = activity.getSupportFragmentManager();
|
||||
if (!fm.isStateSaved() && fm.findFragmentByTag(OnlineRoutingEngineFragment.TAG) == null) {
|
||||
OnlineRoutingEngineFragment fragment = new OnlineRoutingEngineFragment();
|
||||
|
@ -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) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (shouldBeOpened && !isOpened(amenity)) {
|
||||
return false;
|
||||
}
|
||||
if (allTime) {
|
||||
if (!"24/7".equalsIgnoreCase(a.getOpeningHours()) && !"Mo-Su 00:00-24:00".equalsIgnoreCase(a.getOpeningHours())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!acceptedAnyFilterOfEachCategory(amenity, selectedFilters)) {
|
||||
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() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(PROFILE_KEY_ARG, profile.getStringKey());
|
||||
Fragment target = getTargetFragment();
|
||||
if (target instanceof OnSelectProfileCallback) {
|
||||
if (profile instanceof OnlineRoutingEngineDataObject) {
|
||||
if (getActivity() != null) {
|
||||
OnlineRoutingEngineFragment.showInstance(getActivity(), getAppMode(), profile.getStringKey());
|
||||
}
|
||||
dismiss();
|
||||
} else {
|
||||
((OnSelectProfileCallback) target).onProfileSelected(args);
|
||||
}
|
||||
}
|
||||
dismiss();
|
||||
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) {
|
||||
((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());
|
||||
}
|
||||
})
|
||||
.create());
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
builder.setOnClickListener(listener);
|
||||
}
|
||||
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,64 +1207,33 @@ 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);
|
||||
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();
|
||||
wpt.lon = pt.getLongitude();
|
||||
res.add(createLocation(wpt));
|
||||
}
|
||||
}
|
||||
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()) {
|
||||
params.intermediates = null;
|
||||
return new RouteCalculationResult(res, null, params, null, true);
|
||||
} else {
|
||||
return new RouteCalculationResult("Route is empty");
|
||||
}
|
||||
for (LatLon pt : route) {
|
||||
WptPt wpt = new WptPt();
|
||||
wpt.lat = pt.getLatitude();
|
||||
wpt.lon = pt.getLongitude();
|
||||
res.add(createLocation(wpt));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
params.intermediates = null;
|
||||
return new RouteCalculationResult(res, null, params, null, true);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -492,7 +492,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;
|
||||
|
@ -510,8 +510,25 @@ public class TravelObfHelper implements TravelHelper {
|
|||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
x, y, title, left, right, top, bottom, getSearchRouteArticleFilter(), null, null);
|
||||
amenities = reader.searchPoiByName(req);
|
||||
x, y, title, left, right, top, bottom, getSearchRouteArticleFilter(),
|
||||
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());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue