This commit is contained in:
Dmitriy Ruban 2019-12-27 19:20:30 +02:00
parent c5cfb47950
commit 11e3da3701
6 changed files with 228 additions and 28 deletions

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="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:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="25dp" />
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="54dp"
android:background="?attr/shared_chat_card_bg"
android:gravity="start|center_vertical"
android:paddingStart="@dimen/content_padding_standard"
android:paddingLeft="@dimen/content_padding_half"
android:paddingRight="@dimen/content_padding_half"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/hint_text_size"
app:typeface="@string/font_roboto_mono_bold"
tools:text="Suggested" />
</LinearLayout>

View file

@ -26,8 +26,11 @@
tools:src="@drawable/img_user_picture" /> tools:src="@drawable/img_user_picture" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_half"
android:layout_weight="1"
android:orientation="vertical"> android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx <net.osmand.telegram.ui.views.TextViewEx
@ -47,13 +50,29 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textColor="?attr/android:textColorSecondary" android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/list_item_description_text_size" android:textSize="@dimen/list_item_description_text_size"
app:typeface="@string/font_roboto_regular" app:typeface="@string/font_roboto_regular"
tools:text="for 1 hour" /> tools:text="for 1 hour" />
</LinearLayout> </LinearLayout>
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="@dimen/dialog_button_height"
android:layout_marginEnd="@dimen/image_button_padding"
android:layout_marginRight="@dimen/image_button_padding"
android:background="?attr/secondary_btn_bg"
android:gravity="center"
android:paddingLeft="@dimen/image_button_padding"
android:paddingRight="@dimen/image_button_padding"
android:text="@string/shared_string_start"
android:textColor="?attr/ctrl_active_color"
android:textSize="@dimen/text_button_text_size"
app:typeface="@string/font_roboto_medium"
tools:text="Start" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="shared_string_suggested">Suggested</string>
<string name="time_zone_descr">Select time zone to show in your location messages.</string> <string name="time_zone_descr">Select time zone to show in your location messages.</string>
<string name="time_zone">Time zone</string> <string name="time_zone">Time zone</string>
<string name="units_and_formats">Units &amp; formats</string> <string name="units_and_formats">Units &amp; formats</string>

View file

@ -7,6 +7,7 @@ import android.support.annotation.DrawableRes
import android.support.annotation.StringRes import android.support.annotation.StringRes
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import com.google.gson.JsonObject
import net.osmand.PlatformUtil import net.osmand.PlatformUtil
import net.osmand.telegram.helpers.OsmandAidlHelper import net.osmand.telegram.helpers.OsmandAidlHelper
import net.osmand.telegram.helpers.ShowLocationHelper import net.osmand.telegram.helpers.ShowLocationHelper
@ -14,13 +15,15 @@ import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.utils.* import net.osmand.telegram.utils.*
import net.osmand.telegram.utils.OsmandFormatter.MetricsConstants import net.osmand.telegram.utils.OsmandFormatter.MetricsConstants
import net.osmand.telegram.utils.OsmandFormatter.SpeedConstants import net.osmand.telegram.utils.OsmandFormatter.SpeedConstants
import net.osmand.telegram.utils.OsmandLocationUtils
import org.drinkless.td.libcore.telegram.TdApi import org.drinkless.td.libcore.telegram.TdApi
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.collections.ArrayList
val ADDITIONAL_ACTIVE_TIME_VALUES_SEC = listOf(15 * 60L, 30 * 60L, 60 * 60L, 180 * 60L) val ADDITIONAL_ACTIVE_TIME_VALUES_SEC = listOf(15 * 60L, 30 * 60L, 60 * 60L, 180 * 60L)
@ -838,6 +841,8 @@ class TelegramSettings(private val app: TelegramApplication) {
val obj = JSONObject() val obj = JSONObject()
obj.put(LastChatInfo.CHAT_ID_KEY, chatId) obj.put(LastChatInfo.CHAT_ID_KEY, chatId)
obj.put(LastChatInfo.LIVE_PERIOD_KEY, lastInfo.livePeriod) obj.put(LastChatInfo.LIVE_PERIOD_KEY, lastInfo.livePeriod)
obj.put(LastChatInfo.PERIODS_KEY, convertPeriodsToJson(lastInfo.periods))
log.info("Periods to put: ${lastInfo.periods}")
jArray.put(obj) jArray.put(obj)
} }
jArray jArray
@ -847,6 +852,22 @@ class TelegramSettings(private val app: TelegramApplication) {
} }
} }
private fun convertPeriodsToJson(periods: LinkedList<Long>): JSONArray? {
return try {
val jArray = JSONArray()
for (i in 0 until periods.count()) {
val obj = JSONObject()
obj.put(i.toString(), periods[i])
jArray.put(obj)
}
log.info("Json array periods: $jArray")
jArray
} catch (e: JSONException) {
log.error(e)
null
}
}
private fun parseShareChatsInfo(json: JSONArray) { private fun parseShareChatsInfo(json: JSONArray) {
for (i in 0 until json.length()) { for (i in 0 until json.length()) {
val obj = json.getJSONObject(i) val obj = json.getJSONObject(i)
@ -918,12 +939,59 @@ class TelegramSettings(private val app: TelegramApplication) {
val obj = json.getJSONObject(i) val obj = json.getJSONObject(i)
val lastInfo = LastChatInfo().apply { val lastInfo = LastChatInfo().apply {
chatId = obj.optLong(LastChatInfo.CHAT_ID_KEY) chatId = obj.optLong(LastChatInfo.CHAT_ID_KEY)
livePeriod = obj.getLong(LastChatInfo.LIVE_PERIOD_KEY) // livePeriod = obj.optLong(LastChatInfo.LIVE_PERIOD_KEY)
periods = LinkedList<Long>()
val jsonArray = obj.getJSONArray(LastChatInfo.PERIODS_KEY)
log.info("getJson: $jsonArray")
for (j in 0 until jsonArray.length()) {
val obj=jsonArray.get(j) as JSONObject
periods.add(obj.optLong(j.toString()))
}
log.info("Periods: $periods")
livePeriod = calcLivePeriod(periods)
} }
lastChatsInfo[lastInfo.chatId] = lastInfo lastChatsInfo[lastInfo.chatId] = lastInfo
} }
} }
fun addTimePeriodToLastItem(id: Long, time: Long) {
if (lastChatsInfo.containsKey(id)) {
lastChatsInfo[id]?.periods = addTimeToPeriods(lastChatsInfo[id]?.periods, time)
} else {
lastChatsInfo[id] = LastChatInfo().apply {
chatId = id
livePeriod = time
periods = LinkedList<Long>().apply {
addFirst(time)
}
}
}
}
private fun addTimeToPeriods(periods: LinkedList<Long>?, time: Long): LinkedList<Long> {
if (periods?.isNotEmpty() != null) {
return if (periods.count() < 5) {
periods.addFirst(time)
periods
} else {
periods.removeLast()
periods.addFirst(time)
periods
}
}
return LinkedList<Long>().apply { addFirst(time) }
}
private fun calcLivePeriod(periods: LinkedList<Long>): Long {
periods.sort()
return if (periods.count() % 2 == 0) {
(periods[periods.count() / 2] + periods[periods.count() / 2 - 1]) / 2
} else {
periods[periods.count() / 2]
}
}
private fun getLiveNowChats() = app.telegramHelper.getMessagesByChatIds(locHistoryTime).keys private fun getLiveNowChats() = app.telegramHelper.getMessagesByChatIds(locHistoryTime).keys
private fun updatePrefs() { private fun updatePrefs() {
@ -1417,10 +1485,12 @@ class TelegramSettings(private val app: TelegramApplication) {
var chatId = -1L var chatId = -1L
var livePeriod = -1L var livePeriod = -1L
var periods = LinkedList<Long>()
companion object { companion object {
internal const val CHAT_ID_KEY = "chatId" internal const val CHAT_ID_KEY = "chatId"
internal const val LIVE_PERIOD_KEY = "livePeriod" internal const val LIVE_PERIOD_KEY = "livePeriod"
internal const val PERIODS_KEY = "periods"
} }
} }
} }

View file

@ -1,6 +1,8 @@
package net.osmand.telegram.helpers package net.osmand.telegram.helpers
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.widget.ImageView import android.widget.ImageView
import net.osmand.data.LatLon import net.osmand.data.LatLon
@ -13,6 +15,11 @@ import org.drinkless.td.libcore.telegram.TdApi
object TelegramUiHelper { object TelegramUiHelper {
fun applyGrayscaleFilter(iv: ImageView?) {
val matrix = ColorMatrix().apply { setSaturation(0F) }
iv?.colorFilter = ColorMatrixColorFilter(matrix)
}
fun setupPhoto( fun setupPhoto(
app: TelegramApplication, app: TelegramApplication,
iv: ImageView?, iv: ImageView?,

View file

@ -3,7 +3,11 @@ package net.osmand.telegram.ui
import android.animation.* import android.animation.*
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.Typeface import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -33,6 +37,7 @@ import java.util.concurrent.ConcurrentHashMap
private const val SELECTED_CHATS_KEY = "selected_chats" private const val SELECTED_CHATS_KEY = "selected_chats"
private const val SELECTED_CHATS_USERS = "selected_users" private const val SELECTED_CHATS_USERS = "selected_users"
private const val HEADER = 3
private const val LAST_SHARE_CHAT = 2 private const val LAST_SHARE_CHAT = 2
private const val SHARE_LOCATION_CHAT = 1 private const val SHARE_LOCATION_CHAT = 1
private const val DEFAULT_CHAT = 0 private const val DEFAULT_CHAT = 0
@ -209,6 +214,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
} }
}) })
addItemDecoration(createDividerItemDecoration(sharingMode))
} }
mainView.findViewById<View>(R.id.stop_all_sharing_row).setOnClickListener { mainView.findViewById<View>(R.id.stop_all_sharing_row).setOnClickListener {
@ -248,6 +254,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
updateCurrentUserPhoto() updateCurrentUserPhoto()
updateContent() updateContent()
updateEnable = true updateEnable = true
settings.read()
startHandler() startHandler()
} }
@ -459,6 +466,54 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
} }
private fun createDividerItemDecoration(sharingMode: Boolean): RecyclerView.ItemDecoration {
val divider: Drawable = ColorDrawable(ContextCompat.getColor(app, R.color.card_divider_dark))
val pluginDividerHeight: Int = AndroidUtils.dpToPx(app, 1f)
return object : RecyclerView.ItemDecoration() {
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
val dividerLeft = if (sharingMode){
AndroidUtils.dpToPx(app, 72f)
} else {
parent.paddingLeft
}
val dividerRight = parent.width - parent.paddingRight
val childCount = parent.childCount
for (i in 0 until childCount - 1) {
val child = parent.getChildAt(i)
if (shouldDrawDivider(i)) {
val params = child.layoutParams as RecyclerView.LayoutParams
val dividerTop = child.bottom + params.bottomMargin
val dividerBottom = dividerTop + pluginDividerHeight
divider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom)
divider.draw(canvas)
}
}
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
if (shouldDrawDivider(position)) {
outRect[0, 0, 0] = pluginDividerHeight
}
}
private fun shouldDrawDivider(position: Int): Boolean {
val item = adapter.items[position]
val nextP = position + 1
if (nextP < adapter.items.count()) {
val next = adapter.items[nextP]
if (!sharingMode && item is LastChat && next !is LastChat) {
return true
}
}
if (sharingMode && item is LastChat) {
return true
}
return false
}
}
}
private fun updateContent() { private fun updateContent() {
sharingMode = sharingMode && settings.hasAnyChatToShareLocation() sharingMode = sharingMode && settings.hasAnyChatToShareLocation()
updateSharingStatus() updateSharingStatus()
@ -493,7 +548,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
private fun updateList() { private fun updateList() {
val items: MutableList<TdApi.Object> = mutableListOf() val lastItems = getLastShareItems()
val items: MutableList<Any> = mutableListOf()
val chats: MutableList<TdApi.Chat> = mutableListOf() val chats: MutableList<TdApi.Chat> = mutableListOf()
val contacts = telegramHelper.getContacts() val contacts = telegramHelper.getContacts()
val chatList = if (sharingMode) { val chatList = if (sharingMode) {
@ -521,28 +577,33 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
} }
if (sharingMode && settings.hasAnyChatToShareLocation()) { if (sharingMode && settings.hasAnyChatToShareLocation()) {
adapter.items = sortAdapterItems(items) val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList()
val sorted = sortAdapterItems(items as MutableList<TdApi.Object>)
if (filteredLastItems.isNotEmpty()) {
sorted.add(getString(R.string.shared_string_suggested))
}
sorted.addAll(filteredLastItems)
adapter.items = sorted
} else { } else {
items.addAll(0, getLastShareItems(items)) val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList()
items.addAll(0, filteredLastItems)
adapter.items = items adapter.items = items
} }
} }
private fun getLastShareItems(items: MutableList<TdApi.Object>): MutableList<TdApi.Object> { private fun getLastShareItems(): MutableList<LastChat> {
val lastItems: MutableList<TdApi.Object> = mutableListOf() val lastItems: MutableList<LastChat> = mutableListOf()
items.forEach { val chatListIds = telegramHelper.getChatListIds()
val id = when (it) { chatListIds.forEach { chatId ->
is TdApi.Chat -> it.id val chat = telegramHelper.getChat(chatId)
else -> -1 if (chat != null && lastChatsInfo.containsKey(chatId)) {
} lastItems.add(LastChat(chat, lastChatsInfo[chatId]!!.livePeriod))
if (lastChatsInfo.containsKey(id)) {
lastItems.add(LastChat(it as TdApi.Chat, lastChatsInfo[id]!!.livePeriod))
} }
} }
return lastItems return lastItems
} }
private fun sortAdapterItems(list: MutableList<TdApi.Object>): MutableList<TdApi.Object> { private fun sortAdapterItems(list: MutableList<TdApi.Object>): MutableList<Any> {
list.sortWith(Comparator<TdApi.Object> { o1, o2 -> list.sortWith(Comparator<TdApi.Object> { o1, o2 ->
val title1 = when (o1) { val title1 = when (o1) {
is TdApi.Chat -> o1.title is TdApi.Chat -> o1.title
@ -556,12 +617,12 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
title1.compareTo(title2) title1.compareTo(title2)
}) })
return list return list.toMutableList()
} }
inner class MyLocationListAdapter : inner class MyLocationListAdapter :
RecyclerView.Adapter<MyLocationListAdapter.BaseViewHolder>() { RecyclerView.Adapter<MyLocationListAdapter.BaseViewHolder>() {
var items = mutableListOf<TdApi.Object>() var items = mutableListOf<Any>()
set(value) { set(value) {
field = value field = value
notifyDataSetChanged() notifyDataSetChanged()
@ -576,6 +637,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
return if (item is LastChat) { return if (item is LastChat) {
LAST_SHARE_CHAT LAST_SHARE_CHAT
} else if (item is String) {
HEADER
} else if (settings.isSharingLocationToChat(id) && sharingMode) { } else if (settings.isSharingLocationToChat(id) && sharingMode) {
SHARE_LOCATION_CHAT SHARE_LOCATION_CHAT
} else { } else {
@ -600,6 +663,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
.inflate(R.layout.last_share_list_item, parent, false) .inflate(R.layout.last_share_list_item, parent, false)
LastChatViewHolder(view) LastChatViewHolder(view)
} }
HEADER -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.header_list_item, parent, false)
HeaderViewHolder(view)
}
else -> throw RuntimeException("Unsupported view type: $viewType") else -> throw RuntimeException("Unsupported view type: $viewType")
} }
} }
@ -610,8 +678,10 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
val isChat = item is TdApi.Chat val isChat = item is TdApi.Chat
val itemId = if (isChat) { val itemId = if (isChat) {
(item as TdApi.Chat).id (item as TdApi.Chat).id
} else if (item is TdApi.User) {
item.id.toLong()
} else { } else {
(item as TdApi.User).id.toLong() -1
} }
val lastItem = position == itemCount - 1 val lastItem = position == itemCount - 1
@ -629,6 +699,10 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
TelegramUiHelper.setupPhoto(app, holder.icon, photoPath, placeholderId, false) TelegramUiHelper.setupPhoto(app, holder.icon, photoPath, placeholderId, false)
if (item is LastChat) {
TelegramUiHelper.applyGrayscaleFilter(holder.icon)
}
val currentUserId = telegramHelper.getCurrentUserId() val currentUserId = telegramHelper.getCurrentUserId()
val title = when (item) { val title = when (item) {
is LastChat -> { is LastChat -> {
@ -705,13 +779,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
settings.shareLocationToChat(itemId, false) settings.shareLocationToChat(itemId, false)
if (shareInfo != null) { if (shareInfo != null) {
telegramHelper.stopSendingLiveLocationToChat(shareInfo) telegramHelper.stopSendingLiveLocationToChat(shareInfo)
app.settings.lastChatsInfo[shareInfo.chatId] = TelegramSettings.LastChatInfo().apply { settings.addTimePeriodToLastItem(shareInfo.chatId,shareInfo.livePeriod)
chatId = shareInfo.chatId
livePeriod = shareInfo.livePeriod
}
log.info("Save chat to last: ${shareInfo.chatId}")
} }
removeItem(item) removeItem(item as TdApi.Object)
} }
} }
} }
@ -802,6 +872,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
(activity as DataSetListener).onDataSetChanged() (activity as DataSetListener).onDataSetChanged()
} }
} }
} else if (holder is HeaderViewHolder) {
holder.header?.text = item as String
} }
} }
@ -842,6 +914,10 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
val container: LinearLayout? = view.findViewById(R.id.container) val container: LinearLayout? = view.findViewById(R.id.container)
val time: TextView? = view.findViewById(R.id.time) val time: TextView? = view.findViewById(R.id.time)
} }
inner class HeaderViewHolder(val view: View) : BaseViewHolder(view) {
val header: TextView? = view.findViewById(R.id.header)
}
} }
interface ActionButtonsListener { interface ActionButtonsListener {
@ -849,4 +925,4 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
} }
class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) : TdApi.Chat() class LastChat internal constructor(val chat: TdApi.Chat, val time: Long)