Merge pull request #5881 from osmandapp/TravelUiImprovements

SetTimeDialog UI Improvements
This commit is contained in:
Alexander Sytnyk 2018-08-16 14:29:55 +03:00 committed by GitHub
commit 7d3ea473e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 31 deletions

View file

@ -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>

View file

@ -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)
}

View file

@ -177,6 +177,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 {
@ -485,9 +487,7 @@ class TelegramHelper private constructor() {
val viaBot = isOsmAndBot(message.viaBotUserId)
val oldContent = message.content
if (oldContent is TdApi.MessageText) {
message.content = parseOsmAndBotLocation(oldContent.text.text).apply {
created = message.date
}
message.content = parseOsmAndBotLocation(oldContent.text.text)
} else if (oldContent is TdApi.MessageLocation && (fromBot || viaBot)) {
message.content = parseOsmAndBotLocation(message)
}
@ -761,13 +761,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)
}
}
@ -777,7 +771,6 @@ class TelegramHelper private constructor() {
name = oldContent.name
lat = messageLocation.location.latitude
lon = messageLocation.location.longitude
created = oldContent.created
lastUpdated = (System.currentTimeMillis() / 1000).toInt()
}
}
@ -1069,9 +1062,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)

View file

@ -54,8 +54,7 @@ object TelegramUiHelper {
val type = chat.type
val message = messages.firstOrNull()
if (message != null) {
res.lastUpdated = message.editDate
res.created = message.date
res.lastUpdated = helper.getLastUpdatedTime(message)
}
if (type is TdApi.ChatTypePrivate || type is TdApi.ChatTypeSecret) {
val userId = getUserIdFromChatType(type)
@ -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

View file

@ -361,12 +361,12 @@ 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 formattedTime = OsmandFormatter.getFormattedDuration(app, getListItemLiveTime(item))
return getString(R.string.last_response) + ": $formattedTime " + getString(R.string.time_ago)
}
private fun getListItemLiveTime(item: ListItem): Long = (System.currentTimeMillis() / 1000) - item.created
private fun getListItemLiveTime(item: ListItem): Long = (System.currentTimeMillis() / 1000) - item.lastUpdated
private fun showPopupMenu(holder: ChatViewHolder, chatId: Long) {
val ctx = holder.itemView.context

View file

@ -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()) {

View file

@ -12,16 +12,23 @@ 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.concurrent.TimeUnit
class SetTimeDialogFragment : DialogFragment() {
class SetTimeDialogFragment : DialogFragment(), TelegramLocationListener, TelegramCompassListener {
private val app: TelegramApplication
get() = activity?.application as TelegramApplication
@ -29,6 +36,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 +44,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 +78,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 +116,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 +136,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 +282,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 +323,21 @@ class SetTimeDialogFragment : DialogFragment() {
override fun getItemCount() = chats.size
private fun getListItemLiveTimeDescr(lastUpdated: Int): String {
val formattedTime = OsmandFormatter.getFormattedDuration(app, getListItemLiveTime(lastUpdated))
return "$formattedTime " + getString(R.string.time_ago)
}
private fun getListItemLiveTime(lastUpdated: Int): Long {
return (System.currentTimeMillis() / 1000) - lastUpdated
}
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)