From 0e4a5f3cd47539bbac48a14199aa54c2b04a9f26 Mon Sep 17 00:00:00 2001 From: Dmitriy Ruban Date: Mon, 23 Dec 2019 13:06:01 +0200 Subject: [PATCH 1/7] lastChatsInfo in settings --- .../net/osmand/telegram/TelegramSettings.kt | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt index 71ae9f6215..09a2ed2aa4 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt @@ -105,6 +105,8 @@ private const val WAITING_TDLIB_TIME = 30 // 2 seconds private const val GPS_UPDATE_EXPIRED_TIME = 60 * 3L // 3 minutes +private const val LAST_CHATS_INFO_KEY = "last_chats_info" + class TelegramSettings(private val app: TelegramApplication) { private val log = PlatformUtil.getLog(TelegramSettings::class.java) @@ -113,6 +115,7 @@ class TelegramSettings(private val app: TelegramApplication) { private var hiddenOnMapChats: Set = emptySet() private var shareDevices: Set = emptySet() private var liveTracksInfo = emptyList() + private var lastChatsInfo = ConcurrentHashMap() var sharingStatusChanges = ConcurrentLinkedQueue() @@ -651,6 +654,11 @@ class TelegramSettings(private val app: TelegramApplication) { edit.putString(LIVE_TRACKS_KEY, jsonArrayLiveTracks.toString()) } + val jArrayLastInfo = convertLastChatsInfoToJson() + if (jArrayLastInfo != null) { + edit.putString(LAST_CHATS_INFO_KEY, jArrayLastInfo.toString()) + } + edit.apply() } @@ -678,6 +686,12 @@ class TelegramSettings(private val app: TelegramApplication) { e.printStackTrace() } + try { + parseLastChatsInfo(JSONArray(prefs.getString(LAST_CHATS_INFO_KEY, ""))) + } catch (e: JSONException) { + log.error(e) + } + parseShareDevices(prefs.getString(SHARE_DEVICES_KEY, "")) val sendMyLocDef = SEND_MY_LOC_VALUES_SEC[SEND_MY_LOC_DEFAULT_INDEX] @@ -817,6 +831,22 @@ class TelegramSettings(private val app: TelegramApplication) { } } + private fun convertLastChatsInfoToJson(): JSONArray? { + return try { + val jArray = JSONArray() + lastChatsInfo.forEach { (chatId, lastInfo) -> + val obj = JSONObject() + obj.put(LastChatInfo.CHAT_ID_KEY, chatId) + obj.put(LastChatInfo.LIVE_PERIOD_KEY, lastInfo.livePeriod) + jArray.put(obj) + } + jArray + } catch (e: JSONException) { + log.error(e) + null + } + } + private fun parseShareChatsInfo(json: JSONArray) { for (i in 0 until json.length()) { val obj = json.getJSONObject(i) @@ -883,6 +913,17 @@ class TelegramSettings(private val app: TelegramApplication) { shareDevices = OsmandApiUtils.parseJsonContents(json).toHashSet() } + private fun parseLastChatsInfo(json: JSONArray) { + for (i in 0 until json.length()) { + val obj = json.getJSONObject(i) + val lastInfo = LastChatInfo().apply { + chatId = obj.optLong(LastChatInfo.CHAT_ID_KEY) + livePeriod = obj.getLong(LastChatInfo.LIVE_PERIOD_KEY) + } + lastChatsInfo[lastInfo.chatId] = lastInfo + } + } + private fun getLiveNowChats() = app.telegramHelper.getMessagesByChatIds(locHistoryTime).keys private fun updatePrefs() { @@ -1371,4 +1412,15 @@ class TelegramSettings(private val app: TelegramApplication) { internal const val SENT_MESSAGES_KEY = "sentMessages" } } + + class LastChatInfo { + + var chatId = -1L + var livePeriod = -1L + + companion object { + internal const val CHAT_ID_KEY = "chatId" + internal const val LIVE_PERIOD_KEY = "livePeriod" + } + } } \ No newline at end of file From c5cfb479501a8e02d8aa8f00c30c20d549d91368 Mon Sep 17 00:00:00 2001 From: Dmitriy Ruban Date: Thu, 26 Dec 2019 19:17:06 +0200 Subject: [PATCH 2/7] suggestion list on first screen --- .../res/layout/last_share_list_item.xml | 59 ++++++++++++++ .../net/osmand/telegram/TelegramSettings.kt | 2 +- .../net/osmand/telegram/ui/MainActivity.kt | 20 ++++- .../telegram/ui/MyLocationTabFragment.kt | 78 +++++++++++++++++-- 4 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 OsmAnd-telegram/res/layout/last_share_list_item.xml diff --git a/OsmAnd-telegram/res/layout/last_share_list_item.xml b/OsmAnd-telegram/res/layout/last_share_list_item.xml new file mode 100644 index 0000000000..e6d1804f40 --- /dev/null +++ b/OsmAnd-telegram/res/layout/last_share_list_item.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt index 09a2ed2aa4..fa056eed7b 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt @@ -115,7 +115,7 @@ class TelegramSettings(private val app: TelegramApplication) { private var hiddenOnMapChats: Set = emptySet() private var shareDevices: Set = emptySet() private var liveTracksInfo = emptyList() - private var lastChatsInfo = ConcurrentHashMap() + var lastChatsInfo = ConcurrentHashMap() var sharingStatusChanges = ConcurrentLinkedQueue() diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt index 38a5fe631f..493f376c36 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt @@ -12,6 +12,8 @@ import android.support.v4.app.DialogFragment import android.support.v4.app.Fragment import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentPagerAdapter +import android.support.v4.view.PagerAdapter +import android.support.v4.view.ViewPager import android.support.v7.app.AlertDialog import android.support.v7.app.AppCompatActivity import android.support.v7.widget.ListPopupWindow @@ -22,7 +24,6 @@ import net.osmand.PlatformUtil import net.osmand.telegram.R import net.osmand.telegram.TelegramApplication import net.osmand.telegram.helpers.OsmandAidlHelper -import net.osmand.telegram.helpers.TelegramHelper import net.osmand.telegram.helpers.TelegramHelper.* import net.osmand.telegram.ui.LoginDialogFragment.LoginDialogType import net.osmand.telegram.ui.MyLocationTabFragment.ActionButtonsListener @@ -43,7 +44,7 @@ private const val MY_LOCATION_TAB_POS = 0 private const val LIVE_NOW_TAB_POS = 1 private const val TIMELINE_TAB_POS = 2 -class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListener, TelegramIncomingMessagesListener { +class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListener, TelegramIncomingMessagesListener, DataSetListener { private val log = PlatformUtil.getLog(MainActivity::class.java) @@ -66,6 +67,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene private lateinit var buttonsBar: LinearLayout private lateinit var bottomNav: BottomNavigationView private lateinit var coordinatorLayout: CoordinatorLayout + private lateinit var viewPager: ViewPager private var snackbarShown = false @@ -81,7 +83,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene paused = false - val viewPager = findViewById(R.id.view_pager).apply { + viewPager = findViewById(R.id.view_pager).apply { swipeLocked = true offscreenPageLimit = 3 adapter = ViewPagerAdapter(supportFragmentManager) @@ -484,6 +486,10 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene } } + override fun onDataSetChanged() { + viewPager.adapter?.notifyDataSetChanged() + } + private fun showOsmandMissingDialog() { OsmandMissingDialogFragment().show(supportFragmentManager, null) } @@ -510,5 +516,13 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene override fun getItem(position: Int) = fragments[position] override fun getCount() = fragments.size + + override fun getItemPosition(`object`: Any): Int { + return PagerAdapter.POSITION_NONE + } } } + +interface DataSetListener { + fun onDataSetChanged() +} diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt index 29026a6743..f6dcca9c9d 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt @@ -20,10 +20,8 @@ import android.text.style.StyleSpan import android.view.* import android.view.animation.LinearInterpolator import android.widget.* -import net.osmand.telegram.ADDITIONAL_ACTIVE_TIME_VALUES_SEC -import net.osmand.telegram.R -import net.osmand.telegram.SHARE_TYPE_MAP -import net.osmand.telegram.TelegramApplication +import net.osmand.PlatformUtil +import net.osmand.telegram.* import net.osmand.telegram.helpers.LocationMessages import net.osmand.telegram.helpers.TelegramHelper import net.osmand.telegram.helpers.TelegramHelper.TelegramListener @@ -31,9 +29,11 @@ import net.osmand.telegram.helpers.TelegramUiHelper import net.osmand.telegram.utils.AndroidUtils import net.osmand.telegram.utils.OsmandFormatter import org.drinkless.td.libcore.telegram.TdApi +import java.util.concurrent.ConcurrentHashMap private const val SELECTED_CHATS_KEY = "selected_chats" private const val SELECTED_CHATS_USERS = "selected_users" +private const val LAST_SHARE_CHAT = 2 private const val SHARE_LOCATION_CHAT = 1 private const val DEFAULT_CHAT = 0 @@ -41,6 +41,8 @@ private const val ADAPTER_UPDATE_INTERVAL_MIL = 5 * 1000L // 5 sec class MyLocationTabFragment : Fragment(), TelegramListener { + private val log = PlatformUtil.getLog(MyLocationTabFragment::class.java) + private var textMarginSmall: Int = 0 private var textMarginBig: Int = 0 private var searchBoxHeight: Int = 0 @@ -85,6 +87,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener { private var updateEnable: Boolean = false + private lateinit var lastChatsInfo: ConcurrentHashMap + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -234,6 +238,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } + lastChatsInfo = settings.lastChatsInfo + return mainView } @@ -517,10 +523,25 @@ class MyLocationTabFragment : Fragment(), TelegramListener { if (sharingMode && settings.hasAnyChatToShareLocation()) { adapter.items = sortAdapterItems(items) } else { + items.addAll(0, getLastShareItems(items)) adapter.items = items } } + private fun getLastShareItems(items: MutableList): MutableList { + val lastItems: MutableList = mutableListOf() + items.forEach { + val id = when (it) { + is TdApi.Chat -> it.id + else -> -1 + } + if (lastChatsInfo.containsKey(id)) { + lastItems.add(LastChat(it as TdApi.Chat, lastChatsInfo[id]!!.livePeriod)) + } + } + return lastItems + } + private fun sortAdapterItems(list: MutableList): MutableList { list.sortWith(Comparator { o1, o2 -> val title1 = when (o1) { @@ -553,7 +574,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener { is TdApi.User -> item.id.toLong() else -> -1 } - return if (settings.isSharingLocationToChat(id) && sharingMode) { + return if (item is LastChat) { + LAST_SHARE_CHAT + } else if (settings.isSharingLocationToChat(id) && sharingMode) { SHARE_LOCATION_CHAT } else { DEFAULT_CHAT @@ -572,6 +595,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener { .inflate(R.layout.user_list_item, parent, false) ChatViewHolder(view) } + LAST_SHARE_CHAT -> { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.last_share_list_item, parent, false) + LastChatViewHolder(view) + } else -> throw RuntimeException("Unsupported view type: $viewType") } } @@ -593,6 +621,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { val shareInfo = if (isChat) settings.getChatsShareInfo()[itemId] else null val photoPath = when (item) { + is LastChat -> item.chat.photo?.small?.local?.path is TdApi.Chat -> item.photo?.small?.local?.path is TdApi.User -> item.profilePhoto?.small?.local?.path else -> null @@ -602,6 +631,13 @@ class MyLocationTabFragment : Fragment(), TelegramListener { val currentUserId = telegramHelper.getCurrentUserId() val title = when (item) { + is LastChat -> { + if (telegramHelper.isPrivateChat(item.chat) && (item.chat.type as TdApi.ChatTypePrivate).userId == currentUserId) { + getString(R.string.saved_messages) + } else { + item.chat.title + } + } is TdApi.Chat -> { if (telegramHelper.isPrivateChat(item) && (item.type as TdApi.ChatTypePrivate).userId == currentUserId) { getString(R.string.saved_messages) @@ -669,6 +705,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener { settings.shareLocationToChat(itemId, false) if (shareInfo != null) { telegramHelper.stopSendingLiveLocationToChat(shareInfo) + app.settings.lastChatsInfo[shareInfo.chatId] = TelegramSettings.LastChatInfo().apply { + chatId = shareInfo.chatId + livePeriod = shareInfo.livePeriod + } + log.info("Save chat to last: ${shareInfo.chatId}") } removeItem(item) } @@ -743,6 +784,24 @@ class MyLocationTabFragment : Fragment(), TelegramListener { text = description } } + } else if (holder is LastChatViewHolder) { + val sharingTime = SpannableStringBuilder("${getString(R.string.sharing_time)}: ") + val formattedTime = OsmandFormatter.getFormattedDuration(app, (item as LastChat).time, false) + val start = sharingTime.length + sharingTime.append(formattedTime) + sharingTime.setSpan(StyleSpan(Typeface.BOLD), start, sharingTime.length, 0) + sharingTime.setSpan(ForegroundColorSpan(ContextCompat.getColor(app, R.color.ctrl_active_light)), start, sharingTime.length, 0) + holder.time?.text = sharingTime + + holder.container?.setOnClickListener { + if (!AndroidUtils.isLocationPermissionAvailable(view!!.context)) { + AndroidUtils.requestLocationPermission(activity!!) + } else { + settings.shareLocationToChat((item as LastChat).chat.id, true, item.time) + app.shareLocationHelper.startSharingLocation() + (activity as DataSetListener).onDataSetChanged() + } + } } } @@ -778,9 +837,16 @@ class MyLocationTabFragment : Fragment(), TelegramListener { val sharingExpiresLine: TextView? = view.findViewById(R.id.expires_line) val gpsPointsLine: TextView? = view.findViewById(R.id.gps_points_line) } + + inner class LastChatViewHolder(val view: View) : BaseViewHolder(view) { + val container: LinearLayout? = view.findViewById(R.id.container) + val time: TextView? = view.findViewById(R.id.time) + } } interface ActionButtonsListener { fun switchButtonsVisibility(visible: Boolean) } -} \ No newline at end of file +} + +class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) : TdApi.Chat() \ No newline at end of file From 11e3da3701ba6b70bf63ca418b52c09d000eaaa1 Mon Sep 17 00:00:00 2001 From: Dmitriy Ruban Date: Fri, 27 Dec 2019 19:20:30 +0200 Subject: [PATCH 3/7] wip --- .../res/layout/header_list_item.xml | 27 ++++ .../res/layout/last_share_list_item.xml | 23 +++- OsmAnd-telegram/res/values/strings.xml | 1 + .../net/osmand/telegram/TelegramSettings.kt | 76 ++++++++++- .../telegram/helpers/TelegramUiHelper.kt | 7 + .../telegram/ui/MyLocationTabFragment.kt | 122 ++++++++++++++---- 6 files changed, 228 insertions(+), 28 deletions(-) create mode 100644 OsmAnd-telegram/res/layout/header_list_item.xml diff --git a/OsmAnd-telegram/res/layout/header_list_item.xml b/OsmAnd-telegram/res/layout/header_list_item.xml new file mode 100644 index 0000000000..bb6a49e891 --- /dev/null +++ b/OsmAnd-telegram/res/layout/header_list_item.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/OsmAnd-telegram/res/layout/last_share_list_item.xml b/OsmAnd-telegram/res/layout/last_share_list_item.xml index e6d1804f40..e72da6e6b5 100644 --- a/OsmAnd-telegram/res/layout/last_share_list_item.xml +++ b/OsmAnd-telegram/res/layout/last_share_list_item.xml @@ -26,8 +26,11 @@ tools:src="@drawable/img_user_picture" /> + + diff --git a/OsmAnd-telegram/res/values/strings.xml b/OsmAnd-telegram/res/values/strings.xml index 05b27552e7..b4ccb58984 100644 --- a/OsmAnd-telegram/res/values/strings.xml +++ b/OsmAnd-telegram/res/values/strings.xml @@ -1,5 +1,6 @@ + Suggested Select time zone to show in your location messages. Time zone Units & formats diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt index fa056eed7b..c49a233145 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt @@ -7,6 +7,7 @@ import android.support.annotation.DrawableRes import android.support.annotation.StringRes import android.text.SpannableStringBuilder import android.text.style.ForegroundColorSpan +import com.google.gson.JsonObject import net.osmand.PlatformUtil import net.osmand.telegram.helpers.OsmandAidlHelper 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.OsmandFormatter.MetricsConstants import net.osmand.telegram.utils.OsmandFormatter.SpeedConstants -import net.osmand.telegram.utils.OsmandLocationUtils import org.drinkless.td.libcore.telegram.TdApi import org.json.JSONArray import org.json.JSONException import org.json.JSONObject +import java.util.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedQueue +import kotlin.collections.ArrayList + 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() obj.put(LastChatInfo.CHAT_ID_KEY, chatId) 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 @@ -847,6 +852,22 @@ class TelegramSettings(private val app: TelegramApplication) { } } + private fun convertPeriodsToJson(periods: LinkedList): 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) { for (i in 0 until json.length()) { val obj = json.getJSONObject(i) @@ -918,12 +939,59 @@ class TelegramSettings(private val app: TelegramApplication) { val obj = json.getJSONObject(i) val lastInfo = LastChatInfo().apply { chatId = obj.optLong(LastChatInfo.CHAT_ID_KEY) - livePeriod = obj.getLong(LastChatInfo.LIVE_PERIOD_KEY) +// livePeriod = obj.optLong(LastChatInfo.LIVE_PERIOD_KEY) + periods = LinkedList() + 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 } } - + + 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().apply { + addFirst(time) + } + } + } + } + + private fun addTimeToPeriods(periods: LinkedList?, time: Long): LinkedList { + if (periods?.isNotEmpty() != null) { + return if (periods.count() < 5) { + periods.addFirst(time) + periods + } else { + periods.removeLast() + periods.addFirst(time) + periods + } + } + return LinkedList().apply { addFirst(time) } + } + + private fun calcLivePeriod(periods: LinkedList): 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 updatePrefs() { @@ -1417,10 +1485,12 @@ class TelegramSettings(private val app: TelegramApplication) { var chatId = -1L var livePeriod = -1L + var periods = LinkedList() companion object { internal const val CHAT_ID_KEY = "chatId" internal const val LIVE_PERIOD_KEY = "livePeriod" + internal const val PERIODS_KEY = "periods" } } } \ No newline at end of file diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt index 288d166bc1..19eb83f802 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt @@ -1,6 +1,8 @@ package net.osmand.telegram.helpers import android.graphics.Bitmap +import android.graphics.ColorMatrix +import android.graphics.ColorMatrixColorFilter import android.graphics.drawable.Drawable import android.widget.ImageView import net.osmand.data.LatLon @@ -13,6 +15,11 @@ import org.drinkless.td.libcore.telegram.TdApi object TelegramUiHelper { + fun applyGrayscaleFilter(iv: ImageView?) { + val matrix = ColorMatrix().apply { setSaturation(0F) } + iv?.colorFilter = ColorMatrixColorFilter(matrix) + } + fun setupPhoto( app: TelegramApplication, iv: ImageView?, diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt index f6dcca9c9d..ffc99c60df 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt @@ -3,7 +3,11 @@ package net.osmand.telegram.ui import android.animation.* import android.annotation.SuppressLint import android.content.Intent +import android.graphics.Canvas +import android.graphics.Rect import android.graphics.Typeface +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.os.Build 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_USERS = "selected_users" +private const val HEADER = 3 private const val LAST_SHARE_CHAT = 2 private const val SHARE_LOCATION_CHAT = 1 private const val DEFAULT_CHAT = 0 @@ -209,6 +214,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } }) + addItemDecoration(createDividerItemDecoration(sharingMode)) } mainView.findViewById(R.id.stop_all_sharing_row).setOnClickListener { @@ -248,6 +254,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { updateCurrentUserPhoto() updateContent() updateEnable = true + settings.read() 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() { sharingMode = sharingMode && settings.hasAnyChatToShareLocation() updateSharingStatus() @@ -493,7 +548,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } private fun updateList() { - val items: MutableList = mutableListOf() + val lastItems = getLastShareItems() + val items: MutableList = mutableListOf() val chats: MutableList = mutableListOf() val contacts = telegramHelper.getContacts() val chatList = if (sharingMode) { @@ -521,28 +577,33 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } if (sharingMode && settings.hasAnyChatToShareLocation()) { - adapter.items = sortAdapterItems(items) + val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList() + val sorted = sortAdapterItems(items as MutableList) + if (filteredLastItems.isNotEmpty()) { + sorted.add(getString(R.string.shared_string_suggested)) + } + sorted.addAll(filteredLastItems) + adapter.items = sorted } else { - items.addAll(0, getLastShareItems(items)) + val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList() + items.addAll(0, filteredLastItems) adapter.items = items } } - private fun getLastShareItems(items: MutableList): MutableList { - val lastItems: MutableList = mutableListOf() - items.forEach { - val id = when (it) { - is TdApi.Chat -> it.id - else -> -1 - } - if (lastChatsInfo.containsKey(id)) { - lastItems.add(LastChat(it as TdApi.Chat, lastChatsInfo[id]!!.livePeriod)) + private fun getLastShareItems(): MutableList { + val lastItems: MutableList = mutableListOf() + val chatListIds = telegramHelper.getChatListIds() + chatListIds.forEach { chatId -> + val chat = telegramHelper.getChat(chatId) + if (chat != null && lastChatsInfo.containsKey(chatId)) { + lastItems.add(LastChat(chat, lastChatsInfo[chatId]!!.livePeriod)) } } return lastItems } - private fun sortAdapterItems(list: MutableList): MutableList { + private fun sortAdapterItems(list: MutableList): MutableList { list.sortWith(Comparator { o1, o2 -> val title1 = when (o1) { is TdApi.Chat -> o1.title @@ -556,12 +617,12 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } title1.compareTo(title2) }) - return list + return list.toMutableList() } inner class MyLocationListAdapter : RecyclerView.Adapter() { - var items = mutableListOf() + var items = mutableListOf() set(value) { field = value notifyDataSetChanged() @@ -576,6 +637,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } return if (item is LastChat) { LAST_SHARE_CHAT + } else if (item is String) { + HEADER } else if (settings.isSharingLocationToChat(id) && sharingMode) { SHARE_LOCATION_CHAT } else { @@ -600,6 +663,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener { .inflate(R.layout.last_share_list_item, parent, false) 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") } } @@ -610,8 +678,10 @@ class MyLocationTabFragment : Fragment(), TelegramListener { val isChat = item is TdApi.Chat val itemId = if (isChat) { (item as TdApi.Chat).id + } else if (item is TdApi.User) { + item.id.toLong() } else { - (item as TdApi.User).id.toLong() + -1 } val lastItem = position == itemCount - 1 @@ -629,6 +699,10 @@ class MyLocationTabFragment : Fragment(), TelegramListener { TelegramUiHelper.setupPhoto(app, holder.icon, photoPath, placeholderId, false) + if (item is LastChat) { + TelegramUiHelper.applyGrayscaleFilter(holder.icon) + } + val currentUserId = telegramHelper.getCurrentUserId() val title = when (item) { is LastChat -> { @@ -705,13 +779,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener { settings.shareLocationToChat(itemId, false) if (shareInfo != null) { telegramHelper.stopSendingLiveLocationToChat(shareInfo) - app.settings.lastChatsInfo[shareInfo.chatId] = TelegramSettings.LastChatInfo().apply { - chatId = shareInfo.chatId - livePeriod = shareInfo.livePeriod - } - log.info("Save chat to last: ${shareInfo.chatId}") + settings.addTimePeriodToLastItem(shareInfo.chatId,shareInfo.livePeriod) } - removeItem(item) + removeItem(item as TdApi.Object) } } } @@ -802,6 +872,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener { (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 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 { @@ -849,4 +925,4 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } -class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) : TdApi.Chat() \ No newline at end of file +class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) \ No newline at end of file From 7eae6d1717f8d75c92197f6293309bdbdb0a2c9d Mon Sep 17 00:00:00 2001 From: Dmitriy Ruban Date: Thu, 2 Jan 2020 19:03:04 +0200 Subject: [PATCH 4/7] suggested list like one item in recycler --- .../res/layout/header_list_item.xml | 27 -- .../res/layout/last_share_list_item.xml | 109 +++++--- .../res/layout/suggested_list_item.xml | 51 ++++ .../net/osmand/telegram/TelegramSettings.kt | 19 +- .../telegram/ui/MyLocationTabFragment.kt | 243 ++++++++---------- 5 files changed, 234 insertions(+), 215 deletions(-) delete mode 100644 OsmAnd-telegram/res/layout/header_list_item.xml create mode 100644 OsmAnd-telegram/res/layout/suggested_list_item.xml diff --git a/OsmAnd-telegram/res/layout/header_list_item.xml b/OsmAnd-telegram/res/layout/header_list_item.xml deleted file mode 100644 index bb6a49e891..0000000000 --- a/OsmAnd-telegram/res/layout/header_list_item.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/OsmAnd-telegram/res/layout/last_share_list_item.xml b/OsmAnd-telegram/res/layout/last_share_list_item.xml index e72da6e6b5..0857a8674e 100644 --- a/OsmAnd-telegram/res/layout/last_share_list_item.xml +++ b/OsmAnd-telegram/res/layout/last_share_list_item.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" + android:orientation="vertical" android:background="?attr/card_bg_color"> - + - + android:layout_gravity="center_vertical" + android:orientation="horizontal"> - + - + - + + + + + + + + + + + diff --git a/OsmAnd-telegram/res/layout/suggested_list_item.xml b/OsmAnd-telegram/res/layout/suggested_list_item.xml new file mode 100644 index 0000000000..f98c000dc2 --- /dev/null +++ b/OsmAnd-telegram/res/layout/suggested_list_item.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt index c49a233145..d6f9eec6df 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt @@ -7,7 +7,6 @@ import android.support.annotation.DrawableRes import android.support.annotation.StringRes import android.text.SpannableStringBuilder import android.text.style.ForegroundColorSpan -import com.google.gson.JsonObject import net.osmand.PlatformUtil import net.osmand.telegram.helpers.OsmandAidlHelper import net.osmand.telegram.helpers.ShowLocationHelper @@ -840,9 +839,8 @@ class TelegramSettings(private val app: TelegramApplication) { lastChatsInfo.forEach { (chatId, lastInfo) -> val obj = JSONObject() obj.put(LastChatInfo.CHAT_ID_KEY, chatId) - obj.put(LastChatInfo.LIVE_PERIOD_KEY, lastInfo.livePeriod) obj.put(LastChatInfo.PERIODS_KEY, convertPeriodsToJson(lastInfo.periods)) - log.info("Periods to put: ${lastInfo.periods}") + log.info("Save last info: ${lastInfo.periods} / id: ${lastInfo.chatId}") jArray.put(obj) } jArray @@ -855,12 +853,13 @@ class TelegramSettings(private val app: TelegramApplication) { private fun convertPeriodsToJson(periods: LinkedList): JSONArray? { return try { val jArray = JSONArray() + log.info("periods to convert : $periods") 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") + log.info("Converted to json periods: $jArray") jArray } catch (e: JSONException) { log.error(e) @@ -939,16 +938,14 @@ class TelegramSettings(private val app: TelegramApplication) { val obj = json.getJSONObject(i) val lastInfo = LastChatInfo().apply { chatId = obj.optLong(LastChatInfo.CHAT_ID_KEY) -// livePeriod = obj.optLong(LastChatInfo.LIVE_PERIOD_KEY) periods = LinkedList() val jsonArray = obj.getJSONArray(LastChatInfo.PERIODS_KEY) - log.info("getJson: $jsonArray") + log.info("get Json periods: $jsonArray") for (j in 0 until jsonArray.length()) { - val obj=jsonArray.get(j) as JSONObject - - periods.add(obj.optLong(j.toString())) + val o = jsonArray.get(j) as JSONObject + periods.addLast(o.optLong(j.toString())) } - log.info("Periods: $periods") + log.info("Converted from json periods: $periods") livePeriod = calcLivePeriod(periods) } lastChatsInfo[lastInfo.chatId] = lastInfo @@ -967,6 +964,7 @@ class TelegramSettings(private val app: TelegramApplication) { } } } + log.info("added to periods: ${lastChatsInfo[id]?.periods}") } private fun addTimeToPeriods(periods: LinkedList?, time: Long): LinkedList { @@ -984,7 +982,6 @@ class TelegramSettings(private val app: TelegramApplication) { } private fun calcLivePeriod(periods: LinkedList): Long { - periods.sort() return if (periods.count() % 2 == 0) { (periods[periods.count() / 2] + periods[periods.count() / 2 - 1]) / 2 } else { diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt index ffc99c60df..8c813b5c26 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt @@ -3,11 +3,7 @@ package net.osmand.telegram.ui import android.animation.* import android.annotation.SuppressLint import android.content.Intent -import android.graphics.Canvas -import android.graphics.Rect import android.graphics.Typeface -import android.graphics.drawable.ColorDrawable -import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.os.Build import android.os.Bundle @@ -21,6 +17,7 @@ import android.text.SpannableString import android.text.SpannableStringBuilder import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan +import android.util.TypedValue import android.view.* import android.view.animation.LinearInterpolator import android.widget.* @@ -37,8 +34,7 @@ import java.util.concurrent.ConcurrentHashMap private const val SELECTED_CHATS_KEY = "selected_chats" private const val SELECTED_CHATS_USERS = "selected_users" -private const val HEADER = 3 -private const val LAST_SHARE_CHAT = 2 +private const val SUGGESTED = 2 private const val SHARE_LOCATION_CHAT = 1 private const val DEFAULT_CHAT = 0 @@ -214,7 +210,6 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } }) - addItemDecoration(createDividerItemDecoration(sharingMode)) } mainView.findViewById(R.id.stop_all_sharing_row).setOnClickListener { @@ -466,54 +461,6 @@ 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() { sharingMode = sharingMode && settings.hasAnyChatToShareLocation() updateSharingStatus() @@ -579,14 +526,13 @@ class MyLocationTabFragment : Fragment(), TelegramListener { if (sharingMode && settings.hasAnyChatToShareLocation()) { val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList() val sorted = sortAdapterItems(items as MutableList) - if (filteredLastItems.isNotEmpty()) { - sorted.add(getString(R.string.shared_string_suggested)) - } - sorted.addAll(filteredLastItems) + val lastChats = LastChats(filteredLastItems) + sorted.add(lastChats) adapter.items = sorted } else { val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList() - items.addAll(0, filteredLastItems) + val lastChats = LastChats(filteredLastItems) + items.add(0, lastChats) adapter.items = items } } @@ -635,10 +581,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener { is TdApi.User -> item.id.toLong() else -> -1 } - return if (item is LastChat) { - LAST_SHARE_CHAT - } else if (item is String) { - HEADER + return if (item is LastChats) { + SUGGESTED } else if (settings.isSharingLocationToChat(id) && sharingMode) { SHARE_LOCATION_CHAT } else { @@ -658,15 +602,10 @@ class MyLocationTabFragment : Fragment(), TelegramListener { .inflate(R.layout.user_list_item, parent, false) ChatViewHolder(view) } - LAST_SHARE_CHAT -> { + SUGGESTED -> { val view = LayoutInflater.from(parent.context) - .inflate(R.layout.last_share_list_item, parent, false) - LastChatViewHolder(view) - } - HEADER -> { - val view = LayoutInflater.from(parent.context) - .inflate(R.layout.header_list_item, parent, false) - HeaderViewHolder(view) + .inflate(R.layout.suggested_list_item, parent, false) + SuggestedViewHolder(view) } else -> throw RuntimeException("Unsupported view type: $viewType") } @@ -685,47 +624,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } val lastItem = position == itemCount - 1 - val placeholderId = - if (isChat && telegramHelper.isGroup(item as TdApi.Chat)) R.drawable.img_group_picture else R.drawable.img_user_picture val live = (isChat && settings.isSharingLocationToChat(itemId)) val shareInfo = if (isChat) settings.getChatsShareInfo()[itemId] else null - val photoPath = when (item) { - is LastChat -> item.chat.photo?.small?.local?.path - is TdApi.Chat -> item.photo?.small?.local?.path - is TdApi.User -> item.profilePhoto?.small?.local?.path - else -> null - } - - TelegramUiHelper.setupPhoto(app, holder.icon, photoPath, placeholderId, false) - - if (item is LastChat) { - TelegramUiHelper.applyGrayscaleFilter(holder.icon) - } - - val currentUserId = telegramHelper.getCurrentUserId() - val title = when (item) { - is LastChat -> { - if (telegramHelper.isPrivateChat(item.chat) && (item.chat.type as TdApi.ChatTypePrivate).userId == currentUserId) { - getString(R.string.saved_messages) - } else { - item.chat.title - } - } - is TdApi.Chat -> { - if (telegramHelper.isPrivateChat(item) && (item.type as TdApi.ChatTypePrivate).userId == currentUserId) { - getString(R.string.saved_messages) - } else { - item.title - } - } - is TdApi.User -> { - if (item.id == currentUserId) getString(R.string.saved_messages) else TelegramUiHelper.getUserName(item) - } - else -> null - } - - holder.title?.text = title + setupPhoto(item, holder.icon, isChat) + holder.title?.text = getTitleText(item) if (holder is ChatViewHolder) { holder.description?.visibility = View.GONE @@ -854,32 +757,101 @@ class MyLocationTabFragment : Fragment(), TelegramListener { text = description } } - } else if (holder is LastChatViewHolder) { - val sharingTime = SpannableStringBuilder("${getString(R.string.sharing_time)}: ") - val formattedTime = OsmandFormatter.getFormattedDuration(app, (item as LastChat).time, false) - val start = sharingTime.length - sharingTime.append(formattedTime) - sharingTime.setSpan(StyleSpan(Typeface.BOLD), start, sharingTime.length, 0) - sharingTime.setSpan(ForegroundColorSpan(ContextCompat.getColor(app, R.color.ctrl_active_light)), start, sharingTime.length, 0) - holder.time?.text = sharingTime - - holder.container?.setOnClickListener { - if (!AndroidUtils.isLocationPermissionAvailable(view!!.context)) { - AndroidUtils.requestLocationPermission(activity!!) - } else { - settings.shareLocationToChat((item as LastChat).chat.id, true, item.time) - app.shareLocationHelper.startSharingLocation() - (activity as DataSetListener).onDataSetChanged() + } else if (holder is SuggestedViewHolder) { + holder.list.removeAllViews() + val iterator = (item as LastChats).list.iterator() + iterator.forEach { + holder.list.addView(createLastChatView(it, iterator.hasNext())) + } + if (!sharingMode) { + holder.dividerTop?.visibility = View.GONE + holder.dividerBottom?.visibility = View.VISIBLE + holder.header?.visibility = View.GONE + val storedValueInTheme = TypedValue() + if (context?.theme?.resolveAttribute(R.attr.card_bg_color, storedValueInTheme, true) != null) { + holder.container?.setBackgroundColor(storedValueInTheme.data) } } - } else if (holder is HeaderViewHolder) { - holder.header?.text = item as String } } + private fun getTitleText(item: Any): String? { + val currentUserId = telegramHelper.getCurrentUserId() + return when (item) { + is LastChat -> { + if (telegramHelper.isPrivateChat(item.chat) && (item.chat.type as TdApi.ChatTypePrivate).userId == currentUserId) { + getString(R.string.saved_messages) + } else { + item.chat.title + } + } + is TdApi.Chat -> { + if (telegramHelper.isPrivateChat(item) && (item.type as TdApi.ChatTypePrivate).userId == currentUserId) { + getString(R.string.saved_messages) + } else { + item.title + } + } + is TdApi.User -> { + if (item.id == currentUserId) getString(R.string.saved_messages) else TelegramUiHelper.getUserName(item) + } + else -> null + } + } + + private fun setupPhoto(item: Any, icon: ImageView?, isChat: Boolean) { + val photoPath = when (item) { + is LastChat -> item.chat.photo?.small?.local?.path + is TdApi.Chat -> item.photo?.small?.local?.path + is TdApi.User -> item.profilePhoto?.small?.local?.path + else -> null + } + val placeholderId = + if (isChat && telegramHelper.isGroup(item as TdApi.Chat)) R.drawable.img_group_picture else R.drawable.img_user_picture + + TelegramUiHelper.setupPhoto(app, icon, photoPath, placeholderId, false) + } + + private fun createLastChatView(lastChat: LastChat, hasNext: Boolean): View { + val view = layoutInflater.inflate(R.layout.last_share_list_item, null) + val time: TextView = view.findViewById(R.id.time) + val container: LinearLayout = view.findViewById(R.id.container) + val icon: ImageView = view.findViewById(R.id.icon) + val title: TextView = view.findViewById(R.id.title) + val divider: View = view.findViewById(R.id.divider) + + if (sharingMode && hasNext) { + divider.visibility = View.VISIBLE + } + + container.setOnClickListener { + if (!AndroidUtils.isLocationPermissionAvailable(view!!.context)) { + AndroidUtils.requestLocationPermission(activity!!) + } else { + settings.shareLocationToChat(lastChat.chat.id, true, lastChat.time) + app.shareLocationHelper.startSharingLocation() + (activity as DataSetListener).onDataSetChanged() + } + } + + title.text = getTitleText(lastChat.chat) + setupPhoto(lastChat.chat, icon, true) + TelegramUiHelper.applyGrayscaleFilter(icon) + + val sharingTime = SpannableStringBuilder("${getString(R.string.sharing_time)}: ") + val formattedTime = OsmandFormatter.getFormattedDuration(app, lastChat.time, false) + val start = sharingTime.length + sharingTime.append(formattedTime) + sharingTime.setSpan(StyleSpan(Typeface.BOLD), start, sharingTime.length, 0) + sharingTime.setSpan(ForegroundColorSpan(ContextCompat.getColor(app, R.color.ctrl_active_light)), start, sharingTime.length, 0) + time.text = sharingTime + return view + } + private fun removeItem(chat: TdApi.Object) { items.remove(chat) - if (items.isEmpty()) { + val filtered = items.filterIsInstance() + if (filtered.isEmpty()) { sharingMode = false updateContent() shareLocationHelper.stopSharingLocation() @@ -910,12 +882,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener { val gpsPointsLine: TextView? = view.findViewById(R.id.gps_points_line) } - inner class LastChatViewHolder(val view: View) : BaseViewHolder(view) { + inner class SuggestedViewHolder(val view: View) : BaseViewHolder(view) { + val list: LinearLayout = view.findViewById(R.id.last_items_list) val container: LinearLayout? = view.findViewById(R.id.container) - val time: TextView? = view.findViewById(R.id.time) - } - - inner class HeaderViewHolder(val view: View) : BaseViewHolder(view) { + val dividerBottom: View? = view.findViewById(R.id.divider_bottom) + val dividerTop: View? = view.findViewById(R.id.divider_top) val header: TextView? = view.findViewById(R.id.header) } } @@ -925,4 +896,6 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } -class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) \ No newline at end of file +class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) + +class LastChats constructor(val list: MutableList) \ No newline at end of file From b25cd548646e92a13139e2c48be30e6dfb60e318 Mon Sep 17 00:00:00 2001 From: Dmitriy Ruban Date: Fri, 3 Jan 2020 13:24:10 +0200 Subject: [PATCH 5/7] limit suggested list by 5 items --- .../net/osmand/telegram/TelegramSettings.kt | 56 ++++++++++--------- .../telegram/ui/MyLocationTabFragment.kt | 56 ++++++++++++++----- 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt index d6f9eec6df..a66a83d521 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt @@ -117,7 +117,7 @@ class TelegramSettings(private val app: TelegramApplication) { private var hiddenOnMapChats: Set = emptySet() private var shareDevices: Set = emptySet() private var liveTracksInfo = emptyList() - var lastChatsInfo = ConcurrentHashMap() + var lastChatsInfo = LinkedList() var sharingStatusChanges = ConcurrentLinkedQueue() @@ -836,11 +836,10 @@ class TelegramSettings(private val app: TelegramApplication) { private fun convertLastChatsInfoToJson(): JSONArray? { return try { val jArray = JSONArray() - lastChatsInfo.forEach { (chatId, lastInfo) -> + lastChatsInfo.forEach { lastInfo -> val obj = JSONObject() - obj.put(LastChatInfo.CHAT_ID_KEY, chatId) + obj.put(LastChatInfo.CHAT_ID_KEY, lastInfo.chatId) obj.put(LastChatInfo.PERIODS_KEY, convertPeriodsToJson(lastInfo.periods)) - log.info("Save last info: ${lastInfo.periods} / id: ${lastInfo.chatId}") jArray.put(obj) } jArray @@ -853,13 +852,11 @@ class TelegramSettings(private val app: TelegramApplication) { private fun convertPeriodsToJson(periods: LinkedList): JSONArray? { return try { val jArray = JSONArray() - log.info("periods to convert : $periods") for (i in 0 until periods.count()) { val obj = JSONObject() obj.put(i.toString(), periods[i]) jArray.put(obj) } - log.info("Converted to json periods: $jArray") jArray } catch (e: JSONException) { log.error(e) @@ -940,36 +937,43 @@ class TelegramSettings(private val app: TelegramApplication) { chatId = obj.optLong(LastChatInfo.CHAT_ID_KEY) periods = LinkedList() val jsonArray = obj.getJSONArray(LastChatInfo.PERIODS_KEY) - log.info("get Json periods: $jsonArray") for (j in 0 until jsonArray.length()) { val o = jsonArray.get(j) as JSONObject periods.addLast(o.optLong(j.toString())) } - log.info("Converted from json periods: $periods") - livePeriod = calcLivePeriod(periods) } - lastChatsInfo[lastInfo.chatId] = lastInfo + lastChatsInfo.addLast(lastInfo) } } fun addTimePeriodToLastItem(id: Long, time: Long) { - if (lastChatsInfo.containsKey(id)) { - lastChatsInfo[id]?.periods = addTimeToPeriods(lastChatsInfo[id]?.periods, time) + val lastInfo = lastChatsInfo.find { it.chatId == id } + if (lastInfo == null) { + addItemToSuggested(id, time) } else { - lastChatsInfo[id] = LastChatInfo().apply { - chatId = id - livePeriod = time - periods = LinkedList().apply { - addFirst(time) - } + val index = lastChatsInfo.indexOf(lastInfo) + lastChatsInfo[index].periods = addTimeToPeriods(lastChatsInfo[index].periods, time) + } + } + + private fun addItemToSuggested(id: Long, time: Long) { + val newLastInfo = LastChatInfo().apply { + chatId = id + periods = LinkedList().apply { + addFirst(time) } } - log.info("added to periods: ${lastChatsInfo[id]?.periods}") + if (lastChatsInfo.size < 5) { + lastChatsInfo.addFirst(newLastInfo) + } else { + lastChatsInfo.removeLast() + lastChatsInfo.addFirst(newLastInfo) + } } private fun addTimeToPeriods(periods: LinkedList?, time: Long): LinkedList { if (periods?.isNotEmpty() != null) { - return if (periods.count() < 5) { + return if (periods.size < 5) { periods.addFirst(time) periods } else { @@ -981,11 +985,13 @@ class TelegramSettings(private val app: TelegramApplication) { return LinkedList().apply { addFirst(time) } } - private fun calcLivePeriod(periods: LinkedList): Long { - return if (periods.count() % 2 == 0) { - (periods[periods.count() / 2] + periods[periods.count() / 2 - 1]) / 2 + fun calcLivePeriod(periods: LinkedList): Long { + val copy = periods.toLongArray() + copy.sort() + return if (copy.size % 2 == 0) { + (copy[copy.size / 2] + copy[copy.size / 2 - 1]) / 2 } else { - periods[periods.count() / 2] + copy[copy.size / 2] } } @@ -1481,12 +1487,10 @@ class TelegramSettings(private val app: TelegramApplication) { class LastChatInfo { var chatId = -1L - var livePeriod = -1L var periods = LinkedList() companion object { internal const val CHAT_ID_KEY = "chatId" - internal const val LIVE_PERIOD_KEY = "livePeriod" internal const val PERIODS_KEY = "periods" } } diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt index 8c813b5c26..dee26e20c7 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt @@ -30,7 +30,9 @@ import net.osmand.telegram.helpers.TelegramUiHelper import net.osmand.telegram.utils.AndroidUtils import net.osmand.telegram.utils.OsmandFormatter import org.drinkless.td.libcore.telegram.TdApi -import java.util.concurrent.ConcurrentHashMap +import java.util.* +import kotlin.Comparator +import kotlin.collections.HashSet private const val SELECTED_CHATS_KEY = "selected_chats" private const val SELECTED_CHATS_USERS = "selected_users" @@ -88,7 +90,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { private var updateEnable: Boolean = false - private lateinit var lastChatsInfo: ConcurrentHashMap + private lateinit var lastChatsInfo: LinkedList override fun onCreateView( inflater: LayoutInflater, @@ -249,7 +251,6 @@ class MyLocationTabFragment : Fragment(), TelegramListener { updateCurrentUserPhoto() updateContent() updateEnable = true - settings.read() startHandler() } @@ -276,6 +277,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } DisableSharingBottomSheet.SHARING_DISABLED_REQUEST_CODE -> { + saveChatsToSuggested() sharingMode = false app.stopSharingLocation() updateContent() @@ -286,6 +288,16 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } + private fun saveChatsToSuggested() { + val chatListIds = settings.getShareLocationChats() + chatListIds.forEach { id -> + val shareInfo = settings.getChatsShareInfo()[id] + if (shareInfo != null) { + settings.addTimePeriodToLastItem(shareInfo.chatId, shareInfo.livePeriod) + } + } + } + override fun onTelegramStatusChanged( prevTelegramAuthorizationState: TelegramHelper.TelegramAuthorizationState, newTelegramAuthorizationState: TelegramHelper.TelegramAuthorizationState @@ -526,12 +538,12 @@ class MyLocationTabFragment : Fragment(), TelegramListener { if (sharingMode && settings.hasAnyChatToShareLocation()) { val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList() val sorted = sortAdapterItems(items as MutableList) - val lastChats = LastChats(filteredLastItems) + val lastChats = SuggestedChats(filteredLastItems) sorted.add(lastChats) adapter.items = sorted } else { val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList() - val lastChats = LastChats(filteredLastItems) + val lastChats = SuggestedChats(filteredLastItems) items.add(0, lastChats) adapter.items = items } @@ -542,8 +554,10 @@ class MyLocationTabFragment : Fragment(), TelegramListener { val chatListIds = telegramHelper.getChatListIds() chatListIds.forEach { chatId -> val chat = telegramHelper.getChat(chatId) - if (chat != null && lastChatsInfo.containsKey(chatId)) { - lastItems.add(LastChat(chat, lastChatsInfo[chatId]!!.livePeriod)) + val lastInfo = lastChatsInfo.find { it.chatId == chatId } + if (chat != null && lastInfo != null) { + val index = lastChatsInfo.indexOf(lastInfo) + lastItems.add(LastChat(chat, settings.calcLivePeriod(lastChatsInfo[index].periods))) } } return lastItems @@ -581,7 +595,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { is TdApi.User -> item.id.toLong() else -> -1 } - return if (item is LastChats) { + return if (item is SuggestedChats) { SUGGESTED } else if (settings.isSharingLocationToChat(id) && sharingMode) { SHARE_LOCATION_CHAT @@ -759,17 +773,29 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } else if (holder is SuggestedViewHolder) { holder.list.removeAllViews() - val iterator = (item as LastChats).list.iterator() - iterator.forEach { - holder.list.addView(createLastChatView(it, iterator.hasNext())) + if ((item as SuggestedChats).list.isEmpty()) { + holder.container?.visibility = View.GONE + } else { + holder.container?.visibility = View.VISIBLE + val iterator = item.list.iterator() + iterator.forEach { + holder.list.addView(createLastChatView(it, iterator.hasNext())) + } } + val tv = TypedValue() if (!sharingMode) { holder.dividerTop?.visibility = View.GONE holder.dividerBottom?.visibility = View.VISIBLE holder.header?.visibility = View.GONE - val storedValueInTheme = TypedValue() - if (context?.theme?.resolveAttribute(R.attr.card_bg_color, storedValueInTheme, true) != null) { - holder.container?.setBackgroundColor(storedValueInTheme.data) + if (context?.theme?.resolveAttribute(R.attr.card_bg_color, tv, true) != null) { + holder.container?.setBackgroundColor(tv.data) + } + } else { + holder.dividerTop?.visibility = View.VISIBLE + holder.dividerBottom?.visibility = View.GONE + holder.header?.visibility = View.VISIBLE + if (context?.theme?.resolveAttribute(R.attr.shared_chat_card_bg, tv, true) != null) { + holder.container?.setBackgroundResource(tv.resourceId) } } } @@ -898,4 +924,4 @@ class MyLocationTabFragment : Fragment(), TelegramListener { class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) -class LastChats constructor(val list: MutableList) \ No newline at end of file +class SuggestedChats internal constructor(val list: MutableList) \ No newline at end of file From 3ab25bef40dd011d47d2850287aed4f2ad21770f Mon Sep 17 00:00:00 2001 From: Dmitriy Ruban Date: Fri, 3 Jan 2020 14:45:39 +0200 Subject: [PATCH 6/7] clean --- .../net/osmand/telegram/TelegramSettings.kt | 3 +- .../telegram/helpers/TelegramUiHelper.kt | 5 --- .../telegram/ui/MyLocationTabFragment.kt | 38 +++++++++---------- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt index 65724f2c98..b35d004c43 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt @@ -23,7 +23,6 @@ import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedQueue import kotlin.collections.ArrayList - val ADDITIONAL_ACTIVE_TIME_VALUES_SEC = listOf(15 * 60L, 30 * 60L, 60 * 60L, 180 * 60L) const val SHARE_DEVICES_KEY = "devices" @@ -1520,4 +1519,4 @@ class TelegramSettings(private val app: TelegramApplication) { internal const val PERIODS_KEY = "periods" } } -} \ No newline at end of file +} diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt index 19eb83f802..73f1eee7b9 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt @@ -15,11 +15,6 @@ import org.drinkless.td.libcore.telegram.TdApi object TelegramUiHelper { - fun applyGrayscaleFilter(iv: ImageView?) { - val matrix = ColorMatrix().apply { setSaturation(0F) } - iv?.colorFilter = ColorMatrixColorFilter(matrix) - } - fun setupPhoto( app: TelegramApplication, iv: ImageView?, diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt index dee26e20c7..d3f07aea04 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt @@ -3,6 +3,8 @@ package net.osmand.telegram.ui import android.animation.* import android.annotation.SuppressLint import android.content.Intent +import android.graphics.ColorMatrix +import android.graphics.ColorMatrixColorFilter import android.graphics.Typeface import android.graphics.drawable.GradientDrawable import android.os.Build @@ -277,7 +279,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } DisableSharingBottomSheet.SHARING_DISABLED_REQUEST_CODE -> { - saveChatsToSuggested() + saveChatsToLastChatsInfo() sharingMode = false app.stopSharingLocation() updateContent() @@ -288,16 +290,6 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } - private fun saveChatsToSuggested() { - val chatListIds = settings.getShareLocationChats() - chatListIds.forEach { id -> - val shareInfo = settings.getChatsShareInfo()[id] - if (shareInfo != null) { - settings.addTimePeriodToLastItem(shareInfo.chatId, shareInfo.livePeriod) - } - } - } - override fun onTelegramStatusChanged( prevTelegramAuthorizationState: TelegramHelper.TelegramAuthorizationState, newTelegramAuthorizationState: TelegramHelper.TelegramAuthorizationState @@ -537,14 +529,12 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } if (sharingMode && settings.hasAnyChatToShareLocation()) { val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList() - val sorted = sortAdapterItems(items as MutableList) - val lastChats = SuggestedChats(filteredLastItems) - sorted.add(lastChats) - adapter.items = sorted + val sortedItems = sortAdapterItems(items as MutableList) + sortedItems.add(SuggestedChats(filteredLastItems)) + adapter.items = sortedItems } else { val filteredLastItems = lastItems.filter { !settings.isSharingLocationToChat(it.chat.id) }.toMutableList() - val lastChats = SuggestedChats(filteredLastItems) - items.add(0, lastChats) + items.add(0, SuggestedChats(filteredLastItems)) adapter.items = items } } @@ -563,6 +553,16 @@ class MyLocationTabFragment : Fragment(), TelegramListener { return lastItems } + private fun saveChatsToLastChatsInfo() { + val chatListIds = settings.getShareLocationChats() + chatListIds.forEach { id -> + val shareInfo = settings.getChatsShareInfo()[id] + if (shareInfo != null) { + settings.addTimePeriodToLastItem(shareInfo.chatId, shareInfo.livePeriod) + } + } + } + private fun sortAdapterItems(list: MutableList): MutableList { list.sortWith(Comparator { o1, o2 -> val title1 = when (o1) { @@ -862,7 +862,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { title.text = getTitleText(lastChat.chat) setupPhoto(lastChat.chat, icon, true) - TelegramUiHelper.applyGrayscaleFilter(icon) + icon.colorFilter = ColorMatrixColorFilter(ColorMatrix().apply { setSaturation(0F) }) val sharingTime = SpannableStringBuilder("${getString(R.string.sharing_time)}: ") val formattedTime = OsmandFormatter.getFormattedDuration(app, lastChat.time, false) @@ -924,4 +924,4 @@ class MyLocationTabFragment : Fragment(), TelegramListener { class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) -class SuggestedChats internal constructor(val list: MutableList) \ No newline at end of file +class SuggestedChats internal constructor(val list: MutableList) From 5a0811967f6a8086c2565aee1454eadd4efaaf67 Mon Sep 17 00:00:00 2001 From: Dmitriy Ruban Date: Fri, 3 Jan 2020 14:48:07 +0200 Subject: [PATCH 7/7] clean --- .../src/net/osmand/telegram/helpers/TelegramUiHelper.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt index 73f1eee7b9..288d166bc1 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt @@ -1,8 +1,6 @@ package net.osmand.telegram.helpers import android.graphics.Bitmap -import android.graphics.ColorMatrix -import android.graphics.ColorMatrixColorFilter import android.graphics.drawable.Drawable import android.widget.ImageView import net.osmand.data.LatLon