Merge branch 'master' of ssh://github.com/osmandapp/Osmand into js_voice_routing
|
@ -1,4 +1,7 @@
|
|||
<resources>
|
||||
<string name="time_ago">ago</string>
|
||||
<string name="last_response">Last response</string>
|
||||
<string name="shared_string_group">Group</string>
|
||||
<string name="logout_no_internet_msg">To properly log out from your Telegram account, the Internet is needed.</string>
|
||||
<string name="shared_string_close">Close</string>
|
||||
<string name="disconnect_from_telegram_desc">To invoke access to your Telegram account from OsmAnd, open Telegram, go to Settings - Privacy and Security - Sessions and terminate OsmAnd Telegram session. After that, OsmAnd Location Sharing will no longer have access to your account, and you will not be able to use this app until you log in again.</string>
|
||||
|
|
|
@ -54,7 +54,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
val messages = telegramHelper.getMessages()
|
||||
for (message in messages) {
|
||||
val date = Math.max(message.date, message.editDate) * 1000L
|
||||
val expired = System.currentTimeMillis() - date > app.settings.locHistoryTime
|
||||
val expired = System.currentTimeMillis() - date > app.settings.locHistoryTime * 1000L
|
||||
if (expired) {
|
||||
removeMapPoint(message.chatId, message)
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ class TelegramHelper private constructor() {
|
|||
|
||||
private const val DEVICE_PREFIX = "Device: "
|
||||
private const val LOCATION_PREFIX = "Location: "
|
||||
private const val LAST_LOCATION_PREFIX = "Last location: "
|
||||
|
||||
private const val FEW_SECONDS_AGO = "few seconds ago"
|
||||
private const val SECONDS_AGO_SUFFIX = " seconds ago"
|
||||
|
@ -177,6 +178,8 @@ class TelegramHelper private constructor() {
|
|||
return chat.type is TdApi.ChatTypeSupergroup || chat.type is TdApi.ChatTypeBasicGroup
|
||||
}
|
||||
|
||||
fun getLastUpdatedTime(message: TdApi.Message) = Math.max(message.editDate, message.date)
|
||||
|
||||
fun isPrivateChat(chat: TdApi.Chat): Boolean = chat.type is TdApi.ChatTypePrivate
|
||||
|
||||
private fun isChannel(chat: TdApi.Chat): Boolean {
|
||||
|
@ -481,16 +484,15 @@ class TelegramHelper private constructor() {
|
|||
|
||||
private fun addNewMessage(message: TdApi.Message) {
|
||||
if (message.isAppropriate()) {
|
||||
val fromBot = isOsmAndBot(message.senderUserId)
|
||||
val viaBot = isOsmAndBot(message.viaBotUserId)
|
||||
val oldContent = message.content
|
||||
if (oldContent is TdApi.MessageText) {
|
||||
val messageOsmAndBotLocation = parseOsmAndBotLocation(oldContent.text.text)
|
||||
messageOsmAndBotLocation.created = message.date
|
||||
message.content = messageOsmAndBotLocation
|
||||
} else if (oldContent is TdApi.MessageLocation &&
|
||||
(isOsmAndBot(message.senderUserId) || isOsmAndBot(message.viaBotUserId))) {
|
||||
message.content = parseOsmAndBotLocation(oldContent.text.text)
|
||||
} else if (oldContent is TdApi.MessageLocation && (fromBot || viaBot)) {
|
||||
message.content = parseOsmAndBotLocation(message)
|
||||
}
|
||||
removeOldMessages(message.senderUserId, message.chatId)
|
||||
removeOldMessages(message, fromBot, viaBot)
|
||||
usersLocationMessages[message.id] = message
|
||||
incomingMessagesListeners.forEach {
|
||||
it.onReceiveChatLocationMessages(message.chatId, message)
|
||||
|
@ -498,13 +500,25 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun removeOldMessages(userId: Int, chatId: Long) {
|
||||
val user = users[userId]
|
||||
if (user != null && user.username != OSMAND_BOT_USERNAME) {
|
||||
usersLocationMessages.values.filter { it.senderUserId == userId && it.chatId == chatId }
|
||||
.forEach {
|
||||
usersLocationMessages.remove(it.id)
|
||||
private fun removeOldMessages(newMessage: TdApi.Message, fromBot: Boolean, viaBot: Boolean) {
|
||||
val iterator = usersLocationMessages.entries.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val message = iterator.next().value
|
||||
if (newMessage.chatId == message.chatId) {
|
||||
val sameSender = newMessage.senderUserId == message.senderUserId
|
||||
val viaSameBot = newMessage.viaBotUserId == message.viaBotUserId
|
||||
if ((fromBot && sameSender) || (viaBot && viaSameBot)) {
|
||||
val newCont = newMessage.content
|
||||
val cont = message.content
|
||||
if (newCont is MessageOsmAndBotLocation && cont is MessageOsmAndBotLocation) {
|
||||
if (newCont.name == cont.name) {
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
} else if (sameSender) {
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -749,7 +763,8 @@ class TelegramHelper private constructor() {
|
|||
val content = content
|
||||
return when (content) {
|
||||
is TdApi.MessageLocation -> true
|
||||
is TdApi.MessageText -> isOsmAndBot(senderUserId) || isOsmAndBot(viaBotUserId)
|
||||
is TdApi.MessageText -> (isOsmAndBot(senderUserId) || isOsmAndBot(viaBotUserId))
|
||||
&& content.text.text.startsWith(DEVICE_PREFIX)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
@ -760,13 +775,7 @@ class TelegramHelper private constructor() {
|
|||
name = getOsmAndBotDeviceName(message)
|
||||
lat = messageLocation.location.latitude
|
||||
lon = messageLocation.location.longitude
|
||||
created = message.date
|
||||
val date = message.editDate
|
||||
lastUpdated = if (date != 0) {
|
||||
date
|
||||
} else {
|
||||
message.date
|
||||
}
|
||||
lastUpdated = getLastUpdatedTime(message)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -776,33 +785,46 @@ class TelegramHelper private constructor() {
|
|||
name = oldContent.name
|
||||
lat = messageLocation.location.latitude
|
||||
lon = messageLocation.location.longitude
|
||||
created = oldContent.created
|
||||
lastUpdated = (System.currentTimeMillis() / 1000).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseOsmAndBotLocation(text: String): MessageOsmAndBotLocation {
|
||||
val res = MessageOsmAndBotLocation()
|
||||
var locationNA = false
|
||||
for (s in text.lines()) {
|
||||
when {
|
||||
s.startsWith(DEVICE_PREFIX) -> {
|
||||
res.name = s.removePrefix(DEVICE_PREFIX)
|
||||
}
|
||||
s.startsWith(LOCATION_PREFIX) -> {
|
||||
val locStr = s.removePrefix(LOCATION_PREFIX)
|
||||
try {
|
||||
val (latS, lonS) = locStr.split(" ")
|
||||
val updatedS = locStr.substring(locStr.indexOf("("), locStr.length)
|
||||
val timeSecs = parseTime(updatedS.removePrefix("(").removeSuffix(")"))
|
||||
res.lat = latS.dropLast(1).toDouble()
|
||||
res.lon = lonS.toDouble()
|
||||
if (timeSecs < messageActiveTimeSec) {
|
||||
res.lastUpdated = (System.currentTimeMillis() / 1000 - timeSecs).toInt()
|
||||
} else {
|
||||
res.lastUpdated = timeSecs
|
||||
s.startsWith(LOCATION_PREFIX) || s.startsWith(LAST_LOCATION_PREFIX) -> {
|
||||
var locStr: String
|
||||
var parse = true
|
||||
if (s.startsWith(LAST_LOCATION_PREFIX)) {
|
||||
locStr = s.removePrefix(LAST_LOCATION_PREFIX)
|
||||
if (!locationNA) {
|
||||
parse = false
|
||||
}
|
||||
} else {
|
||||
locStr = s.removePrefix(LOCATION_PREFIX)
|
||||
if (locStr.trim() == "n/a") {
|
||||
locationNA = true
|
||||
parse = false
|
||||
}
|
||||
}
|
||||
if (parse) {
|
||||
try {
|
||||
val (latS, lonS) = locStr.split(" ")
|
||||
val updatedS = locStr.substring(locStr.indexOf("("), locStr.length)
|
||||
|
||||
res.lastUpdated =
|
||||
(parseTime(updatedS.removePrefix("(").removeSuffix(")")) / 1000).toInt()
|
||||
res.lat = latS.dropLast(1).toDouble()
|
||||
res.lon = lonS.toDouble()
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -810,24 +832,24 @@ class TelegramHelper private constructor() {
|
|||
return res
|
||||
}
|
||||
|
||||
private fun parseTime(timeS: String): Int {
|
||||
private fun parseTime(timeS: String): Long {
|
||||
try {
|
||||
when {
|
||||
timeS.endsWith(FEW_SECONDS_AGO) -> return 5
|
||||
timeS.endsWith(FEW_SECONDS_AGO) -> return System.currentTimeMillis() - 5000
|
||||
|
||||
timeS.endsWith(SECONDS_AGO_SUFFIX) -> {
|
||||
val locStr = timeS.removeSuffix(SECONDS_AGO_SUFFIX)
|
||||
return locStr.toInt()
|
||||
return System.currentTimeMillis() - locStr.toLong() * 1000
|
||||
}
|
||||
timeS.endsWith(MINUTES_AGO_SUFFIX) -> {
|
||||
val locStr = timeS.removeSuffix(MINUTES_AGO_SUFFIX)
|
||||
val minutes = locStr.toInt()
|
||||
return minutes * 60
|
||||
val minutes = locStr.toLong()
|
||||
return System.currentTimeMillis() - minutes * 60 * 1000
|
||||
}
|
||||
timeS.endsWith(HOURS_AGO_SUFFIX) -> {
|
||||
val locStr = timeS.removeSuffix(HOURS_AGO_SUFFIX)
|
||||
val hours = locStr.toInt()
|
||||
return hours * 60 * 60
|
||||
val hours = locStr.toLong()
|
||||
return (System.currentTimeMillis() - hours * 60 * 60 * 1000)
|
||||
}
|
||||
timeS.endsWith(UTC_FORMAT_SUFFIX) -> {
|
||||
val locStr = timeS.removeSuffix(UTC_FORMAT_SUFFIX)
|
||||
|
@ -835,7 +857,7 @@ class TelegramHelper private constructor() {
|
|||
val date = UTC_DATE_FORMAT.parse(latS)
|
||||
val time = UTC_TIME_FORMAT.parse(lonS)
|
||||
val res = date.time + time.time
|
||||
return res.toInt()
|
||||
return res
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
@ -1068,9 +1090,7 @@ class TelegramHelper private constructor() {
|
|||
synchronized(message) {
|
||||
val newContent = updateMessageContent.newContent
|
||||
message.content = if (newContent is TdApi.MessageText) {
|
||||
val messageOsmAndBotLocation = parseOsmAndBotLocation(newContent.text.text)
|
||||
messageOsmAndBotLocation.created = message.date
|
||||
messageOsmAndBotLocation
|
||||
parseOsmAndBotLocation(newContent.text.text)
|
||||
} else if (newContent is TdApi.MessageLocation &&
|
||||
(isOsmAndBot(message.senderUserId) || isOsmAndBot(message.viaBotUserId))) {
|
||||
parseOsmAndBotLocationContent(message.content as MessageOsmAndBotLocation, newContent)
|
||||
|
|
|
@ -52,11 +52,6 @@ object TelegramUiHelper {
|
|||
placeholderId = R.drawable.img_user_picture
|
||||
}
|
||||
val type = chat.type
|
||||
val message = messages.firstOrNull()
|
||||
if (message != null) {
|
||||
res.lastUpdated = message.editDate
|
||||
res.created = message.date
|
||||
}
|
||||
if (type is TdApi.ChatTypePrivate || type is TdApi.ChatTypeSecret) {
|
||||
val userId = getUserIdFromChatType(type)
|
||||
val chatWithBot = helper.isBot(userId)
|
||||
|
@ -64,9 +59,13 @@ object TelegramUiHelper {
|
|||
res.chatWithBot = chatWithBot
|
||||
if (!chatWithBot) {
|
||||
res.userId = userId
|
||||
val content = message?.content
|
||||
if (content is TdApi.MessageLocation) {
|
||||
res.latLon = LatLon(content.location.latitude, content.location.longitude)
|
||||
val message = messages.firstOrNull { it.viaBotUserId == 0 }
|
||||
if (message != null) {
|
||||
res.lastUpdated = helper.getLastUpdatedTime(message)
|
||||
val content = message.content
|
||||
if (content is TdApi.MessageLocation) {
|
||||
res.latLon = LatLon(content.location.latitude, content.location.longitude)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type is TdApi.ChatTypeBasicGroup) {
|
||||
|
@ -125,7 +124,6 @@ object TelegramUiHelper {
|
|||
latLon = LatLon(content.lat, content.lon)
|
||||
placeholderId = R.drawable.img_user_picture
|
||||
lastUpdated = content.lastUpdated
|
||||
created = content.created
|
||||
}
|
||||
} else {
|
||||
null
|
||||
|
@ -147,8 +145,7 @@ object TelegramUiHelper {
|
|||
photoPath = helper.getUserPhotoPath(user)
|
||||
placeholderId = R.drawable.img_user_picture
|
||||
userId = message.senderUserId
|
||||
lastUpdated = message.editDate
|
||||
created = message.date
|
||||
lastUpdated = helper.getLastUpdatedTime(message)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,8 +165,6 @@ object TelegramUiHelper {
|
|||
internal set
|
||||
var lastUpdated: Int = 0
|
||||
internal set
|
||||
var created: Int = 0
|
||||
internal set
|
||||
|
||||
abstract fun canBeOpenedOnMap(): Boolean
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ import net.osmand.telegram.utils.OsmandFormatter
|
|||
import net.osmand.telegram.utils.UiUtils.UpdateLocationViewCache
|
||||
import net.osmand.util.MapUtils
|
||||
import org.drinkless.td.libcore.telegram.TdApi
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
private const val CHAT_VIEW_TYPE = 0
|
||||
private const val LOCATION_ITEM_VIEW_TYPE = 1
|
||||
|
@ -221,31 +223,32 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
|
|||
for ((id, messages) in telegramHelper.getMessagesByChatIds()) {
|
||||
telegramHelper.getChat(id)?.also { chat ->
|
||||
res.add(TelegramUiHelper.chatToChatItem(telegramHelper, chat, messages))
|
||||
if (needLocationItems(chat.type)) {
|
||||
val type = chat.type
|
||||
if (type is TdApi.ChatTypeBasicGroup || type is TdApi.ChatTypeSupergroup) {
|
||||
res.addAll(convertToLocationItems(chat, messages))
|
||||
} else if (type is TdApi.ChatTypePrivate) {
|
||||
if (telegramHelper.isOsmAndBot(type.userId)) {
|
||||
res.addAll(convertToLocationItems(chat, messages))
|
||||
} else if (messages.firstOrNull { it.viaBotUserId != 0 } != null) {
|
||||
res.addAll(convertToLocationItems(chat, messages, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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.isOsmAndBot(type.userId)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertToLocationItems(
|
||||
chat: TdApi.Chat,
|
||||
messages: List<TdApi.Message>
|
||||
messages: List<TdApi.Message>,
|
||||
addOnlyViaBotMessages: Boolean = false
|
||||
): List<LocationItem> {
|
||||
val res = mutableListOf<LocationItem>()
|
||||
messages.forEach { message ->
|
||||
TelegramUiHelper.messageToLocationItem(telegramHelper, chat, message)?.also {
|
||||
res.add(it)
|
||||
if (!addOnlyViaBotMessages || message.viaBotUserId != 0) {
|
||||
TelegramUiHelper.messageToLocationItem(telegramHelper, chat, message)?.also {
|
||||
res.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
@ -319,7 +322,7 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
|
|||
}
|
||||
if (location != null && item.latLon != null) {
|
||||
holder.locationViewContainer?.visibility = View.VISIBLE
|
||||
locationViewCache.outdatedLocation = System.currentTimeMillis() / 1000 - item.lastUpdated > settings.staleLocTime
|
||||
locationViewCache.outdatedLocation = System.currentTimeMillis() / 1000 - item.lastUpdated > settings.staleLocTime
|
||||
app.uiUtils.updateLocationView(
|
||||
holder.directionIcon,
|
||||
holder.distanceText,
|
||||
|
@ -361,13 +364,19 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
|
|||
}
|
||||
}
|
||||
|
||||
private fun getListItemLiveTimeDescr(item: ListItem):String {
|
||||
return getString(R.string.shared_string_live) +
|
||||
": ${OsmandFormatter.getFormattedDuration(app, getListItemLiveTime(item))}"
|
||||
private fun getListItemLiveTimeDescr(item: ListItem): String {
|
||||
val duration = System.currentTimeMillis() / 1000 - item.lastUpdated
|
||||
var formattedTime = OsmandFormatter.getFormattedDuration(app, duration)
|
||||
return if (duration > 48 * 60 * 60) {
|
||||
// TODO make constant
|
||||
val day = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault())
|
||||
formattedTime = day.format(Date(item.lastUpdated * 1000.toLong()))
|
||||
getString(R.string.last_response) + ": $formattedTime"
|
||||
} else {
|
||||
getString(R.string.last_response) + ": $formattedTime " + getString(R.string.time_ago)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getListItemLiveTime(item: ListItem): Long = (System.currentTimeMillis() / 1000) - item.created
|
||||
|
||||
private fun showPopupMenu(holder: ChatViewHolder, chatId: Long) {
|
||||
val ctx = holder.itemView.context
|
||||
|
||||
|
|
|
@ -577,23 +577,25 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
|
|||
}
|
||||
|
||||
holder.stopSharingDescr?.apply {
|
||||
visibility = View.VISIBLE
|
||||
visibility = getStopSharingVisibility(expiresIn)
|
||||
text = "${getText(R.string.stop_at)}:"
|
||||
}
|
||||
|
||||
holder.stopSharingFirstPart?.apply {
|
||||
visibility = View.VISIBLE
|
||||
visibility = getStopSharingVisibility(expiresIn)
|
||||
text = OsmandFormatter.getFormattedTime(expiresIn)
|
||||
}
|
||||
|
||||
holder.stopSharingSecondPart?.apply {
|
||||
visibility = View.VISIBLE
|
||||
visibility = getStopSharingVisibility(expiresIn)
|
||||
text = "(${getString(R.string.in_time,
|
||||
OsmandFormatter.getFormattedDuration(context!!, expiresIn, true))})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getStopSharingVisibility(expiresIn: Long) = if (expiresIn > 0) View.VISIBLE else View.INVISIBLE
|
||||
|
||||
private fun removeItem(chat: TdApi.Chat) {
|
||||
chats.remove(chat)
|
||||
if (chats.isEmpty()) {
|
||||
|
|
|
@ -12,16 +12,24 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
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.TelegramLocationProvider.TelegramLocationListener
|
||||
import net.osmand.telegram.TelegramLocationProvider.TelegramCompassListener
|
||||
import net.osmand.telegram.helpers.ShareLocationHelper
|
||||
import net.osmand.telegram.helpers.TelegramUiHelper
|
||||
import net.osmand.telegram.ui.SetTimeDialogFragment.SetTimeListAdapter.ChatViewHolder
|
||||
import net.osmand.telegram.utils.AndroidUtils
|
||||
import net.osmand.telegram.utils.OsmandFormatter
|
||||
import net.osmand.telegram.utils.UiUtils
|
||||
import net.osmand.util.MapUtils
|
||||
import org.drinkless.td.libcore.telegram.TdApi
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class SetTimeDialogFragment : DialogFragment() {
|
||||
class SetTimeDialogFragment : DialogFragment(), TelegramLocationListener, TelegramCompassListener {
|
||||
|
||||
private val app: TelegramApplication
|
||||
get() = activity?.application as TelegramApplication
|
||||
|
@ -29,6 +37,7 @@ class SetTimeDialogFragment : DialogFragment() {
|
|||
private val telegramHelper get() = app.telegramHelper
|
||||
private val settings get() = app.settings
|
||||
|
||||
private lateinit var locationViewCache: UiUtils.UpdateLocationViewCache
|
||||
private val adapter = SetTimeListAdapter()
|
||||
|
||||
private lateinit var timeForAllTitle: TextView
|
||||
|
@ -36,6 +45,10 @@ class SetTimeDialogFragment : DialogFragment() {
|
|||
|
||||
private val chatLivePeriods = HashMap<Long, Long>()
|
||||
|
||||
private var location: Location? = null
|
||||
private var heading: Float? = null
|
||||
private var locationUiUpdateAllowed: Boolean = true
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(DialogFragment.STYLE_NO_FRAME, R.style.AppTheme_NoActionbar)
|
||||
|
@ -66,6 +79,12 @@ class SetTimeDialogFragment : DialogFragment() {
|
|||
view.findViewById<RecyclerView>(R.id.recycler_view).apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = this@SetTimeDialogFragment.adapter
|
||||
addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
locationUiUpdateAllowed = newState == RecyclerView.SCROLL_STATE_IDLE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
view.findViewById<TextView>(R.id.secondary_btn).apply {
|
||||
|
@ -98,9 +117,16 @@ class SetTimeDialogFragment : DialogFragment() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
locationViewCache = app.uiUtils.getUpdateLocationViewCache()
|
||||
startLocationUpdate()
|
||||
updateList()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
stopLocationUpdate()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
val chats = mutableListOf<Long>()
|
||||
|
@ -111,6 +137,47 @@ class SetTimeDialogFragment : DialogFragment() {
|
|||
outState.putLongArray(CHATS_KEY, chats.toLongArray())
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateCompassValue(value: Float) {
|
||||
// 99 in next line used to one-time initialize arrows (with reference vs. fixed-north direction)
|
||||
// on non-compass devices
|
||||
val lastHeading = heading ?: 99f
|
||||
heading = value
|
||||
if (Math.abs(MapUtils.degreesDiff(lastHeading.toDouble(), value.toDouble())) > 5) {
|
||||
updateLocationUi()
|
||||
} else {
|
||||
heading = lastHeading
|
||||
}
|
||||
}
|
||||
|
||||
private fun startLocationUpdate() {
|
||||
app.locationProvider.addLocationListener(this)
|
||||
app.locationProvider.addCompassListener(this)
|
||||
updateLocationUi()
|
||||
}
|
||||
|
||||
private fun stopLocationUpdate() {
|
||||
app.locationProvider.removeLocationListener(this)
|
||||
app.locationProvider.removeCompassListener(this)
|
||||
}
|
||||
|
||||
private fun updateLocationUi() {
|
||||
if (locationUiUpdateAllowed) {
|
||||
app.runInUIThread { adapter.notifyDataSetChanged() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun readFromBundle(bundle: Bundle?) {
|
||||
chatLivePeriods.clear()
|
||||
bundle?.getLongArray(CHATS_KEY)?.also {
|
||||
|
@ -216,7 +283,35 @@ class SetTimeDialogFragment : DialogFragment() {
|
|||
|
||||
TelegramUiHelper.setupPhoto(app, holder.icon, chat.photo?.small?.local?.path, placeholderId, false)
|
||||
holder.title?.text = chat.title
|
||||
holder.description?.visibility = View.INVISIBLE
|
||||
|
||||
if (telegramHelper.isGroup(chat)) {
|
||||
holder.locationViewContainer?.visibility = View.GONE
|
||||
holder.description?.visibility = View.VISIBLE
|
||||
holder.description?.text = getString(R.string.shared_string_group)
|
||||
} else {
|
||||
val message = telegramHelper.getChatMessages(chat.id).firstOrNull()
|
||||
val content = message?.content
|
||||
if (message != null && content is TdApi.MessageLocation && (location != null && content.location != null)) {
|
||||
val lastUpdated = telegramHelper.getLastUpdatedTime(message)
|
||||
holder.description?.visibility = View.VISIBLE
|
||||
holder.description?.text = getListItemLiveTimeDescr(lastUpdated)
|
||||
|
||||
holder.locationViewContainer?.visibility = View.VISIBLE
|
||||
locationViewCache.outdatedLocation = System.currentTimeMillis() / 1000 -
|
||||
lastUpdated > settings.staleLocTime
|
||||
|
||||
app.uiUtils.updateLocationView(
|
||||
holder.directionIcon,
|
||||
holder.distanceText,
|
||||
LatLon(content.location.latitude, content.location.longitude),
|
||||
locationViewCache
|
||||
)
|
||||
} else {
|
||||
holder.locationViewContainer?.visibility = View.GONE
|
||||
holder.description?.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
holder.textInArea?.apply {
|
||||
visibility = View.VISIBLE
|
||||
chatLivePeriods[chat.id]?.also { text = formatLivePeriod(it) }
|
||||
|
@ -229,9 +324,22 @@ class SetTimeDialogFragment : DialogFragment() {
|
|||
|
||||
override fun getItemCount() = chats.size
|
||||
|
||||
private fun getListItemLiveTimeDescr(lastUpdated: Int): String {
|
||||
val duration = System.currentTimeMillis() / 1000 - lastUpdated
|
||||
var formattedTime = OsmandFormatter.getFormattedDuration(app, duration)
|
||||
if (duration > 48 * 60 * 60) {
|
||||
// TODO make constant
|
||||
formattedTime = Date(lastUpdated * 1000.toLong()).toString();
|
||||
}
|
||||
return "$formattedTime " + getString(R.string.time_ago)
|
||||
}
|
||||
|
||||
inner class ChatViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
val icon: ImageView? = view.findViewById(R.id.icon)
|
||||
val title: TextView? = view.findViewById(R.id.title)
|
||||
val directionIcon: ImageView? = view.findViewById(R.id.direction_icon)
|
||||
val distanceText: TextView? = view.findViewById(R.id.distance_text)
|
||||
val locationViewContainer: View? = view.findViewById(R.id.location_view_container)
|
||||
val description: TextView? = view.findViewById(R.id.description)
|
||||
val textInArea: TextView? = view.findViewById(R.id.text_in_area)
|
||||
val bottomShadow: View? = view.findViewById(R.id.bottom_shadow)
|
||||
|
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.5 KiB |
BIN
OsmAnd/res/drawable-hdpi/map_pin_user_stale_location_day.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
OsmAnd/res/drawable-hdpi/map_pin_user_stale_location_night.png
Normal file
After Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
OsmAnd/res/drawable-mdpi/map_pin_user_stale_location_day.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
OsmAnd/res/drawable-mdpi/map_pin_user_stale_location_night.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 3 KiB |
BIN
OsmAnd/res/drawable-xhdpi/map_pin_user_stale_location_day.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
OsmAnd/res/drawable-xhdpi/map_pin_user_stale_location_night.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 4.1 KiB |
BIN
OsmAnd/res/drawable-xxhdpi/map_pin_user_stale_location_day.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
OsmAnd/res/drawable-xxhdpi/map_pin_user_stale_location_night.png
Normal file
After Width: | Height: | Size: 11 KiB |