From 78c1e5a5a83cd09308d85848ace90ff15ac3c019 Mon Sep 17 00:00:00 2001 From: crimean Date: Sat, 9 Jun 2018 22:37:00 +0300 Subject: [PATCH] Telegram - store chat titles instead of ids --- .../java/net/osmand/telegram/MainActivity.kt | 21 +- .../net/osmand/telegram/TelegramSettings.kt | 56 +++--- .../osmand/telegram/helpers/TelegramHelper.kt | 187 +++++++++++------- 3 files changed, 161 insertions(+), 103 deletions(-) diff --git a/OsmAnd-telegram/src/main/java/net/osmand/telegram/MainActivity.kt b/OsmAnd-telegram/src/main/java/net/osmand/telegram/MainActivity.kt index 4e50626608..d5effc6a08 100644 --- a/OsmAnd-telegram/src/main/java/net/osmand/telegram/MainActivity.kt +++ b/OsmAnd-telegram/src/main/java/net/osmand/telegram/MainActivity.kt @@ -116,7 +116,6 @@ class MainActivity : AppCompatActivity(), TelegramListener { when (newTelegramAuthorizationState) { TelegramAuthorizationState.READY -> { updateChatsList() - telegramHelper.requestChats() } TelegramAuthorizationState.CLOSED, TelegramAuthorizationState.UNKNOWN -> { @@ -128,6 +127,13 @@ class MainActivity : AppCompatActivity(), TelegramListener { } override fun onTelegramChatsRead() { + runOnUi { + removeNonexistingChatsFromSettings() + updateChatsList() + } + } + + override fun onTelegramChatsChanged() { runOnUi { updateChatsList() } @@ -144,6 +150,11 @@ class MainActivity : AppCompatActivity(), TelegramListener { app.isInternetConnectionAvailable(true) } + private fun removeNonexistingChatsFromSettings() { + val presentChatTitles = telegramHelper.getChatTitles() + settings.removeNonexistingChats(presentChatTitles) + } + private fun updateChatsList() { val chatList = telegramHelper.getChatList() val chats: MutableList = mutableListOf() @@ -302,12 +313,12 @@ class MainActivity : AppCompatActivity(), TelegramListener { } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val chatId = chats[position].id - holder.groupName?.text = chats[position].title + val chatTitle = chats[position].title + holder.groupName?.text = chatTitle holder.shareLocationSwitch?.setOnCheckedChangeListener(null) - holder.shareLocationSwitch?.isChecked = settings.isSharingLocationToChat(chatId) + holder.shareLocationSwitch?.isChecked = settings.isSharingLocationToChat(chatTitle) holder.shareLocationSwitch?.setOnCheckedChangeListener { view, isChecked -> - settings.shareLocationToChat(chatId, isChecked) + settings.shareLocationToChat(chatTitle, isChecked) if (settings.hasAnyChatToShareLocation()) { if (!AndroidUtils.isLocationPermissionAvailable(view.context)) { requestLocationPermission() diff --git a/OsmAnd-telegram/src/main/java/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/main/java/net/osmand/telegram/TelegramSettings.kt index 2037e1f5a5..aed758416f 100644 --- a/OsmAnd-telegram/src/main/java/net/osmand/telegram/TelegramSettings.kt +++ b/OsmAnd-telegram/src/main/java/net/osmand/telegram/TelegramSettings.kt @@ -10,17 +10,17 @@ class TelegramSettings(private val app: TelegramApplication) { private const val SETTINGS_NAME = "osmand_telegram_settings" - private const val SHARE_LOCATION_CHATS_KEY = "share_location_chats_key" - private const val SHOW_ON_MAP_CHATS_KEY = "show_on_map_chats_key" + private const val SHARE_LOCATION_CHATS_KEY = "share_location_chats" + private const val SHOW_ON_MAP_CHATS_KEY = "show_on_map_chats" - private const val METRICS_CONSTANTS_KEY = "metrics_constants_key" - private const val SPEED_CONSTANTS_KEY = "speed_constants_key" + private const val METRICS_CONSTANTS_KEY = "metrics_constants" + private const val SPEED_CONSTANTS_KEY = "speed_constants" - private const val SHOW_NOTIFICATION_ALWAYS_KEY = "show_notification_always_key" + private const val SHOW_NOTIFICATION_ALWAYS_KEY = "show_notification_always" } - private var shareLocationChats: Set = emptySet() - private var showOnMapChats: Set = emptySet() + private var shareLocationChats: Set = emptySet() + private var showOnMapChats: Set = emptySet() var metricsConstants = MetricsConstants.KILOMETERS_AND_METERS var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR @@ -35,16 +35,22 @@ class TelegramSettings(private val app: TelegramApplication) { return shareLocationChats.isNotEmpty() } - fun isSharingLocationToChat(chatId: Long): Boolean { - return shareLocationChats.contains(chatId) + fun isSharingLocationToChat(chatTitle: String): Boolean { + return shareLocationChats.contains(chatTitle) } - fun shareLocationToChat(chatId: Long, share: Boolean) { + fun removeNonexistingChats(presentChatTitles: List) { + val shareLocationChats = shareLocationChats.toMutableList() + shareLocationChats.intersect(presentChatTitles) + this.shareLocationChats = shareLocationChats.toHashSet() + } + + fun shareLocationToChat(chatTitle: String, share: Boolean) { val shareLocationChats = shareLocationChats.toMutableList() if (share) { - shareLocationChats.add(chatId) + shareLocationChats.add(chatTitle) } else { - shareLocationChats.remove(chatId) + shareLocationChats.remove(chatTitle) } this.shareLocationChats = shareLocationChats.toHashSet() } @@ -57,15 +63,15 @@ class TelegramSettings(private val app: TelegramApplication) { val shareLocationChatsSet = mutableSetOf() val shareLocationChats = ArrayList(shareLocationChats) - for (chatId in shareLocationChats) { - shareLocationChatsSet.add(chatId.toString()) + for (chatTitle in shareLocationChats) { + shareLocationChatsSet.add(chatTitle) } edit.putStringSet(SHARE_LOCATION_CHATS_KEY, shareLocationChatsSet) val showOnMapChatsSet = mutableSetOf() val showOnMapChats = ArrayList(showOnMapChats) - for (chatId in showOnMapChats) { - showOnMapChatsSet.add(chatId.toString()) + for (chatTitle in showOnMapChats) { + showOnMapChatsSet.add(chatTitle) } edit.putStringSet(SHOW_ON_MAP_CHATS_KEY, showOnMapChatsSet) @@ -80,23 +86,17 @@ class TelegramSettings(private val app: TelegramApplication) { fun read() { val prefs = app.getSharedPreferences(SETTINGS_NAME, Context.MODE_PRIVATE) - val shareLocationChats = mutableSetOf() + val shareLocationChats = mutableSetOf() val shareLocationChatsSet = prefs.getStringSet(SHARE_LOCATION_CHATS_KEY, mutableSetOf()) - for (chatIdStr in shareLocationChatsSet) { - val chatId = chatIdStr.toLongOrNull() - if (chatId != null) { - shareLocationChats.add(chatId) - } + for (chatTitle in shareLocationChatsSet) { + shareLocationChats.add(chatTitle) } this.shareLocationChats = shareLocationChats - val showOnMapChats = mutableSetOf() + val showOnMapChats = mutableSetOf() val showOnMapChatsSet = prefs.getStringSet(SHOW_ON_MAP_CHATS_KEY, mutableSetOf()) - for (chatIdStr in showOnMapChatsSet) { - val chatId = chatIdStr.toLongOrNull() - if (chatId != null) { - showOnMapChats.add(chatId) - } + for (chatTitle in showOnMapChatsSet) { + showOnMapChats.add(chatTitle) } this.showOnMapChats = showOnMapChats diff --git a/OsmAnd-telegram/src/main/java/net/osmand/telegram/helpers/TelegramHelper.kt b/OsmAnd-telegram/src/main/java/net/osmand/telegram/helpers/TelegramHelper.kt index 26591dbb4c..ef3c09fa92 100644 --- a/OsmAnd-telegram/src/main/java/net/osmand/telegram/helpers/TelegramHelper.kt +++ b/OsmAnd-telegram/src/main/java/net/osmand/telegram/helpers/TelegramHelper.kt @@ -17,22 +17,10 @@ class TelegramHelper private constructor() { companion object { private val log = PlatformUtil.getLog(TelegramHelper::class.java) private const val CHATS_LIMIT = 100 + private const val IGNORED_ERROR_CODE = 406 private var helper: TelegramHelper? = null - private val users = ConcurrentHashMap() - private val basicGroups = ConcurrentHashMap() - private val supergroups = ConcurrentHashMap() - private val secretChats = ConcurrentHashMap() - - private val chats = ConcurrentHashMap() - private val chatList = TreeSet() - private val chatLiveMessages = ConcurrentHashMap() - - private val usersFullInfo = ConcurrentHashMap() - private val basicGroupsFullInfo = ConcurrentHashMap() - private val supergroupsFullInfo = ConcurrentHashMap() - val instance: TelegramHelper get() { if (helper == null) { @@ -40,35 +28,37 @@ class TelegramHelper private constructor() { } return helper!! } - - private fun setChatOrder(chat: TdApi.Chat, order: Long) { - synchronized(chatList) { - if (chat.order != 0L) { - chatList.remove(OrderedChat(chat.order, chat.id)) - } - - chat.order = order - - if (chat.order != 0L) { - chatList.add(OrderedChat(chat.order, chat.id)) - } - } - } } + private val users = ConcurrentHashMap() + private val basicGroups = ConcurrentHashMap() + private val supergroups = ConcurrentHashMap() + private val secretChats = ConcurrentHashMap() + + private val chats = ConcurrentHashMap() + private val chatTitles = ConcurrentHashMap() + private val chatList = TreeSet() + private val chatLiveMessages = ConcurrentHashMap() + + private val usersFullInfo = ConcurrentHashMap() + private val basicGroupsFullInfo = ConcurrentHashMap() + private val supergroupsFullInfo = ConcurrentHashMap() + var appDir: String? = null private var libraryLoaded = false private var telegramAuthorizationRequestHandler: TelegramAuthorizationRequestHandler? = null private var client: Client? = null + private var haveFullChatList: Boolean = false - private var firstTimeSendingLiveLocation: Boolean = true - private var requestingLiveLocationMessages: Boolean = false + private var needRefreshActiveLiveLocationMessages: Boolean = true + private var requestingActiveLiveLocationMessages: Boolean = false private var authorizationState: AuthorizationState? = null - private var isHaveAuthorization = false + private var haveAuthorization = false private val defaultHandler = DefaultHandler() + private val liveLocationMessageUpdatesHandler = LiveLocationMessageUpdatesHandler() var listener: TelegramListener? = null @@ -78,10 +68,21 @@ class TelegramHelper private constructor() { } } + fun getChatTitles(): List { + return chatTitles.keys().toList() + } + fun getChat(id: Long): TdApi.Chat? { return chats[id] } + private fun updateChatTitles() { + chatTitles.clear() + for (chatEntry in chats.entries) { + chatTitles[chatEntry.value.title] = chatEntry.key + } + } + enum class TelegramAuthenticationParameterType { PHONE_NUMBER, CODE, @@ -105,6 +106,7 @@ class TelegramHelper private constructor() { newTelegramAuthorizationState: TelegramAuthorizationState) fun onTelegramChatsRead() + fun onTelegramChatsChanged() fun onTelegramError(code: Int, message: String) fun onSendLiveLicationError(code: Int, message: String) } @@ -172,8 +174,12 @@ class TelegramHelper private constructor() { } } - fun requestChats() { + fun requestChats(reload: Boolean = false) { synchronized(chatList) { + if (reload) { + chatList.clear() + haveFullChatList = false + } if (!haveFullChatList && CHATS_LIMIT > chatList.size) { // have enough chats in the chat list or chat list is too small var offsetOrder = java.lang.Long.MAX_VALUE @@ -187,7 +193,9 @@ class TelegramHelper private constructor() { when (obj.constructor) { TdApi.Error.CONSTRUCTOR -> { val error = obj as TdApi.Error - listener?.onTelegramError(error.code, error.message) + if (error.code != IGNORED_ERROR_CODE) { + listener?.onTelegramError(error.code, error.message) + } } TdApi.Chats.CONSTRUCTOR -> { val chatIds = (obj as TdApi.Chats).chatIds @@ -205,6 +213,7 @@ class TelegramHelper private constructor() { return } } + updateChatTitles() listener?.onTelegramChatsRead() } @@ -214,29 +223,35 @@ class TelegramHelper private constructor() { * @latitude Latitude of the location * @longitude Longitude of the location */ - fun sendLiveLocationMessage(chatIds: List, livePeriod: Int = 61, latitude: Double, longitude: Double) { - if (!requestingLiveLocationMessages) { - if (firstTimeSendingLiveLocation) { + fun sendLiveLocationMessage(chatTitles: List, livePeriod: Int = 61, latitude: Double, longitude: Double): Boolean { + if (!requestingActiveLiveLocationMessages && haveAuthorization) { + if (needRefreshActiveLiveLocationMessages) { getActiveLiveLocationMessages { - sendLiveLocationImpl(chatIds, livePeriod, latitude, longitude) + sendLiveLocationImpl(chatTitles, livePeriod, latitude, longitude) } - firstTimeSendingLiveLocation = false + needRefreshActiveLiveLocationMessages = false } else { - sendLiveLocationImpl(chatIds, livePeriod, latitude, longitude) + sendLiveLocationImpl(chatTitles, livePeriod, latitude, longitude) } + return true } + return false } private fun getActiveLiveLocationMessages(onComplete: (() -> Unit)?) { - requestingLiveLocationMessages = true + requestingActiveLiveLocationMessages = true client?.send(TdApi.GetActiveLiveLocationMessages(), { obj -> when (obj.constructor) { TdApi.Error.CONSTRUCTOR -> { val error = obj as TdApi.Error - listener?.onSendLiveLicationError(error.code, error.message) + if (error.code != IGNORED_ERROR_CODE) { + needRefreshActiveLiveLocationMessages = true + listener?.onSendLiveLicationError(error.code, error.message) + } } TdApi.Messages.CONSTRUCTOR -> { val messages = (obj as TdApi.Messages).messages + chatLiveMessages.clear() if (messages.isNotEmpty()) { for (msg in messages) { val chatId = msg.chatId @@ -247,24 +262,27 @@ class TelegramHelper private constructor() { } else -> listener?.onSendLiveLicationError(-1, "Receive wrong response from TDLib: $obj") } - requestingLiveLocationMessages = false + requestingActiveLiveLocationMessages = false }) } - private fun sendLiveLocationImpl(chatIds: List, livePeriod: Int = 61, latitude: Double, longitude: Double) { + private fun sendLiveLocationImpl(chatTitles: List, livePeriod: Int = 61, latitude: Double, longitude: Double) { val lp = livePeriod.coerceAtLeast(61) val location = TdApi.Location(latitude, longitude) val content = TdApi.InputMessageLocation(location, lp) - for (chatId in chatIds) { - val msgId = chatLiveMessages[chatId] - if (msgId != null) { - if (msgId != 0L) { - client?.send(TdApi.EditMessageLiveLocation(chatId, msgId, null, location), LiveLocationMessageUpdatesHandler(chatId)) + for (chatTitle in chatTitles) { + val chatId = this.chatTitles[chatTitle] + if (chatId != null) { + val msgId = chatLiveMessages[chatId] + if (msgId != null) { + if (msgId != 0L) { + client?.send(TdApi.EditMessageLiveLocation(chatId, msgId, null, location), liveLocationMessageUpdatesHandler) + } + } else { + chatLiveMessages[chatId] = 0L + client?.send(TdApi.SendMessage(chatId, 0, false, true, null, content), liveLocationMessageUpdatesHandler) } - } else { - chatLiveMessages[chatId] = 0L - client?.send(TdApi.SendMessage(chatId, 0, false, true, null, content), LiveLocationMessageUpdatesHandler(chatId)) } } } @@ -273,18 +291,22 @@ class TelegramHelper private constructor() { * @chatId Id of the chat * @message Text of the message */ - fun sendTextMessage(chatId: Long, message: String) { + fun sendTextMessage(chatId: Long, message: String): Boolean { // initialize reply markup just for testing //val row = arrayOf(TdApi.InlineKeyboardButton("https://telegram.org?1", TdApi.InlineKeyboardButtonTypeUrl()), TdApi.InlineKeyboardButton("https://telegram.org?2", TdApi.InlineKeyboardButtonTypeUrl()), TdApi.InlineKeyboardButton("https://telegram.org?3", TdApi.InlineKeyboardButtonTypeUrl())) //val replyMarkup = TdApi.ReplyMarkupInlineKeyboard(arrayOf(row, row, row)) - val content = TdApi.InputMessageText(TdApi.FormattedText(message, null), false, true) - client?.send(TdApi.SendMessage(chatId, 0, false, true, null, content), defaultHandler) + if (haveAuthorization) { + val content = TdApi.InputMessageText(TdApi.FormattedText(message, null), false, true) + client?.send(TdApi.SendMessage(chatId, 0, false, true, null, content), defaultHandler) + return true + } + return false } fun logout(): Boolean { return if (libraryLoaded) { - isHaveAuthorization = false + haveAuthorization = false client!!.send(TdApi.LogOut(), defaultHandler) true } else { @@ -294,7 +316,7 @@ class TelegramHelper private constructor() { fun close(): Boolean { return if (libraryLoaded) { - isHaveAuthorization = false + haveAuthorization = false client!!.send(TdApi.Close(), defaultHandler) true } else { @@ -302,19 +324,35 @@ class TelegramHelper private constructor() { } } - private inner class LiveLocationMessageUpdatesHandler(val chatId: Long): ResultHandler { + private fun setChatOrder(chat: TdApi.Chat, order: Long) { + synchronized(chatList) { + if (chat.order != 0L) { + chatList.remove(OrderedChat(chat.order, chat.id)) + } + + chat.order = order + + if (chat.order != 0L) { + chatList.add(OrderedChat(chat.order, chat.id)) + } + } + } + + private inner class LiveLocationMessageUpdatesHandler: ResultHandler { override fun onResult(obj: TdApi.Object) { when (obj.constructor) { TdApi.Error.CONSTRUCTOR -> { val error = obj as TdApi.Error - chatLiveMessages.remove(chatId) - listener?.onSendLiveLicationError(error.code, error.message) + if (error.code != IGNORED_ERROR_CODE) { + needRefreshActiveLiveLocationMessages = true + listener?.onSendLiveLicationError(error.code, error.message) + } } else -> { if (obj is TdApi.Message) { when (obj.sendingState?.constructor) { TdApi.MessageSendingStateFailed.CONSTRUCTOR -> { - chatLiveMessages.remove(obj.chatId) + needRefreshActiveLiveLocationMessages = true listener?.onSendLiveLicationError(-1, "Live location message ${obj.id} failed to send") } } @@ -329,7 +367,7 @@ class TelegramHelper private constructor() { if (authorizationState != null) { this.authorizationState = authorizationState } - when (this.authorizationState!!.constructor) { + when (this.authorizationState?.constructor) { TdApi.AuthorizationStateWaitTdlibParameters.CONSTRUCTOR -> { log.info("Init tdlib parameters") @@ -363,16 +401,12 @@ class TelegramHelper private constructor() { telegramAuthorizationRequestHandler?.telegramAuthorizationRequestListener?.onRequestTelegramAuthenticationParameter(PASSWORD) } TdApi.AuthorizationStateReady.CONSTRUCTOR -> { - isHaveAuthorization = true - firstTimeSendingLiveLocation = true log.info("Ready") } TdApi.AuthorizationStateLoggingOut.CONSTRUCTOR -> { - isHaveAuthorization = false log.info("Logging out") } TdApi.AuthorizationStateClosing.CONSTRUCTOR -> { - isHaveAuthorization = false log.info("Closing") } TdApi.AuthorizationStateClosed.CONSTRUCTOR -> { @@ -380,6 +414,14 @@ class TelegramHelper private constructor() { } else -> log.error("Unsupported authorization state: " + this.authorizationState!!) } + val wasAuthorized = haveAuthorization + haveAuthorization = this.authorizationState?.constructor == TdApi.AuthorizationStateReady.CONSTRUCTOR + if (wasAuthorized != haveAuthorization) { + needRefreshActiveLiveLocationMessages = true + if (haveAuthorization) { + requestChats(true) + } + } val newAuthState = getTelegramAuthorizationState() listener?.onTelegramStatusChanged(prevAuthState, newAuthState) } @@ -456,7 +498,8 @@ class TelegramHelper private constructor() { setChatOrder(chat, order) } } - listener?.onTelegramChatsRead() + updateChatTitles() + listener?.onTelegramChatsChanged() } TdApi.UpdateChatTitle.CONSTRUCTOR -> { val updateChat = obj as TdApi.UpdateChatTitle @@ -464,6 +507,8 @@ class TelegramHelper private constructor() { synchronized(chat!!) { chat.title = updateChat.title } + updateChatTitles() + listener?.onTelegramChatsChanged() } TdApi.UpdateChatPhoto.CONSTRUCTOR -> { val updateChat = obj as TdApi.UpdateChatPhoto @@ -471,6 +516,7 @@ class TelegramHelper private constructor() { synchronized(chat!!) { chat.photo = updateChat.photo } + listener?.onTelegramChatsChanged() } TdApi.UpdateChatLastMessage.CONSTRUCTOR -> { val updateChat = obj as TdApi.UpdateChatLastMessage @@ -486,6 +532,7 @@ class TelegramHelper private constructor() { synchronized(chat!!) { setChatOrder(chat, updateChat.order) } + listener?.onTelegramChatsChanged() } TdApi.UpdateChatIsPinned.CONSTRUCTOR -> { val updateChat = obj as TdApi.UpdateChatIsPinned @@ -525,9 +572,7 @@ class TelegramHelper private constructor() { } } TdApi.UpdateMessageSendFailed.CONSTRUCTOR -> { - val updateMessageSendFailed = obj as TdApi.UpdateMessageSendFailed - val message = updateMessageSendFailed.message - chatLiveMessages.remove(message.chatId) + needRefreshActiveLiveLocationMessages = true } TdApi.UpdateMessageSendSucceeded.CONSTRUCTOR -> { val updateMessageSendSucceeded = obj as TdApi.UpdateMessageSendSucceeded @@ -593,8 +638,10 @@ class TelegramHelper private constructor() { TdApi.Error.CONSTRUCTOR -> { log.error("Receive an error: $obj") val errorObj = obj as TdApi.Error - telegramAuthorizationRequestHandler?.telegramAuthorizationRequestListener?.onTelegramAuthorizationRequestError(errorObj.code, errorObj.message) - onAuthorizationStateUpdated(null) // repeat last action + if (errorObj.code != IGNORED_ERROR_CODE) { + telegramAuthorizationRequestHandler?.telegramAuthorizationRequestListener?.onTelegramAuthorizationRequestError(errorObj.code, errorObj.message) + onAuthorizationStateUpdated(null) // repeat last action + } } TdApi.Ok.CONSTRUCTOR -> { }