Merge branch 'master' of ssh://github.com/osmandapp/Osmand into js_voice_routing

This commit is contained in:
PaulStets 2018-08-16 17:03:43 +03:00
commit 6edf2f9dc8
19 changed files with 221 additions and 84 deletions

View file

@ -1,4 +1,7 @@
<resources> <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="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="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> <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>

View file

@ -54,7 +54,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
val messages = telegramHelper.getMessages() val messages = telegramHelper.getMessages()
for (message in messages) { for (message in messages) {
val date = Math.max(message.date, message.editDate) * 1000L 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) { if (expired) {
removeMapPoint(message.chatId, message) removeMapPoint(message.chatId, message)
} }

View file

@ -28,6 +28,7 @@ class TelegramHelper private constructor() {
private const val DEVICE_PREFIX = "Device: " private const val DEVICE_PREFIX = "Device: "
private const val LOCATION_PREFIX = "Location: " 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 FEW_SECONDS_AGO = "few seconds ago"
private const val SECONDS_AGO_SUFFIX = " 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 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 fun isPrivateChat(chat: TdApi.Chat): Boolean = chat.type is TdApi.ChatTypePrivate
private fun isChannel(chat: TdApi.Chat): Boolean { private fun isChannel(chat: TdApi.Chat): Boolean {
@ -481,16 +484,15 @@ class TelegramHelper private constructor() {
private fun addNewMessage(message: TdApi.Message) { private fun addNewMessage(message: TdApi.Message) {
if (message.isAppropriate()) { if (message.isAppropriate()) {
val fromBot = isOsmAndBot(message.senderUserId)
val viaBot = isOsmAndBot(message.viaBotUserId)
val oldContent = message.content val oldContent = message.content
if (oldContent is TdApi.MessageText) { if (oldContent is TdApi.MessageText) {
val messageOsmAndBotLocation = parseOsmAndBotLocation(oldContent.text.text) message.content = parseOsmAndBotLocation(oldContent.text.text)
messageOsmAndBotLocation.created = message.date } else if (oldContent is TdApi.MessageLocation && (fromBot || viaBot)) {
message.content = messageOsmAndBotLocation
} else if (oldContent is TdApi.MessageLocation &&
(isOsmAndBot(message.senderUserId) || isOsmAndBot(message.viaBotUserId))) {
message.content = parseOsmAndBotLocation(message) message.content = parseOsmAndBotLocation(message)
} }
removeOldMessages(message.senderUserId, message.chatId) removeOldMessages(message, fromBot, viaBot)
usersLocationMessages[message.id] = message usersLocationMessages[message.id] = message
incomingMessagesListeners.forEach { incomingMessagesListeners.forEach {
it.onReceiveChatLocationMessages(message.chatId, message) it.onReceiveChatLocationMessages(message.chatId, message)
@ -498,13 +500,25 @@ class TelegramHelper private constructor() {
} }
} }
private fun removeOldMessages(userId: Int, chatId: Long) { private fun removeOldMessages(newMessage: TdApi.Message, fromBot: Boolean, viaBot: Boolean) {
val user = users[userId] val iterator = usersLocationMessages.entries.iterator()
if (user != null && user.username != OSMAND_BOT_USERNAME) { while (iterator.hasNext()) {
usersLocationMessages.values.filter { it.senderUserId == userId && it.chatId == chatId } val message = iterator.next().value
.forEach { if (newMessage.chatId == message.chatId) {
usersLocationMessages.remove(it.id) 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 val content = content
return when (content) { return when (content) {
is TdApi.MessageLocation -> true 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 else -> false
} }
} }
@ -760,13 +775,7 @@ class TelegramHelper private constructor() {
name = getOsmAndBotDeviceName(message) name = getOsmAndBotDeviceName(message)
lat = messageLocation.location.latitude lat = messageLocation.location.latitude
lon = messageLocation.location.longitude lon = messageLocation.location.longitude
created = message.date lastUpdated = getLastUpdatedTime(message)
val date = message.editDate
lastUpdated = if (date != 0) {
date
} else {
message.date
}
} }
} }
@ -776,33 +785,46 @@ class TelegramHelper private constructor() {
name = oldContent.name name = oldContent.name
lat = messageLocation.location.latitude lat = messageLocation.location.latitude
lon = messageLocation.location.longitude lon = messageLocation.location.longitude
created = oldContent.created
lastUpdated = (System.currentTimeMillis() / 1000).toInt() lastUpdated = (System.currentTimeMillis() / 1000).toInt()
} }
} }
private fun parseOsmAndBotLocation(text: String): MessageOsmAndBotLocation { private fun parseOsmAndBotLocation(text: String): MessageOsmAndBotLocation {
val res = MessageOsmAndBotLocation() val res = MessageOsmAndBotLocation()
var locationNA = false
for (s in text.lines()) { for (s in text.lines()) {
when { when {
s.startsWith(DEVICE_PREFIX) -> { s.startsWith(DEVICE_PREFIX) -> {
res.name = s.removePrefix(DEVICE_PREFIX) res.name = s.removePrefix(DEVICE_PREFIX)
} }
s.startsWith(LOCATION_PREFIX) -> { s.startsWith(LOCATION_PREFIX) || s.startsWith(LAST_LOCATION_PREFIX) -> {
val locStr = s.removePrefix(LOCATION_PREFIX) var locStr: String
try { var parse = true
val (latS, lonS) = locStr.split(" ") if (s.startsWith(LAST_LOCATION_PREFIX)) {
val updatedS = locStr.substring(locStr.indexOf("("), locStr.length) locStr = s.removePrefix(LAST_LOCATION_PREFIX)
val timeSecs = parseTime(updatedS.removePrefix("(").removeSuffix(")")) if (!locationNA) {
res.lat = latS.dropLast(1).toDouble() parse = false
res.lon = lonS.toDouble() }
if (timeSecs < messageActiveTimeSec) { } else {
res.lastUpdated = (System.currentTimeMillis() / 1000 - timeSecs).toInt() locStr = s.removePrefix(LOCATION_PREFIX)
} else { if (locStr.trim() == "n/a") {
res.lastUpdated = timeSecs 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 return res
} }
private fun parseTime(timeS: String): Int { private fun parseTime(timeS: String): Long {
try { try {
when { when {
timeS.endsWith(FEW_SECONDS_AGO) -> return 5 timeS.endsWith(FEW_SECONDS_AGO) -> return System.currentTimeMillis() - 5000
timeS.endsWith(SECONDS_AGO_SUFFIX) -> { timeS.endsWith(SECONDS_AGO_SUFFIX) -> {
val locStr = timeS.removeSuffix(SECONDS_AGO_SUFFIX) val locStr = timeS.removeSuffix(SECONDS_AGO_SUFFIX)
return locStr.toInt() return System.currentTimeMillis() - locStr.toLong() * 1000
} }
timeS.endsWith(MINUTES_AGO_SUFFIX) -> { timeS.endsWith(MINUTES_AGO_SUFFIX) -> {
val locStr = timeS.removeSuffix(MINUTES_AGO_SUFFIX) val locStr = timeS.removeSuffix(MINUTES_AGO_SUFFIX)
val minutes = locStr.toInt() val minutes = locStr.toLong()
return minutes * 60 return System.currentTimeMillis() - minutes * 60 * 1000
} }
timeS.endsWith(HOURS_AGO_SUFFIX) -> { timeS.endsWith(HOURS_AGO_SUFFIX) -> {
val locStr = timeS.removeSuffix(HOURS_AGO_SUFFIX) val locStr = timeS.removeSuffix(HOURS_AGO_SUFFIX)
val hours = locStr.toInt() val hours = locStr.toLong()
return hours * 60 * 60 return (System.currentTimeMillis() - hours * 60 * 60 * 1000)
} }
timeS.endsWith(UTC_FORMAT_SUFFIX) -> { timeS.endsWith(UTC_FORMAT_SUFFIX) -> {
val locStr = timeS.removeSuffix(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 date = UTC_DATE_FORMAT.parse(latS)
val time = UTC_TIME_FORMAT.parse(lonS) val time = UTC_TIME_FORMAT.parse(lonS)
val res = date.time + time.time val res = date.time + time.time
return res.toInt() return res
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -1068,9 +1090,7 @@ class TelegramHelper private constructor() {
synchronized(message) { synchronized(message) {
val newContent = updateMessageContent.newContent val newContent = updateMessageContent.newContent
message.content = if (newContent is TdApi.MessageText) { message.content = if (newContent is TdApi.MessageText) {
val messageOsmAndBotLocation = parseOsmAndBotLocation(newContent.text.text) parseOsmAndBotLocation(newContent.text.text)
messageOsmAndBotLocation.created = message.date
messageOsmAndBotLocation
} else if (newContent is TdApi.MessageLocation && } else if (newContent is TdApi.MessageLocation &&
(isOsmAndBot(message.senderUserId) || isOsmAndBot(message.viaBotUserId))) { (isOsmAndBot(message.senderUserId) || isOsmAndBot(message.viaBotUserId))) {
parseOsmAndBotLocationContent(message.content as MessageOsmAndBotLocation, newContent) parseOsmAndBotLocationContent(message.content as MessageOsmAndBotLocation, newContent)

View file

@ -52,11 +52,6 @@ object TelegramUiHelper {
placeholderId = R.drawable.img_user_picture placeholderId = R.drawable.img_user_picture
} }
val type = chat.type 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) { if (type is TdApi.ChatTypePrivate || type is TdApi.ChatTypeSecret) {
val userId = getUserIdFromChatType(type) val userId = getUserIdFromChatType(type)
val chatWithBot = helper.isBot(userId) val chatWithBot = helper.isBot(userId)
@ -64,9 +59,13 @@ object TelegramUiHelper {
res.chatWithBot = chatWithBot res.chatWithBot = chatWithBot
if (!chatWithBot) { if (!chatWithBot) {
res.userId = userId res.userId = userId
val content = message?.content val message = messages.firstOrNull { it.viaBotUserId == 0 }
if (content is TdApi.MessageLocation) { if (message != null) {
res.latLon = LatLon(content.location.latitude, content.location.longitude) 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) { } else if (type is TdApi.ChatTypeBasicGroup) {
@ -125,7 +124,6 @@ object TelegramUiHelper {
latLon = LatLon(content.lat, content.lon) latLon = LatLon(content.lat, content.lon)
placeholderId = R.drawable.img_user_picture placeholderId = R.drawable.img_user_picture
lastUpdated = content.lastUpdated lastUpdated = content.lastUpdated
created = content.created
} }
} else { } else {
null null
@ -147,8 +145,7 @@ object TelegramUiHelper {
photoPath = helper.getUserPhotoPath(user) photoPath = helper.getUserPhotoPath(user)
placeholderId = R.drawable.img_user_picture placeholderId = R.drawable.img_user_picture
userId = message.senderUserId userId = message.senderUserId
lastUpdated = message.editDate lastUpdated = helper.getLastUpdatedTime(message)
created = message.date
} }
} }
@ -168,8 +165,6 @@ object TelegramUiHelper {
internal set internal set
var lastUpdated: Int = 0 var lastUpdated: Int = 0
internal set internal set
var created: Int = 0
internal set
abstract fun canBeOpenedOnMap(): Boolean abstract fun canBeOpenedOnMap(): Boolean

View file

@ -29,6 +29,8 @@ import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.telegram.utils.UiUtils.UpdateLocationViewCache import net.osmand.telegram.utils.UiUtils.UpdateLocationViewCache
import net.osmand.util.MapUtils import net.osmand.util.MapUtils
import org.drinkless.td.libcore.telegram.TdApi import org.drinkless.td.libcore.telegram.TdApi
import java.text.SimpleDateFormat
import java.util.*
private const val CHAT_VIEW_TYPE = 0 private const val CHAT_VIEW_TYPE = 0
private const val LOCATION_ITEM_VIEW_TYPE = 1 private const val LOCATION_ITEM_VIEW_TYPE = 1
@ -221,31 +223,32 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
for ((id, messages) in telegramHelper.getMessagesByChatIds()) { for ((id, messages) in telegramHelper.getMessagesByChatIds()) {
telegramHelper.getChat(id)?.also { chat -> telegramHelper.getChat(id)?.also { chat ->
res.add(TelegramUiHelper.chatToChatItem(telegramHelper, chat, messages)) 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)) 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 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( private fun convertToLocationItems(
chat: TdApi.Chat, chat: TdApi.Chat,
messages: List<TdApi.Message> messages: List<TdApi.Message>,
addOnlyViaBotMessages: Boolean = false
): List<LocationItem> { ): List<LocationItem> {
val res = mutableListOf<LocationItem>() val res = mutableListOf<LocationItem>()
messages.forEach { message -> messages.forEach { message ->
TelegramUiHelper.messageToLocationItem(telegramHelper, chat, message)?.also { if (!addOnlyViaBotMessages || message.viaBotUserId != 0) {
res.add(it) TelegramUiHelper.messageToLocationItem(telegramHelper, chat, message)?.also {
res.add(it)
}
} }
} }
return res return res
@ -319,7 +322,7 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
} }
if (location != null && item.latLon != null) { if (location != null && item.latLon != null) {
holder.locationViewContainer?.visibility = View.VISIBLE 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( app.uiUtils.updateLocationView(
holder.directionIcon, holder.directionIcon,
holder.distanceText, holder.distanceText,
@ -361,13 +364,19 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
} }
} }
private fun getListItemLiveTimeDescr(item: ListItem):String { private fun getListItemLiveTimeDescr(item: ListItem): String {
return getString(R.string.shared_string_live) + val duration = System.currentTimeMillis() / 1000 - item.lastUpdated
": ${OsmandFormatter.getFormattedDuration(app, getListItemLiveTime(item))}" 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) { private fun showPopupMenu(holder: ChatViewHolder, chatId: Long) {
val ctx = holder.itemView.context val ctx = holder.itemView.context

View file

@ -577,23 +577,25 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
holder.stopSharingDescr?.apply { holder.stopSharingDescr?.apply {
visibility = View.VISIBLE visibility = getStopSharingVisibility(expiresIn)
text = "${getText(R.string.stop_at)}:" text = "${getText(R.string.stop_at)}:"
} }
holder.stopSharingFirstPart?.apply { holder.stopSharingFirstPart?.apply {
visibility = View.VISIBLE visibility = getStopSharingVisibility(expiresIn)
text = OsmandFormatter.getFormattedTime(expiresIn) text = OsmandFormatter.getFormattedTime(expiresIn)
} }
holder.stopSharingSecondPart?.apply { holder.stopSharingSecondPart?.apply {
visibility = View.VISIBLE visibility = getStopSharingVisibility(expiresIn)
text = "(${getString(R.string.in_time, text = "(${getString(R.string.in_time,
OsmandFormatter.getFormattedDuration(context!!, expiresIn, true))})" OsmandFormatter.getFormattedDuration(context!!, expiresIn, true))})"
} }
} }
} }
private fun getStopSharingVisibility(expiresIn: Long) = if (expiresIn > 0) View.VISIBLE else View.INVISIBLE
private fun removeItem(chat: TdApi.Chat) { private fun removeItem(chat: TdApi.Chat) {
chats.remove(chat) chats.remove(chat)
if (chats.isEmpty()) { if (chats.isEmpty()) {

View file

@ -12,16 +12,24 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import net.osmand.Location
import net.osmand.data.LatLon
import net.osmand.telegram.R import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication 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.ShareLocationHelper
import net.osmand.telegram.helpers.TelegramUiHelper import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.ui.SetTimeDialogFragment.SetTimeListAdapter.ChatViewHolder import net.osmand.telegram.ui.SetTimeDialogFragment.SetTimeListAdapter.ChatViewHolder
import net.osmand.telegram.utils.AndroidUtils 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 org.drinkless.td.libcore.telegram.TdApi
import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class SetTimeDialogFragment : DialogFragment() { class SetTimeDialogFragment : DialogFragment(), TelegramLocationListener, TelegramCompassListener {
private val app: TelegramApplication private val app: TelegramApplication
get() = activity?.application as TelegramApplication get() = activity?.application as TelegramApplication
@ -29,6 +37,7 @@ class SetTimeDialogFragment : DialogFragment() {
private val telegramHelper get() = app.telegramHelper private val telegramHelper get() = app.telegramHelper
private val settings get() = app.settings private val settings get() = app.settings
private lateinit var locationViewCache: UiUtils.UpdateLocationViewCache
private val adapter = SetTimeListAdapter() private val adapter = SetTimeListAdapter()
private lateinit var timeForAllTitle: TextView private lateinit var timeForAllTitle: TextView
@ -36,6 +45,10 @@ class SetTimeDialogFragment : DialogFragment() {
private val chatLivePeriods = HashMap<Long, Long>() 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?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setStyle(DialogFragment.STYLE_NO_FRAME, R.style.AppTheme_NoActionbar) setStyle(DialogFragment.STYLE_NO_FRAME, R.style.AppTheme_NoActionbar)
@ -66,6 +79,12 @@ class SetTimeDialogFragment : DialogFragment() {
view.findViewById<RecyclerView>(R.id.recycler_view).apply { view.findViewById<RecyclerView>(R.id.recycler_view).apply {
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
adapter = this@SetTimeDialogFragment.adapter 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 { view.findViewById<TextView>(R.id.secondary_btn).apply {
@ -98,9 +117,16 @@ class SetTimeDialogFragment : DialogFragment() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
locationViewCache = app.uiUtils.getUpdateLocationViewCache()
startLocationUpdate()
updateList() updateList()
} }
override fun onPause() {
super.onPause()
stopLocationUpdate()
}
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
val chats = mutableListOf<Long>() val chats = mutableListOf<Long>()
@ -111,6 +137,47 @@ class SetTimeDialogFragment : DialogFragment() {
outState.putLongArray(CHATS_KEY, chats.toLongArray()) 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?) { private fun readFromBundle(bundle: Bundle?) {
chatLivePeriods.clear() chatLivePeriods.clear()
bundle?.getLongArray(CHATS_KEY)?.also { bundle?.getLongArray(CHATS_KEY)?.also {
@ -216,7 +283,35 @@ class SetTimeDialogFragment : DialogFragment() {
TelegramUiHelper.setupPhoto(app, holder.icon, chat.photo?.small?.local?.path, placeholderId, false) TelegramUiHelper.setupPhoto(app, holder.icon, chat.photo?.small?.local?.path, placeholderId, false)
holder.title?.text = chat.title 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 { holder.textInArea?.apply {
visibility = View.VISIBLE visibility = View.VISIBLE
chatLivePeriods[chat.id]?.also { text = formatLivePeriod(it) } chatLivePeriods[chat.id]?.also { text = formatLivePeriod(it) }
@ -229,9 +324,22 @@ class SetTimeDialogFragment : DialogFragment() {
override fun getItemCount() = chats.size 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) { inner class ChatViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
val icon: ImageView? = view.findViewById(R.id.icon) val icon: ImageView? = view.findViewById(R.id.icon)
val title: TextView? = view.findViewById(R.id.title) 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 description: TextView? = view.findViewById(R.id.description)
val textInArea: TextView? = view.findViewById(R.id.text_in_area) val textInArea: TextView? = view.findViewById(R.id.text_in_area)
val bottomShadow: View? = view.findViewById(R.id.bottom_shadow) val bottomShadow: View? = view.findViewById(R.id.bottom_shadow)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB