Merge pull request #10157 from osmandapp/master

update test branch
This commit is contained in:
Hardy 2020-11-09 18:19:10 +01:00 committed by GitHub
commit 79280b7263
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 578 additions and 231 deletions

15
GPX.md
View file

@ -1,11 +1,11 @@
The OsmAnd's GPX file format conforms to GPX 1.1 specification with additional data written as extensions. There are few sections of such data: The OsmAnd's GPX file format conforms to the GPX 1.1 specification with additional data written as extensions. There are several sections of such data:
## Track appearance ## Track appearance
These parameters are used to customize the appearance of a track on the map. Used inside "gpx" tag and applies to all tracks inside gpx. The following parameters are used to customize the appearance of a track on the map. They are used inside the "gpx" tag and apply to all tracks contained in the gpx.
#### Parameters #### Parameters
* **show_arrows** [*true, false*] - show / hide arrows along the path line. * **show_arrows** [*true, false*] - show / hide arrows along the path line.
* **width** [*thin, medium, bold, 1-24*] - width of a track line on the map. The thin, medium and bold are style depended values (should be defined as currentTrackWidth attribute). * **width** [*thin, medium, bold, 1-24*] - width of the track line on the map. The thin, medium, and bold are style depended values (should be defined as currentTrackWidth attribute).
* **color** [*#AARRGGBB, #RRGGBB*] - color of a track line on the map. Hex values. * **color** [*#AARRGGBB, #RRGGBB*] - color of a track line on the map. Hex value.
* **split_type** [*no_split, distance, time*] - split type for a track. * **split_type** [*no_split, distance, time*] - split type for a track.
* **split_interval** [*double*] - split interval for a track. Distance (meters), time (seconds). * **split_interval** [*double*] - split interval for a track. Distance (meters), time (seconds).
@ -41,11 +41,10 @@ Written to a gpx file while recording a track.
``` ```
## Calculated route(s) ## Calculated route(s)
This data contains information about a route built with **OsmAnd** (route segments, turns, road names and types, restrictions, etc.). With their help, route can be restored completely as if it had just been built even without the currently installed offline maps. This data contains all details of a route built with **OsmAnd** (route segments, turns, road names, road types, restrictions, etc.). The route can be completely restored as if just built, even in the absence of the respective offline maps.
There can be several routes in one gpx file. Each of them is contained in a specific segment (**trkseg** / **extensions**). In this form, a gpx file is saved when exporting a constructed route or when saving a track that consists of several separate segments via the **Plan route**.
When using the **Plan route** tool, route key points (**rtept**) are additionally written to the gpx file. There can also be several **rte** blocks (according to a number of separate segments / tracks in a gpx file).
A gpx file may contain several routes. Each of them is contained in a specific segment under **trkseg** / **extensions**. A gpx file is saved in this form when exporting a constructed route or when saving a track that consists of several separate segments via the **Plan a route** functionality.
**Plan a route** also adds one (or several, in accordance with the number of contained separate segments / tracks) **rte** blocks to the gpx file, containing route key points (**rtept**).
#### Gpx structure: #### Gpx structure:
```xml ```xml
<trk> <trk>

View file

@ -71,6 +71,7 @@ public class GPXUtilities {
WHITE(0xFFFFFFFF), WHITE(0xFFFFFFFF),
RED(0xFFFF0000), RED(0xFFFF0000),
GREEN(0xFF00FF00), GREEN(0xFF00FF00),
DARKGREEN(0xFF006400),
BLUE(0xFF0000FF), BLUE(0xFF0000FF),
YELLOW(0xFFFFFF00), YELLOW(0xFFFFFF00),
CYAN(0xFF00FFFF), CYAN(0xFF00FFFF),

View file

@ -18,7 +18,6 @@ import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.* import net.osmand.telegram.helpers.TelegramHelper.*
import net.osmand.telegram.notifications.TelegramNotification.NotificationType import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import net.osmand.telegram.utils.AndroidUtils import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandLocationUtils
import org.drinkless.td.libcore.telegram.TdApi import org.drinkless.td.libcore.telegram.TdApi
import java.util.* import java.util.*
@ -377,7 +376,10 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
Log.d(PlatformUtil.TAG, "Send live location error: $code - $message") Log.d(PlatformUtil.TAG, "Send live location error: $code - $message")
when (messageType) { when (messageType) {
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText-- TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText--
TelegramHelper.MESSAGE_TYPE_MAP -> shareInfo.pendingTdLibMap-- TelegramHelper.MESSAGE_TYPE_MAP -> {
shareInfo.pendingTdLibMap--
shareInfo.currentMapMessageId = -1L
}
} }
} }

View file

@ -304,27 +304,18 @@ class TelegramSettings(private val app: TelegramApplication) {
fun prepareForSharingNewMessages() { fun prepareForSharingNewMessages() {
shareChatsInfo.forEach { (_, shareInfo) -> shareChatsInfo.forEach { (_, shareInfo) ->
prepareForSharingNewMessages(shareInfo) shareInfo.resetMessagesInfo()
} }
} }
fun prepareForSharingNewMessages(chatsIds: List<Long>) { fun prepareForSharingNewMessages(chatsIds: List<Long>) {
chatsIds.forEach { chatsIds.forEach {
shareChatsInfo[it]?.also { shareInfo -> shareChatsInfo[it]?.also { shareInfo ->
prepareForSharingNewMessages(shareInfo) shareInfo.resetMessagesInfo()
} }
} }
} }
fun prepareForSharingNewMessages(shareInfo: ShareChatInfo) {
shareInfo.pendingTdLibText = 0
shareInfo.pendingTdLibMap = 0
shareInfo.currentTextMessageId = -1L
shareInfo.currentMapMessageId = -1L
shareInfo.pendingTextMessage = false
shareInfo.pendingMapMessage = false
}
fun getChatLivePeriod(chatId: Long) = shareChatsInfo[chatId]?.livePeriod fun getChatLivePeriod(chatId: Long) = shareChatsInfo[chatId]?.livePeriod
fun getChatsShareInfo() = shareChatsInfo fun getChatsShareInfo() = shareChatsInfo
@ -1497,6 +1488,27 @@ class TelegramSettings(private val app: TelegramApplication) {
fun isPendingMapMessagesLimitReached() = pendingTdLibMap >= MAX_MESSAGES_IN_TDLIB_PER_CHAT fun isPendingMapMessagesLimitReached() = pendingTdLibMap >= MAX_MESSAGES_IN_TDLIB_PER_CHAT
fun resetMessagesInfo() {
resetTextMessageInfo()
resetMapMessageInfo()
}
fun resetTextMessageInfo() {
pendingTdLibText = 0
currentTextMessageId = -1L
pendingTextMessage = false
}
fun resetMapMessageInfo() {
pendingTdLibMap = 0
currentMapMessageId = -1L
pendingMapMessage = false
}
fun isTextMessageIdPresent() = currentTextMessageId != -1L
fun isMapMessageIdPresent() = currentMapMessageId != -1L
companion object { companion object {
internal const val CHAT_ID_KEY = "chatId" internal const val CHAT_ID_KEY = "chatId"

View file

@ -138,7 +138,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
} }
} }
if (pendingMessagesLimitReached && checkNetworkTypeAllowed) { if (pendingMessagesLimitReached && checkNetworkTypeAllowed) {
checkNetworkType() updateNetworkType()
} }
} }
@ -167,7 +167,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
app.locationMessages.getBufferedTextMessagesForChat(chatId).take(MAX_MESSAGES_IN_TDLIB_PER_CHAT).forEach { app.locationMessages.getBufferedTextMessagesForChat(chatId).take(MAX_MESSAGES_IN_TDLIB_PER_CHAT).forEach {
if (!shareInfo.isPendingTextMessagesLimitReached()) { if (!shareInfo.isPendingTextMessagesLimitReached()) {
if (it.deviceName.isEmpty()) { if (it.deviceName.isEmpty()) {
if (!shareInfo.pendingTextMessage && shareInfo.currentTextMessageId != -1L) { if (!shareInfo.pendingTextMessage && shareInfo.isTextMessageIdPresent()) {
val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, it, app) val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, it, app)
app.telegramHelper.editTextLocation(shareInfo, content) app.telegramHelper.editTextLocation(shareInfo, content)
app.locationMessages.removeBufferedMessage(it) app.locationMessages.removeBufferedMessage(it)
@ -180,8 +180,12 @@ class ShareLocationHelper(private val app: TelegramApplication) {
app.locationMessages.getBufferedMapMessagesForChat(chatId).take(MAX_MESSAGES_IN_TDLIB_PER_CHAT).forEach { app.locationMessages.getBufferedMapMessagesForChat(chatId).take(MAX_MESSAGES_IN_TDLIB_PER_CHAT).forEach {
if (!shareInfo.isPendingMapMessagesLimitReached()) { if (!shareInfo.isPendingMapMessagesLimitReached()) {
if (it.deviceName.isEmpty()) { if (it.deviceName.isEmpty()) {
if (!shareInfo.pendingMapMessage && shareInfo.currentMapMessageId != -1L) { if (!shareInfo.pendingMapMessage) {
app.telegramHelper.editMapLocation(shareInfo, it) if (shareInfo.isMapMessageIdPresent()) {
app.telegramHelper.editMapLocation(shareInfo, it)
} else {
app.telegramHelper.sendNewMapLocation(shareInfo, it)
}
app.locationMessages.removeBufferedMessage(it) app.locationMessages.removeBufferedMessage(it)
} }
} else { } else {
@ -279,7 +283,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
} }
} }
if (pendingMessagesLimitReached) { if (pendingMessagesLimitReached) {
checkNetworkType() updateNetworkType()
} }
} }
@ -347,7 +351,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
} }
} }
fun checkNetworkType(){ fun updateNetworkType(){
if (app.isInternetConnectionAvailable) { if (app.isInternetConnectionAvailable) {
val networkType = when { val networkType = when {
app.isWifiConnected -> TdApi.NetworkTypeWiFi() app.isWifiConnected -> TdApi.NetworkTypeWiFi()

View file

@ -840,7 +840,7 @@ class TelegramHelper private constructor() {
} }
fun stopSendingLiveLocationToChat(shareInfo: ShareChatInfo) { fun stopSendingLiveLocationToChat(shareInfo: ShareChatInfo) {
if (shareInfo.currentMapMessageId != -1L && shareInfo.chatId != -1L) { if (!shareInfo.isMapMessageIdPresent() && shareInfo.chatId != -1L) {
shareInfo.lastSendMapMessageTime = (System.currentTimeMillis() / 1000).toInt() shareInfo.lastSendMapMessageTime = (System.currentTimeMillis() / 1000).toInt()
client?.send( client?.send(
TdApi.EditMessageLiveLocation(shareInfo.chatId, shareInfo.currentMapMessageId, null, null)) { obj -> TdApi.EditMessageLiveLocation(shareInfo.chatId, shareInfo.currentMapMessageId, null, null)) { obj ->

View file

@ -15,7 +15,6 @@ import android.widget.TextView
import androidx.appcompat.widget.ListPopupWindow import androidx.appcompat.widget.ListPopupWindow
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import net.osmand.Location import net.osmand.Location
import net.osmand.data.LatLon import net.osmand.data.LatLon
import net.osmand.telegram.R import net.osmand.telegram.R
@ -99,7 +98,7 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
mainView.findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipe_refresh).apply { mainView.findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipe_refresh).apply {
setOnRefreshListener { setOnRefreshListener {
app.shareLocationHelper.checkNetworkType() app.shareLocationHelper.updateNetworkType()
app.telegramHelper.scanChatsHistory() app.telegramHelper.scanChatsHistory()
updateList() updateList()
isRefreshing = false isRefreshing = false

View file

@ -72,7 +72,7 @@ class SharingStatusBottomSheet : DialogFragment() {
if (sharingStatusType.canResendLocation) { if (sharingStatusType.canResendLocation) {
if (i == 0) { if (i == 0) {
setOnClickListener { setOnClickListener {
app.shareLocationHelper.checkNetworkType() app.shareLocationHelper.updateNetworkType()
app.settings.prepareForSharingNewMessages(sharingStatus.chatsIds) app.settings.prepareForSharingNewMessages(sharingStatus.chatsIds)
app.shareLocationHelper.checkAndSendBufferMessages() app.shareLocationHelper.checkAndSendBufferMessages()
app.forceUpdateMyLocation() app.forceUpdateMyLocation()

View file

@ -7,7 +7,7 @@
android:layout_height="@dimen/dialog_button_height" android:layout_height="@dimen/dialog_button_height"
android:layout_weight="1"> android:layout_weight="1">
<LinearLayout <FrameLayout
android:id="@+id/button_container" android:id="@+id/button_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -16,18 +16,20 @@
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:id="@+id/button_text" android:id="@+id/button_text"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingLeft="@dimen/content_padding_small" android:paddingLeft="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding_small" android:paddingRight="@dimen/content_padding_small"
android:gravity="center" android:gravity="center"
android:layout_gravity="center"
android:textSize="@dimen/default_desc_text_size" android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium" osmand:typeface="@string/font_roboto_medium"
android:duplicateParentState="true" android:duplicateParentState="true"
android:drawablePadding="@dimen/content_padding_half"
tools:text="Button" tools:text="Button"
android:paddingStart="@dimen/content_padding_small" android:paddingStart="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding_small" /> android:paddingEnd="@dimen/content_padding_small" />
</LinearLayout> </FrameLayout>
</LinearLayout> </LinearLayout>

View file

@ -0,0 +1,50 @@
<?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:minHeight="@dimen/bottom_sheet_selected_item_title_height"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:paddingTop="@dimen/measurement_tool_menu_title_padding_top"
android:orientation="vertical"
android:paddingEnd="@dimen/content_padding"
android:paddingStart="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_half">
<ImageView
android:id="@+id/header"
osmand:srcCompat="@drawable/ic_action_openstreetmap_logo_colored"
android:gravity="center"
android:layout_width="@dimen/bottom_sheet_list_item_height"
android:layout_height="@dimen/bottom_sheet_list_item_height"
android:layout_gravity="center"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/content_padding_small"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:layout_marginTop="@dimen/content_padding_small"
android:paddingBottom="@dimen/content_padding_small"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium"
android:text="@string/login_open_street_map_org" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lineSpacingMultiplier="@dimen/bottom_sheet_text_spacing_multiplier"
android:textColor="?android:textColorPrimary"
android:paddingTop="@dimen/content_padding_small"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
android:text="@string/open_street_map_login_mode" />
</LinearLayout>

View file

@ -4,67 +4,54 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding" android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding" android:paddingTop="@dimen/bottom_sheet_content_margin"
android:paddingBottom="@dimen/dialog_button_height"
android:paddingEnd="@dimen/content_padding" android:paddingEnd="@dimen/content_padding"
android:paddingStart="@dimen/content_padding"> android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/bottom_sheet_content_margin">
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/bottom_sheet_content_margin"
android:ellipsize="end" android:ellipsize="end"
android:gravity="center_vertical" android:gravity="center_vertical"
android:letterSpacing="@dimen/text_button_letter_spacing" android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="1" android:maxLines="1"
android:minHeight="@dimen/bottom_sheet_title_height" android:minHeight="@dimen/bottom_sheet_icon_margin"
android:text="@string/login_and_pass" android:text="@string/login_open_street_map"
android:textAppearance="@style/TextAppearance.ListItemTitle" android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium" /> osmand:typeface="@string/font_roboto_medium" />
<net.osmand.plus.widgets.TextViewEx <com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center_vertical"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="1"
android:paddingBottom="@dimen/content_padding"
android:text="@string/open_street_map_login_descr"
android:textAppearance="@style/TextAppearance.ListItemTitle"
osmand:typeface="@string/font_roboto_regular" />
<net.osmand.plus.widgets.OsmandTextFieldBoxes
android:id="@+id/name_text_box" android:id="@+id/name_text_box"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingBottom="@dimen/content_padding" android:layout_marginBottom="@dimen/bottom_sheet_content_margin"
osmand:labelText="@string/user_name"> android:hint="@string/user_login">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/name_edit_text" android:id="@+id/name_edit_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:imeOptions="actionDone" android:imeOptions="actionDone" />
android:inputType="text"
android:maxLines="1" />
</net.osmand.plus.widgets.OsmandTextFieldBoxes> </com.google.android.material.textfield.TextInputLayout>
<net.osmand.plus.widgets.OsmandTextFieldBoxes <com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_text_box" android:id="@+id/password_text_box"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
osmand:labelText="@string/user_password"> android:hint="@string/user_password">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_edit_text" android:id="@+id/password_edit_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:imeOptions="actionDone" android:imeOptions="actionDone"
android:inputType="textPassword" android:inputType="textPassword" />
android:maxLines="1" />
</net.osmand.plus.widgets.OsmandTextFieldBoxes> </com.google.android.material.textfield.TextInputLayout>
</LinearLayout> </LinearLayout>

View file

@ -0,0 +1,80 @@
<?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/list_background_color"
android:gravity="center_vertical">
<LinearLayout
android:id="@+id/selectable_list_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/setting_list_item_large_height"
tools:background="?android:attr/selectableItemBackground">
<androidx.appcompat.widget.AppCompatImageView
android:id="@android:id/icon"
android:layout_width="@dimen/standard_icon_size"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/bottom_sheet_icon_margin"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/bottom_sheet_icon_margin"
tools:src="@drawable/ic_action_user_account" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<net.osmand.plus.widgets.TextViewEx
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:singleLine="true"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular" />
<net.osmand.plus.widgets.TextViewEx
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/description_letter_spacing"
android:maxLines="4"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon_logout"
android:layout_width="wrap_content"
android:layout_height="@dimen/standard_icon_size"
android:layout_gravity="center"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/bottom_sheet_icon_margin"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/bottom_sheet_icon_margin"
android:tint="@color/active_buttons_and_links_text_disabled_light"
osmand:srcCompat="@drawable/ic_action_logout" />
</LinearLayout>
</LinearLayout>

View file

@ -16,6 +16,16 @@
<string name="subscription_expired_title">OsmAnd Live subscription has been expired</string> <string name="subscription_expired_title">OsmAnd Live subscription has been expired</string>
<string name="subscription_payment_issue_title">There is a problem with your subscription. Click the button to go to the Google Play subscription settings to fix your payment method.</string> <string name="subscription_payment_issue_title">There is a problem with your subscription. Click the button to go to the Google Play subscription settings to fix your payment method.</string>
<string name="manage_subscription">Manage subscription</string> <string name="manage_subscription">Manage subscription</string>
<string name="user_login">Login</string>
<string name="user_password">Password</string>
<string name="login_account">Account</string>
<string name="use_login_password">Use login and password</string>
<string name="open_street_map_login_mode">You need to login to upload new or modified changes. \n\nYou can log in using the safe OAuth method or use your login and password.</string>
<string name="osm_edits_view_descr">You can view all your unloaded edits or OSM bugs in %1$s. Uploaded points dont show in OsmAnd.</string>
<string name="sing_in_with_open_street_map">Sing in with OpenStreetMap</string>
<string name="login_open_street_map_org">Login to OpenStreetMap.org</string>
<string name="login_open_street_map">Login to OpenStreetMap</string>
<string name="plugin_global_prefs_info">These plugin setting are global, and apply to all profiles</string>
<string name="message_you_need_add_two_points_to_show_graphs">You must add at least two points.</string> <string name="message_you_need_add_two_points_to_show_graphs">You must add at least two points.</string>
<string name="icon_group_travel">Travel</string> <string name="icon_group_travel">Travel</string>
<string name="icon_group_emergency">Emergency</string> <string name="icon_group_emergency">Emergency</string>
@ -487,9 +497,7 @@
<string name="route_recalculation">Route recalculation</string> <string name="route_recalculation">Route recalculation</string>
<string name="accessibility_announce">Announce</string> <string name="accessibility_announce">Announce</string>
<string name="login_and_pass">Username and password</string> <string name="login_and_pass">Username and password</string>
<string name="plugin_global_prefs_info">These settings apply to all profiles.</string>
<string name="osm_editing">OSM editing</string> <string name="osm_editing">OSM editing</string>
<string name="osm_edits_view_descr">View your edits or OSM bugs not yet uploaded in %1$s. Uploaded points will not show any more.</string>
<string name="app_mode_osm">OSM</string> <string name="app_mode_osm">OSM</string>
<string name="select_nav_icon_descr">Icon shown while navigating or moving.</string> <string name="select_nav_icon_descr">Icon shown while navigating or moving.</string>
<string name="select_map_icon_descr">Icon shown at rest.</string> <string name="select_map_icon_descr">Icon shown at rest.</string>
@ -2426,7 +2434,6 @@
<string name="lang_fr">French</string> <string name="lang_fr">French</string>
<string name="lang_ka">Georgian</string> <string name="lang_ka">Georgian</string>
<string name="lang_de">German</string> <string name="lang_de">German</string>
<string name="lang_de_casual">German (casual)</string>
<string name="lang_el">Greek</string> <string name="lang_el">Greek</string>
<string name="lang_he">Hebrew</string> <string name="lang_he">Hebrew</string>
<string name="lang_iw">Hebrew</string> <string name="lang_iw">Hebrew</string>
@ -3202,7 +3209,6 @@
<string name="global_app_settings">Global app settings</string> <string name="global_app_settings">Global app settings</string>
<string name="user_name">Your OSM username</string> <string name="user_name">Your OSM username</string>
<string name="open_street_map_login_descr">Needed for openstreetmap.org submissions.</string> <string name="open_street_map_login_descr">Needed for openstreetmap.org submissions.</string>
<string name="user_password">Your OSM password</string>
<string name="osmand_service">Background mode</string> <string name="osmand_service">Background mode</string>
<string name="osmand_service_descr">OsmAnd runs in the background with the screen off.</string> <string name="osmand_service_descr">OsmAnd runs in the background with the screen off.</string>
<string name="download_files_not_enough_space">There is not enough free space to download %1$s MB (free: %2$s).</string> <string name="download_files_not_enough_space">There is not enough free space to download %1$s MB (free: %2$s).</string>

View file

@ -16,9 +16,13 @@
android:key="osm_login_data" android:key="osm_login_data"
android:layout="@layout/preference_with_descr" android:layout="@layout/preference_with_descr"
android:persistent="false" android:persistent="false"
android:title="@string/login_and_pass" android:title="@string/login_open_street_map" />
tools:icon="@drawable/ic_action_openstreetmap_logo"
tools:summary="@string/open_street_map_login_descr" /> <Preference
android:key="osm_logout"
android:layout="@layout/preference_login"
android:persistent="false"
android:title="@string/login_account" />
<net.osmand.plus.settings.preferences.SwitchPreferenceEx <net.osmand.plus.settings.preferences.SwitchPreferenceEx
android:key="offline_osm_editing" android:key="offline_osm_editing"

View file

@ -541,10 +541,10 @@ public abstract class OsmandPlugin {
protected void addMyPlacesTab(FavoritesActivity favoritesActivity, List<TabItem> mTabs, Intent intent) { protected void addMyPlacesTab(FavoritesActivity favoritesActivity, List<TabItem> mTabs, Intent intent) {
} }
protected void contextMenuFragment(Activity activity, Fragment fragment, Object info, ContextMenuAdapter adapter) { protected void contextMenuFragment(FragmentActivity activity, Fragment fragment, Object info, ContextMenuAdapter adapter) {
} }
protected void optionsMenuFragment(Activity activity, Fragment fragment, ContextMenuAdapter optionsMenuAdapter) { protected void optionsMenuFragment(FragmentActivity activity, Fragment fragment, ContextMenuAdapter optionsMenuAdapter) {
} }
protected boolean searchFinished(QuickSearchDialogFragment searchFragment, SearchPhrase phrase, boolean isResultEmpty) { protected boolean searchFinished(QuickSearchDialogFragment searchFragment, SearchPhrase phrase, boolean isResultEmpty) {
@ -815,14 +815,13 @@ public abstract class OsmandPlugin {
} }
} }
public static void onContextMenuActivity(Activity activity, Fragment fragment, Object info, ContextMenuAdapter adapter) { public static void onContextMenuActivity(FragmentActivity activity, Fragment fragment, Object info, ContextMenuAdapter adapter) {
for (OsmandPlugin plugin : getEnabledPlugins()) { for (OsmandPlugin plugin : getEnabledPlugins()) {
plugin.contextMenuFragment(activity, fragment, info, adapter); plugin.contextMenuFragment(activity, fragment, info, adapter);
} }
} }
public static void onOptionsMenuActivity(FragmentActivity activity, Fragment fragment, ContextMenuAdapter optionsMenuAdapter) {
public static void onOptionsMenuActivity(Activity activity, Fragment fragment, ContextMenuAdapter optionsMenuAdapter) {
for (OsmandPlugin plugin : getEnabledPlugins()) { for (OsmandPlugin plugin : getEnabledPlugins()) {
plugin.optionsMenuFragment(activity, fragment, optionsMenuAdapter); plugin.optionsMenuFragment(activity, fragment, optionsMenuAdapter);
} }

View file

@ -134,11 +134,11 @@ public class Version {
} }
public static boolean isDeveloperVersion(OsmandApplication ctx){ public static boolean isDeveloperVersion(OsmandApplication ctx){
return false;//getAppName(ctx).contains("~") || ctx.getPackageName().equals(FREE_DEV_VERSION_NAME); return getAppName(ctx).contains("~") || ctx.getPackageName().equals(FREE_DEV_VERSION_NAME);
} }
public static boolean isDeveloperBuild(OsmandApplication ctx){ public static boolean isDeveloperBuild(OsmandApplication ctx){
return false;//getAppName(ctx).contains("~"); return getAppName(ctx).contains("~");
} }
public static String getVersionForTracker(OsmandApplication ctx) { public static String getVersionForTracker(OsmandApplication ctx) {

View file

@ -115,10 +115,10 @@ import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
import net.osmand.plus.mapmarkers.PlanRouteFragment; import net.osmand.plus.mapmarkers.PlanRouteFragment;
import net.osmand.plus.measurementtool.GpxApproximationFragment; import net.osmand.plus.measurementtool.GpxApproximationFragment;
import net.osmand.plus.measurementtool.GpxData; import net.osmand.plus.measurementtool.GpxData;
import net.osmand.plus.measurementtool.LoginBottomSheetFragment;
import net.osmand.plus.measurementtool.MeasurementEditingContext; import net.osmand.plus.measurementtool.MeasurementEditingContext;
import net.osmand.plus.measurementtool.MeasurementToolFragment; import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.measurementtool.SnapTrackWarningFragment; import net.osmand.plus.measurementtool.SnapTrackWarningFragment;
import net.osmand.plus.osmedit.OsmEditingFragment;
import net.osmand.plus.render.RendererRegistry; import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.resources.ResourceManager; import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.routepreparationmenu.ChooseRouteFragment; import net.osmand.plus.routepreparationmenu.ChooseRouteFragment;
@ -2215,8 +2215,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
return getFragment(GpxApproximationFragment.TAG); return getFragment(GpxApproximationFragment.TAG);
} }
public OsmEditingFragment getOsmEditingFragment() { public LoginBottomSheetFragment getLoginBottomSheetFragment() {
return getFragment(SettingsScreenType.OPEN_STREET_MAP_EDITING.fragmentName); return getFragment(LoginBottomSheetFragment.TAG);
} }
public SnapTrackWarningFragment getSnapTrackWarningBottomSheet() { public SnapTrackWarningFragment getSnapTrackWarningBottomSheet() {

View file

@ -377,7 +377,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
return getResources().getDimensionPixelSize(R.dimen.content_padding); return getResources().getDimensionPixelSize(R.dimen.content_padding);
} }
private void setupThirdButton() { protected void setupThirdButton() {
thirdButton = buttonsContainer.findViewById(R.id.third_button); thirdButton = buttonsContainer.findViewById(R.id.third_button);
int buttonTextId = getThirdBottomButtonTextId(); int buttonTextId = getThirdBottomButtonTextId();
if (buttonTextId != DEFAULT_VALUE) { if (buttonTextId != DEFAULT_VALUE) {

View file

@ -79,13 +79,6 @@ public class RasterMapMenu {
new OnMapSelectedCallback() { new OnMapSelectedCallback() {
@Override @Override
public void onMapSelected(boolean canceled) { public void onMapSelected(boolean canceled) {
if (type == RasterMapType.UNDERLAY && !canceled && !selected) {
hidePolygonsPref.set(true);
refreshMapComplete(mapActivity);
} else if (type == RasterMapType.UNDERLAY && !canceled && mapTypePreference.get() == null) {
hidePolygonsPref.set(false);
refreshMapComplete(mapActivity);
}
mapActivity.getDashboard().refreshContent(true); mapActivity.getDashboard().refreshContent(true);
} }
}; };

View file

@ -19,7 +19,7 @@ import net.osmand.plus.activities.PluginsFragment;
import net.osmand.plus.dashboard.DashboardOnMap.DashboardType; import net.osmand.plus.dashboard.DashboardOnMap.DashboardType;
import net.osmand.plus.mapmarkers.MapMarkersDialogFragment; import net.osmand.plus.mapmarkers.MapMarkersDialogFragment;
import net.osmand.plus.mapsource.EditMapSourceDialogFragment; import net.osmand.plus.mapsource.EditMapSourceDialogFragment;
import net.osmand.plus.osmedit.OsmEditingFragment; import net.osmand.plus.measurementtool.LoginBottomSheetFragment;
import net.osmand.plus.search.QuickSearchDialogFragment; import net.osmand.plus.search.QuickSearchDialogFragment;
import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.backend.OsmandSettings;
@ -293,7 +293,7 @@ public class IntentHelper {
if (intent != null && intent.getData() != null) { if (intent != null && intent.getData() != null) {
Uri uri = intent.getData(); Uri uri = intent.getData();
if (uri.toString().startsWith("osmand-oauth")) { if (uri.toString().startsWith("osmand-oauth")) {
OsmEditingFragment fragment = mapActivity.getOsmEditingFragment(); LoginBottomSheetFragment fragment = mapActivity.getLoginBottomSheetFragment();
if (fragment != null) { if (fragment != null) {
String oauthVerifier = uri.getQueryParameter("oauth_verifier"); String oauthVerifier = uri.getQueryParameter("oauth_verifier");
fragment.authorize(oauthVerifier); fragment.authorize(oauthVerifier);

View file

@ -0,0 +1,142 @@
package net.osmand.plus.measurementtool;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities.DialogButtonType;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.bottomsheets.OsmLoginDataBottomSheet;
import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
public class LoginBottomSheetFragment extends MenuBottomSheetDialogFragment {
public static final String TAG = LoginBottomSheetFragment.class.getSimpleName();
private static final Log log = PlatformUtil.getLog(LoginBottomSheetFragment.class);
private static final String OSM_LOGIN_DATA = "osm_login_data";
private OsmOAuthAuthorizationAdapter authorizationAdapter;
@Override
public void createMenuItems(Bundle savedInstanceState) {
OsmandApplication app = requiredMyApplication();
authorizationAdapter = new OsmOAuthAuthorizationAdapter(app);
items.add(new SimpleBottomSheetItem.Builder().setLayoutId(R.layout.bottom_sheet_login).create());
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_cancel;
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.use_login_password;
}
@Override
protected void setupThirdButton() {
super.setupThirdButton();
OsmandApplication app = getMyApplication();
if (app != null) {
Drawable icon = app.getUIUtilities().getIcon(R.drawable.ic_action_openstreetmap_logo, R.color.popup_text_color);
TextView buttonText = thirdButton.findViewById(R.id.button_text);
AndroidUtils.setCompoundDrawablesWithIntrinsicBounds(buttonText, icon, null, null, null);
}
}
@Override
protected int getThirdBottomButtonTextId() {
return R.string.sing_in_with_open_street_map;
}
@Override
public int getFirstDividerHeight() {
return getResources().getDimensionPixelSize(R.dimen.card_content_padding_large);
}
@Override
protected void onRightBottomButtonClick() {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) {
OsmLoginDataBottomSheet.showInstance(fragmentManager, OSM_LOGIN_DATA, getTargetFragment(), usedOnMap, null);
}
dismiss();
}
@Override
protected void onThirdBottomButtonClick() {
View view = getView();
if (view != null) {
authorizationAdapter.startOAuth((ViewGroup) view);
}
}
@Override
protected DialogButtonType getRightBottomButtonType() {
return (DialogButtonType.SECONDARY);
}
public static void showInstance(@NonNull FragmentManager fragmentManager, @Nullable Fragment targetFragment) {
if (!fragmentManager.isStateSaved()) {
LoginBottomSheetFragment fragment = new LoginBottomSheetFragment();
fragment.setTargetFragment(targetFragment, 0);
fragment.show(fragmentManager, TAG);
}
}
public void authorize(String oauthVerifier) {
if (authorizationAdapter != null) {
authorizationAdapter.authorize(oauthVerifier);
updateUserName();
}
Fragment target = getTargetFragment();
if (target instanceof OsmAuthorizationListener) {
((OsmAuthorizationListener) target).authorizationCompleted();
}
dismiss();
}
private void updateUserName() {
OsmandApplication app = getMyApplication();
if (app != null) {
String userName = "";
try {
userName = authorizationAdapter.getUserName();
} catch (InterruptedException e) {
log.error(e);
} catch (ExecutionException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
} catch (XmlPullParserException e) {
log.error(e);
}
app.getSettings().USER_DISPLAY_NAME.set(userName);
}
}
public interface OsmAuthorizationListener {
void authorizationCompleted();
}
}

View file

@ -92,7 +92,7 @@ public class MeasurementEditingContext {
private final WptPt end; private final WptPt end;
private final List<WptPt> points; private final List<WptPt> points;
private final List<RouteSegmentResult> segments; private final List<RouteSegmentResult> segments;
private double distance; private final double distance;
public RoadSegmentData(@NonNull ApplicationMode appMode, @NonNull WptPt start, @NonNull WptPt end, public RoadSegmentData(@NonNull ApplicationMode appMode, @NonNull WptPt start, @NonNull WptPt end,
@Nullable List<WptPt> points, @Nullable List<RouteSegmentResult> segments) { @Nullable List<WptPt> points, @Nullable List<RouteSegmentResult> segments) {
@ -101,20 +101,18 @@ public class MeasurementEditingContext {
this.end = end; this.end = end;
this.points = points; this.points = points;
this.segments = segments; this.segments = segments;
if (segments != null) { double distance = 0;
double distance = 0; if (points != null && points.size() > 1) {
for (RouteSegmentResult segment : segments) {
distance += segment.getDistance();
}
this.distance = distance;
} else if (points != null && points.size() > 1) {
double distance = 0;
for (int i = 1; i < points.size(); i++) { for (int i = 1; i < points.size(); i++) {
distance += MapUtils.getDistance(points.get(i - 1).lat, points.get(i - 1).lon, distance += MapUtils.getDistance(points.get(i - 1).lat, points.get(i - 1).lon,
points.get(i).lat, points.get(i).lon); points.get(i).lat, points.get(i).lon);
} }
this.distance = distance; } else if (segments != null) {
for (RouteSegmentResult segment : segments) {
distance += segment.getDistance();
}
} }
this.distance = distance;
} }
public ApplicationMode getAppMode() { public ApplicationMode getAppMode() {
@ -259,14 +257,8 @@ public class MeasurementEditingContext {
RoadSegmentData data = this.roadSegmentData.get(pair); RoadSegmentData data = this.roadSegmentData.get(pair);
if (data == null) { if (data == null) {
if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE || !pair.first.lastPoint || !pair.second.firstPoint) { if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE || !pair.first.lastPoint || !pair.second.firstPoint) {
double localDist = MapUtils.getDistance(pair.first.getLatitude(), pair.first.getLongitude(), distance += MapUtils.getDistance(pair.first.getLatitude(), pair.first.getLongitude(),
pair.second.getLatitude(), pair.second.getLongitude()); pair.second.getLatitude(), pair.second.getLongitude());
if (!Double.isNaN(pair.first.ele) && !Double.isNaN(pair.second.ele) &&
pair.first.ele != 0 && pair.second.ele != 0) {
double h = Math.abs(pair.first.ele - pair.second.ele);
localDist = Math.sqrt(localDist * localDist + h * h);
}
distance += localDist;
} }
} else { } else {
distance += data.getDistance(); distance += data.getDistance();
@ -1069,7 +1061,7 @@ public class MeasurementEditingContext {
return new RouteExporter("", route, locations, null).generateRouteSegment(); return new RouteExporter("", route, locations, null).generateRouteSegment();
} else if (endPointIndex - startPointIndex >= 0) { } else if (endPointIndex - startPointIndex >= 0) {
TrkSegment segment = new TrkSegment(); TrkSegment segment = new TrkSegment();
segment.points = before.points.subList(startPointIndex, endPointIndex + 1); segment.points = new ArrayList<>(before.points.subList(startPointIndex, endPointIndex + 1));
return segment; return segment;
} }
return null; return null;

View file

@ -2,18 +2,23 @@ package net.osmand.plus.osmedit;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import net.osmand.data.PointDescription; import net.osmand.data.PointDescription;
import net.osmand.osm.PoiType; import net.osmand.osm.PoiType;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.MenuController; import net.osmand.plus.mapcontextmenu.MenuController;
import net.osmand.plus.measurementtool.LoginBottomSheetFragment;
import net.osmand.plus.osmedit.OsmPoint.Action; import net.osmand.plus.osmedit.OsmPoint.Action;
import net.osmand.plus.osmedit.dialogs.SendPoiDialogFragment; import net.osmand.plus.osmedit.dialogs.SendPoiDialogFragment.SimpleProgressDialogPoiUploader;
import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter; import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter;
import net.osmand.plus.render.RenderingIcons; import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import java.util.Map; import java.util.Map;
@ -40,15 +45,16 @@ public class EditPOIMenuController extends MenuController {
public void buttonPressed() { public void buttonPressed() {
MapActivity activity = getMapActivity(); MapActivity activity = getMapActivity();
if (plugin != null && activity != null) { if (plugin != null && activity != null) {
OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(activity.getMyApplication()); OsmandApplication app = activity.getMyApplication();
if (client.isValidToken()){ OsmandSettings settings = app.getSettings();
new SendPoiDialogFragment.SimpleProgressDialogPoiUploader(activity). OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(app);
showProgressDialog(new OsmPoint[] { getOsmPoint() }, false, false); if (client.isValidToken()
} || !Algorithms.isEmpty(settings.USER_NAME.get())
else { && !Algorithms.isEmpty(settings.USER_PASSWORD.get())) {
SendPoiDialogFragment sendPoiDialogFragment = SimpleProgressDialogPoiUploader poiDialogUploader = new SimpleProgressDialogPoiUploader(activity);
SendPoiDialogFragment.createInstance(new OsmPoint[]{getOsmPoint()}, SendPoiDialogFragment.PoiUploaderType.SIMPLE); poiDialogUploader.showProgressDialog(new OsmPoint[] {getOsmPoint()}, false, false);
sendPoiDialogFragment.show(activity.getSupportFragmentManager(), SendPoiDialogFragment.TAG); } else {
LoginBottomSheetFragment.showInstance(activity.getSupportFragmentManager(), null);
} }
} }
} }

View file

@ -1,6 +1,5 @@
package net.osmand.plus.osmedit; package net.osmand.plus.osmedit;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@ -8,12 +7,10 @@ import android.os.Bundle;
import android.text.SpannableString; import android.text.SpannableString;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder; import androidx.preference.PreferenceViewHolder;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
@ -21,36 +18,37 @@ import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache; import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.measurementtool.LoginBottomSheetFragment;
import net.osmand.plus.measurementtool.LoginBottomSheetFragment.OsmAuthorizationListener;
import net.osmand.plus.osmedit.ValidateOsmLoginDetailsTask.ValidateOsmLoginListener;
import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter; import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter;
import net.osmand.plus.settings.backend.OsmAndAppCustomization; import net.osmand.plus.settings.backend.OsmAndAppCustomization;
import net.osmand.plus.settings.bottomsheets.OsmLoginDataBottomSheet;
import net.osmand.plus.settings.fragments.BaseSettingsFragment; import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import net.osmand.plus.settings.fragments.OnPreferenceChanged; import net.osmand.plus.settings.fragments.OnPreferenceChanged;
import net.osmand.plus.settings.preferences.SwitchPreferenceEx; import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
import net.osmand.plus.widgets.style.CustomTypefaceSpan; import net.osmand.plus.widgets.style.CustomTypefaceSpan;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID; import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID;
import static net.osmand.plus.osmedit.OsmEditingPlugin.OSM_EDIT_TAB; import static net.osmand.plus.osmedit.OsmEditingPlugin.OSM_EDIT_TAB;
public class OsmEditingFragment extends BaseSettingsFragment implements OnPreferenceChanged { public class OsmEditingFragment extends BaseSettingsFragment implements OnPreferenceChanged, ValidateOsmLoginListener, OsmAuthorizationListener {
private static final Log log = PlatformUtil.getLog(OsmEditingFragment.class); private static final Log log = PlatformUtil.getLog(OsmEditingFragment.class);
private static final String OSM_EDITING_INFO = "osm_editing_info"; private static final String OSM_LOGOUT = "osm_logout";
private static final String OPEN_OSM_EDITS = "open_osm_edits"; private static final String OPEN_OSM_EDITS = "open_osm_edits";
private static final String OSM_LOGIN_DATA = "osm_login_data"; private static final String OSM_LOGIN_DATA = "osm_login_data";
private static final String OSM_OAUTH_SUCCESS = "osm_oauth_success"; private static final String OSM_EDITING_INFO = "osm_editing_info";
private static final String OSM_OAUTH_CLEAR = "osm_oauth_clear";
private static final String OSM_OAUTH_LOGIN = "osm_oauth_login";
private OsmOAuthAuthorizationAdapter client; private OsmOAuthAuthorizationAdapter authorizationAdapter;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
client = new OsmOAuthAuthorizationAdapter(app); authorizationAdapter = new OsmOAuthAuthorizationAdapter(app);
} }
@Override @Override
@ -58,11 +56,12 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
Preference osmEditingInfo = findPreference(OSM_EDITING_INFO); Preference osmEditingInfo = findPreference(OSM_EDITING_INFO);
osmEditingInfo.setIcon(getContentIcon(R.drawable.ic_action_info_dark)); osmEditingInfo.setIcon(getContentIcon(R.drawable.ic_action_info_dark));
setupNameAndPasswordPref(); setupLoginPref();
setupLogoutPref();
setupOfflineEditingPref(); setupOfflineEditingPref();
setupOsmEditsDescrPref(); setupOsmEditsDescrPref();
setupOsmEditsPref(); setupOsmEditsPref();
setupOAuthPrefs();
} }
@Override @Override
@ -83,10 +82,40 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
} }
} }
private void setupNameAndPasswordPref() { @Override
public void loginValidationFinished(String warning) {
updateAllSettings();
}
private void setupLoginPref() {
Preference nameAndPasswordPref = findPreference(OSM_LOGIN_DATA); Preference nameAndPasswordPref = findPreference(OSM_LOGIN_DATA);
nameAndPasswordPref.setSummary(settings.USER_NAME.get()); if (!isValidToken() && !isLoginExists()) {
nameAndPasswordPref.setIcon(getContentIcon(R.drawable.ic_action_openstreetmap_logo)); nameAndPasswordPref.setIcon(getContentIcon(R.drawable.ic_action_user_account));
nameAndPasswordPref.setVisible(true);
} else {
nameAndPasswordPref.setVisible(false);
}
}
private void setupLogoutPref() {
boolean validToken = isValidToken();
Preference nameAndPasswordPref = findPreference(OSM_LOGOUT);
if (validToken || isLoginExists()) {
String userName = validToken ? settings.USER_DISPLAY_NAME.get() : settings.USER_NAME.get();
nameAndPasswordPref.setVisible(true);
nameAndPasswordPref.setSummary(userName);
nameAndPasswordPref.setIcon(getContentIcon(R.drawable.ic_action_user_account));
} else {
nameAndPasswordPref.setVisible(false);
}
}
private boolean isValidToken() {
return authorizationAdapter.isValidToken();
}
private boolean isLoginExists() {
return !Algorithms.isEmpty(settings.USER_NAME.get()) && !Algorithms.isEmpty(settings.USER_PASSWORD.get());
} }
private void setupOfflineEditingPref() { private void setupOfflineEditingPref() {
@ -122,33 +151,6 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
createProfile.setIcon(getActiveIcon(R.drawable.ic_action_folder)); createProfile.setIcon(getActiveIcon(R.drawable.ic_action_folder));
} }
private void setupOAuthPrefs() {
Context ctx = getContext();
if (ctx != null) {
PreferenceScreen screen = getPreferenceScreen();
if (client.isValidToken()) {
Preference prefOAuth = new Preference(ctx);
prefOAuth.setTitle(R.string.osm_authorization_success);
prefOAuth.setSummary(R.string.osm_authorization_success);
prefOAuth.setKey(OSM_OAUTH_SUCCESS);
Preference prefClearToken = new Preference(ctx);
prefClearToken.setTitle(R.string.shared_string_logoff);
prefClearToken.setSummary(R.string.clear_osm_token);
prefClearToken.setKey(OSM_OAUTH_CLEAR);
screen.addPreference(prefOAuth);
screen.addPreference(prefClearToken);
} else {
Preference prefOAuth = new Preference(ctx);
prefOAuth.setTitle(R.string.perform_oauth_authorization);
prefOAuth.setSummary(R.string.perform_oauth_authorization_description);
prefOAuth.setKey(OSM_OAUTH_LOGIN);
screen.addPreference(prefOAuth);
}
}
}
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
String prefId = preference.getKey(); String prefId = preference.getKey();
@ -165,42 +167,35 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
} else if (OSM_LOGIN_DATA.equals(prefId)) { } else if (OSM_LOGIN_DATA.equals(prefId)) {
FragmentManager fragmentManager = getFragmentManager(); FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) { if (fragmentManager != null) {
OsmLoginDataBottomSheet.showInstance(fragmentManager, OSM_LOGIN_DATA, this, false, getSelectedAppMode()); LoginBottomSheetFragment.showInstance(fragmentManager, this);
return true; return true;
} }
} else if (OSM_OAUTH_CLEAR.equals(prefId)) { } else if (OSM_LOGOUT.equals(prefId)) {
settings.USER_ACCESS_TOKEN.set(""); if (isValidToken()) {
settings.USER_ACCESS_TOKEN_SECRET.set(""); settings.USER_ACCESS_TOKEN.resetToDefault();
settings.USER_ACCESS_TOKEN_SECRET.resetToDefault();
client.resetToken();
client = new OsmOAuthAuthorizationAdapter(app);
authorizationAdapter.resetToken();
authorizationAdapter = new OsmOAuthAuthorizationAdapter(app);
} else {
settings.USER_NAME.resetToDefault();
settings.USER_PASSWORD.resetToDefault();
}
app.showShortToastMessage(R.string.osm_edit_logout_success); app.showShortToastMessage(R.string.osm_edit_logout_success);
updateAllSettings(); updateAllSettings();
return true; return true;
} else if (OSM_OAUTH_LOGIN.equals(prefId)) {
View view = getView();
if (view != null) {
ViewGroup appBarLayout = view.findViewById(R.id.appbar);
client.startOAuth(appBarLayout);
}
return true;
} }
return super.onPreferenceClick(preference); return super.onPreferenceClick(preference);
} }
@Override @Override
public void onPreferenceChanged(String prefId) { public void onPreferenceChanged(String prefId) {
if (OSM_LOGIN_DATA.equals(prefId)) { updateAllSettings();
Preference nameAndPasswordPref = findPreference(OSM_LOGIN_DATA);
nameAndPasswordPref.setSummary(settings.USER_NAME.get());
}
} }
public void authorize(String oauthVerifier) { @Override
if (client != null) { public void authorizationCompleted() {
client.authorize(oauthVerifier); authorizationAdapter = new OsmOAuthAuthorizationAdapter(app);
}
updateAllSettings(); updateAllSettings();
} }
} }

View file

@ -1,6 +1,5 @@
package net.osmand.plus.osmedit; package net.osmand.plus.osmedit;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
@ -16,11 +15,11 @@ import android.view.View;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
@ -41,6 +40,7 @@ import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.TabActivity; import net.osmand.plus.activities.TabActivity;
import net.osmand.plus.dashboard.DashboardOnMap.DashboardType; import net.osmand.plus.dashboard.DashboardOnMap.DashboardType;
import net.osmand.plus.dashboard.tools.DashFragmentData; import net.osmand.plus.dashboard.tools.DashFragmentData;
import net.osmand.plus.measurementtool.LoginBottomSheetFragment;
import net.osmand.plus.myplaces.AvailableGPXFragment; import net.osmand.plus.myplaces.AvailableGPXFragment;
import net.osmand.plus.myplaces.AvailableGPXFragment.GpxInfo; import net.osmand.plus.myplaces.AvailableGPXFragment.GpxInfo;
import net.osmand.plus.myplaces.FavoritesActivity; import net.osmand.plus.myplaces.FavoritesActivity;
@ -395,15 +395,15 @@ public class OsmEditingPlugin extends OsmandPlugin {
} }
@Override @Override
public void contextMenuFragment(final Activity la, final Fragment fragment, final Object info, ContextMenuAdapter adapter) { public void contextMenuFragment(final FragmentActivity activity, final Fragment fragment, final Object info, ContextMenuAdapter adapter) {
if (fragment instanceof AvailableGPXFragment) { if (fragment instanceof AvailableGPXFragment) {
adapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.local_index_mi_upload_gpx, la) adapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.local_index_mi_upload_gpx, activity)
.setIcon(R.drawable.ic_action_export) .setIcon(R.drawable.ic_action_export)
.setListener(new ContextMenuAdapter.ItemClickListener() { .setListener(new ContextMenuAdapter.ItemClickListener() {
@Override @Override
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) { public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) {
sendGPXFiles(la, (AvailableGPXFragment) fragment, (GpxInfo) info); sendGPXFiles(activity, (AvailableGPXFragment) fragment, (GpxInfo) info);
return true; return true;
} }
}).createItem()); }).createItem());
@ -411,7 +411,7 @@ public class OsmEditingPlugin extends OsmandPlugin {
} }
@Override @Override
public void optionsMenuFragment(final Activity activity, final Fragment fragment, ContextMenuAdapter optionsMenuAdapter) { public void optionsMenuFragment(final FragmentActivity activity, final Fragment fragment, ContextMenuAdapter optionsMenuAdapter) {
if (fragment instanceof AvailableGPXFragment) { if (fragment instanceof AvailableGPXFragment) {
final AvailableGPXFragment f = ((AvailableGPXFragment) fragment); final AvailableGPXFragment f = ((AvailableGPXFragment) fragment);
optionsMenuAdapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.local_index_mi_upload_gpx, activity) optionsMenuAdapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.local_index_mi_upload_gpx, activity)
@ -437,7 +437,6 @@ public class OsmEditingPlugin extends OsmandPlugin {
} }
} }
public enum UploadVisibility implements IEnumWithResource { public enum UploadVisibility implements IEnumWithResource {
Public(R.string.gpxup_public), Public(R.string.gpxup_public),
Identifiable(R.string.gpxup_identifiable), Identifiable(R.string.gpxup_identifiable),
@ -459,16 +458,16 @@ public class OsmEditingPlugin extends OsmandPlugin {
} }
} }
public boolean sendGPXFiles(final Activity la, AvailableGPXFragment f, final GpxInfo... info) { public boolean sendGPXFiles(final FragmentActivity activity, AvailableGPXFragment fragment, final GpxInfo... info) {
String name = settings.USER_NAME.get(); String name = settings.USER_NAME.get();
String pwd = settings.USER_PASSWORD.get(); String pwd = settings.USER_PASSWORD.get();
String authToken = settings.USER_ACCESS_TOKEN.get(); String authToken = settings.USER_ACCESS_TOKEN.get();
if ((Algorithms.isEmpty(name) || Algorithms.isEmpty(pwd)) && Algorithms.isEmpty(authToken)) { if ((Algorithms.isEmpty(name) || Algorithms.isEmpty(pwd)) && Algorithms.isEmpty(authToken)) {
Toast.makeText(la, R.string.validate_gpx_upload_name_pwd, Toast.LENGTH_LONG).show(); LoginBottomSheetFragment.showInstance(activity.getSupportFragmentManager(), fragment.getTargetFragment());
return false; return false;
} }
AlertDialog.Builder bldr = new AlertDialog.Builder(la); AlertDialog.Builder builder = new AlertDialog.Builder(activity);
LayoutInflater inflater = (LayoutInflater) la.getSystemService(Context.LAYOUT_INFLATER_SERVICE); LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View view = inflater.inflate(R.layout.send_gpx_osm, null); final View view = inflater.inflate(R.layout.send_gpx_osm, null);
final EditText descr = (EditText) view.findViewById(R.id.memory_size); final EditText descr = (EditText) view.findViewById(R.id.memory_size);
if (info.length > 0 && info[0].getFileName() != null) { if (info.length > 0 && info[0].getFileName() != null) {
@ -477,23 +476,23 @@ public class OsmEditingPlugin extends OsmandPlugin {
} }
final EditText tags = (EditText) view.findViewById(R.id.TagsText); final EditText tags = (EditText) view.findViewById(R.id.TagsText);
final Spinner visibility = ((Spinner) view.findViewById(R.id.Visibility)); final Spinner visibility = ((Spinner) view.findViewById(R.id.Visibility));
EnumAdapter<UploadVisibility> adapter = new EnumAdapter<>(la, android.R.layout.simple_spinner_item, UploadVisibility.values()); EnumAdapter<UploadVisibility> adapter = new EnumAdapter<>(activity, android.R.layout.simple_spinner_item, UploadVisibility.values());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
visibility.setAdapter(adapter); visibility.setAdapter(adapter);
visibility.setSelection(0); visibility.setSelection(0);
bldr.setView(view); builder.setView(view);
bldr.setNegativeButton(R.string.shared_string_no, null); builder.setNegativeButton(R.string.shared_string_no, null);
bldr.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() { builder.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
new UploadGPXFilesTask(la, descr.getText().toString(), tags.getText().toString(), new UploadGPXFilesTask(activity, descr.getText().toString(), tags.getText().toString(),
(UploadVisibility) visibility.getItemAtPosition(visibility.getSelectedItemPosition()) (UploadVisibility) visibility.getItemAtPosition(visibility.getSelectedItemPosition())
).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, info); ).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, info);
} }
}); });
bldr.show(); builder.show();
return true; return true;
} }

View file

@ -29,6 +29,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ActionMode; import androidx.appcompat.view.ActionMode;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
@ -41,6 +42,8 @@ import net.osmand.osm.edit.Entity;
import net.osmand.osm.edit.Node; import net.osmand.osm.edit.Node;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.measurementtool.LoginBottomSheetFragment;
import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter;
import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
@ -624,10 +627,20 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
} }
private void uploadItems(final OsmPoint[] items) { private void uploadItems(final OsmPoint[] items) {
SendPoiDialogFragment.createInstance(items, PoiUploaderType.FRAGMENT) FragmentActivity activity = getActivity();
.show(getChildFragmentManager(), SendPoiDialogFragment.TAG); if (activity != null) {
// UploadOsmEditsConfirmDialogFragment.createInstancee(items).show(getChildFragmentManager(), OsmandApplication app = getMyApplication();
// UploadOsmEditsConfirmDialogFragment.TAG); OsmandSettings settings = app.getSettings();
OsmOAuthAuthorizationAdapter authorizationAdapter = new OsmOAuthAuthorizationAdapter(app);
if (authorizationAdapter.isValidToken()
|| !Algorithms.isEmpty(settings.USER_NAME.get())
&& !Algorithms.isEmpty(settings.USER_PASSWORD.get())) {
SendPoiDialogFragment.createInstance(items, PoiUploaderType.FRAGMENT)
.show(getChildFragmentManager(), SendPoiDialogFragment.TAG);
} else {
LoginBottomSheetFragment.showInstance(activity.getSupportFragmentManager(), this);
}
}
} }
public void showProgressDialog(OsmPoint[] points, boolean closeChangeSet, boolean anonymously) { public void showProgressDialog(OsmPoint[] points, boolean closeChangeSet, boolean anonymously) {

View file

@ -2,6 +2,8 @@ package net.osmand.plus.osmedit;
import android.os.AsyncTask; import android.os.AsyncTask;
import androidx.annotation.NonNull;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R; import net.osmand.plus.R;
@ -10,9 +12,11 @@ import net.osmand.plus.osmedit.OsmBugsUtil.OsmBugResult;
public class ValidateOsmLoginDetailsTask extends AsyncTask<Void, Void, OsmBugResult> { public class ValidateOsmLoginDetailsTask extends AsyncTask<Void, Void, OsmBugResult> {
private OsmandApplication app; private OsmandApplication app;
private ValidateOsmLoginListener validateListener;
public ValidateOsmLoginDetailsTask(OsmandApplication app) { public ValidateOsmLoginDetailsTask(@NonNull OsmandApplication app, ValidateOsmLoginListener validateListener) {
this.app = app; this.app = app;
this.validateListener = validateListener;
} }
@Override @Override
@ -26,9 +30,20 @@ public class ValidateOsmLoginDetailsTask extends AsyncTask<Void, Void, OsmBugRes
@Override @Override
protected void onPostExecute(OsmBugResult osmBugResult) { protected void onPostExecute(OsmBugResult osmBugResult) {
if (osmBugResult.warning != null) { if (osmBugResult.warning != null) {
app.getSettings().USER_NAME.resetToDefault();
app.getSettings().USER_PASSWORD.resetToDefault();
app.showToastMessage(osmBugResult.warning); app.showToastMessage(osmBugResult.warning);
} else { } else {
app.showToastMessage(R.string.osm_authorization_success); app.showToastMessage(R.string.osm_authorization_success);
} }
if (validateListener != null) {
validateListener.loginValidationFinished(osmBugResult.warning);
}
}
public interface ValidateOsmLoginListener {
void loginValidationFinished(String warning);
} }
} }

View file

@ -4,26 +4,38 @@ import android.net.TrafficStats;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.webkit.WebView; import android.webkit.WebView;
import com.github.scribejava.core.model.OAuth1AccessToken; import com.github.scribejava.core.model.OAuth1AccessToken;
import com.github.scribejava.core.model.OAuth1RequestToken; import com.github.scribejava.core.model.OAuth1RequestToken;
import com.github.scribejava.core.model.OAuthAsyncRequestCallback; import com.github.scribejava.core.model.OAuthAsyncRequestCallback;
import com.github.scribejava.core.model.Response; import com.github.scribejava.core.model.Response;
import com.github.scribejava.core.model.Verb;
import net.osmand.PlatformUtil;
import net.osmand.osm.oauth.OsmOAuthAuthorizationClient; import net.osmand.osm.oauth.OsmOAuthAuthorizationClient;
import net.osmand.plus.BuildConfig; import net.osmand.plus.BuildConfig;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
public class OsmOAuthAuthorizationAdapter { public class OsmOAuthAuthorizationAdapter {
private OsmandApplication application;
private static final int THREAD_ID = 10101;
private static final String OSM_USER = "user";
private static final String DISPLAY_NAME = "display_name";
private static final String OSM_USER_DETAILS_URL = "https://api.openstreetmap.org/api/0.6/user/details";
private OsmandApplication app;
private OsmOAuthAuthorizationClient client = private OsmOAuthAuthorizationClient client =
new OsmOAuthAuthorizationClient(BuildConfig.OSM_OAUTH_CONSUMER_KEY, BuildConfig.OSM_OAUTH_CONSUMER_SECRET); new OsmOAuthAuthorizationClient(BuildConfig.OSM_OAUTH_CONSUMER_KEY, BuildConfig.OSM_OAUTH_CONSUMER_SECRET);
private static final int THREAD_ID = 10101;
public OsmOAuthAuthorizationAdapter(OsmandApplication application) { public OsmOAuthAuthorizationAdapter(OsmandApplication app) {
TrafficStats.setThreadStatsTag(THREAD_ID); TrafficStats.setThreadStatsTag(THREAD_ID);
this.application = application; this.app = app;
restoreToken(); restoreToken();
} }
@ -40,8 +52,8 @@ public class OsmOAuthAuthorizationAdapter {
} }
public void restoreToken() { public void restoreToken() {
String token = application.getSettings().USER_ACCESS_TOKEN.get(); String token = app.getSettings().USER_ACCESS_TOKEN.get();
String tokenSecret = application.getSettings().USER_ACCESS_TOKEN_SECRET.get(); String tokenSecret = app.getSettings().USER_ACCESS_TOKEN_SECRET.get();
if (!(token.isEmpty() || tokenSecret.isEmpty())) { if (!(token.isEmpty() || tokenSecret.isEmpty())) {
client.setAccessToken(new OAuth1AccessToken(token, tokenSecret)); client.setAccessToken(new OAuth1AccessToken(token, tokenSecret));
} else { } else {
@ -56,8 +68,8 @@ public class OsmOAuthAuthorizationAdapter {
private void saveToken() { private void saveToken() {
OAuth1AccessToken accessToken = client.getAccessToken(); OAuth1AccessToken accessToken = client.getAccessToken();
application.getSettings().USER_ACCESS_TOKEN.set(accessToken.getToken()); app.getSettings().USER_ACCESS_TOKEN.set(accessToken.getToken());
application.getSettings().USER_ACCESS_TOKEN_SECRET.set(accessToken.getTokenSecret()); app.getSettings().USER_ACCESS_TOKEN_SECRET.set(accessToken.getTokenSecret());
} }
private void loadWebView(ViewGroup root, String url) { private void loadWebView(ViewGroup root, String url) {
@ -85,4 +97,26 @@ public class OsmOAuthAuthorizationAdapter {
client.authorize(oauthVerifier); client.authorize(oauthVerifier);
saveToken(); saveToken();
} }
public String getUserName() throws InterruptedException, ExecutionException, IOException, XmlPullParserException {
Response response = getOsmUserDetails();
return parseUserName(response);
}
public Response getOsmUserDetails() throws InterruptedException, ExecutionException, IOException {
return performRequest(OSM_USER_DETAILS_URL, Verb.GET.name(), null);
}
public String parseUserName(Response response) throws XmlPullParserException, IOException {
String userName = null;
XmlPullParser parser = PlatformUtil.newXMLPullParser();
parser.setInput(response.getStream(), "UTF-8");
int tok;
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (tok == XmlPullParser.START_TAG && OSM_USER.equals(parser.getName())) {
userName = parser.getAttributeValue("", DISPLAY_NAME);
}
}
return userName;
}
} }

View file

@ -339,9 +339,6 @@ public class OsmandRasterMapsPlugin extends OsmandPlugin {
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
final CommonPreference<Boolean> hidePolygonsPref =
mapActivity.getMyApplication().getSettings().getCustomRenderBooleanProperty("noPolygons");
hidePolygonsPref.set(hasUnderlayDescription);
RasterMapMenu.refreshMapComplete(mapActivity); RasterMapMenu.refreshMapComplete(mapActivity);
} }
} }

View file

@ -1088,6 +1088,7 @@ public class OsmandSettings {
// this value string is synchronized with settings_pref.xml preference name // this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<String> USER_NAME = new StringPreference(this, "user_name", "").makeGlobal().makeShared(); public final OsmandPreference<String> USER_NAME = new StringPreference(this, "user_name", "").makeGlobal().makeShared();
public final OsmandPreference<String> USER_DISPLAY_NAME = new StringPreference(this, "user_display_name", "").makeGlobal().makeShared();
public static final String BILLING_USER_DONATION_WORLD_PARAMETER = ""; public static final String BILLING_USER_DONATION_WORLD_PARAMETER = "";
public static final String BILLING_USER_DONATION_NONE_PARAMETER = "none"; public static final String BILLING_USER_DONATION_NONE_PARAMETER = "none";

View file

@ -10,16 +10,17 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import net.osmand.plus.osmedit.ValidateOsmLoginDetailsTask; import com.google.android.material.textfield.TextInputLayout;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.UiUtilities; import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.settings.fragments.OnPreferenceChanged; import net.osmand.plus.osmedit.ValidateOsmLoginDetailsTask;
import net.osmand.plus.osmedit.ValidateOsmLoginDetailsTask.ValidateOsmLoginListener;
import net.osmand.plus.settings.backend.ApplicationMode;
public class OsmLoginDataBottomSheet extends BasePreferenceBottomSheet { public class OsmLoginDataBottomSheet extends BasePreferenceBottomSheet {
@ -55,6 +56,14 @@ public class OsmLoginDataBottomSheet extends BasePreferenceBottomSheet {
userNameEditText.setText(name); userNameEditText.setText(name);
passwordEditText.setText(password); passwordEditText.setText(password);
TextInputLayout loginBox = view.findViewById(R.id.name_text_box);
TextInputLayout passwordBox = view.findViewById(R.id.password_text_box);
passwordBox.setStartIconDrawable(R.drawable.ic_action_lock);
loginBox.setStartIconDrawable(R.drawable.ic_action_user_account);
loginBox.setEndIconMode(TextInputLayout.END_ICON_CLEAR_TEXT);
passwordBox.setEndIconMode(TextInputLayout.END_ICON_PASSWORD_TOGGLE);
BaseBottomSheetItem titleItem = new SimpleBottomSheetItem.Builder() BaseBottomSheetItem titleItem = new SimpleBottomSheetItem.Builder()
.setCustomView(view) .setCustomView(view)
.create(); .create();
@ -75,7 +84,7 @@ public class OsmLoginDataBottomSheet extends BasePreferenceBottomSheet {
@Override @Override
protected int getRightBottomButtonTextId() { protected int getRightBottomButtonTextId() {
return R.string.shared_string_apply; return R.string.user_login;
} }
@Override @Override
@ -84,12 +93,11 @@ public class OsmLoginDataBottomSheet extends BasePreferenceBottomSheet {
app.getSettings().USER_NAME.set(userNameEditText.getText().toString()); app.getSettings().USER_NAME.set(userNameEditText.getText().toString());
app.getSettings().USER_PASSWORD.set(passwordEditText.getText().toString()); app.getSettings().USER_PASSWORD.set(passwordEditText.getText().toString());
new ValidateOsmLoginDetailsTask(app).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Fragment target = getTargetFragment(); Fragment targetFragment = getTargetFragment();
Preference preference = getPreference(); if (targetFragment instanceof ValidateOsmLoginListener) {
if (target instanceof OnPreferenceChanged && preference != null) { ValidateOsmLoginDetailsTask validateTask = new ValidateOsmLoginDetailsTask(app, (ValidateOsmLoginListener) targetFragment);
((OnPreferenceChanged) target).onPreferenceChanged(preference.getKey()); validateTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
dismiss(); dismiss();

View file

@ -84,7 +84,7 @@ public class ImportCompleteFragment extends BaseOsmAndFragment {
View root = inflater.inflate(R.layout.fragment_import_complete, container, false); View root = inflater.inflate(R.layout.fragment_import_complete, container, false);
TextView description = root.findViewById(R.id.description); TextView description = root.findViewById(R.id.description);
TextView btnClose = root.findViewById(R.id.button_close); TextView btnClose = root.findViewById(R.id.button_close);
final LinearLayout buttonContainer = root.findViewById(R.id.button_container); final ViewGroup buttonContainer = root.findViewById(R.id.button_container);
recyclerView = root.findViewById(R.id.list); recyclerView = root.findViewById(R.id.list);
description.setText(UiUtilities.createSpannableString( description.setText(UiUtilities.createSpannableString(
String.format(getString(R.string.import_complete_description), fileName), String.format(getString(R.string.import_complete_description), fileName),

View file

@ -225,6 +225,13 @@ public class AnimateDraggingMapThread {
if (!stopped) { if (!stopped) {
animatingMoveInThread(mMoveX, mMoveY, animationTime, notifyListener, finishAnimationCallback); animatingMoveInThread(mMoveX, mMoveY, animationTime, notifyListener, finishAnimationCallback);
} else if (finishAnimationCallback != null) {
tileView.getApplication().runInUIThread(new Runnable() {
@Override
public void run() {
finishAnimationCallback.run();
}
});
} }
if (!stopped) { if (!stopped) {
tileView.setLatLonAnimate(finalLat, finalLon, notifyListener); tileView.setLatLonAnimate(finalLat, finalLon, notifyListener);