diff --git a/OsmAnd-telegram/res/drawable-hdpi/ic_direction_arrow.png b/OsmAnd-telegram/res/drawable-hdpi/ic_direction_arrow.png new file mode 100644 index 0000000000..790efba776 Binary files /dev/null and b/OsmAnd-telegram/res/drawable-hdpi/ic_direction_arrow.png differ diff --git a/OsmAnd-telegram/res/drawable-mdpi/ic_direction_arrow.png b/OsmAnd-telegram/res/drawable-mdpi/ic_direction_arrow.png new file mode 100644 index 0000000000..0dd7c1772e Binary files /dev/null and b/OsmAnd-telegram/res/drawable-mdpi/ic_direction_arrow.png differ diff --git a/OsmAnd-telegram/res/drawable-xhdpi/ic_direction_arrow.png b/OsmAnd-telegram/res/drawable-xhdpi/ic_direction_arrow.png new file mode 100644 index 0000000000..fbab873b59 Binary files /dev/null and b/OsmAnd-telegram/res/drawable-xhdpi/ic_direction_arrow.png differ diff --git a/OsmAnd-telegram/res/drawable-xxhdpi/ic_direction_arrow.png b/OsmAnd-telegram/res/drawable-xxhdpi/ic_direction_arrow.png new file mode 100644 index 0000000000..bd17a41d7f Binary files /dev/null and b/OsmAnd-telegram/res/drawable-xxhdpi/ic_direction_arrow.png differ diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt index 946934478b..ed9126d182 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt @@ -5,10 +5,17 @@ import android.graphics.drawable.Drawable import android.widget.ImageView import net.osmand.telegram.R import net.osmand.telegram.TelegramApplication +import net.osmand.telegram.helpers.TelegramHelper.MessageOsmAndBotLocation +import org.drinkless.td.libcore.telegram.TdApi object TelegramUiHelper { - fun setupPhoto(app: TelegramApplication, iv: ImageView?, photoPath: String?) { + fun setupPhoto( + app: TelegramApplication, + iv: ImageView?, + photoPath: String?, + placeholderId: Int = R.drawable.ic_group + ) { if (iv == null) { return } @@ -18,7 +25,7 @@ object TelegramUiHelper { bitmap = app.uiUtils.getCircleBitmap(photoPath) } if (bitmap == null) { - drawable = app.uiUtils.getThemedIcon(R.drawable.ic_group) + drawable = app.uiUtils.getThemedIcon(placeholderId) } if (bitmap != null) { iv.setImageBitmap(bitmap) @@ -26,4 +33,60 @@ object TelegramUiHelper { iv.setImageDrawable(drawable) } } + + fun messageToLocationItem(helper: TelegramHelper, message: TdApi.Message): LocationItem? { + val content = message.content + return when (content) { + is MessageOsmAndBotLocation -> botMessageToLocationItem(content) + is TdApi.MessageLocation -> locationMessageToLocationItem(helper, message) + else -> null + } + } + + private fun botMessageToLocationItem(content: MessageOsmAndBotLocation): LocationItem? { + return if (content.isValid()) { + LocationItem().apply { + name = content.name + lat = content.lat + lon = content.lon + placeholderId = R.drawable.ic_group + } + } else { + null + } + } + + private fun locationMessageToLocationItem( + helper: TelegramHelper, + message: TdApi.Message + ): LocationItem? { + val user = helper.getUser(message.senderUserId) ?: return null + val content = message.content as TdApi.MessageLocation + return LocationItem().apply { + name = "${user.firstName} ${user.lastName}".trim() + if (name.isEmpty()) { + name = user.username + } + if (name.isEmpty()) { + name = user.phoneNumber + } + lat = content.location.latitude + lon = content.location.longitude + photoPath = helper.getUserPhotoPath(user) + placeholderId = R.drawable.ic_group + } + } + + class LocationItem { + var name: String = "" + internal set + var lat: Double = 0.0 + internal set + var lon: Double = 0.0 + internal set + var photoPath: String? = null + internal set + var placeholderId: Int = 0 + internal set + } } diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt index b657f42799..d30752baac 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt @@ -13,18 +13,24 @@ import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.ImageView import android.widget.TextView +import net.osmand.Location import net.osmand.telegram.R import net.osmand.telegram.TelegramApplication +import net.osmand.telegram.TelegramLocationProvider.TelegramLocationListener import net.osmand.telegram.helpers.TelegramHelper import net.osmand.telegram.helpers.TelegramHelper.* import net.osmand.telegram.helpers.TelegramUiHelper +import net.osmand.telegram.helpers.TelegramUiHelper.LocationItem import net.osmand.telegram.utils.AndroidUtils +import net.osmand.telegram.utils.OsmandFormatter +import net.osmand.util.MapUtils import org.drinkless.td.libcore.telegram.TdApi private const val CHAT_VIEW_TYPE = 0 -private const val CONTACT_VIEW_TYPE = 1 +private const val LOCATION_ITEM_VIEW_TYPE = 1 -class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessagesListener { +class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessagesListener, + TelegramLocationListener { private val app: TelegramApplication get() = activity?.application as TelegramApplication @@ -35,6 +41,8 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage private lateinit var adapter: LiveNowListAdapter + private var location: Location? = null + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -53,11 +61,13 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage super.onResume() updateList() telegramHelper.addIncomingMessagesListener(this) + startLocationUpdate() } override fun onPause() { super.onPause() telegramHelper.removeIncomingMessagesListener(this) + stopLocationUpdate() } override fun onTelegramStatusChanged( @@ -92,17 +102,39 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage updateList() } - override fun onTelegramError(code: Int, message: String) { - } + override fun onTelegramError(code: Int, message: String) {} - override fun onSendLiveLocationError(code: Int, message: String) { - } + override fun onSendLiveLocationError(code: Int, message: String) {} override fun onReceiveChatLocationMessages(chatTitle: String, vararg messages: TdApi.Message) { app.runInUIThread { updateList() } } - override fun updateLocationMessages() { + override fun updateLocationMessages() {} + + override fun updateLocation(location: Location?) { + val loc = this.location + val newLocation = loc == null && location != null + val locationChanged = loc != null && location != null + && loc.latitude != location.latitude + && loc.longitude != location.longitude + if (newLocation || locationChanged) { + this.location = location + updateLocationUi() + } + } + + fun startLocationUpdate() { + app.locationProvider.addLocationListener(this) + updateLocationUi() + } + + fun stopLocationUpdate() { + app.locationProvider.removeLocationListener(this) + } + + private fun updateLocationUi() { + adapter.notifyDataSetChanged() } private fun updateList() { @@ -110,23 +142,33 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage for ((id, messages) in telegramHelper.getMessagesByChatIds()) { telegramHelper.getChat(id)?.also { chat -> res.add(chat) - val type = chat.type - if (type is TdApi.ChatTypeBasicGroup || type is TdApi.ChatTypeSupergroup) { - messages.forEach { message -> - if (message.content is MessageOsmAndBotLocation) { - res.add(message.content) - } else { - telegramHelper.getUser(message.senderUserId)?.also { res.add(it) } - } - } - } else if (type is TdApi.ChatTypePrivate && telegramHelper.getUser(type.userId)?.username == TelegramHelper.OSMAND_BOT_USERNAME) { - res.addAll(messages.filter { it.content is MessageOsmAndBotLocation }) + if (needLocationItems(chat.type)) { + res.addAll(convertToLocationItems(messages)) } } } adapter.items = res } + private fun needLocationItems(type: TdApi.ChatType): Boolean { + return when (type) { + is TdApi.ChatTypeBasicGroup -> true + is TdApi.ChatTypeSupergroup -> true + is TdApi.ChatTypePrivate -> { + telegramHelper.getUser(type.userId)?.username == TelegramHelper.OSMAND_BOT_USERNAME + } + else -> false + } + } + + private fun convertToLocationItems(messages: List): List { + return mutableListOf().apply { + messages.forEach { message -> + TelegramUiHelper.messageToLocationItem(telegramHelper, message)?.also { add(it) } + } + } + } + inner class LiveNowListAdapter : RecyclerView.Adapter() { private val menuList = @@ -141,7 +183,7 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage override fun getItemViewType(position: Int): Int { return when (items[position]) { is TdApi.Chat -> CHAT_VIEW_TYPE - else -> CONTACT_VIEW_TYPE + else -> LOCATION_ITEM_VIEW_TYPE } } @@ -173,15 +215,18 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage holder.showOnMapState?.text = menuList[stateTextInd] holder.bottomDivider?.visibility = if (nextItemIsUser) View.VISIBLE else View.GONE holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE - } else if (item is TdApi.User && holder is ContactViewHolder) { - TelegramUiHelper.setupPhoto(app, holder.icon, telegramHelper.getUserPhotoPath(item)) - holder.title?.text = "${item.firstName} ${item.lastName}" - holder.description?.text = "User description" // FIXME - holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE - } else if (item is MessageOsmAndBotLocation && holder is ContactViewHolder) { - holder.icon?.setImageDrawable(app.uiUtils.getThemedIcon(R.drawable.ic_group)) + } else if (item is LocationItem && holder is ContactViewHolder) { + TelegramUiHelper.setupPhoto(app, holder.icon, item.photoPath, item.placeholderId) holder.title?.text = item.name - holder.description?.text = "Location from osmand_bot" // FIXME + if (location != null) { + val dist = MapUtils.getDistance( + location!!.latitude, location!!.longitude, + item.lat, item.lon + ).toFloat() + holder.description?.text = OsmandFormatter.getFormattedDistance(dist, app) + } else { + holder.description?.text = "Current location is not available" + } holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE } } diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/views/DirectionDrawable.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/views/DirectionDrawable.kt new file mode 100644 index 0000000000..60e44aec52 --- /dev/null +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/views/DirectionDrawable.kt @@ -0,0 +1,63 @@ +package net.osmand.telegram.ui.views + +import android.graphics.Canvas +import android.graphics.ColorFilter +import android.graphics.PixelFormat +import android.graphics.Rect +import android.graphics.drawable.Drawable +import net.osmand.telegram.TelegramApplication + +class DirectionDrawable(private val app: TelegramApplication) : Drawable() { + + private var angle: Float = 0.toFloat() + private var arrowImage: Drawable? = null + + fun setImage(resourceId: Int, clrId: Int) { + arrowImage = app.uiUtils.getIcon(resourceId, clrId) + onBoundsChange(bounds) + } + + fun setAngle(angle: Float) { + this.angle = angle + } + + override fun getIntrinsicWidth() = arrowImage?.intrinsicWidth ?: super.getIntrinsicWidth() + + override fun getIntrinsicHeight() = arrowImage?.intrinsicHeight ?: super.getIntrinsicHeight() + + override fun onBoundsChange(bounds: Rect) { + super.onBoundsChange(bounds) + if (arrowImage != null) { + val w = arrowImage!!.intrinsicWidth + val h = arrowImage!!.intrinsicHeight + val dx = Math.max(0, bounds.width() - w) + val dy = Math.max(0, bounds.height() - h) + if (bounds.width() == 0 && bounds.height() == 0) { + arrowImage!!.setBounds(0, 0, w, h) + } else { + arrowImage!!.setBounds( + bounds.left + dx / 2, + bounds.top + dy / 2, + bounds.right - dx / 2, + bounds.bottom - dy / 2 + ) + } + } + } + + override fun draw(canvas: Canvas) { + canvas.save() + if (arrowImage != null) { + val r = bounds + canvas.rotate(angle, r.centerX().toFloat(), r.centerY().toFloat()) + arrowImage!!.draw(canvas) + } + canvas.restore() + } + + override fun getOpacity() = PixelFormat.UNKNOWN + + override fun setAlpha(alpha: Int) {} + + override fun setColorFilter(cf: ColorFilter?) {} +} diff --git a/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt b/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt index a45e53d8ba..b744ff09c7 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt @@ -1,15 +1,25 @@ package net.osmand.telegram.utils +import android.content.Context import android.graphics.* import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable +import android.hardware.Sensor +import android.hardware.SensorManager import android.support.annotation.ColorInt import android.support.annotation.ColorRes import android.support.annotation.DrawableRes import android.support.v4.content.ContextCompat import android.support.v4.graphics.drawable.DrawableCompat +import android.view.Surface +import android.view.WindowManager +import android.widget.ImageView +import android.widget.TextView +import net.osmand.Location +import net.osmand.data.LatLon import net.osmand.telegram.R import net.osmand.telegram.TelegramApplication +import net.osmand.telegram.ui.views.DirectionDrawable import java.util.* class UiUtils(private val app: TelegramApplication) { @@ -122,4 +132,84 @@ class UiUtils(private val app: TelegramApplication) { return bitmap } + + fun updateLocationView( + arrow: ImageView?, + text: TextView?, + lat: Double, + lon: Double, + cache: UpdateLocationViewCache + ) { + updateLocationView(arrow, text, LatLon(lat, lon), cache) + } + + fun updateLocationView( + arrow: ImageView?, + text: TextView?, + toLoc: LatLon, + cache: UpdateLocationViewCache + ) { + val fromLoc = app.locationProvider.lastKnownLocationLatLon + val heading = app.locationProvider.heading + val mes = FloatArray(2) + val locPassive = fromLoc == null || cache.outdatedLocation + val colorId = if (locPassive) R.color.icon_light else R.color.ctrl_active_light + + fromLoc?.also { l -> + Location.distanceBetween(toLoc.latitude, toLoc.longitude, l.latitude, l.longitude, mes) + } + + if (arrow != null) { + var newImage = false + val drawable = arrow.drawable + val dd = if (drawable is DirectionDrawable) { + drawable + } else { + newImage = true + DirectionDrawable(app) + } + dd.setImage(R.drawable.ic_direction_arrow, colorId) + if (fromLoc == null || heading == null) { + dd.setAngle(0f) + } else { + dd.setAngle(mes[1] - heading + 180 + cache.screenOrientation) + } + if (newImage) { + arrow.setImageDrawable(dd) + } + arrow.invalidate() + } + + if (text != null) { + text.setTextColor(ContextCompat.getColor(app, colorId)) + val meters = if (fromLoc == null) 0f else mes[1] + text.text = OsmandFormatter.getFormattedDistance(meters, app) + } + } + + fun getUpdateLocationViewCache() = + UpdateLocationViewCache().apply { screenOrientation = getScreenOrientation() } + + private fun getScreenOrientation(): Int { + // screenOrientation correction must not be applied for devices without compass + val sensorManager = app.getSystemService(Context.SENSOR_SERVICE) as SensorManager? + if (sensorManager?.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) == null) { + return 0 + } + + val windowManager = app.getSystemService(Context.WINDOW_SERVICE) as WindowManager? + val rotation = windowManager?.defaultDisplay?.rotation ?: return 0 + + return when (rotation) { + Surface.ROTATION_90 -> 90 + Surface.ROTATION_180 -> 180 + Surface.ROTATION_270 -> 270 + else -> 0 + } + } + + class UpdateLocationViewCache { + var screenOrientation: Int = 0 + var outdatedLocation: Boolean = false + } } diff --git a/OsmAnd/res/values-el/phrases.xml b/OsmAnd/res/values-el/phrases.xml index 2d953c3112..7e8a62d7df 100644 --- a/OsmAnd/res/values-el/phrases.xml +++ b/OsmAnd/res/values-el/phrases.xml @@ -3246,4 +3246,124 @@ Πίτα Φόντυ Μπαγκέτα (ψωμί) + Εμπανάντα (παστέλ) + Μπουρίτο + Τεριγιάκι + Σαουάρμα + + Τοπικό + Ιταλικό + Κινέζικο + Μεξικάνικο + Γιαπωνέζικο + Γερμανικό + Ινδικό + Αμερικάνικο + Ασιατικό + Γαλλικό + Ελληνικό + Τάι + Διεθνές + Τούρκικο + Ισπανικό + Βιετναμέζικο + Κορεάτικο + Μεσογειακό + Βαβαρικό + Λιβανέζικο + Ρώσικο + Φιλιπινέζικο + Πορτογαλλικό + Γεωργιανό + Πολωνικό + Βραζιλιάνικο + Αραβικό + Δανικό + Ινδονησιακό + Αφρικανικό + Καραϊβικής + Αργεντίνικο + Βαλκανικό + Περουβιανό + Κροατικό + Βολιβιανό + Μαδαγασκάρης + Περσικό + Μαροκινό + Αυστριακό + Μαλαισιανό + Ιρλανδικό + Αιθιοπικό + Ουγγρικό + Λάο + Ευρωπαϊκό + Ουζμπέκικο + Τσέχικο + Κουβανικό + Βρετανικό + Λατινοαμερικάνικο + Νεπαλέζικο + Μογγολικό + Μέσης Ανατολής + Ουκρανικό + Αφγανικό + Βελγικό + Βασκικό + Ελβετικό + Καντονέζικο + Σουηδικό + Τζαμάικας + Αρμενικό + Χαβανέζικο + Αγγλικό + Πακιστανικό + Ταϊβανέζικο + Τέξας-Μεξικό + Ολλανδικό + Συριακό + Αυστραλέζικο + Κατζούν + Αιγυπτιακό + Σενεγαλέζικο + Εβραϊκό + Βουλγάρικο + Θιβετιανό + + Τόπος για τάισμα ζώων + + Προμήθειες γιορτής + Ηλεκτρικό κατάστημα + Κλειδαράδικο + Φωτισμός + Λαχείο + Αίθουσα τυχερών παιχνιδιών + + Τύπος + Λοταρία + Πατσίνκο + Κουλοχέρης + Στοίχημα + Μπίνγκο + + Ηλεκτρονικά τσιγάρα + + Μηχανή τρένου + + Συμπληρώματα διατροφής + Φωτογραφείο + + Γκρεμός + + Φύλαξη ζώων + Φύλαξη ζώων: άλογα + Φύλαξη ζώων: πρόβατα + Τύπος: μάντρα + Τύπος: ανοιχτός στάβλος + + Κατασκευή: πλέγμα + Κατασκευή: ελεύθερη + Κατασκευή: πιάτο + Κατασκευή: θόλος + Κατασκευή: κρυφή + diff --git a/OsmAnd/res/values-he/phrases.xml b/OsmAnd/res/values-he/phrases.xml index c943d8f0e8..92bb7a62af 100644 --- a/OsmAnd/res/values-he/phrases.xml +++ b/OsmAnd/res/values-he/phrases.xml @@ -412,7 +412,7 @@ צמיגים מבחן רישוי שנתי לרכב שטיפת רכב - תחנת דלק + תחנת דלק;תחנת תדלוק;תחנת מילוי דלק;תחנת בנזין דיזל דיזל מגז ביו דיזל @@ -1576,4 +1576,28 @@ ללא מגע לא מקבלים ללא מגע - +מסוע שטיח + נקודת מפנה במסלול שיט + תחנת משנה + שנאי + פחיות + מתכת + מנורות מתח נמוך + צינורות פלורוסנט + טטרה פק + נייר אלומיניום + שבבית + השלכת אשפה + אזור מסילות + שימוש קרקע מסחרי + שימוש קרקע קמעונאי + + מעגן + כניסה + יציאה + + מפרק ברשת רכיבה בינלאומית + מפרק ברשת רכיבה לאומית + מפרק ברשת רכיבה אזורית + מפרק ברשת רכיבה מקומית + diff --git a/OsmAnd/res/values-sr/phrases.xml b/OsmAnd/res/values-sr/phrases.xml index ded12d37d2..096cc07422 100644 --- a/OsmAnd/res/values-sr/phrases.xml +++ b/OsmAnd/res/values-sr/phrases.xml @@ -988,7 +988,7 @@ Да Не Ограничен - + Приватни посед Без приступа @@ -1018,7 +1018,7 @@ Неформалан - + Маслина Јабука Палмино уље @@ -1134,4 +1134,108 @@ Трава Песак + Штандови + Специјална зграда + Шупа + Мешано + Врсте + Род + Таксон + + Повремено + + Табла + Маркација на дрвету + Маркер пута + Огласна табла + Нема огњишта + + За пушаче + + Путарина + Без путарине + Мртво дрво + + Ниво + Лака + Средња + Напредна + Почетничка + Експертска + Слободна вожња + Класично + Класично+клизање + Скутером + Клизање + Не + Могул + + Тип баште: стамбена + Тип баште: јавна + Тип баште: приватна + Тип баште: ботаничка + + Тип баште: кухињска + Тип баште: розаријум + Тип баште: француски + Тип баште: енглески + Тип баште: јапански + + Капацитет + Да + Нема посебних места за особе са инвалидитетом + Посебна места за особе са инвалидитетом + Посебна места за жене + Нема посебних места за жене + Посебна места за жене + Посебна места за ученике + Посебна места за наставнике + Посебна места за родитеље + Без посебних места за родитеље + Посебна места за родитеље + + Капацитет на сат + Просечно време путовања, у минутима + Балон + Без балона + Да + Без грејања + Дозвољене + Бицикле: недозвољене + Дозвољене само лети + Само улаз + Само излаз + Улаз и излаз + Летњи приступ: само улаз + Летњи приступ: само излаз + Летњи приступ: улаз и излаз + + Собе + + Љубавни хотел + + Кованице + Кованице се не прихватају + $0.5 кованице + 50c, 1€ и 2€ кованице + Телефонске картице + Телефонске картице се не прихватају + Кредитне картице + Кредитне картице се не прихватају + Новчанице + Новчанице се не прихватају + Електронске ташне + Електронске ташне се не прихватају + Кеш + Кеш се не прихвата + Дебитне картице + Дебитне картице се не прихватају + Биткоин + Биткоин се не прихвата + Visa картице + Visa картице се не прихватају + MasterCard картице + MasterCard картице се не прихватају + Maestro картице + Maestro картице се не прихватају diff --git a/OsmAnd/res/values-sv/strings.xml b/OsmAnd/res/values-sv/strings.xml index cf5e2ca0be..9a9e9c091a 100644 --- a/OsmAnd/res/values-sv/strings.xml +++ b/OsmAnd/res/values-sv/strings.xml @@ -2477,13 +2477,13 @@ Vänligen tillhandahåll fullständig kod Visa/Dölj OSM-anteckningar Visa OSM-anteckningar Dölj OSM-anteckningar - Tryck på åtgärdsknappen visar eller döljer OSM-anteckningar på kartan. + Ett tryck på denna åtgärdsknapp visar eller döljer OSM-anteckningar på kartan. Starta om sökningen Utöka sökradien - Hittade ingenting :( + Hittade ingenting Ändra sökord eller utöka sökradien. Sorterat efter avstånd - Sök favoriter + Sök Favoriter Insticksmodul Färgschema Gruppnamn @@ -2541,11 +2541,11 @@ Vänligen tillhandahåll fullständig kod Välj navigeringsprofil Namn på GPX-fil: Mät avstånd - Återuppta/Pausa navigeringen + Pausa/Återuppta navigeringen Starta/Stoppa navigeringen Återställ Ladda om - Fel användarnamn! + Fel användarnamn Till Från Datum @@ -2572,7 +2572,7 @@ Vänligen tillhandahåll fullständig kod Ordna efter: Alla kartmarkörer har flyttats till historiken Kartmarkören har flyttats till historiken - Använd inte animeringar + Inga animeringar Inaktiverar animeringar i appen. Linje Spara som ruttpunkter @@ -2581,7 +2581,7 @@ Vänligen tillhandahåll fullständig kod Redigera linje Lägg till punkt före Lägg till punkt efter - Du kan spara punkterna antingen som ruttpunkter eller som en linje. + Spara punkterna antingen som ruttpunkter eller som en linje. Lägg till minst en punkt. Visa på kartan när den sparats Peta på denna knapp för att pausa eller fortsätta med navigeringen. @@ -2589,16 +2589,16 @@ Vänligen tillhandahåll fullständig kod Mapillary-bild Öppna Mapillary Förbättra fototäckning med Mapillary - Gör så att du snabbt kan bidraga till Mapillary. + Möjliggör snabba bidrag till Mapillary. nedåt uppåt Kartmarkören flyttad till aktiva Flytta alla till historiken Fortsätt att visa på kartan Titta på kartan och lägg till punkter - Visa dialogen Navigation avslutad + Visa dialogen \'Navigation avslutad\' Spara inspelade spår i mappar efter månad - Spara inspelade spår i undermappar efter inspelad månad (typ 2017-01). + Spara inspelade spår i undermappar efter inspelad månad (typ 2018-01). Visa endast tillagda bilder Visa endast bilder tillagda av kan importeras som favoriter eller som GPX-fil. @@ -2682,7 +2682,7 @@ Vänligen tillhandahåll fullständig kod Åtgärder Markör Tryck på en markör på kartan för att flytta den till toppen av de aktiva markörerna utan att öppna sammanhangsmenyn. - Ett tryck för att aktivera + \'Ett tryck\' aktiv Lägg till ljud-, video- eller fotonotering för varje punkt på kartan, med hjälp av widgeten eller menyn. Välj ett spår för att lägga till dess waypoints till markörer. Välj en favoritkategori för att lägga till markörer. @@ -2721,27 +2721,25 @@ Vänligen tillhandahåll fullständig kod Charlott ansluter punkter med vägar för den valda profilen. Ladda tiles för att se aktuell data. Tile-cache - Du kan filtrera bilderna enligt inlämnare eller datum. Filter tillämpas endast för närbildszoom. + Filtrera bilderna enligt inlämnare eller datum. Filter tillämpas endast för närbildszoom. Radielinjal - Du kan ta dina egna bilder eller en serie bilder och bifoga dem till denna kartplats. -\n -\nFör att göra detta måste du installera Mapillary app från Google Play Store. + Installera Mapillary för att lägga till en eller flera bilder till denna plats på kartan. Bidra med din egen gatnivåvy på denna plats via Mapillary. Online gatunivåbilder för alla. Upptäck platser, samarbeta, fånga världen. Gatunivå bilder för alla. Upptäck platser, samarbeta, fånga världen. - Din destination är belägen i ett område med privat tillträde. Vill du att ge tillgång till privata vägar för denna resa? - För att se relief-höjdskuggning på kartan, behöver du för att ladda ner den höjdskuggskartan för denna region. - För att se höjdskuggningsrelief på kartan, behöver du köpa och installera insticksmodulen konturlinjer + Din destination är belägen i ett område med privat tillträde. Tillåt tillgång till privata vägar för denna resa? + För att se relief-höjdskuggning på kartan, ladda ner höjdskuggskartan för denna region. + För att se höjdskuggningsrelief på kartan, behöver du köpa och installera insticksmodulen \'Konturlinjer\' Dölja från zoom-nivå - Om du vill visa höjdkurvor på kartan, behöver du ladda ner konturlinjekarta över denna region. - För att se höjdkurvor på kartan, behöver du köpa och installera insticksmodulen Konturlinjer + Ladda ner \'konturlinjekarta\' över denna region. + För att se höjdkurvor på kartan, behöver du köpa och installera insticksmodulen \'Konturlinjer\' Visa från zoom-nivå Tillåt privat åtkomst Tillåta åtkomst till privata områden. Visa zoom-nivå: %1$s - Aktivera kartpanoreringsanimation av Min Position under navigering. + Aktivera kartpanoreringsanimation av \'Min Position\' under navigering. Översikt - Knackning på åtgärdsknappen kommer att slå på/av automatisk zoomkarta enligt din hastighet. + Ett tryck på den här åtgärdsknappen kommer att slå på/av automatisk zoomkarta enligt din hastighet. Aktivera autozoom karta Inaktivera autozoom karta Lägg till första mellanliggande